2002-12-29 23:03:38 +00:00
|
|
|
import unittest
|
2013-04-02 12:47:23 -04:00
|
|
|
import unittest.mock
|
2002-05-05 20:40:00 +00:00
|
|
|
import random
|
2017-05-27 17:50:54 +02:00
|
|
|
import os
|
2002-12-29 23:03:38 +00:00
|
|
|
import time
|
2003-06-24 20:29:04 +00:00
|
|
|
import pickle
|
2024-05-05 08:30:03 +02:00
|
|
|
import shlex
|
2003-10-05 09:09:15 +00:00
|
|
|
import warnings
|
2020-06-21 18:44:58 +09:00
|
|
|
import test.support
|
|
|
|
|
2013-04-02 12:47:23 -04:00
|
|
|
from functools import partial
|
2016-10-19 10:11:37 +02:00
|
|
|
from math import log, exp, pi, fsum, sin, factorial
|
2008-05-20 21:35:26 +00:00
|
|
|
from test import support
|
2016-09-06 17:15:29 -07:00
|
|
|
from fractions import Fraction
|
2020-12-19 05:33:36 +01:00
|
|
|
from collections import abc, Counter
|
2017-05-11 11:19:35 -04:00
|
|
|
|
2025-06-11 04:51:08 +03:00
|
|
|
|
|
|
|
class MyIndex:
|
|
|
|
def __init__(self, value):
|
|
|
|
self.value = value
|
|
|
|
|
|
|
|
def __index__(self):
|
|
|
|
return self.value
|
|
|
|
|
|
|
|
|
2013-04-19 05:45:27 +03:00
|
|
|
class TestBasicOps:
|
2002-12-29 23:03:38 +00:00
|
|
|
# Superclass with tests common to all generators.
|
|
|
|
# Subclasses must arrange for self.gen to retrieve the Random instance
|
|
|
|
# to be tested.
|
|
|
|
|
|
|
|
def randomlist(self, n):
|
|
|
|
"""Helper function to make a list of random numbers"""
|
2007-05-07 22:24:25 +00:00
|
|
|
return [self.gen.random() for i in range(n)]
|
2002-12-29 23:03:38 +00:00
|
|
|
|
|
|
|
def test_autoseed(self):
|
|
|
|
self.gen.seed()
|
|
|
|
state1 = self.gen.getstate()
|
2003-08-09 18:30:57 +00:00
|
|
|
time.sleep(0.1)
|
2017-12-14 14:04:53 +03:00
|
|
|
self.gen.seed() # different seeds at different times
|
2002-12-29 23:03:38 +00:00
|
|
|
state2 = self.gen.getstate()
|
|
|
|
self.assertNotEqual(state1, state2)
|
|
|
|
|
|
|
|
def test_saverestore(self):
|
|
|
|
N = 1000
|
|
|
|
self.gen.seed()
|
|
|
|
state = self.gen.getstate()
|
|
|
|
randseq = self.randomlist(N)
|
|
|
|
self.gen.setstate(state) # should regenerate the same sequence
|
|
|
|
self.assertEqual(randseq, self.randomlist(N))
|
|
|
|
|
|
|
|
def test_seedargs(self):
|
2012-06-24 11:05:30 +01:00
|
|
|
# Seed value with a negative hash.
|
|
|
|
class MySeed(object):
|
|
|
|
def __hash__(self):
|
|
|
|
return -1729
|
2019-09-12 09:13:20 +01:00
|
|
|
for arg in [None, 0, 1, -1, 10**20, -(10**20),
|
2020-03-10 15:15:14 +01:00
|
|
|
False, True, 3.14, 'a']:
|
2002-12-29 23:03:38 +00:00
|
|
|
self.gen.seed(arg)
|
2019-09-12 09:13:20 +01:00
|
|
|
|
|
|
|
for arg in [1+2j, tuple('abc'), MySeed()]:
|
2021-05-04 01:55:40 -07:00
|
|
|
with self.assertRaises(TypeError):
|
2019-09-12 09:13:20 +01:00
|
|
|
self.gen.seed(arg)
|
|
|
|
|
2007-05-07 22:24:25 +00:00
|
|
|
for arg in [list(range(3)), dict(one=1)]:
|
2021-05-04 01:55:40 -07:00
|
|
|
self.assertRaises(TypeError, self.gen.seed, arg)
|
2010-09-07 00:38:15 +00:00
|
|
|
self.assertRaises(TypeError, self.gen.seed, 1, 2, 3, 4)
|
2004-07-09 14:26:18 +00:00
|
|
|
self.assertRaises(TypeError, type(self.gen), [])
|
2002-12-29 23:03:38 +00:00
|
|
|
|
2021-05-03 16:11:35 -07:00
|
|
|
def test_seed_no_mutate_bug_44018(self):
|
|
|
|
a = bytearray(b'1234')
|
|
|
|
self.gen.seed(a)
|
|
|
|
self.assertEqual(a, bytearray(b'1234'))
|
|
|
|
|
2013-04-02 12:47:23 -04:00
|
|
|
@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
|
2017-05-11 11:19:35 -04:00
|
|
|
# randomness source is not found. To test this on machines where it
|
2013-04-02 12:47:23 -04:00
|
|
|
# exists, run the above test, test_seedargs(), again after mocking
|
|
|
|
# os.urandom() so that it raises the exception expected when the
|
|
|
|
# randomness source is not available.
|
|
|
|
urandom_mock.side_effect = NotImplementedError
|
|
|
|
self.test_seedargs()
|
|
|
|
|
2012-11-04 02:10:33 +01:00
|
|
|
def test_shuffle(self):
|
|
|
|
shuffle = self.gen.shuffle
|
|
|
|
lst = []
|
|
|
|
shuffle(lst)
|
|
|
|
self.assertEqual(lst, [])
|
|
|
|
lst = [37]
|
|
|
|
shuffle(lst)
|
|
|
|
self.assertEqual(lst, [37])
|
|
|
|
seqs = [list(range(n)) for n in range(10)]
|
|
|
|
shuffled_seqs = [list(range(n)) for n in range(10)]
|
|
|
|
for shuffled_seq in shuffled_seqs:
|
|
|
|
shuffle(shuffled_seq)
|
|
|
|
for (seq, shuffled_seq) in zip(seqs, shuffled_seqs):
|
|
|
|
self.assertEqual(len(seq), len(shuffled_seq))
|
|
|
|
self.assertEqual(set(seq), set(shuffled_seq))
|
|
|
|
# The above tests all would pass if the shuffle was a
|
|
|
|
# no-op. The following non-deterministic test covers that. It
|
|
|
|
# asserts that the shuffled sequence of 1000 distinct elements
|
|
|
|
# must be different from the original one. Although there is
|
|
|
|
# mathematically a non-zero probability that this could
|
|
|
|
# actually happen in a genuinely random shuffle, it is
|
|
|
|
# completely negligible, given that the number of possible
|
|
|
|
# permutations of 1000 objects is 1000! (factorial of 1000),
|
|
|
|
# which is considerably larger than the number of atoms in the
|
|
|
|
# universe...
|
|
|
|
lst = list(range(1000))
|
|
|
|
shuffled_lst = list(range(1000))
|
|
|
|
shuffle(shuffled_lst)
|
|
|
|
self.assertTrue(lst != shuffled_lst)
|
|
|
|
shuffle(lst)
|
|
|
|
self.assertTrue(lst != shuffled_lst)
|
2017-05-11 11:19:35 -04:00
|
|
|
self.assertRaises(TypeError, shuffle, (1, 2, 3))
|
|
|
|
|
2010-09-07 10:06:56 +00:00
|
|
|
def test_choice(self):
|
|
|
|
choice = self.gen.choice
|
|
|
|
with self.assertRaises(IndexError):
|
|
|
|
choice([])
|
|
|
|
self.assertEqual(choice([50]), 50)
|
|
|
|
self.assertIn(choice([25, 75]), [25, 75])
|
|
|
|
|
2023-01-08 13:40:35 -06:00
|
|
|
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])
|
|
|
|
|
2002-12-29 23:03:38 +00:00
|
|
|
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
|
|
|
|
N = 100
|
2007-05-07 22:24:25 +00:00
|
|
|
population = range(N)
|
|
|
|
for k in range(N+1):
|
2002-12-29 23:03:38 +00:00
|
|
|
s = self.gen.sample(population, k)
|
|
|
|
self.assertEqual(len(s), k)
|
2003-11-16 16:17:49 +00:00
|
|
|
uniq = set(s)
|
2002-12-29 23:03:38 +00:00
|
|
|
self.assertEqual(len(uniq), k)
|
2009-06-30 23:06:06 +00:00
|
|
|
self.assertTrue(uniq <= set(population))
|
2003-01-04 05:55:11 +00:00
|
|
|
self.assertEqual(self.gen.sample([], 0), []) # test edge case N==k==0
|
2013-04-02 12:47:23 -04:00
|
|
|
# Exception raised if size of sample exceeds that of population
|
|
|
|
self.assertRaises(ValueError, self.gen.sample, population, N+1)
|
2016-11-21 14:34:33 -08:00
|
|
|
self.assertRaises(ValueError, self.gen.sample, [], -1)
|
2025-06-18 18:26:01 +03:00
|
|
|
self.assertRaises(TypeError, self.gen.sample, population, 1.0)
|
2002-12-29 23:03:38 +00:00
|
|
|
|
2003-01-17 17:23:23 +00:00
|
|
|
def test_sample_distribution(self):
|
|
|
|
# For the entire allowable range of 0 <= k <= N, validate that
|
|
|
|
# sample generates all possible permutations
|
|
|
|
n = 5
|
|
|
|
pop = range(n)
|
|
|
|
trials = 10000 # large num prevents false negatives without slowing normal case
|
2007-05-07 22:24:25 +00:00
|
|
|
for k in range(n):
|
2004-09-27 15:29:05 +00:00
|
|
|
expected = factorial(n) // factorial(n-k)
|
2003-01-17 17:23:23 +00:00
|
|
|
perms = {}
|
2007-05-07 22:24:25 +00:00
|
|
|
for i in range(trials):
|
2003-01-17 17:23:23 +00:00
|
|
|
perms[tuple(self.gen.sample(pop, k))] = None
|
|
|
|
if len(perms) == expected:
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
self.fail()
|
|
|
|
|
2003-09-06 04:25:54 +00:00
|
|
|
def test_sample_inputs(self):
|
|
|
|
# SF bug #801342 -- population can be any iterable defining __len__()
|
|
|
|
self.gen.sample(range(20), 2)
|
2007-05-07 22:24:25 +00:00
|
|
|
self.gen.sample(range(20), 2)
|
2003-09-06 04:25:54 +00:00
|
|
|
self.gen.sample(str('abcdefghijklmnopqrst'), 2)
|
|
|
|
self.gen.sample(tuple('abcdefghijklmnopqrst'), 2)
|
|
|
|
|
2006-04-21 10:40:58 +00:00
|
|
|
def test_sample_on_dicts(self):
|
2008-01-14 01:00:53 +00:00
|
|
|
self.assertRaises(TypeError, self.gen.sample, dict.fromkeys('abcdef'), 2)
|
2006-04-21 10:40:58 +00:00
|
|
|
|
2020-04-19 00:36:42 -07:00
|
|
|
def test_sample_on_sets(self):
|
2021-05-04 01:55:40 -07:00
|
|
|
with self.assertRaises(TypeError):
|
2020-04-19 00:36:42 -07:00
|
|
|
population = {10, 20, 30, 40, 50, 60, 70}
|
|
|
|
self.gen.sample(population, k=5)
|
|
|
|
|
2020-12-19 05:33:36 +01:00
|
|
|
def test_sample_on_seqsets(self):
|
|
|
|
class SeqSet(abc.Sequence, abc.Set):
|
|
|
|
def __init__(self, items):
|
|
|
|
self._items = items
|
|
|
|
|
|
|
|
def __len__(self):
|
|
|
|
return len(self._items)
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
return self._items[index]
|
|
|
|
|
|
|
|
population = SeqSet([2, 4, 1, 3])
|
|
|
|
with warnings.catch_warnings():
|
|
|
|
warnings.simplefilter("error", DeprecationWarning)
|
|
|
|
self.gen.sample(population, k=2)
|
|
|
|
|
2020-05-08 07:53:15 -07:00
|
|
|
def test_sample_with_counts(self):
|
|
|
|
sample = self.gen.sample
|
|
|
|
|
|
|
|
# General case
|
|
|
|
colors = ['red', 'green', 'blue', 'orange', 'black', 'brown', 'amber']
|
|
|
|
counts = [500, 200, 20, 10, 5, 0, 1 ]
|
|
|
|
k = 700
|
|
|
|
summary = Counter(sample(colors, counts=counts, k=k))
|
|
|
|
self.assertEqual(sum(summary.values()), k)
|
|
|
|
for color, weight in zip(colors, counts):
|
|
|
|
self.assertLessEqual(summary[color], weight)
|
|
|
|
self.assertNotIn('brown', summary)
|
|
|
|
|
|
|
|
# Case that exhausts the population
|
|
|
|
k = sum(counts)
|
|
|
|
summary = Counter(sample(colors, counts=counts, k=k))
|
|
|
|
self.assertEqual(sum(summary.values()), k)
|
|
|
|
for color, weight in zip(colors, counts):
|
|
|
|
self.assertLessEqual(summary[color], weight)
|
|
|
|
self.assertNotIn('brown', summary)
|
|
|
|
|
|
|
|
# Case with population size of 1
|
|
|
|
summary = Counter(sample(['x'], counts=[10], k=8))
|
|
|
|
self.assertEqual(summary, Counter(x=8))
|
|
|
|
|
|
|
|
# Case with all counts equal.
|
|
|
|
nc = len(colors)
|
|
|
|
summary = Counter(sample(colors, counts=[10]*nc, k=10*nc))
|
|
|
|
self.assertEqual(summary, Counter(10*colors))
|
|
|
|
|
|
|
|
# Test error handling
|
|
|
|
with self.assertRaises(TypeError):
|
|
|
|
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'], counts=[10, 10], k=21) # population too small
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
sample(['red', 'green', 'blue'], counts=[1, 2], k=2) # too few counts
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
sample(['red', 'green', 'blue'], counts=[1, 2, 3, 4], k=2) # too many counts
|
|
|
|
|
2025-02-21 11:33:10 -06:00
|
|
|
# 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])
|
|
|
|
|
2016-09-07 00:08:44 -07:00
|
|
|
def test_choices(self):
|
|
|
|
choices = self.gen.choices
|
2016-09-06 17:15:29 -07:00
|
|
|
data = ['red', 'green', 'blue', 'yellow']
|
|
|
|
str_data = 'abcd'
|
|
|
|
range_data = range(4)
|
|
|
|
set_data = set(range(4))
|
|
|
|
|
|
|
|
# basic functionality
|
|
|
|
for sample in [
|
2016-09-26 21:45:57 -07:00
|
|
|
choices(data, k=5),
|
|
|
|
choices(data, range(4), k=5),
|
2016-09-07 00:08:44 -07:00
|
|
|
choices(k=5, population=data, weights=range(4)),
|
|
|
|
choices(k=5, population=data, cum_weights=range(4)),
|
2025-06-18 18:26:01 +03:00
|
|
|
choices(data, k=MyIndex(5)),
|
2016-09-06 17:15:29 -07:00
|
|
|
]:
|
|
|
|
self.assertEqual(len(sample), 5)
|
|
|
|
self.assertEqual(type(sample), list)
|
|
|
|
self.assertTrue(set(sample) <= set(data))
|
|
|
|
|
|
|
|
# test argument handling
|
2016-09-07 00:08:44 -07:00
|
|
|
with self.assertRaises(TypeError): # missing arguments
|
|
|
|
choices(2)
|
2016-09-06 17:15:29 -07:00
|
|
|
|
2016-09-26 21:45:57 -07:00
|
|
|
self.assertEqual(choices(data, k=0), []) # k == 0
|
|
|
|
self.assertEqual(choices(data, k=-1), []) # negative k behaves like ``[0] * -1``
|
2016-09-06 17:15:29 -07:00
|
|
|
with self.assertRaises(TypeError):
|
2016-09-26 21:45:57 -07:00
|
|
|
choices(data, k=2.5) # k is a float
|
2016-09-06 17:15:29 -07:00
|
|
|
|
2016-09-26 21:45:57 -07:00
|
|
|
self.assertTrue(set(choices(str_data, k=5)) <= set(str_data)) # population is a string sequence
|
|
|
|
self.assertTrue(set(choices(range_data, k=5)) <= set(range_data)) # population is a range
|
2016-09-06 17:15:29 -07:00
|
|
|
with self.assertRaises(TypeError):
|
2016-09-26 21:45:57 -07:00
|
|
|
choices(set_data, k=2) # population is not a sequence
|
2016-09-06 17:15:29 -07:00
|
|
|
|
2016-09-26 21:45:57 -07:00
|
|
|
self.assertTrue(set(choices(data, None, k=5)) <= set(data)) # weights is None
|
|
|
|
self.assertTrue(set(choices(data, weights=None, k=5)) <= set(data))
|
2016-09-06 17:15:29 -07:00
|
|
|
with self.assertRaises(ValueError):
|
2016-09-26 21:45:57 -07:00
|
|
|
choices(data, [1,2], k=5) # len(weights) != len(population)
|
2016-09-06 17:15:29 -07:00
|
|
|
with self.assertRaises(TypeError):
|
2016-09-26 21:45:57 -07:00
|
|
|
choices(data, 10, k=5) # non-iterable weights
|
2016-09-06 17:15:29 -07:00
|
|
|
with self.assertRaises(TypeError):
|
2016-09-26 21:45:57 -07:00
|
|
|
choices(data, [None]*4, k=5) # non-numeric weights
|
2016-09-06 17:15:29 -07:00
|
|
|
for weights in [
|
|
|
|
[15, 10, 25, 30], # integer weights
|
|
|
|
[15.1, 10.2, 25.2, 30.3], # float weights
|
|
|
|
[Fraction(1, 3), Fraction(2, 6), Fraction(3, 6), Fraction(4, 6)], # fractional weights
|
|
|
|
[True, False, True, False] # booleans (include / exclude)
|
|
|
|
]:
|
2016-09-26 21:45:57 -07:00
|
|
|
self.assertTrue(set(choices(data, weights, k=5)) <= set(data))
|
2016-09-06 17:15:29 -07:00
|
|
|
|
|
|
|
with self.assertRaises(ValueError):
|
2016-09-26 21:45:57 -07:00
|
|
|
choices(data, cum_weights=[1,2], k=5) # len(weights) != len(population)
|
2016-09-06 17:15:29 -07:00
|
|
|
with self.assertRaises(TypeError):
|
2016-09-26 21:45:57 -07:00
|
|
|
choices(data, cum_weights=10, k=5) # non-iterable cum_weights
|
2016-09-06 17:15:29 -07:00
|
|
|
with self.assertRaises(TypeError):
|
2016-09-26 21:45:57 -07:00
|
|
|
choices(data, cum_weights=[None]*4, k=5) # non-numeric cum_weights
|
2016-09-06 17:15:29 -07:00
|
|
|
with self.assertRaises(TypeError):
|
2016-09-26 21:45:57 -07:00
|
|
|
choices(data, range(4), cum_weights=range(4), k=5) # both weights and cum_weights
|
2016-09-06 17:15:29 -07:00
|
|
|
for weights in [
|
|
|
|
[15, 10, 25, 30], # integer cum_weights
|
|
|
|
[15.1, 10.2, 25.2, 30.3], # float cum_weights
|
|
|
|
[Fraction(1, 3), Fraction(2, 6), Fraction(3, 6), Fraction(4, 6)], # fractional cum_weights
|
|
|
|
]:
|
2016-09-26 21:45:57 -07:00
|
|
|
self.assertTrue(set(choices(data, cum_weights=weights, k=5)) <= set(data))
|
2016-09-06 17:15:29 -07:00
|
|
|
|
2016-10-14 01:19:38 -04:00
|
|
|
# Test weight focused on a single element of the population
|
|
|
|
self.assertEqual(choices('abcd', [1, 0, 0, 0]), ['a'])
|
|
|
|
self.assertEqual(choices('abcd', [0, 1, 0, 0]), ['b'])
|
|
|
|
self.assertEqual(choices('abcd', [0, 0, 1, 0]), ['c'])
|
|
|
|
self.assertEqual(choices('abcd', [0, 0, 0, 1]), ['d'])
|
|
|
|
|
|
|
|
# Test consistency with random.choice() for empty population
|
|
|
|
with self.assertRaises(IndexError):
|
|
|
|
choices([], k=1)
|
|
|
|
with self.assertRaises(IndexError):
|
|
|
|
choices([], weights=[], k=1)
|
|
|
|
with self.assertRaises(IndexError):
|
|
|
|
choices([], cum_weights=[], k=5)
|
|
|
|
|
2018-06-27 01:08:31 -07:00
|
|
|
def test_choices_subnormal(self):
|
2019-07-22 06:12:33 +10:00
|
|
|
# Subnormal weights would occasionally trigger an IndexError
|
2018-06-27 01:08:31 -07:00
|
|
|
# in choices() when the value returned by random() was large
|
|
|
|
# enough to make `random() * total` round up to the total.
|
|
|
|
# See https://bugs.python.org/msg275594 for more detail.
|
|
|
|
choices = self.gen.choices
|
|
|
|
choices(population=[1, 2], weights=[1e-323, 1e-323], k=5000)
|
|
|
|
|
2019-11-23 02:22:13 -08:00
|
|
|
def test_choices_with_all_zero_weights(self):
|
|
|
|
# See issue #38881
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
self.gen.choices('AB', [0.0, 0.0])
|
|
|
|
|
2020-09-29 04:32:10 +03:00
|
|
|
def test_choices_negative_total(self):
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
self.gen.choices('ABC', [3, -5, 1])
|
|
|
|
|
|
|
|
def test_choices_infinite_total(self):
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
self.gen.choices('A', [float('inf')])
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
self.gen.choices('AB', [0.0, float('inf')])
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
self.gen.choices('AB', [-float('inf'), 123])
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
self.gen.choices('AB', [0.0, float('nan')])
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
self.gen.choices('AB', [float('-inf'), float('inf')])
|
|
|
|
|
2002-12-29 23:03:38 +00:00
|
|
|
def test_gauss(self):
|
|
|
|
# Ensure that the seed() method initializes all the hidden state. In
|
|
|
|
# particular, through 2.2.1 it failed to reset a piece of state used
|
|
|
|
# by (and only by) the .gauss() method.
|
|
|
|
|
|
|
|
for seed in 1, 12, 123, 1234, 12345, 123456, 654321:
|
|
|
|
self.gen.seed(seed)
|
|
|
|
x1 = self.gen.random()
|
|
|
|
y1 = self.gen.gauss(0, 1)
|
|
|
|
|
|
|
|
self.gen.seed(seed)
|
|
|
|
x2 = self.gen.random()
|
|
|
|
y2 = self.gen.gauss(0, 1)
|
|
|
|
|
|
|
|
self.assertEqual(x1, x2)
|
|
|
|
self.assertEqual(y1, y2)
|
|
|
|
|
2025-06-18 18:26:01 +03:00
|
|
|
@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)
|
|
|
|
|
2020-04-17 19:32:14 +02:00
|
|
|
def test_getrandbits(self):
|
2025-06-18 18:26:01 +03:00
|
|
|
getrandbits = self.gen.getrandbits
|
2020-04-17 19:32:14 +02:00
|
|
|
# Verify ranges
|
|
|
|
for k in range(1, 1000):
|
2025-06-18 18:26:01 +03:00
|
|
|
self.assertTrue(0 <= getrandbits(k) < 2**k)
|
|
|
|
self.assertEqual(getrandbits(0), 0)
|
2020-04-17 19:32:14 +02:00
|
|
|
|
|
|
|
# Verify all bits active
|
|
|
|
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):
|
2025-06-18 18:26:01 +03:00
|
|
|
v = getrandbits(span)
|
2020-04-17 19:32:14 +02:00
|
|
|
cum |= v
|
|
|
|
cpl_cum |= all_bits ^ v
|
|
|
|
self.assertEqual(cum, all_bits)
|
|
|
|
self.assertEqual(cpl_cum, all_bits)
|
|
|
|
|
|
|
|
# Verify argument checking
|
2025-06-18 18:26:01 +03:00
|
|
|
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)
|
2004-08-30 06:14:31 +00:00
|
|
|
|
|
|
|
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
|
2007-05-07 22:24:25 +00:00
|
|
|
for i in range(100):
|
2004-08-30 06:14:31 +00:00
|
|
|
r = self.gen.randrange(span)
|
2009-06-30 23:06:06 +00:00
|
|
|
self.assertTrue(0 <= r < span)
|
2004-08-30 06:14:31 +00:00
|
|
|
cum |= r
|
|
|
|
self.assertEqual(cum, span-1)
|
|
|
|
|
|
|
|
def test_bigrand_ranges(self):
|
|
|
|
for i in [40,80, 160, 200, 211, 250, 375, 512, 550]:
|
2013-11-26 14:50:10 -06:00
|
|
|
start = self.gen.randrange(2 ** (i-2))
|
|
|
|
stop = self.gen.randrange(2 ** i)
|
2004-08-30 06:14:31 +00:00
|
|
|
if stop <= start:
|
2013-11-26 14:50:10 -06:00
|
|
|
continue
|
2009-06-30 23:06:06 +00:00
|
|
|
self.assertTrue(start <= self.gen.randrange(start, stop) < stop)
|
2004-08-30 06:14:31 +00:00
|
|
|
|
|
|
|
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)),
|
2007-05-07 22:24:25 +00:00
|
|
|
set([self.gen.randrange(start,stop) for i in range(100)]))
|
2004-08-30 06:14:31 +00:00
|
|
|
|
2013-04-02 12:47:23 -04:00
|
|
|
def test_randrange_nonunit_step(self):
|
|
|
|
rint = self.gen.randrange(0, 10, 2)
|
|
|
|
self.assertIn(rint, (0, 2, 4, 6, 8))
|
|
|
|
rint = self.gen.randrange(0, 2, 2)
|
|
|
|
self.assertEqual(rint, 0)
|
|
|
|
|
|
|
|
def test_randrange_errors(self):
|
2022-05-11 23:54:51 -05:00
|
|
|
raises_value_error = partial(self.assertRaises, ValueError, self.gen.randrange)
|
|
|
|
raises_type_error = partial(self.assertRaises, TypeError, self.gen.randrange)
|
|
|
|
|
2013-04-02 12:47:23 -04:00
|
|
|
# Empty range
|
2022-05-11 23:54:51 -05:00
|
|
|
raises_value_error(3, 3)
|
|
|
|
raises_value_error(-721)
|
|
|
|
raises_value_error(0, 100, -12)
|
|
|
|
|
|
|
|
# Zero step
|
|
|
|
raises_value_error(0, 42, 0)
|
|
|
|
raises_type_error(0, 42, 0.0)
|
|
|
|
raises_type_error(0, 0, 0.0)
|
|
|
|
|
|
|
|
# Non-integer stop
|
|
|
|
raises_type_error(3.14159)
|
|
|
|
raises_type_error(3.0)
|
|
|
|
raises_type_error(Fraction(3, 1))
|
|
|
|
raises_type_error('3')
|
|
|
|
raises_type_error(0, 2.71827)
|
|
|
|
raises_type_error(0, 2.0)
|
|
|
|
raises_type_error(0, Fraction(2, 1))
|
|
|
|
raises_type_error(0, '2')
|
|
|
|
raises_type_error(0, 2.71827, 2)
|
|
|
|
|
|
|
|
# Non-integer start
|
|
|
|
raises_type_error(2.71827, 5)
|
|
|
|
raises_type_error(2.0, 5)
|
|
|
|
raises_type_error(Fraction(2, 1), 5)
|
|
|
|
raises_type_error('2', 5)
|
|
|
|
raises_type_error(2.71827, 5, 2)
|
|
|
|
|
|
|
|
# Non-integer step
|
|
|
|
raises_type_error(0, 42, 3.14159)
|
|
|
|
raises_type_error(0, 42, 3.0)
|
|
|
|
raises_type_error(0, 42, Fraction(3, 1))
|
|
|
|
raises_type_error(0, 42, '3')
|
|
|
|
raises_type_error(0, 42, 1.0)
|
|
|
|
raises_type_error(0, 0, 1.0)
|
2013-04-02 12:47:23 -04:00
|
|
|
|
2021-01-02 10:24:51 -08:00
|
|
|
def test_randrange_step(self):
|
|
|
|
# bpo-42772: When stop is None, the step argument was being ignored.
|
|
|
|
randrange = self.gen.randrange
|
|
|
|
with self.assertRaises(TypeError):
|
|
|
|
randrange(1000, step=100)
|
|
|
|
with self.assertRaises(TypeError):
|
|
|
|
randrange(1000, None, step=100)
|
2025-06-18 18:26:01 +03:00
|
|
|
with self.assertRaises(TypeError):
|
|
|
|
randrange(1000, step=MyIndex(1))
|
|
|
|
with self.assertRaises(TypeError):
|
|
|
|
randrange(1000, None, step=MyIndex(1))
|
2021-01-02 10:24:51 -08:00
|
|
|
|
2004-08-30 06:14:31 +00:00
|
|
|
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
|
2007-05-07 22:24:25 +00:00
|
|
|
for i in range(1, 1000):
|
2007-01-15 16:59:06 +00:00
|
|
|
n = 1 << i # check an exact power of two
|
2004-08-30 06:14:31 +00:00
|
|
|
numbits = i+1
|
|
|
|
k = int(1.00001 + _log(n, 2))
|
|
|
|
self.assertEqual(k, numbits)
|
2007-07-11 12:20:59 +00:00
|
|
|
self.assertEqual(n, 2**(k-1))
|
2004-08-30 06:14:31 +00:00
|
|
|
|
|
|
|
n += n - 1 # check 1 below the next power of two
|
|
|
|
k = int(1.00001 + _log(n, 2))
|
2010-01-19 00:09:57 +00:00
|
|
|
self.assertIn(k, [numbits, numbits+1])
|
2009-06-30 23:06:06 +00:00
|
|
|
self.assertTrue(2**k > n > 2**(k-2))
|
2004-08-30 06:14:31 +00:00
|
|
|
|
|
|
|
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
|
2009-06-30 23:06:06 +00:00
|
|
|
self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion
|
2004-08-30 06:14:31 +00:00
|
|
|
|
2025-06-18 18:26:01 +03:00
|
|
|
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)
|
|
|
|
|
2004-08-30 06:14:31 +00:00
|
|
|
|
2021-05-31 23:24:20 +03:00
|
|
|
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())
|
|
|
|
|
|
|
|
|
2013-04-19 05:45:27 +03:00
|
|
|
class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
|
2002-12-29 23:03:38 +00:00
|
|
|
gen = random.Random()
|
|
|
|
|
2010-09-07 00:38:15 +00:00
|
|
|
def test_guaranteed_stable(self):
|
|
|
|
# These sequences are guaranteed to stay the same across versions of python
|
|
|
|
self.gen.seed(3456147, version=1)
|
|
|
|
self.assertEqual([self.gen.random().hex() for i in range(4)],
|
|
|
|
['0x1.ac362300d90d2p-1', '0x1.9d16f74365005p-1',
|
|
|
|
'0x1.1ebb4352e4c4dp-1', '0x1.1a7422abf9c11p-1'])
|
|
|
|
self.gen.seed("the quick brown fox", version=2)
|
|
|
|
self.assertEqual([self.gen.random().hex() for i in range(4)],
|
2010-12-08 01:13:53 +00:00
|
|
|
['0x1.1239ddfb11b7cp-3', '0x1.b3cbb5c51b120p-4',
|
|
|
|
'0x1.8c4f55116b60fp-1', '0x1.63eb525174a27p-1'])
|
2010-09-07 00:38:15 +00:00
|
|
|
|
2016-08-31 15:01:08 -07:00
|
|
|
def test_bug_27706(self):
|
|
|
|
# Verify that version 1 seeds are unaffected by hash randomization
|
|
|
|
|
|
|
|
self.gen.seed('nofar', version=1) # hash('nofar') == 5990528763808513177
|
|
|
|
self.assertEqual([self.gen.random().hex() for i in range(4)],
|
|
|
|
['0x1.8645314505ad7p-1', '0x1.afb1f82e40a40p-5',
|
|
|
|
'0x1.2a59d2285e971p-1', '0x1.56977142a7880p-6'])
|
|
|
|
|
|
|
|
self.gen.seed('rachel', version=1) # hash('rachel') == -9091735575445484789
|
|
|
|
self.assertEqual([self.gen.random().hex() for i in range(4)],
|
|
|
|
['0x1.0b294cc856fcdp-1', '0x1.2ad22d79e77b8p-3',
|
|
|
|
'0x1.3052b9c072678p-2', '0x1.578f332106574p-3'])
|
|
|
|
|
|
|
|
self.gen.seed('', version=1) # hash('') == 0
|
|
|
|
self.assertEqual([self.gen.random().hex() for i in range(4)],
|
|
|
|
['0x1.b0580f98a7dbep-1', '0x1.84129978f9c1ap-1',
|
|
|
|
'0x1.aeaa51052e978p-2', '0x1.092178fb945a6p-2'])
|
|
|
|
|
2017-09-28 10:50:01 +03:00
|
|
|
def test_bug_31478(self):
|
|
|
|
# There shouldn't be an assertion failure in _random.Random.seed() in
|
|
|
|
# case the argument has a bad __abs__() method.
|
|
|
|
class BadInt(int):
|
|
|
|
def __abs__(self):
|
|
|
|
return None
|
|
|
|
try:
|
|
|
|
self.gen.seed(BadInt())
|
|
|
|
except TypeError:
|
|
|
|
pass
|
|
|
|
|
2017-09-17 09:04:30 -07:00
|
|
|
def test_bug_31482(self):
|
|
|
|
# Verify that version 1 seeds are unaffected by hash randomization
|
|
|
|
# when the seeds are expressed as bytes rather than strings.
|
|
|
|
# The hash(b) values listed are the Python2.7 hash() values
|
|
|
|
# which were used for seeding.
|
|
|
|
|
|
|
|
self.gen.seed(b'nofar', version=1) # hash('nofar') == 5990528763808513177
|
|
|
|
self.assertEqual([self.gen.random().hex() for i in range(4)],
|
|
|
|
['0x1.8645314505ad7p-1', '0x1.afb1f82e40a40p-5',
|
|
|
|
'0x1.2a59d2285e971p-1', '0x1.56977142a7880p-6'])
|
|
|
|
|
|
|
|
self.gen.seed(b'rachel', version=1) # hash('rachel') == -9091735575445484789
|
|
|
|
self.assertEqual([self.gen.random().hex() for i in range(4)],
|
|
|
|
['0x1.0b294cc856fcdp-1', '0x1.2ad22d79e77b8p-3',
|
|
|
|
'0x1.3052b9c072678p-2', '0x1.578f332106574p-3'])
|
|
|
|
|
|
|
|
self.gen.seed(b'', version=1) # hash('') == 0
|
|
|
|
self.assertEqual([self.gen.random().hex() for i in range(4)],
|
|
|
|
['0x1.b0580f98a7dbep-1', '0x1.84129978f9c1ap-1',
|
|
|
|
'0x1.aeaa51052e978p-2', '0x1.092178fb945a6p-2'])
|
|
|
|
|
|
|
|
b = b'\x00\x20\x40\x60\x80\xA0\xC0\xE0\xF0'
|
|
|
|
self.gen.seed(b, version=1) # hash(b) == 5015594239749365497
|
|
|
|
self.assertEqual([self.gen.random().hex() for i in range(4)],
|
|
|
|
['0x1.52c2fde444d23p-1', '0x1.875174f0daea4p-2',
|
|
|
|
'0x1.9e9b2c50e5cd2p-1', '0x1.fa57768bd321cp-2'])
|
|
|
|
|
2004-07-09 14:26:18 +00:00
|
|
|
def test_setstate_first_arg(self):
|
|
|
|
self.assertRaises(ValueError, self.gen.setstate, (1, None, None))
|
|
|
|
|
|
|
|
def test_setstate_middle_arg(self):
|
2017-04-21 23:10:46 -07:00
|
|
|
start_state = self.gen.getstate()
|
2004-07-09 14:26:18 +00:00
|
|
|
# Wrong type, s/b tuple
|
|
|
|
self.assertRaises(TypeError, self.gen.setstate, (2, None, None))
|
|
|
|
# Wrong length, s/b 625
|
|
|
|
self.assertRaises(ValueError, self.gen.setstate, (2, (1,2,3), None))
|
|
|
|
# Wrong type, s/b tuple of 625 ints
|
|
|
|
self.assertRaises(TypeError, self.gen.setstate, (2, ('a',)*625, None))
|
|
|
|
# Last element s/b an int also
|
|
|
|
self.assertRaises(TypeError, self.gen.setstate, (2, (0,)*624+('a',), None))
|
2015-07-24 09:02:53 +03:00
|
|
|
# Last element s/b between 0 and 624
|
|
|
|
with self.assertRaises((ValueError, OverflowError)):
|
|
|
|
self.gen.setstate((2, (1,)*624+(625,), None))
|
|
|
|
with self.assertRaises((ValueError, OverflowError)):
|
|
|
|
self.gen.setstate((2, (1,)*624+(-1,), None))
|
2017-04-21 23:10:46 -07:00
|
|
|
# Failed calls to setstate() should not have changed the state.
|
|
|
|
bits100 = self.gen.getrandbits(100)
|
|
|
|
self.gen.setstate(start_state)
|
|
|
|
self.assertEqual(self.gen.getrandbits(100), bits100)
|
2004-07-09 14:26:18 +00:00
|
|
|
|
2013-04-02 12:47:23 -04:00
|
|
|
# Little trick to make "tuple(x % (2**32) for x in internalstate)"
|
|
|
|
# raise ValueError. I cannot think of a simple way to achieve this, so
|
|
|
|
# I am opting for using a generator as the middle argument of setstate
|
|
|
|
# which attempts to cast a NaN to integer.
|
|
|
|
state_values = self.gen.getstate()[1]
|
|
|
|
state_values = list(state_values)
|
|
|
|
state_values[-1] = float('nan')
|
|
|
|
state = (int(x) for x in state_values)
|
|
|
|
self.assertRaises(TypeError, self.gen.setstate, (2, state, None))
|
|
|
|
|
2002-12-29 23:03:38 +00:00
|
|
|
def test_referenceImplementation(self):
|
|
|
|
# Compare the python implementation with results from the original
|
|
|
|
# code. Create 2000 53-bit precision random floats. Compare only
|
|
|
|
# the last ten entries to show that the independent implementations
|
|
|
|
# are tracking. Here is the main() function needed to create the
|
|
|
|
# list of expected random numbers:
|
|
|
|
# void main(void){
|
|
|
|
# int i;
|
|
|
|
# unsigned long init[4]={61731, 24903, 614, 42143}, length=4;
|
|
|
|
# init_by_array(init, length);
|
|
|
|
# for (i=0; i<2000; i++) {
|
|
|
|
# printf("%.15f ", genrand_res53());
|
|
|
|
# if (i%5==4) printf("\n");
|
|
|
|
# }
|
|
|
|
# }
|
|
|
|
expected = [0.45839803073713259,
|
|
|
|
0.86057815201978782,
|
|
|
|
0.92848331726782152,
|
|
|
|
0.35932681119782461,
|
|
|
|
0.081823493762449573,
|
|
|
|
0.14332226470169329,
|
|
|
|
0.084297823823520024,
|
|
|
|
0.53814864671831453,
|
|
|
|
0.089215024911993401,
|
|
|
|
0.78486196105372907]
|
|
|
|
|
2007-01-15 16:59:06 +00:00
|
|
|
self.gen.seed(61731 + (24903<<32) + (614<<64) + (42143<<96))
|
2002-12-29 23:03:38 +00:00
|
|
|
actual = self.randomlist(2000)[-10:]
|
|
|
|
for a, e in zip(actual, expected):
|
|
|
|
self.assertAlmostEqual(a,e,places=14)
|
|
|
|
|
|
|
|
def test_strong_reference_implementation(self):
|
|
|
|
# Like test_referenceImplementation, but checks for exact bit-level
|
|
|
|
# equality. This should pass on any box where C double contains
|
|
|
|
# at least 53 bits of precision (the underlying algorithm suffers
|
|
|
|
# no rounding errors -- all results are exact).
|
|
|
|
from math import ldexp
|
|
|
|
|
2007-01-15 16:59:06 +00:00
|
|
|
expected = [0x0eab3258d2231f,
|
|
|
|
0x1b89db315277a5,
|
|
|
|
0x1db622a5518016,
|
|
|
|
0x0b7f9af0d575bf,
|
|
|
|
0x029e4c4db82240,
|
|
|
|
0x04961892f5d673,
|
|
|
|
0x02b291598e4589,
|
|
|
|
0x11388382c15694,
|
|
|
|
0x02dad977c9e1fe,
|
|
|
|
0x191d96d4d334c6]
|
|
|
|
self.gen.seed(61731 + (24903<<32) + (614<<64) + (42143<<96))
|
2002-12-29 23:03:38 +00:00
|
|
|
actual = self.randomlist(2000)[-10:]
|
|
|
|
for a, e in zip(actual, expected):
|
2007-01-15 16:59:06 +00:00
|
|
|
self.assertEqual(int(ldexp(a, 53)), e)
|
2002-12-29 23:03:38 +00:00
|
|
|
|
|
|
|
def test_long_seed(self):
|
|
|
|
# This is most interesting to run in debug mode, just to make sure
|
|
|
|
# nothing blows up. Under the covers, a dynamically resized array
|
|
|
|
# is allocated, consuming space proportional to the number of bits
|
|
|
|
# in the seed. Unfortunately, that's a quadratic-time algorithm,
|
|
|
|
# so don't make this horribly big.
|
2007-01-15 16:59:06 +00:00
|
|
|
seed = (1 << (10000 * 8)) - 1 # about 10K bytes
|
2002-12-29 23:03:38 +00:00
|
|
|
self.gen.seed(seed)
|
2002-05-05 20:40:00 +00:00
|
|
|
|
2020-04-17 19:32:14 +02:00
|
|
|
def test_getrandbits(self):
|
|
|
|
super().test_getrandbits()
|
|
|
|
|
2003-10-05 09:09:15 +00:00
|
|
|
# Verify cross-platform repeatability
|
|
|
|
self.gen.seed(1234567)
|
|
|
|
self.assertEqual(self.gen.getrandbits(100),
|
2007-01-15 16:59:06 +00:00
|
|
|
97904845777343510404718956115)
|
2025-06-11 04:51:08 +03:00
|
|
|
self.gen.seed(1234567)
|
|
|
|
self.assertEqual(self.gen.getrandbits(MyIndex(100)),
|
|
|
|
97904845777343510404718956115)
|
2004-07-09 14:26:18 +00:00
|
|
|
|
2025-05-31 11:23:01 +03:00
|
|
|
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)
|
|
|
|
|
2018-04-17 17:16:17 +02:00
|
|
|
def test_randrange_uses_getrandbits(self):
|
|
|
|
# Verify use of getrandbits by randrange
|
|
|
|
# Use same seed as in the cross-platform repeatability test
|
2020-04-17 19:32:14 +02:00
|
|
|
# in test_getrandbits above.
|
2018-04-17 17:16:17 +02:00
|
|
|
self.gen.seed(1234567)
|
|
|
|
# If randrange uses getrandbits, it should pick getrandbits(100)
|
|
|
|
# when called with a 100-bits stop argument.
|
|
|
|
self.assertEqual(self.gen.randrange(2**99),
|
|
|
|
97904845777343510404718956115)
|
|
|
|
|
|
|
|
def test_randbelow_without_getrandbits(self):
|
2013-04-02 12:47:23 -04:00
|
|
|
# Random._randbelow() can only use random() when the built-in one
|
|
|
|
# has been overridden but no new getrandbits() method was supplied.
|
|
|
|
maxsize = 1<<random.BPF
|
|
|
|
with warnings.catch_warnings():
|
|
|
|
warnings.simplefilter("ignore", UserWarning)
|
|
|
|
# Population range too large (n >= maxsize)
|
2018-04-17 17:16:17 +02:00
|
|
|
self.gen._randbelow_without_getrandbits(
|
|
|
|
maxsize+1, maxsize=maxsize
|
|
|
|
)
|
|
|
|
self.gen._randbelow_without_getrandbits(5640, maxsize=maxsize)
|
|
|
|
|
2013-04-02 12:47:23 -04:00
|
|
|
# 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
|
|
|
|
# which the following line in Random._randbelow() gets executed:
|
|
|
|
#
|
|
|
|
# rem = maxsize % n
|
|
|
|
# limit = (maxsize - rem) / maxsize
|
|
|
|
# r = random()
|
|
|
|
# while r >= limit:
|
|
|
|
# r = random() # <== *This line* <==<
|
|
|
|
#
|
|
|
|
# Therefore, to guarantee that the while loop is executed at least
|
|
|
|
# once, we need to mock random() so that it returns a number greater
|
|
|
|
# than 'limit' the first time it gets called.
|
|
|
|
|
|
|
|
n = 42
|
|
|
|
epsilon = 0.01
|
|
|
|
limit = (maxsize - (maxsize % n)) / maxsize
|
2018-04-17 17:16:17 +02:00
|
|
|
with unittest.mock.patch.object(random.Random, 'random') as random_mock:
|
|
|
|
random_mock.side_effect = [limit + epsilon, limit - epsilon]
|
|
|
|
self.gen._randbelow_without_getrandbits(n, maxsize=maxsize)
|
|
|
|
self.assertEqual(random_mock.call_count, 2)
|
2013-04-02 12:47:23 -04:00
|
|
|
|
2016-10-29 16:55:36 -07:00
|
|
|
def test_choices_algorithms(self):
|
2016-11-13 00:42:56 -05:00
|
|
|
# The various ways of specifying weights should produce the same results
|
2016-10-29 16:55:36 -07:00
|
|
|
choices = self.gen.choices
|
2016-11-21 15:32:08 -08:00
|
|
|
n = 104729
|
2016-10-29 16:55:36 -07:00
|
|
|
|
|
|
|
self.gen.seed(8675309)
|
|
|
|
a = self.gen.choices(range(n), k=10000)
|
|
|
|
|
|
|
|
self.gen.seed(8675309)
|
|
|
|
b = self.gen.choices(range(n), [1]*n, k=10000)
|
|
|
|
self.assertEqual(a, b)
|
|
|
|
|
|
|
|
self.gen.seed(8675309)
|
|
|
|
c = self.gen.choices(range(n), cum_weights=range(1, n+1), k=10000)
|
|
|
|
self.assertEqual(a, c)
|
2016-10-29 17:42:36 -07:00
|
|
|
|
2019-05-06 14:57:17 -04:00
|
|
|
# American Roulette
|
2016-10-29 17:42:36 -07:00
|
|
|
population = ['Red', 'Black', 'Green']
|
|
|
|
weights = [18, 18, 2]
|
|
|
|
cum_weights = [18, 36, 38]
|
|
|
|
expanded_population = ['Red'] * 18 + ['Black'] * 18 + ['Green'] * 2
|
|
|
|
|
|
|
|
self.gen.seed(9035768)
|
|
|
|
a = self.gen.choices(expanded_population, k=10000)
|
|
|
|
|
|
|
|
self.gen.seed(9035768)
|
|
|
|
b = self.gen.choices(population, weights, k=10000)
|
|
|
|
self.assertEqual(a, b)
|
|
|
|
|
|
|
|
self.gen.seed(9035768)
|
|
|
|
c = self.gen.choices(population, cum_weights=cum_weights, k=10000)
|
|
|
|
self.assertEqual(a, c)
|
2016-10-29 16:55:36 -07:00
|
|
|
|
2020-04-17 19:05:35 +02:00
|
|
|
def test_randbytes(self):
|
|
|
|
super().test_randbytes()
|
|
|
|
|
|
|
|
# Mersenne Twister randbytes() is deterministic
|
|
|
|
# and does not depend on the endian and bitness.
|
|
|
|
seed = 8675309
|
2020-04-17 23:51:28 +03:00
|
|
|
expected = b'3\xa8\xf9f\xf4\xa4\xd06\x19\x8f\x9f\x82\x02oe\xf0'
|
2020-04-17 19:05:35 +02:00
|
|
|
|
|
|
|
self.gen.seed(seed)
|
|
|
|
self.assertEqual(self.gen.randbytes(16), expected)
|
|
|
|
|
|
|
|
# randbytes(0) must not consume any entropy
|
|
|
|
self.gen.seed(seed)
|
|
|
|
self.assertEqual(self.gen.randbytes(0), b'')
|
|
|
|
self.assertEqual(self.gen.randbytes(16), expected)
|
|
|
|
|
|
|
|
# Four randbytes(4) calls give the same output than randbytes(16)
|
|
|
|
self.gen.seed(seed)
|
|
|
|
self.assertEqual(b''.join([self.gen.randbytes(4) for _ in range(4)]),
|
|
|
|
expected)
|
|
|
|
|
2020-04-17 23:51:28 +03:00
|
|
|
# Each randbytes(1), randbytes(2) or randbytes(3) call consumes
|
|
|
|
# 4 bytes of entropy
|
2020-04-17 19:05:35 +02:00
|
|
|
self.gen.seed(seed)
|
2020-04-17 23:51:28 +03:00
|
|
|
expected1 = expected[3::4]
|
|
|
|
self.assertEqual(b''.join(self.gen.randbytes(1) for _ in range(4)),
|
|
|
|
expected1)
|
|
|
|
|
|
|
|
self.gen.seed(seed)
|
|
|
|
expected2 = b''.join(expected[i + 2: i + 4]
|
2020-04-17 19:05:35 +02:00
|
|
|
for i in range(0, len(expected), 4))
|
|
|
|
self.assertEqual(b''.join(self.gen.randbytes(2) for _ in range(4)),
|
|
|
|
expected2)
|
|
|
|
|
|
|
|
self.gen.seed(seed)
|
2020-04-17 23:51:28 +03:00
|
|
|
expected3 = b''.join(expected[i + 1: i + 4]
|
2020-04-17 19:05:35 +02:00
|
|
|
for i in range(0, len(expected), 4))
|
|
|
|
self.assertEqual(b''.join(self.gen.randbytes(3) for _ in range(4)),
|
|
|
|
expected3)
|
|
|
|
|
2020-04-17 23:51:28 +03:00
|
|
|
def test_randbytes_getrandbits(self):
|
|
|
|
# There is a simple relation between randbytes() and getrandbits()
|
|
|
|
seed = 2849427419
|
|
|
|
gen2 = random.Random()
|
|
|
|
self.gen.seed(seed)
|
|
|
|
gen2.seed(seed)
|
|
|
|
for n in range(9):
|
|
|
|
self.assertEqual(self.gen.randbytes(n),
|
|
|
|
gen2.getrandbits(n * 8).to_bytes(n, 'little'))
|
|
|
|
|
2025-05-31 11:23:01 +03:00
|
|
|
@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')
|
|
|
|
|
2021-01-18 19:04:29 +01:00
|
|
|
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
|
|
|
|
# for a given seed value.
|
|
|
|
sample = self.gen.sample
|
|
|
|
seed = self.gen.seed
|
|
|
|
|
|
|
|
colors = ['red', 'green', 'blue', 'orange', 'black', 'amber']
|
|
|
|
counts = [500, 200, 20, 10, 5, 1 ]
|
|
|
|
k = 700
|
|
|
|
seed(8675309)
|
|
|
|
s1 = sample(colors, counts=counts, k=k)
|
|
|
|
seed(8675309)
|
|
|
|
expanded = [color for (color, count) in zip(colors, counts) for i in range(count)]
|
|
|
|
self.assertEqual(len(expanded), sum(counts))
|
|
|
|
s2 = sample(expanded, k=k)
|
|
|
|
self.assertEqual(s1, s2)
|
|
|
|
|
|
|
|
pop = 'abcdefghi'
|
|
|
|
counts = [10, 9, 8, 7, 6, 5, 4, 3, 2]
|
|
|
|
seed(8675309)
|
|
|
|
s1 = ''.join(sample(pop, counts=counts, k=30))
|
|
|
|
expanded = ''.join([letter for (letter, count) in zip(pop, counts) for i in range(count)])
|
|
|
|
seed(8675309)
|
|
|
|
s2 = ''.join(sample(expanded, k=30))
|
|
|
|
self.assertEqual(s1, s2)
|
|
|
|
|
2020-04-17 19:05:35 +02:00
|
|
|
|
2009-02-19 09:53:18 +00:00
|
|
|
def gamma(z, sqrt2pi=(2.0*pi)**0.5):
|
|
|
|
# Reflection to right half of complex plane
|
|
|
|
if z < 0.5:
|
|
|
|
return pi / sin(pi*z) / gamma(1.0-z)
|
|
|
|
# Lanczos approximation with g=7
|
|
|
|
az = z + (7.0 - 0.5)
|
|
|
|
return az ** (z-0.5) / exp(az) * sqrt2pi * fsum([
|
|
|
|
0.9999999999995183,
|
|
|
|
676.5203681218835 / z,
|
|
|
|
-1259.139216722289 / (z+1.0),
|
|
|
|
771.3234287757674 / (z+2.0),
|
|
|
|
-176.6150291498386 / (z+3.0),
|
|
|
|
12.50734324009056 / (z+4.0),
|
|
|
|
-0.1385710331296526 / (z+5.0),
|
|
|
|
0.9934937113930748e-05 / (z+6.0),
|
|
|
|
0.1659470187408462e-06 / (z+7.0),
|
|
|
|
])
|
2003-01-05 09:20:06 +00:00
|
|
|
|
2003-01-05 01:08:34 +00:00
|
|
|
class TestDistributions(unittest.TestCase):
|
|
|
|
def test_zeroinputs(self):
|
|
|
|
# Verify that distributions can handle a series of zero inputs'
|
|
|
|
g = random.Random()
|
2007-05-07 22:24:25 +00:00
|
|
|
x = [g.random() for i in range(50)] + [0.0]*5
|
2003-01-05 01:08:34 +00:00
|
|
|
g.random = x[:].pop; g.uniform(1,10)
|
|
|
|
g.random = x[:].pop; g.paretovariate(1.0)
|
|
|
|
g.random = x[:].pop; g.expovariate(1.0)
|
2022-12-15 20:40:45 +02:00
|
|
|
g.random = x[:].pop; g.expovariate()
|
2003-01-05 01:08:34 +00:00
|
|
|
g.random = x[:].pop; g.weibullvariate(1.0, 1.0)
|
2013-02-10 19:28:56 +02:00
|
|
|
g.random = x[:].pop; g.vonmisesvariate(1.0, 1.0)
|
2003-01-05 01:08:34 +00:00
|
|
|
g.random = x[:].pop; g.normalvariate(0.0, 1.0)
|
|
|
|
g.random = x[:].pop; g.gauss(0.0, 1.0)
|
|
|
|
g.random = x[:].pop; g.lognormvariate(0.0, 1.0)
|
|
|
|
g.random = x[:].pop; g.vonmisesvariate(0.0, 1.0)
|
|
|
|
g.random = x[:].pop; g.gammavariate(0.01, 1.0)
|
|
|
|
g.random = x[:].pop; g.gammavariate(1.0, 1.0)
|
|
|
|
g.random = x[:].pop; g.gammavariate(200.0, 1.0)
|
|
|
|
g.random = x[:].pop; g.betavariate(3.0, 3.0)
|
Merged revisions 61724-61725,61731-61735,61737,61739,61741,61743-61744,61753,61761,61765-61767,61769,61773,61776-61778,61780-61783,61788,61793,61796,61807,61813 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
................
r61724 | martin.v.loewis | 2008-03-22 01:01:12 +0100 (Sat, 22 Mar 2008) | 49 lines
Merged revisions 61602-61723 via svnmerge from
svn+ssh://pythondev@svn.python.org/sandbox/trunk/2to3/lib2to3
........
r61626 | david.wolever | 2008-03-19 17:19:16 +0100 (Mi, 19 M?\195?\164r 2008) | 1 line
Added fixer for implicit local imports. See #2414.
........
r61628 | david.wolever | 2008-03-19 17:57:43 +0100 (Mi, 19 M?\195?\164r 2008) | 1 line
Added a class for tests which should not run if a particular import is found.
........
r61629 | collin.winter | 2008-03-19 17:58:19 +0100 (Mi, 19 M?\195?\164r 2008) | 1 line
Two more relative import fixes in pgen2.
........
r61635 | david.wolever | 2008-03-19 20:16:03 +0100 (Mi, 19 M?\195?\164r 2008) | 1 line
Fixed print fixer so it will do the Right Thing when it encounters __future__.print_function. 2to3 gets upset, though, so the tests have been commented out.
........
r61637 | david.wolever | 2008-03-19 21:37:17 +0100 (Mi, 19 M?\195?\164r 2008) | 3 lines
Added a fixer for itertools imports (from itertools import imap, ifilterfalse --> from itertools import filterfalse)
........
r61645 | david.wolever | 2008-03-19 23:22:35 +0100 (Mi, 19 M?\195?\164r 2008) | 1 line
SVN is happier when you add the files you create... -_-'
........
r61654 | david.wolever | 2008-03-20 01:09:56 +0100 (Do, 20 M?\195?\164r 2008) | 1 line
Added an explicit sort order to fixers -- fixes problems like #2427
........
r61664 | david.wolever | 2008-03-20 04:32:40 +0100 (Do, 20 M?\195?\164r 2008) | 3 lines
Fixes #2428 -- comments are no longer eatten by __future__ fixer.
........
r61673 | david.wolever | 2008-03-20 17:22:40 +0100 (Do, 20 M?\195?\164r 2008) | 1 line
Added 2to3 node pretty-printer
........
r61679 | david.wolever | 2008-03-20 20:50:42 +0100 (Do, 20 M?\195?\164r 2008) | 1 line
Made node printing a little bit prettier
........
r61723 | martin.v.loewis | 2008-03-22 00:59:27 +0100 (Sa, 22 M?\195?\164r 2008) | 2 lines
Fix whitespace.
........
................
r61725 | martin.v.loewis | 2008-03-22 01:02:41 +0100 (Sat, 22 Mar 2008) | 2 lines
Install lib2to3.
................
r61731 | facundo.batista | 2008-03-22 03:45:37 +0100 (Sat, 22 Mar 2008) | 4 lines
Small fix that complicated the test actually when that
test failed.
................
r61732 | alexandre.vassalotti | 2008-03-22 05:08:44 +0100 (Sat, 22 Mar 2008) | 2 lines
Added warning for the removal of 'hotshot' in Py3k.
................
r61733 | georg.brandl | 2008-03-22 11:07:29 +0100 (Sat, 22 Mar 2008) | 4 lines
#1918: document that weak references *to* an object are
cleared before the object's __del__ is called, to ensure that the weak
reference callback (if any) finds the object healthy.
................
r61734 | georg.brandl | 2008-03-22 11:56:23 +0100 (Sat, 22 Mar 2008) | 2 lines
Activate the Sphinx doctest extension and convert howto/functional to use it.
................
r61735 | georg.brandl | 2008-03-22 11:58:38 +0100 (Sat, 22 Mar 2008) | 2 lines
Allow giving source names on the cmdline.
................
r61737 | georg.brandl | 2008-03-22 12:00:48 +0100 (Sat, 22 Mar 2008) | 2 lines
Fixup this HOWTO's doctest blocks so that they can be run with sphinx' doctest builder.
................
r61739 | georg.brandl | 2008-03-22 12:47:10 +0100 (Sat, 22 Mar 2008) | 2 lines
Test decimal.rst doctests as far as possible with sphinx doctest.
................
r61741 | georg.brandl | 2008-03-22 13:04:26 +0100 (Sat, 22 Mar 2008) | 2 lines
Make doctests in re docs usable with sphinx' doctest.
................
r61743 | georg.brandl | 2008-03-22 13:59:37 +0100 (Sat, 22 Mar 2008) | 2 lines
Make more doctests in pprint docs testable.
................
r61744 | georg.brandl | 2008-03-22 14:07:06 +0100 (Sat, 22 Mar 2008) | 2 lines
No need to specify explicit "doctest_block" anymore.
................
r61753 | georg.brandl | 2008-03-22 21:08:43 +0100 (Sat, 22 Mar 2008) | 2 lines
Fix-up syntax problems.
................
r61761 | georg.brandl | 2008-03-22 22:06:20 +0100 (Sat, 22 Mar 2008) | 4 lines
Make collections' doctests executable.
(The <BLANKLINE>s will be stripped from presentation output.)
................
r61765 | georg.brandl | 2008-03-22 22:21:57 +0100 (Sat, 22 Mar 2008) | 2 lines
Test doctests in datetime docs.
................
r61766 | georg.brandl | 2008-03-22 22:26:44 +0100 (Sat, 22 Mar 2008) | 2 lines
Test doctests in operator docs.
................
r61767 | georg.brandl | 2008-03-22 22:38:33 +0100 (Sat, 22 Mar 2008) | 2 lines
Enable doctests in functions.rst. Already found two errors :)
................
r61769 | georg.brandl | 2008-03-22 23:04:10 +0100 (Sat, 22 Mar 2008) | 3 lines
Enable doctest running for several other documents.
We have now over 640 doctests that are run with "make doctest".
................
r61773 | raymond.hettinger | 2008-03-23 01:55:46 +0100 (Sun, 23 Mar 2008) | 1 line
Simplify demo code.
................
r61776 | neal.norwitz | 2008-03-23 04:43:33 +0100 (Sun, 23 Mar 2008) | 7 lines
Try to make this test a little more robust and not fail with:
timeout (10.0025) is more than 2 seconds more than expected (0.001)
I'm assuming this problem is caused by DNS lookup. This change
does a DNS lookup of the hostname before trying to connect, so the time
is not included.
................
r61777 | neal.norwitz | 2008-03-23 05:08:30 +0100 (Sun, 23 Mar 2008) | 1 line
Speed up the test by avoiding socket timeouts.
................
r61778 | neal.norwitz | 2008-03-23 05:43:09 +0100 (Sun, 23 Mar 2008) | 1 line
Skip the epoll test if epoll() does not work
................
r61780 | neal.norwitz | 2008-03-23 06:47:20 +0100 (Sun, 23 Mar 2008) | 1 line
Suppress failure (to avoid a flaky test) if we cannot connect to svn.python.org
................
r61781 | neal.norwitz | 2008-03-23 07:13:25 +0100 (Sun, 23 Mar 2008) | 4 lines
Move itertools before future_builtins since the latter depends on the former.
From a clean build importing future_builtins would fail since itertools
wasn't built yet.
................
r61782 | neal.norwitz | 2008-03-23 07:16:04 +0100 (Sun, 23 Mar 2008) | 1 line
Try to prevent the alarm going off early in tearDown
................
r61783 | neal.norwitz | 2008-03-23 07:19:57 +0100 (Sun, 23 Mar 2008) | 4 lines
Remove compiler warnings (on Alpha at least) about using chars as
array subscripts. Using chars are dangerous b/c they are signed
on some platforms and unsigned on others.
................
r61788 | georg.brandl | 2008-03-23 09:05:30 +0100 (Sun, 23 Mar 2008) | 2 lines
Make the doctests presentation-friendlier.
................
r61793 | amaury.forgeotdarc | 2008-03-23 10:55:29 +0100 (Sun, 23 Mar 2008) | 4 lines
#1477: ur'\U0010FFFF' raised in narrow unicode builds.
Corrected the raw-unicode-escape codec to use UTF-16 surrogates in
this case, just like the unicode-escape codec.
................
r61796 | raymond.hettinger | 2008-03-23 14:32:32 +0100 (Sun, 23 Mar 2008) | 1 line
Issue 1681432: Add triangular distribution the random module.
................
r61807 | raymond.hettinger | 2008-03-23 20:37:53 +0100 (Sun, 23 Mar 2008) | 4 lines
Adopt Nick's suggestion for useful default arguments.
Clean-up floating point issues by adding true division and float constants.
................
r61813 | gregory.p.smith | 2008-03-23 22:04:43 +0100 (Sun, 23 Mar 2008) | 6 lines
Fix gzip to deal with CRC's being signed values in Python 2.x properly and to
read 32bit values as unsigned to start with rather than applying signedness
fixups allover the place afterwards.
This hopefully fixes the test_tarfile failure on the alpha/tru64 buildbot.
................
2008-03-23 21:54:12 +00:00
|
|
|
g.random = x[:].pop; g.triangular(0.0, 1.0, 1.0/3.0)
|
2003-01-05 01:08:34 +00:00
|
|
|
|
2003-01-05 09:20:06 +00:00
|
|
|
def test_avg_std(self):
|
|
|
|
# Use integration to test distribution average and standard deviation.
|
|
|
|
# Only works for distributions which do not consume variates in pairs
|
|
|
|
g = random.Random()
|
|
|
|
N = 5000
|
2007-05-07 22:24:25 +00:00
|
|
|
x = [i/float(N) for i in range(1,N)]
|
2003-01-05 09:20:06 +00:00
|
|
|
for variate, args, mu, sigmasqrd in [
|
|
|
|
(g.uniform, (1.0,10.0), (10.0+1.0)/2, (10.0-1.0)**2/12),
|
Merged revisions 61724-61725,61731-61735,61737,61739,61741,61743-61744,61753,61761,61765-61767,61769,61773,61776-61778,61780-61783,61788,61793,61796,61807,61813 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
................
r61724 | martin.v.loewis | 2008-03-22 01:01:12 +0100 (Sat, 22 Mar 2008) | 49 lines
Merged revisions 61602-61723 via svnmerge from
svn+ssh://pythondev@svn.python.org/sandbox/trunk/2to3/lib2to3
........
r61626 | david.wolever | 2008-03-19 17:19:16 +0100 (Mi, 19 M?\195?\164r 2008) | 1 line
Added fixer for implicit local imports. See #2414.
........
r61628 | david.wolever | 2008-03-19 17:57:43 +0100 (Mi, 19 M?\195?\164r 2008) | 1 line
Added a class for tests which should not run if a particular import is found.
........
r61629 | collin.winter | 2008-03-19 17:58:19 +0100 (Mi, 19 M?\195?\164r 2008) | 1 line
Two more relative import fixes in pgen2.
........
r61635 | david.wolever | 2008-03-19 20:16:03 +0100 (Mi, 19 M?\195?\164r 2008) | 1 line
Fixed print fixer so it will do the Right Thing when it encounters __future__.print_function. 2to3 gets upset, though, so the tests have been commented out.
........
r61637 | david.wolever | 2008-03-19 21:37:17 +0100 (Mi, 19 M?\195?\164r 2008) | 3 lines
Added a fixer for itertools imports (from itertools import imap, ifilterfalse --> from itertools import filterfalse)
........
r61645 | david.wolever | 2008-03-19 23:22:35 +0100 (Mi, 19 M?\195?\164r 2008) | 1 line
SVN is happier when you add the files you create... -_-'
........
r61654 | david.wolever | 2008-03-20 01:09:56 +0100 (Do, 20 M?\195?\164r 2008) | 1 line
Added an explicit sort order to fixers -- fixes problems like #2427
........
r61664 | david.wolever | 2008-03-20 04:32:40 +0100 (Do, 20 M?\195?\164r 2008) | 3 lines
Fixes #2428 -- comments are no longer eatten by __future__ fixer.
........
r61673 | david.wolever | 2008-03-20 17:22:40 +0100 (Do, 20 M?\195?\164r 2008) | 1 line
Added 2to3 node pretty-printer
........
r61679 | david.wolever | 2008-03-20 20:50:42 +0100 (Do, 20 M?\195?\164r 2008) | 1 line
Made node printing a little bit prettier
........
r61723 | martin.v.loewis | 2008-03-22 00:59:27 +0100 (Sa, 22 M?\195?\164r 2008) | 2 lines
Fix whitespace.
........
................
r61725 | martin.v.loewis | 2008-03-22 01:02:41 +0100 (Sat, 22 Mar 2008) | 2 lines
Install lib2to3.
................
r61731 | facundo.batista | 2008-03-22 03:45:37 +0100 (Sat, 22 Mar 2008) | 4 lines
Small fix that complicated the test actually when that
test failed.
................
r61732 | alexandre.vassalotti | 2008-03-22 05:08:44 +0100 (Sat, 22 Mar 2008) | 2 lines
Added warning for the removal of 'hotshot' in Py3k.
................
r61733 | georg.brandl | 2008-03-22 11:07:29 +0100 (Sat, 22 Mar 2008) | 4 lines
#1918: document that weak references *to* an object are
cleared before the object's __del__ is called, to ensure that the weak
reference callback (if any) finds the object healthy.
................
r61734 | georg.brandl | 2008-03-22 11:56:23 +0100 (Sat, 22 Mar 2008) | 2 lines
Activate the Sphinx doctest extension and convert howto/functional to use it.
................
r61735 | georg.brandl | 2008-03-22 11:58:38 +0100 (Sat, 22 Mar 2008) | 2 lines
Allow giving source names on the cmdline.
................
r61737 | georg.brandl | 2008-03-22 12:00:48 +0100 (Sat, 22 Mar 2008) | 2 lines
Fixup this HOWTO's doctest blocks so that they can be run with sphinx' doctest builder.
................
r61739 | georg.brandl | 2008-03-22 12:47:10 +0100 (Sat, 22 Mar 2008) | 2 lines
Test decimal.rst doctests as far as possible with sphinx doctest.
................
r61741 | georg.brandl | 2008-03-22 13:04:26 +0100 (Sat, 22 Mar 2008) | 2 lines
Make doctests in re docs usable with sphinx' doctest.
................
r61743 | georg.brandl | 2008-03-22 13:59:37 +0100 (Sat, 22 Mar 2008) | 2 lines
Make more doctests in pprint docs testable.
................
r61744 | georg.brandl | 2008-03-22 14:07:06 +0100 (Sat, 22 Mar 2008) | 2 lines
No need to specify explicit "doctest_block" anymore.
................
r61753 | georg.brandl | 2008-03-22 21:08:43 +0100 (Sat, 22 Mar 2008) | 2 lines
Fix-up syntax problems.
................
r61761 | georg.brandl | 2008-03-22 22:06:20 +0100 (Sat, 22 Mar 2008) | 4 lines
Make collections' doctests executable.
(The <BLANKLINE>s will be stripped from presentation output.)
................
r61765 | georg.brandl | 2008-03-22 22:21:57 +0100 (Sat, 22 Mar 2008) | 2 lines
Test doctests in datetime docs.
................
r61766 | georg.brandl | 2008-03-22 22:26:44 +0100 (Sat, 22 Mar 2008) | 2 lines
Test doctests in operator docs.
................
r61767 | georg.brandl | 2008-03-22 22:38:33 +0100 (Sat, 22 Mar 2008) | 2 lines
Enable doctests in functions.rst. Already found two errors :)
................
r61769 | georg.brandl | 2008-03-22 23:04:10 +0100 (Sat, 22 Mar 2008) | 3 lines
Enable doctest running for several other documents.
We have now over 640 doctests that are run with "make doctest".
................
r61773 | raymond.hettinger | 2008-03-23 01:55:46 +0100 (Sun, 23 Mar 2008) | 1 line
Simplify demo code.
................
r61776 | neal.norwitz | 2008-03-23 04:43:33 +0100 (Sun, 23 Mar 2008) | 7 lines
Try to make this test a little more robust and not fail with:
timeout (10.0025) is more than 2 seconds more than expected (0.001)
I'm assuming this problem is caused by DNS lookup. This change
does a DNS lookup of the hostname before trying to connect, so the time
is not included.
................
r61777 | neal.norwitz | 2008-03-23 05:08:30 +0100 (Sun, 23 Mar 2008) | 1 line
Speed up the test by avoiding socket timeouts.
................
r61778 | neal.norwitz | 2008-03-23 05:43:09 +0100 (Sun, 23 Mar 2008) | 1 line
Skip the epoll test if epoll() does not work
................
r61780 | neal.norwitz | 2008-03-23 06:47:20 +0100 (Sun, 23 Mar 2008) | 1 line
Suppress failure (to avoid a flaky test) if we cannot connect to svn.python.org
................
r61781 | neal.norwitz | 2008-03-23 07:13:25 +0100 (Sun, 23 Mar 2008) | 4 lines
Move itertools before future_builtins since the latter depends on the former.
From a clean build importing future_builtins would fail since itertools
wasn't built yet.
................
r61782 | neal.norwitz | 2008-03-23 07:16:04 +0100 (Sun, 23 Mar 2008) | 1 line
Try to prevent the alarm going off early in tearDown
................
r61783 | neal.norwitz | 2008-03-23 07:19:57 +0100 (Sun, 23 Mar 2008) | 4 lines
Remove compiler warnings (on Alpha at least) about using chars as
array subscripts. Using chars are dangerous b/c they are signed
on some platforms and unsigned on others.
................
r61788 | georg.brandl | 2008-03-23 09:05:30 +0100 (Sun, 23 Mar 2008) | 2 lines
Make the doctests presentation-friendlier.
................
r61793 | amaury.forgeotdarc | 2008-03-23 10:55:29 +0100 (Sun, 23 Mar 2008) | 4 lines
#1477: ur'\U0010FFFF' raised in narrow unicode builds.
Corrected the raw-unicode-escape codec to use UTF-16 surrogates in
this case, just like the unicode-escape codec.
................
r61796 | raymond.hettinger | 2008-03-23 14:32:32 +0100 (Sun, 23 Mar 2008) | 1 line
Issue 1681432: Add triangular distribution the random module.
................
r61807 | raymond.hettinger | 2008-03-23 20:37:53 +0100 (Sun, 23 Mar 2008) | 4 lines
Adopt Nick's suggestion for useful default arguments.
Clean-up floating point issues by adding true division and float constants.
................
r61813 | gregory.p.smith | 2008-03-23 22:04:43 +0100 (Sun, 23 Mar 2008) | 6 lines
Fix gzip to deal with CRC's being signed values in Python 2.x properly and to
read 32bit values as unsigned to start with rather than applying signedness
fixups allover the place afterwards.
This hopefully fixes the test_tarfile failure on the alpha/tru64 buildbot.
................
2008-03-23 21:54:12 +00:00
|
|
|
(g.triangular, (0.0, 1.0, 1.0/3.0), 4.0/9.0, 7.0/9.0/18.0),
|
2003-01-05 09:20:06 +00:00
|
|
|
(g.expovariate, (1.5,), 1/1.5, 1/1.5**2),
|
2013-02-10 19:28:56 +02:00
|
|
|
(g.vonmisesvariate, (1.23, 0), pi, pi**2/3),
|
2003-01-05 09:20:06 +00:00
|
|
|
(g.paretovariate, (5.0,), 5.0/(5.0-1),
|
|
|
|
5.0/((5.0-1)**2*(5.0-2))),
|
|
|
|
(g.weibullvariate, (1.0, 3.0), gamma(1+1/3.0),
|
|
|
|
gamma(1+2/3.0)-gamma(1+1/3.0)**2) ]:
|
|
|
|
g.random = x[:].pop
|
|
|
|
y = []
|
2007-05-07 22:24:25 +00:00
|
|
|
for i in range(len(x)):
|
2003-01-05 09:20:06 +00:00
|
|
|
try:
|
|
|
|
y.append(variate(*args))
|
|
|
|
except IndexError:
|
|
|
|
pass
|
|
|
|
s1 = s2 = 0
|
|
|
|
for e in y:
|
|
|
|
s1 += e
|
|
|
|
s2 += (e - mu) ** 2
|
|
|
|
N = len(y)
|
2013-02-10 19:28:56 +02:00
|
|
|
self.assertAlmostEqual(s1/N, mu, places=2,
|
|
|
|
msg='%s%r' % (variate.__name__, args))
|
|
|
|
self.assertAlmostEqual(s2/(N-1), sigmasqrd, places=2,
|
|
|
|
msg='%s%r' % (variate.__name__, args))
|
|
|
|
|
|
|
|
def test_constant(self):
|
|
|
|
g = random.Random()
|
|
|
|
N = 100
|
|
|
|
for variate, args, expected in [
|
|
|
|
(g.uniform, (10.0, 10.0), 10.0),
|
|
|
|
(g.triangular, (10.0, 10.0), 10.0),
|
2014-05-25 17:25:27 -07:00
|
|
|
(g.triangular, (10.0, 10.0, 10.0), 10.0),
|
2013-02-10 19:28:56 +02:00
|
|
|
(g.expovariate, (float('inf'),), 0.0),
|
|
|
|
(g.vonmisesvariate, (3.0, float('inf')), 3.0),
|
|
|
|
(g.gauss, (10.0, 0.0), 10.0),
|
|
|
|
(g.lognormvariate, (0.0, 0.0), 1.0),
|
|
|
|
(g.lognormvariate, (-float('inf'), 0.0), 0.0),
|
|
|
|
(g.normalvariate, (10.0, 0.0), 10.0),
|
2022-07-13 09:46:04 -05:00
|
|
|
(g.binomialvariate, (0, 0.5), 0),
|
|
|
|
(g.binomialvariate, (10, 0.0), 0),
|
|
|
|
(g.binomialvariate, (10, 1.0), 10),
|
2013-02-10 19:28:56 +02:00
|
|
|
(g.paretovariate, (float('inf'),), 1.0),
|
|
|
|
(g.weibullvariate, (10.0, float('inf')), 10.0),
|
|
|
|
(g.weibullvariate, (0.0, 10.0), 0.0),
|
|
|
|
]:
|
|
|
|
for i in range(N):
|
|
|
|
self.assertEqual(variate(*args), expected)
|
2003-01-05 09:20:06 +00:00
|
|
|
|
2022-07-13 09:46:04 -05:00
|
|
|
def test_binomialvariate(self):
|
|
|
|
B = random.binomialvariate
|
|
|
|
|
|
|
|
# Cover all the code paths
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
B(n=-1) # Negative n
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
B(n=1, p=-0.5) # Negative p
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
B(n=1, p=1.5) # p > 1.0
|
2023-11-23 10:31:03 -08:00
|
|
|
self.assertEqual(B(0, 0.5), 0) # n == 0
|
2022-07-13 09:46:04 -05:00
|
|
|
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
|
|
|
|
self.assertTrue(B(1, 0.9) in {0, 1}) # n == 1 fast path
|
|
|
|
self.assertTrue(B(1, 0.0) in {0}) # n == 1 fast path
|
|
|
|
self.assertTrue(B(1, 1.0) in {1}) # n == 1 fast path
|
|
|
|
|
2023-11-23 10:31:03 -08:00
|
|
|
# BG method very small p
|
|
|
|
self.assertEqual(B(5, 1e-18), 0)
|
|
|
|
|
2022-07-13 09:46:04 -05:00
|
|
|
# BG method p <= 0.5 and n*p=1.25
|
|
|
|
self.assertTrue(B(5, 0.25) in set(range(6)))
|
|
|
|
|
|
|
|
# BG method p >= 0.5 and n*(1-p)=1.25
|
|
|
|
self.assertTrue(B(5, 0.75) in set(range(6)))
|
|
|
|
|
|
|
|
# BTRS method p <= 0.5 and n*p=25
|
|
|
|
self.assertTrue(B(100, 0.25) in set(range(101)))
|
|
|
|
|
|
|
|
# BTRS method p > 0.5 and n*(1-p)=25
|
|
|
|
self.assertTrue(B(100, 0.75) in set(range(101)))
|
|
|
|
|
|
|
|
# Statistical tests chosen such that they are
|
|
|
|
# exceedingly unlikely to ever fail for correct code.
|
|
|
|
|
|
|
|
# BG code path
|
|
|
|
# Expected dist: [31641, 42188, 21094, 4688, 391]
|
|
|
|
c = Counter(B(4, 0.25) for i in range(100_000))
|
|
|
|
self.assertTrue(29_641 <= c[0] <= 33_641, c)
|
|
|
|
self.assertTrue(40_188 <= c[1] <= 44_188)
|
|
|
|
self.assertTrue(19_094 <= c[2] <= 23_094)
|
|
|
|
self.assertTrue(2_688 <= c[3] <= 6_688)
|
|
|
|
self.assertEqual(set(c), {0, 1, 2, 3, 4})
|
|
|
|
|
|
|
|
# BTRS code path
|
|
|
|
# Sum of c[20], c[21], c[22], c[23], c[24] expected to be 36,214
|
|
|
|
c = Counter(B(100, 0.25) for i in range(100_000))
|
|
|
|
self.assertTrue(34_214 <= c[20]+c[21]+c[22]+c[23]+c[24] <= 38_214)
|
|
|
|
self.assertTrue(set(c) <= set(range(101)))
|
|
|
|
self.assertEqual(c.total(), 100_000)
|
|
|
|
|
|
|
|
# Demonstrate the BTRS works for huge values of n
|
|
|
|
self.assertTrue(19_000_000 <= B(100_000_000, 0.2) <= 21_000_000)
|
|
|
|
self.assertTrue(89_000_000 <= B(100_000_000, 0.9) <= 91_000_000)
|
|
|
|
|
|
|
|
|
2013-02-10 14:16:10 +00:00
|
|
|
def test_von_mises_range(self):
|
|
|
|
# Issue 17149: von mises variates were not consistently in the
|
|
|
|
# range [0, 2*PI].
|
|
|
|
g = random.Random()
|
|
|
|
N = 100
|
|
|
|
for mu in 0.0, 0.1, 3.1, 6.2:
|
|
|
|
for kappa in 0.0, 2.3, 500.0:
|
|
|
|
for _ in range(N):
|
|
|
|
sample = g.vonmisesvariate(mu, kappa)
|
|
|
|
self.assertTrue(
|
|
|
|
0 <= sample <= random.TWOPI,
|
|
|
|
msg=("vonmisesvariate({}, {}) produced a result {} out"
|
|
|
|
" of range [0, 2*pi]").format(mu, kappa, sample))
|
|
|
|
|
2013-02-10 19:28:56 +02:00
|
|
|
def test_von_mises_large_kappa(self):
|
|
|
|
# Issue #17141: vonmisesvariate() was hang for large kappas
|
|
|
|
random.vonmisesvariate(0, 1e15)
|
|
|
|
random.vonmisesvariate(0, 1e100)
|
|
|
|
|
2013-04-02 12:47:23 -04:00
|
|
|
def test_gammavariate_errors(self):
|
|
|
|
# Both alpha and beta must be > 0.0
|
|
|
|
self.assertRaises(ValueError, random.gammavariate, -1, 3)
|
|
|
|
self.assertRaises(ValueError, random.gammavariate, 0, 2)
|
|
|
|
self.assertRaises(ValueError, random.gammavariate, 2, 0)
|
|
|
|
self.assertRaises(ValueError, random.gammavariate, 1, -3)
|
|
|
|
|
2018-12-24 07:54:25 +01:00
|
|
|
# There are three different possibilities in the current implementation
|
|
|
|
# of random.gammavariate(), depending on the value of 'alpha'. What we
|
|
|
|
# are going to do here is to fix the values returned by random() to
|
|
|
|
# generate test cases that provide 100% line coverage of the method.
|
2013-04-02 12:47:23 -04:00
|
|
|
@unittest.mock.patch('random.Random.random')
|
2018-12-24 07:54:25 +01:00
|
|
|
def test_gammavariate_alpha_greater_one(self, random_mock):
|
2013-04-02 12:47:23 -04:00
|
|
|
|
2018-12-24 07:54:25 +01:00
|
|
|
# #1: alpha > 1.0.
|
|
|
|
# We want the first random number to be outside the
|
2013-04-02 12:47:23 -04:00
|
|
|
# [1e-7, .9999999] range, so that the continue statement executes
|
|
|
|
# once. The values of u1 and u2 will be 0.5 and 0.3, respectively.
|
|
|
|
random_mock.side_effect = [1e-8, 0.5, 0.3]
|
|
|
|
returned_value = random.gammavariate(1.1, 2.3)
|
|
|
|
self.assertAlmostEqual(returned_value, 2.53)
|
|
|
|
|
2018-12-24 07:54:25 +01:00
|
|
|
@unittest.mock.patch('random.Random.random')
|
|
|
|
def test_gammavariate_alpha_equal_one(self, random_mock):
|
|
|
|
|
|
|
|
# #2.a: alpha == 1.
|
|
|
|
# The execution body of the while loop executes once.
|
|
|
|
# Then random.random() returns 0.45,
|
2013-04-02 12:47:23 -04:00
|
|
|
# which causes while to stop looping and the algorithm to terminate.
|
2018-12-24 07:54:25 +01:00
|
|
|
random_mock.side_effect = [0.45]
|
2013-04-02 12:47:23 -04:00
|
|
|
returned_value = random.gammavariate(1.0, 3.14)
|
2018-12-24 07:54:25 +01:00
|
|
|
self.assertAlmostEqual(returned_value, 1.877208182372648)
|
|
|
|
|
|
|
|
@unittest.mock.patch('random.Random.random')
|
|
|
|
def test_gammavariate_alpha_equal_one_equals_expovariate(self, random_mock):
|
|
|
|
|
|
|
|
# #2.b: alpha == 1.
|
|
|
|
# It must be equivalent of calling expovariate(1.0 / beta).
|
|
|
|
beta = 3.14
|
|
|
|
random_mock.side_effect = [1e-8, 1e-8]
|
|
|
|
gammavariate_returned_value = random.gammavariate(1.0, beta)
|
|
|
|
expovariate_returned_value = random.expovariate(1.0 / beta)
|
|
|
|
self.assertAlmostEqual(gammavariate_returned_value, expovariate_returned_value)
|
|
|
|
|
|
|
|
@unittest.mock.patch('random.Random.random')
|
|
|
|
def test_gammavariate_alpha_between_zero_and_one(self, random_mock):
|
2013-04-02 12:47:23 -04:00
|
|
|
|
2018-12-24 07:54:25 +01:00
|
|
|
# #3: 0 < alpha < 1.
|
|
|
|
# This is the most complex region of code to cover,
|
2013-04-02 12:47:23 -04:00
|
|
|
# as there are multiple if-else statements. Let's take a look at the
|
|
|
|
# source code, and determine the values that we need accordingly:
|
|
|
|
#
|
|
|
|
# while 1:
|
|
|
|
# u = random()
|
|
|
|
# b = (_e + alpha)/_e
|
|
|
|
# p = b*u
|
|
|
|
# if p <= 1.0: # <=== (A)
|
|
|
|
# x = p ** (1.0/alpha)
|
|
|
|
# else: # <=== (B)
|
|
|
|
# x = -_log((b-p)/alpha)
|
|
|
|
# u1 = random()
|
|
|
|
# if p > 1.0: # <=== (C)
|
|
|
|
# if u1 <= x ** (alpha - 1.0): # <=== (D)
|
|
|
|
# break
|
|
|
|
# elif u1 <= _exp(-x): # <=== (E)
|
|
|
|
# break
|
|
|
|
# return x * beta
|
|
|
|
#
|
|
|
|
# First, we want (A) to be True. For that we need that:
|
|
|
|
# b*random() <= 1.0
|
|
|
|
# r1 = random() <= 1.0 / b
|
|
|
|
#
|
|
|
|
# We now get to the second if-else branch, and here, since p <= 1.0,
|
|
|
|
# (C) is False and we take the elif branch, (E). For it to be True,
|
|
|
|
# so that the break is executed, we need that:
|
|
|
|
# r2 = random() <= _exp(-x)
|
|
|
|
# r2 <= _exp(-(p ** (1.0/alpha)))
|
|
|
|
# r2 <= _exp(-((b*r1) ** (1.0/alpha)))
|
|
|
|
|
|
|
|
_e = random._e
|
|
|
|
_exp = random._exp
|
|
|
|
_log = random._log
|
|
|
|
alpha = 0.35
|
|
|
|
beta = 1.45
|
|
|
|
b = (_e + alpha)/_e
|
|
|
|
epsilon = 0.01
|
|
|
|
|
|
|
|
r1 = 0.8859296441566 # 1.0 / b
|
|
|
|
r2 = 0.3678794411714 # _exp(-((b*r1) ** (1.0/alpha)))
|
|
|
|
|
|
|
|
# These four "random" values result in the following trace:
|
|
|
|
# (A) True, (E) False --> [next iteration of while]
|
|
|
|
# (A) True, (E) True --> [while loop breaks]
|
|
|
|
random_mock.side_effect = [r1, r2 + epsilon, r1, r2]
|
|
|
|
returned_value = random.gammavariate(alpha, beta)
|
|
|
|
self.assertAlmostEqual(returned_value, 1.4499999999997544)
|
|
|
|
|
|
|
|
# Let's now make (A) be False. If this is the case, when we get to the
|
|
|
|
# second if-else 'p' is greater than 1, so (C) evaluates to True. We
|
|
|
|
# now encounter a second if statement, (D), which in order to execute
|
|
|
|
# must satisfy the following condition:
|
|
|
|
# r2 <= x ** (alpha - 1.0)
|
|
|
|
# r2 <= (-_log((b-p)/alpha)) ** (alpha - 1.0)
|
|
|
|
# r2 <= (-_log((b-(b*r1))/alpha)) ** (alpha - 1.0)
|
|
|
|
r1 = 0.8959296441566 # (1.0 / b) + epsilon -- so that (A) is False
|
|
|
|
r2 = 0.9445400408898141
|
|
|
|
|
|
|
|
# And these four values result in the following trace:
|
|
|
|
# (B) and (C) True, (D) False --> [next iteration of while]
|
|
|
|
# (B) and (C) True, (D) True [while loop breaks]
|
|
|
|
random_mock.side_effect = [r1, r2 + epsilon, r1, r2]
|
|
|
|
returned_value = random.gammavariate(alpha, beta)
|
|
|
|
self.assertAlmostEqual(returned_value, 1.5830349561760781)
|
|
|
|
|
|
|
|
@unittest.mock.patch('random.Random.gammavariate')
|
|
|
|
def test_betavariate_return_zero(self, gammavariate_mock):
|
|
|
|
# betavariate() returns zero when the Gamma distribution
|
|
|
|
# that it uses internally returns this same value.
|
|
|
|
gammavariate_mock.return_value = 0.0
|
|
|
|
self.assertEqual(0.0, random.betavariate(2.71828, 3.14159))
|
2013-02-10 19:28:56 +02:00
|
|
|
|
2018-05-08 15:45:15 +03:00
|
|
|
|
2018-04-17 17:16:17 +02:00
|
|
|
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,
|
|
|
|
# but should use a getrandbits-independent implementation instead.
|
|
|
|
|
|
|
|
# subclass providing its own random **and** getrandbits methods
|
|
|
|
# like random.SystemRandom does => keep relying on getrandbits for
|
|
|
|
# randrange
|
|
|
|
class SubClass1(random.Random):
|
|
|
|
def random(self):
|
2018-05-08 15:45:15 +03:00
|
|
|
called.add('SubClass1.random')
|
|
|
|
return random.Random.random(self)
|
2018-04-17 17:16:17 +02:00
|
|
|
|
|
|
|
def getrandbits(self, n):
|
2018-05-08 15:45:15 +03:00
|
|
|
called.add('SubClass1.getrandbits')
|
|
|
|
return random.Random.getrandbits(self, n)
|
|
|
|
called = set()
|
|
|
|
SubClass1().randrange(42)
|
|
|
|
self.assertEqual(called, {'SubClass1.getrandbits'})
|
2018-04-17 17:16:17 +02:00
|
|
|
|
|
|
|
# subclass providing only random => can only use random for randrange
|
|
|
|
class SubClass2(random.Random):
|
|
|
|
def random(self):
|
2018-05-08 15:45:15 +03:00
|
|
|
called.add('SubClass2.random')
|
|
|
|
return random.Random.random(self)
|
|
|
|
called = set()
|
|
|
|
SubClass2().randrange(42)
|
|
|
|
self.assertEqual(called, {'SubClass2.random'})
|
2018-04-17 17:16:17 +02:00
|
|
|
|
|
|
|
# subclass defining getrandbits to complement its inherited random
|
|
|
|
# => can now rely on getrandbits for randrange again
|
|
|
|
class SubClass3(SubClass2):
|
|
|
|
def getrandbits(self, n):
|
2018-05-08 15:45:15 +03:00
|
|
|
called.add('SubClass3.getrandbits')
|
|
|
|
return random.Random.getrandbits(self, n)
|
|
|
|
called = set()
|
|
|
|
SubClass3().randrange(42)
|
|
|
|
self.assertEqual(called, {'SubClass3.getrandbits'})
|
|
|
|
|
|
|
|
# subclass providing only random and inherited getrandbits
|
|
|
|
# => random takes precedence
|
|
|
|
class SubClass4(SubClass3):
|
|
|
|
def random(self):
|
|
|
|
called.add('SubClass4.random')
|
|
|
|
return random.Random.random(self)
|
|
|
|
called = set()
|
|
|
|
SubClass4().randrange(42)
|
|
|
|
self.assertEqual(called, {'SubClass4.random'})
|
|
|
|
|
|
|
|
# Following subclasses don't define random or getrandbits directly,
|
|
|
|
# but inherit them from classes which are not subclasses of Random
|
|
|
|
class Mixin1:
|
|
|
|
def random(self):
|
|
|
|
called.add('Mixin1.random')
|
|
|
|
return random.Random.random(self)
|
|
|
|
class Mixin2:
|
|
|
|
def getrandbits(self, n):
|
|
|
|
called.add('Mixin2.getrandbits')
|
|
|
|
return random.Random.getrandbits(self, n)
|
|
|
|
|
|
|
|
class SubClass5(Mixin1, random.Random):
|
|
|
|
pass
|
|
|
|
called = set()
|
|
|
|
SubClass5().randrange(42)
|
|
|
|
self.assertEqual(called, {'Mixin1.random'})
|
|
|
|
|
|
|
|
class SubClass6(Mixin2, random.Random):
|
|
|
|
pass
|
|
|
|
called = set()
|
|
|
|
SubClass6().randrange(42)
|
|
|
|
self.assertEqual(called, {'Mixin2.getrandbits'})
|
|
|
|
|
|
|
|
class SubClass7(Mixin1, Mixin2, random.Random):
|
|
|
|
pass
|
|
|
|
called = set()
|
|
|
|
SubClass7().randrange(42)
|
|
|
|
self.assertEqual(called, {'Mixin1.random'})
|
|
|
|
|
|
|
|
class SubClass8(Mixin2, Mixin1, random.Random):
|
|
|
|
pass
|
|
|
|
called = set()
|
|
|
|
SubClass8().randrange(42)
|
|
|
|
self.assertEqual(called, {'Mixin2.getrandbits'})
|
|
|
|
|
2018-04-17 17:16:17 +02:00
|
|
|
|
2002-12-29 23:03:38 +00:00
|
|
|
class TestModule(unittest.TestCase):
|
|
|
|
def testMagicConstants(self):
|
|
|
|
self.assertAlmostEqual(random.NV_MAGICCONST, 1.71552776992141)
|
|
|
|
self.assertAlmostEqual(random.TWOPI, 6.28318530718)
|
|
|
|
self.assertAlmostEqual(random.LOG4, 1.38629436111989)
|
|
|
|
self.assertAlmostEqual(random.SG_MAGICCONST, 2.50407739677627)
|
2002-05-05 20:40:00 +00:00
|
|
|
|
2002-12-29 23:03:38 +00:00
|
|
|
def test__all__(self):
|
|
|
|
# tests validity but not completeness of the __all__ list
|
2009-06-30 23:06:06 +00:00
|
|
|
self.assertTrue(set(random.__all__) <= set(dir(random)))
|
2002-05-05 20:40:00 +00:00
|
|
|
|
2022-01-16 23:52:43 +02:00
|
|
|
@test.support.requires_fork()
|
2017-05-27 17:50:54 +02:00
|
|
|
def test_after_fork(self):
|
|
|
|
# Test the global Random instance gets reseeded in child
|
|
|
|
r, w = os.pipe()
|
2017-08-09 17:59:05 +02:00
|
|
|
pid = os.fork()
|
|
|
|
if pid == 0:
|
|
|
|
# child process
|
2017-05-27 17:50:54 +02:00
|
|
|
try:
|
|
|
|
val = random.getrandbits(128)
|
|
|
|
with open(w, "w") as f:
|
|
|
|
f.write(str(val))
|
|
|
|
finally:
|
|
|
|
os._exit(0)
|
|
|
|
else:
|
2017-08-09 17:59:05 +02:00
|
|
|
# parent process
|
2017-05-27 17:50:54 +02:00
|
|
|
os.close(w)
|
|
|
|
val = random.getrandbits(128)
|
|
|
|
with open(r, "r") as f:
|
|
|
|
child_val = eval(f.read())
|
|
|
|
self.assertNotEqual(val, child_val)
|
|
|
|
|
2020-03-31 20:08:12 +02:00
|
|
|
support.wait_process(pid, exitcode=0)
|
2017-08-09 17:59:05 +02:00
|
|
|
|
Merged revisions 53451-53537 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r53454 | brett.cannon | 2007-01-15 20:12:08 +0100 (Mon, 15 Jan 2007) | 3 lines
Add a note for strptime that just because strftime supports some extra
directive that is not documented that strptime will as well.
........
r53458 | vinay.sajip | 2007-01-16 10:50:07 +0100 (Tue, 16 Jan 2007) | 1 line
Updated rotating file handlers to use _open().
........
r53459 | marc-andre.lemburg | 2007-01-16 14:03:06 +0100 (Tue, 16 Jan 2007) | 2 lines
Add news items for the recent pybench and platform changes.
........
r53460 | sjoerd.mullender | 2007-01-16 17:42:38 +0100 (Tue, 16 Jan 2007) | 4 lines
Fixed ntpath.expandvars to not replace references to non-existing
variables with nothing. Also added tests.
This fixes bug #494589.
........
r53464 | neal.norwitz | 2007-01-17 07:23:51 +0100 (Wed, 17 Jan 2007) | 1 line
Give Calvin Spealman access for python-dev summaries.
........
r53465 | neal.norwitz | 2007-01-17 09:37:26 +0100 (Wed, 17 Jan 2007) | 1 line
Remove Calvin since he only has access to the website currently.
........
r53466 | thomas.heller | 2007-01-17 10:40:34 +0100 (Wed, 17 Jan 2007) | 2 lines
Replace C++ comments with C comments.
........
r53472 | andrew.kuchling | 2007-01-17 20:55:06 +0100 (Wed, 17 Jan 2007) | 1 line
[Part of bug #1599254] Add suggestion to Mailbox docs to use Maildir, and warn user to lock/unlock mailboxes when modifying them
........
r53475 | georg.brandl | 2007-01-17 22:09:04 +0100 (Wed, 17 Jan 2007) | 2 lines
Bug #1637967: missing //= operator in list.
........
r53477 | georg.brandl | 2007-01-17 22:19:58 +0100 (Wed, 17 Jan 2007) | 2 lines
Bug #1629125: fix wrong data type (int -> Py_ssize_t) in PyDict_Next docs.
........
r53481 | neal.norwitz | 2007-01-18 06:40:58 +0100 (Thu, 18 Jan 2007) | 1 line
Try reverting part of r53145 that seems to cause the Windows buildbots to fail in test_uu.UUFileTest.test_encode
........
r53482 | fred.drake | 2007-01-18 06:42:30 +0100 (Thu, 18 Jan 2007) | 1 line
add missing version entry
........
r53483 | neal.norwitz | 2007-01-18 07:20:55 +0100 (Thu, 18 Jan 2007) | 7 lines
This test doesn't pass on Windows. The cause seems to be that chmod
doesn't support the same funcationality as on Unix. I'm not sure if
this fix is the best (or if it will even work)--it's a test to see
if the buildbots start passing again.
It might be better to not even run this test if it's windows (or non-posix).
........
r53488 | neal.norwitz | 2007-01-19 06:53:33 +0100 (Fri, 19 Jan 2007) | 1 line
SF #1635217, Fix unbalanced paren
........
r53489 | martin.v.loewis | 2007-01-19 07:42:22 +0100 (Fri, 19 Jan 2007) | 3 lines
Prefix AST symbols with _Py_. Fixes #1637022.
Will backport.
........
r53497 | martin.v.loewis | 2007-01-19 19:01:38 +0100 (Fri, 19 Jan 2007) | 2 lines
Add UUIDs for 2.5.1 and 2.5.2
........
r53499 | raymond.hettinger | 2007-01-19 19:07:18 +0100 (Fri, 19 Jan 2007) | 1 line
SF# 1635892: Fix docs for betavariate's input parameters .
........
r53503 | martin.v.loewis | 2007-01-20 15:05:39 +0100 (Sat, 20 Jan 2007) | 2 lines
Merge 53501 and 53502 from 25 branch:
Add /GS- for AMD64 and Itanium builds where missing.
........
r53504 | walter.doerwald | 2007-01-20 18:28:31 +0100 (Sat, 20 Jan 2007) | 2 lines
Port test_resource.py to unittest.
........
r53505 | walter.doerwald | 2007-01-20 19:19:33 +0100 (Sat, 20 Jan 2007) | 2 lines
Add argument tests an calls of resource.getrusage().
........
r53506 | walter.doerwald | 2007-01-20 20:03:17 +0100 (Sat, 20 Jan 2007) | 2 lines
resource.RUSAGE_BOTH might not exist.
........
r53507 | walter.doerwald | 2007-01-21 00:07:28 +0100 (Sun, 21 Jan 2007) | 2 lines
Port test_new.py to unittest.
........
r53508 | martin.v.loewis | 2007-01-21 10:33:07 +0100 (Sun, 21 Jan 2007) | 2 lines
Patch #1610575: Add support for _Bool to struct.
........
r53509 | georg.brandl | 2007-01-21 11:28:43 +0100 (Sun, 21 Jan 2007) | 3 lines
Bug #1486663: don't reject keyword arguments for subclasses of builtin
types.
........
r53511 | georg.brandl | 2007-01-21 11:35:10 +0100 (Sun, 21 Jan 2007) | 2 lines
Patch #1627441: close sockets properly in urllib2.
........
r53517 | georg.brandl | 2007-01-22 20:40:21 +0100 (Mon, 22 Jan 2007) | 3 lines
Use new email module names (#1637162, #1637159, #1637157).
........
r53518 | andrew.kuchling | 2007-01-22 21:26:40 +0100 (Mon, 22 Jan 2007) | 1 line
Improve pattern used for mbox 'From' lines; add a simple test
........
r53519 | andrew.kuchling | 2007-01-22 21:27:50 +0100 (Mon, 22 Jan 2007) | 1 line
Make comment match the code
........
r53522 | georg.brandl | 2007-01-22 22:10:33 +0100 (Mon, 22 Jan 2007) | 2 lines
Bug #1249573: fix rfc822.parsedate not accepting a certain date format
........
r53524 | georg.brandl | 2007-01-22 22:23:41 +0100 (Mon, 22 Jan 2007) | 2 lines
Bug #1627316: handle error in condition/ignore pdb commands more gracefully.
........
r53526 | lars.gustaebel | 2007-01-23 12:17:33 +0100 (Tue, 23 Jan 2007) | 4 lines
Patch #1507247: tarfile.py: use current umask for intermediate
directories.
........
r53527 | thomas.wouters | 2007-01-23 14:42:00 +0100 (Tue, 23 Jan 2007) | 13 lines
SF patch #1630975: Fix crash when replacing sys.stdout in sitecustomize
When running the interpreter in an environment that would cause it to set
stdout/stderr/stdin's encoding, having a sitecustomize that would replace
them with something other than PyFile objects would crash the interpreter.
Fix it by simply ignoring the encoding-setting for non-files.
This could do with a test, but I can think of no maintainable and portable
way to test this bug, short of adding a sitecustomize.py to the buildsystem
and have it always run with it (hmmm....)
........
r53528 | thomas.wouters | 2007-01-23 14:50:49 +0100 (Tue, 23 Jan 2007) | 4 lines
Add news entry about last checkin (oops.)
........
r53531 | martin.v.loewis | 2007-01-23 22:11:47 +0100 (Tue, 23 Jan 2007) | 4 lines
Make PyTraceBack_Here use the current thread, not the
frame's thread state. Fixes #1579370.
Will backport.
........
r53535 | brett.cannon | 2007-01-24 00:21:22 +0100 (Wed, 24 Jan 2007) | 5 lines
Fix crasher for when an object's __del__ creates a new weakref to itself.
Patch only fixes new-style classes; classic classes still buggy.
Closes bug #1377858. Already backported.
........
r53536 | walter.doerwald | 2007-01-24 01:42:19 +0100 (Wed, 24 Jan 2007) | 2 lines
Port test_popen.py to unittest.
........
2007-02-01 18:02:27 +00:00
|
|
|
|
2024-05-05 08:30:03 +02:00
|
|
|
class CommandLineTest(unittest.TestCase):
|
2025-05-05 20:46:46 +03:00
|
|
|
@support.force_not_colorized
|
2024-05-05 08:30:03 +02:00
|
|
|
def test_parse_args(self):
|
|
|
|
args, help_text = random._parse_args(shlex.split("--choice a b c"))
|
|
|
|
self.assertEqual(args.choice, ["a", "b", "c"])
|
2025-05-22 13:17:22 +03:00
|
|
|
self.assertStartsWith(help_text, "usage: ")
|
2024-05-05 08:30:03 +02:00
|
|
|
|
|
|
|
args, help_text = random._parse_args(shlex.split("--integer 5"))
|
|
|
|
self.assertEqual(args.integer, 5)
|
2025-05-22 13:17:22 +03:00
|
|
|
self.assertStartsWith(help_text, "usage: ")
|
2024-05-05 08:30:03 +02:00
|
|
|
|
|
|
|
args, help_text = random._parse_args(shlex.split("--float 2.5"))
|
|
|
|
self.assertEqual(args.float, 2.5)
|
2025-05-22 13:17:22 +03:00
|
|
|
self.assertStartsWith(help_text, "usage: ")
|
2024-05-05 08:30:03 +02:00
|
|
|
|
|
|
|
args, help_text = random._parse_args(shlex.split("a b c"))
|
|
|
|
self.assertEqual(args.input, ["a", "b", "c"])
|
2025-05-22 13:17:22 +03:00
|
|
|
self.assertStartsWith(help_text, "usage: ")
|
2024-05-05 08:30:03 +02:00
|
|
|
|
|
|
|
args, help_text = random._parse_args(shlex.split("5"))
|
|
|
|
self.assertEqual(args.input, ["5"])
|
2025-05-22 13:17:22 +03:00
|
|
|
self.assertStartsWith(help_text, "usage: ")
|
2024-05-05 08:30:03 +02:00
|
|
|
|
|
|
|
args, help_text = random._parse_args(shlex.split("2.5"))
|
|
|
|
self.assertEqual(args.input, ["2.5"])
|
2025-05-22 13:17:22 +03:00
|
|
|
self.assertStartsWith(help_text, "usage: ")
|
2024-05-05 08:30:03 +02:00
|
|
|
|
|
|
|
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),
|
2024-09-12 06:54:18 -07:00
|
|
|
("--float 2.5", 2.1110546288126204),
|
|
|
|
("2.5", 2.1110546288126204),
|
2024-05-05 08:30:03 +02:00
|
|
|
]:
|
|
|
|
random.seed(0)
|
|
|
|
self.assertEqual(random.main(shlex.split(command)), expected)
|
|
|
|
|
|
|
|
|
2002-12-29 23:03:38 +00:00
|
|
|
if __name__ == "__main__":
|
2013-04-19 05:45:27 +03:00
|
|
|
unittest.main()
|