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