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