Add NewType support to typing.stringify() and restify()

This commit is contained in:
Takeshi KOMIYA 2020-11-18 22:29:03 +09:00
parent 93d6c212f7
commit 46a7ea7ada
2 changed files with 14 additions and 1 deletions

View File

@ -88,10 +88,14 @@ def is_system_TypeVar(typ: Any) -> bool:
def restify(cls: Optional["Type"]) -> str: def restify(cls: Optional["Type"]) -> str:
"""Convert python class to a reST reference.""" """Convert python class to a reST reference."""
from sphinx.util import inspect # lazy loading
if cls is None or cls is NoneType: if cls is None or cls is NoneType:
return ':obj:`None`' return ':obj:`None`'
elif cls is Ellipsis: elif cls is Ellipsis:
return '...' return '...'
elif inspect.isNewType(cls):
return ':class:`%s`' % cls.__name__
elif cls.__module__ in ('__builtin__', 'builtins'): elif cls.__module__ in ('__builtin__', 'builtins'):
return ':class:`%s`' % cls.__name__ return ':class:`%s`' % cls.__name__
else: else:
@ -277,6 +281,8 @@ def _restify_py36(cls: Optional["Type"]) -> str:
def stringify(annotation: Any) -> str: def stringify(annotation: Any) -> str:
"""Stringify type annotation object.""" """Stringify type annotation object."""
from sphinx.util import inspect # lazy loading
if isinstance(annotation, str): if isinstance(annotation, str):
if annotation.startswith("'") and annotation.endswith("'"): if annotation.startswith("'") and annotation.endswith("'"):
# might be a double Forward-ref'ed type. Go unquoting. # might be a double Forward-ref'ed type. Go unquoting.
@ -285,6 +291,9 @@ def stringify(annotation: Any) -> str:
return annotation return annotation
elif isinstance(annotation, TypeVar): elif isinstance(annotation, TypeVar):
return annotation.__name__ return annotation.__name__
elif inspect.isNewType(annotation):
# Could not get the module where it defiend
return annotation.__name__
elif not annotation: elif not annotation:
return repr(annotation) return repr(annotation)
elif annotation is NoneType: elif annotation is NoneType:

View File

@ -10,7 +10,8 @@
import sys import sys
from numbers import Integral from numbers import Integral
from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, TypeVar, Union from typing import (Any, Callable, Dict, Generator, List, NewType, Optional, Tuple, TypeVar,
Union)
import pytest import pytest
@ -26,6 +27,7 @@ class MyClass2(MyClass1):
T = TypeVar('T') T = TypeVar('T')
MyInt = NewType('MyInt', int)
class MyList(List[T]): class MyList(List[T]):
@ -92,6 +94,7 @@ def test_restify_type_hints_typevars():
assert restify(T_co) == ":obj:`tests.test_util_typing.T_co`" assert restify(T_co) == ":obj:`tests.test_util_typing.T_co`"
assert restify(T_contra) == ":obj:`tests.test_util_typing.T_contra`" assert restify(T_contra) == ":obj:`tests.test_util_typing.T_contra`"
assert restify(List[T]) == ":class:`List`\\ [:obj:`tests.test_util_typing.T`]" assert restify(List[T]) == ":class:`List`\\ [:obj:`tests.test_util_typing.T`]"
assert restify(MyInt) == ":class:`MyInt`"
def test_restify_type_hints_custom_class(): def test_restify_type_hints_custom_class():
@ -179,6 +182,7 @@ def test_stringify_type_hints_typevars():
assert stringify(T_co) == "T_co" assert stringify(T_co) == "T_co"
assert stringify(T_contra) == "T_contra" assert stringify(T_contra) == "T_contra"
assert stringify(List[T]) == "List[T]" assert stringify(List[T]) == "List[T]"
assert stringify(MyInt) == "MyInt"
def test_stringify_type_hints_custom_class(): def test_stringify_type_hints_custom_class():