mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
autodoc: Reset `sys.modules
` on partial import failure (#11645)
If importing with ``TYPE_CHECKING is True`` fails, reset the state of ``sys.modules`` so that the attempt with ``TYPE_CHECKING is False`` may succeed. Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com>
This commit is contained in:
parent
e494baa9dd
commit
8248be31db
5
CHANGES
5
CHANGES
@ -16,6 +16,11 @@ Features added
|
|||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
* #11645: Fix a regression preventing autodoc from importing modules within
|
||||||
|
packages that make use of ``if typing.TYPE_CHECKING:`` to guard circular
|
||||||
|
imports needed by type checkers.
|
||||||
|
Patch by Matt Wozniski.
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import importlib
|
import importlib
|
||||||
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import typing
|
import typing
|
||||||
from typing import TYPE_CHECKING, Any, Callable, NamedTuple
|
from typing import TYPE_CHECKING, Any, Callable, NamedTuple
|
||||||
@ -82,13 +83,18 @@ def import_object(modname: str, objpath: list[str], objtype: str = '',
|
|||||||
objpath = list(objpath)
|
objpath = list(objpath)
|
||||||
while module is None:
|
while module is None:
|
||||||
try:
|
try:
|
||||||
|
orig_modules = frozenset(sys.modules)
|
||||||
try:
|
try:
|
||||||
# try importing with ``typing.TYPE_CHECKING == True``
|
# try importing with ``typing.TYPE_CHECKING == True``
|
||||||
typing.TYPE_CHECKING = True
|
typing.TYPE_CHECKING = True
|
||||||
module = import_module(modname, warningiserror=warningiserror)
|
module = import_module(modname, warningiserror=warningiserror)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# if that fails (e.g. circular import), retry with
|
# if that fails (e.g. circular import), retry with
|
||||||
# ``typing.TYPE_CHECKING == False``
|
# ``typing.TYPE_CHECKING == False`` after reverting
|
||||||
|
# changes made to ``sys.modules`` by the failed try
|
||||||
|
for m in [m for m in sys.modules if m not in orig_modules]:
|
||||||
|
sys.modules.pop(m)
|
||||||
|
|
||||||
typing.TYPE_CHECKING = False
|
typing.TYPE_CHECKING = False
|
||||||
module = import_module(modname, warningiserror=warningiserror)
|
module = import_module(modname, warningiserror=warningiserror)
|
||||||
finally:
|
finally:
|
||||||
|
1
tests/roots/test-ext-autodoc/circular_import/__init__.py
Normal file
1
tests/roots/test-ext-autodoc/circular_import/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from circular_import.c import SomeClass
|
1
tests/roots/test-ext-autodoc/circular_import/a.py
Normal file
1
tests/roots/test-ext-autodoc/circular_import/a.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
X = 42
|
4
tests/roots/test-ext-autodoc/circular_import/b.py
Normal file
4
tests/roots/test-ext-autodoc/circular_import/b.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import typing
|
||||||
|
|
||||||
|
if typing.TYPE_CHECKING:
|
||||||
|
from circular_import import SomeClass
|
6
tests/roots/test-ext-autodoc/circular_import/c.py
Normal file
6
tests/roots/test-ext-autodoc/circular_import/c.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import circular_import.a
|
||||||
|
import circular_import.b
|
||||||
|
|
||||||
|
|
||||||
|
class SomeClass:
|
||||||
|
X = circular_import.a.X
|
@ -2024,6 +2024,19 @@ def test_autodoc_TYPE_CHECKING(app):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||||
|
def test_autodoc_TYPE_CHECKING_circular_import(app):
|
||||||
|
options = {"members": None,
|
||||||
|
"undoc-members": None}
|
||||||
|
actual = do_autodoc(app, 'module', 'circular_import', options)
|
||||||
|
assert list(actual) == [
|
||||||
|
'',
|
||||||
|
'.. py:module:: circular_import',
|
||||||
|
'',
|
||||||
|
]
|
||||||
|
assert sys.modules["circular_import"].a is sys.modules["circular_import.a"]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||||
def test_singledispatch(app):
|
def test_singledispatch(app):
|
||||||
options = {"members": None}
|
options = {"members": None}
|
||||||
|
Loading…
Reference in New Issue
Block a user