diff --git a/Lib/random.py b/Lib/random.py index f8735d42a1..85bad08d57 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -167,15 +167,11 @@ def seed(self, a=None, version=2): elif version == 2 and isinstance(a, (str, bytes, bytearray)): if isinstance(a, str): a = a.encode() - a = int.from_bytes(a + _sha512(a).digest(), 'big') + a = int.from_bytes(a + _sha512(a).digest()) elif not isinstance(a, (type(None), int, float, str, bytes, bytearray)): - _warn('Seeding based on hashing is deprecated\n' - 'since Python 3.9 and will be removed in a subsequent ' - 'version. The only \n' - 'supported seed types are: None, ' - 'int, float, str, bytes, and bytearray.', - DeprecationWarning, 2) + raise TypeError('The only supported seed types are: None,\n' + 'int, float, str, bytes, and bytearray.') super().seed(a) self.gauss_next = None @@ -250,10 +246,8 @@ def __init_subclass__(cls, /, **kwargs): break def _randbelow_with_getrandbits(self, n): - "Return a random int in the range [0,n). Returns 0 if n==0." + "Return a random int in the range [0,n). Defined for n > 0." - if not n: - return 0 getrandbits = self.getrandbits k = n.bit_length() # don't use (n-1) here because n can be 1 r = getrandbits(k) # 0 <= r < 2**k @@ -262,7 +256,7 @@ def _randbelow_with_getrandbits(self, n): return r def _randbelow_without_getrandbits(self, n, maxsize=1< 0. The implementation does not use getrandbits, but only random. """ @@ -273,8 +267,6 @@ def _randbelow_without_getrandbits(self, n, maxsize=1<> 3) * RECIP_BPF + """Get the next random number in the range 0.0 <= X < 1.0.""" + return (int.from_bytes(_urandom(7)) >> 3) * RECIP_BPF def getrandbits(self, k): """getrandbits(k) -> x. Generates an int with k random bits.""" if k < 0: raise ValueError('number of bits must be non-negative') numbytes = (k + 7) // 8 # bits / 8 and rounded up - x = int.from_bytes(_urandom(numbytes), 'big') + x = int.from_bytes(_urandom(numbytes)) return x >> (numbytes * 8 - k) # trim excess bits def randbytes(self, n): diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index e7028504ea..4bf00d5dbb 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -52,12 +52,11 @@ def __hash__(self): self.gen.seed(arg) for arg in [1+2j, tuple('abc'), MySeed()]: - with self.assertWarns(DeprecationWarning): + with self.assertRaises(TypeError): self.gen.seed(arg) for arg in [list(range(3)), dict(one=1)]: - with self.assertWarns(DeprecationWarning): - self.assertRaises(TypeError, self.gen.seed, arg) + self.assertRaises(TypeError, self.gen.seed, arg) self.assertRaises(TypeError, self.gen.seed, 1, 2, 3, 4) self.assertRaises(TypeError, type(self.gen), []) @@ -110,15 +109,6 @@ def test_shuffle(self): self.assertTrue(lst != shuffled_lst) self.assertRaises(TypeError, shuffle, (1, 2, 3)) - def test_shuffle_random_argument(self): - # Test random argument to shuffle. - shuffle = self.gen.shuffle - mock_random = unittest.mock.Mock(return_value=0.5) - seq = bytearray(b'abcdefghijk') - with self.assertWarns(DeprecationWarning): - shuffle(seq, mock_random) - mock_random.assert_called_with() - def test_choice(self): choice = self.gen.choice with self.assertRaises(IndexError): @@ -126,6 +116,21 @@ def test_choice(self): self.assertEqual(choice([50]), 50) self.assertIn(choice([25, 75]), [25, 75]) + def test_choice_with_numpy(self): + # Accommodation for NumPy arrays which have disabled __bool__(). + # See: https://github.com/python/cpython/issues/100805 + choice = self.gen.choice + + class NA(list): + "Simulate numpy.array() behavior" + def __bool__(self): + raise RuntimeError + + with self.assertRaises(IndexError): + choice(NA([])) + self.assertEqual(choice(NA([50])), 50) + self.assertIn(choice(NA([25, 75])), [25, 75]) + def test_sample(self): # For the entire allowable range of 0 <= k <= N, validate that # the sample is of the correct length and contains only unique items @@ -169,7 +174,7 @@ def test_sample_on_dicts(self): self.assertRaises(TypeError, self.gen.sample, dict.fromkeys('abcdef'), 2) def test_sample_on_sets(self): - with self.assertWarns(DeprecationWarning): + with self.assertRaises(TypeError): population = {10, 20, 30, 40, 50, 60, 70} self.gen.sample(population, k=5) @@ -391,23 +396,6 @@ def test_pickling(self): restoredseq = [newgen.random() for i in range(10)] self.assertEqual(origseq, restoredseq) - @test.support.cpython_only - def test_bug_41052(self): - # _random.Random should not be allowed to serialization - import _random - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - r = _random.Random() - self.assertRaises(TypeError, pickle.dumps, r, proto) - - @test.support.cpython_only - def test_bug_42008(self): - # _random.Random should call seed with first element of arg tuple - import _random - r1 = _random.Random() - r1.seed(8675309) - r2 = _random.Random(8675309) - self.assertEqual(r1.random(), r2.random()) - # TODO: RUSTPYTHON AttributeError: 'super' object has no attribute 'getstate' @unittest.expectedFailure def test_bug_1727780(self): @@ -445,6 +433,10 @@ def test_randbytes(self): self.assertRaises(ValueError, self.gen.randbytes, -1) self.assertRaises(TypeError, self.gen.randbytes, 1.0) + def test_mu_sigma_default_args(self): + self.assertIsInstance(self.gen.normalvariate(), float) + self.assertIsInstance(self.gen.gauss(), float) + try: random.SystemRandom().random() @@ -592,6 +584,25 @@ def test_randbelow_logic(self, _log=log, int=int): self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion +class TestRawMersenneTwister(unittest.TestCase): + @test.support.cpython_only + def test_bug_41052(self): + # _random.Random should not be allowed to serialization + import _random + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + r = _random.Random() + self.assertRaises(TypeError, pickle.dumps, r, proto) + + @test.support.cpython_only + def test_bug_42008(self): + # _random.Random should call seed with first element of arg tuple + import _random + r1 = _random.Random() + r1.seed(8675309) + r2 = _random.Random(8675309) + self.assertEqual(r1.random(), r2.random()) + + class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase): gen = random.Random() @@ -846,10 +857,6 @@ def test_randbelow_without_getrandbits(self): maxsize+1, maxsize=maxsize ) self.gen._randbelow_without_getrandbits(5640, maxsize=maxsize) - # issue 33203: test that _randbelow returns zero on - # n == 0 also in its getrandbits-independent branch. - x = self.gen._randbelow_without_getrandbits(0, maxsize=maxsize) - self.assertEqual(x, 0) # This might be going too far to test a single line, but because of our # noble aim of achieving 100% test coverage we need to write a case in @@ -1331,7 +1338,7 @@ def test__all__(self): # tests validity but not completeness of the __all__ list self.assertTrue(set(random.__all__) <= set(dir(random))) - @unittest.skipUnless(hasattr(os, "fork"), "fork() required") + @test.support.requires_fork() def test_after_fork(self): # Test the global Random instance gets reseeded in child r, w = os.pipe() diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index f46047f67e..0ad9949c6a 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -794,6 +794,7 @@ pub struct IntOptions { #[derive(FromArgs)] struct IntFromByteArgs { bytes: PyBytesInner, + #[pyarg(any, default = "ArgByteOrder::Big")] byteorder: ArgByteOrder, #[pyarg(named, optional)] signed: OptionalArg,