Exclude __getattr__ for deprecated attributes from type checkers (#1294)

This commit is contained in:
Steven B. 2024-11-21 18:40:13 +00:00 committed by GitHub
parent 652b4e0bd7
commit cae9decb02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 73 additions and 50 deletions

View File

@ -97,8 +97,9 @@ deprecated_classes = {
"DeviceFamilyType": DeviceFamily,
}
if not TYPE_CHECKING:
def __getattr__(name: str) -> Any:
def __getattr__(name: str) -> Any:
if name in deprecated_names:
warn(f"{name} is deprecated", DeprecationWarning, stacklevel=2)
return globals()[f"_deprecated_{name}"]
@ -106,8 +107,8 @@ def __getattr__(name: str) -> Any:
new_class = deprecated_smart_devices[name]
package_name = ".".join(new_class.__module__.split(".")[:-1])
warn(
f"{name} is deprecated, use {new_class.__name__} "
+ f"from package {package_name} instead or use Discover.discover_single()"
f"{name} is deprecated, use {new_class.__name__} from "
+ f"package {package_name} instead or use Discover.discover_single()"
+ " and Device.connect() to support new protocols",
DeprecationWarning,
stacklevel=2,

View File

@ -190,7 +190,7 @@ async def presets_modify(dev: Device, index, brightness, hue, saturation, temper
@click.option("--preset", type=int)
async def turn_on_behavior(dev: Device, type, last, preset):
"""Modify bulb turn-on behavior."""
if not dev.is_bulb or not isinstance(dev, IotBulb):
if dev.device_type is not Device.Type.Bulb or not isinstance(dev, IotBulb):
error("Presets only supported on iot bulbs")
return
settings = await dev.get_turn_on_behavior()

View File

@ -566,9 +566,13 @@ class Device(ABC):
"supported_modules": (None, ["modules"]),
}
if not TYPE_CHECKING:
def __getattr__(self, name: str) -> Any:
# is_device_type
if dep_device_type_attr := self._deprecated_device_type_attributes.get(name):
if dep_device_type_attr := self._deprecated_device_type_attributes.get(
name
):
msg = f"{name} is deprecated, use device_type property instead"
warn(msg, DeprecationWarning, stacklevel=2)
return self.device_type == dep_device_type_attr[1]

View File

@ -4,7 +4,7 @@ from __future__ import annotations
from abc import ABC, abstractmethod
from enum import IntFlag, auto
from typing import Any
from typing import TYPE_CHECKING, Any
from warnings import warn
from ..emeterstatus import EmeterStatus
@ -184,6 +184,8 @@ class Energy(Module, ABC):
"get_monthstat": "get_monthly_stats",
}
if not TYPE_CHECKING:
def __getattr__(self, name: str) -> Any:
if attr := self._deprecated_attributes.get(name):
msg = f"{name} is deprecated, use {attr} instead"

View File

@ -154,7 +154,7 @@ class IotDimmer(IotPlug):
"""
if transition is not None:
return await self.set_dimmer_transition(
brightness=self.brightness, transition=transition
brightness=self._brightness, transition=transition
)
return await super().turn_on()

View File

@ -3,13 +3,16 @@
from __future__ import annotations
import logging
from typing import Any
from typing import TYPE_CHECKING, Any
from ..exceptions import KasaException
from ..module import Module
_LOGGER = logging.getLogger(__name__)
if TYPE_CHECKING:
from .iotdevice import IotDevice
def _merge_dict(dest: dict, source: dict) -> dict:
"""Update dict recursively."""
@ -27,6 +30,8 @@ merge = _merge_dict
class IotModule(Module):
"""Base class implemention for all IOT modules."""
_device: IotDevice
async def call(self, method: str, params: dict | None = None) -> dict:
"""Call the given method with the given parameters."""
return await self._device._query_helper(self._module, method, params)

View File

@ -5,7 +5,7 @@ from __future__ import annotations
import logging
from collections import defaultdict
from datetime import datetime, timedelta
from typing import Any
from typing import TYPE_CHECKING, Any
from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
@ -145,6 +145,8 @@ class IotStrip(IotDevice):
if update_children:
for plug in self.children:
if TYPE_CHECKING:
assert isinstance(plug, IotStripPlug)
await plug._update()
if not self.features:

View File

@ -207,6 +207,8 @@ class Light(IotModule, LightInterface):
# iot protocol Dimmers and smart protocol devices do not support
# brightness of 0 so 0 will turn off all devices for consistency
if (bulb := self._get_bulb_device()) is None: # Dimmer
if TYPE_CHECKING:
assert isinstance(self._device, IotDimmer)
if state.brightness == 0 or state.light_on is False:
return await self._device.turn_off(transition=state.transition)
elif state.brightness:

View File

@ -28,6 +28,8 @@ from .modules import (
)
from .smartmodule import SmartModule
if TYPE_CHECKING:
from .smartchilddevice import SmartChildDevice
_LOGGER = logging.getLogger(__name__)
@ -196,6 +198,8 @@ class SmartDevice(Device):
# child modules have access to their sysinfo.
if update_children or self.device_type != DeviceType.Hub:
for child in self._children.values():
if TYPE_CHECKING:
assert isinstance(child, SmartChildDevice)
await child._update()
# We can first initialize the features after the first update.

View File

@ -16,6 +16,7 @@ from kasa.iot import IotDevice, IotStrip
from kasa.iot.modules.emeter import Emeter
from kasa.smart import SmartDevice
from kasa.smart.modules import Energy as SmartEnergyModule
from kasa.smart.smartmodule import SmartModule
from .conftest import has_emeter, has_emeter_iot, no_emeter
@ -192,6 +193,7 @@ async def test_supported(dev: Device):
pytest.skip(f"Energy module not supported for {dev}.")
energy_module = dev.modules.get(Module.Energy)
assert energy_module
if isinstance(dev, IotDevice):
info = (
dev._last_update
@ -210,6 +212,7 @@ async def test_supported(dev: Device):
)
assert energy_module.supports(Energy.ModuleFeature.PERIODIC_STATS) is True
else:
assert isinstance(energy_module, SmartModule)
assert energy_module.supports(Energy.ModuleFeature.CONSUMPTION_TOTAL) is False
assert energy_module.supports(Energy.ModuleFeature.PERIODIC_STATS) is False
if energy_module.supported_version < 2: