Update random from v3.14.3

This commit is contained in:
CPython Developers
2026-02-28 22:50:51 +09:00
committed by Jeong, YunWon
parent cc4a7bbbe5
commit c4de2a7239
2 changed files with 348 additions and 199 deletions

149
Lib/random.py vendored
View File

@@ -50,39 +50,18 @@ General notes on the underlying Mersenne Twister core generator:
# Adrian Baddeley. Adapted by Raymond Hettinger for use with
# the Mersenne Twister and os.urandom() core generators.
from warnings import warn as _warn
from math import log as _log, exp as _exp, pi as _pi, e as _e, ceil as _ceil
from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin
from math import tau as TWOPI, floor as _floor, isfinite as _isfinite
from math import lgamma as _lgamma, fabs as _fabs, log2 as _log2
try:
from os import urandom as _urandom
except ImportError:
# XXX RUSTPYTHON
# On wasm, _random.Random.random() does give a proper random value, but
# we don't have the os module
def _urandom(*args, **kwargs):
raise NotImplementedError("urandom")
_os = None
from _collections_abc import Set as _Set, Sequence as _Sequence
from os import urandom as _urandom
from _collections_abc import Sequence as _Sequence
from operator import index as _index
from itertools import accumulate as _accumulate, repeat as _repeat
from bisect import bisect as _bisect
try:
import os as _os
except ImportError:
# XXX RUSTPYTHON
# On wasm, we don't have the os module
_os = None
import os as _os
import _random
try:
# hashlib is pretty heavy to load, try lean internal module first
from _sha2 import sha512 as _sha512
except ImportError:
# fallback to official implementation
from hashlib import sha512 as _sha512
__all__ = [
"Random",
"SystemRandom",
@@ -118,6 +97,7 @@ SG_MAGICCONST = 1.0 + _log(4.5)
BPF = 53 # Number of bits in a float
RECIP_BPF = 2 ** -BPF
_ONE = 1
_sha512 = None
class Random(_random.Random):
@@ -172,13 +152,23 @@ class Random(_random.Random):
a = -2 if x == -1 else x
elif version == 2 and isinstance(a, (str, bytes, bytearray)):
global _sha512
if _sha512 is None:
try:
# hashlib is pretty heavy to load, try lean internal
# module first
from _sha2 import sha512 as _sha512
except ImportError:
# fallback to official implementation
from hashlib import sha512 as _sha512
if isinstance(a, str):
a = a.encode()
a = int.from_bytes(a + _sha512(a).digest())
elif not isinstance(a, (type(None), int, float, str, bytes, bytearray)):
raise TypeError('The only supported seed types are: None,\n'
'int, float, str, bytes, and bytearray.')
raise TypeError('The only supported seed types are:\n'
'None, int, float, str, bytes, and bytearray.')
super().seed(a)
self.gauss_next = None
@@ -255,11 +245,10 @@ class Random(_random.Random):
def _randbelow_with_getrandbits(self, n):
"Return a random int in the range [0,n). Defined for n > 0."
getrandbits = self.getrandbits
k = n.bit_length()
r = getrandbits(k) # 0 <= r < 2**k
r = self.getrandbits(k) # 0 <= r < 2**k
while r >= n:
r = getrandbits(k)
r = self.getrandbits(k)
return r
def _randbelow_without_getrandbits(self, n, maxsize=1<<BPF):
@@ -270,9 +259,10 @@ class Random(_random.Random):
random = self.random
if n >= maxsize:
_warn("Underlying random() generator does not supply \n"
"enough bits to choose from a population range this large.\n"
"To remove the range limitation, add a getrandbits() method.")
from warnings import warn
warn("Underlying random() generator does not supply \n"
"enough bits to choose from a population range this large.\n"
"To remove the range limitation, add a getrandbits() method.")
return _floor(random() * n)
rem = maxsize % n
limit = (maxsize - rem) / maxsize # int(limit * maxsize) % n == 0
@@ -345,8 +335,11 @@ class Random(_random.Random):
def randint(self, a, b):
"""Return random integer in range [a, b], including both end points.
"""
return self.randrange(a, b+1)
a = _index(a)
b = _index(b)
if b < a:
raise ValueError(f"empty range in randint({a}, {b})")
return a + self._randbelow(b - a + 1)
## -------------------- sequence methods -------------------
@@ -430,11 +423,11 @@ class Random(_random.Random):
cum_counts = list(_accumulate(counts))
if len(cum_counts) != n:
raise ValueError('The number of counts does not match the population')
total = cum_counts.pop()
total = cum_counts.pop() if cum_counts else 0
if not isinstance(total, int):
raise TypeError('Counts must be integers')
if total <= 0:
raise ValueError('Total of counts must be greater than zero')
if total < 0:
raise ValueError('Counts must be non-negative')
selections = self.sample(range(total), k=k)
bisect = _bisect
return [population[bisect(cum_counts, s)] for s in selections]
@@ -801,12 +794,18 @@ class Random(_random.Random):
sum(random() < p for i in range(n))
Returns an integer in the range: 0 <= X <= n
Returns an integer in the range:
0 <= X <= n
The integer is chosen with the probability:
P(X == k) = math.comb(n, k) * p ** k * (1 - p) ** (n - k)
The mean (expected value) and variance of the random variable are:
E[X] = n * p
Var[x] = n * p * (1 - p)
Var[X] = n * p * (1 - p)
"""
# Error check inputs and handle edge cases
@@ -1005,5 +1004,75 @@ if hasattr(_os, "fork"):
_os.register_at_fork(after_in_child=_inst.seed)
# ------------------------------------------------------
# -------------- command-line interface ----------------
def _parse_args(arg_list: list[str] | None):
import argparse
parser = argparse.ArgumentParser(
formatter_class=argparse.RawTextHelpFormatter, color=True)
group = parser.add_mutually_exclusive_group()
group.add_argument(
"-c", "--choice", nargs="+",
help="print a random choice")
group.add_argument(
"-i", "--integer", type=int, metavar="N",
help="print a random integer between 1 and N inclusive")
group.add_argument(
"-f", "--float", type=float, metavar="N",
help="print a random floating-point number between 0 and N inclusive")
group.add_argument(
"--test", type=int, const=10_000, nargs="?",
help=argparse.SUPPRESS)
parser.add_argument("input", nargs="*",
help="""\
if no options given, output depends on the input
string or multiple: same as --choice
integer: same as --integer
float: same as --float""")
args = parser.parse_args(arg_list)
return args, parser.format_help()
def main(arg_list: list[str] | None = None) -> int | str:
args, help_text = _parse_args(arg_list)
# Explicit arguments
if args.choice:
return choice(args.choice)
if args.integer is not None:
return randint(1, args.integer)
if args.float is not None:
return uniform(0, args.float)
if args.test:
_test(args.test)
return ""
# No explicit argument, select based on input
if len(args.input) == 1:
val = args.input[0]
try:
# Is it an integer?
val = int(val)
return randint(1, val)
except ValueError:
try:
# Is it a float?
val = float(val)
return uniform(0, val)
except ValueError:
# Split in case of space-separated string: "a b c"
return choice(val.split())
if len(args.input) >= 2:
return choice(args.input)
return help_text
if __name__ == '__main__':
_test()
print(main())

View File

@@ -4,6 +4,7 @@ import random
import os
import time
import pickle
import shlex
import warnings
import test.support
@@ -13,6 +14,15 @@ from test import support
from fractions import Fraction
from collections import abc, Counter
class MyIndex:
def __init__(self, value):
self.value = value
def __index__(self):
return self.value
class TestBasicOps:
# Superclass with tests common to all generators.
# Subclasses must arrange for self.gen to retrieve the Random instance
@@ -141,6 +151,7 @@ class TestBasicOps:
# Exception raised if size of sample exceeds that of population
self.assertRaises(ValueError, self.gen.sample, population, N+1)
self.assertRaises(ValueError, self.gen.sample, [], -1)
self.assertRaises(TypeError, self.gen.sample, population, 1.0)
def test_sample_distribution(self):
# For the entire allowable range of 0 <= k <= N, validate that
@@ -224,8 +235,6 @@ class TestBasicOps:
sample(['red', 'green', 'blue'], counts=10, k=10) # counts not iterable
with self.assertRaises(ValueError):
sample(['red', 'green', 'blue'], counts=[-3, -7, -8], k=2) # counts are negative
with self.assertRaises(ValueError):
sample(['red', 'green', 'blue'], counts=[0, 0, 0], k=2) # counts are zero
with self.assertRaises(ValueError):
sample(['red', 'green'], counts=[10, 10], k=21) # population too small
with self.assertRaises(ValueError):
@@ -233,6 +242,20 @@ class TestBasicOps:
with self.assertRaises(ValueError):
sample(['red', 'green', 'blue'], counts=[1, 2, 3, 4], k=2) # too many counts
# Cases with zero counts match equivalents without counts (see gh-130285)
self.assertEqual(
sample('abc', k=0, counts=[0, 0, 0]),
sample([], k=0),
)
self.assertEqual(
sample([], 0, counts=[]),
sample([], 0),
)
with self.assertRaises(ValueError):
sample([], 1, counts=[])
with self.assertRaises(ValueError):
sample('x', 1, counts=[0])
def test_choices(self):
choices = self.gen.choices
data = ['red', 'green', 'blue', 'yellow']
@@ -246,6 +269,7 @@ class TestBasicOps:
choices(data, range(4), k=5),
choices(k=5, population=data, weights=range(4)),
choices(k=5, population=data, cum_weights=range(4)),
choices(data, k=MyIndex(5)),
]:
self.assertEqual(len(sample), 5)
self.assertEqual(type(sample), list)
@@ -356,118 +380,40 @@ class TestBasicOps:
self.assertEqual(x1, x2)
self.assertEqual(y1, y2)
@support.requires_IEEE_754
def test_53_bits_per_float(self):
span = 2 ** 53
cum = 0
for i in range(100):
cum |= int(self.gen.random() * span)
self.assertEqual(cum, span-1)
def test_getrandbits(self):
getrandbits = self.gen.getrandbits
# Verify ranges
for k in range(1, 1000):
self.assertTrue(0 <= self.gen.getrandbits(k) < 2**k)
self.assertEqual(self.gen.getrandbits(0), 0)
self.assertTrue(0 <= getrandbits(k) < 2**k)
self.assertEqual(getrandbits(0), 0)
# Verify all bits active
getbits = self.gen.getrandbits
for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]:
all_bits = 2**span-1
cum = 0
cpl_cum = 0
for i in range(100):
v = getbits(span)
v = getrandbits(span)
cum |= v
cpl_cum |= all_bits ^ v
self.assertEqual(cum, all_bits)
self.assertEqual(cpl_cum, all_bits)
# Verify argument checking
self.assertRaises(TypeError, self.gen.getrandbits)
self.assertRaises(TypeError, self.gen.getrandbits, 1, 2)
self.assertRaises(ValueError, self.gen.getrandbits, -1)
self.assertRaises(TypeError, self.gen.getrandbits, 10.1)
def test_pickling(self):
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
state = pickle.dumps(self.gen, proto)
origseq = [self.gen.random() for i in range(10)]
newgen = pickle.loads(state)
restoredseq = [newgen.random() for i in range(10)]
self.assertEqual(origseq, restoredseq)
def test_bug_1727780(self):
# verify that version-2-pickles can be loaded
# fine, whether they are created on 32-bit or 64-bit
# platforms, and that version-3-pickles load fine.
files = [("randv2_32.pck", 780),
("randv2_64.pck", 866),
("randv3.pck", 343)]
for file, value in files:
with open(support.findfile(file),"rb") as f:
r = pickle.load(f)
self.assertEqual(int(r.random()*1000), value)
def test_bug_9025(self):
# Had problem with an uneven distribution in int(n*random())
# Verify the fix by checking that distributions fall within expectations.
n = 100000
randrange = self.gen.randrange
k = sum(randrange(6755399441055744) % 3 == 2 for i in range(n))
self.assertTrue(0.30 < k/n < .37, (k/n))
def test_randbytes(self):
# Verify ranges
for n in range(1, 10):
data = self.gen.randbytes(n)
self.assertEqual(type(data), bytes)
self.assertEqual(len(data), n)
self.assertEqual(self.gen.randbytes(0), b'')
# Verify argument checking
self.assertRaises(TypeError, self.gen.randbytes)
self.assertRaises(TypeError, self.gen.randbytes, 1, 2)
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()
except NotImplementedError:
SystemRandom_available = False
else:
SystemRandom_available = True
@unittest.skipUnless(SystemRandom_available, "random.SystemRandom not available")
class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase):
gen = random.SystemRandom()
def test_autoseed(self):
# Doesn't need to do anything except not fail
self.gen.seed()
def test_saverestore(self):
self.assertRaises(NotImplementedError, self.gen.getstate)
self.assertRaises(NotImplementedError, self.gen.setstate, None)
def test_seedargs(self):
# Doesn't need to do anything except not fail
self.gen.seed(100)
def test_gauss(self):
self.gen.gauss_next = None
self.gen.seed(100)
self.assertEqual(self.gen.gauss_next, None)
def test_pickling(self):
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
self.assertRaises(NotImplementedError, pickle.dumps, self.gen, proto)
def test_53_bits_per_float(self):
# This should pass whenever a C double has 53 bit precision.
span = 2 ** 53
cum = 0
for i in range(100):
cum |= int(self.gen.random() * span)
self.assertEqual(cum, span-1)
self.assertRaises(TypeError, getrandbits)
self.assertRaises(TypeError, getrandbits, 1, 2)
self.assertRaises(ValueError, getrandbits, -1)
self.assertRaises(OverflowError, getrandbits, 1<<1000)
self.assertRaises(ValueError, getrandbits, -1<<1000)
self.assertRaises(TypeError, getrandbits, 10.1)
def test_bigrand(self):
# The randrange routine should build-up the required number of bits
@@ -546,6 +492,10 @@ class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase):
randrange(1000, step=100)
with self.assertRaises(TypeError):
randrange(1000, None, step=100)
with self.assertRaises(TypeError):
randrange(1000, step=MyIndex(1))
with self.assertRaises(TypeError):
randrange(1000, None, step=MyIndex(1))
def test_randbelow_logic(self, _log=log, int=int):
# check bitcount transition points: 2**i and 2**(i+1)-1
@@ -568,6 +518,116 @@ class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase):
self.assertEqual(k, numbits) # note the stronger assertion
self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion
def test_randrange_index(self):
randrange = self.gen.randrange
self.assertIn(randrange(MyIndex(5)), range(5))
self.assertIn(randrange(MyIndex(2), MyIndex(7)), range(2, 7))
self.assertIn(randrange(MyIndex(5), MyIndex(15), MyIndex(2)), range(5, 15, 2))
def test_randint(self):
randint = self.gen.randint
self.assertIn(randint(2, 5), (2, 3, 4, 5))
self.assertEqual(randint(2, 2), 2)
self.assertIn(randint(MyIndex(2), MyIndex(5)), (2, 3, 4, 5))
self.assertEqual(randint(MyIndex(2), MyIndex(2)), 2)
self.assertRaises(ValueError, randint, 5, 2)
self.assertRaises(TypeError, randint)
self.assertRaises(TypeError, randint, 2)
self.assertRaises(TypeError, randint, 2, 5, 1)
self.assertRaises(TypeError, randint, 2.0, 5)
self.assertRaises(TypeError, randint, 2, 5.0)
def test_pickling(self):
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
state = pickle.dumps(self.gen, proto)
origseq = [self.gen.random() for i in range(10)]
newgen = pickle.loads(state)
restoredseq = [newgen.random() for i in range(10)]
self.assertEqual(origseq, restoredseq)
def test_bug_1727780(self):
# verify that version-2-pickles can be loaded
# fine, whether they are created on 32-bit or 64-bit
# platforms, and that version-3-pickles load fine.
files = [("randv2_32.pck", 780),
("randv2_64.pck", 866),
("randv3.pck", 343)]
for file, value in files:
with open(support.findfile(file),"rb") as f:
r = pickle.load(f)
self.assertEqual(int(r.random()*1000), value)
def test_bug_9025(self):
# Had problem with an uneven distribution in int(n*random())
# Verify the fix by checking that distributions fall within expectations.
n = 100000
randrange = self.gen.randrange
k = sum(randrange(6755399441055744) % 3 == 2 for i in range(n))
self.assertTrue(0.30 < k/n < .37, (k/n))
def test_randrange_bug_1590891(self):
start = 1000000000000
stop = -100000000000000000000
step = -200
x = self.gen.randrange(start, stop, step)
self.assertTrue(stop < x <= start)
self.assertEqual((x+stop)%step, 0)
def test_randbytes(self):
# Verify ranges
for n in range(1, 10):
data = self.gen.randbytes(n)
self.assertEqual(type(data), bytes)
self.assertEqual(len(data), n)
self.assertEqual(self.gen.randbytes(0), b'')
# Verify argument checking
self.assertRaises(TypeError, self.gen.randbytes)
self.assertRaises(TypeError, self.gen.randbytes, 1, 2)
self.assertRaises(ValueError, self.gen.randbytes, -1)
self.assertRaises(OverflowError, self.gen.randbytes, 1<<1000)
self.assertRaises((ValueError, OverflowError), self.gen.randbytes, -1<<1000)
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()
except NotImplementedError:
SystemRandom_available = False
else:
SystemRandom_available = True
@unittest.skipUnless(SystemRandom_available, "random.SystemRandom not available")
class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase):
gen = random.SystemRandom()
def test_autoseed(self):
# Doesn't need to do anything except not fail
self.gen.seed()
def test_saverestore(self):
self.assertRaises(NotImplementedError, self.gen.getstate)
self.assertRaises(NotImplementedError, self.gen.setstate, None)
def test_seedargs(self):
# Doesn't need to do anything except not fail
self.gen.seed(100)
def test_gauss(self):
self.gen.gauss_next = None
self.gen.seed(100)
self.assertEqual(self.gen.gauss_next, None)
def test_pickling(self):
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
self.assertRaises(NotImplementedError, pickle.dumps, self.gen, proto)
class TestRawMersenneTwister(unittest.TestCase):
@test.support.cpython_only
@@ -753,38 +813,6 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
seed = (1 << (10000 * 8)) - 1 # about 10K bytes
self.gen.seed(seed)
def test_53_bits_per_float(self):
# This should pass whenever a C double has 53 bit precision.
span = 2 ** 53
cum = 0
for i in range(100):
cum |= int(self.gen.random() * span)
self.assertEqual(cum, span-1)
def test_bigrand(self):
# The randrange routine should build-up the required number of bits
# in stages so that all bit positions are active.
span = 2 ** 500
cum = 0
for i in range(100):
r = self.gen.randrange(span)
self.assertTrue(0 <= r < span)
cum |= r
self.assertEqual(cum, span-1)
def test_bigrand_ranges(self):
for i in [40,80, 160, 200, 211, 250, 375, 512, 550]:
start = self.gen.randrange(2 ** (i-2))
stop = self.gen.randrange(2 ** i)
if stop <= start:
continue
self.assertTrue(start <= self.gen.randrange(start, stop) < stop)
def test_rangelimits(self):
for start, stop in [(-2,0), (-(2**60)-2,-(2**60)), (2**60,2**60+2)]:
self.assertEqual(set(range(start,stop)),
set([self.gen.randrange(start,stop) for i in range(100)]))
def test_getrandbits(self):
super().test_getrandbits()
@@ -792,6 +820,25 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
self.gen.seed(1234567)
self.assertEqual(self.gen.getrandbits(100),
97904845777343510404718956115)
self.gen.seed(1234567)
self.assertEqual(self.gen.getrandbits(MyIndex(100)),
97904845777343510404718956115)
def test_getrandbits_2G_bits(self):
size = 2**31
self.gen.seed(1234567)
x = self.gen.getrandbits(size)
self.assertEqual(x.bit_length(), size)
self.assertEqual(x & (2**100-1), 890186470919986886340158459475)
self.assertEqual(x >> (size-100), 1226514312032729439655761284440)
@support.bigmemtest(size=2**32, memuse=1/8+2/15, dry_run=False)
def test_getrandbits_4G_bits(self, size):
self.gen.seed(1234568)
x = self.gen.getrandbits(size)
self.assertEqual(x.bit_length(), size)
self.assertEqual(x & (2**100-1), 287241425661104632871036099814)
self.assertEqual(x >> (size-100), 739728759900339699429794460738)
def test_randrange_uses_getrandbits(self):
# Verify use of getrandbits by randrange
@@ -803,27 +850,6 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
self.assertEqual(self.gen.randrange(2**99),
97904845777343510404718956115)
def test_randbelow_logic(self, _log=log, int=int):
# check bitcount transition points: 2**i and 2**(i+1)-1
# show that: k = int(1.001 + _log(n, 2))
# is equal to or one greater than the number of bits in n
for i in range(1, 1000):
n = 1 << i # check an exact power of two
numbits = i+1
k = int(1.00001 + _log(n, 2))
self.assertEqual(k, numbits)
self.assertEqual(n, 2**(k-1))
n += n - 1 # check 1 below the next power of two
k = int(1.00001 + _log(n, 2))
self.assertIn(k, [numbits, numbits+1])
self.assertTrue(2**k > n > 2**(k-2))
n -= n >> 15 # check a little farther below the next power of two
k = int(1.00001 + _log(n, 2))
self.assertEqual(k, numbits) # note the stronger assertion
self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion
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.
@@ -858,14 +884,6 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
self.gen._randbelow_without_getrandbits(n, maxsize=maxsize)
self.assertEqual(random_mock.call_count, 2)
def test_randrange_bug_1590891(self):
start = 1000000000000
stop = -100000000000000000000
step = -200
x = self.gen.randrange(start, stop, step)
self.assertTrue(stop < x <= start)
self.assertEqual((x+stop)%step, 0)
def test_choices_algorithms(self):
# The various ways of specifying weights should produce the same results
choices = self.gen.choices
@@ -949,6 +967,14 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
self.assertEqual(self.gen.randbytes(n),
gen2.getrandbits(n * 8).to_bytes(n, 'little'))
@support.bigmemtest(size=2**29, memuse=1+16/15, dry_run=False)
def test_randbytes_256M(self, size):
self.gen.seed(2849427419)
x = self.gen.randbytes(size)
self.assertEqual(len(x), size)
self.assertEqual(x[:12].hex(), 'f6fd9ae63855ab91ea238b4f')
self.assertEqual(x[-12:].hex(), '0e7af69a84ee99bf4a11becc')
def test_sample_counts_equivalence(self):
# Test the documented strong equivalence to a sample with repeated elements.
# We run this test on random.Random() which makes deterministic selections
@@ -1081,6 +1107,7 @@ class TestDistributions(unittest.TestCase):
B(n=1, p=-0.5) # Negative p
with self.assertRaises(ValueError):
B(n=1, p=1.5) # p > 1.0
self.assertEqual(B(0, 0.5), 0) # n == 0
self.assertEqual(B(10, 0.0), 0) # p == 0.0
self.assertEqual(B(10, 1.0), 10) # p == 1.0
self.assertTrue(B(1, 0.3) in {0, 1}) # n == 1 fast path
@@ -1088,6 +1115,9 @@ class TestDistributions(unittest.TestCase):
self.assertTrue(B(1, 0.0) in {0}) # n == 1 fast path
self.assertTrue(B(1, 1.0) in {1}) # n == 1 fast path
# BG method very small p
self.assertEqual(B(5, 1e-18), 0)
# BG method p <= 0.5 and n*p=1.25
self.assertTrue(B(5, 0.25) in set(range(6)))
@@ -1266,6 +1296,13 @@ class TestDistributions(unittest.TestCase):
class TestRandomSubclassing(unittest.TestCase):
def test_random_subclass_with_kwargs(self):
# SF bug #1486663 -- this used to erroneously raise a TypeError
class Subclass(random.Random):
def __init__(self, newarg=None):
random.Random.__init__(self)
Subclass(newarg=1)
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,
@@ -1386,5 +1423,48 @@ class TestModule(unittest.TestCase):
support.wait_process(pid, exitcode=0)
class CommandLineTest(unittest.TestCase):
@support.force_not_colorized
def test_parse_args(self):
args, help_text = random._parse_args(shlex.split("--choice a b c"))
self.assertEqual(args.choice, ["a", "b", "c"])
self.assertStartsWith(help_text, "usage: ")
args, help_text = random._parse_args(shlex.split("--integer 5"))
self.assertEqual(args.integer, 5)
self.assertStartsWith(help_text, "usage: ")
args, help_text = random._parse_args(shlex.split("--float 2.5"))
self.assertEqual(args.float, 2.5)
self.assertStartsWith(help_text, "usage: ")
args, help_text = random._parse_args(shlex.split("a b c"))
self.assertEqual(args.input, ["a", "b", "c"])
self.assertStartsWith(help_text, "usage: ")
args, help_text = random._parse_args(shlex.split("5"))
self.assertEqual(args.input, ["5"])
self.assertStartsWith(help_text, "usage: ")
args, help_text = random._parse_args(shlex.split("2.5"))
self.assertEqual(args.input, ["2.5"])
self.assertStartsWith(help_text, "usage: ")
def test_main(self):
for command, expected in [
("--choice a b c", "b"),
('"a b c"', "b"),
("a b c", "b"),
("--choice 'a a' 'b b' 'c c'", "b b"),
("'a a' 'b b' 'c c'", "b b"),
("--integer 5", 4),
("5", 4),
("--float 2.5", 2.1110546288126204),
("2.5", 2.1110546288126204),
]:
random.seed(0)
self.assertEqual(random.main(shlex.split(command)), expected)
if __name__ == "__main__":
unittest.main()