Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 4f3ccf2

Browse filesBrowse files
committed
refactor: a better way to have maybe-importable third-party modules
1 parent 98301ed commit 4f3ccf2
Copy full SHA for 4f3ccf2

File tree

6 files changed

+18
-47
lines changed
Filter options

6 files changed

+18
-47
lines changed

‎coverage/misc.py

Copy file name to clipboardExpand all lines: coverage/misc.py
+5-3Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,16 @@ def import_third_party(modname):
8383
modname (str): the name of the module to import.
8484
8585
Returns:
86-
The imported module, or None if the module couldn't be imported.
86+
The imported module, and a boolean indicating if the module could be imported.
87+
88+
If the boolean is False, the module returned is not the one you want: don't use it.
8789
8890
"""
8991
with sys_modules_saved():
9092
try:
91-
return importlib.import_module(modname)
93+
return importlib.import_module(modname), True
9294
except ImportError:
93-
return None
95+
return sys, False
9496

9597

9698
def nice_pair(pair):

‎coverage/tomlconfig.py

Copy file name to clipboardExpand all lines: coverage/tomlconfig.py
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import os
77
import re
8-
import sys
98

109
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Type, TypeVar
1110

@@ -17,9 +16,10 @@
1716

1817
if env.PYVERSION >= (3, 11, 0, "alpha", 7):
1918
import tomllib # pylint: disable=import-error
19+
has_tomllib = True
2020
else:
2121
# TOML support on Python 3.10 and below is an install-time extra option.
22-
tomllib = import_third_party("tomli")
22+
tomllib, has_tomllib = import_third_party("tomli")
2323

2424

2525
class TomlDecodeError(Exception):
@@ -51,7 +51,7 @@ def read(self, filenames: Iterable[str]) -> List[str]:
5151
toml_text = fp.read()
5252
except OSError:
5353
return []
54-
if sys.version_info >= (3, 11) or tomllib is not None:
54+
if has_tomllib:
5555
try:
5656
self.data = tomllib.loads(toml_text)
5757
except tomllib.TOMLDecodeError as err:

‎tests/helpers.py

Copy file name to clipboardExpand all lines: tests/helpers.py
-20Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@
1515
import textwrap
1616
import warnings
1717

18-
from types import ModuleType
1918
from typing import (
2019
cast,
2120
Any, Callable, Generator, Iterable, List, Optional, Set, Tuple, Type, Union,
2221
)
23-
from unittest import mock
2422

2523
import pytest
2624

@@ -284,24 +282,6 @@ def change_dir(new_dir: str) -> Generator[None, None, None]:
284282
os.chdir(old_dir)
285283

286284

287-
def without_module(using_module: ModuleType, missing_module_name: str) -> mock._patch[Any]:
288-
"""
289-
Hide a module for testing.
290-
291-
Use this in a test function to make an optional module unavailable during
292-
the test::
293-
294-
with without_module(product.something, 'tomli'):
295-
use_toml_somehow()
296-
297-
Arguments:
298-
using_module: a module in which to hide `missing_module_name`.
299-
missing_module_name (str): the name of the module to hide.
300-
301-
"""
302-
return mock.patch.object(using_module, missing_module_name, None)
303-
304-
305285
def assert_count_equal(a: Iterable[Union[int, str]], b: Iterable[Union[int, str]]) -> None:
306286
"""
307287
A pytest-friendly implementation of assertCountEqual.

‎tests/test_config.py

Copy file name to clipboardExpand all lines: tests/test_config.py
+5-6Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
from coverage.tomlconfig import TomlConfigParser
1616

1717
from tests.coveragetest import CoverageTest, UsingModulesMixin
18-
from tests.helpers import without_module
1918

2019

2120
class ConfigTest(CoverageTest):
@@ -713,7 +712,7 @@ def test_nocoveragerc_file_when_specified(self) -> None:
713712

714713
def test_no_toml_installed_no_toml(self) -> None:
715714
# Can't read a toml file that doesn't exist.
716-
with without_module(coverage.tomlconfig, 'tomllib'):
715+
with mock.patch.object(coverage.tomlconfig, "has_tomllib", False):
717716
msg = "Couldn't read 'cov.toml' as a config file"
718717
with pytest.raises(ConfigError, match=msg):
719718
coverage.Coverage(config_file="cov.toml")
@@ -722,7 +721,7 @@ def test_no_toml_installed_no_toml(self) -> None:
722721
def test_no_toml_installed_explicit_toml(self) -> None:
723722
# Can't specify a toml config file if toml isn't installed.
724723
self.make_file("cov.toml", "# A toml file!")
725-
with without_module(coverage.tomlconfig, 'tomllib'):
724+
with mock.patch.object(coverage.tomlconfig, "has_tomllib", False):
726725
msg = "Can't read 'cov.toml' without TOML support"
727726
with pytest.raises(ConfigError, match=msg):
728727
coverage.Coverage(config_file="cov.toml")
@@ -735,7 +734,7 @@ def test_no_toml_installed_pyproject_toml(self) -> None:
735734
[tool.coverage.run]
736735
xyzzy = 17
737736
""")
738-
with without_module(coverage.tomlconfig, 'tomllib'):
737+
with mock.patch.object(coverage.tomlconfig, "has_tomllib", False):
739738
msg = "Can't read 'pyproject.toml' without TOML support"
740739
with pytest.raises(ConfigError, match=msg):
741740
coverage.Coverage()
@@ -748,7 +747,7 @@ def test_no_toml_installed_pyproject_toml_shorter_syntax(self) -> None:
748747
[tool.coverage]
749748
run.parallel = true
750749
""")
751-
with without_module(coverage.tomlconfig, 'tomllib'):
750+
with mock.patch.object(coverage.tomlconfig, "has_tomllib", False):
752751
msg = "Can't read 'pyproject.toml' without TOML support"
753752
with pytest.raises(ConfigError, match=msg):
754753
coverage.Coverage()
@@ -761,7 +760,7 @@ def test_no_toml_installed_pyproject_no_coverage(self) -> None:
761760
[tool.something]
762761
xyzzy = 17
763762
""")
764-
with without_module(coverage.tomlconfig, 'tomllib'):
763+
with mock.patch.object(coverage.tomlconfig, "has_tomllib", False):
765764
cov = coverage.Coverage()
766765
# We get default settings:
767766
assert not cov.config.timid

‎tests/test_misc.py

Copy file name to clipboardExpand all lines: tests/test_misc.py
+4-3Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ def test_success(self):
118118
# Make sure we don't have pytest in sys.modules before we start.
119119
del sys.modules["pytest"]
120120
# Import pytest
121-
mod = import_third_party("pytest")
121+
mod, has = import_third_party("pytest")
122+
assert has
122123
# Yes, it's really pytest:
123124
assert mod.__name__ == "pytest"
124125
print(dir(mod))
@@ -127,8 +128,8 @@ def test_success(self):
127128
assert "pytest" not in sys.modules
128129

129130
def test_failure(self):
130-
mod = import_third_party("xyzzy")
131-
assert mod is None
131+
_, has = import_third_party("xyzzy")
132+
assert not has
132133
assert "xyzzy" not in sys.modules
133134

134135

‎tests/test_testing.py

Copy file name to clipboardExpand all lines: tests/test_testing.py
+1-12Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@
1212
import pytest
1313

1414
import coverage
15-
from coverage import tomlconfig
1615
from coverage.exceptions import CoverageWarning
1716
from coverage.files import actual_path
1817

1918
from tests.coveragetest import CoverageTest
2019
from tests.helpers import (
2120
arcs_to_arcz_repr, arcz_to_arcs, assert_count_equal, assert_coverage_warnings,
22-
CheckUniqueFilenames, re_lines, re_lines_text, re_line, without_module,
21+
CheckUniqueFilenames, re_lines, re_lines_text, re_line,
2322
)
2423

2524

@@ -356,16 +355,6 @@ def _same_python_executable(e1, e2):
356355
return False # pragma: only failure
357356

358357

359-
def test_without_module():
360-
toml1 = tomlconfig.tomllib
361-
with without_module(tomlconfig, 'tomllib'):
362-
toml2 = tomlconfig.tomllib
363-
toml3 = tomlconfig.tomllib
364-
365-
assert toml1 is toml3 is not None
366-
assert toml2 is None
367-
368-
369358
class ArczTest(CoverageTest):
370359
"""Tests of arcz/arcs helpers."""
371360

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.