Saturday 7 March 2009

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

  • 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 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
  • 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

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, or send me an email. Discussion is welcome on the Testing In Python mailing list.


Jesper Noehr 4:36 AM on 8 Mar 2009

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:

You can also link to snapshots by entering '', etc.

Grahack 9:39 AM on 14 Mar 2009

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
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 = \
# 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 = []
    tested_file = open(tested_pth)
except IOError:
    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 =, line)
                if match is not None:
                    interesting = False
            if interesting:
                stmts_not_cleaned.append(line_idx + 1)
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!

Ned Batchelder 12:01 PM on 14 Mar 2009

@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?

Grahack 1:51 PM on 14 Mar 2009

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).


Add a comment:

Ignore this:
not displayed and no spam.
Leave this empty:
not searched.
Name and either email or www are required.
Don't put anything here:
Leave this empty:
URLs auto-link and some tags are allowed: <a><b><i><p><br><pre>.