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