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