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