Enable and convert to future annotations (#838)

This commit is contained in:
Steven B
2024-04-17 14:39:24 +01:00
committed by GitHub
parent 82d92aeea5
commit 203bd79253
59 changed files with 562 additions and 462 deletions

View File

@@ -1,9 +1,11 @@
"""Module for bulbs (LB*, KL*, KB*)."""
from __future__ import annotations
import logging
import re
from enum import Enum
from typing import Dict, List, Optional, cast
from typing import Optional, cast
try:
from pydantic.v1 import BaseModel, Field, root_validator
@@ -40,7 +42,7 @@ class TurnOnBehavior(BaseModel):
"""
#: Index of preset to use, or ``None`` for the last known state.
preset: Optional[int] = Field(alias="index", default=None)
preset: Optional[int] = Field(alias="index", default=None) # noqa: UP007
#: Wanted behavior
mode: BehaviorMode
@@ -193,8 +195,8 @@ class IotBulb(IotDevice, Bulb):
self,
host: str,
*,
config: Optional[DeviceConfig] = None,
protocol: Optional[BaseProtocol] = None,
config: DeviceConfig | None = None,
protocol: BaseProtocol | None = None,
) -> None:
super().__init__(host=host, config=config, protocol=protocol)
self._device_type = DeviceType.Bulb
@@ -275,7 +277,7 @@ class IotBulb(IotDevice, Bulb):
@property # type: ignore
@requires_update
def light_state(self) -> Dict[str, str]:
def light_state(self) -> dict[str, str]:
"""Query the light state."""
light_state = self.sys_info["light_state"]
if light_state is None:
@@ -298,7 +300,7 @@ class IotBulb(IotDevice, Bulb):
"""Return True if the device supports effects."""
return "lighting_effect_state" in self.sys_info
async def get_light_details(self) -> Dict[str, int]:
async def get_light_details(self) -> dict[str, int]:
"""Return light details.
Example::
@@ -325,14 +327,14 @@ class IotBulb(IotDevice, Bulb):
self.LIGHT_SERVICE, "set_default_behavior", behavior.dict(by_alias=True)
)
async def get_light_state(self) -> Dict[str, Dict]:
async def get_light_state(self) -> dict[str, dict]:
"""Query the light state."""
# TODO: add warning and refer to use light.state?
return await self._query_helper(self.LIGHT_SERVICE, "get_light_state")
async def set_light_state(
self, state: Dict, *, transition: Optional[int] = None
) -> Dict:
self, state: dict, *, transition: int | None = None
) -> dict:
"""Set the light state."""
if transition is not None:
state["transition_period"] = transition
@@ -378,10 +380,10 @@ class IotBulb(IotDevice, Bulb):
self,
hue: int,
saturation: int,
value: Optional[int] = None,
value: int | None = None,
*,
transition: Optional[int] = None,
) -> Dict:
transition: int | None = None,
) -> dict:
"""Set new HSV.
:param int hue: hue in degrees
@@ -424,8 +426,8 @@ class IotBulb(IotDevice, Bulb):
@requires_update
async def set_color_temp(
self, temp: int, *, brightness=None, transition: Optional[int] = None
) -> Dict:
self, temp: int, *, brightness=None, transition: int | None = None
) -> dict:
"""Set the color temperature of the device in kelvin.
:param int temp: The new color temperature, in Kelvin
@@ -460,8 +462,8 @@ class IotBulb(IotDevice, Bulb):
@requires_update
async def set_brightness(
self, brightness: int, *, transition: Optional[int] = None
) -> Dict:
self, brightness: int, *, transition: int | None = None
) -> dict:
"""Set the brightness in percentage.
:param int brightness: brightness in percent
@@ -482,14 +484,14 @@ class IotBulb(IotDevice, Bulb):
light_state = self.light_state
return bool(light_state["on_off"])
async def turn_off(self, *, transition: Optional[int] = None, **kwargs) -> Dict:
async def turn_off(self, *, transition: int | None = None, **kwargs) -> dict:
"""Turn the bulb off.
:param int transition: transition in milliseconds.
"""
return await self.set_light_state({"on_off": 0}, transition=transition)
async def turn_on(self, *, transition: Optional[int] = None, **kwargs) -> Dict:
async def turn_on(self, *, transition: int | None = None, **kwargs) -> dict:
"""Turn the bulb on.
:param int transition: transition in milliseconds.
@@ -513,7 +515,7 @@ class IotBulb(IotDevice, Bulb):
@property # type: ignore
@requires_update
def presets(self) -> List[BulbPreset]:
def presets(self) -> list[BulbPreset]:
"""Return a list of available bulb setting presets."""
return [BulbPreset(**vals) for vals in self.sys_info["preferred_state"]]

View File

@@ -12,12 +12,14 @@ You may obtain a copy of the license at
http://www.apache.org/licenses/LICENSE-2.0
"""
from __future__ import annotations
import collections.abc
import functools
import inspect
import logging
from datetime import datetime, timedelta
from typing import Any, Dict, List, Mapping, Optional, Sequence, Set
from typing import Any, Mapping, Sequence
from ..device import Device, WifiNetwork
from ..deviceconfig import DeviceConfig
@@ -66,7 +68,7 @@ def requires_update(f):
@functools.lru_cache
def _parse_features(features: str) -> Set[str]:
def _parse_features(features: str) -> set[str]:
"""Parse features string."""
return set(features.split(":"))
@@ -177,19 +179,19 @@ class IotDevice(Device):
self,
host: str,
*,
config: Optional[DeviceConfig] = None,
protocol: Optional[BaseProtocol] = None,
config: DeviceConfig | None = None,
protocol: BaseProtocol | None = None,
) -> None:
"""Create a new IotDevice instance."""
super().__init__(host=host, config=config, protocol=protocol)
self._sys_info: Any = None # TODO: this is here to avoid changing tests
self._supported_modules: Optional[Dict[str, IotModule]] = None
self._legacy_features: Set[str] = set()
self._children: Mapping[str, "IotDevice"] = {}
self._supported_modules: dict[str, IotModule] | None = None
self._legacy_features: set[str] = set()
self._children: Mapping[str, IotDevice] = {}
@property
def children(self) -> Sequence["IotDevice"]:
def children(self) -> Sequence[IotDevice]:
"""Return list of children."""
return list(self._children.values())
@@ -203,9 +205,9 @@ class IotDevice(Device):
self.modules[name] = module
def _create_request(
self, target: str, cmd: str, arg: Optional[Dict] = None, child_ids=None
self, target: str, cmd: str, arg: dict | None = None, child_ids=None
):
request: Dict[str, Any] = {target: {cmd: arg}}
request: dict[str, Any] = {target: {cmd: arg}}
if child_ids is not None:
request = {"context": {"child_ids": child_ids}, target: {cmd: arg}}
@@ -219,7 +221,7 @@ class IotDevice(Device):
raise KasaException("update() required prior accessing emeter")
async def _query_helper(
self, target: str, cmd: str, arg: Optional[Dict] = None, child_ids=None
self, target: str, cmd: str, arg: dict | None = None, child_ids=None
) -> Any:
"""Query device, return results or raise an exception.
@@ -256,13 +258,13 @@ class IotDevice(Device):
@property # type: ignore
@requires_update
def features(self) -> Dict[str, Feature]:
def features(self) -> dict[str, Feature]:
"""Return a set of features that the device supports."""
return self._features
@property # type: ignore
@requires_update
def supported_modules(self) -> List[str]:
def supported_modules(self) -> list[str]:
"""Return a set of modules supported by the device."""
# TODO: this should rather be called `features`, but we don't want to break
# the API now. Maybe just deprecate it and point the users to use this?
@@ -274,7 +276,7 @@ class IotDevice(Device):
"""Return True if device has an energy meter."""
return "ENE" in self._legacy_features
async def get_sys_info(self) -> Dict[str, Any]:
async def get_sys_info(self) -> dict[str, Any]:
"""Retrieve system information."""
return await self._query_helper("system", "get_sysinfo")
@@ -363,12 +365,12 @@ class IotDevice(Device):
# responses on top of it so we remember
# which modules are not supported, otherwise
# every other update will query for them
update: Dict = self._last_update.copy() if self._last_update else {}
update: dict = self._last_update.copy() if self._last_update else {}
for response in responses:
update = {**update, **response}
self._last_update = update
def update_from_discover_info(self, info: Dict[str, Any]) -> None:
def update_from_discover_info(self, info: dict[str, Any]) -> None:
"""Update state from info from the discover call."""
self._discovery_info = info
if "system" in info and (sys_info := info["system"].get("get_sysinfo")):
@@ -380,7 +382,7 @@ class IotDevice(Device):
# by the requires_update decorator
self._set_sys_info(info)
def _set_sys_info(self, sys_info: Dict[str, Any]) -> None:
def _set_sys_info(self, sys_info: dict[str, Any]) -> None:
"""Set sys_info."""
self._sys_info = sys_info
if features := sys_info.get("feature"):
@@ -388,7 +390,7 @@ class IotDevice(Device):
@property # type: ignore
@requires_update
def sys_info(self) -> Dict[str, Any]:
def sys_info(self) -> dict[str, Any]:
"""
Return system information.
@@ -405,7 +407,7 @@ class IotDevice(Device):
return str(sys_info["model"])
@property # type: ignore
def alias(self) -> Optional[str]:
def alias(self) -> str | None:
"""Return device name (alias)."""
sys_info = self._sys_info
return sys_info.get("alias") if sys_info else None
@@ -422,18 +424,18 @@ class IotDevice(Device):
@property # type: ignore
@requires_update
def timezone(self) -> Dict:
def timezone(self) -> dict:
"""Return the current timezone."""
return self.modules["time"].timezone
async def get_time(self) -> Optional[datetime]:
async def get_time(self) -> datetime | None:
"""Return current time from the device, if available."""
_LOGGER.warning(
"Use `time` property instead, this call will be removed in the future."
)
return await self.modules["time"].get_time()
async def get_timezone(self) -> Dict:
async def get_timezone(self) -> dict:
"""Return timezone information."""
_LOGGER.warning(
"Use `timezone` property instead, this call will be removed in the future."
@@ -442,7 +444,7 @@ class IotDevice(Device):
@property # type: ignore
@requires_update
def hw_info(self) -> Dict:
def hw_info(self) -> dict:
"""Return hardware information.
This returns just a selection of sysinfo keys that are related to hardware.
@@ -464,7 +466,7 @@ class IotDevice(Device):
@property # type: ignore
@requires_update
def location(self) -> Dict:
def location(self) -> dict:
"""Return geographical location."""
sys_info = self._sys_info
loc = {"latitude": None, "longitude": None}
@@ -482,7 +484,7 @@ class IotDevice(Device):
@property # type: ignore
@requires_update
def rssi(self) -> Optional[int]:
def rssi(self) -> int | None:
"""Return WiFi signal strength (rssi)."""
rssi = self._sys_info.get("rssi")
return None if rssi is None else int(rssi)
@@ -528,21 +530,21 @@ class IotDevice(Device):
@property # type: ignore
@requires_update
def emeter_today(self) -> Optional[float]:
def emeter_today(self) -> float | None:
"""Return today's energy consumption in kWh."""
self._verify_emeter()
return self.modules["emeter"].emeter_today
@property # type: ignore
@requires_update
def emeter_this_month(self) -> Optional[float]:
def emeter_this_month(self) -> float | None:
"""Return this month's energy consumption in kWh."""
self._verify_emeter()
return self.modules["emeter"].emeter_this_month
async def get_emeter_daily(
self, year: Optional[int] = None, month: Optional[int] = None, kwh: bool = True
) -> Dict:
self, year: int | None = None, month: int | None = None, kwh: bool = True
) -> dict:
"""Retrieve daily statistics for a given month.
:param year: year for which to retrieve statistics (default: this year)
@@ -556,8 +558,8 @@ class IotDevice(Device):
@requires_update
async def get_emeter_monthly(
self, year: Optional[int] = None, kwh: bool = True
) -> Dict:
self, year: int | None = None, kwh: bool = True
) -> dict:
"""Retrieve monthly statistics for a given year.
:param year: year for which to retrieve statistics (default: this year)
@@ -568,7 +570,7 @@ class IotDevice(Device):
return await self.modules["emeter"].get_monthstat(year=year, kwh=kwh)
@requires_update
async def erase_emeter_stats(self) -> Dict:
async def erase_emeter_stats(self) -> dict:
"""Erase energy meter statistics."""
self._verify_emeter()
return await self.modules["emeter"].erase_stats()
@@ -588,11 +590,11 @@ class IotDevice(Device):
"""
await self._query_helper("system", "reboot", {"delay": delay})
async def turn_off(self, **kwargs) -> Dict:
async def turn_off(self, **kwargs) -> dict:
"""Turn off the device."""
raise NotImplementedError("Device subclass needs to implement this.")
async def turn_on(self, **kwargs) -> Optional[Dict]:
async def turn_on(self, **kwargs) -> dict | None:
"""Turn device on."""
raise NotImplementedError("Device subclass needs to implement this.")
@@ -604,7 +606,7 @@ class IotDevice(Device):
@property # type: ignore
@requires_update
def on_since(self) -> Optional[datetime]:
def on_since(self) -> datetime | None:
"""Return pretty-printed on-time, or None if not available."""
if "on_time" not in self._sys_info:
return None
@@ -626,7 +628,7 @@ class IotDevice(Device):
"""
return self.mac
async def wifi_scan(self) -> List[WifiNetwork]: # noqa: D202
async def wifi_scan(self) -> list[WifiNetwork]: # noqa: D202
"""Scan for available wifi networks."""
async def _scan(target):

View File

@@ -1,7 +1,9 @@
"""Module for dimmers (currently only HS220)."""
from __future__ import annotations
from enum import Enum
from typing import Any, Dict, Optional
from typing import Any
from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
@@ -72,8 +74,8 @@ class IotDimmer(IotPlug):
self,
host: str,
*,
config: Optional[DeviceConfig] = None,
protocol: Optional[BaseProtocol] = None,
config: DeviceConfig | None = None,
protocol: BaseProtocol | None = None,
) -> None:
super().__init__(host=host, config=config, protocol=protocol)
self._device_type = DeviceType.Dimmer
@@ -112,9 +114,7 @@ class IotDimmer(IotPlug):
return int(sys_info["brightness"])
@requires_update
async def set_brightness(
self, brightness: int, *, transition: Optional[int] = None
):
async def set_brightness(self, brightness: int, *, transition: int | None = None):
"""Set the new dimmer brightness level in percentage.
:param int transition: transition duration in milliseconds.
@@ -143,7 +143,7 @@ class IotDimmer(IotPlug):
self.DIMMER_SERVICE, "set_brightness", {"brightness": brightness}
)
async def turn_off(self, *, transition: Optional[int] = None, **kwargs):
async def turn_off(self, *, transition: int | None = None, **kwargs):
"""Turn the bulb off.
:param int transition: transition duration in milliseconds.
@@ -154,7 +154,7 @@ class IotDimmer(IotPlug):
return await super().turn_off()
@requires_update
async def turn_on(self, *, transition: Optional[int] = None, **kwargs):
async def turn_on(self, *, transition: int | None = None, **kwargs):
"""Turn the bulb on.
:param int transition: transition duration in milliseconds.
@@ -202,7 +202,7 @@ class IotDimmer(IotPlug):
@requires_update
async def set_button_action(
self, action_type: ActionType, action: ButtonAction, index: Optional[int] = None
self, action_type: ActionType, action: ButtonAction, index: int | None = None
):
"""Set action to perform on button click/hold.
@@ -213,7 +213,7 @@ class IotDimmer(IotPlug):
"""
action_type_setter = f"set_{action_type}"
payload: Dict[str, Any] = {"mode": str(action)}
payload: dict[str, Any] = {"mode": str(action)}
if index is not None:
payload["index"] = index

View File

@@ -1,6 +1,6 @@
"""Module for light strips (KL430)."""
from typing import Dict, List, Optional
from __future__ import annotations
from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
@@ -49,8 +49,8 @@ class IotLightStrip(IotBulb):
self,
host: str,
*,
config: Optional[DeviceConfig] = None,
protocol: Optional[BaseProtocol] = None,
config: DeviceConfig | None = None,
protocol: BaseProtocol | None = None,
) -> None:
super().__init__(host=host, config=config, protocol=protocol)
self._device_type = DeviceType.LightStrip
@@ -63,7 +63,7 @@ class IotLightStrip(IotBulb):
@property # type: ignore
@requires_update
def effect(self) -> Dict:
def effect(self) -> dict:
"""Return effect state.
Example:
@@ -77,7 +77,7 @@ class IotLightStrip(IotBulb):
@property # type: ignore
@requires_update
def effect_list(self) -> Optional[List[str]]:
def effect_list(self) -> list[str] | None:
"""Return built-in effects list.
Example:
@@ -90,8 +90,8 @@ class IotLightStrip(IotBulb):
self,
effect: str,
*,
brightness: Optional[int] = None,
transition: Optional[int] = None,
brightness: int | None = None,
transition: int | None = None,
) -> None:
"""Set an effect on the device.
@@ -118,7 +118,7 @@ class IotLightStrip(IotBulb):
@requires_update
async def set_custom_effect(
self,
effect_dict: Dict,
effect_dict: dict,
) -> None:
"""Set a custom effect on the device.

View File

@@ -1,7 +1,8 @@
"""Module for smart plugs (HS100, HS110, ..)."""
from __future__ import annotations
import logging
from typing import Optional
from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
@@ -47,8 +48,8 @@ class IotPlug(IotDevice):
self,
host: str,
*,
config: Optional[DeviceConfig] = None,
protocol: Optional[BaseProtocol] = None,
config: DeviceConfig | None = None,
protocol: BaseProtocol | None = None,
) -> None:
super().__init__(host=host, config=config, protocol=protocol)
self._device_type = DeviceType.Plug
@@ -108,8 +109,8 @@ class IotWallSwitch(IotPlug):
self,
host: str,
*,
config: Optional[DeviceConfig] = None,
protocol: Optional[BaseProtocol] = None,
config: DeviceConfig | None = None,
protocol: BaseProtocol | None = None,
) -> None:
super().__init__(host=host, config=config, protocol=protocol)
self._device_type = DeviceType.WallSwitch

View File

@@ -1,9 +1,11 @@
"""Module for multi-socket devices (HS300, HS107, KP303, ..)."""
from __future__ import annotations
import logging
from collections import defaultdict
from datetime import datetime, timedelta
from typing import Any, DefaultDict, Dict, Optional
from typing import Any
from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
@@ -23,7 +25,7 @@ _LOGGER = logging.getLogger(__name__)
def merge_sums(dicts):
"""Merge the sum of dicts."""
total_dict: DefaultDict[int, float] = defaultdict(lambda: 0.0)
total_dict: defaultdict[int, float] = defaultdict(lambda: 0.0)
for sum_dict in dicts:
for day, value in sum_dict.items():
total_dict[day] += value
@@ -86,8 +88,8 @@ class IotStrip(IotDevice):
self,
host: str,
*,
config: Optional[DeviceConfig] = None,
protocol: Optional[BaseProtocol] = None,
config: DeviceConfig | None = None,
protocol: BaseProtocol | None = None,
) -> None:
super().__init__(host=host, config=config, protocol=protocol)
self.emeter_type = "emeter"
@@ -137,7 +139,7 @@ class IotStrip(IotDevice):
@property # type: ignore
@requires_update
def on_since(self) -> Optional[datetime]:
def on_since(self) -> datetime | None:
"""Return the maximum on-time of all outlets."""
if self.is_off:
return None
@@ -170,8 +172,8 @@ class IotStrip(IotDevice):
@requires_update
async def get_emeter_daily(
self, year: Optional[int] = None, month: Optional[int] = None, kwh: bool = True
) -> Dict:
self, year: int | None = None, month: int | None = None, kwh: bool = True
) -> dict:
"""Retrieve daily statistics for a given month.
:param year: year for which to retrieve statistics (default: this year)
@@ -186,8 +188,8 @@ class IotStrip(IotDevice):
@requires_update
async def get_emeter_monthly(
self, year: Optional[int] = None, kwh: bool = True
) -> Dict:
self, year: int | None = None, kwh: bool = True
) -> dict:
"""Retrieve monthly statistics for a given year.
:param year: year for which to retrieve statistics (default: this year)
@@ -197,7 +199,7 @@ class IotStrip(IotDevice):
"get_emeter_monthly", {"year": year, "kwh": kwh}
)
async def _async_get_emeter_sum(self, func: str, kwargs: Dict[str, Any]) -> Dict:
async def _async_get_emeter_sum(self, func: str, kwargs: dict[str, Any]) -> dict:
"""Retreive emeter stats for a time period from children."""
self._verify_emeter()
return merge_sums(
@@ -212,13 +214,13 @@ class IotStrip(IotDevice):
@property # type: ignore
@requires_update
def emeter_this_month(self) -> Optional[float]:
def emeter_this_month(self) -> float | None:
"""Return this month's energy consumption in kWh."""
return sum(plug.emeter_this_month for plug in self.children)
@property # type: ignore
@requires_update
def emeter_today(self) -> Optional[float]:
def emeter_today(self) -> float | None:
"""Return this month's energy consumption in kWh."""
return sum(plug.emeter_today for plug in self.children)
@@ -243,7 +245,7 @@ class IotStripPlug(IotPlug):
The plug inherits (most of) the system information from the parent.
"""
def __init__(self, host: str, parent: "IotStrip", child_id: str) -> None:
def __init__(self, host: str, parent: IotStrip, child_id: str) -> None:
super().__init__(host)
self.parent = parent
@@ -262,16 +264,14 @@ class IotStripPlug(IotPlug):
"""
await self._modular_update({})
def _create_emeter_request(
self, year: Optional[int] = None, month: Optional[int] = None
):
def _create_emeter_request(self, year: int | None = None, month: int | None = None):
"""Create a request for requesting all emeter statistics at once."""
if year is None:
year = datetime.now().year
if month is None:
month = datetime.now().month
req: Dict[str, Any] = {}
req: dict[str, Any] = {}
merge(req, self._create_request("emeter", "get_realtime"))
merge(req, self._create_request("emeter", "get_monthstat", {"year": year}))
@@ -285,16 +285,16 @@ class IotStripPlug(IotPlug):
return req
def _create_request(
self, target: str, cmd: str, arg: Optional[Dict] = None, child_ids=None
self, target: str, cmd: str, arg: dict | None = None, child_ids=None
):
request: Dict[str, Any] = {
request: dict[str, Any] = {
"context": {"child_ids": [self.child_id]},
target: {cmd: arg},
}
return request
async def _query_helper(
self, target: str, cmd: str, arg: Optional[Dict] = None, child_ids=None
self, target: str, cmd: str, arg: dict | None = None, child_ids=None
) -> Any:
"""Override query helper to include the child_ids."""
return await self.parent._query_helper(
@@ -335,14 +335,14 @@ class IotStripPlug(IotPlug):
@property # type: ignore
@requires_update
def next_action(self) -> Dict:
def next_action(self) -> dict:
"""Return next scheduled(?) action."""
info = self._get_child_info()
return info["next_action"]
@property # type: ignore
@requires_update
def on_since(self) -> Optional[datetime]:
def on_since(self) -> datetime | None:
"""Return on-time, if available."""
if self.is_off:
return None
@@ -359,7 +359,7 @@ class IotStripPlug(IotPlug):
sys_info = self.parent.sys_info
return f"Socket for {sys_info['model']}"
def _get_child_info(self) -> Dict:
def _get_child_info(self) -> dict:
"""Return the subdevice information for this device."""
for plug in self.parent.sys_info["children"]:
if plug["id"] == self.child_id:

View File

@@ -1,7 +1,8 @@
"""Implementation of the emeter module."""
from __future__ import annotations
from datetime import datetime
from typing import Dict, List, Optional, Union
from ...emeterstatus import EmeterStatus
from .usage import Usage
@@ -16,7 +17,7 @@ class Emeter(Usage):
return EmeterStatus(self.data["get_realtime"])
@property
def emeter_today(self) -> Optional[float]:
def emeter_today(self) -> float | None:
"""Return today's energy consumption in kWh."""
raw_data = self.daily_data
today = datetime.now().day
@@ -24,7 +25,7 @@ class Emeter(Usage):
return data.get(today)
@property
def emeter_this_month(self) -> Optional[float]:
def emeter_this_month(self) -> float | None:
"""Return this month's energy consumption in kWh."""
raw_data = self.monthly_data
current_month = datetime.now().month
@@ -42,7 +43,7 @@ class Emeter(Usage):
"""Return real-time statistics."""
return await self.call("get_realtime")
async def get_daystat(self, *, year=None, month=None, kwh=True) -> Dict:
async def get_daystat(self, *, year=None, month=None, kwh=True) -> dict:
"""Return daily stats for the given year & month.
The return value is a dictionary of {day: energy, ...}.
@@ -51,7 +52,7 @@ class Emeter(Usage):
data = self._convert_stat_data(data["day_list"], entry_key="day", kwh=kwh)
return data
async def get_monthstat(self, *, year=None, kwh=True) -> Dict:
async def get_monthstat(self, *, year=None, kwh=True) -> dict:
"""Return monthly stats for the given year.
The return value is a dictionary of {month: energy, ...}.
@@ -62,11 +63,11 @@ class Emeter(Usage):
def _convert_stat_data(
self,
data: List[Dict[str, Union[int, float]]],
data: list[dict[str, int | float]],
entry_key: str,
kwh: bool = True,
key: Optional[int] = None,
) -> Dict[Union[int, float], Union[int, float]]:
key: int | None = None,
) -> dict[int | float, int | float]:
"""Return emeter information keyed with the day/month.
The incoming data is a list of dictionaries::

View File

@@ -1,7 +1,8 @@
"""Implementation of the motion detection (PIR) module found in some dimmers."""
from __future__ import annotations
from enum import Enum
from typing import Optional
from ...exceptions import KasaException
from ..iotmodule import IotModule
@@ -43,7 +44,7 @@ class Motion(IotModule):
return await self.call("set_enable", {"enable": int(state)})
async def set_range(
self, *, range: Optional[Range] = None, custom_range: Optional[int] = None
self, *, range: Range | None = None, custom_range: int | None = None
):
"""Set the range for the sensor.

View File

@@ -1,5 +1,7 @@
"""Base implementation for all rule-based modules."""
from __future__ import annotations
import logging
from enum import Enum
from typing import Dict, List, Optional
@@ -37,20 +39,20 @@ class Rule(BaseModel):
id: str
name: str
enable: bool
wday: List[int]
wday: List[int] # noqa: UP006
repeat: bool
# start action
sact: Optional[Action]
sact: Optional[Action] # noqa: UP007
stime_opt: TimeOption
smin: int
eact: Optional[Action]
eact: Optional[Action] # noqa: UP007
etime_opt: TimeOption
emin: int
# Only on bulbs
s_light: Optional[Dict]
s_light: Optional[Dict] # noqa: UP006,UP007
_LOGGER = logging.getLogger(__name__)
@@ -65,7 +67,7 @@ class RuleModule(IotModule):
return merge(q, self.query_for_command("get_next_action"))
@property
def rules(self) -> List[Rule]:
def rules(self) -> list[Rule]:
"""Return the list of rules for the service."""
try:
return [

View File

@@ -1,7 +1,8 @@
"""Implementation of the usage interface."""
from __future__ import annotations
from datetime import datetime
from typing import Dict
from ..iotmodule import IotModule, merge
@@ -58,7 +59,7 @@ class Usage(IotModule):
return entry["time"]
return None
async def get_raw_daystat(self, *, year=None, month=None) -> Dict:
async def get_raw_daystat(self, *, year=None, month=None) -> dict:
"""Return raw daily stats for the given year & month."""
if year is None:
year = datetime.now().year
@@ -67,14 +68,14 @@ class Usage(IotModule):
return await self.call("get_daystat", {"year": year, "month": month})
async def get_raw_monthstat(self, *, year=None) -> Dict:
async def get_raw_monthstat(self, *, year=None) -> dict:
"""Return raw monthly stats for the given year."""
if year is None:
year = datetime.now().year
return await self.call("get_monthstat", {"year": year})
async def get_daystat(self, *, year=None, month=None) -> Dict:
async def get_daystat(self, *, year=None, month=None) -> dict:
"""Return daily stats for the given year & month.
The return value is a dictionary of {day: time, ...}.
@@ -83,7 +84,7 @@ class Usage(IotModule):
data = self._convert_stat_data(data["day_list"], entry_key="day")
return data
async def get_monthstat(self, *, year=None) -> Dict:
async def get_monthstat(self, *, year=None) -> dict:
"""Return monthly stats for the given year.
The return value is a dictionary of {month: time, ...}.
@@ -96,7 +97,7 @@ class Usage(IotModule):
"""Erase all stats."""
return await self.call("erase_runtime_stat")
def _convert_stat_data(self, data, entry_key) -> Dict:
def _convert_stat_data(self, data, entry_key) -> dict:
"""Return usage information keyed with the day/month.
The incoming data is a list of dictionaries::