2024-05-10 18:29:28 +00:00
|
|
|
"""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.
|
|
|
|
"""
|
2024-11-18 18:46:36 +00:00
|
|
|
from typing import Any, NewType, assert_type, cast
|
2024-05-10 18:29:28 +00:00
|
|
|
|
|
|
|
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
|