1 import unittest, test.support 2 from test.support.script_helper import assert_python_ok, assert_python_failure 3 import sys, io, os 4 import struct 5 import subprocess 6 import textwrap 7 import warnings 8 import operator 9 import codecs 10 import gc 11 import sysconfig 12 import platform 13 import locale 14 15 # count the number of test runs, used to create unique 16 # strings to intern in test_intern() 17 numruns = 0 18 19 try: 20 import threading 21 except ImportError: 22 threading = None 23 24 class SysModuleTest(unittest.TestCase): 25 26 def setUp(self): 27 self.orig_stdout = sys.stdout 28 self.orig_stderr = sys.stderr 29 self.orig_displayhook = sys.displayhook 30 31 def tearDown(self): 32 sys.stdout = self.orig_stdout 33 sys.stderr = self.orig_stderr 34 sys.displayhook = self.orig_displayhook 35 test.support.reap_children() 36 37 def test_original_displayhook(self): 38 import builtins 39 out = io.StringIO() 40 sys.stdout = out 41 42 dh = sys.__displayhook__ 43 44 self.assertRaises(TypeError, dh) 45 if hasattr(builtins, "_"): 46 del builtins._ 47 48 dh(None) 49 self.assertEqual(out.getvalue(), "") 50 self.assertTrue(not hasattr(builtins, "_")) 51 dh(42) 52 self.assertEqual(out.getvalue(), "42\n") 53 self.assertEqual(builtins._, 42) 54 55 del sys.stdout 56 self.assertRaises(RuntimeError, dh, 42) 57 58 def test_lost_displayhook(self): 59 del sys.displayhook 60 code = compile("42", "<string>", "single") 61 self.assertRaises(RuntimeError, eval, code) 62 63 def test_custom_displayhook(self): 64 def baddisplayhook(obj): 65 raise ValueError 66 sys.displayhook = baddisplayhook 67 code = compile("42", "<string>", "single") 68 self.assertRaises(ValueError, eval, code) 69 70 def test_original_excepthook(self): 71 err = io.StringIO() 72 sys.stderr = err 73 74 eh = sys.__excepthook__ 75 76 self.assertRaises(TypeError, eh) 77 try: 78 raise ValueError(42) 79 except ValueError as exc: 80 eh(*sys.exc_info()) 81 82 self.assertTrue(err.getvalue().endswith("ValueError: 42\n")) 83 84 def test_excepthook(self): 85 with test.support.captured_output("stderr") as stderr: 86 sys.excepthook(1, '1', 1) 87 self.assertTrue("TypeError: print_exception(): Exception expected for " \ 88 "value, str found" in stderr.getvalue()) 89 90 # FIXME: testing the code for a lost or replaced excepthook in 91 # Python/pythonrun.c::PyErr_PrintEx() is tricky. 92 93 def test_exit(self): 94 # call with two arguments 95 self.assertRaises(TypeError, sys.exit, 42, 42) 96 97 # call without argument 98 with self.assertRaises(SystemExit) as cm: 99 sys.exit() 100 self.assertIsNone(cm.exception.code) 101 102 rc, out, err = assert_python_ok('-c', 'import sys; sys.exit()') 103 self.assertEqual(rc, 0) 104 self.assertEqual(out, b'') 105 self.assertEqual(err, b'') 106 107 # call with integer argument 108 with self.assertRaises(SystemExit) as cm: 109 sys.exit(42) 110 self.assertEqual(cm.exception.code, 42) 111 112 # call with tuple argument with one entry 113 # entry will be unpacked 114 with self.assertRaises(SystemExit) as cm: 115 sys.exit((42,)) 116 self.assertEqual(cm.exception.code, 42) 117 118 # call with string argument 119 with self.assertRaises(SystemExit) as cm: 120 sys.exit("exit") 121 self.assertEqual(cm.exception.code, "exit") 122 123 # call with tuple argument with two entries 124 with self.assertRaises(SystemExit) as cm: 125 sys.exit((17, 23)) 126 self.assertEqual(cm.exception.code, (17, 23)) 127 128 # test that the exit machinery handles SystemExits properly 129 rc, out, err = assert_python_failure('-c', 'raise SystemExit(47)') 130 self.assertEqual(rc, 47) 131 self.assertEqual(out, b'') 132 self.assertEqual(err, b'') 133 134 def check_exit_message(code, expected, **env_vars): 135 rc, out, err = assert_python_failure('-c', code, **env_vars) 136 self.assertEqual(rc, 1) 137 self.assertEqual(out, b'') 138 self.assertTrue(err.startswith(expected), 139 "%s doesn't start with %s" % (ascii(err), ascii(expected))) 140 141 # test that stderr buffer is flushed before the exit message is written 142 # into stderr 143 check_exit_message( 144 r'import sys; sys.stderr.write("unflushed,"); sys.exit("message")', 145 b"unflushed,message") 146 147 # test that the exit message is written with backslashreplace error 148 # handler to stderr 149 check_exit_message( 150 r'import sys; sys.exit("surrogates:\uDCFF")', 151 b"surrogates:\\udcff") 152 153 # test that the unicode message is encoded to the stderr encoding 154 # instead of the default encoding (utf8) 155 check_exit_message( 156 r'import sys; sys.exit("h\xe9")', 157 b"h\xe9", PYTHONIOENCODING='latin-1') 158 159 def test_getdefaultencoding(self): 160 self.assertRaises(TypeError, sys.getdefaultencoding, 42) 161 # can't check more than the type, as the user might have changed it 162 self.assertIsInstance(sys.getdefaultencoding(), str) 163 164 # testing sys.settrace() is done in test_sys_settrace.py 165 # testing sys.setprofile() is done in test_sys_setprofile.py 166 167 def test_setcheckinterval(self): 168 with warnings.catch_warnings(): 169 warnings.simplefilter("ignore") 170 self.assertRaises(TypeError, sys.setcheckinterval) 171 orig = sys.getcheckinterval() 172 for n in 0, 100, 120, orig: # orig last to restore starting state 173 sys.setcheckinterval(n) 174 self.assertEqual(sys.getcheckinterval(), n) 175 176 @unittest.skipUnless(threading, 'Threading required for this test.') 177 def test_switchinterval(self): 178 self.assertRaises(TypeError, sys.setswitchinterval) 179 self.assertRaises(TypeError, sys.setswitchinterval, "a") 180 self.assertRaises(ValueError, sys.setswitchinterval, -1.0) 181 self.assertRaises(ValueError, sys.setswitchinterval, 0.0) 182 orig = sys.getswitchinterval() 183 # sanity check 184 self.assertTrue(orig < 0.5, orig) 185 try: 186 for n in 0.00001, 0.05, 3.0, orig: 187 sys.setswitchinterval(n) 188 self.assertAlmostEqual(sys.getswitchinterval(), n) 189 finally: 190 sys.setswitchinterval(orig) 191 192 def test_recursionlimit(self): 193 self.assertRaises(TypeError, sys.getrecursionlimit, 42) 194 oldlimit = sys.getrecursionlimit() 195 self.assertRaises(TypeError, sys.setrecursionlimit) 196 self.assertRaises(ValueError, sys.setrecursionlimit, -42) 197 sys.setrecursionlimit(10000) 198 self.assertEqual(sys.getrecursionlimit(), 10000) 199 sys.setrecursionlimit(oldlimit) 200 201 def test_recursionlimit_recovery(self): 202 if hasattr(sys, 'gettrace') and sys.gettrace(): 203 self.skipTest('fatal error if run with a trace function') 204 205 oldlimit = sys.getrecursionlimit() 206 def f(): 207 f() 208 try: 209 for depth in (10, 25, 50, 75, 100, 250, 1000): 210 try: 211 sys.setrecursionlimit(depth) 212 except RecursionError: 213 # Issue #25274: The recursion limit is too low at the 214 # current recursion depth 215 continue 216 217 # Issue #5392: test stack overflow after hitting recursion 218 # limit twice 219 self.assertRaises(RecursionError, f) 220 self.assertRaises(RecursionError, f) 221 finally: 222 sys.setrecursionlimit(oldlimit) 223 224 @test.support.cpython_only 225 def test_setrecursionlimit_recursion_depth(self): 226 # Issue #25274: Setting a low recursion limit must be blocked if the 227 # current recursion depth is already higher than the "lower-water 228 # mark". Otherwise, it may not be possible anymore to 229 # reset the overflowed flag to 0. 230 231 from _testcapi import get_recursion_depth 232 233 def set_recursion_limit_at_depth(depth, limit): 234 recursion_depth = get_recursion_depth() 235 if recursion_depth >= depth: 236 with self.assertRaises(RecursionError) as cm: 237 sys.setrecursionlimit(limit) 238 self.assertRegex(str(cm.exception), 239 "cannot set the recursion limit to [0-9]+ " 240 "at the recursion depth [0-9]+: " 241 "the limit is too low") 242 else: 243 set_recursion_limit_at_depth(depth, limit) 244 245 oldlimit = sys.getrecursionlimit() 246 try: 247 sys.setrecursionlimit(1000) 248 249 for limit in (10, 25, 50, 75, 100, 150, 200): 250 # formula extracted from _Py_RecursionLimitLowerWaterMark() 251 if limit > 200: 252 depth = limit - 50 253 else: 254 depth = limit * 3 // 4 255 set_recursion_limit_at_depth(depth, limit) 256 finally: 257 sys.setrecursionlimit(oldlimit) 258 259 def test_recursionlimit_fatalerror(self): 260 # A fatal error occurs if a second recursion limit is hit when recovering 261 # from a first one. 262 code = textwrap.dedent(""" 263 import sys 264 265 def f(): 266 try: 267 f() 268 except RecursionError: 269 f() 270 271 sys.setrecursionlimit(%d) 272 f()""") 273 with test.support.SuppressCrashReport(): 274 for i in (50, 1000): 275 sub = subprocess.Popen([sys.executable, '-c', code % i], 276 stderr=subprocess.PIPE) 277 err = sub.communicate()[1] 278 self.assertTrue(sub.returncode, sub.returncode) 279 self.assertIn( 280 b"Fatal Python error: Cannot recover from stack overflow", 281 err) 282 283 def test_getwindowsversion(self): 284 # Raise SkipTest if sys doesn't have getwindowsversion attribute 285 test.support.get_attribute(sys, "getwindowsversion") 286 v = sys.getwindowsversion() 287 self.assertEqual(len(v), 5) 288 self.assertIsInstance(v[0], int) 289 self.assertIsInstance(v[1], int) 290 self.assertIsInstance(v[2], int) 291 self.assertIsInstance(v[3], int) 292 self.assertIsInstance(v[4], str) 293 self.assertRaises(IndexError, operator.getitem, v, 5) 294 self.assertIsInstance(v.major, int) 295 self.assertIsInstance(v.minor, int) 296 self.assertIsInstance(v.build, int) 297 self.assertIsInstance(v.platform, int) 298 self.assertIsInstance(v.service_pack, str) 299 self.assertIsInstance(v.service_pack_minor, int) 300 self.assertIsInstance(v.service_pack_major, int) 301 self.assertIsInstance(v.suite_mask, int) 302 self.assertIsInstance(v.product_type, int) 303 self.assertEqual(v[0], v.major) 304 self.assertEqual(v[1], v.minor) 305 self.assertEqual(v[2], v.build) 306 self.assertEqual(v[3], v.platform) 307 self.assertEqual(v[4], v.service_pack) 308 309 # This is how platform.py calls it. Make sure tuple 310 # still has 5 elements 311 maj, min, buildno, plat, csd = sys.getwindowsversion() 312 313 def test_call_tracing(self): 314 self.assertRaises(TypeError, sys.call_tracing, type, 2) 315 316 @unittest.skipUnless(hasattr(sys, "setdlopenflags"), 317 'test needs sys.setdlopenflags()') 318 def test_dlopenflags(self): 319 self.assertTrue(hasattr(sys, "getdlopenflags")) 320 self.assertRaises(TypeError, sys.getdlopenflags, 42) 321 oldflags = sys.getdlopenflags() 322 self.assertRaises(TypeError, sys.setdlopenflags) 323 sys.setdlopenflags(oldflags+1) 324 self.assertEqual(sys.getdlopenflags(), oldflags+1) 325 sys.setdlopenflags(oldflags) 326 327 @test.support.refcount_test 328 def test_refcount(self): 329 # n here must be a global in order for this test to pass while 330 # tracing with a python function. Tracing calls PyFrame_FastToLocals 331 # which will add a copy of any locals to the frame object, causing 332 # the reference count to increase by 2 instead of 1. 333 global n 334 self.assertRaises(TypeError, sys.getrefcount) 335 c = sys.getrefcount(None) 336 n = None 337 self.assertEqual(sys.getrefcount(None), c+1) 338 del n 339 self.assertEqual(sys.getrefcount(None), c) 340 if hasattr(sys, "gettotalrefcount"): 341 self.assertIsInstance(sys.gettotalrefcount(), int) 342 343 def test_getframe(self): 344 self.assertRaises(TypeError, sys._getframe, 42, 42) 345 self.assertRaises(ValueError, sys._getframe, 2000000000) 346 self.assertTrue( 347 SysModuleTest.test_getframe.__code__ \ 348 is sys._getframe().f_code 349 ) 350 351 # sys._current_frames() is a CPython-only gimmick. 352 def test_current_frames(self): 353 have_threads = True 354 try: 355 import _thread 356 except ImportError: 357 have_threads = False 358 359 if have_threads: 360 self.current_frames_with_threads() 361 else: 362 self.current_frames_without_threads() 363 364 # Test sys._current_frames() in a WITH_THREADS build. 365 @test.support.reap_threads 366 def current_frames_with_threads(self): 367 import threading 368 import traceback 369 370 # Spawn a thread that blocks at a known place. Then the main 371 # thread does sys._current_frames(), and verifies that the frames 372 # returned make sense. 373 entered_g = threading.Event() 374 leave_g = threading.Event() 375 thread_info = [] # the thread's id 376 377 def f123(): 378 g456() 379 380 def g456(): 381 thread_info.append(threading.get_ident()) 382 entered_g.set() 383 leave_g.wait() 384 385 t = threading.Thread(target=f123) 386 t.start() 387 entered_g.wait() 388 389 # At this point, t has finished its entered_g.set(), although it's 390 # impossible to guess whether it's still on that line or has moved on 391 # to its leave_g.wait(). 392 self.assertEqual(len(thread_info), 1) 393 thread_id = thread_info[0] 394 395 d = sys._current_frames() 396 397 main_id = threading.get_ident() 398 self.assertIn(main_id, d) 399 self.assertIn(thread_id, d) 400 401 # Verify that the captured main-thread frame is _this_ frame. 402 frame = d.pop(main_id) 403 self.assertTrue(frame is sys._getframe()) 404 405 # Verify that the captured thread frame is blocked in g456, called 406 # from f123. This is a litte tricky, since various bits of 407 # threading.py are also in the thread's call stack. 408 frame = d.pop(thread_id) 409 stack = traceback.extract_stack(frame) 410 for i, (filename, lineno, funcname, sourceline) in enumerate(stack): 411 if funcname == "f123": 412 break 413 else: 414 self.fail("didn't find f123() on thread's call stack") 415 416 self.assertEqual(sourceline, "g456()") 417 418 # And the next record must be for g456(). 419 filename, lineno, funcname, sourceline = stack[i+1] 420 self.assertEqual(funcname, "g456") 421 self.assertIn(sourceline, ["leave_g.wait()", "entered_g.set()"]) 422 423 # Reap the spawned thread. 424 leave_g.set() 425 t.join() 426 427 # Test sys._current_frames() when thread support doesn't exist. 428 def current_frames_without_threads(self): 429 # Not much happens here: there is only one thread, with artificial 430 # "thread id" 0. 431 d = sys._current_frames() 432 self.assertEqual(len(d), 1) 433 self.assertIn(0, d) 434 self.assertTrue(d[0] is sys._getframe()) 435 436 def test_attributes(self): 437 self.assertIsInstance(sys.api_version, int) 438 self.assertIsInstance(sys.argv, list) 439 self.assertIn(sys.byteorder, ("little", "big")) 440 self.assertIsInstance(sys.builtin_module_names, tuple) 441 self.assertIsInstance(sys.copyright, str) 442 self.assertIsInstance(sys.exec_prefix, str) 443 self.assertIsInstance(sys.base_exec_prefix, str) 444 self.assertIsInstance(sys.executable, str) 445 self.assertEqual(len(sys.float_info), 11) 446 self.assertEqual(sys.float_info.radix, 2) 447 self.assertEqual(len(sys.int_info), 2) 448 self.assertTrue(sys.int_info.bits_per_digit % 5 == 0) 449 self.assertTrue(sys.int_info.sizeof_digit >= 1) 450 self.assertEqual(type(sys.int_info.bits_per_digit), int) 451 self.assertEqual(type(sys.int_info.sizeof_digit), int) 452 self.assertIsInstance(sys.hexversion, int) 453 454 self.assertEqual(len(sys.hash_info), 9) 455 self.assertLess(sys.hash_info.modulus, 2**sys.hash_info.width) 456 # sys.hash_info.modulus should be a prime; we do a quick 457 # probable primality test (doesn't exclude the possibility of 458 # a Carmichael number) 459 for x in range(1, 100): 460 self.assertEqual( 461 pow(x, sys.hash_info.modulus-1, sys.hash_info.modulus), 462 1, 463 "sys.hash_info.modulus {} is a non-prime".format( 464 sys.hash_info.modulus) 465 ) 466 self.assertIsInstance(sys.hash_info.inf, int) 467 self.assertIsInstance(sys.hash_info.nan, int) 468 self.assertIsInstance(sys.hash_info.imag, int) 469 algo = sysconfig.get_config_var("Py_HASH_ALGORITHM") 470 if sys.hash_info.algorithm in {"fnv", "siphash24"}: 471 self.assertIn(sys.hash_info.hash_bits, {32, 64}) 472 self.assertIn(sys.hash_info.seed_bits, {32, 64, 128}) 473 474 if algo == 1: 475 self.assertEqual(sys.hash_info.algorithm, "siphash24") 476 elif algo == 2: 477 self.assertEqual(sys.hash_info.algorithm, "fnv") 478 else: 479 self.assertIn(sys.hash_info.algorithm, {"fnv", "siphash24"}) 480 else: 481 # PY_HASH_EXTERNAL 482 self.assertEqual(algo, 0) 483 self.assertGreaterEqual(sys.hash_info.cutoff, 0) 484 self.assertLess(sys.hash_info.cutoff, 8) 485 486 self.assertIsInstance(sys.maxsize, int) 487 self.assertIsInstance(sys.maxunicode, int) 488 self.assertEqual(sys.maxunicode, 0x10FFFF) 489 self.assertIsInstance(sys.platform, str) 490 self.assertIsInstance(sys.prefix, str) 491 self.assertIsInstance(sys.base_prefix, str) 492 self.assertIsInstance(sys.version, str) 493 vi = sys.version_info 494 self.assertIsInstance(vi[:], tuple) 495 self.assertEqual(len(vi), 5) 496 self.assertIsInstance(vi[0], int) 497 self.assertIsInstance(vi[1], int) 498 self.assertIsInstance(vi[2], int) 499 self.assertIn(vi[3], ("alpha", "beta", "candidate", "final")) 500 self.assertIsInstance(vi[4], int) 501 self.assertIsInstance(vi.major, int) 502 self.assertIsInstance(vi.minor, int) 503 self.assertIsInstance(vi.micro, int) 504 self.assertIn(vi.releaselevel, ("alpha", "beta", "candidate", "final")) 505 self.assertIsInstance(vi.serial, int) 506 self.assertEqual(vi[0], vi.major) 507 self.assertEqual(vi[1], vi.minor) 508 self.assertEqual(vi[2], vi.micro) 509 self.assertEqual(vi[3], vi.releaselevel) 510 self.assertEqual(vi[4], vi.serial) 511 self.assertTrue(vi > (1,0,0)) 512 self.assertIsInstance(sys.float_repr_style, str) 513 self.assertIn(sys.float_repr_style, ('short', 'legacy')) 514 if not sys.platform.startswith('win'): 515 self.assertIsInstance(sys.abiflags, str) 516 517 @unittest.skipUnless(hasattr(sys, 'thread_info'), 518 'Threading required for this test.') 519 def test_thread_info(self): 520 info = sys.thread_info 521 self.assertEqual(len(info), 3) 522 self.assertIn(info.name, ('nt', 'pthread', 'solaris', None)) 523 self.assertIn(info.lock, ('semaphore', 'mutex+cond', None)) 524 525 def test_43581(self): 526 # Can't use sys.stdout, as this is a StringIO object when 527 # the test runs under regrtest. 528 self.assertEqual(sys.__stdout__.encoding, sys.__stderr__.encoding) 529 530 def test_intern(self): 531 global numruns 532 numruns += 1 533 self.assertRaises(TypeError, sys.intern) 534 s = "never interned before" + str(numruns) 535 self.assertTrue(sys.intern(s) is s) 536 s2 = s.swapcase().swapcase() 537 self.assertTrue(sys.intern(s2) is s) 538 539 # Subclasses of string can't be interned, because they 540 # provide too much opportunity for insane things to happen. 541 # We don't want them in the interned dict and if they aren't 542 # actually interned, we don't want to create the appearance 543 # that they are by allowing intern() to succeed. 544 class S(str): 545 def __hash__(self): 546 return 123 547 548 self.assertRaises(TypeError, sys.intern, S("abc")) 549 550 def test_sys_flags(self): 551 self.assertTrue(sys.flags) 552 attrs = ("debug", 553 "inspect", "interactive", "optimize", "dont_write_bytecode", 554 "no_user_site", "no_site", "ignore_environment", "verbose", 555 "bytes_warning", "quiet", "hash_randomization", "isolated") 556 for attr in attrs: 557 self.assertTrue(hasattr(sys.flags, attr), attr) 558 self.assertEqual(type(getattr(sys.flags, attr)), int, attr) 559 self.assertTrue(repr(sys.flags)) 560 self.assertEqual(len(sys.flags), len(attrs)) 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, isolated=False, encoding=None): 680 # Force the POSIX locale 681 env = os.environ.copy() 682 env["LC_ALL"] = "C" 683 code = '\n'.join(( 684 'import sys', 685 'def dump(name):', 686 ' std = getattr(sys, name)', 687 ' print("%s: %s" % (name, std.errors))', 688 'dump("stdin")', 689 'dump("stdout")', 690 'dump("stderr")', 691 )) 692 args = [sys.executable, "-c", code] 693 if isolated: 694 args.append("-I") 695 if encoding is not None: 696 env['PYTHONIOENCODING'] = encoding 697 else: 698 env.pop('PYTHONIOENCODING', None) 699 p = subprocess.Popen(args, 700 stdout=subprocess.PIPE, 701 stderr=subprocess.STDOUT, 702 env=env, 703 universal_newlines=True) 704 stdout, stderr = p.communicate() 705 return stdout 706 707 def test_c_locale_surrogateescape(self): 708 out = self.c_locale_get_error_handler(isolated=True) 709 self.assertEqual(out, 710 'stdin: surrogateescape\n' 711 'stdout: surrogateescape\n' 712 'stderr: backslashreplace\n') 713 714 # replace the default error handler 715 out = self.c_locale_get_error_handler(encoding=':ignore') 716 self.assertEqual(out, 717 'stdin: ignore\n' 718 'stdout: ignore\n' 719 'stderr: backslashreplace\n') 720 721 # force the encoding 722 out = self.c_locale_get_error_handler(encoding='iso8859-1') 723 self.assertEqual(out, 724 'stdin: strict\n' 725 'stdout: strict\n' 726 'stderr: backslashreplace\n') 727 out = self.c_locale_get_error_handler(encoding='iso8859-1:') 728 self.assertEqual(out, 729 'stdin: strict\n' 730 'stdout: strict\n' 731 'stderr: backslashreplace\n') 732 733 # have no any effect 734 out = self.c_locale_get_error_handler(encoding=':') 735 self.assertEqual(out, 736 'stdin: surrogateescape\n' 737 'stdout: surrogateescape\n' 738 'stderr: backslashreplace\n') 739 out = self.c_locale_get_error_handler(encoding='') 740 self.assertEqual(out, 741 'stdin: surrogateescape\n' 742 'stdout: surrogateescape\n' 743 'stderr: backslashreplace\n') 744 745 def test_implementation(self): 746 # This test applies to all implementations equally. 747 748 levels = {'alpha': 0xA, 'beta': 0xB, 'candidate': 0xC, 'final': 0xF} 749 750 self.assertTrue(hasattr(sys.implementation, 'name')) 751 self.assertTrue(hasattr(sys.implementation, 'version')) 752 self.assertTrue(hasattr(sys.implementation, 'hexversion')) 753 self.assertTrue(hasattr(sys.implementation, 'cache_tag')) 754 755 version = sys.implementation.version 756 self.assertEqual(version[:2], (version.major, version.minor)) 757 758 hexversion = (version.major << 24 | version.minor << 16 | 759 version.micro << 8 | levels[version.releaselevel] << 4 | 760 version.serial << 0) 761 self.assertEqual(sys.implementation.hexversion, hexversion) 762 763 # PEP 421 requires that .name be lower case. 764 self.assertEqual(sys.implementation.name, 765 sys.implementation.name.lower()) 766 767 @test.support.cpython_only 768 def test_debugmallocstats(self): 769 # Test sys._debugmallocstats() 770 from test.support.script_helper import assert_python_ok 771 args = ['-c', 'import sys; sys._debugmallocstats()'] 772 ret, out, err = assert_python_ok(*args) 773 self.assertIn(b"free PyDictObjects", err) 774 775 # The function has no parameter 776 self.assertRaises(TypeError, sys._debugmallocstats, True) 777 778 @unittest.skipUnless(hasattr(sys, "getallocatedblocks"), 779 "sys.getallocatedblocks unavailable on this build") 780 def test_getallocatedblocks(self): 781 # Some sanity checks 782 with_pymalloc = sysconfig.get_config_var('WITH_PYMALLOC') 783 a = sys.getallocatedblocks() 784 self.assertIs(type(a), int) 785 if with_pymalloc: 786 self.assertGreater(a, 0) 787 else: 788 # When WITH_PYMALLOC isn't available, we don't know anything 789 # about the underlying implementation: the function might 790 # return 0 or something greater. 791 self.assertGreaterEqual(a, 0) 792 try: 793 # While we could imagine a Python session where the number of 794 # multiple buffer objects would exceed the sharing of references, 795 # it is unlikely to happen in a normal test run. 796 self.assertLess(a, sys.gettotalrefcount()) 797 except AttributeError: 798 # gettotalrefcount() not available 799 pass 800 gc.collect() 801 b = sys.getallocatedblocks() 802 self.assertLessEqual(b, a) 803 gc.collect() 804 c = sys.getallocatedblocks() 805 self.assertIn(c, range(b - 50, b + 50)) 806 807 @test.support.requires_type_collecting 808 def test_is_finalizing(self): 809 self.assertIs(sys.is_finalizing(), False) 810 # Don't use the atexit module because _Py_Finalizing is only set 811 # after calling atexit callbacks 812 code = """if 1: 813 import sys 814 815 class AtExit: 816 is_finalizing = sys.is_finalizing 817 print = print 818 819 def __del__(self): 820 self.print(self.is_finalizing(), flush=True) 821 822 # Keep a reference in the __main__ module namespace, so the 823 # AtExit destructor will be called at Python exit 824 ref = AtExit() 825 """ 826 rc, stdout, stderr = assert_python_ok('-c', code) 827 self.assertEqual(stdout.rstrip(), b'True') 828 829 830 @test.support.cpython_only 831 class SizeofTest(unittest.TestCase): 832 833 def setUp(self): 834 self.P = struct.calcsize('P') 835 self.longdigit = sys.int_info.sizeof_digit 836 import _testcapi 837 self.gc_headsize = _testcapi.SIZEOF_PYGC_HEAD 838 839 check_sizeof = test.support.check_sizeof 840 841 def test_gc_head_size(self): 842 # Check that the gc header size is added to objects tracked by the gc. 843 vsize = test.support.calcvobjsize 844 gc_header_size = self.gc_headsize 845 # bool objects are not gc tracked 846 self.assertEqual(sys.getsizeof(True), vsize('') + self.longdigit) 847 # but lists are 848 self.assertEqual(sys.getsizeof([]), vsize('Pn') + gc_header_size) 849 850 def test_errors(self): 851 class BadSizeof: 852 def __sizeof__(self): 853 raise ValueError 854 self.assertRaises(ValueError, sys.getsizeof, BadSizeof()) 855 856 class InvalidSizeof: 857 def __sizeof__(self): 858 return None 859 self.assertRaises(TypeError, sys.getsizeof, InvalidSizeof()) 860 sentinel = ["sentinel"] 861 self.assertIs(sys.getsizeof(InvalidSizeof(), sentinel), sentinel) 862 863 class FloatSizeof: 864 def __sizeof__(self): 865 return 4.5 866 self.assertRaises(TypeError, sys.getsizeof, FloatSizeof()) 867 self.assertIs(sys.getsizeof(FloatSizeof(), sentinel), sentinel) 868 869 class OverflowSizeof(int): 870 def __sizeof__(self): 871 return int(self) 872 self.assertEqual(sys.getsizeof(OverflowSizeof(sys.maxsize)), 873 sys.maxsize + self.gc_headsize) 874 with self.assertRaises(OverflowError): 875 sys.getsizeof(OverflowSizeof(sys.maxsize + 1)) 876 with self.assertRaises(ValueError): 877 sys.getsizeof(OverflowSizeof(-1)) 878 with self.assertRaises((ValueError, OverflowError)): 879 sys.getsizeof(OverflowSizeof(-sys.maxsize - 1)) 880 881 def test_default(self): 882 size = test.support.calcvobjsize 883 self.assertEqual(sys.getsizeof(True), size('') + self.longdigit) 884 self.assertEqual(sys.getsizeof(True, -1), size('') + self.longdigit) 885 886 def test_objecttypes(self): 887 # check all types defined in Objects/ 888 calcsize = struct.calcsize 889 size = test.support.calcobjsize 890 vsize = test.support.calcvobjsize 891 check = self.check_sizeof 892 # bool 893 check(True, vsize('') + self.longdigit) 894 # buffer 895 # XXX 896 # builtin_function_or_method 897 check(len, size('4P')) # XXX check layout 898 # bytearray 899 samples = [b'', b'u'*100000] 900 for sample in samples: 901 x = bytearray(sample) 902 check(x, vsize('n2Pi') + x.__alloc__()) 903 # bytearray_iterator 904 check(iter(bytearray()), size('nP')) 905 # bytes 906 check(b'', vsize('n') + 1) 907 check(b'x' * 10, vsize('n') + 11) 908 # cell 909 def get_cell(): 910 x = 42 911 def inner(): 912 return x 913 return inner 914 check(get_cell().__closure__[0], size('P')) 915 # code 916 check(get_cell().__code__, size('6i13P')) 917 check(get_cell.__code__, size('6i13P')) 918 def get_cell2(x): 919 def inner(): 920 return x 921 return inner 922 check(get_cell2.__code__, size('6i13P') + 1) 923 # complex 924 check(complex(0,1), size('2d')) 925 # method_descriptor (descriptor object) 926 check(str.lower, size('3PP')) 927 # classmethod_descriptor (descriptor object) 928 # XXX 929 # member_descriptor (descriptor object) 930 import datetime 931 check(datetime.timedelta.days, size('3PP')) 932 # getset_descriptor (descriptor object) 933 import collections 934 check(collections.defaultdict.default_factory, size('3PP')) 935 # wrapper_descriptor (descriptor object) 936 check(int.__add__, size('3P2P')) 937 # method-wrapper (descriptor object) 938 check({}.__iter__, size('2P')) 939 # dict 940 check({}, size('nQ2P') + calcsize('2nP2n') + 8 + (8*2//3)*calcsize('n2P')) 941 longdict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8} 942 check(longdict, size('nQ2P') + calcsize('2nP2n') + 16 + (16*2//3)*calcsize('n2P')) 943 # dictionary-keyview 944 check({}.keys(), size('P')) 945 # dictionary-valueview 946 check({}.values(), size('P')) 947 # dictionary-itemview 948 check({}.items(), size('P')) 949 # dictionary iterator 950 check(iter({}), size('P2nPn')) 951 # dictionary-keyiterator 952 check(iter({}.keys()), size('P2nPn')) 953 # dictionary-valueiterator 954 check(iter({}.values()), size('P2nPn')) 955 # dictionary-itemiterator 956 check(iter({}.items()), size('P2nPn')) 957 # dictproxy 958 class C(object): pass 959 check(C.__dict__, size('P')) 960 # BaseException 961 check(BaseException(), size('5Pb')) 962 # UnicodeEncodeError 963 check(UnicodeEncodeError("", "", 0, 0, ""), size('5Pb 2P2nP')) 964 # UnicodeDecodeError 965 check(UnicodeDecodeError("", b"", 0, 0, ""), size('5Pb 2P2nP')) 966 # UnicodeTranslateError 967 check(UnicodeTranslateError("", 0, 1, ""), size('5Pb 2P2nP')) 968 # ellipses 969 check(Ellipsis, size('')) 970 # EncodingMap 971 import codecs, encodings.iso8859_3 972 x = codecs.charmap_build(encodings.iso8859_3.decoding_table) 973 check(x, size('32B2iB')) 974 # enumerate 975 check(enumerate([]), size('n3P')) 976 # reverse 977 check(reversed(''), size('nP')) 978 # float 979 check(float(0), size('d')) 980 # sys.floatinfo 981 check(sys.float_info, vsize('') + self.P * len(sys.float_info)) 982 # frame 983 import inspect 984 CO_MAXBLOCKS = 20 985 x = inspect.currentframe() 986 ncells = len(x.f_code.co_cellvars) 987 nfrees = len(x.f_code.co_freevars) 988 extras = x.f_code.co_stacksize + x.f_code.co_nlocals +\ 989 ncells + nfrees - 1 990 check(x, vsize('12P3ic' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) 991 # function 992 def func(): pass 993 check(func, size('12P')) 994 class c(): 995 @staticmethod 996 def foo(): 997 pass 998 @classmethod 999 def bar(cls): 1000 pass 1001 # staticmethod 1002 check(foo, size('PP')) 1003 # classmethod 1004 check(bar, size('PP')) 1005 # generator 1006 def get_gen(): yield 1 1007 check(get_gen(), size('Pb2PPP')) 1008 # iterator 1009 check(iter('abc'), size('lP')) 1010 # callable-iterator 1011 import re 1012 check(re.finditer('',''), size('2P')) 1013 # list 1014 samples = [[], [1,2,3], ['1', '2', '3']] 1015 for sample in samples: 1016 check(sample, vsize('Pn') + len(sample)*self.P) 1017 # sortwrapper (list) 1018 # XXX 1019 # cmpwrapper (list) 1020 # XXX 1021 # listiterator (list) 1022 check(iter([]), size('lP')) 1023 # listreverseiterator (list) 1024 check(reversed([]), size('nP')) 1025 # int 1026 check(0, vsize('')) 1027 check(1, vsize('') + self.longdigit) 1028 check(-1, vsize('') + self.longdigit) 1029 PyLong_BASE = 2**sys.int_info.bits_per_digit 1030 check(int(PyLong_BASE), vsize('') + 2*self.longdigit) 1031 check(int(PyLong_BASE**2-1), vsize('') + 2*self.longdigit) 1032 check(int(PyLong_BASE**2), vsize('') + 3*self.longdigit) 1033 # module 1034 check(unittest, size('PnPPP')) 1035 # None 1036 check(None, size('')) 1037 # NotImplementedType 1038 check(NotImplemented, size('')) 1039 # object 1040 check(object(), size('')) 1041 # property (descriptor object) 1042 class C(object): 1043 def getx(self): return self.__x 1044 def setx(self, value): self.__x = value 1045 def delx(self): del self.__x 1046 x = property(getx, setx, delx, "") 1047 check(x, size('4Pi')) 1048 # PyCapsule 1049 # XXX 1050 # rangeiterator 1051 check(iter(range(1)), size('4l')) 1052 # reverse 1053 check(reversed(''), size('nP')) 1054 # range 1055 check(range(1), size('4P')) 1056 check(range(66000), size('4P')) 1057 # set 1058 # frozenset 1059 PySet_MINSIZE = 8 1060 samples = [[], range(10), range(50)] 1061 s = size('3nP' + PySet_MINSIZE*'nP' + '2nP') 1062 for sample in samples: 1063 minused = len(sample) 1064 if minused == 0: tmp = 1 1065 # the computation of minused is actually a bit more complicated 1066 # but this suffices for the sizeof test 1067 minused = minused*2 1068 newsize = PySet_MINSIZE 1069 while newsize <= minused: 1070 newsize = newsize << 1 1071 if newsize <= 8: 1072 check(set(sample), s) 1073 check(frozenset(sample), s) 1074 else: 1075 check(set(sample), s + newsize*calcsize('nP')) 1076 check(frozenset(sample), s + newsize*calcsize('nP')) 1077 # setiterator 1078 check(iter(set()), size('P3n')) 1079 # slice 1080 check(slice(0), size('3P')) 1081 # super 1082 check(super(int), size('3P')) 1083 # tuple 1084 check((), vsize('')) 1085 check((1,2,3), vsize('') + 3*self.P) 1086 # type 1087 # static type: PyTypeObject 1088 fmt = 'P2n15Pl4Pn9Pn11PIP' 1089 if hasattr(sys, 'getcounts'): 1090 fmt += '3n2P' 1091 s = vsize(fmt) 1092 check(int, s) 1093 s = vsize(fmt + # PyTypeObject 1094 '3P' # PyAsyncMethods 1095 '36P' # PyNumberMethods 1096 '3P' # PyMappingMethods 1097 '10P' # PySequenceMethods 1098 '2P' # PyBufferProcs 1099 '4P') 1100 # Separate block for PyDictKeysObject with 8 keys and 5 entries 1101 s += calcsize("2nP2n") + 8 + 5*calcsize("n2P") 1102 # class 1103 class newstyleclass(object): pass 1104 check(newstyleclass, s) 1105 # dict with shared keys 1106 check(newstyleclass().__dict__, size('nQ2P' + '2nP2n')) 1107 # unicode 1108 # each tuple contains a string and its expected character size 1109 # don't put any static strings here, as they may contain 1110 # wchar_t or UTF-8 representations 1111 samples = ['1'*100, '\xff'*50, 1112 '\u0100'*40, '\uffff'*100, 1113 '\U00010000'*30, '\U0010ffff'*100] 1114 asciifields = "nnbP" 1115 compactfields = asciifields + "nPn" 1116 unicodefields = compactfields + "P" 1117 for s in samples: 1118 maxchar = ord(max(s)) 1119 if maxchar < 128: 1120 L = size(asciifields) + len(s) + 1 1121 elif maxchar < 256: 1122 L = size(compactfields) + len(s) + 1 1123 elif maxchar < 65536: 1124 L = size(compactfields) + 2*(len(s) + 1) 1125 else: 1126 L = size(compactfields) + 4*(len(s) + 1) 1127 check(s, L) 1128 # verify that the UTF-8 size is accounted for 1129 s = chr(0x4000) # 4 bytes canonical representation 1130 check(s, size(compactfields) + 4) 1131 # compile() will trigger the generation of the UTF-8 1132 # representation as a side effect 1133 compile(s, "<stdin>", "eval") 1134 check(s, size(compactfields) + 4 + 4) 1135 # TODO: add check that forces the presence of wchar_t representation 1136 # TODO: add check that forces layout of unicodefields 1137 # weakref 1138 import weakref 1139 check(weakref.ref(int), size('2Pn2P')) 1140 # weakproxy 1141 # XXX 1142 # weakcallableproxy 1143 check(weakref.proxy(int), size('2Pn2P')) 1144 1145 def check_slots(self, obj, base, extra): 1146 expected = sys.getsizeof(base) + struct.calcsize(extra) 1147 if gc.is_tracked(obj) and not gc.is_tracked(base): 1148 expected += self.gc_headsize 1149 self.assertEqual(sys.getsizeof(obj), expected) 1150 1151 def test_slots(self): 1152 # check all subclassable types defined in Objects/ that allow 1153 # non-empty __slots__ 1154 check = self.check_slots 1155 class BA(bytearray): 1156 __slots__ = 'a', 'b', 'c' 1157 check(BA(), bytearray(), '3P') 1158 class D(dict): 1159 __slots__ = 'a', 'b', 'c' 1160 check(D(x=[]), {'x': []}, '3P') 1161 class L(list): 1162 __slots__ = 'a', 'b', 'c' 1163 check(L(), [], '3P') 1164 class S(set): 1165 __slots__ = 'a', 'b', 'c' 1166 check(S(), set(), '3P') 1167 class FS(frozenset): 1168 __slots__ = 'a', 'b', 'c' 1169 check(FS(), frozenset(), '3P') 1170 from collections import OrderedDict 1171 class OD(OrderedDict): 1172 __slots__ = 'a', 'b', 'c' 1173 check(OD(x=[]), OrderedDict(x=[]), '3P') 1174 1175 def test_pythontypes(self): 1176 # check all types defined in Python/ 1177 size = test.support.calcobjsize 1178 vsize = test.support.calcvobjsize 1179 check = self.check_sizeof 1180 # _ast.AST 1181 import _ast 1182 check(_ast.AST(), size('P')) 1183 try: 1184 raise TypeError 1185 except TypeError: 1186 tb = sys.exc_info()[2] 1187 # traceback 1188 if tb is not None: 1189 check(tb, size('2P2i')) 1190 # symtable entry 1191 # XXX 1192 # sys.flags 1193 check(sys.flags, vsize('') + self.P * len(sys.flags)) 1194 1195 def test_asyncgen_hooks(self): 1196 old = sys.get_asyncgen_hooks() 1197 self.assertIsNone(old.firstiter) 1198 self.assertIsNone(old.finalizer) 1199 1200 firstiter = lambda *a: None 1201 sys.set_asyncgen_hooks(firstiter=firstiter) 1202 hooks = sys.get_asyncgen_hooks() 1203 self.assertIs(hooks.firstiter, firstiter) 1204 self.assertIs(hooks[0], firstiter) 1205 self.assertIs(hooks.finalizer, None) 1206 self.assertIs(hooks[1], None) 1207 1208 finalizer = lambda *a: None 1209 sys.set_asyncgen_hooks(finalizer=finalizer) 1210 hooks = sys.get_asyncgen_hooks() 1211 self.assertIs(hooks.firstiter, firstiter) 1212 self.assertIs(hooks[0], firstiter) 1213 self.assertIs(hooks.finalizer, finalizer) 1214 self.assertIs(hooks[1], finalizer) 1215 1216 sys.set_asyncgen_hooks(*old) 1217 cur = sys.get_asyncgen_hooks() 1218 self.assertIsNone(cur.firstiter) 1219 self.assertIsNone(cur.finalizer) 1220 1221 1222 def test_main(): 1223 test.support.run_unittest(SysModuleTest, SizeofTest) 1224 1225 if __name__ == "__main__": 1226 test_main() 1227