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