pyrobale 0.3.7__py3-none-any.whl → 0.3.8__py3-none-any.whl
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.
- pyrobale/StateMachine/__init__.py +21 -0
- pyrobale/__init__.py +3 -1
- pyrobale/client/__init__.py +125 -24
- pyrobale/exceptions/__init__.py +1 -0
- pyrobale/exceptions/common.py +6 -0
- pyrobale/filters/__init__.py +2 -0
- pyrobale/filters/enum_filters.py +12 -0
- pyrobale/filters/func_filters.py +17 -0
- pyrobale/objects/enums.py +1 -9
- pyrobale/objects/inlinekeyboardmarkup.py +11 -4
- pyrobale/objects/message.py +6 -8
- pyrobale/objects/utils.py +23 -2
- {pyrobale-0.3.7.dist-info → pyrobale-0.3.8.dist-info}/METADATA +5 -6
- {pyrobale-0.3.7.dist-info → pyrobale-0.3.8.dist-info}/RECORD +16 -13
- {pyrobale-0.3.7.dist-info → pyrobale-0.3.8.dist-info}/licenses/LICENSE +2 -2
- {pyrobale-0.3.7.dist-info → pyrobale-0.3.8.dist-info}/WHEEL +0 -0
@@ -43,3 +43,24 @@ class StateMachine:
|
|
43
43
|
del self.__states[user_id]
|
44
44
|
else:
|
45
45
|
raise KeyError
|
46
|
+
|
47
|
+
def save_local(self, file_name: str):
|
48
|
+
"""Saves the state of all users to a file
|
49
|
+
|
50
|
+
Args:
|
51
|
+
file_name (string): name of file to save the state of users
|
52
|
+
"""
|
53
|
+
with open(file_name, "w") as f:
|
54
|
+
for user_id, state in self.__states.items():
|
55
|
+
f.write(f"{user_id} {state}\n")
|
56
|
+
|
57
|
+
def load_local(self, file_name: str):
|
58
|
+
"""Loads the state of all users from a file
|
59
|
+
|
60
|
+
Args:
|
61
|
+
file_name (string): name of file to load the state of users
|
62
|
+
"""
|
63
|
+
with open(file_name, "r") as f:
|
64
|
+
for line in f:
|
65
|
+
user_id, state = line.split()
|
66
|
+
self.__states[user_id] = state
|
pyrobale/__init__.py
CHANGED
@@ -31,7 +31,7 @@ from pyrobale.objects import Message, UpdatesTypes
|
|
31
31
|
bot = Client("YOUR_BOT_TOKEN")
|
32
32
|
|
33
33
|
@bot.on_message()
|
34
|
-
async def message_handler(message:
|
34
|
+
async def message_handler(message: Message):
|
35
35
|
await message.reply("Hello, world!")
|
36
36
|
|
37
37
|
bot.run()
|
@@ -116,8 +116,10 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
116
116
|
- 📖 [Documentation](https://pyrobale.readthedocs.io)
|
117
117
|
- 🐛 [Issue Tracker](https://github.com/pyrobale/pyrobale/issues)
|
118
118
|
- 💬 [Discussions](https://github.com/pyrobale/pyrobale/discussions)
|
119
|
+
|
119
120
|
"""
|
120
121
|
|
121
122
|
from .objects.utils import *
|
122
123
|
from .exceptions import *
|
123
124
|
from .objects import *
|
125
|
+
from .client import Client
|
pyrobale/client/__init__.py
CHANGED
@@ -40,7 +40,9 @@ from ..objects.utils import *
|
|
40
40
|
import asyncio
|
41
41
|
from enum import Enum
|
42
42
|
from ..objects.enums import UpdatesTypes, ChatAction, ChatType
|
43
|
+
from ..filters import Filters, equals
|
43
44
|
from ..StateMachine import StateMachine
|
45
|
+
from ..exceptions import NotFoundException, InvalidTokenException, PyroBaleException
|
44
46
|
|
45
47
|
|
46
48
|
class Client:
|
@@ -81,7 +83,12 @@ class Client:
|
|
81
83
|
self.requests_base
|
82
84
|
+ f"/getUpdates?offset={offset}&limit={limit}&timeout={timeout}"
|
83
85
|
)
|
84
|
-
|
86
|
+
if data['ok']:
|
87
|
+
if 'result' in data.keys():
|
88
|
+
return data["result"]
|
89
|
+
else:
|
90
|
+
if data['error_code'] == 403:
|
91
|
+
raise InvalidTokenException("Forbidden 403 : --ENTERED TOKEN IS NOT VALID--")
|
85
92
|
|
86
93
|
async def set_webhook(self, url: str) -> bool:
|
87
94
|
"""Set the webhook for the bot.
|
@@ -421,6 +428,7 @@ class Client:
|
|
421
428
|
chat_id: int,
|
422
429
|
latitude: float,
|
423
430
|
longitude: float,
|
431
|
+
horizontal_accuracy: Optional[float] = None,
|
424
432
|
reply_to_message_id: Optional[int] = None,
|
425
433
|
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
426
434
|
) -> Message:
|
@@ -441,6 +449,7 @@ class Client:
|
|
441
449
|
"chat_id": chat_id,
|
442
450
|
"latitude": latitude,
|
443
451
|
"longitude": longitude,
|
452
|
+
"horizontal_accuracy": horizontal_accuracy,
|
444
453
|
"reply_to_message_id": reply_to_message_id,
|
445
454
|
"reply_markup": reply_markup.to_dict() if reply_markup else None,
|
446
455
|
},
|
@@ -507,6 +516,9 @@ class Client:
|
|
507
516
|
Returns:
|
508
517
|
Message: returns the sent message with invoice
|
509
518
|
"""
|
519
|
+
new_prices = []
|
520
|
+
for price in prices:
|
521
|
+
new_prices.append(price.json)
|
510
522
|
data = await make_post(
|
511
523
|
self.requests_base + "/sendInvoice",
|
512
524
|
data={
|
@@ -515,7 +527,7 @@ class Client:
|
|
515
527
|
"description": description,
|
516
528
|
"payload": payload,
|
517
529
|
"provider_token": provider_token,
|
518
|
-
"prices":
|
530
|
+
"prices": new_prices,
|
519
531
|
"photo_url": photo_url,
|
520
532
|
"reply_to_message_id": reply_to_message_id,
|
521
533
|
},
|
@@ -922,51 +934,136 @@ class Client:
|
|
922
934
|
if not future.done():
|
923
935
|
future.set_result(event)
|
924
936
|
self._waiters.remove(waiter)
|
925
|
-
return
|
937
|
+
return
|
926
938
|
|
927
939
|
for handler in self.handlers:
|
928
940
|
update_type = handler["type"].value
|
929
941
|
if update_type in update:
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
942
|
+
raw_event = update[update_type]
|
943
|
+
event = self._convert_event(handler["type"], raw_event)
|
944
|
+
|
945
|
+
if handler["type"] == UpdatesTypes.COMMAND:
|
946
|
+
if hasattr(event, 'text') and event.text and event.text.startswith('/'):
|
947
|
+
command_text = event.text[1:]
|
948
|
+
command_parts = command_text.split()
|
949
|
+
if command_parts:
|
950
|
+
actual_command = command_parts[0]
|
951
|
+
expected_command = handler.get("command", "")
|
952
|
+
|
953
|
+
if actual_command != expected_command:
|
954
|
+
continue
|
955
|
+
|
956
|
+
flt = handler.get("filter")
|
957
|
+
if flt is not None:
|
958
|
+
if callable(flt):
|
959
|
+
try:
|
960
|
+
if not flt(event):
|
961
|
+
continue
|
962
|
+
except Exception as e:
|
963
|
+
print(f"[Filter Error] {e}")
|
964
|
+
continue
|
965
|
+
elif isinstance(flt, Filters):
|
966
|
+
if not hasattr(event, flt.value):
|
967
|
+
continue
|
968
|
+
|
934
969
|
if asyncio.iscoroutinefunction(handler["callback"]):
|
935
970
|
asyncio.create_task(handler["callback"](event))
|
936
971
|
else:
|
937
972
|
handler["callback"](event)
|
938
973
|
|
974
|
+
|
975
|
+
|
939
976
|
def base_handler_decorator(self, update_type: UpdatesTypes):
|
977
|
+
"""Base decorator for handling different types of updates.
|
978
|
+
|
979
|
+
Args:
|
980
|
+
update_type (UpdatesTypes): The type of update to handle.
|
981
|
+
|
982
|
+
Returns:
|
983
|
+
Callable: A decorator function that registers the callback for the specified update type.
|
984
|
+
"""
|
985
|
+
def wrapper(filter: Optional[Filters] = None):
|
986
|
+
def decorator(callback: Callable[[Any], Union[None, Awaitable[None]]]):
|
987
|
+
self.add_handler(update_type, callback, filter)
|
988
|
+
return callback
|
989
|
+
return decorator
|
990
|
+
return wrapper
|
991
|
+
|
992
|
+
def on_command(self, command: str, filter: Optional[Filters] = None):
|
993
|
+
"""Decorator for handling command updates.
|
994
|
+
|
995
|
+
Args:
|
996
|
+
command (str): The command to handle.
|
997
|
+
filter (Optional[Filters]): An optional filter to apply to the command.
|
998
|
+
Returns:
|
999
|
+
Callable: A decorator function that registers the callback for the specified command.
|
1000
|
+
"""
|
940
1001
|
def decorator(callback: Callable[[Any], Union[None, Awaitable[None]]]):
|
941
|
-
self.add_handler(
|
1002
|
+
self.add_handler(UpdatesTypes.COMMAND, callback, filter, command=command)
|
942
1003
|
return callback
|
943
|
-
|
944
1004
|
return decorator
|
945
1005
|
|
946
|
-
|
947
|
-
|
1006
|
+
|
1007
|
+
def on_message(self, filter: Optional[Filters] = None):
|
1008
|
+
"""Decorator for handling new message updates.
|
1009
|
+
|
1010
|
+
Returns:
|
1011
|
+
Callable: A decorator function that registers the callback for message updates.
|
1012
|
+
"""
|
1013
|
+
return self.base_handler_decorator(UpdatesTypes.MESSAGE)(filter)
|
1014
|
+
|
948
1015
|
|
949
1016
|
def on_edited_message(self):
|
1017
|
+
"""Decorator for handling edited message updates.
|
1018
|
+
|
1019
|
+
Returns:
|
1020
|
+
Callable: A decorator function that registers the callback for edited message updates.
|
1021
|
+
"""
|
950
1022
|
return self.base_handler_decorator(UpdatesTypes.MESSAGE_EDITED)
|
951
1023
|
|
952
1024
|
def on_callback_query(self):
|
1025
|
+
"""Decorator for handling callback query updates.
|
1026
|
+
|
1027
|
+
Returns:
|
1028
|
+
Callable: A decorator function that registers the callback for callback query updates.
|
1029
|
+
"""
|
953
1030
|
return self.base_handler_decorator(UpdatesTypes.CALLBACK_QUERY)
|
954
1031
|
|
955
1032
|
def on_new_members(self):
|
1033
|
+
"""Decorator for handling new chat members updates.
|
1034
|
+
|
1035
|
+
Returns:
|
1036
|
+
Callable: A decorator function that registers the callback for new members updates.
|
1037
|
+
"""
|
956
1038
|
return self.base_handler_decorator(UpdatesTypes.MEMBER_JOINED)
|
957
1039
|
|
958
|
-
def
|
1040
|
+
def on_members_left(self):
|
959
1041
|
return self.base_handler_decorator(UpdatesTypes.MEMBER_LEFT)
|
960
1042
|
|
961
1043
|
def on_pre_checkout_query(self):
|
1044
|
+
"""Decorator for handling pre-checkout query updates.
|
1045
|
+
|
1046
|
+
Returns:
|
1047
|
+
Callable: A decorator function that registers the callback for pre-checkout query updates.
|
1048
|
+
"""
|
962
1049
|
return self.base_handler_decorator(UpdatesTypes.PRE_CHECKOUT_QUERY)
|
963
1050
|
|
964
1051
|
def on_photo(self):
|
1052
|
+
"""Decorator for handling photo updates.
|
1053
|
+
|
1054
|
+
Returns:
|
1055
|
+
Callable: A decorator function that registers the callback for photo updates.
|
1056
|
+
"""
|
965
1057
|
return self.base_handler_decorator(UpdatesTypes.PHOTO)
|
966
1058
|
|
967
1059
|
def on_successful_payment(self):
|
968
|
-
|
1060
|
+
"""Decorator for handling successful payment updates.
|
969
1061
|
|
1062
|
+
Returns:
|
1063
|
+
Callable: A decorator function that registers the callback for successful payment updates.
|
1064
|
+
"""
|
1065
|
+
return self.base_handler_decorator(UpdatesTypes.SUCCESSFUL_PAYMENT)
|
1066
|
+
|
970
1067
|
def _convert_event(self, handler_type: UpdatesTypes, event: Dict[str, Any]) -> Any:
|
971
1068
|
"""Convert raw event data to appropriate object type.
|
972
1069
|
|
@@ -983,6 +1080,7 @@ class Client:
|
|
983
1080
|
UpdatesTypes.MEMBER_JOINED,
|
984
1081
|
UpdatesTypes.MEMBER_LEFT,
|
985
1082
|
UpdatesTypes.SUCCESSFUL_PAYMENT,
|
1083
|
+
UpdatesTypes.COMMAND
|
986
1084
|
):
|
987
1085
|
if (
|
988
1086
|
event.get("new_chat_member", False)
|
@@ -1033,18 +1131,22 @@ class Client:
|
|
1033
1131
|
|
1034
1132
|
return event
|
1035
1133
|
|
1036
|
-
|
1037
|
-
|
1038
|
-
update_type: UpdatesTypes,
|
1039
|
-
callback: Callable[[Any], Union[None, Awaitable[None]]],
|
1040
|
-
) -> None:
|
1134
|
+
|
1135
|
+
def add_handler(self, update_type, callback, filter: Optional[Filters] = None, **kwargs):
|
1041
1136
|
"""Register a handler for specific update type.
|
1042
1137
|
|
1043
1138
|
Args:
|
1044
1139
|
update_type (UpdatesTypes): Type of update to handle
|
1045
1140
|
callback (Callable): Function to call when update is received
|
1046
1141
|
"""
|
1047
|
-
|
1142
|
+
data = {
|
1143
|
+
"type": update_type,
|
1144
|
+
"callback": callback,
|
1145
|
+
"filter": filter,
|
1146
|
+
}
|
1147
|
+
data.update(kwargs)
|
1148
|
+
self.handlers.append(data)
|
1149
|
+
|
1048
1150
|
|
1049
1151
|
def remove_handler(
|
1050
1152
|
self, callback: Callable[[Any], Union[None, Awaitable[None]]]
|
@@ -1077,17 +1179,16 @@ class Client:
|
|
1077
1179
|
|
1078
1180
|
self.running = True
|
1079
1181
|
while self.running:
|
1080
|
-
|
1182
|
+
try:
|
1081
1183
|
updates = await self.get_updates(
|
1082
1184
|
offset=self.last_update_id, limit=limit, timeout=timeout
|
1083
1185
|
)
|
1084
1186
|
|
1085
1187
|
for update in updates:
|
1086
1188
|
await self.process_update(update)
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
await asyncio.sleep(5)
|
1189
|
+
|
1190
|
+
except Exception as e:
|
1191
|
+
raise e
|
1091
1192
|
|
1092
1193
|
async def stop_polling(self) -> None:
|
1093
1194
|
"""Stop polling updates."""
|
pyrobale/exceptions/__init__.py
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
from .common import *
|
pyrobale/exceptions/common.py
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
def equals(expected_text: str):
|
2
|
+
"""
|
3
|
+
Check if the event text or caption is equal to the expected text.
|
4
|
+
|
5
|
+
Args:
|
6
|
+
expected_text (str): The expected text to compare with.
|
7
|
+
|
8
|
+
Returns:
|
9
|
+
Callable: A function that checks if the event text or caption is equal to the expected text.
|
10
|
+
"""
|
11
|
+
def check(event):
|
12
|
+
try:
|
13
|
+
return getattr(event, "text", None) == expected_text or getattr(event, "caption", None) == expected_text
|
14
|
+
except:
|
15
|
+
return False
|
16
|
+
return check
|
17
|
+
|
pyrobale/objects/enums.py
CHANGED
@@ -11,18 +11,10 @@ class UpdatesTypes(Enum):
|
|
11
11
|
MEMBER_JOINED = "member_joined"
|
12
12
|
MEMBER_LEFT = "member_left"
|
13
13
|
SUCCESSFUL_PAYMENT = "successful_payment"
|
14
|
+
COMMAND = "message"
|
14
15
|
|
15
16
|
|
16
|
-
class Filters(Enum):
|
17
|
-
"""Filters that you can use in handlers"""
|
18
17
|
|
19
|
-
TEXT = "text"
|
20
|
-
PHOTO = "photo"
|
21
|
-
VIDEO = "video"
|
22
|
-
AUDIO = "audio"
|
23
|
-
VOICE = "voice"
|
24
|
-
CONTACT = "contact"
|
25
|
-
LOCATION = "location"
|
26
18
|
|
27
19
|
|
28
20
|
class ChatAction(Enum):
|
@@ -15,7 +15,7 @@ class InlineKeyboardMarkup:
|
|
15
15
|
callback_data: Optional[str] = None,
|
16
16
|
url: Optional[str] = None,
|
17
17
|
web_app: Optional[Union["WebAppInfo", str]] = None,
|
18
|
-
copy_text_button: Optional["CopyTextButton"] = None,
|
18
|
+
copy_text_button: Optional[Union["CopyTextButton", str]] = None,
|
19
19
|
**kwargs
|
20
20
|
) -> "InlineKeyboardMarkup":
|
21
21
|
"""Adds a button to the inline keyboard.
|
@@ -24,8 +24,8 @@ class InlineKeyboardMarkup:
|
|
24
24
|
text (str): The text to display on the button.
|
25
25
|
callback_data (str, optional): The callback data to send when the button is clicked.
|
26
26
|
url (str, optional): The URL to open when the button is clicked.
|
27
|
-
web_app (WebAppInfo, optional): The web app to open when the button is clicked.
|
28
|
-
copy_text_button (CopyTextButton, optional): The copy text button to add to the button.
|
27
|
+
web_app (WebAppInfo OR string, optional): The web app to open when the button is clicked.
|
28
|
+
copy_text_button (CopyTextButton OR string, optional): The copy text button to add to the button.
|
29
29
|
|
30
30
|
Returns:
|
31
31
|
InlineKeyboardMarkup: The updated InlineKeyboardMarkup object.
|
@@ -59,7 +59,14 @@ class InlineKeyboardMarkup:
|
|
59
59
|
"web_app must be a string URL or an object with to_dict() method."
|
60
60
|
)
|
61
61
|
elif copy_text_button:
|
62
|
-
|
62
|
+
if isinstance(copy_text_button, str):
|
63
|
+
button["copy_text"] = {"text": copy_text_button}
|
64
|
+
elif hasattr(copy_text_button, "text"):
|
65
|
+
button["copy_text"] = {"text": copy_text_button.text}
|
66
|
+
else:
|
67
|
+
raise ValueError(
|
68
|
+
"copy_text_button must be a string or an object with a 'text' attribute."
|
69
|
+
)
|
63
70
|
|
64
71
|
if not self.inline_keyboard:
|
65
72
|
self.inline_keyboard.append([])
|
pyrobale/objects/message.py
CHANGED
@@ -124,6 +124,7 @@ class Message:
|
|
124
124
|
reply_markup: Inline keyboard markup
|
125
125
|
**kwargs: Additional keyword arguments
|
126
126
|
"""
|
127
|
+
self.client: Client = kwargs.get("kwargs", {}).get("client")
|
127
128
|
self.id: int = message_id
|
128
129
|
self.user: "User" = (
|
129
130
|
User(**from_user, kwargs={"client": self.client}) if from_user else None
|
@@ -154,7 +155,7 @@ class Message:
|
|
154
155
|
self.successful_payment: Optional["SuccessfulPayment"] = successful_payment
|
155
156
|
self.web_app_data: Optional["WebAppData"] = web_app_data
|
156
157
|
self.reply_markup: Optional["InlineKeyboardMarkup"] = reply_markup
|
157
|
-
|
158
|
+
|
158
159
|
|
159
160
|
async def reply(
|
160
161
|
self,
|
@@ -313,6 +314,7 @@ class Message:
|
|
313
314
|
self,
|
314
315
|
latitude: float,
|
315
316
|
longitude: float,
|
317
|
+
horizontal_accuracy: Optional[float] = None,
|
316
318
|
reply_markup: Union["ReplyKeyboardMarkup", "InlineKeyboardMarkup"] = None,
|
317
319
|
):
|
318
320
|
"""Reply with a location to the current message.
|
@@ -327,6 +329,7 @@ class Message:
|
|
327
329
|
self.chat.id,
|
328
330
|
latitude=latitude,
|
329
331
|
longitude=longitude,
|
332
|
+
horizontal_accuracy=horizontal_accuracy,
|
330
333
|
reply_to_message_id=self.id,
|
331
334
|
reply_markup=reply_markup,
|
332
335
|
)
|
@@ -359,9 +362,7 @@ class Message:
|
|
359
362
|
description: str,
|
360
363
|
payload: str,
|
361
364
|
provider_token: str,
|
362
|
-
|
363
|
-
prices: list,
|
364
|
-
reply_markup: Union["ReplyKeyboardMarkup", "InlineKeyboardMarkup"] = None,
|
365
|
+
prices: list
|
365
366
|
):
|
366
367
|
"""Reply with an invoice to the current message.
|
367
368
|
|
@@ -370,7 +371,6 @@ class Message:
|
|
370
371
|
description: Product description
|
371
372
|
payload: Bot-defined invoice payload
|
372
373
|
provider_token: Payment provider token
|
373
|
-
currency: Three-letter ISO 4217 currency code
|
374
374
|
prices: Price breakdown (amount in smallest units)
|
375
375
|
reply_markup: Optional keyboard markup
|
376
376
|
"""
|
@@ -381,7 +381,5 @@ class Message:
|
|
381
381
|
description=description,
|
382
382
|
payload=payload,
|
383
383
|
provider_token=provider_token,
|
384
|
-
|
385
|
-
prices=prices,
|
386
|
-
reply_markup=reply_markup,
|
384
|
+
prices=prices
|
387
385
|
)
|
pyrobale/objects/utils.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
from ..exceptions import *
|
1
2
|
import aiohttp
|
2
3
|
|
3
4
|
|
@@ -8,13 +9,33 @@ def build_api_url(base: str, endpoint: str) -> str:
|
|
8
9
|
async def make_post(url: str, data: dict = None, headers: dict = None) -> dict:
|
9
10
|
async with aiohttp.ClientSession() as session:
|
10
11
|
async with session.post(url, json=data, headers=headers) as response:
|
11
|
-
|
12
|
+
json = await response.json()
|
13
|
+
if json['ok']:
|
14
|
+
if 'result' in json.keys():
|
15
|
+
return json
|
16
|
+
else:
|
17
|
+
if json['error_code'] == 404:
|
18
|
+
raise NotFoundException(f"Error not found 404 : {json['description'] if json['description'] else 'No description returned in error'}")
|
19
|
+
elif json['error_code'] == 403:
|
20
|
+
raise ForbiddenException(f"Error Forbidden 403 : {json['description'] if json['description'] else 'No description returned in error'}")
|
21
|
+
else:
|
22
|
+
raise PyroBaleException(f"unknown error : {json['description'] if json['description'] else 'No description!'}")
|
12
23
|
|
13
24
|
|
14
25
|
async def make_get(url: str, headers: dict = None) -> dict:
|
15
26
|
async with aiohttp.ClientSession() as session:
|
16
27
|
async with session.get(url, headers=headers) as response:
|
17
|
-
|
28
|
+
json = await response.json()
|
29
|
+
if json['ok']:
|
30
|
+
if 'result' in json.keys():
|
31
|
+
return json
|
32
|
+
else:
|
33
|
+
if json['error_code'] == 404:
|
34
|
+
raise NotFoundException(f"Error not found 404 : {json['description'] if json['description'] else 'No description returned in error'}")
|
35
|
+
elif json['error_code'] == 403:
|
36
|
+
raise ForbiddenException(f"Error Forbidden 403 : {json['description'] if json['description'] else 'No description returned in error'}")
|
37
|
+
else:
|
38
|
+
raise PyroBaleException(f"unknown error : {json['description'] if json['description'] else 'No description'}")
|
18
39
|
|
19
40
|
|
20
41
|
def pythonize(dictionary: dict) -> dict:
|
@@ -1,13 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: pyrobale
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.8
|
4
4
|
Summary: A python wrapper for bale api
|
5
5
|
Project-URL: github, https://github.com/pyrobale/pyrobale
|
6
6
|
Project-URL: website, https://pyrobale.github.io
|
7
7
|
Author-email: Ali Safamanesh <darg.q.a.a@gmail.com>, Aydin Rahbaran <codewizaard9@gmail.com>
|
8
8
|
License: MIT License
|
9
9
|
|
10
|
-
Copyright (c) 2025
|
10
|
+
Copyright (c) 2025 PyroBale Team
|
11
11
|
|
12
12
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
13
13
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -49,7 +49,7 @@ A modern, easy-to-use Python wrapper for the Bale Bot API that makes building Ba
|
|
49
49
|
- 📁 **File Handling** - Easy upload and download of media files
|
50
50
|
- 🛡️ **Error Handling** - Comprehensive exception handling
|
51
51
|
- 📖 **Type Hints** - Full typing support for better development experience
|
52
|
-
- ⚡ **Async Support** -
|
52
|
+
- ⚡ **Async Support** - asynchronous operations
|
53
53
|
|
54
54
|
## Installation
|
55
55
|
|
@@ -66,7 +66,7 @@ from pyrobale.objects import Message, UpdatesTypes
|
|
66
66
|
bot = Client("YOUR_BOT_TOKEN")
|
67
67
|
|
68
68
|
@bot.on_message()
|
69
|
-
async def message_handler(message:
|
69
|
+
async def message_handler(message: Message):
|
70
70
|
await message.reply("Hello, world!")
|
71
71
|
|
72
72
|
bot.run()
|
@@ -78,13 +78,12 @@ bot.run()
|
|
78
78
|
```python
|
79
79
|
from pyrobale.objects import *
|
80
80
|
from pyrobale.client import Client, Message, UpdatesTypes
|
81
|
-
import asyncio
|
82
81
|
|
83
82
|
client = Client("YOUR_BOT_TOKEN")
|
84
83
|
|
85
84
|
async def handle_message(message: Message):
|
86
85
|
if message.text == "/start":
|
87
|
-
await message.reply("
|
86
|
+
await message.reply("Hi! Im a pyrobale RoBot!")
|
88
87
|
await client.wait_for(UpdatesTypes.MESSAGE)
|
89
88
|
await message.reply("Okay! wait_for Test Compeleted")
|
90
89
|
|
@@ -1,8 +1,11 @@
|
|
1
|
-
pyrobale/__init__.py,sha256=
|
2
|
-
pyrobale/StateMachine/__init__.py,sha256=
|
3
|
-
pyrobale/client/__init__.py,sha256=
|
4
|
-
pyrobale/exceptions/__init__.py,sha256=
|
5
|
-
pyrobale/exceptions/common.py,sha256=
|
1
|
+
pyrobale/__init__.py,sha256=tC4gr6RIg4tYdzoBDFQCU2CDigXytc-MQ7yH6BJzTzM,3651
|
2
|
+
pyrobale/StateMachine/__init__.py,sha256=TRCBwcr4UlnpU2Olik0vOtNASUOK7_O6RMAG6RrVYlM,1911
|
3
|
+
pyrobale/client/__init__.py,sha256=xl7TyimdjJLLEPmhpRGV_0-JIN8hCPISmYwle7a6eSI,45539
|
4
|
+
pyrobale/exceptions/__init__.py,sha256=oa412OuokRm9Vf3XlCJLqpZjz9ZcuxAKxnEBvOK7u2M,21
|
5
|
+
pyrobale/exceptions/common.py,sha256=6ubWjGNmbRbNuzM_ohPuLvGhLdCiCZ-RscEERnv3JMA,273
|
6
|
+
pyrobale/filters/__init__.py,sha256=Q-VFK1U5W9jMWneAqNLNlYSTZI2gjnAkwA-lcqF9GbU,55
|
7
|
+
pyrobale/filters/enum_filters.py,sha256=5kVtmZ1dCbhUx-_T7tPFbgx8KxAz0W3clwCjOvZy5R0,239
|
8
|
+
pyrobale/filters/func_filters.py,sha256=C4cIckRkHk5ISvWFdrvLVFZPmYA1nuNCzC84BpEdkc0,523
|
6
9
|
pyrobale/objects/__init__.py,sha256=uy0xBJc5d-1TnlPD6CgxAaUjBnIvQs-GuAgLeEKoXSQ,2239
|
7
10
|
pyrobale/objects/animation.py,sha256=jpM9V8AOaGLWkcENTDmsxKf57Abf-MArYBLfU6GwkD0,978
|
8
11
|
pyrobale/objects/audio.py,sha256=q14wz5WpC3SgKZkAlH-D9M554RYQNDwuCT2z7v7IZYU,696
|
@@ -13,17 +16,17 @@ pyrobale/objects/chatphoto.py,sha256=vOb5xzpr3oBiCloi2_ufBnVlUfmcPqSTmMMMTTBYdJo
|
|
13
16
|
pyrobale/objects/contact.py,sha256=6LDxT5RoGbY5Tsw64lg5-jvKSRmmvOiIJha1HqdTaG4,411
|
14
17
|
pyrobale/objects/copytextbutton.py,sha256=CbFWeY9Ebor7dnHJpQUMB1zYhJWl7b5a2T_cdmo1qQ0,134
|
15
18
|
pyrobale/objects/document.py,sha256=cI9_McPzySNKZaQmOma9eX75a3YsyzkVrLvUBDIuwsA,661
|
16
|
-
pyrobale/objects/enums.py,sha256
|
19
|
+
pyrobale/objects/enums.py,sha256=-8SQ6jvAk4n5oYTSU--E3rZ2kGABy51SbK9QruMQf-Y,720
|
17
20
|
pyrobale/objects/file.py,sha256=4PBfjouP0knd1vFDNs7mx_jwBoDQVBKS7ESjzF4Y6E8,360
|
18
21
|
pyrobale/objects/inlinekeyboardbutton.py,sha256=w4HehdisD7RQodS66gG-DJjaf0gO2U-6wYaVXaatTN8,617
|
19
|
-
pyrobale/objects/inlinekeyboardmarkup.py,sha256=
|
22
|
+
pyrobale/objects/inlinekeyboardmarkup.py,sha256=pMcJDCI3iTvn7OZFPOCV_xnsq9Atx7ixdfKyObdGG1M,3254
|
20
23
|
pyrobale/objects/inputfile.py,sha256=vjw96uJZzp4UargWd2p3OQKyvTpHu2PH_dR_RwwshRI,621
|
21
24
|
pyrobale/objects/inputmedias.py,sha256=2h5YKWNjrrLD1QKZ5J_iOfpCZIRpAZST9q7eBd8edo0,6248
|
22
25
|
pyrobale/objects/invoice.py,sha256=hI225mtsSSV7fYre6aFHp-o1NxUT8MLugJAD6NfAeIs,375
|
23
26
|
pyrobale/objects/keyboardbutton.py,sha256=J7c1ma7swjk3zkgcD7vnMdIMsBGExicmbm1bnP_puzU,459
|
24
27
|
pyrobale/objects/labeledprice.py,sha256=d-fbOLzpkBslfor13BXGeVoySKCcSxsXY4QVwub2Z9o,228
|
25
28
|
pyrobale/objects/location.py,sha256=w_9sRJRntLpNbn8Jk6JhRJVVigD9Bd4BxbjFyglxWhU,143
|
26
|
-
pyrobale/objects/message.py,sha256=
|
29
|
+
pyrobale/objects/message.py,sha256=cCe0qU0ClGc66S7tW6TexnDzqyAafeKgN_h0h8UZMfs,14532
|
27
30
|
pyrobale/objects/messageid.py,sha256=DrWKV8y9m9H8G_Fj68KgiJKwDJOGduNJGJ-Dyn8N580,95
|
28
31
|
pyrobale/objects/photosize.py,sha256=I4hnmi46uoU-cW7hPN_tTT9kn0u80BtG5QJ3uRjoUiE,298
|
29
32
|
pyrobale/objects/precheckoutquery.py,sha256=Rtjh1qqRc9TRZMJU1W5r0B8y7K5dayLMXX6WH9h1Ul4,470
|
@@ -33,12 +36,12 @@ pyrobale/objects/stickerset.py,sha256=xlSdlnb5TCzI_MCkB_bJsZPgELVevbO7R3BAYN2jIt
|
|
33
36
|
pyrobale/objects/successfulpayment.py,sha256=aEAApcd60dByqPw253jEifG_CVsbLYiphB1ep3CEm2E,502
|
34
37
|
pyrobale/objects/update.py,sha256=cDR9hpcC8r4bJjixgMQD84Dg_-8ZrlZq1HninVVVDuQ,716
|
35
38
|
pyrobale/objects/user.py,sha256=uCvG3k7rIbGP73fFQt_uy7-shS-BRWAL2aEcCEZWyWY,554
|
36
|
-
pyrobale/objects/utils.py,sha256=
|
39
|
+
pyrobale/objects/utils.py,sha256=Odyy6y9wKexYBUrk-iErtrV-iEHHOWw-32yTU_iS_AU,2288
|
37
40
|
pyrobale/objects/video.py,sha256=DuZMGHio_w8yQvi87Vc3XpJOpEaltkM4_bNRSeocPZo,509
|
38
41
|
pyrobale/objects/voice.py,sha256=ZdsJFH2IsBwelEk4rb4oZfX9xrfJ2_DgfjsMc0e4Tmg,148
|
39
42
|
pyrobale/objects/webappdata.py,sha256=QlZlCa8Mylt8VmcdgdoHeyita5CVnz2WsT1yueEY1tY,78
|
40
43
|
pyrobale/objects/webappinfo.py,sha256=qnTvfNqx91Yzbc1gO5y4XQ3w6g0RpMUqMuF5wk_EZMc,75
|
41
|
-
pyrobale-0.3.
|
42
|
-
pyrobale-0.3.
|
43
|
-
pyrobale-0.3.
|
44
|
-
pyrobale-0.3.
|
44
|
+
pyrobale-0.3.8.dist-info/METADATA,sha256=386ZydRqEYd61G8-SgfJH_3eTz4YnNFgcb0l-nhp80A,5262
|
45
|
+
pyrobale-0.3.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
46
|
+
pyrobale-0.3.8.dist-info/licenses/LICENSE,sha256=rf_1ZkId-bcjw1kHBq6bV5t5TVob3RgjUyjfKr1CHAk,1070
|
47
|
+
pyrobale-0.3.8.dist-info/RECORD,,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
MIT License
|
2
2
|
|
3
|
-
Copyright (c) 2025
|
3
|
+
Copyright (c) 2025 PyroBale Team
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
18
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
SOFTWARE.
|
21
|
+
SOFTWARE.
|
File without changes
|