Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX TypeError: unhashable type #319

Merged
merged 12 commits into from Jan 27, 2023
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