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