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