summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS.txt1
-rw-r--r--CHANGES.txt4
-rw-r--r--coverage/collector.py13
-rw-r--r--coverage/files.py14
-rw-r--r--setup.py2
-rw-r--r--test/test_files.py3
-rw-r--r--test/test_oddball.py8
-rw-r--r--tox.ini11
8 files changed, 47 insertions, 9 deletions
diff --git a/AUTHORS.txt b/AUTHORS.txt
index edb6be94..ef8ef276 100644
--- a/AUTHORS.txt
+++ b/AUTHORS.txt
@@ -3,6 +3,7 @@ extended and maintained by Ned Batchelder.
Other contributions have been made by:
+Marc Abramowitz
Chris Adams
Geoff Bache
Titus Brown
diff --git a/CHANGES.txt b/CHANGES.txt
index 955e523f..490a81b7 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -5,6 +5,10 @@ Change history for Coverage.py
Version 3.5.3b1
---------------
+- When specifying a directory as the source= option, the directory itself no
+ longer needs to have a ``__init__.py`` file, though its subdirectories do, to
+ be considered as source files.
+
- Files encoded as UTF-8 with a BOM are now properly handled, fixing
`issue 179`_. Thanks, Pablo Carballo.
diff --git a/coverage/collector.py b/coverage/collector.py
index 3fdedaad..73a14b93 100644
--- a/coverage/collector.py
+++ b/coverage/collector.py
@@ -1,12 +1,23 @@
"""Raw data collector for Coverage."""
-import sys, threading
+import os, sys, threading
try:
# Use the C extension code when we can, for speed.
from coverage.tracer import CTracer
except ImportError:
# Couldn't import the C extension, maybe it isn't built.
+ if os.getenv('COVERAGE_TEST_TRACER') == 'c':
+ # During testing, we use the COVERAGE_TEST_TRACER env var to indicate
+ # that we've fiddled with the environment to test this fallback code.
+ # If we thought we had a C tracer, but couldn't import it, then exit
+ # quickly and clearly instead of dribbling confusing errors. I'm using
+ # sys.exit here instead of an exception because an exception here
+ # causes all sorts of other noise in unittest.
+ sys.stderr.write(
+ "*** COVERAGE_TEST_TRACER is 'c' but can't import CTracer!\n"
+ )
+ sys.exit(1)
CTracer = None
diff --git a/coverage/files.py b/coverage/files.py
index e6dc4aa1..e07c5766 100644
--- a/coverage/files.py
+++ b/coverage/files.py
@@ -207,9 +207,17 @@ class PathAliases(object):
def find_python_files(dirname):
- """Yield all of the importable Python files in `dirname`, recursively."""
- for dirpath, dirnames, filenames in os.walk(dirname, topdown=True):
- if '__init__.py' not in filenames:
+ """Yield all of the importable Python files in `dirname`, recursively.
+
+ To be importable, the files have to be in a directory with a __init__.py,
+ except for `dirname` itself, which isn't required to have one. The
+ assumption is that `dirname` was specified directly, so the user knows
+ best, but subdirectories are checked for a __init__.py to be sure we only
+ find the importable files.
+
+ """
+ for i, (dirpath, dirnames, filenames) in enumerate(os.walk(dirname)):
+ if i > 0 and '__init__.py' not in filenames:
# If a directory doesn't have __init__.py, then it isn't
# importable and neither are its files
del dirnames[:]
diff --git a/setup.py b/setup.py
index 39756796..1d4e9efd 100644
--- a/setup.py
+++ b/setup.py
@@ -132,7 +132,7 @@ try:
setup(**setup_args)
except: # pylint: disable=W0702
# When setup() can't compile, it tries to exit. We'll catch SystemExit
- # here :-(, and try again.
+ # here :-(, and try again.
if 'install' not in sys.argv or 'ext_modules' not in setup_args:
# We weren't trying to install an extension, so forget it.
raise
diff --git a/test/test_files.py b/test/test_files.py
index a00a9680..d45f5973 100644
--- a/test/test_files.py
+++ b/test/test_files.py
@@ -147,7 +147,6 @@ class FindPythonFilesTest(CoverageTest):
def test_find_python_files(self):
self.make_file("sub/a.py")
self.make_file("sub/b.py")
- self.make_file("sub/__init__.py")
self.make_file("sub/x.c") # nope: not .py
self.make_file("sub/ssub/__init__.py")
self.make_file("sub/ssub/s.py")
@@ -155,7 +154,7 @@ class FindPythonFilesTest(CoverageTest):
self.make_file("sub/lab/exp.py") # nope: no __init__.py
py_files = set(find_python_files("sub"))
self.assert_same_files(py_files, [
- "sub/__init__.py", "sub/a.py", "sub/b.py",
+ "sub/a.py", "sub/b.py",
"sub/ssub/__init__.py", "sub/ssub/s.py",
])
diff --git a/test/test_oddball.py b/test/test_oddball.py
index 859648fa..1a3bd22f 100644
--- a/test/test_oddball.py
+++ b/test/test_oddball.py
@@ -129,7 +129,13 @@ class RecursionTest(CoverageTest):
class MemoryLeakTest(CoverageTest):
- """Attempt the impossible: test that memory doesn't leak."""
+ """Attempt the impossible: test that memory doesn't leak.
+
+ Note: this test is truly unusual, and may fail unexpectedly.
+ In particular, it is known to fail on PyPy if test_oddball.py is run in
+ isolation: https://bitbucket.org/ned/coveragepy/issue/186
+
+ """
def test_for_leaks(self):
lines = list(range(301, 315))
diff --git a/tox.ini b/tox.ini
index eea9dc85..b67d5f23 100644
--- a/tox.ini
+++ b/tox.ini
@@ -10,9 +10,18 @@ envlist = py24, py25, py26, py27, py32, py33, pypy
setenv = PYTHONPATH=test/eggsrc
commands =
{envpython} setup.py clean
- {envpython} setup.py build_ext --inplace
{envpython} setup.py develop
+
+ # Create test/zipmods.zip
make testdata
+
+ # Remove tracer.so so that we can test the PyTracer
+ rm {toxinidir}/coverage/tracer.so
+
+ # Test with the PyTracer
env COVERAGE_TEST_TRACER="py" nosetests -w {toxinidir}
+
+ # Build tracer.so and test with the CTracer
+ {envpython} setup.py build_ext --inplace
env COVERAGE_TEST_TRACER="c" nosetests -w {toxinidir}
deps = nose