def test_assert_python_failure_raises(self): with self.assertRaises(AssertionError) as error_context: script_helper.assert_python_failure('-c', 'import sys; sys.exit(0)') error_msg = str(error_context.exception) self.assertIn('Process return code is 0\n', error_msg) self.assertIn('import sys; sys.exit(0)', error_msg, msg='unexpected command line.')
def test_run_code(self): # Test expected operation of the '-c' switch # Switch needs an argument assert_python_failure('-c') # Check we get an error for an uncaught exception assert_python_failure('-c', 'raise Exception') # All good if execution is successful assert_python_ok('-c', 'pass')
def test_crashers_crash(self): for fname in glob.glob(CRASHER_FILES): if os.path.basename(fname) in infinite_loops: continue # Some "crashers" only trigger an exception rather than a # segfault. Consider that an acceptable outcome. if test.support.verbose: print("Checking crasher:", fname) assert_python_failure(fname)
def test_run_profile_as_module(self): # Test that -m switch needs an argument assert_python_failure('-m', self.profilermodule.__name__, '-m') # Test failure for not-existent module assert_python_failure('-m', self.profilermodule.__name__, '-m', 'random_module_xyz') # Test successful run assert_python_ok('-m', self.profilermodule.__name__, '-m', 'timeit', '-n', '1')
def test_module_path_option(self): # Test -m switch with modules # Test that -m switch needs an argument assert_python_failure('-m', 'cProfile', '-m') # Test failure for not-existent module assert_python_failure('-m', 'cProfile', '-m', 'random_module_xyz') # Test successful run assert_python_ok('-m', 'cProfile', '-m', 'timeit', '-n', '1')
def test_bad_traverse(self): ''' Issue #32374: Test that traverse fails when accessing per-module state before Py_mod_exec was executed. (Multiphase initialization modules only) ''' script = """if True: import importlib.util as util spec = util.find_spec('_testmultiphase') spec.name = '_testmultiphase_with_bad_traverse' m = spec.loader.create_module(spec)""" assert_python_failure("-c", script)
def test_return_result_with_error(self): # Issue #23571: A function must not return a result with an error set if Py_DEBUG: code = textwrap.dedent( """ import _testcapi from test import support with support.SuppressCrashReport(): _testcapi.return_result_with_error() """ ) rc, out, err = assert_python_failure("-c", code) self.assertRegex( err.replace(b"\r", b""), br"Fatal Python error: a function returned a " br"result with an error set\n" br"ValueError\n" br"\n" br"During handling of the above exception, " br"another exception occurred:\n" br"\n" br"SystemError: <built-in " br"function return_result_with_error> " br"returned a result with an error set\n" br"\n" br"Current thread.*:\n" br" File .*, line 6 in <module>", ) else: with self.assertRaises(SystemError) as cm: _testcapi.return_result_with_error() self.assertRegex(str(cm.exception), "return_result_with_error.* " "returned a result with an error set")
def test_return_null_without_error(self): # Issue #23571: A function must not return NULL without setting an # error if Py_DEBUG: code = textwrap.dedent(""" import _testcapi from test import support with support.SuppressCrashReport(): _testcapi.return_null_without_error() """) rc, out, err = assert_python_failure('-c', code) self.assertRegex(err.replace(b'\r', b''), br'Fatal Python error: a function returned NULL ' br'without setting an error\n' br'SystemError: <built-in function ' br'return_null_without_error> returned NULL ' br'without setting an error\n' br'\n' br'Current thread.*:\n' br' File .*", line 6 in <module>') else: with self.assertRaises(SystemError) as cm: _testcapi.return_null_without_error() self.assertRegex(str(cm.exception), 'return_null_without_error.* ' 'returned NULL without setting an error')
def test_return_result_with_error(self): # Issue #23571: A function must not return a result with an error set if Py_DEBUG: code = textwrap.dedent(""" import _testcapi from test import support with support.SuppressCrashReport(): _testcapi.return_result_with_error() """) rc, out, err = assert_python_failure('-c', code) self.assertRegex(err.replace(b'\r', b''), br'Fatal Python error: a function returned a ' br'result with an error set\n' br'ValueError\n' br'\n' br'During handling of the above exception, ' br'another exception occurred:\n' br'\n' br'SystemError: <built-in ' br'function return_result_with_error> ' br'returned a result with an error set\n' br'\n' br'Current thread.*:\n' br' File .*, line 6 in <module>') else: with self.assertRaises(SystemError) as cm: _testcapi.return_result_with_error() self.assertRegex(str(cm.exception), 'return_result_with_error.* ' 'returned a result with an error set')
def test_trigger_memory_error(self): e = self._nested_expression(100) rc, out, err = assert_python_failure('-c', e) # parsing the expression will result in an error message # followed by a MemoryError (see #11963) self.assertIn(b's_push: parser stack overflow', err) self.assertIn(b'MemoryError', err)
def test_finalize_runnning_thread(self): # Issue 1402: the PyGILState_Ensure / _Release functions may be called # very late on python exit: on deallocation of a running thread for # example. import_module("ctypes") rc, out, err = assert_python_failure("-c", """if 1: import ctypes, sys, time, _thread # This lock is used as a simple event variable. ready = _thread.allocate_lock() ready.acquire() # Module globals are cleared before __del__ is run # So we save the functions in class dict class C: ensure = ctypes.pythonapi.PyGILState_Ensure release = ctypes.pythonapi.PyGILState_Release def __del__(self): state = self.ensure() self.release(state) def waitingThread(): x = C() ready.release() time.sleep(100) _thread.start_new_thread(waitingThread, ()) ready.acquire() # Be sure the other thread is waiting. sys.exit(42) """) self.assertEqual(rc, 42)
def _check_import_error(self, script_name, expected_msg, *cmd_line_switches): run_args = cmd_line_switches + (script_name,) rc, out, err = assert_python_failure(*run_args) if verbose > 1: print("Output from test script %r:" % script_name) print(repr(err)) print("Expected output: %r" % expected_msg) self.assertIn(expected_msg.encode("utf-8"), err)
def test_syntaxerror_unindented_caret_position(self): script = "1 + 1 = 2\n" with support.temp_dir() as script_dir: script_name = _make_test_script(script_dir, 'script', script) exitcode, stdout, stderr = assert_python_failure(script_name) text = io.TextIOWrapper(io.BytesIO(stderr), 'ascii').read() # Confirm that the caret is located under the first 1 character self.assertIn("\n 1 + 1 = 2\n ^", text)
def test_unknown_options(self): rc, out, err = assert_python_failure('-E', '-z') self.assertIn(b'Unknown option: -z', err) self.assertEqual(err.splitlines().count(b'Unknown option: -z'), 1) self.assertEqual(b'', out) # Add "without='-E'" to prevent _assert_python to append -E # to env_vars and change the output of stderr rc, out, err = assert_python_failure('-z', without='-E') self.assertIn(b'Unknown option: -z', err) self.assertEqual(err.splitlines().count(b'Unknown option: -z'), 1) self.assertEqual(b'', out) rc, out, err = assert_python_failure('-a', '-z', without='-E') self.assertIn(b'Unknown option: -a', err) # only the first unknown option is reported self.assertNotIn(b'Unknown option: -z', err) self.assertEqual(err.splitlines().count(b'Unknown option: -a'), 1) self.assertEqual(b'', out)
def test_recursion_normalizing_exception(self): # Issue #22898. # Test that a RecursionError is raised when tstate->recursion_depth is # equal to recursion_limit in PyErr_NormalizeException() and check # that a ResourceWarning is printed. # Prior to #22898, the recursivity of PyErr_NormalizeException() was # controlled by tstate->recursion_depth and a PyExc_RecursionErrorInst # singleton was being used in that case, that held traceback data and # locals indefinitely and would cause a segfault in _PyExc_Fini() upon # finalization of these locals. code = """if 1: import sys from _testcapi import get_recursion_depth class MyException(Exception): pass def setrecursionlimit(depth): while 1: try: sys.setrecursionlimit(depth) return depth except RecursionError: # sys.setrecursionlimit() raises a RecursionError if # the new recursion limit is too low (issue #25274). depth += 1 def recurse(cnt): cnt -= 1 if cnt: recurse(cnt) else: generator.throw(MyException) def gen(): f = open(%a, mode='rb', buffering=0) yield generator = gen() next(generator) recursionlimit = sys.getrecursionlimit() depth = get_recursion_depth() try: # Upon the last recursive invocation of recurse(), # tstate->recursion_depth is equal to (recursion_limit - 1) # and is equal to recursion_limit when _gen_throw() calls # PyErr_NormalizeException(). recurse(setrecursionlimit(depth + 2) - depth - 1) finally: sys.setrecursionlimit(recursionlimit) print('Done.') """ % __file__ rc, out, err = script_helper.assert_python_failure("-Wd", "-c", code) # Check that the program does not fail with SIGABRT. self.assertEqual(rc, 1) self.assertIn(b'RecursionError', err) self.assertIn(b'ResourceWarning', err) self.assertIn(b'Done.', out)
def test_d_runtime_error(self): bazfn = script_helper.make_script(self.pkgdir, 'baz', 'raise Exception') self.assertRunOK('-q', '-d', 'dinsdale', self.pkgdir) fn = script_helper.make_script(self.pkgdir, 'bing', 'import baz') pyc = importlib.util.cache_from_source(bazfn) os.rename(pyc, os.path.join(self.pkgdir, 'baz.pyc')) os.remove(bazfn) rc, out, err = script_helper.assert_python_failure(fn, __isolated=False) self.assertRegex(err, b'File "dinsdale')
def test_sys_xoptions_invalid(self): for nframe in (-1, 0, 2**30): with self.subTest(nframe=nframe): with support.SuppressCrashReport(): args = ('-X', 'tracemalloc=%s' % nframe, '-c', 'pass') ok, stdout, stderr = assert_python_failure(*args) self.assertIn(b'-X tracemalloc=NFRAME: invalid ' b'number of frames', stderr)
def get_output(self, *args, failure=False, **kw): kw = dict(self.DEFAULT_ENV, **kw) if failure: out = assert_python_failure(*args, **kw) out = out[2] else: out = assert_python_ok(*args, **kw) out = out[1] return out.decode().rstrip("\n\r")
def test_d_runtime_error(self): bazfn = script_helper.make_script(self.pkgdir, "baz", "raise Exception") self.assertRunOK("-q", "-d", "dinsdale", self.pkgdir) fn = script_helper.make_script(self.pkgdir, "bing", "import baz") pyc = importlib.util.cache_from_source(bazfn) os.rename(pyc, os.path.join(self.pkgdir, "baz.pyc")) os.remove(bazfn) rc, out, err = script_helper.assert_python_failure(fn, __isolated=False) self.assertRegex(err, b'File "dinsdale')
def test_env_var_invalid(self): for nframe in (-1, 0, 2**30): with self.subTest(nframe=nframe): with support.SuppressCrashReport(): ok, stdout, stderr = assert_python_failure( '-c', 'pass', PYTHONTRACEMALLOC=str(nframe)) self.assertIn(b'PYTHONTRACEMALLOC: invalid ' b'number of frames', stderr)
def check_sys_xoptions_invalid(self, nframe): args = ('-X', 'tracemalloc=%s' % nframe, '-c', 'pass') with support.SuppressCrashReport(): ok, stdout, stderr = assert_python_failure(*args) if b'ValueError: the number of frames must be in range' in stderr: return if b'-X tracemalloc=NFRAME: invalid number of frames' in stderr: return self.fail(f"unexpeced output: {stderr!a}")
def test_conflicting_envvar_and_command_line(self): rc, stdout, stderr = assert_python_failure("-Werror::DeprecationWarning", "-c", "import sys, warnings; sys.stdout.write(str(sys.warnoptions)); " "warnings.warn('Message', DeprecationWarning)", PYTHONWARNINGS="default::DeprecationWarning") self.assertEqual(stdout, b"['default::DeprecationWarning', 'error::DeprecationWarning']") self.assertEqual(stderr.splitlines(), [b"Traceback (most recent call last):", b" File \"<string>\", line 1, in <module>", b"DeprecationWarning: Message"])
def check_env_var_invalid(self, nframe): with support.SuppressCrashReport(): ok, stdout, stderr = assert_python_failure( '-c', 'pass', PYTHONTRACEMALLOC=str(nframe)) if b'ValueError: the number of frames must be in range' in stderr: return if b'PYTHONTRACEMALLOC: invalid number of frames' in stderr: return self.fail(f"unexpeced output: {stderr!a}")
def test_bad_traverse(self): ''' Issue #32374: Test that traverse fails when accessing per-module state before Py_mod_exec was executed. (Multiphase initialization modules only) ''' script = """if True: try: from test import support import importlib.util as util spec = util.find_spec('_testmultiphase') spec.name = '_testmultiphase_with_bad_traverse' with support.SuppressCrashReport(): m = spec.loader.create_module(spec) except: # Prevent Python-level exceptions from # ending the process with non-zero status # (We are testing for a crash in C-code) pass""" assert_python_failure("-c", script)
def test_failed_import_during_compiling(self): # Issue 4367 # Decoding \N escapes requires the unicodedata module. If it can't be # imported, we shouldn't segfault. # This program should raise a SyntaxError in the eval. code = "import sys;" "sys.modules['unicodedata'] = None;" """eval("'\\\\N{SOFT HYPHEN}'")""" # We use a separate process because the unicodedata module may already # have been loaded in this process. result = script_helper.assert_python_failure("-c", code) error = "SyntaxError: (unicode error) \\N escapes not supported " "(can't load unicodedata module)" self.assertIn(error, result.err.decode("ascii"))
def test_syshook_no_logdir_text_format(self): # Issue 12890: we were emitting the <p> tag in text mode. with temp_dir() as tracedir: rc, out, err = assert_python_failure( '-c', ('import cgitb; cgitb.enable(format="text", logdir=%s); ' 'raise ValueError("Hello World")') % repr(tracedir)) out = out.decode(sys.getfilesystemencoding()) self.assertIn("ValueError", out) self.assertIn("Hello World", out) self.assertNotIn('<p>', out) self.assertNotIn('</p>', out)
def test_syshook_no_logdir_default_format(self): with temp_dir() as tracedir: rc, out, err = assert_python_failure( '-c', ('import cgitb; cgitb.enable(logdir=%s); ' 'raise ValueError("Hello World")') % repr(tracedir)) out = out.decode(sys.getfilesystemencoding()) self.assertIn("ValueError", out) self.assertIn("Hello World", out) # By default we emit HTML markup. self.assertIn('<p>', out) self.assertIn('</p>', out)
def test_failures(self): _errors = ( (b'filename is missing: required with the main options', '-l', '-T'), (b'cannot specify both --listfuncs and (--trace or --count)', '-lc'), (b'argument -R/--no-report: not allowed with argument -r/--report', '-rR'), (b'must specify one of --trace, --count, --report, --listfuncs, or --trackcalls', '-g'), (b'-r/--report requires -f/--file', '-r'), (b'--summary can only be used with --count or --report', '-sT'), (b'unrecognized arguments: -y', '-y')) for message, *args in _errors: *_, stderr = assert_python_failure('-m', 'trace', *args) self.assertIn(message, stderr)
def test_syntaxerror_indented_caret_position(self): script = textwrap.dedent("""\ if True: 1 + 1 = 2 """) with support.temp_dir() as script_dir: script_name = _make_test_script(script_dir, 'script', script) exitcode, stdout, stderr = assert_python_failure(script_name) text = io.TextIOWrapper(io.BytesIO(stderr), 'ascii').read() # Confirm that the caret is located under the first 1 character self.assertIn("\n 1 + 1 = 2\n ^", text) # Try the same with a form feed at the start of the indented line script = ( "if True:\n" "\f 1 + 1 = 2\n" ) script_name = _make_test_script(script_dir, "script", script) exitcode, stdout, stderr = assert_python_failure(script_name) text = io.TextIOWrapper(io.BytesIO(stderr), "ascii").read() self.assertNotIn("\f", text) self.assertIn("\n 1 + 1 = 2\n ^", text)
def test_stdout_flush_at_shutdown(self): # Issue #5319: if stdout.flush() fails at shutdown, an error should # be printed out. code = """if 1: import os, sys, test.support test.support.SuppressCrashReport().__enter__() sys.stdout.write('x') os.close(sys.stdout.fileno())""" rc, out, err = assert_python_failure('-c', code) self.assertEqual(b'', out) self.assertEqual(120, rc) self.assertRegex(err.decode('ascii', 'ignore'), 'Exception ignored in.*\nOSError: .*')
def test_assert_python_failure(self): # I didn't import the sys module so this child will fail. rc, out, err = script_helper.assert_python_failure('-c', 'sys.exit(0)') self.assertNotEqual(0, rc, 'return code should not be 0')
def test_run_code(self): assert_python_failure('-c') assert_python_failure('-c', 'raise Exception') assert_python_ok('-c', 'pass')
def test_run_module(self): assert_python_failure('-m') assert_python_failure('-m', 'fnord43520xyz') assert_python_failure('-m', 'runpy', 'fnord43520xyz') assert_python_ok('-m', 'timeit', '-n', '1')
def check_exit_message(code, expected, **env_vars): rc, out, err = assert_python_failure('-c', code, **env_vars) self.assertEqual(rc, 1) self.assertEqual(out, b'') self.assertTrue(err.startswith(expected), "%s doesn't start with %s" % (ascii(err), ascii(expected)))
def test_unmached_quote(self): # Issue #10206: python program starting with unmatched quote # spewed spaces to stdout rc, out, err = assert_python_failure('-c', "'") self.assertRegex(err.decode('ascii', 'ignore'), 'SyntaxError') self.assertEqual(b'', out)
def check_dash_m_failure(self, *args): rc, out, err = assert_python_failure('-m', *args, __isolated=False) if verbose > 1: print(repr(out)) self.assertEqual(rc, 1) return err
def test_sort(self): rc, out, err = assert_python_failure('-m', 'cProfile', '-s', 'demo') self.assertGreater(rc, 0) self.assertIn(b"option -s: invalid choice: 'demo'", err)
def test_exit(self): # call with two arguments self.assertRaises(TypeError, sys.exit, 42, 42) # call without argument with self.assertRaises(SystemExit) as cm: sys.exit() self.assertIsNone(cm.exception.code) rc, out, err = assert_python_ok('-c', 'import sys; sys.exit()') self.assertEqual(rc, 0) self.assertEqual(out, b'') self.assertEqual(err, b'') # call with integer argument with self.assertRaises(SystemExit) as cm: sys.exit(42) self.assertEqual(cm.exception.code, 42) # call with tuple argument with one entry # entry will be unpacked with self.assertRaises(SystemExit) as cm: sys.exit((42, )) self.assertEqual(cm.exception.code, 42) # call with string argument with self.assertRaises(SystemExit) as cm: sys.exit("exit") self.assertEqual(cm.exception.code, "exit") # call with tuple argument with two entries with self.assertRaises(SystemExit) as cm: sys.exit((17, 23)) self.assertEqual(cm.exception.code, (17, 23)) # test that the exit machinery handles SystemExits properly rc, out, err = assert_python_failure('-c', 'raise SystemExit(47)') self.assertEqual(rc, 47) self.assertEqual(out, b'') self.assertEqual(err, b'') def check_exit_message(code, expected, **env_vars): rc, out, err = assert_python_failure('-c', code, **env_vars) self.assertEqual(rc, 1) self.assertEqual(out, b'') self.assertTrue( err.startswith(expected), "%s doesn't start with %s" % (ascii(err), ascii(expected))) # test that stderr buffer is flushed before the exit message is written # into stderr check_exit_message( r'import sys; sys.stderr.write("unflushed,"); sys.exit("message")', b"unflushed,message") # test that the exit message is written with backslashreplace error # handler to stderr check_exit_message(r'import sys; sys.exit("surrogates:\uDCFF")', b"surrogates:\\udcff") # test that the unicode message is encoded to the stderr encoding # instead of the default encoding (utf8) check_exit_message(r'import sys; sys.exit("h\xe9")', b"h\xe9", PYTHONIOENCODING='latin-1')
def test_decompress_cannot_have_flags_compression(self): rc, out, err = assert_python_failure('-m', 'gzip', '--fast', '-d') self.assertIn( b'error: argument -d/--decompress: not allowed with argument --fast', err) self.assertEqual(out, b'')
def test_compress_fast_best_are_exclusive(self): rc, out, err = assert_python_failure('-m', 'gzip', '--fast', '--best') self.assertIn( b"error: argument --best: not allowed with argument --fast", err) self.assertEqual(out, b'')
def test_usage(self): rc, out, err = assert_python_failure(self.script, '-h') self.assertEqual(rc, 2) self.assertEqual(out, b'') self.assertGreater(err, b'')
def test_unknown_xoptions(self): rc, out, err = assert_python_failure('-X', 'blech') self.assertIn(b'Unknown value for option -X', err) msg = b'Fatal Python error: Unknown value for option -X' self.assertEqual(err.splitlines().count(msg), 1) self.assertEqual(b'', out)
def assertRunNotOK(self, *args, **env_vars): rc, out, err = script_helper.assert_python_failure( *self._get_run_args(args), **env_vars) return rc, out, err
def check(self, code): with support.SuppressCrashReport(): out = assert_python_failure('-c', code, PYTHONMALLOC=self.PYTHONMALLOC) stderr = out.err return stderr.decode('ascii', 'replace')
def test_directories(self): assert_python_failure('.') assert_python_failure('< .')
def test_unmached_quote(self): rc, out, err = assert_python_failure('-c', "'") self.assertRegex(err.decode('ascii', 'ignore'), 'SyntaxError') self.assertEqual(b'', out)
def test_parentless_import_shadowed_by_global(self): # Test as if this were done from the REPL where this error most commonly occurs (bpo-37409). script_helper.assert_python_failure('-W', 'ignore', '-c', "foo = 1; from . import foo")
def pycompilecmd_failure(self, *args): return script_helper.assert_python_failure('-m', 'py_compile', *args)
def test_assert_python_failure(self): rc, out, err = script_helper.assert_python_failure('-c', 'sys.exit(0)') self.assertNotEqual(0, rc, 'return code should not be 0')
def test_decompress_infile_outfile_error(self): rc, out, err = assert_python_failure('-m', 'gzip', '-d', 'thisisatest.out') self.assertEqual(b"filename doesn't end in .gz: 'thisisatest.out'", err.strip()) self.assertEqual(rc, 1) self.assertEqual(out, b'')
def assertFailure(self, *args): rc, stdout, stderr = assert_python_failure('-m', 'calendar', *args) self.assertIn(b'usage:', stderr) self.assertEqual(rc, 2)
def test_run_as_module(self): assert_python_ok('-m', 'trace', '-l', '--module', 'timeit', '-n', '1') assert_python_failure('-m', 'trace', '-l', '--module', 'not_a_module_zzz')
def test_prints_usage_with_invalid_flag(self): output = script_helper.assert_python_failure('-m', 'base64', '-x').err self.assertIn(b'usage: ', output) self.assertIn(b'-d, -u: decode', output)
def assertRunNotOK(self, *args, **env_vars): rc, out, err = script_helper.assert_python_failure( *self._get_run_args(args), **env_vars, PYTHONIOENCODING='utf-8') return rc, out, err
def check(content): with open(fn, 'wb') as fp: fp.write(template % content) script_helper.assert_python_failure(fn)