1 import unittest
2 import unittest.mock
3 import random
4 import os
5 import time
6 import pickle
7 import warnings
8 import test.support
9
10 from functools import partial
11 from math import log, exp, pi, fsum, sin, factorial
12 from test import support
13 from fractions import Fraction
14 from collections import abc, Counter
15
16 class ESC[4;38;5;81mTestBasicOps:
17 # Superclass with tests common to all generators.
18 # Subclasses must arrange for self.gen to retrieve the Random instance
19 # to be tested.
20
21 def randomlist(self, n):
22 """Helper function to make a list of random numbers"""
23 return [self.gen.random() for i in range(n)]
24
25 def test_autoseed(self):
26 self.gen.seed()
27 state1 = self.gen.getstate()
28 time.sleep(0.1)
29 self.gen.seed() # different seeds at different times
30 state2 = self.gen.getstate()
31 self.assertNotEqual(state1, state2)
32
33 def test_saverestore(self):
34 N = 1000
35 self.gen.seed()
36 state = self.gen.getstate()
37 randseq = self.randomlist(N)
38 self.gen.setstate(state) # should regenerate the same sequence
39 self.assertEqual(randseq, self.randomlist(N))
40
41 def test_seedargs(self):
42 # Seed value with a negative hash.
43 class ESC[4;38;5;81mMySeed(ESC[4;38;5;149mobject):
44 def __hash__(self):
45 return -1729
46 for arg in [None, 0, 1, -1, 10**20, -(10**20),
47 False, True, 3.14, 'a']:
48 self.gen.seed(arg)
49
50 for arg in [1+2j, tuple('abc'), MySeed()]:
51 with self.assertRaises(TypeError):
52 self.gen.seed(arg)
53
54 for arg in [list(range(3)), dict(one=1)]:
55 self.assertRaises(TypeError, self.gen.seed, arg)
56 self.assertRaises(TypeError, self.gen.seed, 1, 2, 3, 4)
57 self.assertRaises(TypeError, type(self.gen), [])
58
59 def test_seed_no_mutate_bug_44018(self):
60 a = bytearray(b'1234')
61 self.gen.seed(a)
62 self.assertEqual(a, bytearray(b'1234'))
63
64 @unittest.mock.patch('random._urandom') # os.urandom
65 def test_seed_when_randomness_source_not_found(self, urandom_mock):
66 # Random.seed() uses time.time() when an operating system specific
67 # randomness source is not found. To test this on machines where it
68 # exists, run the above test, test_seedargs(), again after mocking
69 # os.urandom() so that it raises the exception expected when the
70 # randomness source is not available.
71 urandom_mock.side_effect = NotImplementedError
72 self.test_seedargs()
73
74 def test_shuffle(self):
75 shuffle = self.gen.shuffle
76 lst = []
77 shuffle(lst)
78 self.assertEqual(lst, [])
79 lst = [37]
80 shuffle(lst)
81 self.assertEqual(lst, [37])
82 seqs = [list(range(n)) for n in range(10)]
83 shuffled_seqs = [list(range(n)) for n in range(10)]
84 for shuffled_seq in shuffled_seqs:
85 shuffle(shuffled_seq)
86 for (seq, shuffled_seq) in zip(seqs, shuffled_seqs):
87 self.assertEqual(len(seq), len(shuffled_seq))
88 self.assertEqual(set(seq), set(shuffled_seq))
89 # The above tests all would pass if the shuffle was a
90 # no-op. The following non-deterministic test covers that. It
91 # asserts that the shuffled sequence of 1000 distinct elements
92 # must be different from the original one. Although there is
93 # mathematically a non-zero probability that this could
94 # actually happen in a genuinely random shuffle, it is
95 # completely negligible, given that the number of possible
96 # permutations of 1000 objects is 1000! (factorial of 1000),
97 # which is considerably larger than the number of atoms in the
98 # universe...
99 lst = list(range(1000))
100 shuffled_lst = list(range(1000))
101 shuffle(shuffled_lst)
102 self.assertTrue(lst != shuffled_lst)
103 shuffle(lst)
104 self.assertTrue(lst != shuffled_lst)
105 self.assertRaises(TypeError, shuffle, (1, 2, 3))
106
107 def test_choice(self):
108 choice = self.gen.choice
109 with self.assertRaises(IndexError):
110 choice([])
111 self.assertEqual(choice([50]), 50)
112 self.assertIn(choice([25, 75]), [25, 75])
113
114 def test_choice_with_numpy(self):
115 # Accommodation for NumPy arrays which have disabled __bool__().
116 # See: https://github.com/python/cpython/issues/100805
117 choice = self.gen.choice
118
119 class ESC[4;38;5;81mNA(ESC[4;38;5;149mlist):
120 "Simulate numpy.array() behavior"
121 def __bool__(self):
122 raise RuntimeError
123
124 with self.assertRaises(IndexError):
125 choice(NA([]))
126 self.assertEqual(choice(NA([50])), 50)
127 self.assertIn(choice(NA([25, 75])), [25, 75])
128
129 def test_sample(self):
130 # For the entire allowable range of 0 <= k <= N, validate that
131 # the sample is of the correct length and contains only unique items
132 N = 100
133 population = range(N)
134 for k in range(N+1):
135 s = self.gen.sample(population, k)
136 self.assertEqual(len(s), k)
137 uniq = set(s)
138 self.assertEqual(len(uniq), k)
139 self.assertTrue(uniq <= set(population))
140 self.assertEqual(self.gen.sample([], 0), []) # test edge case N==k==0
141 # Exception raised if size of sample exceeds that of population
142 self.assertRaises(ValueError, self.gen.sample, population, N+1)
143 self.assertRaises(ValueError, self.gen.sample, [], -1)
144
145 def test_sample_distribution(self):
146 # For the entire allowable range of 0 <= k <= N, validate that
147 # sample generates all possible permutations
148 n = 5
149 pop = range(n)
150 trials = 10000 # large num prevents false negatives without slowing normal case
151 for k in range(n):
152 expected = factorial(n) // factorial(n-k)
153 perms = {}
154 for i in range(trials):
155 perms[tuple(self.gen.sample(pop, k))] = None
156 if len(perms) == expected:
157 break
158 else:
159 self.fail()
160
161 def test_sample_inputs(self):
162 # SF bug #801342 -- population can be any iterable defining __len__()
163 self.gen.sample(range(20), 2)
164 self.gen.sample(range(20), 2)
165 self.gen.sample(str('abcdefghijklmnopqrst'), 2)
166 self.gen.sample(tuple('abcdefghijklmnopqrst'), 2)
167
168 def test_sample_on_dicts(self):
169 self.assertRaises(TypeError, self.gen.sample, dict.fromkeys('abcdef'), 2)
170
171 def test_sample_on_sets(self):
172 with self.assertRaises(TypeError):
173 population = {10, 20, 30, 40, 50, 60, 70}
174 self.gen.sample(population, k=5)
175
176 def test_sample_on_seqsets(self):
177 class ESC[4;38;5;81mSeqSet(ESC[4;38;5;149mabcESC[4;38;5;149m.ESC[4;38;5;149mSequence, ESC[4;38;5;149mabcESC[4;38;5;149m.ESC[4;38;5;149mSet):
178 def __init__(self, items):
179 self._items = items
180
181 def __len__(self):
182 return len(self._items)
183
184 def __getitem__(self, index):
185 return self._items[index]
186
187 population = SeqSet([2, 4, 1, 3])
188 with warnings.catch_warnings():
189 warnings.simplefilter("error", DeprecationWarning)
190 self.gen.sample(population, k=2)
191
192 def test_sample_with_counts(self):
193 sample = self.gen.sample
194
195 # General case
196 colors = ['red', 'green', 'blue', 'orange', 'black', 'brown', 'amber']
197 counts = [500, 200, 20, 10, 5, 0, 1 ]
198 k = 700
199 summary = Counter(sample(colors, counts=counts, k=k))
200 self.assertEqual(sum(summary.values()), k)
201 for color, weight in zip(colors, counts):
202 self.assertLessEqual(summary[color], weight)
203 self.assertNotIn('brown', summary)
204
205 # Case that exhausts the population
206 k = sum(counts)
207 summary = Counter(sample(colors, counts=counts, k=k))
208 self.assertEqual(sum(summary.values()), k)
209 for color, weight in zip(colors, counts):
210 self.assertLessEqual(summary[color], weight)
211 self.assertNotIn('brown', summary)
212
213 # Case with population size of 1
214 summary = Counter(sample(['x'], counts=[10], k=8))
215 self.assertEqual(summary, Counter(x=8))
216
217 # Case with all counts equal.
218 nc = len(colors)
219 summary = Counter(sample(colors, counts=[10]*nc, k=10*nc))
220 self.assertEqual(summary, Counter(10*colors))
221
222 # Test error handling
223 with self.assertRaises(TypeError):
224 sample(['red', 'green', 'blue'], counts=10, k=10) # counts not iterable
225 with self.assertRaises(ValueError):
226 sample(['red', 'green', 'blue'], counts=[-3, -7, -8], k=2) # counts are negative
227 with self.assertRaises(ValueError):
228 sample(['red', 'green', 'blue'], counts=[0, 0, 0], k=2) # counts are zero
229 with self.assertRaises(ValueError):
230 sample(['red', 'green'], counts=[10, 10], k=21) # population too small
231 with self.assertRaises(ValueError):
232 sample(['red', 'green', 'blue'], counts=[1, 2], k=2) # too few counts
233 with self.assertRaises(ValueError):
234 sample(['red', 'green', 'blue'], counts=[1, 2, 3, 4], k=2) # too many counts
235
236 def test_choices(self):
237 choices = self.gen.choices
238 data = ['red', 'green', 'blue', 'yellow']
239 str_data = 'abcd'
240 range_data = range(4)
241 set_data = set(range(4))
242
243 # basic functionality
244 for sample in [
245 choices(data, k=5),
246 choices(data, range(4), k=5),
247 choices(k=5, population=data, weights=range(4)),
248 choices(k=5, population=data, cum_weights=range(4)),
249 ]:
250 self.assertEqual(len(sample), 5)
251 self.assertEqual(type(sample), list)
252 self.assertTrue(set(sample) <= set(data))
253
254 # test argument handling
255 with self.assertRaises(TypeError): # missing arguments
256 choices(2)
257
258 self.assertEqual(choices(data, k=0), []) # k == 0
259 self.assertEqual(choices(data, k=-1), []) # negative k behaves like ``[0] * -1``
260 with self.assertRaises(TypeError):
261 choices(data, k=2.5) # k is a float
262
263 self.assertTrue(set(choices(str_data, k=5)) <= set(str_data)) # population is a string sequence
264 self.assertTrue(set(choices(range_data, k=5)) <= set(range_data)) # population is a range
265 with self.assertRaises(TypeError):
266 choices(set_data, k=2) # population is not a sequence
267
268 self.assertTrue(set(choices(data, None, k=5)) <= set(data)) # weights is None
269 self.assertTrue(set(choices(data, weights=None, k=5)) <= set(data))
270 with self.assertRaises(ValueError):
271 choices(data, [1,2], k=5) # len(weights) != len(population)
272 with self.assertRaises(TypeError):
273 choices(data, 10, k=5) # non-iterable weights
274 with self.assertRaises(TypeError):
275 choices(data, [None]*4, k=5) # non-numeric weights
276 for weights in [
277 [15, 10, 25, 30], # integer weights
278 [15.1, 10.2, 25.2, 30.3], # float weights
279 [Fraction(1, 3), Fraction(2, 6), Fraction(3, 6), Fraction(4, 6)], # fractional weights
280 [True, False, True, False] # booleans (include / exclude)
281 ]:
282 self.assertTrue(set(choices(data, weights, k=5)) <= set(data))
283
284 with self.assertRaises(ValueError):
285 choices(data, cum_weights=[1,2], k=5) # len(weights) != len(population)
286 with self.assertRaises(TypeError):
287 choices(data, cum_weights=10, k=5) # non-iterable cum_weights
288 with self.assertRaises(TypeError):
289 choices(data, cum_weights=[None]*4, k=5) # non-numeric cum_weights
290 with self.assertRaises(TypeError):
291 choices(data, range(4), cum_weights=range(4), k=5) # both weights and cum_weights
292 for weights in [
293 [15, 10, 25, 30], # integer cum_weights
294 [15.1, 10.2, 25.2, 30.3], # float cum_weights
295 [Fraction(1, 3), Fraction(2, 6), Fraction(3, 6), Fraction(4, 6)], # fractional cum_weights
296 ]:
297 self.assertTrue(set(choices(data, cum_weights=weights, k=5)) <= set(data))
298
299 # Test weight focused on a single element of the population
300 self.assertEqual(choices('abcd', [1, 0, 0, 0]), ['a'])
301 self.assertEqual(choices('abcd', [0, 1, 0, 0]), ['b'])
302 self.assertEqual(choices('abcd', [0, 0, 1, 0]), ['c'])
303 self.assertEqual(choices('abcd', [0, 0, 0, 1]), ['d'])
304
305 # Test consistency with random.choice() for empty population
306 with self.assertRaises(IndexError):
307 choices([], k=1)
308 with self.assertRaises(IndexError):
309 choices([], weights=[], k=1)
310 with self.assertRaises(IndexError):
311 choices([], cum_weights=[], k=5)
312
313 def test_choices_subnormal(self):
314 # Subnormal weights would occasionally trigger an IndexError
315 # in choices() when the value returned by random() was large
316 # enough to make `random() * total` round up to the total.
317 # See https://bugs.python.org/msg275594 for more detail.
318 choices = self.gen.choices
319 choices(population=[1, 2], weights=[1e-323, 1e-323], k=5000)
320
321 def test_choices_with_all_zero_weights(self):
322 # See issue #38881
323 with self.assertRaises(ValueError):
324 self.gen.choices('AB', [0.0, 0.0])
325
326 def test_choices_negative_total(self):
327 with self.assertRaises(ValueError):
328 self.gen.choices('ABC', [3, -5, 1])
329
330 def test_choices_infinite_total(self):
331 with self.assertRaises(ValueError):
332 self.gen.choices('A', [float('inf')])
333 with self.assertRaises(ValueError):
334 self.gen.choices('AB', [0.0, float('inf')])
335 with self.assertRaises(ValueError):
336 self.gen.choices('AB', [-float('inf'), 123])
337 with self.assertRaises(ValueError):
338 self.gen.choices('AB', [0.0, float('nan')])
339 with self.assertRaises(ValueError):
340 self.gen.choices('AB', [float('-inf'), float('inf')])
341
342 def test_gauss(self):
343 # Ensure that the seed() method initializes all the hidden state. In
344 # particular, through 2.2.1 it failed to reset a piece of state used
345 # by (and only by) the .gauss() method.
346
347 for seed in 1, 12, 123, 1234, 12345, 123456, 654321:
348 self.gen.seed(seed)
349 x1 = self.gen.random()
350 y1 = self.gen.gauss(0, 1)
351
352 self.gen.seed(seed)
353 x2 = self.gen.random()
354 y2 = self.gen.gauss(0, 1)
355
356 self.assertEqual(x1, x2)
357 self.assertEqual(y1, y2)
358
359 def test_getrandbits(self):
360 # Verify ranges
361 for k in range(1, 1000):
362 self.assertTrue(0 <= self.gen.getrandbits(k) < 2**k)
363 self.assertEqual(self.gen.getrandbits(0), 0)
364
365 # Verify all bits active
366 getbits = self.gen.getrandbits
367 for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]:
368 all_bits = 2**span-1
369 cum = 0
370 cpl_cum = 0
371 for i in range(100):
372 v = getbits(span)
373 cum |= v
374 cpl_cum |= all_bits ^ v
375 self.assertEqual(cum, all_bits)
376 self.assertEqual(cpl_cum, all_bits)
377
378 # Verify argument checking
379 self.assertRaises(TypeError, self.gen.getrandbits)
380 self.assertRaises(TypeError, self.gen.getrandbits, 1, 2)
381 self.assertRaises(ValueError, self.gen.getrandbits, -1)
382 self.assertRaises(TypeError, self.gen.getrandbits, 10.1)
383
384 def test_pickling(self):
385 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
386 state = pickle.dumps(self.gen, proto)
387 origseq = [self.gen.random() for i in range(10)]
388 newgen = pickle.loads(state)
389 restoredseq = [newgen.random() for i in range(10)]
390 self.assertEqual(origseq, restoredseq)
391
392 def test_bug_1727780(self):
393 # verify that version-2-pickles can be loaded
394 # fine, whether they are created on 32-bit or 64-bit
395 # platforms, and that version-3-pickles load fine.
396 files = [("randv2_32.pck", 780),
397 ("randv2_64.pck", 866),
398 ("randv3.pck", 343)]
399 for file, value in files:
400 with open(support.findfile(file),"rb") as f:
401 r = pickle.load(f)
402 self.assertEqual(int(r.random()*1000), value)
403
404 def test_bug_9025(self):
405 # Had problem with an uneven distribution in int(n*random())
406 # Verify the fix by checking that distributions fall within expectations.
407 n = 100000
408 randrange = self.gen.randrange
409 k = sum(randrange(6755399441055744) % 3 == 2 for i in range(n))
410 self.assertTrue(0.30 < k/n < .37, (k/n))
411
412 def test_randbytes(self):
413 # Verify ranges
414 for n in range(1, 10):
415 data = self.gen.randbytes(n)
416 self.assertEqual(type(data), bytes)
417 self.assertEqual(len(data), n)
418
419 self.assertEqual(self.gen.randbytes(0), b'')
420
421 # Verify argument checking
422 self.assertRaises(TypeError, self.gen.randbytes)
423 self.assertRaises(TypeError, self.gen.randbytes, 1, 2)
424 self.assertRaises(ValueError, self.gen.randbytes, -1)
425 self.assertRaises(TypeError, self.gen.randbytes, 1.0)
426
427 def test_mu_sigma_default_args(self):
428 self.assertIsInstance(self.gen.normalvariate(), float)
429 self.assertIsInstance(self.gen.gauss(), float)
430
431
432 try:
433 random.SystemRandom().random()
434 except NotImplementedError:
435 SystemRandom_available = False
436 else:
437 SystemRandom_available = True
438
439 @unittest.skipUnless(SystemRandom_available, "random.SystemRandom not available")
440 class ESC[4;38;5;81mSystemRandom_TestBasicOps(ESC[4;38;5;149mTestBasicOps, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
441 gen = random.SystemRandom()
442
443 def test_autoseed(self):
444 # Doesn't need to do anything except not fail
445 self.gen.seed()
446
447 def test_saverestore(self):
448 self.assertRaises(NotImplementedError, self.gen.getstate)
449 self.assertRaises(NotImplementedError, self.gen.setstate, None)
450
451 def test_seedargs(self):
452 # Doesn't need to do anything except not fail
453 self.gen.seed(100)
454
455 def test_gauss(self):
456 self.gen.gauss_next = None
457 self.gen.seed(100)
458 self.assertEqual(self.gen.gauss_next, None)
459
460 def test_pickling(self):
461 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
462 self.assertRaises(NotImplementedError, pickle.dumps, self.gen, proto)
463
464 def test_53_bits_per_float(self):
465 # This should pass whenever a C double has 53 bit precision.
466 span = 2 ** 53
467 cum = 0
468 for i in range(100):
469 cum |= int(self.gen.random() * span)
470 self.assertEqual(cum, span-1)
471
472 def test_bigrand(self):
473 # The randrange routine should build-up the required number of bits
474 # in stages so that all bit positions are active.
475 span = 2 ** 500
476 cum = 0
477 for i in range(100):
478 r = self.gen.randrange(span)
479 self.assertTrue(0 <= r < span)
480 cum |= r
481 self.assertEqual(cum, span-1)
482
483 def test_bigrand_ranges(self):
484 for i in [40,80, 160, 200, 211, 250, 375, 512, 550]:
485 start = self.gen.randrange(2 ** (i-2))
486 stop = self.gen.randrange(2 ** i)
487 if stop <= start:
488 continue
489 self.assertTrue(start <= self.gen.randrange(start, stop) < stop)
490
491 def test_rangelimits(self):
492 for start, stop in [(-2,0), (-(2**60)-2,-(2**60)), (2**60,2**60+2)]:
493 self.assertEqual(set(range(start,stop)),
494 set([self.gen.randrange(start,stop) for i in range(100)]))
495
496 def test_randrange_nonunit_step(self):
497 rint = self.gen.randrange(0, 10, 2)
498 self.assertIn(rint, (0, 2, 4, 6, 8))
499 rint = self.gen.randrange(0, 2, 2)
500 self.assertEqual(rint, 0)
501
502 def test_randrange_errors(self):
503 raises_value_error = partial(self.assertRaises, ValueError, self.gen.randrange)
504 raises_type_error = partial(self.assertRaises, TypeError, self.gen.randrange)
505
506 # Empty range
507 raises_value_error(3, 3)
508 raises_value_error(-721)
509 raises_value_error(0, 100, -12)
510
511 # Zero step
512 raises_value_error(0, 42, 0)
513 raises_type_error(0, 42, 0.0)
514 raises_type_error(0, 0, 0.0)
515
516 # Non-integer stop
517 raises_type_error(3.14159)
518 raises_type_error(3.0)
519 raises_type_error(Fraction(3, 1))
520 raises_type_error('3')
521 raises_type_error(0, 2.71827)
522 raises_type_error(0, 2.0)
523 raises_type_error(0, Fraction(2, 1))
524 raises_type_error(0, '2')
525 raises_type_error(0, 2.71827, 2)
526
527 # Non-integer start
528 raises_type_error(2.71827, 5)
529 raises_type_error(2.0, 5)
530 raises_type_error(Fraction(2, 1), 5)
531 raises_type_error('2', 5)
532 raises_type_error(2.71827, 5, 2)
533
534 # Non-integer step
535 raises_type_error(0, 42, 3.14159)
536 raises_type_error(0, 42, 3.0)
537 raises_type_error(0, 42, Fraction(3, 1))
538 raises_type_error(0, 42, '3')
539 raises_type_error(0, 42, 1.0)
540 raises_type_error(0, 0, 1.0)
541
542 def test_randrange_step(self):
543 # bpo-42772: When stop is None, the step argument was being ignored.
544 randrange = self.gen.randrange
545 with self.assertRaises(TypeError):
546 randrange(1000, step=100)
547 with self.assertRaises(TypeError):
548 randrange(1000, None, step=100)
549
550 def test_randbelow_logic(self, _log=log, int=int):
551 # check bitcount transition points: 2**i and 2**(i+1)-1
552 # show that: k = int(1.001 + _log(n, 2))
553 # is equal to or one greater than the number of bits in n
554 for i in range(1, 1000):
555 n = 1 << i # check an exact power of two
556 numbits = i+1
557 k = int(1.00001 + _log(n, 2))
558 self.assertEqual(k, numbits)
559 self.assertEqual(n, 2**(k-1))
560
561 n += n - 1 # check 1 below the next power of two
562 k = int(1.00001 + _log(n, 2))
563 self.assertIn(k, [numbits, numbits+1])
564 self.assertTrue(2**k > n > 2**(k-2))
565
566 n -= n >> 15 # check a little farther below the next power of two
567 k = int(1.00001 + _log(n, 2))
568 self.assertEqual(k, numbits) # note the stronger assertion
569 self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion
570
571
572 class ESC[4;38;5;81mTestRawMersenneTwister(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
573 @test.support.cpython_only
574 def test_bug_41052(self):
575 # _random.Random should not be allowed to serialization
576 import _random
577 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
578 r = _random.Random()
579 self.assertRaises(TypeError, pickle.dumps, r, proto)
580
581 @test.support.cpython_only
582 def test_bug_42008(self):
583 # _random.Random should call seed with first element of arg tuple
584 import _random
585 r1 = _random.Random()
586 r1.seed(8675309)
587 r2 = _random.Random(8675309)
588 self.assertEqual(r1.random(), r2.random())
589
590
591 class ESC[4;38;5;81mMersenneTwister_TestBasicOps(ESC[4;38;5;149mTestBasicOps, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
592 gen = random.Random()
593
594 def test_guaranteed_stable(self):
595 # These sequences are guaranteed to stay the same across versions of python
596 self.gen.seed(3456147, version=1)
597 self.assertEqual([self.gen.random().hex() for i in range(4)],
598 ['0x1.ac362300d90d2p-1', '0x1.9d16f74365005p-1',
599 '0x1.1ebb4352e4c4dp-1', '0x1.1a7422abf9c11p-1'])
600 self.gen.seed("the quick brown fox", version=2)
601 self.assertEqual([self.gen.random().hex() for i in range(4)],
602 ['0x1.1239ddfb11b7cp-3', '0x1.b3cbb5c51b120p-4',
603 '0x1.8c4f55116b60fp-1', '0x1.63eb525174a27p-1'])
604
605 def test_bug_27706(self):
606 # Verify that version 1 seeds are unaffected by hash randomization
607
608 self.gen.seed('nofar', version=1) # hash('nofar') == 5990528763808513177
609 self.assertEqual([self.gen.random().hex() for i in range(4)],
610 ['0x1.8645314505ad7p-1', '0x1.afb1f82e40a40p-5',
611 '0x1.2a59d2285e971p-1', '0x1.56977142a7880p-6'])
612
613 self.gen.seed('rachel', version=1) # hash('rachel') == -9091735575445484789
614 self.assertEqual([self.gen.random().hex() for i in range(4)],
615 ['0x1.0b294cc856fcdp-1', '0x1.2ad22d79e77b8p-3',
616 '0x1.3052b9c072678p-2', '0x1.578f332106574p-3'])
617
618 self.gen.seed('', version=1) # hash('') == 0
619 self.assertEqual([self.gen.random().hex() for i in range(4)],
620 ['0x1.b0580f98a7dbep-1', '0x1.84129978f9c1ap-1',
621 '0x1.aeaa51052e978p-2', '0x1.092178fb945a6p-2'])
622
623 def test_bug_31478(self):
624 # There shouldn't be an assertion failure in _random.Random.seed() in
625 # case the argument has a bad __abs__() method.
626 class ESC[4;38;5;81mBadInt(ESC[4;38;5;149mint):
627 def __abs__(self):
628 return None
629 try:
630 self.gen.seed(BadInt())
631 except TypeError:
632 pass
633
634 def test_bug_31482(self):
635 # Verify that version 1 seeds are unaffected by hash randomization
636 # when the seeds are expressed as bytes rather than strings.
637 # The hash(b) values listed are the Python2.7 hash() values
638 # which were used for seeding.
639
640 self.gen.seed(b'nofar', version=1) # hash('nofar') == 5990528763808513177
641 self.assertEqual([self.gen.random().hex() for i in range(4)],
642 ['0x1.8645314505ad7p-1', '0x1.afb1f82e40a40p-5',
643 '0x1.2a59d2285e971p-1', '0x1.56977142a7880p-6'])
644
645 self.gen.seed(b'rachel', version=1) # hash('rachel') == -9091735575445484789
646 self.assertEqual([self.gen.random().hex() for i in range(4)],
647 ['0x1.0b294cc856fcdp-1', '0x1.2ad22d79e77b8p-3',
648 '0x1.3052b9c072678p-2', '0x1.578f332106574p-3'])
649
650 self.gen.seed(b'', version=1) # hash('') == 0
651 self.assertEqual([self.gen.random().hex() for i in range(4)],
652 ['0x1.b0580f98a7dbep-1', '0x1.84129978f9c1ap-1',
653 '0x1.aeaa51052e978p-2', '0x1.092178fb945a6p-2'])
654
655 b = b'\x00\x20\x40\x60\x80\xA0\xC0\xE0\xF0'
656 self.gen.seed(b, version=1) # hash(b) == 5015594239749365497
657 self.assertEqual([self.gen.random().hex() for i in range(4)],
658 ['0x1.52c2fde444d23p-1', '0x1.875174f0daea4p-2',
659 '0x1.9e9b2c50e5cd2p-1', '0x1.fa57768bd321cp-2'])
660
661 def test_setstate_first_arg(self):
662 self.assertRaises(ValueError, self.gen.setstate, (1, None, None))
663
664 def test_setstate_middle_arg(self):
665 start_state = self.gen.getstate()
666 # Wrong type, s/b tuple
667 self.assertRaises(TypeError, self.gen.setstate, (2, None, None))
668 # Wrong length, s/b 625
669 self.assertRaises(ValueError, self.gen.setstate, (2, (1,2,3), None))
670 # Wrong type, s/b tuple of 625 ints
671 self.assertRaises(TypeError, self.gen.setstate, (2, ('a',)*625, None))
672 # Last element s/b an int also
673 self.assertRaises(TypeError, self.gen.setstate, (2, (0,)*624+('a',), None))
674 # Last element s/b between 0 and 624
675 with self.assertRaises((ValueError, OverflowError)):
676 self.gen.setstate((2, (1,)*624+(625,), None))
677 with self.assertRaises((ValueError, OverflowError)):
678 self.gen.setstate((2, (1,)*624+(-1,), None))
679 # Failed calls to setstate() should not have changed the state.
680 bits100 = self.gen.getrandbits(100)
681 self.gen.setstate(start_state)
682 self.assertEqual(self.gen.getrandbits(100), bits100)
683
684 # Little trick to make "tuple(x % (2**32) for x in internalstate)"
685 # raise ValueError. I cannot think of a simple way to achieve this, so
686 # I am opting for using a generator as the middle argument of setstate
687 # which attempts to cast a NaN to integer.
688 state_values = self.gen.getstate()[1]
689 state_values = list(state_values)
690 state_values[-1] = float('nan')
691 state = (int(x) for x in state_values)
692 self.assertRaises(TypeError, self.gen.setstate, (2, state, None))
693
694 def test_referenceImplementation(self):
695 # Compare the python implementation with results from the original
696 # code. Create 2000 53-bit precision random floats. Compare only
697 # the last ten entries to show that the independent implementations
698 # are tracking. Here is the main() function needed to create the
699 # list of expected random numbers:
700 # void main(void){
701 # int i;
702 # unsigned long init[4]={61731, 24903, 614, 42143}, length=4;
703 # init_by_array(init, length);
704 # for (i=0; i<2000; i++) {
705 # printf("%.15f ", genrand_res53());
706 # if (i%5==4) printf("\n");
707 # }
708 # }
709 expected = [0.45839803073713259,
710 0.86057815201978782,
711 0.92848331726782152,
712 0.35932681119782461,
713 0.081823493762449573,
714 0.14332226470169329,
715 0.084297823823520024,
716 0.53814864671831453,
717 0.089215024911993401,
718 0.78486196105372907]
719
720 self.gen.seed(61731 + (24903<<32) + (614<<64) + (42143<<96))
721 actual = self.randomlist(2000)[-10:]
722 for a, e in zip(actual, expected):
723 self.assertAlmostEqual(a,e,places=14)
724
725 def test_strong_reference_implementation(self):
726 # Like test_referenceImplementation, but checks for exact bit-level
727 # equality. This should pass on any box where C double contains
728 # at least 53 bits of precision (the underlying algorithm suffers
729 # no rounding errors -- all results are exact).
730 from math import ldexp
731
732 expected = [0x0eab3258d2231f,
733 0x1b89db315277a5,
734 0x1db622a5518016,
735 0x0b7f9af0d575bf,
736 0x029e4c4db82240,
737 0x04961892f5d673,
738 0x02b291598e4589,
739 0x11388382c15694,
740 0x02dad977c9e1fe,
741 0x191d96d4d334c6]
742 self.gen.seed(61731 + (24903<<32) + (614<<64) + (42143<<96))
743 actual = self.randomlist(2000)[-10:]
744 for a, e in zip(actual, expected):
745 self.assertEqual(int(ldexp(a, 53)), e)
746
747 def test_long_seed(self):
748 # This is most interesting to run in debug mode, just to make sure
749 # nothing blows up. Under the covers, a dynamically resized array
750 # is allocated, consuming space proportional to the number of bits
751 # in the seed. Unfortunately, that's a quadratic-time algorithm,
752 # so don't make this horribly big.
753 seed = (1 << (10000 * 8)) - 1 # about 10K bytes
754 self.gen.seed(seed)
755
756 def test_53_bits_per_float(self):
757 # This should pass whenever a C double has 53 bit precision.
758 span = 2 ** 53
759 cum = 0
760 for i in range(100):
761 cum |= int(self.gen.random() * span)
762 self.assertEqual(cum, span-1)
763
764 def test_bigrand(self):
765 # The randrange routine should build-up the required number of bits
766 # in stages so that all bit positions are active.
767 span = 2 ** 500
768 cum = 0
769 for i in range(100):
770 r = self.gen.randrange(span)
771 self.assertTrue(0 <= r < span)
772 cum |= r
773 self.assertEqual(cum, span-1)
774
775 def test_bigrand_ranges(self):
776 for i in [40,80, 160, 200, 211, 250, 375, 512, 550]:
777 start = self.gen.randrange(2 ** (i-2))
778 stop = self.gen.randrange(2 ** i)
779 if stop <= start:
780 continue
781 self.assertTrue(start <= self.gen.randrange(start, stop) < stop)
782
783 def test_rangelimits(self):
784 for start, stop in [(-2,0), (-(2**60)-2,-(2**60)), (2**60,2**60+2)]:
785 self.assertEqual(set(range(start,stop)),
786 set([self.gen.randrange(start,stop) for i in range(100)]))
787
788 def test_getrandbits(self):
789 super().test_getrandbits()
790
791 # Verify cross-platform repeatability
792 self.gen.seed(1234567)
793 self.assertEqual(self.gen.getrandbits(100),
794 97904845777343510404718956115)
795
796 def test_randrange_uses_getrandbits(self):
797 # Verify use of getrandbits by randrange
798 # Use same seed as in the cross-platform repeatability test
799 # in test_getrandbits above.
800 self.gen.seed(1234567)
801 # If randrange uses getrandbits, it should pick getrandbits(100)
802 # when called with a 100-bits stop argument.
803 self.assertEqual(self.gen.randrange(2**99),
804 97904845777343510404718956115)
805
806 def test_randbelow_logic(self, _log=log, int=int):
807 # check bitcount transition points: 2**i and 2**(i+1)-1
808 # show that: k = int(1.001 + _log(n, 2))
809 # is equal to or one greater than the number of bits in n
810 for i in range(1, 1000):
811 n = 1 << i # check an exact power of two
812 numbits = i+1
813 k = int(1.00001 + _log(n, 2))
814 self.assertEqual(k, numbits)
815 self.assertEqual(n, 2**(k-1))
816
817 n += n - 1 # check 1 below the next power of two
818 k = int(1.00001 + _log(n, 2))
819 self.assertIn(k, [numbits, numbits+1])
820 self.assertTrue(2**k > n > 2**(k-2))
821
822 n -= n >> 15 # check a little farther below the next power of two
823 k = int(1.00001 + _log(n, 2))
824 self.assertEqual(k, numbits) # note the stronger assertion
825 self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion
826
827 def test_randbelow_without_getrandbits(self):
828 # Random._randbelow() can only use random() when the built-in one
829 # has been overridden but no new getrandbits() method was supplied.
830 maxsize = 1<<random.BPF
831 with warnings.catch_warnings():
832 warnings.simplefilter("ignore", UserWarning)
833 # Population range too large (n >= maxsize)
834 self.gen._randbelow_without_getrandbits(
835 maxsize+1, maxsize=maxsize
836 )
837 self.gen._randbelow_without_getrandbits(5640, maxsize=maxsize)
838
839 # This might be going too far to test a single line, but because of our
840 # noble aim of achieving 100% test coverage we need to write a case in
841 # which the following line in Random._randbelow() gets executed:
842 #
843 # rem = maxsize % n
844 # limit = (maxsize - rem) / maxsize
845 # r = random()
846 # while r >= limit:
847 # r = random() # <== *This line* <==<
848 #
849 # Therefore, to guarantee that the while loop is executed at least
850 # once, we need to mock random() so that it returns a number greater
851 # than 'limit' the first time it gets called.
852
853 n = 42
854 epsilon = 0.01
855 limit = (maxsize - (maxsize % n)) / maxsize
856 with unittest.mock.patch.object(random.Random, 'random') as random_mock:
857 random_mock.side_effect = [limit + epsilon, limit - epsilon]
858 self.gen._randbelow_without_getrandbits(n, maxsize=maxsize)
859 self.assertEqual(random_mock.call_count, 2)
860
861 def test_randrange_bug_1590891(self):
862 start = 1000000000000
863 stop = -100000000000000000000
864 step = -200
865 x = self.gen.randrange(start, stop, step)
866 self.assertTrue(stop < x <= start)
867 self.assertEqual((x+stop)%step, 0)
868
869 def test_choices_algorithms(self):
870 # The various ways of specifying weights should produce the same results
871 choices = self.gen.choices
872 n = 104729
873
874 self.gen.seed(8675309)
875 a = self.gen.choices(range(n), k=10000)
876
877 self.gen.seed(8675309)
878 b = self.gen.choices(range(n), [1]*n, k=10000)
879 self.assertEqual(a, b)
880
881 self.gen.seed(8675309)
882 c = self.gen.choices(range(n), cum_weights=range(1, n+1), k=10000)
883 self.assertEqual(a, c)
884
885 # American Roulette
886 population = ['Red', 'Black', 'Green']
887 weights = [18, 18, 2]
888 cum_weights = [18, 36, 38]
889 expanded_population = ['Red'] * 18 + ['Black'] * 18 + ['Green'] * 2
890
891 self.gen.seed(9035768)
892 a = self.gen.choices(expanded_population, k=10000)
893
894 self.gen.seed(9035768)
895 b = self.gen.choices(population, weights, k=10000)
896 self.assertEqual(a, b)
897
898 self.gen.seed(9035768)
899 c = self.gen.choices(population, cum_weights=cum_weights, k=10000)
900 self.assertEqual(a, c)
901
902 def test_randbytes(self):
903 super().test_randbytes()
904
905 # Mersenne Twister randbytes() is deterministic
906 # and does not depend on the endian and bitness.
907 seed = 8675309
908 expected = b'3\xa8\xf9f\xf4\xa4\xd06\x19\x8f\x9f\x82\x02oe\xf0'
909
910 self.gen.seed(seed)
911 self.assertEqual(self.gen.randbytes(16), expected)
912
913 # randbytes(0) must not consume any entropy
914 self.gen.seed(seed)
915 self.assertEqual(self.gen.randbytes(0), b'')
916 self.assertEqual(self.gen.randbytes(16), expected)
917
918 # Four randbytes(4) calls give the same output than randbytes(16)
919 self.gen.seed(seed)
920 self.assertEqual(b''.join([self.gen.randbytes(4) for _ in range(4)]),
921 expected)
922
923 # Each randbytes(1), randbytes(2) or randbytes(3) call consumes
924 # 4 bytes of entropy
925 self.gen.seed(seed)
926 expected1 = expected[3::4]
927 self.assertEqual(b''.join(self.gen.randbytes(1) for _ in range(4)),
928 expected1)
929
930 self.gen.seed(seed)
931 expected2 = b''.join(expected[i + 2: i + 4]
932 for i in range(0, len(expected), 4))
933 self.assertEqual(b''.join(self.gen.randbytes(2) for _ in range(4)),
934 expected2)
935
936 self.gen.seed(seed)
937 expected3 = b''.join(expected[i + 1: i + 4]
938 for i in range(0, len(expected), 4))
939 self.assertEqual(b''.join(self.gen.randbytes(3) for _ in range(4)),
940 expected3)
941
942 def test_randbytes_getrandbits(self):
943 # There is a simple relation between randbytes() and getrandbits()
944 seed = 2849427419
945 gen2 = random.Random()
946 self.gen.seed(seed)
947 gen2.seed(seed)
948 for n in range(9):
949 self.assertEqual(self.gen.randbytes(n),
950 gen2.getrandbits(n * 8).to_bytes(n, 'little'))
951
952 def test_sample_counts_equivalence(self):
953 # Test the documented strong equivalence to a sample with repeated elements.
954 # We run this test on random.Random() which makes deterministic selections
955 # for a given seed value.
956 sample = self.gen.sample
957 seed = self.gen.seed
958
959 colors = ['red', 'green', 'blue', 'orange', 'black', 'amber']
960 counts = [500, 200, 20, 10, 5, 1 ]
961 k = 700
962 seed(8675309)
963 s1 = sample(colors, counts=counts, k=k)
964 seed(8675309)
965 expanded = [color for (color, count) in zip(colors, counts) for i in range(count)]
966 self.assertEqual(len(expanded), sum(counts))
967 s2 = sample(expanded, k=k)
968 self.assertEqual(s1, s2)
969
970 pop = 'abcdefghi'
971 counts = [10, 9, 8, 7, 6, 5, 4, 3, 2]
972 seed(8675309)
973 s1 = ''.join(sample(pop, counts=counts, k=30))
974 expanded = ''.join([letter for (letter, count) in zip(pop, counts) for i in range(count)])
975 seed(8675309)
976 s2 = ''.join(sample(expanded, k=30))
977 self.assertEqual(s1, s2)
978
979
980 def gamma(z, sqrt2pi=(2.0*pi)**0.5):
981 # Reflection to right half of complex plane
982 if z < 0.5:
983 return pi / sin(pi*z) / gamma(1.0-z)
984 # Lanczos approximation with g=7
985 az = z + (7.0 - 0.5)
986 return az ** (z-0.5) / exp(az) * sqrt2pi * fsum([
987 0.9999999999995183,
988 676.5203681218835 / z,
989 -1259.139216722289 / (z+1.0),
990 771.3234287757674 / (z+2.0),
991 -176.6150291498386 / (z+3.0),
992 12.50734324009056 / (z+4.0),
993 -0.1385710331296526 / (z+5.0),
994 0.9934937113930748e-05 / (z+6.0),
995 0.1659470187408462e-06 / (z+7.0),
996 ])
997
998 class ESC[4;38;5;81mTestDistributions(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
999 def test_zeroinputs(self):
1000 # Verify that distributions can handle a series of zero inputs'
1001 g = random.Random()
1002 x = [g.random() for i in range(50)] + [0.0]*5
1003 g.random = x[:].pop; g.uniform(1,10)
1004 g.random = x[:].pop; g.paretovariate(1.0)
1005 g.random = x[:].pop; g.expovariate(1.0)
1006 g.random = x[:].pop; g.expovariate()
1007 g.random = x[:].pop; g.weibullvariate(1.0, 1.0)
1008 g.random = x[:].pop; g.vonmisesvariate(1.0, 1.0)
1009 g.random = x[:].pop; g.normalvariate(0.0, 1.0)
1010 g.random = x[:].pop; g.gauss(0.0, 1.0)
1011 g.random = x[:].pop; g.lognormvariate(0.0, 1.0)
1012 g.random = x[:].pop; g.vonmisesvariate(0.0, 1.0)
1013 g.random = x[:].pop; g.gammavariate(0.01, 1.0)
1014 g.random = x[:].pop; g.gammavariate(1.0, 1.0)
1015 g.random = x[:].pop; g.gammavariate(200.0, 1.0)
1016 g.random = x[:].pop; g.betavariate(3.0, 3.0)
1017 g.random = x[:].pop; g.triangular(0.0, 1.0, 1.0/3.0)
1018
1019 def test_avg_std(self):
1020 # Use integration to test distribution average and standard deviation.
1021 # Only works for distributions which do not consume variates in pairs
1022 g = random.Random()
1023 N = 5000
1024 x = [i/float(N) for i in range(1,N)]
1025 for variate, args, mu, sigmasqrd in [
1026 (g.uniform, (1.0,10.0), (10.0+1.0)/2, (10.0-1.0)**2/12),
1027 (g.triangular, (0.0, 1.0, 1.0/3.0), 4.0/9.0, 7.0/9.0/18.0),
1028 (g.expovariate, (1.5,), 1/1.5, 1/1.5**2),
1029 (g.vonmisesvariate, (1.23, 0), pi, pi**2/3),
1030 (g.paretovariate, (5.0,), 5.0/(5.0-1),
1031 5.0/((5.0-1)**2*(5.0-2))),
1032 (g.weibullvariate, (1.0, 3.0), gamma(1+1/3.0),
1033 gamma(1+2/3.0)-gamma(1+1/3.0)**2) ]:
1034 g.random = x[:].pop
1035 y = []
1036 for i in range(len(x)):
1037 try:
1038 y.append(variate(*args))
1039 except IndexError:
1040 pass
1041 s1 = s2 = 0
1042 for e in y:
1043 s1 += e
1044 s2 += (e - mu) ** 2
1045 N = len(y)
1046 self.assertAlmostEqual(s1/N, mu, places=2,
1047 msg='%s%r' % (variate.__name__, args))
1048 self.assertAlmostEqual(s2/(N-1), sigmasqrd, places=2,
1049 msg='%s%r' % (variate.__name__, args))
1050
1051 def test_constant(self):
1052 g = random.Random()
1053 N = 100
1054 for variate, args, expected in [
1055 (g.uniform, (10.0, 10.0), 10.0),
1056 (g.triangular, (10.0, 10.0), 10.0),
1057 (g.triangular, (10.0, 10.0, 10.0), 10.0),
1058 (g.expovariate, (float('inf'),), 0.0),
1059 (g.vonmisesvariate, (3.0, float('inf')), 3.0),
1060 (g.gauss, (10.0, 0.0), 10.0),
1061 (g.lognormvariate, (0.0, 0.0), 1.0),
1062 (g.lognormvariate, (-float('inf'), 0.0), 0.0),
1063 (g.normalvariate, (10.0, 0.0), 10.0),
1064 (g.binomialvariate, (0, 0.5), 0),
1065 (g.binomialvariate, (10, 0.0), 0),
1066 (g.binomialvariate, (10, 1.0), 10),
1067 (g.paretovariate, (float('inf'),), 1.0),
1068 (g.weibullvariate, (10.0, float('inf')), 10.0),
1069 (g.weibullvariate, (0.0, 10.0), 0.0),
1070 ]:
1071 for i in range(N):
1072 self.assertEqual(variate(*args), expected)
1073
1074 def test_binomialvariate(self):
1075 B = random.binomialvariate
1076
1077 # Cover all the code paths
1078 with self.assertRaises(ValueError):
1079 B(n=-1) # Negative n
1080 with self.assertRaises(ValueError):
1081 B(n=1, p=-0.5) # Negative p
1082 with self.assertRaises(ValueError):
1083 B(n=1, p=1.5) # p > 1.0
1084 self.assertEqual(B(10, 0.0), 0) # p == 0.0
1085 self.assertEqual(B(10, 1.0), 10) # p == 1.0
1086 self.assertTrue(B(1, 0.3) in {0, 1}) # n == 1 fast path
1087 self.assertTrue(B(1, 0.9) in {0, 1}) # n == 1 fast path
1088 self.assertTrue(B(1, 0.0) in {0}) # n == 1 fast path
1089 self.assertTrue(B(1, 1.0) in {1}) # n == 1 fast path
1090
1091 # BG method p <= 0.5 and n*p=1.25
1092 self.assertTrue(B(5, 0.25) in set(range(6)))
1093
1094 # BG method p >= 0.5 and n*(1-p)=1.25
1095 self.assertTrue(B(5, 0.75) in set(range(6)))
1096
1097 # BTRS method p <= 0.5 and n*p=25
1098 self.assertTrue(B(100, 0.25) in set(range(101)))
1099
1100 # BTRS method p > 0.5 and n*(1-p)=25
1101 self.assertTrue(B(100, 0.75) in set(range(101)))
1102
1103 # Statistical tests chosen such that they are
1104 # exceedingly unlikely to ever fail for correct code.
1105
1106 # BG code path
1107 # Expected dist: [31641, 42188, 21094, 4688, 391]
1108 c = Counter(B(4, 0.25) for i in range(100_000))
1109 self.assertTrue(29_641 <= c[0] <= 33_641, c)
1110 self.assertTrue(40_188 <= c[1] <= 44_188)
1111 self.assertTrue(19_094 <= c[2] <= 23_094)
1112 self.assertTrue(2_688 <= c[3] <= 6_688)
1113 self.assertEqual(set(c), {0, 1, 2, 3, 4})
1114
1115 # BTRS code path
1116 # Sum of c[20], c[21], c[22], c[23], c[24] expected to be 36,214
1117 c = Counter(B(100, 0.25) for i in range(100_000))
1118 self.assertTrue(34_214 <= c[20]+c[21]+c[22]+c[23]+c[24] <= 38_214)
1119 self.assertTrue(set(c) <= set(range(101)))
1120 self.assertEqual(c.total(), 100_000)
1121
1122 # Demonstrate the BTRS works for huge values of n
1123 self.assertTrue(19_000_000 <= B(100_000_000, 0.2) <= 21_000_000)
1124 self.assertTrue(89_000_000 <= B(100_000_000, 0.9) <= 91_000_000)
1125
1126
1127 def test_von_mises_range(self):
1128 # Issue 17149: von mises variates were not consistently in the
1129 # range [0, 2*PI].
1130 g = random.Random()
1131 N = 100
1132 for mu in 0.0, 0.1, 3.1, 6.2:
1133 for kappa in 0.0, 2.3, 500.0:
1134 for _ in range(N):
1135 sample = g.vonmisesvariate(mu, kappa)
1136 self.assertTrue(
1137 0 <= sample <= random.TWOPI,
1138 msg=("vonmisesvariate({}, {}) produced a result {} out"
1139 " of range [0, 2*pi]").format(mu, kappa, sample))
1140
1141 def test_von_mises_large_kappa(self):
1142 # Issue #17141: vonmisesvariate() was hang for large kappas
1143 random.vonmisesvariate(0, 1e15)
1144 random.vonmisesvariate(0, 1e100)
1145
1146 def test_gammavariate_errors(self):
1147 # Both alpha and beta must be > 0.0
1148 self.assertRaises(ValueError, random.gammavariate, -1, 3)
1149 self.assertRaises(ValueError, random.gammavariate, 0, 2)
1150 self.assertRaises(ValueError, random.gammavariate, 2, 0)
1151 self.assertRaises(ValueError, random.gammavariate, 1, -3)
1152
1153 # There are three different possibilities in the current implementation
1154 # of random.gammavariate(), depending on the value of 'alpha'. What we
1155 # are going to do here is to fix the values returned by random() to
1156 # generate test cases that provide 100% line coverage of the method.
1157 @unittest.mock.patch('random.Random.random')
1158 def test_gammavariate_alpha_greater_one(self, random_mock):
1159
1160 # #1: alpha > 1.0.
1161 # We want the first random number to be outside the
1162 # [1e-7, .9999999] range, so that the continue statement executes
1163 # once. The values of u1 and u2 will be 0.5 and 0.3, respectively.
1164 random_mock.side_effect = [1e-8, 0.5, 0.3]
1165 returned_value = random.gammavariate(1.1, 2.3)
1166 self.assertAlmostEqual(returned_value, 2.53)
1167
1168 @unittest.mock.patch('random.Random.random')
1169 def test_gammavariate_alpha_equal_one(self, random_mock):
1170
1171 # #2.a: alpha == 1.
1172 # The execution body of the while loop executes once.
1173 # Then random.random() returns 0.45,
1174 # which causes while to stop looping and the algorithm to terminate.
1175 random_mock.side_effect = [0.45]
1176 returned_value = random.gammavariate(1.0, 3.14)
1177 self.assertAlmostEqual(returned_value, 1.877208182372648)
1178
1179 @unittest.mock.patch('random.Random.random')
1180 def test_gammavariate_alpha_equal_one_equals_expovariate(self, random_mock):
1181
1182 # #2.b: alpha == 1.
1183 # It must be equivalent of calling expovariate(1.0 / beta).
1184 beta = 3.14
1185 random_mock.side_effect = [1e-8, 1e-8]
1186 gammavariate_returned_value = random.gammavariate(1.0, beta)
1187 expovariate_returned_value = random.expovariate(1.0 / beta)
1188 self.assertAlmostEqual(gammavariate_returned_value, expovariate_returned_value)
1189
1190 @unittest.mock.patch('random.Random.random')
1191 def test_gammavariate_alpha_between_zero_and_one(self, random_mock):
1192
1193 # #3: 0 < alpha < 1.
1194 # This is the most complex region of code to cover,
1195 # as there are multiple if-else statements. Let's take a look at the
1196 # source code, and determine the values that we need accordingly:
1197 #
1198 # while 1:
1199 # u = random()
1200 # b = (_e + alpha)/_e
1201 # p = b*u
1202 # if p <= 1.0: # <=== (A)
1203 # x = p ** (1.0/alpha)
1204 # else: # <=== (B)
1205 # x = -_log((b-p)/alpha)
1206 # u1 = random()
1207 # if p > 1.0: # <=== (C)
1208 # if u1 <= x ** (alpha - 1.0): # <=== (D)
1209 # break
1210 # elif u1 <= _exp(-x): # <=== (E)
1211 # break
1212 # return x * beta
1213 #
1214 # First, we want (A) to be True. For that we need that:
1215 # b*random() <= 1.0
1216 # r1 = random() <= 1.0 / b
1217 #
1218 # We now get to the second if-else branch, and here, since p <= 1.0,
1219 # (C) is False and we take the elif branch, (E). For it to be True,
1220 # so that the break is executed, we need that:
1221 # r2 = random() <= _exp(-x)
1222 # r2 <= _exp(-(p ** (1.0/alpha)))
1223 # r2 <= _exp(-((b*r1) ** (1.0/alpha)))
1224
1225 _e = random._e
1226 _exp = random._exp
1227 _log = random._log
1228 alpha = 0.35
1229 beta = 1.45
1230 b = (_e + alpha)/_e
1231 epsilon = 0.01
1232
1233 r1 = 0.8859296441566 # 1.0 / b
1234 r2 = 0.3678794411714 # _exp(-((b*r1) ** (1.0/alpha)))
1235
1236 # These four "random" values result in the following trace:
1237 # (A) True, (E) False --> [next iteration of while]
1238 # (A) True, (E) True --> [while loop breaks]
1239 random_mock.side_effect = [r1, r2 + epsilon, r1, r2]
1240 returned_value = random.gammavariate(alpha, beta)
1241 self.assertAlmostEqual(returned_value, 1.4499999999997544)
1242
1243 # Let's now make (A) be False. If this is the case, when we get to the
1244 # second if-else 'p' is greater than 1, so (C) evaluates to True. We
1245 # now encounter a second if statement, (D), which in order to execute
1246 # must satisfy the following condition:
1247 # r2 <= x ** (alpha - 1.0)
1248 # r2 <= (-_log((b-p)/alpha)) ** (alpha - 1.0)
1249 # r2 <= (-_log((b-(b*r1))/alpha)) ** (alpha - 1.0)
1250 r1 = 0.8959296441566 # (1.0 / b) + epsilon -- so that (A) is False
1251 r2 = 0.9445400408898141
1252
1253 # And these four values result in the following trace:
1254 # (B) and (C) True, (D) False --> [next iteration of while]
1255 # (B) and (C) True, (D) True [while loop breaks]
1256 random_mock.side_effect = [r1, r2 + epsilon, r1, r2]
1257 returned_value = random.gammavariate(alpha, beta)
1258 self.assertAlmostEqual(returned_value, 1.5830349561760781)
1259
1260 @unittest.mock.patch('random.Random.gammavariate')
1261 def test_betavariate_return_zero(self, gammavariate_mock):
1262 # betavariate() returns zero when the Gamma distribution
1263 # that it uses internally returns this same value.
1264 gammavariate_mock.return_value = 0.0
1265 self.assertEqual(0.0, random.betavariate(2.71828, 3.14159))
1266
1267
1268 class ESC[4;38;5;81mTestRandomSubclassing(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
1269 def test_random_subclass_with_kwargs(self):
1270 # SF bug #1486663 -- this used to erroneously raise a TypeError
1271 class ESC[4;38;5;81mSubclass(ESC[4;38;5;149mrandomESC[4;38;5;149m.ESC[4;38;5;149mRandom):
1272 def __init__(self, newarg=None):
1273 random.Random.__init__(self)
1274 Subclass(newarg=1)
1275
1276 def test_subclasses_overriding_methods(self):
1277 # Subclasses with an overridden random, but only the original
1278 # getrandbits method should not rely on getrandbits in for randrange,
1279 # but should use a getrandbits-independent implementation instead.
1280
1281 # subclass providing its own random **and** getrandbits methods
1282 # like random.SystemRandom does => keep relying on getrandbits for
1283 # randrange
1284 class ESC[4;38;5;81mSubClass1(ESC[4;38;5;149mrandomESC[4;38;5;149m.ESC[4;38;5;149mRandom):
1285 def random(self):
1286 called.add('SubClass1.random')
1287 return random.Random.random(self)
1288
1289 def getrandbits(self, n):
1290 called.add('SubClass1.getrandbits')
1291 return random.Random.getrandbits(self, n)
1292 called = set()
1293 SubClass1().randrange(42)
1294 self.assertEqual(called, {'SubClass1.getrandbits'})
1295
1296 # subclass providing only random => can only use random for randrange
1297 class ESC[4;38;5;81mSubClass2(ESC[4;38;5;149mrandomESC[4;38;5;149m.ESC[4;38;5;149mRandom):
1298 def random(self):
1299 called.add('SubClass2.random')
1300 return random.Random.random(self)
1301 called = set()
1302 SubClass2().randrange(42)
1303 self.assertEqual(called, {'SubClass2.random'})
1304
1305 # subclass defining getrandbits to complement its inherited random
1306 # => can now rely on getrandbits for randrange again
1307 class ESC[4;38;5;81mSubClass3(ESC[4;38;5;149mSubClass2):
1308 def getrandbits(self, n):
1309 called.add('SubClass3.getrandbits')
1310 return random.Random.getrandbits(self, n)
1311 called = set()
1312 SubClass3().randrange(42)
1313 self.assertEqual(called, {'SubClass3.getrandbits'})
1314
1315 # subclass providing only random and inherited getrandbits
1316 # => random takes precedence
1317 class ESC[4;38;5;81mSubClass4(ESC[4;38;5;149mSubClass3):
1318 def random(self):
1319 called.add('SubClass4.random')
1320 return random.Random.random(self)
1321 called = set()
1322 SubClass4().randrange(42)
1323 self.assertEqual(called, {'SubClass4.random'})
1324
1325 # Following subclasses don't define random or getrandbits directly,
1326 # but inherit them from classes which are not subclasses of Random
1327 class ESC[4;38;5;81mMixin1:
1328 def random(self):
1329 called.add('Mixin1.random')
1330 return random.Random.random(self)
1331 class ESC[4;38;5;81mMixin2:
1332 def getrandbits(self, n):
1333 called.add('Mixin2.getrandbits')
1334 return random.Random.getrandbits(self, n)
1335
1336 class ESC[4;38;5;81mSubClass5(ESC[4;38;5;149mMixin1, ESC[4;38;5;149mrandomESC[4;38;5;149m.ESC[4;38;5;149mRandom):
1337 pass
1338 called = set()
1339 SubClass5().randrange(42)
1340 self.assertEqual(called, {'Mixin1.random'})
1341
1342 class ESC[4;38;5;81mSubClass6(ESC[4;38;5;149mMixin2, ESC[4;38;5;149mrandomESC[4;38;5;149m.ESC[4;38;5;149mRandom):
1343 pass
1344 called = set()
1345 SubClass6().randrange(42)
1346 self.assertEqual(called, {'Mixin2.getrandbits'})
1347
1348 class ESC[4;38;5;81mSubClass7(ESC[4;38;5;149mMixin1, ESC[4;38;5;149mMixin2, ESC[4;38;5;149mrandomESC[4;38;5;149m.ESC[4;38;5;149mRandom):
1349 pass
1350 called = set()
1351 SubClass7().randrange(42)
1352 self.assertEqual(called, {'Mixin1.random'})
1353
1354 class ESC[4;38;5;81mSubClass8(ESC[4;38;5;149mMixin2, ESC[4;38;5;149mMixin1, ESC[4;38;5;149mrandomESC[4;38;5;149m.ESC[4;38;5;149mRandom):
1355 pass
1356 called = set()
1357 SubClass8().randrange(42)
1358 self.assertEqual(called, {'Mixin2.getrandbits'})
1359
1360
1361 class ESC[4;38;5;81mTestModule(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
1362 def testMagicConstants(self):
1363 self.assertAlmostEqual(random.NV_MAGICCONST, 1.71552776992141)
1364 self.assertAlmostEqual(random.TWOPI, 6.28318530718)
1365 self.assertAlmostEqual(random.LOG4, 1.38629436111989)
1366 self.assertAlmostEqual(random.SG_MAGICCONST, 2.50407739677627)
1367
1368 def test__all__(self):
1369 # tests validity but not completeness of the __all__ list
1370 self.assertTrue(set(random.__all__) <= set(dir(random)))
1371
1372 @test.support.requires_fork()
1373 def test_after_fork(self):
1374 # Test the global Random instance gets reseeded in child
1375 r, w = os.pipe()
1376 pid = os.fork()
1377 if pid == 0:
1378 # child process
1379 try:
1380 val = random.getrandbits(128)
1381 with open(w, "w") as f:
1382 f.write(str(val))
1383 finally:
1384 os._exit(0)
1385 else:
1386 # parent process
1387 os.close(w)
1388 val = random.getrandbits(128)
1389 with open(r, "r") as f:
1390 child_val = eval(f.read())
1391 self.assertNotEqual(val, child_val)
1392
1393 support.wait_process(pid, exitcode=0)
1394
1395
1396 if __name__ == "__main__":
1397 unittest.main()