Skip to content

Commit

Permalink
fix: Handling of _SpecialForm objects in repr_type in 3.8.
Browse files Browse the repository at this point in the history
  • Loading branch information
DanCardin committed Sep 26, 2024
1 parent 08ba15c commit f0f9390
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 12 deletions.
3 changes: 0 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,6 @@ omit = ["*/tests/*"]
plugins = ["covdefaults"]
source = ["type_lens"]

[tool.coverage.report]
fail-under = 100

[tool.pytest.ini_options]
addopts = "--strict-markers --strict-config"
testpaths = ["tests"]
Expand Down
4 changes: 4 additions & 0 deletions tests/test_type_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import pytest
from typing_extensions import Annotated, NotRequired, Required, get_type_hints
from typing_extensions import Literal as ExtensionsLiteral

from type_lens import TypeView
from type_lens.types.builtins import NoneType
Expand Down Expand Up @@ -349,6 +350,9 @@ def test_repr() -> None:
assert repr(TypeView(int)) == "TypeView(int)"
assert repr(TypeView(Optional[str])) == "TypeView(Union[str, NoneType])"
assert repr(TypeView(Literal["1", 2, True])) == "TypeView(Literal['1', 2, True])"
assert repr(TypeView(Tuple[Literal["1"], int])) == "TypeView(Tuple[Literal['1'], int])"
assert repr(TypeView(ExtensionsLiteral["1", 2, True])) == "TypeView(Literal['1', 2, True])"
assert repr(TypeView(Any)) == "TypeView(Any)"


def test_is_none_type() -> None:
Expand Down
28 changes: 19 additions & 9 deletions type_lens/type_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

from collections import abc
from collections.abc import Collection, Mapping
from typing import Any, AnyStr, Final, ForwardRef, Generic, Literal, TypeVar, Union
from typing import Any, AnyStr, Final, ForwardRef, Generic, Literal, TypeVar, Union, _SpecialForm

from typing_extensions import Annotated, NotRequired, Required, get_args, get_origin
from typing_extensions import Literal as ExtensionsLiteral

from type_lens.types.builtins import UNION_TYPES, NoneType
from type_lens.utils import INSTANTIABLE_TYPE_MAPPING, SAFE_GENERIC_ORIGIN_MAP, unwrap_annotation
Expand Down Expand Up @@ -71,13 +72,22 @@ def __repr__(self) -> str:

@property
def repr_type(self) -> str:
if isinstance(self.annotation, type) or self.origin:
if self.is_literal:
name = "Literal"
elif self.is_union:
name = "Union"
else:
name = self.annotation.__name__
"""Returns a consistent, canonical repr of the contained annotation.
Removes preceding `typing.` prefix for built-in typing constructs. Python's
native repr for `typing` types is inconsistent across python versions!
"""
# Literal/Union both appear to have no name on some versions of python.
if self.is_literal:
name = "Literal"
elif self.is_union:
name = "Union"
elif isinstance(self.annotation, (type, _SpecialForm)) or self.origin:
try:
name = self.annotation.__name__ # pyright: ignore[reportAttributeAccessIssue]
except AttributeError:
# Certain _SpecialForm items have no __name__ python 3.8.
name = self.annotation._name # pyright: ignore[reportAttributeAccessIssue]
else:
name = repr(self.annotation)

Expand Down Expand Up @@ -128,7 +138,7 @@ def is_forward_ref(self) -> bool:
@property
def is_literal(self) -> bool:
"""Whether the annotation is a literal value or not."""
return self.origin is Literal
return self.origin in {Literal, ExtensionsLiteral}

@property
def is_mapping(self) -> bool:
Expand Down

0 comments on commit f0f9390

Please sign in to comment.