def restify(cls: Optional[Type], mode: str = 'fully-qualified-except-typing') -> str: """Convert python class to a reST reference. :param mode: Specify a method how annotations will be stringified. 'fully-qualified-except-typing' Show the module name and qualified name of the annotation except the "typing" module. 'smart' Show the name of the annotation. """ from sphinx.ext.autodoc.mock import ismock, ismockmodule # lazy loading from sphinx.util import inspect # lazy loading if mode == 'smart': modprefix = '~' else: modprefix = '' try: if cls is None or cls is NoneType: return ':py:obj:`None`' elif cls is Ellipsis: return '...' elif isinstance(cls, str): return cls elif ismockmodule(cls): return ':py:class:`%s%s`' % (modprefix, cls.__name__) elif ismock(cls): return ':py:class:`%s%s.%s`' % (modprefix, cls.__module__, cls.__name__) elif is_invalid_builtin_class(cls): return ':py:class:`%s%s`' % (modprefix, INVALID_BUILTIN_CLASSES[cls]) elif inspect.isNewType(cls): if sys.version_info > (3, 10): # newtypes have correct module info since Python 3.10+ return ':py:class:`%s%s.%s`' % (modprefix, cls.__module__, cls.__name__) else: return ':py:class:`%s`' % cls.__name__ elif UnionType and isinstance(cls, UnionType): if len(cls.__args__) > 1 and None in cls.__args__: args = ' | '.join(restify(a, mode) for a in cls.__args__ if a) return 'Optional[%s]' % args else: return ' | '.join(restify(a, mode) for a in cls.__args__) elif cls.__module__ in ('__builtin__', 'builtins'): if hasattr(cls, '__args__'): return ':py:class:`%s`\\ [%s]' % ( cls.__name__, ', '.join(restify(arg, mode) for arg in cls.__args__), ) else: return ':py:class:`%s`' % cls.__name__ else: return _restify_py37(cls, mode) except (AttributeError, TypeError): return inspect.object_description(cls)
def stringify(annotation: Any, mode: str = 'fully-qualified-except-typing') -> str: """Stringify type annotation object. :param mode: Specify a method how annotations will be stringified. 'fully-qualified-except-typing' Show the module name and qualified name of the annotation except the "typing" module. 'smart' Show the name of the annotation. 'fully-qualified' Show the module name and qualified name of the annotation. """ from sphinx.ext.autodoc.mock import ismock, ismockmodule # lazy loading from sphinx.util import inspect # lazy loading if mode == 'smart': modprefix = '~' else: modprefix = '' if isinstance(annotation, str): if annotation.startswith("'") and annotation.endswith("'"): # might be a double Forward-ref'ed type. Go unquoting. return annotation[1:-1] else: return annotation elif isinstance(annotation, TypeVar): if (annotation.__module__ == 'typing' and mode in ('fully-qualified-except-typing', 'smart')): return annotation.__name__ else: return modprefix + '.'.join([annotation.__module__, annotation.__name__]) elif inspect.isNewType(annotation): if sys.version_info > (3, 10): # newtypes have correct module info since Python 3.10+ return modprefix + '%s.%s' % (annotation.__module__, annotation.__name__) else: return annotation.__name__ elif not annotation: return repr(annotation) elif annotation is NoneType: return 'None' elif ismockmodule(annotation): return modprefix + annotation.__name__ elif ismock(annotation): return modprefix + '%s.%s' % (annotation.__module__, annotation.__name__) elif is_invalid_builtin_class(annotation): return modprefix + INVALID_BUILTIN_CLASSES[annotation] elif str(annotation).startswith('typing.Annotated'): # for py310+ pass elif (getattr(annotation, '__module__', None) == 'builtins' and getattr(annotation, '__qualname__', None)): if hasattr(annotation, '__args__'): # PEP 585 generic return repr(annotation) else: return annotation.__qualname__ elif annotation is Ellipsis: return '...' if sys.version_info >= (3, 7): # py37+ return _stringify_py37(annotation, mode) else: return _stringify_py36(annotation, mode)