diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2015-10-06 07:14:18 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2015-10-06 07:14:18 -0400 |
commit | 3b8f4a0b86f8796f1e7925b9c6593a9d5198b437 (patch) | |
tree | 68f192e6be5ee3cb4cba489b860a951b75755c28 /coverage | |
parent | 0101eff78ab68dcf8a8c20e06c24b68d8e4c45e6 (diff) | |
download | python-coveragepy-git-3b8f4a0b86f8796f1e7925b9c6593a9d5198b437.tar.gz |
Protect ourselves from mock'ed os. #416
Diffstat (limited to 'coverage')
-rw-r--r-- | coverage/annotate.py | 4 | ||||
-rw-r--r-- | coverage/collector.py | 8 | ||||
-rw-r--r-- | coverage/config.py | 4 | ||||
-rw-r--r-- | coverage/control.py | 3 | ||||
-rw-r--r-- | coverage/data.py | 4 | ||||
-rw-r--r-- | coverage/debug.py | 4 | ||||
-rw-r--r-- | coverage/execfile.py | 4 | ||||
-rw-r--r-- | coverage/files.py | 4 | ||||
-rw-r--r-- | coverage/html.py | 4 | ||||
-rw-r--r-- | coverage/misc.py | 24 | ||||
-rw-r--r-- | coverage/plugin_support.py | 5 | ||||
-rw-r--r-- | coverage/python.py | 4 | ||||
-rw-r--r-- | coverage/report.py | 4 | ||||
-rw-r--r-- | coverage/xmlreport.py | 4 |
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' |