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