Skip to content

Commit

Permalink
Use PEP 695 for hass_dict annotations (home-assistant#117779)
Browse files Browse the repository at this point in the history
  • Loading branch information
cdce8p authored and bajansen committed May 20, 2024
1 parent a02f828 commit a043cf5
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 29 deletions.
8 changes: 2 additions & 6 deletions homeassistant/util/hass_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@

from __future__ import annotations

from typing import Generic, TypeVar

_T = TypeVar("_T")


class HassKey(str, Generic[_T]):
class HassKey[_T](str):
"""Generic Hass key type.
At runtime this is a generic subclass of str.
Expand All @@ -19,7 +15,7 @@ class HassKey(str, Generic[_T]):
__slots__ = ()


class HassEntryKey(str, Generic[_T]):
class HassEntryKey[_T](str):
"""Key type for integrations with config entries.
At runtime this is a generic subclass of str.
Expand Down
51 changes: 28 additions & 23 deletions homeassistant/util/hass_dict.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ __all__ = [
"HassKey",
]

_T = TypeVar("_T")
_U = TypeVar("_U")
_T = TypeVar("_T") # needs to be invariant

class _Key(Generic[_T]):
"""Base class for Hass key types. At runtime delegated to str."""
Expand All @@ -31,65 +30,71 @@ class HassDict(dict[_Key[Any] | str, Any]):
"""Custom dict type to provide better value type hints for Hass key types."""

@overload # type: ignore[override]
def __getitem__(self, key: HassEntryKey[_T], /) -> dict[str, _T]: ...
def __getitem__[_S](self, key: HassEntryKey[_S], /) -> dict[str, _S]: ...
@overload
def __getitem__(self, key: HassKey[_T], /) -> _T: ...
def __getitem__[_S](self, key: HassKey[_S], /) -> _S: ...
@overload
def __getitem__(self, key: str, /) -> Any: ...

# ------
@overload # type: ignore[override]
def __setitem__(self, key: HassEntryKey[_T], value: dict[str, _T], /) -> None: ...
def __setitem__[_S](
self, key: HassEntryKey[_S], value: dict[str, _S], /
) -> None: ...
@overload
def __setitem__(self, key: HassKey[_T], value: _T, /) -> None: ...
def __setitem__[_S](self, key: HassKey[_S], value: _S, /) -> None: ...
@overload
def __setitem__(self, key: str, value: Any, /) -> None: ...

# ------
@overload # type: ignore[override]
def setdefault(
self, key: HassEntryKey[_T], default: dict[str, _T], /
) -> dict[str, _T]: ...
def setdefault[_S](
self, key: HassEntryKey[_S], default: dict[str, _S], /
) -> dict[str, _S]: ...
@overload
def setdefault(self, key: HassKey[_T], default: _T, /) -> _T: ...
def setdefault[_S](self, key: HassKey[_S], default: _S, /) -> _S: ...
@overload
def setdefault(self, key: str, default: None = None, /) -> Any | None: ...
@overload
def setdefault(self, key: str, default: Any, /) -> Any: ...

# ------
@overload # type: ignore[override]
def get(self, key: HassEntryKey[_T], /) -> dict[str, _T] | None: ...
def get[_S](self, key: HassEntryKey[_S], /) -> dict[str, _S] | None: ...
@overload
def get(self, key: HassEntryKey[_T], default: _U, /) -> dict[str, _T] | _U: ...
def get[_S, _U](
self, key: HassEntryKey[_S], default: _U, /
) -> dict[str, _S] | _U: ...
@overload
def get(self, key: HassKey[_T], /) -> _T | None: ...
def get[_S](self, key: HassKey[_S], /) -> _S | None: ...
@overload
def get(self, key: HassKey[_T], default: _U, /) -> _T | _U: ...
def get[_S, _U](self, key: HassKey[_S], default: _U, /) -> _S | _U: ...
@overload
def get(self, key: str, /) -> Any | None: ...
@overload
def get(self, key: str, default: Any, /) -> Any: ...

# ------
@overload # type: ignore[override]
def pop(self, key: HassEntryKey[_T], /) -> dict[str, _T]: ...
def pop[_S](self, key: HassEntryKey[_S], /) -> dict[str, _S]: ...
@overload
def pop(
self, key: HassEntryKey[_T], default: dict[str, _T], /
) -> dict[str, _T]: ...
def pop[_S](
self, key: HassEntryKey[_S], default: dict[str, _S], /
) -> dict[str, _S]: ...
@overload
def pop(self, key: HassEntryKey[_T], default: _U, /) -> dict[str, _T] | _U: ...
def pop[_S, _U](
self, key: HassEntryKey[_S], default: _U, /
) -> dict[str, _S] | _U: ...
@overload
def pop(self, key: HassKey[_T], /) -> _T: ...
def pop[_S](self, key: HassKey[_S], /) -> _S: ...
@overload
def pop(self, key: HassKey[_T], default: _T, /) -> _T: ...
def pop[_S](self, key: HassKey[_S], default: _S, /) -> _S: ...
@overload
def pop(self, key: HassKey[_T], default: _U, /) -> _T | _U: ...
def pop[_S, _U](self, key: HassKey[_S], default: _U, /) -> _S | _U: ...
@overload
def pop(self, key: str, /) -> Any: ...
@overload
def pop(self, key: str, default: _U, /) -> Any | _U: ...
def pop[_U](self, key: str, default: _U, /) -> Any | _U: ...

def _test_hass_dict_typing() -> None: # noqa: PYI048
"""Test HassDict overloads work as intended.
Expand Down

0 comments on commit a043cf5

Please sign in to comment.