Pytdbot 0.9.0.dev6__tar.gz → 0.9.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.
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/LICENSE +1 -1
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/PKG-INFO +45 -17
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/Pytdbot.egg-info/PKG-INFO +45 -17
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/Pytdbot.egg-info/requires.txt +3 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/README.md +27 -13
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/__init__.py +2 -2
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/client.py +49 -81
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/handlers/td_updates.py +89 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/methods/methods.py +0 -65
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/methods/td_functions.py +413 -122
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/tdjson/tdjson.py +59 -36
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/types/__init__.py +69 -9
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/types/td_types/bound_methods/callback_query.py +1 -1
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/types/td_types/bound_methods/message.py +8 -21
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/types/td_types/types.py +1853 -208
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/utils/__init__.py +9 -1
- pytdbot-0.9.1/pytdbot/utils/json_utils.py +27 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/utils/strings.py +19 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/setup.py +4 -1
- pytdbot-0.9.0.dev6/pytdbot/utils/json_utils.py +0 -23
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/MANIFEST.in +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/Pytdbot.egg-info/SOURCES.txt +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/Pytdbot.egg-info/dependency_links.txt +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/Pytdbot.egg-info/top_level.txt +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/exception/__init__.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/filters.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/handlers/__init__.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/handlers/decorators.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/handlers/handler.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/methods/__init__.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/tdjson/__init__.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/types/plugins/__init__.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/types/td_types/__init__.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/types/td_types/bound_methods/__init__.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/types/td_types/bound_methods/chatActions.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/types/td_types/bound_methods/file.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/utils/escape.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/utils/obj_encoder.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/utils/text_format.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/pytdbot/utils/webapps.py +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/requirements.txt +0 -0
- {pytdbot-0.9.0.dev6 → pytdbot-0.9.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: Pytdbot
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.1
|
|
4
4
|
Summary: Easy-to-use asynchronous TDLib wrapper for Python.
|
|
5
5
|
Home-page: https://github.com/pytdbot/client
|
|
6
6
|
Author: AYMEN Mohammed
|
|
@@ -14,14 +14,28 @@ Description-Content-Type: text/markdown
|
|
|
14
14
|
License-File: LICENSE
|
|
15
15
|
Requires-Dist: deepdiff
|
|
16
16
|
Requires-Dist: aio-pika
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
Provides-Extra: tdjson
|
|
18
|
+
Requires-Dist: tdjson; extra == "tdjson"
|
|
19
|
+
Dynamic: author
|
|
20
|
+
Dynamic: author-email
|
|
21
|
+
Dynamic: description
|
|
22
|
+
Dynamic: description-content-type
|
|
23
|
+
Dynamic: home-page
|
|
24
|
+
Dynamic: keywords
|
|
25
|
+
Dynamic: license
|
|
26
|
+
Dynamic: project-url
|
|
27
|
+
Dynamic: provides-extra
|
|
28
|
+
Dynamic: requires-dist
|
|
29
|
+
Dynamic: requires-python
|
|
30
|
+
Dynamic: summary
|
|
31
|
+
|
|
32
|
+
# Pytdbot [](https://pypi.org/project/Pytdbot) [](https://github.com/tdlib/td) [](https://pepy.tech/project/pytdbot)
|
|
33
|
+
|
|
34
|
+
Pytdbot (Python TDLib) is an asynchronous [**TDLib**](https://github.com/tdlib/td) wrapper for **Telegram** users/bots written in **Python**.
|
|
21
35
|
|
|
22
36
|
### Features
|
|
23
37
|
|
|
24
|
-
|
|
38
|
+
`Pytdbot` offers numerous advantages, including:
|
|
25
39
|
|
|
26
40
|
- **Easy to Use**: Designed with simplicity in mind, making it accessible for developers
|
|
27
41
|
- **Performance**: Fast and powerful, making it ready to fight
|
|
@@ -32,30 +46,42 @@ Pytdbot (Python TDLib) is an asynchronous [**TDLib**](https://github.com/tdlib/t
|
|
|
32
46
|
- **Bound Methods**: Features types bound methods for improved usability
|
|
33
47
|
- **Unlimited Support**: Supports **Plugins**, [**filters**](pytdbot/filters.py#L23), [**TDLib**](https://github.com/tdlib/td) types/functions and much more
|
|
34
48
|
|
|
35
|
-
|
|
36
|
-
|
|
37
49
|
### Requirements
|
|
38
50
|
|
|
39
51
|
- Python 3.9+
|
|
40
52
|
- Telegram [API key](https://my.telegram.org/apps)
|
|
41
|
-
- [tdjson](https://github.com/tdlib/td#building)
|
|
53
|
+
- [tdjson](https://github.com/AYMENJD/tdjson) or [TDLib](https://github.com/tdlib/td#building)
|
|
42
54
|
- [deepdiff](https://github.com/seperman/deepdiff)
|
|
43
55
|
- [aio-pika](https://github.com/mosquito/aio-pika)
|
|
44
56
|
|
|
45
57
|
### Installation
|
|
58
|
+
|
|
46
59
|
> For better performance, it's recommended to install [orjson](https://github.com/ijl/orjson#install) or [ujson](https://github.com/ultrajson/ultrajson#ultrajson).
|
|
47
60
|
|
|
48
|
-
You can install Pytdbot using pip:
|
|
61
|
+
You can install Pytdbot with TDLib included using pip:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install --upgrade pytdbot[tdjson]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
If the installation fails, then install without **pre-built** TDLib:
|
|
68
|
+
|
|
49
69
|
```bash
|
|
50
70
|
pip install pytdbot
|
|
51
71
|
```
|
|
52
|
-
|
|
72
|
+
|
|
73
|
+
Then you need to build TDLib from [source](https://github.com/tdlib/td#building) and pass it to `Client.lib_path`.
|
|
74
|
+
|
|
75
|
+
You could also install the development version using the following command:
|
|
76
|
+
|
|
53
77
|
```bash
|
|
54
|
-
pip install
|
|
78
|
+
pip install --pre pytdbot
|
|
55
79
|
```
|
|
56
80
|
|
|
57
81
|
### Examples
|
|
82
|
+
|
|
58
83
|
Basic example:
|
|
84
|
+
|
|
59
85
|
```python
|
|
60
86
|
|
|
61
87
|
import asyncio
|
|
@@ -63,10 +89,9 @@ import asyncio
|
|
|
63
89
|
from pytdbot import Client, types
|
|
64
90
|
|
|
65
91
|
client = Client(
|
|
66
|
-
token="1088394097:AAQX2DnWiw4ihwiJUhIHOGog8gGOI", # Your bot token
|
|
67
|
-
api_id=0,
|
|
68
|
-
api_hash="API_HASH",
|
|
69
|
-
lib_path="/path/to/libtdjson.so", # Path to TDjson shared library
|
|
92
|
+
token="1088394097:AAQX2DnWiw4ihwiJUhIHOGog8gGOI", # Your bot token
|
|
93
|
+
api_id=0,
|
|
94
|
+
api_hash="API_HASH",
|
|
70
95
|
files_directory="BotDB", # Path where to store TDLib files
|
|
71
96
|
database_encryption_key="1234echobot$",
|
|
72
97
|
td_verbosity=2, # TDLib verbosity level
|
|
@@ -94,12 +119,15 @@ async def say_hello(c: Client, message: types.Message):
|
|
|
94
119
|
client.run()
|
|
95
120
|
|
|
96
121
|
```
|
|
122
|
+
|
|
97
123
|
For more examples, check the [examples](https://github.com/pytdbot/client/tree/main/examples) folder.
|
|
98
124
|
|
|
99
125
|
# Thanks to
|
|
126
|
+
|
|
100
127
|
- You for viewing or using this project.
|
|
101
128
|
|
|
102
129
|
- [@levlam](https://github.com/levlam) for maintaining [TDLib](https://github.com/tdlib/td) and for the help to create [Pytdbot](https://github.com/pytdbot/client).
|
|
130
|
+
|
|
103
131
|
# License
|
|
104
132
|
|
|
105
133
|
MIT [License](https://github.com/pytdbot/client/blob/main/LICENSE)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: Pytdbot
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.1
|
|
4
4
|
Summary: Easy-to-use asynchronous TDLib wrapper for Python.
|
|
5
5
|
Home-page: https://github.com/pytdbot/client
|
|
6
6
|
Author: AYMEN Mohammed
|
|
@@ -14,14 +14,28 @@ Description-Content-Type: text/markdown
|
|
|
14
14
|
License-File: LICENSE
|
|
15
15
|
Requires-Dist: deepdiff
|
|
16
16
|
Requires-Dist: aio-pika
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
Provides-Extra: tdjson
|
|
18
|
+
Requires-Dist: tdjson; extra == "tdjson"
|
|
19
|
+
Dynamic: author
|
|
20
|
+
Dynamic: author-email
|
|
21
|
+
Dynamic: description
|
|
22
|
+
Dynamic: description-content-type
|
|
23
|
+
Dynamic: home-page
|
|
24
|
+
Dynamic: keywords
|
|
25
|
+
Dynamic: license
|
|
26
|
+
Dynamic: project-url
|
|
27
|
+
Dynamic: provides-extra
|
|
28
|
+
Dynamic: requires-dist
|
|
29
|
+
Dynamic: requires-python
|
|
30
|
+
Dynamic: summary
|
|
31
|
+
|
|
32
|
+
# Pytdbot [](https://pypi.org/project/Pytdbot) [](https://github.com/tdlib/td) [](https://pepy.tech/project/pytdbot)
|
|
33
|
+
|
|
34
|
+
Pytdbot (Python TDLib) is an asynchronous [**TDLib**](https://github.com/tdlib/td) wrapper for **Telegram** users/bots written in **Python**.
|
|
21
35
|
|
|
22
36
|
### Features
|
|
23
37
|
|
|
24
|
-
|
|
38
|
+
`Pytdbot` offers numerous advantages, including:
|
|
25
39
|
|
|
26
40
|
- **Easy to Use**: Designed with simplicity in mind, making it accessible for developers
|
|
27
41
|
- **Performance**: Fast and powerful, making it ready to fight
|
|
@@ -32,30 +46,42 @@ Pytdbot (Python TDLib) is an asynchronous [**TDLib**](https://github.com/tdlib/t
|
|
|
32
46
|
- **Bound Methods**: Features types bound methods for improved usability
|
|
33
47
|
- **Unlimited Support**: Supports **Plugins**, [**filters**](pytdbot/filters.py#L23), [**TDLib**](https://github.com/tdlib/td) types/functions and much more
|
|
34
48
|
|
|
35
|
-
|
|
36
|
-
|
|
37
49
|
### Requirements
|
|
38
50
|
|
|
39
51
|
- Python 3.9+
|
|
40
52
|
- Telegram [API key](https://my.telegram.org/apps)
|
|
41
|
-
- [tdjson](https://github.com/tdlib/td#building)
|
|
53
|
+
- [tdjson](https://github.com/AYMENJD/tdjson) or [TDLib](https://github.com/tdlib/td#building)
|
|
42
54
|
- [deepdiff](https://github.com/seperman/deepdiff)
|
|
43
55
|
- [aio-pika](https://github.com/mosquito/aio-pika)
|
|
44
56
|
|
|
45
57
|
### Installation
|
|
58
|
+
|
|
46
59
|
> For better performance, it's recommended to install [orjson](https://github.com/ijl/orjson#install) or [ujson](https://github.com/ultrajson/ultrajson#ultrajson).
|
|
47
60
|
|
|
48
|
-
You can install Pytdbot using pip:
|
|
61
|
+
You can install Pytdbot with TDLib included using pip:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install --upgrade pytdbot[tdjson]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
If the installation fails, then install without **pre-built** TDLib:
|
|
68
|
+
|
|
49
69
|
```bash
|
|
50
70
|
pip install pytdbot
|
|
51
71
|
```
|
|
52
|
-
|
|
72
|
+
|
|
73
|
+
Then you need to build TDLib from [source](https://github.com/tdlib/td#building) and pass it to `Client.lib_path`.
|
|
74
|
+
|
|
75
|
+
You could also install the development version using the following command:
|
|
76
|
+
|
|
53
77
|
```bash
|
|
54
|
-
pip install
|
|
78
|
+
pip install --pre pytdbot
|
|
55
79
|
```
|
|
56
80
|
|
|
57
81
|
### Examples
|
|
82
|
+
|
|
58
83
|
Basic example:
|
|
84
|
+
|
|
59
85
|
```python
|
|
60
86
|
|
|
61
87
|
import asyncio
|
|
@@ -63,10 +89,9 @@ import asyncio
|
|
|
63
89
|
from pytdbot import Client, types
|
|
64
90
|
|
|
65
91
|
client = Client(
|
|
66
|
-
token="1088394097:AAQX2DnWiw4ihwiJUhIHOGog8gGOI", # Your bot token
|
|
67
|
-
api_id=0,
|
|
68
|
-
api_hash="API_HASH",
|
|
69
|
-
lib_path="/path/to/libtdjson.so", # Path to TDjson shared library
|
|
92
|
+
token="1088394097:AAQX2DnWiw4ihwiJUhIHOGog8gGOI", # Your bot token
|
|
93
|
+
api_id=0,
|
|
94
|
+
api_hash="API_HASH",
|
|
70
95
|
files_directory="BotDB", # Path where to store TDLib files
|
|
71
96
|
database_encryption_key="1234echobot$",
|
|
72
97
|
td_verbosity=2, # TDLib verbosity level
|
|
@@ -94,12 +119,15 @@ async def say_hello(c: Client, message: types.Message):
|
|
|
94
119
|
client.run()
|
|
95
120
|
|
|
96
121
|
```
|
|
122
|
+
|
|
97
123
|
For more examples, check the [examples](https://github.com/pytdbot/client/tree/main/examples) folder.
|
|
98
124
|
|
|
99
125
|
# Thanks to
|
|
126
|
+
|
|
100
127
|
- You for viewing or using this project.
|
|
101
128
|
|
|
102
129
|
- [@levlam](https://github.com/levlam) for maintaining [TDLib](https://github.com/tdlib/td) and for the help to create [Pytdbot](https://github.com/pytdbot/client).
|
|
130
|
+
|
|
103
131
|
# License
|
|
104
132
|
|
|
105
133
|
MIT [License](https://github.com/pytdbot/client/blob/main/LICENSE)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# Pytdbot [](https://pypi.org/project/Pytdbot) [](https://pypi.org/project/Pytdbot) [](https://github.com/tdlib/td) [](https://pepy.tech/project/pytdbot)
|
|
2
2
|
|
|
3
|
-
Pytdbot (Python TDLib) is an asynchronous [**TDLib**](https://github.com/tdlib/td) wrapper for **Telegram** users/bots written in **Python**.
|
|
3
|
+
Pytdbot (Python TDLib) is an asynchronous [**TDLib**](https://github.com/tdlib/td) wrapper for **Telegram** users/bots written in **Python**.
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
`Pytdbot` offers numerous advantages, including:
|
|
8
8
|
|
|
9
9
|
- **Easy to Use**: Designed with simplicity in mind, making it accessible for developers
|
|
10
10
|
- **Performance**: Fast and powerful, making it ready to fight
|
|
@@ -15,30 +15,42 @@ Pytdbot (Python TDLib) is an asynchronous [**TDLib**](https://github.com/tdlib/t
|
|
|
15
15
|
- **Bound Methods**: Features types bound methods for improved usability
|
|
16
16
|
- **Unlimited Support**: Supports **Plugins**, [**filters**](pytdbot/filters.py#L23), [**TDLib**](https://github.com/tdlib/td) types/functions and much more
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
18
|
### Requirements
|
|
21
19
|
|
|
22
20
|
- Python 3.9+
|
|
23
21
|
- Telegram [API key](https://my.telegram.org/apps)
|
|
24
|
-
- [tdjson](https://github.com/tdlib/td#building)
|
|
22
|
+
- [tdjson](https://github.com/AYMENJD/tdjson) or [TDLib](https://github.com/tdlib/td#building)
|
|
25
23
|
- [deepdiff](https://github.com/seperman/deepdiff)
|
|
26
24
|
- [aio-pika](https://github.com/mosquito/aio-pika)
|
|
27
25
|
|
|
28
26
|
### Installation
|
|
27
|
+
|
|
29
28
|
> For better performance, it's recommended to install [orjson](https://github.com/ijl/orjson#install) or [ujson](https://github.com/ultrajson/ultrajson#ultrajson).
|
|
30
29
|
|
|
31
|
-
You can install Pytdbot using pip:
|
|
30
|
+
You can install Pytdbot with TDLib included using pip:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install --upgrade pytdbot[tdjson]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If the installation fails, then install without **pre-built** TDLib:
|
|
37
|
+
|
|
32
38
|
```bash
|
|
33
39
|
pip install pytdbot
|
|
34
40
|
```
|
|
35
|
-
|
|
41
|
+
|
|
42
|
+
Then you need to build TDLib from [source](https://github.com/tdlib/td#building) and pass it to `Client.lib_path`.
|
|
43
|
+
|
|
44
|
+
You could also install the development version using the following command:
|
|
45
|
+
|
|
36
46
|
```bash
|
|
37
|
-
pip install
|
|
47
|
+
pip install --pre pytdbot
|
|
38
48
|
```
|
|
39
49
|
|
|
40
50
|
### Examples
|
|
51
|
+
|
|
41
52
|
Basic example:
|
|
53
|
+
|
|
42
54
|
```python
|
|
43
55
|
|
|
44
56
|
import asyncio
|
|
@@ -46,10 +58,9 @@ import asyncio
|
|
|
46
58
|
from pytdbot import Client, types
|
|
47
59
|
|
|
48
60
|
client = Client(
|
|
49
|
-
token="1088394097:AAQX2DnWiw4ihwiJUhIHOGog8gGOI", # Your bot token
|
|
50
|
-
api_id=0,
|
|
51
|
-
api_hash="API_HASH",
|
|
52
|
-
lib_path="/path/to/libtdjson.so", # Path to TDjson shared library
|
|
61
|
+
token="1088394097:AAQX2DnWiw4ihwiJUhIHOGog8gGOI", # Your bot token
|
|
62
|
+
api_id=0,
|
|
63
|
+
api_hash="API_HASH",
|
|
53
64
|
files_directory="BotDB", # Path where to store TDLib files
|
|
54
65
|
database_encryption_key="1234echobot$",
|
|
55
66
|
td_verbosity=2, # TDLib verbosity level
|
|
@@ -77,12 +88,15 @@ async def say_hello(c: Client, message: types.Message):
|
|
|
77
88
|
client.run()
|
|
78
89
|
|
|
79
90
|
```
|
|
91
|
+
|
|
80
92
|
For more examples, check the [examples](https://github.com/pytdbot/client/tree/main/examples) folder.
|
|
81
93
|
|
|
82
94
|
# Thanks to
|
|
95
|
+
|
|
83
96
|
- You for viewing or using this project.
|
|
84
97
|
|
|
85
98
|
- [@levlam](https://github.com/levlam) for maintaining [TDLib](https://github.com/tdlib/td) and for the help to create [Pytdbot](https://github.com/pytdbot/client).
|
|
99
|
+
|
|
86
100
|
# License
|
|
87
101
|
|
|
88
102
|
MIT [License](https://github.com/pytdbot/client/blob/main/LICENSE)
|
|
@@ -4,8 +4,8 @@ from .client import Client
|
|
|
4
4
|
|
|
5
5
|
__all__ = ["types", "utils", "filters", "exception", "TdJson", "Client"]
|
|
6
6
|
|
|
7
|
-
__version__ = "0.9.
|
|
8
|
-
__copyright__ = "Copyright (c) 2022-2025
|
|
7
|
+
__version__ = "0.9.1"
|
|
8
|
+
__copyright__ = "Copyright (c) 2022-2025 Pytdbot, AYMENJD"
|
|
9
9
|
__license__ = "MIT License"
|
|
10
10
|
|
|
11
11
|
VERSION = __version__
|
|
@@ -33,6 +33,13 @@ from .utils import (
|
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
def get_running_loop():
|
|
37
|
+
try:
|
|
38
|
+
return asyncio.get_running_loop()
|
|
39
|
+
except RuntimeError:
|
|
40
|
+
return asyncio.new_event_loop()
|
|
41
|
+
|
|
42
|
+
|
|
36
43
|
class Client(Decorators, Methods):
|
|
37
44
|
r"""Pytdbot, a TDLib client
|
|
38
45
|
|
|
@@ -92,10 +99,6 @@ class Client(Decorators, Methods):
|
|
|
92
99
|
options (``dict``, *optional*):
|
|
93
100
|
Pass key-value dictionary to set TDLib options. Check the list of available options at https://core.telegram.org/tdlib/options
|
|
94
101
|
|
|
95
|
-
sleep_threshold (``int``, *optional*):
|
|
96
|
-
Sleep threshold for all ``FLOOD_WAIT_X`` a.k.a ``Too Many Requests: retry after`` errors occur to this client.
|
|
97
|
-
If any request is rate limited (flood waited) the client will repeat the request after sleeping the required amount of seconds returned by the error. If the ``retry after`` value is higher than ``sleep_threshold`` the error is returned. Default is ``None`` (Disabled)
|
|
98
|
-
|
|
99
102
|
workers (``int``, *optional*):
|
|
100
103
|
Number of workers to handle updates. Default is ``5``. If set to ``None``, updates will be immediately handled instead of being queued, which can impact performance.
|
|
101
104
|
|
|
@@ -129,7 +132,6 @@ class Client(Decorators, Methods):
|
|
|
129
132
|
use_message_database: bool = True,
|
|
130
133
|
loop: asyncio.AbstractEventLoop = None,
|
|
131
134
|
options: dict = None,
|
|
132
|
-
sleep_threshold: int = None,
|
|
133
135
|
workers: int = 5,
|
|
134
136
|
no_updates: bool = False,
|
|
135
137
|
td_verbosity: int = 2,
|
|
@@ -159,9 +161,6 @@ class Client(Decorators, Methods):
|
|
|
159
161
|
self.use_chat_info_database = use_chat_info_database
|
|
160
162
|
self.use_message_database = use_message_database
|
|
161
163
|
self.td_options = options
|
|
162
|
-
self.sleep_threshold = (
|
|
163
|
-
sleep_threshold if isinstance(sleep_threshold, int) else 0
|
|
164
|
-
)
|
|
165
164
|
self.workers = workers
|
|
166
165
|
self.no_updates = no_updates
|
|
167
166
|
self.queue = asyncio.Queue()
|
|
@@ -180,7 +179,7 @@ class Client(Decorators, Methods):
|
|
|
180
179
|
self._handlers = {"initializer": [], "finalizer": []}
|
|
181
180
|
self._results: Dict[str, asyncio.Future] = {}
|
|
182
181
|
self._tdjson = None if self.is_rabbitmq else TdJson(lib_path, td_verbosity)
|
|
183
|
-
self.
|
|
182
|
+
self.__listen_loop_task = None
|
|
184
183
|
self._workers_tasks = None
|
|
185
184
|
self.__authorization_state = None
|
|
186
185
|
self.__cache = {"is_coro_filter": {}}
|
|
@@ -196,9 +195,7 @@ class Client(Decorators, Methods):
|
|
|
196
195
|
self.__is_closing = False
|
|
197
196
|
|
|
198
197
|
self.loop = (
|
|
199
|
-
loop
|
|
200
|
-
if isinstance(loop, asyncio.AbstractEventLoop)
|
|
201
|
-
else asyncio.get_event_loop()
|
|
198
|
+
loop if isinstance(loop, asyncio.AbstractEventLoop) else get_running_loop()
|
|
202
199
|
)
|
|
203
200
|
|
|
204
201
|
if plugins is not None:
|
|
@@ -254,7 +251,7 @@ class Client(Decorators, Methods):
|
|
|
254
251
|
if self.is_rabbitmq:
|
|
255
252
|
await self.__startRabbitMQ()
|
|
256
253
|
else:
|
|
257
|
-
self.loop.create_task(self.__listen_loop())
|
|
254
|
+
self.__listen_loop_task = self.loop.create_task(self.__listen_loop())
|
|
258
255
|
|
|
259
256
|
if login:
|
|
260
257
|
await self.login()
|
|
@@ -399,54 +396,48 @@ class Client(Decorators, Methods):
|
|
|
399
396
|
): # dumping all requests may create performance issues
|
|
400
397
|
self.logger.debug(f"Sending: {dumps(request, indent=4)}")
|
|
401
398
|
|
|
402
|
-
|
|
403
|
-
result = await future
|
|
399
|
+
is_chat_attempted_load = request["@type"].lower() == "getchat"
|
|
404
400
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
401
|
+
while True:
|
|
402
|
+
future = self._create_request_future(request)
|
|
403
|
+
await self.__send(request)
|
|
404
|
+
result = await future
|
|
408
405
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
406
|
+
if isinstance(result, types.Error):
|
|
407
|
+
if result.code == 400:
|
|
408
|
+
if result.message.startswith(
|
|
409
|
+
"Failed to parse JSON object as TDLib request:"
|
|
410
|
+
):
|
|
411
|
+
raise ValueError(result.message)
|
|
413
412
|
|
|
414
|
-
|
|
413
|
+
if not is_chat_attempted_load and (
|
|
414
|
+
result.message == "Chat not found" and "chat_id" in request
|
|
415
|
+
):
|
|
416
|
+
is_chat_attempted_load = True
|
|
415
417
|
|
|
416
|
-
|
|
418
|
+
chat_id = request["chat_id"]
|
|
417
419
|
|
|
418
|
-
|
|
419
|
-
result = await future
|
|
420
|
-
elif not self.use_message_database and (
|
|
421
|
-
result.code == 400
|
|
422
|
-
and result.message == "Chat not found"
|
|
423
|
-
and "chat_id" in request
|
|
424
|
-
):
|
|
425
|
-
chat_id = request["chat_id"]
|
|
420
|
+
self.logger.debug(f"Attempt to load chat {chat_id}")
|
|
426
421
|
|
|
427
|
-
|
|
422
|
+
load_chat = await self.getChat(chat_id)
|
|
428
423
|
|
|
429
|
-
|
|
424
|
+
if not isinstance(load_chat, types.Error):
|
|
425
|
+
self.logger.debug(f"Chat {chat_id} is loaded")
|
|
430
426
|
|
|
431
|
-
|
|
432
|
-
|
|
427
|
+
reply_to_message_id = (request.get("reply_to") or {}).get(
|
|
428
|
+
"message_id", 0
|
|
429
|
+
)
|
|
433
430
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
431
|
+
# if the request is a reply to another message
|
|
432
|
+
# load the replied message to avoid "Message not found"
|
|
433
|
+
if reply_to_message_id > 0:
|
|
434
|
+
await self.getMessage(chat_id, reply_to_message_id)
|
|
437
435
|
|
|
438
|
-
|
|
439
|
-
# load the replied message to avoid "Message not found"
|
|
440
|
-
if reply_to_message_id > 0:
|
|
441
|
-
await self.getMessage(chat_id, reply_to_message_id)
|
|
436
|
+
continue
|
|
442
437
|
|
|
443
|
-
|
|
444
|
-
future = self._create_request_future(request)
|
|
438
|
+
self.logger.error(f"Couldn't load chat {chat_id}")
|
|
445
439
|
|
|
446
|
-
|
|
447
|
-
result = await future
|
|
448
|
-
else:
|
|
449
|
-
self.logger.error(f"Couldn't load chat {chat_id}")
|
|
440
|
+
break
|
|
450
441
|
|
|
451
442
|
return result
|
|
452
443
|
|
|
@@ -568,7 +559,8 @@ class Client(Decorators, Methods):
|
|
|
568
559
|
else:
|
|
569
560
|
await self.__rchannel.default_exchange.publish(
|
|
570
561
|
aio_pika.Message(
|
|
571
|
-
json_dumps(request
|
|
562
|
+
json_dumps(request, encode=True),
|
|
563
|
+
reply_to=self.__rqueues["responses"].name,
|
|
572
564
|
),
|
|
573
565
|
routing_key=self.__rqueues["requests"].name,
|
|
574
566
|
)
|
|
@@ -592,22 +584,6 @@ class Client(Decorators, Methods):
|
|
|
592
584
|
if isinstance(self.workers, int) and self.workers < 1:
|
|
593
585
|
raise ValueError("workers must be greater than 0")
|
|
594
586
|
|
|
595
|
-
def get_retry_after_time(self, error_message: str) -> int:
|
|
596
|
-
r"""Get the retry after time from flood wait error message
|
|
597
|
-
|
|
598
|
-
Parameters:
|
|
599
|
-
error_message (``str``):
|
|
600
|
-
The returned error message from TDLib
|
|
601
|
-
|
|
602
|
-
Returns:
|
|
603
|
-
py:class:`int`
|
|
604
|
-
"""
|
|
605
|
-
|
|
606
|
-
try:
|
|
607
|
-
return int(error_message.removeprefix(self._retry_after_prefex))
|
|
608
|
-
except Exception:
|
|
609
|
-
return 0
|
|
610
|
-
|
|
611
587
|
def _load_plugins(self):
|
|
612
588
|
count = 0
|
|
613
589
|
handlers = 0
|
|
@@ -694,7 +670,7 @@ class Client(Decorators, Methods):
|
|
|
694
670
|
update = await self.loop.run_in_executor(
|
|
695
671
|
thread,
|
|
696
672
|
self._tdjson.receive,
|
|
697
|
-
|
|
673
|
+
1.0, # Seconds
|
|
698
674
|
)
|
|
699
675
|
if update is None:
|
|
700
676
|
continue
|
|
@@ -858,6 +834,7 @@ class Client(Decorators, Methods):
|
|
|
858
834
|
application_version=f"Pytdbot {pytdbot.__version__}",
|
|
859
835
|
)
|
|
860
836
|
if isinstance(res, types.Error):
|
|
837
|
+
await self.stop()
|
|
861
838
|
raise AuthorizationError(res.message)
|
|
862
839
|
|
|
863
840
|
async def _set_options(self):
|
|
@@ -929,20 +906,7 @@ class Client(Decorators, Methods):
|
|
|
929
906
|
m_id = f"{update.message.chat_id}:{update.old_message_id}"
|
|
930
907
|
|
|
931
908
|
if result := self._results.pop(m_id, None):
|
|
932
|
-
|
|
933
|
-
retry_after = update.message.sending_state.retry_after
|
|
934
|
-
|
|
935
|
-
if retry_after <= self.sleep_threshold:
|
|
936
|
-
self.logger.error(
|
|
937
|
-
f"Sleeping for {retry_after}s (Caused by {result.request['@type']})"
|
|
938
|
-
)
|
|
939
|
-
|
|
940
|
-
await asyncio.sleep(retry_after)
|
|
941
|
-
res = await self.invoke(result.request)
|
|
942
|
-
|
|
943
|
-
self._results[f"{res.id}{update.message.chat_id}"] = result
|
|
944
|
-
else:
|
|
945
|
-
result.set_result(update.error)
|
|
909
|
+
result.set_result(update.error)
|
|
946
910
|
|
|
947
911
|
async def __handle_update_option(self, update: types.UpdateOption):
|
|
948
912
|
if isinstance(update.value, types.OptionValueBoolean):
|
|
@@ -1067,6 +1031,7 @@ class Client(Decorators, Methods):
|
|
|
1067
1031
|
res = await self.checkAuthenticationBotToken(self.__token)
|
|
1068
1032
|
|
|
1069
1033
|
if isinstance(res, types.Error):
|
|
1034
|
+
await self.stop()
|
|
1070
1035
|
raise AuthorizationError(res.message)
|
|
1071
1036
|
|
|
1072
1037
|
def __stop_client(self) -> None:
|
|
@@ -1077,6 +1042,9 @@ class Client(Decorators, Methods):
|
|
|
1077
1042
|
for worker_task in self._workers_tasks:
|
|
1078
1043
|
worker_task.cancel()
|
|
1079
1044
|
|
|
1045
|
+
if self.__listen_loop_task:
|
|
1046
|
+
self.__listen_loop_task.cancel()
|
|
1047
|
+
|
|
1080
1048
|
def _register_signal_handlers(self):
|
|
1081
1049
|
def _handle_signal():
|
|
1082
1050
|
self.loop.create_task(self.stop())
|