During development, web frameworks often spawn a subprocess to serve requests so that they can reload the code if it changes. You might be measuring only the first process, and not the spawned process that is actually doing the work.

Ah, thanks Ned. That makes sense. I suspect the subprocess coverage section in the documentation might be helpful.

I fiddled around with sitecustomize.py, defining COVERAGE_PROCESS_START, and tweaking the --concurrency flag. Nothing worked. In fact, my code coverage went to zero. :-(

I then looked at the flask docs to see if it had some clues and noticed its run command has a --no-reload flag. Setting that worked like a charm. Since I'm not actively fiddling on-the-fly when running tests, that's perfect. Now I have nice coverage stats. I figured I'd toss out my solution in case someone else comes along looking for flask+coverage assistance.