20

My SUT looks like:

foo.py
bar.py
tests/__init__.py [empty]
tests/foo_tests.py
tests/bar_tests.py
tests/integration/__init__.py [empty]
tests/integration/foo_tests.py
tests/integration/bar_tests.py

When I run nosetests --with-coverage, I get details for all sorts of modules that I'd rather ignore. But I can't use the --cover-package=PACKAGE option because foo.py & bar.py are not in a package. (See the thread after http://lists.idyll.org/pipermail/testing-in-python/2008-November/001091.html for my reasons for not putting them in a package.)

Can I restrict coverage output to just foo.py & bar.py?

Update - Assuming that there isn't a better answer than Nadia's below, I've asked a follow up question: "How do I write some (bash) shell script to convert all matching filenames in directory to command-line options?"

Community
  • 1
  • 1
Daryl Spitzer
  • 143,156
  • 76
  • 154
  • 173
  • With the latest versions of nose and coverage, the code in the test files is ignored under nose, so you shouldn't need to specify the package at all. – dbn Apr 19 '13 at 19:05

8 Answers8

22

You can use it like this:

--cover-package=foo --cover-package=bar

I had a quick look at nose source code to confirm: This is the line

    if options.cover_packages:
        for pkgs in [tolist(x) for x in options.cover_packages]:
Kannan Ekanath
  • 16,759
  • 22
  • 75
  • 101
Nadia Alramli
  • 111,714
  • 37
  • 173
  • 152
  • I'm impressed that you looked at the source. (I should have thought of that.) But it shows I need to use "--cover-package=foo --cover-package=bar". If you modify your answer I'll accept it (and vote it up). – Daryl Spitzer May 12 '09 at 22:36
  • 1
    Thanks for the note. I fixed the answer. I've never used nose before. But I thought I'd give the question a try since no one else answered. – Nadia Alramli May 12 '09 at 22:41
  • Thanks Nadia. You still need to remove the ".py" extensions, since the arguments are the package names, not the file names. – Daryl Spitzer May 12 '09 at 22:45
  • Opps, sorry about the mistakes. Fixed :) – Nadia Alramli May 12 '09 at 22:49
  • I'm sorry, but this is just wrong. That line you found doesn't prove anything, it just shows that the flag is converted and passed to the coverage tool as the "source=" keyword argument.The coverage tool takes paths as shown here: https://coverage.readthedocs.io/en/v4.5.x/source.html – Ehsan Kia Dec 31 '18 at 21:54
15

You can use:

--cover-package=.

or even set environment variable

NOSE_COVER_PACKAGE=.

Tested with nose 1.1.2

parsons
  • 221
  • 2
  • 3
4

I have a lot of top-level Python files/packages and find it annoying to list them all manually using --cover-package, so I made two aliases for myself. Alias nosetests_cover will run coverage with all your top-level Python files/packages listed in --cover-package. Alias nosetests_cover_sort will do the same and additionally sort your results by coverage percentage.

nosetests_cover_cmd="nosetests --with-coverage --cover-erase --cover-inclusive --cover-package=\$( ls | sed -r 's/[.]py$//' | fgrep -v '.' | paste -s -d ',' )"
alias nosetests_cover=$nosetests_cover_cmd
alias nosetests_cover_sort="$nosetests_cover_cmd 2>&1 | fgrep '%' | sort -nr -k 4"

Notes:

  • This is from my .bashrc file. Modify appropriately if you don't use bash.
  • These must be run from your top-level directory. Otherwise, the package names will be incorrect and coverage will silently fail to process them (i.e. instead of telling you your --cover-package is incorrect, it will act like you didn't supply the option at all).
  • I'm currently using Python 2.7.6 on Ubuntu 13.10, with nose version 1.3.0 and coverage version 3.7.1. This is the only setup in which I've tested these commands.
  • In your usage, remove --cover-erase and --cover-inclusive if they don't match your needs.
  • If you want to sort in normal order instead of reverse order, replace -nr with -n in the sort command.
  • These commands assume that all of your top-level Python files/packages are named without a dot (other than the dot in ".py"). If this is not true for you, read Details section below to understand the command parts, then modify the commands as appropriate.

Details:

I don't claim that these are the most efficient commands to achieve the results I want. They're just the commands I happened to come up with. =P

The main thing to explain would be the argument to --cover-package. It builds the comma-separated list of top-level Python file/package names (with ".py" stripped from file names) as follows:

  • \$ -- Escapes the $ character in a double-quoted string.
  • $( ) -- Inserts the result of the command contained within.
  • ls -- Lists all names in current directory (must be top-level Python directory).
  • | sed -r 's/[.]py$//' -- In the list, replaces "foo_bar.py" with "foo_bar".
  • | fgrep -v '.' -- In the list, removes all names without a dot (e.g. removes foo_bar.pyc and notes.txt).
  • | paste -s -d ',' -- Changes the list from newline-separated to comma-separated.

I should also explain the sorting.

  • 2>&1 -- Joins stderr and stdout.
  • | fgrep '%' -- Removes all output lines without a % character.
  • | sort -nr -k 4 -- Sorts the remaining lines in reverse numerical order by the 4th column (which is the column for coverage percentage). If you want normal order instead of reverse order, replace -nr with -n.

Hope this helps someone! =)

walrus
  • 2,945
  • 5
  • 18
  • 19
3

If you use coverage:py 3.0, then code in the Python directory is ignored by default, including the standard library and all installed packages.

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
2

I would do this:

nosetests --with-coverage --cover-package=foo,bar tests/*

I prefer this solution to the others suggested; it's simple yet you are explicit about which packages you wish to have coverage for. Nadia's answer involves a lot more redundant typing, Stuart's answer uses sed and still creates a package by invoking touch __init__.py, and --cover-package=. doesn't work for me.

imolit
  • 7,743
  • 3
  • 25
  • 29
2

For anyone trying to do this with setup.cfg, the following works. I had some trouble figuring out how to specify multiple packages.

[nosetests]
with-coverage=1
cover-html=1
cover-package=module1,module2
zombieguru
  • 76
  • 1
  • 2
1
touch __init__.py; nosetests --with-coverage --cover-package=`pwd | sed 's@.*/@@g'`
Stuart
  • 11
  • 1
0

You can improve the accepted answer like so --cover-package=foo,bar

jfunk
  • 7,176
  • 4
  • 37
  • 38