From 231200d372932ed2f36b441ab004b8b861bf5d95 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Fri, 12 Sep 2025 16:18:35 +0100 Subject: [PATCH] Modify Numpy seed restriction --- CHANGELOG.rst | 8 +++++++- src/pytest_randomly/__init__.py | 17 +++-------------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4bf13fb..e38fd10 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,11 +5,17 @@ Changelog Unreleased ---------- -* Removed the random state caching, which would grow without bound, leaking memory in long test runs. +* Remove the random state caching, which would grow without bound, leaking memory in long test runs. The caching was added to slightly speed up re-using the same (final) seed, but since the final seed is now different for each test, it has no effect. `PR #690 `__. +* Modify Numpy seed restriction, replacing hashing with a modulo operation. + The extra work to hash is unnecessary now that we generate a final seed per test with CRC32. + This change saves ~500ns per test when Numpy is installed. + + `PR #691 `__. + 4.0.0 (2025-09-10) ------------------ diff --git a/src/pytest_randomly/__init__.py b/src/pytest_randomly/__init__.py index 03ec284..fd4d042 100644 --- a/src/pytest_randomly/__init__.py +++ b/src/pytest_randomly/__init__.py @@ -1,7 +1,6 @@ from __future__ import annotations import argparse -import hashlib import random import sys from functools import lru_cache @@ -160,8 +159,7 @@ def _reseed(config: Config, offset: int = 0) -> int: baker_random.setstate(random_state) if have_numpy: # pragma: no branch - numpy_seed = _truncate_seed_for_numpy(seed) - np_random.seed(numpy_seed) + np_random.seed(seed % 2**32) if entrypoint_reseeds is None: eps = entry_points(group="pytest_randomly.random_seeder") @@ -172,15 +170,6 @@ def _reseed(config: Config, offset: int = 0) -> int: return seed -def _truncate_seed_for_numpy(seed: int) -> int: - seed = abs(seed) - if seed <= 2**32 - 1: - return seed - - seed_bytes = seed.to_bytes(seed.bit_length(), "big") - return int.from_bytes(hashlib.sha512(seed_bytes).digest()[: 32 // 8], "big") - - def pytest_report_header(config: Config) -> str: seed = config.getoption("randomly_seed") _reseed(config) @@ -189,7 +178,7 @@ def pytest_report_header(config: Config) -> str: def pytest_runtest_setup(item: Item) -> None: if item.config.getoption("randomly_reset_seed"): - _reseed(item.config, _crc32(item.nodeid) - 1) + _reseed(item.config, (_crc32(item.nodeid) - 1) % 2**32) def pytest_runtest_call(item: Item) -> None: @@ -199,7 +188,7 @@ def pytest_runtest_call(item: Item) -> None: def pytest_runtest_teardown(item: Item) -> None: if item.config.getoption("randomly_reset_seed"): - _reseed(item.config, _crc32(item.nodeid) + 1) + _reseed(item.config, (_crc32(item.nodeid) + 1) % 2**32) @hookimpl(tryfirst=True)