From 3fefe059d1e93e912763e17d5a4f588150ed1a28 Mon Sep 17 00:00:00 2001 From: Michael Ekstrand Date: Tue, 28 May 2024 16:11:33 -0400 Subject: [PATCH 1/3] add std_rng to create stdlib Random --- docs/api.rst | 1 + seedbank/__init__.py | 1 + seedbank/stdlib.py | 25 +++++++++++++++++++++++++ tests/test_stdlib.py | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 tests/test_stdlib.py diff --git a/docs/api.rst b/docs/api.rst index 6f5dc61..f26ef23 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -65,6 +65,7 @@ override the global seed to support seed-specifying APIs. Packages that expect their client code to use SeedBank to seed the random number ecosystem should use these functions to obtain random number generators. +.. autofunction:: std_rng .. autofunction:: numpy_rng .. autofunction:: numpy_random_state .. autofunction:: cupy_rng diff --git a/seedbank/__init__.py b/seedbank/__init__.py index 9310889..f20b64f 100644 --- a/seedbank/__init__.py +++ b/seedbank/__init__.py @@ -136,3 +136,4 @@ def int_seed( from seedbank._config import init_file # noqa: E402 from seedbank.cupy import cupy_rng # noqa: E402 from seedbank.numpy import numpy_random_state, numpy_rng # noqa: E402 +from seedbank.stdlib import std_rng # noqa: E402 diff --git a/seedbank/stdlib.py b/seedbank/stdlib.py index 95e47e0..989b38c 100644 --- a/seedbank/stdlib.py +++ b/seedbank/stdlib.py @@ -1,6 +1,9 @@ import logging import random +from typing import Optional +from . import derive_seed +from ._keys import SeedLike, make_seed from ._state import SeedState _log = logging.getLogger(__name__) @@ -13,3 +16,25 @@ def is_available(): def seed(state: SeedState): _log.debug("initializing stdlib seed") random.seed(state.int_seed) + + +def std_rng( + spec: Optional[SeedLike] = None, +) -> random.Random: + """ + Get a standard library random number generator with either the specified + seed or a fresh seed. + + Args: + spec: + The spec for this RNG. + + Returns: + A random number generator. + """ + if spec is None: + seed = derive_seed() + else: + seed = make_seed(spec) + data = seed.generate_state(4) + return random.Random(bytes(data)) diff --git a/tests/test_stdlib.py b/tests/test_stdlib.py new file mode 100644 index 0000000..22d52e4 --- /dev/null +++ b/tests/test_stdlib.py @@ -0,0 +1,33 @@ +""" +stdlib python tests +""" + +import random + +from seedbank import std_rng + + +def test_stdlib_rng(): + """ + Make sure we get an stdlib RNG. + """ + rng = std_rng() + assert isinstance(rng, random.Random) + + +def test_stdlib_rng_fresh_seed(): + """ + Test that two stdlib RNGs with fresh seeds return different numbers. + """ + rng1 = std_rng() + rng2 = std_rng() + assert rng1.getrandbits(10) != rng2.getrandbits(10) + + +def test_stdlib_rng_same_seed(): + """ + Test that two stdlib RNGs with the same seed start the same. + """ + rng1 = std_rng("foo") + rng2 = std_rng("foo") + assert rng1.getrandbits(10) == rng2.getrandbits(10) From eed3e178baa85dee8aa4aa714b75d38ce48c20f3 Mon Sep 17 00:00:00 2001 From: Michael Ekstrand Date: Tue, 28 May 2024 16:13:18 -0400 Subject: [PATCH 2/3] small doc fix --- seedbank/stdlib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seedbank/stdlib.py b/seedbank/stdlib.py index 989b38c..1169956 100644 --- a/seedbank/stdlib.py +++ b/seedbank/stdlib.py @@ -22,8 +22,8 @@ def std_rng( spec: Optional[SeedLike] = None, ) -> random.Random: """ - Get a standard library random number generator with either the specified - seed or a fresh seed. + Get a standard library random number generator (:class:`random.Random`) with + either the specified seed or a fresh seed. Args: spec: From 8693ff7434a5a7d3382fdfdd6aa36f9a07b7f93b Mon Sep 17 00:00:00 2001 From: Michael Ekstrand Date: Tue, 28 May 2024 16:16:51 -0400 Subject: [PATCH 3/3] add std_rng to exports --- seedbank/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/seedbank/__init__.py b/seedbank/__init__.py index f20b64f..8b8c4e5 100644 --- a/seedbank/__init__.py +++ b/seedbank/__init__.py @@ -31,6 +31,7 @@ "initialize", "init_file", "derive_seed", + "std_rng", "numpy_rng", "numpy_random_state", "cupy_rng",