summaryrefslogtreecommitdiff
path: root/coverage
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2015-10-06 07:14:18 -0400
committerNed Batchelder <ned@nedbatchelder.com>2015-10-06 07:14:18 -0400
commit3b8f4a0b86f8796f1e7925b9c6593a9d5198b437 (patch)
tree68f192e6be5ee3cb4cba489b860a951b75755c28 /coverage
parent0101eff78ab68dcf8a8c20e06c24b68d8e4c45e6 (diff)
downloadpython-coveragepy-git-3b8f4a0b86f8796f1e7925b9c6593a9d5198b437.tar.gz
Protect ourselves from mock'ed os. #416
Diffstat (limited to 'coverage')
-rw-r--r--coverage/annotate.py4
-rw-r--r--coverage/collector.py8
-rw-r--r--coverage/config.py4
-rw-r--r--coverage/control.py3
-rw-r--r--coverage/data.py4
-rw-r--r--coverage/debug.py4
-rw-r--r--coverage/execfile.py4
-rw-r--r--coverage/files.py4
-rw-r--r--coverage/html.py4
-rw-r--r--coverage/misc.py24
-rw-r--r--coverage/plugin_support.py5
-rw-r--r--coverage/python.py4
-rw-r--r--coverage/report.py4
-rw-r--r--coverage/xmlreport.py4
14 files changed, 69 insertions, 11 deletions
diff --git a/coverage/annotate.py b/coverage/annotate.py
index 60772656..4060450f 100644
--- a/coverage/annotate.py
+++ b/coverage/annotate.py
@@ -8,8 +8,12 @@ import os
import re
from coverage.files import flat_rootname
+from coverage.misc import isolate_module
from coverage.report import Reporter
+os = isolate_module(os)
+
+
class AnnotateReporter(Reporter):
"""Generate annotated source files showing line coverage.
diff --git a/coverage/collector.py b/coverage/collector.py
index 42a97f1a..0a43d87c 100644
--- a/coverage/collector.py
+++ b/coverage/collector.py
@@ -3,14 +3,18 @@
"""Raw data collector for coverage.py."""
-import os, sys
+import os
+import sys
from coverage import env
from coverage.backward import iitems
from coverage.files import abs_file
-from coverage.misc import CoverageException
+from coverage.misc import CoverageException, isolate_module
from coverage.pytracer import PyTracer
+os = isolate_module(os)
+
+
try:
# Use the C extension code when we can, for speed.
from coverage.tracer import CTracer, CFileDisposition # pylint: disable=no-name-in-module
diff --git a/coverage/config.py b/coverage/config.py
index 458d4903..cd66697d 100644
--- a/coverage/config.py
+++ b/coverage/config.py
@@ -9,7 +9,9 @@ import re
import sys
from coverage.backward import configparser, iitems, string_class
-from coverage.misc import CoverageException
+from coverage.misc import CoverageException, isolate_module
+
+os = isolate_module(os)
class HandyConfigParser(configparser.RawConfigParser):
diff --git a/coverage/control.py b/coverage/control.py
index 1fb0f5bf..16b5f35e 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -23,7 +23,7 @@ from coverage.files import PathAliases, find_python_files, prep_patterns
from coverage.files import ModuleMatcher, abs_file
from coverage.html import HtmlReporter
from coverage.misc import CoverageException, bool_or_none, join_regex
-from coverage.misc import file_be_gone
+from coverage.misc import file_be_gone, isolate_module
from coverage.monkey import patch_multiprocessing
from coverage.plugin import FileReporter
from coverage.plugin_support import Plugins
@@ -32,6 +32,7 @@ from coverage.results import Analysis, Numbers
from coverage.summary import SummaryReporter
from coverage.xmlreport import XmlReporter
+os = isolate_module(os)
# Pypy has some unusual stuff in the "stdlib". Consider those locations
# when deciding where the stdlib is.
diff --git a/coverage/data.py b/coverage/data.py
index fb0b0224..324d7335 100644
--- a/coverage/data.py
+++ b/coverage/data.py
@@ -16,7 +16,9 @@ from coverage import env
from coverage.backward import iitems, string_class
from coverage.debug import _TEST_NAME_FILE
from coverage.files import PathAliases
-from coverage.misc import CoverageException, file_be_gone
+from coverage.misc import CoverageException, file_be_gone, isolate_module
+
+os = isolate_module(os)
class CoverageData(object):
diff --git a/coverage/debug.py b/coverage/debug.py
index 8d6892bb..4076b9b2 100644
--- a/coverage/debug.py
+++ b/coverage/debug.py
@@ -7,6 +7,10 @@ import inspect
import os
import sys
+from coverage.misc import isolate_module
+
+os = isolate_module(os)
+
# When debugging, it can be helpful to force some options, especially when
# debugging the configuration mechanisms you usually use to control debugging!
diff --git a/coverage/execfile.py b/coverage/execfile.py
index 1845f8d7..844c11bc 100644
--- a/coverage/execfile.py
+++ b/coverage/execfile.py
@@ -10,10 +10,12 @@ import types
from coverage.backward import BUILTINS
from coverage.backward import PYC_MAGIC_NUMBER, imp, importlib_util_find_spec
-from coverage.misc import ExceptionDuringRun, NoCode, NoSource
+from coverage.misc import ExceptionDuringRun, NoCode, NoSource, isolate_module
from coverage.phystokens import compile_unicode
from coverage.python import get_python_source
+os = isolate_module(os)
+
class DummyLoader(object):
"""A shim for the pep302 __loader__, emulating pkgutil.ImpLoader.
diff --git a/coverage/files.py b/coverage/files.py
index 2b8727d4..0b5651cb 100644
--- a/coverage/files.py
+++ b/coverage/files.py
@@ -13,12 +13,14 @@ import sys
from coverage import env
from coverage.backward import unicode_class
-from coverage.misc import CoverageException, join_regex
+from coverage.misc import CoverageException, join_regex, isolate_module
RELATIVE_DIR = None
CANONICAL_FILENAME_CACHE = {}
+os = isolate_module(os)
+
def set_relative_directory():
"""Set the directory that `relative_filename` will be relative to."""
diff --git a/coverage/html.py b/coverage/html.py
index de18cefa..8dca6323 100644
--- a/coverage/html.py
+++ b/coverage/html.py
@@ -13,11 +13,13 @@ import coverage
from coverage import env
from coverage.backward import iitems
from coverage.files import flat_rootname
-from coverage.misc import CoverageException, Hasher
+from coverage.misc import CoverageException, Hasher, isolate_module
from coverage.report import Reporter
from coverage.results import Numbers
from coverage.templite import Templite
+os = isolate_module(os)
+
# Static files are looked for in a list of places.
STATIC_PATH = [
diff --git a/coverage/misc.py b/coverage/misc.py
index 44f89772..36e4fe9c 100644
--- a/coverage/misc.py
+++ b/coverage/misc.py
@@ -7,10 +7,34 @@ import errno
import hashlib
import inspect
import os
+import types
from coverage import env
from coverage.backward import string_class, to_bytes, unicode_class
+ISOLATED_MODULES = {}
+
+
+def isolate_module(mod):
+ """Copy a module so that we are isolated from aggressive mocking.
+
+ If a test suite mocks os.path.exists (for example), and then we need to use
+ it during the test, everything will get tangled up if we use their mock.
+ Making a copy of the module when we import it will isolate coverage.py from
+ those complications.
+ """
+ if mod not in ISOLATED_MODULES:
+ new_mod = types.ModuleType(mod.__name__)
+ ISOLATED_MODULES[mod] = new_mod
+ for name in dir(mod):
+ value = getattr(mod, name)
+ if isinstance(value, types.ModuleType):
+ value = isolate_module(value)
+ setattr(new_mod, name, value)
+ return ISOLATED_MODULES[mod]
+
+os = isolate_module(os)
+
# Use PyContracts for assertion testing on parameters and returns, but only if
# we are running our own test suite.
diff --git a/coverage/plugin_support.py b/coverage/plugin_support.py
index f88342e9..8a4fbec5 100644
--- a/coverage/plugin_support.py
+++ b/coverage/plugin_support.py
@@ -3,12 +3,15 @@
"""Support for plugins."""
+import os
import os.path
import sys
-from coverage.misc import CoverageException
+from coverage.misc import CoverageException, isolate_module
from coverage.plugin import CoveragePlugin, FileTracer, FileReporter
+os = isolate_module(os)
+
class Plugins(object):
"""The currently loaded collection of coverage.py plugins."""
diff --git a/coverage/python.py b/coverage/python.py
index 33e6ec01..71b50f0c 100644
--- a/coverage/python.py
+++ b/coverage/python.py
@@ -7,11 +7,13 @@ import os.path
import zipimport
from coverage import env, files
-from coverage.misc import contract, expensive, NoSource, join_regex
+from coverage.misc import contract, expensive, NoSource, join_regex, isolate_module
from coverage.parser import PythonParser
from coverage.phystokens import source_token_lines, source_encoding
from coverage.plugin import FileReporter
+os = isolate_module(os)
+
@contract(returns='bytes')
def read_python_source(filename):
diff --git a/coverage/report.py b/coverage/report.py
index 78ad7484..df34e43f 100644
--- a/coverage/report.py
+++ b/coverage/report.py
@@ -6,7 +6,9 @@
import os
from coverage.files import prep_patterns, FnmatchMatcher
-from coverage.misc import CoverageException, NoSource, NotPython
+from coverage.misc import CoverageException, NoSource, NotPython, isolate_module
+
+os = isolate_module(os)
class Reporter(object):
diff --git a/coverage/xmlreport.py b/coverage/xmlreport.py
index 998b9599..b8f8a9e4 100644
--- a/coverage/xmlreport.py
+++ b/coverage/xmlreport.py
@@ -9,8 +9,12 @@ import time
import xml.dom.minidom
from coverage import __url__, __version__, files
+from coverage.misc import isolate_module
from coverage.report import Reporter
+os = isolate_module(os)
+
+
DTD_URL = (
'https://raw.githubusercontent.com/cobertura/web/'
'f0366e5e2cf18f111cbd61fc34ef720a6584ba02'