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