def _prepare2(self): """Do more preparation to run Python code. Includes finding the module to run and adjusting sys.argv[0]. This method is allowed to import code. """ if self.as_module: self.modulename = self.arg0 pathname, self.package, self.spec = find_module(self.modulename) if self.spec is not None: self.modulename = self.spec.name self.loader = DummyLoader(self.modulename) self.pathname = os.path.abspath(pathname) self.args[0] = self.arg0 = self.pathname elif os.path.isdir(self.arg0): # Running a directory means running the __main__.py file in that # directory. for ext in [".py", ".pyc", ".pyo"]: try_filename = os.path.join(self.arg0, "__main__" + ext) if os.path.exists(try_filename): self.arg0 = try_filename break else: raise NoSource("Can't find '__main__' module in '%s'" % self.arg0) if env.PY2: self.arg0 = os.path.abspath(self.arg0) # Make a spec. I don't know if this is the right way to do it. try: import importlib.machinery except ImportError: pass else: try_filename = python_reported_file(try_filename) self.spec = importlib.machinery.ModuleSpec("__main__", None, origin=try_filename) self.spec.has_location = True self.package = "" self.loader = DummyLoader("__main__") else: if env.PY3: self.loader = DummyLoader("__main__") self.arg0 = python_reported_file(self.arg0)
def test_code_throws(self): self.make_file("throw.py", """\ class MyException(Exception): pass def f1(): raise MyException("hey!") def f2(): f1() f2() """) # The important thing is for "coverage run" and "python" to report the # same traceback. status, out = self.run_command_status("coverage run throw.py") out2 = self.run_command("python throw.py") if env.PYPY: # Pypy has an extra frame in the traceback for some reason out2 = re_lines_text("toplevel", out2, match=False) assert out == out2 # But also make sure that the output is what we expect. path = python_reported_file('throw.py') msg = f'File "{re.escape(path)}", line 8, in f2' assert re.search(msg, out) assert 'raise MyException("hey!")' in out assert status == 1
def prepare(self): """Set sys.path properly. This needs to happen before any importing, and without importing anything. """ should_update_sys_path = True if self.as_module: if env.PYBEHAVIOR.actual_syspath0_dash_m: path0 = os.getcwd() else: path0 = "" sys.path[0] = path0 should_update_sys_path = False elif os.path.isdir(self.arg0): # Running a directory means running the __main__.py file in that # directory. path0 = self.arg0 else: path0 = os.path.abspath(os.path.dirname(self.arg0)) if should_update_sys_path: # sys.path fakery. If we are being run as a command, then sys.path[0] # is the directory of the "coverage" script. If this is so, replace # sys.path[0] with the directory of the file we're running, or the # current directory when running modules. If it isn't so, then we # don't know what's going on, and just leave it alone. top_file = inspect.stack()[-1][0].f_code.co_filename if os.path.abspath(sys.path[0]) == os.path.abspath( os.path.dirname(top_file)): # Set sys.path correctly. sys.path[0] = python_reported_file(path0)
def test_run_python_file(self): run_python_file([TRY_EXECFILE, "arg1", "arg2"]) mod_globs = json.loads(self.stdout()) # The file should think it is __main__ self.assertEqual(mod_globs['__name__'], "__main__") # It should seem to come from a file named try_execfile.py dunder_file = os.path.basename(mod_globs['__file__']) self.assertEqual(dunder_file, "try_execfile.py") # It should have its correct module data. self.assertEqual(mod_globs['__doc__'].splitlines()[0], "Test file for run_python_file.") self.assertEqual(mod_globs['DATA'], "xyzzy") self.assertEqual(mod_globs['FN_VAL'], "my_fn('fooey')") # It must be self-importable as __main__. self.assertEqual(mod_globs['__main__.DATA'], "xyzzy") # Argv should have the proper values. self.assertEqual(mod_globs['argv0'], python_reported_file(TRY_EXECFILE)) self.assertEqual(mod_globs['argv1-n'], ["arg1", "arg2"]) # __builtins__ should have the right values, like open(). self.assertEqual(mod_globs['__builtins__.has_open'], True)
def _prepare2(self): """Do more preparation to run Python code. Includes finding the module to run and adjusting sys.argv[0]. This method is allowed to import code. """ if self.as_module: self.modulename = self.arg0 pathname, self.package, self.spec = find_module(self.modulename) if self.spec is not None: self.modulename = self.spec.name self.loader = DummyLoader(self.modulename) self.pathname = os.path.abspath(pathname) self.args[0] = self.arg0 = self.pathname elif os.path.isdir(self.arg0): # Running a directory means running the __main__.py file in that # directory. for ext in [".py", ".pyc", ".pyo"]: try_filename = os.path.join(self.arg0, "__main__" + ext) # 3.8.10 changed how files are reported when running a # directory. But I'm not sure how far this change is going to # spread, so I'll just hard-code it here for now. if env.PYVERSION >= (3, 8, 10): try_filename = os.path.abspath(try_filename) if os.path.exists(try_filename): self.arg0 = try_filename break else: raise NoSource( f"Can't find '__main__' module in '{self.arg0}'") # Make a spec. I don't know if this is the right way to do it. try_filename = python_reported_file(try_filename) self.spec = importlib.machinery.ModuleSpec("__main__", None, origin=try_filename) self.spec.has_location = True self.package = "" self.loader = DummyLoader("__main__") else: self.loader = DummyLoader("__main__") self.arg0 = python_reported_file(self.arg0)
def test_removing_directory_with_error(self): self.make_file("bug806.py", self.BUG_806) out = self.run_command("coverage run bug806.py") path = python_reported_file('bug806.py') # Python 3.11 adds an extra line to the traceback. # Check that the lines we expect are there. lines = textwrap.dedent(f"""\ Traceback (most recent call last): File "{path}", line 8, in <module> print(sys.argv[1]) IndexError: list index out of range """).splitlines(keepends=True) assert all(line in out for line in lines)
def test_running_py_from_binary(self): # Use make_file to get the bookkeeping. Ideally, it would # be able to write binary files. bf = self.make_file("binary") with open(bf, "wb") as f: f.write(b'\x7fELF\x02\x01\x01\x00\x00\x00') path = python_reported_file('binary') msg = ( re.escape(f"Couldn't run '{path}' as Python code: ") + r"(TypeError|ValueError): source code string cannot contain null bytes" ) with pytest.raises(Exception, match=msg): run_python_file([bf])
def test_warns_if_never_run(self): # Note: the name of the function can't have "warning" in it, or the # absolute path of the file will have "warning" in it, and an assertion # will fail. out = self.run_command("coverage run i_dont_exist.py") path = python_reported_file('i_dont_exist.py') assert f"No file to run: '{path}'" in out assert "warning" not in out assert "Exception" not in out out = self.run_command("coverage run -m no_such_module") assert ( ("No module named no_such_module" in out) or ("No module named 'no_such_module'" in out) ) assert "warning" not in out assert "Exception" not in out
def test_running_py_from_binary(self): # Use make_file to get the bookkeeping. Ideally, it would # be able to write binary files. bf = self.make_file("binary") with open(bf, "wb") as f: f.write(b'\x7fELF\x02\x01\x01\x00\x00\x00') path = python_reported_file('binary') msg = ( re.escape("Couldn't run '{}' as Python code: ".format(path)) + r"(TypeError|ValueError): " r"(" r"compile\(\) expected string without null bytes" # for py2 r"|" r"source code string cannot contain null bytes" # for py3 r")") with self.assertRaisesRegex(Exception, msg): run_python_file([bf])
def prepare(self): """Set sys.path properly. This needs to happen before any importing, and without importing anything. """ if self.as_module: if env.PYBEHAVIOR.actual_syspath0_dash_m: path0 = os.getcwd() else: path0 = "" elif os.path.isdir(self.arg0): # Running a directory means running the __main__.py file in that # directory. path0 = self.arg0 else: path0 = os.path.abspath(os.path.dirname(self.arg0)) if os.path.isdir(sys.path[0]): # sys.path fakery. If we are being run as a command, then sys.path[0] # is the directory of the "coverage" script. If this is so, replace # sys.path[0] with the directory of the file we're running, or the # current directory when running modules. If it isn't so, then we # don't know what's going on, and just leave it alone. top_file = inspect.stack()[-1][0].f_code.co_filename sys_path_0_abs = os.path.abspath(sys.path[0]) top_file_dir_abs = os.path.abspath(os.path.dirname(top_file)) sys_path_0_abs = canonical_filename(sys_path_0_abs) top_file_dir_abs = canonical_filename(top_file_dir_abs) if sys_path_0_abs != top_file_dir_abs: path0 = None else: # sys.path[0] is a file. Is the next entry the directory containing # that file? if sys.path[1] == os.path.dirname(sys.path[0]): # Can it be right to always remove that? del sys.path[1] if path0 is not None: sys.path[0] = python_reported_file(path0)
def test_no_such_file(self): path = python_reported_file('xyzzy.py') msg = re.escape("No file to run: '{}'".format(path)) with self.assertRaisesRegex(NoSource, msg): run_python_file(["xyzzy.py"])
def test_no_such_file(self): path = python_reported_file('xyzzy.py') msg = re.escape("No file to run: '{}'".format(path)) with pytest.raises(NoSource, match=msg): run_python_file(["xyzzy.py"])
def test_no_such_pyc_file(self): path = python_reported_file('xyzzy.pyc') msg = re.escape(f"No file to run: '{path}'") with pytest.raises(NoCode, match=msg): run_python_file(["xyzzy.pyc"])
def prepare(self): """Do initial preparation to run Python code. Includes finding the module to run, adjusting sys.argv[0], and changing sys.path to match what Python does. """ should_update_sys_path = True if self.as_module: if env.PYBEHAVIOR.actual_syspath0_dash_m: path0 = os.getcwd() else: path0 = "" sys.path[0] = path0 should_update_sys_path = False self.modulename = self.arg0 pathname, self.package, self.spec = find_module(self.modulename) if self.spec is not None: self.modulename = self.spec.name self.loader = DummyLoader(self.modulename) self.pathname = os.path.abspath(pathname) self.args[0] = self.arg0 = self.pathname elif os.path.isdir(self.arg0): # Running a directory means running the __main__.py file in that # directory. path0 = self.arg0 for ext in [".py", ".pyc", ".pyo"]: try_filename = os.path.join(self.arg0, "__main__" + ext) if os.path.exists(try_filename): self.arg0 = try_filename break else: raise NoSource("Can't find '__main__' module in '%s'" % self.arg0) if env.PY2: self.arg0 = os.path.abspath(self.arg0) # Make a spec. I don't know if this is the right way to do it. try: import importlib.machinery except ImportError: pass else: try_filename = python_reported_file(try_filename) self.spec = importlib.machinery.ModuleSpec("__main__", None, origin=try_filename) self.spec.has_location = True self.package = "" self.loader = DummyLoader("__main__") else: path0 = os.path.abspath(os.path.dirname(self.arg0)) if env.PY3: self.loader = DummyLoader("__main__") self.args[0] = python_reported_file(self.args[0]) self.arg0 = python_reported_file(self.arg0) if self.modulename is None: self.modulename = '__main__' if should_update_sys_path: # sys.path fakery. If we are being run as a command, then sys.path[0] # is the directory of the "coverage" script. If this is so, replace # sys.path[0] with the directory of the file we're running, or the # current directory when running modules. If it isn't so, then we # don't know what's going on, and just leave it alone. top_file = inspect.stack()[-1][0].f_code.co_filename if os.path.abspath(sys.path[0]) == os.path.abspath( os.path.dirname(top_file)): # Set sys.path correctly. sys.path[0] = python_reported_file(path0)