Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically compute path remapping rules in "coverage combine" #1840

Open
zackw opened this issue Aug 28, 2024 · 0 comments
Open

Automatically compute path remapping rules in "coverage combine" #1840

zackw opened this issue Aug 28, 2024 · 0 comments
Labels
enhancement New feature or request

Comments

@zackw
Copy link
Contributor

zackw commented Aug 28, 2024

Is your feature request related to a problem? Please describe.

The [paths] section of a .coveragerc is a fragile beast. By way of example, if I'm testing my Python package in Github Actions CI on MacOS, Ubuntu, and Windows using both pip and conda, and I want to merge coverage reports from all of them, then I need to have a [paths] section like this:

[paths]
merge =
    <PKG>/
    /Users/runner/miniconda3/envs/test/lib/python3.<V>/site-packages/<PKG>/
    /Users/runner/work/<PKG>/<PKG>/venv/lib/python3.<V>/site-packages/<PKG>/
    /home/runner/work/<PKG>/<PKG>/venv/lib/python3.<V>/site-packages/<PKG>/
    /usr/share/miniconda/envs/test/lib/python3.<V>/site-packages/<PKG>/
    C:\Miniconda\envs\test\Lib\site-packages\<PKG>\
    D:\a\<PKG>\<PKG>\venv\Lib\site-packages\<PKG>\

where <V> is the Python minor version (each path with <V> in it has to be duplicated for each version of Python I'm testing with) and <PKG> is the name of my package (there has to be a whole 'nother merge group for each package simultaneously under test).

All these absolute paths are implementation details of the CI runner that could change without any warning. I shouldn't have to know them at all, let alone write them into a file that's checked into version control.

Describe the solution you'd like
Instead of having the user determine and then write down a [paths] stanza, coverage combine should be able to compute all the necessary path remapping rules itself, for example like this:

def remap_paths_for_databases(cfg, databases):
    from coverage import CoverageData
    from collections import defaultdict
    from os.path import commonprefix
    from pathlib import PurePosixPath, PureWindowsPath

    prefixes = set()
    for db_fname in databases:
        db = CoverageData(basename=db_fname)
        db.read()
        prefixes.add(commonprefix(list(db.measured_files())))

    packages = defaultdict(set)
    for p in prefixes:
        if '\\' in p or (len(p) >= 2 and p[0].isalpha() and p[1] == ':'):
            name = PureWindowsPath(p).name
        else:
            name = PurePosixPath(p).name
        packages[name].add(p)

    pkg_names = sorted(packages.keys())

    cfg["run"]["relative_files"] = "true"
    cfg["run"]["source_pkgs"] = " ".join(pkg_names)

    cfg["paths"] = {}
    for pkg in pkg_names:
        pkg_paths = ['', pkg + '/']
        pkg_paths.extend(sorted(packages[pkg]))

The cfg argument to this function is the ConfigParser instance for the .coveragerc, and the databases argument is a list of all the coverage databases to be combined.

Describe alternatives you've considered

One alternative would be to make relative_files mode more aggressive; it could trim out all path components above an element of sources / source_pkgs, and canonicalize path separators to /, before writing the database in the first place. That would make the subsequent combine step not need to remap paths.

Ideally, I would like to see both of the above two options implemented and maybe even on by default.

@zackw zackw added the enhancement New feature or request label Aug 28, 2024
zackw added a commit to MillionConcepts/pdr that referenced this issue Aug 28, 2024
Instead of running the unit tests against an “editable install” of
the PDR git repo, build an sdist and wheel from the git repo, then,
in separate jobs that don’t ever check out the git repo, install the
wheel and run the tests from the sdist against the installed wheel.

This has several advantages.  Most importantly, it verifies that we
generate *correct* binary packages, as we were not doing until the
previous commit.  Testing an editable install is also subtly different
in terms of things like sys.path than testing something that’s been
officially installed to site-packages.[^1]  Finally, this puts us in
a better position to create *conda* packages (as a separate project).

It would be possible to add further automation that uploads the sdist
and wheel to PyPI if the commit has a release tag.

The mechanism for tweaking .coveragerc for CI’s needs has also been
overhauled, using a helper Python script that parses .coveragerc
exactly the same way coverage.py itself does (i.e. using configparser).
This should be much more reliable, both because we no longer need to
make assumptions about what goes where in the file, and because the
Python script can also use the coverage.py API to compute the path-
remapping configuration (yes, coverage.py ought to do this itself,
filed nedbat/coveragepy#1840 ).  And it
means we can strip all the junk that’s in .coveragerc solely for
CI’s needs back out.

[^1]: https://setuptools.pypa.io/en/latest/userguide/development_mode.html#limitations
zackw added a commit to MillionConcepts/pdr that referenced this issue Aug 28, 2024
Instead of running the unit tests against an “editable install” of
the PDR git repo, build an sdist and wheel from the git repo, then,
in separate jobs that don’t ever check out the git repo, install the
wheel and run the tests from the sdist against the installed wheel.

This has several advantages.  Most importantly, it verifies that we
generate *correct* binary packages, as we were not doing until the
previous commit.  Testing an editable install is also subtly different
in terms of things like sys.path than testing something that’s been
officially installed to site-packages.[^1]  Finally, this puts us in
a better position to create *conda* packages (as a separate project).

It would be possible to add further automation that uploads the sdist
and wheel to PyPI if the commit has a release tag.

The mechanism for tweaking .coveragerc for CI’s needs has also been
overhauled, using a helper Python script that parses .coveragerc
exactly the same way coverage.py itself does (i.e. using configparser).
This should be much more reliable, both because we no longer need to
make assumptions about what goes where in the file, and because the
Python script can also use the coverage.py API to compute the path-
remapping configuration (yes, coverage.py ought to do this itself,
filed nedbat/coveragepy#1840 ).  And it
means we can strip all the junk that’s in .coveragerc solely for
CI’s needs back out.

[^1]: https://setuptools.pypa.io/en/latest/userguide/development_mode.html#limitations
zackw added a commit to MillionConcepts/pdr that referenced this issue Aug 28, 2024
Instead of running the unit tests against an “editable install” of
the PDR git repo, build an sdist and wheel from the git repo, then,
in separate jobs that don’t ever check out the git repo, install the
wheel and run the tests from the sdist against the installed wheel.

This has several advantages.  Most importantly, it verifies that we
generate *correct* binary packages, as we were not doing until the
previous commit.  Testing an editable install is also subtly different
in terms of things like sys.path than testing something that’s been
officially installed to site-packages.[^1]  Finally, this puts us in
a better position to create *conda* packages (as a separate project).

It would be possible to add further automation that uploads the sdist
and wheel to PyPI if the commit has a release tag.

The mechanism for tweaking .coveragerc for CI’s needs has also been
overhauled, using a helper Python script that parses .coveragerc
exactly the same way coverage.py itself does (i.e. using configparser).
This should be much more reliable, both because we no longer need to
make assumptions about what goes where in the file, and because the
Python script can also use the coverage.py API to compute the path-
remapping configuration (yes, coverage.py ought to do this itself,
filed nedbat/coveragepy#1840 ).  And it
means we can strip all the junk that’s in .coveragerc solely for
CI’s needs back out.

[^1]: https://setuptools.pypa.io/en/latest/userguide/development_mode.html#limitations
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant