test_sys.py revision 871dfc41d37b02a7af6eb03028edc6702f24fd1d
1import unittest, test.support 2from test.script_helper import assert_python_ok, assert_python_failure 3import sys, io, os 4import struct 5import subprocess 6import textwrap 7import warnings 8import operator 9import codecs 10import gc 11import sysconfig 12import platform 13 14# count the number of test runs, used to create unique 15# strings to intern in test_intern() 16numruns = 0 17 18try: 19 import threading 20except ImportError: 21 threading = None 22 23class SysModuleTest(unittest.TestCase): 24 25 def setUp(self): 26 self.orig_stdout = sys.stdout 27 self.orig_stderr = sys.stderr 28 self.orig_displayhook = sys.displayhook 29 30 def tearDown(self): 31 sys.stdout = self.orig_stdout 32 sys.stderr = self.orig_stderr 33 sys.displayhook = self.orig_displayhook 34 test.support.reap_children() 35 36 def test_original_displayhook(self): 37 import builtins 38 out = io.StringIO() 39 sys.stdout = out 40 41 dh = sys.__displayhook__ 42 43 self.assertRaises(TypeError, dh) 44 if hasattr(builtins, "_"): 45 del builtins._ 46 47 dh(None) 48 self.assertEqual(out.getvalue(), "") 49 self.assertTrue(not hasattr(builtins, "_")) 50 dh(42) 51 self.assertEqual(out.getvalue(), "42\n") 52 self.assertEqual(builtins._, 42) 53 54 del sys.stdout 55 self.assertRaises(RuntimeError, dh, 42) 56 57 def test_lost_displayhook(self): 58 del sys.displayhook 59 code = compile("42", "<string>", "single") 60 self.assertRaises(RuntimeError, eval, code) 61 62 def test_custom_displayhook(self): 63 def baddisplayhook(obj): 64 raise ValueError 65 sys.displayhook = baddisplayhook 66 code = compile("42", "<string>", "single") 67 self.assertRaises(ValueError, eval, code) 68 69 def test_original_excepthook(self): 70 err = io.StringIO() 71 sys.stderr = err 72 73 eh = sys.__excepthook__ 74 75 self.assertRaises(TypeError, eh) 76 try: 77 raise ValueError(42) 78 except ValueError as exc: 79 eh(*sys.exc_info()) 80 81 self.assertTrue(err.getvalue().endswith("ValueError: 42\n")) 82 83 def test_excepthook(self): 84 with test.support.captured_output("stderr") as stderr: 85 sys.excepthook(1, '1', 1) 86 self.assertTrue("TypeError: print_exception(): Exception expected for " \ 87 "value, str found" in stderr.getvalue()) 88 89 # FIXME: testing the code for a lost or replaced excepthook in 90 # Python/pythonrun.c::PyErr_PrintEx() is tricky. 91 92 def test_exit(self): 93 # call with two arguments 94 self.assertRaises(TypeError, sys.exit, 42, 42) 95 96 # call without argument 97 with self.assertRaises(SystemExit) as cm: 98 sys.exit() 99 self.assertIsNone(cm.exception.code) 100 101 rc, out, err = assert_python_ok('-c', 'import sys; sys.exit()') 102 self.assertEqual(rc, 0) 103 self.assertEqual(out, b'') 104 self.assertEqual(err, b'') 105 106 # call with integer argument 107 with self.assertRaises(SystemExit) as cm: 108 sys.exit(42) 109 self.assertEqual(cm.exception.code, 42) 110 111 # call with tuple argument with one entry 112 # entry will be unpacked 113 with self.assertRaises(SystemExit) as cm: 114 sys.exit((42,)) 115 self.assertEqual(cm.exception.code, 42) 116 117 # call with string argument 118 with self.assertRaises(SystemExit) as cm: 119 sys.exit("exit") 120 self.assertEqual(cm.exception.code, "exit") 121 122 # call with tuple argument with two entries 123 with self.assertRaises(SystemExit) as cm: 124 sys.exit((17, 23)) 125 self.assertEqual(cm.exception.code, (17, 23)) 126 127 # test that the exit machinery handles SystemExits properly 128 rc, out, err = assert_python_failure('-c', 'raise SystemExit(47)') 129 self.assertEqual(rc, 47) 130 self.assertEqual(out, b'') 131 self.assertEqual(err, b'') 132 133 def check_exit_message(code, expected, **env_vars): 134 rc, out, err = assert_python_failure('-c', code, **env_vars) 135 self.assertEqual(rc, 1) 136 self.assertEqual(out, b'') 137 self.assertTrue(err.startswith(expected), 138 "%s doesn't start with %s" % (ascii(err), ascii(expected))) 139 140 # test that stderr buffer is flushed before the exit message is written 141 # into stderr 142 check_exit_message( 143 r'import sys; sys.stderr.write("unflushed,"); sys.exit("message")', 144 b"unflushed,message") 145 146 # test that the exit message is written with backslashreplace error 147 # handler to stderr 148 check_exit_message( 149 r'import sys; sys.exit("surrogates:\uDCFF")', 150 b"surrogates:\\udcff") 151 152 # test that the unicode message is encoded to the stderr encoding 153 # instead of the default encoding (utf8) 154 check_exit_message( 155 r'import sys; sys.exit("h\xe9")', 156 b"h\xe9", PYTHONIOENCODING='latin-1') 157 158 def test_getdefaultencoding(self): 159 self.assertRaises(TypeError, sys.getdefaultencoding, 42) 160 # can't check more than the type, as the user might have changed it 161 self.assertIsInstance(sys.getdefaultencoding(), str) 162 163 # testing sys.settrace() is done in test_sys_settrace.py 164 # testing sys.setprofile() is done in test_sys_setprofile.py 165 166 def test_setcheckinterval(self): 167 with warnings.catch_warnings(): 168 warnings.simplefilter("ignore") 169 self.assertRaises(TypeError, sys.setcheckinterval) 170 orig = sys.getcheckinterval() 171 for n in 0, 100, 120, orig: # orig last to restore starting state 172 sys.setcheckinterval(n) 173 self.assertEqual(sys.getcheckinterval(), n) 174 175 @unittest.skipUnless(threading, 'Threading required for this test.') 176 def test_switchinterval(self): 177 self.assertRaises(TypeError, sys.setswitchinterval) 178 self.assertRaises(TypeError, sys.setswitchinterval, "a") 179 self.assertRaises(ValueError, sys.setswitchinterval, -1.0) 180 self.assertRaises(ValueError, sys.setswitchinterval, 0.0) 181 orig = sys.getswitchinterval() 182 # sanity check 183 self.assertTrue(orig < 0.5, orig) 184 try: 185 for n in 0.00001, 0.05, 3.0, orig: 186 sys.setswitchinterval(n) 187 self.assertAlmostEqual(sys.getswitchinterval(), n) 188 finally: 189 sys.setswitchinterval(orig) 190 191 def test_recursionlimit(self): 192 self.assertRaises(TypeError, sys.getrecursionlimit, 42) 193 oldlimit = sys.getrecursionlimit() 194 self.assertRaises(TypeError, sys.setrecursionlimit) 195 self.assertRaises(ValueError, sys.setrecursionlimit, -42) 196 sys.setrecursionlimit(10000) 197 self.assertEqual(sys.getrecursionlimit(), 10000) 198 sys.setrecursionlimit(oldlimit) 199 200 @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(), 201 'fatal error if run with a trace function') 202 def test_recursionlimit_recovery(self): 203 # NOTE: this test is slightly fragile in that it depends on the current 204 # recursion count when executing the test being low enough so as to 205 # trigger the recursion recovery detection in the _Py_MakeEndRecCheck 206 # macro (see ceval.h). 207 oldlimit = sys.getrecursionlimit() 208 def f(): 209 f() 210 try: 211 for i in (50, 1000): 212 # Issue #5392: stack overflow after hitting recursion limit twice 213 sys.setrecursionlimit(i) 214 self.assertRaises(RuntimeError, f) 215 self.assertRaises(RuntimeError, f) 216 finally: 217 sys.setrecursionlimit(oldlimit) 218 219 def test_recursionlimit_fatalerror(self): 220 # A fatal error occurs if a second recursion limit is hit when recovering 221 # from a first one. 222 code = textwrap.dedent(""" 223 import sys 224 225 def f(): 226 try: 227 f() 228 except RuntimeError: 229 f() 230 231 sys.setrecursionlimit(%d) 232 f()""") 233 with test.support.SuppressCrashReport(): 234 for i in (50, 1000): 235 sub = subprocess.Popen([sys.executable, '-c', code % i], 236 stderr=subprocess.PIPE) 237 err = sub.communicate()[1] 238 self.assertTrue(sub.returncode, sub.returncode) 239 self.assertIn( 240 b"Fatal Python error: Cannot recover from stack overflow", 241 err) 242 243 def test_getwindowsversion(self): 244 # Raise SkipTest if sys doesn't have getwindowsversion attribute 245 test.support.get_attribute(sys, "getwindowsversion") 246 v = sys.getwindowsversion() 247 self.assertEqual(len(v), 5) 248 self.assertIsInstance(v[0], int) 249 self.assertIsInstance(v[1], int) 250 self.assertIsInstance(v[2], int) 251 self.assertIsInstance(v[3], int) 252 self.assertIsInstance(v[4], str) 253 self.assertRaises(IndexError, operator.getitem, v, 5) 254 self.assertIsInstance(v.major, int) 255 self.assertIsInstance(v.minor, int) 256 self.assertIsInstance(v.build, int) 257 self.assertIsInstance(v.platform, int) 258 self.assertIsInstance(v.service_pack, str) 259 self.assertIsInstance(v.service_pack_minor, int) 260 self.assertIsInstance(v.service_pack_major, int) 261 self.assertIsInstance(v.suite_mask, int) 262 self.assertIsInstance(v.product_type, int) 263 self.assertEqual(v[0], v.major) 264 self.assertEqual(v[1], v.minor) 265 self.assertEqual(v[2], v.build) 266 self.assertEqual(v[3], v.platform) 267 self.assertEqual(v[4], v.service_pack) 268 269 # This is how platform.py calls it. Make sure tuple 270 # still has 5 elements 271 maj, min, buildno, plat, csd = sys.getwindowsversion() 272 273 def test_call_tracing(self): 274 self.assertRaises(TypeError, sys.call_tracing, type, 2) 275 276 @unittest.skipUnless(hasattr(sys, "setdlopenflags"), 277 'test needs sys.setdlopenflags()') 278 def test_dlopenflags(self): 279 self.assertTrue(hasattr(sys, "getdlopenflags")) 280 self.assertRaises(TypeError, sys.getdlopenflags, 42) 281 oldflags = sys.getdlopenflags() 282 self.assertRaises(TypeError, sys.setdlopenflags) 283 sys.setdlopenflags(oldflags+1) 284 self.assertEqual(sys.getdlopenflags(), oldflags+1) 285 sys.setdlopenflags(oldflags) 286 287 @test.support.refcount_test 288 def test_refcount(self): 289 # n here must be a global in order for this test to pass while 290 # tracing with a python function. Tracing calls PyFrame_FastToLocals 291 # which will add a copy of any locals to the frame object, causing 292 # the reference count to increase by 2 instead of 1. 293 global n 294 self.assertRaises(TypeError, sys.getrefcount) 295 c = sys.getrefcount(None) 296 n = None 297 self.assertEqual(sys.getrefcount(None), c+1) 298 del n 299 self.assertEqual(sys.getrefcount(None), c) 300 if hasattr(sys, "gettotalrefcount"): 301 self.assertIsInstance(sys.gettotalrefcount(), int) 302 303 def test_getframe(self): 304 self.assertRaises(TypeError, sys._getframe, 42, 42) 305 self.assertRaises(ValueError, sys._getframe, 2000000000) 306 self.assertTrue( 307 SysModuleTest.test_getframe.__code__ \ 308 is sys._getframe().f_code 309 ) 310 311 # sys._current_frames() is a CPython-only gimmick. 312 def test_current_frames(self): 313 have_threads = True 314 try: 315 import _thread 316 except ImportError: 317 have_threads = False 318 319 if have_threads: 320 self.current_frames_with_threads() 321 else: 322 self.current_frames_without_threads() 323 324 # Test sys._current_frames() in a WITH_THREADS build. 325 @test.support.reap_threads 326 def current_frames_with_threads(self): 327 import threading 328 import traceback 329 330 # Spawn a thread that blocks at a known place. Then the main 331 # thread does sys._current_frames(), and verifies that the frames 332 # returned make sense. 333 entered_g = threading.Event() 334 leave_g = threading.Event() 335 thread_info = [] # the thread's id 336 337 def f123(): 338 g456() 339 340 def g456(): 341 thread_info.append(threading.get_ident()) 342 entered_g.set() 343 leave_g.wait() 344 345 t = threading.Thread(target=f123) 346 t.start() 347 entered_g.wait() 348 349 # At this point, t has finished its entered_g.set(), although it's 350 # impossible to guess whether it's still on that line or has moved on 351 # to its leave_g.wait(). 352 self.assertEqual(len(thread_info), 1) 353 thread_id = thread_info[0] 354 355 d = sys._current_frames() 356 357 main_id = threading.get_ident() 358 self.assertIn(main_id, d) 359 self.assertIn(thread_id, d) 360 361 # Verify that the captured main-thread frame is _this_ frame. 362 frame = d.pop(main_id) 363 self.assertTrue(frame is sys._getframe()) 364 365 # Verify that the captured thread frame is blocked in g456, called 366 # from f123. This is a litte tricky, since various bits of 367 # threading.py are also in the thread's call stack. 368 frame = d.pop(thread_id) 369 stack = traceback.extract_stack(frame) 370 for i, (filename, lineno, funcname, sourceline) in enumerate(stack): 371 if funcname == "f123": 372 break 373 else: 374 self.fail("didn't find f123() on thread's call stack") 375 376 self.assertEqual(sourceline, "g456()") 377 378 # And the next record must be for g456(). 379 filename, lineno, funcname, sourceline = stack[i+1] 380 self.assertEqual(funcname, "g456") 381 self.assertIn(sourceline, ["leave_g.wait()", "entered_g.set()"]) 382 383 # Reap the spawned thread. 384 leave_g.set() 385 t.join() 386 387 # Test sys._current_frames() when thread support doesn't exist. 388 def current_frames_without_threads(self): 389 # Not much happens here: there is only one thread, with artificial 390 # "thread id" 0. 391 d = sys._current_frames() 392 self.assertEqual(len(d), 1) 393 self.assertIn(0, d) 394 self.assertTrue(d[0] is sys._getframe()) 395 396 def test_attributes(self): 397 self.assertIsInstance(sys.api_version, int) 398 self.assertIsInstance(sys.argv, list) 399 self.assertIn(sys.byteorder, ("little", "big")) 400 self.assertIsInstance(sys.builtin_module_names, tuple) 401 self.assertIsInstance(sys.copyright, str) 402 self.assertIsInstance(sys.exec_prefix, str) 403 self.assertIsInstance(sys.base_exec_prefix, str) 404 self.assertIsInstance(sys.executable, str) 405 self.assertEqual(len(sys.float_info), 11) 406 self.assertEqual(sys.float_info.radix, 2) 407 self.assertEqual(len(sys.int_info), 2) 408 self.assertTrue(sys.int_info.bits_per_digit % 5 == 0) 409 self.assertTrue(sys.int_info.sizeof_digit >= 1) 410 self.assertEqual(type(sys.int_info.bits_per_digit), int) 411 self.assertEqual(type(sys.int_info.sizeof_digit), int) 412 self.assertIsInstance(sys.hexversion, int) 413 414 self.assertEqual(len(sys.hash_info), 9) 415 self.assertLess(sys.hash_info.modulus, 2**sys.hash_info.width) 416 # sys.hash_info.modulus should be a prime; we do a quick 417 # probable primality test (doesn't exclude the possibility of 418 # a Carmichael number) 419 for x in range(1, 100): 420 self.assertEqual( 421 pow(x, sys.hash_info.modulus-1, sys.hash_info.modulus), 422 1, 423 "sys.hash_info.modulus {} is a non-prime".format( 424 sys.hash_info.modulus) 425 ) 426 self.assertIsInstance(sys.hash_info.inf, int) 427 self.assertIsInstance(sys.hash_info.nan, int) 428 self.assertIsInstance(sys.hash_info.imag, int) 429 algo = sysconfig.get_config_var("Py_HASH_ALGORITHM") 430 if sys.hash_info.algorithm in {"fnv", "siphash24"}: 431 self.assertIn(sys.hash_info.hash_bits, {32, 64}) 432 self.assertIn(sys.hash_info.seed_bits, {32, 64, 128}) 433 434 if algo == 1: 435 self.assertEqual(sys.hash_info.algorithm, "siphash24") 436 elif algo == 2: 437 self.assertEqual(sys.hash_info.algorithm, "fnv") 438 else: 439 self.assertIn(sys.hash_info.algorithm, {"fnv", "siphash24"}) 440 else: 441 # PY_HASH_EXTERNAL 442 self.assertEqual(algo, 0) 443 self.assertGreaterEqual(sys.hash_info.cutoff, 0) 444 self.assertLess(sys.hash_info.cutoff, 8) 445 446 self.assertIsInstance(sys.maxsize, int) 447 self.assertIsInstance(sys.maxunicode, int) 448 self.assertEqual(sys.maxunicode, 0x10FFFF) 449 self.assertIsInstance(sys.platform, str) 450 self.assertIsInstance(sys.prefix, str) 451 self.assertIsInstance(sys.base_prefix, str) 452 self.assertIsInstance(sys.version, str) 453 vi = sys.version_info 454 self.assertIsInstance(vi[:], tuple) 455 self.assertEqual(len(vi), 5) 456 self.assertIsInstance(vi[0], int) 457 self.assertIsInstance(vi[1], int) 458 self.assertIsInstance(vi[2], int) 459 self.assertIn(vi[3], ("alpha", "beta", "candidate", "final")) 460 self.assertIsInstance(vi[4], int) 461 self.assertIsInstance(vi.major, int) 462 self.assertIsInstance(vi.minor, int) 463 self.assertIsInstance(vi.micro, int) 464 self.assertIn(vi.releaselevel, ("alpha", "beta", "candidate", "final")) 465 self.assertIsInstance(vi.serial, int) 466 self.assertEqual(vi[0], vi.major) 467 self.assertEqual(vi[1], vi.minor) 468 self.assertEqual(vi[2], vi.micro) 469 self.assertEqual(vi[3], vi.releaselevel) 470 self.assertEqual(vi[4], vi.serial) 471 self.assertTrue(vi > (1,0,0)) 472 self.assertIsInstance(sys.float_repr_style, str) 473 self.assertIn(sys.float_repr_style, ('short', 'legacy')) 474 if not sys.platform.startswith('win'): 475 self.assertIsInstance(sys.abiflags, str) 476 477 @unittest.skipUnless(hasattr(sys, 'thread_info'), 478 'Threading required for this test.') 479 def test_thread_info(self): 480 info = sys.thread_info 481 self.assertEqual(len(info), 3) 482 self.assertIn(info.name, ('nt', 'pthread', 'solaris', None)) 483 self.assertIn(info.lock, ('semaphore', 'mutex+cond', None)) 484 485 def test_43581(self): 486 # Can't use sys.stdout, as this is a StringIO object when 487 # the test runs under regrtest. 488 self.assertEqual(sys.__stdout__.encoding, sys.__stderr__.encoding) 489 490 def test_intern(self): 491 global numruns 492 numruns += 1 493 self.assertRaises(TypeError, sys.intern) 494 s = "never interned before" + str(numruns) 495 self.assertTrue(sys.intern(s) is s) 496 s2 = s.swapcase().swapcase() 497 self.assertTrue(sys.intern(s2) is s) 498 499 # Subclasses of string can't be interned, because they 500 # provide too much opportunity for insane things to happen. 501 # We don't want them in the interned dict and if they aren't 502 # actually interned, we don't want to create the appearance 503 # that they are by allowing intern() to succeed. 504 class S(str): 505 def __hash__(self): 506 return 123 507 508 self.assertRaises(TypeError, sys.intern, S("abc")) 509 510 def test_sys_flags(self): 511 self.assertTrue(sys.flags) 512 attrs = ("debug", 513 "inspect", "interactive", "optimize", "dont_write_bytecode", 514 "no_user_site", "no_site", "ignore_environment", "verbose", 515 "bytes_warning", "quiet", "hash_randomization", "isolated") 516 for attr in attrs: 517 self.assertTrue(hasattr(sys.flags, attr), attr) 518 self.assertEqual(type(getattr(sys.flags, attr)), int, attr) 519 self.assertTrue(repr(sys.flags)) 520 self.assertEqual(len(sys.flags), len(attrs)) 521 522 def assert_raise_on_new_sys_type(self, sys_attr): 523 # Users are intentionally prevented from creating new instances of 524 # sys.flags, sys.version_info, and sys.getwindowsversion. 525 attr_type = type(sys_attr) 526 with self.assertRaises(TypeError): 527 attr_type() 528 with self.assertRaises(TypeError): 529 attr_type.__new__(attr_type) 530 531 def test_sys_flags_no_instantiation(self): 532 self.assert_raise_on_new_sys_type(sys.flags) 533 534 def test_sys_version_info_no_instantiation(self): 535 self.assert_raise_on_new_sys_type(sys.version_info) 536 537 def test_sys_getwindowsversion_no_instantiation(self): 538 # Skip if not being run on Windows. 539 test.support.get_attribute(sys, "getwindowsversion") 540 self.assert_raise_on_new_sys_type(sys.getwindowsversion()) 541 542 def test_clear_type_cache(self): 543 sys._clear_type_cache() 544 545 def test_ioencoding(self): 546 env = dict(os.environ) 547 548 # Test character: cent sign, encoded as 0x4A (ASCII J) in CP424, 549 # not representable in ASCII. 550 551 env["PYTHONIOENCODING"] = "cp424" 552 p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xa2))'], 553 stdout = subprocess.PIPE, env=env) 554 out = p.communicate()[0].strip() 555 expected = ("\xa2" + os.linesep).encode("cp424") 556 self.assertEqual(out, expected) 557 558 env["PYTHONIOENCODING"] = "ascii:replace" 559 p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xa2))'], 560 stdout = subprocess.PIPE, env=env) 561 out = p.communicate()[0].strip() 562 self.assertEqual(out, b'?') 563 564 env["PYTHONIOENCODING"] = "ascii" 565 p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xa2))'], 566 stdout=subprocess.PIPE, stderr=subprocess.PIPE, 567 env=env) 568 out, err = p.communicate() 569 self.assertEqual(out, b'') 570 self.assertIn(b'UnicodeEncodeError:', err) 571 self.assertIn(rb"'\xa2'", err) 572 573 env["PYTHONIOENCODING"] = "ascii:" 574 p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xa2))'], 575 stdout=subprocess.PIPE, stderr=subprocess.PIPE, 576 env=env) 577 out, err = p.communicate() 578 self.assertEqual(out, b'') 579 self.assertIn(b'UnicodeEncodeError:', err) 580 self.assertIn(rb"'\xa2'", err) 581 582 env["PYTHONIOENCODING"] = ":surrogateescape" 583 p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xdcbd))'], 584 stdout=subprocess.PIPE, env=env) 585 out = p.communicate()[0].strip() 586 self.assertEqual(out, b'\xbd') 587 588 @unittest.skipUnless(test.support.FS_NONASCII, 589 'requires OS support of non-ASCII encodings') 590 def test_ioencoding_nonascii(self): 591 env = dict(os.environ) 592 593 env["PYTHONIOENCODING"] = "" 594 p = subprocess.Popen([sys.executable, "-c", 595 'print(%a)' % test.support.FS_NONASCII], 596 stdout=subprocess.PIPE, env=env) 597 out = p.communicate()[0].strip() 598 self.assertEqual(out, os.fsencode(test.support.FS_NONASCII)) 599 600 @unittest.skipIf(sys.base_prefix != sys.prefix, 601 'Test is not venv-compatible') 602 def test_executable(self): 603 # sys.executable should be absolute 604 self.assertEqual(os.path.abspath(sys.executable), sys.executable) 605 606 # Issue #7774: Ensure that sys.executable is an empty string if argv[0] 607 # has been set to an non existent program name and Python is unable to 608 # retrieve the real program name 609 610 # For a normal installation, it should work without 'cwd' 611 # argument. For test runs in the build directory, see #7774. 612 python_dir = os.path.dirname(os.path.realpath(sys.executable)) 613 p = subprocess.Popen( 614 ["nonexistent", "-c", 615 'import sys; print(sys.executable.encode("ascii", "backslashreplace"))'], 616 executable=sys.executable, stdout=subprocess.PIPE, cwd=python_dir) 617 stdout = p.communicate()[0] 618 executable = stdout.strip().decode("ASCII") 619 p.wait() 620 self.assertIn(executable, ["b''", repr(sys.executable.encode("ascii", "backslashreplace"))]) 621 622 def check_fsencoding(self, fs_encoding, expected=None): 623 self.assertIsNotNone(fs_encoding) 624 codecs.lookup(fs_encoding) 625 if expected: 626 self.assertEqual(fs_encoding, expected) 627 628 def test_getfilesystemencoding(self): 629 fs_encoding = sys.getfilesystemencoding() 630 if sys.platform == 'darwin': 631 expected = 'utf-8' 632 elif sys.platform == 'win32': 633 expected = 'mbcs' 634 else: 635 expected = None 636 self.check_fsencoding(fs_encoding, expected) 637 638 def test_implementation(self): 639 # This test applies to all implementations equally. 640 641 levels = {'alpha': 0xA, 'beta': 0xB, 'candidate': 0xC, 'final': 0xF} 642 643 self.assertTrue(hasattr(sys.implementation, 'name')) 644 self.assertTrue(hasattr(sys.implementation, 'version')) 645 self.assertTrue(hasattr(sys.implementation, 'hexversion')) 646 self.assertTrue(hasattr(sys.implementation, 'cache_tag')) 647 648 version = sys.implementation.version 649 self.assertEqual(version[:2], (version.major, version.minor)) 650 651 hexversion = (version.major << 24 | version.minor << 16 | 652 version.micro << 8 | levels[version.releaselevel] << 4 | 653 version.serial << 0) 654 self.assertEqual(sys.implementation.hexversion, hexversion) 655 656 # PEP 421 requires that .name be lower case. 657 self.assertEqual(sys.implementation.name, 658 sys.implementation.name.lower()) 659 660 def test_debugmallocstats(self): 661 # Test sys._debugmallocstats() 662 from test.script_helper import assert_python_ok 663 args = ['-c', 'import sys; sys._debugmallocstats()'] 664 ret, out, err = assert_python_ok(*args) 665 self.assertIn(b"free PyDictObjects", err) 666 667 # The function has no parameter 668 self.assertRaises(TypeError, sys._debugmallocstats, True) 669 670 @unittest.skipUnless(hasattr(sys, "getallocatedblocks"), 671 "sys.getallocatedblocks unavailable on this build") 672 def test_getallocatedblocks(self): 673 # Some sanity checks 674 with_pymalloc = sysconfig.get_config_var('WITH_PYMALLOC') 675 a = sys.getallocatedblocks() 676 self.assertIs(type(a), int) 677 if with_pymalloc: 678 self.assertGreater(a, 0) 679 else: 680 # When WITH_PYMALLOC isn't available, we don't know anything 681 # about the underlying implementation: the function might 682 # return 0 or something greater. 683 self.assertGreaterEqual(a, 0) 684 try: 685 # While we could imagine a Python session where the number of 686 # multiple buffer objects would exceed the sharing of references, 687 # it is unlikely to happen in a normal test run. 688 self.assertLess(a, sys.gettotalrefcount()) 689 except AttributeError: 690 # gettotalrefcount() not available 691 pass 692 gc.collect() 693 b = sys.getallocatedblocks() 694 self.assertLessEqual(b, a) 695 gc.collect() 696 c = sys.getallocatedblocks() 697 self.assertIn(c, range(b - 50, b + 50)) 698 699 700@test.support.cpython_only 701class SizeofTest(unittest.TestCase): 702 703 def setUp(self): 704 self.P = struct.calcsize('P') 705 self.longdigit = sys.int_info.sizeof_digit 706 import _testcapi 707 self.gc_headsize = _testcapi.SIZEOF_PYGC_HEAD 708 self.file = open(test.support.TESTFN, 'wb') 709 710 def tearDown(self): 711 self.file.close() 712 test.support.unlink(test.support.TESTFN) 713 714 check_sizeof = test.support.check_sizeof 715 716 def test_gc_head_size(self): 717 # Check that the gc header size is added to objects tracked by the gc. 718 vsize = test.support.calcvobjsize 719 gc_header_size = self.gc_headsize 720 # bool objects are not gc tracked 721 self.assertEqual(sys.getsizeof(True), vsize('') + self.longdigit) 722 # but lists are 723 self.assertEqual(sys.getsizeof([]), vsize('Pn') + gc_header_size) 724 725 def test_default(self): 726 size = test.support.calcvobjsize 727 self.assertEqual(sys.getsizeof(True), size('') + self.longdigit) 728 self.assertEqual(sys.getsizeof(True, -1), size('') + self.longdigit) 729 730 def test_objecttypes(self): 731 # check all types defined in Objects/ 732 size = test.support.calcobjsize 733 vsize = test.support.calcvobjsize 734 check = self.check_sizeof 735 # bool 736 check(True, vsize('') + self.longdigit) 737 # buffer 738 # XXX 739 # builtin_function_or_method 740 check(len, size('3P')) # XXX check layout 741 # bytearray 742 samples = [b'', b'u'*100000] 743 for sample in samples: 744 x = bytearray(sample) 745 check(x, vsize('n2Pi') + x.__alloc__()) 746 # bytearray_iterator 747 check(iter(bytearray()), size('nP')) 748 # cell 749 def get_cell(): 750 x = 42 751 def inner(): 752 return x 753 return inner 754 check(get_cell().__closure__[0], size('P')) 755 # code 756 check(get_cell().__code__, size('5i9Pi3P')) 757 check(get_cell.__code__, size('5i9Pi3P')) 758 def get_cell2(x): 759 def inner(): 760 return x 761 return inner 762 check(get_cell2.__code__, size('5i9Pi3P') + 1) 763 # complex 764 check(complex(0,1), size('2d')) 765 # method_descriptor (descriptor object) 766 check(str.lower, size('3PP')) 767 # classmethod_descriptor (descriptor object) 768 # XXX 769 # member_descriptor (descriptor object) 770 import datetime 771 check(datetime.timedelta.days, size('3PP')) 772 # getset_descriptor (descriptor object) 773 import collections 774 check(collections.defaultdict.default_factory, size('3PP')) 775 # wrapper_descriptor (descriptor object) 776 check(int.__add__, size('3P2P')) 777 # method-wrapper (descriptor object) 778 check({}.__iter__, size('2P')) 779 # dict 780 check({}, size('n2P' + '2nPn' + 8*'n2P')) 781 longdict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8} 782 check(longdict, size('n2P' + '2nPn') + 16*struct.calcsize('n2P')) 783 # dictionary-keyiterator 784 check({}.keys(), size('P')) 785 # dictionary-valueiterator 786 check({}.values(), size('P')) 787 # dictionary-itemiterator 788 check({}.items(), size('P')) 789 # dictionary iterator 790 check(iter({}), size('P2nPn')) 791 # dictproxy 792 class C(object): pass 793 check(C.__dict__, size('P')) 794 # BaseException 795 check(BaseException(), size('5Pb')) 796 # UnicodeEncodeError 797 check(UnicodeEncodeError("", "", 0, 0, ""), size('5Pb 2P2nP')) 798 # UnicodeDecodeError 799 check(UnicodeDecodeError("", b"", 0, 0, ""), size('5Pb 2P2nP')) 800 # UnicodeTranslateError 801 check(UnicodeTranslateError("", 0, 1, ""), size('5Pb 2P2nP')) 802 # ellipses 803 check(Ellipsis, size('')) 804 # EncodingMap 805 import codecs, encodings.iso8859_3 806 x = codecs.charmap_build(encodings.iso8859_3.decoding_table) 807 check(x, size('32B2iB')) 808 # enumerate 809 check(enumerate([]), size('n3P')) 810 # reverse 811 check(reversed(''), size('nP')) 812 # float 813 check(float(0), size('d')) 814 # sys.floatinfo 815 check(sys.float_info, vsize('') + self.P * len(sys.float_info)) 816 # frame 817 import inspect 818 CO_MAXBLOCKS = 20 819 x = inspect.currentframe() 820 ncells = len(x.f_code.co_cellvars) 821 nfrees = len(x.f_code.co_freevars) 822 extras = x.f_code.co_stacksize + x.f_code.co_nlocals +\ 823 ncells + nfrees - 1 824 check(x, vsize('12P3ic' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) 825 # function 826 def func(): pass 827 check(func, size('12P')) 828 class c(): 829 @staticmethod 830 def foo(): 831 pass 832 @classmethod 833 def bar(cls): 834 pass 835 # staticmethod 836 check(foo, size('PP')) 837 # classmethod 838 check(bar, size('PP')) 839 # generator 840 def get_gen(): yield 1 841 check(get_gen(), size('Pb2P')) 842 # iterator 843 check(iter('abc'), size('lP')) 844 # callable-iterator 845 import re 846 check(re.finditer('',''), size('2P')) 847 # list 848 samples = [[], [1,2,3], ['1', '2', '3']] 849 for sample in samples: 850 check(sample, vsize('Pn') + len(sample)*self.P) 851 # sortwrapper (list) 852 # XXX 853 # cmpwrapper (list) 854 # XXX 855 # listiterator (list) 856 check(iter([]), size('lP')) 857 # listreverseiterator (list) 858 check(reversed([]), size('nP')) 859 # int 860 check(0, vsize('')) 861 check(1, vsize('') + self.longdigit) 862 check(-1, vsize('') + self.longdigit) 863 PyLong_BASE = 2**sys.int_info.bits_per_digit 864 check(int(PyLong_BASE), vsize('') + 2*self.longdigit) 865 check(int(PyLong_BASE**2-1), vsize('') + 2*self.longdigit) 866 check(int(PyLong_BASE**2), vsize('') + 3*self.longdigit) 867 # memoryview 868 check(memoryview(b''), size('Pnin 2P2n2i5P 3cPn')) 869 # module 870 check(unittest, size('PnPPP')) 871 # None 872 check(None, size('')) 873 # NotImplementedType 874 check(NotImplemented, size('')) 875 # object 876 check(object(), size('')) 877 # property (descriptor object) 878 class C(object): 879 def getx(self): return self.__x 880 def setx(self, value): self.__x = value 881 def delx(self): del self.__x 882 x = property(getx, setx, delx, "") 883 check(x, size('4Pi')) 884 # PyCapsule 885 # XXX 886 # rangeiterator 887 check(iter(range(1)), size('4l')) 888 # reverse 889 check(reversed(''), size('nP')) 890 # range 891 check(range(1), size('4P')) 892 check(range(66000), size('4P')) 893 # set 894 # frozenset 895 PySet_MINSIZE = 8 896 samples = [[], range(10), range(50)] 897 s = size('3n2P' + PySet_MINSIZE*'nP' + 'nP') 898 for sample in samples: 899 minused = len(sample) 900 if minused == 0: tmp = 1 901 # the computation of minused is actually a bit more complicated 902 # but this suffices for the sizeof test 903 minused = minused*2 904 newsize = PySet_MINSIZE 905 while newsize <= minused: 906 newsize = newsize << 1 907 if newsize <= 8: 908 check(set(sample), s) 909 check(frozenset(sample), s) 910 else: 911 check(set(sample), s + newsize*struct.calcsize('nP')) 912 check(frozenset(sample), s + newsize*struct.calcsize('nP')) 913 # setiterator 914 check(iter(set()), size('P3n')) 915 # slice 916 check(slice(0), size('3P')) 917 # super 918 check(super(int), size('3P')) 919 # tuple 920 check((), vsize('')) 921 check((1,2,3), vsize('') + 3*self.P) 922 # type 923 # static type: PyTypeObject 924 s = vsize('P2n15Pl4Pn9Pn11PIP') 925 check(int, s) 926 # (PyTypeObject + PyNumberMethods + PyMappingMethods + 927 # PySequenceMethods + PyBufferProcs + 4P) 928 s = vsize('P2n15Pl4Pn9Pn11PIP') + struct.calcsize('34P 3P 10P 2P 4P') 929 # Separate block for PyDictKeysObject with 4 entries 930 s += struct.calcsize("2nPn") + 4*struct.calcsize("n2P") 931 # class 932 class newstyleclass(object): pass 933 check(newstyleclass, s) 934 # dict with shared keys 935 check(newstyleclass().__dict__, size('n2P' + '2nPn')) 936 # unicode 937 # each tuple contains a string and its expected character size 938 # don't put any static strings here, as they may contain 939 # wchar_t or UTF-8 representations 940 samples = ['1'*100, '\xff'*50, 941 '\u0100'*40, '\uffff'*100, 942 '\U00010000'*30, '\U0010ffff'*100] 943 asciifields = "nnbP" 944 compactfields = asciifields + "nPn" 945 unicodefields = compactfields + "P" 946 for s in samples: 947 maxchar = ord(max(s)) 948 if maxchar < 128: 949 L = size(asciifields) + len(s) + 1 950 elif maxchar < 256: 951 L = size(compactfields) + len(s) + 1 952 elif maxchar < 65536: 953 L = size(compactfields) + 2*(len(s) + 1) 954 else: 955 L = size(compactfields) + 4*(len(s) + 1) 956 check(s, L) 957 # verify that the UTF-8 size is accounted for 958 s = chr(0x4000) # 4 bytes canonical representation 959 check(s, size(compactfields) + 4) 960 # compile() will trigger the generation of the UTF-8 961 # representation as a side effect 962 compile(s, "<stdin>", "eval") 963 check(s, size(compactfields) + 4 + 4) 964 # TODO: add check that forces the presence of wchar_t representation 965 # TODO: add check that forces layout of unicodefields 966 # weakref 967 import weakref 968 check(weakref.ref(int), size('2Pn2P')) 969 # weakproxy 970 # XXX 971 # weakcallableproxy 972 check(weakref.proxy(int), size('2Pn2P')) 973 974 def test_pythontypes(self): 975 # check all types defined in Python/ 976 size = test.support.calcobjsize 977 vsize = test.support.calcvobjsize 978 check = self.check_sizeof 979 # _ast.AST 980 import _ast 981 check(_ast.AST(), size('P')) 982 try: 983 raise TypeError 984 except TypeError: 985 tb = sys.exc_info()[2] 986 # traceback 987 if tb is not None: 988 check(tb, size('2P2i')) 989 # symtable entry 990 # XXX 991 # sys.flags 992 check(sys.flags, vsize('') + self.P * len(sys.flags)) 993 994 995def test_main(): 996 test.support.run_unittest(SysModuleTest, SizeofTest) 997 998if __name__ == "__main__": 999 test_main() 1000