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