summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2021-03-11 20:52:27 -0500
committerNed Batchelder <ned@nedbatchelder.com>2021-03-11 20:52:27 -0500
commitcdafcb0913ac238300521463436f03571ad9ae9e (patch)
treeb85192e002f9eb7f0b1ada9df1808b7b26f48d1d
parent1d83d59ffacd0736411e492786f83953d247819f (diff)
downloadpython-coveragepy-git-cdafcb0913ac238300521463436f03571ad9ae9e.tar.gz
refactor: pull module cleaning into here
We don't need unittest_mixins' module cleaner anymore.
-rw-r--r--coverage/backward.py6
-rw-r--r--tests/coveragetest.py16
-rw-r--r--tests/helpers.py27
-rw-r--r--tests/mixins.py76
-rw-r--r--tests/test_test_mixins.py27
5 files changed, 86 insertions, 66 deletions
diff --git a/coverage/backward.py b/coverage/backward.py
index ac781ab9..779cd661 100644
--- a/coverage/backward.py
+++ b/coverage/backward.py
@@ -229,12 +229,6 @@ def format_local_datetime(dt):
return dt.strftime('%Y-%m-%d %H:%M')
-def invalidate_import_caches():
- """Invalidate any import caches that may or may not exist."""
- if importlib and hasattr(importlib, "invalidate_caches"):
- importlib.invalidate_caches()
-
-
def import_local_file(modname, modfile=None):
"""Import a local file as a module.
diff --git a/tests/coveragetest.py b/tests/coveragetest.py
index f08de798..65678d52 100644
--- a/tests/coveragetest.py
+++ b/tests/coveragetest.py
@@ -22,8 +22,8 @@ from coverage.backward import StringIO, import_local_file, string_class, shlex_q
from coverage.cmdline import CoverageScript
from tests.helpers import arcs_to_arcz_repr, arcz_to_arcs, assert_count_equal
-from tests.helpers import run_command, SuperModuleCleaner
-from tests.mixins import StdStreamCapturingMixin, TempDirMixin, PytestBase
+from tests.helpers import run_command
+from tests.mixins import PytestBase, StdStreamCapturingMixin, SysPathModulesMixin, TempDirMixin
# Status returns for the command line.
@@ -35,6 +35,7 @@ TESTS_DIR = os.path.dirname(__file__)
class CoverageTest(
StdStreamCapturingMixin,
+ SysPathModulesMixin,
TempDirMixin,
PytestBase,
):
@@ -61,22 +62,11 @@ class CoverageTest(
def setup_test(self):
super(CoverageTest, self).setup_test()
- self.module_cleaner = SuperModuleCleaner()
-
# Attributes for getting info about what happened.
self.last_command_status = None
self.last_command_output = None
self.last_module_name = None
- def clean_local_file_imports(self):
- """Clean up the results of calls to `import_local_file`.
-
- Use this if you need to `import_local_file` the same file twice in
- one test.
-
- """
- self.module_cleaner.clean_local_file_imports()
-
def start_import_stop(self, cov, modname, modfile=None):
"""Start coverage, import a file, then stop coverage.
diff --git a/tests/helpers.py b/tests/helpers.py
index 195fefde..d4dd33ea 100644
--- a/tests/helpers.py
+++ b/tests/helpers.py
@@ -8,15 +8,13 @@ import contextlib
import glob
import os
import re
-import shutil
import subprocess
import sys
import mock
-from unittest_mixins import ModuleCleaner
from coverage import env
-from coverage.backward import invalidate_import_caches, unicode_class
+from coverage.backward import unicode_class
from coverage.misc import output_encoding
@@ -115,29 +113,6 @@ def remove_files(*patterns):
os.remove(fname)
-class SuperModuleCleaner(ModuleCleaner):
- """Remember the state of sys.modules and restore it later."""
-
- def clean_local_file_imports(self):
- """Clean up the results of calls to `import_local_file`.
-
- Use this if you need to `import_local_file` the same file twice in
- one test.
-
- """
- # So that we can re-import files, clean them out first.
- self.cleanup_modules()
-
- # Also have to clean out the .pyc file, since the timestamp
- # resolution is only one second, a changed file might not be
- # picked up.
- remove_files("*.pyc", "*$py.class")
- if os.path.exists("__pycache__"):
- shutil.rmtree("__pycache__")
-
- invalidate_import_caches()
-
-
# Map chars to numbers for arcz_to_arcs
_arcz_map = {'.': -1}
_arcz_map.update(dict((c, ord(c) - ord('0')) for c in '123456789'))
diff --git a/tests/mixins.py b/tests/mixins.py
index 7492e90c..ef9cdb6f 100644
--- a/tests/mixins.py
+++ b/tests/mixins.py
@@ -9,12 +9,16 @@ Some of these are transitional while working toward pure-pytest style.
import os
import os.path
+import shutil
import sys
import textwrap
import pytest
from coverage import env
+from coverage.backward import importlib
+
+from tests.helpers import remove_files
class PytestBase(object):
@@ -78,26 +82,6 @@ class TempDirMixin(object):
if old_dir is not None:
os.chdir(old_dir)
- @pytest.fixture(autouse=True)
- def _save_sys_path(self):
- """Restore sys.path at the end of each test."""
- old_syspath = sys.path[:]
- try:
- yield
- finally:
- sys.path = old_syspath
-
- @pytest.fixture(autouse=True)
- def _module_saving(self):
- """Remove modules we imported during the test."""
- old_modules = list(sys.modules)
- try:
- yield
- finally:
- added_modules = [m for m in sys.modules if m not in old_modules]
- for m in added_modules:
- del sys.modules[m]
-
def make_file(self, filename, text="", bytes=b"", newline=None):
"""Create a file for testing.
@@ -138,6 +122,58 @@ class TempDirMixin(object):
return filename
+class SysPathModulesMixin:
+ """Auto-restore sys.path and the imported modules at the end of each test."""
+
+ @pytest.fixture(autouse=True)
+ def _save_sys_path(self):
+ """Restore sys.path at the end of each test."""
+ old_syspath = sys.path[:]
+ try:
+ yield
+ finally:
+ sys.path = old_syspath
+
+ @pytest.fixture(autouse=True)
+ def _module_saving(self):
+ """Remove modules we imported during the test."""
+ self._old_modules = list(sys.modules)
+ try:
+ yield
+ finally:
+ self._cleanup_modules()
+
+ def _cleanup_modules(self):
+ """Remove any new modules imported since our construction.
+
+ This lets us import the same source files for more than one test, or
+ if called explicitly, within one test.
+
+ """
+ for m in [m for m in sys.modules if m not in self._old_modules]:
+ del sys.modules[m]
+
+ def clean_local_file_imports(self):
+ """Clean up the results of calls to `import_local_file`.
+
+ Use this if you need to `import_local_file` the same file twice in
+ one test.
+
+ """
+ # So that we can re-import files, clean them out first.
+ self._cleanup_modules()
+
+ # Also have to clean out the .pyc file, since the timestamp
+ # resolution is only one second, a changed file might not be
+ # picked up.
+ remove_files("*.pyc", "*$py.class")
+ if os.path.exists("__pycache__"):
+ shutil.rmtree("__pycache__")
+
+ if importlib and hasattr(importlib, "invalidate_caches"):
+ importlib.invalidate_caches()
+
+
class StdStreamCapturingMixin:
"""
Adapter from the pytest capsys fixture to more convenient methods.
diff --git a/tests/test_test_mixins.py b/tests/test_test_mixins.py
index b8a3ac67..028a19fd 100644
--- a/tests/test_test_mixins.py
+++ b/tests/test_test_mixins.py
@@ -4,7 +4,11 @@
"""Tests of code in tests/mixins.py"""
-from tests.mixins import TempDirMixin
+import pytest
+
+from coverage.backward import import_local_file
+
+from tests.mixins import TempDirMixin, SysPathModulesMixin
class TempDirMixinTest(TempDirMixin):
@@ -54,3 +58,24 @@ class TempDirMixinTest(TempDirMixin):
with open("binary.dat", "rb") as f:
data = f.read()
assert data == b"\x99\x33\x66hello\0"
+
+
+class SysPathModulessMixinTest(TempDirMixin, SysPathModulesMixin):
+ """Tests of SysPathModulesMixin."""
+
+ @pytest.mark.parametrize("val", [17, 42])
+ def test_module_independence(self, val):
+ self.make_file("xyzzy.py", "A = {}".format(val))
+ import xyzzy # pylint: disable=import-error
+ assert xyzzy.A == val
+
+ def test_cleanup_and_reimport(self):
+ self.make_file("xyzzy.py", "A = 17")
+ xyzzy = import_local_file("xyzzy")
+ assert xyzzy.A == 17
+
+ self.clean_local_file_imports()
+
+ self.make_file("xyzzy.py", "A = 42")
+ xyzzy = import_local_file("xyzzy")
+ assert xyzzy.A == 42