diff options
-rw-r--r-- | coverage/cmdline.py | 14 | ||||
-rw-r--r-- | coverage/execfile.py | 178 | ||||
-rw-r--r-- | tests/modules/pkg1/__main__.py | 2 | ||||
-rw-r--r-- | tests/modules/pkg1/runmod2.py | 2 | ||||
-rw-r--r-- | tests/modules/pkg1/sub/__main__.py | 2 | ||||
-rw-r--r-- | tests/modules/pkg1/sub/runmod3.py | 2 | ||||
-rw-r--r-- | tests/modules/runmod1.py | 2 | ||||
-rw-r--r-- | tests/test_cmdline.py | 87 | ||||
-rw-r--r-- | tests/test_execfile.py | 44 | ||||
-rw-r--r-- | tests/test_process.py | 18 |
10 files changed, 214 insertions, 137 deletions
diff --git a/coverage/cmdline.py b/coverage/cmdline.py index be258b5e..67efa8db 100644 --- a/coverage/cmdline.py +++ b/coverage/cmdline.py @@ -19,7 +19,7 @@ from coverage import env from coverage.collector import CTracer from coverage.data import line_counts from coverage.debug import info_formatter, info_header -from coverage.execfile import run_python_file, run_python_module +from coverage.execfile import PyRunner from coverage.misc import BaseCoverageException, ExceptionDuringRun, NoSource from coverage.results import should_fail_under @@ -504,6 +504,10 @@ class CoverageScript(object): include=include, ) + # We need to be able to import from the current directory, because + # plugins may try to, for example, to read Django settings. + sys.path.insert(0, '') + self.coverage.load() total = None @@ -633,6 +637,9 @@ class CoverageScript(object): ) return ERR + runner = PyRunner(args, as_module=bool(options.module)) + runner.prepare() + if options.append: self.coverage.load() @@ -640,10 +647,7 @@ class CoverageScript(object): self.coverage.start() code_ran = True try: - if options.module: - run_python_module(args[0], args) - else: - run_python_file(args[0], args) + runner.run() except NoSource: code_ran = False raise diff --git a/coverage/execfile.py b/coverage/execfile.py index b2b78444..4fc6a85f 100644 --- a/coverage/execfile.py +++ b/coverage/execfile.py @@ -3,6 +3,7 @@ """Execute files of Python code.""" +import inspect import marshal import os import struct @@ -100,93 +101,99 @@ else: return pathname, packagename -def run_python_module(modulename, args): - """Run a Python module, as though with ``python -m name args...``. +class PyRunner(object): + """Multi-stage execution of Python code. - `modulename` is the name of the module, possibly a dot-separated name. - `args` is the argument array to present as sys.argv, including the first - element naming the module being executed. + This is meant to emulate real Python execution as closely as possible. """ - pathname, packagename = find_module(modulename) - - pathname = os.path.abspath(pathname) - args[0] = pathname - # Python 3.7.0b3 changed the behavior of the sys.path[0] entry for -m. It - # used to be an empty string (meaning the current directory). It changed - # to be the actual path to the current directory, so that os.chdir wouldn't - # affect the outcome. - if env.PYVERSION >= (3, 7, 0, 'beta', 3): - path0 = os.getcwd() - else: - path0 = "" - run_python_file(pathname, args, package=packagename, modulename=modulename, path0=path0) - - -def run_python_file(filename, args, package=None, modulename=None, path0=None): - """Run a Python file as if it were the main program on the command line. + def __init__(self, args, as_module=False): + self.args = args + self.as_module = as_module - `filename` is the path to the file to execute, it need not be a .py file. - `args` is the argument array to present as sys.argv, including the first - element naming the file being executed. `package` is the name of the - enclosing package, if any. + self.arg0 = args[0] + self.package = self.modulename = self.pathname = None - `modulename` is the name of the module the file was run as. + def prepare(self): + """Do initial preparation to run Python code. - `path0` is the value to put into sys.path[0]. If it's None, then this - function will decide on a value. + Includes finding the module to run, adjusting sys.argv[0], and changing + sys.path to match what Python does. - """ - if modulename is None and env.PYVERSION >= (3, 3): - modulename = '__main__' - - # Create a module to serve as __main__ - old_main_mod = sys.modules['__main__'] - main_mod = types.ModuleType('__main__') - sys.modules['__main__'] = main_mod - main_mod.__file__ = filename - if package: - main_mod.__package__ = package - if modulename: - main_mod.__loader__ = DummyLoader(modulename) - - main_mod.__builtins__ = BUILTINS - - # Set sys.argv properly. - old_argv = sys.argv - sys.argv = args - - if os.path.isdir(filename): - # Running a directory means running the __main__.py file in that - # directory. - my_path0 = filename - - for ext in [".py", ".pyc", ".pyo"]: - try_filename = os.path.join(filename, "__main__" + ext) - if os.path.exists(try_filename): - filename = try_filename - break + """ + should_update_sys_path = True + + if self.as_module: + # Python 3.7.0b3 changed the behavior of the sys.path[0] entry for -m. It + # used to be an empty string (meaning the current directory). It changed + # to be the actual path to the current directory, so that os.chdir wouldn't + # affect the outcome. + if env.PYVERSION >= (3, 7, 0, 'beta', 3): + path0 = os.getcwd() + else: + path0 = "" + sys.path[0] = path0 + should_update_sys_path = False + self.modulename = self.arg0 + pathname, self.package = find_module(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) else: - raise NoSource("Can't find '__main__' module in '%s'" % filename) - else: - my_path0 = os.path.abspath(os.path.dirname(filename)) - - # Set sys.path correctly. - old_path0 = sys.path[0] - sys.path[0] = path0 if path0 is not None else my_path0 + path0 = os.path.abspath(os.path.dirname(self.arg0)) + + if self.modulename is None and env.PYVERSION >= (3, 3): + 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] = path0 + + def run(self): + """Run the Python code!""" + + # Create a module to serve as __main__ + main_mod = types.ModuleType('__main__') + sys.modules['__main__'] = main_mod + main_mod.__file__ = self.arg0 + if self.package: + main_mod.__package__ = self.package + if self.modulename: + main_mod.__loader__ = DummyLoader(self.modulename) + + main_mod.__builtins__ = BUILTINS + + # Set sys.argv properly. + sys.argv = self.args - try: try: # Make a code object somehow. - if filename.endswith((".pyc", ".pyo")): - code = make_code_from_pyc(filename) + if self.arg0.endswith((".pyc", ".pyo")): + code = make_code_from_pyc(self.arg0) else: - code = make_code_from_py(filename) + code = make_code_from_py(self.arg0) except CoverageException: raise except Exception as exc: msg = "Couldn't run {filename!r} as Python code: {exc.__class__.__name__}: {exc}" - raise CoverageException(msg.format(filename=filename, exc=exc)) + raise CoverageException(msg.format(filename=self.arg0, exc=exc)) # Execute the code object. try: @@ -230,11 +237,30 @@ def run_python_file(filename, args, package=None, modulename=None, path0=None): else: sys.exit(1) - finally: - # Restore the old __main__, argv, and path. - sys.modules['__main__'] = old_main_mod - sys.argv = old_argv - sys.path[0] = old_path0 + +def run_python_module(args): + """Run a Python module, as though with ``python -m name args...``. + + `args` is the argument array to present as sys.argv, including the first + element naming the module being executed. + + """ + runner = PyRunner(args, as_module=True) + runner.prepare() + runner.run() + + +def run_python_file(args): + """Run a Python file as if it were the main program on the command line. + + `args` is the argument array to present as sys.argv, including the first + element naming the file being executed. `package` is the name of the + enclosing package, if any. + + """ + runner = PyRunner(args, as_module=False) + runner.prepare() + runner.run() def make_code_from_py(filename): diff --git a/tests/modules/pkg1/__main__.py b/tests/modules/pkg1/__main__.py index 66ce5956..0d38e33e 100644 --- a/tests/modules/pkg1/__main__.py +++ b/tests/modules/pkg1/__main__.py @@ -1,3 +1,3 @@ -# Used in the tests for run_python_module +# Used in the tests for PyRunner import sys print("pkg1.__main__: passed %s" % sys.argv[1]) diff --git a/tests/modules/pkg1/runmod2.py b/tests/modules/pkg1/runmod2.py index b0f43c2e..e2778669 100644 --- a/tests/modules/pkg1/runmod2.py +++ b/tests/modules/pkg1/runmod2.py @@ -1,6 +1,6 @@ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt -# Used in the tests for run_python_module +# Used in the tests for PyRunner import sys print("runmod2: passed %s" % sys.argv[1]) diff --git a/tests/modules/pkg1/sub/__main__.py b/tests/modules/pkg1/sub/__main__.py index b5be9f1c..1af82c43 100644 --- a/tests/modules/pkg1/sub/__main__.py +++ b/tests/modules/pkg1/sub/__main__.py @@ -1,3 +1,3 @@ -# Used in the tests for run_python_module +# Used in the tests for PyRunner import sys print("pkg1.sub.__main__: passed %s" % sys.argv[1]) diff --git a/tests/modules/pkg1/sub/runmod3.py b/tests/modules/pkg1/sub/runmod3.py index b3b40327..d2be9e5c 100644 --- a/tests/modules/pkg1/sub/runmod3.py +++ b/tests/modules/pkg1/sub/runmod3.py @@ -1,6 +1,6 @@ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt -# Used in the tests for run_python_module +# Used in the tests for PyRunner import sys print("runmod3: passed %s" % sys.argv[1]) diff --git a/tests/modules/runmod1.py b/tests/modules/runmod1.py index cb1f7e99..f79fae83 100644 --- a/tests/modules/runmod1.py +++ b/tests/modules/runmod1.py @@ -1,6 +1,6 @@ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt -# Used in the tests for run_python_module +# Used in the tests for PyRunner import sys print("runmod1: passed %s" % sys.argv[1]) diff --git a/tests/test_cmdline.py b/tests/test_cmdline.py index 18702c96..fd2821b0 100644 --- a/tests/test_cmdline.py +++ b/tests/test_cmdline.py @@ -71,7 +71,7 @@ class BaseCmdLineTest(CoverageTest): return mk # Global names in cmdline.py that will be mocked during the tests. - MOCK_GLOBALS = ['Coverage', 'run_python_file', 'run_python_module'] + MOCK_GLOBALS = ['Coverage', 'PyRunner'] def mock_command_line(self, args, options=None): """Run `args` through the command line, with a Mock. @@ -371,98 +371,113 @@ class CmdLineTest(BaseCmdLineTest): # run calls coverage.erase first. self.cmd_executes("run foo.py", """\ cov = Coverage() + runner = PyRunner(['foo.py'], as_module=False) + runner.prepare() cov.start() - run_python_file('foo.py', ['foo.py']) + runner.run() cov.stop() cov.save() """) # run -a combines with an existing data file before saving. self.cmd_executes("run -a foo.py", """\ cov = Coverage() + runner = PyRunner(['foo.py'], as_module=False) + runner.prepare() cov.load() cov.start() - run_python_file('foo.py', ['foo.py']) - cov.stop() - cov.save() - """) - # run -a doesn't combine anything if the data file doesn't exist. - self.cmd_executes("run -a foo.py", """\ - cov = Coverage() - cov.load() - cov.start() - run_python_file('foo.py', ['foo.py']) + runner.run() cov.stop() cov.save() """) # --timid sets a flag, and program arguments get passed through. self.cmd_executes("run --timid foo.py abc 123", """\ cov = Coverage(timid=True) + runner = PyRunner(['foo.py', 'abc', '123'], as_module=False) + runner.prepare() cov.start() - run_python_file('foo.py', ['foo.py', 'abc', '123']) + runner.run() cov.stop() cov.save() """) # -L sets a flag, and flags for the program don't confuse us. self.cmd_executes("run -p -L foo.py -a -b", """\ cov = Coverage(cover_pylib=True, data_suffix=True) + runner = PyRunner(['foo.py', '-a', '-b'], as_module=False) + runner.prepare() cov.start() - run_python_file('foo.py', ['foo.py', '-a', '-b']) + runner.run() cov.stop() cov.save() """) self.cmd_executes("run --branch foo.py", """\ cov = Coverage(branch=True) + runner = PyRunner(['foo.py'], as_module=False) + runner.prepare() cov.start() - run_python_file('foo.py', ['foo.py']) + runner.run() cov.stop() cov.save() """) self.cmd_executes("run --rcfile=myrc.rc foo.py", """\ cov = Coverage(config_file="myrc.rc") + runner = PyRunner(['foo.py'], as_module=False) + runner.prepare() cov.start() - run_python_file('foo.py', ['foo.py']) + runner.run() cov.stop() cov.save() """) self.cmd_executes("run --include=pre1,pre2 foo.py", """\ cov = Coverage(include=["pre1", "pre2"]) + runner = PyRunner(['foo.py'], as_module=False) + runner.prepare() cov.start() - run_python_file('foo.py', ['foo.py']) + runner.run() cov.stop() cov.save() """) self.cmd_executes("run --omit=opre1,opre2 foo.py", """\ cov = Coverage(omit=["opre1", "opre2"]) + runner = PyRunner(['foo.py'], as_module=False) + runner.prepare() cov.start() - run_python_file('foo.py', ['foo.py']) + runner.run() cov.stop() cov.save() """) self.cmd_executes("run --include=pre1,pre2 --omit=opre1,opre2 foo.py", """\ cov = Coverage(include=["pre1", "pre2"], omit=["opre1", "opre2"]) + runner = PyRunner(['foo.py'], as_module=False) + runner.prepare() cov.start() - run_python_file('foo.py', ['foo.py']) + runner.run() cov.stop() cov.save() """) self.cmd_executes("run --source=quux,hi.there,/home/bar foo.py", """\ cov = Coverage(source=["quux", "hi.there", "/home/bar"]) + runner = PyRunner(['foo.py'], as_module=False) + runner.prepare() cov.start() - run_python_file('foo.py', ['foo.py']) + runner.run() cov.stop() cov.save() """) self.cmd_executes("run --concurrency=gevent foo.py", """\ cov = Coverage(concurrency='gevent') + runner = PyRunner(['foo.py'], as_module=False) + runner.prepare() cov.start() - run_python_file('foo.py', ['foo.py']) + runner.run() cov.stop() cov.save() """) self.cmd_executes("run --concurrency=multiprocessing foo.py", """\ cov = Coverage(concurrency='multiprocessing') + runner = PyRunner(['foo.py'], as_module=False) + runner.prepare() cov.start() - run_python_file('foo.py', ['foo.py']) + runner.run() cov.stop() cov.save() """) @@ -497,15 +512,19 @@ class CmdLineTest(BaseCmdLineTest): def test_run_debug(self): self.cmd_executes("run --debug=opt1 foo.py", """\ cov = Coverage(debug=["opt1"]) + runner = PyRunner(['foo.py'], as_module=False) + runner.prepare() cov.start() - run_python_file('foo.py', ['foo.py']) + runner.run() cov.stop() cov.save() """) self.cmd_executes("run --debug=opt1,opt2 foo.py", """\ cov = Coverage(debug=["opt1","opt2"]) + runner = PyRunner(['foo.py'], as_module=False) + runner.prepare() cov.start() - run_python_file('foo.py', ['foo.py']) + runner.run() cov.stop() cov.save() """) @@ -513,22 +532,28 @@ class CmdLineTest(BaseCmdLineTest): def test_run_module(self): self.cmd_executes("run -m mymodule", """\ cov = Coverage() + runner = PyRunner(['mymodule'], as_module=True) + runner.prepare() cov.start() - run_python_module('mymodule', ['mymodule']) + runner.run() cov.stop() cov.save() """) self.cmd_executes("run -m mymodule -qq arg1 arg2", """\ cov = Coverage() + runner = PyRunner(['mymodule', '-qq', 'arg1', 'arg2'], as_module=True) + runner.prepare() cov.start() - run_python_module('mymodule', ['mymodule', '-qq', 'arg1', 'arg2']) + runner.run() cov.stop() cov.save() """) self.cmd_executes("run --branch -m mymodule", """\ cov = Coverage(branch=True) + runner = PyRunner(['mymodule'], as_module=True) + runner.prepare() cov.start() - run_python_module('mymodule', ['mymodule']) + runner.run() cov.stop() cov.save() """) @@ -542,8 +567,10 @@ class CmdLineTest(BaseCmdLineTest): options = {"run:command_line": "myprog.py a 123 'a quoted thing' xyz"} self.cmd_executes("run", """\ cov = Coverage() + runner = PyRunner(['myprog.py', 'a', '123', 'a quoted thing', 'xyz'], as_module=False) + runner.prepare() cov.start() - run_python_file('myprog.py', ['myprog.py', 'a', '123', 'a quoted thing', 'xyz']) + runner.run() cov.stop() cov.save() """, @@ -553,8 +580,10 @@ class CmdLineTest(BaseCmdLineTest): def test_run_module_from_config(self): self.cmd_executes("run", """\ cov = Coverage() + runner = PyRunner(['mymodule', 'thing1', 'thing2'], as_module=True) + runner.prepare() cov.start() - run_python_module('mymodule', ['mymodule', 'thing1', 'thing2']) + runner.run() cov.stop() cov.save() """, diff --git a/tests/test_execfile.py b/tests/test_execfile.py index cb835c2a..ced4c28f 100644 --- a/tests/test_execfile.py +++ b/tests/test_execfile.py @@ -23,7 +23,7 @@ class RunFileTest(CoverageTest): """Test cases for `run_python_file`.""" def test_run_python_file(self): - run_python_file(TRY_EXECFILE, [TRY_EXECFILE, "arg1", "arg2"]) + run_python_file([TRY_EXECFILE, "arg1", "arg2"]) mod_globs = json.loads(self.stdout()) # The file should think it is __main__ @@ -56,7 +56,7 @@ class RunFileTest(CoverageTest): """) self.assertEqual(os.listdir("."), ["xxx"]) - run_python_file("xxx", ["xxx"]) + run_python_file(["xxx"]) self.assertEqual(os.listdir("."), ["xxx"]) def test_universal_newlines(self): @@ -65,7 +65,7 @@ class RunFileTest(CoverageTest): for nl in ('\n', '\r\n', '\r'): with open('nl.py', 'wb') as fpy: fpy.write(nl.join(pylines).encode('utf-8')) - run_python_file('nl.py', ['nl.py']) + run_python_file(['nl.py']) self.assertEqual(self.stdout(), "Hello, world!\n"*3) def test_missing_final_newline(self): @@ -78,24 +78,24 @@ class RunFileTest(CoverageTest): with open("abrupt.py") as f: abrupt = f.read() self.assertEqual(abrupt[-1], '#') - run_python_file("abrupt.py", ["abrupt.py"]) + run_python_file(["abrupt.py"]) self.assertEqual(self.stdout(), "a is 1\n") def test_no_such_file(self): with self.assertRaises(NoSource): - run_python_file("xyzzy.py", []) + run_python_file(["xyzzy.py"]) def test_directory_with_main(self): self.make_file("with_main/__main__.py", """\ print("I am __main__") """) - run_python_file("with_main", ["with_main"]) + run_python_file(["with_main"]) self.assertEqual(self.stdout(), "I am __main__\n") def test_directory_without_main(self): self.make_file("without_main/__init__.py", "") with self.assertRaisesRegex(NoSource, "Can't find '__main__' module in 'without_main'"): - run_python_file("without_main", ["without_main"]) + run_python_file(["without_main"]) class RunPycFileTest(CoverageTest): @@ -123,7 +123,7 @@ class RunPycFileTest(CoverageTest): def test_running_pyc(self): pycfile = self.make_pyc() - run_python_file(pycfile, [pycfile]) + run_python_file([pycfile]) self.assertEqual(self.stdout(), "I am here!\n") def test_running_pyo(self): @@ -131,7 +131,7 @@ class RunPycFileTest(CoverageTest): pyofile = re.sub(r"[.]pyc$", ".pyo", pycfile) self.assertNotEqual(pycfile, pyofile) os.rename(pycfile, pyofile) - run_python_file(pyofile, [pyofile]) + run_python_file([pyofile]) self.assertEqual(self.stdout(), "I am here!\n") def test_running_pyc_from_wrong_python(self): @@ -143,11 +143,11 @@ class RunPycFileTest(CoverageTest): fpyc.write(binary_bytes([0x2a, 0xeb, 0x0d, 0x0a])) with self.assertRaisesRegex(NoCode, "Bad magic number in .pyc file"): - run_python_file(pycfile, [pycfile]) + run_python_file([pycfile]) def test_no_such_pyc_file(self): with self.assertRaisesRegex(NoCode, "No file to run: 'xyzzy.pyc'"): - run_python_file("xyzzy.pyc", []) + run_python_file(["xyzzy.pyc"]) def test_running_py_from_binary(self): # Use make_file to get the bookkeeping. Ideally, it would @@ -166,7 +166,7 @@ class RunPycFileTest(CoverageTest): r")" ) with self.assertRaisesRegex(Exception, msg): - run_python_file(bf, [bf]) + run_python_file([bf]) class RunModuleTest(UsingModulesMixin, CoverageTest): @@ -175,43 +175,43 @@ class RunModuleTest(UsingModulesMixin, CoverageTest): run_in_temp_dir = False def test_runmod1(self): - run_python_module("runmod1", ["runmod1", "hello"]) + run_python_module(["runmod1", "hello"]) self.assertEqual(self.stderr(), "") self.assertEqual(self.stdout(), "runmod1: passed hello\n") def test_runmod2(self): - run_python_module("pkg1.runmod2", ["runmod2", "hello"]) + run_python_module(["pkg1.runmod2", "hello"]) self.assertEqual(self.stderr(), "") self.assertEqual(self.stdout(), "pkg1.__init__: pkg1\nrunmod2: passed hello\n") def test_runmod3(self): - run_python_module("pkg1.sub.runmod3", ["runmod3", "hello"]) + run_python_module(["pkg1.sub.runmod3", "hello"]) self.assertEqual(self.stderr(), "") self.assertEqual(self.stdout(), "pkg1.__init__: pkg1\nrunmod3: passed hello\n") def test_pkg1_main(self): - run_python_module("pkg1", ["pkg1", "hello"]) + run_python_module(["pkg1", "hello"]) self.assertEqual(self.stderr(), "") self.assertEqual(self.stdout(), "pkg1.__init__: pkg1\npkg1.__main__: passed hello\n") def test_pkg1_sub_main(self): - run_python_module("pkg1.sub", ["pkg1.sub", "hello"]) + run_python_module(["pkg1.sub", "hello"]) self.assertEqual(self.stderr(), "") self.assertEqual(self.stdout(), "pkg1.__init__: pkg1\npkg1.sub.__main__: passed hello\n") def test_pkg1_init(self): - run_python_module("pkg1.__init__", ["pkg1.__init__", "wut?"]) + run_python_module(["pkg1.__init__", "wut?"]) self.assertEqual(self.stderr(), "") self.assertEqual(self.stdout(), "pkg1.__init__: pkg1\npkg1.__init__: __main__\n") def test_no_such_module(self): with self.assertRaises(NoSource): - run_python_module("i_dont_exist", []) + run_python_module(["i_dont_exist"]) with self.assertRaises(NoSource): - run_python_module("i.dont_exist", []) + run_python_module(["i.dont_exist"]) with self.assertRaises(NoSource): - run_python_module("i.dont.exist", []) + run_python_module(["i.dont.exist"]) def test_no_main(self): with self.assertRaises(NoSource): - run_python_module("pkg2", ["pkg2", "hi"]) + run_python_module(["pkg2", "hi"]) diff --git a/tests/test_process.py b/tests/test_process.py index 9f7a16f5..bba58c54 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -861,6 +861,13 @@ class EnvironmentTest(CoverageTest): actual = self.run_command("coverage run run_me.py") self.assert_tryexecfile_output(expected, actual) + def test_coverage_run_far_away_is_like_python(self): + with open(TRY_EXECFILE) as f: + self.make_file("sub/overthere/prog.py", f.read()) + expected = self.run_command("python sub/overthere/prog.py") + actual = self.run_command("coverage run sub/overthere/prog.py") + self.assert_tryexecfile_output(expected, actual) + def test_coverage_run_dashm_is_like_python_dashm(self): # These -m commands assume the coverage tree is on the path. expected = self.run_command("python -m process_test.try_execfile") @@ -904,6 +911,17 @@ class EnvironmentTest(CoverageTest): def test_coverage_run_dashm_superset_of_doubledashsource(self): """Edge case: --source foo -m foo.bar""" + # Ugh: without this config file, we'll get a warning about + # Coverage.py warning: Module process_test was previously imported, + # but not measured (module-not-measured) + # + # This is because process_test/__init__.py is imported while looking + # for process_test.try_execfile. That import happens while setting + # sys.path before start() is called. + self.make_file(".coveragerc", """\ + [run] + disable_warnings = module-not-measured + """) # These -m commands assume the coverage tree is on the path. expected = self.run_command("python -m process_test.try_execfile") actual = self.run_command( |