@@ -640,21 +640,22 @@ def test_randbelow_logic(self, _log=log, int=int):
640640 self .assertEqual (k , numbits ) # note the stronger assertion
641641 self .assertTrue (2 ** k > n > 2 ** (k - 1 )) # note the stronger assertion
642642
643- @unittest .mock .patch ('random.Random.random' )
644- def test_randbelow_overridden_random (self , random_mock ):
643+ def test_randbelow_without_getrandbits (self ):
645644 # Random._randbelow() can only use random() when the built-in one
646645 # has been overridden but no new getrandbits() method was supplied.
647- random_mock .side_effect = random .SystemRandom ().random
648646 maxsize = 1 << random .BPF
649647 with warnings .catch_warnings ():
650648 warnings .simplefilter ("ignore" , UserWarning )
651649 # Population range too large (n >= maxsize)
652- self .gen ._randbelow (maxsize + 1 , maxsize = maxsize )
653- self .gen ._randbelow (5640 , maxsize = maxsize )
650+ self .gen ._randbelow_without_getrandbits (
651+ maxsize + 1 , maxsize = maxsize
652+ )
653+ self .gen ._randbelow_without_getrandbits (5640 , maxsize = maxsize )
654654 # issue 33203: test that _randbelow raises ValueError on
655655 # n == 0 also in its getrandbits-independent branch.
656656 with self .assertRaises (ValueError ):
657- self .gen ._randbelow (0 , maxsize = maxsize )
657+ self .gen ._randbelow_without_getrandbits (0 , maxsize = maxsize )
658+
658659 # This might be going too far to test a single line, but because of our
659660 # noble aim of achieving 100% test coverage we need to write a case in
660661 # which the following line in Random._randbelow() gets executed:
@@ -672,8 +673,10 @@ def test_randbelow_overridden_random(self, random_mock):
672673 n = 42
673674 epsilon = 0.01
674675 limit = (maxsize - (maxsize % n )) / maxsize
675- random_mock .side_effect = [limit + epsilon , limit - epsilon ]
676- self .gen ._randbelow (n , maxsize = maxsize )
676+ with unittest .mock .patch .object (random .Random , 'random' ) as random_mock :
677+ random_mock .side_effect = [limit + epsilon , limit - epsilon ]
678+ self .gen ._randbelow_without_getrandbits (n , maxsize = maxsize )
679+ self .assertEqual (random_mock .call_count , 2 )
677680
678681 def test_randrange_bug_1590891 (self ):
679682 start = 1000000000000
@@ -926,6 +929,81 @@ def test_betavariate_return_zero(self, gammavariate_mock):
926929 gammavariate_mock .return_value = 0.0
927930 self .assertEqual (0.0 , random .betavariate (2.71828 , 3.14159 ))
928931
932+ class TestRandomSubclassing (unittest .TestCase ):
933+ def test_random_subclass_with_kwargs (self ):
934+ # SF bug #1486663 -- this used to erroneously raise a TypeError
935+ class Subclass (random .Random ):
936+ def __init__ (self , newarg = None ):
937+ random .Random .__init__ (self )
938+ Subclass (newarg = 1 )
939+
940+ def test_overriding_random (self ):
941+ # First, let's assert our base class gets the selection of its
942+ # _randbelow implementation right.
943+ self .assertIs (
944+ random .Random ._randbelow , random .Random ._randbelow_with_getrandbits
945+ )
946+
947+ # Subclasses with a random method that got more recently defined than
948+ # their getrandbits method should not rely on getrandbits in
949+ # _randbelow, but select the getrandbits-independent implementation
950+ # of _randbelow instead.
951+
952+ # Subclass doesn't override any of the methods => keep using
953+ # original getrandbits-dependent version of _randbelow
954+ class SubClass1 (random .Random ):
955+ pass
956+ self .assertIs (
957+ SubClass1 ._randbelow , random .Random ._randbelow_with_getrandbits
958+ )
959+ # subclass providing its own random **and** getrandbits methods
960+ # like random.SystemRandom does => keep relying on getrandbits for
961+ # _randbelow
962+ class SubClass2 (random .Random ):
963+ def random (self ):
964+ pass
965+
966+ def getrandbits (self ):
967+ pass
968+ self .assertIs (
969+ SubClass2 ._randbelow , random .Random ._randbelow_with_getrandbits
970+ )
971+ # subclass providing only random => switch to getrandbits-independent
972+ # version of _randbelow
973+ class SubClass3 (random .Random ):
974+ def random (self ):
975+ pass
976+ self .assertIs (
977+ SubClass3 ._randbelow , random .Random ._randbelow_without_getrandbits
978+ )
979+ # subclass defining getrandbits to complement its inherited random
980+ # => can now rely on getrandbits for _randbelow again
981+ class SubClass4 (SubClass3 ):
982+ def getrandbits (self ):
983+ pass
984+ self .assertIs (
985+ SubClass4 ._randbelow , random .Random ._randbelow_with_getrandbits
986+ )
987+ # subclass overriding the getrandbits-dependent implementation of
988+ # _randbelow => make sure it is used
989+ class SubClass5 (SubClass4 ):
990+ def _randbelow_with_getrandbits (self ):
991+ pass
992+ self .assertIs (
993+ SubClass5 ._randbelow , SubClass5 ._randbelow_with_getrandbits
994+ )
995+ self .assertIsNot (
996+ SubClass5 ._randbelow , random .Random ._randbelow_with_getrandbits
997+ )
998+ # subclass defining random making it more recent than its inherited
999+ # getrandbits => switch back to getrandbits-independent implementaion
1000+ class SubClass6 (SubClass5 ):
1001+ def random (self ):
1002+ pass
1003+ self .assertIs (
1004+ SubClass6 ._randbelow , random .Random ._randbelow_without_getrandbits
1005+ )
1006+
9291007class TestModule (unittest .TestCase ):
9301008 def testMagicConstants (self ):
9311009 self .assertAlmostEqual (random .NV_MAGICCONST , 1.71552776992141 )
@@ -937,13 +1015,6 @@ def test__all__(self):
9371015 # tests validity but not completeness of the __all__ list
9381016 self .assertTrue (set (random .__all__ ) <= set (dir (random )))
9391017
940- def test_random_subclass_with_kwargs (self ):
941- # SF bug #1486663 -- this used to erroneously raise a TypeError
942- class Subclass (random .Random ):
943- def __init__ (self , newarg = None ):
944- random .Random .__init__ (self )
945- Subclass (newarg = 1 )
946-
9471018 @unittest .skipUnless (hasattr (os , "fork" ), "fork() required" )
9481019 def test_after_fork (self ):
9491020 # Test the global Random instance gets reseeded in child
0 commit comments