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