Telegram-Py-Arang 0.0.1__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.
Files changed (87) hide show
  1. pyrogram/__init__.py +34 -0
  2. pyrogram/__main__.py +18 -0
  3. pyrogram/client.py +353 -0
  4. pyrogram/dispatcher.py +63 -0
  5. pyrogram/enums/__init__.py +18 -0
  6. pyrogram/enums/chat_action.py +15 -0
  7. pyrogram/enums/chat_member_status.py +10 -0
  8. pyrogram/enums/chat_type.py +8 -0
  9. pyrogram/enums/message_entity_type.py +23 -0
  10. pyrogram/enums/message_service_type.py +35 -0
  11. pyrogram/enums/parse_mode.py +7 -0
  12. pyrogram/enums/update_type.py +30 -0
  13. pyrogram/errors/__init__.py +25 -0
  14. pyrogram/errors/bad_request.py +5 -0
  15. pyrogram/errors/conflict.py +5 -0
  16. pyrogram/errors/flood_wait.py +12 -0
  17. pyrogram/errors/forbidden.py +5 -0
  18. pyrogram/errors/internal_server_error.py +5 -0
  19. pyrogram/errors/map_error.py +45 -0
  20. pyrogram/errors/message_not_modified.py +5 -0
  21. pyrogram/errors/not_found.py +5 -0
  22. pyrogram/errors/rpc_error.py +13 -0
  23. pyrogram/errors/service_unavailable.py +5 -0
  24. pyrogram/errors/unauthorized.py +5 -0
  25. pyrogram/filters.py +191 -0
  26. pyrogram/handlers/__init__.py +23 -0
  27. pyrogram/handlers/base.py +13 -0
  28. pyrogram/handlers/callback_query_handler.py +19 -0
  29. pyrogram/handlers/chat_join_request_handler.py +19 -0
  30. pyrogram/handlers/chat_member_updated_handler.py +21 -0
  31. pyrogram/handlers/inline_query_handler.py +19 -0
  32. pyrogram/handlers/message_handler.py +36 -0
  33. pyrogram/handlers/message_reaction_handler.py +24 -0
  34. pyrogram/handlers/poll_answer_handler.py +19 -0
  35. pyrogram/handlers/poll_handler.py +17 -0
  36. pyrogram/handlers/raw_update_handler.py +11 -0
  37. pyrogram/http.py +51 -0
  38. pyrogram/idle.py +28 -0
  39. pyrogram/methods.py +425 -0
  40. pyrogram/py.typed +0 -0
  41. pyrogram/session.py +132 -0
  42. pyrogram/sync.py +36 -0
  43. pyrogram/types/__init__.py +92 -0
  44. pyrogram/types/business_connection.py +18 -0
  45. pyrogram/types/business_messages_deleted.py +12 -0
  46. pyrogram/types/callback_query.py +36 -0
  47. pyrogram/types/chat.py +128 -0
  48. pyrogram/types/chat_boost.py +53 -0
  49. pyrogram/types/chat_join_request.py +34 -0
  50. pyrogram/types/chat_member.py +61 -0
  51. pyrogram/types/chat_member_updated.py +39 -0
  52. pyrogram/types/chosen_inline_result.py +15 -0
  53. pyrogram/types/file.py +12 -0
  54. pyrogram/types/inline_query.py +20 -0
  55. pyrogram/types/keyboard.py +138 -0
  56. pyrogram/types/labeled_price.py +15 -0
  57. pyrogram/types/link_preview_options.py +15 -0
  58. pyrogram/types/message.py +300 -0
  59. pyrogram/types/message_entity.py +17 -0
  60. pyrogram/types/message_origin.py +71 -0
  61. pyrogram/types/message_reaction_count_updated.py +14 -0
  62. pyrogram/types/message_reaction_updated.py +27 -0
  63. pyrogram/types/object.py +22 -0
  64. pyrogram/types/order_info.py +16 -0
  65. pyrogram/types/paid_media.py +44 -0
  66. pyrogram/types/poll.py +47 -0
  67. pyrogram/types/poll_answer.py +16 -0
  68. pyrogram/types/pre_checkout_query.py +27 -0
  69. pyrogram/types/purchased_paid_media.py +13 -0
  70. pyrogram/types/reaction_type.py +27 -0
  71. pyrogram/types/refunded_payment.py +16 -0
  72. pyrogram/types/reply_parameters.py +29 -0
  73. pyrogram/types/shipping_address.py +15 -0
  74. pyrogram/types/shipping_option.py +14 -0
  75. pyrogram/types/shipping_query.py +17 -0
  76. pyrogram/types/successful_payment.py +26 -0
  77. pyrogram/types/user.py +35 -0
  78. pyrogram/types/vanue.py +19 -0
  79. pyrogram/types/web_app_data.py +10 -0
  80. pyrogram/utils/__init__.py +18 -0
  81. pyrogram/utils/file.py +35 -0
  82. pyrogram/utils/helpers.py +36 -0
  83. telegram_py_arang-0.0.1.dist-info/METADATA +481 -0
  84. telegram_py_arang-0.0.1.dist-info/RECORD +87 -0
  85. telegram_py_arang-0.0.1.dist-info/WHEEL +5 -0
  86. telegram_py_arang-0.0.1.dist-info/licenses/LICENSE +674 -0
  87. telegram_py_arang-0.0.1.dist-info/top_level.txt +1 -0
pyrogram/__init__.py ADDED
@@ -0,0 +1,34 @@
1
+ """
2
+ TelePy
3
+ ~~~~~~
4
+ Pyrogram-style framework for Telegram bots.
5
+ Bot-only. Backend: Telegram Bot API 8.x via aiohttp.
6
+ Tidak ada userbot, tidak ada MTProto, tidak ada crypto.
7
+ """
8
+
9
+ __version__ = "0.0.1"
10
+ __license__ = "LGPL-3.0-or-later"
11
+ __author__ = "TelePy Contributors"
12
+
13
+ from .client import Client
14
+ from .idle import idle
15
+ from .session import Session, MemoryStorage, SQLiteStorage
16
+ from .types import (
17
+ User, Chat, ChatMember, Message, CallbackQuery, InlineQuery,
18
+ InlineKeyboardMarkup, InlineKeyboardButton,
19
+ ReplyKeyboardMarkup, KeyboardButton,
20
+ ReplyKeyboardRemove, ForceReply, CopyTextButton,
21
+ LinkPreviewOptions, ReplyParameters,
22
+ )
23
+ from . import filters, enums, errors, handlers, types, utils
24
+
25
+ __all__ = [
26
+ "Client", "idle", "Session", "MemoryStorage", "SQLiteStorage",
27
+ "filters", "enums", "errors", "handlers", "types", "utils",
28
+ "User", "Chat", "ChatMember", "Message",
29
+ "CallbackQuery", "InlineQuery",
30
+ "InlineKeyboardMarkup", "InlineKeyboardButton",
31
+ "ReplyKeyboardMarkup", "KeyboardButton",
32
+ "ReplyKeyboardRemove", "ForceReply", "CopyTextButton",
33
+ "LinkPreviewOptions", "ReplyParameters",
34
+ ]
pyrogram/__main__.py ADDED
@@ -0,0 +1,18 @@
1
+ """Entry point CLI: `telepy <script.py>` atau `python -m pyrogram <script.py>`."""
2
+
3
+ import runpy
4
+ import sys
5
+
6
+
7
+ def main():
8
+ if len(sys.argv) < 2:
9
+ print("TelePy — Pyrogram bot-only fork")
10
+ print("Usage: telepy <module.py>")
11
+ print(" or: python -m pyrogram <module.py>")
12
+ sys.exit(0)
13
+
14
+ runpy.run_path(sys.argv[1], run_name="__main__")
15
+
16
+
17
+ if __name__ == "__main__":
18
+ main()
pyrogram/client.py ADDED
@@ -0,0 +1,353 @@
1
+ """
2
+ Client — pintu masuk utama TelePy.
3
+
4
+ Contoh:
5
+ from pyrogram import Client, filters
6
+
7
+ app = Client("BOT_TOKEN")
8
+
9
+ @app.on_message(filters.text)
10
+ async def echo(client, message):
11
+ await message.reply_text(message.text)
12
+
13
+ app.run()
14
+ """
15
+
16
+ import asyncio
17
+ import logging
18
+ from typing import Optional
19
+
20
+ from .dispatcher import Dispatcher
21
+ from .errors import map_error
22
+ from .filters import filters
23
+ from .handlers import (
24
+ MessageHandler,
25
+ CallbackQueryHandler,
26
+ InlineQueryHandler,
27
+ ChatMemberUpdatedHandler,
28
+ ChatJoinRequestHandler,
29
+ PollHandler,
30
+ PollAnswerHandler,
31
+ MessageReactionHandler,
32
+ RawUpdateHandler,
33
+ )
34
+ from .http import get_session, close_pool
35
+ from .methods import AllMethods
36
+ from .session import Session, MemoryStorage
37
+
38
+ log = logging.getLogger(__name__)
39
+
40
+ DEFAULT_API = "https://api.telegram.org/bot{token}/{method}"
41
+ DEFAULT_FILE = "https://api.telegram.org/file/bot{token}/{path}"
42
+
43
+ # Update yang diminta dari getUpdates
44
+ ALLOWED_UPDATES = [
45
+ "message",
46
+ "edited_message",
47
+ "channel_post",
48
+ "edited_channel_post",
49
+ "callback_query",
50
+ "inline_query",
51
+ "chosen_inline_result",
52
+ "my_chat_member",
53
+ "chat_member",
54
+ "chat_join_request",
55
+ "poll",
56
+ "poll_answer",
57
+ "message_reaction",
58
+ "message_reaction_count",
59
+ "pre_checkout_query",
60
+ "shipping_query",
61
+ "business_connection",
62
+ "business_message",
63
+ "edited_business_message",
64
+ "purchased_paid_media",
65
+ ]
66
+
67
+
68
+ class Client(AllMethods):
69
+ """
70
+ Pyrogram-style bot client. Bot-only. Multi-bot friendly.
71
+
72
+ Parameter:
73
+ bot_token : Token bot dari @BotFather (wajib).
74
+ name : Nama session file (default "pyrogram").
75
+ parse_mode : "HTML" / "Markdown" / "MarkdownV2" / None.
76
+ workers : Batas konkurensi request.
77
+ storage : Objek storage (MemoryStorage default).
78
+ proxy : URL proxy aiohttp (opsional).
79
+ flood_retry : Retry otomatis saat FloodWait (default True).
80
+ store_raw : Simpan raw JSON di tipe (default False, hemat RAM).
81
+ api_url : URL Bot API kustom (mis. local Bot API server).
82
+ """
83
+
84
+ def __init__(
85
+ self,
86
+ bot_token: str = None,
87
+ name: str = "pyrogram",
88
+ parse_mode: Optional[str] = None,
89
+ workers: int = 4,
90
+ storage=None,
91
+ proxy: Optional[str] = None,
92
+ flood_retry: bool = True,
93
+ store_raw: bool = False,
94
+ api_url: Optional[str] = None,
95
+ ):
96
+ if not bot_token:
97
+ raise ValueError("bot_token wajib diisi")
98
+
99
+ self.bot_token = bot_token
100
+ self.name = name
101
+ self.parse_mode = parse_mode
102
+ self.workers = workers
103
+ self.proxy = proxy
104
+ self.flood_retry = flood_retry
105
+ self.store_raw = store_raw
106
+
107
+ self.api_url = api_url or DEFAULT_API
108
+ self.file_url = DEFAULT_FILE
109
+
110
+ self.session = Session(name)
111
+ self.storage = storage or MemoryStorage()
112
+ self.dispatcher = Dispatcher(self)
113
+
114
+ self._offset = self.session.get("offset", 0)
115
+ self._running = False
116
+ self._poll_task = None
117
+ self._sem = asyncio.Semaphore(workers)
118
+ self._http = None
119
+ self.me = None
120
+
121
+ # =================== Decorators ===================
122
+ def on_message(self, filter=None, group: int = 0):
123
+ f = filter or filters.all
124
+
125
+ def deco(func):
126
+ self.dispatcher.add_handler(
127
+ MessageHandler(func, f, group, edited=False)
128
+ )
129
+ return func
130
+ return deco
131
+
132
+ def on_edited_message(self, filter=None, group: int = 0):
133
+ f = filter or filters.all
134
+
135
+ def deco(func):
136
+ self.dispatcher.add_handler(
137
+ MessageHandler(func, f, group, edited=True)
138
+ )
139
+ return func
140
+ return deco
141
+
142
+ def on_channel_post(self, filter=None, group: int = 0):
143
+ f = filter or filters.all
144
+
145
+ def deco(func):
146
+ self.dispatcher.add_handler(
147
+ MessageHandler(func, f, group, edited=False)
148
+ )
149
+ return func
150
+ return deco
151
+
152
+ def on_edited_channel_post(self, filter=None, group: int = 0):
153
+ f = filter or filters.all
154
+
155
+ def deco(func):
156
+ self.dispatcher.add_handler(
157
+ MessageHandler(func, f, group, edited=True)
158
+ )
159
+ return func
160
+ return deco
161
+
162
+ def on_callback_query(self, filter=None, group: int = 0):
163
+ f = filter or filters.all
164
+
165
+ def deco(func):
166
+ self.dispatcher.add_handler(CallbackQueryHandler(func, f, group))
167
+ return func
168
+ return deco
169
+
170
+ def on_inline_query(self, filter=None, group: int = 0):
171
+ f = filter or filters.all
172
+
173
+ def deco(func):
174
+ self.dispatcher.add_handler(InlineQueryHandler(func, f, group))
175
+ return func
176
+ return deco
177
+
178
+ def on_chat_member_updated(self, filter=None, group: int = 0):
179
+ f = filter or filters.all
180
+
181
+ def deco(func):
182
+ self.dispatcher.add_handler(ChatMemberUpdatedHandler(func, f, group))
183
+ return func
184
+ return deco
185
+
186
+ def on_chat_join_request(self, filter=None, group: int = 0):
187
+ f = filter or filters.all
188
+
189
+ def deco(func):
190
+ self.dispatcher.add_handler(ChatJoinRequestHandler(func, f, group))
191
+ return func
192
+ return deco
193
+
194
+ def on_poll(self, filter=None, group: int = 0):
195
+ f = filter or filters.all
196
+
197
+ def deco(func):
198
+ self.dispatcher.add_handler(PollHandler(func, f, group))
199
+ return func
200
+ return deco
201
+
202
+ def on_poll_answer(self, filter=None, group: int = 0):
203
+ f = filter or filters.all
204
+
205
+ def deco(func):
206
+ self.dispatcher.add_handler(PollAnswerHandler(func, f, group))
207
+ return func
208
+ return deco
209
+
210
+ def on_message_reaction(self, filter=None, group: int = 0):
211
+ f = filter or filters.all
212
+
213
+ def deco(func):
214
+ self.dispatcher.add_handler(MessageReactionHandler(func, f, group))
215
+ return func
216
+ return deco
217
+
218
+ def on_raw_update(self, group: int = 0):
219
+ def deco(func):
220
+ self.dispatcher.add_handler(RawUpdateHandler(func, filters.all, group))
221
+ return func
222
+ return deco
223
+
224
+ # =================== Middleware ===================
225
+ def add_middleware(self, middleware, group: int = 0):
226
+ self.dispatcher.add_middleware(middleware, group)
227
+
228
+ # =================== HTTP ===================
229
+ async def _ensure_http(self):
230
+ if self._http is None:
231
+ self._http = await get_session()
232
+ return self._http
233
+
234
+ async def _request(self, method: str, **params):
235
+ sess = await self._ensure_http()
236
+ url = self.api_url.format(token=self.bot_token, method=method)
237
+ payload = {k: v for k, v in params.items() if v is not None}
238
+
239
+ for attempt in range(2):
240
+ async with self._sem:
241
+ async with sess.post(url, json=payload, proxy=self.proxy) as resp:
242
+ data = await resp.json(content_type=None)
243
+
244
+ if data.get("ok"):
245
+ return data["result"]
246
+
247
+ err = map_error(
248
+ data.get("error_code", 400),
249
+ data.get("description", "unknown error"),
250
+ )
251
+
252
+ if (
253
+ self.flood_retry
254
+ and getattr(err, "seconds", None)
255
+ and attempt == 0
256
+ ):
257
+ log.warning(
258
+ "FloodWait %ss — retry %s", err.seconds, method
259
+ )
260
+ await asyncio.sleep(err.seconds + 1)
261
+ continue
262
+
263
+ raise err
264
+
265
+ raise RuntimeError(f"Request {method} gagal setelah retry")
266
+
267
+ # =================== Polling ===================
268
+ async def _polling_loop(self):
269
+ while self._running:
270
+ try:
271
+ updates = await self._request(
272
+ "getUpdates",
273
+ offset=self._offset,
274
+ timeout=30,
275
+ allowed_updates=ALLOWED_UPDATES,
276
+ )
277
+
278
+ for u in updates:
279
+ self._offset = u["update_id"] + 1
280
+ self.session.set("offset", self._offset)
281
+ await self.dispatcher.feed(u)
282
+
283
+ except asyncio.CancelledError:
284
+ break
285
+ except Exception as e:
286
+ log.exception("Polling error: %s", e)
287
+ await asyncio.sleep(3)
288
+
289
+ # =================== Lifecycle ===================
290
+ async def start(self):
291
+ """Mulai bot: login, ambil info, jalankan polling."""
292
+ if self._running:
293
+ return
294
+
295
+ await self._ensure_http()
296
+ self.me = await self.get_me()
297
+ log.info("Bot started: @%s (id=%s)",
298
+ self.me.get("username"), self.me.get("id"))
299
+
300
+ self._running = True
301
+ self._poll_task = asyncio.create_task(self._polling_loop())
302
+
303
+ async def stop(self):
304
+ """Hentikan bot."""
305
+ self._running = False
306
+
307
+ if self._poll_task:
308
+ self._poll_task.cancel()
309
+ try:
310
+ await self._poll_task
311
+ except asyncio.CancelledError:
312
+ pass
313
+ self._poll_task = None
314
+
315
+ log.info("Bot stopped")
316
+
317
+ async def idle(self):
318
+ from .idle import idle as _idle
319
+ try:
320
+ await _idle()
321
+ finally:
322
+ await self.stop()
323
+
324
+ def run(self):
325
+ """
326
+ Blocking entry point — mirip pyrogram.Client.run().
327
+
328
+ Menjalankan start(), menahan sampai Ctrl+C, lalu stop().
329
+ """
330
+ async def _main():
331
+ await self.start()
332
+ try:
333
+ await self.idle()
334
+ except KeyboardInterrupt:
335
+ await self.stop()
336
+
337
+ try:
338
+ asyncio.run(_main())
339
+ finally:
340
+ # Tutup pool aiohttp global (kalau tidak ada client lain)
341
+ try:
342
+ loop = asyncio.new_event_loop()
343
+ loop.run_until_complete(close_pool())
344
+ loop.close()
345
+ except Exception:
346
+ pass
347
+
348
+ async def __aenter__(self):
349
+ await self.start()
350
+ return self
351
+
352
+ async def __aexit__(self, *exc):
353
+ await self.stop()
pyrogram/dispatcher.py ADDED
@@ -0,0 +1,63 @@
1
+ """
2
+ Dispatcher: menerima update dari polling/webhook dan menyalurkannya
3
+ ke handler sesuai urutan `group`.
4
+
5
+ Middleware bisa disisipkan dengan `add_middleware(mw, group=...)`.
6
+ Middleware berjalan sebelum handler, bisa memanggil `await next()` untuk
7
+ melanjutkan, atau tidak memanggilnya untuk menggugurkan update.
8
+ """
9
+
10
+ import asyncio
11
+ import logging
12
+
13
+ from .errors import RPCError
14
+
15
+ log = logging.getLogger(__name__)
16
+
17
+
18
+ class Dispatcher:
19
+ def __init__(self, client):
20
+ self.client = client
21
+ self.handlers = []
22
+ self.middlewares = []
23
+ self._sem = asyncio.Semaphore(max(4, client.workers))
24
+
25
+ def add_handler(self, handler):
26
+ self.handlers.append(handler)
27
+ self.handlers.sort(key=lambda h: h.group)
28
+
29
+ def add_middleware(self, middleware, group=0):
30
+ self.middlewares.append((group, middleware))
31
+ self.middlewares.sort(key=lambda x: x[0])
32
+
33
+ async def feed(self, update: dict):
34
+ """Terima update — dispatch di task terpisah, dibatasi semaphore."""
35
+ async with self._sem:
36
+ asyncio.create_task(self._dispatch(update))
37
+
38
+ async def _dispatch(self, update: dict):
39
+ async def terminal():
40
+ for handler in self.handlers:
41
+ try:
42
+ if await handler.check(self.client, update):
43
+ await handler.handle(self.client, update)
44
+ except RPCError as e:
45
+ log.warning("RPC error di handler %r: %s", handler, e)
46
+ except Exception:
47
+ log.exception("Handler error di %r", handler)
48
+
49
+ async def run_chain(i=0):
50
+ if i >= len(self.middlewares):
51
+ await terminal()
52
+ return
53
+ _, mw = self.middlewares[i]
54
+
55
+ async def nxt():
56
+ await run_chain(i + 1)
57
+
58
+ try:
59
+ await mw(self.client, update, nxt)
60
+ except Exception:
61
+ log.exception("Middleware error di %r", mw)
62
+
63
+ await run_chain()
@@ -0,0 +1,18 @@
1
+ from .chat_action import ChatAction
2
+ from .chat_member_status import ChatMemberStatus
3
+ from .chat_type import ChatType
4
+ from .message_entity_type import MessageEntityType
5
+ from .message_service_type import MessageServiceType
6
+ from .parse_mode import ParseMode
7
+ from .update_type import UpdateType, ALLOWED_UPDATES
8
+
9
+ __all__ = [
10
+ "ChatAction",
11
+ "ChatMemberStatus",
12
+ "ChatType",
13
+ "MessageEntityType",
14
+ "MessageServiceType",
15
+ "ParseMode",
16
+ "UpdateType",
17
+ "ALLOWED_UPDATES",
18
+ ]
@@ -0,0 +1,15 @@
1
+ from enum import Enum
2
+
3
+
4
+ class ChatAction(str, Enum):
5
+ TYPING = "typing"
6
+ UPLOAD_PHOTO = "upload_photo"
7
+ RECORD_VIDEO = "record_video"
8
+ UPLOAD_VIDEO = "upload_video"
9
+ RECORD_VOICE = "record_voice"
10
+ UPLOAD_VOICE = "upload_voice"
11
+ UPLOAD_DOCUMENT = "upload_document"
12
+ CHOOSE_STICKER = "choose_sticker"
13
+ FIND_LOCATION = "find_location"
14
+ RECORD_VIDEO_NOTE = "record_video_note"
15
+ UPLOAD_VIDEO_NOTE = "upload_video_note"
@@ -0,0 +1,10 @@
1
+ from enum import Enum
2
+
3
+
4
+ class ChatMemberStatus(str, Enum):
5
+ CREATOR = "creator"
6
+ ADMINISTRATOR = "administrator"
7
+ MEMBER = "member"
8
+ RESTRICTED = "restricted"
9
+ LEFT = "left"
10
+ KICKED = "kicked"
@@ -0,0 +1,8 @@
1
+ from enum import Enum
2
+
3
+
4
+ class ChatType(str, Enum):
5
+ PRIVATE = "private"
6
+ GROUP = "group"
7
+ SUPERGROUP = "supergroup"
8
+ CHANNEL = "channel"
@@ -0,0 +1,23 @@
1
+ from enum import Enum
2
+
3
+
4
+ class MessageEntityType(str, Enum):
5
+ MENTION = "mention"
6
+ HASHTAG = "hashtag"
7
+ CASHTAG = "cashtag"
8
+ BOT_COMMAND = "bot_command"
9
+ URL = "url"
10
+ EMAIL = "email"
11
+ PHONE_NUMBER = "phone_number"
12
+ BOLD = "bold"
13
+ ITALIC = "italic"
14
+ UNDERLINE = "underline"
15
+ STRIKETHROUGH = "strikethrough"
16
+ SPOILER = "spoiler"
17
+ BLOCKQUOTE = "blockquote"
18
+ EXPANDABLE_BLOCKQUOTE = "expandable_blockquote"
19
+ CODE = "code"
20
+ PRE = "pre"
21
+ TEXT_LINK = "text_link"
22
+ TEXT_MENTION = "text_mention"
23
+ CUSTOM_EMOJI = "custom_emoji"
@@ -0,0 +1,35 @@
1
+ from enum import Enum
2
+
3
+
4
+ class MessageServiceType(str, Enum):
5
+ NEW_CHAT_MEMBERS = "new_chat_members"
6
+ LEFT_CHAT_MEMBER = "left_chat_member"
7
+ NEW_CHAT_TITLE = "new_chat_title"
8
+ NEW_CHAT_PHOTO = "new_chat_photo"
9
+ DELETE_CHAT_PHOTO = "delete_chat_photo"
10
+ GROUP_CHAT_CREATED = "group_chat_created"
11
+ SUPERGROUP_CHAT_CREATED = "supergroup_chat_created"
12
+ CHANNEL_CHAT_CREATED = "channel_chat_created"
13
+ MESSAGE_AUTO_DELETE_TIMER_CHANGED = "message_auto_delete_timer_changed"
14
+ MIGRATE_TO_CHAT_ID = "migrate_to_chat_id"
15
+ MIGRATE_FROM_CHAT_ID = "migrate_from_chat_id"
16
+ PINNED_MESSAGE = "pinned_message"
17
+ FORUM_TOPIC_CREATED = "forum_topic_created"
18
+ FORUM_TOPIC_EDITED = "forum_topic_edited"
19
+ FORUM_TOPIC_CLOSED = "forum_topic_closed"
20
+ FORUM_TOPIC_REOPENED = "forum_topic_reopened"
21
+ GENERAL_FORUM_TOPIC_HIDDEN = "general_forum_topic_hidden"
22
+ GENERAL_FORUM_TOPIC_UNHIDDEN = "general_forum_topic_unhidden"
23
+ VIDEO_CHAT_SCHEDULED = "video_chat_scheduled"
24
+ VIDEO_CHAT_STARTED = "video_chat_started"
25
+ VIDEO_CHAT_ENDED = "video_chat_ended"
26
+ VIDEO_CHAT_PARTICIPANTS_INVITED = "video_chat_participants_invited"
27
+ WEB_APP_DATA = "web_app_data"
28
+ BOOST_ADDED = "boost_added"
29
+ CHAT_BACKGROUND_SET = "chat_background_set"
30
+ WRITE_ACCESS_ALLOWED = "write_access_allowed"
31
+ PROXIMITY_ALERT_TRIGGERED = "proximity_alert_triggered"
32
+ GIVEAWAY_CREATED = "giveaway_created"
33
+ GIVEAWAY_COMPLETED = "giveaway_completed"
34
+ GIVEAWAY_WINNERS = "giveaway_winners"
35
+ CHECKLIST = "checklist"
@@ -0,0 +1,7 @@
1
+ from enum import Enum
2
+
3
+
4
+ class ParseMode(str, Enum):
5
+ HTML = "HTML"
6
+ MARKDOWN = "Markdown"
7
+ MARKDOWN_V2 = "MarkdownV2"
@@ -0,0 +1,30 @@
1
+ from enum import Enum
2
+
3
+
4
+ class UpdateType(str, Enum):
5
+ MESSAGE = "message"
6
+ EDITED_MESSAGE = "edited_message"
7
+ CHANNEL_POST = "channel_post"
8
+ EDITED_CHANNEL_POST = "edited_channel_post"
9
+ BUSINESS_CONNECTION = "business_connection"
10
+ BUSINESS_MESSAGE = "business_message"
11
+ EDITED_BUSINESS_MESSAGE = "edited_business_message"
12
+ DELETED_BUSINESS_MESSAGES = "deleted_business_messages"
13
+ MESSAGE_REACTION = "message_reaction"
14
+ MESSAGE_REACTION_COUNT = "message_reaction_count"
15
+ INLINE_QUERY = "inline_query"
16
+ CHOSEN_INLINE_RESULT = "chosen_inline_result"
17
+ CALLBACK_QUERY = "callback_query"
18
+ SHIPPING_QUERY = "shipping_query"
19
+ PRE_CHECKOUT_QUERY = "pre_checkout_query"
20
+ PURCHASED_PAID_MEDIA = "purchased_paid_media"
21
+ POLL = "poll"
22
+ POLL_ANSWER = "poll_answer"
23
+ MY_CHAT_MEMBER = "my_chat_member"
24
+ CHAT_MEMBER = "chat_member"
25
+ CHAT_JOIN_REQUEST = "chat_join_request"
26
+ CHAT_BOOST = "chat_boost"
27
+ REMOVED_CHAT_BOOST = "removed_chat_boost"
28
+
29
+
30
+ ALLOWED_UPDATES = [u.value for u in UpdateType]
@@ -0,0 +1,25 @@
1
+ from .rpc_error import RPCError
2
+ from .bad_request import BadRequest
3
+ from .unauthorized import Unauthorized
4
+ from .forbidden import Forbidden
5
+ from .not_found import NotFound
6
+ from .conflict import Conflict
7
+ from .internal_server_error import InternalServerError
8
+ from .service_unavailable import ServiceUnavailable
9
+ from .flood_wait import FloodWait
10
+ from .message_not_modified import MessageNotModified
11
+ from .map_error import map_error
12
+
13
+ __all__ = [
14
+ "RPCError",
15
+ "BadRequest",
16
+ "Unauthorized",
17
+ "Forbidden",
18
+ "NotFound",
19
+ "Conflict",
20
+ "InternalServerError",
21
+ "ServiceUnavailable",
22
+ "FloodWait",
23
+ "MessageNotModified",
24
+ "map_error",
25
+ ]
@@ -0,0 +1,5 @@
1
+ from .rpc_error import RPCError
2
+
3
+
4
+ class BadRequest(RPCError):
5
+ """HTTP 400 — request tidak valid."""
@@ -0,0 +1,5 @@
1
+ from .rpc_error import RPCError
2
+
3
+
4
+ class Conflict(RPCError):
5
+ """HTTP 409 — konflik, mis. dua instance polling memakai token sama."""
@@ -0,0 +1,12 @@
1
+ from .rpc_error import RPCError
2
+
3
+
4
+ class FloodWait(RPCError):
5
+ """
6
+ Bot harus menunggu `seconds` detik sebelum request berikutnya.
7
+ Dilempar saat Telegram mengembalikan 429 dengan "retry after".
8
+ """
9
+
10
+ def __init__(self, seconds, description=None):
11
+ super().__init__(f"Flood wait: {seconds}s", code=429, description=description)
12
+ self.seconds = seconds
@@ -0,0 +1,5 @@
1
+ from .rpc_error import RPCError
2
+
3
+
4
+ class Forbidden(RPCError):
5
+ """HTTP 403 — bot tidak punya izin untuk aksi ini."""