@@ -171,6 +171,8 @@ def _format_node( # ruff:ignore[complex-structure, too-many-return-statements,
171171 if isinstance (annotation , TypeAliasType ):
172172 if (crossref := _type_alias_crossref (annotation , config )) is not None :
173173 return crossref
174+ if not _can_expand_alias (annotation , config ):
175+ return _alias_name_reference (annotation , config )
174176 return (yield annotation .__value__ )
175177
176178 if isinstance (alias := get_origin (annotation ), TypeAliasType | TypeAliasForwardRef ):
@@ -182,9 +184,9 @@ def _format_node( # ruff:ignore[complex-structure, too-many-return-statements,
182184 rendered_alias = yield alias
183185 elif (crossref := _type_alias_crossref (alias , config )) is not None :
184186 rendered_alias = crossref
185- elif _matches_type_params (alias , args ): # an undocumented alias : expand its value, with args substituted
187+ elif _matches_type_params (alias , args ) and _can_expand_alias ( alias , config ) : # undocumented: expand its value
186188 return (yield _substitute_type_params (alias , args ))
187- else : # a wrong-arity subscript cannot expand, so name the alias instead of leaking its type params
189+ else : # cannot expand, so name the alias instead of leaking its type params
188190 rendered_alias = _alias_name_reference (alias , config )
189191 parts = []
190192 for arg in args :
@@ -390,6 +392,30 @@ def _underlying_type_alias(annotation: Any) -> TypeAliasType | None:
390392 return None
391393
392394
395+ def _can_expand_alias (alias : TypeAliasType , config : Config ) -> bool :
396+ """
397+ Whether the alias' lazily evaluated value is available.
398+
399+ A module reached only through an annotation has not had its ``if TYPE_CHECKING`` block executed, so the names
400+ the value uses can still be missing; run that block before giving up, so what we render does not depend on the
401+ order Sphinx reads modules in (#764).
402+ """
403+ if _alias_value_evaluates (alias ):
404+ return True
405+ if (resolve_guarded_imports := getattr (config , "_typehints_resolve_guarded_imports" , None )) is None :
406+ return False
407+ resolve_guarded_imports (inspect .getmodule (alias ))
408+ return _alias_value_evaluates (alias )
409+
410+
411+ def _alias_value_evaluates (alias : TypeAliasType ) -> bool :
412+ try :
413+ _ = alias .__value__
414+ except NameError :
415+ return False
416+ return True
417+
418+
393419def _matches_type_params (alias : TypeAliasType , args : tuple [Any , ...]) -> bool :
394420 """Whether ``args`` can be substituted: the runtime accepts a wrong-arity subscript, so check it here."""
395421 params = alias .__type_params__
0 commit comments