summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coverage/data.py5
-rw-r--r--coverage/files.py14
-rw-r--r--test/coveragetest.py6
-rw-r--r--test/modules/pkg1/p1c.py3
-rw-r--r--test/modules/pkg1/sub/__init__.py0
-rw-r--r--test/modules/pkg1/sub/ps1a.py3
-rw-r--r--test/test_api.py1
-rw-r--r--test/test_files.py24
8 files changed, 55 insertions, 1 deletions
diff --git a/coverage/data.py b/coverage/data.py
index fe076bef..6d49f710 100644
--- a/coverage/data.py
+++ b/coverage/data.py
@@ -52,7 +52,10 @@ class CoverageData(object):
# A map from canonical Python source file name to a dictionary with an
# entry for each pair of line numbers forming an arc:
#
- # { filename: { (l1,l2): None, ... }, ...}
+ # {
+ # 'filename1.py': { (12,14): None, (47,48): None, ... },
+ # ...
+ # }
#
self.arcs = {}
diff --git a/coverage/files.py b/coverage/files.py
index 741b456f..9a8ac564 100644
--- a/coverage/files.py
+++ b/coverage/files.py
@@ -102,6 +102,7 @@ class TreeMatcher(object):
return True
return False
+
class FnmatchMatcher(object):
"""A matcher for files by filename pattern."""
def __init__(self, pats):
@@ -116,3 +117,16 @@ class FnmatchMatcher(object):
if fnmatch.fnmatch(fpath, pat):
return True
return False
+
+
+def find_python_files(dirname):
+ """Yield all of the importable Python files in `dirname`, recursively."""
+ for dirpath, dirnames, filenames in os.walk(dirname, topdown=True):
+ if '__init__.py' not in filenames:
+ # If a directory doesn't have __init__.py, then it isn't
+ # importable and neither are its files
+ del dirnames[:]
+ continue
+ for filename in filenames:
+ if fnmatch.fnmatch(filename, "*.py"):
+ yield os.path.join(dirpath, filename)
diff --git a/test/coveragetest.py b/test/coveragetest.py
index bdee9185..53f0ef0b 100644
--- a/test/coveragetest.py
+++ b/test/coveragetest.py
@@ -327,6 +327,12 @@ class CoverageTest(TestCase):
fname = os.path.join(*fparts)
return os.path.normcase(os.path.abspath(os.path.realpath(fname)))
+ def assert_same_files(self, flist1, flist2):
+ """Assert that `flist1` and `flist2` are the same set of file names."""
+ flist1_nice = [self.nice_file(f) for f in flist1]
+ flist2_nice = [self.nice_file(f) for f in flist2]
+ self.assertSameElements(flist1_nice, flist2_nice)
+
def command_line(self, args, ret=OK, _covpkg=None):
"""Run `args` through the command line.
diff --git a/test/modules/pkg1/p1c.py b/test/modules/pkg1/p1c.py
new file mode 100644
index 00000000..a9aeef04
--- /dev/null
+++ b/test/modules/pkg1/p1c.py
@@ -0,0 +1,3 @@
+a = 1
+b = 2
+c = 3
diff --git a/test/modules/pkg1/sub/__init__.py b/test/modules/pkg1/sub/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/modules/pkg1/sub/__init__.py
diff --git a/test/modules/pkg1/sub/ps1a.py b/test/modules/pkg1/sub/ps1a.py
new file mode 100644
index 00000000..4b6a15cc
--- /dev/null
+++ b/test/modules/pkg1/sub/ps1a.py
@@ -0,0 +1,3 @@
+d = 1
+e = 2
+f = 3
diff --git a/test/test_api.py b/test/test_api.py
index f64ad44d..aa6f42cd 100644
--- a/test/test_api.py
+++ b/test/test_api.py
@@ -324,6 +324,7 @@ class SourceOmitIncludeTest(CoverageTest):
self.assertEqual(lines['p1b.py'], 3)
self.assertEqual(lines['p2a.py'], 3)
self.assertEqual(lines['p2b.py'], 3)
+ self.assert_('p1c.py' not in lines)
def test_source_package(self):
lines = self.coverage_usepkgs_summary(source=["pkg1"])
diff --git a/test/test_files.py b/test/test_files.py
index db835e5e..ecb2a750 100644
--- a/test/test_files.py
+++ b/test/test_files.py
@@ -3,6 +3,7 @@
import os, sys
from coverage.files import FileLocator, TreeMatcher, FnmatchMatcher
+from coverage.files import find_python_files
sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
from coveragetest import CoverageTest
@@ -34,6 +35,10 @@ class FileLocatorTest(CoverageTest):
self.assertEqual(fl.relative_filename(a1), "file1.py")
self.assertEqual(fl.relative_filename(a2), a2)
+
+class MatcherTest(CoverageTest):
+ """Tests of file matchers."""
+
def test_tree_matcher(self):
file1 = self.make_file("sub/file1.py")
file2 = self.make_file("sub/file2.c")
@@ -64,3 +69,22 @@ class FileLocatorTest(CoverageTest):
self.assertTrue(fnm.match(fl.canonical_filename(file3)))
self.assertTrue(fnm.match(fl.canonical_filename(file4)))
self.assertFalse(fnm.match(fl.canonical_filename(file5)))
+
+
+class FindPythonFilesTest(CoverageTest):
+ """Tests of `find_python_files`."""
+
+ def test_find_python_files(self):
+ self.make_file("sub/a.py")
+ self.make_file("sub/b.py")
+ self.make_file("sub/__init__.py")
+ self.make_file("sub/x.c") # nope: not .py
+ self.make_file("sub/ssub/__init__.py")
+ self.make_file("sub/ssub/s.py")
+ self.make_file("sub/lab/exp.py") # nope: no __init__.py
+ py_files = set(find_python_files("sub"))
+ self.assert_same_files(py_files, [
+ "sub/__init__.py", "sub/a.py", "sub/b.py",
+ "sub/ssub/__init__.py", "sub/ssub/s.py",
+ ])
+