summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgtags1
-rw-r--r--AUTHORS.txt1
-rw-r--r--CHANGES.txt21
-rw-r--r--coverage/__init__.py16
-rw-r--r--coverage/backward.py2
-rw-r--r--coverage/cmdline.py27
-rw-r--r--coverage/collector.py47
-rw-r--r--coverage/config.py13
-rw-r--r--coverage/control.py20
-rw-r--r--coverage/misc.py2
-rw-r--r--coverage/parser.py4
-rw-r--r--coverage/tracer.c20
-rw-r--r--coverage/version.py2
-rw-r--r--doc/_ext/px_xlator.py18
-rw-r--r--doc/changes.rst25
-rw-r--r--doc/cmd.rst28
-rw-r--r--doc/conf.py6
-rw-r--r--doc/config.rst18
-rw-r--r--doc/index.rst9
-rw-r--r--doc/install.rst29
-rw-r--r--doc/python-coverage.1.txt10
-rw-r--r--howto.txt3
-rw-r--r--metacov.ini16
-rw-r--r--setup.py3
-rw-r--r--tests/coveragetest.py9
-rw-r--r--tests/farm/run/run_timid.py20
-rw-r--r--tests/test_cmdline.py45
-rw-r--r--tests/test_concurrency.py (renamed from tests/test_coroutine.py)34
-rw-r--r--tests/test_config.py4
-rw-r--r--tests/test_execfile.py4
-rw-r--r--tests/test_farm.py7
-rw-r--r--tests/test_oddball.py2
-rw-r--r--tests/test_plugins.py6
-rw-r--r--tests/test_process.py2
-rw-r--r--tests/test_templite.py6
-rw-r--r--tests/test_testing.py4
-rw-r--r--tests/try_execfile.py7
-rw-r--r--tox.ini2
-rw-r--r--tox_winkits.ini2
39 files changed, 290 insertions, 205 deletions
diff --git a/.hgtags b/.hgtags
index 37da691d..ab6d166e 100644
--- a/.hgtags
+++ b/.hgtags
@@ -36,3 +36,4 @@ afc3c2ffdb323bf059f136c4c88199899ed93d36 coverage-3.5.2b1
af20c6543c226fbc9deeba4a6d4114641374734a coverage-3.6
092c0be6d011b6abf85b11476e3b548ed4d5b4c3 coverage-3.7
41932e001f215955dff895a1fd2fe4133abb89dc coverage-3.7.1
+175fd36ea47ea668066965c80343e1de34f2a94a coverage-4.0a1
diff --git a/AUTHORS.txt b/AUTHORS.txt
index d374c2ac..1de7e9f6 100644
--- a/AUTHORS.txt
+++ b/AUTHORS.txt
@@ -17,6 +17,7 @@ Matthew Desmarais
Danek Duvall
Ben Finney
Martin Fuzzey
+Carl Gieringer
Imri Goldberg
Bill Hart
Christian Heimes
diff --git a/CHANGES.txt b/CHANGES.txt
index b034744f..2dfce50f 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -2,13 +2,22 @@
Change history for Coverage.py
------------------------------
-4.0
----
+
+4.0dev
+------
+
+- The ``COVERAGE_OPTIONS`` environment variable is no longer supported. It was
+ a hack for ``--timid`` before configuration files were available.
+
+
+4.0a1 --- 27 September 2014
+---------------------------
- Python versions supported are now CPython 2.6, 2.7, 3.2, 3.3, and 3.4, and
PyPy 2.2.
-- Gevent, eventlet, and greenlet are now supported, closing `issue 149`_. Huge
+- Gevent, eventlet, and greenlet are now supported, closing `issue 149`_.
+ The ``concurrency`` setting specifies the concurrency library in use. Huge
thanks to Peter Portante for initial implementation, and to Joe Jevnik for
the final insight that completed the work.
@@ -17,7 +26,7 @@ Change history for Coverage.py
``[coverage:run]`` section of setup.cfg. Finishes `issue 304`_.
- The ``report`` command can now show missing branches when reporting on branch
- coverage. Thanks, Steve Leonard. Closes `issue 230`.
+ coverage. Thanks, Steve Leonard. Closes `issue 230`_.
- The XML report now contains a <source> element, fixing `issue 94`_. Thanks
Stan Hu.
@@ -54,8 +63,8 @@ Change history for Coverage.py
.. _issue 305: https://bitbucket.org/ned/coveragepy/issue/305/pendingdeprecationwarning-the-imp-module
-3.7.1 -- 13 December 2013
--------------------------
+3.7.1 --- 13 December 2013
+--------------------------
- Improved the speed of HTML report generation by about 20%.
diff --git a/coverage/__init__.py b/coverage/__init__.py
index 5ae32aba..67dd6e88 100644
--- a/coverage/__init__.py
+++ b/coverage/__init__.py
@@ -17,9 +17,9 @@ from coverage.plugin import CoveragePlugin
coverage = Coverage
# Module-level functions. The original API to this module was based on
-# functions defined directly in the module, with a singleton of the coverage()
+# functions defined directly in the module, with a singleton of the Coverage()
# class. That design hampered programmability, so the current api uses
-# explicitly-created coverage objects. But for backward compatibility, here we
+# explicitly-created Coverage objects. But for backward compatibility, here we
# define the top-level functions to create the singleton when they are first
# called.
@@ -28,7 +28,7 @@ coverage = Coverage
_the_coverage = None
def _singleton_method(name):
- """Return a function to the `name` method on a singleton `coverage` object.
+ """Return a function to the `name` method on a singleton `Coverage` object.
The singleton object is created the first time one of these functions is
called.
@@ -42,19 +42,19 @@ def _singleton_method(name):
"""Singleton wrapper around a coverage method."""
global _the_coverage
if not _the_coverage:
- _the_coverage = coverage(auto_data=True)
+ _the_coverage = Coverage(auto_data=True)
return getattr(_the_coverage, name)(*args, **kwargs)
import inspect
- meth = getattr(coverage, name)
+ meth = getattr(Coverage, name)
args, varargs, kw, defaults = inspect.getargspec(meth)
argspec = inspect.formatargspec(args[1:], varargs, kw, defaults)
docstring = meth.__doc__
wrapper.__doc__ = ("""\
- A first-use-singleton wrapper around coverage.%(name)s.
+ A first-use-singleton wrapper around Coverage.%(name)s.
This wrapper is provided for backward compatibility with legacy code.
- New code should use coverage.%(name)s directly.
+ New code should use Coverage.%(name)s directly.
%(name)s%(argspec)s:
@@ -96,7 +96,7 @@ except KeyError:
# COPYRIGHT AND LICENSE
#
# Copyright 2001 Gareth Rees. All rights reserved.
-# Copyright 2004-2013 Ned Batchelder. All rights reserved.
+# Copyright 2004-2014 Ned Batchelder. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
diff --git a/coverage/backward.py b/coverage/backward.py
index 9597449c..e839f6bd 100644
--- a/coverage/backward.py
+++ b/coverage/backward.py
@@ -148,7 +148,7 @@ def import_local_file(modname):
if SourceFileLoader:
mod = SourceFileLoader(modname, modfile).load_module()
else:
- for suff in imp.get_suffixes():
+ for suff in imp.get_suffixes(): # pragma: part covered
if suff[0] == '.py':
break
diff --git a/coverage/cmdline.py b/coverage/cmdline.py
index bd10d5a8..58f4817f 100644
--- a/coverage/cmdline.py
+++ b/coverage/cmdline.py
@@ -19,9 +19,12 @@ class Opts(object):
'', '--branch', action='store_true',
help="Measure branch coverage in addition to statement coverage."
)
- coroutine = optparse.make_option(
- '', '--coroutine', action='store', metavar="LIB",
- help="Properly measure code using coroutines."
+ CONCURRENCY_CHOICES = ["thread", "gevent", "greenlet", "eventlet"]
+ concurrency = optparse.make_option(
+ '', '--concurrency', action='store', metavar="LIB",
+ choices=CONCURRENCY_CHOICES,
+ help="Properly measure code using a concurrency library. "
+ "Valid values are: %s." % ", ".join(CONCURRENCY_CHOICES)
)
debug = optparse.make_option(
'', '--debug', action='store', metavar="OPTS",
@@ -46,8 +49,8 @@ class Opts(object):
include = optparse.make_option(
'', '--include', action='store',
metavar="PAT1,PAT2,...",
- help="Include files only when their filename path matches one of "
- "these patterns. Usually needs quoting on the command line."
+ help="Include only files whose paths match one of these patterns."
+ "Accepts shell-style wildcards, which must be quoted."
)
pylib = optparse.make_option(
'-L', '--pylib', action='store_true',
@@ -62,14 +65,14 @@ class Opts(object):
old_omit = optparse.make_option(
'-o', '--omit', action='store',
metavar="PAT1,PAT2,...",
- help="Omit files when their filename matches one of these patterns. "
- "Usually needs quoting on the command line."
+ help="Omit files whose paths match one of these patterns. "
+ "Accepts shell-style wildcards, which must be quoted."
)
omit = optparse.make_option(
'', '--omit', action='store',
metavar="PAT1,PAT2,...",
- help="Omit files when their filename matches one of these patterns. "
- "Usually needs quoting on the command line."
+ help="Omit files whose paths match one of these patterns. "
+ "Accepts shell-style wildcards, which must be quoted."
)
output_xml = optparse.make_option(
'-o', '', action='store', dest="outfile",
@@ -125,7 +128,7 @@ class CoverageOptionParser(optparse.OptionParser, object):
self.set_defaults(
actions=[],
branch=None,
- coroutine=None,
+ concurrency=None,
debug=None,
directory=None,
fail_under=None,
@@ -320,7 +323,7 @@ CMDS = {
[
Opts.append,
Opts.branch,
- Opts.coroutine,
+ Opts.concurrency,
Opts.debug,
Opts.pylib,
Opts.parallel_mode,
@@ -429,7 +432,7 @@ class CoverageScript(object):
omit = omit,
include = include,
debug = debug,
- coroutine = options.coroutine,
+ concurrency = options.concurrency,
)
if 'debug' in options.actions:
diff --git a/coverage/collector.py b/coverage/collector.py
index c571cb06..66de8b61 100644
--- a/coverage/collector.py
+++ b/coverage/collector.py
@@ -51,7 +51,7 @@ class Collector(object):
_collectors = []
def __init__(self,
- should_trace, check_include, timid, branch, warn, coroutine,
+ should_trace, check_include, timid, branch, warn, concurrency,
):
"""Create a collector.
@@ -73,7 +73,9 @@ class Collector(object):
`warn` is a warning function, taking a single string message argument,
to be used if a warning needs to be issued.
- TODO: `coroutine`
+ `concurrency` is a string indicating the concurrency library in use.
+ Valid values are "greenlet", "eventlet", "gevent", or "thread" (the
+ default).
"""
self.should_trace = should_trace
@@ -81,21 +83,21 @@ class Collector(object):
self.warn = warn
self.branch = branch
self.threading = None
- self.coroutine = coroutine
+ self.concurrency = concurrency
- self.coroutine_id_func = None
+ self.concur_id_func = None
try:
- if coroutine == "greenlet":
- import greenlet
- self.coroutine_id_func = greenlet.getcurrent
- elif coroutine == "eventlet":
- import eventlet.greenthread
- self.coroutine_id_func = eventlet.greenthread.getcurrent
- elif coroutine == "gevent":
- import gevent
- self.coroutine_id_func = gevent.getcurrent
- elif coroutine == "thread" or not coroutine:
+ if concurrency == "greenlet":
+ import greenlet # pylint: disable=import-error
+ self.concur_id_func = greenlet.getcurrent
+ elif concurrency == "eventlet":
+ import eventlet.greenthread # pylint: disable=import-error
+ self.concur_id_func = eventlet.greenthread.getcurrent
+ elif concurrency == "gevent":
+ import gevent # pylint: disable=import-error
+ self.concur_id_func = gevent.getcurrent
+ elif concurrency == "thread" or not concurrency:
# It's important to import threading only if we need it. If
# it's imported early, and the program being measured uses
# gevent, then gevent's monkey-patching won't work properly.
@@ -103,12 +105,12 @@ class Collector(object):
self.threading = threading
else:
raise CoverageException(
- "Don't understand coroutine=%s" % coroutine
+ "Don't understand concurrency=%s" % concurrency
)
except ImportError:
raise CoverageException(
- "Couldn't trace with coroutine=%s, "
- "the module isn't installed." % coroutine
+ "Couldn't trace with concurrency=%s, "
+ "the module isn't installed." % concurrency
)
self.reset()
@@ -156,13 +158,13 @@ class Collector(object):
tracer.should_trace_cache = self.should_trace_cache
tracer.warn = self.warn
- if hasattr(tracer, 'coroutine_id_func'):
- tracer.coroutine_id_func = self.coroutine_id_func
- elif self.coroutine_id_func:
+ if hasattr(tracer, 'concur_id_func'):
+ tracer.concur_id_func = self.concur_id_func
+ elif self.concur_id_func:
raise CoverageException(
- "Can't support coroutine=%s with %s, "
+ "Can't support concurrency=%s with %s, "
"only threads are supported" % (
- self.coroutine, self.tracer_name(),
+ self.concurrency, self.tracer_name(),
)
)
@@ -212,6 +214,7 @@ class Collector(object):
# Install the tracer on this thread.
fn = self._start_tracer()
+ # Replay all the events from fullcoverage into the new trace function.
for args in traces0:
(frame, event, arg), lineno = args
try:
diff --git a/coverage/config.py b/coverage/config.py
index c671ef75..ece68ba8 100644
--- a/coverage/config.py
+++ b/coverage/config.py
@@ -140,7 +140,7 @@ class CoverageConfig(object):
# Defaults for [run]
self.branch = False
- self.coroutine = None
+ self.concurrency = None
self.cover_pylib = False
self.data_file = ".coverage"
self.parallel = False
@@ -173,15 +173,6 @@ class CoverageConfig(object):
# Options for plugins
self.plugin_options = {}
- def from_environment(self, env_var):
- """Read configuration from the `env_var` environment variable."""
- # Timidity: for nose users, read an environment variable. This is a
- # cheap hack, since the rest of the command line arguments aren't
- # recognized, but it solves some users' problems.
- env = os.environ.get(env_var, '')
- if env:
- self.timid = ('--timid' in env)
-
MUST_BE_LIST = ["omit", "include", "debug", "plugins"]
def from_args(self, **kwargs):
@@ -235,7 +226,7 @@ class CoverageConfig(object):
# [run]
('branch', 'run:branch', 'boolean'),
- ('coroutine', 'run:coroutine'),
+ ('concurrency', 'run:concurrency'),
('cover_pylib', 'run:cover_pylib', 'boolean'),
('data_file', 'run:data_file'),
('debug', 'run:debug', 'list'),
diff --git a/coverage/control.py b/coverage/control.py
index 86a2ae23..b2ec64ab 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -45,7 +45,7 @@ class Coverage(object):
def __init__(self, data_file=None, data_suffix=None, cover_pylib=None,
auto_data=False, timid=None, branch=None, config_file=True,
source=None, omit=None, include=None, debug=None,
- debug_file=None, coroutine=None, plugins=None):
+ debug_file=None, concurrency=None, plugins=None):
"""
`data_file` is the base name of the data file to use, defaulting to
".coverage". `data_suffix` is appended (with a dot) to `data_file` to
@@ -84,10 +84,10 @@ class Coverage(object):
desired. `debug_file` is the file to write debug messages to,
defaulting to stderr.
- `coroutine` is a string indicating the coroutining library being used
+ `concurrency` is a string indicating the concurrency library being used
in the measured code. Without this, coverage.py will get incorrect
- results. Valid strings are "greenlet", "eventlet", or "gevent", which
- are all equivalent. TODO: really?
+ results. Valid strings are "greenlet", "eventlet", "gevent", or
+ "thread" (the default).
`plugins` TODO.
@@ -118,7 +118,6 @@ class Coverage(object):
self.config.from_file("setup.cfg", section_prefix="coverage:")
# 3: from environment variables:
- self.config.from_environment('COVERAGE_OPTIONS')
env_data_file = os.environ.get('COVERAGE_FILE')
if env_data_file:
self.config.data_file = env_data_file
@@ -128,7 +127,7 @@ class Coverage(object):
data_file=data_file, cover_pylib=cover_pylib, timid=timid,
branch=branch, parallel=bool_or_none(data_suffix),
source=source, omit=omit, include=include, debug=debug,
- coroutine=coroutine, plugins=plugins,
+ concurrency=concurrency, plugins=plugins,
)
# Create and configure the debugging controller.
@@ -170,7 +169,7 @@ class Coverage(object):
timid=self.config.timid,
branch=self.config.branch,
warn=self._warn,
- coroutine=self.config.coroutine,
+ concurrency=self.config.concurrency,
)
# Suffixes are a bit tricky. We want to use the data suffix only when
@@ -551,10 +550,9 @@ class Coverage(object):
# `save()` at the last minute so that the pid will be correct even
# if the process forks.
extra = ""
- if _TEST_NAME_FILE:
- f = open(_TEST_NAME_FILE)
- test_name = f.read()
- f.close()
+ if _TEST_NAME_FILE: # pragma: debugging
+ with open(_TEST_NAME_FILE) as f:
+ test_name = f.read()
extra = "." + test_name
data_suffix = "%s%s.%s.%06d" % (
socket.gethostname(), extra, os.getpid(),
diff --git a/coverage/misc.py b/coverage/misc.py
index 6962ae32..a653bb62 100644
--- a/coverage/misc.py
+++ b/coverage/misc.py
@@ -55,7 +55,7 @@ def format_lines(statements, lines):
return ret
-def short_stack():
+def short_stack(): # pragma: debugging
"""Return a string summarizing the call stack."""
stack = inspect.stack()[:0:-1]
return "\n".join("%30s : %s @%d" % (t[3],t[1],t[2]) for t in stack)
diff --git a/coverage/parser.py b/coverage/parser.py
index c5e95baa..e7b9c029 100644
--- a/coverage/parser.py
+++ b/coverage/parser.py
@@ -413,7 +413,7 @@ class ByteParser(object):
for _, l in bp._bytes_lines():
yield l
- def _block_stack_repr(self, block_stack):
+ def _block_stack_repr(self, block_stack): # pragma: debugging
"""Get a string version of `block_stack`, for debugging."""
blocks = ", ".join(
"(%s, %r)" % (dis.opname[b[0]], b[1]) for b in block_stack
@@ -552,7 +552,7 @@ class ByteParser(object):
#self.validate_chunks(chunks)
return chunks
- def validate_chunks(self, chunks):
+ def validate_chunks(self, chunks): # pragma: debugging
"""Validate the rule that chunks have a single entrance."""
# starts is the entrances to the chunks
starts = set(ch.byte for ch in chunks)
diff --git a/coverage/tracer.c b/coverage/tracer.c
index 5bf5c462..dcc3b727 100644
--- a/coverage/tracer.c
+++ b/coverage/tracer.c
@@ -81,7 +81,7 @@ typedef struct {
/* Python objects manipulated directly by the Collector class. */
PyObject * should_trace;
PyObject * warn;
- PyObject * coroutine_id_func;
+ PyObject * concur_id_func;
PyObject * data;
PyObject * plugin_data;
PyObject * should_trace_cache;
@@ -104,8 +104,8 @@ typedef struct {
(None).
*/
- DataStack data_stack; /* Used if we aren't doing coroutines. */
- PyObject * data_stack_index; /* Used if we are doing coroutines. */
+ DataStack data_stack; /* Used if we aren't doing concurrency. */
+ PyObject * data_stack_index; /* Used if we are doing concurrency. */
DataStack * data_stacks;
int data_stacks_alloc;
int data_stacks_used;
@@ -191,7 +191,7 @@ CTracer_init(CTracer *self, PyObject *args_unused, PyObject *kwds_unused)
self->should_trace = NULL;
self->warn = NULL;
- self->coroutine_id_func = NULL;
+ self->concur_id_func = NULL;
self->data = NULL;
self->plugin_data = NULL;
self->should_trace_cache = NULL;
@@ -234,7 +234,7 @@ CTracer_dealloc(CTracer *self)
Py_XDECREF(self->should_trace);
Py_XDECREF(self->warn);
- Py_XDECREF(self->coroutine_id_func);
+ Py_XDECREF(self->concur_id_func);
Py_XDECREF(self->data);
Py_XDECREF(self->plugin_data);
Py_XDECREF(self->should_trace_cache);
@@ -327,18 +327,18 @@ CTracer_record_pair(CTracer *self, int l1, int l2)
static int
CTracer_set_pdata_stack(CTracer *self)
{
- if (self->coroutine_id_func != Py_None) {
+ if (self->concur_id_func != Py_None) {
PyObject * co_obj = NULL;
PyObject * stack_index = NULL;
long the_index = 0;
- co_obj = PyObject_CallObject(self->coroutine_id_func, NULL);
+ co_obj = PyObject_CallObject(self->concur_id_func, NULL);
if (co_obj == NULL) {
return RET_ERROR;
}
stack_index = PyDict_GetItem(self->data_stack_index, co_obj);
if (stack_index == NULL) {
- /* A new coroutine object. Make a new data stack. */
+ /* A new concurrency object. Make a new data stack. */
the_index = self->data_stacks_used;
stack_index = MyInt_FromLong(the_index);
if (PyDict_SetItem(self->data_stack_index, co_obj, stack_index) < 0) {
@@ -781,8 +781,8 @@ CTracer_members[] = {
{ "warn", T_OBJECT, offsetof(CTracer, warn), 0,
PyDoc_STR("Function for issuing warnings.") },
- { "coroutine_id_func", T_OBJECT, offsetof(CTracer, coroutine_id_func), 0,
- PyDoc_STR("Function for determining coroutine context") },
+ { "concur_id_func", T_OBJECT, offsetof(CTracer, concur_id_func), 0,
+ PyDoc_STR("Function for determining concurrency context") },
{ "data", T_OBJECT, offsetof(CTracer, data), 0,
PyDoc_STR("The raw dictionary of trace data.") },
diff --git a/coverage/version.py b/coverage/version.py
index 27c2f6b1..fe3f44fa 100644
--- a/coverage/version.py
+++ b/coverage/version.py
@@ -1,7 +1,7 @@
"""The version and URL for coverage.py"""
# This file is exec'ed in setup.py, don't import anything!
-__version__ = "4.0a0" # see detailed history in CHANGES.txt
+__version__ = "4.0a1" # see detailed history in CHANGES.txt
__url__ = "http://nedbatchelder.com/code/coverage"
if max(__version__).isalpha():
diff --git a/doc/_ext/px_xlator.py b/doc/_ext/px_xlator.py
index 6085b697..41619119 100644
--- a/doc/_ext/px_xlator.py
+++ b/doc/_ext/px_xlator.py
@@ -1,4 +1,5 @@
from docutils import nodes
+from sphinx import addnodes
from sphinx.writers.html import SmartyPantsHTMLTranslator
from sphinx.builders.html import StandaloneHTMLBuilder
import os
@@ -10,7 +11,7 @@ def setup(app):
BaseHtmlXlator = SmartyPantsHTMLTranslator
class PxTranslator(BaseHtmlXlator):
"""Adjust the HTML translator into a .px translator.
-
+
"""
def __init__(self, *args, **kwargs):
@@ -45,11 +46,11 @@ class PxTranslator(BaseHtmlXlator):
when, what = hist.split(',', 1)
self.body.append("<what when='%s'>%s</what>\n" % (when, self.encode(what.strip())))
self.body.append("</history>\n")
-
+
if "b" in self.builder.config.release:
self.body.append("""
<box>
- These docs are for a beta release, %s.
+ These docs are for a beta release, %s.
For the latest released version, see <a href='/code/coverage'>coverage.py</a>.
</box>
""" % self.builder.config.release)
@@ -76,8 +77,15 @@ class PxTranslator(BaseHtmlXlator):
raise nodes.SkipNode
def visit_desc_parameterlist(self, node):
+ # I'm overriding this method so that the base class doesn't write out
+ # <big>(</big>, but I also have to handle the logic from the base class,
+ # so most of this is just copied from sphinx/writers/html.py...
self.body.append('(')
self.first_param = 1
+ self.optional_param_level = 0
+ # How many required parameters are left.
+ self.required_params_left = sum([isinstance(c, addnodes.desc_parameter)
+ for c in node.children])
self.param_separator = node.child_text_separator
def depart_desc_parameterlist(self, node):
self.body.append(')')
@@ -91,10 +99,10 @@ class PxBuilder(StandaloneHTMLBuilder):
self.config.html_translator_class = "px_xlator.PxTranslator"
super(PxBuilder, self).init()
-
+
self.out_suffix = '.px'
self.link_suffix = '.html'
-
+
if "b" in self.config.release:
self.px_uri = "/code/coverage/beta/"
else:
diff --git a/doc/changes.rst b/doc/changes.rst
index 3ddf8896..97c3d8c9 100644
--- a/doc/changes.rst
+++ b/doc/changes.rst
@@ -35,6 +35,31 @@ history, see the `CHANGES.txt`_ file in the source tree.
.. _CHANGES.txt: http://bitbucket.org/ned/coveragepy/src/tip/CHANGES.txt
+.. _changes_40:
+
+Version 4.0 pre-release --- 27 September 2014
+---------------------------------------------
+
+- Python versions supported are now CPython 2.6, 2.7, 3.2, 3.3, and 3.4, and
+ PyPy 2.2.
+
+- Gevent, eventlet, and greenlet are now supported, closing `issue 149`_.
+ The ``concurrency`` setting specifies the concurrency library in use. Huge
+ thanks to Peter Portante for initial implementation, and to Joe Jevnik for
+ the final insight that completed the work.
+
+- Options are now also read from a setup.cfg file, if any. Sections are
+ prefixed with "coverage:", so the ``[run]`` options will be read from the
+ ``[coverage:run]`` section of setup.cfg. Finishes `issue 304`_.
+
+- The ``report`` command can now show missing branches when reporting on branch
+ coverage. Thanks, Steve Leonard. Closes `issue 230`_.
+
+.. _issue 149: https://bitbucket.org/ned/coveragepy/issue/149/coverage-gevent-looks-broken
+.. _issue 230: https://bitbucket.org/ned/coveragepy/issue/230/show-line-no-for-missing-branches-in
+.. _issue 304: https://bitbucket.org/ned/coveragepy/issue/304/attempt-to-get-configuration-from-setupcfg
+
+
.. _changes_371:
Version 3.7.1 --- 13 December 2013
diff --git a/doc/cmd.rst b/doc/cmd.rst
index 49062b31..cd6ae955 100644
--- a/doc/cmd.rst
+++ b/doc/cmd.rst
@@ -17,6 +17,7 @@ Coverage command line usage
:history: 20120807T211600, Clarified the combine rules.
:history: 20121003T074600, Fixed an option reference, https://bitbucket.org/ned/coveragepy/issue/200/documentation-mentions-output-xml-instead
:history: 20121117T091000, Added command aliases.
+:history: 20140924T193000, Added --concurrency
.. highlight:: console
@@ -95,6 +96,16 @@ but before the program invocation::
$ coverage run --source=dir1,dir2 my_program.py arg1 arg2
$ coverage run --source=dir1,dir2 -m packagename.modulename arg1 arg2
+Coverage can measure multi-threaded programs by default. If you are using
+more exotic concurrency, with the `greenlet`_, `eventlet`_, or `gevent`_
+libraries, then coverage will get very confused. Use the ``--concurrency``
+switch to properly measure programs using these libraries. Give it a value of
+``greenlet``, ``eventlet``, or ``gevent``.
+
+.. _greenlet: http://greenlet.readthedocs.org/en/latest/
+.. _gevent: http://www.gevent.org/
+.. _eventlet: http://eventlet.net/
+
By default, coverage does not measure code installed with the Python
interpreter, for example, the standard library. If you want to measure that
code as well as your own, add the ``-L`` flag.
@@ -102,9 +113,7 @@ code as well as your own, add the ``-L`` flag.
If your coverage results seem to be overlooking code that you know has been
executed, try running coverage again with the ``--timid`` flag. This uses a
simpler but slower trace method. Projects that use DecoratorTools, including
-TurboGears, will need to use ``--timid`` to get correct results. This option
-can also be enabled by setting the environment variable COVERAGE_OPTIONS to
-``--timid``.
+TurboGears, will need to use ``--timid`` to get correct results.
If you are measuring coverage in a multi-process program, or across a number of
machines, you'll want the ``--parallel-mode`` switch to keep the data separate
@@ -266,6 +275,19 @@ The ``-m`` flag also shows the line numbers of missing statements::
-------------------------------------------------------
TOTAL 91 12 87%
+If you are using branch coverage, then branch statistics will be reported in
+the Branch and BrMiss columns, the Missing column will detail the missed
+branches::
+
+ $ coverage report -m
+ Name Stmts Miss Branch BrMiss Cover Missing
+ ---------------------------------------------------------------------
+ my_program 20 4 10 2 80% 33-35, 36->38, 39
+ my_module 15 2 3 0 86% 8, 12
+ my_other_module 56 6 5 1 89% 17-23, 40->45
+ ---------------------------------------------------------------------
+ TOTAL 91 12 18 3 87%
+
You can restrict the report to only certain files by naming them on the
command line::
diff --git a/doc/conf.py b/doc/conf.py
index 41a00e3e..16f566f0 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -40,16 +40,16 @@ master_doc = 'index'
# General information about the project.
project = u'coverage.py'
-copyright = u'2009\N{EN DASH}2013, Ned Batchelder'
+copyright = u'2009\N{EN DASH}2014, Ned Batchelder'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
-version = '3.7.1'
+version = '4.0'
# The full version, including alpha/beta/rc tags.
-release = '3.7.1'
+release = '4.0a1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/doc/config.rst b/doc/config.rst
index 882fc777..cec14e0f 100644
--- a/doc/config.rst
+++ b/doc/config.rst
@@ -10,6 +10,7 @@ Configuration files
:history: 20110604T184400, updated for 3.5.
:history: 20110827T212700, updated for 3.5.1
:history: 20130926T222300, updated for 3.6.1
+:history: 20140925T064700, updated for 4.0a1
Coverage.py options can be specified in a configuration file. This makes it
@@ -26,6 +27,14 @@ configuration file are tied to your source code and how it should be measured,
so it should be stored with your source, and checked into source control,
rather than put in your home directory.
+A different name for the configuration file can be specified with the
+``--rcfile=FILE`` command line option.
+
+Coverage.py will read settings from a ``setup.cfg`` file if no other
+configuration file is used. In this case, the section names have "coverage:"
+prefixed, so the ``[run]`` options described below will be found in the
+``[coverage:run]`` section of ``setup.cfg``.
+
Syntax
------
@@ -90,6 +99,15 @@ to more than one command.
``cover_pylib`` (boolean, default False): whether to measure the Python
standard library.
+``concurrency`` (string, default "thread"): the name of the concurrency
+library in use by the product code. If your program uses `gevent`_,
+`greenlet`_, or `eventlet`_, you must name that library in this option, or
+coverage will produce very wrong results.
+
+.. _greenlet: http://greenlet.readthedocs.org/en/latest/
+.. _gevent: http://www.gevent.org/
+.. _eventlet: http://eventlet.net/
+
``data_file`` (string, default ".coverage"): the name of the data file to use
for storing or reporting coverage.
diff --git a/doc/index.rst b/doc/index.rst
index 3a0d9308..2f5c28a6 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -31,6 +31,7 @@ coverage.py
:history: 20130105T174000, Updated for 3.6
:history: 20131005T210000, Updated for 3.7
:history: 20131212T213300, Updated for 3.7.1
+:history: 20140924T073000, Updated for 4.0a1
Coverage.py is a tool for measuring code coverage of Python programs. It
@@ -44,14 +45,14 @@ not.
.. ifconfig:: not prerelease
The latest version is coverage.py 3.7.1, released 13 December 2013.
- It is supported on Python versions 2.3 through 3.4, and PyPy 2.1.
+ It is supported on Python versions 2.6 through 3.4, and PyPy 2.2.
.. ifconfig:: prerelease
- The latest version is coverage.py 3.6b3, released 29 December 2012.
- It is supported on Python versions 2.3 through 3.3, and PyPy 1.9.
+ The latest version is coverage.py 4.0a1, released 27 September 2014.
+ It is supported on Python versions 2.6 through 3.4, and PyPy 2.2.
**This is a pre-release build. The usual warnings about possible bugs apply.**
- The latest stable version is coverage.py 3.5.3, `described here`_.
+ The latest stable version is coverage.py 3.7.1, `described here`_.
.. _described here: http://nedbatchelder.com/code/coverage
diff --git a/doc/install.rst b/doc/install.rst
index bc8097a2..7dfa5668 100644
--- a/doc/install.rst
+++ b/doc/install.rst
@@ -20,29 +20,36 @@ Installation
:history: 20130105T174400, updated for 3.6.
:history: 20131005T210600, updated for 3.7.
:history: 20131212T213500, updated for 3.7.1.
+:history: 20140927T102700, updated for 4.0a1.
.. highlight:: console
+
.. _coverage_pypi: http://pypi.python.org/pypi/coverage
.. _setuptools: http://pypi.python.org/pypi/setuptools
.. _Distribute: http://packages.python.org/distribute/
-Installing coverage.py is done in the usual ways. You must have `setuptools`_
-or `Distribute`_ installed already, and then you:
+Installing coverage.py is done in the usual ways. The simplest way is with
+pip::
-#. Download the appropriate kit from the
- `coverage page on the Python Package Index`__.
+ $ pip install coverage
-#. Run ``python setup.py install``.
+.. ifconfig:: prerelease
-or, use::
+ To install a pre-release version, you will need to specify ``--pre``::
- $ pip install coverage
+ $ pip install --pre coverage
-or even::
- $ easy_install coverage
+The alternate old-school technique is:
+
+#. Install (or already have installed) `setuptools`_ or `Distribute`_.
+
+#. Download the appropriate kit from the
+ `coverage page on the Python Package Index`__.
+
+#. Run ``python setup.py install``.
.. __: coverage_pypi_
@@ -75,9 +82,9 @@ If all went well, you should be able to open a command prompt, and see coverage
installed properly::
$ coverage --version
- Coverage.py, version 3.7.1. http://nedbatchelder.com/code/coverage
+ Coverage.py, version 4.0a1. http://nedbatchelder.com/code/coverage
You can also invoke coverage as a module::
$ python -m coverage --version
- Coverage.py, version 3.7.1. http://nedbatchelder.com/code/coverage
+ Coverage.py, version 4.0a1. http://nedbatchelder.com/code/coverage
diff --git a/doc/python-coverage.1.txt b/doc/python-coverage.1.txt
index 89c70b53..f79f33d8 100644
--- a/doc/python-coverage.1.txt
+++ b/doc/python-coverage.1.txt
@@ -8,7 +8,7 @@ measure code coverage of Python program execution
:Author: Ned Batchelder <ned@nedbatchelder.com>
:Author: |author|
-:Date: 2013-10-10
+:Date: 2014-09-27
:Copyright: BSD license, attribution and disclaimer required.
:Manual section: 1
:Manual group: Coverage
@@ -76,8 +76,8 @@ GLOBAL OPTIONS
Usually needs quoting on the command line.
**--include** `PATTERN` [ , ... ]
- Include files only when their filename path matches one of these
- PATTERNs. Usually needs quoting on the command line.
+ Include only files whose paths match one of these
+ PATTERNs. Accepts shell-style wildcards, which must be quoted.
COMMAND REFERENCE
@@ -160,6 +160,10 @@ COMMAND REFERENCE
\--branch
Measure branch coverage in addition to statement coverage.
+ \--concurrency `LIB`
+ Properly measure code using a concurrency library. Valid values are:
+ thread, gevent, greenlet, eventlet.
+
\--debug `DEBUGOPT`,...
Debug options `DEBUGOPT`, separated by commas.
diff --git a/howto.txt b/howto.txt
index 3367a063..932a16a3 100644
--- a/howto.txt
+++ b/howto.txt
@@ -7,6 +7,7 @@
- Pythons 2.6, 2.7, 3.2, 3.3, 3.4
- Version number in coverage/version.py
- 3.1a1, 3.1b1, 3.1c1, 3.1
+- Copyright date in coverage/__init__.py
- Update CHANGES.txt, including release date.
- Update docstring in setup.py, including "New in x.y:"
- Update docs
@@ -17,7 +18,7 @@
- Don't forget the man page: doc/python-coverage.1.txt
- Generate new sample_html to get the latest, incl footer version number:
python setup.py develop
- cd C:\ned\cog\trunk
+ cd ~/cog/trunk
rm -rf htmlcov
coverage run --branch --source=cogapp -m cogapp.test_cogapp CogTestsInMemory
coverage html
diff --git a/metacov.ini b/metacov.ini
index f94b834c..3bce01e2 100644
--- a/metacov.ini
+++ b/metacov.ini
@@ -6,17 +6,6 @@ parallel = true
source =
$COVERAGE_HOME/coverage
$COVERAGE_HOME/tests
- $COVERAGE_HOME/.tox/py26/lib/python2.6/site-packages/coverage
- $COVERAGE_HOME/.tox/py27/lib/python2.7/site-packages/coverage
- $COVERAGE_HOME/.tox/py32/lib/python3.2/site-packages/coverage
- $COVERAGE_HOME/.tox/py33/lib/python3.3/site-packages/coverage
- $COVERAGE_HOME/.tox/py34/lib/python3.4/site-packages/coverage
- $COVERAGE_HOME/.tox/pypy/site-packages/coverage
- $COVERAGE_HOME\.tox\py26\Lib\site-packages\coverage
- $COVERAGE_HOME\.tox\py27\Lib\site-packages\coverage
- $COVERAGE_HOME\.tox\py32\Lib\site-packages\coverage
- $COVERAGE_HOME\.tox\py33\Lib\site-packages\coverage
- $COVERAGE_HOME\.tox\py34\Lib\site-packages\coverage
[report]
# We set a different pragma so our code won't be confused with test code.
@@ -26,6 +15,8 @@ exclude_lines =
def __repr__
if __name__ == .__main__.:
raise AssertionError
+ # pragma: debugging
+ # pragma: only failure
partial_branches =
# pragma: part covered
@@ -37,6 +28,5 @@ precision = 1
[paths]
source =
.
- */.tox/*/lib/*/site-packages
- */.tox/pypy/site-packages
+ *\coverage\trunk
*/coverage/trunk
diff --git a/setup.py b/setup.py
index 52eb086f..3f7afae6 100644
--- a/setup.py
+++ b/setup.py
@@ -12,6 +12,9 @@ Documentation is at `nedbatchelder.com <%s>`_. Code repository and issue
tracker are on `Bitbucket <http://bitbucket.org/ned/coveragepy>`_, with a
mirrored repo on `Github <https://github.com/nedbat/coveragepy>`_.
+New in 4.0 alpha: ``--concurrency``, dropped support for older Pythons,
+setup.cfg support.
+
New in 3.7: ``--debug``, and 12 bugs closed.
New in 3.6: ``--fail-under``, and >20 bugs closed.
diff --git a/tests/coveragetest.py b/tests/coveragetest.py
index 4053059f..19fc0612 100644
--- a/tests/coveragetest.py
+++ b/tests/coveragetest.py
@@ -37,10 +37,11 @@ class CoverageTest(
def setUp(self):
super(CoverageTest, self).setUp()
- if _TEST_NAME_FILE:
- f = open(_TEST_NAME_FILE, "w")
- f.write("%s_%s" % (self.__class__.__name__, self._testMethodName))
- f.close()
+ if _TEST_NAME_FILE: # pragma: debugging
+ with open(_TEST_NAME_FILE, "w") as f:
+ f.write("%s_%s" % (
+ self.__class__.__name__, self._testMethodName,
+ ))
def clean_local_file_imports(self):
"""Clean up the results of calls to `import_local_file`.
diff --git a/tests/farm/run/run_timid.py b/tests/farm/run/run_timid.py
index d4e69a46..99155b85 100644
--- a/tests/farm/run/run_timid.py
+++ b/tests/farm/run/run_timid.py
@@ -37,24 +37,4 @@ else:
# also show the Python function.
contains("out/showtraceout.txt", "regular PyTracer")
-# Try the environment variable.
-old_opts = os.environ.get('COVERAGE_OPTIONS')
-os.environ['COVERAGE_OPTIONS'] = '--timid'
-
-run("""
- coverage run showtrace.py regular
- coverage run --timid showtrace.py timid
- """, rundir="out", outfile="showtraceout.txt")
-
-contains("out/showtraceout.txt",
- "none None",
- "timid PyTracer",
- "regular PyTracer",
- )
-
-if old_opts:
- os.environ['COVERAGE_OPTIONS'] = old_opts
-else:
- del os.environ['COVERAGE_OPTIONS']
-
clean("out")
diff --git a/tests/test_cmdline.py b/tests/test_cmdline.py
index 08f7937a..bf99bf85 100644
--- a/tests/test_cmdline.py
+++ b/tests/test_cmdline.py
@@ -8,6 +8,7 @@ from coverage.misc import ExceptionDuringRun
from tests.coveragetest import CoverageTest, OK, ERR
+# TODO: base these tests on new cmdline, not old.
class CmdLineTest(CoverageTest):
"""Tests of execution paths through the command line interpreter."""
@@ -20,7 +21,7 @@ class CmdLineTest(CoverageTest):
defaults.coverage(
cover_pylib=None, data_suffix=None, timid=None, branch=None,
config_file=True, source=None, include=None, omit=None, debug=None,
- coroutine=None,
+ concurrency=None,
)
defaults.annotate(
directory=None, ignore_errors=None, include=None, omit=None, morfs=[],
@@ -474,8 +475,8 @@ class NewCmdLineTest(CmdLineTest):
def test_debug_sys(self):
self.command_line("debug sys")
out = self.stdout()
- assert "version:" in out
- assert "data_path:" in out
+ self.assertIn("version:", out)
+ self.assertIn("data_path:", out)
def test_erase(self):
self.cmd_executes_same("erase", "-e")
@@ -565,8 +566,7 @@ class NewCmdLineTest(CmdLineTest):
.stop()
.save()
""")
- self.cmd_executes("run --source=quux,hi.there,/home/bar foo.py",
- """\
+ self.cmd_executes("run --source=quux,hi.there,/home/bar foo.py", """\
.coverage(source=["quux", "hi.there", "/home/bar"])
.erase()
.start()
@@ -574,6 +574,19 @@ class NewCmdLineTest(CmdLineTest):
.stop()
.save()
""")
+ self.cmd_executes("run --concurrency=gevent foo.py", """\
+ .coverage(concurrency='gevent')
+ .erase()
+ .start()
+ .run_python_file('foo.py', ['foo.py'])
+ .stop()
+ .save()
+ """)
+
+ def test_bad_concurrency(self):
+ self.command_line("run --concurrency=nothing", ret=ERR)
+ out = self.stdout()
+ self.assertIn("option --concurrency: invalid choice: 'nothing'", out)
def test_run_debug(self):
self.cmd_executes("run --debug=opt1 foo.py", """\
@@ -676,33 +689,33 @@ class CmdLineStdoutTest(CmdLineTest):
def test_minimum_help(self):
self.command_line("")
out = self.stdout()
- assert "Code coverage for Python." in out
- assert out.count("\n") < 4
+ self.assertIn("Code coverage for Python.", out)
+ self.assertLess(out.count("\n"), 4)
def test_version(self):
self.command_line("--version")
out = self.stdout()
- assert "ersion " in out
- assert out.count("\n") < 4
+ self.assertIn("ersion ", out)
+ self.assertLess(out.count("\n"), 4)
def test_help(self):
self.command_line("help")
out = self.stdout()
- assert "nedbatchelder.com" in out
- assert out.count("\n") > 10
+ self.assertIn("nedbatchelder.com", out)
+ self.assertGreater(out.count("\n"), 10)
def test_cmd_help(self):
self.command_line("help run")
out = self.stdout()
- assert "<pyfile>" in out
- assert "--timid" in out
- assert out.count("\n") > 10
+ self.assertIn("<pyfile>", out)
+ self.assertIn("--timid", out)
+ self.assertGreater(out.count("\n"), 10)
def test_error(self):
self.command_line("fooey kablooey", ret=ERR)
out = self.stdout()
- assert "fooey" in out
- assert "help" in out
+ self.assertIn("fooey", out)
+ self.assertIn("help", out)
class CmdMainTest(CoverageTest):
diff --git a/tests/test_coroutine.py b/tests/test_concurrency.py
index 4abdd6f6..5ea756f6 100644
--- a/tests/test_coroutine.py
+++ b/tests/test_concurrency.py
@@ -1,4 +1,4 @@
-"""Tests for coroutining."""
+"""Tests for concurrency libraries."""
import os, os.path, sys, threading
@@ -36,8 +36,8 @@ def line_count(s):
return sum(1 for l in s.splitlines() if code_line(l))
-class CoroutineTest(CoverageTest):
- """Tests of the coroutine support in coverage.py."""
+class ConcurrencyTest(CoverageTest):
+ """Tests of the concurrency support in coverage.py."""
LIMIT = 1000
@@ -103,7 +103,7 @@ class CoroutineTest(CoverageTest):
import gevent.queue as queue
""" + COMMON
- # Uncomplicated code that doesn't use any of the coroutining stuff, to test
+ # Uncomplicated code that doesn't use any of the concurrency stuff, to test
# the simple case under each of the regimes.
SIMPLE = """\
total = 0
@@ -112,32 +112,32 @@ class CoroutineTest(CoverageTest):
print(total)
""".format(LIMIT=LIMIT)
- def try_some_code(self, code, coroutine, the_module, expected_out=None):
- """Run some coroutine testing code and see that it was all covered.
+ def try_some_code(self, code, concurrency, the_module, expected_out=None):
+ """Run some concurrency testing code and see that it was all covered.
- `code` is the Python code to execute. `coroutine` is the name of the
- coroutine regime to test it under. `the_module` is the imported module
- that must be available for this to work at all. `expected_out` is the
- text we expect the code to produce.
+ `code` is the Python code to execute. `concurrency` is the name of
+ the concurrency regime to test it under. `the_module` is the imported
+ module that must be available for this to work at all. `expected_out`
+ is the text we expect the code to produce.
"""
self.make_file("try_it.py", code)
- cmd = "coverage run --coroutine=%s try_it.py" % coroutine
+ cmd = "coverage run --concurrency=%s try_it.py" % concurrency
out = self.run_command(cmd)
if not the_module:
# We don't even have the underlying module installed, we expect
# coverage to alert us to this fact.
expected_out = (
- "Couldn't trace with coroutine=%s, "
- "the module isn't installed.\n" % coroutine
+ "Couldn't trace with concurrency=%s, "
+ "the module isn't installed.\n" % concurrency
)
self.assertEqual(out, expected_out)
- elif C_TRACER or coroutine == "thread":
+ elif C_TRACER or concurrency == "thread":
# We can fully measure the code if we are using the C tracer, which
- # can support all the coroutining, or if we are using threads.
+ # can support all the concurrency, or if we are using threads.
if expected_out is None:
expected_out = "%d\n" % (sum(range(self.LIMIT)))
self.assertEqual(out, expected_out)
@@ -157,8 +157,8 @@ class CoroutineTest(CoverageTest):
self.assertEqual(data.summary()['try_it.py'], lines)
else:
expected_out = (
- "Can't support coroutine=%s with PyTracer, "
- "only threads are supported\n" % coroutine
+ "Can't support concurrency=%s with PyTracer, "
+ "only threads are supported\n" % concurrency
)
self.assertEqual(out, expected_out)
diff --git a/tests/test_config.py b/tests/test_config.py
index bf84423d..4c8735d2 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -144,6 +144,7 @@ class ConfigFileTest(CoverageTest):
cover_pylib = TRUE
parallel = on
include = a/ , b/
+ concurrency = thread
plugins =
plugins.a_plugin
plugins.another
@@ -210,6 +211,7 @@ class ConfigFileTest(CoverageTest):
self.assertTrue(cov.config.branch)
self.assertTrue(cov.config.cover_pylib)
self.assertTrue(cov.config.parallel)
+ self.assertEqual(cov.config.concurrency, "thread")
self.assertEqual(cov.get_exclude_list(),
["if 0:", r"pragma:?\s+no cover", "another_tab"]
@@ -274,7 +276,7 @@ class ConfigFileTest(CoverageTest):
self.assertEqual(cov.config.omit, None)
self.assertEqual(cov.config.branch, False)
- def test_one(self):
+ def test_non_ascii(self):
self.make_file(".coveragerc", """\
[html]
title = tabblo & «ταБЬℓσ» # numbers
diff --git a/tests/test_execfile.py b/tests/test_execfile.py
index 69616e84..3a92ff76 100644
--- a/tests/test_execfile.py
+++ b/tests/test_execfile.py
@@ -91,9 +91,9 @@ class RunPycFileTest(CoverageTest):
os.remove("compiled.py")
# Find the .pyc file!
- for there, _, files in os.walk("."):
+ for there, _, files in os.walk("."): # pragma: part covered
for f in files:
- if f.endswith(".pyc"):
+ if f.endswith(".pyc"): # pragma: part covered
return os.path.join(there, f)
def test_running_pyc(self):
diff --git a/tests/test_farm.py b/tests/test_farm.py
index 47f9b7b7..d0f0a72a 100644
--- a/tests/test_farm.py
+++ b/tests/test_farm.py
@@ -70,10 +70,9 @@ class FarmTestCase(object):
"""Execute the test from the run.py file.
"""
- if _TEST_NAME_FILE:
- f = open(_TEST_NAME_FILE, "w")
- f.write(self.description.replace("/", "_"))
- f.close()
+ if _TEST_NAME_FILE: # pragma: debugging
+ with open(_TEST_NAME_FILE, "w") as f:
+ f.write(self.description.replace("/", "_"))
cwd = self.cd(self.dir)
diff --git a/tests/test_oddball.py b/tests/test_oddball.py
index 47f492f6..3a013b04 100644
--- a/tests/test_oddball.py
+++ b/tests/test_oddball.py
@@ -173,7 +173,7 @@ class MemoryLeakTest(CoverageTest):
if ram_growth > 100000:
fails += 1
- if fails > 8:
+ if fails > 8: # pragma: only failure
self.fail("RAM grew by %d" % (ram_growth))
diff --git a/tests/test_plugins.py b/tests/test_plugins.py
index 9c5a037d..1f175f21 100644
--- a/tests/test_plugins.py
+++ b/tests/test_plugins.py
@@ -1,6 +1,9 @@
"""Tests for plugins."""
import os.path
+import sys
+
+from nose.plugins.skip import SkipTest
import coverage
from coverage.codeunit import CodeUnit
@@ -118,6 +121,9 @@ class PluginTest(CoverageTest):
_ = coverage.Coverage(plugins=["plugin_over_zero"])
def test_importing_myself(self):
+ if sys.platform == 'win32':
+ raise SkipTest("Plugin stuff is jank on windows.. fixing soon...")
+
self.make_file("simple.py", """\
import try_xyz
a = 1
diff --git a/tests/test_process.py b/tests/test_process.py
index 3a0980dc..4669a62f 100644
--- a/tests/test_process.py
+++ b/tests/test_process.py
@@ -559,7 +559,7 @@ class PydocTest(CoverageTest):
self.assert_pydoc_ok("coverage", coverage)
def test_pydoc_coverage_coverage(self):
- self.assert_pydoc_ok("coverage.coverage", coverage.coverage)
+ self.assert_pydoc_ok("coverage.Coverage", coverage.Coverage)
class FailUnderTest(CoverageTest):
diff --git a/tests/test_templite.py b/tests/test_templite.py
index a4667a62..aa697b78 100644
--- a/tests/test_templite.py
+++ b/tests/test_templite.py
@@ -31,8 +31,10 @@ class TempliteTest(CoverageTest):
an exception and never get to the result comparison.
"""
actual = Templite(text).render(ctx or {})
- if result:
- self.assertEqual(actual, result)
+ # If result is None, then an exception should have prevented us getting
+ # to here.
+ assert result is not None
+ self.assertEqual(actual, result)
def assertSynErr(self, msg):
"""Assert that a `TempliteSyntaxError` will happen.
diff --git a/tests/test_testing.py b/tests/test_testing.py
index 4a19098f..05db7298 100644
--- a/tests/test_testing.py
+++ b/tests/test_testing.py
@@ -114,7 +114,7 @@ def same_python_executable(e1, e2):
e2 = os.path.abspath(os.path.realpath(e2))
if os.path.dirname(e1) != os.path.dirname(e2):
- return False
+ return False # pragma: only failure
e1 = os.path.basename(e1)
e2 = os.path.basename(e2)
@@ -126,4 +126,4 @@ def same_python_executable(e1, e2):
# python2.3 and python2.3: ok
return True
- return False
+ return False # pragma: only failure
diff --git a/tests/try_execfile.py b/tests/try_execfile.py
index 9bbabd1a..825fdb70 100644
--- a/tests/try_execfile.py
+++ b/tests/try_execfile.py
@@ -12,18 +12,13 @@ def my_function(a):
FN_VAL = my_function("fooey")
-try:
- pkg = __package__
-except NameError:
- pkg = "*No __package__*"
-
globals_to_check = {
'__name__': __name__,
'__file__': __file__,
'__doc__': __doc__,
'__builtins__.has_open': hasattr(__builtins__, 'open'),
'__builtins__.dir': dir(__builtins__),
- '__package__': pkg,
+ '__package__': __package__,
'DATA': DATA,
'FN_VAL': FN_VAL,
'__main__.DATA': getattr(__main__, "DATA", "nothing"),
diff --git a/tox.ini b/tox.ini
index ca0d1721..6610b5fa 100644
--- a/tox.ini
+++ b/tox.ini
@@ -26,6 +26,8 @@ deps =
nose
mock
+usedevelop = True
+
[testenv:py26]
deps =
{[testenv]deps}
diff --git a/tox_winkits.ini b/tox_winkits.ini
index 49057d3b..f1941918 100644
--- a/tox_winkits.ini
+++ b/tox_winkits.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py26, py27, py32, py33
+envlist = py26, py27, py32, py33, py34
toxworkdir = {toxinidir}/.tox_kits
[testenv]