test_int.py 29 KB

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