diff options
-rw-r--r-- | CHANGES.txt | 10 | ||||
-rw-r--r-- | coverage/cmdline.py | 13 | ||||
-rw-r--r-- | coverage/control.py | 6 | ||||
-rw-r--r-- | coverage/execfile.py | 9 | ||||
-rw-r--r-- | tests/test_api.py | 12 | ||||
-rw-r--r-- | tests/test_process.py | 43 |
6 files changed, 68 insertions, 25 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 82b1b84f..48876c18 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -7,12 +7,22 @@ Change history for Coverage.py - Improved the branch coverage mechanism, fixing `issue 175`_. +- Running code with ``coverage run -m`` now behaves more like Python does, + setting sys.path properly, which fixes `issue 207`_ and `issue 242`_. + +- Omitting files within a tree specified with the ``source`` option would + cause them to be incorrectly marked as unexecuted, as described in + `issue 218`_. This is now fixed. + - When running a threaded program under the Python tracer, coverage would issue a spurious warning about the trace function changing: "Trace function changed, measurement is likely wrong: None." This is now fixed. .. _issue 164: https://bitbucket.org/ned/coveragepy/issue/164/trace-function-changed-warning-when-using .. _issue 175: https://bitbucket.org/ned/coveragepy/issue/175/branch-coverage-gets-confused-in-certain +.. _issue 207: https://bitbucket.org/ned/coveragepy/issue/207/run-m-cannot-find-module-or-package-in +.. _issue 242: https://bitbucket.org/ned/coveragepy/issue/242/running-a-two-level-package-doesnt-work +.. _issue 218: https://bitbucket.org/ned/coveragepy/issue/218/run-command-does-not-respect-the-omit-flag Version 3.6 --- 5 January 2013 diff --git a/coverage/cmdline.py b/coverage/cmdline.py index cb1d7a3e..ac803109 100644 --- a/coverage/cmdline.py +++ b/coverage/cmdline.py @@ -1,6 +1,6 @@ """Command-line support for Coverage.""" -import optparse, sys, traceback +import optparse, os, sys, traceback from coverage.backward import sorted # pylint: disable=W0622 from coverage.execfile import run_python_file, run_python_module @@ -549,15 +549,21 @@ class CoverageScript(object): def do_execute(self, options, args): """Implementation of 'coverage run'.""" + # Set the first path element properly. + old_path0 = sys.path[0] + # Run the script. self.coverage.start() code_ran = True try: try: if options.module: + sys.path[0] = '' self.run_python_module(args[0], args) else: - self.run_python_file(args[0], args) + filename = args[0] + sys.path[0] = os.path.abspath(os.path.dirname(filename)) + self.run_python_file(filename, args) except NoSource: code_ran = False raise @@ -566,6 +572,9 @@ class CoverageScript(object): if code_ran: self.coverage.save() + # Restore the old path + sys.path[0] = old_path0 + def do_debug(self, args): """Implementation of 'coverage debug'.""" diff --git a/coverage/control.py b/coverage/control.py index afb61370..09bd75fc 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -499,6 +499,12 @@ class coverage(object): for src in self.source: for py_file in find_python_files(src): py_file = self.file_locator.canonical_filename(py_file) + + if self.omit_match and self.omit_match.match(py_file): + # Turns out this file was omitted, so don't pull it + # back in as unexecuted. + continue + self.data.touch_file(py_file) self._measured = False diff --git a/coverage/execfile.py b/coverage/execfile.py index 587c2d3c..fbb49b2a 100644 --- a/coverage/execfile.py +++ b/coverage/execfile.py @@ -65,6 +65,7 @@ def run_python_module(modulename, args): openfile.close() # Finally, hand the file off to run_python_file for execution. + pathname = os.path.abspath(pathname) args[0] = pathname run_python_file(pathname, args, package=packagename) @@ -87,14 +88,9 @@ def run_python_file(filename, args, package=None): main_mod.__package__ = package main_mod.__builtins__ = BUILTINS - # Set sys.argv and the first path element properly. + # Set sys.argv properly. old_argv = sys.argv - old_path0 = sys.path[0] sys.argv = args - if package: - sys.path[0] = '' - else: - sys.path[0] = os.path.abspath(os.path.dirname(filename)) try: # Open the source file. @@ -135,4 +131,3 @@ def run_python_file(filename, args, package=None): # Restore the old argv and path sys.argv = old_argv - sys.path[0] = old_path0 diff --git a/tests/test_api.py b/tests/test_api.py index 300a2374..097947d2 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -430,7 +430,7 @@ class OmitIncludeTestsMixin(UsingModulesMixin): self.filenames_not_in(result, "p1a p1c p2a othera osa") def test_omit_and_include(self): - result = self.coverage_usepkgs( include=["*/p1*"], omit=["*/p1a.py"]) + result = self.coverage_usepkgs(include=["*/p1*"], omit=["*/p1a.py"]) self.filenames_in(result, "p1b") self.filenames_not_in(result, "p1a p1c p2a p2b") @@ -467,6 +467,16 @@ class SourceOmitIncludeTest(OmitIncludeTestsMixin, CoverageTest): self.filenames_in(lines, "p1b") self.filenames_not_in(lines, "p1a p1c p2a p2b othera otherb osa osb") + def test_source_package_part_omitted(self): + # https://bitbucket.org/ned/coveragepy/issue/218 + # Used to be if you omitted something executed and inside the source, + # then after it was executed but not recorded, it would be found in + # the search for unexecuted files, and given a score of 0%. + lines = self.coverage_usepkgs(source=["pkg1"], omit=["pkg1/p1b.py"]) + self.filenames_in(lines, "p1a") + self.filenames_not_in(lines, "p1b") + self.assertEqual(lines['p1c'], 0) + class ReportIncludeOmitTest(OmitIncludeTestsMixin, CoverageTest): """Tests of the report include/omit functionality.""" diff --git a/tests/test_process.py b/tests/test_process.py index 8e31bd18..8554eb54 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -320,25 +320,38 @@ class ProcessTest(CoverageTest): def test_coverage_run_is_like_python(self): tryfile = os.path.join(here, "try_execfile.py") self.make_file("run_me.py", open(tryfile).read()) - out = self.run_command("coverage run run_me.py") - out2 = self.run_command("python run_me.py") - self.assertMultiLineEqual(out, out2) + out_cov = self.run_command("coverage run run_me.py") + out_py = self.run_command("python run_me.py") + self.assertMultiLineEqual(out_cov, out_py) - if sys.version_info >= (2, 6): # Doesn't work in 2.5, and I don't care! + if sys.version_info >= (2, 6): + # Doesn't work in 2.5, and I don't care! For some reason, python -m + # in 2.5 has __builtins__ as a dictionary instead of a module? def test_coverage_run_dashm_is_like_python_dashm(self): # These -m commands assume the coverage tree is on the path. - out = self.run_command("coverage run -m tests.try_execfile") - out2 = self.run_command("python -m tests.try_execfile") - self.assertMultiLineEqual(out, out2) - - if 0: # Expected failure - # For https://bitbucket.org/ned/coveragepy/issue/207 + out_cov = self.run_command("coverage run -m tests.try_execfile") + out_py = self.run_command("python -m tests.try_execfile") + self.assertMultiLineEqual(out_cov, out_py) + + def test_coverage_run_dashm_is_like_python_dashm_off_path(self): + # https://bitbucket.org/ned/coveragepy/issue/242 + tryfile = os.path.join(here, "try_execfile.py") + self.make_file("sub/__init__.py", "") + self.make_file("sub/run_me.py", open(tryfile).read()) + out_cov = self.run_command("coverage run -m sub.run_me") + out_py = self.run_command("python -m sub.run_me") + self.assertMultiLineEqual(out_cov, out_py) + + if sys.version_info >= (2, 7): + # Coverage isn't bug-for-bug compatible in the behavior of -m for + # Pythons < 2.7 def test_coverage_run_dashm_is_like_python_dashm_with__main__207(self): - self.make_file("package/__init__.py") # empty - self.make_file("package/__main__.py", "#\n") # empty - out = self.run_command("coverage run -m package") - out2 = self.run_command("python -m package") - self.assertMultiLineEqual(out, out2) + # https://bitbucket.org/ned/coveragepy/issue/207 + self.make_file("package/__init__.py", "print('init')") + self.make_file("package/__main__.py", "print('main')") + out_cov = self.run_command("coverage run -m package") + out_py = self.run_command("python -m package") + self.assertMultiLineEqual(out_cov, out_py) if hasattr(os, 'fork'): def test_fork(self): |