Skip to content

Commit 8ef0708

Browse files
djhoeseAA-Turner
andauthored
Fix viewcode extension importing modules more than once (#13380)
Co-authored-by: Adam Turner <[email protected]>
1 parent 7e1bf28 commit 8ef0708

File tree

3 files changed

+15
-8
lines changed

3 files changed

+15
-8
lines changed

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Contributors
4545
* Daniel Eades -- improved static typing
4646
* Daniel Hahler -- testing and CI improvements
4747
* Daniel Pizetta -- inheritance diagram improvements
48+
* Dave Hoese -- ``sphinx.ext.viewcode`` bug fix
4849
* Dave Kuhlman -- original LaTeX writer
4950
* Dimitri Papadopoulos Orfanos -- linting and spelling
5051
* Dmitry Shachnev -- modernisation and reproducibility

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Bugs fixed
1919
* #13377: Restore support for using ``sphinx.testing.path`` paths with
2020
``sphinx.testing.fixtures``.
2121
Patch by Kazuya Takei.
22+
* #13380: viewcode: Fix importing modules more than once.
23+
Patch by Dave Hoese.
2224

2325
Testing
2426
-------

sphinx/ext/viewcode.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from __future__ import annotations
44

5-
import importlib.util
5+
import importlib
66
import operator
77
import posixpath
88
import traceback
@@ -62,16 +62,20 @@ def _get_full_modname(modname: str, attribute: str) -> str | None:
6262
num_parts = len(module_path)
6363
for i in range(num_parts, 0, -1):
6464
mod_root = '.'.join(module_path[:i])
65-
module_spec = importlib.util.find_spec(mod_root)
66-
if module_spec is not None:
65+
try:
66+
# import_module() caches the module in sys.modules
67+
module = importlib.import_module(mod_root)
6768
break
69+
except ModuleNotFoundError:
70+
continue
71+
except BaseException as exc:
72+
# Importing modules may cause any side effects, including
73+
# SystemExit, so we need to catch all errors.
74+
msg = f"viewcode failed to import '{mod_root}'."
75+
raise ImportError(msg) from exc
6876
else:
6977
return None
70-
# Load and execute the module
71-
module = importlib.util.module_from_spec(module_spec)
72-
if module_spec.loader is None:
73-
return None
74-
module_spec.loader.exec_module(module)
78+
7579
if i != num_parts:
7680
for mod in module_path[i:]:
7781
module = getattr(module, mod)

0 commit comments

Comments
 (0)