Pytdbot 0.9.4__tar.gz → 0.9.5.dev0__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.
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/PKG-INFO +1 -1
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/Pytdbot.egg-info/PKG-INFO +1 -1
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/Pytdbot.egg-info/SOURCES.txt +3 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/__init__.py +1 -1
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/client.py +107 -12
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/handlers/decorators.py +45 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/types/__init__.py +4 -0
- pytdbot-0.9.5.dev0/pytdbot/types/tdserver/__init__.py +3 -0
- pytdbot-0.9.5.dev0/pytdbot/types/tdserver/schedule.py +96 -0
- pytdbot-0.9.5.dev0/pytdbot/types/tdserver/stats.py +65 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/utils/__init__.py +4 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/utils/text_format.py +44 -12
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/LICENSE +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/MANIFEST.in +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/Pytdbot.egg-info/dependency_links.txt +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/Pytdbot.egg-info/requires.txt +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/Pytdbot.egg-info/top_level.txt +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/README.md +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/client_manager.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/exception/__init__.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/filters.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/handlers/__init__.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/handlers/handler.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/handlers/td_updates.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/methods/__init__.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/methods/methods.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/methods/td_functions.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/tdjson/__init__.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/tdjson/tdjson.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/types/plugins/__init__.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/types/td_types/__init__.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/types/td_types/bound_methods/__init__.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/types/td_types/bound_methods/callback_query.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/types/td_types/bound_methods/chatActions.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/types/td_types/bound_methods/file.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/types/td_types/bound_methods/message.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/types/td_types/types.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/utils/asyncio_utils.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/utils/escape.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/utils/json_utils.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/utils/obj_encoder.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/utils/strings.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/pytdbot/utils/webapps.py +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/requirements.txt +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/setup.cfg +0 -0
- {pytdbot-0.9.4 → pytdbot-0.9.5.dev0}/setup.py +0 -0
|
@@ -31,6 +31,9 @@ pytdbot/types/td_types/bound_methods/callback_query.py
|
|
|
31
31
|
pytdbot/types/td_types/bound_methods/chatActions.py
|
|
32
32
|
pytdbot/types/td_types/bound_methods/file.py
|
|
33
33
|
pytdbot/types/td_types/bound_methods/message.py
|
|
34
|
+
pytdbot/types/tdserver/__init__.py
|
|
35
|
+
pytdbot/types/tdserver/schedule.py
|
|
36
|
+
pytdbot/types/tdserver/stats.py
|
|
34
37
|
pytdbot/utils/__init__.py
|
|
35
38
|
pytdbot/utils/asyncio_utils.py
|
|
36
39
|
pytdbot/utils/escape.py
|
|
@@ -102,6 +102,9 @@ class Client(Decorators, Methods):
|
|
|
102
102
|
|
|
103
103
|
td_log (:class:`~pytdbot.types.LogStream`, *optional*):
|
|
104
104
|
Log stream. Default is ``None`` (Log to ``stdout``)
|
|
105
|
+
|
|
106
|
+
user_bot (``bool``, *optional*):
|
|
107
|
+
Pass ``True`` if this is a user-bot. Default is ``False``
|
|
105
108
|
"""
|
|
106
109
|
|
|
107
110
|
def __init__(
|
|
@@ -183,6 +186,7 @@ class Client(Decorators, Methods):
|
|
|
183
186
|
self._current_handlers = {}
|
|
184
187
|
self._results: Dict[str, asyncio.Future] = {}
|
|
185
188
|
self._workers_tasks = None
|
|
189
|
+
self.__rabbitmq_iterator_task = None
|
|
186
190
|
self.__authorization_state = None
|
|
187
191
|
self.__cache = {"is_coro_filter": {}}
|
|
188
192
|
self.__local_handlers = {
|
|
@@ -226,17 +230,72 @@ class Client(Decorators, Methods):
|
|
|
226
230
|
|
|
227
231
|
return self.__authorization_state
|
|
228
232
|
|
|
233
|
+
async def getServerStats(
|
|
234
|
+
self,
|
|
235
|
+
) -> Union["pytdbot.types.ServerStats", "pytdbot.types.Error"]:
|
|
236
|
+
"""Returns TDLib Server stats"""
|
|
237
|
+
|
|
238
|
+
self._check_rabbitmq()
|
|
239
|
+
|
|
240
|
+
return await self.invoke({"@type": "getServerStats"})
|
|
241
|
+
|
|
242
|
+
async def scheduleEvent(
|
|
243
|
+
self, data: dict, send_at: int
|
|
244
|
+
) -> Union["pytdbot.types.ScheduledEvent", "pytdbot.types.Error"]:
|
|
245
|
+
"""Schedule an event
|
|
246
|
+
|
|
247
|
+
Parameters:
|
|
248
|
+
data (:class:`dict`):
|
|
249
|
+
The event data to be scheduled
|
|
250
|
+
|
|
251
|
+
send_at (:class:`int`):
|
|
252
|
+
Unix timestamp when the event should be sent
|
|
253
|
+
"""
|
|
254
|
+
|
|
255
|
+
self._check_rabbitmq()
|
|
256
|
+
|
|
257
|
+
if not isinstance(data, dict):
|
|
258
|
+
raise ValueError("data must be dict")
|
|
259
|
+
if not isinstance(send_at, (int, float)):
|
|
260
|
+
raise ValueError("send_at must be int")
|
|
261
|
+
|
|
262
|
+
return await self.invoke(
|
|
263
|
+
{"@type": "scheduleEvent", "data": data, "send_at": send_at}
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
async def cancelScheduledEvent(
|
|
267
|
+
self, event_id: str
|
|
268
|
+
) -> Union["pytdbot.types.Ok", "pytdbot.types.Error"]:
|
|
269
|
+
"""Cancel a scheduled event
|
|
270
|
+
|
|
271
|
+
Parameters:
|
|
272
|
+
event_id (:class:`str`):
|
|
273
|
+
Event ID to cancel
|
|
274
|
+
"""
|
|
275
|
+
|
|
276
|
+
self._check_rabbitmq()
|
|
277
|
+
|
|
278
|
+
if not isinstance(event_id, str):
|
|
279
|
+
raise ValueError("event_id must be str")
|
|
280
|
+
|
|
281
|
+
return await self.invoke(
|
|
282
|
+
{"@type": "cancelScheduledEvent", "event_id": event_id}
|
|
283
|
+
)
|
|
284
|
+
|
|
229
285
|
async def start(self) -> None:
|
|
230
286
|
r"""Start pytdbot client"""
|
|
231
287
|
|
|
232
288
|
if not self.is_running:
|
|
233
289
|
self.logger.info("Starting pytdbot client...")
|
|
234
290
|
|
|
235
|
-
if
|
|
291
|
+
if self.is_rabbitmq:
|
|
292
|
+
await self.__start_rabbitmq()
|
|
293
|
+
elif not self.client_manager:
|
|
236
294
|
self.client_manager = ClientManager(
|
|
237
295
|
self, self.lib_path, self.td_verbosity, loop=self.loop
|
|
238
296
|
)
|
|
239
297
|
await self.client_manager.start()
|
|
298
|
+
self.is_running = True
|
|
240
299
|
|
|
241
300
|
if isinstance(self.td_log, LogStream) and not self.is_rabbitmq:
|
|
242
301
|
await self.__send(
|
|
@@ -245,21 +304,22 @@ class Client(Decorators, Methods):
|
|
|
245
304
|
|
|
246
305
|
if isinstance(self.workers, int):
|
|
247
306
|
self._workers_tasks = [
|
|
248
|
-
self.loop.create_task(
|
|
307
|
+
self.loop.create_task(
|
|
308
|
+
self._queue_update_worker()
|
|
309
|
+
if not self.is_rabbitmq
|
|
310
|
+
else self.__rabbitmq_worker()
|
|
311
|
+
)
|
|
249
312
|
for _ in range(self.workers)
|
|
250
313
|
]
|
|
251
314
|
self.__is_queue_worker = True
|
|
252
315
|
|
|
253
316
|
self.logger.info(f"Started with {self.workers} workers")
|
|
317
|
+
elif self.is_rabbitmq:
|
|
318
|
+
raise ValueError("workers must be an int when using TDLib Server")
|
|
254
319
|
else:
|
|
255
320
|
self.__is_queue_worker = False
|
|
256
321
|
self.logger.info("Started with unlimited updates processes")
|
|
257
322
|
|
|
258
|
-
if self.is_rabbitmq:
|
|
259
|
-
await self.__start_rabbitmq()
|
|
260
|
-
else: # client_manager
|
|
261
|
-
self.is_running = True
|
|
262
|
-
|
|
263
323
|
self.loop.create_task(
|
|
264
324
|
self.getOption("version")
|
|
265
325
|
) # Ping TDLib to start processing updates
|
|
@@ -535,7 +595,7 @@ class Client(Decorators, Methods):
|
|
|
535
595
|
|
|
536
596
|
self.__stop_client()
|
|
537
597
|
|
|
538
|
-
if not self.client_manager.start_clients_on_add:
|
|
598
|
+
if self.client_manager and not self.client_manager.start_clients_on_add:
|
|
539
599
|
await self.client_manager.close()
|
|
540
600
|
|
|
541
601
|
self.logger.info("Instance closed")
|
|
@@ -567,6 +627,9 @@ class Client(Decorators, Methods):
|
|
|
567
627
|
else:
|
|
568
628
|
self.client_manager.send(self.client_id, request)
|
|
569
629
|
|
|
630
|
+
def _check_rabbitmq(self):
|
|
631
|
+
assert self.is_rabbitmq, "This method is only available for TDLib Server"
|
|
632
|
+
|
|
570
633
|
def _check_init_args(self):
|
|
571
634
|
if self.user_bot:
|
|
572
635
|
return
|
|
@@ -696,7 +759,7 @@ class Client(Decorators, Methods):
|
|
|
696
759
|
if update_handler:
|
|
697
760
|
self.loop.create_task(update_handler(update))
|
|
698
761
|
|
|
699
|
-
if self.__is_queue_worker:
|
|
762
|
+
if not self.is_rabbitmq and self.__is_queue_worker:
|
|
700
763
|
self.queue.put_nowait(update)
|
|
701
764
|
else:
|
|
702
765
|
await self._handle_update(update)
|
|
@@ -884,7 +947,9 @@ class Client(Decorators, Methods):
|
|
|
884
947
|
f"{str(self.me.id) if not self.me.usernames else '@' + self.me.usernames.editable_username}"
|
|
885
948
|
)
|
|
886
949
|
|
|
887
|
-
if
|
|
950
|
+
if self.authorization_state == "authorizationStateClosing":
|
|
951
|
+
self.__is_closing = True
|
|
952
|
+
elif (
|
|
888
953
|
self.authorization_state == "authorizationStateClosed"
|
|
889
954
|
and self.__is_closing is False
|
|
890
955
|
):
|
|
@@ -955,6 +1020,8 @@ class Client(Decorators, Methods):
|
|
|
955
1020
|
)
|
|
956
1021
|
self.__rchannel = await self.__rconnection.channel()
|
|
957
1022
|
|
|
1023
|
+
self.logger.info("Connected to TDLib server via RabbitMQ")
|
|
1024
|
+
|
|
958
1025
|
updates_queue = await self.__get_updates_queue()
|
|
959
1026
|
|
|
960
1027
|
notify_queue = await self.__rchannel.declare_queue(
|
|
@@ -968,7 +1035,7 @@ class Client(Decorators, Methods):
|
|
|
968
1035
|
|
|
969
1036
|
self.__rqueues = {
|
|
970
1037
|
"updates": updates_queue,
|
|
971
|
-
"requests": await self.__rchannel.get_queue(self.my_id
|
|
1038
|
+
"requests": await self.__rchannel.get_queue(f"{self.my_id}_requests"),
|
|
972
1039
|
"notify": notify_queue,
|
|
973
1040
|
"responses": responses_queue,
|
|
974
1041
|
}
|
|
@@ -986,10 +1053,35 @@ class Client(Decorators, Methods):
|
|
|
986
1053
|
await self.process_update(obj_to_dict(update))
|
|
987
1054
|
|
|
988
1055
|
if not self.no_updates:
|
|
989
|
-
|
|
1056
|
+
self.__rabbitmq_iterator_task = self.loop.create_task(
|
|
1057
|
+
self.__rabbitmq_iterator()
|
|
1058
|
+
)
|
|
990
1059
|
|
|
991
1060
|
await self.__rqueues["notify"].consume(self.__on_update, no_ack=True)
|
|
992
1061
|
|
|
1062
|
+
async def __rabbitmq_iterator(self):
|
|
1063
|
+
async with self.__rqueues["updates"].iterator() as iterator:
|
|
1064
|
+
async for message in iterator:
|
|
1065
|
+
await self.queue.put(message)
|
|
1066
|
+
|
|
1067
|
+
async def __rabbitmq_worker(self):
|
|
1068
|
+
while self.is_running:
|
|
1069
|
+
message: aio_pika.IncomingMessage = await self.queue.get()
|
|
1070
|
+
|
|
1071
|
+
try:
|
|
1072
|
+
update = json_loads(message.body)
|
|
1073
|
+
if self.__is_closing and not isinstance(
|
|
1074
|
+
update, types.UpdateAuthorizationState
|
|
1075
|
+
):
|
|
1076
|
+
await message.nack(requeue=True)
|
|
1077
|
+
continue
|
|
1078
|
+
|
|
1079
|
+
await self.process_update(update)
|
|
1080
|
+
except Exception:
|
|
1081
|
+
self.logger.exception("Error processing message")
|
|
1082
|
+
|
|
1083
|
+
await message.ack() # ack after processing
|
|
1084
|
+
|
|
993
1085
|
async def __handle_rabbitmq_message(self, message: aio_pika.IncomingMessage):
|
|
994
1086
|
await self.process_update(json_loads(message.body))
|
|
995
1087
|
|
|
@@ -1026,6 +1118,9 @@ class Client(Decorators, Methods):
|
|
|
1026
1118
|
self.is_authenticated = False
|
|
1027
1119
|
self.is_running = False
|
|
1028
1120
|
|
|
1121
|
+
if self.__rabbitmq_iterator_task:
|
|
1122
|
+
self.__rabbitmq_iterator_task.cancel()
|
|
1123
|
+
|
|
1029
1124
|
if self.__is_queue_worker:
|
|
1030
1125
|
for worker_task in self._workers_tasks:
|
|
1031
1126
|
worker_task.cancel()
|
|
@@ -134,3 +134,48 @@ class Decorators(Updates):
|
|
|
134
134
|
return func
|
|
135
135
|
|
|
136
136
|
return decorator
|
|
137
|
+
|
|
138
|
+
def on_updateScheduledEvent(
|
|
139
|
+
self: "pytdbot.Client" = None,
|
|
140
|
+
filters: "pytdbot.filters.Filter" = None,
|
|
141
|
+
position: int = None,
|
|
142
|
+
inner_object: bool = False,
|
|
143
|
+
) -> None:
|
|
144
|
+
r"""A scheduled event has been triggered
|
|
145
|
+
|
|
146
|
+
Parameters:
|
|
147
|
+
filters (:class:`~pytdbot.filters.Filter`, *optional*):
|
|
148
|
+
An update filter
|
|
149
|
+
|
|
150
|
+
position (``int``, *optional*):
|
|
151
|
+
The function position in handlers list. Default is ``None`` (append)
|
|
152
|
+
|
|
153
|
+
inner_object (``bool``, *optional*):
|
|
154
|
+
Wether to pass an inner object of update or not; for example ``UpdateNewMessage.message``. Default is ``False``
|
|
155
|
+
|
|
156
|
+
Raises:
|
|
157
|
+
:py:class:`TypeError`
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
def decorator(func: Callable) -> Callable:
|
|
161
|
+
if hasattr(func, "_handler"):
|
|
162
|
+
return func
|
|
163
|
+
elif isinstance(self, pytdbot.Client):
|
|
164
|
+
if iscoroutinefunction(func):
|
|
165
|
+
self.add_handler(
|
|
166
|
+
"updateScheduledEvent", func, filters, position, inner_object
|
|
167
|
+
)
|
|
168
|
+
else:
|
|
169
|
+
raise TypeError("Handler must be async")
|
|
170
|
+
elif isinstance(self, pytdbot.filters.Filter):
|
|
171
|
+
func._handler = Handler(
|
|
172
|
+
func, "updateScheduledEvent", self, position, inner_object
|
|
173
|
+
)
|
|
174
|
+
else:
|
|
175
|
+
func._handler = Handler(
|
|
176
|
+
func, "updateScheduledEvent", filters, position, inner_object
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
return func
|
|
180
|
+
|
|
181
|
+
return decorator
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
__all__ = [
|
|
2
2
|
"TlObject",
|
|
3
3
|
"Plugins",
|
|
4
|
+
"ServerStats",
|
|
5
|
+
"ScheduledEvent",
|
|
6
|
+
"UpdateScheduledEvent",
|
|
4
7
|
"AuthenticationCodeType",
|
|
5
8
|
"EmailAddressAuthentication",
|
|
6
9
|
"EmailAddressResetState",
|
|
@@ -3901,5 +3904,6 @@ from .td_types import (
|
|
|
3901
3904
|
Updates,
|
|
3902
3905
|
)
|
|
3903
3906
|
from .plugins import Plugins
|
|
3907
|
+
from .tdserver import ServerStats, ScheduledEvent, UpdateScheduledEvent
|
|
3904
3908
|
|
|
3905
3909
|
TDLIB_VERSION = "1.8.50"
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import pytdbot
|
|
2
|
+
from typing import Literal, Union
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ScheduledEvent:
|
|
6
|
+
r"""Describes a scheduled event
|
|
7
|
+
|
|
8
|
+
Parameters:
|
|
9
|
+
event_id (:class:`str`):
|
|
10
|
+
Unique identifier of the scheduled event
|
|
11
|
+
|
|
12
|
+
send_at (:class:`int`):
|
|
13
|
+
Point in time \(Unix timestamp\) when the scheduled event will be sent
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
event_id: str = "",
|
|
19
|
+
send_at: int = 0,
|
|
20
|
+
) -> None:
|
|
21
|
+
self.event_id = event_id
|
|
22
|
+
r"""Unique identifier of the scheduled event"""
|
|
23
|
+
self.send_at = send_at
|
|
24
|
+
r"""Point in time \(Unix timestamp\) when the scheduled event will be sent"""
|
|
25
|
+
|
|
26
|
+
def __str__(self):
|
|
27
|
+
return str(pytdbot.utils.obj_to_json(self, indent=4))
|
|
28
|
+
|
|
29
|
+
def getType(self) -> Literal["scheduledEvent"]:
|
|
30
|
+
return "scheduledEvent"
|
|
31
|
+
|
|
32
|
+
def getClass(self) -> Literal["ScheduledEvent"]:
|
|
33
|
+
return "ScheduledEvent"
|
|
34
|
+
|
|
35
|
+
def to_dict(self) -> dict:
|
|
36
|
+
return {
|
|
37
|
+
"@type": self.getType(),
|
|
38
|
+
"event_id": self.event_id,
|
|
39
|
+
"send_at": self.send_at,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def from_dict(cls, data: dict) -> Union["ScheduledEvent", None]:
|
|
44
|
+
if data:
|
|
45
|
+
data_class = cls()
|
|
46
|
+
data_class.event_id = data.get("event_id", None)
|
|
47
|
+
data_class.send_at = data.get("send_at", None)
|
|
48
|
+
|
|
49
|
+
return data_class
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class UpdateScheduledEvent:
|
|
53
|
+
r"""A scheduled event
|
|
54
|
+
|
|
55
|
+
Parameters:
|
|
56
|
+
event_id (:class:`str`):
|
|
57
|
+
Unique identifier of the scheduled event
|
|
58
|
+
|
|
59
|
+
data (:class:`dict`):
|
|
60
|
+
Event data
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def __init__(
|
|
64
|
+
self,
|
|
65
|
+
event_id: str = "",
|
|
66
|
+
data: dict = None,
|
|
67
|
+
) -> None:
|
|
68
|
+
self.event_id = event_id
|
|
69
|
+
r"""Unique identifier of the scheduled event"""
|
|
70
|
+
self.data = data
|
|
71
|
+
r"""Event data"""
|
|
72
|
+
|
|
73
|
+
def __str__(self):
|
|
74
|
+
return str(pytdbot.utils.obj_to_json(self, indent=4))
|
|
75
|
+
|
|
76
|
+
def getType(self) -> Literal["updateScheduledEvent"]:
|
|
77
|
+
return "updateScheduledEvent"
|
|
78
|
+
|
|
79
|
+
def getClass(self) -> Literal["UpdateScheduledEvent"]:
|
|
80
|
+
return "UpdateScheduledEvent"
|
|
81
|
+
|
|
82
|
+
def to_dict(self) -> dict:
|
|
83
|
+
return {
|
|
84
|
+
"@type": self.getType(),
|
|
85
|
+
"event_id": self.event_id,
|
|
86
|
+
"data": self.data,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@classmethod
|
|
90
|
+
def from_dict(cls, data: dict) -> Union["UpdateScheduledEvent", None]:
|
|
91
|
+
if data:
|
|
92
|
+
data_class = cls()
|
|
93
|
+
data_class.event_id = data.get("event_id", None)
|
|
94
|
+
data_class.data = data.get("data", None)
|
|
95
|
+
|
|
96
|
+
return data_class
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import pytdbot
|
|
2
|
+
from typing import Literal, Union
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ServerStats:
|
|
6
|
+
r"""Describes TDLib Server stats
|
|
7
|
+
|
|
8
|
+
Parameters:
|
|
9
|
+
my_id (:class:`int`):
|
|
10
|
+
Identifier of the current user
|
|
11
|
+
|
|
12
|
+
uptime (:class:`int`):
|
|
13
|
+
Server uptime in seconds
|
|
14
|
+
|
|
15
|
+
updates_count (:class:`int`):
|
|
16
|
+
Total number of received updates
|
|
17
|
+
|
|
18
|
+
requests_count (:class:`int`):
|
|
19
|
+
Total number of sent requests
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
my_id: int = 0,
|
|
25
|
+
uptime: int = 0,
|
|
26
|
+
updates_count: int = 0,
|
|
27
|
+
requests_count: int = 0,
|
|
28
|
+
) -> None:
|
|
29
|
+
self.my_id = my_id
|
|
30
|
+
r"""Identifier of the current user"""
|
|
31
|
+
self.uptime = uptime
|
|
32
|
+
r"""Server uptime in seconds"""
|
|
33
|
+
self.updates_count = updates_count
|
|
34
|
+
r"""Total number of received updates"""
|
|
35
|
+
self.requests_count = requests_count
|
|
36
|
+
r"""Total number of sent requests"""
|
|
37
|
+
|
|
38
|
+
def __str__(self):
|
|
39
|
+
return str(pytdbot.utils.obj_to_json(self, indent=4))
|
|
40
|
+
|
|
41
|
+
def getType(self) -> Literal["serverStats"]:
|
|
42
|
+
return "serverStats"
|
|
43
|
+
|
|
44
|
+
def getClass(self) -> Literal["ServerStats"]:
|
|
45
|
+
return "ServerStats"
|
|
46
|
+
|
|
47
|
+
def to_dict(self) -> dict:
|
|
48
|
+
return {
|
|
49
|
+
"@type": self.getType(),
|
|
50
|
+
"my_id": self.my_id,
|
|
51
|
+
"uptime": self.uptime,
|
|
52
|
+
"updates_count": self.updates_count,
|
|
53
|
+
"requests_count": self.requests_count,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def from_dict(cls, data: dict) -> Union["ServerStats", None]:
|
|
58
|
+
if data:
|
|
59
|
+
data_class = cls()
|
|
60
|
+
data_class.my_id = data.get("my_id", None)
|
|
61
|
+
data_class.uptime = data.get("uptime", None)
|
|
62
|
+
data_class.updates_count = data.get("updates_count", None)
|
|
63
|
+
data_class.requests_count = data.get("requests_count", None)
|
|
64
|
+
|
|
65
|
+
return data_class
|
|
@@ -15,7 +15,7 @@ def bold(text: str, html: bool = True, escape: bool = True) -> str:
|
|
|
15
15
|
Whether escape special characters to the given text or not. Default is ``True``
|
|
16
16
|
|
|
17
17
|
Returns:
|
|
18
|
-
py:class:`str`: The formated text
|
|
18
|
+
:py:class:`str`: The formated text
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
21
|
if html:
|
|
@@ -38,7 +38,7 @@ def italic(text: str, html: bool = True, escape: bool = True) -> str:
|
|
|
38
38
|
Whether escape special characters to the given text or not. Default is ``True``
|
|
39
39
|
|
|
40
40
|
Returns:
|
|
41
|
-
py:class:`str`: The formated text
|
|
41
|
+
:py:class:`str`: The formated text
|
|
42
42
|
"""
|
|
43
43
|
|
|
44
44
|
if html:
|
|
@@ -61,7 +61,7 @@ def underline(text: str, html: bool = True, escape: bool = True) -> str:
|
|
|
61
61
|
Whether escape special characters to the given text or not. Default is ``True``
|
|
62
62
|
|
|
63
63
|
Returns:
|
|
64
|
-
py:class:`str`: The formated text
|
|
64
|
+
:py:class:`str`: The formated text
|
|
65
65
|
"""
|
|
66
66
|
|
|
67
67
|
if html:
|
|
@@ -84,7 +84,7 @@ def strikethrough(text: str, html: bool = True, escape: bool = True) -> str:
|
|
|
84
84
|
Whether escape special characters to the given text or not. Default is ``True``
|
|
85
85
|
|
|
86
86
|
Returns:
|
|
87
|
-
py:class:`str`: The formated text
|
|
87
|
+
:py:class:`str`: The formated text
|
|
88
88
|
"""
|
|
89
89
|
|
|
90
90
|
if html:
|
|
@@ -107,7 +107,7 @@ def spoiler(text: str, html: bool = True, escape: bool = True) -> str:
|
|
|
107
107
|
Whether escape special characters to the given text or not. Default is ``True``
|
|
108
108
|
|
|
109
109
|
Returns:
|
|
110
|
-
py:class:`str`: The formated text
|
|
110
|
+
:py:class:`str`: The formated text
|
|
111
111
|
"""
|
|
112
112
|
|
|
113
113
|
if html:
|
|
@@ -133,7 +133,7 @@ def hyperlink(text: str, url: str, html: bool = True, escape: bool = True) -> st
|
|
|
133
133
|
Whether escape special characters to the given text or not. Default is ``True``
|
|
134
134
|
|
|
135
135
|
Returns:
|
|
136
|
-
py:class:`str`: The formated text
|
|
136
|
+
:py:class:`str`: The formated text
|
|
137
137
|
"""
|
|
138
138
|
|
|
139
139
|
assert isinstance(url, str), "url must be str"
|
|
@@ -163,7 +163,7 @@ def mention(text: str, user_id: str, html: bool = True, escape: bool = True) ->
|
|
|
163
163
|
Whether escape special characters to the given text or not. Default is ``True``
|
|
164
164
|
|
|
165
165
|
Returns:
|
|
166
|
-
py:class:`str`: The formated text
|
|
166
|
+
:py:class:`str`: The formated text
|
|
167
167
|
"""
|
|
168
168
|
|
|
169
169
|
if html:
|
|
@@ -186,7 +186,7 @@ def custom_emoji(emoji: str, custom_emoji_id: int, html: bool = True) -> str:
|
|
|
186
186
|
If ``True``, returns HTML format, if ``False`` returns MarkdownV2. Default is ``True``
|
|
187
187
|
|
|
188
188
|
Returns:
|
|
189
|
-
py:class:`str`: The formated text
|
|
189
|
+
:py:class:`str`: The formated text
|
|
190
190
|
"""
|
|
191
191
|
|
|
192
192
|
if html:
|
|
@@ -209,7 +209,7 @@ def code(text: str, html: bool = True, escape: bool = True) -> str:
|
|
|
209
209
|
Whether escape special characters to the given text or not. Default is ``True``
|
|
210
210
|
|
|
211
211
|
Returns:
|
|
212
|
-
py:class:`str`: The formated text
|
|
212
|
+
:py:class:`str`: The formated text
|
|
213
213
|
"""
|
|
214
214
|
|
|
215
215
|
if html:
|
|
@@ -232,7 +232,7 @@ def pre(text: str, html: bool = True, escape: bool = True) -> str:
|
|
|
232
232
|
Whether escape special characters to the given text or not. Default is ``True``
|
|
233
233
|
|
|
234
234
|
Returns:
|
|
235
|
-
py:class:`str`: The formated text
|
|
235
|
+
:py:class:`str`: The formated text
|
|
236
236
|
"""
|
|
237
237
|
|
|
238
238
|
if html:
|
|
@@ -258,7 +258,7 @@ def pre_code(text: str, language: str, html: bool = True, escape: bool = True) -
|
|
|
258
258
|
Whether escape special characters to the given text or not. Default is ``True``
|
|
259
259
|
|
|
260
260
|
Returns:
|
|
261
|
-
py:class:`str`: The formated text
|
|
261
|
+
:py:class:`str`: The formated text
|
|
262
262
|
"""
|
|
263
263
|
|
|
264
264
|
assert isinstance(language, str), "text must be str"
|
|
@@ -288,10 +288,42 @@ def quote(text: str, expandable: bool = False, html: bool = True, escape: bool =
|
|
|
288
288
|
Whether escape special characters to the given text or not. Default is ``True``
|
|
289
289
|
|
|
290
290
|
Returns:
|
|
291
|
-
py:class:`str`: The formated text
|
|
291
|
+
:py:class:`str`: The formated text
|
|
292
292
|
"""
|
|
293
293
|
|
|
294
294
|
if html:
|
|
295
295
|
return f"<blockquote{' expandable' if expandable else ''}>{text if escape is False else escape_html(str(text))}</blockquote>"
|
|
296
296
|
|
|
297
297
|
return f"{'**' if expandable else ''}>{text if escape is False else escape_markdown(str(text))}"
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
rtl_mark = "\u200f"
|
|
301
|
+
ltr_mark = "\u200e"
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def rtl(text: str) -> str:
|
|
305
|
+
r"""Add RTL (Right-to-Left) mark to the given text
|
|
306
|
+
|
|
307
|
+
Parameters:
|
|
308
|
+
text (``str``):
|
|
309
|
+
The text to convert
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
:py:class:`str`: The formated text
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
return f"{rtl_mark}{text}"
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def ltr(text: str) -> str:
|
|
319
|
+
r"""Add LTR (Left-to-Right) mark to the given text
|
|
320
|
+
|
|
321
|
+
Parameters:
|
|
322
|
+
text (``str``):
|
|
323
|
+
The text to convert
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
:py:class:`str`: The formated text
|
|
327
|
+
"""
|
|
328
|
+
|
|
329
|
+
return f"{ltr_mark}{text}"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|