diff --git a/covdefaults.py b/covdefaults.py index 54353ca..0b89619 100644 --- a/covdefaults.py +++ b/covdefaults.py @@ -2,6 +2,7 @@ import re import sys import sysconfig +from collections import OrderedDict from typing import Dict from typing import List @@ -69,39 +70,64 @@ def __init__( def _parse_inst_pkg(installed_package: str) -> Dict[str, str]: result: Dict[str, str] = {} for entry in installed_package.split(): - if entry: - key, value = entry, '.' - if entry.count(':') == 1: - key, value = entry.split(':') - result[key] = value + key, value = entry, '.' + if entry.count(':') == 1: + key, value = entry.split(':') + result[key] = value return result def _set_source(self, config: CoverageConfig) -> None: - if not isinstance(config, CoverageConfig): # pragma: no cover - # https://github.com/nedbat/coveragepy/issues/967 - config = config.config + # set source to either: + # - cwd + # - installed pkg within purelib/platlib, these map back to src tree + # https://coverage.readthedocs.io/en/latest/config.html#paths source = [] + paths = config.get_option('paths') if self._installed_package: - for path in { + search_packages = list({ sysconfig.get_paths()['platlib'], sysconfig.get_paths()['purelib'], - }: - for pkg, dest in self._installed_package.items(): + }) + for pkg, dest in self._installed_package.items(): + found = False + # also check in dest in case this is a develop install + possible_dir = search_packages + [os.path.abspath(dest)] + poss_dir_ord = list( + OrderedDict( + (i, None) for i in sys.path if i in possible_dir + ).keys(), + ) + for path in poss_dir_ord: base = os.path.join(path, pkg) for suffix in ('', '.py'): at = f'{base}{suffix}' if os.path.exists(at): source.append(at) - if dest is not None: - if os.path.isfile(at): - src_path = dest - else: - src_path = os.path.join(dest, pkg) - config.paths[pkg] = [src_path, at] - # set paths to map to cwd - # https://coverage.readthedocs.io/en/latest/config.html#paths + if os.path.isfile(at): + src_path = dest + else: + src_path = os.path.join(dest, pkg) + if not os.path.exists(src_path): + raise RuntimeError( + 'source path {} for {} does not exists' + ''.format( + src_path, + at, + ), + ) + paths[pkg] = [src_path, at] + found = True + break + if found: + break + if not found: + raise RuntimeError( + f'could not find installed package {pkg}', + ) + source.append(os.getcwd()) config.set_option('run:source', source) + config.set_option('paths', paths) def _fix_omit(self, config: CoverageConfig) -> None: omit = set(config.get_option('run:omit') or []) @@ -131,7 +157,7 @@ def _fix_omit(self, config: CoverageConfig) -> None: if os.path.isdir(os.path.join(level, entry)): pattern += '/*' else: - if not entry.endswith('.pyc'): + if not entry.endswith('.py'): continue omit.add(pattern) break diff --git a/setup.cfg b/setup.cfg index 2ec6197..83e09bf 100644 --- a/setup.cfg +++ b/setup.cfg @@ -22,7 +22,7 @@ classifiers = [options] py_modules = covdefaults install_requires = - coverage>=4.5 + coverage>=5.1 python_requires = >=3.6.1 [bdist_wheel] diff --git a/tests/covdefaults_test.py b/tests/covdefaults_test.py index ac5f6c1..b1a392e 100644 --- a/tests/covdefaults_test.py +++ b/tests/covdefaults_test.py @@ -123,33 +123,54 @@ def test_fix_coverage(): importlib.reload(covdefaults) -def test_installed_package(): - import easy_install # module example - map +def test_installed_package(tmp_path, monkeypatch): + root = os.path.dirname(os.path.dirname(__file__)) + monkeypatch.chdir(root) import setuptools # pkg example - map - import coverage # package example - no map cfg = CoverageConfig() - value = 'easy_install:src setuptools:src coverage' + setuptools_src = (tmp_path / 'setuptools') + setuptools_src.mkdir() + value = 'covdefaults setuptools:{}' \ + ''.format(setuptools_src.parent) c = covdefaults.CovDefaults(installed_package=value) c.configure(cfg) - - assert dict(cfg.paths) == { - 'easy_install': [ - 'src', - easy_install.__file__, - ], + setuptools_dir = os.path.dirname(setuptools.__file__) + cov_defaults = covdefaults.__file__ + exp_source = [ + cov_defaults, + setuptools_dir, + os.getcwd(), + ] + assert cfg.source == exp_source + exp_paths = { + 'covdefaults': ['.', cov_defaults], 'setuptools': [ - 'src/setuptools', + str(setuptools_src), os.path.dirname(setuptools.__file__), ], - 'coverage': [ - './coverage', - os.path.dirname(coverage.__file__), - ], } - assert cfg.source == [ - easy_install.__file__, - os.path.dirname(setuptools.__file__), - os.path.dirname(coverage.__file__), - os.getcwd(), - ] + assert dict(cfg.paths) == exp_paths + + +def test_installed_package_missing_pkg(): + cfg = CoverageConfig() + value = 'missing' + c = covdefaults.CovDefaults(installed_package=value) + with pytest.raises( + RuntimeError, + match='could not find installed package missing', + ): + c.configure(cfg) + + +def test_installed_package_missing_src(): + cfg = CoverageConfig() + value = 'coverage:this-does-not-exists' + + c = covdefaults.CovDefaults(installed_package=value) + with pytest.raises( + RuntimeError, + match='source path .* for .* does not exists', + ): + c.configure(cfg)