1 import sys
2 import time
3
4 import unittest
5 from unittest import mock
6 from test import support
7 from test.test_grammar import (VALID_UNDERSCORE_LITERALS,
8 INVALID_UNDERSCORE_LITERALS)
9
10 try:
11 import _pylong
12 except ImportError:
13 _pylong = None
14
15 L = [
16 ('0', 0),
17 ('1', 1),
18 ('9', 9),
19 ('10', 10),
20 ('99', 99),
21 ('100', 100),
22 ('314', 314),
23 (' 314', 314),
24 ('314 ', 314),
25 (' \t\t 314 \t\t ', 314),
26 (repr(sys.maxsize), sys.maxsize),
27 (' 1x', ValueError),
28 (' 1 ', 1),
29 (' 1\02 ', ValueError),
30 ('', ValueError),
31 (' ', ValueError),
32 (' \t\t ', ValueError),
33 ("\u0200", ValueError)
34 ]
35
36 class ESC[4;38;5;81mIntSubclass(ESC[4;38;5;149mint):
37 pass
38
39 class ESC[4;38;5;81mIntTestCases(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
40
41 def test_basic(self):
42 self.assertEqual(int(314), 314)
43 self.assertEqual(int(3.14), 3)
44 # Check that conversion from float truncates towards zero
45 self.assertEqual(int(-3.14), -3)
46 self.assertEqual(int(3.9), 3)
47 self.assertEqual(int(-3.9), -3)
48 self.assertEqual(int(3.5), 3)
49 self.assertEqual(int(-3.5), -3)
50 self.assertEqual(int("-3"), -3)
51 self.assertEqual(int(" -3 "), -3)
52 self.assertEqual(int("\N{EM SPACE}-3\N{EN SPACE}"), -3)
53 # Different base:
54 self.assertEqual(int("10",16), 16)
55 # Test conversion from strings and various anomalies
56 for s, v in L:
57 for sign in "", "+", "-":
58 for prefix in "", " ", "\t", " \t\t ":
59 ss = prefix + sign + s
60 vv = v
61 if sign == "-" and v is not ValueError:
62 vv = -v
63 try:
64 self.assertEqual(int(ss), vv)
65 except ValueError:
66 pass
67
68 s = repr(-1-sys.maxsize)
69 x = int(s)
70 self.assertEqual(x+1, -sys.maxsize)
71 self.assertIsInstance(x, int)
72 # should return int
73 self.assertEqual(int(s[1:]), sys.maxsize+1)
74
75 # should return int
76 x = int(1e100)
77 self.assertIsInstance(x, int)
78 x = int(-1e100)
79 self.assertIsInstance(x, int)
80
81
82 # SF bug 434186: 0x80000000/2 != 0x80000000>>1.
83 # Worked by accident in Windows release build, but failed in debug build.
84 # Failed in all Linux builds.
85 x = -1-sys.maxsize
86 self.assertEqual(x >> 1, x//2)
87
88 x = int('1' * 600)
89 self.assertIsInstance(x, int)
90
91
92 self.assertRaises(TypeError, int, 1, 12)
93
94 self.assertEqual(int('0o123', 0), 83)
95 self.assertEqual(int('0x123', 16), 291)
96
97 # Bug 1679: "0x" is not a valid hex literal
98 self.assertRaises(ValueError, int, "0x", 16)
99 self.assertRaises(ValueError, int, "0x", 0)
100
101 self.assertRaises(ValueError, int, "0o", 8)
102 self.assertRaises(ValueError, int, "0o", 0)
103
104 self.assertRaises(ValueError, int, "0b", 2)
105 self.assertRaises(ValueError, int, "0b", 0)
106
107 # SF bug 1334662: int(string, base) wrong answers
108 # Various representations of 2**32 evaluated to 0
109 # rather than 2**32 in previous versions
110
111 self.assertEqual(int('100000000000000000000000000000000', 2), 4294967296)
112 self.assertEqual(int('102002022201221111211', 3), 4294967296)
113 self.assertEqual(int('10000000000000000', 4), 4294967296)
114 self.assertEqual(int('32244002423141', 5), 4294967296)
115 self.assertEqual(int('1550104015504', 6), 4294967296)
116 self.assertEqual(int('211301422354', 7), 4294967296)
117 self.assertEqual(int('40000000000', 8), 4294967296)
118 self.assertEqual(int('12068657454', 9), 4294967296)
119 self.assertEqual(int('4294967296', 10), 4294967296)
120 self.assertEqual(int('1904440554', 11), 4294967296)
121 self.assertEqual(int('9ba461594', 12), 4294967296)
122 self.assertEqual(int('535a79889', 13), 4294967296)
123 self.assertEqual(int('2ca5b7464', 14), 4294967296)
124 self.assertEqual(int('1a20dcd81', 15), 4294967296)
125 self.assertEqual(int('100000000', 16), 4294967296)
126 self.assertEqual(int('a7ffda91', 17), 4294967296)
127 self.assertEqual(int('704he7g4', 18), 4294967296)
128 self.assertEqual(int('4f5aff66', 19), 4294967296)
129 self.assertEqual(int('3723ai4g', 20), 4294967296)
130 self.assertEqual(int('281d55i4', 21), 4294967296)
131 self.assertEqual(int('1fj8b184', 22), 4294967296)
132 self.assertEqual(int('1606k7ic', 23), 4294967296)
133 self.assertEqual(int('mb994ag', 24), 4294967296)
134 self.assertEqual(int('hek2mgl', 25), 4294967296)
135 self.assertEqual(int('dnchbnm', 26), 4294967296)
136 self.assertEqual(int('b28jpdm', 27), 4294967296)
137 self.assertEqual(int('8pfgih4', 28), 4294967296)
138 self.assertEqual(int('76beigg', 29), 4294967296)
139 self.assertEqual(int('5qmcpqg', 30), 4294967296)
140 self.assertEqual(int('4q0jto4', 31), 4294967296)
141 self.assertEqual(int('4000000', 32), 4294967296)
142 self.assertEqual(int('3aokq94', 33), 4294967296)
143 self.assertEqual(int('2qhxjli', 34), 4294967296)
144 self.assertEqual(int('2br45qb', 35), 4294967296)
145 self.assertEqual(int('1z141z4', 36), 4294967296)
146
147 # tests with base 0
148 # this fails on 3.0, but in 2.x the old octal syntax is allowed
149 self.assertEqual(int(' 0o123 ', 0), 83)
150 self.assertEqual(int(' 0o123 ', 0), 83)
151 self.assertEqual(int('000', 0), 0)
152 self.assertEqual(int('0o123', 0), 83)
153 self.assertEqual(int('0x123', 0), 291)
154 self.assertEqual(int('0b100', 0), 4)
155 self.assertEqual(int(' 0O123 ', 0), 83)
156 self.assertEqual(int(' 0X123 ', 0), 291)
157 self.assertEqual(int(' 0B100 ', 0), 4)
158 with self.assertRaises(ValueError):
159 int('010', 0)
160
161 # without base still base 10
162 self.assertEqual(int('0123'), 123)
163 self.assertEqual(int('0123', 10), 123)
164
165 # tests with prefix and base != 0
166 self.assertEqual(int('0x123', 16), 291)
167 self.assertEqual(int('0o123', 8), 83)
168 self.assertEqual(int('0b100', 2), 4)
169 self.assertEqual(int('0X123', 16), 291)
170 self.assertEqual(int('0O123', 8), 83)
171 self.assertEqual(int('0B100', 2), 4)
172
173 # the code has special checks for the first character after the
174 # type prefix
175 self.assertRaises(ValueError, int, '0b2', 2)
176 self.assertRaises(ValueError, int, '0b02', 2)
177 self.assertRaises(ValueError, int, '0B2', 2)
178 self.assertRaises(ValueError, int, '0B02', 2)
179 self.assertRaises(ValueError, int, '0o8', 8)
180 self.assertRaises(ValueError, int, '0o08', 8)
181 self.assertRaises(ValueError, int, '0O8', 8)
182 self.assertRaises(ValueError, int, '0O08', 8)
183 self.assertRaises(ValueError, int, '0xg', 16)
184 self.assertRaises(ValueError, int, '0x0g', 16)
185 self.assertRaises(ValueError, int, '0Xg', 16)
186 self.assertRaises(ValueError, int, '0X0g', 16)
187
188 # SF bug 1334662: int(string, base) wrong answers
189 # Checks for proper evaluation of 2**32 + 1
190 self.assertEqual(int('100000000000000000000000000000001', 2), 4294967297)
191 self.assertEqual(int('102002022201221111212', 3), 4294967297)
192 self.assertEqual(int('10000000000000001', 4), 4294967297)
193 self.assertEqual(int('32244002423142', 5), 4294967297)
194 self.assertEqual(int('1550104015505', 6), 4294967297)
195 self.assertEqual(int('211301422355', 7), 4294967297)
196 self.assertEqual(int('40000000001', 8), 4294967297)
197 self.assertEqual(int('12068657455', 9), 4294967297)
198 self.assertEqual(int('4294967297', 10), 4294967297)
199 self.assertEqual(int('1904440555', 11), 4294967297)
200 self.assertEqual(int('9ba461595', 12), 4294967297)
201 self.assertEqual(int('535a7988a', 13), 4294967297)
202 self.assertEqual(int('2ca5b7465', 14), 4294967297)
203 self.assertEqual(int('1a20dcd82', 15), 4294967297)
204 self.assertEqual(int('100000001', 16), 4294967297)
205 self.assertEqual(int('a7ffda92', 17), 4294967297)
206 self.assertEqual(int('704he7g5', 18), 4294967297)
207 self.assertEqual(int('4f5aff67', 19), 4294967297)
208 self.assertEqual(int('3723ai4h', 20), 4294967297)
209 self.assertEqual(int('281d55i5', 21), 4294967297)
210 self.assertEqual(int('1fj8b185', 22), 4294967297)
211 self.assertEqual(int('1606k7id', 23), 4294967297)
212 self.assertEqual(int('mb994ah', 24), 4294967297)
213 self.assertEqual(int('hek2mgm', 25), 4294967297)
214 self.assertEqual(int('dnchbnn', 26), 4294967297)
215 self.assertEqual(int('b28jpdn', 27), 4294967297)
216 self.assertEqual(int('8pfgih5', 28), 4294967297)
217 self.assertEqual(int('76beigh', 29), 4294967297)
218 self.assertEqual(int('5qmcpqh', 30), 4294967297)
219 self.assertEqual(int('4q0jto5', 31), 4294967297)
220 self.assertEqual(int('4000001', 32), 4294967297)
221 self.assertEqual(int('3aokq95', 33), 4294967297)
222 self.assertEqual(int('2qhxjlj', 34), 4294967297)
223 self.assertEqual(int('2br45qc', 35), 4294967297)
224 self.assertEqual(int('1z141z5', 36), 4294967297)
225
226 def test_invalid_signs(self):
227 with self.assertRaises(ValueError):
228 int('+')
229 with self.assertRaises(ValueError):
230 int('-')
231 with self.assertRaises(ValueError):
232 int('- 1')
233 with self.assertRaises(ValueError):
234 int('+ 1')
235 with self.assertRaises(ValueError):
236 int(' + 1 ')
237
238 def test_unicode(self):
239 self.assertEqual(int("१२३४५६à¥à¥®à¥¯à¥¦1234567890"), 12345678901234567890)
240 self.assertEqual(int('١٢٣٤٥٦٧٨٩٠'), 1234567890)
241 self.assertEqual(int("१२३४५६à¥à¥®à¥¯à¥¦1234567890", 0), 12345678901234567890)
242 self.assertEqual(int('١٢٣٤٥٦٧٨٩٠', 0), 1234567890)
243
244 def test_underscores(self):
245 for lit in VALID_UNDERSCORE_LITERALS:
246 if any(ch in lit for ch in '.eEjJ'):
247 continue
248 self.assertEqual(int(lit, 0), eval(lit))
249 self.assertEqual(int(lit, 0), int(lit.replace('_', ''), 0))
250 for lit in INVALID_UNDERSCORE_LITERALS:
251 if any(ch in lit for ch in '.eEjJ'):
252 continue
253 self.assertRaises(ValueError, int, lit, 0)
254 # Additional test cases with bases != 0, only for the constructor:
255 self.assertEqual(int("1_00", 3), 9)
256 self.assertEqual(int("0_100"), 100) # not valid as a literal!
257 self.assertEqual(int(b"1_00"), 100) # byte underscore
258 self.assertRaises(ValueError, int, "_100")
259 self.assertRaises(ValueError, int, "+_100")
260 self.assertRaises(ValueError, int, "1__00")
261 self.assertRaises(ValueError, int, "100_")
262
263 @support.cpython_only
264 def test_small_ints(self):
265 # Bug #3236: Return small longs from PyLong_FromString
266 self.assertIs(int('10'), 10)
267 self.assertIs(int('-1'), -1)
268 self.assertIs(int(b'10'), 10)
269 self.assertIs(int(b'-1'), -1)
270
271 def test_no_args(self):
272 self.assertEqual(int(), 0)
273
274 def test_keyword_args(self):
275 # Test invoking int() using keyword arguments.
276 self.assertEqual(int('100', base=2), 4)
277 with self.assertRaisesRegex(TypeError, 'keyword argument'):
278 int(x=1.2)
279 with self.assertRaisesRegex(TypeError, 'keyword argument'):
280 int(x='100', base=2)
281 self.assertRaises(TypeError, int, base=10)
282 self.assertRaises(TypeError, int, base=0)
283
284 def test_int_base_limits(self):
285 """Testing the supported limits of the int() base parameter."""
286 self.assertEqual(int('0', 5), 0)
287 with self.assertRaises(ValueError):
288 int('0', 1)
289 with self.assertRaises(ValueError):
290 int('0', 37)
291 with self.assertRaises(ValueError):
292 int('0', -909) # An old magic value base from Python 2.
293 with self.assertRaises(ValueError):
294 int('0', base=0-(2**234))
295 with self.assertRaises(ValueError):
296 int('0', base=2**234)
297 # Bases 2 through 36 are supported.
298 for base in range(2,37):
299 self.assertEqual(int('0', base=base), 0)
300
301 def test_int_base_bad_types(self):
302 """Not integer types are not valid bases; issue16772."""
303 with self.assertRaises(TypeError):
304 int('0', 5.5)
305 with self.assertRaises(TypeError):
306 int('0', 5.0)
307
308 def test_int_base_indexable(self):
309 class ESC[4;38;5;81mMyIndexable(ESC[4;38;5;149mobject):
310 def __init__(self, value):
311 self.value = value
312 def __index__(self):
313 return self.value
314
315 # Check out of range bases.
316 for base in 2**100, -2**100, 1, 37:
317 with self.assertRaises(ValueError):
318 int('43', base)
319
320 # Check in-range bases.
321 self.assertEqual(int('101', base=MyIndexable(2)), 5)
322 self.assertEqual(int('101', base=MyIndexable(10)), 101)
323 self.assertEqual(int('101', base=MyIndexable(36)), 1 + 36**2)
324
325 def test_non_numeric_input_types(self):
326 # Test possible non-numeric types for the argument x, including
327 # subclasses of the explicitly documented accepted types.
328 class ESC[4;38;5;81mCustomStr(ESC[4;38;5;149mstr): pass
329 class ESC[4;38;5;81mCustomBytes(ESC[4;38;5;149mbytes): pass
330 class ESC[4;38;5;81mCustomByteArray(ESC[4;38;5;149mbytearray): pass
331
332 factories = [
333 bytes,
334 bytearray,
335 lambda b: CustomStr(b.decode()),
336 CustomBytes,
337 CustomByteArray,
338 memoryview,
339 ]
340 try:
341 from array import array
342 except ImportError:
343 pass
344 else:
345 factories.append(lambda b: array('B', b))
346
347 for f in factories:
348 x = f(b'100')
349 with self.subTest(type(x)):
350 self.assertEqual(int(x), 100)
351 if isinstance(x, (str, bytes, bytearray)):
352 self.assertEqual(int(x, 2), 4)
353 else:
354 msg = "can't convert non-string"
355 with self.assertRaisesRegex(TypeError, msg):
356 int(x, 2)
357 with self.assertRaisesRegex(ValueError, 'invalid literal'):
358 int(f(b'A' * 0x10))
359
360 def test_int_memoryview(self):
361 self.assertEqual(int(memoryview(b'123')[1:3]), 23)
362 self.assertEqual(int(memoryview(b'123\x00')[1:3]), 23)
363 self.assertEqual(int(memoryview(b'123 ')[1:3]), 23)
364 self.assertEqual(int(memoryview(b'123A')[1:3]), 23)
365 self.assertEqual(int(memoryview(b'1234')[1:3]), 23)
366
367 def test_string_float(self):
368 self.assertRaises(ValueError, int, '1.2')
369
370 def test_intconversion(self):
371 # Test __int__()
372 class ESC[4;38;5;81mClassicMissingMethods:
373 pass
374 self.assertRaises(TypeError, int, ClassicMissingMethods())
375
376 class ESC[4;38;5;81mMissingMethods(ESC[4;38;5;149mobject):
377 pass
378 self.assertRaises(TypeError, int, MissingMethods())
379
380 class ESC[4;38;5;81mFoo0:
381 def __int__(self):
382 return 42
383
384 self.assertEqual(int(Foo0()), 42)
385
386 class ESC[4;38;5;81mClassic:
387 pass
388 for base in (object, Classic):
389 class ESC[4;38;5;81mIntOverridesTrunc(ESC[4;38;5;149mbase):
390 def __int__(self):
391 return 42
392 def __trunc__(self):
393 return -12
394 self.assertEqual(int(IntOverridesTrunc()), 42)
395
396 class ESC[4;38;5;81mJustTrunc(ESC[4;38;5;149mbase):
397 def __trunc__(self):
398 return 42
399 with self.assertWarns(DeprecationWarning):
400 self.assertEqual(int(JustTrunc()), 42)
401
402 class ESC[4;38;5;81mExceptionalTrunc(ESC[4;38;5;149mbase):
403 def __trunc__(self):
404 1 / 0
405 with self.assertRaises(ZeroDivisionError), \
406 self.assertWarns(DeprecationWarning):
407 int(ExceptionalTrunc())
408
409 for trunc_result_base in (object, Classic):
410 class ESC[4;38;5;81mIndex(ESC[4;38;5;149mtrunc_result_base):
411 def __index__(self):
412 return 42
413
414 class ESC[4;38;5;81mTruncReturnsNonInt(ESC[4;38;5;149mbase):
415 def __trunc__(self):
416 return Index()
417 with self.assertWarns(DeprecationWarning):
418 self.assertEqual(int(TruncReturnsNonInt()), 42)
419
420 class ESC[4;38;5;81mIntable(ESC[4;38;5;149mtrunc_result_base):
421 def __int__(self):
422 return 42
423
424 class ESC[4;38;5;81mTruncReturnsNonIndex(ESC[4;38;5;149mbase):
425 def __trunc__(self):
426 return Intable()
427 with self.assertWarns(DeprecationWarning):
428 self.assertEqual(int(TruncReturnsNonInt()), 42)
429
430 class ESC[4;38;5;81mNonIntegral(ESC[4;38;5;149mtrunc_result_base):
431 def __trunc__(self):
432 # Check that we avoid infinite recursion.
433 return NonIntegral()
434
435 class ESC[4;38;5;81mTruncReturnsNonIntegral(ESC[4;38;5;149mbase):
436 def __trunc__(self):
437 return NonIntegral()
438 try:
439 with self.assertWarns(DeprecationWarning):
440 int(TruncReturnsNonIntegral())
441 except TypeError as e:
442 self.assertEqual(str(e),
443 "__trunc__ returned non-Integral"
444 " (type NonIntegral)")
445 else:
446 self.fail("Failed to raise TypeError with %s" %
447 ((base, trunc_result_base),))
448
449 # Regression test for bugs.python.org/issue16060.
450 class ESC[4;38;5;81mBadInt(ESC[4;38;5;149mtrunc_result_base):
451 def __int__(self):
452 return 42.0
453
454 class ESC[4;38;5;81mTruncReturnsBadInt(ESC[4;38;5;149mbase):
455 def __trunc__(self):
456 return BadInt()
457
458 with self.assertRaises(TypeError), \
459 self.assertWarns(DeprecationWarning):
460 int(TruncReturnsBadInt())
461
462 def test_int_subclass_with_index(self):
463 class ESC[4;38;5;81mMyIndex(ESC[4;38;5;149mint):
464 def __index__(self):
465 return 42
466
467 class ESC[4;38;5;81mBadIndex(ESC[4;38;5;149mint):
468 def __index__(self):
469 return 42.0
470
471 my_int = MyIndex(7)
472 self.assertEqual(my_int, 7)
473 self.assertEqual(int(my_int), 7)
474
475 self.assertEqual(int(BadIndex()), 0)
476
477 def test_int_subclass_with_int(self):
478 class ESC[4;38;5;81mMyInt(ESC[4;38;5;149mint):
479 def __int__(self):
480 return 42
481
482 class ESC[4;38;5;81mBadInt(ESC[4;38;5;149mint):
483 def __int__(self):
484 return 42.0
485
486 my_int = MyInt(7)
487 self.assertEqual(my_int, 7)
488 self.assertEqual(int(my_int), 42)
489
490 my_int = BadInt(7)
491 self.assertEqual(my_int, 7)
492 self.assertRaises(TypeError, int, my_int)
493
494 def test_int_returns_int_subclass(self):
495 class ESC[4;38;5;81mBadIndex:
496 def __index__(self):
497 return True
498
499 class ESC[4;38;5;81mBadIndex2(ESC[4;38;5;149mint):
500 def __index__(self):
501 return True
502
503 class ESC[4;38;5;81mBadInt:
504 def __int__(self):
505 return True
506
507 class ESC[4;38;5;81mBadInt2(ESC[4;38;5;149mint):
508 def __int__(self):
509 return True
510
511 class ESC[4;38;5;81mTruncReturnsBadIndex:
512 def __trunc__(self):
513 return BadIndex()
514
515 class ESC[4;38;5;81mTruncReturnsBadInt:
516 def __trunc__(self):
517 return BadInt()
518
519 class ESC[4;38;5;81mTruncReturnsIntSubclass:
520 def __trunc__(self):
521 return True
522
523 bad_int = BadIndex()
524 with self.assertWarns(DeprecationWarning):
525 n = int(bad_int)
526 self.assertEqual(n, 1)
527 self.assertIs(type(n), int)
528
529 bad_int = BadIndex2()
530 n = int(bad_int)
531 self.assertEqual(n, 0)
532 self.assertIs(type(n), int)
533
534 bad_int = BadInt()
535 with self.assertWarns(DeprecationWarning):
536 n = int(bad_int)
537 self.assertEqual(n, 1)
538 self.assertIs(type(n), int)
539
540 bad_int = BadInt2()
541 with self.assertWarns(DeprecationWarning):
542 n = int(bad_int)
543 self.assertEqual(n, 1)
544 self.assertIs(type(n), int)
545
546 bad_int = TruncReturnsBadIndex()
547 with self.assertWarns(DeprecationWarning):
548 n = int(bad_int)
549 self.assertEqual(n, 1)
550 self.assertIs(type(n), int)
551
552 bad_int = TruncReturnsBadInt()
553 with self.assertWarns(DeprecationWarning):
554 self.assertRaises(TypeError, int, bad_int)
555
556 good_int = TruncReturnsIntSubclass()
557 with self.assertWarns(DeprecationWarning):
558 n = int(good_int)
559 self.assertEqual(n, 1)
560 self.assertIs(type(n), int)
561 with self.assertWarns(DeprecationWarning):
562 n = IntSubclass(good_int)
563 self.assertEqual(n, 1)
564 self.assertIs(type(n), IntSubclass)
565
566 def test_error_message(self):
567 def check(s, base=None):
568 with self.assertRaises(ValueError,
569 msg="int(%r, %r)" % (s, base)) as cm:
570 if base is None:
571 int(s)
572 else:
573 int(s, base)
574 self.assertEqual(cm.exception.args[0],
575 "invalid literal for int() with base %d: %r" %
576 (10 if base is None else base, s))
577
578 check('\xbd')
579 check('123\xbd')
580 check(' 123 456 ')
581
582 check('123\x00')
583 # SF bug 1545497: embedded NULs were not detected with explicit base
584 check('123\x00', 10)
585 check('123\x00 245', 20)
586 check('123\x00 245', 16)
587 check('123\x00245', 20)
588 check('123\x00245', 16)
589 # byte string with embedded NUL
590 check(b'123\x00')
591 check(b'123\x00', 10)
592 # non-UTF-8 byte string
593 check(b'123\xbd')
594 check(b'123\xbd', 10)
595 # lone surrogate in Unicode string
596 check('123\ud800')
597 check('123\ud800', 10)
598
599 def test_issue31619(self):
600 self.assertEqual(int('1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1', 2),
601 0b1010101010101010101010101010101)
602 self.assertEqual(int('1_2_3_4_5_6_7_0_1_2_3', 8), 0o12345670123)
603 self.assertEqual(int('1_2_3_4_5_6_7_8_9', 16), 0x123456789)
604 self.assertEqual(int('1_2_3_4_5_6_7', 32), 1144132807)
605
606
607 class ESC[4;38;5;81mIntStrDigitLimitsTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
608
609 int_class = int # Override this in subclasses to reuse the suite.
610
611 def setUp(self):
612 super().setUp()
613 self._previous_limit = sys.get_int_max_str_digits()
614 sys.set_int_max_str_digits(2048)
615
616 def tearDown(self):
617 sys.set_int_max_str_digits(self._previous_limit)
618 super().tearDown()
619
620 def test_disabled_limit(self):
621 self.assertGreater(sys.get_int_max_str_digits(), 0)
622 self.assertLess(sys.get_int_max_str_digits(), 20_000)
623 with support.adjust_int_max_str_digits(0):
624 self.assertEqual(sys.get_int_max_str_digits(), 0)
625 i = self.int_class('1' * 20_000)
626 str(i)
627 self.assertGreater(sys.get_int_max_str_digits(), 0)
628
629 def test_max_str_digits_edge_cases(self):
630 """Ignore the +/- sign and space padding."""
631 int_class = self.int_class
632 maxdigits = sys.get_int_max_str_digits()
633
634 int_class('1' * maxdigits)
635 int_class(' ' + '1' * maxdigits)
636 int_class('1' * maxdigits + ' ')
637 int_class('+' + '1' * maxdigits)
638 int_class('-' + '1' * maxdigits)
639 self.assertEqual(len(str(10 ** (maxdigits - 1))), maxdigits)
640
641 def check(self, i, base=None):
642 with self.assertRaises(ValueError):
643 if base is None:
644 self.int_class(i)
645 else:
646 self.int_class(i, base)
647
648 def test_max_str_digits(self):
649 maxdigits = sys.get_int_max_str_digits()
650
651 self.check('1' * (maxdigits + 1))
652 self.check(' ' + '1' * (maxdigits + 1))
653 self.check('1' * (maxdigits + 1) + ' ')
654 self.check('+' + '1' * (maxdigits + 1))
655 self.check('-' + '1' * (maxdigits + 1))
656 self.check('1' * (maxdigits + 1))
657
658 i = 10 ** maxdigits
659 with self.assertRaises(ValueError):
660 str(i)
661
662 def test_denial_of_service_prevented_int_to_str(self):
663 """Regression test: ensure we fail before performing O(N**2) work."""
664 maxdigits = sys.get_int_max_str_digits()
665 assert maxdigits < 50_000, maxdigits # A test prerequisite.
666 get_time = time.process_time
667 if get_time() <= 0: # some platforms like WASM lack process_time()
668 get_time = time.monotonic
669
670 huge_int = int(f'0x{"c"*65_000}', base=16) # 78268 decimal digits.
671 digits = 78_268
672 with support.adjust_int_max_str_digits(digits):
673 start = get_time()
674 huge_decimal = str(huge_int)
675 seconds_to_convert = get_time() - start
676 self.assertEqual(len(huge_decimal), digits)
677 # Ensuring that we chose a slow enough conversion to measure.
678 # It takes 0.1 seconds on a Zen based cloud VM in an opt build.
679 # Some OSes have a low res 1/64s timer, skip if hard to measure.
680 if seconds_to_convert < 1/64:
681 raise unittest.SkipTest('"slow" conversion took only '
682 f'{seconds_to_convert} seconds.')
683
684 # We test with the limit almost at the size needed to check performance.
685 # The performant limit check is slightly fuzzy, give it a some room.
686 with support.adjust_int_max_str_digits(int(.995 * digits)):
687 with self.assertRaises(ValueError) as err:
688 start = get_time()
689 str(huge_int)
690 seconds_to_fail_huge = get_time() - start
691 self.assertIn('conversion', str(err.exception))
692 self.assertLessEqual(seconds_to_fail_huge, seconds_to_convert/2)
693
694 # Now we test that a conversion that would take 30x as long also fails
695 # in a similarly fast fashion.
696 extra_huge_int = int(f'0x{"c"*500_000}', base=16) # 602060 digits.
697 with self.assertRaises(ValueError) as err:
698 start = get_time()
699 # If not limited, 8 seconds said Zen based cloud VM.
700 str(extra_huge_int)
701 seconds_to_fail_extra_huge = get_time() - start
702 self.assertIn('conversion', str(err.exception))
703 self.assertLess(seconds_to_fail_extra_huge, seconds_to_convert/2)
704
705 def test_denial_of_service_prevented_str_to_int(self):
706 """Regression test: ensure we fail before performing O(N**2) work."""
707 maxdigits = sys.get_int_max_str_digits()
708 assert maxdigits < 100_000, maxdigits # A test prerequisite.
709 get_time = time.process_time
710 if get_time() <= 0: # some platforms like WASM lack process_time()
711 get_time = time.monotonic
712
713 digits = 133700
714 huge = '8'*digits
715 with support.adjust_int_max_str_digits(digits):
716 start = get_time()
717 int(huge)
718 seconds_to_convert = get_time() - start
719 # Ensuring that we chose a slow enough conversion to measure.
720 # It takes 0.1 seconds on a Zen based cloud VM in an opt build.
721 # Some OSes have a low res 1/64s timer, skip if hard to measure.
722 if seconds_to_convert < 1/64:
723 raise unittest.SkipTest('"slow" conversion took only '
724 f'{seconds_to_convert} seconds.')
725
726 with support.adjust_int_max_str_digits(digits - 1):
727 with self.assertRaises(ValueError) as err:
728 start = get_time()
729 int(huge)
730 seconds_to_fail_huge = get_time() - start
731 self.assertIn('conversion', str(err.exception))
732 self.assertLessEqual(seconds_to_fail_huge, seconds_to_convert/2)
733
734 # Now we test that a conversion that would take 30x as long also fails
735 # in a similarly fast fashion.
736 extra_huge = '7'*1_200_000
737 with self.assertRaises(ValueError) as err:
738 start = get_time()
739 # If not limited, 8 seconds in the Zen based cloud VM.
740 int(extra_huge)
741 seconds_to_fail_extra_huge = get_time() - start
742 self.assertIn('conversion', str(err.exception))
743 self.assertLessEqual(seconds_to_fail_extra_huge, seconds_to_convert/2)
744
745 def test_power_of_two_bases_unlimited(self):
746 """The limit does not apply to power of 2 bases."""
747 maxdigits = sys.get_int_max_str_digits()
748
749 for base in (2, 4, 8, 16, 32):
750 with self.subTest(base=base):
751 self.int_class('1' * (maxdigits + 1), base)
752 assert maxdigits < 100_000
753 self.int_class('1' * 100_000, base)
754
755 def test_underscores_ignored(self):
756 maxdigits = sys.get_int_max_str_digits()
757
758 triples = maxdigits // 3
759 s = '111' * triples
760 s_ = '1_11' * triples
761 self.int_class(s) # succeeds
762 self.int_class(s_) # succeeds
763 self.check(f'{s}111')
764 self.check(f'{s_}_111')
765
766 def test_sign_not_counted(self):
767 int_class = self.int_class
768 max_digits = sys.get_int_max_str_digits()
769 s = '5' * max_digits
770 i = int_class(s)
771 pos_i = int_class(f'+{s}')
772 assert i == pos_i
773 neg_i = int_class(f'-{s}')
774 assert -pos_i == neg_i
775 str(pos_i)
776 str(neg_i)
777
778 def _other_base_helper(self, base):
779 int_class = self.int_class
780 max_digits = sys.get_int_max_str_digits()
781 s = '2' * max_digits
782 i = int_class(s, base)
783 if base > 10:
784 with self.assertRaises(ValueError):
785 str(i)
786 elif base < 10:
787 str(i)
788 with self.assertRaises(ValueError) as err:
789 int_class(f'{s}1', base)
790
791 def test_int_from_other_bases(self):
792 base = 3
793 with self.subTest(base=base):
794 self._other_base_helper(base)
795 base = 36
796 with self.subTest(base=base):
797 self._other_base_helper(base)
798
799 def test_int_max_str_digits_is_per_interpreter(self):
800 # Changing the limit in one interpreter does not change others.
801 code = """if 1:
802 # Subinterpreters maintain and enforce their own limit
803 import sys
804 sys.set_int_max_str_digits(2323)
805 try:
806 int('3'*3333)
807 except ValueError:
808 pass
809 else:
810 raise AssertionError('Expected a int max str digits ValueError.')
811 """
812 with support.adjust_int_max_str_digits(4000):
813 before_value = sys.get_int_max_str_digits()
814 self.assertEqual(support.run_in_subinterp(code), 0,
815 'subinterp code failure, check stderr.')
816 after_value = sys.get_int_max_str_digits()
817 self.assertEqual(before_value, after_value)
818
819
820 class ESC[4;38;5;81mIntSubclassStrDigitLimitsTests(ESC[4;38;5;149mIntStrDigitLimitsTests):
821 int_class = IntSubclass
822
823
824 class ESC[4;38;5;81mPyLongModuleTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
825 # Tests of the functions in _pylong.py. Those get used when the
826 # number of digits in the input values are large enough.
827
828 def setUp(self):
829 super().setUp()
830 self._previous_limit = sys.get_int_max_str_digits()
831 sys.set_int_max_str_digits(0)
832
833 def tearDown(self):
834 sys.set_int_max_str_digits(self._previous_limit)
835 super().tearDown()
836
837 def test_pylong_int_to_decimal(self):
838 n = (1 << 100_000) - 1
839 suffix = '9883109375'
840 s = str(n)
841 assert s[-10:] == suffix
842 s = str(-n)
843 assert s[-10:] == suffix
844 s = '%d' % n
845 assert s[-10:] == suffix
846 s = b'%d' % n
847 assert s[-10:] == suffix.encode('ascii')
848
849 def test_pylong_int_divmod(self):
850 n = (1 << 100_000)
851 a, b = divmod(n*3 + 1, n)
852 assert a == 3 and b == 1
853
854 def test_pylong_str_to_int(self):
855 v1 = 1 << 100_000
856 s = str(v1)
857 v2 = int(s)
858 assert v1 == v2
859 v3 = int(' -' + s)
860 assert -v1 == v3
861 v4 = int(' +' + s + ' ')
862 assert v1 == v4
863 with self.assertRaises(ValueError) as err:
864 int(s + 'z')
865 with self.assertRaises(ValueError) as err:
866 int(s + '_')
867 with self.assertRaises(ValueError) as err:
868 int('_' + s)
869
870 @support.cpython_only # tests implementation details of CPython.
871 @unittest.skipUnless(_pylong, "_pylong module required")
872 @mock.patch.object(_pylong, "int_to_decimal_string")
873 def test_pylong_misbehavior_error_path_to_str(
874 self, mock_int_to_str):
875 with support.adjust_int_max_str_digits(20_000):
876 big_value = int('7'*19_999)
877 mock_int_to_str.return_value = None # not a str
878 with self.assertRaises(TypeError) as ctx:
879 str(big_value)
880 self.assertIn('_pylong.int_to_decimal_string did not',
881 str(ctx.exception))
882 mock_int_to_str.side_effect = RuntimeError("testABC")
883 with self.assertRaises(RuntimeError):
884 str(big_value)
885
886 @support.cpython_only # tests implementation details of CPython.
887 @unittest.skipUnless(_pylong, "_pylong module required")
888 @mock.patch.object(_pylong, "int_from_string")
889 def test_pylong_misbehavior_error_path_from_str(
890 self, mock_int_from_str):
891 big_value = '7'*19_999
892 with support.adjust_int_max_str_digits(20_000):
893 mock_int_from_str.return_value = b'not an int'
894 with self.assertRaises(TypeError) as ctx:
895 int(big_value)
896 self.assertIn('_pylong.int_from_string did not',
897 str(ctx.exception))
898
899 mock_int_from_str.side_effect = RuntimeError("test123")
900 with self.assertRaises(RuntimeError):
901 int(big_value)
902
903
904 if __name__ == "__main__":
905 unittest.main()