Skip to content

Commit 2dc6faf

Browse files
authored
Drop python3.8 support (#1979)
1 parent e88159f commit 2dc6faf

File tree

88 files changed

+484
-590
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+484
-590
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ jobs:
5959
strategy:
6060
fail-fast: false
6161
matrix:
62-
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "pypy3.8"]
62+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "pypy3.9"]
6363
os: [ubuntu-latest, macos-latest, windows-latest]
6464
# Exclude example, in case needed again in the future:
6565
# exclude:

.pre-commit-config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,4 @@ repos:
5858
rev: v3.15.0
5959
hooks:
6060
- id: pyupgrade
61-
args: ['--py38-plus']
61+
args: ['--py39-plus']

devtools/containers.py

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22
from dataclasses import dataclass, field
33
from operator import attrgetter
4-
from typing import Any, Dict, List, Optional
4+
from typing import Any, Optional
55

66
from dataclasses_json import DataClassJsonMixin, config
77

@@ -45,7 +45,7 @@ def filename(self) -> str:
4545

4646
@dataclass
4747
class ModelMapping(DataClassJsonMixin):
48-
instances: List[InstanceInfo]
48+
instances: list[InstanceInfo]
4949

5050
def info_for_model(self, model: str, *, status_filter="released") -> InstanceInfo:
5151
matches = [inst for inst in self.instances if inst.model == model]
@@ -76,12 +76,12 @@ class Property(DataClassJsonMixin):
7676
type: str
7777
description: str
7878
format: str
79-
access: List[str]
79+
access: list[str]
8080

81-
value_list: Optional[List[Dict[str, Any]]] = field(
81+
value_list: Optional[list[dict[str, Any]]] = field(
8282
default_factory=list, metadata=config(field_name="value-list")
8383
) # type: ignore
84-
value_range: Optional[List[int]] = field(
84+
value_range: Optional[list[int]] = field(
8585
default=None, metadata=config(field_name="value-range")
8686
)
8787

@@ -156,8 +156,8 @@ class Action(DataClassJsonMixin):
156156
iid: int
157157
type: str
158158
description: str
159-
out: List[Any] = field(default_factory=list)
160-
in_: List[Any] = field(default_factory=list, metadata=config(field_name="in"))
159+
out: list[Any] = field(default_factory=list)
160+
in_: list[Any] = field(default_factory=list, metadata=config(field_name="in"))
161161

162162
def __repr__(self):
163163
return f"aiid {self.iid} {self.description}: in: {self.in_} -> out: {self.out}"
@@ -178,7 +178,7 @@ class Event(DataClassJsonMixin):
178178
iid: int
179179
type: str
180180
description: str
181-
arguments: List[int]
181+
arguments: list[int]
182182

183183
def __repr__(self):
184184
return f"eiid {self.iid} ({self.description}): (args: {self.arguments})"
@@ -189,9 +189,9 @@ class Service(DataClassJsonMixin):
189189
iid: int
190190
type: str
191191
description: str
192-
properties: List[Property] = field(default_factory=list)
193-
actions: List[Action] = field(default_factory=list)
194-
events: List[Event] = field(default_factory=list)
192+
properties: list[Property] = field(default_factory=list)
193+
actions: list[Action] = field(default_factory=list)
194+
events: list[Event] = field(default_factory=list)
195195

196196
def __repr__(self):
197197
return f"siid {self.iid}: ({self.description}): {len(self.properties)} props, {len(self.actions)} actions"
@@ -220,7 +220,7 @@ def as_code(self):
220220
class Device(DataClassJsonMixin):
221221
type: str
222222
description: str
223-
services: List[Service] = field(default_factory=list)
223+
services: list[Service] = field(default_factory=list)
224224

225225
def as_code(self):
226226
s = ""

docs/conf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@
183183
)
184184
]
185185

186-
intersphinx_mapping = {"python": ("https://docs.python.org/3.8", None)}
186+
intersphinx_mapping = {"python": ("https://docs.python.org/3", None)}
187187

188188
apidoc_module_dir = "../miio"
189189
apidoc_output_dir = "api"

miio/cli.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import logging
2-
from typing import Any, Dict
2+
from typing import Any
33

44
import click
55

@@ -30,7 +30,7 @@
3030
@click.version_option(package_name="python-miio")
3131
@click.pass_context
3232
def cli(ctx, debug: int, output: str):
33-
logging_config: Dict[str, Any] = {
33+
logging_config: dict[str, Any] = {
3434
"level": logging.DEBUG if debug > 0 else logging.INFO
3535
}
3636
try:
@@ -56,7 +56,7 @@ def cli(ctx, debug: int, output: str):
5656

5757

5858
for device_class in DeviceGroupMeta._device_classes:
59-
cli.add_command(device_class.get_device_group())
59+
cli.add_command(device_class.get_device_group()) # type: ignore[attr-defined]
6060

6161

6262
@click.command()

miio/click_common.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import logging
1010
import re
1111
from functools import partial, wraps
12-
from typing import Any, Callable, ClassVar, Dict, List, Optional, Set, Type, Union
12+
from typing import Any, Callable, ClassVar, Optional, Union
1313

1414
import click
1515

@@ -111,9 +111,9 @@ def __init__(self, debug: int = 0, output: Optional[Callable] = None):
111111

112112

113113
class DeviceGroupMeta(type):
114-
_device_classes: Set[Type] = set()
115-
_supported_models: ClassVar[List[str]]
116-
_mappings: ClassVar[Dict[str, Any]]
114+
_device_classes: set[type] = set()
115+
_supported_models: ClassVar[list[str]]
116+
_mappings: ClassVar[dict[str, Any]]
117117

118118
def __new__(mcs, name, bases, namespace):
119119
commands = {}
@@ -150,7 +150,7 @@ def get_device_group(dcls):
150150
return cls
151151

152152
@property
153-
def supported_models(cls) -> List[str]:
153+
def supported_models(cls) -> list[str]:
154154
"""Return list of supported models."""
155155
return list(cls._mappings.keys()) or cls._supported_models
156156

miio/cloud.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
22
import logging
3-
from typing import TYPE_CHECKING, Dict, Optional
3+
from typing import TYPE_CHECKING, Optional
44

55
import click
66

@@ -127,14 +127,14 @@ def _parse_device_list(self, data, locale):
127127
return devs
128128

129129
@classmethod
130-
def available_locales(cls) -> Dict[str, str]:
130+
def available_locales(cls) -> dict[str, str]:
131131
"""Return available locales.
132132
133133
The value is the human-readable name of the locale.
134134
"""
135135
return AVAILABLE_LOCALES
136136

137-
def get_devices(self, locale: Optional[str] = None) -> Dict[str, CloudDeviceInfo]:
137+
def get_devices(self, locale: Optional[str] = None) -> dict[str, CloudDeviceInfo]:
138138
"""Return a list of available devices keyed with a device id.
139139
140140
If no locale is given, all known locales are browsed. If a device id is already
@@ -147,7 +147,7 @@ def get_devices(self, locale: Optional[str] = None) -> Dict[str, CloudDeviceInfo
147147
self._micloud.get_devices(country=locale), locale=locale
148148
)
149149

150-
all_devices: Dict[str, CloudDeviceInfo] = {}
150+
all_devices: dict[str, CloudDeviceInfo] = {}
151151
for loc in AVAILABLE_LOCALES:
152152
if loc == "all":
153153
continue

miio/descriptors.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"""
1111

1212
from enum import Enum, Flag, auto
13-
from typing import Any, Callable, Dict, List, Optional, Type
13+
from typing import Any, Callable, Optional
1414

1515
import attr
1616

@@ -55,7 +55,7 @@ class Descriptor:
5555
#: Name of the attribute in the status container that contains the value, if applicable.
5656
status_attribute: Optional[str] = None
5757
#: Additional data related to this descriptor.
58-
extras: Dict = attr.ib(factory=dict, repr=False)
58+
extras: dict = attr.ib(factory=dict, repr=False)
5959
#: Access flags (read, write, execute) for the described item.
6060
access: AccessFlags = attr.ib(default=AccessFlags(0))
6161

@@ -84,7 +84,7 @@ class ActionDescriptor(Descriptor):
8484
method: Optional[Callable] = attr.ib(default=None, repr=False)
8585
#: Name of the method in the device class that can be used to execute the action.
8686
method_name: Optional[str] = attr.ib(default=None, repr=False)
87-
inputs: Optional[List[Any]] = attr.ib(default=None, repr=True)
87+
inputs: Optional[list[Any]] = attr.ib(default=None, repr=True)
8888

8989
access: AccessFlags = attr.ib(default=AccessFlags.Execute)
9090

@@ -153,7 +153,7 @@ class EnumDescriptor(PropertyDescriptor):
153153
#: Name of the attribute in the device class that returns the choices.
154154
choices_attribute: Optional[str] = attr.ib(default=None, repr=False)
155155
#: Enum class containing the available choices.
156-
choices: Optional[Type[Enum]] = attr.ib(default=None, repr=False)
156+
choices: Optional[type[Enum]] = attr.ib(default=None, repr=False)
157157

158158
@property
159159
def __cli_output__(self) -> str:

miio/device.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ class Device(metaclass=DeviceGroupMeta):
3636

3737
retry_count = 3
3838
timeout = 5
39-
_mappings: Dict[str, Any] = {}
40-
_supported_models: List[str] = []
39+
_mappings: dict[str, Any] = {}
40+
_supported_models: list[str] = []
4141

4242
def __init_subclass__(cls, **kwargs):
4343
"""Overridden to register all integrations to the factory."""
@@ -182,7 +182,7 @@ def raw_id(self) -> int:
182182
return self._protocol.raw_id
183183

184184
@property
185-
def supported_models(self) -> List[str]:
185+
def supported_models(self) -> list[str]:
186186
"""Return a list of supported models."""
187187
return list(self._mappings.keys()) or self._supported_models
188188

miio/devicefactory.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import logging
2-
from typing import Dict, List, Optional, Type
2+
from typing import Optional
33

44
import click
55

@@ -22,11 +22,11 @@ class DeviceFactory:
2222
dev = DeviceFactory.create("127.0.0.1", 32*"0")
2323
"""
2424

25-
_integration_classes: List[Type[Device]] = []
26-
_supported_models: Dict[str, Type[Device]] = {}
25+
_integration_classes: list[type[Device]] = []
26+
_supported_models: dict[str, type[Device]] = {}
2727

2828
@classmethod
29-
def register(cls, integration_cls: Type[Device]):
29+
def register(cls, integration_cls: type[Device]):
3030
"""Register class for to the registry."""
3131
cls._integration_classes.append(integration_cls)
3232
_LOGGER.debug("Registering %s", integration_cls.__name__)
@@ -44,13 +44,13 @@ def register(cls, integration_cls: Type[Device]):
4444
cls._supported_models[model] = integration_cls
4545

4646
@classmethod
47-
def supported_models(cls) -> Dict[str, Type[Device]]:
47+
def supported_models(cls) -> dict[str, type[Device]]:
4848
"""Return a dictionary of models and their corresponding implementation
4949
classes."""
5050
return cls._supported_models
5151

5252
@classmethod
53-
def integrations(cls) -> List[Type[Device]]:
53+
def integrations(cls) -> list[type[Device]]:
5454
"""Return the list of integration classes."""
5555
return cls._integration_classes
5656

miio/deviceinfo.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Dict, Optional
1+
from typing import Optional
22

33

44
class DeviceInfo:
@@ -40,7 +40,7 @@ def __repr__(self):
4040
)
4141

4242
@property
43-
def network_interface(self) -> Dict:
43+
def network_interface(self) -> dict:
4444
"""Information about network configuration.
4545
4646
If unavailable, returns an empty dictionary.

miio/devicestatus.py

+4-13
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,9 @@
11
import inspect
22
import logging
33
import warnings
4+
from collections.abc import Iterable
45
from enum import Enum
5-
from typing import (
6-
Callable,
7-
Dict,
8-
Iterable,
9-
Optional,
10-
Type,
11-
Union,
12-
get_args,
13-
get_origin,
14-
get_type_hints,
15-
)
6+
from typing import Callable, Optional, Union, get_args, get_origin, get_type_hints
167

178
import attr
189

@@ -37,7 +28,7 @@ def __new__(metacls, name, bases, namespace, **kwargs):
3728

3829
cls._descriptors: DescriptorCollection[PropertyDescriptor] = {}
3930
cls._parent: Optional["DeviceStatus"] = None
40-
cls._embedded: Dict[str, "DeviceStatus"] = {}
31+
cls._embedded: dict[str, "DeviceStatus"] = {}
4132

4233
for n in namespace:
4334
prop = getattr(namespace[n], "fget", None)
@@ -222,7 +213,7 @@ def setting(
222213
max_value: Optional[int] = None,
223214
step: Optional[int] = None,
224215
range_attribute: Optional[str] = None,
225-
choices: Optional[Type[Enum]] = None,
216+
choices: Optional[type[Enum]] = None,
226217
choices_attribute: Optional[str] = None,
227218
**kwargs,
228219
):

miio/devtools/pcapparser.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from collections import Counter, defaultdict
44
from ipaddress import ip_address
55
from pprint import pformat as pf
6-
from typing import List
76

87
import click
98

@@ -16,7 +15,7 @@
1615
from miio import Message
1716

1817

19-
def read_payloads_from_file(file, tokens: List[str]):
18+
def read_payloads_from_file(file, tokens: list[str]):
2019
"""Read the given pcap file and yield src, dst, and result."""
2120
try:
2221
import dpkt
@@ -86,7 +85,7 @@ def read_payloads_from_file(file, tokens: List[str]):
8685
@click.command()
8786
@click.argument("file", type=click.File("rb"))
8887
@click.argument("token", nargs=-1)
89-
def parse_pcap(file, token: List[str]):
88+
def parse_pcap(file, token: list[str]):
9089
"""Read PCAP file and output decrypted miio communication."""
9190
for src_addr, dst_addr, payload in read_payloads_from_file(file, token):
9291
echo(f"{src_addr:<15} -> {dst_addr:<15} {pf(payload)}")

0 commit comments

Comments
 (0)