Begin preparing client for documentation

This commit is contained in:
Lonami Exo 2023-09-13 19:00:47 +02:00
parent 80fefca2e9
commit e36c35c805
8 changed files with 165 additions and 15 deletions

View File

@ -1,6 +1,7 @@
from ._impl import tl as _tl
from ._impl.client import Client, Config
from ._impl.mtproto import RpcError
from ._impl.session import Session
from .version import __version__
__all__ = ["_tl", "Client", "Config", "Session"]
__all__ = ["_tl", "Client", "Config", "RpcError", "Session"]

View File

@ -33,6 +33,7 @@ from ..events import Event
from ..events.filters import Filter
from ..types import (
AsyncList,
Chat,
ChatLike,
File,
InFileLike,
@ -46,6 +47,7 @@ from ..types import (
from .auth import (
bot_sign_in,
check_password,
interactive_login,
is_authorized,
request_login_code,
sign_in,
@ -92,7 +94,13 @@ from .updates import (
remove_event_handler,
set_handler_filter,
)
from .users import get_me, input_to_peer, resolve_to_packed
from .users import (
get_contacts,
get_me,
input_to_peer,
resolve_to_packed,
resolve_username,
)
Return = TypeVar("Return")
T = TypeVar("T")
@ -169,6 +177,12 @@ class Client:
await disconnect(self)
async def download(self, media: MediaLike, file: OutFileLike) -> None:
"""
Download a file.
This is simply a more convenient method to `iter_download`,
as it will handle dealing with the file chunks and writes by itself.
"""
await download(self, media, file)
async def edit_message(
@ -196,6 +210,9 @@ class Client:
) -> List[Message]:
return await forward_messages(self, target, message_ids, source)
async def get_contacts(self) -> AsyncList[User]:
return await get_contacts(self)
def get_dialogs(self) -> None:
get_dialogs(self)
@ -232,6 +249,9 @@ class Client:
) -> AsyncIterator[InlineResult]:
return await inline_query(self, bot, query, chat=chat)
async def interactive_login(self) -> User:
return await interactive_login(self)
async def is_authorized(self) -> bool:
return await is_authorized(self)
@ -257,6 +277,9 @@ class Client:
async def resolve_to_packed(self, chat: ChatLike) -> PackedChat:
return await resolve_to_packed(self, chat)
async def resolve_username(self) -> Chat:
return await resolve_username(self)
async def run_until_disconnected(self) -> None:
await run_until_disconnected(self)
@ -299,6 +322,12 @@ class Client:
title: Optional[str] = None,
performer: Optional[str] = None,
) -> Message:
"""
Send an audio file.
Unlike `send_file`, this method will attempt to guess the values for
duration, title and performer if they are not provided.
"""
return await send_audio(
self,
chat,
@ -340,6 +369,19 @@ class Client:
caption_markdown: Optional[str] = None,
caption_html: Optional[str] = None,
) -> Message:
"""
Send any type of file with any amount of attributes.
This method will not attempt to guess any of the file metadata such as
width, duration, title, etc. If you want to let the library attempt to
guess the file metadata, use the type-specific methods to send media:
`send_photo`, `send_audio` or `send_file`.
Unlike `send_photo`, image files will be sent as documents by default.
The parameters are used to construct a `File`. See the documentation
for `File.new` to learn what they do and when they are in effect.
"""
return await send_file(
self,
chat,
@ -398,6 +440,20 @@ class Client:
width: Optional[int] = None,
height: Optional[int] = None,
) -> Message:
"""
Send a photo file.
Exactly one of path, url or file must be specified.
A `File` can also be used as the second parameter.
By default, the server will be allowed to `compress` the image.
Only compressed images can be displayed as photos in applications.
Images that cannot be compressed will be sent as file documents,
with a thumbnail if possible.
Unlike `send_file`, this method will attempt to guess the values for
width and height if they are not provided and the can't be compressed.
"""
return await send_photo(
self,
chat,
@ -426,6 +482,12 @@ class Client:
round: bool = False,
supports_streaming: bool = False,
) -> Message:
"""
Send a video file.
Unlike `send_file`, this method will attempt to guess the values for
duration, width and height if they are not provided.
"""
return await send_video(
self,
chat,

View File

@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Optional
from ...session import PackedChat, PackedType
from ...tl import abcs, types
from ..types import Channel, ChatLike, Group, User
from ..types import AsyncList, Channel, Chat, ChatLike, Group, User
if TYPE_CHECKING:
from .client import Client
@ -15,6 +15,16 @@ async def get_me(self: Client) -> User:
raise NotImplementedError
async def get_contacts(self: Client) -> AsyncList[User]:
self
raise NotImplementedError
async def resolve_username(self: Client) -> Chat:
self
raise NotImplementedError
async def resolve_to_packed(self: Client, chat: ChatLike) -> PackedChat:
if isinstance(chat, (User, Group, Channel)):
packed = chat.pack()

View File

@ -1,12 +1,11 @@
from typing import Union
from ....session import PackedChat
from ....tl import abcs
from .channel import Channel
from .group import Group
from .user import RestrictionReason, User
Chat = Union[Channel, Group, User]
ChatLike = Union[Chat, PackedChat, int, str, abcs.InputPeer]
ChatLike = Union[Chat, PackedChat, int, str]
__all__ = ["Chat", "ChatLike", "Channel", "Group", "RestrictionReason", "User"]

View File

@ -41,6 +41,10 @@ class Message(metaclass=NoPublicConstructor):
def chat(self) -> Chat:
raise NotImplementedError
@property
def sender(self) -> Chat:
raise NotImplementedError
def _file(self) -> Optional[File]:
return (
File._try_from_raw(self._raw.media)

View File

@ -20,10 +20,22 @@ class RpcError(ValueError):
append_value = f" ({value})" if value else None
super().__init__(f"rpc error {code}: {name}{append_value}")
self.code = code
self.name = name
self.value = value
self.caused_by = caused_by
self._code = code
self._name = name
self._value = value
self._caused_by = caused_by
@property
def code(self) -> int:
return self._code
@property
def name(self) -> str:
return self._name
@property
def value(self) -> Optional[int]:
return self._value
@classmethod
def from_mtproto_error(cls, error: GeneratedRpcError) -> Self:
@ -49,9 +61,9 @@ class RpcError(ValueError):
if not isinstance(other, self.__class__):
return NotImplemented
return (
self.code == other.code
and self.name == other.name
and self.value == other.value
self._code == other._code
and self._name == other._name
and self._value == other._value
)
@ -64,13 +76,17 @@ class BadMessage(ValueError):
) -> None:
super().__init__(f"bad msg: {code}")
self.code = code
self.caused_by = caused_by
self._code = code
self._caused_by = caused_by
@property
def code(self) -> int:
return self._code
def __eq__(self, other: object) -> bool:
if not isinstance(other, self.__class__):
return NotImplemented
return self.code == other.code
return self._code == other._code
RpcResult = bytes | RpcError | BadMessage

View File

@ -0,0 +1,21 @@
from ._impl.session import (
ChannelState,
DataCenter,
MemorySession,
Session,
SqliteSession,
Storage,
UpdateState,
User,
)
__all__ = [
"ChannelState",
"DataCenter",
"MemorySession",
"Session",
"SqliteSession",
"Storage",
"UpdateState",
"User",
]

View File

@ -0,0 +1,37 @@
from ._impl.client.types import (
AsyncList,
Channel,
Chat,
ChatLike,
File,
Group,
InFileLike,
LoginToken,
MediaLike,
Message,
NoPublicConstructor,
OutFileLike,
PasswordToken,
RestrictionReason,
User,
)
from ._impl.session import PackedChat
__all__ = [
"AsyncList",
"Channel",
"Chat",
"ChatLike",
"File",
"Group",
"InFileLike",
"LoginToken",
"MediaLike",
"Message",
"NoPublicConstructor",
"OutFileLike",
"PasswordToken",
"RestrictionReason",
"User",
"PackedChat",
]