From 950a2cfad3638bfc39db00b19ac4046743c8b8e8 Mon Sep 17 00:00:00 2001 From: jfh Date: Thu, 4 Nov 2021 14:56:09 +0200 Subject: [PATCH 1/3] Add test_random from CPython 3.8. --- Lib/test/test_random.py | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index 4648e2742..899ca108c 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -28,8 +28,6 @@ class TestBasicOps: state2 = self.gen.getstate() self.assertNotEqual(state1, state2) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_saverestore(self): N = 1000 self.gen.seed() @@ -262,8 +260,6 @@ class TestBasicOps: restoredseq = [newgen.random() for i in range(10)] self.assertEqual(origseq, restoredseq) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_bug_1727780(self): # verify that version-2-pickles can be loaded # fine, whether they are created on 32-bit or 64-bit @@ -412,26 +408,6 @@ class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase): class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase): gen = random.Random() - # TODO: RUSTPYTHON - @unittest.expectedFailure - def test_autoseed(self): - super().test_autoseed() - - # TODO: RUSTPYTHON - @unittest.expectedFailure - def test_seedargs(self): - super().test_seedargs() - - # TODO: RUSTPYTHON - @unittest.expectedFailure - def test_pickling(self): - super().test_pickling() - - # TODO: RUSTPYTHON - @unittest.expectedFailure - def test_seed_when_randomness_source_not_found(self): - super().test_seed_when_randomness_source_not_found() - def test_guaranteed_stable(self): # These sequences are guaranteed to stay the same across versions of python self.gen.seed(3456147, version=1) @@ -502,8 +478,6 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase): def test_setstate_first_arg(self): self.assertRaises(ValueError, self.gen.setstate, (1, None, None)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_setstate_middle_arg(self): start_state = self.gen.getstate() # Wrong type, s/b tuple @@ -628,8 +602,6 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase): self.assertEqual(set(range(start,stop)), set([self.gen.randrange(start,stop) for i in range(100)])) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_genrandbits(self): # Verify cross-platform repeatability self.gen.seed(1234567) @@ -685,8 +657,6 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase): self.assertEqual(k, numbits) # note the stronger assertion self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_randbelow_without_getrandbits(self): # Random._randbelow() can only use random() when the built-in one # has been overridden but no new getrandbits() method was supplied. @@ -785,8 +755,6 @@ def gamma(z, sqrt2pi=(2.0*pi)**0.5): ]) class TestDistributions(unittest.TestCase): - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_zeroinputs(self): # Verify that distributions can handle a series of zero inputs' g = random.Random() @@ -899,8 +867,6 @@ class TestDistributions(unittest.TestCase): returned_value = random.gammavariate(1.1, 2.3) self.assertAlmostEqual(returned_value, 2.53) - # TODO: RUSTPYTHON - @unittest.expectedFailure @unittest.mock.patch('random.Random.random') def test_gammavariate_alpha_equal_one(self, random_mock): @@ -912,8 +878,6 @@ class TestDistributions(unittest.TestCase): returned_value = random.gammavariate(1.0, 3.14) self.assertAlmostEqual(returned_value, 1.877208182372648) - # TODO: RUSTPYTHON - @unittest.expectedFailure @unittest.mock.patch('random.Random.random') def test_gammavariate_alpha_equal_one_equals_expovariate(self, random_mock): @@ -1004,8 +968,6 @@ class TestDistributions(unittest.TestCase): class TestRandomSubclassing(unittest.TestCase): - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_random_subclass_with_kwargs(self): # SF bug #1486663 -- this used to erroneously raise a TypeError class Subclass(random.Random): @@ -1013,8 +975,6 @@ class TestRandomSubclassing(unittest.TestCase): random.Random.__init__(self) Subclass(newarg=1) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_subclasses_overriding_methods(self): # Subclasses with an overridden random, but only the original # getrandbits method should not rely on getrandbits in for randrange, From aa00fe9c64d8ae2cfe0144e305d21010a569b30c Mon Sep 17 00:00:00 2001 From: jfh Date: Thu, 4 Nov 2021 15:12:32 +0200 Subject: [PATCH 2/3] Mark failing tests in test_random. --- Lib/test/test_random.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index 899ca108c..cee28f283 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -20,6 +20,8 @@ class TestBasicOps: """Helper function to make a list of random numbers""" return [self.gen.random() for i in range(n)] + # TODO: RUSTPYTHON AttributeError: 'super' object has no attribute 'getstate' + @unittest.expectedFailure def test_autoseed(self): self.gen.seed() state1 = self.gen.getstate() @@ -28,6 +30,8 @@ class TestBasicOps: state2 = self.gen.getstate() self.assertNotEqual(state1, state2) + # TODO: RUSTPYTHON AttributeError: 'super' object has no attribute 'getstate' + @unittest.expectedFailure def test_saverestore(self): N = 1000 self.gen.seed() @@ -36,6 +40,8 @@ class TestBasicOps: self.gen.setstate(state) # should regenerate the same sequence self.assertEqual(randseq, self.randomlist(N)) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_seedargs(self): # Seed value with a negative hash. class MySeed(object): @@ -49,6 +55,8 @@ class TestBasicOps: self.assertRaises(TypeError, self.gen.seed, 1, 2, 3, 4) self.assertRaises(TypeError, type(self.gen), []) + # TODO: RUSTPYTHON Success for SystemRandom, failure for MersenneTwister + @unittest.skip @unittest.mock.patch('random._urandom') # os.urandom def test_seed_when_randomness_source_not_found(self, urandom_mock): # Random.seed() uses time.time() when an operating system specific @@ -252,6 +260,8 @@ class TestBasicOps: self.assertEqual(x1, x2) self.assertEqual(y1, y2) + # TODO: RUSTPYTHON AttributeError: 'super' object has no attribute 'getstate' + @unittest.expectedFailure def test_pickling(self): for proto in range(pickle.HIGHEST_PROTOCOL + 1): state = pickle.dumps(self.gen, proto) @@ -260,6 +270,8 @@ class TestBasicOps: restoredseq = [newgen.random() for i in range(10)] self.assertEqual(origseq, restoredseq) + # TODO: RUSTPYTHON AttributeError: 'super' object has no attribute 'getstate' + @unittest.expectedFailure def test_bug_1727780(self): # verify that version-2-pickles can be loaded # fine, whether they are created on 32-bit or 64-bit @@ -478,6 +490,8 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase): def test_setstate_first_arg(self): self.assertRaises(ValueError, self.gen.setstate, (1, None, None)) + # TODO: RUSTPYTHON AttributeError: 'super' object has no attribute 'getstate' + @unittest.expectedFailure def test_setstate_middle_arg(self): start_state = self.gen.getstate() # Wrong type, s/b tuple @@ -602,6 +616,8 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase): self.assertEqual(set(range(start,stop)), set([self.gen.randrange(start,stop) for i in range(100)])) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_genrandbits(self): # Verify cross-platform repeatability self.gen.seed(1234567) @@ -657,6 +673,8 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase): self.assertEqual(k, numbits) # note the stronger assertion self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion + # TODO: RUSTPYTHON AttributeError: 'Random' object has no attribute '_randbelow_without_getrandbits' + @unittest.expectedFailure def test_randbelow_without_getrandbits(self): # Random._randbelow() can only use random() when the built-in one # has been overridden but no new getrandbits() method was supplied. @@ -755,6 +773,8 @@ def gamma(z, sqrt2pi=(2.0*pi)**0.5): ]) class TestDistributions(unittest.TestCase): + # TODO: RUSTPYTHON ValueError: math domain error + @unittest.expectedFailure def test_zeroinputs(self): # Verify that distributions can handle a series of zero inputs' g = random.Random() @@ -867,6 +887,8 @@ class TestDistributions(unittest.TestCase): returned_value = random.gammavariate(1.1, 2.3) self.assertAlmostEqual(returned_value, 2.53) + # TODO: RUSTPYTHON + @unittest.expectedFailure @unittest.mock.patch('random.Random.random') def test_gammavariate_alpha_equal_one(self, random_mock): @@ -878,6 +900,8 @@ class TestDistributions(unittest.TestCase): returned_value = random.gammavariate(1.0, 3.14) self.assertAlmostEqual(returned_value, 1.877208182372648) + # TODO: RUSTPYTHON + @unittest.expectedFailure @unittest.mock.patch('random.Random.random') def test_gammavariate_alpha_equal_one_equals_expovariate(self, random_mock): @@ -968,6 +992,8 @@ class TestDistributions(unittest.TestCase): class TestRandomSubclassing(unittest.TestCase): + # TODO: RUSTPYTHON Unexpected keyword argument newarg + @unittest.expectedFailure def test_random_subclass_with_kwargs(self): # SF bug #1486663 -- this used to erroneously raise a TypeError class Subclass(random.Random): @@ -975,6 +1001,8 @@ class TestRandomSubclassing(unittest.TestCase): random.Random.__init__(self) Subclass(newarg=1) + # TODO: RUSTPYTHON AssertionError: items in the second set but not the first. + @unittest.expectedFailure def test_subclasses_overriding_methods(self): # Subclasses with an overridden random, but only the original # getrandbits method should not rely on getrandbits in for randrange, From 05c4fcf9347e87ee06d9d799fff53e0249ff70cd Mon Sep 17 00:00:00 2001 From: jfh Date: Thu, 4 Nov 2021 15:23:06 +0200 Subject: [PATCH 3/3] Allow any object as an argument for random.seed --- Lib/test/test_random.py | 8 ++------ stdlib/src/random.rs | 13 +++++++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index cee28f283..594bfb62a 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -40,8 +40,6 @@ class TestBasicOps: self.gen.setstate(state) # should regenerate the same sequence self.assertEqual(randseq, self.randomlist(N)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_seedargs(self): # Seed value with a negative hash. class MySeed(object): @@ -55,8 +53,6 @@ class TestBasicOps: self.assertRaises(TypeError, self.gen.seed, 1, 2, 3, 4) self.assertRaises(TypeError, type(self.gen), []) - # TODO: RUSTPYTHON Success for SystemRandom, failure for MersenneTwister - @unittest.skip @unittest.mock.patch('random._urandom') # os.urandom def test_seed_when_randomness_source_not_found(self, urandom_mock): # Random.seed() uses time.time() when an operating system specific @@ -887,7 +883,7 @@ class TestDistributions(unittest.TestCase): returned_value = random.gammavariate(1.1, 2.3) self.assertAlmostEqual(returned_value, 2.53) - # TODO: RUSTPYTHON + # TODO: RUSTPYTHON assertAlmostEqual failure. @unittest.expectedFailure @unittest.mock.patch('random.Random.random') def test_gammavariate_alpha_equal_one(self, random_mock): @@ -900,7 +896,7 @@ class TestDistributions(unittest.TestCase): returned_value = random.gammavariate(1.0, 3.14) self.assertAlmostEqual(returned_value, 1.877208182372648) - # TODO: RUSTPYTHON + # TODO: RUSTPYTHON assertAlmostEqual failure. @unittest.expectedFailure @unittest.mock.patch('random.Random.random') def test_gammavariate_alpha_equal_one_equals_expovariate(self, random_mock): diff --git a/stdlib/src/random.rs b/stdlib/src/random.rs index 4fd7b3147..5e74e4310 100644 --- a/stdlib/src/random.rs +++ b/stdlib/src/random.rs @@ -6,7 +6,7 @@ pub(crate) use _random::make_module; mod _random { use crate::common::lock::PyMutex; use crate::vm::{ - builtins::{PyIntRef, PyTypeRef}, + builtins::{PyInt, PyTypeRef}, function::OptionalOption, types::Constructor, PyObjectRef, PyResult, PyValue, VirtualMachine, @@ -85,13 +85,17 @@ mod _random { mt19937::gen_res53(&mut *rng) } - // TODO: n can be a float, str, bytes, or bytearray #[pymethod] - fn seed(&self, n: OptionalOption) { + fn seed(&self, n: OptionalOption, vm: &VirtualMachine) -> PyResult<()> { let new_rng = match n.flatten() { None => PyRng::default(), Some(n) => { - let (_, mut key) = n.as_bigint().abs().to_u32_digits(); + // Fallback to using hash if object isn't Int-like. + let (_, mut key) = match n.downcast::() { + Ok(n) => n.as_bigint().abs(), + Err(obj) => BigInt::from(obj.hash(vm)?).abs(), + } + .to_u32_digits(); if cfg!(target_endian = "big") { key.reverse(); } @@ -101,6 +105,7 @@ mod _random { }; *self.rng.lock() = new_rng; + Ok(()) } #[pymethod]