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), 4) 451 self.assertTrue(sys.int_info.bits_per_digit % 5 == 0) 452 self.assertTrue(sys.int_info.sizeof_digit >= 1) 453 self.assertGreaterEqual(sys.int_info.default_max_str_digits, 500) 454 self.assertGreaterEqual(sys.int_info.str_digits_check_threshold, 100) 455 self.assertGreater(sys.int_info.default_max_str_digits, 456 sys.int_info.str_digits_check_threshold) 457 self.assertEqual(type(sys.int_info.bits_per_digit), int) 458 self.assertEqual(type(sys.int_info.sizeof_digit), int) 459 self.assertIsInstance(sys.int_info.default_max_str_digits, int) 460 self.assertIsInstance(sys.int_info.str_digits_check_threshold, int) 461 self.assertIsInstance(sys.hexversion, int) 462 463 self.assertEqual(len(sys.hash_info), 9) 464 self.assertLess(sys.hash_info.modulus, 2**sys.hash_info.width) 465 # sys.hash_info.modulus should be a prime; we do a quick 466 # probable primality test (doesn't exclude the possibility of 467 # a Carmichael number) 468 for x in range(1, 100): 469 self.assertEqual( 470 pow(x, sys.hash_info.modulus-1, sys.hash_info.modulus), 471 1, 472 "sys.hash_info.modulus {} is a non-prime".format( 473 sys.hash_info.modulus) 474 ) 475 self.assertIsInstance(sys.hash_info.inf, int) 476 self.assertIsInstance(sys.hash_info.nan, int) 477 self.assertIsInstance(sys.hash_info.imag, int) 478 algo = sysconfig.get_config_var("Py_HASH_ALGORITHM") 479 if sys.hash_info.algorithm in {"fnv", "siphash24"}: 480 self.assertIn(sys.hash_info.hash_bits, {32, 64}) 481 self.assertIn(sys.hash_info.seed_bits, {32, 64, 128}) 482 483 if algo == 1: 484 self.assertEqual(sys.hash_info.algorithm, "siphash24") 485 elif algo == 2: 486 self.assertEqual(sys.hash_info.algorithm, "fnv") 487 else: 488 self.assertIn(sys.hash_info.algorithm, {"fnv", "siphash24"}) 489 else: 490 # PY_HASH_EXTERNAL 491 self.assertEqual(algo, 0) 492 self.assertGreaterEqual(sys.hash_info.cutoff, 0) 493 self.assertLess(sys.hash_info.cutoff, 8) 494 495 self.assertIsInstance(sys.maxsize, int) 496 self.assertIsInstance(sys.maxunicode, int) 497 self.assertEqual(sys.maxunicode, 0x10FFFF) 498 self.assertIsInstance(sys.platform, str) 499 self.assertIsInstance(sys.prefix, str) 500 self.assertIsInstance(sys.base_prefix, str) 501 self.assertIsInstance(sys.version, str) 502 vi = sys.version_info 503 self.assertIsInstance(vi[:], tuple) 504 self.assertEqual(len(vi), 5) 505 self.assertIsInstance(vi[0], int) 506 self.assertIsInstance(vi[1], int) 507 self.assertIsInstance(vi[2], int) 508 self.assertIn(vi[3], ("alpha", "beta", "candidate", "final")) 509 self.assertIsInstance(vi[4], int) 510 self.assertIsInstance(vi.major, int) 511 self.assertIsInstance(vi.minor, int) 512 self.assertIsInstance(vi.micro, int) 513 self.assertIn(vi.releaselevel, ("alpha", "beta", "candidate", "final")) 514 self.assertIsInstance(vi.serial, int) 515 self.assertEqual(vi[0], vi.major) 516 self.assertEqual(vi[1], vi.minor) 517 self.assertEqual(vi[2], vi.micro) 518 self.assertEqual(vi[3], vi.releaselevel) 519 self.assertEqual(vi[4], vi.serial) 520 self.assertTrue(vi > (1,0,0)) 521 self.assertIsInstance(sys.float_repr_style, str) 522 self.assertIn(sys.float_repr_style, ('short', 'legacy')) 523 if not sys.platform.startswith('win'): 524 self.assertIsInstance(sys.abiflags, str) 525 526 def test_thread_info(self): 527 info = sys.thread_info 528 self.assertEqual(len(info), 3) 529 self.assertIn(info.name, ('nt', 'pthread', 'solaris', None)) 530 self.assertIn(info.lock, ('semaphore', 'mutex+cond', None)) 531 532 def test_43581(self): 533 # Can't use sys.stdout, as this is a StringIO object when 534 # the test runs under regrtest. 535 self.assertEqual(sys.__stdout__.encoding, sys.__stderr__.encoding) 536 537 def test_intern(self): 538 global INTERN_NUMRUNS 539 INTERN_NUMRUNS += 1 540 self.assertRaises(TypeError, sys.intern) 541 s = "never interned before" + str(INTERN_NUMRUNS) 542 self.assertTrue(sys.intern(s) is s) 543 s2 = s.swapcase().swapcase() 544 self.assertTrue(sys.intern(s2) is s) 545 546 # Subclasses of string can't be interned, because they 547 # provide too much opportunity for insane things to happen. 548 # We don't want them in the interned dict and if they aren't 549 # actually interned, we don't want to create the appearance 550 # that they are by allowing intern() to succeed. 551 class S(str): 552 def __hash__(self): 553 return 123 554 555 self.assertRaises(TypeError, sys.intern, S("abc")) 556 557 def test_sys_flags(self): 558 self.assertTrue(sys.flags) 559 attrs = ("debug", 560 "inspect", "interactive", "optimize", "dont_write_bytecode", 561 "no_user_site", "no_site", "ignore_environment", "verbose", 562 "bytes_warning", "quiet", "hash_randomization", "isolated", 563 "dev_mode", "utf8_mode", "int_max_str_digits") 564 for attr in attrs: 565 self.assertTrue(hasattr(sys.flags, attr), attr) 566 attr_type = bool if attr == "dev_mode" else int 567 self.assertEqual(type(getattr(sys.flags, attr)), attr_type, attr) 568 self.assertTrue(repr(sys.flags)) 569 self.assertEqual(len(sys.flags), len(attrs)) 570 571 self.assertIn(sys.flags.utf8_mode, {0, 1, 2}) 572 573 def assert_raise_on_new_sys_type(self, sys_attr): 574 # Users are intentionally prevented from creating new instances of 575 # sys.flags, sys.version_info, and sys.getwindowsversion. 576 attr_type = type(sys_attr) 577 with self.assertRaises(TypeError): 578 attr_type() 579 with self.assertRaises(TypeError): 580 attr_type.__new__(attr_type) 581 582 def test_sys_flags_no_instantiation(self): 583 self.assert_raise_on_new_sys_type(sys.flags) 584 585 def test_sys_version_info_no_instantiation(self): 586 self.assert_raise_on_new_sys_type(sys.version_info) 587 588 def test_sys_getwindowsversion_no_instantiation(self): 589 # Skip if not being run on Windows. 590 test.support.get_attribute(sys, "getwindowsversion") 591 self.assert_raise_on_new_sys_type(sys.getwindowsversion()) 592 593 @test.support.cpython_only 594 def test_clear_type_cache(self): 595 sys._clear_type_cache() 596 597 def test_ioencoding(self): 598 env = dict(os.environ) 599 600 # Test character: cent sign, encoded as 0x4A (ASCII J) in CP424, 601 # not representable in ASCII. 602 603 env["PYTHONIOENCODING"] = "cp424" 604 p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xa2))'], 605 stdout = subprocess.PIPE, env=env) 606 out = p.communicate()[0].strip() 607 expected = ("\xa2" + os.linesep).encode("cp424") 608 self.assertEqual(out, expected) 609 610 env["PYTHONIOENCODING"] = "ascii:replace" 611 p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xa2))'], 612 stdout = subprocess.PIPE, env=env) 613 out = p.communicate()[0].strip() 614 self.assertEqual(out, b'?') 615 616 env["PYTHONIOENCODING"] = "ascii" 617 p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xa2))'], 618 stdout=subprocess.PIPE, stderr=subprocess.PIPE, 619 env=env) 620 out, err = p.communicate() 621 self.assertEqual(out, b'') 622 self.assertIn(b'UnicodeEncodeError:', err) 623 self.assertIn(rb"'\xa2'", err) 624 625 env["PYTHONIOENCODING"] = "ascii:" 626 p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xa2))'], 627 stdout=subprocess.PIPE, stderr=subprocess.PIPE, 628 env=env) 629 out, err = p.communicate() 630 self.assertEqual(out, b'') 631 self.assertIn(b'UnicodeEncodeError:', err) 632 self.assertIn(rb"'\xa2'", err) 633 634 env["PYTHONIOENCODING"] = ":surrogateescape" 635 p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xdcbd))'], 636 stdout=subprocess.PIPE, env=env) 637 out = p.communicate()[0].strip() 638 self.assertEqual(out, b'\xbd') 639 640 @unittest.skipUnless(test.support.FS_NONASCII, 641 'requires OS support of non-ASCII encodings') 642 @unittest.skipUnless(sys.getfilesystemencoding() == locale.getpreferredencoding(False), 643 'requires FS encoding to match locale') 644 def test_ioencoding_nonascii(self): 645 env = dict(os.environ) 646 647 env["PYTHONIOENCODING"] = "" 648 p = subprocess.Popen([sys.executable, "-c", 649 'print(%a)' % test.support.FS_NONASCII], 650 stdout=subprocess.PIPE, env=env) 651 out = p.communicate()[0].strip() 652 self.assertEqual(out, os.fsencode(test.support.FS_NONASCII)) 653 654 @unittest.skipIf(sys.base_prefix != sys.prefix, 655 'Test is not venv-compatible') 656 def test_executable(self): 657 # sys.executable should be absolute 658 self.assertEqual(os.path.abspath(sys.executable), sys.executable) 659 660 # Issue #7774: Ensure that sys.executable is an empty string if argv[0] 661 # has been set to a non existent program name and Python is unable to 662 # retrieve the real program name 663 664 # For a normal installation, it should work without 'cwd' 665 # argument. For test runs in the build directory, see #7774. 666 python_dir = os.path.dirname(os.path.realpath(sys.executable)) 667 p = subprocess.Popen( 668 ["nonexistent", "-c", 669 'import sys; print(sys.executable.encode("ascii", "backslashreplace"))'], 670 executable=sys.executable, stdout=subprocess.PIPE, cwd=python_dir) 671 stdout = p.communicate()[0] 672 executable = stdout.strip().decode("ASCII") 673 p.wait() 674 self.assertIn(executable, ["b''", repr(sys.executable.encode("ascii", "backslashreplace"))]) 675 676 def check_fsencoding(self, fs_encoding, expected=None): 677 self.assertIsNotNone(fs_encoding) 678 codecs.lookup(fs_encoding) 679 if expected: 680 self.assertEqual(fs_encoding, expected) 681 682 def test_getfilesystemencoding(self): 683 fs_encoding = sys.getfilesystemencoding() 684 if sys.platform == 'darwin': 685 expected = 'utf-8' 686 else: 687 expected = None 688 self.check_fsencoding(fs_encoding, expected) 689 690 def c_locale_get_error_handler(self, locale, isolated=False, encoding=None): 691 # Force the POSIX locale 692 env = os.environ.copy() 693 env["LC_ALL"] = locale 694 env["PYTHONCOERCECLOCALE"] = "0" 695 code = '\n'.join(( 696 'import sys', 697 'def dump(name):', 698 ' std = getattr(sys, name)', 699 ' print("%s: %s" % (name, std.errors))', 700 'dump("stdin")', 701 'dump("stdout")', 702 'dump("stderr")', 703 )) 704 args = [sys.executable, "-X", "utf8=0", "-c", code] 705 if isolated: 706 args.append("-I") 707 if encoding is not None: 708 env['PYTHONIOENCODING'] = encoding 709 else: 710 env.pop('PYTHONIOENCODING', None) 711 p = subprocess.Popen(args, 712 stdout=subprocess.PIPE, 713 stderr=subprocess.STDOUT, 714 env=env, 715 universal_newlines=True) 716 stdout, stderr = p.communicate() 717 return stdout 718 719 def check_locale_surrogateescape(self, locale): 720 out = self.c_locale_get_error_handler(locale, isolated=True) 721 self.assertEqual(out, 722 'stdin: surrogateescape\n' 723 'stdout: surrogateescape\n' 724 'stderr: backslashreplace\n') 725 726 # replace the default error handler 727 out = self.c_locale_get_error_handler(locale, encoding=':ignore') 728 self.assertEqual(out, 729 'stdin: ignore\n' 730 'stdout: ignore\n' 731 'stderr: backslashreplace\n') 732 733 # force the encoding 734 out = self.c_locale_get_error_handler(locale, encoding='iso8859-1') 735 self.assertEqual(out, 736 'stdin: strict\n' 737 'stdout: strict\n' 738 'stderr: backslashreplace\n') 739 out = self.c_locale_get_error_handler(locale, encoding='iso8859-1:') 740 self.assertEqual(out, 741 'stdin: strict\n' 742 'stdout: strict\n' 743 'stderr: backslashreplace\n') 744 745 # have no any effect 746 out = self.c_locale_get_error_handler(locale, encoding=':') 747 self.assertEqual(out, 748 'stdin: surrogateescape\n' 749 'stdout: surrogateescape\n' 750 'stderr: backslashreplace\n') 751 out = self.c_locale_get_error_handler(locale, encoding='') 752 self.assertEqual(out, 753 'stdin: surrogateescape\n' 754 'stdout: surrogateescape\n' 755 'stderr: backslashreplace\n') 756 757 def test_c_locale_surrogateescape(self): 758 self.check_locale_surrogateescape('C') 759 760 def test_posix_locale_surrogateescape(self): 761 self.check_locale_surrogateescape('POSIX') 762 763 def test_implementation(self): 764 # This test applies to all implementations equally. 765 766 levels = {'alpha': 0xA, 'beta': 0xB, 'candidate': 0xC, 'final': 0xF} 767 768 self.assertTrue(hasattr(sys.implementation, 'name')) 769 self.assertTrue(hasattr(sys.implementation, 'version')) 770 self.assertTrue(hasattr(sys.implementation, 'hexversion')) 771 self.assertTrue(hasattr(sys.implementation, 'cache_tag')) 772 773 version = sys.implementation.version 774 self.assertEqual(version[:2], (version.major, version.minor)) 775 776 hexversion = (version.major << 24 | version.minor << 16 | 777 version.micro << 8 | levels[version.releaselevel] << 4 | 778 version.serial << 0) 779 self.assertEqual(sys.implementation.hexversion, hexversion) 780 781 # PEP 421 requires that .name be lower case. 782 self.assertEqual(sys.implementation.name, 783 sys.implementation.name.lower()) 784 785 @test.support.cpython_only 786 def test_debugmallocstats(self): 787 # Test sys._debugmallocstats() 788 from test.support.script_helper import assert_python_ok 789 args = ['-c', 'import sys; sys._debugmallocstats()'] 790 ret, out, err = assert_python_ok(*args) 791 self.assertIn(b"free PyDictObjects", err) 792 793 # The function has no parameter 794 self.assertRaises(TypeError, sys._debugmallocstats, True) 795 796 @unittest.skipUnless(hasattr(sys, "getallocatedblocks"), 797 "sys.getallocatedblocks unavailable on this build") 798 def test_getallocatedblocks(self): 799 try: 800 import _testcapi 801 except ImportError: 802 with_pymalloc = support.with_pymalloc() 803 else: 804 try: 805 alloc_name = _testcapi.pymem_getallocatorsname() 806 except RuntimeError as exc: 807 # "cannot get allocators name" (ex: tracemalloc is used) 808 with_pymalloc = True 809 else: 810 with_pymalloc = (alloc_name in ('pymalloc', 'pymalloc_debug')) 811 812 # Some sanity checks 813 a = sys.getallocatedblocks() 814 self.assertIs(type(a), int) 815 if with_pymalloc: 816 self.assertGreater(a, 0) 817 else: 818 # When WITH_PYMALLOC isn't available, we don't know anything 819 # about the underlying implementation: the function might 820 # return 0 or something greater. 821 self.assertGreaterEqual(a, 0) 822 try: 823 # While we could imagine a Python session where the number of 824 # multiple buffer objects would exceed the sharing of references, 825 # it is unlikely to happen in a normal test run. 826 self.assertLess(a, sys.gettotalrefcount()) 827 except AttributeError: 828 # gettotalrefcount() not available 829 pass 830 gc.collect() 831 b = sys.getallocatedblocks() 832 self.assertLessEqual(b, a) 833 gc.collect() 834 c = sys.getallocatedblocks() 835 self.assertIn(c, range(b - 50, b + 50)) 836 837 @test.support.requires_type_collecting 838 def test_is_finalizing(self): 839 self.assertIs(sys.is_finalizing(), False) 840 # Don't use the atexit module because _Py_Finalizing is only set 841 # after calling atexit callbacks 842 code = """if 1: 843 import sys 844 845 class AtExit: 846 is_finalizing = sys.is_finalizing 847 print = print 848 849 def __del__(self): 850 self.print(self.is_finalizing(), flush=True) 851 852 # Keep a reference in the __main__ module namespace, so the 853 # AtExit destructor will be called at Python exit 854 ref = AtExit() 855 """ 856 rc, stdout, stderr = assert_python_ok('-c', code) 857 self.assertEqual(stdout.rstrip(), b'True') 858 859 @test.support.requires_type_collecting 860 def test_issue20602(self): 861 # sys.flags and sys.float_info were wiped during shutdown. 862 code = """if 1: 863 import sys 864 class A: 865 def __del__(self, sys=sys): 866 print(sys.flags) 867 print(sys.float_info) 868 a = A() 869 """ 870 rc, out, err = assert_python_ok('-c', code) 871 out = out.splitlines() 872 self.assertIn(b'sys.flags', out[0]) 873 self.assertIn(b'sys.float_info', out[1]) 874 875 @unittest.skipUnless(hasattr(sys, 'getandroidapilevel'), 876 'need sys.getandroidapilevel()') 877 def test_getandroidapilevel(self): 878 level = sys.getandroidapilevel() 879 self.assertIsInstance(level, int) 880 self.assertGreater(level, 0) 881 882 def test_sys_tracebacklimit(self): 883 code = """if 1: 884 import sys 885 def f1(): 886 1 / 0 887 def f2(): 888 f1() 889 sys.tracebacklimit = %r 890 f2() 891 """ 892 def check(tracebacklimit, expected): 893 p = subprocess.Popen([sys.executable, '-c', code % tracebacklimit], 894 stderr=subprocess.PIPE) 895 out = p.communicate()[1] 896 self.assertEqual(out.splitlines(), expected) 897 898 traceback = [ 899 b'Traceback (most recent call last):', 900 b' File "<string>", line 8, in <module>', 901 b' File "<string>", line 6, in f2', 902 b' File "<string>", line 4, in f1', 903 b'ZeroDivisionError: division by zero' 904 ] 905 check(10, traceback) 906 check(3, traceback) 907 check(2, traceback[:1] + traceback[2:]) 908 check(1, traceback[:1] + traceback[3:]) 909 check(0, [traceback[-1]]) 910 check(-1, [traceback[-1]]) 911 check(1<<1000, traceback) 912 check(-1<<1000, [traceback[-1]]) 913 check(None, traceback) 914 915 def test_no_duplicates_in_meta_path(self): 916 self.assertEqual(len(sys.meta_path), len(set(sys.meta_path))) 917 918 @unittest.skipUnless(hasattr(sys, "_enablelegacywindowsfsencoding"), 919 'needs sys._enablelegacywindowsfsencoding()') 920 def test__enablelegacywindowsfsencoding(self): 921 code = ('import sys', 922 'sys._enablelegacywindowsfsencoding()', 923 'print(sys.getfilesystemencoding(), sys.getfilesystemencodeerrors())') 924 rc, out, err = assert_python_ok('-c', '; '.join(code)) 925 out = out.decode('ascii', 'replace').rstrip() 926 self.assertEqual(out, 'mbcs replace') 927 928 929@test.support.cpython_only 930class UnraisableHookTest(unittest.TestCase): 931 def write_unraisable_exc(self, exc, err_msg, obj): 932 import _testcapi 933 import types 934 err_msg2 = f"Exception ignored {err_msg}" 935 try: 936 _testcapi.write_unraisable_exc(exc, err_msg, obj) 937 return types.SimpleNamespace(exc_type=type(exc), 938 exc_value=exc, 939 exc_traceback=exc.__traceback__, 940 err_msg=err_msg2, 941 object=obj) 942 finally: 943 # Explicitly break any reference cycle 944 exc = None 945 946 def test_original_unraisablehook(self): 947 for err_msg in (None, "original hook"): 948 with self.subTest(err_msg=err_msg): 949 obj = "an object" 950 951 with test.support.captured_output("stderr") as stderr: 952 with test.support.swap_attr(sys, 'unraisablehook', 953 sys.__unraisablehook__): 954 self.write_unraisable_exc(ValueError(42), err_msg, obj) 955 956 err = stderr.getvalue() 957 if err_msg is not None: 958 self.assertIn(f'Exception ignored {err_msg}: {obj!r}\n', err) 959 else: 960 self.assertIn(f'Exception ignored in: {obj!r}\n', err) 961 self.assertIn('Traceback (most recent call last):\n', err) 962 self.assertIn('ValueError: 42\n', err) 963 964 def test_original_unraisablehook_err(self): 965 # bpo-22836: PyErr_WriteUnraisable() should give sensible reports 966 class BrokenDel: 967 def __del__(self): 968 exc = ValueError("del is broken") 969 # The following line is included in the traceback report: 970 raise exc 971 972 class BrokenStrException(Exception): 973 def __str__(self): 974 raise Exception("str() is broken") 975 976 class BrokenExceptionDel: 977 def __del__(self): 978 exc = BrokenStrException() 979 # The following line is included in the traceback report: 980 raise exc 981 982 for test_class in (BrokenDel, BrokenExceptionDel): 983 with self.subTest(test_class): 984 obj = test_class() 985 with test.support.captured_stderr() as stderr, \ 986 test.support.swap_attr(sys, 'unraisablehook', 987 sys.__unraisablehook__): 988 # Trigger obj.__del__() 989 del obj 990 991 report = stderr.getvalue() 992 self.assertIn("Exception ignored", report) 993 self.assertIn(test_class.__del__.__qualname__, report) 994 self.assertIn("test_sys.py", report) 995 self.assertIn("raise exc", report) 996 if test_class is BrokenExceptionDel: 997 self.assertIn("BrokenStrException", report) 998 self.assertIn("<exception str() failed>", report) 999 else: 1000 self.assertIn("ValueError", report) 1001 self.assertIn("del is broken", report) 1002 self.assertTrue(report.endswith("\n")) 1003 1004 1005 def test_original_unraisablehook_wrong_type(self): 1006 exc = ValueError(42) 1007 with test.support.swap_attr(sys, 'unraisablehook', 1008 sys.__unraisablehook__): 1009 with self.assertRaises(TypeError): 1010 sys.unraisablehook(exc) 1011 1012 def test_custom_unraisablehook(self): 1013 hook_args = None 1014 1015 def hook_func(args): 1016 nonlocal hook_args 1017 hook_args = args 1018 1019 obj = object() 1020 try: 1021 with test.support.swap_attr(sys, 'unraisablehook', hook_func): 1022 expected = self.write_unraisable_exc(ValueError(42), 1023 "custom hook", obj) 1024 for attr in "exc_type exc_value exc_traceback err_msg object".split(): 1025 self.assertEqual(getattr(hook_args, attr), 1026 getattr(expected, attr), 1027 (hook_args, expected)) 1028 finally: 1029 # expected and hook_args contain an exception: break reference cycle 1030 expected = None 1031 hook_args = None 1032 1033 def test_custom_unraisablehook_fail(self): 1034 def hook_func(*args): 1035 raise Exception("hook_func failed") 1036 1037 with test.support.captured_output("stderr") as stderr: 1038 with test.support.swap_attr(sys, 'unraisablehook', hook_func): 1039 self.write_unraisable_exc(ValueError(42), 1040 "custom hook fail", None) 1041 1042 err = stderr.getvalue() 1043 self.assertIn(f'Exception ignored in sys.unraisablehook: ' 1044 f'{hook_func!r}\n', 1045 err) 1046 self.assertIn('Traceback (most recent call last):\n', err) 1047 self.assertIn('Exception: hook_func failed\n', err) 1048 1049 1050@test.support.cpython_only 1051class SizeofTest(unittest.TestCase): 1052 1053 def setUp(self): 1054 self.P = struct.calcsize('P') 1055 self.longdigit = sys.int_info.sizeof_digit 1056 import _testcapi 1057 self.gc_headsize = _testcapi.SIZEOF_PYGC_HEAD 1058 1059 check_sizeof = test.support.check_sizeof 1060 1061 def test_gc_head_size(self): 1062 # Check that the gc header size is added to objects tracked by the gc. 1063 vsize = test.support.calcvobjsize 1064 gc_header_size = self.gc_headsize 1065 # bool objects are not gc tracked 1066 self.assertEqual(sys.getsizeof(True), vsize('') + self.longdigit) 1067 # but lists are 1068 self.assertEqual(sys.getsizeof([]), vsize('Pn') + gc_header_size) 1069 1070 def test_errors(self): 1071 class BadSizeof: 1072 def __sizeof__(self): 1073 raise ValueError 1074 self.assertRaises(ValueError, sys.getsizeof, BadSizeof()) 1075 1076 class InvalidSizeof: 1077 def __sizeof__(self): 1078 return None 1079 self.assertRaises(TypeError, sys.getsizeof, InvalidSizeof()) 1080 sentinel = ["sentinel"] 1081 self.assertIs(sys.getsizeof(InvalidSizeof(), sentinel), sentinel) 1082 1083 class FloatSizeof: 1084 def __sizeof__(self): 1085 return 4.5 1086 self.assertRaises(TypeError, sys.getsizeof, FloatSizeof()) 1087 self.assertIs(sys.getsizeof(FloatSizeof(), sentinel), sentinel) 1088 1089 class OverflowSizeof(int): 1090 def __sizeof__(self): 1091 return int(self) 1092 self.assertEqual(sys.getsizeof(OverflowSizeof(sys.maxsize)), 1093 sys.maxsize + self.gc_headsize) 1094 with self.assertRaises(OverflowError): 1095 sys.getsizeof(OverflowSizeof(sys.maxsize + 1)) 1096 with self.assertRaises(ValueError): 1097 sys.getsizeof(OverflowSizeof(-1)) 1098 with self.assertRaises((ValueError, OverflowError)): 1099 sys.getsizeof(OverflowSizeof(-sys.maxsize - 1)) 1100 1101 def test_default(self): 1102 size = test.support.calcvobjsize 1103 self.assertEqual(sys.getsizeof(True), size('') + self.longdigit) 1104 self.assertEqual(sys.getsizeof(True, -1), size('') + self.longdigit) 1105 1106 def test_objecttypes(self): 1107 # check all types defined in Objects/ 1108 calcsize = struct.calcsize 1109 size = test.support.calcobjsize 1110 vsize = test.support.calcvobjsize 1111 check = self.check_sizeof 1112 # bool 1113 check(True, vsize('') + self.longdigit) 1114 # buffer 1115 # XXX 1116 # builtin_function_or_method 1117 check(len, size('5P')) 1118 # bytearray 1119 samples = [b'', b'u'*100000] 1120 for sample in samples: 1121 x = bytearray(sample) 1122 check(x, vsize('n2Pi') + x.__alloc__()) 1123 # bytearray_iterator 1124 check(iter(bytearray()), size('nP')) 1125 # bytes 1126 check(b'', vsize('n') + 1) 1127 check(b'x' * 10, vsize('n') + 11) 1128 # cell 1129 def get_cell(): 1130 x = 42 1131 def inner(): 1132 return x 1133 return inner 1134 check(get_cell().__closure__[0], size('P')) 1135 # code 1136 def check_code_size(a, expected_size): 1137 self.assertGreaterEqual(sys.getsizeof(a), expected_size) 1138 check_code_size(get_cell().__code__, size('6i13P')) 1139 check_code_size(get_cell.__code__, size('6i13P')) 1140 def get_cell2(x): 1141 def inner(): 1142 return x 1143 return inner 1144 check_code_size(get_cell2.__code__, size('6i13P') + calcsize('n')) 1145 # complex 1146 check(complex(0,1), size('2d')) 1147 # method_descriptor (descriptor object) 1148 check(str.lower, size('3PPP')) 1149 # classmethod_descriptor (descriptor object) 1150 # XXX 1151 # member_descriptor (descriptor object) 1152 import datetime 1153 check(datetime.timedelta.days, size('3PP')) 1154 # getset_descriptor (descriptor object) 1155 import collections 1156 check(collections.defaultdict.default_factory, size('3PP')) 1157 # wrapper_descriptor (descriptor object) 1158 check(int.__add__, size('3P2P')) 1159 # method-wrapper (descriptor object) 1160 check({}.__iter__, size('2P')) 1161 # empty dict 1162 check({}, size('nQ2P')) 1163 # dict 1164 check({"a": 1}, size('nQ2P') + calcsize('2nP2n') + 8 + (8*2//3)*calcsize('n2P')) 1165 longdict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8} 1166 check(longdict, size('nQ2P') + calcsize('2nP2n') + 16 + (16*2//3)*calcsize('n2P')) 1167 # dictionary-keyview 1168 check({}.keys(), size('P')) 1169 # dictionary-valueview 1170 check({}.values(), size('P')) 1171 # dictionary-itemview 1172 check({}.items(), size('P')) 1173 # dictionary iterator 1174 check(iter({}), size('P2nPn')) 1175 # dictionary-keyiterator 1176 check(iter({}.keys()), size('P2nPn')) 1177 # dictionary-valueiterator 1178 check(iter({}.values()), size('P2nPn')) 1179 # dictionary-itemiterator 1180 check(iter({}.items()), size('P2nPn')) 1181 # dictproxy 1182 class C(object): pass 1183 check(C.__dict__, size('P')) 1184 # BaseException 1185 check(BaseException(), size('5Pb')) 1186 # UnicodeEncodeError 1187 check(UnicodeEncodeError("", "", 0, 0, ""), size('5Pb 2P2nP')) 1188 # UnicodeDecodeError 1189 check(UnicodeDecodeError("", b"", 0, 0, ""), size('5Pb 2P2nP')) 1190 # UnicodeTranslateError 1191 check(UnicodeTranslateError("", 0, 1, ""), size('5Pb 2P2nP')) 1192 # ellipses 1193 check(Ellipsis, size('')) 1194 # EncodingMap 1195 import codecs, encodings.iso8859_3 1196 x = codecs.charmap_build(encodings.iso8859_3.decoding_table) 1197 check(x, size('32B2iB')) 1198 # enumerate 1199 check(enumerate([]), size('n3P')) 1200 # reverse 1201 check(reversed(''), size('nP')) 1202 # float 1203 check(float(0), size('d')) 1204 # sys.floatinfo 1205 check(sys.float_info, vsize('') + self.P * len(sys.float_info)) 1206 # frame 1207 import inspect 1208 CO_MAXBLOCKS = 20 1209 x = inspect.currentframe() 1210 ncells = len(x.f_code.co_cellvars) 1211 nfrees = len(x.f_code.co_freevars) 1212 extras = x.f_code.co_stacksize + x.f_code.co_nlocals +\ 1213 ncells + nfrees - 1 1214 check(x, vsize('5P2c4P3ic' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) 1215 # function 1216 def func(): pass 1217 check(func, size('13P')) 1218 class c(): 1219 @staticmethod 1220 def foo(): 1221 pass 1222 @classmethod 1223 def bar(cls): 1224 pass 1225 # staticmethod 1226 check(foo, size('PP')) 1227 # classmethod 1228 check(bar, size('PP')) 1229 # generator 1230 def get_gen(): yield 1 1231 check(get_gen(), size('Pb2PPP4P')) 1232 # iterator 1233 check(iter('abc'), size('lP')) 1234 # callable-iterator 1235 import re 1236 check(re.finditer('',''), size('2P')) 1237 # list 1238 samples = [[], [1,2,3], ['1', '2', '3']] 1239 for sample in samples: 1240 check(sample, vsize('Pn') + len(sample)*self.P) 1241 # sortwrapper (list) 1242 # XXX 1243 # cmpwrapper (list) 1244 # XXX 1245 # listiterator (list) 1246 check(iter([]), size('lP')) 1247 # listreverseiterator (list) 1248 check(reversed([]), size('nP')) 1249 # int 1250 check(0, vsize('')) 1251 check(1, vsize('') + self.longdigit) 1252 check(-1, vsize('') + self.longdigit) 1253 PyLong_BASE = 2**sys.int_info.bits_per_digit 1254 check(int(PyLong_BASE), vsize('') + 2*self.longdigit) 1255 check(int(PyLong_BASE**2-1), vsize('') + 2*self.longdigit) 1256 check(int(PyLong_BASE**2), vsize('') + 3*self.longdigit) 1257 # module 1258 check(unittest, size('PnPPP')) 1259 # None 1260 check(None, size('')) 1261 # NotImplementedType 1262 check(NotImplemented, size('')) 1263 # object 1264 check(object(), size('')) 1265 # property (descriptor object) 1266 class C(object): 1267 def getx(self): return self.__x 1268 def setx(self, value): self.__x = value 1269 def delx(self): del self.__x 1270 x = property(getx, setx, delx, "") 1271 check(x, size('4Pi')) 1272 # PyCapsule 1273 # XXX 1274 # rangeiterator 1275 check(iter(range(1)), size('4l')) 1276 # reverse 1277 check(reversed(''), size('nP')) 1278 # range 1279 check(range(1), size('4P')) 1280 check(range(66000), size('4P')) 1281 # set 1282 # frozenset 1283 PySet_MINSIZE = 8 1284 samples = [[], range(10), range(50)] 1285 s = size('3nP' + PySet_MINSIZE*'nP' + '2nP') 1286 for sample in samples: 1287 minused = len(sample) 1288 if minused == 0: tmp = 1 1289 # the computation of minused is actually a bit more complicated 1290 # but this suffices for the sizeof test 1291 minused = minused*2 1292 newsize = PySet_MINSIZE 1293 while newsize <= minused: 1294 newsize = newsize << 1 1295 if newsize <= 8: 1296 check(set(sample), s) 1297 check(frozenset(sample), s) 1298 else: 1299 check(set(sample), s + newsize*calcsize('nP')) 1300 check(frozenset(sample), s + newsize*calcsize('nP')) 1301 # setiterator 1302 check(iter(set()), size('P3n')) 1303 # slice 1304 check(slice(0), size('3P')) 1305 # super 1306 check(super(int), size('3P')) 1307 # tuple 1308 check((), vsize('')) 1309 check((1,2,3), vsize('') + 3*self.P) 1310 # type 1311 # static type: PyTypeObject 1312 fmt = 'P2nPI13Pl4Pn9Pn11PIPPP' 1313 if hasattr(sys, 'getcounts'): 1314 fmt += '3n2P' 1315 s = vsize(fmt) 1316 check(int, s) 1317 # class 1318 s = vsize(fmt + # PyTypeObject 1319 '3P' # PyAsyncMethods 1320 '36P' # PyNumberMethods 1321 '3P' # PyMappingMethods 1322 '10P' # PySequenceMethods 1323 '2P' # PyBufferProcs 1324 '4P') 1325 class newstyleclass(object): pass 1326 # Separate block for PyDictKeysObject with 8 keys and 5 entries 1327 check(newstyleclass, s + calcsize("2nP2n0P") + 8 + 5*calcsize("n2P")) 1328 # dict with shared keys 1329 check(newstyleclass().__dict__, size('nQ2P') + 5*self.P) 1330 o = newstyleclass() 1331 o.a = o.b = o.c = o.d = o.e = o.f = o.g = o.h = 1 1332 # Separate block for PyDictKeysObject with 16 keys and 10 entries 1333 check(newstyleclass, s + calcsize("2nP2n0P") + 16 + 10*calcsize("n2P")) 1334 # dict with shared keys 1335 check(newstyleclass().__dict__, size('nQ2P') + 10*self.P) 1336 # unicode 1337 # each tuple contains a string and its expected character size 1338 # don't put any static strings here, as they may contain 1339 # wchar_t or UTF-8 representations 1340 samples = ['1'*100, '\xff'*50, 1341 '\u0100'*40, '\uffff'*100, 1342 '\U00010000'*30, '\U0010ffff'*100] 1343 asciifields = "nnbP" 1344 compactfields = asciifields + "nPn" 1345 unicodefields = compactfields + "P" 1346 for s in samples: 1347 maxchar = ord(max(s)) 1348 if maxchar < 128: 1349 L = size(asciifields) + len(s) + 1 1350 elif maxchar < 256: 1351 L = size(compactfields) + len(s) + 1 1352 elif maxchar < 65536: 1353 L = size(compactfields) + 2*(len(s) + 1) 1354 else: 1355 L = size(compactfields) + 4*(len(s) + 1) 1356 check(s, L) 1357 # verify that the UTF-8 size is accounted for 1358 s = chr(0x4000) # 4 bytes canonical representation 1359 check(s, size(compactfields) + 4) 1360 # compile() will trigger the generation of the UTF-8 1361 # representation as a side effect 1362 compile(s, "<stdin>", "eval") 1363 check(s, size(compactfields) + 4 + 4) 1364 # TODO: add check that forces the presence of wchar_t representation 1365 # TODO: add check that forces layout of unicodefields 1366 # weakref 1367 import weakref 1368 check(weakref.ref(int), size('2Pn2P')) 1369 # weakproxy 1370 # XXX 1371 # weakcallableproxy 1372 check(weakref.proxy(int), size('2Pn2P')) 1373 1374 def check_slots(self, obj, base, extra): 1375 expected = sys.getsizeof(base) + struct.calcsize(extra) 1376 if gc.is_tracked(obj) and not gc.is_tracked(base): 1377 expected += self.gc_headsize 1378 self.assertEqual(sys.getsizeof(obj), expected) 1379 1380 def test_slots(self): 1381 # check all subclassable types defined in Objects/ that allow 1382 # non-empty __slots__ 1383 check = self.check_slots 1384 class BA(bytearray): 1385 __slots__ = 'a', 'b', 'c' 1386 check(BA(), bytearray(), '3P') 1387 class D(dict): 1388 __slots__ = 'a', 'b', 'c' 1389 check(D(x=[]), {'x': []}, '3P') 1390 class L(list): 1391 __slots__ = 'a', 'b', 'c' 1392 check(L(), [], '3P') 1393 class S(set): 1394 __slots__ = 'a', 'b', 'c' 1395 check(S(), set(), '3P') 1396 class FS(frozenset): 1397 __slots__ = 'a', 'b', 'c' 1398 check(FS(), frozenset(), '3P') 1399 from collections import OrderedDict 1400 class OD(OrderedDict): 1401 __slots__ = 'a', 'b', 'c' 1402 check(OD(x=[]), OrderedDict(x=[]), '3P') 1403 1404 def test_pythontypes(self): 1405 # check all types defined in Python/ 1406 size = test.support.calcobjsize 1407 vsize = test.support.calcvobjsize 1408 check = self.check_sizeof 1409 # _ast.AST 1410 import _ast 1411 check(_ast.AST(), size('P')) 1412 try: 1413 raise TypeError 1414 except TypeError: 1415 tb = sys.exc_info()[2] 1416 # traceback 1417 if tb is not None: 1418 check(tb, size('2P2i')) 1419 # symtable entry 1420 # XXX 1421 # sys.flags 1422 check(sys.flags, vsize('') + self.P * len(sys.flags)) 1423 1424 def test_asyncgen_hooks(self): 1425 old = sys.get_asyncgen_hooks() 1426 self.assertIsNone(old.firstiter) 1427 self.assertIsNone(old.finalizer) 1428 1429 firstiter = lambda *a: None 1430 sys.set_asyncgen_hooks(firstiter=firstiter) 1431 hooks = sys.get_asyncgen_hooks() 1432 self.assertIs(hooks.firstiter, firstiter) 1433 self.assertIs(hooks[0], firstiter) 1434 self.assertIs(hooks.finalizer, None) 1435 self.assertIs(hooks[1], None) 1436 1437 finalizer = lambda *a: None 1438 sys.set_asyncgen_hooks(finalizer=finalizer) 1439 hooks = sys.get_asyncgen_hooks() 1440 self.assertIs(hooks.firstiter, firstiter) 1441 self.assertIs(hooks[0], firstiter) 1442 self.assertIs(hooks.finalizer, finalizer) 1443 self.assertIs(hooks[1], finalizer) 1444 1445 sys.set_asyncgen_hooks(*old) 1446 cur = sys.get_asyncgen_hooks() 1447 self.assertIsNone(cur.firstiter) 1448 self.assertIsNone(cur.finalizer) 1449 1450 1451if __name__ == "__main__": 1452 unittest.main() 1453