Skip to content

Commit 6d6bc97

Browse files
authored
#7124: Fix --doctest-modules crashing when __main__.py is present (#8949)
* Fix ``--doctest-modules`` crashing when ``__main__.py`` is present
1 parent 6a1ba80 commit 6d6bc97

File tree

6 files changed

+30
-1
lines changed

6 files changed

+30
-1
lines changed

changelog/7124.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed an issue where ``__main__.py`` would raise an ``ImportError`` when ``--doctest-modules`` was provided.

src/_pytest/doctest.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,9 @@ def pytest_collect_file(
125125
) -> Optional[Union["DoctestModule", "DoctestTextfile"]]:
126126
config = parent.config
127127
if fspath.suffix == ".py":
128-
if config.option.doctestmodules and not _is_setup_py(fspath):
128+
if config.option.doctestmodules and not any(
129+
(_is_setup_py(fspath), _is_main_py(fspath))
130+
):
129131
mod: DoctestModule = DoctestModule.from_parent(parent, path=fspath)
130132
return mod
131133
elif _is_doctest(config, fspath, parent):
@@ -148,6 +150,10 @@ def _is_doctest(config: Config, path: Path, parent: Collector) -> bool:
148150
return any(fnmatch_ex(glob, path) for glob in globs)
149151

150152

153+
def _is_main_py(path: Path) -> bool:
154+
return path.name == "__main__.py"
155+
156+
151157
class ReprFailDoctest(TerminalRepr):
152158
def __init__(
153159
self, reprlocation_lines: Sequence[Tuple[ReprFileLocation, Sequence[str]]]

testing/example_scripts/__init__.py

Whitespace-only changes.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def test_this_is_ignored():
2+
assert True
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
def test_doc():
2+
"""
3+
>>> 10 > 5
4+
True
5+
"""
6+
assert False

testing/test_doctest.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import pytest
88
from _pytest.doctest import _get_checker
9+
from _pytest.doctest import _is_main_py
910
from _pytest.doctest import _is_mocked
1011
from _pytest.doctest import _is_setup_py
1112
from _pytest.doctest import _patch_unwrap_mock_aware
@@ -811,6 +812,11 @@ def test_valid_setup_py(self, pytester: Pytester):
811812
result = pytester.runpytest(p, "--doctest-modules")
812813
result.stdout.fnmatch_lines(["*collected 0 items*"])
813814

815+
def test_main_py_does_not_cause_import_errors(self, pytester: Pytester):
816+
p = pytester.copy_example("doctest/main_py")
817+
result = pytester.runpytest(p, "--doctest-modules")
818+
result.stdout.fnmatch_lines(["*collected 2 items*", "*1 failed, 1 passed*"])
819+
814820
def test_invalid_setup_py(self, pytester: Pytester):
815821
"""
816822
Test to make sure that pytest reads setup.py files that are not used
@@ -1518,3 +1524,11 @@ def test_is_setup_py_different_encoding(tmp_path: Path, mod: str) -> None:
15181524
)
15191525
setup_py.write_bytes(contents.encode("cp1252"))
15201526
assert _is_setup_py(setup_py)
1527+
1528+
1529+
@pytest.mark.parametrize(
1530+
"name, expected", [("__main__.py", True), ("__init__.py", False)]
1531+
)
1532+
def test_is_main_py(tmp_path: Path, name: str, expected: bool) -> None:
1533+
dunder_main = tmp_path.joinpath(name)
1534+
assert _is_main_py(dunder_main) == expected

0 commit comments

Comments
 (0)