""" test_util_typing ~~~~~~~~~~~~~~~~ Tests util.typing functions. :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import sys from numbers import Integral from typing import ( Any, Dict, Generator, List, TypeVar, Union, Callable, Tuple, Optional, Generic ) import pytest from sphinx.util.typing import restify, stringify class MyClass1: pass class MyClass2(MyClass1): __qualname__ = '' T = TypeVar('T') class MyList(List[T]): pass class BrokenType: __args__ = int def test_restify(): assert restify(int) == ":class:`int`" assert restify(str) == ":class:`str`" assert restify(None) == ":obj:`None`" assert restify(Integral) == ":class:`numbers.Integral`" assert restify(Any) == ":obj:`Any`" def test_restify_type_hints_containers(): assert restify(List) == ":class:`List`" assert restify(Dict) == ":class:`Dict`" assert restify(List[int]) == ":class:`List`\\ [:class:`int`]" assert restify(List[str]) == ":class:`List`\\ [:class:`str`]" assert restify(Dict[str, float]) == ":class:`Dict`\\ [:class:`str`, :class:`float`]" assert restify(Tuple[str, str, str]) == ":class:`Tuple`\\ [:class:`str`, :class:`str`, :class:`str`]" assert restify(Tuple[str, ...]) == ":class:`Tuple`\\ [:class:`str`, ...]" assert restify(List[Dict[str, Tuple]]) == ":class:`List`\\ [:class:`Dict`\\ [:class:`str`, :class:`Tuple`]]" assert restify(MyList[Tuple[int, int]]) == ":class:`test_util_typing.MyList`\\ [:class:`Tuple`\\ [:class:`int`, :class:`int`]]" assert restify(Generator[None, None, None]) == ":class:`Generator`\\ [:obj:`None`, :obj:`None`, :obj:`None`]" def test_restify_type_hints_Callable(): assert restify(Callable) == ":class:`Callable`" if sys.version_info >= (3, 7): assert restify(Callable[[str], int]) == ":class:`Callable`\\ [[:class:`str`], :class:`int`]" assert restify(Callable[..., int]) == ":class:`Callable`\\ [[...], :class:`int`]" else: assert restify(Callable[[str], int]) == ":class:`Callable`\\ [:class:`str`, :class:`int`]" assert restify(Callable[..., int]) == ":class:`Callable`\\ [..., :class:`int`]" def test_restify_type_hints_Union(): assert restify(Optional[int]) == ":obj:`Optional`\\ [:class:`int`]" assert restify(Union[str, None]) == ":obj:`Optional`\\ [:class:`str`]" assert restify(Union[int, str]) == ":obj:`Union`\\ [:class:`int`, :class:`str`]" if sys.version_info >= (3, 7): assert restify(Union[int, Integral]) == ":obj:`Union`\\ [:class:`int`, :class:`numbers.Integral`]" assert (restify(Union[MyClass1, MyClass2]) == ":obj:`Union`\\ [:class:`test_util_typing.MyClass1`, :class:`test_util_typing.`]") else: assert restify(Union[int, Integral]) == ":class:`numbers.Integral`" assert restify(Union[MyClass1, MyClass2]) == ":class:`test_util_typing.MyClass1`" @pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.') def test_restify_type_hints_typevars(): T = TypeVar('T') T_co = TypeVar('T_co', covariant=True) T_contra = TypeVar('T_contra', contravariant=True) assert restify(T) == ":obj:`test_util_typing.T`" assert restify(T_co) == ":obj:`test_util_typing.T_co`" assert restify(T_contra) == ":obj:`test_util_typing.T_contra`" assert restify(List[T]) == ":class:`List`\\ [:obj:`test_util_typing.T`]" def test_restify_type_hints_custom_class(): assert restify(MyClass1) == ":class:`test_util_typing.MyClass1`" assert restify(MyClass2) == ":class:`test_util_typing.`" def test_restify_type_hints_alias(): MyStr = str MyTuple = Tuple[str, str] assert restify(MyStr) == ":class:`str`" assert restify(MyTuple) == ":class:`Tuple`\\ [:class:`str`, :class:`str`]" # type: ignore def test_restify_broken_type_hints(): assert restify(BrokenType) == ':class:`test_util_typing.BrokenType`' def test_stringify(): assert stringify(int) == "int" assert stringify(str) == "str" assert stringify(None) == "None" assert stringify(Integral) == "numbers.Integral" assert stringify(Any) == "Any" def test_stringify_type_hints_containers(): assert stringify(List) == "List" assert stringify(Dict) == "Dict" assert stringify(List[int]) == "List[int]" assert stringify(List[str]) == "List[str]" assert stringify(Dict[str, float]) == "Dict[str, float]" assert stringify(Tuple[str, str, str]) == "Tuple[str, str, str]" assert stringify(Tuple[str, ...]) == "Tuple[str, ...]" assert stringify(List[Dict[str, Tuple]]) == "List[Dict[str, Tuple]]" assert stringify(MyList[Tuple[int, int]]) == "test_util_typing.MyList[Tuple[int, int]]" assert stringify(Generator[None, None, None]) == "Generator[None, None, None]" @pytest.mark.skipif(sys.version_info < (3, 9), reason='python 3.9+ is required.') def test_stringify_Annotated(): from typing import Annotated assert stringify(Annotated[str, "foo", "bar"]) == "str" def test_stringify_type_hints_string(): assert stringify("int") == "int" assert stringify("str") == "str" assert stringify(List["int"]) == "List[int]" assert stringify("Tuple[str]") == "Tuple[str]" assert stringify("unknown") == "unknown" def test_stringify_type_hints_Callable(): assert stringify(Callable) == "Callable" if sys.version_info >= (3, 7): assert stringify(Callable[[str], int]) == "Callable[[str], int]" assert stringify(Callable[..., int]) == "Callable[[...], int]" else: assert stringify(Callable[[str], int]) == "Callable[str, int]" assert stringify(Callable[..., int]) == "Callable[..., int]" def test_stringify_type_hints_Union(): assert stringify(Optional[int]) == "Optional[int]" assert stringify(Union[str, None]) == "Optional[str]" assert stringify(Union[int, str]) == "Union[int, str]" if sys.version_info >= (3, 7): assert stringify(Union[int, Integral]) == "Union[int, numbers.Integral]" assert (stringify(Union[MyClass1, MyClass2]) == "Union[test_util_typing.MyClass1, test_util_typing.]") else: assert stringify(Union[int, Integral]) == "numbers.Integral" assert stringify(Union[MyClass1, MyClass2]) == "test_util_typing.MyClass1" def test_stringify_type_hints_typevars(): T = TypeVar('T') T_co = TypeVar('T_co', covariant=True) T_contra = TypeVar('T_contra', contravariant=True) assert stringify(T) == "T" assert stringify(T_co) == "T_co" assert stringify(T_contra) == "T_contra" assert stringify(List[T]) == "List[T]" def test_stringify_type_hints_custom_class(): assert stringify(MyClass1) == "test_util_typing.MyClass1" assert stringify(MyClass2) == "test_util_typing." def test_stringify_type_hints_alias(): MyStr = str MyTuple = Tuple[str, str] assert stringify(MyStr) == "str" assert stringify(MyTuple) == "Tuple[str, str]" # type: ignore def test_stringify_broken_type_hints(): assert stringify(BrokenType) == 'test_util_typing.BrokenType'