diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2011-03-21 21:40:07 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2011-03-21 21:40:07 -0400 |
commit | 43167860f5d36940bd56b0a55d4694ab27fff182 (patch) | |
tree | 853903565be12621da594b0be32c8c4eb4877592 | |
parent | 27028b408fa4f8ac0ba2da3a3031935ed40fe699 (diff) | |
download | python-coveragepy-43167860f5d36940bd56b0a55d4694ab27fff182.tar.gz |
--omit and --include now interpret their values more usefully. Fixes #121.
-rw-r--r-- | CHANGES.txt | 6 | ||||
-rw-r--r-- | coverage/control.py | 26 | ||||
-rw-r--r-- | doc/source.rst | 5 | ||||
-rw-r--r-- | test/modules/usepkgs.py | 2 | ||||
-rw-r--r-- | test/othermods/__init__.py | 0 | ||||
-rw-r--r-- | test/othermods/othera.py | 2 | ||||
-rw-r--r-- | test/othermods/otherb.py | 2 | ||||
-rw-r--r-- | test/othermods/sub/__init__.py | 0 | ||||
-rw-r--r-- | test/othermods/sub/osa.py | 2 | ||||
-rw-r--r-- | test/othermods/sub/osb.py | 2 | ||||
-rw-r--r-- | test/test_api.py | 103 |
11 files changed, 114 insertions, 36 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 768b582..cd07ce7 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -11,6 +11,11 @@ Version 3.5 On a file page, ``r``, ``m``, ``x``, and ``p`` toggle the run, missing, excluded, and partial line markings. +- The ``--omit`` and ``--include`` switches now interpret their values more + usefully. If the value starts with a wildcard character, it is used as-is. + If it does not, it is interpreted relative to the current directory. + Closes `issue 121`. + - Modules can now be run directly using ``coverage run -m modulename``, to mirror Python's ``-m`` flag. Closes `issue 95_`, thanks, Brandon Rhodes. @@ -37,6 +42,7 @@ Version 3.5 .. _issue 95: https://bitbucket.org/ned/coveragepy/issue/95/run-subcommand-should-take-a-module-name .. _issue 104: https://bitbucket.org/ned/coveragepy/issue/104/explicitly-close-files .. _issue 107: https://bitbucket.org/ned/coveragepy/issue/107/codeparser-not-opening-source-files-with +.. _issue 121: https://bitbucket.org/ned/coveragepy/issue/121/filename-patterns-are-applied-stupidly Version 3.4 --- 19 September 2010 diff --git a/coverage/control.py b/coverage/control.py index 3369d04..584f093 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -118,8 +118,8 @@ class coverage(object): else: self.source_pkgs.append(src) - self.omit = self._abs_files(self.config.omit) - self.include = self._abs_files(self.config.include) + self.omit = self._prep_patterns(self.config.omit) + self.include = self._prep_patterns(self.config.include) self.collector = Collector( self._should_trace, timid=self.config.timid, @@ -280,10 +280,24 @@ class coverage(object): self._warnings.append(msg) sys.stderr.write("Coverage.py warning: %s\n" % msg) - def _abs_files(self, files): - """Return a list of absolute file names for the names in `files`.""" - files = files or [] - return [self.file_locator.abs_file(f) for f in files] + def _prep_patterns(self, patterns): + """Prepare the file patterns for use in a `FnmatchMatcher`. + + If a pattern starts with a wildcard, it is used as a pattern + as-is. If it does not start with a wildcard, then it is made + absolute with the current directory. + + If `patterns` is None, an empty list is returned. + + """ + patterns = patterns or [] + prepped = [] + for p in patterns or []: + if p.startswith("*") or p.startswith("?"): + prepped.append(p) + else: + prepped.append(self.file_locator.abs_file(p)) + return prepped def _check_for_packages(self): """Update the source_match matcher with latest imported packages.""" diff --git a/doc/source.rst b/doc/source.rst index 3f0a156..8700bcb 100644 --- a/doc/source.rst +++ b/doc/source.rst @@ -43,9 +43,8 @@ the set. The ``include`` and ``omit`` filename patterns follow typical shell syntax: ``*`` matches any number of characters and ``?`` matches a single character. -The full semantics are specified in the `fnmatch docs`_. - -.. _fnmatch docs: http://docs.python.org/library/fnmatch.html +Patterns that start with a wildcard character are used as-is, other patterns +are interpreted relative to the current directory. The ``source``, ``include``, and ``omit`` values all work together to determine the source that will be measured. diff --git a/test/modules/usepkgs.py b/test/modules/usepkgs.py index 208e3f3..93c7d90 100644 --- a/test/modules/usepkgs.py +++ b/test/modules/usepkgs.py @@ -1,2 +1,4 @@ import pkg1.p1a, pkg1.p1b import pkg2.p2a, pkg2.p2b +import othermods.othera, othermods.otherb +import othermods.sub.osa, othermods.sub.osb diff --git a/test/othermods/__init__.py b/test/othermods/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/othermods/__init__.py diff --git a/test/othermods/othera.py b/test/othermods/othera.py new file mode 100644 index 0000000..7889692 --- /dev/null +++ b/test/othermods/othera.py @@ -0,0 +1,2 @@ +o = 1 +p = 2 diff --git a/test/othermods/otherb.py b/test/othermods/otherb.py new file mode 100644 index 0000000..2bd8a44 --- /dev/null +++ b/test/othermods/otherb.py @@ -0,0 +1,2 @@ +q = 3 +r = 4 diff --git a/test/othermods/sub/__init__.py b/test/othermods/sub/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/othermods/sub/__init__.py diff --git a/test/othermods/sub/osa.py b/test/othermods/sub/osa.py new file mode 100644 index 0000000..0139d28 --- /dev/null +++ b/test/othermods/sub/osa.py @@ -0,0 +1,2 @@ +s = 5 +t = 6 diff --git a/test/othermods/sub/osb.py b/test/othermods/sub/osb.py new file mode 100644 index 0000000..b024b14 --- /dev/null +++ b/test/othermods/sub/osb.py @@ -0,0 +1,2 @@ +u = 7 +v = 8 diff --git a/test/test_api.py b/test/test_api.py index aee0734..ccd7a29 100644 --- a/test/test_api.py +++ b/test/test_api.py @@ -304,7 +304,14 @@ class SourceOmitIncludeTest(CoverageTest): def setUp(self): super(SourceOmitIncludeTest, self).setUp() # Parent class saves and restores sys.path, we can just modify it. - sys.path.append(self.nice_file(os.path.dirname(__file__), 'modules')) + #sys.path.append(self.nice_file(os.path.dirname(__file__), 'modules')) + self.old_dir = os.getcwd() + os.chdir(self.nice_file(os.path.dirname(__file__), 'modules')) + sys.path.append(".") + + def tearDown(self): + os.chdir(self.old_dir) + super(SourceOmitIncludeTest, self).tearDown() def coverage_usepkgs_summary(self, **kwargs): """Run coverage on usepkgs and return the line summary. @@ -318,52 +325,94 @@ class SourceOmitIncludeTest(CoverageTest): cov.stop() return cov.data.summary() + def filenames_in_summary(self, summary, filenames): + """Assert the `filenames` are in the keys of `summary`.""" + for filename in filenames.split(): + self.assert_(filename in summary, + "%s should be in %r" % (filename, summary) + ) + + def filenames_not_in_summary(self, summary, filenames): + """Assert the `filenames` are not in the keys of `summary`.""" + for filename in filenames.split(): + self.assert_(filename not in summary, + "%s should not be in %r" % (filename, summary) + ) + def test_nothing_specified(self): lines = self.coverage_usepkgs_summary() - self.assertEqual(lines['p1a.py'], 3) - self.assertEqual(lines['p1b.py'], 3) - self.assertEqual(lines['p2a.py'], 3) - self.assertEqual(lines['p2b.py'], 3) + self.filenames_in_summary(lines, + "p1a.py p1b.py p2a.py p2b.py othera.py otherb.py osa.py osb.py" + ) + self.filenames_not_in_summary(lines, + "p1c.py" + ) # Because there was no source= specified, we don't search for # unexecuted files. - self.assert_('p1c.py' not in lines) def test_source_package(self): lines = self.coverage_usepkgs_summary(source=["pkg1"]) - self.assertEqual(lines['p1a.py'], 3) - self.assertEqual(lines['p1b.py'], 3) - self.assert_('p2a.py' not in lines) - self.assert_('p2b.py' not in lines) + self.filenames_in_summary(lines, + "p1a.py p1b.py" + ) + self.filenames_not_in_summary(lines, + "p2a.py p2b.py othera.py otherb.py osa.py osb.py" + ) # Because source= was specified, we do search for unexecuted files. self.assertEqual(lines['p1c.py'], 0) def test_source_package_dotted(self): lines = self.coverage_usepkgs_summary(source=["pkg1.p1b"]) - self.assert_('p1a.py' not in lines) - self.assertEqual(lines['p1b.py'], 3) - self.assert_('p2a.py' not in lines) - self.assert_('p2b.py' not in lines) - self.assert_('p1c.py' not in lines) + self.filenames_in_summary(lines, + "p1b.py" + ) + self.filenames_not_in_summary(lines, + "p1a.py p1c.py p2a.py p2b.py othera.py otherb.py osa.py osb.py" + ) def test_include(self): lines = self.coverage_usepkgs_summary(include=["*/p1a.py"]) - self.assertEqual(lines['p1a.py'], 3) - self.assert_('p1b.py' not in lines) - self.assert_('p2a.py' not in lines) - self.assert_('p2b.py' not in lines) + self.filenames_in_summary(lines, + "p1a.py" + ) + self.filenames_not_in_summary(lines, + "p1b.py p1c.py p2a.py p2b.py othera.py otherb.py osa.py osb.py" + ) + + def test_include_2(self): + lines = self.coverage_usepkgs_summary(include=["*a.py"]) + self.filenames_in_summary(lines, + "p1a.py p2a.py othera.py osa.py" + ) + self.filenames_not_in_summary(lines, + "p1b.py p1c.py p2b.py otherb.py osb.py" + ) def test_omit(self): lines = self.coverage_usepkgs_summary(omit=["*/p1a.py"]) - self.assert_('p1a.py' not in lines) - self.assertEqual(lines['p1b.py'], 3) - self.assertEqual(lines['p2a.py'], 3) - self.assertEqual(lines['p2b.py'], 3) + self.filenames_in_summary(lines, + "p1b.py p2a.py p2b.py" + ) + self.filenames_not_in_summary(lines, + "p1a.py p1c.py" + ) + + def test_omit_2(self): + lines = self.coverage_usepkgs_summary(omit=["*a.py"]) + self.filenames_in_summary(lines, + "p1b.py p2b.py otherb.py osb.py" + ) + self.filenames_not_in_summary(lines, + "p1a.py p1c.py p2a.py othera.py osa.py" + ) def test_omit_and_include(self): lines = self.coverage_usepkgs_summary( include=["*/p1*"], omit=["*/p1a.py"] ) - self.assert_('p1a.py' not in lines) - self.assertEqual(lines['p1b.py'], 3) - self.assert_('p2a.py' not in lines) - self.assert_('p2b.py' not in lines) + self.filenames_in_summary(lines, + "p1b.py" + ) + self.filenames_not_in_summary(lines, + "p1a.py p1c.py p2a.py p2b.py" + ) |