RubigramClient 1.7.0__py3-none-any.whl → 1.7.2__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.

Potentially problematic release.


This version of RubigramClient might be problematic. Click here for more details.

Files changed (74) hide show
  1. rubigram/__init__.py +1 -5
  2. rubigram/client.py +102 -154
  3. rubigram/enums.py +4 -3
  4. rubigram/filters.py +600 -139
  5. rubigram/handler.py +24 -0
  6. rubigram/http.py +32 -0
  7. rubigram/logger.py +20 -0
  8. rubigram/method/__init__.py +18 -0
  9. rubigram/method/chat/__init__.py +10 -0
  10. rubigram/method/chat/get_chat.py +26 -0
  11. rubigram/method/chat/get_me.py +22 -0
  12. rubigram/method/chat/get_update.py +32 -0
  13. rubigram/method/decorator/__init__.py +8 -0
  14. rubigram/method/decorator/on_delete_message.py +37 -0
  15. rubigram/method/decorator/on_edit_message.py +37 -0
  16. rubigram/method/decorator/on_inline_message.py +40 -0
  17. rubigram/method/decorator/on_message.py +38 -0
  18. rubigram/method/decorator/on_start.py +30 -0
  19. rubigram/method/decorator/on_stop.py +29 -0
  20. rubigram/method/decorator/register.py +43 -0
  21. rubigram/method/file/__init__.py +32 -0
  22. rubigram/method/file/download_file.py +34 -0
  23. rubigram/method/file/get_bytes.py +25 -0
  24. rubigram/method/file/get_file.py +27 -0
  25. rubigram/method/file/get_file_name.py +29 -0
  26. rubigram/method/file/request_download_file.py +35 -0
  27. rubigram/method/file/request_send_file.py +28 -0
  28. rubigram/method/file/request_upload_file.py +62 -0
  29. rubigram/method/file/send_document.py +58 -0
  30. rubigram/method/file/send_file.py +78 -0
  31. rubigram/method/file/send_gif.py +58 -0
  32. rubigram/method/file/send_music.py +58 -0
  33. rubigram/method/file/send_photo.py +58 -0
  34. rubigram/method/file/send_video.py +58 -0
  35. rubigram/method/file/send_voice.py +55 -0
  36. rubigram/method/messages/__init__.py +29 -0
  37. rubigram/method/messages/delete_message.py +50 -0
  38. rubigram/method/messages/edit_chat_keypad.py +34 -0
  39. rubigram/method/messages/edit_message.py +41 -0
  40. rubigram/method/messages/edit_message_keypad.py +38 -0
  41. rubigram/method/messages/edit_message_text.py +34 -0
  42. rubigram/method/messages/forward_message.py +43 -0
  43. rubigram/method/messages/remove_chat_keypad.py +28 -0
  44. rubigram/method/messages/send_contact.py +74 -0
  45. rubigram/method/messages/send_location.py +70 -0
  46. rubigram/method/messages/send_message.py +67 -0
  47. rubigram/method/messages/send_poll.py +71 -0
  48. rubigram/method/messages/send_sticker.py +66 -0
  49. rubigram/method/network/__init__.py +7 -0
  50. rubigram/method/network/request.py +20 -0
  51. rubigram/method/setting/__init__.py +9 -0
  52. rubigram/method/setting/set_command.py +32 -0
  53. rubigram/method/setting/update_bot_endpoint.py +31 -0
  54. rubigram/method/utilities/__init__.py +11 -0
  55. rubigram/method/utilities/dispatch.py +25 -0
  56. rubigram/method/utilities/setup_endpoint.py +16 -0
  57. rubigram/method/utilities/updater.py +17 -0
  58. rubigram/state.py +14 -19
  59. rubigram/types/__init__.py +3 -0
  60. rubigram/types/messages.py +175 -0
  61. rubigram/types/object.py +112 -0
  62. rubigram/types/types.py +211 -0
  63. rubigram/types/updates.py +572 -0
  64. {rubigramclient-1.7.0.dist-info → rubigramclient-1.7.2.dist-info}/METADATA +12 -8
  65. rubigramclient-1.7.2.dist-info/RECORD +68 -0
  66. rubigram/method.py +0 -354
  67. rubigram/network.py +0 -80
  68. rubigram/rubino/__init__.py +0 -1
  69. rubigram/rubino/client.py +0 -480
  70. rubigram/types.py +0 -538
  71. rubigramclient-1.7.0.dist-info/RECORD +0 -15
  72. {rubigramclient-1.7.0.dist-info → rubigramclient-1.7.2.dist-info}/WHEEL +0 -0
  73. {rubigramclient-1.7.0.dist-info → rubigramclient-1.7.2.dist-info}/licenses/LICENSE +0 -0
  74. {rubigramclient-1.7.0.dist-info → rubigramclient-1.7.2.dist-info}/top_level.txt +0 -0
rubigram/handler.py ADDED
@@ -0,0 +1,24 @@
1
+ from typing import Callable, Optional
2
+ import rubigram
3
+
4
+
5
+ class Handler:
6
+ def __init__(
7
+ self,
8
+ func: Callable,
9
+ filters: Optional[str] = None, # Filter Class
10
+ group: Optional[int] = 1
11
+ ):
12
+ self.func = func
13
+ self.filters = filters
14
+ self.group = group
15
+
16
+ async def runner(
17
+ self,
18
+ client,
19
+ update: "rubigram.types.Update"
20
+ ):
21
+ if self.filters is None or await self.filters(update):
22
+ await self.func(client, update)
23
+ return True
24
+ return False
rubigram/http.py ADDED
@@ -0,0 +1,32 @@
1
+ from aiohttp import ClientSession, TCPConnector, ClientTimeout
2
+ from typing import Optional
3
+ import logging
4
+
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+
9
+ class Http:
10
+ def __init__(self, timeout: Optional[float] = 30):
11
+ self.timeout = timeout
12
+ self.session: Optional[ClientSession] = None
13
+
14
+ async def connect(self):
15
+ connector = TCPConnector(limit=100)
16
+ timeout = ClientTimeout(total=self.timeout)
17
+ if self.session is None:
18
+ self.session = ClientSession(connector=connector, timeout=timeout)
19
+ logger.info("[<] Open HTTP session")
20
+
21
+ async def disconnect(self):
22
+ if self.session:
23
+ await self.session.close()
24
+ self.session = None
25
+ logger.info("[<] Close HTTP session")
26
+
27
+ async def __aenter__(self):
28
+ await self.connect()
29
+ return self
30
+
31
+ async def __aexit__(self, *args):
32
+ await self.disconnect()
rubigram/logger.py ADDED
@@ -0,0 +1,20 @@
1
+ import logging
2
+ import sys
3
+
4
+
5
+ class RubigramFormatter(logging.Formatter):
6
+ def format(self, record):
7
+ module_name = record.name
8
+ log_time = self.formatTime(record, "%Y-%m-%d %H:%M:%S")
9
+ level = record.levelname.upper().ljust(5)
10
+ message = record.getMessage()
11
+ return f"{log_time} | {level} | {module_name} | {message}"
12
+
13
+
14
+ logger = logging.getLogger("rubigram")
15
+ logger.setLevel(logging.DEBUG)
16
+
17
+ if not logger.handlers:
18
+ handler = logging.StreamHandler(sys.stdout)
19
+ handler.setFormatter(RubigramFormatter())
20
+ logger.addHandler(handler)
@@ -0,0 +1,18 @@
1
+ from .chat import Chat
2
+ from .file import File
3
+ from .setting import Setting
4
+ from .network import Network
5
+ from .messages import Message
6
+ from .decorator import Decorator
7
+ from .utilities import Utilities
8
+
9
+ class Method(
10
+ Chat,
11
+ File,
12
+ Setting,
13
+ Network,
14
+ Message,
15
+ Decorator,
16
+ Utilities
17
+ ):
18
+ pass
@@ -0,0 +1,10 @@
1
+ from .get_me import GetMe
2
+ from .get_chat import GetChat
3
+ from .get_update import GetUpdates
4
+
5
+ class Chat(
6
+ GetMe,
7
+ GetChat,
8
+ GetUpdates
9
+ ):
10
+ pass
@@ -0,0 +1,26 @@
1
+ import rubigram
2
+
3
+
4
+ class GetChat:
5
+ async def get_chat(
6
+ self: "rubigram.Client",
7
+ chat_id: str
8
+ ) -> "rubigram.types.Chat":
9
+ """Get information about a chat.
10
+
11
+ Args:
12
+ self (rubigram.Client): The active Rubigram client instance.
13
+ chat_id (str): Unique identifier of the chat to get information about.
14
+
15
+ Returns:
16
+ rubigram.types.Chat: An object containing chat information.
17
+
18
+ Example:
19
+ >>> chat = await client.get_chat("u0f1a2b3c4d5e6")
20
+ >>> print(chat.chat_id, chat.title)
21
+ """
22
+ data = {
23
+ "chat_id": chat_id
24
+ }
25
+ response = await self.request("getChat", data)
26
+ return rubigram.types.Chat.parse(response["chat"])
@@ -0,0 +1,22 @@
1
+ import rubigram
2
+
3
+
4
+ class GetMe:
5
+ async def get_me(self: "rubigram.Client") -> "rubigram.types.Bot":
6
+ """Get information about the current bot.
7
+
8
+ Sends a `getMe` request to the Rubigram API and retrieves
9
+ detailed information about the bot associated with the current token.
10
+
11
+ Returns:
12
+ rubigram.types.Bot: The bot information object containing attributes
13
+ such as bot ID, name, username, and creation date.
14
+
15
+ Example:
16
+ >>> bot = await client.get_me()
17
+ >>> print(bot.id)
18
+ >>> print(bot.name)
19
+ >>> print(bot.username)
20
+ """
21
+ response = await self.request("getMe")
22
+ return rubigram.types.Bot(response["bot"])
@@ -0,0 +1,32 @@
1
+ from typing import Optional
2
+ import rubigram
3
+
4
+
5
+ class GetUpdates:
6
+ async def get_updates(
7
+ self: "rubigram.Client",
8
+ limit: Optional[int] = 1,
9
+ offset_id: Optional[str] = None
10
+ ) -> "rubigram.types.Updates":
11
+ """Get new updates for the bot (messages, events, etc.).
12
+
13
+ Args:
14
+ self (rubigram.Client): The active Rubigram client instance.
15
+ limit (Optional[int], optional): Maximum number of updates to retrieve. Defaults to 1.
16
+ offset_id (Optional[str], optional): Identifier of the last processed update to skip older ones. Defaults to None.
17
+
18
+ Returns:
19
+ rubigram.types.Updates: A parsed object containing a list of updates received from the server.
20
+
21
+ Example:
22
+ >>> updates = await client.get_updates(limit=5)
23
+ >>> for update in updates.updates:
24
+ >>> print(update.new_message.text)
25
+ """
26
+ data = {
27
+ "limit": limit,
28
+ "offset_id": offset_id
29
+ }
30
+
31
+ response = await self.request("getUpdates", data)
32
+ return rubigram.types.Updates.parse(response)
@@ -0,0 +1,8 @@
1
+ from .register import Register
2
+ from .on_message import OnMessage
3
+
4
+ class Decorator(
5
+ Register,
6
+ OnMessage
7
+ ):
8
+ pass
@@ -0,0 +1,37 @@
1
+ from typing import Optional
2
+ from rubigram.filters import Filter
3
+ import rubigram
4
+
5
+
6
+ class OnDeleteMessage:
7
+ def on_delete_message(
8
+ self: "rubigram.Client",
9
+ filters: Optional["Filter"] = None,
10
+ group: int = 0
11
+ ):
12
+ """Register a handler for deleted messages.
13
+
14
+ This decorator allows you to handle events where a message has been removed
15
+ from a chat (either by the sender, admin, or system). The handler function
16
+ will be called whenever a `RemovedMessage` update is received.
17
+
18
+ Args:
19
+ self (rubigram.Client): The active Rubigram client instance.
20
+ filters (Optional[Filter], optional): A filter or combined filters to restrict
21
+ which deleted messages trigger the handler. Defaults to None.
22
+ group (int, optional): Execution priority for this handler. Handlers with
23
+ lower group values are executed first. Defaults to 0.
24
+
25
+ Returns:
26
+ Callable: A decorator that registers the function as a delete-message handler.
27
+
28
+ Example:
29
+ >>> @app.on_delete_message()
30
+ >>> async def on_delete(client, update):
31
+ >>> print(f"Message deleted in chat: {update.chat_id}")
32
+ """
33
+ return self.register_handler(
34
+ self.handlers["delete"],
35
+ filters,
36
+ group
37
+ )
@@ -0,0 +1,37 @@
1
+ from typing import Optional
2
+ from rubigram.filters import Filter
3
+ import rubigram
4
+
5
+
6
+ class OnEditMessage:
7
+ def on_edit_message(
8
+ self: "rubigram.Client",
9
+ filters: Optional["Filter"] = None,
10
+ group: int = 0
11
+ ):
12
+ """Register a handler for edited messages.
13
+
14
+ This decorator allows you to handle updates where an existing message
15
+ in a chat has been edited. The handler function will be triggered whenever
16
+ an `UpdatedMessage` event is received.
17
+
18
+ Args:
19
+ self (rubigram.Client): The active Rubigram client instance.
20
+ filters (Optional[Filter], optional): A filter or combination of filters to limit
21
+ which edited messages should trigger the handler. Defaults to None.
22
+ group (int, optional): Execution priority for this handler. Handlers with
23
+ smaller group values run first. Defaults to 0.
24
+
25
+ Returns:
26
+ Callable: A decorator that registers the function as an edit-message handler.
27
+
28
+ Example:
29
+ >>> @app.on_edit_message()
30
+ >>> async def on_edit(client, update):
31
+ >>> await client.send_message(update.chat_id, "A message was edited!")
32
+ """
33
+ return self.register_handler(
34
+ self.handlers["edit"],
35
+ filters,
36
+ group
37
+ )
@@ -0,0 +1,40 @@
1
+ from typing import Optional
2
+ from rubigram.filters import Filter
3
+ import rubigram
4
+
5
+
6
+ class OnInlineMessage:
7
+ def on_inline_message(
8
+ self: "rubigram.Client",
9
+ filters: Optional["Filter"] = None,
10
+ group: int = 0
11
+ ):
12
+ """Register a handler for inline message updates.
13
+
14
+ This decorator registers a callback function that will be called
15
+ whenever an inline message update is received by the client.
16
+
17
+ Args:
18
+ self (rubigram.Client): The Rubigram client instance.
19
+ filters (Optional[Filter], optional): Filter(s) to restrict which updates
20
+ should trigger the callback. Defaults to None.
21
+ group (int, optional): Determines the order in which multiple handlers
22
+ are executed. Lower numbers are executed first. Defaults to 0.
23
+
24
+ Returns:
25
+ Callable: A decorator that registers the provided function as a handler.
26
+
27
+ Example:
28
+ >>> from rubigram import Client, filters
29
+ >>>
30
+ >>> app = Client("TOKEN")
31
+ >>>
32
+ >>> @app.on_inline_message(filters.button("click_me"))
33
+ >>> async def handle_inline(client, inline):
34
+ >>> await client.send_message(inline.chat_id, "Button clicked!")
35
+ """
36
+ return self.register_handler(
37
+ self.handlers["inline"],
38
+ filters,
39
+ group
40
+ )
@@ -0,0 +1,38 @@
1
+ from typing import Optional
2
+ from rubigram.filters import Filter
3
+ import rubigram
4
+
5
+
6
+ class OnMessage:
7
+ def on_message(
8
+ self: "rubigram.Client",
9
+ filters: Optional["Filter"] = None,
10
+ group: int = 0
11
+ ):
12
+ """Register a handler for new incoming messages.
13
+
14
+ This decorator allows you to listen for new message updates that match
15
+ the provided filters. Handlers are executed in order based on their group priority.
16
+
17
+ Args:
18
+ self (rubigram.Client): The Rubigram client instance.
19
+ filters (Optional[Filter], optional): A filter or combination of filters
20
+ that determine which messages trigger this handler. Defaults to None.
21
+ group (int, optional): The handler execution priority.
22
+ Lower values run first. Defaults to 0.
23
+
24
+ Returns:
25
+ Callable: A decorator used to register the function as a message handler.
26
+
27
+ Example:
28
+ >>> from rubigram import filters
29
+ >>>
30
+ >>> @app.on_message(filters.text)
31
+ >>> async def handle_text(client, update):
32
+ >>> await client.send_message(update.chat_id, "Received a text message!")
33
+ """
34
+ return self.register_handler(
35
+ self.handlers["message"],
36
+ filters,
37
+ group
38
+ )
@@ -0,0 +1,30 @@
1
+ from typing import Callable
2
+ import rubigram
3
+
4
+
5
+ class OnStart:
6
+ def on_start(
7
+ self: "rubigram.Client",
8
+ func: Callable[["rubigram.Client"], None]
9
+ ):
10
+ """Register a startup handler.
11
+
12
+ This decorator registers a function that will be called when the
13
+ client starts. It is typically used for initializing resources,
14
+ database connections, or performing setup tasks before the bot begins
15
+ processing updates.
16
+
17
+ Args:
18
+ self (rubigram.Client): The active Rubigram client instance.
19
+ func (Callable[[rubigram.Client], None]): The async function to be executed on startup.
20
+
21
+ Returns:
22
+ Callable: The function itself, after being registered.
23
+
24
+ Example:
25
+ >>> @app.on_start
26
+ >>> async def on_start(client):
27
+ >>> print("Bot started and ready!")
28
+ """
29
+ self.on_start_app.append(func)
30
+ return func
@@ -0,0 +1,29 @@
1
+ from typing import Callable
2
+ import rubigram
3
+
4
+
5
+ class OnStop:
6
+ def on_stop(
7
+ self: "rubigram.Client",
8
+ func: Callable[["rubigram.Client"], None]
9
+ ):
10
+ """Register a shutdown handler.
11
+
12
+ This decorator registers a function that will be called when the
13
+ client stops. It is typically used for cleaning up resources,
14
+ saving data, or closing database connections before shutdown.
15
+
16
+ Args:
17
+ self (rubigram.Client): The active Rubigram client instance.
18
+ func (Callable[[rubigram.Client], None]): The async function to be executed on shutdown.
19
+
20
+ Returns:
21
+ Callable: The function itself, after being registered.
22
+
23
+ Example:
24
+ >>> @app.on_stop
25
+ >>> async def on_stop(client):
26
+ >>> print("Bot stopped gracefully.")
27
+ """
28
+ self.on_stop_app.append(func)
29
+ return func
@@ -0,0 +1,43 @@
1
+ from typing import Optional, Callable
2
+ from rubigram.filters import Filter
3
+ from ...handler import Handler
4
+ import rubigram
5
+
6
+
7
+ class Register:
8
+ def register_handler(
9
+ self: "rubigram.Client",
10
+ handlers: list["Handler"],
11
+ filters: Optional["Filter"] = None,
12
+ group: int = 0
13
+ ) -> Callable:
14
+ """Register an event handler with optional filters and group priority.
15
+
16
+ This method is used internally by decorators such as
17
+ `on_message`, `on_inline`, and similar ones to attach a function
18
+ as an event handler. It wraps the given function inside a `Handler`
19
+ object and stores it in the appropriate handler list.
20
+
21
+ Args:
22
+ self (rubigram.Client): The active Rubigram client instance.
23
+ handlers (List[Handler]): The list where the handler should be registered.
24
+ filters (Optional[Filter], optional): A filter or filter group to
25
+ restrict which updates trigger the handler. Defaults to None.
26
+ group (int, optional): The handler's execution priority.
27
+ Lower values are executed first. Defaults to 0.
28
+
29
+ Returns:
30
+ Callable: A decorator that registers the provided function as a handler.
31
+
32
+ Example:
33
+ >>> @app.on_message(filters.text)
34
+ >>> async def handle_text(client, update):
35
+ >>> await client.send_message(update.chat_id, "Received text!")
36
+ """
37
+ def decorator(func: Callable):
38
+ handler = Handler(func, filters, group)
39
+ handlers.append(handler)
40
+ handlers.sort(key=lambda x: x.group)
41
+ return func
42
+
43
+ return decorator
@@ -0,0 +1,32 @@
1
+ from .send_gif import SendGif
2
+ from .get_file import GetFile
3
+ from .get_bytes import GetBytes
4
+ from .send_file import SendFile
5
+ from .send_photo import SendPhoto
6
+ from .send_video import SendVideo
7
+ from .send_music import SendMusic
8
+ from .send_voice import SendVoice
9
+ from .get_file_name import GetFileName
10
+ from .send_document import SendDocument
11
+ from .download_file import DownloadFile
12
+ from .request_send_file import RequestSendFile
13
+ from .request_upload_file import RequestUploadFile
14
+ from .request_download_file import RequestDownloadFile
15
+
16
+ class File(
17
+ SendGif,
18
+ GetFile,
19
+ GetBytes,
20
+ SendFile,
21
+ SendPhoto,
22
+ SendVideo,
23
+ SendMusic,
24
+ SendVoice,
25
+ GetFileName,
26
+ SendDocument,
27
+ DownloadFile,
28
+ RequestSendFile,
29
+ RequestUploadFile,
30
+ RequestDownloadFile
31
+ ):
32
+ pass
@@ -0,0 +1,34 @@
1
+ from typing import Optional
2
+ import rubigram
3
+
4
+
5
+ class DownloadFile:
6
+ async def download_file(
7
+ self: "rubigram.Client",
8
+ file_id: str,
9
+ save_as: Optional[str] = None
10
+ ) -> str:
11
+ """Download a file by its file ID.
12
+
13
+ Retrieves the file download URL from the server using the file ID,
14
+ downloads the file, and saves it locally.
15
+
16
+ Args:
17
+ self (rubigram.Client): The active Rubigram client instance.
18
+ file_id (str): The unique identifier of the file to download.
19
+ save_as (Optional[str], optional): Custom filename or path to save the file as.
20
+ If not provided, the original filename will be used. Defaults to None.
21
+
22
+ Returns:
23
+ str: The local path where the file was saved.
24
+
25
+ Example:
26
+ >>> path = await client.download_file(
27
+ >>> file_id="1234567890abcdef",
28
+ >>> save_as="downloads/photo.png"
29
+ >>> )
30
+ >>> print(f"File saved at: {path}")
31
+ """
32
+ download_url = await self.get_file(file_id)
33
+ response = await self.request_download_file(download_url, save_as)
34
+ return response
@@ -0,0 +1,25 @@
1
+ import rubigram
2
+
3
+ class GetBytes:
4
+ async def get_bytes(
5
+ self: "rubigram.Client",
6
+ url: str
7
+ ) -> bytes:
8
+ """Fetch raw bytes from a given URL.
9
+
10
+ Performs an HTTP GET request and returns the response content as bytes.
11
+
12
+ Args:
13
+ self (rubigram.Client): The active Rubigram client instance.
14
+ url (str): The URL to fetch.
15
+
16
+ Returns:
17
+ bytes: The raw content of the response.
18
+
19
+ Example:
20
+ >>> data = await client.get_bytes("https://rubigram.com/file.png")
21
+ >>> print(len(data))
22
+ """
23
+ async with self.http.session.get(url) as response:
24
+ response.raise_for_status()
25
+ return await response.read()
@@ -0,0 +1,27 @@
1
+ import rubigram
2
+
3
+
4
+ class GetFile:
5
+ async def get_file(
6
+ self: "rubigram.Client",
7
+ file_id: str
8
+ ) -> str:
9
+ """Get the download URL of a file.
10
+
11
+ This method retrieves the direct download URL of a file
12
+ previously uploaded or sent via Rubigram.
13
+
14
+ Args:
15
+ self (rubigram.Client): The active Rubigram client instance.
16
+ file_id (str): The unique identifier of the file.
17
+
18
+ Returns:
19
+ str: The download URL of the file.
20
+
21
+ Example:
22
+ >>> download_url = await client.get_file("file_id")
23
+ >>> print(download_url)
24
+ """
25
+ data = {"file_id": file_id}
26
+ response = await self.request("getFile", data)
27
+ return response["download_url"]
@@ -0,0 +1,29 @@
1
+ import os
2
+ from urllib.parse import urlparse
3
+ import rubigram
4
+
5
+
6
+ class GetFileName:
7
+ async def get_file_name(
8
+ self: "rubigram.Client",
9
+ url: str
10
+ ) -> str:
11
+ """Extract the file name from a given URL.
12
+
13
+ This method parses the URL and returns the last path component,
14
+ which usually corresponds to the file name.
15
+
16
+ Args:
17
+ self (rubigram.Client): The active Rubigram client instance.
18
+ url (str): The URL to parse.
19
+
20
+ Returns:
21
+ str: The file name extracted from the URL.
22
+
23
+ Example:
24
+ >>> file_name = await client.get_file_name("https://example.com/path/to/file.png")
25
+ >>> print(file_name)
26
+ file.png
27
+ """
28
+ parser = urlparse(url)
29
+ return os.path.basename(parser.path)
@@ -0,0 +1,35 @@
1
+ from typing import Optional
2
+ import aiofiles
3
+ import rubigram
4
+
5
+ class RequestDownloadFile:
6
+ async def request_download_file(
7
+ self: "rubigram.Client",
8
+ url: str,
9
+ filename: Optional[str] = None
10
+ ) -> str:
11
+ """Download a file from a URL and save it locally.
12
+
13
+ If `filename` is not provided, the name is extracted from the URL.
14
+
15
+ Args:
16
+ self (rubigram.Client): The active Rubigram client instance.
17
+ url (str): The URL of the file to download.
18
+ filename (Optional[str], optional): Local file name to save as.
19
+
20
+ Returns:
21
+ str: The path of the saved file.
22
+
23
+ Example:
24
+ >>> saved_file = await client.request_download(
25
+ >>> "https://example.com/file.png"
26
+ >>> )
27
+ >>> print(saved_file)
28
+ """
29
+ file_bytes = await self.get_bytes(url)
30
+ file_name = filename or await self.get_file_name(url)
31
+
32
+ async with aiofiles.open(file_name, "wb") as f:
33
+ await f.write(file_bytes)
34
+
35
+ return file_name