mirror of
https://github.com/aiogram/aiogram.git
synced 2026-04-08 16:37:47 +00:00
Merge branch 'dev-3.x-sphinx' into dev-3.x-api-5.0
# Conflicts: # aiogram/client/bot.py # poetry.lock # pyproject.toml
This commit is contained in:
commit
9539c4e2fd
206 changed files with 6420 additions and 242 deletions
|
|
@ -140,13 +140,20 @@ T = TypeVar("T")
|
|||
|
||||
|
||||
class Bot(ContextInstanceMixin["Bot"]):
|
||||
"""
|
||||
Main bot class
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, token: str, session: Optional[BaseSession] = None, parse_mode: Optional[str] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Bot class
|
||||
|
||||
:param token: Telegram Bot token `Obtained from @BotFather <https://t.me/BotFather>`_
|
||||
:param session: HTTP Client session (For example AiohttpSession).
|
||||
If not specified it will be automatically created.
|
||||
:param parse_mode: Default parse mode.
|
||||
If specified it will be propagated into the API methods at runtime.
|
||||
:raise TokenValidationError: When token has invalid format this exception will be raised
|
||||
"""
|
||||
|
||||
validate_token(token)
|
||||
|
||||
if session is None:
|
||||
|
|
|
|||
|
|
@ -32,35 +32,63 @@ _JsonDumps = Callable[..., str]
|
|||
|
||||
|
||||
class BaseSession(abc.ABC):
|
||||
default_timeout: ClassVar[float] = 60.0
|
||||
api: Default[TelegramAPIServer] = Default(PRODUCTION)
|
||||
"""Telegra Bot API URL patterns"""
|
||||
json_loads: Default[_JsonLoads] = Default(json.loads)
|
||||
"""JSON loader"""
|
||||
json_dumps: Default[_JsonDumps] = Default(json.dumps)
|
||||
"""JSON dumper"""
|
||||
default_timeout: ClassVar[float] = 60.0
|
||||
"""Default timeout"""
|
||||
timeout: Default[float] = Default(fget=lambda self: float(self.__class__.default_timeout))
|
||||
"""Session scope request timeout"""
|
||||
|
||||
@classmethod
|
||||
def raise_for_status(cls, response: Response[T]) -> None:
|
||||
"""
|
||||
Check response status
|
||||
|
||||
:param response: Response instance
|
||||
"""
|
||||
if response.ok:
|
||||
return
|
||||
raise TelegramAPIError(response.description)
|
||||
|
||||
@abc.abstractmethod
|
||||
async def close(self) -> None: # pragma: no cover
|
||||
"""
|
||||
Close client session
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
async def make_request(
|
||||
self, bot: Bot, method: TelegramMethod[T], timeout: Optional[int] = UNSET
|
||||
) -> T: # pragma: no cover
|
||||
"""
|
||||
Make request to Telegram Bot API
|
||||
|
||||
:param bot: Bot instance
|
||||
:param method: Method instance
|
||||
:param timeout: Request timeout
|
||||
:return:
|
||||
:raise TelegramApiError:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
async def stream_content(
|
||||
self, url: str, timeout: int, chunk_size: int
|
||||
) -> AsyncGenerator[bytes, None]: # pragma: no cover
|
||||
"""
|
||||
Stream reader
|
||||
"""
|
||||
yield b""
|
||||
|
||||
def prepare_value(self, value: Any) -> Union[str, int, bool]:
|
||||
"""
|
||||
Prepare value before send
|
||||
"""
|
||||
if isinstance(value, str):
|
||||
return value
|
||||
if isinstance(value, (list, dict)):
|
||||
|
|
@ -74,6 +102,9 @@ class BaseSession(abc.ABC):
|
|||
return str(value)
|
||||
|
||||
def clean_json(self, value: Any) -> Any:
|
||||
"""
|
||||
Clean data before send
|
||||
"""
|
||||
if isinstance(value, list):
|
||||
return [self.clean_json(v) for v in value if v is not None]
|
||||
elif isinstance(value, dict):
|
||||
|
|
|
|||
|
|
@ -8,6 +8,19 @@ from .handler import CallbackType, HandlerObject, HandlerType
|
|||
class EventObserver:
|
||||
"""
|
||||
Simple events observer
|
||||
|
||||
Is used for managing events is not related with Telegram (For example startup/shutdown processes)
|
||||
|
||||
Handlers can be registered via decorator or method
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
<observer>.register(my_handler)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@<observer>()
|
||||
async def my_handler(*args, **kwargs): ...
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ if TYPE_CHECKING: # pragma: no cover
|
|||
class TelegramEventObserver:
|
||||
"""
|
||||
Event observer for Telegram events
|
||||
|
||||
Here you can register handler with filters or bounded filters which can be used as keyword arguments instead of writing full references when you register new handlers.
|
||||
This observer will stops event propagation when first handler is pass.
|
||||
"""
|
||||
|
||||
def __init__(self, router: Router, event_name: str) -> None:
|
||||
|
|
@ -153,10 +156,19 @@ class TelegramEventObserver:
|
|||
Decorator for registering inner middlewares
|
||||
|
||||
Usage:
|
||||
>>> @<event>.middleware() # via decorator (variant 1)
|
||||
>>> @<event>.middleware # via decorator (variant 2)
|
||||
>>> async def my_middleware(handler, event, data): ...
|
||||
>>> <event>.middleware(middleware) # via method
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@<event>.middleware() # via decorator (variant 1)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@<event>.middleware # via decorator (variant 2)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
async def my_middleware(handler, event, data): ...
|
||||
<event>.middleware(my_middleware) # via method
|
||||
"""
|
||||
|
||||
def wrapper(m: MiddlewareType) -> MiddlewareType:
|
||||
|
|
@ -174,10 +186,19 @@ class TelegramEventObserver:
|
|||
Decorator for registering outer middlewares
|
||||
|
||||
Usage:
|
||||
>>> @<event>.outer_middleware() # via decorator (variant 1)
|
||||
>>> @<event>.outer_middleware # via decorator (variant 2)
|
||||
>>> async def my_middleware(handler, event, data): ...
|
||||
>>> <event>.outer_middleware(my_middleware) # via method
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@<event>.outer_middleware() # via decorator (variant 1)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@<event>.outer_middleware # via decorator (variant 2)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
async def my_middleware(handler, event, data): ...
|
||||
<event>.outer_middleware(my_middleware) # via method
|
||||
"""
|
||||
|
||||
def wrapper(m: MiddlewareType) -> MiddlewareType:
|
||||
|
|
|
|||
|
|
@ -15,10 +15,22 @@ from .middlewares.error import ErrorsMiddleware
|
|||
|
||||
class Router:
|
||||
"""
|
||||
Events router
|
||||
Router can route update and it nested update types like messages, callback query, polls and all other event types.
|
||||
Here is used event-observer pattern.
|
||||
|
||||
Event handlers can be registered in observer by two ways:
|
||||
|
||||
- By observer method - :obj:`router.<event_type>.register(handler, <filters, ...>)`
|
||||
- By decorator - :obj:`@router.<event_type>(<filters, ...>)`
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, use_builtin_filters: bool = True) -> None:
|
||||
"""
|
||||
|
||||
:param use_builtin_filters: `aiogram` has many builtin filters and you can controll automatic registration of this filters in factory
|
||||
"""
|
||||
|
||||
self.use_builtin_filters = use_builtin_filters
|
||||
|
||||
self._parent_router: Optional[Router] = None
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
from typing_extensions import Protocol
|
||||
try:
|
||||
from typing import Protocol
|
||||
except ImportError: # pragma: no cover
|
||||
from typing_extensions import Protocol # type: ignore
|
||||
|
||||
|
||||
class Downloadable(Protocol):
|
||||
|
|
|
|||
|
|
@ -38,6 +38,13 @@ class InputFile(ABC):
|
|||
|
||||
class BufferedInputFile(InputFile):
|
||||
def __init__(self, file: bytes, filename: str, chunk_size: int = DEFAULT_CHUNK_SIZE):
|
||||
"""
|
||||
Represents object for uploading files from filesystem
|
||||
|
||||
:param file: Bytes
|
||||
:param filename: Filename to be propagated to telegram.
|
||||
:param chunk_size: Uploading chunk size
|
||||
"""
|
||||
super().__init__(filename=filename, chunk_size=chunk_size)
|
||||
|
||||
self.data = file
|
||||
|
|
@ -49,6 +56,15 @@ class BufferedInputFile(InputFile):
|
|||
filename: Optional[str] = None,
|
||||
chunk_size: int = DEFAULT_CHUNK_SIZE,
|
||||
) -> BufferedInputFile:
|
||||
"""
|
||||
Create buffer from file
|
||||
|
||||
:param path: Path to file
|
||||
:param filename: Filename to be propagated to telegram.
|
||||
By default will be parsed from path
|
||||
:param chunk_size: Uploading chunk size
|
||||
:return: instance of :obj:`BufferedInputFile`
|
||||
"""
|
||||
if filename is None:
|
||||
filename = os.path.basename(path)
|
||||
with open(path, "rb") as f:
|
||||
|
|
@ -70,6 +86,14 @@ class FSInputFile(InputFile):
|
|||
filename: Optional[str] = None,
|
||||
chunk_size: int = DEFAULT_CHUNK_SIZE,
|
||||
):
|
||||
"""
|
||||
Represents object for uploading files from filesystem
|
||||
|
||||
:param path: Path to file
|
||||
:param filename: Filename to be propagated to telegram.
|
||||
By default will be parsed from path
|
||||
:param chunk_size: Uploading chunk size
|
||||
"""
|
||||
if filename is None:
|
||||
filename = os.path.basename(path)
|
||||
super().__init__(filename=filename, chunk_size=chunk_size)
|
||||
|
|
@ -92,6 +116,13 @@ class URLInputFile(InputFile):
|
|||
chunk_size: int = DEFAULT_CHUNK_SIZE,
|
||||
timeout: int = 30,
|
||||
):
|
||||
"""
|
||||
Represents object for streaming files from internet
|
||||
|
||||
:param url: URL in internet
|
||||
:param filename: Filename to be propagated to telegram.
|
||||
:param chunk_size: Uploading chunk size
|
||||
"""
|
||||
super().__init__(filename=filename, chunk_size=chunk_size)
|
||||
|
||||
self.url = url
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue