1import builtins 2import sys 3import unittest 4from typing import Callable, List, Optional, Union 5 6import builtin_support as support 7from builtin_grammar import ( 8 INVALID_UNDERSCORE_LITERALS, 9 VALID_UNDERSCORE_LITERALS, 10) 11 12from fastnumbers import int 13 14L = [ 15 ("0", 0), 16 ("1", 1), 17 ("9", 9), 18 ("10", 10), 19 ("99", 99), 20 ("100", 100), 21 ("314", 314), 22 (" 314", 314), 23 ("314 ", 314), 24 (" \t\t 314 \t\t ", 314), 25 (repr(sys.maxsize), sys.maxsize), 26 (" 1x", ValueError), 27 (" 1 ", 1), 28 (" 1\02 ", ValueError), 29 ("", ValueError), 30 (" ", ValueError), 31 (" \t\t ", ValueError), 32 ("\u0200", ValueError), 33] 34 35 36class IntSubclass(builtins.int): 37 pass 38 39 40class IntTestCases(unittest.TestCase): 41 def test_basic(self) -> None: 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 # type: ignore 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, builtins.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, builtins.int) 78 x = int(-1e100) 79 self.assertIsInstance(x, builtins.int) 80 81 # SF bug 434186: 0x80000000/2 != 0x80000000>>1. 82 # Worked by accident in Windows release build, but failed in debug build. 83 # Failed in all Linux builds. 84 x = -1 - sys.maxsize 85 self.assertEqual(x >> 1, x // 2) 86 87 x = int("1" * 600) 88 self.assertIsInstance(x, builtins.int) 89 90 self.assertRaises(TypeError, int, 1, 12) 91 92 self.assertEqual(int("0o123", 0), 83) 93 self.assertEqual(int("0x123", 16), 291) 94 95 # Bug 1679: "0x" is not a valid hex literal 96 self.assertRaises(ValueError, int, "0x", 16) 97 self.assertRaises(ValueError, int, "0x", 0) 98 99 self.assertRaises(ValueError, int, "0o", 8) 100 self.assertRaises(ValueError, int, "0o", 0) 101 102 self.assertRaises(ValueError, int, "0b", 2) 103 self.assertRaises(ValueError, int, "0b", 0) 104 105 # SF bug 1334662: int(string, base) wrong answers 106 # Various representations of 2**32 evaluated to 0 107 # rather than 2**32 in previous versions 108 109 self.assertEqual(int("100000000000000000000000000000000", 2), 4294967296) 110 self.assertEqual(int("102002022201221111211", 3), 4294967296) 111 self.assertEqual(int("10000000000000000", 4), 4294967296) 112 self.assertEqual(int("32244002423141", 5), 4294967296) 113 self.assertEqual(int("1550104015504", 6), 4294967296) 114 self.assertEqual(int("211301422354", 7), 4294967296) 115 self.assertEqual(int("40000000000", 8), 4294967296) 116 self.assertEqual(int("12068657454", 9), 4294967296) 117 self.assertEqual(int("4294967296", 10), 4294967296) 118 self.assertEqual(int("1904440554", 11), 4294967296) 119 self.assertEqual(int("9ba461594", 12), 4294967296) 120 self.assertEqual(int("535a79889", 13), 4294967296) 121 self.assertEqual(int("2ca5b7464", 14), 4294967296) 122 self.assertEqual(int("1a20dcd81", 15), 4294967296) 123 self.assertEqual(int("100000000", 16), 4294967296) 124 self.assertEqual(int("a7ffda91", 17), 4294967296) 125 self.assertEqual(int("704he7g4", 18), 4294967296) 126 self.assertEqual(int("4f5aff66", 19), 4294967296) 127 self.assertEqual(int("3723ai4g", 20), 4294967296) 128 self.assertEqual(int("281d55i4", 21), 4294967296) 129 self.assertEqual(int("1fj8b184", 22), 4294967296) 130 self.assertEqual(int("1606k7ic", 23), 4294967296) 131 self.assertEqual(int("mb994ag", 24), 4294967296) 132 self.assertEqual(int("hek2mgl", 25), 4294967296) 133 self.assertEqual(int("dnchbnm", 26), 4294967296) 134 self.assertEqual(int("b28jpdm", 27), 4294967296) 135 self.assertEqual(int("8pfgih4", 28), 4294967296) 136 self.assertEqual(int("76beigg", 29), 4294967296) 137 self.assertEqual(int("5qmcpqg", 30), 4294967296) 138 self.assertEqual(int("4q0jto4", 31), 4294967296) 139 self.assertEqual(int("4000000", 32), 4294967296) 140 self.assertEqual(int("3aokq94", 33), 4294967296) 141 self.assertEqual(int("2qhxjli", 34), 4294967296) 142 self.assertEqual(int("2br45qb", 35), 4294967296) 143 self.assertEqual(int("1z141z4", 36), 4294967296) 144 145 # tests with base 0 146 # this fails on 3.0, but in 2.x the old octal syntax is allowed 147 self.assertEqual(int(" 0o123 ", 0), 83) 148 self.assertEqual(int(" 0o123 ", 0), 83) 149 self.assertEqual(int("000", 0), 0) 150 self.assertEqual(int("0o123", 0), 83) 151 self.assertEqual(int("0x123", 0), 291) 152 self.assertEqual(int("0b100", 0), 4) 153 self.assertEqual(int(" 0O123 ", 0), 83) 154 self.assertEqual(int(" 0X123 ", 0), 291) 155 self.assertEqual(int(" 0B100 ", 0), 4) 156 157 # without base still base 10 158 self.assertEqual(int("0123"), 123) 159 self.assertEqual(int("0123", 10), 123) 160 161 # tests with prefix and base != 0 162 self.assertEqual(int("0x123", 16), 291) 163 self.assertEqual(int("0o123", 8), 83) 164 self.assertEqual(int("0b100", 2), 4) 165 self.assertEqual(int("0X123", 16), 291) 166 self.assertEqual(int("0O123", 8), 83) 167 self.assertEqual(int("0B100", 2), 4) 168 169 # the code has special checks for the first character after the 170 # type prefix 171 self.assertRaises(ValueError, int, "0b2", 2) 172 self.assertRaises(ValueError, int, "0b02", 2) 173 self.assertRaises(ValueError, int, "0B2", 2) 174 self.assertRaises(ValueError, int, "0B02", 2) 175 self.assertRaises(ValueError, int, "0o8", 8) 176 self.assertRaises(ValueError, int, "0o08", 8) 177 self.assertRaises(ValueError, int, "0O8", 8) 178 self.assertRaises(ValueError, int, "0O08", 8) 179 self.assertRaises(ValueError, int, "0xg", 16) 180 self.assertRaises(ValueError, int, "0x0g", 16) 181 self.assertRaises(ValueError, int, "0Xg", 16) 182 self.assertRaises(ValueError, int, "0X0g", 16) 183 184 # SF bug 1334662: int(string, base) wrong answers 185 # Checks for proper evaluation of 2**32 + 1 186 self.assertEqual(int("100000000000000000000000000000001", 2), 4294967297) 187 self.assertEqual(int("102002022201221111212", 3), 4294967297) 188 self.assertEqual(int("10000000000000001", 4), 4294967297) 189 self.assertEqual(int("32244002423142", 5), 4294967297) 190 self.assertEqual(int("1550104015505", 6), 4294967297) 191 self.assertEqual(int("211301422355", 7), 4294967297) 192 self.assertEqual(int("40000000001", 8), 4294967297) 193 self.assertEqual(int("12068657455", 9), 4294967297) 194 self.assertEqual(int("4294967297", 10), 4294967297) 195 self.assertEqual(int("1904440555", 11), 4294967297) 196 self.assertEqual(int("9ba461595", 12), 4294967297) 197 self.assertEqual(int("535a7988a", 13), 4294967297) 198 self.assertEqual(int("2ca5b7465", 14), 4294967297) 199 self.assertEqual(int("1a20dcd82", 15), 4294967297) 200 self.assertEqual(int("100000001", 16), 4294967297) 201 self.assertEqual(int("a7ffda92", 17), 4294967297) 202 self.assertEqual(int("704he7g5", 18), 4294967297) 203 self.assertEqual(int("4f5aff67", 19), 4294967297) 204 self.assertEqual(int("3723ai4h", 20), 4294967297) 205 self.assertEqual(int("281d55i5", 21), 4294967297) 206 self.assertEqual(int("1fj8b185", 22), 4294967297) 207 self.assertEqual(int("1606k7id", 23), 4294967297) 208 self.assertEqual(int("mb994ah", 24), 4294967297) 209 self.assertEqual(int("hek2mgm", 25), 4294967297) 210 self.assertEqual(int("dnchbnn", 26), 4294967297) 211 self.assertEqual(int("b28jpdn", 27), 4294967297) 212 self.assertEqual(int("8pfgih5", 28), 4294967297) 213 self.assertEqual(int("76beigh", 29), 4294967297) 214 self.assertEqual(int("5qmcpqh", 30), 4294967297) 215 self.assertEqual(int("4q0jto5", 31), 4294967297) 216 self.assertEqual(int("4000001", 32), 4294967297) 217 self.assertEqual(int("3aokq95", 33), 4294967297) 218 self.assertEqual(int("2qhxjlj", 34), 4294967297) 219 self.assertEqual(int("2br45qc", 35), 4294967297) 220 self.assertEqual(int("1z141z5", 36), 4294967297) 221 222 def test_underscores(self) -> None: 223 for lit in VALID_UNDERSCORE_LITERALS: 224 if any(ch in lit for ch in ".eEjJ"): 225 continue 226 self.assertEqual(int(lit, 0), eval(lit)) 227 self.assertEqual(int(lit, 0), int(lit.replace("_", ""), 0)) 228 for lit in INVALID_UNDERSCORE_LITERALS: 229 if any(ch in lit for ch in ".eEjJ"): 230 continue 231 self.assertRaises(ValueError, int, lit, 0) 232 # Additional test cases with bases != 0, only for the constructor: 233 self.assertEqual(int("1_00", 3), 9) 234 self.assertEqual(int("0_100"), 100) # not valid as a literal! 235 self.assertEqual(int(b"1_00"), 100) # byte underscore 236 self.assertRaises(ValueError, int, "_100") 237 self.assertRaises(ValueError, int, "+_100") 238 self.assertRaises(ValueError, int, "1__00") 239 self.assertRaises(ValueError, int, "100_") 240 241 @support.cpython_only 242 def test_small_ints(self) -> None: 243 # Bug #3236: Return small longs from PyLong_FromString 244 self.assertIs(int("10"), 10) 245 self.assertIs(int("-1"), -1) 246 self.assertIs(int(b"10"), 10) 247 self.assertIs(int(b"-1"), -1) 248 249 def test_no_args(self) -> None: 250 self.assertEqual(int(), 0) 251 252 def test_keyword_args(self) -> None: 253 # Test invoking int() using keyword arguments. 254 self.assertEqual(int("100", base=2), 4) 255 if sys.version_info >= (3, 7): 256 with self.assertRaisesRegex(TypeError, "keyword argument"): 257 int(x=1.2) 258 with self.assertRaisesRegex(TypeError, "keyword argument"): 259 int(x="100", base=2) 260 else: 261 self.assertEqual(int(x=1.2), 1) 262 self.assertEqual(int(x="100", base=2), 4) 263 self.assertRaises(TypeError, int, base=10) 264 self.assertRaises(TypeError, int, base=0) 265 266 def test_int_base_limits(self) -> None: 267 """Testing the supported limits of the int() base parameter.""" 268 self.assertEqual(int("0", 5), 0) 269 with self.assertRaises(ValueError): 270 int("0", 1) 271 with self.assertRaises(ValueError): 272 int("0", 37) 273 with self.assertRaises(ValueError): 274 int("0", -909) # An old magic value base from Python 2. 275 with self.assertRaises(ValueError): 276 int("0", base=0 - (2 ** 234)) 277 with self.assertRaises(ValueError): 278 int("0", base=2 ** 234) 279 # Bases 2 through 36 are supported. 280 for base in range(2, 37): 281 self.assertEqual(int("0", base=base), 0) 282 283 def test_int_base_bad_types(self) -> None: 284 """Not integer types are not valid bases; issue16772.""" 285 with self.assertRaises(TypeError): 286 int("0", 5.5) # type: ignore 287 with self.assertRaises(TypeError): 288 int("0", 5.0) # type: ignore 289 290 def test_int_base_indexable(self) -> None: 291 class MyIndexable(object): 292 def __init__(self, value: builtins.int) -> None: 293 self.value = value 294 295 def __index__(self) -> builtins.int: 296 return self.value 297 298 # Check out of range bases. 299 for base in 2 ** 100, -(2 ** 100), 1, 37: 300 with self.assertRaises(ValueError): 301 int("43", base) 302 303 # Check in-range bases. 304 self.assertEqual(int("101", base=MyIndexable(2)), 5) 305 self.assertEqual(int("101", base=MyIndexable(10)), 101) 306 self.assertEqual(int("101", base=MyIndexable(36)), 1 + 36 ** 2) 307 308 def test_non_numeric_input_types(self) -> None: 309 # Test possible non-numeric types for the argument x, including 310 # subclasses of the explicitly documented accepted types. 311 class CustomStr(str): 312 pass 313 314 class CustomBytes(bytes): 315 pass 316 317 class CustomByteArray(bytearray): 318 pass 319 320 factories: List[Callable[[bytes], Union[bytes, bytearray, str]]] = [ 321 bytes, 322 bytearray, 323 lambda b: CustomStr(b.decode()), 324 CustomBytes, 325 CustomByteArray, 326 memoryview, 327 ] 328 try: 329 from array import array 330 except ImportError: 331 pass 332 else: 333 factories.append(lambda b: array("B", b)) # type: ignore 334 335 for f in factories: 336 x = f(b"100") 337 with self.subTest(type(x)): 338 self.assertEqual(int(x), 100) 339 if isinstance(x, (str, bytes, bytearray)): 340 self.assertEqual(int(x, 2), 4) 341 else: 342 msg = "can't convert non-string" 343 with self.assertRaisesRegex(TypeError, msg): 344 int(x, 2) 345 with self.assertRaisesRegex(ValueError, "invalid literal"): 346 int(f(b"A" * 0x10)) 347 348 def test_int_memoryview(self) -> None: 349 self.assertEqual(int(memoryview(b"123")[1:3]), 23) 350 self.assertEqual(int(memoryview(b"123\x00")[1:3]), 23) 351 self.assertEqual(int(memoryview(b"123 ")[1:3]), 23) 352 self.assertEqual(int(memoryview(b"123A")[1:3]), 23) 353 self.assertEqual(int(memoryview(b"1234")[1:3]), 23) 354 355 def test_string_float(self) -> None: 356 self.assertRaises(ValueError, int, "1.2") 357 358 def test_intconversion(self) -> None: 359 # Test __int__() 360 class ClassicMissingMethods: 361 pass 362 363 self.assertRaises(TypeError, int, ClassicMissingMethods()) 364 365 class MissingMethods(object): 366 pass 367 368 self.assertRaises(TypeError, int, MissingMethods()) 369 370 class Foo0: 371 def __int__(self) -> builtins.int: 372 return 42 373 374 self.assertEqual(int(Foo0()), 42) 375 376 class Classic: 377 pass 378 379 for base in (object, Classic): 380 381 class IntOverridesTrunc(base): # type: ignore 382 def __int__(self) -> builtins.int: 383 return 42 384 385 def __trunc__(self) -> builtins.int: 386 return -12 387 388 self.assertEqual(int(IntOverridesTrunc()), 42) 389 390 @unittest.skipUnless(sys.version_info >= (3, 8), "Test introduced in Python 3.8") 391 def test_int_subclass_with_index(self) -> None: 392 class MyIndex(builtins.int): 393 def __index__(self) -> builtins.int: 394 return 42 395 396 class BadIndex(builtins.int): 397 def __index__(self) -> builtins.float: # type: ignore 398 return 42.0 399 400 my_int = MyIndex(7) 401 self.assertEqual(my_int, 7) 402 self.assertEqual(int(my_int), 7) 403 404 self.assertEqual(int(BadIndex()), 0) 405 406 def test_int_subclass_with_int(self) -> None: 407 class MyInt(builtins.int): 408 def __int__(self) -> builtins.int: 409 return 42 410 411 class BadInt(builtins.int): 412 def __int__(self) -> builtins.float: # type: ignore 413 return 42.0 414 415 my_int = MyInt(7) 416 self.assertEqual(my_int, 7) 417 self.assertEqual(int(my_int), 42) 418 419 if sys.version_info >= (3, 8): 420 my_int = BadInt(7) 421 self.assertEqual(my_int, 7) 422 self.assertRaises(TypeError, int, my_int) 423 else: 424 self.assertRaises(TypeError, int, BadInt()) 425 426 def test_int_returns_int_subclass(self) -> None: 427 class BadIndex: 428 def __index__(self) -> bool: 429 return True 430 431 class BadIndex2(builtins.int): 432 def __index__(self) -> bool: 433 return True 434 435 class BadInt: 436 def __int__(self) -> bool: 437 return True 438 439 class BadInt2(builtins.int): 440 def __int__(self) -> bool: 441 return True 442 443 if sys.version_info >= (3, 8): 444 bad_int = BadIndex() 445 with self.assertWarns(DeprecationWarning): 446 n = int(bad_int) 447 self.assertEqual(n, 1) 448 self.assertIs(type(n), builtins.int) 449 450 bad_int = BadIndex2() 451 n = int(bad_int) 452 self.assertEqual(n, 0) 453 self.assertIs(type(n), builtins.int) 454 455 bad_int = BadInt() 456 with self.assertWarns(DeprecationWarning): 457 n = int(bad_int) 458 self.assertEqual(n, 1) 459 self.assertIs(type(n), builtins.int) 460 461 bad_int2 = BadInt2() 462 with self.assertWarns(DeprecationWarning): 463 n = int(bad_int2) 464 self.assertEqual(n, 1) 465 self.assertIs(type(n), builtins.int) 466 467 def test_error_message(self) -> None: 468 def check(s: Union[str, bytes], base: Optional[builtins.int] = None) -> None: 469 with self.assertRaises(ValueError, msg="int(%r, %r)" % (s, base)) as cm: 470 if base is None: 471 int(s) 472 else: 473 int(s, base) 474 self.assertEqual( 475 cm.exception.args[0], 476 "invalid literal for int() with base %d: %r" 477 % (10 if base is None else base, s), 478 ) 479 480 check("\xbd") 481 check("123\xbd") 482 check(" 123 456 ") 483 484 check("123\x00") 485 # SF bug 1545497: embedded NULs were not detected with explicit base 486 check("123\x00", 10) 487 check("123\x00 245", 20) 488 check("123\x00 245", 16) 489 check("123\x00245", 20) 490 check("123\x00245", 16) 491 # byte string with embedded NUL 492 check(b"123\x00") 493 check(b"123\x00", 10) 494 # non-UTF-8 byte string 495 check(b"123\xbd") 496 check(b"123\xbd", 10) 497 # lone surrogate in Unicode string 498 check("123\ud800") 499 check("123\ud800", 10) 500 501 @unittest.skipUnless(sys.version_info >= (3, 7), "Test introduced in Python 3.7") 502 def test_issue31619(self) -> None: 503 self.assertEqual( 504 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), 505 0b1010101010101010101010101010101, 506 ) 507 self.assertEqual(int("1_2_3_4_5_6_7_0_1_2_3", 8), 0o12345670123) 508 self.assertEqual(int("1_2_3_4_5_6_7_8_9", 16), 0x123456789) 509 self.assertEqual(int("1_2_3_4_5_6_7", 32), 1144132807) 510 511 512if __name__ == "__main__": 513 unittest.main() 514