summaryrefslogtreecommitdiff
path: root/coverage
diff options
context:
space:
mode:
Diffstat (limited to 'coverage')
-rw-r--r--coverage/control.py29
-rw-r--r--coverage/files.py92
-rw-r--r--coverage/python.py10
-rw-r--r--coverage/xmlreport.py9
4 files changed, 70 insertions, 70 deletions
diff --git a/coverage/control.py b/coverage/control.py
index 9256edb2..3cae1d36 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -9,14 +9,14 @@ import socket
import sys
import traceback
-from coverage import env
+from coverage import env, files
from coverage.annotate import AnnotateReporter
from coverage.backward import string_class, iitems
from coverage.collector import Collector
from coverage.config import CoverageConfig
from coverage.data import CoverageData
from coverage.debug import DebugControl
-from coverage.files import FileLocator, TreeMatcher, FnmatchMatcher
+from coverage.files import TreeMatcher, FnmatchMatcher
from coverage.files import PathAliases, find_python_files, prep_patterns
from coverage.files import ModuleMatcher, abs_file
from coverage.html import HtmlReporter
@@ -167,7 +167,7 @@ class Coverage(object):
# Other instance attributes, set later.
self.omit = self.include = self.source = None
- self.source_pkgs = self.file_locator = None
+ self.source_pkgs = None
self.data = self.collector = None
self.plugins = self.file_tracing_plugins = None
self.pylib_dirs = self.cover_dirs = None
@@ -214,14 +214,14 @@ class Coverage(object):
self._exclude_re = {}
self._exclude_regex_stale()
- self.file_locator = FileLocator()
+ files.set_relative_directory()
# The source argument can be directories or package names.
self.source = []
self.source_pkgs = []
for src in self.config.source or []:
if os.path.exists(src):
- self.source.append(self.file_locator.canonical_filename(src))
+ self.source.append(files.canonical_filename(src))
else:
self.source_pkgs.append(src)
@@ -468,7 +468,7 @@ class Coverage(object):
if filename.endswith("$py.class"):
filename = filename[:-9] + ".py"
- canonical = self.file_locator.canonical_filename(filename)
+ canonical = files.canonical_filename(filename)
disp.canonical_filename = canonical
# Try the plugins, see if they have an opinion about the file.
@@ -486,10 +486,9 @@ class Coverage(object):
if file_tracer.has_dynamic_source_filename():
disp.has_dynamic_filename = True
else:
- disp.source_filename = \
- self.file_locator.canonical_filename(
- file_tracer.source_filename()
- )
+ disp.source_filename = files.canonical_filename(
+ file_tracer.source_filename()
+ )
break
except Exception:
self._warn(
@@ -740,7 +739,7 @@ class Coverage(object):
self._init()
aliases = None
if self.config.paths:
- aliases = PathAliases(self.file_locator)
+ aliases = PathAliases()
for paths in self.config.paths.values():
result = paths[0]
for pattern in paths[1:]:
@@ -792,7 +791,7 @@ class Coverage(object):
# Find files that were never executed at all.
for src in self.source:
for py_file in find_python_files(src):
- py_file = self.file_locator.canonical_filename(py_file)
+ py_file = files.canonical_filename(py_file)
if self.omit_match and self.omit_match.match(py_file):
# Turns out this file was omitted, so don't pull it back
@@ -872,9 +871,7 @@ class Coverage(object):
# The FileReporter can have a name attribute, but if it doesn't, we'll
# supply it as the relative path to self.filename.
if not hasattr(file_reporter, "name"):
- file_reporter.name = self.file_locator.relative_filename(
- file_reporter.filename
- )
+ file_reporter.name = files.relative_filename(file_reporter.filename)
return file_reporter
@@ -1013,7 +1010,7 @@ class Coverage(object):
outfile = open(self.config.xml_output, "w")
file_to_close = outfile
try:
- reporter = XmlReporter(self, self.config, self.file_locator)
+ reporter = XmlReporter(self, self.config)
return reporter.report(morfs, outfile=outfile)
except CoverageException:
delete_file = True
diff --git a/coverage/files.py b/coverage/files.py
index a800b7a9..665e2f33 100644
--- a/coverage/files.py
+++ b/coverage/files.py
@@ -12,55 +12,66 @@ from coverage import env
from coverage.misc import CoverageException, join_regex
-class FileLocator(object):
- """Understand how filenames work."""
+RELATIVE_DIR = None
+CANONICAL_FILENAME_CACHE = {}
- def __init__(self):
- # The absolute path to our current directory.
- self.relative_dir = os.path.normcase(abs_file(os.curdir) + os.sep)
- # Cache of results of calling the canonical_filename() method, to
- # avoid duplicating work.
- self.canonical_filename_cache = {}
+def set_relative_directory():
+ """Set the directory that `relative_filename` will be relative to."""
+ global RELATIVE_DIR, CANONICAL_FILENAME_CACHE
- def relative_filename(self, filename):
- """Return the relative form of `filename`.
+ # The absolute path to our current directory.
+ RELATIVE_DIR = os.path.normcase(abs_file(os.curdir) + os.sep)
- The filename will be relative to the current directory when the
- `FileLocator` was constructed.
+ # Cache of results of calling the canonical_filename() method, to
+ # avoid duplicating work.
+ CANONICAL_FILENAME_CACHE = {}
- """
- fnorm = os.path.normcase(filename)
- if fnorm.startswith(self.relative_dir):
- filename = filename[len(self.relative_dir):]
- return filename
+def relative_directory():
+ """Return the directory that `relative_filename` is relative to."""
+ return RELATIVE_DIR
- def canonical_filename(self, filename):
- """Return a canonical filename for `filename`.
+def relative_filename(filename):
+ """Return the relative form of `filename`.
- An absolute path with no redundant components and normalized case.
+ The filename will be relative to the current directory when the
+ `set_relative_directory` was called.
- """
- if filename not in self.canonical_filename_cache:
- if not os.path.isabs(filename):
- for path in [os.curdir] + sys.path:
- if path is None:
- continue
- f = os.path.join(path, filename)
- if os.path.exists(f):
- filename = f
- break
- cf = abs_file(filename)
- self.canonical_filename_cache[filename] = cf
- return self.canonical_filename_cache[filename]
+ """
+ fnorm = os.path.normcase(filename)
+ if fnorm.startswith(RELATIVE_DIR):
+ filename = filename[len(RELATIVE_DIR):]
+ return filename
+
+def canonical_filename(filename):
+ """Return a canonical filename for `filename`.
+
+ An absolute path with no redundant components and normalized case.
+
+ """
+ if filename not in CANONICAL_FILENAME_CACHE:
+ if not os.path.isabs(filename):
+ for path in [os.curdir] + sys.path:
+ if path is None:
+ continue
+ f = os.path.join(path, filename)
+ if os.path.exists(f):
+ filename = f
+ break
+ cf = abs_file(filename)
+ CANONICAL_FILENAME_CACHE[filename] = cf
+ return CANONICAL_FILENAME_CACHE[filename]
if env.WINDOWS:
+ _ACTUAL_PATH_CACHE = {}
+ _ACTUAL_PATH_LIST_CACHE = {}
+
def actual_path(path):
"""Get the actual path of `path`, including the correct case."""
- if path in actual_path.cache:
- return actual_path.cache[path]
+ if path in _ACTUAL_PATH_CACHE:
+ return _ACTUAL_PATH_CACHE[path]
head, tail = os.path.split(path)
if not tail:
@@ -70,26 +81,23 @@ if env.WINDOWS:
actpath = tail
else:
head = actual_path(head)
- if head in actual_path.list_cache:
- files = actual_path.list_cache[head]
+ if head in _ACTUAL_PATH_LIST_CACHE:
+ files = _ACTUAL_PATH_LIST_CACHE[head]
else:
try:
files = os.listdir(head)
except OSError:
files = []
- actual_path.list_cache[head] = files
+ _ACTUAL_PATH_LIST_CACHE[head] = files
normtail = os.path.normcase(tail)
for f in files:
if os.path.normcase(f) == normtail:
tail = f
break
actpath = os.path.join(head, tail)
- actual_path.cache[path] = actpath
+ _ACTUAL_PATH_CACHE[path] = actpath
return actpath
- actual_path.cache = {}
- actual_path.list_cache = {}
-
else:
def actual_path(filename):
"""The actual path for non-Windows platforms."""
diff --git a/coverage/python.py b/coverage/python.py
index 69823da7..8dc163df 100644
--- a/coverage/python.py
+++ b/coverage/python.py
@@ -3,8 +3,7 @@
import os.path
import zipimport
-from coverage import env
-from coverage.files import FileLocator
+from coverage import env, files
from coverage.misc import contract, NoSource, join_regex
from coverage.parser import PythonParser
from coverage.phystokens import source_token_lines, source_encoding
@@ -85,7 +84,6 @@ class PythonFileReporter(FileReporter):
def __init__(self, morf, coverage=None):
self.coverage = coverage
- file_locator = coverage.file_locator if coverage else FileLocator()
if hasattr(morf, '__file__'):
filename = morf.__file__
@@ -98,15 +96,13 @@ class PythonFileReporter(FileReporter):
elif filename.endswith('$py.class'): # Jython
filename = filename[:-9] + ".py"
- super(PythonFileReporter, self).__init__(
- file_locator.canonical_filename(filename)
- )
+ super(PythonFileReporter, self).__init__(files.canonical_filename(filename))
if hasattr(morf, '__name__'):
name = morf.__name__
name = name.replace(".", os.sep) + ".py"
else:
- name = file_locator.relative_filename(filename)
+ name = files.relative_filename(filename)
self.name = name
self._source = None
diff --git a/coverage/xmlreport.py b/coverage/xmlreport.py
index 996f19a2..49b73122 100644
--- a/coverage/xmlreport.py
+++ b/coverage/xmlreport.py
@@ -5,7 +5,7 @@ import sys
import time
import xml.dom.minidom
-from coverage import __url__, __version__
+from coverage import __url__, __version__, files
from coverage.report import Reporter
@@ -20,10 +20,9 @@ def rate(hit, num):
class XmlReporter(Reporter):
"""A reporter for writing Cobertura-style XML coverage results."""
- def __init__(self, coverage, config, file_locator):
+ def __init__(self, coverage, config):
super(XmlReporter, self).__init__(coverage, config)
- self.file_locator = file_locator
self.source_paths = set()
self.packages = {}
self.xml_out = None
@@ -122,7 +121,7 @@ class XmlReporter(Reporter):
# Create the 'lines' and 'package' XML elements, which
# are populated later. Note that a package == a directory.
- filename = self.file_locator.relative_filename(fr.filename)
+ filename = files.relative_filename(fr.filename)
filename = filename.replace("\\", "/")
dirname = os.path.dirname(filename) or "."
parts = dirname.split("/")
@@ -130,7 +129,7 @@ class XmlReporter(Reporter):
package_name = dirname.replace("/", ".")
className = fr.name
- self.source_paths.add(self.file_locator.relative_dir.rstrip('/'))
+ self.source_paths.add(files.relative_directory().rstrip('/'))
package = self.packages.setdefault(package_name, [{}, 0, 0, 0, 0])
xclass = self.xml_out.createElement("class")