pyrobale 0.2.9.4__py3-none-any.whl → 0.3.5__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 (47) hide show
  1. pyrobale/__init__.py +3 -0
  2. pyrobale/client/__init__.py +574 -0
  3. pyrobale/exceptions/__init__.py +0 -0
  4. pyrobale/exceptions/common.py +10 -0
  5. pyrobale/objects/__init__.py +86 -0
  6. pyrobale/objects/animation.py +33 -0
  7. pyrobale/objects/audio.py +24 -0
  8. pyrobale/objects/callbackquery.py +42 -0
  9. pyrobale/objects/chat.py +463 -0
  10. pyrobale/objects/chatmember.py +162 -0
  11. pyrobale/objects/chatphoto.py +18 -0
  12. pyrobale/objects/contact.py +16 -0
  13. pyrobale/objects/copytextbutton.py +5 -0
  14. pyrobale/objects/document.py +26 -0
  15. pyrobale/objects/enums.py +28 -0
  16. pyrobale/objects/file.py +15 -0
  17. pyrobale/objects/inlinekeyboardbutton.py +24 -0
  18. pyrobale/objects/inlinekeyboardmarkup.py +84 -0
  19. pyrobale/objects/inputfile.py +17 -0
  20. pyrobale/objects/inputmedias.py +166 -0
  21. pyrobale/objects/invoice.py +14 -0
  22. pyrobale/objects/keyboardbutton.py +19 -0
  23. pyrobale/objects/labeledprice.py +8 -0
  24. pyrobale/objects/location.py +4 -0
  25. pyrobale/objects/message.py +368 -0
  26. pyrobale/objects/messageid.py +3 -0
  27. pyrobale/objects/photosize.py +9 -0
  28. pyrobale/objects/precheckoutquery.py +21 -0
  29. pyrobale/objects/replykeyboardmarkup.py +54 -0
  30. pyrobale/objects/sticker.py +16 -0
  31. pyrobale/objects/stickerset.py +12 -0
  32. pyrobale/objects/successfulpayment.py +15 -0
  33. pyrobale/objects/update.py +23 -0
  34. pyrobale/objects/user.py +20 -0
  35. pyrobale/objects/utils.py +28 -0
  36. pyrobale/objects/video.py +20 -0
  37. pyrobale/objects/voice.py +4 -0
  38. pyrobale/objects/webappdata.py +3 -0
  39. pyrobale/objects/webappinfo.py +3 -0
  40. pyrobale-0.3.5.dist-info/METADATA +176 -0
  41. pyrobale-0.3.5.dist-info/RECORD +43 -0
  42. pyrobale-0.3.5.dist-info/licenses/LICENSE +21 -0
  43. pyrobale-0.2.9.4.dist-info/METADATA +0 -833
  44. pyrobale-0.2.9.4.dist-info/RECORD +0 -5
  45. pyrobale-0.2.9.4.dist-info/licenses/LICENSE +0 -678
  46. pyrobale.py +0 -2545
  47. {pyrobale-0.2.9.4.dist-info → pyrobale-0.3.5.dist-info}/WHEEL +0 -0
@@ -0,0 +1,162 @@
1
+ from typing import TYPE_CHECKING
2
+ from typing import Optional, Union
3
+
4
+ if TYPE_CHECKING:
5
+ from .utils import build_api_url
6
+ from .user import User
7
+ from .chat import Chat
8
+ from .user import User
9
+ from .enums import ChatType
10
+ from ..client import Client
11
+
12
+
13
+ class ChatMember:
14
+ """Represents a chat member in the Bale messenger, including their user
15
+ information and status."""
16
+
17
+ def __init__(
18
+ self,
19
+ user: "User",
20
+ status: str,
21
+ custom_title: Optional[str] = None,
22
+ is_anonymous: Optional[bool] = None,
23
+ can_be_edited: Optional[bool] = None,
24
+ can_manage_chat: Optional[bool] = None,
25
+ can_delete_messages: Optional[bool] = None,
26
+ can_edit_messages: Optional[bool] = None,
27
+ can_post_messages: Optional[bool] = None,
28
+ can_restrict_members: Optional[bool] = None,
29
+ can_promote_members: Optional[bool] = None,
30
+ can_change_info: Optional[bool] = None,
31
+ can_invite_users: Optional[bool] = None,
32
+ can_pin_messages: Optional[bool] = None,
33
+ can_manage_topics: Optional[bool] = None,
34
+ until_date: Optional[int] = None,
35
+ is_member: Optional[bool] = None,
36
+ can_send_messages: Optional[bool] = None,
37
+ can_send_audios: Optional[bool] = None,
38
+ can_send_documents: Optional[bool] = None,
39
+ can_send_photos: Optional[bool] = None,
40
+ can_send_videos: Optional[bool] = None,
41
+ can_send_video_notes: Optional[bool] = None,
42
+ can_send_voice_notes: Optional[bool] = None,
43
+ can_send_polls: Optional[bool] = None,
44
+ can_send_other_messages: Optional[bool] = None,
45
+ can_add_web_page_previews: Optional[bool] = None,
46
+ **kwargs
47
+ ):
48
+ self.user = user
49
+ self.status = status
50
+ self.custom_title = custom_title
51
+ self.is_anonymous = is_anonymous
52
+ self.can_be_edited = can_be_edited
53
+ self.can_manage_chat = can_manage_chat
54
+ self.can_delete_messages = can_delete_messages
55
+ self.can_edit_messages = can_edit_messages
56
+ self.can_post_messages = can_post_messages
57
+ self.can_restrict_members = can_restrict_members
58
+ self.can_promote_members = can_promote_members
59
+ self.can_change_info = can_change_info
60
+ self.can_invite_users = can_invite_users
61
+ self.can_pin_messages = can_pin_messages
62
+ self.can_manage_topics = can_manage_topics
63
+ self.until_date = until_date
64
+ self.is_member = is_member
65
+ self.can_send_messages = can_send_messages
66
+ self.can_send_audios = can_send_audios
67
+ self.can_send_documents = can_send_documents
68
+ self.can_send_photos = can_send_photos
69
+ self.can_send_videos = can_send_videos
70
+ self.can_send_video_notes = can_send_video_notes
71
+ self.can_send_voice_notes = can_send_voice_notes
72
+ self.can_send_polls = can_send_polls
73
+ self.can_send_other_messages = can_send_other_messages
74
+ self.can_add_web_page_previews = can_add_web_page_previews
75
+ self.client: Client = kwargs.get("kwargs", {}).get("client")
76
+ self.chat: Chat = Chat(**kwargs.get("kwargs", {}).get("chat"))
77
+
78
+ async def ban(self) -> bool:
79
+ """Bans the chat member from the chat.
80
+
81
+ :param chat_id: The ID of the chat.
82
+
83
+ :return: True if the member was banned successfully, False otherwise.
84
+ """
85
+ data = await self.chat.ban(self.user.id)
86
+ return data
87
+
88
+ async def unban(self) -> bool:
89
+ """Unbans the chat member from the chat.
90
+
91
+ :return: True if the member was unbanned successfully, False otherwise.
92
+ """
93
+ data = await self.chat.unban(self.user.id)
94
+ return data
95
+
96
+ async def promote(
97
+ self,
98
+ can_change_info: Optional[bool] = None,
99
+ can_post_messages: Optional[bool] = None,
100
+ can_edit_messages: Optional[bool] = None,
101
+ can_delete_messages: Optional[bool] = None,
102
+ can_invite_users: Optional[bool] = None,
103
+ can_restrict_members: Optional[bool] = None,
104
+ can_pin_messages: Optional[bool] = None,
105
+ can_promote_members: Optional[bool] = None,
106
+ ):
107
+ """Promote or demote a user in a chat.
108
+
109
+ Parameters:
110
+ can_change_info (Optional[bool]): Pass True if the user can change chat title, photo and other settings
111
+ can_post_messages (Optional[bool]): Pass True if the user can post messages in channels
112
+ can_edit_messages (Optional[bool]): Pass True if the user can edit messages in channels
113
+ can_delete_messages (Optional[bool]): Pass True if the user can delete messages
114
+ can_invite_users (Optional[bool]): Pass True if the user can invite new users
115
+ can_restrict_members (Optional[bool]): Pass True if the user can restrict, ban or unban chat members
116
+ can_pin_messages (Optional[bool]): Pass True if the user can pin messages
117
+ can_promote_members (Optional[bool]): Pass True if the user can add new administrators
118
+
119
+ Returns:
120
+ bool: True on success
121
+ """
122
+ return await self.chat.promote(
123
+ chat_id=self.chat.id,
124
+ user_id=self.user.id,
125
+ can_change_info=can_change_info,
126
+ can_post_messages=can_post_messages,
127
+ can_edit_messages=can_edit_messages,
128
+ can_delete_messages=can_delete_messages,
129
+ can_invite_users=can_invite_users,
130
+ can_restrict_members=can_restrict_members,
131
+ can_pin_messages=can_pin_messages,
132
+ can_promote_members=can_promote_members,
133
+ )
134
+
135
+ async def restrict(
136
+ self,
137
+ can_send_messages: Optional[bool] = None,
138
+ can_send_media_messages: Optional[bool] = None,
139
+ can_send_other_messages: Optional[bool] = None,
140
+ can_add_web_page_previews: Optional[bool] = None,
141
+ until_date: Optional[int] = None,
142
+ ) -> bool:
143
+ """Restrict a user in a chat.
144
+
145
+ Parameters:
146
+ can_send_messages (Optional[bool]): Pass True if the user can send text messages
147
+ can_send_media_messages (Optional[bool]): Pass True if the user can send media messages
148
+ can_send_other_messages (Optional[bool]): Pass True if the user can send other types of messages
149
+ can_add_web_page_previews (Optional[bool]): Pass True if the user can add web page previews
150
+ until_date (Optional[int]): Date when restrictions will be lifted for the user
151
+
152
+ Returns:
153
+ bool: True on success
154
+ """
155
+ return await self.chat.restrict(
156
+ user_id=self.user.id,
157
+ can_send_messages=can_send_messages,
158
+ can_send_media_messages=can_send_media_messages,
159
+ can_send_other_messages=can_send_other_messages,
160
+ can_add_web_page_previews=can_add_web_page_previews,
161
+ until_date=until_date,
162
+ )
@@ -0,0 +1,18 @@
1
+ from typing import Optional
2
+
3
+
4
+ class ChatPhoto:
5
+ """This object represents a chat photo."""
6
+
7
+ def __init__(
8
+ self,
9
+ small_file_id: Optional[str] = None,
10
+ small_file_unique_id: Optional[str] = None,
11
+ big_file_id: Optional[str] = None,
12
+ big_file_unique_id: Optional[str] = None,
13
+ **kwargs
14
+ ):
15
+ self.small_file_id = small_file_id
16
+ self.small_file_unique_id = small_file_unique_id
17
+ self.big_file_id = big_file_id
18
+ self.big_file_unique_id = big_file_unique_id
@@ -0,0 +1,16 @@
1
+ from typing import Optional
2
+
3
+
4
+ class Contact:
5
+ def __init__(
6
+ self,
7
+ phone_number: Optional[str] = None,
8
+ first_name: Optional[str] = None,
9
+ last_name: Optional[str] = None,
10
+ user_id: Optional[int] = None,
11
+ **kwargs
12
+ ):
13
+ self.phone_number = phone_number
14
+ self.first_name = first_name
15
+ self.last_name = last_name
16
+ self.user_id = user_id
@@ -0,0 +1,5 @@
1
+ class CopyTextButton:
2
+ """Represents a copy text button."""
3
+
4
+ def __init__(self, text: str, **kwargs):
5
+ self.text = text
@@ -0,0 +1,26 @@
1
+ from typing import TYPE_CHECKING, Optional
2
+
3
+ if TYPE_CHECKING:
4
+ from .utils import build_api_url
5
+ from .photosize import PhotoSize
6
+
7
+
8
+ class Document:
9
+ """Represents a general file to be sent without any special properties."""
10
+
11
+ def __init__(
12
+ self,
13
+ file_id: str,
14
+ file_unique_id: str,
15
+ thumbnail: "PhotoSize",
16
+ file_name: str,
17
+ mime_type: str,
18
+ file_size: int,
19
+ **kwargs
20
+ ):
21
+ self.file_id = file_id
22
+ self.file_unique_id = file_unique_id
23
+ self.thumbnail = thumbnail
24
+ self.file_name = file_name
25
+ self.mime_type = mime_type
26
+ self.file_size = file_size
@@ -0,0 +1,28 @@
1
+ from enum import Enum
2
+
3
+
4
+ class UpdatesTypes(Enum):
5
+ """Types of updates."""
6
+
7
+ MESSAGE = "message"
8
+ MESSAGE_EDITED = "message_edited"
9
+ CALLBACK_QUERY = "callback_query"
10
+ PRE_CHECKOUT_QUERY = "pre_checkout_query"
11
+ MEMBER_JOINED = "member_joined"
12
+ MEMBER_LEFT = "member_left"
13
+
14
+
15
+ class ChatAction(Enum):
16
+ """Actions of a user in a chat."""
17
+
18
+ TYPING = "typing"
19
+ PHOTO = "upload_photo"
20
+ VIDEO = "upload_video"
21
+
22
+
23
+ class ChatType(Enum):
24
+ """Types of chats."""
25
+
26
+ PRIVATE = "private"
27
+ GROUP = "group"
28
+ CHANNEL = "channel"
@@ -0,0 +1,15 @@
1
+ class File:
2
+ """A class representing a file object."""
3
+
4
+ def __init__(
5
+ self,
6
+ file_id: str,
7
+ file_unique_id: str,
8
+ file_size: int,
9
+ file_path: str,
10
+ **kwargs
11
+ ):
12
+ self.file_id = file_id
13
+ self.file_unique_id = file_unique_id
14
+ self.file_size = file_size
15
+ self.file_path = file_path
@@ -0,0 +1,24 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ from .webappdata import WebAppData
5
+ from .copytextbutton import CopyTextButton
6
+
7
+
8
+ class InlineKeyboardButton:
9
+ """Represents a button in an inline keyboard."""
10
+
11
+ def __init__(
12
+ self,
13
+ text: str,
14
+ url: str = None,
15
+ callback_data: str = None,
16
+ web_app: "WebAppData" = None,
17
+ copy_text_button: "CopyTextButton" = None,
18
+ **kwargs
19
+ ):
20
+ self.text = text
21
+ self.url = url
22
+ self.callback_data = callback_data
23
+ self.web_app = web_app
24
+ self.copy_text_button = copy_text_button
@@ -0,0 +1,84 @@
1
+ from typing import TYPE_CHECKING, Union, Optional
2
+
3
+ if TYPE_CHECKING:
4
+ from .webappinfo import WebAppInfo
5
+ from .copytextbutton import CopyTextButton
6
+
7
+
8
+ class InlineKeyboardMarkup:
9
+ def __init__(self) -> None:
10
+ self.inline_keyboard: list[list[dict]] = []
11
+
12
+ def add_button(
13
+ self,
14
+ text: str,
15
+ callback_data: Optional[str] = None,
16
+ url: Optional[str] = None,
17
+ web_app: Optional[Union["WebAppInfo", str]] = None,
18
+ copy_text_button: Optional["CopyTextButton"] = None,
19
+ **kwargs
20
+ ) -> "InlineKeyboardMarkup":
21
+ """Adds a button to the inline keyboard.
22
+
23
+ Parameters:
24
+ text (str): The text to display on the button.
25
+ callback_data (str, optional): The callback data to send when the button is clicked.
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.
29
+
30
+ Returns:
31
+ InlineKeyboardMarkup: The updated InlineKeyboardMarkup object.
32
+ """
33
+ button = {"text": text}
34
+
35
+ field_count = sum(
36
+ field is not None
37
+ for field in [callback_data, url, web_app, copy_text_button]
38
+ )
39
+ if field_count == 0:
40
+ raise ValueError(
41
+ "At least one of callback_data, url, web_app, or copy_text must be provided."
42
+ )
43
+ if field_count > 1:
44
+ raise ValueError(
45
+ "Only one of callback_data, url, web_app, or copy_text can be provided."
46
+ )
47
+
48
+ if callback_data:
49
+ button["callback_data"] = callback_data
50
+ elif url:
51
+ button["url"] = url
52
+ elif web_app:
53
+ if isinstance(web_app, str):
54
+ button["web_app"] = {"url": web_app}
55
+ elif hasattr(web_app, "to_dict"):
56
+ button["web_app"] = web_app.to_dict()
57
+ else:
58
+ raise ValueError(
59
+ "web_app must be a string URL or an object with to_dict() method."
60
+ )
61
+ elif copy_text_button:
62
+ button["copy_text"] = {"text": copy_text_button.text}
63
+
64
+ if not self.inline_keyboard:
65
+ self.inline_keyboard.append([])
66
+ self.inline_keyboard[-1].append(button)
67
+ return self
68
+
69
+ def add_row(self) -> "InlineKeyboardMarkup":
70
+ """Adds a new row to the inline keyboard.
71
+
72
+ Returns:
73
+ InlineKeyboardMarkup: The updated InlineKeyboardMarkup object.
74
+ """
75
+ self.inline_keyboard.append([])
76
+ return self
77
+
78
+ def to_dict(self) -> dict:
79
+ print(self.inline_keyboard)
80
+ return {"inline_keyboard": self.inline_keyboard}
81
+
82
+ @property
83
+ def json(self) -> dict:
84
+ return self.to_dict()
@@ -0,0 +1,17 @@
1
+ from typing import List, Union
2
+
3
+
4
+ class InputFile:
5
+ def __init__(self, file: Union[bytes, str], **kwargs):
6
+ """
7
+ Initialize an InputFile object that can handle file uploads in 3 ways:
8
+ 1. Using file_id for files already on Bale servers
9
+ 2. Using HTTP URL for remote files (5MB limit for images, 20MB for other content)
10
+ 3. Using multipart/form-data upload (10MB limit for images, 50MB for other content)
11
+
12
+ Args:
13
+ file: Can be either:
14
+ - bytes: For direct file upload
15
+ - str: For file_id or HTTP URL
16
+ """
17
+ self.file = file
@@ -0,0 +1,166 @@
1
+ class InputMedia:
2
+ """Base class for all input media types.
3
+
4
+ This is an abstract class that should not be used directly.
5
+ """
6
+
7
+ def __init__(self, media, caption=None):
8
+ """Initialize the base InputMedia object.
9
+
10
+ Args:
11
+ media (str): File to send. Can be a file_id, HTTP URL, or "<attach://file_attach_name>".
12
+ caption (str, optional): Caption for the media, 0-1024 characters.
13
+ """
14
+ self.media = media
15
+ self.caption = caption
16
+
17
+
18
+ class InputMediaPhoto(InputMedia):
19
+ """Represents a photo to be sent.
20
+
21
+ This object represents a photo that needs to be sent to Bale.
22
+ """
23
+
24
+ def __init__(self, media, caption=None):
25
+ """Initialize an InputMediaPhoto object.
26
+
27
+ Args:
28
+ media (str): File to send. Can be:
29
+ 1) A file_id to send a file that exists on Bale servers (recommended)
30
+ 2) An HTTP URL for Bale to get a file from the Internet
31
+ 3) "<attach://file_attach_name>" to upload a new file using multipart/form-data
32
+ caption (str, optional): Caption for the photo, 0-1024 characters.
33
+ """
34
+ super().__init__(media, caption)
35
+ self.type = "photo"
36
+
37
+
38
+ class InputMediaVideo(InputMedia):
39
+ """Represents a video to be sent.
40
+
41
+ This object represents a video that needs to be sent to Bale.
42
+ """
43
+
44
+ def __init__(
45
+ self,
46
+ media,
47
+ caption=None,
48
+ thumbnail=None,
49
+ width=None,
50
+ height=None,
51
+ duration=None,
52
+ ):
53
+ """Initialize an InputMediaVideo object.
54
+
55
+ Args:
56
+ media (str): File to send. Can be:
57
+ 1) A file_id to send a file that exists on Bale servers (recommended)
58
+ 2) An HTTP URL for Bale to get a file from the Internet
59
+ 3) "<attach://file_attach_name>" to upload a new file using multipart/form-data
60
+ caption (str, optional): Caption for the video, 0-1024 characters.
61
+ thumbnail (InputFile or str, optional): Thumbnail of the video.
62
+ Should be in JPEG format and less than 200 KB in size.
63
+ Width and height should not exceed 320px.
64
+ width (int, optional): Video width.
65
+ height (int, optional): Video height.
66
+ duration (int, optional): Video duration in seconds.
67
+ """
68
+ super().__init__(media, caption)
69
+ self.type = "video"
70
+ self.thumbnail = thumbnail
71
+ self.width = width
72
+ self.height = height
73
+ self.duration = duration
74
+
75
+
76
+ class InputMediaAnimation(InputMedia):
77
+ """Represents an animation to be sent.
78
+
79
+ This object represents an animation file (GIF or H.264/MPEG-4 AVC
80
+ video without sound) that needs to be sent to Bale.
81
+ """
82
+
83
+ def __init__(
84
+ self,
85
+ media,
86
+ caption=None,
87
+ thumbnail=None,
88
+ width=None,
89
+ height=None,
90
+ duration=None,
91
+ ):
92
+ """Initialize an InputMediaAnimation object.
93
+
94
+ Args:
95
+ media (str): File to send. Can be:
96
+ 1) A file_id to send a file that exists on Bale servers (recommended)
97
+ 2) An HTTP URL for Bale to get a file from the Internet
98
+ 3) "<attach://file_attach_name>" to upload a new file using multipart/form-data
99
+ caption (str, optional): Caption for the animation, 0-1024 characters.
100
+ thumbnail (InputFile or str, optional): Thumbnail of the animation.
101
+ Should be in JPEG format and less than 200 KB in size.
102
+ Width and height should not exceed 320px.
103
+ width (int, optional): Animation width.
104
+ height (int, optional): Animation height.
105
+ duration (int, optional): Animation duration in seconds.
106
+ """
107
+ super().__init__(media, caption)
108
+ self.type = "animation"
109
+ self.thumbnail = thumbnail
110
+ self.width = width
111
+ self.height = height
112
+ self.duration = duration
113
+
114
+
115
+ class InputMediaAudio(InputMedia):
116
+ """Represents an audio file to be sent.
117
+
118
+ This object represents an audio file that needs to be sent to Bale.
119
+ The file will be treated as music.
120
+ """
121
+
122
+ def __init__(self, media, caption=None, thumbnail=None, duration=None, title=None):
123
+ """Initialize an InputMediaAudio object.
124
+
125
+ Args:
126
+ media (str): File to send. Can be:
127
+ 1) A file_id to send a file that exists on Bale servers (recommended)
128
+ 2) An HTTP URL for Bale to get a file from the Internet
129
+ 3) "<attach://file_attach_name>" to upload a new file using multipart/form-data
130
+ caption (str, optional): Caption for the audio file, 0-1024 characters.
131
+ thumbnail (InputFile or str, optional): Thumbnail of the audio file.
132
+ Should be in JPEG format and less than 200 KB in size.
133
+ Width and height should not exceed 320px.
134
+ duration (int, optional): Duration of the audio in seconds.
135
+ title (str, optional): Title of the audio.
136
+ """
137
+ super().__init__(media, caption)
138
+ self.type = "audio"
139
+ self.thumbnail = thumbnail
140
+ self.duration = duration
141
+ self.title = title
142
+
143
+
144
+ class InputMediaDocument(InputMedia):
145
+ """Represents a document to be sent.
146
+
147
+ This object represents a general file (document) that needs to be
148
+ sent to Bale.
149
+ """
150
+
151
+ def __init__(self, media, caption=None, thumbnail=None):
152
+ """Initialize an InputMediaDocument object.
153
+
154
+ Args:
155
+ media (str): File to send. Can be:
156
+ 1) A file_id to send a file that exists on Bale servers (recommended)
157
+ 2) An HTTP URL for Bale to get a file from the Internet
158
+ 3) "<attach://file_attach_name>" to upload a new file using multipart/form-data
159
+ caption (str, optional): Caption for the document, 0-1024 characters.
160
+ thumbnail (InputFile or str, optional): Thumbnail of the document.
161
+ Should be in JPEG format and less than 200 KB in size.
162
+ Width and height should not exceed 320px.
163
+ """
164
+ super().__init__(media, caption)
165
+ self.type = "document"
166
+ self.thumbnail = thumbnail
@@ -0,0 +1,14 @@
1
+ class Invoice:
2
+ def __init__(
3
+ self,
4
+ title: str,
5
+ description: str,
6
+ start_parameter: str,
7
+ currency: str,
8
+ total_amount: int,
9
+ ) -> None:
10
+ self.title = title
11
+ self.description = description
12
+ self.start_parameter = start_parameter
13
+ self.currency = currency
14
+ self.total_amount = total_amount
@@ -0,0 +1,19 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ from .webappinfo import WebAppInfo
5
+
6
+
7
+ class KeyboardButton:
8
+ def __init__(
9
+ self,
10
+ text: str,
11
+ request_contact: bool = False,
12
+ request_location: bool = False,
13
+ web_app: "WebAppInfo" = None,
14
+ **kwargs
15
+ ):
16
+ self.text = text
17
+ self.request_contact = request_contact
18
+ self.request_location = request_location
19
+ self.web_app = web_app
@@ -0,0 +1,8 @@
1
+ class LabeledPrice:
2
+ def __init__(self, label: str, amount: int) -> None:
3
+ self.label = label
4
+ self.amount = amount
5
+
6
+ @property
7
+ def json(self):
8
+ return {"label": self.label, "amount": self.amount}
@@ -0,0 +1,4 @@
1
+ class Location:
2
+ def __init__(self, latitude: float, longitude: float):
3
+ self.latitude = latitude
4
+ self.longitude = longitude