Skip to content

Commit 2de2f73

Browse files
committed
feat: migrate to native types
As defined in PEP 585 – Type Hinting Generics In Standard Collections https://peps.python.org/pep-0585/
1 parent 0dad543 commit 2de2f73

38 files changed

Lines changed: 268 additions & 275 deletions

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ repos:
3737
rev: v3.19.1
3838
hooks:
3939
- id: pyupgrade
40-
args: [--py38-plus]
40+
args: [--py39-plus]
4141
- repo: https://github.com/astral-sh/ruff-pre-commit
4242
rev: v0.8.6
4343
hooks:

bench/incoming.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import socket
44
import timeit
5-
from typing import List
65

76
from zeroconf import (
87
DNSAddress,
@@ -15,7 +14,7 @@
1514
)
1615

1716

18-
def generate_packets() -> List[bytes]:
17+
def generate_packets() -> list[bytes]:
1918
out = DNSOutgoing(const._FLAGS_QR_RESPONSE | const._FLAGS_AA)
2019
address = socket.inet_pton(socket.AF_INET, "192.168.208.5")
2120

docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# All configuration values have a default; values that are commented out
88
# serve to show the default.
99

10-
from typing import Any, Dict
10+
from typing import Any
1111

1212
import zeroconf
1313

@@ -173,7 +173,7 @@
173173

174174
# -- Options for LaTeX output --------------------------------------------------
175175

176-
latex_elements: Dict[str, Any] = {}
176+
latex_elements: dict[str, Any] = {}
177177

178178
# Grouping the document tree into LaTeX files. List of tuples
179179
# (source start file, target name, title, author, documentclass [howto/manual]).

examples/async_registration.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import asyncio
77
import logging
88
import socket
9-
from typing import List, Optional
9+
from typing import Optional
1010

1111
from zeroconf import IPVersion
1212
from zeroconf.asyncio import AsyncServiceInfo, AsyncZeroconf
@@ -17,7 +17,7 @@ def __init__(self, ip_version: IPVersion) -> None:
1717
self.ip_version = ip_version
1818
self.aiozc: Optional[AsyncZeroconf] = None
1919

20-
async def register_services(self, infos: List[AsyncServiceInfo]) -> None:
20+
async def register_services(self, infos: list[AsyncServiceInfo]) -> None:
2121
self.aiozc = AsyncZeroconf(ip_version=self.ip_version)
2222
tasks = [self.aiozc.async_register_service(info) for info in infos]
2323
background_tasks = await asyncio.gather(*tasks)
@@ -26,7 +26,7 @@ async def register_services(self, infos: List[AsyncServiceInfo]) -> None:
2626
while True:
2727
await asyncio.sleep(1)
2828

29-
async def unregister_services(self, infos: List[AsyncServiceInfo]) -> None:
29+
async def unregister_services(self, infos: list[AsyncServiceInfo]) -> None:
3030
assert self.aiozc is not None
3131
tasks = [self.aiozc.async_unregister_service(info) for info in infos]
3232
background_tasks = await asyncio.gather(*tasks)

examples/async_service_info_request.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import argparse
1111
import asyncio
1212
import logging
13-
from typing import Any, List, Optional, cast
13+
from typing import Any, Optional, cast
1414

1515
from zeroconf import IPVersion, ServiceBrowser, ServiceStateChange, Zeroconf
1616
from zeroconf.asyncio import AsyncServiceInfo, AsyncZeroconf
@@ -22,7 +22,7 @@ async def async_watch_services(aiozc: AsyncZeroconf) -> None:
2222
zeroconf = aiozc.zeroconf
2323
while True:
2424
await asyncio.sleep(5)
25-
infos: List[AsyncServiceInfo] = []
25+
infos: list[AsyncServiceInfo] = []
2626
for name in zeroconf.cache.names():
2727
if not name.endswith(HAP_TYPE):
2828
continue

src/zeroconf/_cache.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@
2020
USA
2121
"""
2222

23+
from collections.abc import Iterable
2324
from heapq import heapify, heappop, heappush
24-
from typing import Dict, Iterable, List, Optional, Set, Tuple, Union, cast
25+
from typing import Optional, Union, cast
2526

2627
from ._dns import (
2728
DNSAddress,
@@ -38,7 +39,7 @@
3839

3940
_UNIQUE_RECORD_TYPES = (DNSAddress, DNSHinfo, DNSPointer, DNSText, DNSService)
4041
_UniqueRecordsType = Union[DNSAddress, DNSHinfo, DNSPointer, DNSText, DNSService]
41-
_DNSRecordCacheType = Dict[str, Dict[DNSRecord, DNSRecord]]
42+
_DNSRecordCacheType = dict[str, dict[DNSRecord, DNSRecord]]
4243
_DNSRecord = DNSRecord
4344
_str = str
4445
_float = float
@@ -66,8 +67,8 @@ class DNSCache:
6667

6768
def __init__(self) -> None:
6869
self.cache: _DNSRecordCacheType = {}
69-
self._expire_heap: List[Tuple[float, DNSRecord]] = []
70-
self._expirations: Dict[DNSRecord, float] = {}
70+
self._expire_heap: list[tuple[float, DNSRecord]] = []
71+
self._expirations: dict[DNSRecord, float] = {}
7172
self.service_cache: _DNSRecordCacheType = {}
7273

7374
# Functions prefixed with async_ are NOT threadsafe and must
@@ -132,7 +133,7 @@ def async_remove_records(self, entries: Iterable[DNSRecord]) -> None:
132133
for entry in entries:
133134
self._async_remove(entry)
134135

135-
def async_expire(self, now: _float) -> List[DNSRecord]:
136+
def async_expire(self, now: _float) -> list[DNSRecord]:
136137
"""Purge expired entries from the cache.
137138
138139
This function must be run in from event loop.
@@ -142,7 +143,7 @@ def async_expire(self, now: _float) -> List[DNSRecord]:
142143
if not (expire_heap_len := len(self._expire_heap)):
143144
return []
144145

145-
expired: List[DNSRecord] = []
146+
expired: list[DNSRecord] = []
146147
# Find any expired records and add them to the to-delete list
147148
while self._expire_heap:
148149
when, record = self._expire_heap[0]
@@ -189,31 +190,31 @@ def async_get_unique(self, entry: _UniqueRecordsType) -> Optional[DNSRecord]:
189190
return None
190191
return store.get(entry)
191192

192-
def async_all_by_details(self, name: _str, type_: _int, class_: _int) -> List[DNSRecord]:
193+
def async_all_by_details(self, name: _str, type_: _int, class_: _int) -> list[DNSRecord]:
193194
"""Gets all matching entries by details.
194195
195196
This function is not thread-safe and must be called from
196197
the event loop.
197198
"""
198199
key = name.lower()
199200
records = self.cache.get(key)
200-
matches: List[DNSRecord] = []
201+
matches: list[DNSRecord] = []
201202
if records is None:
202203
return matches
203204
for record in records.values():
204205
if type_ == record.type and class_ == record.class_:
205206
matches.append(record)
206207
return matches
207208

208-
def async_entries_with_name(self, name: str) -> List[DNSRecord]:
209+
def async_entries_with_name(self, name: str) -> list[DNSRecord]:
209210
"""Returns a dict of entries whose key matches the name.
210211
211212
This function is not threadsafe and must be called from
212213
the event loop.
213214
"""
214215
return self.entries_with_name(name)
215216

216-
def async_entries_with_server(self, name: str) -> List[DNSRecord]:
217+
def async_entries_with_server(self, name: str) -> list[DNSRecord]:
217218
"""Returns a dict of entries whose key matches the server.
218219
219220
This function is not threadsafe and must be called from
@@ -256,21 +257,21 @@ def get_by_details(self, name: str, type_: _int, class_: _int) -> Optional[DNSRe
256257
return cached_entry
257258
return None
258259

259-
def get_all_by_details(self, name: str, type_: _int, class_: _int) -> List[DNSRecord]:
260+
def get_all_by_details(self, name: str, type_: _int, class_: _int) -> list[DNSRecord]:
260261
"""Gets all matching entries by details."""
261262
key = name.lower()
262263
records = self.cache.get(key)
263264
if records is None:
264265
return []
265266
return [entry for entry in list(records.values()) if type_ == entry.type and class_ == entry.class_]
266267

267-
def entries_with_server(self, server: str) -> List[DNSRecord]:
268+
def entries_with_server(self, server: str) -> list[DNSRecord]:
268269
"""Returns a list of entries whose server matches the name."""
269270
if entries := self.service_cache.get(server.lower()):
270271
return list(entries.values())
271272
return []
272273

273-
def entries_with_name(self, name: str) -> List[DNSRecord]:
274+
def entries_with_name(self, name: str) -> list[DNSRecord]:
274275
"""Returns a list of entries whose key matches the name."""
275276
if entries := self.cache.get(name.lower()):
276277
return list(entries.values())
@@ -287,13 +288,13 @@ def current_entry_with_name_and_alias(self, name: str, alias: str) -> Optional[D
287288
return record
288289
return None
289290

290-
def names(self) -> List[str]:
291+
def names(self) -> list[str]:
291292
"""Return a copy of the list of current cache names."""
292293
return list(self.cache)
293294

294295
def async_mark_unique_records_older_than_1s_to_expire(
295296
self,
296-
unique_types: Set[Tuple[_str, _int, _int]],
297+
unique_types: set[tuple[_str, _int, _int]],
297298
answers: Iterable[DNSRecord],
298299
now: _float,
299300
) -> None:

src/zeroconf/_core.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@
2424
import logging
2525
import sys
2626
import threading
27+
from collections.abc import Awaitable
2728
from types import TracebackType
28-
from typing import Awaitable, Dict, List, Optional, Set, Tuple, Type, Union
29+
from typing import Optional, Union
2930

3031
from ._cache import DNSCache
3132
from ._dns import DNSQuestion, DNSQuestionType
@@ -110,7 +111,7 @@ def async_send_with_transport(
110111
out: DNSOutgoing,
111112
addr: Optional[str],
112113
port: int,
113-
v6_flow_scope: Union[Tuple[()], Tuple[int, int]] = (),
114+
v6_flow_scope: Union[tuple[()], tuple[int, int]] = (),
114115
) -> None:
115116
ipv6_socket = transport.is_ipv6
116117
if addr is None:
@@ -181,7 +182,7 @@ def __init__(
181182

182183
self.engine = AsyncEngine(self, listen_socket, respond_sockets)
183184

184-
self.browsers: Dict[ServiceListener, ServiceBrowser] = {}
185+
self.browsers: dict[ServiceListener, ServiceBrowser] = {}
185186
self.registry = ServiceRegistry()
186187
self.cache = DNSCache()
187188
self.question_history = QuestionHistory()
@@ -192,7 +193,7 @@ def __init__(
192193
self.query_handler = QueryHandler(self)
193194
self.record_manager = RecordManager(self)
194195

195-
self._notify_futures: Set[asyncio.Future] = set()
196+
self._notify_futures: set[asyncio.Future] = set()
196197
self.loop: Optional[asyncio.AbstractEventLoop] = None
197198
self._loop_thread: Optional[threading.Thread] = None
198199

@@ -239,7 +240,7 @@ async def async_wait_for_start(self) -> None:
239240
raise NotRunningException
240241

241242
@property
242-
def listeners(self) -> Set[RecordUpdateListener]:
243+
def listeners(self) -> set[RecordUpdateListener]:
243244
return self.record_manager.listeners
244245

245246
async def async_wait(self, timeout: float) -> None:
@@ -562,7 +563,7 @@ async def async_check_service(
562563
def add_listener(
563564
self,
564565
listener: RecordUpdateListener,
565-
question: Optional[Union[DNSQuestion, List[DNSQuestion]]],
566+
question: Optional[Union[DNSQuestion, list[DNSQuestion]]],
566567
) -> None:
567568
"""Adds a listener for a given question. The listener will have
568569
its update_record method called when information is available to
@@ -584,7 +585,7 @@ def remove_listener(self, listener: RecordUpdateListener) -> None:
584585
def async_add_listener(
585586
self,
586587
listener: RecordUpdateListener,
587-
question: Optional[Union[DNSQuestion, List[DNSQuestion]]],
588+
question: Optional[Union[DNSQuestion, list[DNSQuestion]]],
588589
) -> None:
589590
"""Adds a listener for a given question. The listener will have
590591
its update_record method called when information is available to
@@ -606,7 +607,7 @@ def send(
606607
out: DNSOutgoing,
607608
addr: Optional[str] = None,
608609
port: int = _MDNS_PORT,
609-
v6_flow_scope: Union[Tuple[()], Tuple[int, int]] = (),
610+
v6_flow_scope: Union[tuple[()], tuple[int, int]] = (),
610611
transport: Optional[_WrappedTransport] = None,
611612
) -> None:
612613
"""Sends an outgoing packet threadsafe."""
@@ -618,7 +619,7 @@ def async_send(
618619
out: DNSOutgoing,
619620
addr: Optional[str] = None,
620621
port: int = _MDNS_PORT,
621-
v6_flow_scope: Union[Tuple[()], Tuple[int, int]] = (),
622+
v6_flow_scope: Union[tuple[()], tuple[int, int]] = (),
622623
transport: Optional[_WrappedTransport] = None,
623624
) -> None:
624625
"""Sends an outgoing packet."""
@@ -706,7 +707,7 @@ def __enter__(self) -> "Zeroconf":
706707

707708
def __exit__( # pylint: disable=useless-return
708709
self,
709-
exc_type: Optional[Type[BaseException]],
710+
exc_type: Optional[type[BaseException]],
710711
exc_val: Optional[BaseException],
711712
exc_tb: Optional[TracebackType],
712713
) -> Optional[bool]:

src/zeroconf/_dns.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
import enum
2424
import socket
25-
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Union, cast
25+
from typing import TYPE_CHECKING, Any, Optional, Union, cast
2626

2727
from ._exceptions import AbstractMethodException
2828
from ._utils.net import _is_v6_address
@@ -539,7 +539,7 @@ def __init__(
539539
class_: int,
540540
ttl: Union[int, float],
541541
next_name: str,
542-
rdtypes: List[int],
542+
rdtypes: list[int],
543543
created: Optional[float] = None,
544544
) -> None:
545545
self._fast_init(name, type_, class_, ttl, next_name, rdtypes, created or current_time_millis())
@@ -551,7 +551,7 @@ def _fast_init(
551551
class_: _int,
552552
ttl: _float,
553553
next_name: str,
554-
rdtypes: List[_int],
554+
rdtypes: list[_int],
555555
created: _float,
556556
) -> None:
557557
self._fast_init_record(name, type_, class_, ttl, created)
@@ -610,21 +610,21 @@ class DNSRRSet:
610610

611611
__slots__ = ("_lookup", "_records")
612612

613-
def __init__(self, records: List[DNSRecord]) -> None:
613+
def __init__(self, records: list[DNSRecord]) -> None:
614614
"""Create an RRset from records sets."""
615615
self._records = records
616-
self._lookup: Optional[Dict[DNSRecord, DNSRecord]] = None
616+
self._lookup: Optional[dict[DNSRecord, DNSRecord]] = None
617617

618618
@property
619-
def lookup(self) -> Dict[DNSRecord, DNSRecord]:
619+
def lookup(self) -> dict[DNSRecord, DNSRecord]:
620620
"""Return the lookup table."""
621621
return self._get_lookup()
622622

623-
def lookup_set(self) -> Set[DNSRecord]:
623+
def lookup_set(self) -> set[DNSRecord]:
624624
"""Return the lookup table as aset."""
625625
return set(self._get_lookup())
626626

627-
def _get_lookup(self) -> Dict[DNSRecord, DNSRecord]:
627+
def _get_lookup(self) -> dict[DNSRecord, DNSRecord]:
628628
"""Return the lookup table, building it if needed."""
629629
if self._lookup is None:
630630
# Build the hash table so we can lookup the record ttl

src/zeroconf/_engine.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import itertools
2525
import socket
2626
import threading
27-
from typing import TYPE_CHECKING, List, Optional, cast
27+
from typing import TYPE_CHECKING, Optional, cast
2828

2929
from ._record_update import RecordUpdate
3030
from ._utils.asyncio import get_running_loop, run_coro_with_timeout
@@ -60,13 +60,13 @@ def __init__(
6060
self,
6161
zeroconf: "Zeroconf",
6262
listen_socket: Optional[socket.socket],
63-
respond_sockets: List[socket.socket],
63+
respond_sockets: list[socket.socket],
6464
) -> None:
6565
self.loop: Optional[asyncio.AbstractEventLoop] = None
6666
self.zc = zeroconf
67-
self.protocols: List[AsyncListener] = []
68-
self.readers: List[_WrappedTransport] = []
69-
self.senders: List[_WrappedTransport] = []
67+
self.protocols: list[AsyncListener] = []
68+
self.readers: list[_WrappedTransport] = []
69+
self.senders: list[_WrappedTransport] = []
7070
self.running_event: Optional[asyncio.Event] = None
7171
self._listen_socket = listen_socket
7272
self._respond_sockets = respond_sockets

0 commit comments

Comments
 (0)