Skip to content

Commit

Permalink
FIX TypeError: unhashable type (#319)
Browse files Browse the repository at this point in the history
Fixes #318. The access to `_TYPES_DICT` should be wrapped in a try block so that
if the type is unhashable the error can be caught and discarded.
  • Loading branch information
spacemanspiff2007 committed Jan 27, 2023
1 parent d931001 commit d181c2d
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -3,6 +3,7 @@
## 1.22

- Allow Sphinx explicitly to write in parallel.
- Fixed crash when documenting ParamSpecArgs

## 1.21.7

Expand Down
23 changes: 18 additions & 5 deletions src/sphinx_autodoc_typehints/__init__.py
Expand Up @@ -35,13 +35,25 @@
_TYPES_DICT[types.FunctionType] = "FunctionType"


def _get_types_type(obj: Any) -> str | None:
try:
return _TYPES_DICT.get(obj)
except Exception:
# e.g. exception: unhashable type
return None


def get_annotation_module(annotation: Any) -> str:
if annotation in _TYPES_DICT:
return "types"
if annotation is None:
return "builtins"
if _get_types_type(annotation) is not None:
return "types"
is_new_type = sys.version_info >= (3, 10) and isinstance(annotation, NewType)
if is_new_type or isinstance(annotation, TypeVar) or type(annotation).__name__ == "ParamSpec":
if (
is_new_type
or isinstance(annotation, TypeVar)
or type(annotation).__name__ in ("ParamSpec", "ParamSpecArgs", "ParamSpecKwargs")
):
return "typing"
if hasattr(annotation, "__module__"):
return annotation.__module__ # type: ignore # deduced Any
Expand All @@ -63,8 +75,9 @@ def get_annotation_class_name(annotation: Any, module: str) -> str:
return "None"
if annotation is AnyStr:
return "AnyStr"
if annotation in _TYPES_DICT:
return _TYPES_DICT[annotation]
val = _get_types_type(annotation)
if val is not None:
return val
if _is_newtype(annotation):
return "NewType"

Expand Down
5 changes: 5 additions & 0 deletions tests/test_sphinx_autodoc_typehints.py
Expand Up @@ -58,6 +58,8 @@
S = TypeVar("S", bound="miss") # type: ignore # miss not defined on purpose # noqa: F821
W = NewType("W", str)
P = typing_extensions.ParamSpec("P")
P_args = P.args # type:ignore[attr-defined]
P_kwargs = P.kwargs # type:ignore[attr-defined]
P_co = typing_extensions.ParamSpec("P_co", covariant=True) # type: ignore
P_contra = typing_extensions.ParamSpec("P_contra", contravariant=True) # type: ignore
P_bound = typing_extensions.ParamSpec("P_bound", bound=str) # type: ignore
Expand Down Expand Up @@ -163,6 +165,9 @@ def __getitem__(self, params):
pytest.param(Match[str], "typing", "Match", (str,), id="Match_parametrized"),
pytest.param(IO, "typing", "IO", (), id="IO"),
pytest.param(W, "typing", "NewType", (str,), id="W"),
pytest.param(P, "typing", "ParamSpec", (), id="P"),
pytest.param(P_args, "typing", "ParamSpecArgs", (), id="P_args"),
pytest.param(P_kwargs, "typing", "ParamSpecKwargs", (), id="P_kwargs"),
pytest.param(Metaclass, __name__, "Metaclass", (), id="Metaclass"),
pytest.param(Slotted, __name__, "Slotted", (), id="Slotted"),
pytest.param(A, __name__, "A", (), id="A"),
Expand Down

0 comments on commit d181c2d

Please sign in to comment.