@@ -640,21 +640,22 @@ def test_randbelow_logic(self, _log=log, int=int):
640
640
self .assertEqual (k , numbits ) # note the stronger assertion
641
641
self .assertTrue (2 ** k > n > 2 ** (k - 1 )) # note the stronger assertion
642
642
643
- @unittest .mock .patch ('random.Random.random' )
644
- def test_randbelow_overridden_random (self , random_mock ):
643
+ def test_randbelow_without_getrandbits (self ):
645
644
# Random._randbelow() can only use random() when the built-in one
646
645
# has been overridden but no new getrandbits() method was supplied.
647
- random_mock .side_effect = random .SystemRandom ().random
648
646
maxsize = 1 << random .BPF
649
647
with warnings .catch_warnings ():
650
648
warnings .simplefilter ("ignore" , UserWarning )
651
649
# 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 )
654
654
# issue 33203: test that _randbelow raises ValueError on
655
655
# n == 0 also in its getrandbits-independent branch.
656
656
with self .assertRaises (ValueError ):
657
- self .gen ._randbelow (0 , maxsize = maxsize )
657
+ self .gen ._randbelow_without_getrandbits (0 , maxsize = maxsize )
658
+
658
659
# This might be going too far to test a single line, but because of our
659
660
# noble aim of achieving 100% test coverage we need to write a case in
660
661
# which the following line in Random._randbelow() gets executed:
@@ -672,8 +673,10 @@ def test_randbelow_overridden_random(self, random_mock):
672
673
n = 42
673
674
epsilon = 0.01
674
675
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 )
677
680
678
681
def test_randrange_bug_1590891 (self ):
679
682
start = 1000000000000
@@ -926,6 +929,81 @@ def test_betavariate_return_zero(self, gammavariate_mock):
926
929
gammavariate_mock .return_value = 0.0
927
930
self .assertEqual (0.0 , random .betavariate (2.71828 , 3.14159 ))
928
931
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
+
929
1007
class TestModule (unittest .TestCase ):
930
1008
def testMagicConstants (self ):
931
1009
self .assertAlmostEqual (random .NV_MAGICCONST , 1.71552776992141 )
@@ -937,13 +1015,6 @@ def test__all__(self):
937
1015
# tests validity but not completeness of the __all__ list
938
1016
self .assertTrue (set (random .__all__ ) <= set (dir (random )))
939
1017
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
-
947
1018
@unittest .skipUnless (hasattr (os , "fork" ), "fork() required" )
948
1019
def test_after_fork (self ):
949
1020
# Test the global Random instance gets reseeded in child
0 commit comments