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