botbaleirp 0.0.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.
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.4
2
+ Name: botbaleirp
3
+ Version: 0.0.1
4
+ Summary: کتابخانه کامل پایتون برای API بازوی بله
5
+ Author: Mohammad Latifi
6
+ Requires-Python: >=3.7
7
+ Requires-Dist: requests>=2.25.0
8
+ Dynamic: author
9
+ Dynamic: requires-dist
10
+ Dynamic: requires-python
11
+ Dynamic: summary
@@ -0,0 +1,7 @@
1
+ __version__ = "0.0.1"
2
+ __author__ = "Mohammad Latifi"
3
+
4
+ from .bot import Bot
5
+ from .bale_types import *
6
+ from .errors import *
7
+ from .utils import *
@@ -0,0 +1,215 @@
1
+ from dataclasses import dataclass
2
+ from typing import List, Optional, Dict, Any
3
+
4
+ @dataclass
5
+ class User:
6
+ id: int
7
+ is_bot: bool
8
+ first_name: str
9
+ last_name: Optional[str] = None
10
+ username: Optional[str] = None
11
+ language_code: Optional[str] = None
12
+
13
+ @dataclass
14
+ class Chat:
15
+ id: int
16
+ type: str
17
+ title: Optional[str] = None
18
+ username: Optional[str] = None
19
+ first_name: Optional[str] = None
20
+ last_name: Optional[str] = None
21
+
22
+ @dataclass
23
+ class MessageEntity:
24
+ type: str
25
+ offset: int
26
+ length: int
27
+
28
+ @dataclass
29
+ class PhotoSize:
30
+ file_id: str
31
+ file_unique_id: str
32
+ width: int
33
+ height: int
34
+ file_size: Optional[int] = None
35
+
36
+ @dataclass
37
+ class Document:
38
+ file_id: str
39
+ file_unique_id: str
40
+ thumbnail: Optional[PhotoSize] = None
41
+ file_name: Optional[str] = None
42
+ mime_type: Optional[str] = None
43
+ file_size: Optional[int] = None
44
+
45
+ @dataclass
46
+ class Audio:
47
+ file_id: str
48
+ file_unique_id: str
49
+ duration: int
50
+ title: Optional[str] = None
51
+ file_name: Optional[str] = None
52
+ mime_type: Optional[str] = None
53
+ file_size: Optional[int] = None
54
+
55
+ @dataclass
56
+ class Video:
57
+ file_id: str
58
+ file_unique_id: str
59
+ width: int
60
+ height: int
61
+ duration: int
62
+ file_name: Optional[str] = None
63
+ mime_type: Optional[str] = None
64
+ file_size: Optional[int] = None
65
+
66
+ @dataclass
67
+ class Voice:
68
+ file_id: str
69
+ file_unique_id: str
70
+ duration: int
71
+ mime_type: Optional[str] = None
72
+ file_size: Optional[int] = None
73
+
74
+ @dataclass
75
+ class Animation:
76
+ file_id: str
77
+ file_unique_id: str
78
+ width: int
79
+ height: int
80
+ duration: int
81
+ thumbnail: Optional[PhotoSize] = None
82
+ file_name: Optional[str] = None
83
+ mime_type: Optional[str] = None
84
+ file_size: Optional[int] = None
85
+
86
+ @dataclass
87
+ class Contact:
88
+ phone_number: str
89
+ first_name: str
90
+ last_name: Optional[str] = None
91
+ user_id: Optional[int] = None
92
+
93
+ @dataclass
94
+ class Location:
95
+ longitude: float
96
+ latitude: float
97
+
98
+ @dataclass
99
+ class Invoice:
100
+ title: str
101
+ description: str
102
+ total_amount: int
103
+
104
+ @dataclass
105
+ class SuccessfulPayment:
106
+ currency: str
107
+ total_amount: int
108
+ invoice_payload: str
109
+ telegram_payment_charge_id: str
110
+ provider_payment_charge_id: str
111
+
112
+ @dataclass
113
+ class PreCheckoutQuery:
114
+ id: str
115
+ from_user: User
116
+ currency: str
117
+ total_amount: int
118
+ invoice_payload: str
119
+
120
+ @classmethod
121
+ def from_dict(cls, data):
122
+ data['from_user'] = User(**data.pop('from'))
123
+ return cls(**data)
124
+
125
+ @dataclass
126
+ class CallbackQuery:
127
+ id: str
128
+ from_user: User
129
+ message: Optional['Message'] = None
130
+ data: Optional[str] = None
131
+
132
+ @classmethod
133
+ def from_dict(cls, data):
134
+ data['from_user'] = User(**data.pop('from'))
135
+ if data.get('message'):
136
+ data['message'] = Message.from_dict(data['message'])
137
+ return cls(**data)
138
+
139
+ @dataclass
140
+ class Message:
141
+ message_id: int
142
+ date: int
143
+ chat: Chat
144
+ from_user: Optional[User] = None
145
+ text: Optional[str] = None
146
+ caption: Optional[str] = None
147
+ photo: Optional[List[PhotoSize]] = None
148
+ video: Optional[Video] = None
149
+ audio: Optional[Audio] = None
150
+ voice: Optional[Voice] = None
151
+ document: Optional[Document] = None
152
+ animation: Optional[Animation] = None
153
+ contact: Optional[Contact] = None
154
+ location: Optional[Location] = None
155
+ reply_to_message: Optional['Message'] = None
156
+ entities: Optional[List[MessageEntity]] = None
157
+ new_chat_members: Optional[List[User]] = None
158
+ left_chat_member: Optional[User] = None
159
+ invoice: Optional[Invoice] = None
160
+ successful_payment: Optional[SuccessfulPayment] = None
161
+
162
+ @classmethod
163
+ def from_dict(cls, data):
164
+ if data.get('from'):
165
+ data['from_user'] = User(**data.pop('from'))
166
+ if data.get('chat'):
167
+ data['chat'] = Chat(**data['chat'])
168
+ if data.get('reply_to_message'):
169
+ data['reply_to_message'] = cls.from_dict(data['reply_to_message'])
170
+ return cls(**{k: v for k, v in data.items() if k in cls.__annotations__})
171
+
172
+ @dataclass
173
+ class Update:
174
+ update_id: int
175
+ message: Optional[Message] = None
176
+ edited_message: Optional[Message] = None
177
+ callback_query: Optional[CallbackQuery] = None
178
+ pre_checkout_query: Optional[PreCheckoutQuery] = None
179
+
180
+ @classmethod
181
+ def from_dict(cls, data):
182
+ if data.get('message'):
183
+ data['message'] = Message.from_dict(data['message'])
184
+ if data.get('callback_query'):
185
+ data['callback_query'] = CallbackQuery.from_dict(data['callback_query'])
186
+ if data.get('pre_checkout_query'):
187
+ data['pre_checkout_query'] = PreCheckoutQuery.from_dict(data['pre_checkout_query'])
188
+ return cls(**data)
189
+
190
+ @dataclass
191
+ class File:
192
+ file_id: str
193
+ file_unique_id: str
194
+ file_size: Optional[int] = None
195
+ file_path: Optional[str] = None
196
+
197
+ @dataclass
198
+ class ChatMember:
199
+ status: str
200
+ user: User
201
+
202
+ @classmethod
203
+ def from_dict(cls, data):
204
+ data['user'] = User(**data['user'])
205
+ return cls(**data)
206
+
207
+ @dataclass
208
+ class ChatFullInfo(Chat):
209
+ bio: Optional[str] = None
210
+ description: Optional[str] = None
211
+ invite_link: Optional[str] = None
212
+
213
+ @dataclass
214
+ class MessageId:
215
+ message_id: int
@@ -0,0 +1,340 @@
1
+ import json
2
+ import time
3
+ from typing import Dict, Any, Optional, List, Union, BinaryIO, Callable
4
+ import requests
5
+ from . import bale_types as types
6
+ from .errors import BaleAPIError, BaleNetworkError
7
+ from .utils import prepare_upload_file
8
+
9
+ class Bot:
10
+ BASE_URL = "https://tapi.bale.ai/bot{}"
11
+
12
+ def __init__(self, token: str):
13
+ self.token = token
14
+ self.session = requests.Session()
15
+ self._offset = None
16
+
17
+ def _request(self, method: str, params: Dict = None, files: Dict = None) -> Any:
18
+ url = self.BASE_URL.format(self.token) + f"/{method}"
19
+ try:
20
+ if files:
21
+ resp = self.session.post(url, data=params, files=files)
22
+ elif method in ('getMe', 'getUpdates', 'getWebhookInfo', 'deleteWebhook'):
23
+ resp = self.session.get(url, params=params)
24
+ else:
25
+ resp = self.session.post(url, json=params)
26
+ resp.raise_for_status()
27
+ data = resp.json()
28
+ if not data.get('ok'):
29
+ raise BaleAPIError(data.get('description', 'Unknown error'),
30
+ data.get('error_code'), data.get('parameters'))
31
+ return data.get('result')
32
+ except requests.exceptions.RequestException as e:
33
+ raise BaleNetworkError(str(e))
34
+
35
+ # ----------------------- دریافت آپدیت -----------------------
36
+ def get_updates(self, offset: Optional[int] = None, limit: int = 100, timeout: int = 0) -> List[types.Update]:
37
+ if offset is None and self._offset is not None:
38
+ offset = self._offset
39
+ params = {'limit': limit, 'timeout': timeout}
40
+ if offset:
41
+ params['offset'] = offset
42
+ result = self._request('getUpdates', params)
43
+ updates = [types.Update.from_dict(u) for u in result]
44
+ if updates:
45
+ self._offset = updates[-1].update_id + 1
46
+ return updates
47
+
48
+ def start_polling(self, callback: Callable[[types.Update], None], interval: float = 0.5):
49
+ self._offset = None
50
+ while True:
51
+ try:
52
+ for update in self.get_updates():
53
+ callback(update)
54
+ except KeyboardInterrupt:
55
+ break
56
+ except Exception as e:
57
+ print(f"Polling error: {e}")
58
+ time.sleep(interval)
59
+ time.sleep(interval)
60
+
61
+ def set_webhook(self, url: str) -> bool:
62
+ return self._request('setWebhook', {'url': url}) is True
63
+
64
+ def delete_webhook(self) -> bool:
65
+ return self._request('deleteWebhook') is True
66
+
67
+ def get_webhook_info(self) -> Dict:
68
+ return self._request('getWebhookInfo')
69
+
70
+ # ----------------------- اطلاعات بازو -----------------------
71
+ def get_me(self) -> types.User:
72
+ return types.User(**self._request('getMe'))
73
+
74
+ # ----------------------- ارسال پیام -----------------------
75
+ def send_message(self, chat_id: Union[int, str], text: str,
76
+ reply_to_message_id: int = None, reply_markup: Dict = None) -> types.Message:
77
+ params = {'chat_id': chat_id, 'text': text}
78
+ if reply_to_message_id: params['reply_to_message_id'] = reply_to_message_id
79
+ if reply_markup: params['reply_markup'] = reply_markup
80
+ return types.Message.from_dict(self._request('sendMessage', params))
81
+
82
+ def forward_message(self, chat_id: Union[int, str], from_chat_id: Union[int, str],
83
+ message_id: int) -> types.Message:
84
+ params = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
85
+ return types.Message.from_dict(self._request('forwardMessage', params))
86
+
87
+ def copy_message(self, chat_id: Union[int, str], from_chat_id: Union[int, str],
88
+ message_id: int) -> types.MessageId:
89
+ params = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
90
+ return types.MessageId(**self._request('copyMessage', params))
91
+
92
+ def send_photo(self, chat_id: Union[int, str], photo: Union[str, bytes, BinaryIO],
93
+ caption: str = None, reply_to_message_id: int = None,
94
+ reply_markup: Dict = None) -> types.Message:
95
+ name, data = prepare_upload_file(photo)
96
+ params = {'chat_id': chat_id, 'caption': caption,
97
+ 'reply_to_message_id': reply_to_message_id, 'reply_markup': reply_markup}
98
+ files = None
99
+ if name and data:
100
+ files = {'photo': (name, data)}
101
+ else:
102
+ params['photo'] = data
103
+ return types.Message.from_dict(self._request('sendPhoto', params, files))
104
+
105
+ def send_audio(self, chat_id: Union[int, str], audio: Union[str, bytes, BinaryIO],
106
+ caption: str = None, reply_to_message_id: int = None,
107
+ reply_markup: Dict = None) -> types.Message:
108
+ name, data = prepare_upload_file(audio)
109
+ params = {'chat_id': chat_id, 'caption': caption,
110
+ 'reply_to_message_id': reply_to_message_id, 'reply_markup': reply_markup}
111
+ files = None
112
+ if name and data:
113
+ files = {'audio': (name, data)}
114
+ else:
115
+ params['audio'] = data
116
+ return types.Message.from_dict(self._request('sendAudio', params, files))
117
+
118
+ def send_document(self, chat_id: Union[int, str], document: Union[str, bytes, BinaryIO],
119
+ caption: str = None, reply_to_message_id: int = None,
120
+ reply_markup: Dict = None) -> types.Message:
121
+ name, data = prepare_upload_file(document)
122
+ params = {'chat_id': chat_id, 'caption': caption,
123
+ 'reply_to_message_id': reply_to_message_id, 'reply_markup': reply_markup}
124
+ files = None
125
+ if name and data:
126
+ files = {'document': (name, data)}
127
+ else:
128
+ params['document'] = data
129
+ return types.Message.from_dict(self._request('sendDocument', params, files))
130
+
131
+ def send_video(self, chat_id: Union[int, str], video: Union[str, bytes, BinaryIO],
132
+ caption: str = None, reply_to_message_id: int = None,
133
+ reply_markup: Dict = None) -> types.Message:
134
+ name, data = prepare_upload_file(video)
135
+ params = {'chat_id': chat_id, 'caption': caption,
136
+ 'reply_to_message_id': reply_to_message_id, 'reply_markup': reply_markup}
137
+ files = None
138
+ if name and data:
139
+ files = {'video': (name, data)}
140
+ else:
141
+ params['video'] = data
142
+ return types.Message.from_dict(self._request('sendVideo', params, files))
143
+
144
+ def send_animation(self, chat_id: Union[int, str], animation: Union[str, bytes, BinaryIO],
145
+ reply_to_message_id: int = None, reply_markup: Dict = None) -> types.Message:
146
+ name, data = prepare_upload_file(animation)
147
+ params = {'chat_id': chat_id, 'reply_to_message_id': reply_to_message_id, 'reply_markup': reply_markup}
148
+ files = None
149
+ if name and data:
150
+ files = {'animation': (name, data)}
151
+ else:
152
+ params['animation'] = data
153
+ return types.Message.from_dict(self._request('sendAnimation', params, files))
154
+
155
+ def send_voice(self, chat_id: Union[int, str], voice: Union[str, bytes, BinaryIO],
156
+ caption: str = None, reply_to_message_id: int = None,
157
+ reply_markup: Dict = None) -> types.Message:
158
+ name, data = prepare_upload_file(voice)
159
+ params = {'chat_id': chat_id, 'caption': caption,
160
+ 'reply_to_message_id': reply_to_message_id, 'reply_markup': reply_markup}
161
+ files = None
162
+ if name and data:
163
+ files = {'voice': (name, data)}
164
+ else:
165
+ params['voice'] = data
166
+ return types.Message.from_dict(self._request('sendVoice', params, files))
167
+
168
+ def send_media_group(self, chat_id: Union[int, str], media: List[Dict],
169
+ reply_to_message_id: int = None) -> List[types.Message]:
170
+ params = {'chat_id': chat_id, 'media': json.dumps(media), 'reply_to_message_id': reply_to_message_id}
171
+ result = self._request('sendMediaGroup', params)
172
+ return [types.Message.from_dict(msg) for msg in result]
173
+
174
+ def send_location(self, chat_id: Union[int, str], latitude: float, longitude: float,
175
+ horizontal_accuracy: float = None, reply_to_message_id: int = None,
176
+ reply_markup: Dict = None) -> types.Message:
177
+ params = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude,
178
+ 'horizontal_accuracy': horizontal_accuracy, 'reply_to_message_id': reply_to_message_id,
179
+ 'reply_markup': reply_markup}
180
+ return types.Message.from_dict(self._request('sendLocation', {k: v for k, v in params.items() if v}))
181
+
182
+ def send_contact(self, chat_id: Union[int, str], phone_number: str, first_name: str,
183
+ last_name: str = None, reply_to_message_id: int = None,
184
+ reply_markup: Dict = None) -> types.Message:
185
+ params = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name,
186
+ 'last_name': last_name, 'reply_to_message_id': reply_to_message_id, 'reply_markup': reply_markup}
187
+ return types.Message.from_dict(self._request('sendContact', {k: v for k, v in params.items() if v}))
188
+
189
+ def send_chat_action(self, chat_id: Union[int, str], action: str) -> bool:
190
+ return self._request('sendChatAction', {'chat_id': chat_id, 'action': action}) is True
191
+
192
+ # ----------------------- فایل -----------------------
193
+ def get_file(self, file_id: str) -> types.File:
194
+ return types.File(**self._request('getFile', {'file_id': file_id}))
195
+
196
+ def download_file(self, file_path: str, destination: str = None) -> Optional[bytes]:
197
+ url = f"https://tapi.bale.ai/file/bot{self.token}/{file_path}"
198
+ resp = self.session.get(url)
199
+ resp.raise_for_status()
200
+ if destination:
201
+ with open(destination, 'wb') as f:
202
+ f.write(resp.content)
203
+ return None
204
+ return resp.content
205
+
206
+ # ----------------------- پاسخ به callback -----------------------
207
+ def answer_callback_query(self, callback_query_id: str, text: str = None, show_alert: bool = False) -> bool:
208
+ params = {'callback_query_id': callback_query_id, 'text': text, 'show_alert': show_alert}
209
+ return self._request('answerCallbackQuery', {k: v for k, v in params.items() if v}) is True
210
+
211
+ def ask_review(self, user_id: int, delay_seconds: int = 0) -> bool:
212
+ return self._request('askReview', {'user_id': user_id, 'delay_seconds': delay_seconds}) is True
213
+
214
+ # ----------------------- مدیریت گروه -----------------------
215
+ def ban_chat_member(self, chat_id: Union[int, str], user_id: int) -> bool:
216
+ return self._request('banChatMember', {'chat_id': chat_id, 'user_id': user_id}) is True
217
+
218
+ def unban_chat_member(self, chat_id: Union[int, str], user_id: int, only_if_banned: bool = True) -> bool:
219
+ return self._request('unbanChatMember', {'chat_id': chat_id, 'user_id': user_id, 'only_if_banned': only_if_banned}) is True
220
+
221
+ def promote_chat_member(self, chat_id: Union[int, str], user_id: int,
222
+ can_change_info=False, can_post_messages=False, can_edit_messages=False,
223
+ can_delete_messages=False, can_manage_video_chats=False,
224
+ can_invite_users=False, can_restrict_members=False) -> bool:
225
+ params = {'chat_id': chat_id, 'user_id': user_id, 'can_change_info': can_change_info,
226
+ 'can_post_messages': can_post_messages, 'can_edit_messages': can_edit_messages,
227
+ 'can_delete_messages': can_delete_messages, 'can_manage_video_chats': can_manage_video_chats,
228
+ 'can_invite_users': can_invite_users, 'can_restrict_members': can_restrict_members}
229
+ return self._request('promoteChatMember', {k: v for k, v in params.items() if v}) is True
230
+
231
+ def set_chat_photo(self, chat_id: Union[int, str], photo: Union[str, bytes, BinaryIO]) -> bool:
232
+ name, data = prepare_upload_file(photo)
233
+ if not name or not isinstance(data, (bytes, BinaryIO)):
234
+ raise ValueError("فقط آپلود فایل محلی پشتیبانی می‌شود")
235
+ return self._request('setChatPhoto', {'chat_id': chat_id}, files={'photo': (name, data)}) is True
236
+
237
+ def delete_chat_photo(self, chat_id: Union[int, str]) -> bool:
238
+ return self._request('deleteChatPhoto', {'chat_id': chat_id}) is True
239
+
240
+ def leave_chat(self, chat_id: Union[int, str]) -> bool:
241
+ return self._request('leaveChat', {'chat_id': chat_id}) is True
242
+
243
+ def get_chat(self, chat_id: Union[int, str]) -> types.ChatFullInfo:
244
+ return types.ChatFullInfo(**self._request('getChat', {'chat_id': chat_id}))
245
+
246
+ def get_chat_administrators(self, chat_id: Union[int, str]) -> List[types.ChatMember]:
247
+ result = self._request('getChatAdministrators', {'chat_id': chat_id})
248
+ return [types.ChatMember.from_dict(admin) for admin in result]
249
+
250
+ def get_chat_members_count(self, chat_id: Union[int, str]) -> int:
251
+ return self._request('getChatMembersCount', {'chat_id': chat_id})
252
+
253
+ def get_chat_member(self, chat_id: Union[int, str], user_id: int) -> types.ChatMember:
254
+ return types.ChatMember.from_dict(self._request('getChatMember', {'chat_id': chat_id, 'user_id': user_id}))
255
+
256
+ def pin_chat_message(self, chat_id: Union[int, str], message_id: int) -> bool:
257
+ return self._request('pinChatMessage', {'chat_id': chat_id, 'message_id': message_id}) is True
258
+
259
+ def unpin_chat_message(self, chat_id: Union[int, str], message_id: int) -> bool:
260
+ return self._request('unpinChatMessage', {'chat_id': chat_id, 'message_id': message_id}) is True
261
+
262
+ def unpin_all_chat_messages(self, chat_id: Union[int, str]) -> bool:
263
+ return self._request('unpinAllChatMessages', {'chat_id': chat_id}) is True
264
+
265
+ def set_chat_title(self, chat_id: Union[int, str], title: str) -> bool:
266
+ return self._request('setChatTitle', {'chat_id': chat_id, 'title': title}) is True
267
+
268
+ def set_chat_description(self, chat_id: Union[int, str], description: str) -> bool:
269
+ return self._request('setChatDescription', {'chat_id': chat_id, 'description': description}) is True
270
+
271
+ def create_chat_invite_link(self, chat_id: Union[int, str]) -> str:
272
+ return self._request('createChatInviteLink', {'chat_id': chat_id})
273
+
274
+ def revoke_chat_invite_link(self, chat_id: Union[int, str], invite_link: str) -> str:
275
+ return self._request('revokeChatInviteLink', {'chat_id': chat_id, 'invite_link': invite_link})
276
+
277
+ def export_chat_invite_link(self, chat_id: Union[int, str]) -> str:
278
+ return self._request('exportChatInviteLink', {'chat_id': chat_id})
279
+
280
+ # ----------------------- ویرایش پیام -----------------------
281
+ def edit_message_text(self, chat_id: Union[int, str], message_id: int, text: str,
282
+ reply_markup: Dict = None) -> types.Message:
283
+ params = {'chat_id': chat_id, 'message_id': message_id, 'text': text, 'reply_markup': reply_markup}
284
+ return types.Message.from_dict(self._request('editMessageText', {k: v for k, v in params.items() if v}))
285
+
286
+ def edit_message_caption(self, chat_id: Union[int, str], message_id: int, caption: str,
287
+ reply_markup: Dict = None) -> types.Message:
288
+ params = {'chat_id': chat_id, 'message_id': message_id, 'caption': caption, 'reply_markup': reply_markup}
289
+ return types.Message.from_dict(self._request('editMessageCaption', {k: v for k, v in params.items() if v}))
290
+
291
+ def edit_message_reply_markup(self, chat_id: Union[int, str], message_id: int,
292
+ reply_markup: Dict) -> types.Message:
293
+ params = {'chat_id': chat_id, 'message_id': message_id, 'reply_markup': reply_markup}
294
+ return types.Message.from_dict(self._request('editMessageReplyMarkup', params))
295
+
296
+ def delete_message(self, chat_id: Union[int, str], message_id: int) -> bool:
297
+ return self._request('deleteMessage', {'chat_id': chat_id, 'message_id': message_id}) is True
298
+
299
+ # ----------------------- پرداخت -----------------------
300
+ def send_invoice(self, chat_id: Union[int, str], title: str, description: str,
301
+ payload: str, provider_token: str, prices: List[Dict],
302
+ photo_url: str = None, reply_to_message_id: int = None) -> types.Message:
303
+ params = {'chat_id': chat_id, 'title': title, 'description': description, 'payload': payload,
304
+ 'provider_token': provider_token, 'prices': json.dumps(prices), 'photo_url': photo_url,
305
+ 'reply_to_message_id': reply_to_message_id}
306
+ return types.Message.from_dict(self._request('sendInvoice', {k: v for k, v in params.items() if v}))
307
+
308
+ def create_invoice_link(self, title: str, description: str, payload: str,
309
+ provider_token: str, prices: List[Dict]) -> str:
310
+ params = {'title': title, 'description': description, 'payload': payload,
311
+ 'provider_token': provider_token, 'prices': json.dumps(prices)}
312
+ return self._request('createInvoiceLink', params)
313
+
314
+ def answer_pre_checkout_query(self, pre_checkout_query_id: str, ok: bool,
315
+ error_message: str = None) -> bool:
316
+ params = {'pre_checkout_query_id': pre_checkout_query_id, 'ok': ok, 'error_message': error_message}
317
+ return self._request('answerPreCheckoutQuery', {k: v for k, v in params.items() if v}) is True
318
+
319
+ def inquire_transaction(self, transaction_id: str) -> Dict:
320
+ return self._request('inquireTransaction', {'transaction_id': transaction_id})
321
+
322
+ # ----------------------- استیکر -----------------------
323
+ def upload_sticker_file(self, user_id: int, sticker: Union[str, bytes, BinaryIO]) -> types.File:
324
+ name, data = prepare_upload_file(sticker)
325
+ params = {'user_id': user_id}
326
+ files = None
327
+ if name and data:
328
+ files = {'sticker': (name, data)}
329
+ else:
330
+ params['sticker'] = data
331
+ return types.File(**self._request('uploadStickerFile', params, files))
332
+
333
+ def create_new_sticker_set(self, user_id: int, name: str, title: str,
334
+ stickers: List[Dict]) -> bool:
335
+ params = {'user_id': user_id, 'name': name, 'title': title, 'stickers': json.dumps(stickers)}
336
+ return self._request('createNewStickerSet', params) is True
337
+
338
+ def add_sticker_to_set(self, user_id: int, name: str, sticker: Dict) -> bool:
339
+ params = {'user_id': user_id, 'name': name, 'sticker': json.dumps(sticker)}
340
+ return self._request('addStickerToSet', params) is True
@@ -0,0 +1,11 @@
1
+ class BaleError(Exception):
2
+ def __init__(self, message, error_code=None, parameters=None):
3
+ super().__init__(message)
4
+ self.error_code = error_code
5
+ self.parameters = parameters
6
+
7
+ class BaleAPIError(BaleError):
8
+ pass
9
+
10
+ class BaleNetworkError(BaleError):
11
+ pass
@@ -0,0 +1,26 @@
1
+ import os
2
+ from typing import List, Dict, Union, Any
3
+
4
+ def make_reply_keyboard(buttons: List[List[str]], resize_keyboard=True, one_time_keyboard=False):
5
+ return {
6
+ "keyboard": [[{"text": btn} for btn in row] for row in buttons],
7
+ "resize_keyboard": resize_keyboard,
8
+ "one_time_keyboard": one_time_keyboard
9
+ }
10
+
11
+ def make_inline_keyboard(buttons: List[List[Dict[str, str]]]):
12
+ return {"inline_keyboard": buttons}
13
+
14
+ def remove_keyboard():
15
+ return {"remove_keyboard": True}
16
+
17
+ def prepare_upload_file(file_input):
18
+ if isinstance(file_input, str):
19
+ if file_input.startswith(('http://', 'https://')):
20
+ return None, file_input
21
+ if os.path.isfile(file_input):
22
+ return os.path.basename(file_input), open(file_input, 'rb')
23
+ return None, file_input
24
+ elif isinstance(file_input, bytes):
25
+ return "file.bin", file_input
26
+ raise ValueError("نوع فایل پشتیبانی نمی‌شود")
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.4
2
+ Name: botbaleirp
3
+ Version: 0.0.1
4
+ Summary: کتابخانه کامل پایتون برای API بازوی بله
5
+ Author: Mohammad Latifi
6
+ Requires-Python: >=3.7
7
+ Requires-Dist: requests>=2.25.0
8
+ Dynamic: author
9
+ Dynamic: requires-dist
10
+ Dynamic: requires-python
11
+ Dynamic: summary
@@ -0,0 +1,11 @@
1
+ setup.py
2
+ botbaleirp/__init__.py
3
+ botbaleirp/bale_types.py
4
+ botbaleirp/bot.py
5
+ botbaleirp/errors.py
6
+ botbaleirp/utils.py
7
+ botbaleirp.egg-info/PKG-INFO
8
+ botbaleirp.egg-info/SOURCES.txt
9
+ botbaleirp.egg-info/dependency_links.txt
10
+ botbaleirp.egg-info/requires.txt
11
+ botbaleirp.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ requests>=2.25.0
@@ -0,0 +1 @@
1
+ botbaleirp
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,11 @@
1
+ from setuptools import setup
2
+
3
+ setup(
4
+ name="botbaleirp",
5
+ version="0.0.1",
6
+ author="Mohammad Latifi",
7
+ description="کتابخانه کامل پایتون برای API بازوی بله",
8
+ packages=["botbaleirp"],
9
+ install_requires=["requests>=2.25.0"],
10
+ python_requires=">=3.7",
11
+ )