@@ -318,6 +318,39 @@ def test_accented_directory(self) -> None:
318318 "name" : "â" ,
319319 }
320320
321+ def test_no_duplicate_packages (self ) -> None :
322+ self .make_file (
323+ "namespace/package/__init__.py" ,
324+ "from . import sample; from . import test; from .subpackage import test"
325+ )
326+ self .make_file ("namespace/package/sample.py" , "print('package.sample')" )
327+ self .make_file ("namespace/package/test.py" , "print('package.test')" )
328+ self .make_file ("namespace/package/subpackage/test.py" , "print('package.subpackage.test')" )
329+
330+ # no source path passed to coverage!
331+ # problem occurs when they are dynamically generated during xml report
332+ cov = coverage .Coverage ()
333+
334+ cov .start ()
335+ import_local_file ("foo" , "namespace/package/__init__.py" ) # pragma: nested
336+ cov .stop () # pragma: nested
337+
338+ cov .xml_report ()
339+
340+ dom = ElementTree .parse ("coverage.xml" )
341+
342+ # only two packages should be present
343+ packages = dom .findall (".//package" )
344+ assert len (packages ) == 2
345+
346+ # one of them is namespace.package
347+ named_package = dom .findall (".//package[@name='namespace.package']" )
348+ assert len (named_package ) == 1
349+
350+ # the other one namespace.package.subpackage
351+ named_sub_package = dom .findall (".//package[@name='namespace.package.subpackage']" )
352+ assert len (named_sub_package ) == 1
353+
321354
322355def unbackslash (v : Any ) -> Any :
323356 """Find strings in `v`, and replace backslashes with slashes throughout."""
0 commit comments