python-kasa/kasa/modulemapping.pyi

95 lines
3.7 KiB
Python
Raw Permalink Normal View History

"""Typing stub file for ModuleMapping."""
from abc import ABCMeta
from collections.abc import Mapping
from typing import Generic, TypeVar, overload
from .module import Module
__all__ = [
"ModuleMapping",
"ModuleName",
]
_ModuleT = TypeVar("_ModuleT", bound=Module, covariant=True)
_ModuleBaseT = TypeVar("_ModuleBaseT", bound=Module, covariant=True)
class ModuleName(Generic[_ModuleT]):
"""Class for typed Module names. At runtime delegated to str."""
def __init__(self, value: str, /) -> None: ...
def __len__(self) -> int: ...
def __hash__(self) -> int: ...
def __eq__(self, other: object) -> bool: ...
def __getitem__(self, index: int) -> str: ...
class ModuleMapping(
Mapping[ModuleName[_ModuleBaseT] | str, _ModuleBaseT], metaclass=ABCMeta
):
"""Custom dict type to provide better value type hints for Module key types."""
@overload
def __getitem__(self, key: ModuleName[_ModuleT], /) -> _ModuleT: ...
@overload
def __getitem__(self, key: str, /) -> _ModuleBaseT: ...
@overload
def __getitem__(
self, key: ModuleName[_ModuleT] | str, /
) -> _ModuleT | _ModuleBaseT: ...
@overload # type: ignore[override]
def get(self, key: ModuleName[_ModuleT], /) -> _ModuleT | None: ...
@overload
def get(self, key: str, /) -> _ModuleBaseT | None: ...
@overload
def get(
self, key: ModuleName[_ModuleT] | str, /
) -> _ModuleT | _ModuleBaseT | None: ...
def _test_module_mapping_typing() -> None:
"""Test ModuleMapping overloads work as intended.
This is tested during the mypy run and needs to be in this file.
"""
from typing import Any, NewType, assert_type, cast
from .iot.iotmodule import IotModule
from .module import Module
from .smart.smartmodule import SmartModule
NewCommonModule = NewType("NewCommonModule", Module)
NewIotModule = NewType("NewIotModule", IotModule)
NewSmartModule = NewType("NewSmartModule", SmartModule)
NotModule = NewType("NotModule", list)
NEW_COMMON_MODULE: ModuleName[NewCommonModule] = ModuleName("NewCommonModule")
NEW_IOT_MODULE: ModuleName[NewIotModule] = ModuleName("NewIotModule")
NEW_SMART_MODULE: ModuleName[NewSmartModule] = ModuleName("NewSmartModule")
# TODO Enable --warn-unused-ignores
NOT_MODULE: ModuleName[NotModule] = ModuleName("NotModule") # type: ignore[type-var] # noqa: F841
NOT_MODULE_2 = ModuleName[NotModule]("NotModule2") # type: ignore[type-var] # noqa: F841
device_modules: ModuleMapping[Module] = cast(ModuleMapping[Module], {})
assert_type(device_modules[NEW_COMMON_MODULE], NewCommonModule)
assert_type(device_modules[NEW_IOT_MODULE], NewIotModule)
assert_type(device_modules[NEW_SMART_MODULE], NewSmartModule)
assert_type(device_modules["foobar"], Module)
assert_type(device_modules[3], Any) # type: ignore[call-overload]
assert_type(device_modules.get(NEW_COMMON_MODULE), NewCommonModule | None)
assert_type(device_modules.get(NEW_IOT_MODULE), NewIotModule | None)
assert_type(device_modules.get(NEW_SMART_MODULE), NewSmartModule | None)
assert_type(device_modules.get(NEW_COMMON_MODULE, default=[1, 2]), Any) # type: ignore[call-overload]
iot_modules: ModuleMapping[IotModule] = cast(ModuleMapping[IotModule], {})
smart_modules: ModuleMapping[SmartModule] = cast(ModuleMapping[SmartModule], {})
assert_type(smart_modules["foobar"], SmartModule)
assert_type(iot_modules["foobar"], IotModule)
# Test for covariance
device_modules_2: ModuleMapping[Module] = iot_modules # noqa: F841
device_modules_3: ModuleMapping[Module] = smart_modules # noqa: F841
NEW_MODULE: ModuleName[Module] = NEW_SMART_MODULE # noqa: F841
NEW_MODULE_2: ModuleName[Module] = NEW_IOT_MODULE # noqa: F841