1. Ned Batchelder
  2. coverage.py
  3. Issues
Issue #426 resolved

Difference between coverage results with source specifies full dir instead of module name

Alexander Todorov
created an issue

Anaconda, the Fedora Linux installer supports coverage collection via the API interface. If you boot with inst.debug then the main file /usr/sbin/anaconda will initialize coverage as one of the first things it does.

    cov = coverage.coverage(data_file="/mnt/sysimage/root/anaconda.coverage",
                            branch=True,
                            source=["/usr/sbin/anaconda", "pyanaconda"]
                            )
    cov.start()

The results are 105 files measured, which is short of 19 files which are also present in the pyanaconda module. OTOH if the source path is specified as the full path (e.g. /usr/lib64/python3.4/site-packages/pyanaconda) then all files inside are included in the coverage data. See: https://github.com/rhinstaller/anaconda/pull/397

I've tried to reproduce locally with the same directory structure (but not the same code) and was not able to. I will keep trying so it's easier to reproduce and easier to debug/fix.

Comments (14)

  1. Loic Dachary

    I tried to reproduce the problem with a foo module containing a single a.py file

    def main():
        print('Hello')
    

    With the following we have 50% coverage and that is to be expected:

    $ cat ~/tmp/b.py 
    from foo import a
    import coverage
    cov = coverage.coverage(source=["foo"])
    cov.start()
    a.main()
    cov.stop()
    cov.report()
    $ PYTHONPATH=/tmp python ~/tmp/b.py 
    Hello
    Coverage.py warning: Module foo was previously imported, but not measured.
    Name            Stmts   Miss  Cover
    -----------------------------------
    /tmp/foo/a.py       2      1    50%
    

    Changing the file to import the module after starting coverage there is 100% coverage:

    $ cat ~/tmp/b.py 
    import coverage
    cov = coverage.coverage(source=["foo"])
    cov.start()
    from foo import a
    a.main()
    cov.stop()
    cov.report()
    $ PYTHONPATH=/tmp python ~/tmp/b.py 
    Hello
    Name                   Stmts   Miss  Cover
    ------------------------------------------
    /tmp/foo/__init__.py       0      0   100%
    /tmp/foo/a.py              2      0   100%
    ------------------------------------------
    TOTAL                      2      0   100%
    

    Alexander Todorov am I missing something ? Note that this is with coverage master (i.e. > 4.2) and it could be that things evolved for the best since 4.0 ;-)

  2. Alexander Todorov reporter

    Loic Dachary I don't think your comment is related to the originally reported issue. If you take a look at the PR I've linked above you will see that I import all modules I want to cover after coverage has been enabled. My problem was the way in which the source path was specified. However I don't have the time to investigate and see how things are with 4.x

  3. Loic Dachary

    Alexander Todorov I apologize for the confusion. Your fix look right: the source argument is a list of directories. If you specify pyanaconda instead of the full path to the directory it will only work as expected if pyanaconda is a subdirectory of your current working directory. Am I making sense this time ?

  4. Loic Dachary

    The --source is split into source and source_pkgs variables depending. It is then used to set source_match and source_pkgs_match to figure out if a source should be taken into account during the run.

    After the run and before saving the data to .coverage, the --source is used again to find which files were never executed. But the find_python_files does not know how to iterate over the files of a package. It only knows about listing the files in a directory.

    This difference between directories and packages in the --source argument should be documented. Or maybe this should be considered a bug and there should be no difference between files and modules.

  5. Ned Batchelder repo owner

    Do I understand this correctly? This bug is about a difference between source=dir and source=pkg, and the difference is that with source=dir, coverage will find completely unexecuted files, but with source=pkg, it will not.

    Right?

  6. Ned Batchelder repo owner

    make --source module do the same as --source directory #426

    The --source argument can either be a module or a directory. The user expects that it behaves the same in both cases. Make sure the module is recursively explored so that files that are not run show in the coverage report.

    close #426

    → <<cset ed784d8f334e>>

  7. Log in to comment