22
33from __future__ import annotations
44
5+ import contextlib
56import importlib
7+ import os
68import sys
79import traceback
810import typing
2123)
2224
2325if TYPE_CHECKING :
26+ from types import ModuleType
27+
2428 from sphinx .ext .autodoc import ObjectMember
2529
2630logger = logging .getLogger (__name__ )
@@ -69,6 +73,19 @@ def import_module(modname: str, warningiserror: bool = False) -> Any:
6973 raise ImportError (exc , traceback .format_exc ()) from exc
7074
7175
76+ def _reload_module (module : ModuleType , warningiserror : bool = False ) -> Any :
77+ """
78+ Call importlib.reload(module), convert exceptions to ImportError
79+ """
80+ try :
81+ with logging .skip_warningiserror (not warningiserror ):
82+ return importlib .reload (module )
83+ except BaseException as exc :
84+ # Importing modules may cause any side effects, including
85+ # SystemExit, so we need to catch all errors.
86+ raise ImportError (exc , traceback .format_exc ()) from exc
87+
88+
7289def import_object (modname : str , objpath : list [str ], objtype : str = '' ,
7390 attrgetter : Callable [[Any , str ], Any ] = safe_getattr ,
7491 warningiserror : bool = False ) -> Any :
@@ -83,23 +100,20 @@ def import_object(modname: str, objpath: list[str], objtype: str = '',
83100 objpath = list (objpath )
84101 while module is None :
85102 try :
86- orig_modules = frozenset (sys .modules )
87- try :
88- # try importing with ``typing.TYPE_CHECKING == True``
89- typing .TYPE_CHECKING = True
90- module = import_module (modname , warningiserror = warningiserror )
91- except ImportError :
92- # if that fails (e.g. circular import), retry with
93- # ``typing.TYPE_CHECKING == False`` after reverting
94- # changes made to ``sys.modules`` by the failed try
95- for m in [m for m in sys .modules if m not in orig_modules ]:
96- sys .modules .pop (m )
97-
98- typing .TYPE_CHECKING = False
99- module = import_module (modname , warningiserror = warningiserror )
100- finally :
101- # ensure ``typing.TYPE_CHECKING == False``
102- typing .TYPE_CHECKING = False
103+ original_module_names = frozenset (sys .modules )
104+ module = import_module (modname , warningiserror = warningiserror )
105+ if os .environ .get ('SPHINX_AUTODOC_RELOAD_MODULES' ):
106+ new_modules = [m for m in sys .modules if m not in original_module_names ]
107+ # Try reloading modules with ``typing.TYPE_CHECKING == True``.
108+ try :
109+ typing .TYPE_CHECKING = True
110+ # Ignore failures; we've already successfully loaded these modules
111+ with contextlib .suppress (ImportError , KeyError ):
112+ for m in new_modules :
113+ _reload_module (sys .modules [m ])
114+ finally :
115+ typing .TYPE_CHECKING = False
116+ module = sys .modules [modname ]
103117 logger .debug ('[autodoc] import %s => %r' , modname , module )
104118 except ImportError as exc :
105119 logger .debug ('[autodoc] import %s => failed' , modname )
0 commit comments