From 8267f5d59075f5712a27aaf9e775f7857a18ab48 Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Sun, 17 Mar 2024 13:06:03 +0100 Subject: [PATCH] Use modern typehint syntax --- benches/bench_codegen.py | 3 +- client/build_backend/backend.py | 8 +- .../src/telethon/_impl/client/client/auth.py | 8 +- .../src/telethon/_impl/client/client/bots.py | 5 +- .../src/telethon/_impl/client/client/chats.py | 4 +- .../telethon/_impl/client/client/client.py | 82 ++++++++----------- .../src/telethon/_impl/client/client/files.py | 52 ++++++------ .../telethon/_impl/client/client/messages.py | 36 ++++---- .../src/telethon/_impl/client/client/net.py | 8 +- .../telethon/_impl/client/client/updates.py | 17 +--- .../src/telethon/_impl/client/client/users.py | 16 ++-- client/src/telethon/_impl/client/errors.py | 8 +- .../src/telethon/_impl/client/events/event.py | 4 +- .../client/events/filters/combinators.py | 7 +- .../_impl/client/events/filters/common.py | 10 +-- .../_impl/client/events/filters/messages.py | 6 +- .../telethon/_impl/client/events/messages.py | 24 +++--- .../telethon/_impl/client/events/queries.py | 8 +- .../src/telethon/_impl/client/parsers/html.py | 33 +++----- .../telethon/_impl/client/parsers/markdown.py | 15 ++-- .../_impl/client/types/admin_right.py | 7 +- .../_impl/client/types/album_builder.py | 24 +++--- .../telethon/_impl/client/types/async_list.py | 9 +- .../_impl/client/types/buttons/__init__.py | 6 +- .../_impl/client/types/buttons/button.py | 38 ++++----- .../_impl/client/types/chat/__init__.py | 10 +-- .../_impl/client/types/chat/channel.py | 12 +-- .../telethon/_impl/client/types/chat/group.py | 16 ++-- .../_impl/client/types/chat_restriction.py | 5 +- .../src/telethon/_impl/client/types/dialog.py | 12 +-- .../src/telethon/_impl/client/types/draft.py | 46 ++++++----- .../src/telethon/_impl/client/types/file.py | 29 +++---- .../_impl/client/types/inline_result.py | 4 +- .../telethon/_impl/client/types/message.py | 38 ++++----- .../_impl/client/types/participant.py | 34 ++++---- .../_impl/client/types/recent_action.py | 4 +- client/src/telethon/_impl/crypto/factorize.py | 3 +- .../telethon/_impl/mtproto/authentication.py | 13 ++- .../telethon/_impl/mtproto/mtp/encrypted.py | 16 ++-- .../src/telethon/_impl/mtproto/mtp/plain.py | 6 +- .../src/telethon/_impl/mtproto/mtp/types.py | 6 +- .../telethon/_impl/mtproto/transport/abcs.py | 2 +- client/src/telethon/_impl/mtsender/sender.py | 29 +++---- .../telethon/_impl/session/chat/hash_cache.py | 6 +- .../_impl/session/message_box/defs.py | 6 +- .../_impl/session/message_box/messagebox.py | 26 +++--- client/src/telethon/_impl/session/session.py | 8 +- .../telethon/_impl/session/storage/sqlite.py | 32 ++++---- client/src/telethon/_impl/tl/core/reader.py | 11 +-- client/src/telethon/_impl/tl/core/request.py | 3 +- .../telethon/_impl/tl/core/serializable.py | 6 +- client/tests/mtproto_test.py | 4 +- client/tests/transport/abridged_test.py | 4 +- client/tests/transport/full_test.py | 6 +- client/tests/transport/intermediate_test.py | 4 +- .../_impl/codegen/fakefs.py | 3 +- .../_impl/codegen/generator.py | 21 +++-- .../_impl/codegen/serde/common.py | 4 +- .../_impl/codegen/serde/deserialization.py | 4 +- .../_impl/codegen/serde/serialization.py | 18 ++-- .../_impl/tl_parser/loader.py | 12 +-- .../_impl/tl_parser/tl/definition.py | 14 ++-- .../_impl/tl_parser/tl/parameter_type.py | 6 +- .../_impl/tl_parser/tl/ty.py | 5 +- .../_impl/tl_parser/tl_iterator.py | 3 +- generator/tests/common_test.py | 4 +- generator/tests/generator_test.py | 8 +- tools/copy_client_signatures.py | 13 ++- tools/copy_init_imports.py | 5 +- typings/pyaes.pyi | 6 +- typings/setuptools.build_meta.pyi | 8 +- typings/setuptools.pyi | 8 +- 72 files changed, 461 insertions(+), 520 deletions(-) diff --git a/benches/bench_codegen.py b/benches/bench_codegen.py index 02142bfd..15e29cfc 100644 --- a/benches/bench_codegen.py +++ b/benches/bench_codegen.py @@ -2,7 +2,8 @@ import datetime import io import struct import timeit -from typing import Any, Iterator +from collections.abc import Iterator +from typing import Any from .data_codegen import DATA, Obj diff --git a/client/build_backend/backend.py b/client/build_backend/backend.py index 718c42ee..6bbaf8d3 100644 --- a/client/build_backend/backend.py +++ b/client/build_backend/backend.py @@ -1,6 +1,6 @@ import sys from pathlib import Path -from typing import Any, Dict, Optional +from typing import Any, Optional from setuptools import build_meta as _orig from setuptools.build_meta import * # noqa: F403 # pyright: ignore [reportWildcardImportFromLibrary] @@ -39,7 +39,7 @@ def gen_types_if_needed() -> None: def build_wheel( # type: ignore [no-redef] wheel_directory: str, - config_settings: Optional[Dict[Any, Any]] = None, + config_settings: Optional[dict[Any, Any]] = None, metadata_directory: Optional[str] = None, ) -> str: gen_types_if_needed() @@ -47,7 +47,7 @@ def build_wheel( # type: ignore [no-redef] def build_sdist( # type: ignore [no-redef] - sdist_directory: str, config_settings: Optional[Dict[Any, Any]] = None + sdist_directory: str, config_settings: Optional[dict[Any, Any]] = None ) -> str: gen_types_if_needed() return _orig.build_sdist(sdist_directory, config_settings) @@ -55,7 +55,7 @@ def build_sdist( # type: ignore [no-redef] def build_editable( # type: ignore [no-redef] wheel_directory: str, - config_settings: Optional[Dict[Any, Any]] = None, + config_settings: Optional[dict[Any, Any]] = None, metadata_directory: Optional[str] = None, ) -> str: gen_types_if_needed() diff --git a/client/src/telethon/_impl/client/client/auth.py b/client/src/telethon/_impl/client/client/auth.py index 9d86bea6..4877c467 100644 --- a/client/src/telethon/_impl/client/client/auth.py +++ b/client/src/telethon/_impl/client/client/auth.py @@ -2,7 +2,7 @@ from __future__ import annotations import getpass import re -from typing import TYPE_CHECKING, Optional, Union +from typing import TYPE_CHECKING, Optional from ...crypto import two_factor_auth from ...mtproto import RpcError @@ -115,9 +115,7 @@ async def request_login_code(self: Client, phone: str) -> LoginToken: return LoginToken._new(result, phone) -async def sign_in( - self: Client, token: LoginToken, code: str -) -> Union[User, PasswordToken]: +async def sign_in(self: Client, token: LoginToken, code: str) -> User | PasswordToken: try: result = await self( functions.auth.sign_in( @@ -213,7 +211,7 @@ async def get_password_information(client: Client) -> PasswordToken: async def check_password( - self: Client, token: PasswordToken, password: Union[str, bytes] + self: Client, token: PasswordToken, password: str | bytes ) -> User: algo = token._password.current_algo if not isinstance( diff --git a/client/src/telethon/_impl/client/client/bots.py b/client/src/telethon/_impl/client/client/bots.py index f21fefc3..08f70562 100644 --- a/client/src/telethon/_impl/client/client/bots.py +++ b/client/src/telethon/_impl/client/client/bots.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, AsyncIterator, List, Optional, Self +from collections.abc import AsyncIterator +from typing import TYPE_CHECKING, Optional, Self from ...tl import abcs, functions, types from ..types import ChatLike, InlineResult, NoPublicConstructor @@ -22,7 +23,7 @@ class InlineResults(metaclass=NoPublicConstructor): self._query = query self._peer = chat or types.InputPeerEmpty() self._offset: Optional[str] = "" - self._buffer: List[InlineResult] = [] + self._buffer: list[InlineResult] = [] self._done = False def __aiter__(self) -> Self: diff --git a/client/src/telethon/_impl/client/client/chats.py b/client/src/telethon/_impl/client/client/chats.py index 32cca36f..a8514289 100644 --- a/client/src/telethon/_impl/client/client/chats.py +++ b/client/src/telethon/_impl/client/client/chats.py @@ -1,7 +1,7 @@ from __future__ import annotations import datetime -from typing import TYPE_CHECKING, Optional, Sequence, Set +from typing import TYPE_CHECKING, Optional, Sequence from ...session import PackedChat from ...tl import abcs, functions, types @@ -32,7 +32,7 @@ class ParticipantList(AsyncList[Participant]): self._chat = chat self._packed: Optional[PackedChat] = None self._offset = 0 - self._seen: Set[int] = set() + self._seen: set[int] = set() async def _fetch_next(self) -> None: if self._packed is None: diff --git a/client/src/telethon/_impl/client/client/client.py b/client/src/telethon/_impl/client/client/client.py index fd8d47a0..9399d927 100644 --- a/client/src/telethon/_impl/client/client/client.py +++ b/client/src/telethon/_impl/client/client/client.py @@ -1,24 +1,10 @@ import asyncio import datetime import logging +from collections.abc import AsyncIterator, Awaitable, Callable from pathlib import Path from types import TracebackType -from typing import ( - Any, - AsyncIterator, - Awaitable, - Callable, - Dict, - List, - Literal, - Optional, - Self, - Sequence, - Tuple, - Type, - TypeVar, - Union, -) +from typing import Any, Literal, Optional, Self, Sequence, Type, TypeVar from ....version import __version__ as default_version from ...mtsender import Connector, Sender @@ -215,7 +201,7 @@ class Client: def __init__( self, - session: Optional[Union[str, Path, Storage]], + session: Optional[str | Path | Storage], api_id: int, api_hash: Optional[str] = None, *, @@ -253,9 +239,9 @@ class Client: lang_code=lang_code or "en", catch_up=catch_up or False, datacenter=datacenter, - flood_sleep_threshold=60 - if flood_sleep_threshold is None - else flood_sleep_threshold, + flood_sleep_threshold=( + 60 if flood_sleep_threshold is None else flood_sleep_threshold + ), update_queue_limit=update_queue_limit, base_logger=base_logger, connector=connector or (lambda ip, port: asyncio.open_connection(ip, port)), @@ -267,11 +253,11 @@ class Client: self._chat_hashes = ChatHashCache(None) self._last_update_limit_warn: Optional[float] = None self._updates: asyncio.Queue[ - Tuple[abcs.Update, Dict[int, Chat]] + tuple[abcs.Update, dict[int, Chat]] ] = asyncio.Queue(maxsize=self._config.update_queue_limit or 0) self._dispatcher: Optional[asyncio.Task[None]] = None - self._handlers: Dict[ - Type[Event], List[Tuple[Callable[[Any], Awaitable[Any]], Optional[Filter]]] + self._handlers: dict[ + Type[Event], list[tuple[Callable[[Any], Awaitable[Any]], Optional[Filter]]] ] = {} self._check_all_handlers = check_all_handlers @@ -356,9 +342,7 @@ class Client: """ return await bot_sign_in(self, token) - async def check_password( - self, token: PasswordToken, password: Union[str, bytes] - ) -> User: + async def check_password(self, token: PasswordToken, password: str | bytes) -> User: """ Check the two-factor-authentication (2FA) password. If it is correct, completes the login. @@ -428,7 +412,7 @@ class Client: await delete_dialog(self, chat) async def delete_messages( - self, chat: ChatLike, message_ids: List[int], *, revoke: bool = True + self, chat: ChatLike, message_ids: list[int], *, revoke: bool = True ) -> int: """ Delete messages. @@ -484,7 +468,7 @@ class Client: """ await disconnect(self) - async def download(self, media: File, file: Union[str, Path, OutFileLike]) -> None: + async def download(self, media: File, file: str | Path | OutFileLike) -> None: """ Download a file. @@ -585,7 +569,7 @@ class Client: markdown: Optional[str] = None, html: Optional[str] = None, link_preview: bool = False, - buttons: Optional[Union[List[btns.Button], List[List[btns.Button]]]] = None, + buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, ) -> Message: """ Edit a message. @@ -633,8 +617,8 @@ class Client: ) async def forward_messages( - self, target: ChatLike, message_ids: List[int], source: ChatLike - ) -> List[Message]: + self, target: ChatLike, message_ids: list[int], source: ChatLike + ) -> list[Message]: """ Forward messages from one :term:`chat` to another. @@ -691,8 +675,8 @@ class Client: return get_admin_log(self, chat) async def get_chats( - self, chats: Union[List[ChatLike], Tuple[ChatLike, ...]] - ) -> List[Chat]: + self, chats: list[ChatLike] | tuple[ChatLike, ...] + ) -> list[Chat]: """ Get the latest basic information about the given chats. @@ -907,7 +891,7 @@ class Client: ) def get_messages_with_ids( - self, chat: ChatLike, message_ids: List[int] + self, chat: ChatLike, message_ids: list[int] ) -> AsyncList[Message]: """ Get the full message objects from the corresponding message identifiers. @@ -1160,7 +1144,7 @@ class Client: return prepare_album(self) async def read_message( - self, chat: ChatLike, message_id: Union[int, Literal["all"]] + self, chat: ChatLike, message_id: int | Literal["all"] ) -> None: """ Mark messages as read. @@ -1361,7 +1345,7 @@ class Client: async def send_audio( self, chat: ChatLike, - file: Union[str, Path, InFileLike, File], + file: str | Path | InFileLike | File, mime_type: Optional[str] = None, *, size: Optional[int] = None, @@ -1374,7 +1358,7 @@ class Client: caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[Union[List[btns.Button], List[List[btns.Button]]]] = None, + buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, ) -> Message: """ Send an audio file. @@ -1424,7 +1408,7 @@ class Client: async def send_file( self, chat: ChatLike, - file: Union[str, Path, InFileLike, File], + file: str | Path | InFileLike | File, *, size: Optional[int] = None, name: Optional[str] = None, @@ -1446,7 +1430,7 @@ class Client: caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[Union[List[btns.Button], List[List[btns.Button]]]] = None, + buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, ) -> Message: """ Send any type of file with any amount of attributes. @@ -1606,13 +1590,13 @@ class Client: async def send_message( self, chat: ChatLike, - text: Optional[Union[str, Message]] = None, + text: Optional[str | Message] = None, *, markdown: Optional[str] = None, html: Optional[str] = None, link_preview: bool = False, reply_to: Optional[int] = None, - buttons: Optional[Union[List[btns.Button], List[List[btns.Button]]]] = None, + buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, ) -> Message: """ Send a message. @@ -1653,7 +1637,7 @@ class Client: async def send_photo( self, chat: ChatLike, - file: Union[str, Path, InFileLike, File], + file: str | Path | InFileLike | File, *, size: Optional[int] = None, name: Optional[str] = None, @@ -1665,7 +1649,7 @@ class Client: caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[Union[List[btns.Button], List[List[btns.Button]]]] = None, + buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, ) -> Message: """ Send a photo file. @@ -1717,7 +1701,7 @@ class Client: async def send_video( self, chat: ChatLike, - file: Union[str, Path, InFileLike, File], + file: str | Path | InFileLike | File, *, size: Optional[int] = None, name: Optional[str] = None, @@ -1732,7 +1716,7 @@ class Client: caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[Union[List[btns.Button], List[List[btns.Button]]]] = None, + buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, ) -> Message: """ Send a video file. @@ -1947,7 +1931,7 @@ class Client: """ await set_participant_restrictions(self, chat, user, restrictions, until=until) - async def sign_in(self, token: LoginToken, code: str) -> Union[User, PasswordToken]: + async def sign_in(self, token: LoginToken, code: str) -> User | PasswordToken: """ Sign in to a user account. @@ -1993,7 +1977,7 @@ class Client: await sign_out(self) async def unpin_message( - self, chat: ChatLike, message_id: Union[int, Literal["all"]] + self, chat: ChatLike, message_id: int | Literal["all"] ) -> None: """ Unpin one or all messages from the top. @@ -2041,8 +2025,8 @@ class Client: return input_to_peer(self, input) async def _upload( - self, fd: Union[str, Path, InFileLike], size: Optional[int], name: Optional[str] - ) -> Tuple[abcs.InputFile, str]: + self, fd: str | Path | InFileLike, size: Optional[int], name: Optional[str] + ) -> tuple[abcs.InputFile, str]: return await upload(self, fd, size, name) async def __call__(self, request: Request[Return]) -> Return: diff --git a/client/src/telethon/_impl/client/client/files.py b/client/src/telethon/_impl/client/client/files.py index e622cd92..c0ab0709 100644 --- a/client/src/telethon/_impl/client/client/files.py +++ b/client/src/telethon/_impl/client/client/files.py @@ -4,7 +4,7 @@ import hashlib import mimetypes from inspect import isawaitable from pathlib import Path -from typing import TYPE_CHECKING, List, Optional, Tuple, Union +from typing import TYPE_CHECKING, Optional from ...tl import abcs, functions, types from ..types import ( @@ -45,7 +45,7 @@ def prepare_album(self: Client) -> AlbumBuilder: async def send_photo( self: Client, chat: ChatLike, - file: Union[str, Path, InFileLike, File], + file: str | Path | InFileLike | File, *, size: Optional[int] = None, name: Optional[str] = None, @@ -57,7 +57,7 @@ async def send_photo( caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[Union[List[btns.Button], List[List[btns.Button]]]] = None, + buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, ) -> Message: return await send_file( self, @@ -65,9 +65,11 @@ async def send_photo( file, size=size, name=name, - mime_type="image/jpeg" # specific mime doesn't matter, only that it's image - if compress - else mime_type, + mime_type=( + "image/jpeg" # specific mime doesn't matter, only that it's image + if compress + else mime_type + ), compress=compress, width=width, height=height, @@ -82,7 +84,7 @@ async def send_photo( async def send_audio( self: Client, chat: ChatLike, - file: Union[str, Path, InFileLike, File], + file: str | Path | InFileLike | File, mime_type: Optional[str] = None, *, size: Optional[int] = None, @@ -95,7 +97,7 @@ async def send_audio( caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[Union[List[btns.Button], List[List[btns.Button]]]] = None, + buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, ) -> Message: return await send_file( self, @@ -119,7 +121,7 @@ async def send_audio( async def send_video( self: Client, chat: ChatLike, - file: Union[str, Path, InFileLike, File], + file: str | Path | InFileLike | File, *, size: Optional[int] = None, name: Optional[str] = None, @@ -134,7 +136,7 @@ async def send_video( caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[Union[List[btns.Button], List[List[btns.Button]]]] = None, + buttons: Optional[list[btns.Button] | list[list[btns.Button]]], ) -> Message: return await send_file( self, @@ -160,7 +162,7 @@ async def send_video( async def send_file( self: Client, chat: ChatLike, - file: Union[str, Path, InFileLike, File], + file: str | Path | InFileLike | File, *, size: Optional[int] = None, name: Optional[str] = None, @@ -182,7 +184,7 @@ async def send_file( caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[Union[List[btns.Button], List[List[btns.Button]]]] = None, + buttons: Optional[list[btns.Button] | list[list[btns.Button]]], ) -> Message: message, entities = parse_message( text=caption, markdown=caption_markdown, html=caption_html, allow_empty=True @@ -237,7 +239,7 @@ async def send_file( # Only bother to calculate attributes when sending documents. else: - attributes: List[abcs.DocumentAttribute] = [] + attributes: list[abcs.DocumentAttribute] = [] attributes.append(types.DocumentAttributeFilename(file_name=name)) if mime_type.startswith("image/"): @@ -290,9 +292,9 @@ async def do_send_file( chat: ChatLike, input_media: abcs.InputMedia, message: str, - entities: Optional[List[abcs.MessageEntity]], + entities: Optional[list[abcs.MessageEntity]], reply_to: Optional[int], - buttons: Optional[Union[List[btns.Button], List[List[btns.Button]]]], + buttons: Optional[list[btns.Button] | list[list[btns.Button]]], ) -> Message: peer = (await client._resolve_to_packed(chat))._to_input_peer() random_id = generate_random_id() @@ -305,11 +307,11 @@ async def do_send_file( noforwards=False, update_stickersets_order=False, peer=peer, - reply_to=types.InputReplyToMessage( - reply_to_msg_id=reply_to, top_msg_id=None - ) - if reply_to - else None, + reply_to=( + types.InputReplyToMessage(reply_to_msg_id=reply_to, top_msg_id=None) + if reply_to + else None + ), media=input_media, message=message, random_id=random_id, @@ -325,10 +327,10 @@ async def do_send_file( async def upload( client: Client, - file: Union[str, Path, InFileLike], + file: str | Path | InFileLike, size: Optional[int], name: Optional[str], -) -> Tuple[abcs.InputFile, str]: +) -> tuple[abcs.InputFile, str]: # Paths are opened and closed by us. Anything else is *only* read, not closed. if isinstance(file, (str, Path)): path = Path(file) if isinstance(file, str) else file @@ -360,7 +362,7 @@ async def do_upload( part = 0 total_parts = (size + MAX_CHUNK_SIZE - 1) // MAX_CHUNK_SIZE buffer = bytearray() - to_store: Union[bytearray, bytes] = b"" + to_store: bytearray | bytes = b"" hash_md5 = hashlib.md5() is_big = size > BIG_FILE_SIZE @@ -454,9 +456,7 @@ def get_file_bytes(self: Client, media: File) -> AsyncList[bytes]: return FileBytesList(self, media) -async def download( - self: Client, media: File, file: Union[str, Path, OutFileLike] -) -> None: +async def download(self: Client, media: File, file: str | Path | OutFileLike) -> None: fd = OutWrapper(file) try: async for chunk in get_file_bytes(self, media): diff --git a/client/src/telethon/_impl/client/client/messages.py b/client/src/telethon/_impl/client/client/messages.py index 4797a0b5..cb94ee81 100644 --- a/client/src/telethon/_impl/client/client/messages.py +++ b/client/src/telethon/_impl/client/client/messages.py @@ -2,7 +2,7 @@ from __future__ import annotations import datetime import sys -from typing import TYPE_CHECKING, Dict, List, Literal, Optional, Self, Union +from typing import TYPE_CHECKING, Literal, Optional, Self from ...session import PackedChat from ...tl import abcs, functions, types @@ -17,13 +17,13 @@ if TYPE_CHECKING: async def send_message( self: Client, chat: ChatLike, - text: Optional[Union[str, Message]] = None, + text: Optional[str | Message] = None, *, markdown: Optional[str] = None, html: Optional[str] = None, link_preview: bool = False, reply_to: Optional[int] = None, - buttons: Optional[Union[List[btns.Button], List[List[btns.Button]]]] = None, + buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, ) -> Message: packed = await self._resolve_to_packed(chat) peer = packed._to_input_peer() @@ -121,7 +121,7 @@ async def edit_message( markdown: Optional[str] = None, html: Optional[str] = None, link_preview: bool = False, - buttons: Optional[Union[List[btns.Button], List[List[btns.Button]]]] = None, + buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, ) -> Message: peer = (await self._resolve_to_packed(chat))._to_input_peer() message, entities = parse_message( @@ -145,7 +145,7 @@ async def edit_message( async def delete_messages( - self: Client, chat: ChatLike, message_ids: List[int], *, revoke: bool = True + self: Client, chat: ChatLike, message_ids: list[int], *, revoke: bool = True ) -> int: packed_chat = await self._resolve_to_packed(chat) if packed_chat.is_channel(): @@ -163,8 +163,8 @@ async def delete_messages( async def forward_messages( - self: Client, target: ChatLike, message_ids: List[int], source: ChatLike -) -> List[Message]: + self: Client, target: ChatLike, message_ids: list[int], source: ChatLike +) -> list[Message]: to_peer = (await self._resolve_to_packed(target))._to_input_peer() from_peer = (await self._resolve_to_packed(source))._to_input_peer() random_ids = [generate_random_id() for _ in message_ids] @@ -198,7 +198,7 @@ class MessageList(AsyncList[Message]): def _extend_buffer( self, client: Client, messages: abcs.messages.Messages - ) -> Dict[int, Chat]: + ) -> dict[int, Chat]: if isinstance(messages, types.messages.MessagesNotModified): self._total = messages.count return {} @@ -224,7 +224,7 @@ class MessageList(AsyncList[Message]): def _last_non_empty_message( self, - ) -> Union[types.Message, types.MessageService, types.MessageEmpty]: + ) -> types.Message | types.MessageService | types.MessageEmpty: return next( ( m._raw @@ -318,13 +318,13 @@ class CherryPickedList(MessageList): self, client: Client, chat: ChatLike, - ids: List[int], + ids: list[int], ): super().__init__() self._client = client self._chat = chat self._packed: Optional[PackedChat] = None - self._ids: List[abcs.InputMessage] = [types.InputMessageId(id=id) for id in ids] + self._ids: list[abcs.InputMessage] = [types.InputMessageId(id=id) for id in ids] async def _fetch_next(self) -> None: if not self._ids: @@ -350,7 +350,7 @@ class CherryPickedList(MessageList): def get_messages_with_ids( self: Client, chat: ChatLike, - message_ids: List[int], + message_ids: list[int], ) -> AsyncList[Message]: return CherryPickedList(self, chat, message_ids) @@ -509,7 +509,7 @@ async def pin_message(self: Client, chat: ChatLike, message_id: int) -> Message: async def unpin_message( - self: Client, chat: ChatLike, message_id: Union[int, Literal["all"]] + self: Client, chat: ChatLike, message_id: int | Literal["all"] ) -> None: peer = (await self._resolve_to_packed(chat))._to_input_peer() if message_id == "all": @@ -528,7 +528,7 @@ async def unpin_message( async def read_message( - self: Client, chat: ChatLike, message_id: Union[int, Literal["all"]] + self: Client, chat: ChatLike, message_id: int | Literal["all"] ) -> None: packed = await self._resolve_to_packed(chat) if message_id == "all": @@ -555,8 +555,8 @@ class MessageMap: self, client: Client, peer: Optional[abcs.InputPeer], - random_id_to_id: Dict[int, int], - id_to_message: Dict[int, Message], + random_id_to_id: dict[int, int], + id_to_message: dict[int, Message], ) -> None: self._client = client self._peer = peer @@ -599,8 +599,8 @@ def build_message_map( else: return MessageMap(client, peer, {}, {}) - random_id_to_id: Dict[int, int] = {} - id_to_message: Dict[int, Message] = {} + random_id_to_id: dict[int, int] = {} + id_to_message: dict[int, Message] = {} for update in updates: if isinstance(update, types.UpdateMessageId): random_id_to_id[update.random_id] = update.id diff --git a/client/src/telethon/_impl/client/client/net.py b/client/src/telethon/_impl/client/client/net.py index abd88f84..75bb0f1b 100644 --- a/client/src/telethon/_impl/client/client/net.py +++ b/client/src/telethon/_impl/client/client/net.py @@ -6,7 +6,7 @@ import logging import platform import re from dataclasses import dataclass, field -from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, TypeVar +from typing import TYPE_CHECKING, Optional, TypeVar from ....version import __version__ from ...mtproto import BadStatus, Full, RpcError @@ -75,10 +75,10 @@ def as_concrete_dc_option(opt: abcs.DcOption) -> types.DcOption: async def connect_sender( config: Config, - known_dcs: List[DataCenter], + known_dcs: list[DataCenter], dc: DataCenter, force_auth_gen: bool = False, -) -> Tuple[Sender, List[DataCenter]]: +) -> tuple[Sender, list[DataCenter]]: # Only the ID of the input DC may be known. # Find the corresponding address and authentication key if needed. addr = dc.ipv4_addr or next( @@ -143,7 +143,7 @@ async def connect_sender( ] dc_options.sort(key=lambda opt: opt.static, reverse=True) - latest_dcs: Dict[int, DataCenter] = {} + latest_dcs: dict[int, DataCenter] = {} for opt in dc_options: dc = latest_dcs.setdefault(opt.id, DataCenter(id=opt.id)) if opt.ipv6: diff --git a/client/src/telethon/_impl/client/client/updates.py b/client/src/telethon/_impl/client/client/updates.py index ced4e73f..740f82f1 100644 --- a/client/src/telethon/_impl/client/client/updates.py +++ b/client/src/telethon/_impl/client/client/updates.py @@ -1,17 +1,8 @@ from __future__ import annotations import asyncio -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - List, - Optional, - Sequence, - Type, - TypeVar, -) +from collections.abc import Awaitable, Callable +from typing import TYPE_CHECKING, Any, Optional, Sequence, Type, TypeVar from ...session import Gap from ...tl import abcs @@ -81,7 +72,7 @@ def set_handler_filter( handlers[i] = (h, filter) -def process_socket_updates(client: Client, all_updates: List[abcs.Updates]) -> None: +def process_socket_updates(client: Client, all_updates: list[abcs.Updates]) -> None: if not all_updates: return @@ -103,7 +94,7 @@ def process_socket_updates(client: Client, all_updates: List[abcs.Updates]) -> N def extend_update_queue( client: Client, - updates: List[abcs.Update], + updates: list[abcs.Update], users: Sequence[abcs.User], chats: Sequence[abcs.Chat], ) -> None: diff --git a/client/src/telethon/_impl/client/client/users.py b/client/src/telethon/_impl/client/client/users.py index 47911843..85ab4371 100644 --- a/client/src/telethon/_impl/client/client/users.py +++ b/client/src/telethon/_impl/client/client/users.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, List, Optional, Tuple, Union +from typing import TYPE_CHECKING, Optional from ...mtproto import RpcError from ...session import PackedChat, PackedType @@ -75,12 +75,12 @@ async def resolve_username(self: Client, username: str) -> Chat: async def get_chats( - self: Client, chats: Union[List[ChatLike], Tuple[ChatLike, ...]] -) -> List[Chat]: - packed_chats: List[PackedChat] = [] - input_users: List[types.InputUser] = [] - input_chats: List[int] = [] - input_channels: List[types.InputChannel] = [] + self: Client, chats: list[ChatLike] | tuple[ChatLike, ...] +) -> list[Chat]: + packed_chats: list[PackedChat] = [] + input_users: list[types.InputUser] = [] + input_chats: list[int] = [] + input_channels: list[types.InputChannel] = [] for chat in chats: packed = await resolve_to_packed(self, chat) @@ -121,7 +121,7 @@ async def get_chats( async def resolve_to_packed( - client: Client, chat: Union[ChatLike, abcs.InputPeer, abcs.Peer] + client: Client, chat: ChatLike | abcs.InputPeer | abcs.Peer ) -> PackedChat: if isinstance(chat, PackedChat): return chat diff --git a/client/src/telethon/_impl/client/errors.py b/client/src/telethon/_impl/client/errors.py index 07f104bc..746c4bbd 100644 --- a/client/src/telethon/_impl/client/errors.py +++ b/client/src/telethon/_impl/client/errors.py @@ -1,5 +1,5 @@ import re -from typing import Dict, Tuple, Type +from typing import Type from ..mtproto import RpcError @@ -20,14 +20,14 @@ def pretty_name(name: str) -> str: return "".join(map(str.title, name.split("_"))) -def from_code(code: int, *, _cache: Dict[int, Type[RpcError]] = {}) -> Type[RpcError]: +def from_code(code: int, *, _cache: dict[int, Type[RpcError]] = {}) -> Type[RpcError]: code = canonicalize_code(code) if code not in _cache: _cache[code] = type(f"Code{code}", (RpcError,), {}) return _cache[code] -def from_name(name: str, *, _cache: Dict[str, Type[RpcError]] = {}) -> Type[RpcError]: +def from_name(name: str, *, _cache: dict[str, Type[RpcError]] = {}) -> Type[RpcError]: name = canonicalize_name(name) if name not in _cache: _cache[name] = type(pretty_name(name), (RpcError,), {}) @@ -35,7 +35,7 @@ def from_name(name: str, *, _cache: Dict[str, Type[RpcError]] = {}) -> Type[RpcE def adapt_rpc( - error: RpcError, *, _cache: Dict[Tuple[int, str], Type[RpcError]] = {} + error: RpcError, *, _cache: dict[tuple[int, str], Type[RpcError]] = {} ) -> RpcError: code = canonicalize_code(error.code) name = canonicalize_name(error.name) diff --git a/client/src/telethon/_impl/client/events/event.py b/client/src/telethon/_impl/client/events/event.py index 40ee4d3c..67d8b89e 100644 --- a/client/src/telethon/_impl/client/events/event.py +++ b/client/src/telethon/_impl/client/events/event.py @@ -1,7 +1,7 @@ from __future__ import annotations import abc -from typing import TYPE_CHECKING, Dict, Optional, Self +from typing import TYPE_CHECKING, Optional, Self from ...tl import abcs from ..types import Chat, NoPublicConstructor @@ -25,7 +25,7 @@ class Event(metaclass=NoPublicConstructor): @classmethod @abc.abstractmethod def _try_from_update( - cls, client: Client, update: abcs.Update, chat_map: Dict[int, Chat] + cls, client: Client, update: abcs.Update, chat_map: dict[int, Chat] ) -> Optional[Self]: pass diff --git a/client/src/telethon/_impl/client/events/filters/combinators.py b/client/src/telethon/_impl/client/events/filters/combinators.py index 050ff830..a6bc99d9 100644 --- a/client/src/telethon/_impl/client/events/filters/combinators.py +++ b/client/src/telethon/_impl/client/events/filters/combinators.py @@ -1,6 +1,7 @@ import abc import typing -from typing import Callable, Tuple, TypeAlias +from collections.abc import Callable +from typing import TypeAlias from ..event import Event @@ -74,7 +75,7 @@ class Any(Combinable): self._filters = (filter1, filter2, *filters) @property - def filters(self) -> Tuple[Filter, ...]: + def filters(self) -> tuple[Filter, ...]: """ The filters being checked, in order. """ @@ -114,7 +115,7 @@ class All(Combinable): self._filters = (filter1, filter2, *filters) @property - def filters(self) -> Tuple[Filter, ...]: + def filters(self) -> tuple[Filter, ...]: """ The filters being checked, in order. """ diff --git a/client/src/telethon/_impl/client/events/filters/common.py b/client/src/telethon/_impl/client/events/filters/common.py index 3e9d0944..f37f8bc9 100644 --- a/client/src/telethon/_impl/client/events/filters/common.py +++ b/client/src/telethon/_impl/client/events/filters/common.py @@ -1,4 +1,4 @@ -from typing import Sequence, Set, Type, Union +from typing import Sequence, Type from ...types import Channel, Group, User from ..event import Event @@ -18,7 +18,7 @@ class Chats(Combinable): self._chats = set(chat_ids) @property - def chat_ids(self) -> Set[int]: + def chat_ids(self) -> set[int]: """ A copy of the set of chat identifiers this filter is filtering on. """ @@ -43,7 +43,7 @@ class Senders(Combinable): self._senders = set(sender_ids) @property - def sender_ids(self) -> Set[int]: + def sender_ids(self) -> set[int]: """ A copy of the set of sender identifiers this filter is filtering on. """ @@ -79,12 +79,12 @@ class ChatType(Combinable): def __init__( self, - type: Type[Union[User, Group, Channel]], + type: Type[User | Group | Channel], ) -> None: self._type = type @property - def type(self) -> Type[Union[User, Group, Channel]]: + def type(self) -> Type[User | Group | Channel]: """ The chat type this filter is filtering on. """ diff --git a/client/src/telethon/_impl/client/events/filters/messages.py b/client/src/telethon/_impl/client/events/filters/messages.py index ab2ba484..54c577d2 100644 --- a/client/src/telethon/_impl/client/events/filters/messages.py +++ b/client/src/telethon/_impl/client/events/filters/messages.py @@ -1,7 +1,7 @@ from __future__ import annotations import re -from typing import TYPE_CHECKING, Literal, Optional, Tuple, Union +from typing import TYPE_CHECKING, Literal, Optional from ..event import Event from .combinators import Combinable @@ -28,7 +28,7 @@ class Text(Combinable): __slots__ = ("_pattern",) - def __init__(self, regexp: Union[str, re.Pattern[str]]) -> None: + def __init__(self, regexp: str | re.Pattern[str]) -> None: self._pattern = re.compile(regexp) if isinstance(regexp, str) else regexp def __call__(self, event: Event) -> bool: @@ -164,7 +164,7 @@ class Media(Combinable): @property def types( self, - ) -> Tuple[Literal["photo", "audio", "video"], ...]: + ) -> tuple[Literal["photo", "audio", "video"], ...]: """ The media types being checked. """ diff --git a/client/src/telethon/_impl/client/events/messages.py b/client/src/telethon/_impl/client/events/messages.py index c1c9feeb..ca227980 100644 --- a/client/src/telethon/_impl/client/events/messages.py +++ b/client/src/telethon/_impl/client/events/messages.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Dict, Optional, Self, Sequence, Union +from typing import TYPE_CHECKING, Optional, Self, Sequence from ...tl import abcs, types from ..types import Chat, Message, expand_peer, peer_id @@ -25,7 +25,7 @@ class NewMessage(Event, Message): @classmethod def _try_from_update( - cls, client: Client, update: abcs.Update, chat_map: Dict[int, Chat] + cls, client: Client, update: abcs.Update, chat_map: dict[int, Chat] ) -> Optional[Self]: if isinstance(update, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): if isinstance(update.message, types.Message): @@ -47,7 +47,7 @@ class MessageEdited(Event, Message): @classmethod def _try_from_update( - cls, client: Client, update: abcs.Update, chat_map: Dict[int, Chat] + cls, client: Client, update: abcs.Update, chat_map: dict[int, Chat] ) -> Optional[Self]: if isinstance( update, (types.UpdateEditMessage, types.UpdateEditChannelMessage) @@ -75,7 +75,7 @@ class MessageDeleted(Event): @classmethod def _try_from_update( - cls, client: Client, update: abcs.Update, chat_map: Dict[int, Chat] + cls, client: Client, update: abcs.Update, chat_map: dict[int, Chat] ) -> Optional[Self]: if isinstance(update, types.UpdateDeleteMessages): return cls._create(update.messages, None) @@ -109,13 +109,13 @@ class MessageRead(Event): def __init__( self, client: Client, - update: Union[ - types.UpdateReadHistoryInbox, - types.UpdateReadHistoryOutbox, - types.UpdateReadChannelInbox, - types.UpdateReadChannelOutbox, - ], - chat_map: Dict[int, Chat], + update: ( + types.UpdateReadHistoryInbox + | types.UpdateReadHistoryOutbox + | types.UpdateReadChannelInbox + | types.UpdateReadChannelOutbox + ), + chat_map: dict[int, Chat], ) -> None: self._client = client self._raw = update @@ -123,7 +123,7 @@ class MessageRead(Event): @classmethod def _try_from_update( - cls, client: Client, update: abcs.Update, chat_map: Dict[int, Chat] + cls, client: Client, update: abcs.Update, chat_map: dict[int, Chat] ) -> Optional[Self]: if isinstance( update, diff --git a/client/src/telethon/_impl/client/events/queries.py b/client/src/telethon/_impl/client/events/queries.py index c93e29e2..20a1511c 100644 --- a/client/src/telethon/_impl/client/events/queries.py +++ b/client/src/telethon/_impl/client/events/queries.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Dict, Optional, Self +from typing import TYPE_CHECKING, Optional, Self from ...tl import abcs, functions, types from ..client.messages import CherryPickedList @@ -23,7 +23,7 @@ class ButtonCallback(Event): self, client: Client, update: types.UpdateBotCallbackQuery, - chat_map: Dict[int, Chat], + chat_map: dict[int, Chat], ): self._client = client self._raw = update @@ -31,7 +31,7 @@ class ButtonCallback(Event): @classmethod def _try_from_update( - cls, client: Client, update: abcs.Update, chat_map: Dict[int, Chat] + cls, client: Client, update: abcs.Update, chat_map: dict[int, Chat] ) -> Optional[Self]: if isinstance(update, types.UpdateBotCallbackQuery) and update.data is not None: return cls._create(client, update, chat_map) @@ -105,7 +105,7 @@ class InlineQuery(Event): @classmethod def _try_from_update( - cls, client: Client, update: abcs.Update, chat_map: Dict[int, Chat] + cls, client: Client, update: abcs.Update, chat_map: dict[int, Chat] ) -> Optional[Self]: if isinstance(update, types.UpdateBotInlineQuery): return cls._create(update) diff --git a/client/src/telethon/_impl/client/parsers/html.py b/client/src/telethon/_impl/client/parsers/html.py index aa5ae110..cafa3d3d 100644 --- a/client/src/telethon/_impl/client/parsers/html.py +++ b/client/src/telethon/_impl/client/parsers/html.py @@ -1,19 +1,8 @@ from collections import deque +from collections.abc import Callable, Iterable from html import escape from html.parser import HTMLParser -from typing import ( - Any, - Callable, - Deque, - Dict, - Iterable, - List, - Optional, - Tuple, - Type, - Union, - cast, -) +from typing import Any, Optional, Type, cast from ...tl.abcs import MessageEntity from ...tl.types import ( @@ -37,12 +26,12 @@ class HTMLToTelegramParser(HTMLParser): def __init__(self) -> None: super().__init__() self.text = "" - self.entities: List[MessageEntity] = [] - self._building_entities: Dict[str, MessageEntity] = {} - self._open_tags: Deque[str] = deque() - self._open_tags_meta: Deque[Optional[str]] = deque() + self.entities: list[MessageEntity] = [] + self._building_entities: dict[str, MessageEntity] = {} + self._open_tags: deque[str] = deque() + self._open_tags_meta: deque[Optional[str]] = deque() - def handle_starttag(self, tag: str, attrs: List[Tuple[str, Optional[str]]]) -> None: + def handle_starttag(self, tag: str, attrs: list[tuple[str, Optional[str]]]) -> None: self._open_tags.appendleft(tag) self._open_tags_meta.appendleft(None) @@ -128,7 +117,7 @@ class HTMLToTelegramParser(HTMLParser): self.entities.append(entity) -def parse(html: str) -> Tuple[str, List[MessageEntity]]: +def parse(html: str) -> tuple[str, list[MessageEntity]]: """ Parses the given HTML message and returns its stripped representation plus a list of the MessageEntity's that were found. @@ -144,8 +133,8 @@ def parse(html: str) -> Tuple[str, List[MessageEntity]]: return del_surrogate(parser.text), parser.entities -ENTITY_TO_FORMATTER: Dict[ - Type[MessageEntity], Union[Tuple[str, str], Callable[[Any, str], Tuple[str, str]]] +ENTITY_TO_FORMATTER: dict[ + Type[MessageEntity], tuple[str, str] | Callable[[Any, str], tuple[str, str]] ] = { MessageEntityBold: ("", ""), MessageEntityItalic: ("", ""), @@ -183,7 +172,7 @@ def unparse(text: str, entities: Iterable[MessageEntity]) -> str: return escape(text) text = add_surrogate(text) - insert_at: List[Tuple[int, str]] = [] + insert_at: list[tuple[int, str]] = [] for e in entities: offset, length = getattr(e, "offset", None), getattr(e, "length", None) assert isinstance(offset, int) and isinstance(length, int) diff --git a/client/src/telethon/_impl/client/parsers/markdown.py b/client/src/telethon/_impl/client/parsers/markdown.py index 3b3f7afd..1704d4fb 100644 --- a/client/src/telethon/_impl/client/parsers/markdown.py +++ b/client/src/telethon/_impl/client/parsers/markdown.py @@ -1,5 +1,6 @@ import re -from typing import Any, Dict, Iterator, List, Tuple, Type +from collections.abc import Iterator +from typing import Any, Type import markdown_it import markdown_it.token @@ -19,7 +20,7 @@ from ...tl.types import ( from .strings import add_surrogate, del_surrogate, within_surrogate MARKDOWN = markdown_it.MarkdownIt().enable("strikethrough") -DELIMITERS: Dict[Type[MessageEntity], Tuple[str, str]] = { +DELIMITERS: dict[Type[MessageEntity], tuple[str, str]] = { MessageEntityBlockquote: ("> ", ""), MessageEntityBold: ("**", "**"), MessageEntityCode: ("`", "`"), @@ -44,7 +45,7 @@ HTML_TO_TYPE = { def expand_inline_and_html( - tokens: List[markdown_it.token.Token], + tokens: list[markdown_it.token.Token], ) -> Iterator[markdown_it.token.Token]: for token in tokens: if token.type == "inline": @@ -63,7 +64,7 @@ def expand_inline_and_html( yield token -def parse(message: str) -> Tuple[str, List[MessageEntity]]: +def parse(message: str) -> tuple[str, list[MessageEntity]]: """ Parses the given markdown message and returns its stripped representation plus a list of the MessageEntity's that were found. @@ -71,7 +72,7 @@ def parse(message: str) -> Tuple[str, List[MessageEntity]]: if not message: return message, [] - entities: List[MessageEntity] + entities: list[MessageEntity] token: markdown_it.token.Token def push(ty: Any, **extra: object) -> None: @@ -145,7 +146,7 @@ def parse(message: str) -> Tuple[str, List[MessageEntity]]: return del_surrogate(message), entities -def unparse(text: str, entities: List[MessageEntity]) -> str: +def unparse(text: str, entities: list[MessageEntity]) -> str: """ Performs the reverse operation to .parse(), effectively returning markdown-like syntax given a normal text and its MessageEntity's. @@ -157,7 +158,7 @@ def unparse(text: str, entities: List[MessageEntity]) -> str: return text text = add_surrogate(text) - insert_at: List[Tuple[int, str]] = [] + insert_at: list[tuple[int, str]] = [] for e in entities: offset, length = getattr(e, "offset", None), getattr(e, "length", None) assert isinstance(offset, int) and isinstance(length, int) diff --git a/client/src/telethon/_impl/client/types/admin_right.py b/client/src/telethon/_impl/client/types/admin_right.py index 4c34d414..a63aeb7b 100644 --- a/client/src/telethon/_impl/client/types/admin_right.py +++ b/client/src/telethon/_impl/client/types/admin_right.py @@ -1,7 +1,6 @@ from __future__ import annotations from enum import Enum -from typing import Set from ...tl import abcs, types @@ -62,7 +61,7 @@ class AdminRight(Enum): """Allows deleting stories in a channel.""" @classmethod - def _from_raw(cls, rights: abcs.ChatAdminRights) -> Set[AdminRight]: + def _from_raw(cls, rights: abcs.ChatAdminRights) -> set[AdminRight]: assert isinstance(rights, types.ChatAdminRights) all_rights = ( cls.CHANGE_INFO if rights.change_info else None, @@ -84,7 +83,7 @@ class AdminRight(Enum): return set(filter(None, iter(all_rights))) @classmethod - def _chat_rights(cls) -> Set[AdminRight]: + def _chat_rights(cls) -> set[AdminRight]: return { cls.CHANGE_INFO, cls.POST_MESSAGES, @@ -104,7 +103,7 @@ class AdminRight(Enum): } @classmethod - def _set_to_raw(cls, all_rights: Set[AdminRight]) -> types.ChatAdminRights: + def _set_to_raw(cls, all_rights: set[AdminRight]) -> types.ChatAdminRights: return types.ChatAdminRights( change_info=cls.CHANGE_INFO in all_rights, post_messages=cls.POST_MESSAGES in all_rights, diff --git a/client/src/telethon/_impl/client/types/album_builder.py b/client/src/telethon/_impl/client/types/album_builder.py index e3b3c694..059b2e89 100644 --- a/client/src/telethon/_impl/client/types/album_builder.py +++ b/client/src/telethon/_impl/client/types/album_builder.py @@ -2,7 +2,7 @@ from __future__ import annotations import mimetypes from pathlib import Path -from typing import TYPE_CHECKING, List, Optional, Union +from typing import TYPE_CHECKING, Optional from ...tl import abcs, functions, types from .chat import ChatLike @@ -23,11 +23,11 @@ class AlbumBuilder(metaclass=NoPublicConstructor): def __init__(self, *, client: Client): self._client = client - self._medias: List[types.InputSingleMedia] = [] + self._medias: list[types.InputSingleMedia] = [] async def add_photo( self, - file: Union[str, Path, InFileLike], + file: str | Path | InFileLike, *, size: Optional[int] = None, caption: Optional[str] = None, @@ -90,7 +90,7 @@ class AlbumBuilder(metaclass=NoPublicConstructor): async def add_video( self, - file: Union[str, Path, InFileLike], + file: str | Path | InFileLike, *, size: Optional[int] = None, name: Optional[str] = None, @@ -141,7 +141,7 @@ class AlbumBuilder(metaclass=NoPublicConstructor): if mime_type is None: mime_type = "application/octet-stream" - attributes: List[abcs.DocumentAttribute] = [] + attributes: list[abcs.DocumentAttribute] = [] attributes.append(types.DocumentAttributeFilename(file_name=name)) if duration is not None and width is not None and height is not None: attributes.append( @@ -198,7 +198,7 @@ class AlbumBuilder(metaclass=NoPublicConstructor): async def send( self, chat: ChatLike, *, reply_to: Optional[int] = None - ) -> List[Message]: + ) -> list[Message]: """ Send the album. @@ -224,11 +224,13 @@ class AlbumBuilder(metaclass=NoPublicConstructor): noforwards=False, update_stickersets_order=False, peer=peer, - reply_to=types.InputReplyToMessage( - reply_to_msg_id=reply_to, top_msg_id=None - ) - if reply_to - else None, + reply_to=( + types.InputReplyToMessage( + reply_to_msg_id=reply_to, top_msg_id=None + ) + if reply_to + else None + ), multi_media=self._medias, schedule_date=None, send_as=None, diff --git a/client/src/telethon/_impl/client/types/async_list.py b/client/src/telethon/_impl/client/types/async_list.py index ff491d73..560a4c86 100644 --- a/client/src/telethon/_impl/client/types/async_list.py +++ b/client/src/telethon/_impl/client/types/async_list.py @@ -1,6 +1,7 @@ import abc from collections import deque -from typing import Any, Deque, Generator, Generic, List, Self, TypeVar +from collections.abc import Generator +from typing import Any, Generic, Self, TypeVar T = TypeVar("T") @@ -40,7 +41,7 @@ class AsyncList(abc.ABC, Generic[T]): """ def __init__(self) -> None: - self._buffer: Deque[T] = deque() + self._buffer: deque[T] = deque() self._total: int = 0 self._done = False @@ -54,14 +55,14 @@ class AsyncList(abc.ABC, Generic[T]): The `_done` flag should be set if it is known that the end was reached """ - async def _collect(self) -> List[T]: + async def _collect(self) -> list[T]: prev = -1 while not self._done and prev != len(self._buffer): prev = len(self._buffer) await self._fetch_next() return list(self._buffer) - def __await__(self) -> Generator[Any, None, List[T]]: + def __await__(self) -> Generator[Any, None, list[T]]: return self._collect().__await__() def __aiter__(self) -> Self: diff --git a/client/src/telethon/_impl/client/types/buttons/__init__.py b/client/src/telethon/_impl/client/types/buttons/__init__.py index 65aaaac6..89e7c4a0 100644 --- a/client/src/telethon/_impl/client/types/buttons/__init__.py +++ b/client/src/telethon/_impl/client/types/buttons/__init__.py @@ -1,7 +1,7 @@ from __future__ import annotations import weakref -from typing import TYPE_CHECKING, List, Optional, Union +from typing import TYPE_CHECKING, Optional from ....tl import abcs, types from .button import Button @@ -24,7 +24,7 @@ def as_concrete_row(row: abcs.KeyboardButtonRow) -> types.KeyboardButtonRow: def build_keyboard( - btns: Optional[Union[List[Button], List[List[Button]]]] + btns: Optional[list[Button] | list[list[Button]]], ) -> Optional[abcs.ReplyMarkup]: # list[button] -> list[list[button]] # This does allow for "invalid" inputs (mixing lists and non-lists), but that's acceptable. @@ -37,7 +37,7 @@ def build_keyboard( if not buttons_lists: return None - rows: List[abcs.KeyboardButtonRow] = [ + rows: list[abcs.KeyboardButtonRow] = [ types.KeyboardButtonRow(buttons=[btn._raw for btn in btns]) for btns in buttons_lists ] diff --git a/client/src/telethon/_impl/client/types/buttons/button.py b/client/src/telethon/_impl/client/types/buttons/button.py index c23fe977..558e8ef6 100644 --- a/client/src/telethon/_impl/client/types/buttons/button.py +++ b/client/src/telethon/_impl/client/types/buttons/button.py @@ -1,7 +1,7 @@ from __future__ import annotations import weakref -from typing import TYPE_CHECKING, Optional, Union +from typing import TYPE_CHECKING, Optional from ....tl import types @@ -9,24 +9,24 @@ if TYPE_CHECKING: from ..message import Message -ButtonTypes = Union[ - types.KeyboardButton, - types.KeyboardButtonUrl, - types.KeyboardButtonCallback, - types.KeyboardButtonRequestPhone, - types.KeyboardButtonRequestGeoLocation, - types.KeyboardButtonSwitchInline, - types.KeyboardButtonGame, - types.KeyboardButtonBuy, - types.KeyboardButtonUrlAuth, - types.InputKeyboardButtonUrlAuth, - types.KeyboardButtonRequestPoll, - types.InputKeyboardButtonUserProfile, - types.KeyboardButtonUserProfile, - types.KeyboardButtonWebView, - types.KeyboardButtonSimpleWebView, - types.KeyboardButtonRequestPeer, -] +ButtonTypes = ( + types.KeyboardButton + | types.KeyboardButtonUrl + | types.KeyboardButtonCallback + | types.KeyboardButtonRequestPhone + | types.KeyboardButtonRequestGeoLocation + | types.KeyboardButtonSwitchInline + | types.KeyboardButtonGame + | types.KeyboardButtonBuy + | types.KeyboardButtonUrlAuth + | types.InputKeyboardButtonUrlAuth + | types.KeyboardButtonRequestPoll + | types.InputKeyboardButtonUserProfile + | types.KeyboardButtonUserProfile + | types.KeyboardButtonWebView + | types.KeyboardButtonSimpleWebView + | types.KeyboardButtonRequestPeer +) class Button: diff --git a/client/src/telethon/_impl/client/types/chat/__init__.py b/client/src/telethon/_impl/client/types/chat/__init__.py index 83666b49..ab042721 100644 --- a/client/src/telethon/_impl/client/types/chat/__init__.py +++ b/client/src/telethon/_impl/client/types/chat/__init__.py @@ -3,7 +3,7 @@ from __future__ import annotations import itertools import sys from collections import defaultdict -from typing import TYPE_CHECKING, DefaultDict, Dict, List, Optional, Sequence, Union +from typing import TYPE_CHECKING, Optional, Sequence from ....session import PackedChat from ....tl import abcs, types @@ -15,12 +15,12 @@ from .user import User if TYPE_CHECKING: from ...client.client import Client -ChatLike = Union[Chat, PackedChat, int, str] +ChatLike = Chat | PackedChat | int | str def build_chat_map( client: Client, users: Sequence[abcs.User], chats: Sequence[abcs.Chat] -) -> Dict[int, Chat]: +) -> dict[int, Chat]: users_iter = (User._from_raw(u) for u in users) chats_iter = ( ( @@ -31,11 +31,11 @@ def build_chat_map( for c in chats ) - result: Dict[int, Chat] = {c.id: c for c in itertools.chain(users_iter, chats_iter)} + result: dict[int, Chat] = {c.id: c for c in itertools.chain(users_iter, chats_iter)} if len(result) != len(users) + len(chats): # The fabled ID collision between different chat types. - counter: DefaultDict[int, List[Union[abcs.User, abcs.Chat]]] = defaultdict(list) + counter: defaultdict[int, list[abcs.User | abcs.Chat]] = defaultdict(list) for user in users: if (id := getattr(user, "id", None)) is not None: counter[id].append(user) diff --git a/client/src/telethon/_impl/client/types/chat/channel.py b/client/src/telethon/_impl/client/types/chat/channel.py index b498f4c5..dce7db4b 100644 --- a/client/src/telethon/_impl/client/types/chat/channel.py +++ b/client/src/telethon/_impl/client/types/chat/channel.py @@ -1,4 +1,4 @@ -from typing import Optional, Self, Union +from typing import Optional, Self from ....session import PackedChat, PackedType from ....tl import abcs, types @@ -16,7 +16,7 @@ class Channel(Chat, metaclass=NoPublicConstructor): def __init__( self, - raw: Union[types.Channel, types.ChannelForbidden], + raw: types.Channel | types.ChannelForbidden, ) -> None: self._raw = raw @@ -55,9 +55,11 @@ class Channel(Chat, metaclass=NoPublicConstructor): return None else: return PackedChat( - ty=PackedType.GIGAGROUP - if getattr(self._raw, "gigagroup", False) - else PackedType.BROADCAST, + ty=( + PackedType.GIGAGROUP + if getattr(self._raw, "gigagroup", False) + else PackedType.BROADCAST + ), id=self._raw.id, access_hash=self._raw.access_hash, ) diff --git a/client/src/telethon/_impl/client/types/chat/group.py b/client/src/telethon/_impl/client/types/chat/group.py index 031e18af..d7eb81a1 100644 --- a/client/src/telethon/_impl/client/types/chat/group.py +++ b/client/src/telethon/_impl/client/types/chat/group.py @@ -1,7 +1,7 @@ from __future__ import annotations import datetime -from typing import TYPE_CHECKING, Optional, Self, Sequence, Union +from typing import TYPE_CHECKING, Optional, Self, Sequence from ....session import PackedChat, PackedType from ....tl import abcs, types @@ -24,13 +24,13 @@ class Group(Chat, metaclass=NoPublicConstructor): def __init__( self, client: Client, - chat: Union[ - types.ChatEmpty, - types.Chat, - types.ChatForbidden, - types.Channel, - types.ChannelForbidden, - ], + chat: ( + types.ChatEmpty + | types.Chat + | types.ChatForbidden + | types.Channel + | types.ChannelForbidden + ), ) -> None: self._client = client self._raw = chat diff --git a/client/src/telethon/_impl/client/types/chat_restriction.py b/client/src/telethon/_impl/client/types/chat_restriction.py index 31cb83e2..3c330f91 100644 --- a/client/src/telethon/_impl/client/types/chat_restriction.py +++ b/client/src/telethon/_impl/client/types/chat_restriction.py @@ -1,7 +1,6 @@ from __future__ import annotations from enum import Enum -from typing import Set from ...tl import abcs, types @@ -85,7 +84,7 @@ class ChatRestriction(Enum): """Prevents sending plain text messages with no media to the chat.""" @classmethod - def _from_raw(cls, rights: abcs.ChatBannedRights) -> Set[ChatRestriction]: + def _from_raw(cls, rights: abcs.ChatBannedRights) -> set[ChatRestriction]: assert isinstance(rights, types.ChatBannedRights) restrictions = ( cls.VIEW_MESSAGES if rights.view_messages else None, @@ -113,7 +112,7 @@ class ChatRestriction(Enum): @classmethod def _set_to_raw( - cls, restrictions: Set[ChatRestriction], until_date: int + cls, restrictions: set[ChatRestriction], until_date: int ) -> types.ChatBannedRights: return types.ChatBannedRights( view_messages=cls.VIEW_MESSAGES in restrictions, diff --git a/client/src/telethon/_impl/client/types/dialog.py b/client/src/telethon/_impl/client/types/dialog.py index 54357a11..59890fba 100644 --- a/client/src/telethon/_impl/client/types/dialog.py +++ b/client/src/telethon/_impl/client/types/dialog.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Dict, Optional, Self, Union +from typing import TYPE_CHECKING, Optional, Self from ...tl import abcs, types from .chat import Chat, peer_id @@ -26,9 +26,9 @@ class Dialog(metaclass=NoPublicConstructor): def __init__( self, client: Client, - raw: Union[types.Dialog, types.DialogFolder], - chat_map: Dict[int, Chat], - msg_map: Dict[int, Message], + raw: types.Dialog | types.DialogFolder, + chat_map: dict[int, Chat], + msg_map: dict[int, Message], ) -> None: self._client = client self._raw = raw @@ -40,8 +40,8 @@ class Dialog(metaclass=NoPublicConstructor): cls, client: Client, dialog: abcs.Dialog, - chat_map: Dict[int, Chat], - msg_map: Dict[int, Message], + chat_map: dict[int, Chat], + msg_map: dict[int, Message], ) -> Self: assert isinstance(dialog, (types.Dialog, types.DialogFolder)) return cls._create(client, dialog, chat_map, msg_map) diff --git a/client/src/telethon/_impl/client/types/draft.py b/client/src/telethon/_impl/client/types/draft.py index 4568c613..446af514 100644 --- a/client/src/telethon/_impl/client/types/draft.py +++ b/client/src/telethon/_impl/client/types/draft.py @@ -1,7 +1,7 @@ from __future__ import annotations import datetime -from typing import TYPE_CHECKING, Dict, Optional, Self +from typing import TYPE_CHECKING, Optional, Self from ...session import PackedChat from ...tl import abcs, functions, types @@ -27,7 +27,7 @@ class Draft(metaclass=NoPublicConstructor): peer: abcs.Peer, top_msg_id: Optional[int], raw: abcs.DraftMessage, - chat_map: Dict[int, Chat], + chat_map: dict[int, Chat], ) -> None: assert isinstance(raw, (types.DraftMessage, types.DraftMessageEmpty)) self._client = client @@ -38,7 +38,7 @@ class Draft(metaclass=NoPublicConstructor): @classmethod def _from_raw_update( - cls, client: Client, draft: types.UpdateDraftMessage, chat_map: Dict[int, Chat] + cls, client: Client, draft: types.UpdateDraftMessage, chat_map: dict[int, Chat] ) -> Self: return cls._create(client, draft.peer, draft.top_msg_id, draft.draft, chat_map) @@ -49,7 +49,7 @@ class Draft(metaclass=NoPublicConstructor): peer: abcs.Peer, top_msg_id: int, draft: abcs.DraftMessage, - chat_map: Dict[int, Chat], + chat_map: dict[int, Chat], ) -> Self: return cls._create(client, peer, top_msg_id, draft, chat_map) @@ -197,11 +197,11 @@ class Draft(metaclass=NoPublicConstructor): noforwards=False, update_stickersets_order=False, peer=peer, - reply_to=types.InputReplyToMessage( - reply_to_msg_id=reply_to, top_msg_id=None - ) - if reply_to - else None, + reply_to=( + types.InputReplyToMessage(reply_to_msg_id=reply_to, top_msg_id=None) + if reply_to + else None + ), message=message, random_id=random_id, reply_markup=None, @@ -216,19 +216,23 @@ class Draft(metaclass=NoPublicConstructor): {}, out=result.out, id=result.id, - from_id=types.PeerUser(user_id=self._client._session.user.id) - if self._client._session.user - else None, + from_id=( + types.PeerUser(user_id=self._client._session.user.id) + if self._client._session.user + else None + ), peer_id=packed._to_peer(), - reply_to=types.MessageReplyHeader( - reply_to_scheduled=False, - forum_topic=False, - reply_to_msg_id=reply_to, - reply_to_peer_id=None, - reply_to_top_id=None, - ) - if reply_to - else None, + reply_to=( + types.MessageReplyHeader( + reply_to_scheduled=False, + forum_topic=False, + reply_to_msg_id=reply_to, + reply_to_peer_id=None, + reply_to_top_id=None, + ) + if reply_to + else None + ), date=result.date, message=message, media=result.media, diff --git a/client/src/telethon/_impl/client/types/file.py b/client/src/telethon/_impl/client/types/file.py index 89dc9993..1e5e018f 100644 --- a/client/src/telethon/_impl/client/types/file.py +++ b/client/src/telethon/_impl/client/types/file.py @@ -2,20 +2,11 @@ from __future__ import annotations import mimetypes import urllib.parse +from collections.abc import Coroutine from inspect import isawaitable from io import BufferedWriter from pathlib import Path -from typing import ( - TYPE_CHECKING, - Any, - Coroutine, - List, - Optional, - Protocol, - Self, - Sequence, - Union, -) +from typing import TYPE_CHECKING, Any, Optional, Protocol, Self, Sequence from ...tl import abcs, types from .meta import NoPublicConstructor @@ -79,7 +70,7 @@ def photo_size_dimensions( raise RuntimeError("unexpected case") -def try_get_url_path(maybe_url: Union[str, Path, InFileLike]) -> Optional[str]: +def try_get_url_path(maybe_url: str | Path | InFileLike) -> Optional[str]: if not isinstance(maybe_url, str): return None lowercase = maybe_url.lower() @@ -97,7 +88,7 @@ class InFileLike(Protocol): It's only used in function parameters. """ - def read(self, n: int, /) -> Union[bytes, Coroutine[Any, Any, bytes]]: + def read(self, n: int, /) -> bytes | Coroutine[Any, Any, bytes]: """ Read from the file or buffer. @@ -116,7 +107,7 @@ class OutFileLike(Protocol): It's only used in function parameters. """ - def write(self, data: bytes) -> Union[Any, Coroutine[Any, Any, Any]]: + def write(self, data: bytes) -> Any | Coroutine[Any, Any, Any]: """ Write all the data into the file or buffer. @@ -128,10 +119,10 @@ class OutFileLike(Protocol): class OutWrapper: __slots__ = ("_fd", "_owned_fd") - _fd: Union[OutFileLike, BufferedWriter] + _fd: OutFileLike | BufferedWriter _owned_fd: Optional[BufferedWriter] - def __init__(self, file: Union[str, Path, OutFileLike]): + def __init__(self, file: str | Path | OutFileLike): if isinstance(file, str): file = Path(file) @@ -173,7 +164,7 @@ class File(metaclass=NoPublicConstructor): input_media: abcs.InputMedia, thumb: Optional[abcs.PhotoSize], thumbs: Optional[Sequence[abcs.PhotoSize]], - raw: Optional[Union[abcs.MessageMedia, abcs.Photo, abcs.Document]], + raw: Optional[abcs.MessageMedia | abcs.Photo | abcs.Document], client: Optional[Client], ): self._attributes = attributes @@ -336,7 +327,7 @@ class File(metaclass=NoPublicConstructor): return mimetypes.guess_extension(self._mime) or "" @property - def thumbnails(self) -> List[File]: + def thumbnails(self) -> list[File]: """ The file thumbnails. @@ -393,7 +384,7 @@ class File(metaclass=NoPublicConstructor): return None - async def download(self, file: Union[str, Path, OutFileLike]) -> None: + async def download(self, file: str | Path | OutFileLike) -> None: """ Alias for :meth:`telethon.Client.download`. diff --git a/client/src/telethon/_impl/client/types/inline_result.py b/client/src/telethon/_impl/client/types/inline_result.py index 3a4746a0..92269540 100644 --- a/client/src/telethon/_impl/client/types/inline_result.py +++ b/client/src/telethon/_impl/client/types/inline_result.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Optional, Union +from typing import TYPE_CHECKING, Optional from ...tl import abcs, functions, types from .chat import ChatLike @@ -22,7 +22,7 @@ class InlineResult(metaclass=NoPublicConstructor): self, client: Client, results: types.messages.BotResults, - result: Union[types.BotInlineMediaResult, types.BotInlineResult], + result: types.BotInlineMediaResult | types.BotInlineResult, default_peer: abcs.InputPeer, ): self._client = client diff --git a/client/src/telethon/_impl/client/types/message.py b/client/src/telethon/_impl/client/types/message.py index 5c390b17..8edd6504 100644 --- a/client/src/telethon/_impl/client/types/message.py +++ b/client/src/telethon/_impl/client/types/message.py @@ -2,17 +2,7 @@ from __future__ import annotations import datetime import time -from typing import ( - TYPE_CHECKING, - Any, - Dict, - List, - Optional, - Self, - Sequence, - Tuple, - Union, -) +from typing import TYPE_CHECKING, Any, Optional, Self, Sequence from ...tl import abcs, types from ..parsers import ( @@ -68,7 +58,7 @@ class Message(metaclass=NoPublicConstructor): """ def __init__( - self, client: Client, message: abcs.Message, chat_map: Dict[int, Chat] + self, client: Client, message: abcs.Message, chat_map: dict[int, Chat] ) -> None: assert isinstance( message, (types.Message, types.MessageService, types.MessageEmpty) @@ -79,7 +69,7 @@ class Message(metaclass=NoPublicConstructor): @classmethod def _from_raw( - cls, client: Client, message: abcs.Message, chat_map: Dict[int, Chat] + cls, client: Client, message: abcs.Message, chat_map: dict[int, Chat] ) -> Self: return cls._create(client, message, chat_map) @@ -87,14 +77,14 @@ class Message(metaclass=NoPublicConstructor): def _from_defaults( cls, client: Client, - chat_map: Dict[int, Chat], + chat_map: dict[int, Chat], id: int, peer_id: abcs.Peer, date: int, message: str, **kwargs: Any, ) -> Self: - default_kwargs: Dict[str, Any] = { + default_kwargs: dict[str, Any] = { "out": False, "mentioned": False, "media_unread": False, @@ -337,12 +327,12 @@ class Message(metaclass=NoPublicConstructor): async def respond( self, - text: Optional[Union[str, Message]] = None, + text: Optional[str | Message] = None, *, markdown: Optional[str] = None, html: Optional[str] = None, link_preview: bool = False, - buttons: Optional[Union[List[Button], List[List[Button]]]] = None, + buttons: Optional[list[Button] | list[list[Button]]] = None, ) -> Message: """ Alias for :meth:`telethon.Client.send_message`. @@ -364,12 +354,12 @@ class Message(metaclass=NoPublicConstructor): async def reply( self, - text: Optional[Union[str, Message]] = None, + text: Optional[str | Message] = None, *, markdown: Optional[str] = None, html: Optional[str] = None, link_preview: bool = False, - buttons: Optional[Union[List[Button], List[List[Button]]]] = None, + buttons: Optional[list[Button] | list[list[Button]]] = None, ) -> Message: """ Alias for :meth:`telethon.Client.send_message` with the ``reply_to`` parameter set to this message. @@ -404,7 +394,7 @@ class Message(metaclass=NoPublicConstructor): markdown: Optional[str] = None, html: Optional[str] = None, link_preview: bool = False, - buttons: Optional[Union[List[Button], List[List[Button]]]] = None, + buttons: Optional[list[Button] | list[list[Button]]] = None, ) -> Message: """ Alias for :meth:`telethon.Client.edit_message`. @@ -458,7 +448,7 @@ class Message(metaclass=NoPublicConstructor): pass @property - def buttons(self) -> Optional[List[List[Button]]]: + def buttons(self) -> Optional[list[list[Button]]]: """ The buttons attached to the message. @@ -512,8 +502,8 @@ class Message(metaclass=NoPublicConstructor): def build_msg_map( - client: Client, messages: Sequence[abcs.Message], chat_map: Dict[int, Chat] -) -> Dict[int, Message]: + client: Client, messages: Sequence[abcs.Message], chat_map: dict[int, Chat] +) -> dict[int, Message]: return { msg.id: msg for msg in (Message._from_raw(client, m, chat_map) for m in messages) @@ -526,7 +516,7 @@ def parse_message( markdown: Optional[str], html: Optional[str], allow_empty: bool, -) -> Tuple[str, Optional[List[abcs.MessageEntity]]]: +) -> tuple[str, Optional[list[abcs.MessageEntity]]]: cnt = sum((text is not None, markdown is not None, html is not None)) if cnt != 1: if cnt == 0 and allow_empty: diff --git a/client/src/telethon/_impl/client/types/participant.py b/client/src/telethon/_impl/client/types/participant.py index ae2861a3..6f13a1af 100644 --- a/client/src/telethon/_impl/client/types/participant.py +++ b/client/src/telethon/_impl/client/types/participant.py @@ -1,7 +1,7 @@ from __future__ import annotations import datetime -from typing import TYPE_CHECKING, Dict, Optional, Self, Sequence, Set, Union +from typing import TYPE_CHECKING, Optional, Self, Sequence from ...session import PackedChat from ...tl import abcs, types @@ -25,18 +25,18 @@ class Participant(metaclass=NoPublicConstructor): self, client: Client, chat: PackedChat, - participant: Union[ - types.ChannelParticipant, - types.ChannelParticipantSelf, - types.ChannelParticipantCreator, - types.ChannelParticipantAdmin, - types.ChannelParticipantBanned, - types.ChannelParticipantLeft, - types.ChatParticipant, - types.ChatParticipantCreator, - types.ChatParticipantAdmin, - ], - chat_map: Dict[int, Chat], + participant: ( + types.ChannelParticipant + | types.ChannelParticipantSelf + | types.ChannelParticipantCreator + | types.ChannelParticipantAdmin + | types.ChannelParticipantBanned + | types.ChannelParticipantLeft + | types.ChatParticipant + | types.ChatParticipantCreator + | types.ChatParticipantAdmin + ), + chat_map: dict[int, Chat], ) -> None: self._client = client self._chat = chat @@ -49,7 +49,7 @@ class Participant(metaclass=NoPublicConstructor): client: Client, chat: PackedChat, participant: abcs.ChannelParticipant, - chat_map: Dict[int, Chat], + chat_map: dict[int, Chat], ) -> Self: if isinstance( participant, @@ -72,7 +72,7 @@ class Participant(metaclass=NoPublicConstructor): client: Client, chat: PackedChat, participant: abcs.ChatParticipant, - chat_map: Dict[int, Chat], + chat_map: dict[int, Chat], ) -> Self: if isinstance( participant, @@ -162,7 +162,7 @@ class Participant(metaclass=NoPublicConstructor): ) @property - def admin_rights(self) -> Optional[Set[AdminRight]]: + def admin_rights(self) -> Optional[set[AdminRight]]: """ The set of administrator rights this participant has been granted, if they are an administrator. """ @@ -178,7 +178,7 @@ class Participant(metaclass=NoPublicConstructor): return None @property - def restrictions(self) -> Optional[Set[ChatRestriction]]: + def restrictions(self) -> Optional[set[ChatRestriction]]: """ The set of restrictions applied to this participant, if they are banned. """ diff --git a/client/src/telethon/_impl/client/types/recent_action.py b/client/src/telethon/_impl/client/types/recent_action.py index 47ef8edc..02ed82f3 100644 --- a/client/src/telethon/_impl/client/types/recent_action.py +++ b/client/src/telethon/_impl/client/types/recent_action.py @@ -1,5 +1,3 @@ -from typing import Dict - from ...tl import abcs, types from .chat import Chat from .meta import NoPublicConstructor @@ -17,7 +15,7 @@ class RecentAction(metaclass=NoPublicConstructor): def __init__( self, event: abcs.ChannelAdminLogEvent, - chat_map: Dict[int, Chat], + chat_map: dict[int, Chat], ) -> None: assert isinstance(event, types.ChannelAdminLogEvent) self._raw = event diff --git a/client/src/telethon/_impl/crypto/factorize.py b/client/src/telethon/_impl/crypto/factorize.py index 49d2c509..dcc10866 100644 --- a/client/src/telethon/_impl/crypto/factorize.py +++ b/client/src/telethon/_impl/crypto/factorize.py @@ -1,9 +1,8 @@ from math import gcd from random import randrange -from typing import Tuple -def factorize(pq: int) -> Tuple[int, int]: +def factorize(pq: int) -> tuple[int, int]: """ Factorize the given number into its two prime factors. diff --git a/client/src/telethon/_impl/mtproto/authentication.py b/client/src/telethon/_impl/mtproto/authentication.py index 8b7dc20c..1b20dc47 100644 --- a/client/src/telethon/_impl/mtproto/authentication.py +++ b/client/src/telethon/_impl/mtproto/authentication.py @@ -3,7 +3,6 @@ import struct import time from dataclasses import dataclass from hashlib import sha1 -from typing import Tuple from ..crypto import ( RSA_KEYS, @@ -67,17 +66,17 @@ class DhGenData: nonce_number: int -def _do_step1(random_bytes: bytes) -> Tuple[bytes, Step1]: +def _do_step1(random_bytes: bytes) -> tuple[bytes, Step1]: assert len(random_bytes) == 16 nonce = int.from_bytes(random_bytes) return req_pq_multi(nonce=nonce), Step1(nonce=nonce) -def step1() -> Tuple[bytes, Step1]: +def step1() -> tuple[bytes, Step1]: return _do_step1(os.urandom(16)) -def _do_step2(data: Step1, response: bytes, random_bytes: bytes) -> Tuple[bytes, Step2]: +def _do_step2(data: Step1, response: bytes, random_bytes: bytes) -> tuple[bytes, Step2]: assert len(random_bytes) == 288 nonce = data.nonce res_pq = ResPq.from_bytes(response) @@ -130,13 +129,13 @@ def _do_step2(data: Step1, response: bytes, random_bytes: bytes) -> Tuple[bytes, ), Step2(nonce=nonce, server_nonce=res_pq.server_nonce, new_nonce=new_nonce) -def step2(data: Step1, response: bytes) -> Tuple[bytes, Step2]: +def step2(data: Step1, response: bytes) -> tuple[bytes, Step2]: return _do_step2(data, response, os.urandom(288)) def _do_step3( data: Step2, response: bytes, random_bytes: bytes, now: int -) -> Tuple[bytes, Step3]: +) -> tuple[bytes, Step3]: assert len(random_bytes) == 272 nonce = data.nonce @@ -231,7 +230,7 @@ def _do_step3( ) -def step3(data: Step2, response: bytes) -> Tuple[bytes, Step3]: +def step3(data: Step2, response: bytes) -> tuple[bytes, Step3]: return _do_step3(data, response, os.urandom(272), int(time.time())) diff --git a/client/src/telethon/_impl/mtproto/mtp/encrypted.py b/client/src/telethon/_impl/mtproto/mtp/encrypted.py index 8eb6ec47..6f2f65dc 100644 --- a/client/src/telethon/_impl/mtproto/mtp/encrypted.py +++ b/client/src/telethon/_impl/mtproto/mtp/encrypted.py @@ -2,7 +2,7 @@ import logging import os import struct import time -from typing import List, Optional, Tuple +from typing import Optional from ...crypto import AuthKey, decrypt_data_v2, encrypt_data_v2 from ...tl.core import Reader @@ -107,12 +107,12 @@ class Encrypted(Mtp): ) -> None: self._auth_key = auth_key self._time_offset: int = time_offset or 0 - self._salts: List[FutureSalt] = [ + self._salts: list[FutureSalt] = [ FutureSalt(valid_since=0, valid_until=0x7FFFFFFF, salt=first_salt or 0) ] - self._start_salt_time: Optional[Tuple[int, float]] = None + self._start_salt_time: Optional[tuple[int, float]] = None self._compression_threshold = compression_threshold - self._deserialization: List[Deserialization] = [] + self._deserialization: list[Deserialization] = [] self._buffer = bytearray() self._salt_request_msg_id: Optional[int] = None @@ -141,7 +141,7 @@ class Encrypted(Mtp): self._client_id: int self._sequence: int self._last_msg_id: int - self._in_pending_ack: List[int] = [] + self._in_pending_ack: list[int] = [] self._msg_count: int self._reset_session() @@ -196,7 +196,7 @@ class Encrypted(Mtp): def _get_current_salt(self) -> int: return self._salts[-1].salt if self._salts else 0 - def _finalize_plain(self) -> Optional[Tuple[MsgId, bytes]]: + def _finalize_plain(self) -> Optional[tuple[MsgId, bytes]]: if not self._msg_count: return None @@ -431,7 +431,7 @@ class Encrypted(Mtp): return self._serialize_msg(body, True) - def finalize(self) -> Optional[Tuple[MsgId, bytes]]: + def finalize(self) -> Optional[tuple[MsgId, bytes]]: result = self._finalize_plain() if not result: return None @@ -441,7 +441,7 @@ class Encrypted(Mtp): def deserialize( self, payload: bytes | bytearray | memoryview - ) -> List[Deserialization]: + ) -> list[Deserialization]: check_message_buffer(payload) plaintext = decrypt_data_v2(payload, self._auth_key) diff --git a/client/src/telethon/_impl/mtproto/mtp/plain.py b/client/src/telethon/_impl/mtproto/mtp/plain.py index 70d3a827..b1fe03d2 100644 --- a/client/src/telethon/_impl/mtproto/mtp/plain.py +++ b/client/src/telethon/_impl/mtproto/mtp/plain.py @@ -1,5 +1,5 @@ import struct -from typing import List, Optional, Tuple +from typing import Optional from ..utils import check_message_buffer from .types import Deserialization, MsgId, Mtp, RpcResult @@ -23,7 +23,7 @@ class Plain(Mtp): self._buffer += request # message_data return msg_id - def finalize(self) -> Optional[Tuple[MsgId, bytes]]: + def finalize(self) -> Optional[tuple[MsgId, bytes]]: if not self._buffer: return None @@ -33,7 +33,7 @@ class Plain(Mtp): def deserialize( self, payload: bytes | bytearray | memoryview - ) -> List[Deserialization]: + ) -> list[Deserialization]: check_message_buffer(payload) auth_key_id, msg_id, length = struct.unpack_from(" Optional[Tuple[MsgId, bytes]]: + def finalize(self) -> Optional[tuple[MsgId, bytes]]: """ Finalize the buffer of serialized requests. @@ -203,7 +203,7 @@ class Mtp(ABC): @abstractmethod def deserialize( self, payload: bytes | bytearray | memoryview - ) -> List[Deserialization]: + ) -> list[Deserialization]: """ Deserialize incoming buffer payload. """ diff --git a/client/src/telethon/_impl/mtproto/transport/abcs.py b/client/src/telethon/_impl/mtproto/transport/abcs.py index e64d6e08..149dc6ee 100644 --- a/client/src/telethon/_impl/mtproto/transport/abcs.py +++ b/client/src/telethon/_impl/mtproto/transport/abcs.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import Callable +from collections.abc import Callable OutFn = Callable[[bytes | bytearray | memoryview], None] diff --git a/client/src/telethon/_impl/mtsender/sender.py b/client/src/telethon/_impl/mtsender/sender.py index 140d3c36..84533451 100644 --- a/client/src/telethon/_impl/mtsender/sender.py +++ b/client/src/telethon/_impl/mtsender/sender.py @@ -4,18 +4,9 @@ import struct import time from abc import ABC from asyncio import FIRST_COMPLETED, Event, Future +from collections.abc import Iterator from dataclasses import dataclass -from typing import ( - Generic, - Iterator, - List, - Optional, - Protocol, - Self, - Tuple, - Type, - TypeVar, -) +from typing import Generic, Optional, Protocol, Self, Type, TypeVar from ..crypto import AuthKey from ..mtproto import ( @@ -127,7 +118,7 @@ class Connector(Protocol): The :doc:`/concepts/datacenters` concept has examples on how to combine proxy libraries with Telethon. """ - async def __call__(self, ip: str, port: int) -> Tuple[AsyncReader, AsyncWriter]: + async def __call__(self, ip: str, port: int) -> tuple[AsyncReader, AsyncWriter]: raise NotImplementedError @@ -175,7 +166,7 @@ class Sender: _transport: Transport _mtp: Mtp _mtp_buffer: bytearray - _requests: List[Request[object]] + _requests: list[Request[object]] _request_event: Event _next_ping: float _read_buffer: bytearray @@ -239,7 +230,7 @@ class Sender: if rx.done(): return rx.result() - async def step(self) -> List[Updates]: + async def step(self) -> list[Updates]: self._try_fill_write() recv_req = asyncio.create_task(self._request_event.wait()) @@ -296,13 +287,13 @@ class Sender: self._transport.pack(mtp_buffer, self._writer.write) self._write_drain_pending = True - def _on_net_read(self, read_buffer: bytes) -> List[Updates]: + def _on_net_read(self, read_buffer: bytes) -> list[Updates]: if not read_buffer: raise ConnectionResetError("read 0 bytes") self._read_buffer += read_buffer - updates: List[Updates] = [] + updates: list[Updates] = [] while self._read_buffer: self._mtp_buffer.clear() try: @@ -331,7 +322,7 @@ class Sender: ) self._next_ping = asyncio.get_running_loop().time() + PING_DELAY - def _process_mtp_buffer(self, updates: List[Updates]) -> None: + def _process_mtp_buffer(self, updates: list[Updates]) -> None: results = self._mtp.deserialize(self._mtp_buffer) for result in results: @@ -345,13 +336,13 @@ class Sender: self._process_bad_message(result) def _process_update( - self, updates: List[Updates], update: bytes | bytearray | memoryview + self, updates: list[Updates], update: bytes | bytearray | memoryview ) -> None: try: updates.append(Updates.from_bytes(update)) except ValueError: cid = struct.unpack_from("I", update)[0] - alt_classes: Tuple[Type[Serializable], ...] = ( + alt_classes: tuple[Type[Serializable], ...] = ( AffectedFoundMessages, AffectedHistory, AffectedMessages, diff --git a/client/src/telethon/_impl/session/chat/hash_cache.py b/client/src/telethon/_impl/session/chat/hash_cache.py index decdaf27..40612c9e 100644 --- a/client/src/telethon/_impl/session/chat/hash_cache.py +++ b/client/src/telethon/_impl/session/chat/hash_cache.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, Optional, Sequence, Tuple +from typing import Any, Optional, Sequence from ...tl import abcs, types from .packed import PackedChat, PackedType @@ -7,8 +7,8 @@ from .packed import PackedChat, PackedType class ChatHashCache: __slots__ = ("_hash_map", "_self_id", "_self_bot") - def __init__(self, self_user: Optional[Tuple[int, bool]]): - self._hash_map: Dict[int, Tuple[int, PackedType]] = {} + def __init__(self, self_user: Optional[tuple[int, bool]]): + self._hash_map: dict[int, tuple[int, PackedType]] = {} self._self_id = self_user[0] if self_user else None self._self_bot = self_user[1] if self_user else False diff --git a/client/src/telethon/_impl/session/message_box/defs.py b/client/src/telethon/_impl/session/message_box/defs.py index 82d328cf..3033c921 100644 --- a/client/src/telethon/_impl/session/message_box/defs.py +++ b/client/src/telethon/_impl/session/message_box/defs.py @@ -1,6 +1,6 @@ import logging from enum import Enum -from typing import List, Literal, Union +from typing import Literal from ...tl import abcs @@ -20,7 +20,7 @@ NO_UPDATES_TIMEOUT = 15 * 60 ENTRY_ACCOUNT: Literal["ACCOUNT"] = "ACCOUNT" ENTRY_SECRET: Literal["SECRET"] = "SECRET" -Entry = Union[Literal["ACCOUNT", "SECRET"], int] +Entry = Literal["ACCOUNT", "SECRET"] | int # Python's logging doesn't define a TRACE level. Pick halfway between DEBUG and NOTSET. # We don't define a name for this as libraries shouldn't do that though. @@ -64,7 +64,7 @@ class PossibleGap: def __init__( self, deadline: float, - updates: List[abcs.Update], + updates: list[abcs.Update], ) -> None: self.deadline = deadline self.updates = updates diff --git a/client/src/telethon/_impl/session/message_box/messagebox.py b/client/src/telethon/_impl/session/message_box/messagebox.py index b7db3455..738be714 100644 --- a/client/src/telethon/_impl/session/message_box/messagebox.py +++ b/client/src/telethon/_impl/session/message_box/messagebox.py @@ -2,7 +2,7 @@ import asyncio import datetime import logging import time -from typing import Dict, List, Optional, Sequence, Set, Tuple +from typing import Optional, Sequence from ...tl import Request, abcs, functions, types from ..chat import ChatHashCache @@ -53,11 +53,11 @@ class MessageBox: base_logger: logging.Logger, ) -> None: self._logger = base_logger.getChild("messagebox") - self.map: Dict[Entry, State] = {} + self.map: dict[Entry, State] = {} self.date = epoch() self.seq = NO_SEQ - self.possible_gaps: Dict[Entry, PossibleGap] = {} - self.getting_diff_for: Set[Entry] = set() + self.possible_gaps: dict[Entry, PossibleGap] = {} + self.getting_diff_for: set[Entry] = set() self.next_deadline: Optional[Entry] = None if __debug__: @@ -164,7 +164,7 @@ class MessageBox: return deadline - def reset_deadlines(self, entries: Set[Entry], deadline: float) -> None: + def reset_deadlines(self, entries: set[Entry], deadline: float) -> None: if not entries: return @@ -259,8 +259,8 @@ class MessageBox: self, updates: abcs.Updates, chat_hashes: ChatHashCache, - ) -> Tuple[List[abcs.Update], Sequence[abcs.User], Sequence[abcs.Chat]]: - result: List[abcs.Update] = [] + ) -> tuple[list[abcs.Update], Sequence[abcs.User], Sequence[abcs.Chat]]: + result: list[abcs.Update] = [] combined = adapt(updates, chat_hashes) if __debug__: @@ -290,7 +290,7 @@ class MessageBox: sorted_updates = list(sorted(combined.updates, key=update_sort_key)) any_pts_applied = False - reset_deadlines_for: Set[Entry] = set() + reset_deadlines_for: set[Entry] = set() for update in sorted_updates: entry, applied = self.apply_pts_info(update) if entry is not None: @@ -341,7 +341,7 @@ class MessageBox: def apply_pts_info( self, update: abcs.Update, - ) -> Tuple[Optional[Entry], Optional[abcs.Update]]: + ) -> tuple[Optional[Entry], Optional[abcs.Update]]: if isinstance(update, types.UpdateChannelTooLong): self.try_begin_get_diff(update.channel_id, "received updateChannelTooLong") return None, None @@ -438,12 +438,12 @@ class MessageBox: self, diff: abcs.updates.Difference, chat_hashes: ChatHashCache, - ) -> Tuple[List[abcs.Update], Sequence[abcs.User], Sequence[abcs.Chat]]: + ) -> tuple[list[abcs.Update], Sequence[abcs.User], Sequence[abcs.Chat]]: if __debug__: self._trace("applying account difference: %s", diff) finish: bool - result: Tuple[List[abcs.Update], Sequence[abcs.User], Sequence[abcs.Chat]] + result: tuple[list[abcs.Update], Sequence[abcs.User], Sequence[abcs.Chat]] if isinstance(diff, types.updates.DifferenceEmpty): finish = True self.date = datetime.datetime.fromtimestamp( @@ -496,7 +496,7 @@ class MessageBox: self, diff: types.updates.Difference, chat_hashes: ChatHashCache, - ) -> Tuple[List[abcs.Update], Sequence[abcs.User], Sequence[abcs.Chat]]: + ) -> tuple[list[abcs.Update], Sequence[abcs.User], Sequence[abcs.Chat]]: state = diff.state assert isinstance(state, types.updates.State) self.map[ENTRY_ACCOUNT].pts = state.pts @@ -582,7 +582,7 @@ class MessageBox: channel_id: int, diff: abcs.updates.ChannelDifference, chat_hashes: ChatHashCache, - ) -> Tuple[List[abcs.Update], Sequence[abcs.User], Sequence[abcs.Chat]]: + ) -> tuple[list[abcs.Update], Sequence[abcs.User], Sequence[abcs.Chat]]: entry: Entry = channel_id if __debug__: self._trace("applying channel=%r difference: %s", entry, diff) diff --git a/client/src/telethon/_impl/session/session.py b/client/src/telethon/_impl/session/session.py index 9aa739ae..ccd46fc4 100644 --- a/client/src/telethon/_impl/session/session.py +++ b/client/src/telethon/_impl/session/session.py @@ -1,4 +1,4 @@ -from typing import List, Optional, Tuple +from typing import Optional from ..tl.core.serializable import obj_repr @@ -13,7 +13,7 @@ class DataCenter: :param auth: See below. """ - __slots__: Tuple[str, ...] = ("id", "ipv4_addr", "ipv6_addr", "auth") + __slots__: tuple[str, ...] = ("id", "ipv4_addr", "ipv6_addr", "auth") def __init__( self, @@ -116,7 +116,7 @@ class UpdateState: qts: int, date: int, seq: int, - channels: List[ChannelState], + channels: list[ChannelState], ) -> None: self.pts = pts "The primary partial sequence number." @@ -165,7 +165,7 @@ class Session: def __init__( self, *, - dcs: Optional[List[DataCenter]] = None, + dcs: Optional[list[DataCenter]] = None, user: Optional[User] = None, state: Optional[UpdateState] = None, ): diff --git a/client/src/telethon/_impl/session/storage/sqlite.py b/client/src/telethon/_impl/session/storage/sqlite.py index a9d0ce53..2988e336 100644 --- a/client/src/telethon/_impl/session/storage/sqlite.py +++ b/client/src/telethon/_impl/session/storage/sqlite.py @@ -1,6 +1,6 @@ import sqlite3 from pathlib import Path -from typing import Optional, Union +from typing import Optional from ..session import ChannelState, DataCenter, Session, UpdateState, User from .storage import Storage @@ -20,7 +20,7 @@ class SqliteSession(Storage): an VCS by accident (adding ``*.session`` to ``.gitignore`` will catch them). """ - def __init__(self, file: Union[str, Path]): + def __init__(self, file: str | Path): path = Path(file) if not path.suffix: path = path.with_suffix(EXTENSION) @@ -105,18 +105,22 @@ class SqliteSession(Storage): DataCenter(id=id, ipv4_addr=ipv4_addr, ipv6_addr=ipv6_addr, auth=auth) for (id, ipv4_addr, ipv6_addr, auth) in datacenter ], - user=User(id=user[0], dc=user[1], bot=bool(user[2]), username=user[3]) - if user - else None, - state=UpdateState( - pts=state[0], - qts=state[1], - date=state[2], - seq=state[3], - channels=[ChannelState(id=id, pts=pts) for id, pts in channelstate], - ) - if state - else None, + user=( + User(id=user[0], dc=user[1], bot=bool(user[2]), username=user[3]) + if user + else None + ), + state=( + UpdateState( + pts=state[0], + qts=state[1], + date=state[2], + seq=state[3], + channels=[ChannelState(id=id, pts=pts) for id, pts in channelstate], + ) + if state + else None + ), ) @staticmethod diff --git a/client/src/telethon/_impl/tl/core/reader.py b/client/src/telethon/_impl/tl/core/reader.py index c9f39458..a0d7c019 100644 --- a/client/src/telethon/_impl/tl/core/reader.py +++ b/client/src/telethon/_impl/tl/core/reader.py @@ -1,6 +1,7 @@ import functools import struct -from typing import TYPE_CHECKING, Any, Callable, List, Optional, Type, TypeVar +from collections.abc import Callable +from typing import TYPE_CHECKING, Any, Optional, Type, TypeVar if TYPE_CHECKING: from .serializable import Serializable @@ -96,8 +97,8 @@ def single_deserializer(cls: Type[T]) -> Callable[[bytes], T]: @functools.cache -def list_deserializer(cls: Type[T]) -> Callable[[bytes], List[T]]: - def deserializer(body: bytes) -> List[T]: +def list_deserializer(cls: Type[T]) -> Callable[[bytes], list[T]]: + def deserializer(body: bytes) -> list[T]: reader = Reader(body) vec_id, length = reader.read_fmt("= 0 @@ -106,14 +107,14 @@ def list_deserializer(cls: Type[T]) -> Callable[[bytes], List[T]]: return deserializer -def deserialize_i64_list(body: bytes) -> List[int]: +def deserialize_i64_list(body: bytes) -> list[int]: reader = Reader(body) vec_id, length = reader.read_fmt("= 0 return [*reader.read_fmt(f"<{length}q", length * 8)] -def deserialize_i32_list(body: bytes) -> List[int]: +def deserialize_i32_list(body: bytes) -> list[int]: reader = Reader(body) vec_id, length = reader.read_fmt("= 0 diff --git a/client/src/telethon/_impl/tl/core/request.py b/client/src/telethon/_impl/tl/core/request.py index bfc28f65..b053bdd4 100644 --- a/client/src/telethon/_impl/tl/core/request.py +++ b/client/src/telethon/_impl/tl/core/request.py @@ -1,5 +1,6 @@ import struct -from typing import Any, Callable, Generic, Optional, TypeVar +from collections.abc import Callable +from typing import Any, Generic, Optional, TypeVar Return = TypeVar("Return") diff --git a/client/src/telethon/_impl/tl/core/serializable.py b/client/src/telethon/_impl/tl/core/serializable.py index 79e64e4d..8af4e56c 100644 --- a/client/src/telethon/_impl/tl/core/serializable.py +++ b/client/src/telethon/_impl/tl/core/serializable.py @@ -1,12 +1,12 @@ import abc import struct -from typing import Protocol, Self, Tuple +from typing import Protocol, Self from .reader import Reader class HasSlots(Protocol): - __slots__: Tuple[str, ...] + __slots__: tuple[str, ...] def obj_repr(self: HasSlots) -> str: @@ -16,7 +16,7 @@ def obj_repr(self: HasSlots) -> str: class Serializable(abc.ABC): - __slots__: Tuple[str, ...] = () + __slots__: tuple[str, ...] = () @classmethod @abc.abstractmethod diff --git a/client/tests/mtproto_test.py b/client/tests/mtproto_test.py index 4f0fd518..a0734a3d 100644 --- a/client/tests/mtproto_test.py +++ b/client/tests/mtproto_test.py @@ -1,5 +1,5 @@ import struct -from typing import Optional, Tuple +from typing import Optional from pytest import raises from telethon._impl.crypto import AuthKey @@ -49,7 +49,7 @@ def test_rpc_error_parsing() -> None: PLAIN_REQUEST = b"Hey!" -def unwrap_finalize(finalized: Optional[Tuple[MsgId, bytes]]) -> bytes: +def unwrap_finalize(finalized: Optional[tuple[MsgId, bytes]]) -> bytes: assert finalized is not None _, buffer = finalized return buffer diff --git a/client/tests/transport/abridged_test.py b/client/tests/transport/abridged_test.py index a8683f7a..d3b425ab 100644 --- a/client/tests/transport/abridged_test.py +++ b/client/tests/transport/abridged_test.py @@ -1,5 +1,3 @@ -from typing import Tuple - from pytest import raises from telethon._impl.mtproto import Abridged @@ -11,7 +9,7 @@ class Output(bytearray): self += data -def setup_pack(n: int) -> Tuple[Abridged, bytes, Output]: +def setup_pack(n: int) -> tuple[Abridged, bytes, Output]: input = bytes(x & 0xFF for x in range(n)) return Abridged(), input, Output() diff --git a/client/tests/transport/full_test.py b/client/tests/transport/full_test.py index 767050b3..79441a86 100644 --- a/client/tests/transport/full_test.py +++ b/client/tests/transport/full_test.py @@ -1,5 +1,3 @@ -from typing import Tuple - from pytest import raises from telethon._impl.mtproto import Full @@ -11,12 +9,12 @@ class Output(bytearray): self += data -def setup_pack(n: int) -> Tuple[Full, bytes, Output]: +def setup_pack(n: int) -> tuple[Full, bytes, Output]: input = bytes(x & 0xFF for x in range(n)) return Full(), input, Output() -def setup_unpack(n: int) -> Tuple[bytes, Full, bytes, bytearray]: +def setup_unpack(n: int) -> tuple[bytes, Full, bytes, bytearray]: transport, expected_output, input = setup_pack(n) transport.pack(expected_output, input) diff --git a/client/tests/transport/intermediate_test.py b/client/tests/transport/intermediate_test.py index 10b10e44..e9d55f39 100644 --- a/client/tests/transport/intermediate_test.py +++ b/client/tests/transport/intermediate_test.py @@ -1,5 +1,3 @@ -from typing import Tuple - from pytest import raises from telethon._impl.mtproto import Intermediate @@ -11,7 +9,7 @@ class Output(bytearray): self += data -def setup_pack(n: int) -> Tuple[Intermediate, bytes, Output]: +def setup_pack(n: int) -> tuple[Intermediate, bytes, Output]: input = bytes(x & 0xFF for x in range(n)) return Intermediate(), input, Output() diff --git a/generator/src/telethon_generator/_impl/codegen/fakefs.py b/generator/src/telethon_generator/_impl/codegen/fakefs.py index 71512c02..5ff30311 100644 --- a/generator/src/telethon_generator/_impl/codegen/fakefs.py +++ b/generator/src/telethon_generator/_impl/codegen/fakefs.py @@ -1,11 +1,10 @@ import weakref from pathlib import Path -from typing import Dict class FakeFs: def __init__(self) -> None: - self._files: Dict[Path, bytearray] = {} + self._files: dict[Path, bytearray] = {} def open(self, path: Path) -> "SourceWriter": return SourceWriter(self, path) diff --git a/generator/src/telethon_generator/_impl/codegen/generator.py b/generator/src/telethon_generator/_impl/codegen/generator.py index 695ca444..d3fbe128 100644 --- a/generator/src/telethon_generator/_impl/codegen/generator.py +++ b/generator/src/telethon_generator/_impl/codegen/generator.py @@ -1,5 +1,4 @@ from pathlib import Path -from typing import Set from ..tl_parser import NormalParameter, ParsedTl from .fakefs import FakeFs, SourceWriter @@ -19,7 +18,7 @@ from .serde.serialization import generate_function, generate_write def generate_init( - writer: SourceWriter, namespaces: Set[str], classes: Set[str] + writer: SourceWriter, namespaces: set[str], classes: set[str] ) -> None: sorted_cls = list(sorted(classes)) sorted_ns = list(sorted(namespaces)) @@ -46,14 +45,14 @@ def generate(fs: FakeFs, tl: ParsedTl) -> None: ignored_types = {"true", "boolTrue", "boolFalse"} # also "compiler built-ins" - abc_namespaces: Set[str] = set() - type_namespaces: Set[str] = set() - function_namespaces: Set[str] = set() + abc_namespaces: set[str] = set() + type_namespaces: set[str] = set() + function_namespaces: set[str] = set() - abc_class_names: Set[str] = set() - type_class_names: Set[str] = set() - function_def_names: Set[str] = set() - generated_type_names: Set[str] = set() + abc_class_names: set[str] = set() + type_class_names: set[str] = set() + function_def_names: set[str] = set() + generated_type_names: set[str] = set() for typedef in tl.typedefs: if typedef.ty.full_name not in generated_types: @@ -193,10 +192,10 @@ def generate(fs: FakeFs, tl: ParsedTl) -> None: writer.write( "from .core import Serializable, Reader, deserialize_bool, deserialize_i32_list, deserialize_i64_list, deserialize_identity, single_deserializer, list_deserializer" ) - writer.write("from typing import cast, Tuple, Type") + writer.write("from typing import cast, Type") writer.write(f"LAYER = {tl.layer!r}") writer.write( - "TYPE_MAPPING = {t.constructor_id(): t for t in cast(Tuple[Type[Serializable]], (" + "TYPE_MAPPING = {t.constructor_id(): t for t in cast(tuple[Type[Serializable]], (" ) for name in sorted(generated_type_names): writer.write(f" types.{name},") diff --git a/generator/src/telethon_generator/_impl/codegen/serde/common.py b/generator/src/telethon_generator/_impl/codegen/serde/common.py index 5974b8c7..0269af53 100644 --- a/generator/src/telethon_generator/_impl/codegen/serde/common.py +++ b/generator/src/telethon_generator/_impl/codegen/serde/common.py @@ -1,10 +1,10 @@ import re -from typing import Iterator, List +from collections.abc import Iterator from ....tl_parser import BaseParameter, FlagsParameter, NormalParameter, Type -def split_words(name: str) -> List[str]: +def split_words(name: str) -> list[str]: return re.findall( r""" ^$ diff --git a/generator/src/telethon_generator/_impl/codegen/serde/deserialization.py b/generator/src/telethon_generator/_impl/codegen/serde/deserialization.py index d417a82b..a5aa2d8b 100644 --- a/generator/src/telethon_generator/_impl/codegen/serde/deserialization.py +++ b/generator/src/telethon_generator/_impl/codegen/serde/deserialization.py @@ -1,6 +1,6 @@ import struct from itertools import groupby -from typing import Optional, Tuple +from typing import Optional from ....tl_parser import Definition, NormalParameter, Parameter, Type from ..fakefs import SourceWriter @@ -14,7 +14,7 @@ SPECIAL_CASED_OBJECT_READS = { } -def reader_read_fmt(ty: Type, constructor_id: int) -> Tuple[str, Optional[str]]: +def reader_read_fmt(ty: Type, constructor_id: int) -> tuple[str, Optional[str]]: if is_trivial(NormalParameter(ty=ty, flag=None)): fmt = trivial_struct_fmt(NormalParameter(ty=ty, flag=None)) size = struct.calcsize(f"<{fmt}") diff --git a/generator/src/telethon_generator/_impl/codegen/serde/serialization.py b/generator/src/telethon_generator/_impl/codegen/serde/serialization.py index 3b32087d..792893c9 100644 --- a/generator/src/telethon_generator/_impl/codegen/serde/serialization.py +++ b/generator/src/telethon_generator/_impl/codegen/serde/serialization.py @@ -1,6 +1,6 @@ import struct +from collections.abc import Iterator from itertools import groupby -from typing import Iterator from ....tl_parser import Definition, FlagsParameter, NormalParameter, Parameter, Type from ..fakefs import SourceWriter @@ -104,9 +104,11 @@ def generate_write(writer: SourceWriter, defn: Definition) -> None: for param in group: if isinstance(param.ty, FlagsParameter): flags = " | ".join( - f"({1 << p.ty.flag.index} if self.{p.name} else 0)" - if p.ty.ty.name == "true" - else f"(0 if self.{p.name} is None else {1 << p.ty.flag.index})" + ( + f"({1 << p.ty.flag.index} if self.{p.name} else 0)" + if p.ty.ty.name == "true" + else f"(0 if self.{p.name} is None else {1 << p.ty.flag.index})" + ) for p in defn.params if isinstance(p.ty, NormalParameter) and p.ty.flag @@ -140,9 +142,11 @@ def generate_function(writer: SourceWriter, defn: Definition) -> None: for param in group: if isinstance(param.ty, FlagsParameter): flags = " | ".join( - f"({1 << p.ty.flag.index} if {p.name} else 0)" - if p.ty.ty.name == "true" - else f"(0 if {p.name} is None else {1 << p.ty.flag.index})" + ( + f"({1 << p.ty.flag.index} if {p.name} else 0)" + if p.ty.ty.name == "true" + else f"(0 if {p.name} is None else {1 << p.ty.flag.index})" + ) for p in defn.params if isinstance(p.ty, NormalParameter) and p.ty.flag diff --git a/generator/src/telethon_generator/_impl/tl_parser/loader.py b/generator/src/telethon_generator/_impl/tl_parser/loader.py index 81ffdebe..70185de7 100644 --- a/generator/src/telethon_generator/_impl/tl_parser/loader.py +++ b/generator/src/telethon_generator/_impl/tl_parser/loader.py @@ -1,7 +1,7 @@ import re from dataclasses import dataclass from pathlib import Path -from typing import List, Optional, Union +from typing import Optional from .tl import Definition from .tl_iterator import FunctionDef, TypeDef, iterate @@ -10,13 +10,13 @@ from .tl_iterator import FunctionDef, TypeDef, iterate @dataclass class ParsedTl: layer: Optional[int] - typedefs: List[Definition] - functiondefs: List[Definition] + typedefs: list[Definition] + functiondefs: list[Definition] -def load_tl_file(path: Union[str, Path]) -> ParsedTl: - typedefs: List[TypeDef] = [] - functiondefs: List[FunctionDef] = [] +def load_tl_file(path: str | Path) -> ParsedTl: + typedefs: list[TypeDef] = [] + functiondefs: list[FunctionDef] = [] with open(path, "r", encoding="utf-8") as fd: contents = fd.read() diff --git a/generator/src/telethon_generator/_impl/tl_parser/tl/definition.py b/generator/src/telethon_generator/_impl/tl_parser/tl/definition.py index 479bfa14..70adf636 100644 --- a/generator/src/telethon_generator/_impl/tl_parser/tl/definition.py +++ b/generator/src/telethon_generator/_impl/tl_parser/tl/definition.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import List, Self, Set +from typing import Self from ..utils import infer_id from .parameter import Parameter, TypeDefNotImplemented @@ -9,10 +9,10 @@ from .ty import Type @dataclass class Definition: - namespace: List[str] + namespace: list[str] name: str id: int - params: List[Parameter] + params: list[Parameter] ty: Type @classmethod @@ -58,9 +58,9 @@ class Definition: except ValueError: raise ValueError("invalid id") - type_defs: List[str] = [] - flag_defs: List[str] = [] - params: List[Parameter] = [] + type_defs: list[str] = [] + flag_defs: list[str] = [] + params: list[Parameter] = [] for param_str in middle.split(): try: @@ -102,7 +102,7 @@ class Definition: res += f"{ns}." res += f"{self.name}#{self.id:x}" - def_set: Set[str] = set() + def_set: set[str] = set() for param in self.params: if isinstance(param.ty, NormalParameter): def_set.update(param.ty.ty.find_generic_refs()) diff --git a/generator/src/telethon_generator/_impl/tl_parser/tl/parameter_type.py b/generator/src/telethon_generator/_impl/tl_parser/tl/parameter_type.py index f7a3c584..252d148e 100644 --- a/generator/src/telethon_generator/_impl/tl_parser/tl/parameter_type.py +++ b/generator/src/telethon_generator/_impl/tl_parser/tl/parameter_type.py @@ -1,6 +1,8 @@ +from __future__ import annotations + from abc import ABC from dataclasses import dataclass -from typing import Optional, Union +from typing import Optional from .flag import Flag from .ty import Type @@ -8,7 +10,7 @@ from .ty import Type class BaseParameter(ABC): @staticmethod - def from_str(ty: str) -> Union["FlagsParameter", "NormalParameter"]: + def from_str(ty: str) -> FlagsParameter | NormalParameter: if not ty: raise ValueError("empty") if ty == "#": diff --git a/generator/src/telethon_generator/_impl/tl_parser/tl/ty.py b/generator/src/telethon_generator/_impl/tl_parser/tl/ty.py index cbc70656..b12d86d4 100644 --- a/generator/src/telethon_generator/_impl/tl_parser/tl/ty.py +++ b/generator/src/telethon_generator/_impl/tl_parser/tl/ty.py @@ -1,10 +1,11 @@ +from collections.abc import Iterator from dataclasses import dataclass -from typing import Iterator, List, Optional, Self +from typing import Optional, Self @dataclass class Type: - namespace: List[str] + namespace: list[str] name: str bare: bool generic_ref: bool diff --git a/generator/src/telethon_generator/_impl/tl_parser/tl_iterator.py b/generator/src/telethon_generator/_impl/tl_parser/tl_iterator.py index a7c0670e..aba60878 100644 --- a/generator/src/telethon_generator/_impl/tl_parser/tl_iterator.py +++ b/generator/src/telethon_generator/_impl/tl_parser/tl_iterator.py @@ -1,4 +1,5 @@ -from typing import Iterator, Type +from collections.abc import Iterator +from typing import Type from .tl.definition import Definition from .utils import remove_tl_comments diff --git a/generator/tests/common_test.py b/generator/tests/common_test.py index 9ee3c4df..f94be28d 100644 --- a/generator/tests/common_test.py +++ b/generator/tests/common_test.py @@ -1,5 +1,3 @@ -from typing import List - from pytest import mark from telethon_generator._impl.codegen.serde.common import ( split_words, @@ -19,7 +17,7 @@ from telethon_generator._impl.codegen.serde.common import ( ("fileMp4", ["file", "Mp4"]), ], ) -def test_split_name_words(name: str, expected: List[str]) -> None: +def test_split_name_words(name: str, expected: list[str]) -> None: assert split_words(name) == expected diff --git a/generator/tests/generator_test.py b/generator/tests/generator_test.py index 9b743412..949a3179 100644 --- a/generator/tests/generator_test.py +++ b/generator/tests/generator_test.py @@ -1,17 +1,17 @@ -from typing import List, Optional +from typing import Optional from telethon_generator.codegen import FakeFs, generate from telethon_generator.tl_parser import Definition, ParsedTl, parse_tl_file -def get_definitions(contents: str) -> List[Definition]: +def get_definitions(contents: str) -> list[Definition]: return [defn for defn in parse_tl_file(contents) if not isinstance(defn, Exception)] def gen_py_code( *, - typedefs: Optional[List[Definition]] = None, - functiondefs: Optional[List[Definition]] = None, + typedefs: Optional[list[Definition]] = None, + functiondefs: Optional[list[Definition]] = None, ) -> str: fs = FakeFs() generate( diff --git a/tools/copy_client_signatures.py b/tools/copy_client_signatures.py index 92cf2720..33c76817 100644 --- a/tools/copy_client_signatures.py +++ b/tools/copy_client_signatures.py @@ -15,12 +15,11 @@ import ast import subprocess import sys from pathlib import Path -from typing import Dict, List, Union class FunctionMethodsVisitor(ast.NodeVisitor): def __init__(self) -> None: - self.methods: List[Union[ast.FunctionDef, ast.AsyncFunctionDef]] = [] + self.methods: list[ast.FunctionDef | ast.AsyncFunctionDef] = [] def visit_FunctionDef(self, node: ast.FunctionDef) -> None: self._try_add_def(node) @@ -28,7 +27,7 @@ class FunctionMethodsVisitor(ast.NodeVisitor): def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> None: self._try_add_def(node) - def _try_add_def(self, node: Union[ast.FunctionDef, ast.AsyncFunctionDef]) -> None: + def _try_add_def(self, node: ast.FunctionDef | ast.AsyncFunctionDef) -> None: match node.args.args: case [ast.arg(arg="self", annotation=ast.Name(id="Client")), *_]: self.methods.append(node) @@ -39,7 +38,7 @@ class FunctionMethodsVisitor(ast.NodeVisitor): class MethodVisitor(ast.NodeVisitor): def __init__(self) -> None: self._in_client = False - self.method_docs: Dict[str, str] = {} + self.method_docs: dict[str, str] = {} def visit_ClassDef(self, node: ast.ClassDef) -> None: if node.name == "Client": @@ -55,7 +54,7 @@ class MethodVisitor(ast.NodeVisitor): def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> None: self._try_add_doc(node) - def _try_add_doc(self, node: Union[ast.FunctionDef, ast.AsyncFunctionDef]) -> None: + def _try_add_doc(self, node: ast.FunctionDef | ast.AsyncFunctionDef) -> None: if not self._in_client: return @@ -86,10 +85,10 @@ def main() -> None: m_visitor.visit(ast.parse(contents)) - class_body: List[ast.stmt] = [] + class_body: list[ast.stmt] = [] for function in sorted(fm_visitor.methods, key=lambda f: f.name): - function_body: List[ast.stmt] = [] + function_body: list[ast.stmt] = [] if doc := m_visitor.method_docs.get(function.name): function.body.append(ast.Expr(value=ast.Constant(value=doc))) diff --git a/tools/copy_init_imports.py b/tools/copy_init_imports.py index 2dbfd70a..023a6c5c 100644 --- a/tools/copy_init_imports.py +++ b/tools/copy_init_imports.py @@ -7,12 +7,11 @@ import ast import os import re from pathlib import Path -from typing import List class ImportVisitor(ast.NodeVisitor): def __init__(self) -> None: - self.imported_names: List[str] = [] + self.imported_names: list[str] = [] def visit_ImportFrom(self, node: ast.ImportFrom) -> None: if node.level == 1: @@ -26,7 +25,7 @@ def main() -> None: rf"(tl|mtproto){re.escape(os.path.sep)}(abcs|functions|types)" ) - files: List[str] = [] + files: list[str] = [] for file in impl_root.rglob("__init__.py"): file_str = str(file) if autogenerated_re.search(file_str): diff --git a/typings/pyaes.pyi b/typings/pyaes.pyi index 04ed6293..8af09e3c 100644 --- a/typings/pyaes.pyi +++ b/typings/pyaes.pyi @@ -1,6 +1,4 @@ -from typing import List - class AES: def __init__(self, key: bytes) -> None: ... - def encrypt(self, plaintext: List[int]) -> List[int]: ... - def decrypt(self, ciphertext: List[int]) -> List[int]: ... + def encrypt(self, plaintext: list[int]) -> list[int]: ... + def decrypt(self, ciphertext: list[int]) -> list[int]: ... diff --git a/typings/setuptools.build_meta.pyi b/typings/setuptools.build_meta.pyi index 1a6ea948..da6518c9 100644 --- a/typings/setuptools.build_meta.pyi +++ b/typings/setuptools.build_meta.pyi @@ -1,15 +1,15 @@ -from typing import Any, Dict, Optional +from typing import Any, Optional def build_wheel( wheel_directory: str, - config_settings: Optional[Dict[Any, Any]] = None, + config_settings: Optional[dict[Any, Any]] = None, metadata_directory: Optional[str] = None, ) -> str: ... def build_sdist( - sdist_directory: str, config_settings: Optional[Dict[Any, Any]] = None + sdist_directory: str, config_settings: Optional[dict[Any, Any]] = None ) -> str: ... def build_editable( wheel_directory: str, - config_settings: Optional[Dict[Any, Any]] = None, + config_settings: Optional[dict[Any, Any]] = None, metadata_directory: Optional[str] = None, ) -> str: ... diff --git a/typings/setuptools.pyi b/typings/setuptools.pyi index d6af5577..e3794c75 100644 --- a/typings/setuptools.pyi +++ b/typings/setuptools.pyi @@ -1,19 +1,19 @@ -from typing import Any, Dict, Optional +from typing import Any, Optional class build_meta: @staticmethod def build_wheel( wheel_directory: str, - config_settings: Optional[Dict[Any, Any]] = None, + config_settings: Optional[dict[Any, Any]] = None, metadata_directory: Optional[str] = None, ) -> str: ... @staticmethod def build_sdist( - sdist_directory: str, config_settings: Optional[Dict[Any, Any]] = None + sdist_directory: str, config_settings: Optional[dict[Any, Any]] = None ) -> str: ... @staticmethod def build_editable( wheel_directory: str, - config_settings: Optional[Dict[Any, Any]] = None, + config_settings: Optional[dict[Any, Any]] = None, metadata_directory: Optional[str] = None, ) -> str: ...