1414from docutils .parsers .rst .states import Inliner
1515
1616if TYPE_CHECKING :
17- from typing import Literal
17+ from collections .abc import Mapping
18+ from typing import Final , Literal
1819
1920 from typing_extensions import TypeAlias
2021
3637 UnionType = None
3738
3839# classes that have an incorrect .__module__ attribute
39- _INVALID_BUILTIN_CLASSES = {
40+ _INVALID_BUILTIN_CLASSES : Final [ Mapping [ object , str ]] = {
4041 Context : 'contextvars.Context' , # Context.__module__ == '_contextvars'
4142 ContextVar : 'contextvars.ContextVar' , # ContextVar.__module__ == '_contextvars'
4243 Token : 'contextvars.Token' , # Token.__module__ == '_contextvars'
@@ -83,8 +84,10 @@ def is_invalid_builtin_class(obj: Any) -> bool:
8384PathMatcher = Callable [[str ], bool ]
8485
8586# common role functions
86- RoleFunction = Callable [[str , str , str , int , Inliner , dict [str , Any ], Sequence [str ]],
87- tuple [list [nodes .Node ], list [nodes .system_message ]]]
87+ RoleFunction = Callable [
88+ [str , str , str , int , Inliner , dict [str , Any ], Sequence [str ]],
89+ tuple [list [nodes .Node ], list [nodes .system_message ]],
90+ ]
8891
8992# A option spec for directive
9093OptionSpec = dict [str , Callable [[str ], Any ]]
@@ -127,7 +130,9 @@ class ExtensionMetadata(TypedDict, total=False):
127130
128131
129132def get_type_hints (
130- obj : Any , globalns : dict [str , Any ] | None = None , localns : dict [str , Any ] | None = None ,
133+ obj : Any ,
134+ globalns : dict [str , Any ] | None = None ,
135+ localns : dict [str , Any ] | None = None ,
131136) -> dict [str , Any ]:
132137 """Return a dictionary containing type hints for a function, method, module or class
133138 object.
@@ -201,13 +206,15 @@ def restify(cls: type | None, mode: _RestifyMode = 'fully-qualified-except-typin
201206 elif ismock (cls ):
202207 return f':py:class:`{ modprefix } { cls .__module__ } .{ cls .__name__ } `'
203208 elif is_invalid_builtin_class (cls ):
209+ # The above predicate never raises TypeError but should not be
210+ # evaluated before determining whether *cls* is a mocked object
211+ # or not; instead of two try-except blocks, we keep it here.
204212 return f':py:class:`{ modprefix } { _INVALID_BUILTIN_CLASSES [cls ]} `'
205213 elif inspect .isNewType (cls ):
206214 if sys .version_info [:2 ] >= (3 , 10 ):
207215 # newtypes have correct module info since Python 3.10+
208216 return f':py:class:`{ modprefix } { cls .__module__ } .{ cls .__name__ } `'
209- else :
210- return f':py:class:`{ cls .__name__ } `'
217+ return f':py:class:`{ cls .__name__ } `'
211218 elif UnionType and isinstance (cls , UnionType ):
212219 # Union types (PEP 585) retain their definition order when they
213220 # are printed natively and ``None``-like types are kept as is.
@@ -219,8 +226,7 @@ def restify(cls: type | None, mode: _RestifyMode = 'fully-qualified-except-typin
219226
220227 concatenated_args = ', ' .join (restify (arg , mode ) for arg in cls .__args__ )
221228 return fr':py:class:`{ cls .__name__ } `\ [{ concatenated_args } ]'
222- else :
223- return f':py:class:`{ cls .__name__ } `'
229+ return f':py:class:`{ cls .__name__ } `'
224230 elif (inspect .isgenericalias (cls )
225231 and cls .__module__ == 'typing'
226232 and cls .__origin__ is Union ): # type: ignore[attr-defined]
@@ -241,10 +247,9 @@ def restify(cls: type | None, mode: _RestifyMode = 'fully-qualified-except-typin
241247 elif all (is_system_TypeVar (a ) for a in cls .__args__ ):
242248 # Suppress arguments if all system defined TypeVars (ex. Dict[KT, VT])
243249 pass
244- elif (cls .__module__ == 'typing'
245- and cls ._name == 'Callable' ): # type: ignore[attr-defined]
250+ elif cls .__module__ == 'typing' and cls ._name == 'Callable' : # type: ignore[attr-defined]
246251 args = ', ' .join (restify (a , mode ) for a in cls .__args__ [:- 1 ])
247- text += fr" \ [[{ args } ], { restify (cls .__args__ [- 1 ], mode )} ]"
252+ text += fr' \ [[{ args } ], { restify (cls .__args__ [- 1 ], mode )} ]'
248253 elif cls .__module__ == 'typing' and getattr (origin , '_name' , None ) == 'Literal' :
249254 args = ', ' .join (_format_literal_arg_restify (a , mode = mode )
250255 for a in cls .__args__ )
@@ -327,45 +332,45 @@ def stringify_annotation(
327332 else :
328333 module_prefix = ''
329334
330- annotation_qualname = getattr (annotation , '__qualname__' , '' )
331- annotation_module = getattr (annotation , '__module__' , '' )
332- annotation_name = getattr (annotation , '__name__' , '' )
335+ # The values below must be strings if the objects are well-formed.
336+ annotation_qualname : str = getattr (annotation , '__qualname__' , '' )
337+ annotation_module : str = getattr (annotation , '__module__' , '' )
338+ annotation_name : str = getattr (annotation , '__name__' , '' )
333339 annotation_module_is_typing = annotation_module == 'typing'
334340
335341 if isinstance (annotation , TypeVar ):
336342 if annotation_module_is_typing and mode in {'fully-qualified-except-typing' , 'smart' }:
337343 return annotation_name
338- else :
339- return module_prefix + f'{ annotation_module } .{ annotation_name } '
344+ return module_prefix + f'{ annotation_module } .{ annotation_name } '
340345 elif isNewType (annotation ):
341346 if sys .version_info [:2 ] >= (3 , 10 ):
342347 # newtypes have correct module info since Python 3.10+
343348 return module_prefix + f'{ annotation_module } .{ annotation_name } '
344- else :
345- return annotation_name
349+ return annotation_name
346350 elif ismockmodule (annotation ):
347351 return module_prefix + annotation_name
348352 elif ismock (annotation ):
349353 return module_prefix + f'{ annotation_module } .{ annotation_name } '
350354 elif is_invalid_builtin_class (annotation ):
351355 return module_prefix + _INVALID_BUILTIN_CLASSES [annotation ]
352- elif str (annotation ).startswith ('typing.Annotated' ): # for py310 +
356+ elif str (annotation ).startswith ('typing.Annotated' ): # for py39 +
353357 pass
354358 elif annotation_module == 'builtins' and annotation_qualname :
355- if (args := getattr (annotation , '__args__' , None )) is not None : # PEP 585 generic
356- if not args : # Empty tuple, list, ...
357- return repr (annotation )
358-
359- concatenated_args = ', ' .join (stringify_annotation (arg , mode ) for arg in args )
360- return f'{ annotation_qualname } [{ concatenated_args } ]'
361- else :
359+ args = getattr (annotation , '__args__' , None )
360+ if args is None :
362361 return annotation_qualname
363362
363+ # PEP 585 generic
364+ if not args : # Empty tuple, list, ...
365+ return repr (annotation )
366+ concatenated_args = ', ' .join (stringify_annotation (arg , mode ) for arg in args )
367+ return f'{ annotation_qualname } [{ concatenated_args } ]'
368+
364369 module_prefix = f'{ annotation_module } .'
365- annotation_forward_arg = getattr (annotation , '__forward_arg__' , None )
370+ annotation_forward_arg : str | None = getattr (annotation , '__forward_arg__' , None )
366371 if annotation_qualname or (annotation_module_is_typing and not annotation_forward_arg ):
367372 if mode == 'smart' :
368- module_prefix = '~' + module_prefix
373+ module_prefix = f'~ { module_prefix } '
369374 if annotation_module_is_typing and mode == 'fully-qualified-except-typing' :
370375 module_prefix = ''
371376 else :
0 commit comments