this repo has no description
1#!/usr/bin/env python3
2# Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
3import contextlib
4import sys
5import unittest
6from _io import StringIO, TextIOWrapper
7
8from test_support import pyro_only, cpython_only
9
10
11# Tests for traceback printing in sys.excepthook
12def panic():
13 raise RuntimeError("PANIC!!!")
14
15
16def call_panic():
17 # empty line
18 panic()
19
20
21def raise_after_n_frames(n):
22 if not n:
23 raise RuntimeError("PANIC!!!")
24 raise_after_n_frames(n - 1)
25
26
27class DisplayhookTest(unittest.TestCase):
28 def test_displayhook_with_none_does_not_set_underscore(self):
29 import builtins
30
31 if hasattr(builtins, "_"):
32 del builtins._
33
34 orig_out = sys.stdout
35 out = StringIO()
36 sys.stdout = out
37 sys.__displayhook__(None)
38 self.assertEqual(out.getvalue(), "")
39 self.assertTrue(not hasattr(builtins, "_"))
40 sys.stdout = orig_out
41
42 def test_displayhook_with_int_sets_underscore(self):
43 import builtins
44
45 orig_out = sys.stdout
46 out = StringIO()
47 sys.stdout = out
48 sys.__displayhook__(42)
49 self.assertEqual(out.getvalue(), "42\n")
50 self.assertEqual(builtins._, 42)
51 sys.stdout = orig_out
52
53 def test_has_displayhook(self):
54 self.assertTrue(hasattr(sys, "displayhook"))
55
56 def test_displayhook_initial_value(self):
57 self.assertIs(sys.displayhook, sys.__displayhook__)
58
59 def test_dunder_std_streams_are_text_io_wrappers(self):
60 self.assertIsInstance(sys.__stderr__, TextIOWrapper)
61 self.assertIsInstance(sys.__stdin__, TextIOWrapper)
62 self.assertIsInstance(sys.__stdout__, TextIOWrapper)
63
64
65class ExceptHookTests(unittest.TestCase):
66 def test_traceback_with_sys_tracebacklimit_truncates_stack_trace(self):
67 has_tracebacklimit = hasattr(sys, "tracebacklimit")
68 if has_tracebacklimit:
69 tmp = sys.tracebacklimit
70
71 with StringIO() as stderr, contextlib.redirect_stderr(stderr):
72 try:
73 sys.tracebacklimit = 1
74 call_panic()
75 except Exception:
76 sys.excepthook(*sys.exc_info())
77 finally:
78 if has_tracebacklimit:
79 sys.tracebacklimit = tmp
80 else:
81 del sys.tracebacklimit
82 self.assertRegex(
83 stderr.getvalue(),
84 r"""Traceback \(most recent call last\):
85 File ".*/sys_test.py", line \d+, in panic
86 raise RuntimeError\("PANIC!!!"\)
87RuntimeError: PANIC!!!
88""",
89 )
90
91 def test_traceback_without_sys_tracebacklimit_prints_entire_small_traceback(self):
92 has_tracebacklimit = hasattr(sys, "tracebacklimit")
93 if has_tracebacklimit:
94 tmp = sys.tracebacklimit
95 del sys.tracebacklimit
96
97 with StringIO() as stderr, contextlib.redirect_stderr(stderr):
98 try:
99 call_panic()
100 except Exception:
101 sys.excepthook(*sys.exc_info())
102 finally:
103 if has_tracebacklimit:
104 sys.tracebacklimit = tmp
105 self.assertRegex(
106 stderr.getvalue(),
107 r"""Traceback \(most recent call last\):
108 File ".*/sys_test.py", line \d+, in test_traceback_without_sys_tracebacklimit_prints_entire_small_traceback
109 call_panic\(\)
110 File ".*/sys_test.py", line \d+, in call_panic
111 panic\(\)
112 File ".*/sys_test.py", line \d+, in panic
113 raise RuntimeError\("PANIC!!!"\)
114RuntimeError: PANIC!!!
115""",
116 )
117
118 def test_traceback_cuts_recursion_at_3_repeated_lines(self):
119 has_tracebacklimit = hasattr(sys, "tracebacklimit")
120 if has_tracebacklimit:
121 tmp = sys.tracebacklimit
122 del sys.tracebacklimit
123
124 with StringIO() as stderr, contextlib.redirect_stderr(stderr):
125 try:
126 raise_after_n_frames(4)
127 except Exception:
128 sys.excepthook(*sys.exc_info())
129 finally:
130 if has_tracebacklimit:
131 sys.tracebacklimit = tmp
132 self.assertRegex(
133 stderr.getvalue(),
134 r"""Traceback \(most recent call last\):
135 File ".*/sys_test.py", line \d+, in test_traceback_cuts_recursion_at_3_repeated_lines
136 raise_after_n_frames\(4\)
137 File ".*/sys_test.py", line \d+, in raise_after_n_frames
138 raise_after_n_frames\(n - 1\)
139 File ".*/sys_test.py", line \d+, in raise_after_n_frames
140 raise_after_n_frames\(n - 1\)
141 File ".*/sys_test.py", line \d+, in raise_after_n_frames
142 raise_after_n_frames\(n - 1\)
143 \[Previous line repeated 1 more time\]
144 File ".*/sys_test.py", line \d+, in raise_after_n_frames
145 raise RuntimeError\("PANIC!!!"\)
146RuntimeError: PANIC!!!
147""",
148 )
149
150 def test_traceback_limits_recursion_and_depth(self):
151 has_tracebacklimit = hasattr(sys, "tracebacklimit")
152 if has_tracebacklimit:
153 tmp = sys.tracebacklimit
154
155 with StringIO() as stderr, contextlib.redirect_stderr(stderr):
156 try:
157 sys.tracebacklimit = 10
158 raise_after_n_frames(20)
159 except Exception:
160 sys.excepthook(*sys.exc_info())
161 finally:
162 if has_tracebacklimit:
163 sys.tracebacklimit = tmp
164 else:
165 del sys.tracebacklimit
166 self.assertRegex(
167 stderr.getvalue(),
168 r"""Traceback \(most recent call last\):
169 File ".*/sys_test.py", line \d+, in raise_after_n_frames
170 raise_after_n_frames\(n - 1\)
171 File ".*/sys_test.py", line \d+, in raise_after_n_frames
172 raise_after_n_frames\(n - 1\)
173 File ".*/sys_test.py", line \d+, in raise_after_n_frames
174 raise_after_n_frames\(n - 1\)
175 \[Previous line repeated 6 more times\]
176 File ".*/sys_test.py", line \d+, in raise_after_n_frames
177 raise RuntimeError\("PANIC!!!"\)
178RuntimeError: PANIC!!!
179""",
180 )
181
182
183class SysTests(unittest.TestCase):
184 class Mgr:
185 def __enter__(self):
186 pass
187
188 def __exit__(self, type, value, tb):
189 return True
190
191 def test_excepthook_initial_value(self):
192 self.assertIs(sys.excepthook, sys.__excepthook__)
193
194 def test_exit_raises_system_exit(self):
195 with self.assertRaises(SystemExit) as ctx:
196 sys.exit()
197
198 self.assertEqual(ctx.exception.args, ())
199
200 def test_exit_with_code_raises_system_exit_with_code(self):
201 with self.assertRaises(SystemExit) as ctx:
202 sys.exit("foo")
203
204 self.assertEqual(ctx.exception.args, ("foo",))
205
206 def test_exc_info_with_context_manager(self):
207 try:
208 raise RuntimeError()
209 except RuntimeError:
210 info1 = sys.exc_info()
211 with self.Mgr():
212 raise ValueError()
213 info2 = sys.exc_info()
214 self.assertEqual(info1, info2)
215
216 def test_getdefaultencoding_returns_utf8(self):
217 self.assertEqual(sys.getdefaultencoding(), "utf-8")
218
219 def test_getsizeof_without_dunder_sizeof_raises_type_error(self):
220 class M(type):
221 def mro(cls):
222 return (cls,)
223
224 class C(metaclass=M):
225 __new__ = type.__new__
226 __call__ = type.__call__
227
228 with self.assertRaises(TypeError):
229 sys.getsizeof(C())
230
231 def test_getsizeof_with_non_int_without_default_raises_type_error(self):
232 class C:
233 def __sizeof__(self):
234 return "not an integer"
235
236 with self.assertRaises(TypeError):
237 sys.getsizeof(C())
238
239 def test_getsizeof_with_non_int_returns_default(self):
240 class C:
241 def __sizeof__(self):
242 return "not an integer"
243
244 self.assertEqual(sys.getsizeof(C(), 42), 42)
245
246 def test_getsizeof_with_negative_raises_value_error(self):
247 class C:
248 def __sizeof__(self):
249 return -1
250
251 with self.assertRaises(ValueError):
252 sys.getsizeof(C())
253
254 @pyro_only
255 def test_getsizeof_without_default_returns_size_int(self):
256 class C:
257 def __sizeof__(self):
258 return 42
259
260 self.assertEqual(sys.getsizeof(C()), 42)
261
262 @pyro_only
263 def test_getsizeof_with_default_returns_size_int(self):
264 class C:
265 def __sizeof__(self):
266 return 42
267
268 self.assertEqual(sys.getsizeof(C(), 3), 42)
269
270 @pyro_only
271 def test_getsizeof_with_int_subclass_returns_int(self):
272 class N(int):
273 pass
274
275 class C:
276 def __sizeof__(self):
277 return N(42)
278
279 result = sys.getsizeof(C())
280 self.assertIs(type(result), int)
281 self.assertEqual(result, 42)
282
283 def test_getsetrecursionlimit(self):
284 limit = sys.getrecursionlimit()
285 self.assertGreater(limit, 0)
286 sys.setrecursionlimit(limit + 1)
287 self.assertEqual(sys.getrecursionlimit(), limit + 1)
288 sys.setrecursionlimit(limit)
289 self.assertEqual(sys.getrecursionlimit(), limit)
290
291 def test_gettrace_returns_none(self):
292 self.assertIs(sys.gettrace(), None)
293
294 def test_implementation_cache_tag_matches_version_major_minor(self):
295 name = sys.implementation.name
296 major, minor = sys.version_info.major, sys.version_info.minor
297 cache_tag = f"{name}-{major}{minor}"
298 self.assertEqual(sys.implementation.cache_tag, cache_tag)
299
300 def test_implementation_version_matches_module_version_info(self):
301 self.assertEqual(sys.implementation.version, sys.version_info)
302
303 def test_settrace_with_none_does_nothing(self):
304 sys.settrace(None)
305 self.assertIs(sys.gettrace(), None)
306
307 def test_setrecursionlimit_with_large_limit_raises_overflowerror(self):
308 with self.assertRaises(OverflowError) as context:
309 sys.setrecursionlimit(230992039023490234904329023904239023)
310 self.assertEqual(
311 str(context.exception), "Python int too large to convert to C int"
312 )
313
314 def test_hash_info_is_plausible(self):
315 def is_power_of_two(x):
316 return x & (x - 1) == 0
317
318 hash_info = sys.hash_info
319 max_value = (1 << (hash_info.width - 1)) - 1
320 self.assertTrue(hash_info.modulus <= max_value)
321 self.assertTrue(is_power_of_two(hash_info.modulus + 1))
322 self.assertTrue(hash_info.inf <= max_value)
323 self.assertTrue(hash_info.nan <= max_value)
324 self.assertTrue(hash_info.imag <= max_value)
325 self.assertIsInstance(hash_info.algorithm, str)
326 self.assertTrue(hash_info.hash_bits >= hash_info.width)
327 self.assertTrue(hash_info.seed_bits >= hash_info.hash_bits)
328 self.assertIs(hash_info.width, hash_info[0])
329 self.assertIs(hash_info.modulus, hash_info[1])
330 self.assertIs(hash_info.inf, hash_info[2])
331 self.assertIs(hash_info.nan, hash_info[3])
332 self.assertIs(hash_info.imag, hash_info[4])
333 self.assertIs(hash_info.algorithm, hash_info[5])
334 self.assertIs(hash_info.hash_bits, hash_info[6])
335 self.assertIs(hash_info.seed_bits, hash_info[7])
336 self.assertIs(hash_info.cutoff, hash_info[8])
337
338 def test_hash_info_matches_cpython(self):
339 # We should not deviate from cpython without a good reason.
340 hash_info = sys.hash_info
341 self.assertEqual(hash_info.modulus, (1 << 61) - 1)
342 self.assertEqual(hash_info.inf, 314159)
343 self.assertEqual(hash_info.nan, 0)
344 self.assertEqual(hash_info.imag, 1000003)
345 self.assertEqual(hash_info.algorithm, "siphash24")
346 self.assertEqual(hash_info.hash_bits, 64)
347 self.assertEqual(hash_info.seed_bits, 128)
348
349 def test_float_info_matches_cpython(self):
350 float_info = sys.float_info
351 self.assertEqual(float_info.max, 1.7976931348623157e308)
352 self.assertEqual(float_info.max_exp, 1024)
353 self.assertEqual(float_info.max_10_exp, 308)
354 self.assertEqual(float_info.min, 2.2250738585072014e-308)
355 self.assertEqual(float_info.min_exp, -1021)
356 self.assertEqual(float_info.min_10_exp, -307)
357 self.assertEqual(float_info.dig, 15)
358 self.assertEqual(float_info.mant_dig, 53)
359 self.assertEqual(float_info.epsilon, 2.220446049250313e-16)
360 self.assertEqual(float_info.radix, 2)
361 self.assertEqual(float_info.rounds, 1)
362
363 def test_intern_returns_str(self):
364 self.assertEqual(sys.intern("id"), "id")
365 self.assertEqual(sys.intern("long identifier"), "long identifier")
366
367 def test_intern_with_nonstr_raises_typeerror(self):
368 with self.assertRaises(TypeError):
369 sys.intern(12345)
370
371 def test_intern_with_str_subclass_raises_typeerror(self):
372 class NewString(str):
373 pass
374
375 with self.assertRaises(TypeError) as context:
376 sys.intern(NewString("identifier"))
377
378 self.assertEqual(str(context.exception), "can't intern NewString")
379
380 def test_is_finalizing_before_shutdown_returns_false(self):
381 self.assertEqual(sys.is_finalizing(), False)
382
383 def test_stdio_initial_values(self):
384 self.assertIs(sys.stderr, sys.__stderr__)
385 self.assertIs(sys.stdin, sys.__stdin__)
386 self.assertIs(sys.stdout, sys.__stdout__)
387
388 def test_std_streams_are_utf_8_encoded(self):
389 self.assertEqual(sys.stderr.encoding, "utf-8")
390 self.assertEqual(sys.stdin.encoding, "utf-8")
391 self.assertEqual(sys.stdout.encoding, "utf-8")
392
393 def test_std_streams_have_correct_modes(self):
394 self.assertEqual(sys.stderr.mode, "w")
395 self.assertEqual(sys.stdin.mode, "r")
396 self.assertEqual(sys.stdout.mode, "w")
397
398 @pyro_only
399 def test_std_streams_point_to_correct_fileno(self):
400 self.assertEqual(sys.stderr.buffer.fileno(), sys._stderr_fd)
401 self.assertEqual(sys.stdin.buffer.fileno(), sys._stdin_fd)
402 self.assertEqual(sys.stdout.buffer.fileno(), sys._stdout_fd)
403
404 # TODO(T89882231) enable test for Pyro
405 @cpython_only
406 def test_under_getframe_returns_frame(self):
407 from types import ModuleType
408
409 frame = sys._getframe(0)
410 self.assertTrue(frame.f_globals is not None)
411 self.assertEqual(frame.f_globals["__name__"], "__main__")
412 self.assertTrue(frame.f_locals is not None)
413 self.assertEqual(frame.f_locals["self"], self)
414 builtins = __builtins__
415 if isinstance(builtins, ModuleType):
416 builtins = builtins.__dict__
417 self.assertIs(frame.f_builtins, builtins)
418 self.assertTrue(frame.f_code is not None)
419
420 def test_under_getframe_with_noninteger_raises_typeerror(self):
421 with self.assertRaises(TypeError):
422 sys._getframe(None)
423
424 # TODO(T89882231) enable test for Pyro
425 @cpython_only
426 def test_under_getframe_returns_frame_with_locals(self):
427 def baz():
428 return sys._getframe(1).f_locals
429
430 def bar():
431 foo = 1 # noqa: F841
432 return baz()
433
434 bar_locals = bar()
435 self.assertEqual(len(bar_locals), 2)
436 self.assertEqual(bar_locals["foo"], 1)
437 self.assertEqual(bar_locals["baz"], baz)
438
439 def test_under_getframe_from_function_cannot_modify_locals(self):
440 def baz():
441 sys._getframe(1).f_locals["foo"] = "wrong"
442
443 def bar():
444 foo = "correct"
445 baz()
446 return foo
447
448 self.assertEqual(bar(), "correct")
449
450 def test_under_getframe_from_global_scope_gets_locals(self):
451 from types import ModuleType
452
453 module = ModuleType("")
454 module.sys = sys
455 module.temp = "wrong"
456 exec("sys._getframe(0).f_locals['temp'] = 'correct'", module.__dict__)
457 self.assertEqual(module.temp, "correct")
458
459 def test_under_getframe_with_high_depth_raises_valueerror(self):
460 with self.assertRaises(ValueError) as context:
461 sys._getframe(1000)
462 self.assertEqual(str(context.exception), "call stack is not deep enough")
463
464 def test_under_getframe_with_negative_integer_returns_top_frame(self):
465 self.assertEqual(sys._getframe(-1).f_code, sys._getframe(0).f_code)
466
467 def test_under_getframe_with_no_argument_returns_top_frame(self):
468 self.assertEqual(sys._getframe().f_code, sys._getframe(0).f_code)
469
470 def test_under_getframe_f_back_points_to_previous_frame(self):
471 def baz():
472 return sys._getframe(0)
473
474 def bar():
475 return baz()
476
477 def foo():
478 return bar()
479
480 frame = foo()
481 self.assertIs(frame.f_code, baz.__code__)
482 self.assertIs(frame.f_back.f_code, bar.__code__)
483 self.assertIs(frame.f_back.f_back.f_code, foo.__code__)
484
485 def test_under_getframe_f_back_leads_to_module_frame(self):
486 frame = sys._getframe()
487 while True:
488 if frame.f_back is None:
489 break
490 frame = frame.f_back
491 self.assertIsNone(frame.f_back)
492 self.assertIs(frame.f_globals, sys.modules[self.__module__].__dict__)
493
494 @pyro_only
495 def test_under_getframe_f_back_excludes_builtins_function(self):
496 recorded_frame = None
497
498 class C:
499 def __hash__(self):
500 nonlocal recorded_frame
501 recorded_frame = sys._getframe()
502 return 1234
503
504 def foo():
505 c = C()
506 d = {}
507 # Calling C.__hash__ via native code, dict.__delitem__.
508 try:
509 del d[c]
510 except KeyError:
511 pass
512
513 foo()
514
515 self.assertIs(recorded_frame.f_code, C.__hash__.__code__)
516 # The result excludes dict.__delitem__.
517 self.assertIs(recorded_frame.f_back.f_code, foo.__code__)
518
519 def test_version(self):
520 self.assertTrue(sys.version)
521 self.assertEqual(len(sys.version_info), 5)
522
523 def test_hexversion(self):
524 self.assertIsInstance(sys.hexversion, int)
525 self.assertEqual((sys.hexversion >> 24) & 0xFF, sys.version_info.major)
526 self.assertEqual((sys.hexversion >> 16) & 0xFF, sys.version_info.minor)
527 self.assertEqual((sys.hexversion >> 8) & 0xFF, sys.version_info.micro)
528 release_level = (sys.hexversion >> 4) & 0xF
529 release_level_str = {0xA: "alpha", 0xB: "beta", 0xC: "candidate", 0xF: "final"}
530 self.assertEqual(
531 release_level_str[release_level], sys.version_info.releaselevel
532 )
533 self.assertEqual(sys.hexversion & 0xF, sys.version_info.serial)
534
535 def test_under_getframe_f_lineno(self):
536 d = {}
537 exec("import sys\n\nresult = sys._getframe().f_lineno", d)
538 self.assertIs(d["result"], 3)
539
540 def test_set_asyncgen_hooks_raises_type_error_on_non_none_non_callable_finalizer(
541 self,
542 ):
543 with self.assertRaises(TypeError):
544 sys.set_asyncgen_hooks(finalizer=1)
545
546 def test_set_asyncgen_hooks_raises_type_error_on_non_none_non_callable_firstiter(
547 self,
548 ):
549 with self.assertRaises(TypeError):
550 sys.set_asyncgen_hooks(firstiter=1)
551
552 def test_set_asyncgen_hooks_with_none_values(self):
553 sys.set_asyncgen_hooks(None, None)
554 hooks = sys.get_asyncgen_hooks()
555 self.assertIsNone(hooks[0], None)
556 self.assertIsNone(hooks[1], None)
557
558 def test_set_asyncgen_hooks_with_callables(self):
559 def f1():
560 pass
561
562 def f2():
563 pass
564
565 sys.set_asyncgen_hooks(f1, f2)
566 hooks = sys.get_asyncgen_hooks()
567 self.assertEqual(hooks[0], f1)
568 self.assertEqual(hooks[1], f2)
569
570 def test_set_asyncgen_hooks_with_only_named_firstiter(self):
571 def f():
572 pass
573
574 # Clear any existing values
575 sys.set_asyncgen_hooks(None, None)
576
577 sys.set_asyncgen_hooks(firstiter=f)
578 hooks = sys.get_asyncgen_hooks()
579 self.assertEqual(hooks[0], f)
580 self.assertEqual(hooks[1], None)
581
582 def test_set_asyncgen_hooks_with_only_positional_firstiter(self):
583 def f():
584 pass
585
586 # Clear any existing values
587 sys.set_asyncgen_hooks(None, None)
588
589 sys.set_asyncgen_hooks(f)
590 hooks = sys.get_asyncgen_hooks()
591 self.assertEqual(hooks[0], f)
592 self.assertEqual(hooks[1], None)
593
594 def test_set_asyncgen_hooks_with_only_named_finalizer(self):
595 def f():
596 pass
597
598 # Clear any existing values
599 sys.set_asyncgen_hooks(None, None)
600
601 sys.set_asyncgen_hooks(finalizer=f)
602 hooks = sys.get_asyncgen_hooks()
603 self.assertEqual(hooks[0], None)
604 self.assertEqual(hooks[1], f)
605
606 def test_set_asyncgen_hooks_with_no_args(self):
607 def f1():
608 pass
609
610 def f2():
611 pass
612
613 # Set initial values which shouldn't be affected
614 sys.set_asyncgen_hooks(f1, f2)
615
616 sys.set_asyncgen_hooks()
617 hooks = sys.get_asyncgen_hooks()
618 self.assertEqual(hooks[0], f1)
619 self.assertEqual(hooks[1], f2)
620
621 def test_asyncgen_hooks_attributes(self):
622 def f1():
623 pass
624
625 def f2():
626 pass
627
628 sys.set_asyncgen_hooks(f1, f2)
629 hooks = sys.get_asyncgen_hooks()
630 self.assertEqual(hooks.firstiter, f1)
631 self.assertEqual(hooks.finalizer, f2)
632
633 def test_executable_contains_python3(self):
634 self.assertIn("python", sys.executable)
635
636 def test_under_base_executable_contains_python3(self):
637 self.assertIn("python", sys._base_executable)
638
639
640if __name__ == "__main__":
641 unittest.main()