botapi-py 1.3.3__tar.gz → 1.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {botapi_py-1.3.3 → botapi_py-1.4.1}/PKG-INFO +3 -2
- {botapi_py-1.3.3 → botapi_py-1.4.1}/pyproject.toml +3 -2
- botapi_py-1.4.1/src/botapi/__init__.py +4 -0
- botapi_py-1.4.1/src/botapi/__init__.pyi +4 -0
- {botapi_py-1.3.3 → botapi_py-1.4.1}/src/botapi/core.py +1 -1
- {botapi_py-1.3.3 → botapi_py-1.4.1}/src/botapi/dispatchers/__init__.py +4 -0
- botapi_py-1.4.1/src/botapi/dispatchers/__init__.pyi +10 -0
- botapi_py-1.4.1/src/botapi/dispatchers/common.py +62 -0
- {botapi_py-1.3.3 → botapi_py-1.4.1}/src/botapi/dispatchers/get_updates_handler.py +20 -9
- {botapi_py-1.3.3 → botapi_py-1.4.1}/src/botapi/dispatchers/redis_pubsub_handler.py +48 -12
- botapi_py-1.3.3/src/botapi/api.py → botapi_py-1.4.1/src/botapi/methods.py +1 -1
- {botapi_py-1.3.3 → botapi_py-1.4.1}/src/botapi/types.py +136 -9
- botapi_py-1.3.3/src/botapi/__init__.py +0 -4
- botapi_py-1.3.3/src/botapi/__init__.pyi +0 -4
- {botapi_py-1.3.3 → botapi_py-1.4.1}/src/botapi/enums.py +0 -0
- {botapi_py-1.3.3 → botapi_py-1.4.1}/src/botapi/errors.py +0 -0
- {botapi_py-1.3.3 → botapi_py-1.4.1}/src/botapi/utils.py +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: botapi-py
|
|
3
|
-
Version: 1.
|
|
4
|
-
Summary: A simple and flexible Python library to conveniently build Telegram bots using the Bot API.
|
|
3
|
+
Version: 1.4.1
|
|
4
|
+
Summary: A simple and flexible Python library to conveniently build fast Telegram bots using the Bot API.
|
|
5
5
|
Requires-Dist: httpx>=0.28.1
|
|
6
6
|
Requires-Dist: pydantic>=2.12.0
|
|
7
|
+
Requires-Dist: orjson>=3.11.3 ; extra == 'redis'
|
|
7
8
|
Requires-Dist: redis>=6.4.0 ; extra == 'redis'
|
|
8
9
|
Requires-Python: >=3.12
|
|
9
10
|
Project-URL: Telegram BotAPI Docs, https://core.telegram.org/bots/api
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "botapi-py"
|
|
3
|
-
version = "1.
|
|
4
|
-
description = "A simple and flexible Python library to conveniently build Telegram bots using the Bot API."
|
|
3
|
+
version = "1.4.1"
|
|
4
|
+
description = "A simple and flexible Python library to conveniently build fast Telegram bots using the Bot API."
|
|
5
5
|
# readme = "README.md"
|
|
6
6
|
# authors = [
|
|
7
7
|
# { name = "CalledLuca", email = "me@calledluca.it" }
|
|
@@ -17,6 +17,7 @@ dependencies = [
|
|
|
17
17
|
|
|
18
18
|
[project.optional-dependencies]
|
|
19
19
|
redis = [
|
|
20
|
+
"orjson>=3.11.3",
|
|
20
21
|
"redis>=6.4.0",
|
|
21
22
|
]
|
|
22
23
|
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
from .common import UpdateHandler
|
|
2
|
+
|
|
1
3
|
from .get_updates_handler import GetUpdatesAsyncDispatcher
|
|
2
4
|
try:
|
|
5
|
+
# Fails at runtime if redis-py is not installed
|
|
3
6
|
from .redis_pubsub_handler import RedisPubSubAsyncDispatcher
|
|
4
7
|
except ImportError:
|
|
5
8
|
pass
|
|
6
9
|
|
|
7
10
|
__all__ = [
|
|
11
|
+
'UpdateHandler',
|
|
8
12
|
'GetUpdatesAsyncDispatcher',
|
|
9
13
|
'RedisPubSubAsyncDispatcher',
|
|
10
14
|
]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from .common import UpdateHandler
|
|
2
|
+
|
|
3
|
+
from .get_updates_handler import GetUpdatesAsyncDispatcher
|
|
4
|
+
from .redis_pubsub_handler import RedisPubSubAsyncDispatcher
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
'UpdateHandler',
|
|
8
|
+
'GetUpdatesAsyncDispatcher',
|
|
9
|
+
'RedisPubSubAsyncDispatcher',
|
|
10
|
+
]
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
from typing import Any, Callable, Coroutine, TypeAlias, Union
|
|
3
|
+
|
|
4
|
+
from botapi.types import Update
|
|
5
|
+
|
|
6
|
+
UpdateHandler1: TypeAlias = Callable[
|
|
7
|
+
[Update],
|
|
8
|
+
Coroutine[Any, Any, None]
|
|
9
|
+
]
|
|
10
|
+
'''
|
|
11
|
+
Represents an async update handler function.
|
|
12
|
+
It has the following signature:
|
|
13
|
+
- `async def handler(update: Update) -> None: ...`
|
|
14
|
+
'''
|
|
15
|
+
|
|
16
|
+
UpdateHandler2: TypeAlias = Callable[
|
|
17
|
+
[Update, str],
|
|
18
|
+
Coroutine[Any, Any, None]
|
|
19
|
+
]
|
|
20
|
+
'''
|
|
21
|
+
Represents an async update handler function.
|
|
22
|
+
It has the following signature:
|
|
23
|
+
- `async def handler(update: Update, bot_token: str) -> None: ...`
|
|
24
|
+
'''
|
|
25
|
+
|
|
26
|
+
UpdateHandler: TypeAlias = Union[
|
|
27
|
+
UpdateHandler1,
|
|
28
|
+
UpdateHandler2
|
|
29
|
+
]
|
|
30
|
+
'''
|
|
31
|
+
Represents an async update handler function.
|
|
32
|
+
|
|
33
|
+
It can have one of the following signatures:
|
|
34
|
+
- `async def handler(update: Update) -> None: ...`
|
|
35
|
+
- `async def handler(update: Update, bot_token: str) -> None: ...`
|
|
36
|
+
|
|
37
|
+
The second signature is especially useful when the dispatcher
|
|
38
|
+
is used to handle incoming updates from multiple bots.
|
|
39
|
+
'''
|
|
40
|
+
|
|
41
|
+
class BaseAsyncDispatcher(ABC):
|
|
42
|
+
'''
|
|
43
|
+
Abstract base class for all async update dispatchers.
|
|
44
|
+
'''
|
|
45
|
+
|
|
46
|
+
async def run_forever(self) -> None:
|
|
47
|
+
'''
|
|
48
|
+
Waits for incoming updates forever, and dispatches them to the registered handler.
|
|
49
|
+
This method **is blocking**, it terminates on SIGINT/SIGTERM signals.
|
|
50
|
+
|
|
51
|
+
This method automatically retries failed `getUpdates` requests after a short delay.
|
|
52
|
+
|
|
53
|
+
Example:
|
|
54
|
+
```python
|
|
55
|
+
dispatcher = Dispatcher(
|
|
56
|
+
...
|
|
57
|
+
)
|
|
58
|
+
await dispatcher.run_forever()
|
|
59
|
+
```
|
|
60
|
+
'''
|
|
61
|
+
raise NotImplementedError()
|
|
62
|
+
|
|
@@ -1,23 +1,26 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import asyncio
|
|
4
|
+
import inspect
|
|
2
5
|
import logging
|
|
3
6
|
import signal
|
|
4
|
-
from typing import
|
|
7
|
+
from typing import override
|
|
5
8
|
|
|
6
9
|
import httpx
|
|
7
10
|
|
|
8
11
|
import botapi
|
|
9
12
|
from botapi.types import Update
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
UpdateHandler: TypeAlias = Callable[[Update], Coroutine[Any, Any, None]]
|
|
14
|
+
from .common import BaseAsyncDispatcher, UpdateHandler
|
|
14
15
|
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
15
17
|
|
|
16
|
-
class GetUpdatesAsyncDispatcher:
|
|
18
|
+
class GetUpdatesAsyncDispatcher(BaseAsyncDispatcher):
|
|
17
19
|
update_handler: UpdateHandler
|
|
20
|
+
update_handler_argcount: int
|
|
18
21
|
tasks_shutdown_timeout: float
|
|
19
22
|
tasks: set[asyncio.Task] # prevent gc from collecting tasks before they finish
|
|
20
|
-
bot:
|
|
23
|
+
bot: botapi.methods.Bot
|
|
21
24
|
reconnect_delay: float
|
|
22
25
|
allowed_updates: list[str]
|
|
23
26
|
offset: int
|
|
@@ -25,7 +28,7 @@ class GetUpdatesAsyncDispatcher:
|
|
|
25
28
|
def __init__(
|
|
26
29
|
self,
|
|
27
30
|
update_handler: UpdateHandler,
|
|
28
|
-
bot:
|
|
31
|
+
bot: botapi.methods.Bot,
|
|
29
32
|
allowed_updates: list[str], # botapi.enums.UpdateType
|
|
30
33
|
reconnect_delay: float = 5,
|
|
31
34
|
shutdown_wait_timeout: float = 3
|
|
@@ -37,7 +40,7 @@ class GetUpdatesAsyncDispatcher:
|
|
|
37
40
|
Args:
|
|
38
41
|
update_handler (UpdateHandler):
|
|
39
42
|
Async function to handle received messages.
|
|
40
|
-
bot (botapi.
|
|
43
|
+
bot (botapi.Bot):
|
|
41
44
|
A `Bot` instance.
|
|
42
45
|
allowed_updates (list[botapi.enums.UpdateType]):
|
|
43
46
|
List of allowed update types.
|
|
@@ -53,6 +56,7 @@ class GetUpdatesAsyncDispatcher:
|
|
|
53
56
|
self.shutdown_wait_timeout = shutdown_wait_timeout
|
|
54
57
|
self.offset = -1
|
|
55
58
|
self.tasks = set()
|
|
59
|
+
self.update_handler_argcount = len(inspect.getfullargspec(update_handler).args)
|
|
56
60
|
|
|
57
61
|
def _task_done_callback(self, task: asyncio.Task) -> None:
|
|
58
62
|
'''
|
|
@@ -73,7 +77,13 @@ class GetUpdatesAsyncDispatcher:
|
|
|
73
77
|
'''
|
|
74
78
|
Dispatches the update to the registered handler, in a new task.
|
|
75
79
|
'''
|
|
76
|
-
|
|
80
|
+
if self.update_handler_argcount == 1:
|
|
81
|
+
coro = self.update_handler(update) # pyright: ignore[reportCallIssue]
|
|
82
|
+
else:
|
|
83
|
+
coro = self.update_handler(update, self.bot.token) # pyright: ignore[reportCallIssue]
|
|
84
|
+
|
|
85
|
+
task = asyncio.create_task(coro)
|
|
86
|
+
|
|
77
87
|
self.tasks.add(task)
|
|
78
88
|
task.add_done_callback(self._task_done_callback)
|
|
79
89
|
|
|
@@ -153,6 +163,7 @@ class GetUpdatesAsyncDispatcher:
|
|
|
153
163
|
task_to_cancel.cancel
|
|
154
164
|
)
|
|
155
165
|
|
|
166
|
+
@override
|
|
156
167
|
async def run_forever(self) -> None:
|
|
157
168
|
'''
|
|
158
169
|
Waits for incoming updates forever, and dispatches them to the registered handler.
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import asyncio
|
|
4
|
+
import inspect
|
|
2
5
|
import json
|
|
3
6
|
import logging
|
|
4
7
|
import signal
|
|
5
|
-
from typing import
|
|
8
|
+
from typing import override
|
|
6
9
|
|
|
10
|
+
import orjson
|
|
7
11
|
import pydantic
|
|
12
|
+
|
|
8
13
|
from botapi.types import Update
|
|
9
14
|
|
|
15
|
+
from .common import BaseAsyncDispatcher, UpdateHandler
|
|
16
|
+
|
|
10
17
|
try:
|
|
11
18
|
import redis.asyncio as redis
|
|
12
19
|
from redis.asyncio.client import PubSub
|
|
@@ -17,21 +24,22 @@ except ImportError as e:
|
|
|
17
24
|
|
|
18
25
|
logger = logging.getLogger(__name__)
|
|
19
26
|
|
|
20
|
-
UpdateHandler: TypeAlias = Callable[[Update], Coroutine[Any, Any, None]]
|
|
21
|
-
|
|
22
27
|
|
|
23
|
-
class RedisPubSubAsyncDispatcher:
|
|
28
|
+
class RedisPubSubAsyncDispatcher(BaseAsyncDispatcher):
|
|
24
29
|
update_handler: UpdateHandler
|
|
30
|
+
update_handler_argcount: int
|
|
25
31
|
tasks_shutdown_timeout: float
|
|
26
32
|
tasks: set[asyncio.Task] # prevent gc from collecting tasks before they finish
|
|
27
33
|
redis_client: redis.Redis
|
|
28
34
|
redis_reconnect_delay: float
|
|
29
35
|
pubsub: PubSub
|
|
30
36
|
pubsub_channel: str
|
|
37
|
+
bot_token_json_key: str
|
|
31
38
|
|
|
32
39
|
def __init__(
|
|
33
40
|
self,
|
|
34
41
|
update_handler: UpdateHandler,
|
|
42
|
+
bot_token_json_key: str,
|
|
35
43
|
pubsub_channel: str,
|
|
36
44
|
redis_client: redis.Redis,
|
|
37
45
|
redis_reconnect_delay: float = 5,
|
|
@@ -41,9 +49,20 @@ class RedisPubSubAsyncDispatcher:
|
|
|
41
49
|
Dispatcher that receives updates from a Redis PUB/SUB
|
|
42
50
|
and dispatches them to a registered async handler.
|
|
43
51
|
|
|
52
|
+
This dispatcher is atypical but very useful, especially when you need to handle
|
|
53
|
+
updates coming from a lot of different bots AND from many different projects.
|
|
54
|
+
|
|
55
|
+
**NOTE:**
|
|
56
|
+
This dispatcher assumes that the bot token is part of the update JSON payload itself
|
|
57
|
+
inside the `bot_token_json_key` key (see constructor), so either:
|
|
58
|
+
- the software handling the `PUBLISH` must manipulate the JSON accordingly, or
|
|
59
|
+
- a custom Bot API Server must do this.
|
|
60
|
+
|
|
44
61
|
Args:
|
|
45
62
|
update_handler (UpdateHandler):
|
|
46
63
|
Async function to handle received messages.
|
|
64
|
+
bot_token_json_key (str):
|
|
65
|
+
Name of the JSON key in the update payload that contains the bot token.
|
|
47
66
|
redis_client (redis.Redis):
|
|
48
67
|
Redis client instance.
|
|
49
68
|
pubsub_channel (str):
|
|
@@ -56,13 +75,15 @@ class RedisPubSubAsyncDispatcher:
|
|
|
56
75
|
if not _has_redis:
|
|
57
76
|
raise ImportError('redis-py is not installed. Install `botapi-py[redis]` to use this dispatcher.')
|
|
58
77
|
|
|
59
|
-
self.redis_client = redis_client
|
|
60
78
|
self.update_handler = update_handler
|
|
79
|
+
self.bot_token_json_key = bot_token_json_key
|
|
80
|
+
self.redis_client = redis_client
|
|
61
81
|
self.pubsub_channel = pubsub_channel
|
|
62
82
|
self.redis_reconnect_delay = redis_reconnect_delay
|
|
63
83
|
self.shutdown_wait_timeout = shutdown_wait_timeout
|
|
64
84
|
self.tasks = set()
|
|
65
85
|
self.pubsub = self.redis_client.pubsub(ignore_subscribe_messages=True)
|
|
86
|
+
self.update_handler_argcount = len(inspect.getfullargspec(update_handler).args)
|
|
66
87
|
|
|
67
88
|
def _task_done_callback(self, task: asyncio.Task) -> None:
|
|
68
89
|
'''
|
|
@@ -79,13 +100,21 @@ class RedisPubSubAsyncDispatcher:
|
|
|
79
100
|
finally:
|
|
80
101
|
self.tasks.discard(task)
|
|
81
102
|
|
|
82
|
-
async def
|
|
103
|
+
async def _message_to_update_and_token(self, message: str) -> tuple[Update, str]:
|
|
83
104
|
'''
|
|
84
|
-
Converts raw message (containing a JSON) into a Python dict
|
|
85
|
-
|
|
105
|
+
Converts raw message (containing a JSON) into a Python dict, then:
|
|
106
|
+
- extracts the bot token from the specified `self.bot_token_json_key` key
|
|
107
|
+
- validates the update into an `Update` object.
|
|
86
108
|
'''
|
|
87
|
-
data =
|
|
88
|
-
|
|
109
|
+
data: dict = orjson.loads(message)
|
|
110
|
+
|
|
111
|
+
if self.bot_token_json_key not in data:
|
|
112
|
+
err = f'Missing bot token key "{self.bot_token_json_key}" in the update JSON payload'
|
|
113
|
+
raise KeyError(err)
|
|
114
|
+
|
|
115
|
+
bot_token = data.pop(self.bot_token_json_key)
|
|
116
|
+
|
|
117
|
+
return Update.from_dict(data), bot_token
|
|
89
118
|
|
|
90
119
|
async def _dispatch(self, message: str) -> None:
|
|
91
120
|
'''
|
|
@@ -93,13 +122,19 @@ class RedisPubSubAsyncDispatcher:
|
|
|
93
122
|
then dispatch it, to the registered handler, in a new task.
|
|
94
123
|
'''
|
|
95
124
|
try:
|
|
96
|
-
update = await self.
|
|
125
|
+
update, bot_token = await self._message_to_update_and_token(message)
|
|
97
126
|
except json.JSONDecodeError:
|
|
98
127
|
logger.exception('Failed to decode JSON:')
|
|
99
128
|
except pydantic.ValidationError:
|
|
100
129
|
logger.exception('Failed pydantic validation:')
|
|
101
130
|
else:
|
|
102
|
-
|
|
131
|
+
if self.update_handler_argcount == 1:
|
|
132
|
+
coro = self.update_handler(update) # pyright: ignore[reportCallIssue]
|
|
133
|
+
else:
|
|
134
|
+
coro = self.update_handler(update, bot_token) # pyright: ignore[reportCallIssue]
|
|
135
|
+
|
|
136
|
+
task = asyncio.create_task(coro)
|
|
137
|
+
|
|
103
138
|
self.tasks.add(task)
|
|
104
139
|
task.add_done_callback(self._task_done_callback)
|
|
105
140
|
|
|
@@ -171,6 +206,7 @@ class RedisPubSubAsyncDispatcher:
|
|
|
171
206
|
task_to_cancel.cancel
|
|
172
207
|
)
|
|
173
208
|
|
|
209
|
+
@override
|
|
174
210
|
async def run_forever(self) -> None:
|
|
175
211
|
'''
|
|
176
212
|
Wait for incoming updates forever. This method **is blocking**.
|
|
@@ -10,7 +10,7 @@ from typing import TYPE_CHECKING, Union, Optional, Literal, List, Any
|
|
|
10
10
|
from . import enums
|
|
11
11
|
|
|
12
12
|
if TYPE_CHECKING:
|
|
13
|
-
from . import
|
|
13
|
+
from . import methods
|
|
14
14
|
|
|
15
15
|
class MaybeInaccessibleMessage(BaseModel, frozen=True):
|
|
16
16
|
message_id: int
|
|
@@ -127,15 +127,118 @@ class Message(MaybeInaccessibleMessage, frozen=True):
|
|
|
127
127
|
web_app_data: Optional[WebAppData] = Field(default=None)
|
|
128
128
|
reply_markup: Optional[InlineKeyboardMarkup] = Field(default=None)
|
|
129
129
|
|
|
130
|
-
async def delete(
|
|
130
|
+
async def delete(
|
|
131
|
+
self,
|
|
132
|
+
bot: methods.Bot
|
|
133
|
+
) -> bool:
|
|
134
|
+
'''
|
|
135
|
+
Deletes this message.
|
|
136
|
+
Shortcut for `bot.delete_message`.
|
|
137
|
+
'''
|
|
131
138
|
return await bot.delete_message(
|
|
132
139
|
chat_id=self.chat.id,
|
|
133
140
|
message_id=self.message_id
|
|
134
141
|
)
|
|
135
142
|
|
|
143
|
+
async def pin(
|
|
144
|
+
self,
|
|
145
|
+
bot: methods.Bot,
|
|
146
|
+
disable_notification: bool | None = None,
|
|
147
|
+
) -> bool:
|
|
148
|
+
'''
|
|
149
|
+
Pins this message in the chat.
|
|
150
|
+
Shortcut for `bot.pin_chat_message`.
|
|
151
|
+
'''
|
|
152
|
+
return await bot.pin_chat_message(
|
|
153
|
+
chat_id=self.chat.id,
|
|
154
|
+
message_id=self.message_id,
|
|
155
|
+
disable_notification=disable_notification
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
async def unpin(
|
|
159
|
+
self,
|
|
160
|
+
bot: methods.Bot
|
|
161
|
+
) -> bool:
|
|
162
|
+
'''
|
|
163
|
+
Unpins this message in the chat.
|
|
164
|
+
Shortcut for `bot.unpin_chat_message`.
|
|
165
|
+
'''
|
|
166
|
+
return await bot.unpin_chat_message(
|
|
167
|
+
chat_id=self.chat.id,
|
|
168
|
+
message_id=self.message_id
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
async def forward(
|
|
172
|
+
self,
|
|
173
|
+
bot: methods.Bot,
|
|
174
|
+
chat_id: int | str,
|
|
175
|
+
disable_notification: bool | None = None,
|
|
176
|
+
protect_content: bool | None = None,
|
|
177
|
+
message_thread_id: int | None = None,
|
|
178
|
+
direct_messages_topic_id: int | None = None,
|
|
179
|
+
video_start_timestamp: int | None = None,
|
|
180
|
+
# suggested_post_parameters: SuggestedPostParameters | None = None,
|
|
181
|
+
) -> Message:
|
|
182
|
+
'''
|
|
183
|
+
Forwards this message to another chat.
|
|
184
|
+
Shortcut for `bot.forward_message`.
|
|
185
|
+
'''
|
|
186
|
+
return await bot.forward_message(
|
|
187
|
+
chat_id=chat_id,
|
|
188
|
+
from_chat_id=self.chat.id,
|
|
189
|
+
message_id=self.message_id,
|
|
190
|
+
message_thread_id=message_thread_id,
|
|
191
|
+
direct_messages_topic_id=direct_messages_topic_id,
|
|
192
|
+
video_start_timestamp=video_start_timestamp,
|
|
193
|
+
disable_notification=disable_notification,
|
|
194
|
+
protect_content=protect_content,
|
|
195
|
+
# suggested_post_parameters=suggested_post_parameters
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
async def copy_to(
|
|
199
|
+
self,
|
|
200
|
+
bot: methods.Bot,
|
|
201
|
+
chat_id: int | str,
|
|
202
|
+
message_thread_id: int | None = None,
|
|
203
|
+
direct_messages_topic_id: int | None = None,
|
|
204
|
+
video_start_timestamp: int | None = None,
|
|
205
|
+
# caption: str | None = None,
|
|
206
|
+
# parse_mode: str | None = 'HTML',
|
|
207
|
+
# caption_entities: List[MessageEntity] | None = None,
|
|
208
|
+
# show_caption_above_media: bool | None = None,
|
|
209
|
+
disable_notification: bool | None = None,
|
|
210
|
+
protect_content: bool | None = None,
|
|
211
|
+
# allow_paid_broadcast: bool | None = None,
|
|
212
|
+
# suggested_post_parameters: SuggestedPostParameters | None = None,
|
|
213
|
+
# reply_parameters: ReplyParameters | None = None,
|
|
214
|
+
# reply_markup: InlineKeyboardMarkup | ReplyKeyboardMarkup | ReplyKeyboardRemove | ForceReply | None = None
|
|
215
|
+
) -> MessageId:
|
|
216
|
+
'''
|
|
217
|
+
Copies this message to another chat.
|
|
218
|
+
Shortcut for `bot.copy_message`.
|
|
219
|
+
'''
|
|
220
|
+
return await bot.copy_message(
|
|
221
|
+
chat_id=chat_id,
|
|
222
|
+
from_chat_id=self.chat.id,
|
|
223
|
+
message_id=self.message_id,
|
|
224
|
+
message_thread_id=message_thread_id,
|
|
225
|
+
direct_messages_topic_id=direct_messages_topic_id,
|
|
226
|
+
video_start_timestamp=video_start_timestamp,
|
|
227
|
+
# caption=caption,
|
|
228
|
+
# parse_mode=parse_mode,
|
|
229
|
+
# caption_entities=caption_entities,
|
|
230
|
+
# show_caption_above_media=show_caption_above_media,
|
|
231
|
+
disable_notification=disable_notification,
|
|
232
|
+
protect_content=protect_content,
|
|
233
|
+
# allow_paid_broadcast=allow_paid_broadcast,
|
|
234
|
+
# suggested_post_parameters=suggested_post_parameters,
|
|
235
|
+
# reply_parameters=reply_parameters,
|
|
236
|
+
# reply_markup=reply_markup
|
|
237
|
+
)
|
|
238
|
+
|
|
136
239
|
async def edit_text(
|
|
137
240
|
self,
|
|
138
|
-
bot:
|
|
241
|
+
bot: methods.Bot,
|
|
139
242
|
text: str,
|
|
140
243
|
# inline_message_id: Optional[str] = None,
|
|
141
244
|
parse_mode: str | None = 'HTML',
|
|
@@ -143,6 +246,11 @@ class Message(MaybeInaccessibleMessage, frozen=True):
|
|
|
143
246
|
link_preview_options: LinkPreviewOptions | None = None,
|
|
144
247
|
reply_markup: InlineKeyboardMarkup | None = None,
|
|
145
248
|
) -> Message | bool:
|
|
249
|
+
'''
|
|
250
|
+
Edits the text of this message.
|
|
251
|
+
Shortcut for `bot.edit_message_text`.
|
|
252
|
+
You can pass **either** `parse_mode` or `entities` to format the message text.
|
|
253
|
+
'''
|
|
146
254
|
return await bot.edit_message_text(
|
|
147
255
|
chat_id=self.chat.id,
|
|
148
256
|
message_id=self.message_id,
|
|
@@ -157,10 +265,14 @@ class Message(MaybeInaccessibleMessage, frozen=True):
|
|
|
157
265
|
|
|
158
266
|
async def edit_reply_markup(
|
|
159
267
|
self,
|
|
160
|
-
bot:
|
|
268
|
+
bot: methods.Bot,
|
|
161
269
|
# inline_message_id: Optional[str] = None,
|
|
162
270
|
reply_markup: InlineKeyboardMarkup | None = None,
|
|
163
271
|
) -> Message | bool:
|
|
272
|
+
'''
|
|
273
|
+
Edits the reply markup (inline keyboard) of this message.
|
|
274
|
+
Shortcut for `bot.edit_message_reply_markup`.
|
|
275
|
+
'''
|
|
164
276
|
return await bot.edit_message_reply_markup(
|
|
165
277
|
chat_id=self.chat.id,
|
|
166
278
|
message_id=self.message_id,
|
|
@@ -171,7 +283,7 @@ class Message(MaybeInaccessibleMessage, frozen=True):
|
|
|
171
283
|
|
|
172
284
|
async def reply_text(
|
|
173
285
|
self,
|
|
174
|
-
bot:
|
|
286
|
+
bot: methods.Bot,
|
|
175
287
|
text: str,
|
|
176
288
|
parse_mode: str | None = 'HTML',
|
|
177
289
|
entities: list[MessageEntity] | None = None,
|
|
@@ -194,7 +306,7 @@ class Message(MaybeInaccessibleMessage, frozen=True):
|
|
|
194
306
|
|
|
195
307
|
You can pass **either** `reply_to_original_message` or `reply_parameters` to reply
|
|
196
308
|
to this message. If both are passed, `reply_parameters` will be used.
|
|
197
|
-
|
|
309
|
+
|
|
198
310
|
'''
|
|
199
311
|
if not reply_parameters and reply_to_original_message:
|
|
200
312
|
reply_parameters = ReplyParameters(
|
|
@@ -2093,9 +2205,12 @@ class Update(BaseModel, frozen=True):
|
|
|
2093
2205
|
removed_chat_boost: Optional[ChatBoostRemoved] = Field(default=None)
|
|
2094
2206
|
|
|
2095
2207
|
@staticmethod
|
|
2096
|
-
def
|
|
2208
|
+
def from_dict(
|
|
2097
2209
|
json_data: dict[str, Any]
|
|
2098
2210
|
) -> Update:
|
|
2211
|
+
'''
|
|
2212
|
+
Converts a JSON dictionary to an `Update` object.
|
|
2213
|
+
'''
|
|
2099
2214
|
return Update.model_validate(json_data)
|
|
2100
2215
|
|
|
2101
2216
|
|
|
@@ -2237,6 +2352,9 @@ class MessageEntity(BaseModel, frozen=True):
|
|
|
2237
2352
|
def from_dict(
|
|
2238
2353
|
json_data: list[dict[str, Any]]
|
|
2239
2354
|
) -> list[MessageEntity]:
|
|
2355
|
+
'''
|
|
2356
|
+
Converts a list of JSON dictionaries to a list of `MessageEntity` objects.
|
|
2357
|
+
'''
|
|
2240
2358
|
return [MessageEntity.model_validate(item) for item in json_data]
|
|
2241
2359
|
|
|
2242
2360
|
|
|
@@ -3205,6 +3323,9 @@ class InlineKeyboardMarkup(BaseModel, frozen=True):
|
|
|
3205
3323
|
def from_dict(
|
|
3206
3324
|
json_data: list[list[dict[str, Any]]]
|
|
3207
3325
|
) -> InlineKeyboardMarkup:
|
|
3326
|
+
'''
|
|
3327
|
+
Converts a JSON dictionary to an `InlineKeyboardMarkup` object.
|
|
3328
|
+
'''
|
|
3208
3329
|
keyboard = [
|
|
3209
3330
|
[
|
|
3210
3331
|
InlineKeyboardButton(**button) for button in row
|
|
@@ -3407,8 +3528,11 @@ class ChatJoinRequest(BaseModel, frozen=True):
|
|
|
3407
3528
|
|
|
3408
3529
|
async def approve(
|
|
3409
3530
|
self,
|
|
3410
|
-
bot:
|
|
3531
|
+
bot: methods.Bot
|
|
3411
3532
|
) -> bool:
|
|
3533
|
+
'''
|
|
3534
|
+
Approves this chat join request.
|
|
3535
|
+
'''
|
|
3412
3536
|
return await bot.approve_chat_join_request(
|
|
3413
3537
|
chat_id=self.chat.id,
|
|
3414
3538
|
user_id=self.from_user.id
|
|
@@ -3416,8 +3540,11 @@ class ChatJoinRequest(BaseModel, frozen=True):
|
|
|
3416
3540
|
|
|
3417
3541
|
async def decline(
|
|
3418
3542
|
self,
|
|
3419
|
-
bot:
|
|
3543
|
+
bot: methods.Bot
|
|
3420
3544
|
) -> bool:
|
|
3545
|
+
'''
|
|
3546
|
+
Declines this chat join request.
|
|
3547
|
+
'''
|
|
3421
3548
|
return await bot.decline_chat_join_request(
|
|
3422
3549
|
chat_id=self.chat.id,
|
|
3423
3550
|
user_id=self.from_user.id
|
|
File without changes
|
|
File without changes
|
|
File without changes
|