telebot-py 1.5.0__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 (108) hide show
  1. telebot_py/__init__.py +55 -0
  2. telebot_py/bot/__init__.py +61 -0
  3. telebot_py/bot/base.py +108 -0
  4. telebot_py/bot/bulk.py +140 -0
  5. telebot_py/bot/chat_management.py +374 -0
  6. telebot_py/bot/chats.py +166 -0
  7. telebot_py/bot/client.py +264 -0
  8. telebot_py/bot/edits.py +371 -0
  9. telebot_py/bot/errors.py +52 -0
  10. telebot_py/bot/files.py +56 -0
  11. telebot_py/bot/games.py +154 -0
  12. telebot_py/bot/inline.py +131 -0
  13. telebot_py/bot/invite_links.py +122 -0
  14. telebot_py/bot/media.py +776 -0
  15. telebot_py/bot/members.py +280 -0
  16. telebot_py/bot/messages.py +355 -0
  17. telebot_py/bot/payments.py +373 -0
  18. telebot_py/bot/profile.py +268 -0
  19. telebot_py/bot/reactions.py +125 -0
  20. telebot_py/bot/retry.py +50 -0
  21. telebot_py/bot/stickers.py +455 -0
  22. telebot_py/bot/stories_gifts.py +54 -0
  23. telebot_py/bot/topics.py +71 -0
  24. telebot_py/bot/webhook.py +93 -0
  25. telebot_py/components/__init__.py +50 -0
  26. telebot_py/components/inline_query.py +411 -0
  27. telebot_py/components/keyboard/__init__.py +6 -0
  28. telebot_py/components/keyboard/inline.py +137 -0
  29. telebot_py/components/keyboard/reply.py +240 -0
  30. telebot_py/components/menu/__init__.py +25 -0
  31. telebot_py/components/menu/menu.py +201 -0
  32. telebot_py/components/menu/renderer.py +114 -0
  33. telebot_py/components/menu/types.py +79 -0
  34. telebot_py/components/pagination.py +182 -0
  35. telebot_py/ext_errors.py +17 -0
  36. telebot_py/filters/__init__.py +40 -0
  37. telebot_py/filters/base.py +138 -0
  38. telebot_py/filters/matchers.py +190 -0
  39. telebot_py/kernel/__init__.py +21 -0
  40. telebot_py/kernel/app.py +487 -0
  41. telebot_py/kernel/builder.py +208 -0
  42. telebot_py/kernel/context.py +98 -0
  43. telebot_py/kernel/dispatcher.py +227 -0
  44. telebot_py/kernel/lifecycle.py +26 -0
  45. telebot_py/kernel/polling.py +155 -0
  46. telebot_py/kernel/runners.py +180 -0
  47. telebot_py/kernel/webhook.py +414 -0
  48. telebot_py/plugins/__init__.py +15 -0
  49. telebot_py/plugins/i18n.py +174 -0
  50. telebot_py/plugins/manager.py +242 -0
  51. telebot_py/plugins/plugin.py +70 -0
  52. telebot_py/py.typed +0 -0
  53. telebot_py/routing/__init__.py +75 -0
  54. telebot_py/routing/async_conversation/__init__.py +26 -0
  55. telebot_py/routing/async_conversation/conversation.py +200 -0
  56. telebot_py/routing/async_conversation/handler.py +162 -0
  57. telebot_py/routing/async_conversation/manager.py +326 -0
  58. telebot_py/routing/async_conversation/types.py +49 -0
  59. telebot_py/routing/conversation.py +262 -0
  60. telebot_py/routing/handlers/__init__.py +64 -0
  61. telebot_py/routing/handlers/base.py +93 -0
  62. telebot_py/routing/handlers/business.py +52 -0
  63. telebot_py/routing/handlers/callback_query.py +87 -0
  64. telebot_py/routing/handlers/chat_member.py +81 -0
  65. telebot_py/routing/handlers/chat_request.py +81 -0
  66. telebot_py/routing/handlers/command.py +95 -0
  67. telebot_py/routing/handlers/inline_query.py +157 -0
  68. telebot_py/routing/handlers/message.py +49 -0
  69. telebot_py/routing/handlers/payment.py +67 -0
  70. telebot_py/routing/handlers/reaction.py +120 -0
  71. telebot_py/routing/handlers/type.py +55 -0
  72. telebot_py/routing/linear_conversation.py +236 -0
  73. telebot_py/scheduler/__init__.py +22 -0
  74. telebot_py/scheduler/job.py +203 -0
  75. telebot_py/scheduler/queue.py +313 -0
  76. telebot_py/scheduler/rrule/__init__.py +6 -0
  77. telebot_py/scheduler/rrule/rule.py +159 -0
  78. telebot_py/scheduler/rrule/types.py +69 -0
  79. telebot_py/storage/__init__.py +18 -0
  80. telebot_py/storage/base.py +401 -0
  81. telebot_py/storage/driver.py +76 -0
  82. telebot_py/storage/json.py +132 -0
  83. telebot_py/storage/memory.py +50 -0
  84. telebot_py/storage/sqlite.py +310 -0
  85. telebot_py/types/__init__.py +232 -0
  86. telebot_py/types/base.py +122 -0
  87. telebot_py/types/business.py +160 -0
  88. telebot_py/types/callback_query.py +39 -0
  89. telebot_py/types/chat.py +360 -0
  90. telebot_py/types/chat_members.py +262 -0
  91. telebot_py/types/common.py +251 -0
  92. telebot_py/types/files.py +42 -0
  93. telebot_py/types/games.py +47 -0
  94. telebot_py/types/keyboards.py +280 -0
  95. telebot_py/types/media.py +189 -0
  96. telebot_py/types/message.py +286 -0
  97. telebot_py/types/message_extras.py +250 -0
  98. telebot_py/types/payments.py +169 -0
  99. telebot_py/types/reactions.py +106 -0
  100. telebot_py/types/stickers.py +123 -0
  101. telebot_py/types/topics.py +122 -0
  102. telebot_py/types/update.py +189 -0
  103. telebot_py/types/user.py +46 -0
  104. telebot_py/utils/__init__.py +0 -0
  105. telebot_py-1.5.0.dist-info/METADATA +176 -0
  106. telebot_py-1.5.0.dist-info/RECORD +108 -0
  107. telebot_py-1.5.0.dist-info/WHEEL +4 -0
  108. telebot_py-1.5.0.dist-info/licenses/LICENSE +21 -0
telebot_py/__init__.py ADDED
@@ -0,0 +1,55 @@
1
+ """telebot_py — async-first Telegram Bot framework for Python.
2
+
3
+ Mirrors python-telegram-bot's public API in native snake_case. See
4
+ ``specs/004-python-framework/contracts/public-api.md`` for the stable public
5
+ surface.
6
+ """
7
+
8
+ from telebot_py import filters
9
+ from telebot_py.bot.errors import (
10
+ ApplicationError,
11
+ InvalidTokenError,
12
+ NetworkError,
13
+ TelebotError,
14
+ TelegramApiError,
15
+ )
16
+ from telebot_py.kernel import (
17
+ Application,
18
+ ApplicationBuilder,
19
+ ApplicationState,
20
+ CallbackContext,
21
+ )
22
+ from telebot_py.routing import (
23
+ AsyncConversationHandler,
24
+ ConversationHandler,
25
+ LinearConversationHandler,
26
+ )
27
+ from telebot_py.routing.handlers import (
28
+ BaseHandler,
29
+ CallbackQueryHandler,
30
+ CommandHandler,
31
+ MessageHandler,
32
+ )
33
+
34
+ __version__ = "1.5.0"
35
+
36
+ __all__ = [
37
+ "Application",
38
+ "ApplicationBuilder",
39
+ "ApplicationError",
40
+ "ApplicationState",
41
+ "AsyncConversationHandler",
42
+ "BaseHandler",
43
+ "CallbackContext",
44
+ "CallbackQueryHandler",
45
+ "CommandHandler",
46
+ "ConversationHandler",
47
+ "InvalidTokenError",
48
+ "LinearConversationHandler",
49
+ "MessageHandler",
50
+ "NetworkError",
51
+ "TelegramApiError",
52
+ "TelebotError",
53
+ "__version__",
54
+ "filters",
55
+ ]
@@ -0,0 +1,61 @@
1
+ """Bot API client: HTTP core, retry policy, typed errors, and method mixins."""
2
+
3
+ from telebot_py.bot.base import MarkupLike, Requester, SupportsToDict
4
+ from telebot_py.bot.bulk import BulkMixin
5
+ from telebot_py.bot.chat_management import ChatManagementMixin
6
+ from telebot_py.bot.chats import ChatsMixin
7
+ from telebot_py.bot.client import Bot
8
+ from telebot_py.bot.edits import EditsMixin
9
+ from telebot_py.bot.errors import (
10
+ ApplicationError,
11
+ InvalidTokenError,
12
+ NetworkError,
13
+ TelebotError,
14
+ TelegramApiError,
15
+ )
16
+ from telebot_py.bot.files import FilesMixin
17
+ from telebot_py.bot.games import GamesMixin
18
+ from telebot_py.bot.inline import InlineMixin
19
+ from telebot_py.bot.invite_links import InviteLinksMixin
20
+ from telebot_py.bot.media import MediaMixin
21
+ from telebot_py.bot.members import MembersMixin
22
+ from telebot_py.bot.messages import MessagesMixin
23
+ from telebot_py.bot.payments import PaymentsMixin
24
+ from telebot_py.bot.profile import ProfileMixin
25
+ from telebot_py.bot.reactions import ReactionsMixin
26
+ from telebot_py.bot.retry import RetryPolicy
27
+ from telebot_py.bot.stickers import StickersMixin
28
+ from telebot_py.bot.stories_gifts import StoriesGiftsMixin
29
+ from telebot_py.bot.topics import TopicsMixin
30
+ from telebot_py.bot.webhook import WebhookMixin
31
+
32
+ __all__ = [
33
+ "ApplicationError",
34
+ "Bot",
35
+ "BulkMixin",
36
+ "ChatManagementMixin",
37
+ "ChatsMixin",
38
+ "EditsMixin",
39
+ "FilesMixin",
40
+ "GamesMixin",
41
+ "InlineMixin",
42
+ "InvalidTokenError",
43
+ "InviteLinksMixin",
44
+ "MarkupLike",
45
+ "MediaMixin",
46
+ "MembersMixin",
47
+ "MessagesMixin",
48
+ "NetworkError",
49
+ "PaymentsMixin",
50
+ "ProfileMixin",
51
+ "ReactionsMixin",
52
+ "Requester",
53
+ "RetryPolicy",
54
+ "StoriesGiftsMixin",
55
+ "StickersMixin",
56
+ "SupportsToDict",
57
+ "TelegramApiError",
58
+ "TelebotError",
59
+ "TopicsMixin",
60
+ "WebhookMixin",
61
+ ]
telebot_py/bot/base.py ADDED
@@ -0,0 +1,108 @@
1
+ """Shared seam and helpers for the Bot method mixins."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import abc
6
+ import typing as t
7
+
8
+ from telebot_py.types.base import TelegramObject, TypeParseError
9
+ from telebot_py.types.message import Message
10
+
11
+ TObj = t.TypeVar("TObj", bound=TelegramObject)
12
+
13
+
14
+ class SupportsToDict(t.Protocol):
15
+ """Any typed object serializable to Telegram's wire shape."""
16
+
17
+ def to_dict(self) -> dict[str, object]:
18
+ """Serialize this object to a plain snake_case dict."""
19
+ ...
20
+
21
+
22
+ #: Markup-shaped parameters accept plain dicts or typed objects with ``to_dict``.
23
+ MarkupLike = t.Mapping[str, object] | SupportsToDict
24
+
25
+
26
+ class Requester(abc.ABC):
27
+ """Abstract request seam every Bot method mixin builds on."""
28
+
29
+ @abc.abstractmethod
30
+ async def request(
31
+ self,
32
+ method: str,
33
+ payload: t.Mapping[str, object] | None = None,
34
+ ) -> object:
35
+ """Call a Bot API method and return the unwrapped ``result``.
36
+
37
+ Args:
38
+ method: The Bot API method name (e.g. ``sendMessage``).
39
+ payload: Method parameters keyed by Telegram field names.
40
+
41
+ Returns:
42
+ The ``result`` field of Telegram's response envelope.
43
+ """
44
+
45
+
46
+ def to_wire(value: MarkupLike | None) -> dict[str, object] | None:
47
+ """Serialize a markup-shaped parameter for the wire, ``None`` passing through."""
48
+ if value is None:
49
+ return None
50
+ if isinstance(value, t.Mapping):
51
+ return dict(value)
52
+ return value.to_dict()
53
+
54
+
55
+ def clean_payload(**fields: object) -> dict[str, object]:
56
+ """Build a wire payload, omitting parameters the caller left unset."""
57
+ return {name: value for name, value in fields.items() if value is not None}
58
+
59
+
60
+ def parse_result(cls: type[TObj], result: object) -> TObj:
61
+ """Hydrate a single JSON object result into a typed Telegram object."""
62
+ if isinstance(result, t.Mapping):
63
+ return cls.from_dict(t.cast("t.Mapping[str, object]", result))
64
+ msg = f"expected JSON object for {cls.__name__}, got {type(result).__name__}"
65
+ raise TypeParseError(msg)
66
+
67
+
68
+ def parse_list_result(cls: type[TObj], result: object) -> list[TObj]:
69
+ """Hydrate a JSON array result into a list of typed Telegram objects."""
70
+ if isinstance(result, list):
71
+ return [
72
+ cls.from_dict(t.cast("t.Mapping[str, object]", item))
73
+ for item in result
74
+ if isinstance(item, t.Mapping)
75
+ ]
76
+ msg = f"expected JSON array of {cls.__name__}, got {type(result).__name__}"
77
+ raise TypeParseError(msg)
78
+
79
+
80
+ def parse_flag(result: object) -> bool:
81
+ """Coerce a boolean Bot API result, rejecting unexpected shapes."""
82
+ if isinstance(result, bool):
83
+ return result
84
+ msg = f"expected boolean result, got {type(result).__name__}"
85
+ raise TypeParseError(msg)
86
+
87
+
88
+ def parse_count(result: object) -> int:
89
+ """Coerce an integer Bot API result, rejecting unexpected shapes."""
90
+ if isinstance(result, int) and not isinstance(result, bool):
91
+ return result
92
+ msg = f"expected integer result, got {type(result).__name__}"
93
+ raise TypeParseError(msg)
94
+
95
+
96
+ def parse_string(result: object) -> str:
97
+ """Coerce a string Bot API result, rejecting unexpected shapes."""
98
+ if isinstance(result, str):
99
+ return result
100
+ msg = f"expected string result, got {type(result).__name__}"
101
+ raise TypeParseError(msg)
102
+
103
+
104
+ def parse_message_or_true(result: object) -> Message | bool:
105
+ """Coerce edit-method results: the edited Message, or True for inline edits."""
106
+ if isinstance(result, bool):
107
+ return result
108
+ return parse_result(Message, result)
telebot_py/bot/bulk.py ADDED
@@ -0,0 +1,140 @@
1
+ """Bulk message Bot API methods (parity with packages/go/pkg/bot/bulk.go)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Sequence
6
+
7
+ from telebot_py.bot.base import Requester, clean_payload, parse_flag, parse_list_result
8
+ from telebot_py.types.common import MessageId
9
+
10
+
11
+ class BulkMixin(Requester):
12
+ """Bot methods for forwarding, copying, and deleting many messages at once."""
13
+
14
+ async def forward_messages(
15
+ self,
16
+ chat_id: int | str,
17
+ from_chat_id: int | str,
18
+ message_ids: Sequence[int],
19
+ *,
20
+ business_connection_id: str | None = None,
21
+ message_thread_id: int | None = None,
22
+ disable_notification: bool | None = None,
23
+ protect_content: bool | None = None,
24
+ ) -> list[MessageId]:
25
+ """Forward multiple messages of any kind to a target chat.
26
+
27
+ Example:
28
+ >>> ids = await bot.forward_messages(123, "@source", [11, 12])
29
+
30
+ Args:
31
+ chat_id: Unique identifier for the target chat or username of the
32
+ target channel.
33
+ from_chat_id: Unique identifier of the source chat or username of
34
+ the source channel.
35
+ message_ids: Identifiers of the messages to forward, 1-100.
36
+ business_connection_id: Business connection on whose behalf to act.
37
+ message_thread_id: Target message thread identifier.
38
+ disable_notification: Send silently.
39
+ protect_content: Protect the forwarded content from saving.
40
+
41
+ Returns:
42
+ The MessageId list of the forwarded messages.
43
+
44
+ Raises:
45
+ InvalidTokenError: If Telegram rejects the token (HTTP 401).
46
+ TelegramApiError: If Telegram responds not-ok or retries exhaust.
47
+ NetworkError: If the transport keeps failing after retries.
48
+ """
49
+ payload = clean_payload(
50
+ chat_id=chat_id,
51
+ from_chat_id=from_chat_id,
52
+ message_ids=list(message_ids),
53
+ business_connection_id=business_connection_id,
54
+ message_thread_id=message_thread_id,
55
+ disable_notification=disable_notification,
56
+ protect_content=protect_content,
57
+ )
58
+ return parse_list_result(MessageId, await self.request("forwardMessages", payload))
59
+
60
+ async def copy_messages(
61
+ self,
62
+ chat_id: int | str,
63
+ from_chat_id: int | str,
64
+ message_ids: Sequence[int],
65
+ *,
66
+ business_connection_id: str | None = None,
67
+ message_thread_id: int | None = None,
68
+ disable_notification: bool | None = None,
69
+ protect_content: bool | None = None,
70
+ remove_caption: bool | None = None,
71
+ ) -> list[MessageId]:
72
+ """Copy multiple messages without linking to the originals.
73
+
74
+ Example:
75
+ >>> ids = await bot.copy_messages("@target", 456, [1, 2])
76
+
77
+ Args:
78
+ chat_id: Unique identifier for the target chat or username of the
79
+ target channel.
80
+ from_chat_id: Unique identifier of the source chat or username of
81
+ the source channel.
82
+ message_ids: Identifiers of the messages to copy, 1-100.
83
+ business_connection_id: Business connection on whose behalf to act.
84
+ message_thread_id: Target message thread identifier.
85
+ disable_notification: Send silently.
86
+ protect_content: Protect the copied content from saving.
87
+ remove_caption: Pass True to copy messages without their captions.
88
+
89
+ Returns:
90
+ The MessageId list of the copied messages.
91
+
92
+ Raises:
93
+ InvalidTokenError: If Telegram rejects the token (HTTP 401).
94
+ TelegramApiError: If Telegram responds not-ok or retries exhaust.
95
+ NetworkError: If the transport keeps failing after retries.
96
+ """
97
+ payload = clean_payload(
98
+ chat_id=chat_id,
99
+ from_chat_id=from_chat_id,
100
+ message_ids=list(message_ids),
101
+ business_connection_id=business_connection_id,
102
+ message_thread_id=message_thread_id,
103
+ disable_notification=disable_notification,
104
+ protect_content=protect_content,
105
+ remove_caption=remove_caption,
106
+ )
107
+ return parse_list_result(MessageId, await self.request("copyMessages", payload))
108
+
109
+ async def delete_messages(
110
+ self,
111
+ chat_id: int | str,
112
+ message_ids: Sequence[int],
113
+ *,
114
+ business_connection_id: str | None = None,
115
+ ) -> bool:
116
+ """Delete multiple messages from a chat at once.
117
+
118
+ Example:
119
+ >>> ok = await bot.delete_messages(789, [5, 6])
120
+
121
+ Args:
122
+ chat_id: Unique identifier for the target chat or username of the
123
+ target channel.
124
+ message_ids: Identifiers of the messages to delete, 1-100.
125
+ business_connection_id: Business connection on whose behalf to act.
126
+
127
+ Returns:
128
+ True on success.
129
+
130
+ Raises:
131
+ InvalidTokenError: If Telegram rejects the token (HTTP 401).
132
+ TelegramApiError: If Telegram responds not-ok or retries exhaust.
133
+ NetworkError: If the transport keeps failing after retries.
134
+ """
135
+ payload = clean_payload(
136
+ chat_id=chat_id,
137
+ message_ids=list(message_ids),
138
+ business_connection_id=business_connection_id,
139
+ )
140
+ return parse_flag(await self.request("deleteMessages", payload))