Coverage.py v3.0b1

Saturday 7 March 2009This is close to 16 years old. Be careful.

I’m undertaking a significant overhaul of coverage.py, my Python code coverage measurement tool. The first release of it is ready: coverage.py v3.0b1. Changes include:

  • Coverage.py is now a package rather than a module. The name is now a bit of a misnomer, since there is no longer a file named coverage.py. Functionality has been split into classes.
  • The trace function is implemented in C for speed.
  • Executable lines are identified by reading the line number tables in the compiled code, removing a great deal of complicated analysis code.
  • The singleton coverage object is only created if the module-level functions are used. This maintains the old interface while allowing better programmatic use of coverage.py.
  • The minimum supported Python version is 2.3. Python 3.0 is not supported.
  • Precisely which lines are considered executable has changed in some cases. Therefore, your coverage stats may also change slightly compared to earlier versions of coverage.py.

As you can see, very little has changed functionally since v2.85. So far this is a refactoring, reimplementation, and repackaging effort. The new code will be a much better foundation for more interesting changes in the future. This beta 1 release is so I can find out if I’ve screwed up anything so far or not.

You can download the kit in one of two ways:

If you find a problem, you can file a bug on bitbucket.org, or send me an email. Discussion is welcome on the Testing In Python mailing list.

Comments

[gravatar]
Hi Ned,

If you want, you can let Bitbucket take care of hosting the archives as well. It accepts tag/branch names, so this will work:

http://bitbucket.org/ned/coveragepy/get/coverage-3.0b1.tar.gz

You can also link to snapshots by entering 'tip.zip', etc.
[gravatar]
Hi Ned, and many thanks for 'coverage'.
I'm not very experienced in Python, but found two remarks to tell you:

1) The exclude configuration command excludes everything under a statement, in the tree sense. This is clearly stated in the docs, but say you don't want a line like
class MyClass():
to be reported as uncovered, if you 'exclude' it using
coverage.exclude('class')
this class is then not analysed, which is not what I want.

I found a slow workaround (which is enough for my needs):
tested_pth, stmts, _stmts_excl, stmts_not, coales = \
   coverage.analysis2(sys.modules[testmod2mod(mod_name)])
#
# This is my exclusion algo, because excluding statements with
# coverage.exclude('my_regex')
# excludes the whole code branch under it, not only the line.
#
stmts_not_cleaned = []
try:
    tested_file = open(tested_pth)
except IOError:
    pass
else:
    for line_idx, line in enumerate(tested_file):
        if line_idx + 1 in stmts_not:
            interesting = True
            for pattern in ['^ *class ', '^ *def ', '^ *import ', '^ *from ']:
                match = re.search(pattern, line)
                if match is not None:
                    interesting = False
                    break
            if interesting:
                stmts_not_cleaned.append(line_idx + 1)
    tested_file.close()
stmts_not = stmts_not_cleaned
coales = coverage.the_coverage.format_lines(stmts, stmts_not)
So what do you think of excluding lines only instead of branches?

2) My workaround needed to repack the not covered lines in the coalesced form. I found it could be nice to be able to access your function in an easier way than what I had to write:
coales = coverage.the_coverage.format_lines(stmts, stmts_not)
Thanks again!
[gravatar]
@Grahack, it sounds like you want to define the class, then start coverage. Under this execution, the def Class line will be reported as unexecuted (as will the method definitions), but the contents will be reported as executed. I can see this would be awkward, but I'd rather not change the behavior of the exclude pragma. I find it much more useful in its present form.

Can you start coverage before importing the class definitions?
[gravatar]
Oh, I didn't want you to change anything, and of course I didn't want you to break backward compatibility. Just maybe add an 'exclude_line' thing if you thought it could be useful (well, if so, it would have been already there I guess).

Ok, I understand now. I indeed thought it was weird that those lines were not marked as executed. In fact I build the test suite, then pass it to the test runner that starts/stops coverage for each tested module. Gonna see if I can start coverage before importing my modules without too much work, else I'll stick with my hacky hack until other problems arise (like speed of execution).

Thanks.

Add a comment:

Ignore this:
Leave this empty:
Name is required. Either email or web are required. Email won't be displayed and I won't spam you. Your web site won't be indexed by search engines.
Don't put anything here:
Leave this empty:
Comment text is Markdown.