Skip to content

Commit

Permalink
[7.4.x] Add child modules as attributes of parent modules. (#11163)
Browse files Browse the repository at this point in the history
* [7.4.x] Add child modules as attributes of parent modules.

* Update 10337.bugfix.rst

---------

Co-authored-by: akhilramkee <[email protected]>
Co-authored-by: Bruno Oliveira <[email protected]>
  • Loading branch information
3 people authored Jul 8, 2023
1 parent d539518 commit c71b5df
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 1 deletion.
2 changes: 2 additions & 0 deletions changelog/10337.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fixed bug where fake intermediate modules generated by ``--import-mode=importlib`` would not include the
child modules as attributes of the parent modules.
14 changes: 13 additions & 1 deletion src/_pytest/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,9 @@ def insert_missing_modules(modules: Dict[str, ModuleType], module_name: str) ->
otherwise "src.tests.test_foo" is not importable by ``__import__``.
"""
module_parts = module_name.split(".")
child_module: Union[ModuleType, None] = None
module: Union[ModuleType, None] = None
child_name: str = ""
while module_name:
if module_name not in modules:
try:
Expand All @@ -644,13 +647,22 @@ def insert_missing_modules(modules: Dict[str, ModuleType], module_name: str) ->
# ourselves to fall back to creating a dummy module.
if not sys.meta_path:
raise ModuleNotFoundError
importlib.import_module(module_name)
module = importlib.import_module(module_name)
except ModuleNotFoundError:
module = ModuleType(
module_name,
doc="Empty module created by pytest's importmode=importlib.",
)
else:
module = modules[module_name]
if child_module:
# Add child attribute to the parent that can reference the child
# modules.
if not hasattr(module, child_name):
setattr(module, child_name, child_module)
modules[module_name] = module
# Keep track of the child module while moving up the tree.
child_module, child_name = module, module_name.rpartition(".")[-1]
module_parts.pop(-1)
module_name = ".".join(module_parts)

Expand Down
12 changes: 12 additions & 0 deletions testing/test_pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -603,3 +603,15 @@ def test_insert_missing_modules(
modules = {}
insert_missing_modules(modules, "")
assert modules == {}

def test_parent_contains_child_module_attribute(
self, monkeypatch: MonkeyPatch, tmp_path: Path
):
monkeypatch.chdir(tmp_path)
# Use 'xxx' and 'xxy' as parent names as they are unlikely to exist and
# don't end up being imported.
modules = {"xxx.tests.foo": ModuleType("xxx.tests.foo")}
insert_missing_modules(modules, "xxx.tests.foo")
assert sorted(modules) == ["xxx", "xxx.tests", "xxx.tests.foo"]
assert modules["xxx"].tests is modules["xxx.tests"]
assert modules["xxx.tests"].foo is modules["xxx.tests.foo"]

0 comments on commit c71b5df

Please sign in to comment.