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