summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS.txt1
-rw-r--r--CHANGES.txt5
-rw-r--r--coverage/config.py2
-rw-r--r--coverage/xmlreport.py2
-rw-r--r--tests/test_config.py2
-rw-r--r--tests/test_xml.py94
6 files changed, 88 insertions, 18 deletions
diff --git a/AUTHORS.txt b/AUTHORS.txt
index 5e7bb54..f2d561e 100644
--- a/AUTHORS.txt
+++ b/AUTHORS.txt
@@ -7,6 +7,7 @@ Marc Abramowitz
Chris Adams
Danny Allen
Geoff Bache
+Lex Berezhny
Julian Berman
Titus Brown
Brett Cannon
diff --git a/CHANGES.txt b/CHANGES.txt
index 7bd3bd6..4e801ff 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -14,6 +14,11 @@ Latest
regression, I apologize. This was reported in `issue 235`_, which is now
fixed.
+- A new configuration option for the XML report: ``[xml] package_depth``
+ controls which directories are identified as packages in the report.
+ Directories deeper than this depth are not reported as packages.
+ Thanks, Lex Berezhny.
+
- When looking for the source for a frame, check if the file exists. On
Windows, .pyw files are no longer recorded as .py files. Along the way, this
fixed `issue 290`_.
diff --git a/coverage/config.py b/coverage/config.py
index 326389c..7b14267 100644
--- a/coverage/config.py
+++ b/coverage/config.py
@@ -183,6 +183,7 @@ class CoverageConfig(object):
# Defaults for [xml]
self.xml_output = "coverage.xml"
+ self.xml_package_depth = 99
# Defaults for [paths]
self.paths = {}
@@ -283,6 +284,7 @@ class CoverageConfig(object):
# [xml]
('xml_output', 'xml:output'),
+ ('xml_package_depth', 'xml:package_depth', 'int'),
]
def _set_attr_from_config_option(self, cp, attr, where, type_=''):
diff --git a/coverage/xmlreport.py b/coverage/xmlreport.py
index 3510c5b..f7ad2b8 100644
--- a/coverage/xmlreport.py
+++ b/coverage/xmlreport.py
@@ -124,6 +124,8 @@ class XmlReporter(Reporter):
filename = cu.file_locator.relative_filename(cu.filename)
filename = filename.replace("\\", "/")
dirname = os.path.dirname(filename) or "."
+ parts = dirname.split("/")
+ dirname = "/".join(parts[:self.config.xml_package_depth])
package_name = dirname.replace("/", ".")
className = cu.name
diff --git a/tests/test_config.py b/tests/test_config.py
index 450c94f..366b4bc 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -233,6 +233,7 @@ class ConfigFileTest(CoverageTest):
title = Title & nums # nums!
[{section}xml]
output=mycov.xml
+ package_depth = 17
[{section}paths]
source =
@@ -294,6 +295,7 @@ class ConfigFileTest(CoverageTest):
self.assertEqual(cov.config.html_title, "Title & nums # nums!")
self.assertEqual(cov.config.xml_output, "mycov.xml")
+ self.assertEqual(cov.config.xml_package_depth, 17)
self.assertEqual(cov.config.paths, {
'source': ['.', '/home/ned/src/'],
diff --git a/tests/test_xml.py b/tests/test_xml.py
index 5309ebc..d7611eb 100644
--- a/tests/test_xml.py
+++ b/tests/test_xml.py
@@ -140,30 +140,88 @@ class XmlReportTest(XmlTestHelpers, CoverageTest):
class XmlPackageStructureTest(XmlTestHelpers, CoverageTest):
"""Tests about the package structure reported in the coverage.xml file."""
- def test_packages(self):
+ def package_and_class_tags(self, cov):
+ """Run an XML report on `cov`, and get the package and class tags."""
+ self.captured_stdout.truncate(0)
+ cov.xml_report(outfile="-")
+ packages_and_classes = re_lines(self.stdout(), r"<package |<class ")
+ scrubs = r' branch-rate="0"| complexity="0"| line-rate="[\d.]+"'
+ return clean("".join(packages_and_classes), scrubs)
+
+ def assert_package_and_class_tags(self, cov, result):
+ """Check the XML package and class tags from `cov` match `result`."""
+ self.assertMultiLineEqual(
+ self.package_and_class_tags(cov),
+ clean(result)
+ )
+
+ def test_package_names(self):
self.make_tree(width=1, depth=3)
self.make_file("main.py", """\
from d0.d0 import f0
""")
cov = coverage.coverage(source=".")
self.start_import_stop(cov, "main")
- cov.xml_report(outfile="-")
- xml = self.stdout()
- packages_and_classes = "".join(re_lines(xml, r"<package |<class "))
- scrubs = r' branch-rate="0"| complexity="0"| line-rate="[\d.]+"'
- self.assertMultiLineEqual(
- clean(packages_and_classes, scrubs),
- clean("""\
- <package name=".">
- <class filename="main.py" name="main.py">
- <package name="d0">
- <class filename="d0/__init__.py" name="__init__.py">
- <class filename="d0/f0.py" name="f0.py">
- <package name="d0.d0">
- <class filename="d0/d0/__init__.py" name="__init__.py">
- <class filename="d0/d0/f0.py" name="f0.py">
- """)
- )
+ self.assert_package_and_class_tags(cov, """\
+ <package name=".">
+ <class filename="main.py" name="main.py">
+ <package name="d0">
+ <class filename="d0/__init__.py" name="__init__.py">
+ <class filename="d0/f0.py" name="f0.py">
+ <package name="d0.d0">
+ <class filename="d0/d0/__init__.py" name="__init__.py">
+ <class filename="d0/d0/f0.py" name="f0.py">
+ """)
+
+ def test_package_depth(self):
+ self.make_tree(width=1, depth=4)
+ self.make_file("main.py", """\
+ from d0.d0 import f0
+ """)
+ cov = coverage.coverage(source=".")
+ self.start_import_stop(cov, "main")
+
+ cov.config["xml:package_depth"] = 1
+ self.assert_package_and_class_tags(cov, """\
+ <package name=".">
+ <class filename="main.py" name="main.py">
+ <package name="d0">
+ <class filename="d0/__init__.py" name="__init__.py">
+ <class filename="d0/d0/__init__.py" name="d0/__init__.py">
+ <class filename="d0/d0/d0/__init__.py" name="d0/d0/__init__.py">
+ <class filename="d0/d0/d0/f0.py" name="d0/d0/f0.py">
+ <class filename="d0/d0/f0.py" name="d0/f0.py">
+ <class filename="d0/f0.py" name="f0.py">
+ """)
+
+ cov.config["xml:package_depth"] = 2
+ self.assert_package_and_class_tags(cov, """\
+ <package name=".">
+ <class filename="main.py" name="main.py">
+ <package name="d0">
+ <class filename="d0/__init__.py" name="__init__.py">
+ <class filename="d0/f0.py" name="f0.py">
+ <package name="d0.d0">
+ <class filename="d0/d0/__init__.py" name="__init__.py">
+ <class filename="d0/d0/d0/__init__.py" name="d0/__init__.py">
+ <class filename="d0/d0/d0/f0.py" name="d0/f0.py">
+ <class filename="d0/d0/f0.py" name="f0.py">
+ """)
+
+ cov.config["xml:package_depth"] = 3
+ self.assert_package_and_class_tags(cov, """\
+ <package name=".">
+ <class filename="main.py" name="main.py">
+ <package name="d0">
+ <class filename="d0/__init__.py" name="__init__.py">
+ <class filename="d0/f0.py" name="f0.py">
+ <package name="d0.d0">
+ <class filename="d0/d0/__init__.py" name="__init__.py">
+ <class filename="d0/d0/f0.py" name="f0.py">
+ <package name="d0.d0.d0">
+ <class filename="d0/d0/d0/__init__.py" name="__init__.py">
+ <class filename="d0/d0/d0/f0.py" name="f0.py">
+ """)
def re_lines(text, pat):