1import builtins
2import codecs
3import gc
4import locale
5import operator
6import os
7import struct
8import subprocess
9import sys
10import sysconfig
11import test.support
12from test import support
13from test.support import os_helper
14from test.support.script_helper import assert_python_ok, assert_python_failure
15from test.support import threading_helper
16from test.support import import_helper
17import textwrap
18import unittest
19import warnings
20
21
22# count the number of test runs, used to create unique
23# strings to intern in test_intern()
24INTERN_NUMRUNS = 0
25
26DICT_KEY_STRUCT_FORMAT = 'n2BI2n'
27
28class DisplayHookTest(unittest.TestCase):
29
30    def test_original_displayhook(self):
31        dh = sys.__displayhook__
32
33        with support.captured_stdout() as out:
34            dh(42)
35
36        self.assertEqual(out.getvalue(), "42\n")
37        self.assertEqual(builtins._, 42)
38
39        del builtins._
40
41        with support.captured_stdout() as out:
42            dh(None)
43
44        self.assertEqual(out.getvalue(), "")
45        self.assertTrue(not hasattr(builtins, "_"))
46
47        # sys.displayhook() requires arguments
48        self.assertRaises(TypeError, dh)
49
50        stdout = sys.stdout
51        try:
52            del sys.stdout
53            self.assertRaises(RuntimeError, dh, 42)
54        finally:
55            sys.stdout = stdout
56
57    def test_lost_displayhook(self):
58        displayhook = sys.displayhook
59        try:
60            del sys.displayhook
61            code = compile("42", "<string>", "single")
62            self.assertRaises(RuntimeError, eval, code)
63        finally:
64            sys.displayhook = displayhook
65
66    def test_custom_displayhook(self):
67        def baddisplayhook(obj):
68            raise ValueError
69
70        with support.swap_attr(sys, 'displayhook', baddisplayhook):
71            code = compile("42", "<string>", "single")
72            self.assertRaises(ValueError, eval, code)
73
74class ActiveExceptionTests(unittest.TestCase):
75    def test_exc_info_no_exception(self):
76        self.assertEqual(sys.exc_info(), (None, None, None))
77
78    def test_sys_exception_no_exception(self):
79        self.assertEqual(sys.exception(), None)
80
81    def test_exc_info_with_exception_instance(self):
82        def f():
83            raise ValueError(42)
84
85        try:
86            f()
87        except Exception as e_:
88            e = e_
89            exc_info = sys.exc_info()
90
91        self.assertIsInstance(e, ValueError)
92        self.assertIs(exc_info[0], ValueError)
93        self.assertIs(exc_info[1], e)
94        self.assertIs(exc_info[2], e.__traceback__)
95
96    def test_exc_info_with_exception_type(self):
97        def f():
98            raise ValueError
99
100        try:
101            f()
102        except Exception as e_:
103            e = e_
104            exc_info = sys.exc_info()
105
106        self.assertIsInstance(e, ValueError)
107        self.assertIs(exc_info[0], ValueError)
108        self.assertIs(exc_info[1], e)
109        self.assertIs(exc_info[2], e.__traceback__)
110
111    def test_sys_exception_with_exception_instance(self):
112        def f():
113            raise ValueError(42)
114
115        try:
116            f()
117        except Exception as e_:
118            e = e_
119            exc = sys.exception()
120
121        self.assertIsInstance(e, ValueError)
122        self.assertIs(exc, e)
123
124    def test_sys_exception_with_exception_type(self):
125        def f():
126            raise ValueError
127
128        try:
129            f()
130        except Exception as e_:
131            e = e_
132            exc = sys.exception()
133
134        self.assertIsInstance(e, ValueError)
135        self.assertIs(exc, e)
136
137
138class ExceptHookTest(unittest.TestCase):
139
140    def test_original_excepthook(self):
141        try:
142            raise ValueError(42)
143        except ValueError as exc:
144            with support.captured_stderr() as err:
145                sys.__excepthook__(*sys.exc_info())
146
147        self.assertTrue(err.getvalue().endswith("ValueError: 42\n"))
148
149        self.assertRaises(TypeError, sys.__excepthook__)
150
151    def test_excepthook_bytes_filename(self):
152        # bpo-37467: sys.excepthook() must not crash if a filename
153        # is a bytes string
154        with warnings.catch_warnings():
155            warnings.simplefilter('ignore', BytesWarning)
156
157            try:
158                raise SyntaxError("msg", (b"bytes_filename", 123, 0, "text"))
159            except SyntaxError as exc:
160                with support.captured_stderr() as err:
161                    sys.__excepthook__(*sys.exc_info())
162
163        err = err.getvalue()
164        self.assertIn("""  File "b'bytes_filename'", line 123\n""", err)
165        self.assertIn("""    text\n""", err)
166        self.assertTrue(err.endswith("SyntaxError: msg\n"))
167
168    def test_excepthook(self):
169        with test.support.captured_output("stderr") as stderr:
170            sys.excepthook(1, '1', 1)
171        self.assertTrue("TypeError: print_exception(): Exception expected for " \
172                         "value, str found" in stderr.getvalue())
173
174    # FIXME: testing the code for a lost or replaced excepthook in
175    # Python/pythonrun.c::PyErr_PrintEx() is tricky.
176
177
178class SysModuleTest(unittest.TestCase):
179
180    def tearDown(self):
181        test.support.reap_children()
182
183    def test_exit(self):
184        # call with two arguments
185        self.assertRaises(TypeError, sys.exit, 42, 42)
186
187        # call without argument
188        with self.assertRaises(SystemExit) as cm:
189            sys.exit()
190        self.assertIsNone(cm.exception.code)
191
192        rc, out, err = assert_python_ok('-c', 'import sys; sys.exit()')
193        self.assertEqual(rc, 0)
194        self.assertEqual(out, b'')
195        self.assertEqual(err, b'')
196
197        # call with integer argument
198        with self.assertRaises(SystemExit) as cm:
199            sys.exit(42)
200        self.assertEqual(cm.exception.code, 42)
201
202        # call with tuple argument with one entry
203        # entry will be unpacked
204        with self.assertRaises(SystemExit) as cm:
205            sys.exit((42,))
206        self.assertEqual(cm.exception.code, 42)
207
208        # call with string argument
209        with self.assertRaises(SystemExit) as cm:
210            sys.exit("exit")
211        self.assertEqual(cm.exception.code, "exit")
212
213        # call with tuple argument with two entries
214        with self.assertRaises(SystemExit) as cm:
215            sys.exit((17, 23))
216        self.assertEqual(cm.exception.code, (17, 23))
217
218        # test that the exit machinery handles SystemExits properly
219        rc, out, err = assert_python_failure('-c', 'raise SystemExit(47)')
220        self.assertEqual(rc, 47)
221        self.assertEqual(out, b'')
222        self.assertEqual(err, b'')
223
224        def check_exit_message(code, expected, **env_vars):
225            rc, out, err = assert_python_failure('-c', code, **env_vars)
226            self.assertEqual(rc, 1)
227            self.assertEqual(out, b'')
228            self.assertTrue(err.startswith(expected),
229                "%s doesn't start with %s" % (ascii(err), ascii(expected)))
230
231        # test that stderr buffer is flushed before the exit message is written
232        # into stderr
233        check_exit_message(
234            r'import sys; sys.stderr.write("unflushed,"); sys.exit("message")',
235            b"unflushed,message")
236
237        # test that the exit message is written with backslashreplace error
238        # handler to stderr
239        check_exit_message(
240            r'import sys; sys.exit("surrogates:\uDCFF")',
241            b"surrogates:\\udcff")
242
243        # test that the unicode message is encoded to the stderr encoding
244        # instead of the default encoding (utf8)
245        check_exit_message(
246            r'import sys; sys.exit("h\xe9")',
247            b"h\xe9", PYTHONIOENCODING='latin-1')
248
249    def test_getdefaultencoding(self):
250        self.assertRaises(TypeError, sys.getdefaultencoding, 42)
251        # can't check more than the type, as the user might have changed it
252        self.assertIsInstance(sys.getdefaultencoding(), str)
253
254    # testing sys.settrace() is done in test_sys_settrace.py
255    # testing sys.setprofile() is done in test_sys_setprofile.py
256
257    def test_switchinterval(self):
258        self.assertRaises(TypeError, sys.setswitchinterval)
259        self.assertRaises(TypeError, sys.setswitchinterval, "a")
260        self.assertRaises(ValueError, sys.setswitchinterval, -1.0)
261        self.assertRaises(ValueError, sys.setswitchinterval, 0.0)
262        orig = sys.getswitchinterval()
263        # sanity check
264        self.assertTrue(orig < 0.5, orig)
265        try:
266            for n in 0.00001, 0.05, 3.0, orig:
267                sys.setswitchinterval(n)
268                self.assertAlmostEqual(sys.getswitchinterval(), n)
269        finally:
270            sys.setswitchinterval(orig)
271
272    def test_recursionlimit(self):
273        self.assertRaises(TypeError, sys.getrecursionlimit, 42)
274        oldlimit = sys.getrecursionlimit()
275        self.assertRaises(TypeError, sys.setrecursionlimit)
276        self.assertRaises(ValueError, sys.setrecursionlimit, -42)
277        sys.setrecursionlimit(10000)
278        self.assertEqual(sys.getrecursionlimit(), 10000)
279        sys.setrecursionlimit(oldlimit)
280
281    def test_recursionlimit_recovery(self):
282        if hasattr(sys, 'gettrace') and sys.gettrace():
283            self.skipTest('fatal error if run with a trace function')
284
285        oldlimit = sys.getrecursionlimit()
286        def f():
287            f()
288        try:
289            for depth in (50, 75, 100, 250, 1000):
290                try:
291                    sys.setrecursionlimit(depth)
292                except RecursionError:
293                    # Issue #25274: The recursion limit is too low at the
294                    # current recursion depth
295                    continue
296
297                # Issue #5392: test stack overflow after hitting recursion
298                # limit twice
299                with self.assertRaises(RecursionError):
300                    f()
301                with self.assertRaises(RecursionError):
302                    f()
303        finally:
304            sys.setrecursionlimit(oldlimit)
305
306    @test.support.cpython_only
307    def test_setrecursionlimit_recursion_depth(self):
308        # Issue #25274: Setting a low recursion limit must be blocked if the
309        # current recursion depth is already higher than limit.
310
311        from _testinternalcapi import get_recursion_depth
312
313        def set_recursion_limit_at_depth(depth, limit):
314            recursion_depth = get_recursion_depth()
315            if recursion_depth >= depth:
316                with self.assertRaises(RecursionError) as cm:
317                    sys.setrecursionlimit(limit)
318                self.assertRegex(str(cm.exception),
319                                 "cannot set the recursion limit to [0-9]+ "
320                                 "at the recursion depth [0-9]+: "
321                                 "the limit is too low")
322            else:
323                set_recursion_limit_at_depth(depth, limit)
324
325        oldlimit = sys.getrecursionlimit()
326        try:
327            sys.setrecursionlimit(1000)
328
329            for limit in (10, 25, 50, 75, 100, 150, 200):
330                set_recursion_limit_at_depth(limit, limit)
331        finally:
332            sys.setrecursionlimit(oldlimit)
333
334    def test_getwindowsversion(self):
335        # Raise SkipTest if sys doesn't have getwindowsversion attribute
336        test.support.get_attribute(sys, "getwindowsversion")
337        v = sys.getwindowsversion()
338        self.assertEqual(len(v), 5)
339        self.assertIsInstance(v[0], int)
340        self.assertIsInstance(v[1], int)
341        self.assertIsInstance(v[2], int)
342        self.assertIsInstance(v[3], int)
343        self.assertIsInstance(v[4], str)
344        self.assertRaises(IndexError, operator.getitem, v, 5)
345        self.assertIsInstance(v.major, int)
346        self.assertIsInstance(v.minor, int)
347        self.assertIsInstance(v.build, int)
348        self.assertIsInstance(v.platform, int)
349        self.assertIsInstance(v.service_pack, str)
350        self.assertIsInstance(v.service_pack_minor, int)
351        self.assertIsInstance(v.service_pack_major, int)
352        self.assertIsInstance(v.suite_mask, int)
353        self.assertIsInstance(v.product_type, int)
354        self.assertEqual(v[0], v.major)
355        self.assertEqual(v[1], v.minor)
356        self.assertEqual(v[2], v.build)
357        self.assertEqual(v[3], v.platform)
358        self.assertEqual(v[4], v.service_pack)
359
360        # This is how platform.py calls it. Make sure tuple
361        #  still has 5 elements
362        maj, min, buildno, plat, csd = sys.getwindowsversion()
363
364    def test_call_tracing(self):
365        self.assertRaises(TypeError, sys.call_tracing, type, 2)
366
367    @unittest.skipUnless(hasattr(sys, "setdlopenflags"),
368                         'test needs sys.setdlopenflags()')
369    def test_dlopenflags(self):
370        self.assertTrue(hasattr(sys, "getdlopenflags"))
371        self.assertRaises(TypeError, sys.getdlopenflags, 42)
372        oldflags = sys.getdlopenflags()
373        self.assertRaises(TypeError, sys.setdlopenflags)
374        sys.setdlopenflags(oldflags+1)
375        self.assertEqual(sys.getdlopenflags(), oldflags+1)
376        sys.setdlopenflags(oldflags)
377
378    @test.support.refcount_test
379    def test_refcount(self):
380        # n here must be a global in order for this test to pass while
381        # tracing with a python function.  Tracing calls PyFrame_FastToLocals
382        # which will add a copy of any locals to the frame object, causing
383        # the reference count to increase by 2 instead of 1.
384        global n
385        self.assertRaises(TypeError, sys.getrefcount)
386        c = sys.getrefcount(None)
387        n = None
388        self.assertEqual(sys.getrefcount(None), c+1)
389        del n
390        self.assertEqual(sys.getrefcount(None), c)
391        if hasattr(sys, "gettotalrefcount"):
392            self.assertIsInstance(sys.gettotalrefcount(), int)
393
394    def test_getframe(self):
395        self.assertRaises(TypeError, sys._getframe, 42, 42)
396        self.assertRaises(ValueError, sys._getframe, 2000000000)
397        self.assertTrue(
398            SysModuleTest.test_getframe.__code__ \
399            is sys._getframe().f_code
400        )
401
402    # sys._current_frames() is a CPython-only gimmick.
403    @threading_helper.reap_threads
404    @threading_helper.requires_working_threading()
405    def test_current_frames(self):
406        import threading
407        import traceback
408
409        # Spawn a thread that blocks at a known place.  Then the main
410        # thread does sys._current_frames(), and verifies that the frames
411        # returned make sense.
412        entered_g = threading.Event()
413        leave_g = threading.Event()
414        thread_info = []  # the thread's id
415
416        def f123():
417            g456()
418
419        def g456():
420            thread_info.append(threading.get_ident())
421            entered_g.set()
422            leave_g.wait()
423
424        t = threading.Thread(target=f123)
425        t.start()
426        entered_g.wait()
427
428        # At this point, t has finished its entered_g.set(), although it's
429        # impossible to guess whether it's still on that line or has moved on
430        # to its leave_g.wait().
431        self.assertEqual(len(thread_info), 1)
432        thread_id = thread_info[0]
433
434        d = sys._current_frames()
435        for tid in d:
436            self.assertIsInstance(tid, int)
437            self.assertGreater(tid, 0)
438
439        main_id = threading.get_ident()
440        self.assertIn(main_id, d)
441        self.assertIn(thread_id, d)
442
443        # Verify that the captured main-thread frame is _this_ frame.
444        frame = d.pop(main_id)
445        self.assertTrue(frame is sys._getframe())
446
447        # Verify that the captured thread frame is blocked in g456, called
448        # from f123.  This is a little tricky, since various bits of
449        # threading.py are also in the thread's call stack.
450        frame = d.pop(thread_id)
451        stack = traceback.extract_stack(frame)
452        for i, (filename, lineno, funcname, sourceline) in enumerate(stack):
453            if funcname == "f123":
454                break
455        else:
456            self.fail("didn't find f123() on thread's call stack")
457
458        self.assertEqual(sourceline, "g456()")
459
460        # And the next record must be for g456().
461        filename, lineno, funcname, sourceline = stack[i+1]
462        self.assertEqual(funcname, "g456")
463        self.assertIn(sourceline, ["leave_g.wait()", "entered_g.set()"])
464
465        # Reap the spawned thread.
466        leave_g.set()
467        t.join()
468
469    @threading_helper.reap_threads
470    @threading_helper.requires_working_threading()
471    def test_current_exceptions(self):
472        import threading
473        import traceback
474
475        # Spawn a thread that blocks at a known place.  Then the main
476        # thread does sys._current_frames(), and verifies that the frames
477        # returned make sense.
478        entered_g = threading.Event()
479        leave_g = threading.Event()
480        thread_info = []  # the thread's id
481
482        def f123():
483            g456()
484
485        def g456():
486            thread_info.append(threading.get_ident())
487            entered_g.set()
488            while True:
489                try:
490                    raise ValueError("oops")
491                except ValueError:
492                    if leave_g.wait(timeout=support.LONG_TIMEOUT):
493                        break
494
495        t = threading.Thread(target=f123)
496        t.start()
497        entered_g.wait()
498
499        # At this point, t has finished its entered_g.set(), although it's
500        # impossible to guess whether it's still on that line or has moved on
501        # to its leave_g.wait().
502        self.assertEqual(len(thread_info), 1)
503        thread_id = thread_info[0]
504
505        d = sys._current_exceptions()
506        for tid in d:
507            self.assertIsInstance(tid, int)
508            self.assertGreater(tid, 0)
509
510        main_id = threading.get_ident()
511        self.assertIn(main_id, d)
512        self.assertIn(thread_id, d)
513        self.assertEqual((None, None, None), d.pop(main_id))
514
515        # Verify that the captured thread frame is blocked in g456, called
516        # from f123.  This is a little tricky, since various bits of
517        # threading.py are also in the thread's call stack.
518        exc_type, exc_value, exc_tb = d.pop(thread_id)
519        stack = traceback.extract_stack(exc_tb.tb_frame)
520        for i, (filename, lineno, funcname, sourceline) in enumerate(stack):
521            if funcname == "f123":
522                break
523        else:
524            self.fail("didn't find f123() on thread's call stack")
525
526        self.assertEqual(sourceline, "g456()")
527
528        # And the next record must be for g456().
529        filename, lineno, funcname, sourceline = stack[i+1]
530        self.assertEqual(funcname, "g456")
531        self.assertTrue(sourceline.startswith("if leave_g.wait("))
532
533        # Reap the spawned thread.
534        leave_g.set()
535        t.join()
536
537    def test_attributes(self):
538        self.assertIsInstance(sys.api_version, int)
539        self.assertIsInstance(sys.argv, list)
540        for arg in sys.argv:
541            self.assertIsInstance(arg, str)
542        self.assertIsInstance(sys.orig_argv, list)
543        for arg in sys.orig_argv:
544            self.assertIsInstance(arg, str)
545        self.assertIn(sys.byteorder, ("little", "big"))
546        self.assertIsInstance(sys.builtin_module_names, tuple)
547        self.assertIsInstance(sys.copyright, str)
548        self.assertIsInstance(sys.exec_prefix, str)
549        self.assertIsInstance(sys.base_exec_prefix, str)
550        self.assertIsInstance(sys.executable, str)
551        self.assertEqual(len(sys.float_info), 11)
552        self.assertEqual(sys.float_info.radix, 2)
553        self.assertEqual(len(sys.int_info), 4)
554        self.assertTrue(sys.int_info.bits_per_digit % 5 == 0)
555        self.assertTrue(sys.int_info.sizeof_digit >= 1)
556        self.assertGreaterEqual(sys.int_info.default_max_str_digits, 500)
557        self.assertGreaterEqual(sys.int_info.str_digits_check_threshold, 100)
558        self.assertGreater(sys.int_info.default_max_str_digits,
559                           sys.int_info.str_digits_check_threshold)
560        self.assertEqual(type(sys.int_info.bits_per_digit), int)
561        self.assertEqual(type(sys.int_info.sizeof_digit), int)
562        self.assertIsInstance(sys.int_info.default_max_str_digits, int)
563        self.assertIsInstance(sys.int_info.str_digits_check_threshold, int)
564        self.assertIsInstance(sys.hexversion, int)
565
566        self.assertEqual(len(sys.hash_info), 9)
567        self.assertLess(sys.hash_info.modulus, 2**sys.hash_info.width)
568        # sys.hash_info.modulus should be a prime; we do a quick
569        # probable primality test (doesn't exclude the possibility of
570        # a Carmichael number)
571        for x in range(1, 100):
572            self.assertEqual(
573                pow(x, sys.hash_info.modulus-1, sys.hash_info.modulus),
574                1,
575                "sys.hash_info.modulus {} is a non-prime".format(
576                    sys.hash_info.modulus)
577                )
578        self.assertIsInstance(sys.hash_info.inf, int)
579        self.assertIsInstance(sys.hash_info.nan, int)
580        self.assertIsInstance(sys.hash_info.imag, int)
581        algo = sysconfig.get_config_var("Py_HASH_ALGORITHM")
582        if sys.hash_info.algorithm in {"fnv", "siphash13", "siphash24"}:
583            self.assertIn(sys.hash_info.hash_bits, {32, 64})
584            self.assertIn(sys.hash_info.seed_bits, {32, 64, 128})
585
586            if algo == 1:
587                self.assertEqual(sys.hash_info.algorithm, "siphash24")
588            elif algo == 2:
589                self.assertEqual(sys.hash_info.algorithm, "fnv")
590            elif algo == 3:
591                self.assertEqual(sys.hash_info.algorithm, "siphash13")
592            else:
593                self.assertIn(sys.hash_info.algorithm, {"fnv", "siphash13", "siphash24"})
594        else:
595            # PY_HASH_EXTERNAL
596            self.assertEqual(algo, 0)
597        self.assertGreaterEqual(sys.hash_info.cutoff, 0)
598        self.assertLess(sys.hash_info.cutoff, 8)
599
600        self.assertIsInstance(sys.maxsize, int)
601        self.assertIsInstance(sys.maxunicode, int)
602        self.assertEqual(sys.maxunicode, 0x10FFFF)
603        self.assertIsInstance(sys.platform, str)
604        self.assertIsInstance(sys.prefix, str)
605        self.assertIsInstance(sys.base_prefix, str)
606        self.assertIsInstance(sys.platlibdir, str)
607        self.assertIsInstance(sys.version, str)
608        vi = sys.version_info
609        self.assertIsInstance(vi[:], tuple)
610        self.assertEqual(len(vi), 5)
611        self.assertIsInstance(vi[0], int)
612        self.assertIsInstance(vi[1], int)
613        self.assertIsInstance(vi[2], int)
614        self.assertIn(vi[3], ("alpha", "beta", "candidate", "final"))
615        self.assertIsInstance(vi[4], int)
616        self.assertIsInstance(vi.major, int)
617        self.assertIsInstance(vi.minor, int)
618        self.assertIsInstance(vi.micro, int)
619        self.assertIn(vi.releaselevel, ("alpha", "beta", "candidate", "final"))
620        self.assertIsInstance(vi.serial, int)
621        self.assertEqual(vi[0], vi.major)
622        self.assertEqual(vi[1], vi.minor)
623        self.assertEqual(vi[2], vi.micro)
624        self.assertEqual(vi[3], vi.releaselevel)
625        self.assertEqual(vi[4], vi.serial)
626        self.assertTrue(vi > (1,0,0))
627        self.assertIsInstance(sys.float_repr_style, str)
628        self.assertIn(sys.float_repr_style, ('short', 'legacy'))
629        if not sys.platform.startswith('win'):
630            self.assertIsInstance(sys.abiflags, str)
631
632    def test_thread_info(self):
633        info = sys.thread_info
634        self.assertEqual(len(info), 3)
635        self.assertIn(info.name, ('nt', 'pthread', 'pthread-stubs', 'solaris', None))
636        self.assertIn(info.lock, ('semaphore', 'mutex+cond', None))
637        if sys.platform.startswith(("linux", "freebsd")):
638            self.assertEqual(info.name, "pthread")
639        elif sys.platform == "win32":
640            self.assertEqual(info.name, "nt")
641        elif sys.platform == "emscripten":
642            self.assertIn(info.name, {"pthread", "pthread-stubs"})
643        elif sys.platform == "wasi":
644            self.assertEqual(info.name, "pthread-stubs")
645
646    @unittest.skipUnless(support.is_emscripten, "only available on Emscripten")
647    def test_emscripten_info(self):
648        self.assertEqual(len(sys._emscripten_info), 4)
649        self.assertIsInstance(sys._emscripten_info.emscripten_version, tuple)
650        self.assertIsInstance(sys._emscripten_info.runtime, (str, type(None)))
651        self.assertIsInstance(sys._emscripten_info.pthreads, bool)
652        self.assertIsInstance(sys._emscripten_info.shared_memory, bool)
653
654    def test_43581(self):
655        # Can't use sys.stdout, as this is a StringIO object when
656        # the test runs under regrtest.
657        self.assertEqual(sys.__stdout__.encoding, sys.__stderr__.encoding)
658
659    def test_intern(self):
660        global INTERN_NUMRUNS
661        INTERN_NUMRUNS += 1
662        self.assertRaises(TypeError, sys.intern)
663        s = "never interned before" + str(INTERN_NUMRUNS)
664        self.assertTrue(sys.intern(s) is s)
665        s2 = s.swapcase().swapcase()
666        self.assertTrue(sys.intern(s2) is s)
667
668        # Subclasses of string can't be interned, because they
669        # provide too much opportunity for insane things to happen.
670        # We don't want them in the interned dict and if they aren't
671        # actually interned, we don't want to create the appearance
672        # that they are by allowing intern() to succeed.
673        class S(str):
674            def __hash__(self):
675                return 123
676
677        self.assertRaises(TypeError, sys.intern, S("abc"))
678
679    def test_sys_flags(self):
680        self.assertTrue(sys.flags)
681        attrs = ("debug",
682                 "inspect", "interactive", "optimize",
683                 "dont_write_bytecode", "no_user_site", "no_site",
684                 "ignore_environment", "verbose", "bytes_warning", "quiet",
685                 "hash_randomization", "isolated", "dev_mode", "utf8_mode",
686                 "warn_default_encoding", "safe_path", "int_max_str_digits")
687        for attr in attrs:
688            self.assertTrue(hasattr(sys.flags, attr), attr)
689            attr_type = bool if attr in ("dev_mode", "safe_path") else int
690            self.assertEqual(type(getattr(sys.flags, attr)), attr_type, attr)
691        self.assertTrue(repr(sys.flags))
692        self.assertEqual(len(sys.flags), len(attrs))
693
694        self.assertIn(sys.flags.utf8_mode, {0, 1, 2})
695
696    def assert_raise_on_new_sys_type(self, sys_attr):
697        # Users are intentionally prevented from creating new instances of
698        # sys.flags, sys.version_info, and sys.getwindowsversion.
699        arg = sys_attr
700        attr_type = type(sys_attr)
701        with self.assertRaises(TypeError):
702            attr_type(arg)
703        with self.assertRaises(TypeError):
704            attr_type.__new__(attr_type, arg)
705
706    def test_sys_flags_no_instantiation(self):
707        self.assert_raise_on_new_sys_type(sys.flags)
708
709    def test_sys_version_info_no_instantiation(self):
710        self.assert_raise_on_new_sys_type(sys.version_info)
711
712    def test_sys_getwindowsversion_no_instantiation(self):
713        # Skip if not being run on Windows.
714        test.support.get_attribute(sys, "getwindowsversion")
715        self.assert_raise_on_new_sys_type(sys.getwindowsversion())
716
717    @test.support.cpython_only
718    def test_clear_type_cache(self):
719        sys._clear_type_cache()
720
721    @support.requires_subprocess()
722    def test_ioencoding(self):
723        env = dict(os.environ)
724
725        # Test character: cent sign, encoded as 0x4A (ASCII J) in CP424,
726        # not representable in ASCII.
727
728        env["PYTHONIOENCODING"] = "cp424"
729        p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xa2))'],
730                             stdout = subprocess.PIPE, env=env)
731        out = p.communicate()[0].strip()
732        expected = ("\xa2" + os.linesep).encode("cp424")
733        self.assertEqual(out, expected)
734
735        env["PYTHONIOENCODING"] = "ascii:replace"
736        p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xa2))'],
737                             stdout = subprocess.PIPE, env=env)
738        out = p.communicate()[0].strip()
739        self.assertEqual(out, b'?')
740
741        env["PYTHONIOENCODING"] = "ascii"
742        p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xa2))'],
743                             stdout=subprocess.PIPE, stderr=subprocess.PIPE,
744                             env=env)
745        out, err = p.communicate()
746        self.assertEqual(out, b'')
747        self.assertIn(b'UnicodeEncodeError:', err)
748        self.assertIn(rb"'\xa2'", err)
749
750        env["PYTHONIOENCODING"] = "ascii:"
751        p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xa2))'],
752                             stdout=subprocess.PIPE, stderr=subprocess.PIPE,
753                             env=env)
754        out, err = p.communicate()
755        self.assertEqual(out, b'')
756        self.assertIn(b'UnicodeEncodeError:', err)
757        self.assertIn(rb"'\xa2'", err)
758
759        env["PYTHONIOENCODING"] = ":surrogateescape"
760        p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xdcbd))'],
761                             stdout=subprocess.PIPE, env=env)
762        out = p.communicate()[0].strip()
763        self.assertEqual(out, b'\xbd')
764
765    @unittest.skipUnless(os_helper.FS_NONASCII,
766                         'requires OS support of non-ASCII encodings')
767    @unittest.skipUnless(sys.getfilesystemencoding() == locale.getpreferredencoding(False),
768                         'requires FS encoding to match locale')
769    @support.requires_subprocess()
770    def test_ioencoding_nonascii(self):
771        env = dict(os.environ)
772
773        env["PYTHONIOENCODING"] = ""
774        p = subprocess.Popen([sys.executable, "-c",
775                                'print(%a)' % os_helper.FS_NONASCII],
776                                stdout=subprocess.PIPE, env=env)
777        out = p.communicate()[0].strip()
778        self.assertEqual(out, os.fsencode(os_helper.FS_NONASCII))
779
780    @unittest.skipIf(sys.base_prefix != sys.prefix,
781                     'Test is not venv-compatible')
782    @support.requires_subprocess()
783    def test_executable(self):
784        # sys.executable should be absolute
785        self.assertEqual(os.path.abspath(sys.executable), sys.executable)
786
787        # Issue #7774: Ensure that sys.executable is an empty string if argv[0]
788        # has been set to a non existent program name and Python is unable to
789        # retrieve the real program name
790
791        # For a normal installation, it should work without 'cwd'
792        # argument. For test runs in the build directory, see #7774.
793        python_dir = os.path.dirname(os.path.realpath(sys.executable))
794        p = subprocess.Popen(
795            ["nonexistent", "-c",
796             'import sys; print(sys.executable.encode("ascii", "backslashreplace"))'],
797            executable=sys.executable, stdout=subprocess.PIPE, cwd=python_dir)
798        stdout = p.communicate()[0]
799        executable = stdout.strip().decode("ASCII")
800        p.wait()
801        self.assertIn(executable, ["b''", repr(sys.executable.encode("ascii", "backslashreplace"))])
802
803    def check_fsencoding(self, fs_encoding, expected=None):
804        self.assertIsNotNone(fs_encoding)
805        codecs.lookup(fs_encoding)
806        if expected:
807            self.assertEqual(fs_encoding, expected)
808
809    def test_getfilesystemencoding(self):
810        fs_encoding = sys.getfilesystemencoding()
811        if sys.platform == 'darwin':
812            expected = 'utf-8'
813        else:
814            expected = None
815        self.check_fsencoding(fs_encoding, expected)
816
817    def c_locale_get_error_handler(self, locale, isolated=False, encoding=None):
818        # Force the POSIX locale
819        env = os.environ.copy()
820        env["LC_ALL"] = locale
821        env["PYTHONCOERCECLOCALE"] = "0"
822        code = '\n'.join((
823            'import sys',
824            'def dump(name):',
825            '    std = getattr(sys, name)',
826            '    print("%s: %s" % (name, std.errors))',
827            'dump("stdin")',
828            'dump("stdout")',
829            'dump("stderr")',
830        ))
831        args = [sys.executable, "-X", "utf8=0", "-c", code]
832        if isolated:
833            args.append("-I")
834        if encoding is not None:
835            env['PYTHONIOENCODING'] = encoding
836        else:
837            env.pop('PYTHONIOENCODING', None)
838        p = subprocess.Popen(args,
839                              stdout=subprocess.PIPE,
840                              stderr=subprocess.STDOUT,
841                              env=env,
842                              universal_newlines=True)
843        stdout, stderr = p.communicate()
844        return stdout
845
846    def check_locale_surrogateescape(self, locale):
847        out = self.c_locale_get_error_handler(locale, isolated=True)
848        self.assertEqual(out,
849                         'stdin: surrogateescape\n'
850                         'stdout: surrogateescape\n'
851                         'stderr: backslashreplace\n')
852
853        # replace the default error handler
854        out = self.c_locale_get_error_handler(locale, encoding=':ignore')
855        self.assertEqual(out,
856                         'stdin: ignore\n'
857                         'stdout: ignore\n'
858                         'stderr: backslashreplace\n')
859
860        # force the encoding
861        out = self.c_locale_get_error_handler(locale, encoding='iso8859-1')
862        self.assertEqual(out,
863                         'stdin: strict\n'
864                         'stdout: strict\n'
865                         'stderr: backslashreplace\n')
866        out = self.c_locale_get_error_handler(locale, encoding='iso8859-1:')
867        self.assertEqual(out,
868                         'stdin: strict\n'
869                         'stdout: strict\n'
870                         'stderr: backslashreplace\n')
871
872        # have no any effect
873        out = self.c_locale_get_error_handler(locale, encoding=':')
874        self.assertEqual(out,
875                         'stdin: surrogateescape\n'
876                         'stdout: surrogateescape\n'
877                         'stderr: backslashreplace\n')
878        out = self.c_locale_get_error_handler(locale, encoding='')
879        self.assertEqual(out,
880                         'stdin: surrogateescape\n'
881                         'stdout: surrogateescape\n'
882                         'stderr: backslashreplace\n')
883
884    @support.requires_subprocess()
885    def test_c_locale_surrogateescape(self):
886        self.check_locale_surrogateescape('C')
887
888    @support.requires_subprocess()
889    def test_posix_locale_surrogateescape(self):
890        self.check_locale_surrogateescape('POSIX')
891
892    def test_implementation(self):
893        # This test applies to all implementations equally.
894
895        levels = {'alpha': 0xA, 'beta': 0xB, 'candidate': 0xC, 'final': 0xF}
896
897        self.assertTrue(hasattr(sys.implementation, 'name'))
898        self.assertTrue(hasattr(sys.implementation, 'version'))
899        self.assertTrue(hasattr(sys.implementation, 'hexversion'))
900        self.assertTrue(hasattr(sys.implementation, 'cache_tag'))
901
902        version = sys.implementation.version
903        self.assertEqual(version[:2], (version.major, version.minor))
904
905        hexversion = (version.major << 24 | version.minor << 16 |
906                      version.micro << 8 | levels[version.releaselevel] << 4 |
907                      version.serial << 0)
908        self.assertEqual(sys.implementation.hexversion, hexversion)
909
910        # PEP 421 requires that .name be lower case.
911        self.assertEqual(sys.implementation.name,
912                         sys.implementation.name.lower())
913
914    @test.support.cpython_only
915    def test_debugmallocstats(self):
916        # Test sys._debugmallocstats()
917        from test.support.script_helper import assert_python_ok
918        args = ['-c', 'import sys; sys._debugmallocstats()']
919        ret, out, err = assert_python_ok(*args)
920
921        # Output of sys._debugmallocstats() depends on configure flags.
922        # The sysconfig vars are not available on Windows.
923        if sys.platform != "win32":
924            with_freelists = sysconfig.get_config_var("WITH_FREELISTS")
925            with_pymalloc = sysconfig.get_config_var("WITH_PYMALLOC")
926            if with_freelists:
927                self.assertIn(b"free PyDictObjects", err)
928            if with_pymalloc:
929                self.assertIn(b'Small block threshold', err)
930            if not with_freelists and not with_pymalloc:
931                self.assertFalse(err)
932
933        # The function has no parameter
934        self.assertRaises(TypeError, sys._debugmallocstats, True)
935
936    @unittest.skipUnless(hasattr(sys, "getallocatedblocks"),
937                         "sys.getallocatedblocks unavailable on this build")
938    def test_getallocatedblocks(self):
939        try:
940            import _testcapi
941        except ImportError:
942            with_pymalloc = support.with_pymalloc()
943        else:
944            try:
945                alloc_name = _testcapi.pymem_getallocatorsname()
946            except RuntimeError as exc:
947                # "cannot get allocators name" (ex: tracemalloc is used)
948                with_pymalloc = True
949            else:
950                with_pymalloc = (alloc_name in ('pymalloc', 'pymalloc_debug'))
951
952        # Some sanity checks
953        a = sys.getallocatedblocks()
954        self.assertIs(type(a), int)
955        if with_pymalloc:
956            self.assertGreater(a, 0)
957        else:
958            # When WITH_PYMALLOC isn't available, we don't know anything
959            # about the underlying implementation: the function might
960            # return 0 or something greater.
961            self.assertGreaterEqual(a, 0)
962        try:
963            # While we could imagine a Python session where the number of
964            # multiple buffer objects would exceed the sharing of references,
965            # it is unlikely to happen in a normal test run.
966            self.assertLess(a, sys.gettotalrefcount())
967        except AttributeError:
968            # gettotalrefcount() not available
969            pass
970        gc.collect()
971        b = sys.getallocatedblocks()
972        self.assertLessEqual(b, a)
973        gc.collect()
974        c = sys.getallocatedblocks()
975        self.assertIn(c, range(b - 50, b + 50))
976
977    def test_is_finalizing(self):
978        self.assertIs(sys.is_finalizing(), False)
979        # Don't use the atexit module because _Py_Finalizing is only set
980        # after calling atexit callbacks
981        code = """if 1:
982            import sys
983
984            class AtExit:
985                is_finalizing = sys.is_finalizing
986                print = print
987
988                def __del__(self):
989                    self.print(self.is_finalizing(), flush=True)
990
991            # Keep a reference in the __main__ module namespace, so the
992            # AtExit destructor will be called at Python exit
993            ref = AtExit()
994        """
995        rc, stdout, stderr = assert_python_ok('-c', code)
996        self.assertEqual(stdout.rstrip(), b'True')
997
998    def test_issue20602(self):
999        # sys.flags and sys.float_info were wiped during shutdown.
1000        code = """if 1:
1001            import sys
1002            class A:
1003                def __del__(self, sys=sys):
1004                    print(sys.flags)
1005                    print(sys.float_info)
1006            a = A()
1007            """
1008        rc, out, err = assert_python_ok('-c', code)
1009        out = out.splitlines()
1010        self.assertIn(b'sys.flags', out[0])
1011        self.assertIn(b'sys.float_info', out[1])
1012
1013    def test_sys_ignores_cleaning_up_user_data(self):
1014        code = """if 1:
1015            import struct, sys
1016
1017            class C:
1018                def __init__(self):
1019                    self.pack = struct.pack
1020                def __del__(self):
1021                    self.pack('I', -42)
1022
1023            sys.x = C()
1024            """
1025        rc, stdout, stderr = assert_python_ok('-c', code)
1026        self.assertEqual(rc, 0)
1027        self.assertEqual(stdout.rstrip(), b"")
1028        self.assertEqual(stderr.rstrip(), b"")
1029
1030    @unittest.skipUnless(hasattr(sys, 'getandroidapilevel'),
1031                         'need sys.getandroidapilevel()')
1032    def test_getandroidapilevel(self):
1033        level = sys.getandroidapilevel()
1034        self.assertIsInstance(level, int)
1035        self.assertGreater(level, 0)
1036
1037    @support.requires_subprocess()
1038    def test_sys_tracebacklimit(self):
1039        code = """if 1:
1040            import sys
1041            def f1():
1042                1 / 0
1043            def f2():
1044                f1()
1045            sys.tracebacklimit = %r
1046            f2()
1047        """
1048        def check(tracebacklimit, expected):
1049            p = subprocess.Popen([sys.executable, '-c', code % tracebacklimit],
1050                                 stderr=subprocess.PIPE)
1051            out = p.communicate()[1]
1052            self.assertEqual(out.splitlines(), expected)
1053
1054        traceback = [
1055            b'Traceback (most recent call last):',
1056            b'  File "<string>", line 8, in <module>',
1057            b'  File "<string>", line 6, in f2',
1058            b'  File "<string>", line 4, in f1',
1059            b'ZeroDivisionError: division by zero'
1060        ]
1061        check(10, traceback)
1062        check(3, traceback)
1063        check(2, traceback[:1] + traceback[2:])
1064        check(1, traceback[:1] + traceback[3:])
1065        check(0, [traceback[-1]])
1066        check(-1, [traceback[-1]])
1067        check(1<<1000, traceback)
1068        check(-1<<1000, [traceback[-1]])
1069        check(None, traceback)
1070
1071    def test_no_duplicates_in_meta_path(self):
1072        self.assertEqual(len(sys.meta_path), len(set(sys.meta_path)))
1073
1074    @unittest.skipUnless(hasattr(sys, "_enablelegacywindowsfsencoding"),
1075                         'needs sys._enablelegacywindowsfsencoding()')
1076    def test__enablelegacywindowsfsencoding(self):
1077        code = ('import sys',
1078                'sys._enablelegacywindowsfsencoding()',
1079                'print(sys.getfilesystemencoding(), sys.getfilesystemencodeerrors())')
1080        rc, out, err = assert_python_ok('-c', '; '.join(code))
1081        out = out.decode('ascii', 'replace').rstrip()
1082        self.assertEqual(out, 'mbcs replace')
1083
1084    @support.requires_subprocess()
1085    def test_orig_argv(self):
1086        code = textwrap.dedent('''
1087            import sys
1088            print(sys.argv)
1089            print(sys.orig_argv)
1090        ''')
1091        args = [sys.executable, '-I', '-X', 'utf8', '-c', code, 'arg']
1092        proc = subprocess.run(args, check=True, capture_output=True, text=True)
1093        expected = [
1094            repr(['-c', 'arg']),  # sys.argv
1095            repr(args),  # sys.orig_argv
1096        ]
1097        self.assertEqual(proc.stdout.rstrip().splitlines(), expected,
1098                         proc)
1099
1100    def test_module_names(self):
1101        self.assertIsInstance(sys.stdlib_module_names, frozenset)
1102        for name in sys.stdlib_module_names:
1103            self.assertIsInstance(name, str)
1104
1105    def test_stdlib_dir(self):
1106        os = import_helper.import_fresh_module('os')
1107        marker = getattr(os, '__file__', None)
1108        if marker and not os.path.exists(marker):
1109            marker = None
1110        expected = os.path.dirname(marker) if marker else None
1111        self.assertEqual(os.path.normpath(sys._stdlib_dir),
1112                         os.path.normpath(expected))
1113
1114
1115@test.support.cpython_only
1116class UnraisableHookTest(unittest.TestCase):
1117    def write_unraisable_exc(self, exc, err_msg, obj):
1118        import _testcapi
1119        import types
1120        err_msg2 = f"Exception ignored {err_msg}"
1121        try:
1122            _testcapi.write_unraisable_exc(exc, err_msg, obj)
1123            return types.SimpleNamespace(exc_type=type(exc),
1124                                         exc_value=exc,
1125                                         exc_traceback=exc.__traceback__,
1126                                         err_msg=err_msg2,
1127                                         object=obj)
1128        finally:
1129            # Explicitly break any reference cycle
1130            exc = None
1131
1132    def test_original_unraisablehook(self):
1133        for err_msg in (None, "original hook"):
1134            with self.subTest(err_msg=err_msg):
1135                obj = "an object"
1136
1137                with test.support.captured_output("stderr") as stderr:
1138                    with test.support.swap_attr(sys, 'unraisablehook',
1139                                                sys.__unraisablehook__):
1140                        self.write_unraisable_exc(ValueError(42), err_msg, obj)
1141
1142                err = stderr.getvalue()
1143                if err_msg is not None:
1144                    self.assertIn(f'Exception ignored {err_msg}: {obj!r}\n', err)
1145                else:
1146                    self.assertIn(f'Exception ignored in: {obj!r}\n', err)
1147                self.assertIn('Traceback (most recent call last):\n', err)
1148                self.assertIn('ValueError: 42\n', err)
1149
1150    def test_original_unraisablehook_err(self):
1151        # bpo-22836: PyErr_WriteUnraisable() should give sensible reports
1152        class BrokenDel:
1153            def __del__(self):
1154                exc = ValueError("del is broken")
1155                # The following line is included in the traceback report:
1156                raise exc
1157
1158        class BrokenStrException(Exception):
1159            def __str__(self):
1160                raise Exception("str() is broken")
1161
1162        class BrokenExceptionDel:
1163            def __del__(self):
1164                exc = BrokenStrException()
1165                # The following line is included in the traceback report:
1166                raise exc
1167
1168        for test_class in (BrokenDel, BrokenExceptionDel):
1169            with self.subTest(test_class):
1170                obj = test_class()
1171                with test.support.captured_stderr() as stderr, \
1172                     test.support.swap_attr(sys, 'unraisablehook',
1173                                            sys.__unraisablehook__):
1174                    # Trigger obj.__del__()
1175                    del obj
1176
1177                report = stderr.getvalue()
1178                self.assertIn("Exception ignored", report)
1179                self.assertIn(test_class.__del__.__qualname__, report)
1180                self.assertIn("test_sys.py", report)
1181                self.assertIn("raise exc", report)
1182                if test_class is BrokenExceptionDel:
1183                    self.assertIn("BrokenStrException", report)
1184                    self.assertIn("<exception str() failed>", report)
1185                else:
1186                    self.assertIn("ValueError", report)
1187                    self.assertIn("del is broken", report)
1188                self.assertTrue(report.endswith("\n"))
1189
1190    def test_original_unraisablehook_exception_qualname(self):
1191        # See bpo-41031, bpo-45083.
1192        # Check that the exception is printed with its qualified name
1193        # rather than just classname, and the module names appears
1194        # unless it is one of the hard-coded exclusions.
1195        class A:
1196            class B:
1197                class X(Exception):
1198                    pass
1199
1200        for moduleName in 'builtins', '__main__', 'some_module':
1201            with self.subTest(moduleName=moduleName):
1202                A.B.X.__module__ = moduleName
1203                with test.support.captured_stderr() as stderr, test.support.swap_attr(
1204                    sys, 'unraisablehook', sys.__unraisablehook__
1205                ):
1206                    expected = self.write_unraisable_exc(
1207                        A.B.X(), "msg", "obj"
1208                    )
1209                report = stderr.getvalue()
1210                self.assertIn(A.B.X.__qualname__, report)
1211                if moduleName in ['builtins', '__main__']:
1212                    self.assertNotIn(moduleName + '.', report)
1213                else:
1214                    self.assertIn(moduleName + '.', report)
1215
1216    def test_original_unraisablehook_wrong_type(self):
1217        exc = ValueError(42)
1218        with test.support.swap_attr(sys, 'unraisablehook',
1219                                    sys.__unraisablehook__):
1220            with self.assertRaises(TypeError):
1221                sys.unraisablehook(exc)
1222
1223    def test_custom_unraisablehook(self):
1224        hook_args = None
1225
1226        def hook_func(args):
1227            nonlocal hook_args
1228            hook_args = args
1229
1230        obj = object()
1231        try:
1232            with test.support.swap_attr(sys, 'unraisablehook', hook_func):
1233                expected = self.write_unraisable_exc(ValueError(42),
1234                                                     "custom hook", obj)
1235                for attr in "exc_type exc_value exc_traceback err_msg object".split():
1236                    self.assertEqual(getattr(hook_args, attr),
1237                                     getattr(expected, attr),
1238                                     (hook_args, expected))
1239        finally:
1240            # expected and hook_args contain an exception: break reference cycle
1241            expected = None
1242            hook_args = None
1243
1244    def test_custom_unraisablehook_fail(self):
1245        def hook_func(*args):
1246            raise Exception("hook_func failed")
1247
1248        with test.support.captured_output("stderr") as stderr:
1249            with test.support.swap_attr(sys, 'unraisablehook', hook_func):
1250                self.write_unraisable_exc(ValueError(42),
1251                                          "custom hook fail", None)
1252
1253        err = stderr.getvalue()
1254        self.assertIn(f'Exception ignored in sys.unraisablehook: '
1255                      f'{hook_func!r}\n',
1256                      err)
1257        self.assertIn('Traceback (most recent call last):\n', err)
1258        self.assertIn('Exception: hook_func failed\n', err)
1259
1260
1261@test.support.cpython_only
1262class SizeofTest(unittest.TestCase):
1263
1264    def setUp(self):
1265        self.P = struct.calcsize('P')
1266        self.longdigit = sys.int_info.sizeof_digit
1267        import _testinternalcapi
1268        self.gc_headsize = _testinternalcapi.SIZEOF_PYGC_HEAD
1269
1270    check_sizeof = test.support.check_sizeof
1271
1272    def test_gc_head_size(self):
1273        # Check that the gc header size is added to objects tracked by the gc.
1274        vsize = test.support.calcvobjsize
1275        gc_header_size = self.gc_headsize
1276        # bool objects are not gc tracked
1277        self.assertEqual(sys.getsizeof(True), vsize('') + self.longdigit)
1278        # but lists are
1279        self.assertEqual(sys.getsizeof([]), vsize('Pn') + gc_header_size)
1280
1281    def test_errors(self):
1282        class BadSizeof:
1283            def __sizeof__(self):
1284                raise ValueError
1285        self.assertRaises(ValueError, sys.getsizeof, BadSizeof())
1286
1287        class InvalidSizeof:
1288            def __sizeof__(self):
1289                return None
1290        self.assertRaises(TypeError, sys.getsizeof, InvalidSizeof())
1291        sentinel = ["sentinel"]
1292        self.assertIs(sys.getsizeof(InvalidSizeof(), sentinel), sentinel)
1293
1294        class FloatSizeof:
1295            def __sizeof__(self):
1296                return 4.5
1297        self.assertRaises(TypeError, sys.getsizeof, FloatSizeof())
1298        self.assertIs(sys.getsizeof(FloatSizeof(), sentinel), sentinel)
1299
1300        class OverflowSizeof(int):
1301            def __sizeof__(self):
1302                return int(self)
1303        self.assertEqual(sys.getsizeof(OverflowSizeof(sys.maxsize)),
1304                         sys.maxsize + self.gc_headsize)
1305        with self.assertRaises(OverflowError):
1306            sys.getsizeof(OverflowSizeof(sys.maxsize + 1))
1307        with self.assertRaises(ValueError):
1308            sys.getsizeof(OverflowSizeof(-1))
1309        with self.assertRaises((ValueError, OverflowError)):
1310            sys.getsizeof(OverflowSizeof(-sys.maxsize - 1))
1311
1312    def test_default(self):
1313        size = test.support.calcvobjsize
1314        self.assertEqual(sys.getsizeof(True), size('') + self.longdigit)
1315        self.assertEqual(sys.getsizeof(True, -1), size('') + self.longdigit)
1316
1317    def test_objecttypes(self):
1318        # check all types defined in Objects/
1319        calcsize = struct.calcsize
1320        size = test.support.calcobjsize
1321        vsize = test.support.calcvobjsize
1322        check = self.check_sizeof
1323        # bool
1324        check(True, vsize('') + self.longdigit)
1325        check(False, vsize('') + self.longdigit)
1326        # buffer
1327        # XXX
1328        # builtin_function_or_method
1329        check(len, size('5P'))
1330        # bytearray
1331        samples = [b'', b'u'*100000]
1332        for sample in samples:
1333            x = bytearray(sample)
1334            check(x, vsize('n2Pi') + x.__alloc__())
1335        # bytearray_iterator
1336        check(iter(bytearray()), size('nP'))
1337        # bytes
1338        check(b'', vsize('n') + 1)
1339        check(b'x' * 10, vsize('n') + 11)
1340        # cell
1341        def get_cell():
1342            x = 42
1343            def inner():
1344                return x
1345            return inner
1346        check(get_cell().__closure__[0], size('P'))
1347        # code
1348        def check_code_size(a, expected_size):
1349            self.assertGreaterEqual(sys.getsizeof(a), expected_size)
1350        check_code_size(get_cell().__code__, size('6i13P'))
1351        check_code_size(get_cell.__code__, size('6i13P'))
1352        def get_cell2(x):
1353            def inner():
1354                return x
1355            return inner
1356        check_code_size(get_cell2.__code__, size('6i13P') + calcsize('n'))
1357        # complex
1358        check(complex(0,1), size('2d'))
1359        # method_descriptor (descriptor object)
1360        check(str.lower, size('3PPP'))
1361        # classmethod_descriptor (descriptor object)
1362        # XXX
1363        # member_descriptor (descriptor object)
1364        import datetime
1365        check(datetime.timedelta.days, size('3PP'))
1366        # getset_descriptor (descriptor object)
1367        import collections
1368        check(collections.defaultdict.default_factory, size('3PP'))
1369        # wrapper_descriptor (descriptor object)
1370        check(int.__add__, size('3P2P'))
1371        # method-wrapper (descriptor object)
1372        check({}.__iter__, size('2P'))
1373        # empty dict
1374        check({}, size('nQ2P'))
1375        # dict (string key)
1376        check({"a": 1}, size('nQ2P') + calcsize(DICT_KEY_STRUCT_FORMAT) + 8 + (8*2//3)*calcsize('2P'))
1377        longdict = {str(i): i for i in range(8)}
1378        check(longdict, size('nQ2P') + calcsize(DICT_KEY_STRUCT_FORMAT) + 16 + (16*2//3)*calcsize('2P'))
1379        # dict (non-string key)
1380        check({1: 1}, size('nQ2P') + calcsize(DICT_KEY_STRUCT_FORMAT) + 8 + (8*2//3)*calcsize('n2P'))
1381        longdict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8}
1382        check(longdict, size('nQ2P') + calcsize(DICT_KEY_STRUCT_FORMAT) + 16 + (16*2//3)*calcsize('n2P'))
1383        # dictionary-keyview
1384        check({}.keys(), size('P'))
1385        # dictionary-valueview
1386        check({}.values(), size('P'))
1387        # dictionary-itemview
1388        check({}.items(), size('P'))
1389        # dictionary iterator
1390        check(iter({}), size('P2nPn'))
1391        # dictionary-keyiterator
1392        check(iter({}.keys()), size('P2nPn'))
1393        # dictionary-valueiterator
1394        check(iter({}.values()), size('P2nPn'))
1395        # dictionary-itemiterator
1396        check(iter({}.items()), size('P2nPn'))
1397        # dictproxy
1398        class C(object): pass
1399        check(C.__dict__, size('P'))
1400        # BaseException
1401        check(BaseException(), size('6Pb'))
1402        # UnicodeEncodeError
1403        check(UnicodeEncodeError("", "", 0, 0, ""), size('6Pb 2P2nP'))
1404        # UnicodeDecodeError
1405        check(UnicodeDecodeError("", b"", 0, 0, ""), size('6Pb 2P2nP'))
1406        # UnicodeTranslateError
1407        check(UnicodeTranslateError("", 0, 1, ""), size('6Pb 2P2nP'))
1408        # ellipses
1409        check(Ellipsis, size(''))
1410        # EncodingMap
1411        import codecs, encodings.iso8859_3
1412        x = codecs.charmap_build(encodings.iso8859_3.decoding_table)
1413        check(x, size('32B2iB'))
1414        # enumerate
1415        check(enumerate([]), size('n4P'))
1416        # reverse
1417        check(reversed(''), size('nP'))
1418        # float
1419        check(float(0), size('d'))
1420        # sys.floatinfo
1421        check(sys.float_info, vsize('') + self.P * len(sys.float_info))
1422        # frame
1423        def func():
1424            return sys._getframe()
1425        x = func()
1426        check(x, size('3Pi3c7P2ic??2P'))
1427        # function
1428        def func(): pass
1429        check(func, size('14Pi'))
1430        class c():
1431            @staticmethod
1432            def foo():
1433                pass
1434            @classmethod
1435            def bar(cls):
1436                pass
1437            # staticmethod
1438            check(foo, size('PP'))
1439            # classmethod
1440            check(bar, size('PP'))
1441        # generator
1442        def get_gen(): yield 1
1443        check(get_gen(), size('P2P4P4c7P2ic??P'))
1444        # iterator
1445        check(iter('abc'), size('lP'))
1446        # callable-iterator
1447        import re
1448        check(re.finditer('',''), size('2P'))
1449        # list
1450        check(list([]), vsize('Pn'))
1451        check(list([1]), vsize('Pn') + 2*self.P)
1452        check(list([1, 2]), vsize('Pn') + 2*self.P)
1453        check(list([1, 2, 3]), vsize('Pn') + 4*self.P)
1454        # sortwrapper (list)
1455        # XXX
1456        # cmpwrapper (list)
1457        # XXX
1458        # listiterator (list)
1459        check(iter([]), size('lP'))
1460        # listreverseiterator (list)
1461        check(reversed([]), size('nP'))
1462        # int
1463        check(0, vsize('') + self.longdigit)
1464        check(1, vsize('') + self.longdigit)
1465        check(-1, vsize('') + self.longdigit)
1466        PyLong_BASE = 2**sys.int_info.bits_per_digit
1467        check(int(PyLong_BASE), vsize('') + 2*self.longdigit)
1468        check(int(PyLong_BASE**2-1), vsize('') + 2*self.longdigit)
1469        check(int(PyLong_BASE**2), vsize('') + 3*self.longdigit)
1470        # module
1471        check(unittest, size('PnPPP'))
1472        # None
1473        check(None, size(''))
1474        # NotImplementedType
1475        check(NotImplemented, size(''))
1476        # object
1477        check(object(), size(''))
1478        # property (descriptor object)
1479        class C(object):
1480            def getx(self): return self.__x
1481            def setx(self, value): self.__x = value
1482            def delx(self): del self.__x
1483            x = property(getx, setx, delx, "")
1484            check(x, size('5Pi'))
1485        # PyCapsule
1486        # XXX
1487        # rangeiterator
1488        check(iter(range(1)), size('4l'))
1489        # reverse
1490        check(reversed(''), size('nP'))
1491        # range
1492        check(range(1), size('4P'))
1493        check(range(66000), size('4P'))
1494        # set
1495        # frozenset
1496        PySet_MINSIZE = 8
1497        samples = [[], range(10), range(50)]
1498        s = size('3nP' + PySet_MINSIZE*'nP' + '2nP')
1499        for sample in samples:
1500            minused = len(sample)
1501            if minused == 0: tmp = 1
1502            # the computation of minused is actually a bit more complicated
1503            # but this suffices for the sizeof test
1504            minused = minused*2
1505            newsize = PySet_MINSIZE
1506            while newsize <= minused:
1507                newsize = newsize << 1
1508            if newsize <= 8:
1509                check(set(sample), s)
1510                check(frozenset(sample), s)
1511            else:
1512                check(set(sample), s + newsize*calcsize('nP'))
1513                check(frozenset(sample), s + newsize*calcsize('nP'))
1514        # setiterator
1515        check(iter(set()), size('P3n'))
1516        # slice
1517        check(slice(0), size('3P'))
1518        # super
1519        check(super(int), size('3P'))
1520        # tuple
1521        check((), vsize(''))
1522        check((1,2,3), vsize('') + 3*self.P)
1523        # type
1524        # static type: PyTypeObject
1525        fmt = 'P2nPI13Pl4Pn9Pn12PIP'
1526        s = vsize('2P' + fmt)
1527        check(int, s)
1528        # class
1529        s = vsize(fmt +                 # PyTypeObject
1530                  '4P'                  # PyAsyncMethods
1531                  '36P'                 # PyNumberMethods
1532                  '3P'                  # PyMappingMethods
1533                  '10P'                 # PySequenceMethods
1534                  '2P'                  # PyBufferProcs
1535                  '6P'
1536                  '1P'                  # Specializer cache
1537                  )
1538        class newstyleclass(object): pass
1539        # Separate block for PyDictKeysObject with 8 keys and 5 entries
1540        check(newstyleclass, s + calcsize(DICT_KEY_STRUCT_FORMAT) + 64 + 42*calcsize("2P"))
1541        # dict with shared keys
1542        [newstyleclass() for _ in range(100)]
1543        check(newstyleclass().__dict__, size('nQ2P') + self.P)
1544        o = newstyleclass()
1545        o.a = o.b = o.c = o.d = o.e = o.f = o.g = o.h = 1
1546        # Separate block for PyDictKeysObject with 16 keys and 10 entries
1547        check(newstyleclass, s + calcsize(DICT_KEY_STRUCT_FORMAT) + 64 + 42*calcsize("2P"))
1548        # dict with shared keys
1549        check(newstyleclass().__dict__, size('nQ2P') + self.P)
1550        # unicode
1551        # each tuple contains a string and its expected character size
1552        # don't put any static strings here, as they may contain
1553        # wchar_t or UTF-8 representations
1554        samples = ['1'*100, '\xff'*50,
1555                   '\u0100'*40, '\uffff'*100,
1556                   '\U00010000'*30, '\U0010ffff'*100]
1557        # also update field definitions in test_unicode.test_raiseMemError
1558        asciifields = "nnbP"
1559        compactfields = asciifields + "nPn"
1560        unicodefields = compactfields + "P"
1561        for s in samples:
1562            maxchar = ord(max(s))
1563            if maxchar < 128:
1564                L = size(asciifields) + len(s) + 1
1565            elif maxchar < 256:
1566                L = size(compactfields) + len(s) + 1
1567            elif maxchar < 65536:
1568                L = size(compactfields) + 2*(len(s) + 1)
1569            else:
1570                L = size(compactfields) + 4*(len(s) + 1)
1571            check(s, L)
1572        # verify that the UTF-8 size is accounted for
1573        s = chr(0x4000)   # 4 bytes canonical representation
1574        check(s, size(compactfields) + 4)
1575        # compile() will trigger the generation of the UTF-8
1576        # representation as a side effect
1577        compile(s, "<stdin>", "eval")
1578        check(s, size(compactfields) + 4 + 4)
1579        # TODO: add check that forces the presence of wchar_t representation
1580        # TODO: add check that forces layout of unicodefields
1581        # weakref
1582        import weakref
1583        check(weakref.ref(int), size('2Pn3P'))
1584        # weakproxy
1585        # XXX
1586        # weakcallableproxy
1587        check(weakref.proxy(int), size('2Pn3P'))
1588
1589    def check_slots(self, obj, base, extra):
1590        expected = sys.getsizeof(base) + struct.calcsize(extra)
1591        if gc.is_tracked(obj) and not gc.is_tracked(base):
1592            expected += self.gc_headsize
1593        self.assertEqual(sys.getsizeof(obj), expected)
1594
1595    def test_slots(self):
1596        # check all subclassable types defined in Objects/ that allow
1597        # non-empty __slots__
1598        check = self.check_slots
1599        class BA(bytearray):
1600            __slots__ = 'a', 'b', 'c'
1601        check(BA(), bytearray(), '3P')
1602        class D(dict):
1603            __slots__ = 'a', 'b', 'c'
1604        check(D(x=[]), {'x': []}, '3P')
1605        class L(list):
1606            __slots__ = 'a', 'b', 'c'
1607        check(L(), [], '3P')
1608        class S(set):
1609            __slots__ = 'a', 'b', 'c'
1610        check(S(), set(), '3P')
1611        class FS(frozenset):
1612            __slots__ = 'a', 'b', 'c'
1613        check(FS(), frozenset(), '3P')
1614        from collections import OrderedDict
1615        class OD(OrderedDict):
1616            __slots__ = 'a', 'b', 'c'
1617        check(OD(x=[]), OrderedDict(x=[]), '3P')
1618
1619    def test_pythontypes(self):
1620        # check all types defined in Python/
1621        size = test.support.calcobjsize
1622        vsize = test.support.calcvobjsize
1623        check = self.check_sizeof
1624        # _ast.AST
1625        import _ast
1626        check(_ast.AST(), size('P'))
1627        try:
1628            raise TypeError
1629        except TypeError:
1630            tb = sys.exc_info()[2]
1631            # traceback
1632            if tb is not None:
1633                check(tb, size('2P2i'))
1634        # symtable entry
1635        # XXX
1636        # sys.flags
1637        check(sys.flags, vsize('') + self.P * len(sys.flags))
1638
1639    def test_asyncgen_hooks(self):
1640        old = sys.get_asyncgen_hooks()
1641        self.assertIsNone(old.firstiter)
1642        self.assertIsNone(old.finalizer)
1643
1644        firstiter = lambda *a: None
1645        sys.set_asyncgen_hooks(firstiter=firstiter)
1646        hooks = sys.get_asyncgen_hooks()
1647        self.assertIs(hooks.firstiter, firstiter)
1648        self.assertIs(hooks[0], firstiter)
1649        self.assertIs(hooks.finalizer, None)
1650        self.assertIs(hooks[1], None)
1651
1652        finalizer = lambda *a: None
1653        sys.set_asyncgen_hooks(finalizer=finalizer)
1654        hooks = sys.get_asyncgen_hooks()
1655        self.assertIs(hooks.firstiter, firstiter)
1656        self.assertIs(hooks[0], firstiter)
1657        self.assertIs(hooks.finalizer, finalizer)
1658        self.assertIs(hooks[1], finalizer)
1659
1660        sys.set_asyncgen_hooks(*old)
1661        cur = sys.get_asyncgen_hooks()
1662        self.assertIsNone(cur.firstiter)
1663        self.assertIsNone(cur.finalizer)
1664
1665    def test_changing_sys_stderr_and_removing_reference(self):
1666        # If the default displayhook doesn't take a strong reference
1667        # to sys.stderr the following code can crash. See bpo-43660
1668        # for more details.
1669        code = textwrap.dedent('''
1670            import sys
1671            class MyStderr:
1672                def write(self, s):
1673                    sys.stderr = None
1674            sys.stderr = MyStderr()
1675            1/0
1676        ''')
1677        rc, out, err = assert_python_failure('-c', code)
1678        self.assertEqual(out, b"")
1679        self.assertEqual(err, b"")
1680
1681if __name__ == "__main__":
1682    unittest.main()
1683