summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2011-03-21 21:40:07 -0400
committerNed Batchelder <ned@nedbatchelder.com>2011-03-21 21:40:07 -0400
commit43167860f5d36940bd56b0a55d4694ab27fff182 (patch)
tree853903565be12621da594b0be32c8c4eb4877592
parent27028b408fa4f8ac0ba2da3a3031935ed40fe699 (diff)
downloadpython-coveragepy-43167860f5d36940bd56b0a55d4694ab27fff182.tar.gz
--omit and --include now interpret their values more usefully. Fixes #121.
-rw-r--r--CHANGES.txt6
-rw-r--r--coverage/control.py26
-rw-r--r--doc/source.rst5
-rw-r--r--test/modules/usepkgs.py2
-rw-r--r--test/othermods/__init__.py0
-rw-r--r--test/othermods/othera.py2
-rw-r--r--test/othermods/otherb.py2
-rw-r--r--test/othermods/sub/__init__.py0
-rw-r--r--test/othermods/sub/osa.py2
-rw-r--r--test/othermods/sub/osb.py2
-rw-r--r--test/test_api.py103
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"
+ )