From 8b4c326365182498fd2963d825b29d93006c1512 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 11 Jul 2019 17:13:20 +0200 Subject: [PATCH 01/55] Add missing bound methods to docs --- compiler/docs/compiler.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index d678b370..d261623d 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -412,11 +412,15 @@ def pyrogram_api(): Chat.unban_member Chat.restrict_member Chat.promote_member + Chat.join + Chat.leave """, user=""" User User.archive User.unarchive + User.block + User.unblock """, callback_query=""" Callback Query From 5fe8fba3dfa6bb84c81614c0b9271d79f80d71c3 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 11 Jul 2019 17:13:43 +0200 Subject: [PATCH 02/55] Fix smart plugins load/unload documentation --- docs/source/topics/smart-plugins.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/topics/smart-plugins.rst b/docs/source/topics/smart-plugins.rst index 8e59b971..5131f27b 100644 --- a/docs/source/topics/smart-plugins.rst +++ b/docs/source/topics/smart-plugins.rst @@ -316,9 +316,9 @@ attribute. Here's an example: Unloading ^^^^^^^^^ -In order to unload a plugin, or any other handler, all you need to do is obtain a reference to it by importing the -relevant module and call :meth:`~pyrogram.Client.remove_handler` Client's method with your function -name preceded by the star ``*`` operator as argument. Example: +In order to unload a plugin, all you need to do is obtain a reference to it by importing the relevant module and call +:meth:`~pyrogram.Client.remove_handler` Client's method with your function's *handler* special attribute preceded by the +star ``*`` operator as argument. Example: - ``main.py`` @@ -328,14 +328,14 @@ name preceded by the star ``*`` operator as argument. Example: ... - app.remove_handler(*echo) + app.remove_handler(*echo.handler) The star ``*`` operator is used to unpack the tuple into positional arguments so that *remove_handler* will receive exactly what is needed. The same could have been achieved with: .. code-block:: python - handler, group = echo + handler, group = echo.handler app.remove_handler(handler, group) Loading @@ -352,4 +352,4 @@ using :meth:`~pyrogram.Client.add_handler` instead. Example: ... - app.add_handler(*echo) \ No newline at end of file + app.add_handler(*echo.handler) \ No newline at end of file From e1197e066eadb4673bd70866eef2b22e311fb56c Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 11 Jul 2019 17:14:38 +0200 Subject: [PATCH 03/55] Use a better name for the special plugin attribute when decorating funcs --- pyrogram/client/client.py | 6 +++--- pyrogram/client/methods/decorators/on_callback_query.py | 2 +- pyrogram/client/methods/decorators/on_deleted_messages.py | 2 +- pyrogram/client/methods/decorators/on_inline_query.py | 2 +- pyrogram/client/methods/decorators/on_message.py | 2 +- pyrogram/client/methods/decorators/on_poll.py | 2 +- pyrogram/client/methods/decorators/on_raw_update.py | 2 +- pyrogram/client/methods/decorators/on_user_status.py | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index 9c19e49a..c660ef21 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.py @@ -1108,7 +1108,7 @@ class Client(Methods, BaseClient): for name in vars(module).keys(): # noinspection PyBroadException try: - handler, group = getattr(module, name).pyrogram_plugin + handler, group = getattr(module, name).handler if isinstance(handler, Handler) and isinstance(group, int): self.add_handler(handler, group) @@ -1143,7 +1143,7 @@ class Client(Methods, BaseClient): for name in handlers: # noinspection PyBroadException try: - handler, group = getattr(module, name).pyrogram_plugin + handler, group = getattr(module, name).handler if isinstance(handler, Handler) and isinstance(group, int): self.add_handler(handler, group) @@ -1181,7 +1181,7 @@ class Client(Methods, BaseClient): for name in handlers: # noinspection PyBroadException try: - handler, group = getattr(module, name).pyrogram_plugin + handler, group = getattr(module, name).handler if isinstance(handler, Handler) and isinstance(group, int): self.remove_handler(handler, group) diff --git a/pyrogram/client/methods/decorators/on_callback_query.py b/pyrogram/client/methods/decorators/on_callback_query.py index 1706d71a..1b7e2bcb 100644 --- a/pyrogram/client/methods/decorators/on_callback_query.py +++ b/pyrogram/client/methods/decorators/on_callback_query.py @@ -47,7 +47,7 @@ class OnCallbackQuery(BaseClient): if isinstance(self, pyrogram.Client): self.add_handler(pyrogram.CallbackQueryHandler(func, filters), group) elif isinstance(self, Filter) or self is None: - func.pyrogram_plugin = ( + func.handler = ( pyrogram.CallbackQueryHandler(func, self), group if filters is None else filters ) diff --git a/pyrogram/client/methods/decorators/on_deleted_messages.py b/pyrogram/client/methods/decorators/on_deleted_messages.py index 86dda587..cf31ac87 100644 --- a/pyrogram/client/methods/decorators/on_deleted_messages.py +++ b/pyrogram/client/methods/decorators/on_deleted_messages.py @@ -47,7 +47,7 @@ class OnDeletedMessages(BaseClient): if isinstance(self, pyrogram.Client): self.add_handler(pyrogram.DeletedMessagesHandler(func, filters), group) elif isinstance(self, Filter) or self is None: - func.pyrogram_plugin = ( + func.handler = ( pyrogram.DeletedMessagesHandler(func, self), group if filters is None else filters ) diff --git a/pyrogram/client/methods/decorators/on_inline_query.py b/pyrogram/client/methods/decorators/on_inline_query.py index d0f2925b..a84b7ca9 100644 --- a/pyrogram/client/methods/decorators/on_inline_query.py +++ b/pyrogram/client/methods/decorators/on_inline_query.py @@ -46,7 +46,7 @@ class OnInlineQuery(BaseClient): if isinstance(self, pyrogram.Client): self.add_handler(pyrogram.InlineQueryHandler(func, filters), group) elif isinstance(self, Filter) or self is None: - func.pyrogram_plugin = ( + func.handler = ( pyrogram.InlineQueryHandler(func, self), group if filters is None else filters ) diff --git a/pyrogram/client/methods/decorators/on_message.py b/pyrogram/client/methods/decorators/on_message.py index 5640f22c..0166541c 100644 --- a/pyrogram/client/methods/decorators/on_message.py +++ b/pyrogram/client/methods/decorators/on_message.py @@ -46,7 +46,7 @@ class OnMessage(BaseClient): if isinstance(self, pyrogram.Client): self.add_handler(pyrogram.MessageHandler(func, filters), group) elif isinstance(self, Filter) or self is None: - func.pyrogram_plugin = ( + func.handler = ( pyrogram.MessageHandler(func, self), group if filters is None else filters ) diff --git a/pyrogram/client/methods/decorators/on_poll.py b/pyrogram/client/methods/decorators/on_poll.py index 24282f28..c797c8c6 100644 --- a/pyrogram/client/methods/decorators/on_poll.py +++ b/pyrogram/client/methods/decorators/on_poll.py @@ -46,7 +46,7 @@ class OnPoll(BaseClient): if isinstance(self, pyrogram.Client): self.add_handler(pyrogram.PollHandler(func, filters), group) elif isinstance(self, Filter) or self is None: - func.pyrogram_plugin = ( + func.handler = ( pyrogram.PollHandler(func, self), group if filters is None else filters ) diff --git a/pyrogram/client/methods/decorators/on_raw_update.py b/pyrogram/client/methods/decorators/on_raw_update.py index bbf40c8b..f56de6f9 100644 --- a/pyrogram/client/methods/decorators/on_raw_update.py +++ b/pyrogram/client/methods/decorators/on_raw_update.py @@ -40,7 +40,7 @@ class OnRawUpdate(BaseClient): if isinstance(self, pyrogram.Client): self.add_handler(pyrogram.RawUpdateHandler(func), group) else: - func.pyrogram_plugin = ( + func.handler = ( pyrogram.RawUpdateHandler(func), group if self is None else group ) diff --git a/pyrogram/client/methods/decorators/on_user_status.py b/pyrogram/client/methods/decorators/on_user_status.py index 81a83d02..02ed9e7b 100644 --- a/pyrogram/client/methods/decorators/on_user_status.py +++ b/pyrogram/client/methods/decorators/on_user_status.py @@ -44,7 +44,7 @@ class OnUserStatus(BaseClient): if isinstance(self, pyrogram.Client): self.add_handler(pyrogram.UserStatusHandler(func, filters), group) elif isinstance(self, Filter) or self is None: - func.pyrogram_plugin = ( + func.handler = ( pyrogram.UserStatusHandler(func, self), group if filters is None else filters ) From fed8cbf87e8f5921fad437c603f569b7c83d6012 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 11 Jul 2019 19:28:33 +0200 Subject: [PATCH 04/55] Add new set_parse_mode utility method --- compiler/docs/compiler.py | 1 + pyrogram/client/client.py | 78 +++++++++++++++++++ pyrogram/client/ext/base_client.py | 3 + .../methods/messages/edit_inline_text.py | 2 +- .../methods/messages/edit_message_text.py | 2 +- .../client/methods/messages/send_animation.py | 2 +- .../client/methods/messages/send_audio.py | 2 +- .../methods/messages/send_cached_media.py | 2 +- .../client/methods/messages/send_document.py | 2 +- .../client/methods/messages/send_message.py | 2 +- .../client/methods/messages/send_photo.py | 2 +- .../client/methods/messages/send_video.py | 2 +- .../client/methods/messages/send_voice.py | 2 +- pyrogram/client/parser/parser.py | 14 +++- .../input_media/input_media_animation.py | 2 +- .../types/input_media/input_media_audio.py | 2 +- .../types/input_media/input_media_document.py | 2 +- .../types/input_media/input_media_photo.py | 2 +- .../types/input_media/input_media_video.py | 2 +- .../input_text_message_content.py | 2 +- 20 files changed, 109 insertions(+), 19 deletions(-) diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index d261623d..c4a0f8a8 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -136,6 +136,7 @@ def pyrogram_api(): remove_handler stop_transmission export_session_string + set_parse_mode """, messages=""" Messages diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index c660ef21..81eef671 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.py @@ -491,6 +491,84 @@ class Client(Methods, BaseClient): """ raise Client.StopTransmission + def export_session_string(self): + """Export the current authorized session as a serialized string. + + Session strings are useful for storing in-memory authorized sessions in a portable, serialized string. + More detailed information about session strings can be found at the dedicated page of + :doc:`Storage Engines <../../topics/storage-engines>`. + + Has no parameters. + + Returns: + ``str``: The session serialized into a printable, url-safe string. + + Example: + .. code-block:: python + :emphasize-lines: 6 + + from pyrogram import Client + + app = Client("my_account") + + with app: + print(app.export_session_string()) + """ + return self.storage.export_session_string() + + def set_parse_mode(self, parse_mode: Union[str, None] = "combined"): + """Set the parse mode to be used globally by the client. + + When setting the parse mode with this method, all methods having a *parse_mode* parameter will follow the global + value by default. The default value *"combined"* enables both Markdown and HTML styles to be used and combined + together. + + Parameters: + parse_mode (``str``): + The new parse mode, can be any of: *"combined"*, for the default combined mode. *"markdown"* or *"md"* + to force Markdown-only styles. *"html"* to force HTML-only styles. *None* to disable the parser + completely. + + Raises: + ValueError: In case the provided *parse_mode* is not a valid parse mode. + + Example: + .. code-block:: python + :emphasize-lines: 10,14,18,22 + + from pyrogram import Client + + app = Client("my_account") + + with app: + # Default combined mode: Markdown + HTML + app.send_message("haskell", "1. **markdown** and html") + + # Force Markdown-only, HTML is disabled + app.set_parse_mode("markdown") + app.send_message("haskell", "2. **markdown** and html") + + # Force HTML-only, Markdown is disabled + app.set_parse_mode("html") + app.send_message("haskell", "3. **markdown** and html") + + # Disable the parser completely + app.set_parse_mode(None) + app.send_message("haskell", "4. **markdown** and html") + + # Bring back the default combined mode + app.set_parse_mode() + app.send_message("haskell", "5. **markdown** and html") + """ + + if parse_mode not in self.PARSE_MODES: + raise ValueError('parse_mode must be one of {} or None. Not "{}"'.format( + ", ".join('"{}"'.format(m) for m in self.PARSE_MODES[:-1]), + parse_mode + )) + + self.parse_mode = parse_mode + def authorize_bot(self): try: r = self.send( diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py index b5be089b..bb024250 100644 --- a/pyrogram/client/ext/base_client.py +++ b/pyrogram/client/ext/base_client.py @@ -59,6 +59,8 @@ class BaseClient: WORKDIR = PARENT_DIR CONFIG_FILE = PARENT_DIR / "config.ini" + PARSE_MODES = ["combined", "markdown", "md", "html", None] + MEDIA_TYPE_ID = { 0: "photo_thumbnail", 1: "chat_photo", @@ -93,6 +95,7 @@ class BaseClient: self.rnd_id = MsgId self.parser = Parser(self) + self.parse_mode = "combined" self.session = None self.media_sessions = {} diff --git a/pyrogram/client/methods/messages/edit_inline_text.py b/pyrogram/client/methods/messages/edit_inline_text.py index 0d17b4a4..9b0b34d3 100644 --- a/pyrogram/client/methods/messages/edit_inline_text.py +++ b/pyrogram/client/methods/messages/edit_inline_text.py @@ -28,7 +28,7 @@ class EditInlineText(BaseClient): self, inline_message_id: str, text: str, - parse_mode: Union[str, None] = "", + parse_mode: Union[str, None] = object, disable_web_page_preview: bool = None, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> bool: diff --git a/pyrogram/client/methods/messages/edit_message_text.py b/pyrogram/client/methods/messages/edit_message_text.py index c81139af..063c8c72 100644 --- a/pyrogram/client/methods/messages/edit_message_text.py +++ b/pyrogram/client/methods/messages/edit_message_text.py @@ -29,7 +29,7 @@ class EditMessageText(BaseClient): chat_id: Union[int, str], message_id: int, text: str, - parse_mode: Union[str, None] = "", + parse_mode: Union[str, None] = object, disable_web_page_preview: bool = None, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> "pyrogram.Message": diff --git a/pyrogram/client/methods/messages/send_animation.py b/pyrogram/client/methods/messages/send_animation.py index 34389149..a68984fc 100644 --- a/pyrogram/client/methods/messages/send_animation.py +++ b/pyrogram/client/methods/messages/send_animation.py @@ -32,7 +32,7 @@ class SendAnimation(BaseClient): animation: str, caption: str = "", unsave: bool = False, - parse_mode: Union[str, None] = "", + parse_mode: Union[str, None] = object, duration: int = 0, width: int = 0, height: int = 0, diff --git a/pyrogram/client/methods/messages/send_audio.py b/pyrogram/client/methods/messages/send_audio.py index 43c5a63e..c8ce7368 100644 --- a/pyrogram/client/methods/messages/send_audio.py +++ b/pyrogram/client/methods/messages/send_audio.py @@ -31,7 +31,7 @@ class SendAudio(BaseClient): chat_id: Union[int, str], audio: str, caption: str = "", - parse_mode: Union[str, None] = "", + parse_mode: Union[str, None] = object, duration: int = 0, performer: str = None, title: str = None, diff --git a/pyrogram/client/methods/messages/send_cached_media.py b/pyrogram/client/methods/messages/send_cached_media.py index 0f2e1389..59a24171 100644 --- a/pyrogram/client/methods/messages/send_cached_media.py +++ b/pyrogram/client/methods/messages/send_cached_media.py @@ -29,7 +29,7 @@ class SendCachedMedia(BaseClient): chat_id: Union[int, str], file_id: str, caption: str = "", - parse_mode: Union[str, None] = "", + parse_mode: Union[str, None] = object, disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ diff --git a/pyrogram/client/methods/messages/send_document.py b/pyrogram/client/methods/messages/send_document.py index fcaf5f51..a3cec395 100644 --- a/pyrogram/client/methods/messages/send_document.py +++ b/pyrogram/client/methods/messages/send_document.py @@ -32,7 +32,7 @@ class SendDocument(BaseClient): document: str, thumb: str = None, caption: str = "", - parse_mode: Union[str, None] = "", + parse_mode: Union[str, None] = object, disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ diff --git a/pyrogram/client/methods/messages/send_message.py b/pyrogram/client/methods/messages/send_message.py index 15b5f25c..f652f3d9 100644 --- a/pyrogram/client/methods/messages/send_message.py +++ b/pyrogram/client/methods/messages/send_message.py @@ -28,7 +28,7 @@ class SendMessage(BaseClient): self, chat_id: Union[int, str], text: str, - parse_mode: Union[str, None] = "", + parse_mode: Union[str, None] = object, disable_web_page_preview: bool = None, disable_notification: bool = None, reply_to_message_id: int = None, diff --git a/pyrogram/client/methods/messages/send_photo.py b/pyrogram/client/methods/messages/send_photo.py index c43c0139..981b0045 100644 --- a/pyrogram/client/methods/messages/send_photo.py +++ b/pyrogram/client/methods/messages/send_photo.py @@ -31,7 +31,7 @@ class SendPhoto(BaseClient): chat_id: Union[int, str], photo: str, caption: str = "", - parse_mode: Union[str, None] = "", + parse_mode: Union[str, None] = object, ttl_seconds: int = None, disable_notification: bool = None, reply_to_message_id: int = None, diff --git a/pyrogram/client/methods/messages/send_video.py b/pyrogram/client/methods/messages/send_video.py index ba69aafb..602e3b01 100644 --- a/pyrogram/client/methods/messages/send_video.py +++ b/pyrogram/client/methods/messages/send_video.py @@ -31,7 +31,7 @@ class SendVideo(BaseClient): chat_id: Union[int, str], video: str, caption: str = "", - parse_mode: Union[str, None] = "", + parse_mode: Union[str, None] = object, duration: int = 0, width: int = 0, height: int = 0, diff --git a/pyrogram/client/methods/messages/send_voice.py b/pyrogram/client/methods/messages/send_voice.py index 854385d8..9c0b8514 100644 --- a/pyrogram/client/methods/messages/send_voice.py +++ b/pyrogram/client/methods/messages/send_voice.py @@ -31,7 +31,7 @@ class SendVoice(BaseClient): chat_id: Union[int, str], voice: str, caption: str = "", - parse_mode: Union[str, None] = "", + parse_mode: Union[str, None] = object, duration: int = 0, disable_notification: bool = None, reply_to_message_id: int = None, diff --git a/pyrogram/client/parser/parser.py b/pyrogram/client/parser/parser.py index 8fde46bd..e6681b32 100644 --- a/pyrogram/client/parser/parser.py +++ b/pyrogram/client/parser/parser.py @@ -19,7 +19,6 @@ from collections import OrderedDict from typing import Union - import pyrogram from .html import HTML from .markdown import Markdown @@ -27,12 +26,16 @@ from .markdown import Markdown class Parser: def __init__(self, client: Union["pyrogram.BaseClient", None]): + self.client = client self.html = HTML(client) self.markdown = Markdown(client) - def parse(self, text: str, mode: str = ""): + def parse(self, text: str, mode: Union[str, None] = object): text = str(text or "").strip() + if mode == object: + mode = self.client.parse_mode + if mode is None: return OrderedDict([ ("message", text), @@ -41,7 +44,7 @@ class Parser: mode = mode.lower() - if mode == "": + if mode == "combined": return self.markdown.parse(text) if mode in ["markdown", "md"]: @@ -50,6 +53,11 @@ class Parser: if mode == "html": return self.html.parse(text) + raise ValueError('parse_mode must be one of {} or None. Not "{}"'.format( + ", ".join('"{}"'.format(m) for m in self.client.PARSE_MODES[:-1]), + mode + )) + @staticmethod def unparse(text: str, entities: list, is_html: bool): if is_html: diff --git a/pyrogram/client/types/input_media/input_media_animation.py b/pyrogram/client/types/input_media/input_media_animation.py index e157993b..d6c67d56 100644 --- a/pyrogram/client/types/input_media/input_media_animation.py +++ b/pyrogram/client/types/input_media/input_media_animation.py @@ -63,7 +63,7 @@ class InputMediaAnimation(InputMedia): media: str, thumb: str = None, caption: str = "", - parse_mode: Union[str, None] = "", + parse_mode: Union[str, None] = object, width: int = 0, height: int = 0, duration: int = 0 diff --git a/pyrogram/client/types/input_media/input_media_audio.py b/pyrogram/client/types/input_media/input_media_audio.py index 3eb3ea65..f01444a8 100644 --- a/pyrogram/client/types/input_media/input_media_audio.py +++ b/pyrogram/client/types/input_media/input_media_audio.py @@ -65,7 +65,7 @@ class InputMediaAudio(InputMedia): media: str, thumb: str = None, caption: str = "", - parse_mode: Union[str, None] = "", + parse_mode: Union[str, None] = object, duration: int = 0, performer: int = "", title: str = "" diff --git a/pyrogram/client/types/input_media/input_media_document.py b/pyrogram/client/types/input_media/input_media_document.py index 7aca9a31..af549c81 100644 --- a/pyrogram/client/types/input_media/input_media_document.py +++ b/pyrogram/client/types/input_media/input_media_document.py @@ -54,7 +54,7 @@ class InputMediaDocument(InputMedia): media: str, thumb: str = None, caption: str = "", - parse_mode: Union[str, None] = "" + parse_mode: Union[str, None] = object ): super().__init__(media, caption, parse_mode) diff --git a/pyrogram/client/types/input_media/input_media_photo.py b/pyrogram/client/types/input_media/input_media_photo.py index d2f26a88..30c53777 100644 --- a/pyrogram/client/types/input_media/input_media_photo.py +++ b/pyrogram/client/types/input_media/input_media_photo.py @@ -49,6 +49,6 @@ class InputMediaPhoto(InputMedia): self, media: str, caption: str = "", - parse_mode: Union[str, None] = "" + parse_mode: Union[str, None] = object ): super().__init__(media, caption, parse_mode) diff --git a/pyrogram/client/types/input_media/input_media_video.py b/pyrogram/client/types/input_media/input_media_video.py index d2ee851d..3500ff55 100644 --- a/pyrogram/client/types/input_media/input_media_video.py +++ b/pyrogram/client/types/input_media/input_media_video.py @@ -68,7 +68,7 @@ class InputMediaVideo(InputMedia): media: str, thumb: str = None, caption: str = "", - parse_mode: Union[str, None] = "", + parse_mode: Union[str, None] = object, width: int = 0, height: int = 0, duration: int = 0, diff --git a/pyrogram/client/types/input_message_content/input_text_message_content.py b/pyrogram/client/types/input_message_content/input_text_message_content.py index f4b9aefc..f90b7096 100644 --- a/pyrogram/client/types/input_message_content/input_text_message_content.py +++ b/pyrogram/client/types/input_message_content/input_text_message_content.py @@ -43,7 +43,7 @@ class InputTextMessageContent(InputMessageContent): __slots__ = ["message_text", "parse_mode", "disable_web_page_preview"] - def __init__(self, message_text: str, parse_mode: Union[str, None] = "", disable_web_page_preview: bool = None): + def __init__(self, message_text: str, parse_mode: Union[str, None] = object, disable_web_page_preview: bool = None): super().__init__() self.message_text = message_text From 385ab22b68169fdfe43ce33126d3a8d839ea0f5e Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 11 Jul 2019 19:59:56 +0200 Subject: [PATCH 05/55] Rework Client.idle() idle() is now static and doesn't stop the client anymore --- pyrogram/client/client.py | 53 +++++++++++++++++++++--------- pyrogram/client/ext/base_client.py | 3 +- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index 81eef671..08ea3b39 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.py @@ -394,37 +394,60 @@ class Client(Methods, BaseClient): self.stop() self.start() - def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)): + @staticmethod + def idle(stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)): """Block the main script execution until a signal is received. - Once the signal is received (e.g.: from CTRL+C), the client will automatically stop and the main script will - continue its execution. + This static method will run an infinite loop in order to block the main script execution and prevent it from + exiting while having client(s) that are still running in the background. - This is used after starting one or more clients and is useful for event-driven applications only, that are, - applications which react upon incoming Telegram updates through handlers, rather than executing a set of methods - sequentially. + It is useful for event-driven application only, that are, applications which react upon incoming Telegram + updates through handlers, rather than executing a set of methods sequentially. - The way Pyrogram works, will keep your handlers in a pool of workers, which are executed concurrently outside - the main script; calling idle() will ensure the client(s) will be kept alive by not letting the main script to - end, until you decide to quit. + The way Pyrogram works, it will keep your handlers in a pool of worker threads, which are executed concurrently + outside the main thread; calling idle() will ensure the client(s) will be kept alive by not letting the main + script to end, until you decide to quit. + + Once a signal is received (e.g.: from CTRL+C) the inner infinite loop will break and your main script will + continue. Don't forget to call :meth:`~Client.stop` for each running client before the script ends. Parameters: stop_signals (``tuple``, *optional*): Iterable containing signals the signal handler will listen to. - Defaults to (SIGINT, SIGTERM, SIGABRT). + Defaults to *(SIGINT, SIGTERM, SIGABRT)*. + + Example: + .. code-block:: python + :emphasize-lines: 13 + + from pyrogram import Client + + app1 = Client("account1") + app2 = Client("account2") + app3 = Client("account3") + + ... # Set handlers up + + app1.start() + app2.start() + app3.start() + + Client.idle() + + app1.stop() + app2.stop() + app3.stop() """ - # TODO: Maybe make this method static and don't automatically stop - def signal_handler(*args): - self.is_idle = False + Client.is_idling = False for s in stop_signals: signal(s, signal_handler) - self.is_idle = True + Client.is_idling = True - while self.is_idle: + while Client.is_idling: time.sleep(1) self.stop() diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py index bb024250..ce736e87 100644 --- a/pyrogram/client/ext/base_client.py +++ b/pyrogram/client/ext/base_client.py @@ -89,6 +89,8 @@ class BaseClient: mime_types_to_extensions[mime_type] = " ".join(extensions) + is_idling = False + def __init__(self): self.storage = None @@ -102,7 +104,6 @@ class BaseClient: self.media_sessions_lock = Lock() self.is_started = None - self.is_idle = None self.takeout_id = None From 2095f9fb5e3cf4dc39b7e5f2f51e9313a1526adb Mon Sep 17 00:00:00 2001 From: kalmengr <46006289+kalmengr@users.noreply.github.com> Date: Fri, 12 Jul 2019 12:05:19 -0400 Subject: [PATCH 06/55] Add bound method vote to Message --- .../types/messages_and_media/message.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index 144f04a4..68678210 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.py @@ -2923,6 +2923,43 @@ class Message(Object, Update): progress=progress, progress_args=progress_args, ) + def vote( + self, + option: int, + ) -> "Poll": + """Bound method *vote* of :obj:`Message`. + + Use as a shortcut for: + + .. code-block:: python + + client.vote_poll( + chat_id=message.chat.id, + message_id=message.message_id, + option=1 + ) + + Example: + .. code-block:: python + + message.vote(6) + + Parameters: + option (``int``): + Index of the poll option you want to vote for (0 to 9). + + Returns: + On success, the poll with the chosen option is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + + return self._client.vote_poll( + chat_id=self.chat.id, + message_id= self.message_id, + option=option + ) def pin(self, disable_notification: bool = None) -> "Message": """Bound method *pin* of :obj:`Message`. From ba4748814249dc003341f64b286d56449087a2b9 Mon Sep 17 00:00:00 2001 From: kalmengr <46006289+kalmengr@users.noreply.github.com> Date: Fri, 12 Jul 2019 12:13:14 -0400 Subject: [PATCH 07/55] Update message.py --- pyrogram/client/types/messages_and_media/message.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index 68678210..8b02839f 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.py @@ -2957,7 +2957,7 @@ class Message(Object, Update): return self._client.vote_poll( chat_id=self.chat.id, - message_id= self.message_id, + message_id=self.message_id, option=option ) From 449f318e6d06dd1aeed5cd18d1533b6ef3da1aec Mon Sep 17 00:00:00 2001 From: kalmengr <46006289+kalmengr@users.noreply.github.com> Date: Fri, 12 Jul 2019 18:29:35 -0400 Subject: [PATCH 08/55] Add retract_vote bound method to Message --- .../types/messages_and_media/message.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index 144f04a4..80597e33 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.py @@ -2868,6 +2868,38 @@ class Message(Object, Update): raise ValueError("This button is not supported yet") else: self.reply(button, quote=quote) + + + def retract_vote( + self, + ) -> "Poll": + """Bound method *retract_vote* of :obj:`Message`. + + Use as a shortcut for: + + .. code-block:: python + + client.retract_vote( + chat_id=message.chat.id, + message_id=message_id, + ) + Example: + .. code-block:: python + + message.retract_vote() + + Returns: + :obj:`Poll` + On success, the poll with the retracted vote is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + + return self._client.retract_vote( + chat_id=self.chat.id, + message_id=self.message_id + ) def download( self, From bb1470e57f90a114f0334588055c772debfde48d Mon Sep 17 00:00:00 2001 From: MrNaif2018 Date: Mon, 15 Jul 2019 15:37:18 +0300 Subject: [PATCH 09/55] Add section to docs about scheduling --- docs/source/index.rst | 1 + docs/source/topics/scheduling.rst | 73 +++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 docs/source/topics/scheduling.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index 5cb9bb2e..b8927657 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -40,6 +40,7 @@ Welcome to Pyrogram topics/more-on-updates topics/config-file topics/smart-plugins + topics/scheduling topics/auto-auth topics/session-settings topics/tgcrypto diff --git a/docs/source/topics/scheduling.rst b/docs/source/topics/scheduling.rst new file mode 100644 index 00000000..70f70215 --- /dev/null +++ b/docs/source/topics/scheduling.rst @@ -0,0 +1,73 @@ +Scheduling tasks +================ + +Pyrogram itself as Telegram MTProto API Framework contains only stuff +related to Telegram. Scheduling is out of it's scope. + +But it is easy to integrate pyrogram with your favourite scheduler. + +schedule +-------- + +Note that schedule is not suitable for async version of pyrogram. + +.. code-block:: python + + import time + import schedule + + + def job(): + app.send_message("me", "Hi!") + + + schedule.every(10).minutes.do(job) + schedule.every().hour.do(job) + schedule.every().day.at("10:30").do(job) + schedule.every(5).to(10).minutes.do(job) + schedule.every().monday.do(job) + schedule.every().wednesday.at("13:15").do(job) + schedule.every().minute.at(":17").do(job) + + with app: + while True: + schedule.run_pending() + time.sleep(1) + + +apscheduler +----------- + +.. code-block:: python + + import time + from apscheduler.schedulers.background import BackgroundScheduler + + + def job(): + app.send_message("me", "Hi!") + + + scheduler = BackgroundScheduler() + scheduler.add_job(job, 'interval', seconds=3) + + scheduler.start() + app.run() + +Apscheduler supports async version of pyrogram too, here is async example: + +.. code-block:: python + + from apscheduler.schedulers.asyncio import AsyncIOScheduler + + + async def job(): + await app.send_message("me", "Hi!") + + + scheduler = AsyncIOScheduler() + scheduler.add_job(job, 'interval', seconds=3) + + scheduler.start() + app.run() + From 85c21308757d21fbb55b610ab7f59b8a8ba1f12a Mon Sep 17 00:00:00 2001 From: MrNaif2018 Date: Mon, 15 Jul 2019 16:56:59 +0300 Subject: [PATCH 10/55] Update .gitignore with vscode and alternate docs build dir --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 0b1a0699..ce3407dd 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ pyrogram/api/all.py # PyCharm stuff .idea/ +# VS Code +.vscode/ + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -78,6 +81,7 @@ instance/ # Sphinx documentation docs/_build/ +docs/source/_build # PyBuilder target/ From f2b3db47a9e4de2d0ccf52b3887fc65975360340 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Tue, 16 Jul 2019 07:41:11 +0200 Subject: [PATCH 11/55] Add "bot" chat type into Filters.private. Bots are still 1-to-1 private chats --- pyrogram/client/filters/filters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py index d8768b3b..01d6bbd4 100644 --- a/pyrogram/client/filters/filters.py +++ b/pyrogram/client/filters/filters.py @@ -136,7 +136,7 @@ class Filters: poll = create(lambda _, m: m.poll, "PollFilter") """Filter messages that contain :obj:`Poll` objects.""" - private = create(lambda _, m: bool(m.chat and m.chat.type == "private"), "PrivateFilter") + private = create(lambda _, m: bool(m.chat and m.chat.type in {"private", "bot"}), "PrivateFilter") """Filter messages sent in private chats.""" group = create(lambda _, m: bool(m.chat and m.chat.type in {"group", "supergroup"}), "GroupFilter") From 62a39521d92b6e33132a58ca3e3be228d812d27d Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Fri, 19 Jul 2019 13:40:12 +0200 Subject: [PATCH 12/55] Allow send_media_group send media from URLs --- .../methods/messages/send_media_group.py | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/pyrogram/client/methods/messages/send_media_group.py b/pyrogram/client/methods/messages/send_media_group.py index 681e1850..1f0aa3dd 100644 --- a/pyrogram/client/methods/messages/send_media_group.py +++ b/pyrogram/client/methods/messages/send_media_group.py @@ -31,7 +31,6 @@ log = logging.getLogger(__name__) class SendMediaGroup(BaseClient): # TODO: Add progress parameter - # TODO: Figure out how to send albums using URLs def send_media_group( self, chat_id: Union[int, str], @@ -88,7 +87,24 @@ class SendMediaGroup(BaseClient): id=types.InputPhoto( id=media.photo.id, access_hash=media.photo.access_hash, - file_reference=b"" + file_reference=media.photo.file_reference + ) + ) + elif i.media.startswith("http"): + media = self.send( + functions.messages.UploadMedia( + peer=self.resolve_peer(chat_id), + media=types.InputMediaPhotoExternal( + url=i.media + ) + ) + ) + + media = types.InputMediaPhoto( + id=types.InputPhoto( + id=media.photo.id, + access_hash=media.photo.access_hash, + file_reference=media.photo.file_reference ) ) else: @@ -126,7 +142,24 @@ class SendMediaGroup(BaseClient): id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, - file_reference=b"" + file_reference=media.document.file_reference + ) + ) + elif i.media.startswith("http"): + media = self.send( + functions.messages.UploadMedia( + peer=self.resolve_peer(chat_id), + media=types.InputMediaDocumentExternal( + url=i.media + ) + ) + ) + + media = types.InputMediaDocument( + id=types.InputDocument( + id=media.document.id, + access_hash=media.document.access_hash, + file_reference=media.document.file_reference ) ) else: From 6459ce0a07a6105b435ba9642d099d7d9cb5ad06 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 21 Jul 2019 01:03:19 +0200 Subject: [PATCH 13/55] Fix lots of bound methods breaking due to latest changes on parse_mode Addresses #287 --- .../methods/messages/edit_inline_caption.py | 4 +++- .../methods/messages/edit_message_caption.py | 2 +- pyrogram/client/parser/parser.py | 7 +++++-- .../bots_and_keyboards/callback_query.py | 4 ++-- .../types/messages_and_media/message.py | 20 +++++++++---------- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/pyrogram/client/methods/messages/edit_inline_caption.py b/pyrogram/client/methods/messages/edit_inline_caption.py index 2d904198..298e3ef4 100644 --- a/pyrogram/client/methods/messages/edit_inline_caption.py +++ b/pyrogram/client/methods/messages/edit_inline_caption.py @@ -16,6 +16,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from typing import Union + import pyrogram from pyrogram.client.ext import BaseClient @@ -25,7 +27,7 @@ class EditInlineCaption(BaseClient): self, inline_message_id: str, caption: str, - parse_mode: str = "", + parse_mode: Union[str, None] = object, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> bool: """Edit the caption of **inline** media messages. diff --git a/pyrogram/client/methods/messages/edit_message_caption.py b/pyrogram/client/methods/messages/edit_message_caption.py index 6fefe0b2..c760c675 100644 --- a/pyrogram/client/methods/messages/edit_message_caption.py +++ b/pyrogram/client/methods/messages/edit_message_caption.py @@ -28,7 +28,7 @@ class EditMessageCaption(BaseClient): chat_id: Union[int, str], message_id: int, caption: str, - parse_mode: str = "", + parse_mode: Union[str, None] = object, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> "pyrogram.Message": """Edit the caption of media messages. diff --git a/pyrogram/client/parser/parser.py b/pyrogram/client/parser/parser.py index e6681b32..edf9553d 100644 --- a/pyrogram/client/parser/parser.py +++ b/pyrogram/client/parser/parser.py @@ -34,7 +34,10 @@ class Parser: text = str(text or "").strip() if mode == object: - mode = self.client.parse_mode + if self.client: + mode = self.client.parse_mode + else: + mode = "combined" if mode is None: return OrderedDict([ @@ -54,7 +57,7 @@ class Parser: return self.html.parse(text) raise ValueError('parse_mode must be one of {} or None. Not "{}"'.format( - ", ".join('"{}"'.format(m) for m in self.client.PARSE_MODES[:-1]), + ", ".join('"{}"'.format(m) for m in pyrogram.Client.PARSE_MODES[:-1]), mode )) diff --git a/pyrogram/client/types/bots_and_keyboards/callback_query.py b/pyrogram/client/types/bots_and_keyboards/callback_query.py index b09e5440..d58865b2 100644 --- a/pyrogram/client/types/bots_and_keyboards/callback_query.py +++ b/pyrogram/client/types/bots_and_keyboards/callback_query.py @@ -176,7 +176,7 @@ class CallbackQuery(Object, Update): def edit_message_text( self, text: str, - parse_mode: str = "", + parse_mode: Union[str, None] = object, disable_web_page_preview: bool = None, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> Union["pyrogram.Message", bool]: @@ -229,7 +229,7 @@ class CallbackQuery(Object, Update): def edit_message_caption( self, caption: str, - parse_mode: str = "", + parse_mode: Union[str, None] = object, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> Union["pyrogram.Message", bool]: """Edit the caption of media messages attached to callback queries. diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index 144f04a4..2f1d5928 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.py @@ -654,7 +654,7 @@ class Message(Object, Update): self, text: str, quote: bool = None, - parse_mode: str = "", + parse_mode: Union[str, None] = object, disable_web_page_preview: bool = None, disable_notification: bool = None, reply_to_message_id: int = None, @@ -736,7 +736,7 @@ class Message(Object, Update): animation: str, quote: bool = None, caption: str = "", - parse_mode: str = "", + parse_mode: Union[str, None] = object, duration: int = 0, width: int = 0, height: int = 0, @@ -873,7 +873,7 @@ class Message(Object, Update): audio: str, quote: bool = None, caption: str = "", - parse_mode: str = "", + parse_mode: Union[str, None] = object, duration: int = 0, performer: str = None, title: str = None, @@ -1010,7 +1010,7 @@ class Message(Object, Update): file_id: str, quote: bool = None, caption: str = "", - parse_mode: str = "", + parse_mode: Union[str, None] = object, disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ @@ -1218,7 +1218,7 @@ class Message(Object, Update): quote: bool = None, thumb: str = None, caption: str = "", - parse_mode: str = "", + parse_mode: Union[str, None] = object, disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ @@ -1613,7 +1613,7 @@ class Message(Object, Update): photo: str, quote: bool = None, caption: str = "", - parse_mode: str = "", + parse_mode: Union[str, None] = object, ttl_seconds: int = None, disable_notification: bool = None, reply_to_message_id: int = None, @@ -2007,7 +2007,7 @@ class Message(Object, Update): video: str, quote: bool = None, caption: str = "", - parse_mode: str = "", + parse_mode: Union[str, None] = object, duration: int = 0, width: int = 0, height: int = 0, @@ -2267,7 +2267,7 @@ class Message(Object, Update): voice: str, quote: bool = None, caption: str = "", - parse_mode: str = "", + parse_mode: Union[str, None] = object, duration: int = 0, disable_notification: bool = None, reply_to_message_id: int = None, @@ -2384,7 +2384,7 @@ class Message(Object, Update): def edit_text( self, text: str, - parse_mode: str = "", + parse_mode: Union[str, None] = object, disable_web_page_preview: bool = None, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> "Message": @@ -2442,7 +2442,7 @@ class Message(Object, Update): def edit_caption( self, caption: str, - parse_mode: str = "", + parse_mode: Union[str, None] = object, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> "Message": """Bound method *edit_caption* of :obj:`Message`. From 184f851625d0526c94d55cc6c47184faf601895b Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 21 Jul 2019 02:22:46 +0200 Subject: [PATCH 14/55] Fix idle() and run() breaking after latest changes --- pyrogram/client/client.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index 08ea3b39..19ff1b5e 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.py @@ -450,8 +450,6 @@ class Client(Methods, BaseClient): while Client.is_idling: time.sleep(1) - self.stop() - def run(self): """Start the Client and automatically idle the main script. @@ -464,6 +462,7 @@ class Client(Methods, BaseClient): """ self.start() self.idle() + self.stop() def add_handler(self, handler: Handler, group: int = 0): """Register an update handler. From 036a73997a46c4e0151b6eff304ead5c441b386b Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 21 Jul 2019 23:08:30 +0200 Subject: [PATCH 15/55] Add new methods: add_chat_members, create_* and delete_* chats - add_chat_members - create_group - create_channel - create_supergroup - delete_channel - delete_supergroup --- compiler/docs/compiler.py | 6 ++ pyrogram/client/methods/chats/__init__.py | 14 +++- .../client/methods/chats/add_chat_members.py | 76 +++++++++++++++++++ .../client/methods/chats/create_channel.py | 50 ++++++++++++ pyrogram/client/methods/chats/create_group.py | 60 +++++++++++++++ .../client/methods/chats/create_supergroup.py | 54 +++++++++++++ .../client/methods/chats/delete_channel.py | 43 +++++++++++ .../client/methods/chats/delete_supergroup.py | 43 +++++++++++ 8 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 pyrogram/client/methods/chats/add_chat_members.py create mode 100644 pyrogram/client/methods/chats/create_channel.py create mode 100644 pyrogram/client/methods/chats/create_group.py create mode 100644 pyrogram/client/methods/chats/create_supergroup.py create mode 100644 pyrogram/client/methods/chats/delete_channel.py create mode 100644 pyrogram/client/methods/chats/delete_supergroup.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index c4a0f8a8..98c3c591 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -204,6 +204,12 @@ def pyrogram_api(): update_chat_username archive_chats unarchive_chats + add_chat_members + create_channel + create_group + create_supergroup + delete_channel + delete_supergroup """, users=""" Users diff --git a/pyrogram/client/methods/chats/__init__.py b/pyrogram/client/methods/chats/__init__.py index 969628ee..a7fc2792 100644 --- a/pyrogram/client/methods/chats/__init__.py +++ b/pyrogram/client/methods/chats/__init__.py @@ -16,8 +16,14 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from .add_chat_members import AddChatMembers from .archive_chats import ArchiveChats +from .create_channel import CreateChannel +from .create_group import CreateGroup +from .create_supergroup import CreateSupergroup +from .delete_channel import DeleteChannel from .delete_chat_photo import DeleteChatPhoto +from .delete_supergroup import DeleteSupergroup from .export_chat_invite_link import ExportChatInviteLink from .get_chat import GetChat from .get_chat_member import GetChatMember @@ -68,6 +74,12 @@ class Chats( RestrictChat, GetDialogsCount, ArchiveChats, - UnarchiveChats + UnarchiveChats, + CreateGroup, + CreateSupergroup, + CreateChannel, + AddChatMembers, + DeleteChannel, + DeleteSupergroup ): pass diff --git a/pyrogram/client/methods/chats/add_chat_members.py b/pyrogram/client/methods/chats/add_chat_members.py new file mode 100644 index 00000000..ce5b0cce --- /dev/null +++ b/pyrogram/client/methods/chats/add_chat_members.py @@ -0,0 +1,76 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Union, List + +from pyrogram.api import functions, types +from ...ext import BaseClient + + +class AddChatMembers(BaseClient): + def add_chat_members( + self, + chat_id: Union[int, str], + user_ids: Union[Union[int, str], List[Union[int, str]]], + forward_limit: int = 100 + ) -> bool: + """Add new chat members to a group, supergroup or channel + + Parameters: + chat_id (``int`` | ``str``): + The group, supergroup or channel id + + user_ids (``int`` | ``str`` | List of ``int`` or ``str``): + Users to add in the chat + You can pass an ID (int), username (str) or phone number (str). + Multiple users can be added by passing a list of IDs, usernames or phone numbers. + + forward_limit (``int``, *optional*): + How many of the latest messages you want to forward to the new members. Pass 0 to forward none of them. + Only applicable to basic groups (the argument is ignored for supergroups or channels). + Defaults to 100 (max amount). + + Returns: + ``bool``: On success, True is returned. + """ + peer = self.resolve_peer(chat_id) + + if not isinstance(user_ids, list): + user_ids = [user_ids] + + if isinstance(peer, types.InputPeerChat): + for user_id in user_ids: + self.send( + functions.messages.AddChatUser( + chat_id=peer.chat_id, + user_id=self.resolve_peer(user_id), + fwd_limit=forward_limit + ) + ) + else: + self.send( + functions.channels.InviteToChannel( + channel=peer, + users=[ + self.resolve_peer(user_id) + for user_id in user_ids + ] + ) + ) + + return True diff --git a/pyrogram/client/methods/chats/create_channel.py b/pyrogram/client/methods/chats/create_channel.py new file mode 100644 index 00000000..c9b804f1 --- /dev/null +++ b/pyrogram/client/methods/chats/create_channel.py @@ -0,0 +1,50 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import pyrogram +from pyrogram.api import functions +from ...ext import BaseClient + + +class CreateChannel(BaseClient): + def create_channel( + self, + title: str, + description: str = "" + ) -> "pyrogram.Chat": + """Create a new broadcast channel. + + Parameters: + title (``title``): + The channel title. + + description (``str``, *optional*): + The channel description. + + Returns: + :obj:`Chat`: On success, a chat object is returned. + """ + r = self.send( + functions.channels.CreateChannel( + title=title, + about=description, + broadcast=True + ) + ) + + return pyrogram.Chat._parse_chat(self, r.chats[0]) diff --git a/pyrogram/client/methods/chats/create_group.py b/pyrogram/client/methods/chats/create_group.py new file mode 100644 index 00000000..cbf71bb3 --- /dev/null +++ b/pyrogram/client/methods/chats/create_group.py @@ -0,0 +1,60 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Union, List + +import pyrogram +from pyrogram.api import functions +from ...ext import BaseClient + + +class CreateGroup(BaseClient): + def create_group( + self, + title: str, + users: Union[Union[int, str], List[Union[int, str]]] + ) -> "pyrogram.Chat": + """Create a new basic group. + + .. note:: + + If you want to create a new supergroup, use :meth:`~pyrogram.Client.create_supergroup` instead. + + Parameters: + title (``title``): + The group title. + + users (``int`` | ``str`` | List of ``int`` or ``str``): + Users to create a chat with. + You must pass at least one user using their IDs (int), usernames (str) or phone numbers (str). + Multiple users can be invited by passing a list of IDs, usernames or phone numbers. + + Returns: + :obj:`Chat`: On success, a chat object is returned. + """ + if not isinstance(users, list): + users = [users] + + r = self.send( + functions.messages.CreateChat( + title=title, + users=[self.resolve_peer(u) for u in users] + ) + ) + + return pyrogram.Chat._parse_chat(self, r.chats[0]) diff --git a/pyrogram/client/methods/chats/create_supergroup.py b/pyrogram/client/methods/chats/create_supergroup.py new file mode 100644 index 00000000..163eae93 --- /dev/null +++ b/pyrogram/client/methods/chats/create_supergroup.py @@ -0,0 +1,54 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import pyrogram +from pyrogram.api import functions +from ...ext import BaseClient + + +class CreateSupergroup(BaseClient): + def create_supergroup( + self, + title: str, + description: str = "" + ) -> "pyrogram.Chat": + """Create a new supergroup. + + .. note:: + + If you want to create a new basic group, use :meth:`~pyrogram.Client.create_group` instead. + + Parameters: + title (``title``): + The supergroup title. + + description (``str``, *optional*): + The supergroup description. + + Returns: + :obj:`Chat`: On success, a chat object is returned. + """ + r = self.send( + functions.channels.CreateChannel( + title=title, + about=description, + megagroup=True + ) + ) + + return pyrogram.Chat._parse_chat(self, r.chats[0]) diff --git a/pyrogram/client/methods/chats/delete_channel.py b/pyrogram/client/methods/chats/delete_channel.py new file mode 100644 index 00000000..47a29b76 --- /dev/null +++ b/pyrogram/client/methods/chats/delete_channel.py @@ -0,0 +1,43 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + + +from typing import Union + +from pyrogram.api import functions +from ...ext import BaseClient + + +class DeleteChannel(BaseClient): + def delete_channel(self, chat_id: Union[int, str]) -> bool: + """Delete a channel. + + Parameters: + chat_id (``int`` | ``str``): + The id of the channel to be deleted. + + Returns: + ``bool``: On success, True is returned. + """ + self.send( + functions.channels.DeleteChannel( + channel=self.resolve_peer(chat_id) + ) + ) + + return True diff --git a/pyrogram/client/methods/chats/delete_supergroup.py b/pyrogram/client/methods/chats/delete_supergroup.py new file mode 100644 index 00000000..f4ec5e2f --- /dev/null +++ b/pyrogram/client/methods/chats/delete_supergroup.py @@ -0,0 +1,43 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + + +from typing import Union + +from pyrogram.api import functions +from ...ext import BaseClient + + +class DeleteSupergroup(BaseClient): + def delete_supergroup(self, chat_id: Union[int, str]) -> bool: + """Delete a supergroup. + + Parameters: + chat_id (``int`` | ``str``): + The id of the supergroup to be deleted. + + Returns: + ``bool``: On success, True is returned. + """ + self.send( + functions.channels.DeleteChannel( + channel=self.resolve_peer(chat_id) + ) + ) + + return True From 090675434e640cfa96dcd36c50a42646448e5473 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 21 Jul 2019 23:09:02 +0200 Subject: [PATCH 16/55] Add new RPCErrors --- compiler/error/source/400_BAD_REQUEST.tsv | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/error/source/400_BAD_REQUEST.tsv b/compiler/error/source/400_BAD_REQUEST.tsv index d7942e4b..d9a85cf0 100644 --- a/compiler/error/source/400_BAD_REQUEST.tsv +++ b/compiler/error/source/400_BAD_REQUEST.tsv @@ -113,4 +113,13 @@ FILE_PART_TOO_BIG The size limit (512 KB) for the content of the file part has b FILE_PART_EMPTY The file part sent is empty FILE_PART_SIZE_INVALID 512 KB cannot be evenly divided by part_size FILE_PART_SIZE_CHANGED The part size is different from the size of one of the previous parts in the same file -FILE_MIGRATE_X The file is in Data Center No. {x} \ No newline at end of file +FILE_MIGRATE_X The file is in Data Center No. {x} +RESULT_TYPE_INVALID The result type is invalid +PHOTO_THUMB_URL_EMPTY The photo thumb URL is empty +PHOTO_THUMB_URL_INVALID The photo thumb URL is invalid +PHOTO_CONTENT_URL_EMPTY The photo content URL is empty +PHOTO_CONTENT_TYPE_INVALID The photo content type is invalid +WEBDOCUMENT_INVALID The web document is invalid +WEBDOCUMENT_URL_EMPTY The web document URL is empty +WEBDOCUMENT_URL_INVALID The web document URL is invalid +WEBDOCUMENT_MIME_INVALID The web document mime type is invalid \ No newline at end of file From c0e9b98cab1883d5aff7e637672b0d4675f875e8 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 21 Jul 2019 23:10:23 +0200 Subject: [PATCH 17/55] Add is_gallery parameter to answer_inline_query and InlineQuery.answer --- .../client/methods/bots/answer_inline_query.py | 16 +++++++++++----- .../client/types/inline_mode/inline_query.py | 10 ++++++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/pyrogram/client/methods/bots/answer_inline_query.py b/pyrogram/client/methods/bots/answer_inline_query.py index 38ed99c3..c2777256 100644 --- a/pyrogram/client/methods/bots/answer_inline_query.py +++ b/pyrogram/client/methods/bots/answer_inline_query.py @@ -29,28 +29,34 @@ class AnswerInlineQuery(BaseClient): inline_query_id: str, results: List[InlineQueryResult], cache_time: int = 300, - is_personal: bool = None, + is_gallery: bool = False, + is_personal: bool = False, next_offset: str = "", switch_pm_text: str = "", switch_pm_parameter: str = "" ): """Send answers to an inline query. - No more than 50 results per query are allowed. + + A maximum of 50 results per query is allowed. Parameters: inline_query_id (``str``): Unique identifier for the answered query. - results (List of :obj:`InlineQueryResult `): + results (List of :obj:`InlineQueryResult`): A list of results for the inline query. cache_time (``int``, *optional*): The maximum amount of time in seconds that the result of the inline query may be cached on the server. Defaults to 300. + is_gallery (``bool``, *optional*): + Pass True, if results should be displayed in gallery mode instead of list mode. + Defaults to False. + is_personal (``bool``, *optional*): Pass True, if results may be cached on the server side only for the user that sent the query. - By default, results may be returned to any user who sends the same query. + By default (False), results may be returned to any user who sends the same query. next_offset (``str``, *optional*): Pass the offset that a client should send in the next query with the same text to receive more results. @@ -83,7 +89,7 @@ class AnswerInlineQuery(BaseClient): query_id=int(inline_query_id), results=[r.write() for r in results], cache_time=cache_time, - gallery=None, + gallery=is_gallery or None, private=is_personal or None, next_offset=next_offset or None, switch_pm=types.InlineBotSwitchPM( diff --git a/pyrogram/client/types/inline_mode/inline_query.py b/pyrogram/client/types/inline_mode/inline_query.py index 6bfc58c3..065c4492 100644 --- a/pyrogram/client/types/inline_mode/inline_query.py +++ b/pyrogram/client/types/inline_mode/inline_query.py @@ -87,7 +87,8 @@ class InlineQuery(Object, Update): self, results: List[InlineQueryResult], cache_time: int = 300, - is_personal: bool = None, + is_gallery: bool = False, + is_personal: bool = False, next_offset: str = "", switch_pm_text: str = "", switch_pm_parameter: str = "" @@ -116,9 +117,13 @@ class InlineQuery(Object, Update): The maximum amount of time in seconds that the result of the inline query may be cached on the server. Defaults to 300. + is_gallery (``bool``, *optional*): + Pass True, if results should be displayed in gallery mode instead of list mode. + Defaults to False. + is_personal (``bool``, *optional*): Pass True, if results may be cached on the server side only for the user that sent the query. - By default, results may be returned to any user who sends the same query. + By default (False), results may be returned to any user who sends the same query. next_offset (``str``, *optional*): Pass the offset that a client should send in the next query with the same text to receive more results. @@ -145,6 +150,7 @@ class InlineQuery(Object, Update): inline_query_id=self.id, results=results, cache_time=cache_time, + is_gallery=is_gallery, is_personal=is_personal, next_offset=next_offset, switch_pm_text=switch_pm_text, From 4274ef9639e0bdea57ae5919723ea90029ff0f77 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 21 Jul 2019 23:10:57 +0200 Subject: [PATCH 18/55] Add abstract method InputMessageContent.write --- .../types/input_message_content/input_message_content.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyrogram/client/types/input_message_content/input_message_content.py b/pyrogram/client/types/input_message_content/input_message_content.py index fe11ef7a..b02c6b38 100644 --- a/pyrogram/client/types/input_message_content/input_message_content.py +++ b/pyrogram/client/types/input_message_content/input_message_content.py @@ -35,3 +35,6 @@ class InputMessageContent(Object): def __init__(self): super().__init__() + + def write(self, reply_markup): + raise NotImplementedError From f0c1cb00cab978f57eaeb901db5654502457c16f Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 21 Jul 2019 23:18:38 +0200 Subject: [PATCH 19/55] Rework InlineQueryResultArticle. Also add *Photo and *Animation types --- compiler/docs/compiler.py | 2 + pyrogram/client/types/inline_mode/__init__.py | 5 +- .../types/inline_mode/inline_query_result.py | 20 ++- .../inline_query_result_animation.py | 132 ++++++++++++++++++ .../inline_query_result_article.py | 53 +++---- .../inline_mode/inline_query_result_photo.py | 132 ++++++++++++++++++ 6 files changed, 303 insertions(+), 41 deletions(-) create mode 100644 pyrogram/client/types/inline_mode/inline_query_result_animation.py create mode 100644 pyrogram/client/types/inline_mode/inline_query_result_photo.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 98c3c591..cb3ad5a2 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -341,6 +341,8 @@ def pyrogram_api(): InlineQuery InlineQueryResult InlineQueryResultArticle + InlineQueryResultPhoto + InlineQueryResultAnimation """, input_message_content=""" InputMessageContent diff --git a/pyrogram/client/types/inline_mode/__init__.py b/pyrogram/client/types/inline_mode/__init__.py index 7a3b3023..4768ecae 100644 --- a/pyrogram/client/types/inline_mode/__init__.py +++ b/pyrogram/client/types/inline_mode/__init__.py @@ -18,8 +18,11 @@ from .inline_query import InlineQuery from .inline_query_result import InlineQueryResult +from .inline_query_result_animation import InlineQueryResultAnimation from .inline_query_result_article import InlineQueryResultArticle +from .inline_query_result_photo import InlineQueryResultPhoto __all__ = [ - "InlineQuery", "InlineQueryResult", "InlineQueryResultArticle" + "InlineQuery", "InlineQueryResult", "InlineQueryResultArticle", "InlineQueryResultPhoto", + "InlineQueryResultAnimation" ] diff --git a/pyrogram/client/types/inline_mode/inline_query_result.py b/pyrogram/client/types/inline_mode/inline_query_result.py index 3fc70885..1ff3e5e1 100644 --- a/pyrogram/client/types/inline_mode/inline_query_result.py +++ b/pyrogram/client/types/inline_mode/inline_query_result.py @@ -16,6 +16,10 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from uuid import uuid4 + +from ..bots_and_keyboards import InlineKeyboardMarkup +from ..input_message_content import InputMessageContent from ..object import Object """- :obj:`InlineQueryResultCachedAudio` @@ -45,15 +49,25 @@ class InlineQueryResult(Object): Pyrogram currently supports results of the following types: - :obj:`InlineQueryResultArticle` + - :obj:`InlineQueryResultPhoto` + - :obj:`InlineQueryResultAnimation` """ - __slots__ = ["type", "id"] + __slots__ = ["type", "id", "input_message_content", "reply_markup"] - def __init__(self, type: str, id: str): + def __init__( + self, + type: str, + id: str, + input_message_content: InputMessageContent, + reply_markup: InlineKeyboardMarkup + ): super().__init__() self.type = type - self.id = id + self.id = str(uuid4()) if id is None else id + self.input_message_content = input_message_content + self.reply_markup = reply_markup def write(self): pass diff --git a/pyrogram/client/types/inline_mode/inline_query_result_animation.py b/pyrogram/client/types/inline_mode/inline_query_result_animation.py new file mode 100644 index 00000000..4d2d5596 --- /dev/null +++ b/pyrogram/client/types/inline_mode/inline_query_result_animation.py @@ -0,0 +1,132 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2018 Dan Tès +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Union + +from pyrogram.api import types +from .inline_query_result import InlineQueryResult +from ..bots_and_keyboards import InlineKeyboardMarkup +from ..input_message_content import InputMessageContent +from ...parser import Parser + + +class InlineQueryResultAnimation(InlineQueryResult): + """Link to an animated GIF file. + + By default, this animated GIF file will be sent by the user with optional caption. + Alternatively, you can use *input_message_content* to send a message with the specified content instead of the + animation. + + Parameters: + animation_url (``str``): + A valid URL for the animated GIF file. + File size must not exceed 1 MB. + + thumb_url (``str``, *optional*): + URL of the static thumbnail for the result (jpeg or gif) + Defaults to the value passed in *animation_url*. + + id (``str``, *optional*): + Unique identifier for this result, 1-64 bytes. + Defaults to a randomly generated UUID4. + + title (``str``, *optional*): + Title for the result. + + description (``str``, *optional*): + Short description of the result. + + caption (``str``, *optional*): + Caption of the photo to be sent, 0-1024 characters. + + parse_mode (``str``, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + Pass "markdown" or "md" to enable Markdown-style parsing only. + Pass "html" to enable HTML-style parsing only. + Pass None to completely disable style parsing. + + reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + An InlineKeyboardMarkup object. + + input_message_content (:obj:`InputMessageContent`): + Content of the message to be sent instead of the photo. + """ + + __slots__ = [ + "animation_url", "thumb_url", "title", "description", "caption", "parse_mode", "reply_markup", + "input_message_content" + ] + + def __init__( + self, + animation_url: str, + thumb_url: str = None, + id: str = None, + title: str = None, + description: str = None, + caption: str = None, + parse_mode: Union[str, None] = object, + reply_markup: InlineKeyboardMarkup = None, + input_message_content: InputMessageContent = None + ): + super().__init__("gif", id, input_message_content, reply_markup) + + self.animation_url = animation_url + self.thumb_url = thumb_url + self.title = title + self.description = description + self.caption = caption + self.parse_mode = parse_mode + self.reply_markup = reply_markup + self.input_message_content = input_message_content + + def write(self): + animation = types.InputWebDocument( + url=self.animation_url, + size=0, + mime_type="image/gif", + attributes=[] + ) + + if self.thumb_url is None: + thumb = animation + else: + thumb = types.InputWebDocument( + url=self.thumb_url, + size=0, + mime_type="image/gif", + attributes=[] + ) + + return types.InputBotInlineResult( + id=self.id, + type=self.type, + title=self.title, + description=self.description, + thumb=thumb, + content=animation, + send_message=( + self.input_message_content.write(self.reply_markup) + if self.input_message_content + else types.InputBotInlineMessageMediaAuto( + reply_markup=self.reply_markup.write() if self.reply_markup else None, + **(Parser(None)).parse(self.caption, self.parse_mode) + ) + ) + ) diff --git a/pyrogram/client/types/inline_mode/inline_query_result_article.py b/pyrogram/client/types/inline_mode/inline_query_result_article.py index ad0be9e4..c21416f5 100644 --- a/pyrogram/client/types/inline_mode/inline_query_result_article.py +++ b/pyrogram/client/types/inline_mode/inline_query_result_article.py @@ -16,29 +16,25 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from typing import Any - from pyrogram.api import types from .inline_query_result import InlineQueryResult +from ..bots_and_keyboards import InlineKeyboardMarkup +from ..input_message_content import InputMessageContent class InlineQueryResultArticle(InlineQueryResult): """Link to an article or web page. - TODO: Hide url? - Parameters: - id (``str``): - Unique identifier for this result, 1-64 bytes. - title (``str``): Title for the result. input_message_content (:obj:`InputMessageContent`): Content of the message to be sent. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): - Inline keyboard attached to the message. + id (``str``, *optional*): + Unique identifier for this result, 1-64 bytes. + Defaults to a randomly generated UUID4. url (``str``, *optional*): URL of the result. @@ -47,46 +43,34 @@ class InlineQueryResultArticle(InlineQueryResult): Short description of the result. thumb_url (``str``, *optional*): - Url of the thumbnail for the result. + URL of the thumbnail for the result. - thumb_width (``int``, *optional*): - Thumbnail width. - - thumb_height (``int``, *optional*): - Thumbnail height. + reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + Inline keyboard attached to the message. """ - __slots__ = [ - "title", "input_message_content", "reply_markup", "url", "description", "thumb_url", "thumb_width", - "thumb_height" - ] + __slots__ = ["title", "url", "description", "thumb_url"] def __init__( self, - id: Any, title: str, - input_message_content, - reply_markup=None, + input_message_content: InputMessageContent, + id: str = None, + reply_markup: InlineKeyboardMarkup = None, url: str = None, description: str = None, - thumb_url: str = None, - thumb_width: int = 0, - thumb_height: int = 0 + thumb_url: str = None ): - super().__init__("article", id) + super().__init__("article", id, input_message_content, reply_markup) self.title = title - self.input_message_content = input_message_content - self.reply_markup = reply_markup self.url = url self.description = description self.thumb_url = thumb_url - self.thumb_width = thumb_width - self.thumb_height = thumb_height def write(self): return types.InputBotInlineResult( - id=str(self.id), + id=self.id, type=self.type, send_message=self.input_message_content.write(self.reply_markup), title=self.title, @@ -96,11 +80,6 @@ class InlineQueryResultArticle(InlineQueryResult): url=self.thumb_url, size=0, mime_type="image/jpeg", - attributes=[ - types.DocumentAttributeImageSize( - w=self.thumb_width, - h=self.thumb_height - ) - ] + attributes=[] ) if self.thumb_url else None ) diff --git a/pyrogram/client/types/inline_mode/inline_query_result_photo.py b/pyrogram/client/types/inline_mode/inline_query_result_photo.py new file mode 100644 index 00000000..3442764e --- /dev/null +++ b/pyrogram/client/types/inline_mode/inline_query_result_photo.py @@ -0,0 +1,132 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2018 Dan Tès +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Union + +from pyrogram.api import types +from .inline_query_result import InlineQueryResult +from ..bots_and_keyboards import InlineKeyboardMarkup +from ..input_message_content import InputMessageContent +from ...parser import Parser + + +class InlineQueryResultPhoto(InlineQueryResult): + """Link to a photo. + + By default, this photo will be sent by the user with optional caption. + Alternatively, you can use *input_message_content* to send a message with the specified content instead of the + photo. + + Parameters: + photo_url (``str``): + A valid URL of the photo. + Photo must be in jpeg format an must not exceed 5 MB. + + thumb_url (``str``, *optional*): + URL of the thumbnail for the photo. + Defaults to the value passed in *photo_url*. + + id (``str``, *optional*): + Unique identifier for this result, 1-64 bytes. + Defaults to a randomly generated UUID4. + + title (``str``, *optional*): + Title for the result. + + description (``str``, *optional*): + Short description of the result. + + caption (``str``, *optional*): + Caption of the photo to be sent, 0-1024 characters. + + parse_mode (``str``, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + Pass "markdown" or "md" to enable Markdown-style parsing only. + Pass "html" to enable HTML-style parsing only. + Pass None to completely disable style parsing. + + reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + An InlineKeyboardMarkup object. + + input_message_content (:obj:`InputMessageContent`): + Content of the message to be sent instead of the photo. + """ + + __slots__ = [ + "photo_url", "thumb_url", "title", "description", "caption", "parse_mode", "reply_markup", + "input_message_content" + ] + + def __init__( + self, + photo_url: str, + thumb_url: str = None, + id: str = None, + title: str = None, + description: str = None, + caption: str = None, + parse_mode: Union[str, None] = object, + reply_markup: InlineKeyboardMarkup = None, + input_message_content: InputMessageContent = None + ): + super().__init__("photo", id, input_message_content, reply_markup) + + self.photo_url = photo_url + self.thumb_url = thumb_url + self.title = title + self.description = description + self.caption = caption + self.parse_mode = parse_mode + self.reply_markup = reply_markup + self.input_message_content = input_message_content + + def write(self): + photo = types.InputWebDocument( + url=self.photo_url, + size=0, + mime_type="image/jpeg", + attributes=[] + ) + + if self.thumb_url is None: + thumb = photo + else: + thumb = types.InputWebDocument( + url=self.thumb_url, + size=0, + mime_type="image/jpeg", + attributes=[] + ) + + return types.InputBotInlineResult( + id=self.id, + type=self.type, + title=self.title, + description=self.description, + thumb=thumb, + content=photo, + send_message=( + self.input_message_content.write(self.reply_markup) + if self.input_message_content + else types.InputBotInlineMessageMediaAuto( + reply_markup=self.reply_markup.write() if self.reply_markup else None, + **(Parser(None)).parse(self.caption, self.parse_mode) + ) + ) + ) From af1bb3b0a7d0db6b5bcc34d6387870a397b4448b Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Mon, 22 Jul 2019 13:31:03 +0200 Subject: [PATCH 20/55] Fix command filter relying on a previous command state --- pyrogram/client/filters/filters.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py index 01d6bbd4..0a7346ef 100644 --- a/pyrogram/client/filters/filters.py +++ b/pyrogram/client/filters/filters.py @@ -240,6 +240,7 @@ class Filters: def func(flt, message): text = message.text or message.caption + message.command = None if text: for p in flt.p: From 776557f60bfc08d6feb1cf69fc37a8550698bd81 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Mon, 22 Jul 2019 13:31:50 +0200 Subject: [PATCH 21/55] Refactor regex filter --- pyrogram/client/filters/filters.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py index 0a7346ef..f80127c2 100644 --- a/pyrogram/client/filters/filters.py +++ b/pyrogram/client/filters/filters.py @@ -273,11 +273,15 @@ class Filters: RegEx flags. """ - def f(_, m): - m.matches = [i for i in _.p.finditer(m.text or m.caption or "")] - return bool(m.matches) + def func(flt, message): + text = message.text or message.caption - return create(f, "RegexFilter", p=re.compile(pattern, flags)) + if text: + message.matches = list(flt.p.finditer(text)) or None + + return bool(message.matches) + + return create(func, "RegexFilter", p=re.compile(pattern, flags)) # noinspection PyPep8Naming class user(Filter, set): From 948bba7a08d4aaf14e4144d576f64ccc78069249 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Mon, 22 Jul 2019 14:16:43 +0200 Subject: [PATCH 22/55] Add missing return type --- pyrogram/client/types/messages_and_media/message.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index 8b02839f..ae0e257a 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.py @@ -2949,7 +2949,7 @@ class Message(Object, Update): Index of the poll option you want to vote for (0 to 9). Returns: - On success, the poll with the chosen option is returned. + :obj:`Poll`: On success, the poll with the chosen option is returned. Raises: RPCError: In case of a Telegram RPC error. From a320088fee36cd5f7be49bef1e9ad05bf78eaf84 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Mon, 22 Jul 2019 14:21:42 +0200 Subject: [PATCH 23/55] Fix Message.retract_vote style --- pyrogram/client/types/messages_and_media/message.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index 80597e33..a534aae1 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.py @@ -2871,8 +2871,8 @@ class Message(Object, Update): def retract_vote( - self, - ) -> "Poll": + self, + ) -> "Poll": """Bound method *retract_vote* of :obj:`Message`. Use as a shortcut for: @@ -2883,14 +2883,14 @@ class Message(Object, Update): chat_id=message.chat.id, message_id=message_id, ) + Example: .. code-block:: python message.retract_vote() Returns: - :obj:`Poll` - On success, the poll with the retracted vote is returned. + :obj:`Poll`: On success, the poll with the retracted vote is returned. Raises: RPCError: In case of a Telegram RPC error. From b2886c21ca6faced3d3e9bed1fb73946cf60e396 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 25 Jul 2019 10:48:36 +0200 Subject: [PATCH 24/55] Clarify get_messages error messages --- pyrogram/client/methods/messages/get_messages.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyrogram/client/methods/messages/get_messages.py b/pyrogram/client/methods/messages/get_messages.py index 0f901174..0e3a2ea3 100644 --- a/pyrogram/client/methods/messages/get_messages.py +++ b/pyrogram/client/methods/messages/get_messages.py @@ -66,6 +66,7 @@ class GetMessages(BaseClient): Raises: RPCError: In case of a Telegram RPC error. + ValueError: In case of invalid arguments. """ ids, ids_type = ( (message_ids, types.InputMessageID) if message_ids @@ -74,7 +75,7 @@ class GetMessages(BaseClient): ) if ids is None: - raise ValueError("No argument supplied") + raise ValueError("No argument supplied. Either pass message_ids or reply_to_message_ids") peer = self.resolve_peer(chat_id) From 0302a27b7e0dde1bf4b02ecf7839a1f03cbc558f Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 25 Jul 2019 11:15:14 +0200 Subject: [PATCH 25/55] Update FAQs --- docs/source/faq.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/source/faq.rst b/docs/source/faq.rst index 147eb4fa..2dde12f2 100644 --- a/docs/source/faq.rst +++ b/docs/source/faq.rst @@ -144,7 +144,8 @@ I started a client and nothing happens! --------------------------------------- If you are connecting from Russia, China or Iran :doc:`you need a proxy `, because Telegram could be -partially or totally blocked in those countries. +partially or totally blocked in those countries. More information about this block can be found at +`Wikipedia `_. Another possible cause might be network issues, either yours or Telegram's. To confirm this, add the following code on the top of your script and run it again. You should see some error mentioning a socket timeout or an unreachable network @@ -161,9 +162,9 @@ fails or not. What are the IP addresses of Telegram Data Centers? --------------------------------------------------- -The Telegram cloud is currently composed by a decentralized, multi-DC infrastructure (each of which can work -independently) spread in 5 different locations. However, some of the less busy DCs have been lately dismissed and their -IP addresses are now kept as aliases. +The Telegram cloud is currently composed by a decentralized, multi-DC infrastructure (currently 5 DCs, each of which can +work independently) spread in different locations worldwide. However, some of the less busy DCs have been lately +dismissed and their IP addresses are now kept as aliases to the nearest one. .. csv-table:: Production Environment :header: ID, Location, IPv4, IPv6 From 72b7a53ff5b6a12a74bf18859231e3c94c9279fd Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 25 Jul 2019 11:15:56 +0200 Subject: [PATCH 26/55] Log to warning only in the last attempt --- pyrogram/session/session.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index 5947fc0f..21e2ba10 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -439,9 +439,9 @@ class Session: if retries == 0: raise e from None - (log.warning if retries < 3 else log.info)( + (log.warning if retries < 2 else log.info)( "{}: {} Retrying {}".format( - Session.MAX_RETRIES - retries, + Session.MAX_RETRIES - retries + 1, datetime.now(), type(data))) time.sleep(0.5) From 8f56610c2ca0d216b88331a1d3e5551e8d5bde28 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 25 Jul 2019 11:17:28 +0200 Subject: [PATCH 27/55] Add examples to utility methods --- pyrogram/client/client.py | 206 ++++++++++++++++++++++++++++++-------- 1 file changed, 166 insertions(+), 40 deletions(-) diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index 19ff1b5e..64595a91 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.py @@ -174,6 +174,17 @@ class Client(Methods, BaseClient): download_media, ...) are less prone to throw FloodWait exceptions. Only available for users, bots will ignore this parameter. Defaults to False (normal session). + + Example: + .. code-block:: python + + from pyrogram import Client + + app = Client("my_account") + + with app: + app.send_message("me", "Hi!") + """ terms_of_service_displayed = False @@ -269,11 +280,28 @@ class Client(Methods, BaseClient): self._proxy.update(value) def start(self): - """Start the Client. + """Start the client. + + This method connects the client to Telegram and, in case of new sessions, automatically manages the full login + process using an interactive prompt (by default). + + Has no parameters. Raises: - RPCError: In case of a Telegram RPC error. - ConnectionError: In case you try to start an already started Client. + ConnectionError: In case you try to start an already started client. + + Example: + .. code-block:: python + :emphasize-lines: 4 + + from pyrogram import Client + + app = Client("my_account") + app.start() + + ... # Call API methods + + app.stop() """ if self.is_started: raise ConnectionError("Client has already been started") @@ -346,8 +374,25 @@ class Client(Methods, BaseClient): def stop(self): """Stop the Client. + This method disconnects the client from Telegram and stops the underlying tasks. + + Has no parameters. + Raises: - ConnectionError: In case you try to stop an already stopped Client. + ConnectionError: In case you try to stop an already stopped client. + + Example: + .. code-block:: python + :emphasize-lines: 8 + + from pyrogram import Client + + app = Client("my_account") + app.start() + + ... # Call API methods + + app.stop() """ if not self.is_started: raise ConnectionError("Client is already stopped") @@ -388,8 +433,30 @@ class Client(Methods, BaseClient): def restart(self): """Restart the Client. + This method will first call :meth:`~Client.stop` and then :meth:`~Client.start` in a row in order to restart + a client using a single method. + + Has no parameters. + Raises: ConnectionError: In case you try to restart a stopped Client. + + Example: + .. code-block:: python + :emphasize-lines: 8 + + from pyrogram import Client + + app = Client("my_account") + app.start() + + ... # Call API methods + + app.restart() + + ... # Call other API methods + + app.stop() """ self.stop() self.start() @@ -451,25 +518,40 @@ class Client(Methods, BaseClient): time.sleep(1) def run(self): - """Start the Client and automatically idle the main script. + """Start the client, idle the main script and finally stop the client. - This is a convenience method that literally just calls :meth:`~Client.start` and :meth:`~Client.idle`. It makes - running a client less verbose, but is not suitable in case you want to run more than one client in a single main - script, since :meth:`~Client.idle` will block. + This is a convenience method that calls :meth:`~Client.start`, :meth:`~Client.idle` and :meth:`~Client.stop` in + sequence. It makes running a client less verbose, but is not suitable in case you want to run more than one + client in a single main script, since idle() will block after starting the own client. + + Has no parameters. Raises: - RPCError: In case of a Telegram RPC error. + ConnectionError: In case you try to run an already started client. + + Example: + .. code-block:: python + :emphasize-lines: 7 + + from pyrogram import Client + + app = Client("my_account") + + ... # Set handlers up + + app.run() """ self.start() - self.idle() + Client.idle() self.stop() def add_handler(self, handler: Handler, group: int = 0): """Register an update handler. - You can register multiple handlers, but at most one handler within a group - will be used for a single update. To handle the same update more than once, register - your handler using a different group id (lower group id == higher priority). + You can register multiple handlers, but at most one handler within a group will be used for a single update. + To handle the same update more than once, register your handler using a different group id (lower group id + == higher priority). This mechanism is explained in greater details at + :doc:`More on Updates <../../topics/more-on-updates>`. Parameters: handler (``Handler``): @@ -479,7 +561,22 @@ class Client(Methods, BaseClient): The group identifier, defaults to 0. Returns: - ``tuple``: A tuple consisting of (handler, group). + ``tuple``: A tuple consisting of *(handler, group)*. + + Example: + .. code-block:: python + :emphasize-lines: 8 + + from pyrogram import Client, MessageHandler + + def dump(client, message): + print(message) + + app = Client("my_account") + + app.add_handler(MessageHandler(dump)) + + app.run() """ if isinstance(handler, DisconnectHandler): self.disconnect_handler = handler.callback @@ -491,9 +588,8 @@ class Client(Methods, BaseClient): def remove_handler(self, handler: Handler, group: int = 0): """Remove a previously-registered update handler. - Make sure to provide the right group that the handler was added in. You can use - the return value of the :meth:`~Client.add_handler` method, a tuple of (handler, group), and - pass it directly. + Make sure to provide the right group where the handler was added in. You can use the return value of the + :meth:`~Client.add_handler` method, a tuple of *(handler, group)*, and pass it directly. Parameters: handler (``Handler``): @@ -501,6 +597,24 @@ class Client(Methods, BaseClient): group (``int``, *optional*): The group identifier, defaults to 0. + + Example: + .. code-block:: python + :emphasize-lines: 11 + + from pyrogram import Client, MessageHandler + + def dump(client, message): + print(message) + + app = Client("my_account") + + handler = app.add_handler(MessageHandler(dump)) + + # Starred expression to unpack (handler, group) + app.remove_handler(*handler) + + app.run() """ if isinstance(handler, DisconnectHandler): self.disconnect_handler = None @@ -509,7 +623,28 @@ class Client(Methods, BaseClient): def stop_transmission(self): """Stop downloading or uploading a file. - Must be called inside a progress callback function. + + This method must be called inside a progress callback function in order to stop the transmission at the + desired time. The progress callback is called every time a file chunk is uploaded/downloaded. + + Has no parameters. + + Example: + .. code-block:: python + :emphasize-lines: 9 + + from pyrogram import Client + + app = Client("my_account") + + # Example to stop transmission once the upload progress reaches 50% + # Useless in practice, but shows how to stop on command + def progress(client, current, total): + if (current * 100 / total) > 50: + client.stop_transmission() + + with app: + app.send_document("me", "files.zip", progress=progress) """ raise Client.StopTransmission @@ -541,9 +676,9 @@ class Client(Methods, BaseClient): def set_parse_mode(self, parse_mode: Union[str, None] = "combined"): """Set the parse mode to be used globally by the client. - When setting the parse mode with this method, all methods having a *parse_mode* parameter will follow the global - value by default. The default value *"combined"* enables both Markdown and HTML styles to be used and combined - together. + When setting the parse mode with this method, all other methods having a *parse_mode* parameter will follow the + global value by default. The default value *"combined"* enables both Markdown and HTML styles to be used and + combined together. Parameters: parse_mode (``str``): @@ -1172,7 +1307,7 @@ class Client(Methods, BaseClient): ]) if session_empty: - self.storage.dc_id = 1 + self.storage.dc_id = 4 self.storage.date = 0 self.storage.test_mode = self.test_mode @@ -1445,23 +1580,22 @@ class Client(Methods, BaseClient): In case a file part expired, pass the file_id and the file_part to retry uploading that specific chunk. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -1775,11 +1909,3 @@ class Client(Methods, BaseClient): if extensions: return extensions.split(" ")[0] - - def export_session_string(self): - """Export the current session as serialized string. - - Returns: - ``str``: The session serialized into a printable, url-safe string. - """ - return self.storage.export_session_string() From fe2ccc6036e020087cc68734042dd9c7644b8af1 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 25 Jul 2019 11:18:11 +0200 Subject: [PATCH 28/55] Clean up Message docstrings --- .../types/messages_and_media/message.py | 182 +++++++++--------- 1 file changed, 92 insertions(+), 90 deletions(-) diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index 2f1d5928..88b05e43 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.py @@ -817,23 +817,22 @@ class Message(Object, Update): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -954,23 +953,22 @@ class Message(Object, Update): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -1286,23 +1284,22 @@ class Message(Object, Update): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -1681,23 +1678,22 @@ class Message(Object, Update): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -1859,23 +1855,22 @@ class Message(Object, Update): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -2092,23 +2087,22 @@ class Message(Object, Update): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -2214,23 +2208,22 @@ class Message(Object, Update): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -2333,23 +2326,22 @@ class Message(Object, Update): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -2619,9 +2611,6 @@ class Message(Object, Update): if self.game and not self._client.is_bot: raise ValueError("Users cannot send messages with Game media type") - # TODO: Improve markdown parser. Currently html appears to be more stable, thus we use it here because users - # can"t choose. - if self.text: return self._client.send_message( chat_id, @@ -2900,14 +2889,27 @@ class Message(Object, Update): Blocks the code execution until the file has been downloaded. Defaults to True. - progress (``callable``): - Pass a callback function to view the download progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + progress (``callable``, *optional*): + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. - progress_args (``tuple``): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + progress_args (``tuple``, *optional*): + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. + + Other Parameters: + current (``int``): + The amount of bytes transmitted so far. + + total (``int``): + The total size of the file. + + *args (``tuple``, *optional*): + Extra custom arguments as defined in the *progress_args* parameter. + You can either keep *\*args* or add every single extra argument in your function signature. Returns: On success, the absolute path of the downloaded file as string is returned, None otherwise. From 2dec2442e5506ed96400b75b5ba9446022ff180f Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 25 Jul 2019 11:22:14 +0200 Subject: [PATCH 29/55] Add examples to all available methods --- .../methods/bots/answer_callback_query.py | 10 ++++- .../methods/bots/answer_inline_query.py | 13 +++++- .../methods/bots/get_game_high_scores.py | 7 +++- .../methods/bots/get_inline_bot_results.py | 12 ++++-- .../methods/bots/request_callback_answer.py | 6 ++- pyrogram/client/methods/bots/send_game.py | 6 ++- .../methods/bots/send_inline_bot_result.py | 6 ++- .../client/methods/bots/set_game_score.py | 10 ++++- .../client/methods/chats/add_chat_members.py | 12 ++++++ .../client/methods/chats/archive_chats.py | 10 ++++- .../client/methods/chats/create_channel.py | 5 +++ pyrogram/client/methods/chats/create_group.py | 5 +++ .../client/methods/chats/create_supergroup.py | 5 +++ .../client/methods/chats/delete_channel.py | 5 +++ .../client/methods/chats/delete_chat_photo.py | 14 +++---- .../client/methods/chats/delete_supergroup.py | 5 +++ .../methods/chats/export_chat_invite_link.py | 7 +++- pyrogram/client/methods/chats/get_chat.py | 7 +++- .../client/methods/chats/get_chat_member.py | 7 +++- .../client/methods/chats/get_chat_members.py | 13 +++++- .../methods/chats/get_chat_members_count.py | 7 +++- pyrogram/client/methods/chats/get_dialogs.py | 10 ++++- .../client/methods/chats/get_dialogs_count.py | 7 +++- .../client/methods/chats/iter_chat_members.py | 16 +++++++- pyrogram/client/methods/chats/iter_dialogs.py | 8 +++- pyrogram/client/methods/chats/join_chat.py | 10 ++++- .../client/methods/chats/kick_chat_member.py | 12 +++++- pyrogram/client/methods/chats/leave_chat.py | 11 ++++- .../client/methods/chats/pin_chat_message.py | 10 ++++- .../methods/chats/promote_chat_member.py | 7 +++- .../client/methods/chats/restrict_chat.py | 10 ++++- .../methods/chats/restrict_chat_member.py | 15 ++++++- .../methods/chats/set_chat_description.py | 8 +++- .../client/methods/chats/set_chat_photo.py | 28 +++++++------ .../client/methods/chats/set_chat_title.py | 6 ++- .../client/methods/chats/unarchive_chats.py | 10 ++++- .../client/methods/chats/unban_chat_member.py | 7 +++- .../methods/chats/unpin_chat_message.py | 6 ++- .../methods/chats/update_chat_username.py | 6 ++- .../client/methods/contacts/add_contacts.py | 11 ++++- .../methods/contacts/delete_contacts.py | 6 ++- .../client/methods/contacts/get_contacts.py | 8 ++-- .../methods/contacts/get_contacts_count.py | 7 +++- .../methods/messages/delete_messages.py | 13 +++++- .../client/methods/messages/download_media.py | 33 +++++++++------ .../methods/messages/edit_inline_caption.py | 9 ++-- .../methods/messages/edit_inline_media.py | 19 +++++++-- .../messages/edit_inline_reply_markup.py | 14 +++++-- .../methods/messages/edit_inline_text.py | 16 ++++++-- .../methods/messages/edit_message_caption.py | 6 ++- .../methods/messages/edit_message_media.py | 15 ++++++- .../messages/edit_message_reply_markup.py | 12 +++++- .../methods/messages/edit_message_text.py | 12 +++++- .../methods/messages/forward_messages.py | 17 ++++++-- .../client/methods/messages/get_history.py | 13 +++++- .../methods/messages/get_history_count.py | 6 ++- .../client/methods/messages/get_messages.py | 19 ++++++++- .../client/methods/messages/iter_history.py | 7 +++- .../client/methods/messages/read_history.py | 10 ++++- .../client/methods/messages/retract_vote.py | 6 ++- .../methods/messages/send_animated_sticker.py | 27 ++++++------ .../client/methods/messages/send_animation.py | 40 ++++++++++++------ .../client/methods/messages/send_audio.py | 41 +++++++++++++------ .../methods/messages/send_cached_media.py | 6 ++- .../methods/messages/send_chat_action.py | 18 +++++++- .../client/methods/messages/send_contact.py | 6 ++- .../client/methods/messages/send_document.py | 35 ++++++++++------ .../client/methods/messages/send_location.py | 6 ++- .../methods/messages/send_media_group.py | 15 ++++++- .../client/methods/messages/send_message.py | 39 +++++++++++++++++- .../client/methods/messages/send_photo.py | 35 ++++++++++------ pyrogram/client/methods/messages/send_poll.py | 6 ++- .../client/methods/messages/send_sticker.py | 30 ++++++++------ .../client/methods/messages/send_venue.py | 8 +++- .../client/methods/messages/send_video.py | 35 ++++++++++------ .../methods/messages/send_video_note.py | 29 +++++++------ .../client/methods/messages/send_voice.py | 32 +++++++++------ pyrogram/client/methods/messages/stop_poll.py | 6 ++- pyrogram/client/methods/messages/vote_poll.py | 6 ++- .../methods/password/change_cloud_password.py | 10 ++++- .../methods/password/enable_cloud_password.py | 13 +++++- .../methods/password/remove_cloud_password.py | 6 ++- pyrogram/client/methods/users/block_user.py | 12 +++++- .../methods/users/delete_profile_photos.py | 13 +++++- pyrogram/client/methods/users/get_me.py | 9 ++-- .../methods/users/get_profile_photos.py | 13 +++++- .../methods/users/get_profile_photos_count.py | 7 +++- pyrogram/client/methods/users/get_users.py | 11 +++-- .../methods/users/iter_profile_photos.py | 7 +++- .../client/methods/users/set_profile_photo.py | 6 ++- pyrogram/client/methods/users/unblock_user.py | 12 +++++- .../client/methods/users/update_username.py | 6 ++- 92 files changed, 876 insertions(+), 287 deletions(-) diff --git a/pyrogram/client/methods/bots/answer_callback_query.py b/pyrogram/client/methods/bots/answer_callback_query.py index 010c29ea..dec3bef0 100644 --- a/pyrogram/client/methods/bots/answer_callback_query.py +++ b/pyrogram/client/methods/bots/answer_callback_query.py @@ -56,8 +56,14 @@ class AnswerCallbackQuery(BaseClient): Returns: ``bool``: True, on success. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Answer without alert + app.answer_callback_query(query_id, text=text) + + # Answer with alert + app.answer_callback_query(query_id, text=text, show_alert=True) """ return self.send( functions.messages.SetBotCallbackAnswer( diff --git a/pyrogram/client/methods/bots/answer_inline_query.py b/pyrogram/client/methods/bots/answer_inline_query.py index c2777256..da801c62 100644 --- a/pyrogram/client/methods/bots/answer_inline_query.py +++ b/pyrogram/client/methods/bots/answer_inline_query.py @@ -81,8 +81,17 @@ class AnswerInlineQuery(BaseClient): Returns: ``bool``: True, on success. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + from pyrogram import InlineQueryResultArticle, InputTextMessageContent + + app.answer_inline_query( + inline_query_id, + results=[ + InlineQueryResultArticle( + "Title", + InputTextMessageContent("Message content"))]) """ return self.send( functions.messages.SetInlineBotResults( diff --git a/pyrogram/client/methods/bots/get_game_high_scores.py b/pyrogram/client/methods/bots/get_game_high_scores.py index e6459bac..595e4e1a 100644 --- a/pyrogram/client/methods/bots/get_game_high_scores.py +++ b/pyrogram/client/methods/bots/get_game_high_scores.py @@ -51,8 +51,11 @@ class GetGameHighScores(BaseClient): Returns: List of :obj:`GameHighScore`: On success. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + scores = app.get_game_high_scores(user_id, chat_id, message_id) + print(scores) """ # TODO: inline_message_id diff --git a/pyrogram/client/methods/bots/get_inline_bot_results.py b/pyrogram/client/methods/bots/get_inline_bot_results.py index cc0fc1b1..99f05c95 100644 --- a/pyrogram/client/methods/bots/get_inline_bot_results.py +++ b/pyrogram/client/methods/bots/get_inline_bot_results.py @@ -27,7 +27,7 @@ class GetInlineBotResults(BaseClient): def get_inline_bot_results( self, bot: Union[int, str], - query: str, + query: str = "", offset: str = "", latitude: float = None, longitude: float = None @@ -40,8 +40,9 @@ class GetInlineBotResults(BaseClient): Unique identifier of the inline bot you want to get results from. You can specify a @username (str) or a bot ID (int). - query (``str``): + query (``str``, *optional*): Text of the query (up to 512 characters). + Defaults to "" (empty string). offset (``str``, *optional*): Offset of the results to be returned. @@ -58,8 +59,13 @@ class GetInlineBotResults(BaseClient): :obj:`BotResults `: On Success. Raises: - RPCError: In case of a Telegram RPC error. TimeoutError: In case the bot fails to answer within 10 seconds. + + Example: + .. code-block:: python + + results = app.get_inline_bot_results("pyrogrambot") + print(results) """ # TODO: Don't return the raw type diff --git a/pyrogram/client/methods/bots/request_callback_answer.py b/pyrogram/client/methods/bots/request_callback_answer.py index 97d8d42b..01879bbb 100644 --- a/pyrogram/client/methods/bots/request_callback_answer.py +++ b/pyrogram/client/methods/bots/request_callback_answer.py @@ -53,8 +53,12 @@ class RequestCallbackAnswer(BaseClient): or as an alert. Raises: - RPCError: In case of a Telegram RPC error. TimeoutError: In case the bot fails to answer within 10 seconds. + + Example: + .. code-block:: python + + app.request_callback_answer(chat_id, message_id, "callback_data") """ # Telegram only wants bytes, but we are allowed to pass strings too. diff --git a/pyrogram/client/methods/bots/send_game.py b/pyrogram/client/methods/bots/send_game.py index c10d328a..1a6a772a 100644 --- a/pyrogram/client/methods/bots/send_game.py +++ b/pyrogram/client/methods/bots/send_game.py @@ -62,8 +62,10 @@ class SendGame(BaseClient): Returns: :obj:`Message`: On success, the sent game message is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + app.send_game(chat_id, "gamename") """ r = self.send( functions.messages.SendMedia( diff --git a/pyrogram/client/methods/bots/send_inline_bot_result.py b/pyrogram/client/methods/bots/send_inline_bot_result.py index 411ab462..059185db 100644 --- a/pyrogram/client/methods/bots/send_inline_bot_result.py +++ b/pyrogram/client/methods/bots/send_inline_bot_result.py @@ -60,8 +60,10 @@ class SendInlineBotResult(BaseClient): Returns: :obj:`Message`: On success, the sent inline result message is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + app.send_inline_bot_result(chat_id, query_id, result_id) """ return self.send( functions.messages.SendInlineBotResult( diff --git a/pyrogram/client/methods/bots/set_game_score.py b/pyrogram/client/methods/bots/set_game_score.py index f9115b74..ba2e74fa 100644 --- a/pyrogram/client/methods/bots/set_game_score.py +++ b/pyrogram/client/methods/bots/set_game_score.py @@ -66,8 +66,14 @@ class SetGameScore(BaseClient): :obj:`Message` | ``bool``: On success, if the message was sent by the bot, the edited message is returned, True otherwise. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Set new score + app.set_game_score(user_id, 1000) + + # Force set new score + app.set_game_score(user_id, 25, force=True) """ r = self.send( functions.messages.SetGameScore( diff --git a/pyrogram/client/methods/chats/add_chat_members.py b/pyrogram/client/methods/chats/add_chat_members.py index ce5b0cce..8dbad1a3 100644 --- a/pyrogram/client/methods/chats/add_chat_members.py +++ b/pyrogram/client/methods/chats/add_chat_members.py @@ -47,6 +47,18 @@ class AddChatMembers(BaseClient): Returns: ``bool``: On success, True is returned. + + Example: + .. code-block:: python + + # Add one member to a group or channel + app.add_chat_members(chat_id, user_id) + + # Add multiple members to a group or channel + app.add_chat_members(chat_id, [user_id1, user_id2, user_id3]) + + # Change forward_limit (for basic groups only) + app.add_chat_members(chat_id, user_id, forward_limit=25) """ peer = self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/chats/archive_chats.py b/pyrogram/client/methods/chats/archive_chats.py index 3c929983..14375a92 100644 --- a/pyrogram/client/methods/chats/archive_chats.py +++ b/pyrogram/client/methods/chats/archive_chats.py @@ -37,8 +37,14 @@ class ArchiveChats(BaseClient): Returns: ``bool``: On success, True is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Archive chat + app.archive_chats(chat_id) + + # Archive multiple chats at once + app.archive_chats([chat_id1, chat_id2, chat_id3]) """ if not isinstance(chat_ids, list): diff --git a/pyrogram/client/methods/chats/create_channel.py b/pyrogram/client/methods/chats/create_channel.py index c9b804f1..9520ceef 100644 --- a/pyrogram/client/methods/chats/create_channel.py +++ b/pyrogram/client/methods/chats/create_channel.py @@ -38,6 +38,11 @@ class CreateChannel(BaseClient): Returns: :obj:`Chat`: On success, a chat object is returned. + + Example: + .. code-block:: python + + app.create_channel("Channel Title", "Channel Description") """ r = self.send( functions.channels.CreateChannel( diff --git a/pyrogram/client/methods/chats/create_group.py b/pyrogram/client/methods/chats/create_group.py index cbf71bb3..4e1d63bd 100644 --- a/pyrogram/client/methods/chats/create_group.py +++ b/pyrogram/client/methods/chats/create_group.py @@ -46,6 +46,11 @@ class CreateGroup(BaseClient): Returns: :obj:`Chat`: On success, a chat object is returned. + + Example: + .. code-block:: python + + app.create_group("Group Title", user_id) """ if not isinstance(users, list): users = [users] diff --git a/pyrogram/client/methods/chats/create_supergroup.py b/pyrogram/client/methods/chats/create_supergroup.py index 163eae93..0ad14d06 100644 --- a/pyrogram/client/methods/chats/create_supergroup.py +++ b/pyrogram/client/methods/chats/create_supergroup.py @@ -42,6 +42,11 @@ class CreateSupergroup(BaseClient): Returns: :obj:`Chat`: On success, a chat object is returned. + + Example: + .. code-block:: python + + app.create_supergroup("Supergroup Title", "Supergroup Description") """ r = self.send( functions.channels.CreateChannel( diff --git a/pyrogram/client/methods/chats/delete_channel.py b/pyrogram/client/methods/chats/delete_channel.py index 47a29b76..74fbea13 100644 --- a/pyrogram/client/methods/chats/delete_channel.py +++ b/pyrogram/client/methods/chats/delete_channel.py @@ -33,6 +33,11 @@ class DeleteChannel(BaseClient): Returns: ``bool``: On success, True is returned. + + Example: + .. code-block:: python + + app.delete_channel(channel_id) """ self.send( functions.channels.DeleteChannel( diff --git a/pyrogram/client/methods/chats/delete_chat_photo.py b/pyrogram/client/methods/chats/delete_chat_photo.py index 88d97506..89f869bf 100644 --- a/pyrogram/client/methods/chats/delete_chat_photo.py +++ b/pyrogram/client/methods/chats/delete_chat_photo.py @@ -28,12 +28,8 @@ class DeleteChatPhoto(BaseClient): chat_id: Union[int, str] ) -> bool: """Delete a chat photo. - Photos can't be changed for private chats. - You must be an administrator in the chat for this to work and must have the appropriate admin rights. - Note: - In regular groups (non-supergroups), this method will only work if the "All Members Are Admins" - setting is off. + You must be an administrator in the chat for this to work and must have the appropriate admin rights. Parameters: chat_id (``int`` | ``str``): @@ -43,8 +39,12 @@ class DeleteChatPhoto(BaseClient): ``bool``: True on success. Raises: - RPCError: In case of a Telegram RPC error. - ``ValueError`` if a chat_id belongs to user. + ValueError: if a chat_id belongs to user. + + Example: + .. code-block:: python + + app.delete_chat_photo(chat_id) """ peer = self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/chats/delete_supergroup.py b/pyrogram/client/methods/chats/delete_supergroup.py index f4ec5e2f..a1eb198d 100644 --- a/pyrogram/client/methods/chats/delete_supergroup.py +++ b/pyrogram/client/methods/chats/delete_supergroup.py @@ -33,6 +33,11 @@ class DeleteSupergroup(BaseClient): Returns: ``bool``: On success, True is returned. + + Example: + .. code-block:: python + + app.delete_supergroup(supergroup_id) """ self.send( functions.channels.DeleteChannel( diff --git a/pyrogram/client/methods/chats/export_chat_invite_link.py b/pyrogram/client/methods/chats/export_chat_invite_link.py index ca75cac6..bf5d3a38 100644 --- a/pyrogram/client/methods/chats/export_chat_invite_link.py +++ b/pyrogram/client/methods/chats/export_chat_invite_link.py @@ -47,8 +47,13 @@ class ExportChatInviteLink(BaseClient): ``str``: On success, the exported invite link is returned. Raises: - RPCError: In case of a Telegram RPC error. ValueError: In case the chat_id belongs to a user. + + Example: + .. code-block:: python + + link = app.export_chat_invite_link(chat_id) + print(link) """ peer = self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/chats/get_chat.py b/pyrogram/client/methods/chats/get_chat.py index 4f71c3b3..48c5cc22 100644 --- a/pyrogram/client/methods/chats/get_chat.py +++ b/pyrogram/client/methods/chats/get_chat.py @@ -44,8 +44,13 @@ class GetChat(BaseClient): otherwise, a chat preview object is returned. Raises: - RPCError: In case of a Telegram RPC error. ValueError: In case the chat invite link points to a chat you haven't joined yet. + + Example: + .. code-block:: python + + chat = app.get_chat("pyrogram") + print(chat) """ match = self.INVITE_LINK_RE.match(str(chat_id)) diff --git a/pyrogram/client/methods/chats/get_chat_member.py b/pyrogram/client/methods/chats/get_chat_member.py index b0d0641a..20d9c624 100644 --- a/pyrogram/client/methods/chats/get_chat_member.py +++ b/pyrogram/client/methods/chats/get_chat_member.py @@ -44,8 +44,11 @@ class GetChatMember(BaseClient): Returns: :obj:`ChatMember`: On success, a chat member is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + dan = app.get_chat_member("pyrogramchat", "haskell") + print(dan) """ chat = self.resolve_peer(chat_id) user = self.resolve_peer(user_id) diff --git a/pyrogram/client/methods/chats/get_chat_members.py b/pyrogram/client/methods/chats/get_chat_members.py index 0b4613d8..19b5971e 100644 --- a/pyrogram/client/methods/chats/get_chat_members.py +++ b/pyrogram/client/methods/chats/get_chat_members.py @@ -91,8 +91,19 @@ class GetChatMembers(BaseClient): List of :obj:`ChatMember`: On success, a list of chat members is returned. Raises: - RPCError: In case of a Telegram RPC error. ValueError: In case you used an invalid filter or a chat id that belongs to a user. + + Example: + .. code-block:: python + + # Get first 200 recent members + app.get_chat_members("pyrogramchat") + + # Get all administrators + app.get_chat_members("pyrogramchat", filter="administrators") + + # Get all bots + app.get_chat_members("pyrogramchat", filter="bots") """ peer = self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/chats/get_chat_members_count.py b/pyrogram/client/methods/chats/get_chat_members_count.py index 4c7ab747..74b6cda2 100644 --- a/pyrogram/client/methods/chats/get_chat_members_count.py +++ b/pyrogram/client/methods/chats/get_chat_members_count.py @@ -37,8 +37,13 @@ class GetChatMembersCount(BaseClient): ``int``: On success, the chat members count is returned. Raises: - RPCError: In case of a Telegram RPC error. ValueError: In case a chat id belongs to user. + + Example: + .. code-block:: python + + count = app.get_chat_members_count("pyrogramchat") + print(count) """ peer = self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/chats/get_dialogs.py b/pyrogram/client/methods/chats/get_dialogs.py index 8c374a44..f77ad30a 100644 --- a/pyrogram/client/methods/chats/get_dialogs.py +++ b/pyrogram/client/methods/chats/get_dialogs.py @@ -56,8 +56,14 @@ class GetDialogs(BaseClient): Returns: List of :obj:`Dialog`: On success, a list of dialogs is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Get first 100 dialogs + app.get_dialogs() + + # Get pinned dialogs + app.get_dialogs(pinned_only=True) """ while True: diff --git a/pyrogram/client/methods/chats/get_dialogs_count.py b/pyrogram/client/methods/chats/get_dialogs_count.py index c804709d..128b4364 100644 --- a/pyrogram/client/methods/chats/get_dialogs_count.py +++ b/pyrogram/client/methods/chats/get_dialogs_count.py @@ -31,8 +31,11 @@ class GetDialogsCount(BaseClient): Returns: ``int``: On success, the dialogs count is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + count = app.get_dialogs_count() + print(count) """ if pinned_only: diff --git a/pyrogram/client/methods/chats/iter_chat_members.py b/pyrogram/client/methods/chats/iter_chat_members.py index fe117694..297b8ff3 100644 --- a/pyrogram/client/methods/chats/iter_chat_members.py +++ b/pyrogram/client/methods/chats/iter_chat_members.py @@ -77,8 +77,20 @@ class IterChatMembers(BaseClient): Returns: ``Generator``: A generator yielding :obj:`ChatMember` objects. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Iterate though all chat members + for member in app.iter_chat_members("pyrogramchat"): + print(member.user.first_name) + + # Iterate though all administrators + for member in app.iter_chat_members("pyrogramchat", filter="administrators"): + print(member.user.first_name) + + # Iterate though all bots + for member in app.iter_chat_members("pyrogramchat", filter="bots"): + print(member.user.first_name) """ current = 0 yielded = set() diff --git a/pyrogram/client/methods/chats/iter_dialogs.py b/pyrogram/client/methods/chats/iter_dialogs.py index fce9fb99..55de2a74 100644 --- a/pyrogram/client/methods/chats/iter_dialogs.py +++ b/pyrogram/client/methods/chats/iter_dialogs.py @@ -46,8 +46,12 @@ class IterDialogs(BaseClient): Returns: ``Generator``: A generator yielding :obj:`Dialog` objects. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Iterate through all dialogs + for dialog in app.iter_dialogs(): + print(dialog.chat.first_name or dialog.chat.title) """ current = 0 total = limit or (1 << 31) - 1 diff --git a/pyrogram/client/methods/chats/join_chat.py b/pyrogram/client/methods/chats/join_chat.py index ed6c69ce..c1dd923a 100644 --- a/pyrogram/client/methods/chats/join_chat.py +++ b/pyrogram/client/methods/chats/join_chat.py @@ -36,8 +36,14 @@ class JoinChat(BaseClient): Returns: :obj:`Chat`: On success, a chat object is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Join chat via username + app.join_chat("pyrogram") + + # Join chat via invite link + app.join_chat("https://t.me/joinchat/AAAAAE0QmSW3IUmm3UFR7A") """ match = self.INVITE_LINK_RE.match(chat_id) diff --git a/pyrogram/client/methods/chats/kick_chat_member.py b/pyrogram/client/methods/chats/kick_chat_member.py index 9686e754..20f26c50 100644 --- a/pyrogram/client/methods/chats/kick_chat_member.py +++ b/pyrogram/client/methods/chats/kick_chat_member.py @@ -57,8 +57,16 @@ class KickChatMember(BaseClient): :obj:`Message` | ``bool``: On success, a service message will be returned (when applicable), otherwise, in case a message object couldn't be returned, True is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + from time import time + + # Ban chat member forever + app.kick_chat_member(chat_id, user_id) + + # Kick chat member and automatically unban after 24h + app.kick_chat_member(chat_id, user_id, int(time.time() + 86400)) """ chat_peer = self.resolve_peer(chat_id) user_peer = self.resolve_peer(user_id) diff --git a/pyrogram/client/methods/chats/leave_chat.py b/pyrogram/client/methods/chats/leave_chat.py index 3ed6f10f..0a8aec0e 100644 --- a/pyrogram/client/methods/chats/leave_chat.py +++ b/pyrogram/client/methods/chats/leave_chat.py @@ -37,9 +37,16 @@ class LeaveChat(BaseClient): delete (``bool``, *optional*): Deletes the group chat dialog after leaving (for simple group chats, not supergroups). + Defaults to False. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Leave chat or channel + app.leave_chat(chat_id) + + # Leave basic chat and also delete the dialog + app.leave_chat(chat_id, delete=True) """ peer = self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/chats/pin_chat_message.py b/pyrogram/client/methods/chats/pin_chat_message.py index efb41e67..fcdb31fd 100644 --- a/pyrogram/client/methods/chats/pin_chat_message.py +++ b/pyrogram/client/methods/chats/pin_chat_message.py @@ -47,8 +47,14 @@ class PinChatMessage(BaseClient): Returns: ``bool``: True on success. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Pin with notification + app.pin_chat_message(chat_id, message_id) + + # Pin without notification + app.pin_chat_message(chat_id, message_id, disable_notification=True) """ self.send( functions.messages.UpdatePinnedMessage( diff --git a/pyrogram/client/methods/chats/promote_chat_member.py b/pyrogram/client/methods/chats/promote_chat_member.py index 700b3a68..9394841b 100644 --- a/pyrogram/client/methods/chats/promote_chat_member.py +++ b/pyrogram/client/methods/chats/promote_chat_member.py @@ -78,8 +78,11 @@ class PromoteChatMember(BaseClient): Returns: ``bool``: True on success. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Promote chat member to supergroup admin + app.promote_chat_member(chat_id, user_id) """ self.send( functions.channels.EditAdmin( diff --git a/pyrogram/client/methods/chats/restrict_chat.py b/pyrogram/client/methods/chats/restrict_chat.py index dc0f96a1..20acd5e1 100644 --- a/pyrogram/client/methods/chats/restrict_chat.py +++ b/pyrogram/client/methods/chats/restrict_chat.py @@ -72,8 +72,14 @@ class RestrictChat(BaseClient): Returns: :obj:`Chat`: On success, a chat object is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Completely restrict chat + app.restrict_chat(chat_id) + + # All chat members can only send text messages + app.restrict_chat(chat_id, can_send_messages=True) """ send_messages = True send_media = True diff --git a/pyrogram/client/methods/chats/restrict_chat_member.py b/pyrogram/client/methods/chats/restrict_chat_member.py index 30574022..60787b32 100644 --- a/pyrogram/client/methods/chats/restrict_chat_member.py +++ b/pyrogram/client/methods/chats/restrict_chat_member.py @@ -85,8 +85,19 @@ class RestrictChatMember(BaseClient): Returns: :obj:`Chat`: On success, a chat object is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + from time import time + + # Completely restrict chat member forever + app.restrict_chat_member(chat_id, user_id) + + # Chat member can't send messages for 24h + app.restrict_chat_member(chat_id, user_id, int(time.time() + 86400)) + + # Chat member can only send text messages + app.restrict_chat_member(chat_id, user_id, can_send_messages=True) """ send_messages = True send_media = True diff --git a/pyrogram/client/methods/chats/set_chat_description.py b/pyrogram/client/methods/chats/set_chat_description.py index 68bf9fa2..8d0f0669 100644 --- a/pyrogram/client/methods/chats/set_chat_description.py +++ b/pyrogram/client/methods/chats/set_chat_description.py @@ -42,8 +42,12 @@ class SetChatDescription(BaseClient): ``bool``: True on success. Raises: - RPCError: In case of a Telegram RPC error. - ``ValueError`` if a chat_id doesn't belong to a supergroup or a channel. + ValueError: if a chat_id doesn't belong to a supergroup or a channel. + + Example: + .. code-block:: python + + app.set_chat_description(chat_id, "New Description") """ peer = self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/chats/set_chat_photo.py b/pyrogram/client/methods/chats/set_chat_photo.py index 2baa29fe..71cd6590 100644 --- a/pyrogram/client/methods/chats/set_chat_photo.py +++ b/pyrogram/client/methods/chats/set_chat_photo.py @@ -17,12 +17,11 @@ # along with Pyrogram. If not, see . import os -from base64 import b64decode from struct import unpack from typing import Union from pyrogram.api import functions, types -from ...ext import BaseClient +from ...ext import BaseClient, utils class SetChatPhoto(BaseClient): @@ -32,38 +31,43 @@ class SetChatPhoto(BaseClient): photo: str ) -> bool: """Set a new profile photo for the chat. - Photos can't be changed for private chats. - You must be an administrator in the chat for this to work and must have the appropriate admin rights. - Note: - In regular groups (non-supergroups), this method will only work if the "All Members Are Admins" - setting is off. + You must be an administrator in the chat for this to work and must have the appropriate admin rights. Parameters: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. photo (``str``): - New chat photo. You can pass a :obj:`Photo` id or a file path to upload a new photo. + New chat photo. You can pass a :obj:`Photo` file_id or a file path to upload a new photo from your local + machine. Returns: ``bool``: True on success. Raises: - RPCError: In case of a Telegram RPC error. ValueError: if a chat_id belongs to user. + + Example: + .. code-block:: python + + # Set chat photo using a local file + app.set_chat_photo(chat_id, "photo.jpg") + + # Set chat photo using an exiting Photo file_id + app.set_chat_photo(chat_id, photo.file_id) """ peer = self.resolve_peer(chat_id) if os.path.exists(photo): photo = types.InputChatUploadedPhoto(file=self.save_file(photo)) else: - s = unpack(" List["pyrogram.User"]: - # TODO: Create a Users object and return that """Get contacts from your Telegram address book. Returns: List of :obj:`User`: On success, a list of users is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + contacts = app.get_contacts() + print(contacts) """ while True: try: diff --git a/pyrogram/client/methods/contacts/get_contacts_count.py b/pyrogram/client/methods/contacts/get_contacts_count.py index dddfe8c4..8e23d698 100644 --- a/pyrogram/client/methods/contacts/get_contacts_count.py +++ b/pyrogram/client/methods/contacts/get_contacts_count.py @@ -27,8 +27,11 @@ class GetContactsCount(BaseClient): Returns: ``int``: On success, the contacts count is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + count = app.get_contacts_count() + print(count) """ return len(self.send(functions.contacts.GetContacts(hash=0)).contacts) diff --git a/pyrogram/client/methods/messages/delete_messages.py b/pyrogram/client/methods/messages/delete_messages.py index 3667c8ee..f0c4d991 100644 --- a/pyrogram/client/methods/messages/delete_messages.py +++ b/pyrogram/client/methods/messages/delete_messages.py @@ -50,8 +50,17 @@ class DeleteMessages(BaseClient): Returns: ``bool``: True on success, False otherwise. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Delete one message + app.delete_messages(chat_id, message_id) + + # Delete multiple messages at once + app.delete_messages(chat_id, list_of_message_ids) + + # Delete messages only on your side (without revoking) + app.delete_messages(chat_id, message_id, revoke=False) """ peer = self.resolve_peer(chat_id) message_ids = list(message_ids) if not isinstance(message_ids, int) else [message_ids] diff --git a/pyrogram/client/methods/messages/download_media.py b/pyrogram/client/methods/messages/download_media.py index cc0e54d2..46709ced 100644 --- a/pyrogram/client/methods/messages/download_media.py +++ b/pyrogram/client/methods/messages/download_media.py @@ -57,24 +57,23 @@ class DownloadMedia(BaseClient): Blocks the code execution until the file has been downloaded. Defaults to True. - progress (``callable``): - Pass a callback function to view the download progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + progress (``callable``, *optional*): + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. - progress_args (``tuple``): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + progress_args (``tuple``, *optional*): + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes downloaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -85,8 +84,16 @@ class DownloadMedia(BaseClient): the download failed or was deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Raises: - RPCError: In case of a Telegram RPC error. ValueError: if the message doesn't contain any downloadable media + + Example: + .. code-block:: python + + # Download from Message + app.download_media(message) + + # Download from file id + app.download_media("CAADBAADyg4AAvLQYAEYD4F7vcZ43AI") """ error_message = "This message doesn't contain any downloadable media" available_media = ("audio", "document", "photo", "sticker", "animation", "video", "voice", "video_note") diff --git a/pyrogram/client/methods/messages/edit_inline_caption.py b/pyrogram/client/methods/messages/edit_inline_caption.py index 298e3ef4..57a0ac75 100644 --- a/pyrogram/client/methods/messages/edit_inline_caption.py +++ b/pyrogram/client/methods/messages/edit_inline_caption.py @@ -30,7 +30,7 @@ class EditInlineCaption(BaseClient): parse_mode: Union[str, None] = object, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> bool: - """Edit the caption of **inline** media messages. + """Edit the caption of inline media messages. Parameters: inline_message_id (``str``): @@ -52,8 +52,11 @@ class EditInlineCaption(BaseClient): Returns: ``bool``: On success, True is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Bots only + app.edit_inline_caption(inline_message_id, "new media caption") """ return self.edit_inline_text( inline_message_id=inline_message_id, diff --git a/pyrogram/client/methods/messages/edit_inline_media.py b/pyrogram/client/methods/messages/edit_inline_media.py index 0ed89d17..7a82f3a8 100644 --- a/pyrogram/client/methods/messages/edit_inline_media.py +++ b/pyrogram/client/methods/messages/edit_inline_media.py @@ -33,7 +33,7 @@ class EditInlineMedia(BaseClient): media: InputMedia, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> bool: - """Edit **inline** animation, audio, document, photo or video messages. + """Edit inline animation, audio, document, photo or video messages. When the inline message is edited, a new file can't be uploaded. Use a previously uploaded file via its file_id or specify a URL. @@ -52,8 +52,21 @@ class EditInlineMedia(BaseClient): Returns: ``bool``: On success, True is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + from pyrogram import InputMediaPhoto, InputMediaVideo, InputMediaAudio + + # Bots only + + # Replace the current media with a local photo + app.edit_inline_media(inline_message_id, InputMediaPhoto("new_photo.jpg")) + + # Replace the current media with a local video + app.edit_inline_media(inline_message_id, InputMediaVideo("new_video.mp4")) + + # Replace the current media with a local audio + app.edit_inline_media(inline_message_id, InputMediaAudio("new_audio.mp3")) """ caption = media.caption parse_mode = media.parse_mode diff --git a/pyrogram/client/methods/messages/edit_inline_reply_markup.py b/pyrogram/client/methods/messages/edit_inline_reply_markup.py index 0326ed72..aae64898 100644 --- a/pyrogram/client/methods/messages/edit_inline_reply_markup.py +++ b/pyrogram/client/methods/messages/edit_inline_reply_markup.py @@ -27,7 +27,7 @@ class EditInlineReplyMarkup(BaseClient): inline_message_id: str, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> bool: - """Edit only the reply markup of **inline** messages sent via the bot (for inline bots). + """Edit only the reply markup of inline messages sent via the bot (for inline bots). Parameters: inline_message_id (``str``): @@ -39,8 +39,16 @@ class EditInlineReplyMarkup(BaseClient): Returns: ``bool``: On success, True is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + from pyrogram import InlineKeyboardMarkup, InlineKeyboardButton + + # Bots only + app.edit_inline_reply_markup( + inline_message_id, + InlineKeyboardMarkup([[ + InlineKeyboardButton("New button", callback_data="new_data")]])) """ return self.send( functions.messages.EditInlineBotMessage( diff --git a/pyrogram/client/methods/messages/edit_inline_text.py b/pyrogram/client/methods/messages/edit_inline_text.py index 9b0b34d3..c92e13a1 100644 --- a/pyrogram/client/methods/messages/edit_inline_text.py +++ b/pyrogram/client/methods/messages/edit_inline_text.py @@ -32,7 +32,7 @@ class EditInlineText(BaseClient): disable_web_page_preview: bool = None, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> bool: - """Edit the text of **inline** messages. + """Edit the text of inline messages. Parameters: inline_message_id (``str``): @@ -57,8 +57,18 @@ class EditInlineText(BaseClient): Returns: ``bool``: On success, True is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Bots only + + # Simple edit text + app.edit_inline_text(inline_message_id, "new text") + + # Take the same text message, remove the web page preview only + app.edit_inline_text( + inline_message_id, message.text, + disable_web_page_preview=True) """ return self.send( diff --git a/pyrogram/client/methods/messages/edit_message_caption.py b/pyrogram/client/methods/messages/edit_message_caption.py index c760c675..eae59c62 100644 --- a/pyrogram/client/methods/messages/edit_message_caption.py +++ b/pyrogram/client/methods/messages/edit_message_caption.py @@ -58,8 +58,10 @@ class EditMessageCaption(BaseClient): Returns: :obj:`Message`: On success, the edited message is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + app.edit_message_caption(chat_id, message_id, "new media caption") """ return self.edit_message_text( chat_id=chat_id, diff --git a/pyrogram/client/methods/messages/edit_message_media.py b/pyrogram/client/methods/messages/edit_message_media.py index 72077710..f543af2b 100644 --- a/pyrogram/client/methods/messages/edit_message_media.py +++ b/pyrogram/client/methods/messages/edit_message_media.py @@ -60,8 +60,19 @@ class EditMessageMedia(BaseClient): Returns: :obj:`Message`: On success, the edited message is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + from pyrogram import InputMediaPhoto, InputMediaVideo, InputMediaAudio + + # Replace the current media with a local photo + app.edit_message_media(chat_id, message_id, InputMediaPhoto("new_photo.jpg")) + + # Replace the current media with a local video + app.edit_message_media(chat_id, message_id, InputMediaVideo("new_video.mp4")) + + # Replace the current media with a local audio + app.edit_message_media(chat_id, message_id, InputMediaAudio("new_audio.mp3")) """ caption = media.caption parse_mode = media.parse_mode diff --git a/pyrogram/client/methods/messages/edit_message_reply_markup.py b/pyrogram/client/methods/messages/edit_message_reply_markup.py index 51b77a6a..737fc23b 100644 --- a/pyrogram/client/methods/messages/edit_message_reply_markup.py +++ b/pyrogram/client/methods/messages/edit_message_reply_markup.py @@ -47,8 +47,16 @@ class EditMessageReplyMarkup(BaseClient): Returns: :obj:`Message`: On success, the edited message is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + from pyrogram import InlineKeyboardMarkup, InlineKeyboardButton + + # Bots only + app.edit_message_reply_markup( + chat_id, message_id, + InlineKeyboardMarkup([[ + InlineKeyboardButton("New button", callback_data="new_data")]])) """ r = self.send( functions.messages.EditMessage( diff --git a/pyrogram/client/methods/messages/edit_message_text.py b/pyrogram/client/methods/messages/edit_message_text.py index 063c8c72..31022c0e 100644 --- a/pyrogram/client/methods/messages/edit_message_text.py +++ b/pyrogram/client/methods/messages/edit_message_text.py @@ -63,8 +63,16 @@ class EditMessageText(BaseClient): Returns: :obj:`Message`: On success, the edited message is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Simple edit text + app.edit_message_text(chat_id, message_id, "new text") + + # Take the same text message, remove the web page preview only + app.edit_message_text( + chat_id, message_id, message.text, + disable_web_page_preview=True) """ r = self.send( diff --git a/pyrogram/client/methods/messages/forward_messages.py b/pyrogram/client/methods/messages/forward_messages.py index c69df608..ba74e373 100644 --- a/pyrogram/client/methods/messages/forward_messages.py +++ b/pyrogram/client/methods/messages/forward_messages.py @@ -55,7 +55,8 @@ class ForwardMessages(BaseClient): Users will receive a notification with no sound. as_copy (``bool``, *optional*): - Pass True to forward messages without the forward header (i.e.: send a copy of the message content). + Pass True to forward messages without the forward header (i.e.: send a copy of the message content so + that it appears as originally sent by you). Defaults to False. remove_caption (``bool``, *optional*): @@ -68,8 +69,18 @@ class ForwardMessages(BaseClient): is returned, otherwise, in case *message_ids* was an iterable, the returned value will be a list of messages, even if such iterable contained just a single element. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + :emphasize-lines: 2,5,8 + + # Forward a single message + app.forward_messages("me", "pyrogram", 20) + + # Forward multiple messages at once + app.forward_messages("me", "pyrogram", [3, 20, 27]) + + # Forward messages as copy + app.forward_messages("me", "pyrogram", 20, as_copy=True) """ is_iterable = not isinstance(message_ids, int) diff --git a/pyrogram/client/methods/messages/get_history.py b/pyrogram/client/methods/messages/get_history.py index 8adafe22..e471c6fd 100644 --- a/pyrogram/client/methods/messages/get_history.py +++ b/pyrogram/client/methods/messages/get_history.py @@ -70,8 +70,17 @@ class GetHistory(BaseClient): Returns: List of :obj:`Message` - On success, a list of the retrieved messages is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Get the last 100 messages of a chat + app.get_history("pyrogramchat") + + # Get the last 3 messages of a chat + app.get_history("pyrogramchat", limit=3) + + # Get 3 messages after skipping the first 5 + app.get_history("pyrogramchat", offset=5, limit=3) """ offset_id = offset_id or (1 if reverse else 0) diff --git a/pyrogram/client/methods/messages/get_history_count.py b/pyrogram/client/methods/messages/get_history_count.py index 9f3e2637..8ceba0ed 100644 --- a/pyrogram/client/methods/messages/get_history_count.py +++ b/pyrogram/client/methods/messages/get_history_count.py @@ -45,8 +45,10 @@ class GetHistoryCount(BaseClient): Returns: ``int``: On success, the chat history count is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + app.get_history_count("pyrogramchat") """ r = self.send( diff --git a/pyrogram/client/methods/messages/get_messages.py b/pyrogram/client/methods/messages/get_messages.py index 0e3a2ea3..e9615b43 100644 --- a/pyrogram/client/methods/messages/get_messages.py +++ b/pyrogram/client/methods/messages/get_messages.py @@ -64,8 +64,25 @@ class GetMessages(BaseClient): returned, otherwise, in case *message_ids* was an iterable, the returned value will be a list of messages, even if such iterable contained just a single element. + Example: + .. code-block:: python + + # Get one message + app.get_messages("pyrogramchat", 51110) + + # Get more than one message (list of messages) + app.get_messages("pyrogramchat", [44625, 51110]) + + # Get message by ignoring any replied-to message + app.get_messages(chat_id, message_id, replies=0) + + # Get message with all chained replied-to messages + app.get_messages(chat_id, message_id, replies=-1) + + # Get the replied-to message of a message + app.get_messages(chat_id, reply_to_message_ids=message_id) + Raises: - RPCError: In case of a Telegram RPC error. ValueError: In case of invalid arguments. """ ids, ids_type = ( diff --git a/pyrogram/client/methods/messages/iter_history.py b/pyrogram/client/methods/messages/iter_history.py index 15c48c95..735ed162 100644 --- a/pyrogram/client/methods/messages/iter_history.py +++ b/pyrogram/client/methods/messages/iter_history.py @@ -64,8 +64,11 @@ class IterHistory(BaseClient): Returns: ``Generator``: A generator yielding :obj:`Message` objects. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + for message in app.iter_history("pyrogram"): + print(message.text) """ offset_id = offset_id or (1 if reverse else 0) current = 0 diff --git a/pyrogram/client/methods/messages/read_history.py b/pyrogram/client/methods/messages/read_history.py index f0278e91..f5dc8630 100644 --- a/pyrogram/client/methods/messages/read_history.py +++ b/pyrogram/client/methods/messages/read_history.py @@ -43,8 +43,14 @@ class ReadHistory(BaseClient): Returns: ``bool`` - On success, True is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Mark the whole chat as read + app.read_history("pyrogramlounge") + + # Mark messages as read only up to the given message id + app.read_history("pyrogramlounge", 123456) """ peer = self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/messages/retract_vote.py b/pyrogram/client/methods/messages/retract_vote.py index b52181a6..a273ad7b 100644 --- a/pyrogram/client/methods/messages/retract_vote.py +++ b/pyrogram/client/methods/messages/retract_vote.py @@ -43,8 +43,10 @@ class RetractVote(BaseClient): Returns: :obj:`Poll`: On success, the poll with the retracted vote is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + app.retract_vote(chat_id, message_id) """ r = self.send( functions.messages.SendVote( diff --git a/pyrogram/client/methods/messages/send_animated_sticker.py b/pyrogram/client/methods/messages/send_animated_sticker.py index 6fd0c647..8e57c527 100644 --- a/pyrogram/client/methods/messages/send_animated_sticker.py +++ b/pyrogram/client/methods/messages/send_animated_sticker.py @@ -67,23 +67,22 @@ class SendAnimatedSticker(BaseClient): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -92,8 +91,12 @@ class SendAnimatedSticker(BaseClient): Returns: :obj:`Message` | ``None``: On success, the sent animated sticker message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. - Raises: - RPCError: In case of a Telegram RPC error. + + Example: + .. code-block:: python + + # Send animated sticker by uploading from local file + app.send_animated_sticker("me", "animated_sticker.tgs") """ file = None diff --git a/pyrogram/client/methods/messages/send_animation.py b/pyrogram/client/methods/messages/send_animation.py index a68984fc..5d345010 100644 --- a/pyrogram/client/methods/messages/send_animation.py +++ b/pyrogram/client/methods/messages/send_animation.py @@ -66,7 +66,7 @@ class SendAnimation(BaseClient): Animation caption, 0-1024 characters. unsave (``bool``, *optional*): - By default, the server will save into your own collection any new animation GIF you send. + By default, the server will save into your own collection any new animation you send. Pass True to automatically unsave the sent animation. Defaults to False. parse_mode (``str``, *optional*): @@ -103,23 +103,22 @@ class SendAnimation(BaseClient): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -129,8 +128,23 @@ class SendAnimation(BaseClient): :obj:`Message` | ``None``: On success, the sent animation message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Send animation by uploading from local file + app.send_animation("me", "animation.gif") + + # Add caption to the animation + app.send_animation("me", "animation.gif", caption="cat") + + # Unsave the animation once is sent + app.send_animation("me", "animation.gif", unsave=True) + + # Keep track of the progress while uploading + def progress(current, total): + print("{:.1f}%".format(current * 100 / total)) + + app.send_animation("me", "animation.gif", progress=progress) """ file = None diff --git a/pyrogram/client/methods/messages/send_audio.py b/pyrogram/client/methods/messages/send_audio.py index c8ce7368..7395718b 100644 --- a/pyrogram/client/methods/messages/send_audio.py +++ b/pyrogram/client/methods/messages/send_audio.py @@ -100,23 +100,22 @@ class SendAudio(BaseClient): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -126,8 +125,26 @@ class SendAudio(BaseClient): :obj:`Message` | ``None``: On success, the sent audio message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + :emphasize-lines: 2,5,8-10,13-16 + + # Send audio file by uploading from file + app.send_audio("me", "audio.mp3") + + # Add caption to the audio + app.send_audio("me", "audio.mp3", caption="shoegaze") + + # Set audio metadata + app.send_audio( + "me", "audio.mp3", + title="Printemps émeraude", performer="Alcest", duration=440) + + # Keep track of the progress while uploading + def progress(current, total): + print("{:.1f}%".format(current * 100 / total)) + + app.send_audio("me", "audio.mp3", progress=progress) """ file = None diff --git a/pyrogram/client/methods/messages/send_cached_media.py b/pyrogram/client/methods/messages/send_cached_media.py index 59a24171..9b4fbafa 100644 --- a/pyrogram/client/methods/messages/send_cached_media.py +++ b/pyrogram/client/methods/messages/send_cached_media.py @@ -79,8 +79,10 @@ class SendCachedMedia(BaseClient): Returns: :obj:`Message`: On success, the sent media message is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + app.send_cached_media("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI") """ r = self.send( diff --git a/pyrogram/client/methods/messages/send_chat_action.py b/pyrogram/client/methods/messages/send_chat_action.py index da974c97..7488fb16 100644 --- a/pyrogram/client/methods/messages/send_chat_action.py +++ b/pyrogram/client/methods/messages/send_chat_action.py @@ -64,8 +64,22 @@ class SendChatAction(BaseClient): ``bool``: On success, True is returned. Raises: - RPCError: In case of a Telegram RPC error. - ValueError: In case the provided string is not a valid ChatAction. + ValueError: In case the provided string is not a valid chat action. + + Example: + .. code-block:: python + + # Send "typing" chat action + app.send_chat_action(chat_id, "typing") + + # Send "upload_video" chat action + app.send_chat_action(chat_id, "upload_video") + + # Send "playing" chat action + app.send_chat_action(chat_id, "playing") + + # Cancel any current chat action + app.send_chat_action(chat_id, "cancel") """ try: diff --git a/pyrogram/client/methods/messages/send_contact.py b/pyrogram/client/methods/messages/send_contact.py index d0b6fb58..c32ca25d 100644 --- a/pyrogram/client/methods/messages/send_contact.py +++ b/pyrogram/client/methods/messages/send_contact.py @@ -74,8 +74,10 @@ class SendContact(BaseClient): Returns: :obj:`Message`: On success, the sent contact message is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + app.send_contact("me", "+39 123 456 7890", "Dan") """ r = self.send( functions.messages.SendMedia( diff --git a/pyrogram/client/methods/messages/send_document.py b/pyrogram/client/methods/messages/send_document.py index a3cec395..567bc561 100644 --- a/pyrogram/client/methods/messages/send_document.py +++ b/pyrogram/client/methods/messages/send_document.py @@ -86,23 +86,22 @@ class SendDocument(BaseClient): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -112,8 +111,20 @@ class SendDocument(BaseClient): :obj:`Message` | ``None``: On success, the sent document message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Send document by uploading from local file + app.send_document("me", "document.zip") + + # Add caption to the document file + app.send_document("me", "document.zip", caption="archive") + + # Keep track of the progress while uploading + def progress(current, total): + print("{:.1f}%".format(current * 100 / total)) + + app.send_document("me", "document.zip", progress=progress) """ file = None diff --git a/pyrogram/client/methods/messages/send_location.py b/pyrogram/client/methods/messages/send_location.py index 2e3681e6..245f61f2 100644 --- a/pyrogram/client/methods/messages/send_location.py +++ b/pyrogram/client/methods/messages/send_location.py @@ -66,8 +66,10 @@ class SendLocation(BaseClient): Returns: :obj:`Message`: On success, the sent location message is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + app.send_location("me", 51.500729, -0.124583) """ r = self.send( functions.messages.SendMedia( diff --git a/pyrogram/client/methods/messages/send_media_group.py b/pyrogram/client/methods/messages/send_media_group.py index 1f0aa3dd..ac38c0d6 100644 --- a/pyrogram/client/methods/messages/send_media_group.py +++ b/pyrogram/client/methods/messages/send_media_group.py @@ -59,8 +59,19 @@ class SendMediaGroup(BaseClient): Returns: List of :obj:`Message`: On success, a list of the sent messages is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + from pyrogram import InputMediaPhoto, InputMediaVideo + + app.send_media_group( + "me", + [ + InputMediaPhoto("photo1.jpg"), + InputMediaPhoto("photo2.jpg", caption="photo caption"), + InputMediaVideo("video.mp4", caption="a video") + ] + ) """ multi_media = [] diff --git a/pyrogram/client/methods/messages/send_message.py b/pyrogram/client/methods/messages/send_message.py index f652f3d9..c15b3a84 100644 --- a/pyrogram/client/methods/messages/send_message.py +++ b/pyrogram/client/methods/messages/send_message.py @@ -74,9 +74,44 @@ class SendMessage(BaseClient): Returns: :obj:`Message`: On success, the sent text message is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + :emphasize-lines: 2,5,8,11,21-23,26-33 + + # Simple example + app.send_message("haskell", "Thanks for creating **Pyrogram**!") + + # Disable web page previews + app.send_message("me", "https://docs.pyrogram.org", disable_web_page_preview=True) + + # Reply to a message using its id + app.send_message("me", "this is a reply", reply_to_message_id=12345) + + # Force HTML-only styles for this request only + app.send_message("me", "**not bold**, italic", parse_mode="html") + + ## + # For bots only, send messages with keyboards attached + ## + + from pyrogram import ( + ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton) + + # Send a normal keyboard + app.send_message( + chat_id, "Look at that button!", + reply_markup=ReplyKeyboardMarkup([["Nice!"]])) + + # Send an inline keyboard + app.send_message( + chat_id, "These are inline buttons", + reply_markup=InlineKeyboardMarkup( + [ + [InlineKeyboardButton("Data", callback_data="hidden_callback_data")], + [InlineKeyboardButton("Docs", url="https://docs.pyrogram.org")] + ])) """ + message, entities = self.parser.parse(text, parse_mode).values() r = self.send( diff --git a/pyrogram/client/methods/messages/send_photo.py b/pyrogram/client/methods/messages/send_photo.py index 981b0045..0c82ebfc 100644 --- a/pyrogram/client/methods/messages/send_photo.py +++ b/pyrogram/client/methods/messages/send_photo.py @@ -85,23 +85,22 @@ class SendPhoto(BaseClient): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -111,8 +110,20 @@ class SendPhoto(BaseClient): :obj:`Message` | ``None``: On success, the sent photo message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Send photo by uploading from local file + app.send_photo("me", "photo.jpg") + + # Send photo by uploading from URL + app.send_photo("me", "https://i.imgur.com/BQBTP7d.png") + + # Add caption to a photo + app.send_photo("me", "photo.jpg", caption="Holidays!") + + # Send self-destructing photo + app.send_photo("me", "photo.jpg", ttl_seconds=10) """ file = None diff --git a/pyrogram/client/methods/messages/send_poll.py b/pyrogram/client/methods/messages/send_poll.py index 4dae53b2..2fa008ab 100644 --- a/pyrogram/client/methods/messages/send_poll.py +++ b/pyrogram/client/methods/messages/send_poll.py @@ -66,8 +66,10 @@ class SendPoll(BaseClient): Returns: :obj:`Message`: On success, the sent poll message is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + app.send_poll(chat_id, "Is this a poll question?", ["Yes", "No", "Maybe"]) """ r = self.send( functions.messages.SendMedia( diff --git a/pyrogram/client/methods/messages/send_sticker.py b/pyrogram/client/methods/messages/send_sticker.py index 4f7a99ff..a5fc7b26 100644 --- a/pyrogram/client/methods/messages/send_sticker.py +++ b/pyrogram/client/methods/messages/send_sticker.py @@ -67,23 +67,22 @@ class SendSticker(BaseClient): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -92,8 +91,15 @@ class SendSticker(BaseClient): Returns: :obj:`Message` | ``None``: On success, the sent sticker message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. - Raises: - RPCError: In case of a Telegram RPC error. + + Example: + .. code-block:: python + + # Send sticker by uploading from local file + app.send_sticker("me", "sticker.webp") + + # Send sticker using file_id + app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI") """ file = None diff --git a/pyrogram/client/methods/messages/send_venue.py b/pyrogram/client/methods/messages/send_venue.py index 35545c9b..ab630936 100644 --- a/pyrogram/client/methods/messages/send_venue.py +++ b/pyrogram/client/methods/messages/send_venue.py @@ -83,8 +83,12 @@ class SendVenue(BaseClient): Returns: :obj:`Message`: On success, the sent venue message is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + app.send_venue( + "me", 51.500729, -0.124583, + "Elizabeth Tower", "Westminster, London SW1A 0AA, UK") """ r = self.send( functions.messages.SendMedia( diff --git a/pyrogram/client/methods/messages/send_video.py b/pyrogram/client/methods/messages/send_video.py index 602e3b01..ca6f0519 100644 --- a/pyrogram/client/methods/messages/send_video.py +++ b/pyrogram/client/methods/messages/send_video.py @@ -103,23 +103,22 @@ class SendVideo(BaseClient): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -129,8 +128,20 @@ class SendVideo(BaseClient): :obj:`Message` | ``None``: On success, the sent video message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Send video by uploading from local file + app.send_video("me", "video.mp4") + + # Add caption to the video + app.send_video("me", "video.mp4", caption="recording") + + # Keep track of the progress while uploading + def progress(current, total): + print("{:.1f}%".format(current * 100 / total)) + + app.send_video("me", "video.mp4", progress=progress) """ file = None diff --git a/pyrogram/client/methods/messages/send_video_note.py b/pyrogram/client/methods/messages/send_video_note.py index da8d53c2..65988b36 100644 --- a/pyrogram/client/methods/messages/send_video_note.py +++ b/pyrogram/client/methods/messages/send_video_note.py @@ -82,23 +82,22 @@ class SendVideoNote(BaseClient): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -108,8 +107,14 @@ class SendVideoNote(BaseClient): :obj:`Message` | ``None``: On success, the sent video note message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Send video note by uploading from local file + app.send_video_note("me", "video_note.mp4") + + # Set video note length + app.send_video_note("me", "video_note.mp4", length=25) """ file = None diff --git a/pyrogram/client/methods/messages/send_voice.py b/pyrogram/client/methods/messages/send_voice.py index 9c0b8514..8d9f6c5f 100644 --- a/pyrogram/client/methods/messages/send_voice.py +++ b/pyrogram/client/methods/messages/send_voice.py @@ -83,23 +83,22 @@ class SendVoice(BaseClient): instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): - Pass a callback function to view the upload progress. - The function must take *(client, current, total, \*args)* as positional arguments (look at the section - below for a detailed description). + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. Useful, for example, if you want to pass - a chat_id and a message_id in order to edit a message with the updated progress. + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. Other Parameters: - client (:obj:`Client`): - The Client itself, useful when you want to call other API methods inside the callback function. - current (``int``): - The amount of bytes uploaded so far. + The amount of bytes transmitted so far. total (``int``): - The size of the file. + The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. @@ -109,8 +108,17 @@ class SendVoice(BaseClient): :obj:`Message` | ``None``: On success, the sent voice message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Send voice note by uploading from local file + app.send_voice("me", "voice.ogg") + + # Add caption to the voice note + app.send_voice("me", "voice.ogg", caption="voice note") + + # Set voice note duration + app.send_voice("me", "voice.ogg", duration=20) """ file = None diff --git a/pyrogram/client/methods/messages/stop_poll.py b/pyrogram/client/methods/messages/stop_poll.py index 6abe6791..308bf587 100644 --- a/pyrogram/client/methods/messages/stop_poll.py +++ b/pyrogram/client/methods/messages/stop_poll.py @@ -49,8 +49,10 @@ class StopPoll(BaseClient): Returns: :obj:`Poll`: On success, the stopped poll with the final results is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + app.stop_poll(chat_id, message_id) """ poll = self.get_messages(chat_id, message_id).poll diff --git a/pyrogram/client/methods/messages/vote_poll.py b/pyrogram/client/methods/messages/vote_poll.py index a5d77d86..7c976cd8 100644 --- a/pyrogram/client/methods/messages/vote_poll.py +++ b/pyrogram/client/methods/messages/vote_poll.py @@ -47,8 +47,10 @@ class VotePoll(BaseClient): Returns: :obj:`Poll` - On success, the poll with the chosen option is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + app.vote_poll(chat_id, message_id, 6) """ poll = self.get_messages(chat_id, message_id).poll diff --git a/pyrogram/client/methods/password/change_cloud_password.py b/pyrogram/client/methods/password/change_cloud_password.py index a33b83c7..67e1254f 100644 --- a/pyrogram/client/methods/password/change_cloud_password.py +++ b/pyrogram/client/methods/password/change_cloud_password.py @@ -46,8 +46,16 @@ class ChangeCloudPassword(BaseClient): ``bool``: True on success. Raises: - RPCError: In case of a Telegram RPC error. ValueError: In case there is no cloud password to change. + + Example: + .. code-block:: python + + # Change password only + app.change_cloud_password("current_password", "new_password") + + # Change password and hint + app.change_cloud_password("current_password", "new_password", new_hint="hint") """ r = self.send(functions.account.GetPassword()) diff --git a/pyrogram/client/methods/password/enable_cloud_password.py b/pyrogram/client/methods/password/enable_cloud_password.py index 23ee1608..19683ffc 100644 --- a/pyrogram/client/methods/password/enable_cloud_password.py +++ b/pyrogram/client/methods/password/enable_cloud_password.py @@ -48,8 +48,19 @@ class EnableCloudPassword(BaseClient): ``bool``: True on success. Raises: - RPCError: In case of a Telegram RPC error. ValueError: In case there is already a cloud password enabled. + + Example: + .. code-block:: python + + # Enable password without hint and email + app.enable_cloud_password("password") + + # Enable password with hint and without email + app.enable_cloud_password("password", hint="hint") + + # Enable password with hint and email + app.enable_cloud_password("password", hint="hint", email="user@email.com") """ r = self.send(functions.account.GetPassword()) diff --git a/pyrogram/client/methods/password/remove_cloud_password.py b/pyrogram/client/methods/password/remove_cloud_password.py index 9dcbb005..6b68bd5e 100644 --- a/pyrogram/client/methods/password/remove_cloud_password.py +++ b/pyrogram/client/methods/password/remove_cloud_password.py @@ -36,8 +36,12 @@ class RemoveCloudPassword(BaseClient): ``bool``: True on success. Raises: - RPCError: In case of a Telegram RPC error. ValueError: In case there is no cloud password to remove. + + Example: + .. code-block:: python + + app.remove_cloud_password("password") """ r = self.send(functions.account.GetPassword()) diff --git a/pyrogram/client/methods/users/block_user.py b/pyrogram/client/methods/users/block_user.py index ef3cad85..120a4aaf 100644 --- a/pyrogram/client/methods/users/block_user.py +++ b/pyrogram/client/methods/users/block_user.py @@ -30,11 +30,19 @@ class BlockUser(BaseClient): ) -> bool: """Block a user. + Parameters: + user_id (``int`` | ``str``):: + Unique identifier (int) or username (str) of the target user. + For you yourself you can simply use "me" or "self". + For a contact that exists in your Telegram address book you can use his phone number (str). + Returns: ``bool``: True on success - Raises: - RPCError: In case of Telegram RPC Error. + Example: + .. code-block:: python + + app.block_user(user_id) """ return bool( self.send( diff --git a/pyrogram/client/methods/users/delete_profile_photos.py b/pyrogram/client/methods/users/delete_profile_photos.py index a165f7d1..c155ede8 100644 --- a/pyrogram/client/methods/users/delete_profile_photos.py +++ b/pyrogram/client/methods/users/delete_profile_photos.py @@ -40,8 +40,17 @@ class DeleteProfilePhotos(BaseClient): Returns: ``bool``: True on success. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Get the photos to be deleted + photos = app.get_profile_photos("me") + + # Delete one photo + app.delete_profile_photos(photos[0].file_id) + + # Delete the rest of the photos + app.delete_profile_photos([p.file_id for p in photos[1:]]) """ photo_ids = photo_ids if isinstance(photo_ids, list) else [photo_ids] input_photos = [] diff --git a/pyrogram/client/methods/users/get_me.py b/pyrogram/client/methods/users/get_me.py index 44f16af3..b399187f 100644 --- a/pyrogram/client/methods/users/get_me.py +++ b/pyrogram/client/methods/users/get_me.py @@ -26,10 +26,13 @@ class GetMe(BaseClient): """Get your own user identity. Returns: - :obj:`User`: Basic information about the user or bot. + :obj:`User`: Information about the own logged in user/bot. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + me = app.get_me() + print(me) """ return pyrogram.User._parse( self, diff --git a/pyrogram/client/methods/users/get_profile_photos.py b/pyrogram/client/methods/users/get_profile_photos.py index 3ffeae39..dece6b5d 100644 --- a/pyrogram/client/methods/users/get_profile_photos.py +++ b/pyrogram/client/methods/users/get_profile_photos.py @@ -51,8 +51,17 @@ class GetProfilePhotos(BaseClient): Returns: List of :obj:`Photo`: On success, a list of profile photos is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Get the first 100 profile photos of a user + app.get_profile_photos("haskell") + + # Get only the first profile photo of a user + app.get_profile_photos("haskell", limit=1) + + # Get 3 profile photos of a user, skip the first 5 + app.get_profile_photos("haskell", limit=3, offset=5) """ peer_id = self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/users/get_profile_photos_count.py b/pyrogram/client/methods/users/get_profile_photos_count.py index bf00a10b..4069f85b 100644 --- a/pyrogram/client/methods/users/get_profile_photos_count.py +++ b/pyrogram/client/methods/users/get_profile_photos_count.py @@ -36,8 +36,11 @@ class GetProfilePhotosCount(BaseClient): Returns: ``int``: On success, the user profile photos count is returned. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + count = app.get_profile_photos_count("haskell") + print(count) """ peer_id = self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/users/get_users.py b/pyrogram/client/methods/users/get_users.py index f76e6802..67e58615 100644 --- a/pyrogram/client/methods/users/get_users.py +++ b/pyrogram/client/methods/users/get_users.py @@ -24,7 +24,6 @@ from ...ext import BaseClient class GetUsers(BaseClient): - # TODO: Add Users type and use that def get_users( self, user_ids: Union[Iterable[Union[int, str]], int, str] @@ -43,8 +42,14 @@ class GetUsers(BaseClient): returned, otherwise, in case *user_ids* was an iterable a list of users is returned, even if the iterable contained one item only. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + # Get information about one user + app.get_users("haskell") + + # Get information about multiple users at once + app.get_users([user1, user2, user3]) """ is_iterable = not isinstance(user_ids, (int, str)) user_ids = list(user_ids) if is_iterable else [user_ids] diff --git a/pyrogram/client/methods/users/iter_profile_photos.py b/pyrogram/client/methods/users/iter_profile_photos.py index 49317f87..f812a856 100644 --- a/pyrogram/client/methods/users/iter_profile_photos.py +++ b/pyrogram/client/methods/users/iter_profile_photos.py @@ -51,8 +51,11 @@ class IterProfilePhotos(BaseClient): Returns: ``Generator``: A generator yielding :obj:`Photo` objects. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + for photo in app.iter_profile_photos("haskell"): + print(photo.file_id) """ current = 0 total = limit or (1 << 31) diff --git a/pyrogram/client/methods/users/set_profile_photo.py b/pyrogram/client/methods/users/set_profile_photo.py index a713fd34..975a2ced 100644 --- a/pyrogram/client/methods/users/set_profile_photo.py +++ b/pyrogram/client/methods/users/set_profile_photo.py @@ -38,8 +38,10 @@ class SetProfilePhoto(BaseClient): Returns: ``bool``: True on success. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + app.set_profile_photo("new_photo.jpg") """ return bool( diff --git a/pyrogram/client/methods/users/unblock_user.py b/pyrogram/client/methods/users/unblock_user.py index c06533cd..8b87cd7e 100644 --- a/pyrogram/client/methods/users/unblock_user.py +++ b/pyrogram/client/methods/users/unblock_user.py @@ -30,11 +30,19 @@ class UnblockUser(BaseClient): ) -> bool: """Unblock a user. + Parameters: + user_id (``int`` | ``str``):: + Unique identifier (int) or username (str) of the target user. + For you yourself you can simply use "me" or "self". + For a contact that exists in your Telegram address book you can use his phone number (str). + Returns: ``bool``: True on success - Raises: - RPCError: In case of Telegram RPC Error. + Example: + .. code-block:: python + + app.unblock_user(user_id) """ return bool( self.send( diff --git a/pyrogram/client/methods/users/update_username.py b/pyrogram/client/methods/users/update_username.py index 002dbf75..07bd62bb 100644 --- a/pyrogram/client/methods/users/update_username.py +++ b/pyrogram/client/methods/users/update_username.py @@ -40,8 +40,10 @@ class UpdateUsername(BaseClient): Returns: ``bool``: True on success. - Raises: - RPCError: In case of a Telegram RPC error. + Example: + .. code-block:: python + + app.update_username("new_username") """ return bool( From 7b9a38a2bae77c33ea12ec6887d4789239b6ccf6 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 28 Jul 2019 08:16:41 +0200 Subject: [PATCH 30/55] Fix indentation and docstrings due to bad PR --- pyrogram/client/types/messages_and_media/message.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index 4f5043e4..2994ec56 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.py @@ -2857,11 +2857,10 @@ class Message(Object, Update): raise ValueError("This button is not supported yet") else: self.reply(button, quote=quote) - - - def retract_vote( - self, - ) -> "Poll": + + def retract_vote( + self, + ) -> "pyrogram.Poll": """Bound method *retract_vote* of :obj:`Message`. Use as a shortcut for: @@ -2957,10 +2956,11 @@ class Message(Object, Update): progress=progress, progress_args=progress_args, ) + def vote( self, option: int, - ) -> "Poll": + ) -> "pyrogram.Poll": """Bound method *vote* of :obj:`Message`. Use as a shortcut for: From 87bbd764b9751b8e9e231f0d3ba75efe39bf3cd0 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 28 Jul 2019 08:54:18 +0200 Subject: [PATCH 31/55] Add better summary for get_messages --- pyrogram/client/methods/messages/get_messages.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pyrogram/client/methods/messages/get_messages.py b/pyrogram/client/methods/messages/get_messages.py index e9615b43..8f547227 100644 --- a/pyrogram/client/methods/messages/get_messages.py +++ b/pyrogram/client/methods/messages/get_messages.py @@ -28,6 +28,9 @@ from ...ext import BaseClient, utils log = logging.getLogger(__name__) +# TODO: Rewrite using a flag for replied messages and have message_ids non-optional + + class GetMessages(BaseClient): def get_messages( self, @@ -36,7 +39,8 @@ class GetMessages(BaseClient): reply_to_message_ids: Union[int, Iterable[int]] = None, replies: int = 1 ) -> Union["pyrogram.Message", List["pyrogram.Message"]]: - """Get one or more messages that belong to a specific chat. + """Get one or more messages from a chat by using message identifiers. + You can retrieve up to 200 messages at once. Parameters: From 11ea15aa08fc423154596011ce61944aef368f90 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 28 Jul 2019 09:32:35 +0200 Subject: [PATCH 32/55] Fix yet another compatibility issue with Path objects and Python 3.5 --- pyrogram/client/methods/messages/download_media.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyrogram/client/methods/messages/download_media.py b/pyrogram/client/methods/messages/download_media.py index 46709ced..b00b7c72 100644 --- a/pyrogram/client/methods/messages/download_media.py +++ b/pyrogram/client/methods/messages/download_media.py @@ -214,7 +214,8 @@ class DownloadMedia(BaseClient): extension ) - self.download_queue.put((data, directory, file_name, done, progress, progress_args, path)) + # Cast to string because Path objects aren't supported by Python 3.5 + self.download_queue.put((data, str(directory), str(file_name), done, progress, progress_args, path)) if block: done.wait() From bed13de413a4b0fad4e1662bb0e4e0ddb82d29f2 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 28 Jul 2019 09:47:11 +0200 Subject: [PATCH 33/55] Fix ChatPreview objects failing to parse This happened because Telegram changed the preview photo type from ChatPhoto to Photo. The reason behind this change was due to ChatPhoto requiring now a peer id to be downloaded, which is not available in case of chat previews. --- .../client/types/user_and_chats/chat_preview.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pyrogram/client/types/user_and_chats/chat_preview.py b/pyrogram/client/types/user_and_chats/chat_preview.py index 312bdfe6..781f85c8 100644 --- a/pyrogram/client/types/user_and_chats/chat_preview.py +++ b/pyrogram/client/types/user_and_chats/chat_preview.py @@ -20,7 +20,7 @@ from typing import List import pyrogram from pyrogram.api import types -from .chat_photo import ChatPhoto +from ..messages_and_media import Photo from ..object import Object from ..user_and_chats.user import User @@ -32,48 +32,48 @@ class ChatPreview(Object): title (``str``): Title of the chat. - photo (:obj:`ChatPhoto`, *optional*): - Chat photo. Suitable for downloads only. - type (``str``): Type of chat, can be either, "group", "supergroup" or "channel". members_count (``int``): Chat members count. + photo (:obj:`Photo`, *optional*): + Chat photo. + members (List of :obj:`User`, *optional*): Preview of some of the chat members. """ - __slots__ = ["title", "photo", "type", "members_count", "members"] + __slots__ = ["title", "type", "members_count", "photo", "members"] def __init__( self, *, client: "pyrogram.BaseClient" = None, title: str, - photo: ChatPhoto = None, type: str, members_count: int, + photo: Photo = None, members: List[User] = None ): super().__init__(client) self.title = title - self.photo = photo self.type = type self.members_count = members_count + self.photo = photo self.members = members @staticmethod def _parse(client, chat_invite: types.ChatInvite) -> "ChatPreview": return ChatPreview( title=chat_invite.title, - photo=ChatPhoto._parse(client, chat_invite.photo), type=("group" if not chat_invite.channel else "channel" if chat_invite.broadcast else "supergroup"), members_count=chat_invite.participants_count, + photo=Photo._parse(client, chat_invite.photo), members=[User._parse(client, user) for user in chat_invite.participants] or None, client=client ) From e1c6e6ecc142da31a14608c9b0381ee69b2b804e Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 28 Jul 2019 10:13:38 +0200 Subject: [PATCH 34/55] Better handling of non-string message texts Now everything will be allowed and automatically casted to string. This means that send_message(id, True) would send "True", literally. --- pyrogram/client/parser/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/client/parser/parser.py b/pyrogram/client/parser/parser.py index edf9553d..371c4791 100644 --- a/pyrogram/client/parser/parser.py +++ b/pyrogram/client/parser/parser.py @@ -31,7 +31,7 @@ class Parser: self.markdown = Markdown(client) def parse(self, text: str, mode: Union[str, None] = object): - text = str(text or "").strip() + text = str(text).strip() if mode == object: if self.client: From 8cdcf90b1044a07b5618d99e13111aed27e28b7d Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sun, 28 Jul 2019 15:11:18 +0200 Subject: [PATCH 35/55] Enhance Parser when dealing with leading and trailing whitespaces --- pyrogram/client/parser/html.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyrogram/client/parser/html.py b/pyrogram/client/parser/html.py index 9aff757f..41efe3b3 100644 --- a/pyrogram/client/parser/html.py +++ b/pyrogram/client/parser/html.py @@ -86,7 +86,8 @@ class Parser(HTMLParser): for entities in self.tag_entities.values(): for entity in entities: - entity.length += len(data) + entity.offset += len(data) - len(data.lstrip()) # Ignore left whitespaces for offsets + entity.length += len(data.strip()) # Ignore all whitespaces (left + right) for lengths self.text += data From d875298937636a2fde245f8f05ee08882dec19fc Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Mon, 29 Jul 2019 12:16:00 +0200 Subject: [PATCH 36/55] Fix forward copies having "None" as caption in case of no caption at all --- pyrogram/client/types/messages_and_media/message.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index 2994ec56..4b98c290 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.py @@ -2620,7 +2620,7 @@ class Message(Object, Update): disable_notification=disable_notification ) elif self.media: - caption = self.caption.html if self.caption and not remove_caption else None + caption = self.caption.html if self.caption and not remove_caption else "" send_media = partial( self._client.send_cached_media, From 02451ffeb56bed9918ef548b4744afe069143495 Mon Sep 17 00:00:00 2001 From: Mendel E Date: Mon, 29 Jul 2019 07:31:07 -0400 Subject: [PATCH 37/55] Try/except handler.check() Previously, when handler.check raised errors, it would be excepted by the try on line 153, and would fail to loop through the rest of the groups/handlers. --- pyrogram/client/ext/dispatcher.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pyrogram/client/ext/dispatcher.py b/pyrogram/client/ext/dispatcher.py index 55a31452..5b6bccd2 100644 --- a/pyrogram/client/ext/dispatcher.py +++ b/pyrogram/client/ext/dispatcher.py @@ -166,8 +166,13 @@ class Dispatcher: args = None if isinstance(handler, handler_type): - if handler.check(parsed_update): - args = (parsed_update,) + try: + if handler.check(parsed_update): + args = (parsed_update,) + except Exception as e: + log.error(e, exc_info=True) + continue + elif isinstance(handler, RawUpdateHandler): args = (update, users, chats) From 47e5b9a7cbeb225ea7a0213f69d653b3bb07ec59 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 1 Aug 2019 00:53:17 +0200 Subject: [PATCH 38/55] Set Message.text instead of Message.caption in case of web_page previews --- .../types/messages_and_media/message.py | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index 4b98c290..a5105888 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.py @@ -602,10 +602,26 @@ class Message(Object, Update): date=message.date, chat=Chat._parse(client, message, users, chats), from_user=User._parse(client, users.get(message.from_id, None)), - text=Str(message.message).init(entities) or None if media is None else None, - caption=Str(message.message).init(entities) or None if media is not None else None, - entities=entities or None if media is None else None, - caption_entities=entities or None if media is not None else None, + text=( + Str(message.message).init(entities) or None + if media is None or web_page is not None + else None + ), + caption=( + Str(message.message).init(entities) or None + if media is not None and web_page is None + else None + ), + entities=( + entities or None + if media is None or web_page is not None + else None + ), + caption_entities=( + entities or None + if media is not None and web_page is None + else None + ), author_signature=message.post_author, forward_from=forward_from, forward_sender_name=forward_sender_name, From 93a2fed8e662a1cd581065b0c2c50f4778c8b065 Mon Sep 17 00:00:00 2001 From: MrNaif2018 <39452697+MrNaif2018@users.noreply.github.com> Date: Thu, 1 Aug 2019 10:11:29 +0300 Subject: [PATCH 39/55] Improved examples, added links to docs --- docs/source/topics/scheduling.rst | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/docs/source/topics/scheduling.rst b/docs/source/topics/scheduling.rst index 70f70215..1f4e1e01 100644 --- a/docs/source/topics/scheduling.rst +++ b/docs/source/topics/scheduling.rst @@ -9,8 +9,6 @@ But it is easy to integrate pyrogram with your favourite scheduler. schedule -------- -Note that schedule is not suitable for async version of pyrogram. - .. code-block:: python import time @@ -20,20 +18,15 @@ Note that schedule is not suitable for async version of pyrogram. def job(): app.send_message("me", "Hi!") - - schedule.every(10).minutes.do(job) - schedule.every().hour.do(job) - schedule.every().day.at("10:30").do(job) - schedule.every(5).to(10).minutes.do(job) - schedule.every().monday.do(job) - schedule.every().wednesday.at("13:15").do(job) - schedule.every().minute.at(":17").do(job) + schedule.every(3).seconds.do(job) with app: while True: schedule.run_pending() time.sleep(1) +Note that schedule is not suitable for async version of pyrogram. +For more information read `library `_ docs. apscheduler ----------- @@ -71,3 +64,4 @@ Apscheduler supports async version of pyrogram too, here is async example: scheduler.start() app.run() +For more information read `library `_ docs. From 6973f584886bc5d65e6aa5d88a5f98abeb8a287e Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 1 Aug 2019 12:37:22 +0200 Subject: [PATCH 40/55] Update scheduling.rst --- docs/source/topics/scheduling.rst | 50 +++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/docs/source/topics/scheduling.rst b/docs/source/topics/scheduling.rst index 1f4e1e01..3cb95ec7 100644 --- a/docs/source/topics/scheduling.rst +++ b/docs/source/topics/scheduling.rst @@ -1,23 +1,34 @@ -Scheduling tasks +Scheduling Tasks ================ -Pyrogram itself as Telegram MTProto API Framework contains only stuff -related to Telegram. Scheduling is out of it's scope. +Scheduling tasks means executing one or more functions periodically at pre-defined intervals or after a delay. This is +useful, for example, to send recurring messages to specific chats or users. -But it is easy to integrate pyrogram with your favourite scheduler. +Since there's no built-in task scheduler in Pyrogram, this page will only show examples on how to integrate Pyrogram +with the main Python schedule libraries such as ``schedule`` and ``apscheduler``. For more detailed information, you can +visit and learn from each library documentation. -schedule --------- +Using ``schedule`` +------------------ + +- Install with ``pip3 install schedule`` +- Documentation: https://schedule.readthedocs.io .. code-block:: python import time + import schedule + from pyrogram import Client + + app = Client("my_account") + def job(): app.send_message("me", "Hi!") + schedule.every(3).seconds.do(job) with app: @@ -25,43 +36,52 @@ schedule schedule.run_pending() time.sleep(1) -Note that schedule is not suitable for async version of pyrogram. -For more information read `library `_ docs. -apscheduler ------------ + +Using ``apscheduler`` +--------------------- + +- Install with ``pip3 install apscheduler`` +- Documentation: https://apscheduler.readthedocs.io .. code-block:: python - import time from apscheduler.schedulers.background import BackgroundScheduler + from pyrogram import Client + + app = Client("my_account") + def job(): app.send_message("me", "Hi!") scheduler = BackgroundScheduler() - scheduler.add_job(job, 'interval', seconds=3) + scheduler.add_job(job, "interval", seconds=3) scheduler.start() app.run() -Apscheduler supports async version of pyrogram too, here is async example: +``apscheduler`` does also support async code, here's an example with +`Pyrogram Asyncio `_: .. code-block:: python from apscheduler.schedulers.asyncio import AsyncIOScheduler + from pyrogram import Client + + app = Client("my_account") + async def job(): await app.send_message("me", "Hi!") scheduler = AsyncIOScheduler() - scheduler.add_job(job, 'interval', seconds=3) + scheduler.add_job(job, "interval", seconds=3) scheduler.start() app.run() -For more information read `library `_ docs. From f8f2ad5a60025eaf7a611b7680faa5bec50c1bd7 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 1 Aug 2019 12:44:34 +0200 Subject: [PATCH 41/55] Tidy up docs --- docs/source/index.rst | 4 ++-- docs/source/topics/{serialize.rst => serializing.rst} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename docs/source/topics/{serialize.rst => serializing.rst} (100%) diff --git a/docs/source/index.rst b/docs/source/index.rst index b8927657..f6961bc6 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -40,14 +40,14 @@ Welcome to Pyrogram topics/more-on-updates topics/config-file topics/smart-plugins - topics/scheduling topics/auto-auth topics/session-settings topics/tgcrypto topics/storage-engines topics/text-formatting - topics/serialize + topics/serializing topics/proxy + topics/scheduling topics/bots-interaction topics/mtproto-vs-botapi topics/debugging diff --git a/docs/source/topics/serialize.rst b/docs/source/topics/serializing.rst similarity index 100% rename from docs/source/topics/serialize.rst rename to docs/source/topics/serializing.rst From 3fedae8d820cd455aab69cc8a8a9627bd05af833 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 1 Aug 2019 17:26:59 +0200 Subject: [PATCH 42/55] Update faq.rst --- docs/source/faq.rst | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/source/faq.rst b/docs/source/faq.rst index 2dde12f2..a05ff39c 100644 --- a/docs/source/faq.rst +++ b/docs/source/faq.rst @@ -192,7 +192,6 @@ dismissed and their IP addresses are now kept as aliases to the nearest one. Thanks to `@FrayxRulez `_ for telling about alias DCs. - I want to migrate my account from DCX to DCY. --------------------------------------------- @@ -246,9 +245,13 @@ The error in question is ``[400 PEER_ID_INVALID]``, and could mean several thing - The chat id you tried to use is simply wrong, double check it. - The chat id refers to a group or channel you are not a member of. -- The chat id refers to a user you have't seen yet (from contacts, groups in common, forwarded messages or private - chats). - The chat id argument you passed is in form of a string; you have to convert it into an integer with ``int(chat_id)``. +- The chat id refers to a user your current session haven't met yet. + +About the last point: in order for you to meet a user and thus communicate with them, you should ask yourself how to +contact people using official apps. The answer is the same for Pyrogram too and involves normal usages such as searching +for usernames, meet them in a common group, have their phone contacts saved, getting a message mentioning them (either a +forward or a mention in the message text). UnicodeEncodeError: '' codec can't encode … ----------------------------------------------------- @@ -258,6 +261,14 @@ shows up when you try to print something and has very little to do with Pyrogram your own terminal. To fix it, either find a way to change the encoding settings of your terminal to UTF-8 or switch to a better terminal altogether. +Uploading with URLs gives error WEBPAGE_CURL_FAILED +--------------------------------------------------- + +When uploading media files using an URL, the server automatically tries to download the media and uploads it to the +Telegram cloud. This error usually happens in case the provided URL is not publicly accessible by Telegram itself or the +media exceeds 20 MB in size. In such cases, your only option is to download the media yourself and upload from your +local machine. + My verification code expires immediately! ----------------------------------------- From d727754ad6256eaaa8a2b49850e99e5862a88d30 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 1 Aug 2019 18:41:04 +0200 Subject: [PATCH 43/55] Remove Null primitive It's unused --- compiler/api/compiler.py | 1 - pyrogram/api/core/primitives/__init__.py | 5 ++-- pyrogram/api/core/primitives/null.py | 32 ------------------------ 3 files changed, 3 insertions(+), 35 deletions(-) delete mode 100644 pyrogram/api/core/primitives/null.py diff --git a/compiler/api/compiler.py b/compiler/api/compiler.py index 3995fd5f..255884db 100644 --- a/compiler/api/compiler.py +++ b/compiler/api/compiler.py @@ -478,7 +478,6 @@ def start(): f.write("\n 0xbc799737: \"pyrogram.api.core.BoolFalse\",") f.write("\n 0x997275b5: \"pyrogram.api.core.BoolTrue\",") - f.write("\n 0x56730bcc: \"pyrogram.api.core.Null\",") f.write("\n 0x1cb5c415: \"pyrogram.api.core.Vector\",") f.write("\n 0x73f1f8dc: \"pyrogram.api.core.MsgContainer\",") f.write("\n 0xae500895: \"pyrogram.api.core.FutureSalts\",") diff --git a/pyrogram/api/core/primitives/__init__.py b/pyrogram/api/core/primitives/__init__.py index 8885878b..f86e3cab 100644 --- a/pyrogram/api/core/primitives/__init__.py +++ b/pyrogram/api/core/primitives/__init__.py @@ -16,10 +16,11 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from .bool import Bool, BoolTrue, BoolFalse +from .bool import Bool, BoolFalse, BoolTrue from .bytes import Bytes from .double import Double from .int import Int, Long, Int128, Int256 -from .null import Null from .string import String from .vector import Vector + +__all__ = ["Bool", "BoolFalse", "BoolTrue", "Bytes", "Double", "Int", "Long", "Int128", "Int256", "String", "Vector"] diff --git a/pyrogram/api/core/primitives/null.py b/pyrogram/api/core/primitives/null.py deleted file mode 100644 index ffddea94..00000000 --- a/pyrogram/api/core/primitives/null.py +++ /dev/null @@ -1,32 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-2019 Dan Tès -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -from io import BytesIO - -from ..tl_object import TLObject - - -class Null(TLObject): - ID = 0x56730bcc - - @staticmethod - def read(b: BytesIO, *args) -> None: - return None - - def __new__(cls) -> bytes: - return cls.ID.to_bytes(4, "little") From 9ad5e62dea5fa5d9786770097c2b0de8db10b6f4 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 1 Aug 2019 18:44:20 +0200 Subject: [PATCH 44/55] Move all imported schema objects outside TLObject --- pyrogram/api/__init__.py | 3 +-- pyrogram/api/core/__init__.py | 5 +---- pyrogram/api/core/tl_object.py | 6 +++--- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/pyrogram/api/__init__.py b/pyrogram/api/__init__.py index 8d7831ff..78f1a579 100644 --- a/pyrogram/api/__init__.py +++ b/pyrogram/api/__init__.py @@ -19,8 +19,7 @@ from importlib import import_module from .all import objects -from .core.tl_object import TLObject for k, v in objects.items(): path, name = v.rsplit(".", 1) - TLObject.all[k] = getattr(import_module(path), name) + objects[k] = getattr(import_module(path), name) diff --git a/pyrogram/api/core/__init__.py b/pyrogram/api/core/__init__.py index aaf5a324..ff4fc9c5 100644 --- a/pyrogram/api/core/__init__.py +++ b/pyrogram/api/core/__init__.py @@ -22,8 +22,5 @@ from .gzip_packed import GzipPacked from .list import List from .message import Message from .msg_container import MsgContainer -from .primitives import ( - Bool, BoolTrue, BoolFalse, Bytes, Double, - Int, Long, Int128, Int256, Null, String, Vector -) +from .primitives import * from .tl_object import TLObject diff --git a/pyrogram/api/core/tl_object.py b/pyrogram/api/core/tl_object.py index 4b951404..d39a8ae2 100644 --- a/pyrogram/api/core/tl_object.py +++ b/pyrogram/api/core/tl_object.py @@ -20,17 +20,17 @@ from collections import OrderedDict from io import BytesIO from json import dumps +from ..all import objects + class TLObject: - all = {} - __slots__ = [] QUALNAME = "Base" @staticmethod def read(b: BytesIO, *args): # TODO: Rename b -> data - return TLObject.all[int.from_bytes(b.read(4), "little")].read(b, *args) + return objects[int.from_bytes(b.read(4), "little")].read(b, *args) def write(self, *args) -> bytes: pass From ad0f8284f686b2501460a51943b2149deb9331ce Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 1 Aug 2019 19:07:08 +0200 Subject: [PATCH 45/55] Use the correct way to parse peer identifiers --- pyrogram/client/client.py | 45 +++++++------- pyrogram/client/ext/utils.py | 60 ++++++++++++------- pyrogram/client/methods/chats/get_chat.py | 4 +- pyrogram/client/methods/chats/get_dialogs.py | 6 +- .../bots_and_keyboards/callback_query.py | 12 +--- .../types/messages_and_media/message.py | 7 ++- pyrogram/client/types/user_and_chats/chat.py | 5 +- .../client/types/user_and_chats/dialog.py | 12 +--- 8 files changed, 80 insertions(+), 71 deletions(-) diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index 64595a91..511dbf2a 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.py @@ -1015,7 +1015,7 @@ class Client(Methods, BaseClient): access_hash = 0 peer_type = "group" elif isinstance(peer, (types.Channel, types.ChannelForbidden)): - peer_id = int("-100" + str(peer.id)) + peer_id = utils.get_channel_id(peer.id) access_hash = peer.access_hash username = getattr(peer, "username", None) @@ -1131,7 +1131,7 @@ class Client(Methods, BaseClient): try: diff = self.send( functions.updates.GetChannelDifference( - channel=self.resolve_peer(int("-100" + str(channel_id))), + channel=self.resolve_peer(utils.get_channel_id(channel_id)), filter=types.ChannelMessagesFilter( ranges=[types.MessageRange( min_id=update.message.id, @@ -1519,33 +1519,38 @@ class Client(Methods, BaseClient): except KeyError: raise PeerIdInvalid - if peer_id > 0: + peer_type = utils.get_type(peer_id) + + if peer_type == "user": self.fetch_peers( self.send( functions.users.GetUsers( - id=[types.InputUser( - user_id=peer_id, - access_hash=0 - )] + id=[ + types.InputUser( + user_id=peer_id, + access_hash=0 + ) + ] ) ) ) + elif peer_type == "chat": + self.send( + functions.messages.GetChats( + id=[-peer_id] + ) + ) else: - if str(peer_id).startswith("-100"): - self.send( - functions.channels.GetChannels( - id=[types.InputChannel( - channel_id=int(str(peer_id)[4:]), + self.send( + functions.channels.GetChannels( + id=[ + types.InputChannel( + channel_id=utils.get_channel_id(peer_id), access_hash=0 - )] - ) - ) - else: - self.send( - functions.messages.GetChats( - id=[-peer_id] - ) + ) + ] ) + ) try: return self.storage.get_peer_by_id(peer_id) diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py index e0a797e2..d89f83bb 100644 --- a/pyrogram/client/ext/utils.py +++ b/pyrogram/client/ext/utils.py @@ -18,10 +18,11 @@ import base64 import struct -from typing import Union, List +from typing import List +from typing import Union import pyrogram - +from pyrogram.api.types import PeerUser, PeerChat, PeerChannel from . import BaseClient from ...api import types @@ -62,23 +63,6 @@ def encode(s: bytes) -> str: return base64.urlsafe_b64encode(r).decode().rstrip("=") -def get_peer_id(input_peer) -> int: - return ( - input_peer.user_id if isinstance(input_peer, types.InputPeerUser) - else -input_peer.chat_id if isinstance(input_peer, types.InputPeerChat) - else int("-100" + str(input_peer.channel_id)) - ) - - -def get_input_peer(peer_id: int, access_hash: int): - return ( - types.InputPeerUser(user_id=peer_id, access_hash=access_hash) if peer_id > 0 - else types.InputPeerChannel(channel_id=int(str(peer_id)[4:]), access_hash=access_hash) - if (str(peer_id).startswith("-100") and access_hash) - else types.InputPeerChat(chat_id=-peer_id) - ) - - def get_offset_date(dialogs): for m in reversed(dialogs.messages): if isinstance(m, types.MessageEmpty): @@ -183,7 +167,7 @@ def parse_deleted_messages(client, update) -> List["pyrogram.Message"]: pyrogram.Message( message_id=message, chat=pyrogram.Chat( - id=int("-100" + str(channel_id)), + id=get_channel_id(channel_id), type="channel", client=client ) if channel_id is not None else None, @@ -203,3 +187,39 @@ def unpack_inline_message_id(inline_message_id: str) -> types.InputBotInlineMess id=r[1], access_hash=r[2] ) + + +MIN_CHANNEL_ID = -1002147483647 +MAX_CHANNEL_ID = -1000000000000 +MIN_CHAT_ID = -2147483647 +MAX_USER_ID = 2147483647 + + +def get_peer_id(peer: Union[PeerUser, PeerChat, PeerChannel]) -> int: + if isinstance(peer, PeerUser): + return peer.user_id + + if isinstance(peer, PeerChat): + return -peer.chat_id + + if isinstance(peer, PeerChannel): + return MAX_CHANNEL_ID - peer.channel_id + + raise ValueError("Peer type invalid: {}".format(peer)) + + +def get_type(peer_id: int) -> str: + if peer_id < 0: + if MIN_CHAT_ID <= peer_id: + return "chat" + + if MIN_CHANNEL_ID <= peer_id < MAX_CHANNEL_ID: + return "channel" + elif 0 < peer_id <= MAX_USER_ID: + return "user" + + raise ValueError("Peer id invalid: {}".format(peer_id)) + + +def get_channel_id(peer_id: int) -> int: + return MAX_CHANNEL_ID - peer_id diff --git a/pyrogram/client/methods/chats/get_chat.py b/pyrogram/client/methods/chats/get_chat.py index 48c5cc22..0773ce6c 100644 --- a/pyrogram/client/methods/chats/get_chat.py +++ b/pyrogram/client/methods/chats/get_chat.py @@ -20,7 +20,7 @@ from typing import Union import pyrogram from pyrogram.api import functions, types -from ...ext import BaseClient +from ...ext import BaseClient, utils class GetChat(BaseClient): @@ -70,7 +70,7 @@ class GetChat(BaseClient): chat_id = -r.chat.id if isinstance(r.chat, types.Channel): - chat_id = int("-100" + str(r.chat.id)) + chat_id = utils.get_channel_id(r.chat.id) peer = self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/chats/get_dialogs.py b/pyrogram/client/methods/chats/get_dialogs.py index f77ad30a..30078d57 100644 --- a/pyrogram/client/methods/chats/get_dialogs.py +++ b/pyrogram/client/methods/chats/get_dialogs.py @@ -23,7 +23,7 @@ from typing import List import pyrogram from pyrogram.api import functions, types from pyrogram.errors import FloodWait -from ...ext import BaseClient +from ...ext import BaseClient, utils log = logging.getLogger(__name__) @@ -100,10 +100,8 @@ class GetDialogs(BaseClient): chat_id = to_id.user_id else: chat_id = message.from_id - elif isinstance(to_id, types.PeerChat): - chat_id = -to_id.chat_id else: - chat_id = int("-100" + str(to_id.channel_id)) + chat_id = utils.get_peer_id(to_id) messages[chat_id] = pyrogram.Message._parse(self, message, users, chats) diff --git a/pyrogram/client/types/bots_and_keyboards/callback_query.py b/pyrogram/client/types/bots_and_keyboards/callback_query.py index d58865b2..9ba1804b 100644 --- a/pyrogram/client/types/bots_and_keyboards/callback_query.py +++ b/pyrogram/client/types/bots_and_keyboards/callback_query.py @@ -25,6 +25,7 @@ from pyrogram.api import types from ..object import Object from ..update import Update from ..user_and_chats import User +from ...ext import utils class CallbackQuery(Object, Update): @@ -90,16 +91,7 @@ class CallbackQuery(Object, Update): inline_message_id = None if isinstance(callback_query, types.UpdateBotCallbackQuery): - peer = callback_query.peer - - if isinstance(peer, types.PeerUser): - peer_id = peer.user_id - elif isinstance(peer, types.PeerChat): - peer_id = -peer.chat_id - else: - peer_id = int("-100" + str(peer.channel_id)) - - message = client.get_messages(peer_id, callback_query.msg_id) + message = client.get_messages(utils.get_peer_id(callback_query.peer), callback_query.msg_id) elif isinstance(callback_query, types.UpdateInlineBotCallbackQuery): inline_message_id = b64encode( pack( diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index a5105888..ed0088cd 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.py @@ -31,7 +31,8 @@ from ..object import Object from ..update import Update from ..user_and_chats.chat import Chat from ..user_and_chats.user import User -from ...parser import utils, Parser +from ...ext import utils +from ...parser import utils as parser_utils, Parser class Str(str): @@ -54,7 +55,7 @@ class Str(str): return Parser.unparse(self, self.entities, True) def __getitem__(self, item): - return utils.remove_surrogates(utils.add_surrogates(self)[item]) + return parser_utils.remove_surrogates(parser_utils.add_surrogates(self)[item]) class Message(Object, Update): @@ -446,7 +447,7 @@ class Message(Object, Update): new_chat_title=new_chat_title, new_chat_photo=new_chat_photo, delete_chat_photo=delete_chat_photo, - migrate_to_chat_id=int("-100" + str(migrate_to_chat_id)) if migrate_to_chat_id else None, + migrate_to_chat_id=utils.get_channel_id(migrate_to_chat_id) if migrate_to_chat_id else None, migrate_from_chat_id=-migrate_from_chat_id if migrate_from_chat_id else None, group_chat_created=group_chat_created, channel_chat_created=channel_chat_created, diff --git a/pyrogram/client/types/user_and_chats/chat.py b/pyrogram/client/types/user_and_chats/chat.py index cac5d0c7..396831cc 100644 --- a/pyrogram/client/types/user_and_chats/chat.py +++ b/pyrogram/client/types/user_and_chats/chat.py @@ -23,6 +23,7 @@ from pyrogram.api import types from .chat_permissions import ChatPermissions from .chat_photo import ChatPhoto from ..object import Object +from ...ext import utils class Chat(Object): @@ -180,7 +181,7 @@ class Chat(Object): @staticmethod def _parse_channel_chat(client, channel: types.Channel) -> "Chat": - peer_id = int("-100" + str(channel.id)) + peer_id = utils.get_channel_id(channel.id) return Chat( id=peer_id, @@ -672,7 +673,7 @@ class Chat(Object): can_pin_messages=can_pin_messages, can_promote_members=can_promote_members ) - + def join(self): """Bound method *join* of :obj:`Chat`. diff --git a/pyrogram/client/types/user_and_chats/dialog.py b/pyrogram/client/types/user_and_chats/dialog.py index 4ea82184..a78e501b 100644 --- a/pyrogram/client/types/user_and_chats/dialog.py +++ b/pyrogram/client/types/user_and_chats/dialog.py @@ -21,6 +21,7 @@ import pyrogram from pyrogram.api import types from ..object import Object from ..user_and_chats import Chat +from ...ext import utils class Dialog(Object): @@ -70,18 +71,9 @@ class Dialog(Object): @staticmethod def _parse(client, dialog: types.Dialog, messages, users, chats) -> "Dialog": - chat_id = dialog.peer - - if isinstance(chat_id, types.PeerUser): - chat_id = chat_id.user_id - elif isinstance(chat_id, types.PeerChat): - chat_id = -chat_id.chat_id - else: - chat_id = int("-100" + str(chat_id.channel_id)) - return Dialog( chat=Chat._parse_dialog(client, dialog.peer, users, chats), - top_message=messages.get(chat_id), + top_message=messages.get(utils.get_peer_id(dialog.peer)), unread_messages_count=dialog.unread_count, unread_mentions_count=dialog.unread_mentions_count, unread_mark=dialog.unread_mark, From aa135ea457880a051531b7624c65f8d1dc6b45da Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 1 Aug 2019 19:11:43 +0200 Subject: [PATCH 46/55] Reformat project --- pyrogram/client/ext/utils.py | 3 ++- pyrogram/client/methods/users/block_user.py | 3 +-- pyrogram/client/methods/users/delete_profile_photos.py | 1 - pyrogram/client/methods/users/get_profile_photos.py | 1 - pyrogram/client/methods/users/get_profile_photos_count.py | 1 - pyrogram/client/methods/users/unblock_user.py | 3 +-- pyrogram/client/parser/__init__.py | 2 +- pyrogram/client/storage/__init__.py | 2 +- .../client/types/bots_and_keyboards/inline_keyboard_button.py | 1 + .../client/types/bots_and_keyboards/inline_keyboard_markup.py | 1 + .../client/types/bots_and_keyboards/reply_keyboard_markup.py | 1 + pyrogram/errors/rpc_error.py | 3 ++- pyrogram/session/auth.py | 1 - pyrogram/session/internals/msg_factory.py | 3 ++- pyrogram/session/session.py | 4 ++-- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py index d89f83bb..fbee9ea8 100644 --- a/pyrogram/client/ext/utils.py +++ b/pyrogram/client/ext/utils.py @@ -21,8 +21,9 @@ import struct from typing import List from typing import Union -import pyrogram from pyrogram.api.types import PeerUser, PeerChat, PeerChannel + +import pyrogram from . import BaseClient from ...api import types diff --git a/pyrogram/client/methods/users/block_user.py b/pyrogram/client/methods/users/block_user.py index 120a4aaf..ff29089c 100644 --- a/pyrogram/client/methods/users/block_user.py +++ b/pyrogram/client/methods/users/block_user.py @@ -18,8 +18,7 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types +from pyrogram.api import functions from ...ext import BaseClient diff --git a/pyrogram/client/methods/users/delete_profile_photos.py b/pyrogram/client/methods/users/delete_profile_photos.py index c155ede8..5c3b26e8 100644 --- a/pyrogram/client/methods/users/delete_profile_photos.py +++ b/pyrogram/client/methods/users/delete_profile_photos.py @@ -21,7 +21,6 @@ from typing import List, Union from pyrogram.api import functions, types from pyrogram.client.ext import utils - from ...ext import BaseClient diff --git a/pyrogram/client/methods/users/get_profile_photos.py b/pyrogram/client/methods/users/get_profile_photos.py index dece6b5d..2723a36c 100644 --- a/pyrogram/client/methods/users/get_profile_photos.py +++ b/pyrogram/client/methods/users/get_profile_photos.py @@ -21,7 +21,6 @@ from typing import Union, List import pyrogram from pyrogram.api import functions, types from pyrogram.client.ext import utils - from ...ext import BaseClient diff --git a/pyrogram/client/methods/users/get_profile_photos_count.py b/pyrogram/client/methods/users/get_profile_photos_count.py index 4069f85b..51a4091e 100644 --- a/pyrogram/client/methods/users/get_profile_photos_count.py +++ b/pyrogram/client/methods/users/get_profile_photos_count.py @@ -19,7 +19,6 @@ from typing import Union from pyrogram.api import functions, types - from ...ext import BaseClient diff --git a/pyrogram/client/methods/users/unblock_user.py b/pyrogram/client/methods/users/unblock_user.py index 8b87cd7e..e42fbd24 100644 --- a/pyrogram/client/methods/users/unblock_user.py +++ b/pyrogram/client/methods/users/unblock_user.py @@ -18,8 +18,7 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types +from pyrogram.api import functions from ...ext import BaseClient diff --git a/pyrogram/client/parser/__init__.py b/pyrogram/client/parser/__init__.py index 4769038d..53806619 100644 --- a/pyrogram/client/parser/__init__.py +++ b/pyrogram/client/parser/__init__.py @@ -16,4 +16,4 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from .parser import Parser \ No newline at end of file +from .parser import Parser diff --git a/pyrogram/client/storage/__init__.py b/pyrogram/client/storage/__init__.py index 00d2f144..657c06eb 100644 --- a/pyrogram/client/storage/__init__.py +++ b/pyrogram/client/storage/__init__.py @@ -16,6 +16,6 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from .memory_storage import MemoryStorage from .file_storage import FileStorage +from .memory_storage import MemoryStorage from .storage import Storage diff --git a/pyrogram/client/types/bots_and_keyboards/inline_keyboard_button.py b/pyrogram/client/types/bots_and_keyboards/inline_keyboard_button.py index 54aa7802..514b0303 100644 --- a/pyrogram/client/types/bots_and_keyboards/inline_keyboard_button.py +++ b/pyrogram/client/types/bots_and_keyboards/inline_keyboard_button.py @@ -22,6 +22,7 @@ from pyrogram.api.types import ( KeyboardButtonUrl, KeyboardButtonCallback, KeyboardButtonSwitchInline, KeyboardButtonGame ) + from .callback_game import CallbackGame from ..object import Object diff --git a/pyrogram/client/types/bots_and_keyboards/inline_keyboard_markup.py b/pyrogram/client/types/bots_and_keyboards/inline_keyboard_markup.py index 7b811f88..bdca85d1 100644 --- a/pyrogram/client/types/bots_and_keyboards/inline_keyboard_markup.py +++ b/pyrogram/client/types/bots_and_keyboards/inline_keyboard_markup.py @@ -19,6 +19,7 @@ from typing import List from pyrogram.api.types import ReplyInlineMarkup, KeyboardButtonRow + from . import InlineKeyboardButton from ..object import Object diff --git a/pyrogram/client/types/bots_and_keyboards/reply_keyboard_markup.py b/pyrogram/client/types/bots_and_keyboards/reply_keyboard_markup.py index 4e666d1f..f958051b 100644 --- a/pyrogram/client/types/bots_and_keyboards/reply_keyboard_markup.py +++ b/pyrogram/client/types/bots_and_keyboards/reply_keyboard_markup.py @@ -20,6 +20,7 @@ from typing import List, Union from pyrogram.api.types import KeyboardButtonRow from pyrogram.api.types import ReplyKeyboardMarkup as RawReplyKeyboardMarkup + from . import KeyboardButton from ..object import Object diff --git a/pyrogram/errors/rpc_error.py b/pyrogram/errors/rpc_error.py index 806b5373..9969d3fa 100644 --- a/pyrogram/errors/rpc_error.py +++ b/pyrogram/errors/rpc_error.py @@ -21,8 +21,9 @@ from datetime import datetime from importlib import import_module from typing import Type -from pyrogram.api.core import TLObject from pyrogram.api.types import RpcError as RawRPCError + +from pyrogram.api.core import TLObject from .exceptions.all import exceptions diff --git a/pyrogram/session/auth.py b/pyrogram/session/auth.py index b05b2855..f6d137fa 100644 --- a/pyrogram/session/auth.py +++ b/pyrogram/session/auth.py @@ -27,7 +27,6 @@ from pyrogram.api import functions, types from pyrogram.api.core import TLObject, Long, Int from pyrogram.connection import Connection from pyrogram.crypto import AES, RSA, Prime - from .internals import MsgId log = logging.getLogger(__name__) diff --git a/pyrogram/session/internals/msg_factory.py b/pyrogram/session/internals/msg_factory.py index 2b833ce8..453eefc1 100644 --- a/pyrogram/session/internals/msg_factory.py +++ b/pyrogram/session/internals/msg_factory.py @@ -16,9 +16,10 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api.core import Message, MsgContainer, TLObject from pyrogram.api.functions import Ping from pyrogram.api.types import MsgsAck, HttpWait + +from pyrogram.api.core import Message, MsgContainer, TLObject from .msg_id import MsgId from .seq_no import SeqNo diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index 21e2ba10..689fe584 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -26,15 +26,15 @@ from os import urandom from queue import Queue from threading import Event, Thread +from pyrogram.api.all import layer + import pyrogram from pyrogram import __copyright__, __license__, __version__ from pyrogram.api import functions, types, core -from pyrogram.api.all import layer from pyrogram.api.core import Message, TLObject, MsgContainer, Long, FutureSalt, Int from pyrogram.connection import Connection from pyrogram.crypto import AES, KDF from pyrogram.errors import RPCError, InternalServerError, AuthKeyDuplicated - from .internals import MsgId, MsgFactory log = logging.getLogger(__name__) From 67112a34e92c2265f9aed555b9299fb594cd0869 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Fri, 2 Aug 2019 00:33:48 +0200 Subject: [PATCH 47/55] Remove __slots__ from Pyrogram types --- .../client/types/bots_and_keyboards/callback_game.py | 2 -- .../client/types/bots_and_keyboards/callback_query.py | 2 -- .../client/types/bots_and_keyboards/force_reply.py | 2 -- .../types/bots_and_keyboards/game_high_score.py | 2 -- .../bots_and_keyboards/inline_keyboard_button.py | 4 ---- .../bots_and_keyboards/inline_keyboard_markup.py | 2 -- .../types/bots_and_keyboards/keyboard_button.py | 2 -- .../types/bots_and_keyboards/reply_keyboard_markup.py | 2 -- .../types/bots_and_keyboards/reply_keyboard_remove.py | 2 -- pyrogram/client/types/inline_mode/inline_query.py | 1 - .../client/types/inline_mode/inline_query_result.py | 2 -- .../inline_mode/inline_query_result_animation.py | 5 ----- .../types/inline_mode/inline_query_result_article.py | 2 -- .../types/inline_mode/inline_query_result_photo.py | 5 ----- pyrogram/client/types/input_media/input_media.py | 1 - .../client/types/input_media/input_media_animation.py | 2 -- .../client/types/input_media/input_media_audio.py | 2 -- .../client/types/input_media/input_media_document.py | 2 -- .../client/types/input_media/input_media_photo.py | 2 -- .../client/types/input_media/input_media_video.py | 2 -- .../client/types/input_media/input_phone_contact.py | 2 -- .../input_message_content/input_message_content.py | 2 -- .../input_text_message_content.py | 2 -- pyrogram/client/types/messages_and_media/animation.py | 2 -- pyrogram/client/types/messages_and_media/audio.py | 4 ---- pyrogram/client/types/messages_and_media/contact.py | 2 -- pyrogram/client/types/messages_and_media/document.py | 2 -- pyrogram/client/types/messages_and_media/game.py | 2 -- pyrogram/client/types/messages_and_media/location.py | 2 -- pyrogram/client/types/messages_and_media/message.py | 11 ----------- .../client/types/messages_and_media/message_entity.py | 2 -- pyrogram/client/types/messages_and_media/photo.py | 2 -- pyrogram/client/types/messages_and_media/poll.py | 2 -- .../client/types/messages_and_media/poll_option.py | 2 -- pyrogram/client/types/messages_and_media/sticker.py | 4 ---- .../types/messages_and_media/stripped_thumbnail.py | 2 -- pyrogram/client/types/messages_and_media/thumbnail.py | 2 -- pyrogram/client/types/messages_and_media/venue.py | 2 -- pyrogram/client/types/messages_and_media/video.py | 5 ----- .../client/types/messages_and_media/video_note.py | 2 -- pyrogram/client/types/messages_and_media/voice.py | 2 -- pyrogram/client/types/messages_and_media/webpage.py | 6 ------ pyrogram/client/types/object.py | 8 +++----- pyrogram/client/types/update.py | 2 -- pyrogram/client/types/user_and_chats/chat.py | 6 ------ pyrogram/client/types/user_and_chats/chat_member.py | 2 -- .../client/types/user_and_chats/chat_permissions.py | 7 ------- pyrogram/client/types/user_and_chats/chat_photo.py | 2 -- pyrogram/client/types/user_and_chats/chat_preview.py | 2 -- pyrogram/client/types/user_and_chats/dialog.py | 2 -- pyrogram/client/types/user_and_chats/user.py | 6 ------ 51 files changed, 3 insertions(+), 144 deletions(-) diff --git a/pyrogram/client/types/bots_and_keyboards/callback_game.py b/pyrogram/client/types/bots_and_keyboards/callback_game.py index acf6df60..338cfb06 100644 --- a/pyrogram/client/types/bots_and_keyboards/callback_game.py +++ b/pyrogram/client/types/bots_and_keyboards/callback_game.py @@ -25,7 +25,5 @@ class CallbackGame(Object): Use BotFather to set up your game. """ - __slots__ = [] - def __init__(self): super().__init__() diff --git a/pyrogram/client/types/bots_and_keyboards/callback_query.py b/pyrogram/client/types/bots_and_keyboards/callback_query.py index 9ba1804b..9a5674ae 100644 --- a/pyrogram/client/types/bots_and_keyboards/callback_query.py +++ b/pyrogram/client/types/bots_and_keyboards/callback_query.py @@ -61,8 +61,6 @@ class CallbackQuery(Object, Update): """ - __slots__ = ["id", "from_user", "chat_instance", "message", "inline_message_id", "data", "game_short_name"] - def __init__( self, *, diff --git a/pyrogram/client/types/bots_and_keyboards/force_reply.py b/pyrogram/client/types/bots_and_keyboards/force_reply.py index 6c542aa8..ef5c0ccb 100644 --- a/pyrogram/client/types/bots_and_keyboards/force_reply.py +++ b/pyrogram/client/types/bots_and_keyboards/force_reply.py @@ -37,8 +37,6 @@ class ForceReply(Object): 2) if the bot's message is a reply (has reply_to_message_id), sender of the original message. """ - __slots__ = ["selective"] - def __init__( self, selective: bool = None diff --git a/pyrogram/client/types/bots_and_keyboards/game_high_score.py b/pyrogram/client/types/bots_and_keyboards/game_high_score.py index 5d576ad4..38e2242a 100644 --- a/pyrogram/client/types/bots_and_keyboards/game_high_score.py +++ b/pyrogram/client/types/bots_and_keyboards/game_high_score.py @@ -37,8 +37,6 @@ class GameHighScore(Object): Position in high score table for the game. """ - __slots__ = ["user", "score", "position"] - def __init__( self, *, diff --git a/pyrogram/client/types/bots_and_keyboards/inline_keyboard_button.py b/pyrogram/client/types/bots_and_keyboards/inline_keyboard_button.py index 514b0303..678be614 100644 --- a/pyrogram/client/types/bots_and_keyboards/inline_keyboard_button.py +++ b/pyrogram/client/types/bots_and_keyboards/inline_keyboard_button.py @@ -59,10 +59,6 @@ class InlineKeyboardButton(Object): # TODO: Add callback_game and pay fields - __slots__ = [ - "text", "url", "callback_data", "switch_inline_query", "switch_inline_query_current_chat", "callback_game" - ] - def __init__( self, text: str, diff --git a/pyrogram/client/types/bots_and_keyboards/inline_keyboard_markup.py b/pyrogram/client/types/bots_and_keyboards/inline_keyboard_markup.py index bdca85d1..811c4365 100644 --- a/pyrogram/client/types/bots_and_keyboards/inline_keyboard_markup.py +++ b/pyrogram/client/types/bots_and_keyboards/inline_keyboard_markup.py @@ -32,8 +32,6 @@ class InlineKeyboardMarkup(Object): List of button rows, each represented by a List of InlineKeyboardButton objects. """ - __slots__ = ["inline_keyboard"] - def __init__( self, inline_keyboard: List[List[InlineKeyboardButton]] diff --git a/pyrogram/client/types/bots_and_keyboards/keyboard_button.py b/pyrogram/client/types/bots_and_keyboards/keyboard_button.py index 8374db1b..21c03613 100644 --- a/pyrogram/client/types/bots_and_keyboards/keyboard_button.py +++ b/pyrogram/client/types/bots_and_keyboards/keyboard_button.py @@ -41,8 +41,6 @@ class KeyboardButton(Object): Available in private chats only. """ - __slots__ = ["text", "request_contact", "request_location"] - def __init__( self, text: str, diff --git a/pyrogram/client/types/bots_and_keyboards/reply_keyboard_markup.py b/pyrogram/client/types/bots_and_keyboards/reply_keyboard_markup.py index f958051b..12799bd7 100644 --- a/pyrogram/client/types/bots_and_keyboards/reply_keyboard_markup.py +++ b/pyrogram/client/types/bots_and_keyboards/reply_keyboard_markup.py @@ -50,8 +50,6 @@ class ReplyKeyboardMarkup(Object): select the new language. Other users in the group don't see the keyboard. """ - __slots__ = ["keyboard", "resize_keyboard", "one_time_keyboard", "selective"] - def __init__( self, keyboard: List[List[Union[KeyboardButton, str]]], diff --git a/pyrogram/client/types/bots_and_keyboards/reply_keyboard_remove.py b/pyrogram/client/types/bots_and_keyboards/reply_keyboard_remove.py index d451a8e8..1623c9bd 100644 --- a/pyrogram/client/types/bots_and_keyboards/reply_keyboard_remove.py +++ b/pyrogram/client/types/bots_and_keyboards/reply_keyboard_remove.py @@ -38,8 +38,6 @@ class ReplyKeyboardRemove(Object): keyboard for that user, while still showing the keyboard with poll options to users who haven't voted yet. """ - __slots__ = ["selective"] - def __init__( self, selective: bool = None diff --git a/pyrogram/client/types/inline_mode/inline_query.py b/pyrogram/client/types/inline_mode/inline_query.py index 065c4492..27b73ff4 100644 --- a/pyrogram/client/types/inline_mode/inline_query.py +++ b/pyrogram/client/types/inline_mode/inline_query.py @@ -48,7 +48,6 @@ class InlineQuery(Object, Update): location (:obj:`Location`. *optional*): Sender location, only for bots that request user location. """ - __slots__ = ["id", "from_user", "query", "offset", "location"] def __init__( self, diff --git a/pyrogram/client/types/inline_mode/inline_query_result.py b/pyrogram/client/types/inline_mode/inline_query_result.py index 1ff3e5e1..ef26eacc 100644 --- a/pyrogram/client/types/inline_mode/inline_query_result.py +++ b/pyrogram/client/types/inline_mode/inline_query_result.py @@ -53,8 +53,6 @@ class InlineQueryResult(Object): - :obj:`InlineQueryResultAnimation` """ - __slots__ = ["type", "id", "input_message_content", "reply_markup"] - def __init__( self, type: str, diff --git a/pyrogram/client/types/inline_mode/inline_query_result_animation.py b/pyrogram/client/types/inline_mode/inline_query_result_animation.py index 4d2d5596..c4cb26e4 100644 --- a/pyrogram/client/types/inline_mode/inline_query_result_animation.py +++ b/pyrogram/client/types/inline_mode/inline_query_result_animation.py @@ -68,11 +68,6 @@ class InlineQueryResultAnimation(InlineQueryResult): Content of the message to be sent instead of the photo. """ - __slots__ = [ - "animation_url", "thumb_url", "title", "description", "caption", "parse_mode", "reply_markup", - "input_message_content" - ] - def __init__( self, animation_url: str, diff --git a/pyrogram/client/types/inline_mode/inline_query_result_article.py b/pyrogram/client/types/inline_mode/inline_query_result_article.py index c21416f5..735a1e02 100644 --- a/pyrogram/client/types/inline_mode/inline_query_result_article.py +++ b/pyrogram/client/types/inline_mode/inline_query_result_article.py @@ -49,8 +49,6 @@ class InlineQueryResultArticle(InlineQueryResult): Inline keyboard attached to the message. """ - __slots__ = ["title", "url", "description", "thumb_url"] - def __init__( self, title: str, diff --git a/pyrogram/client/types/inline_mode/inline_query_result_photo.py b/pyrogram/client/types/inline_mode/inline_query_result_photo.py index 3442764e..ffcc21c0 100644 --- a/pyrogram/client/types/inline_mode/inline_query_result_photo.py +++ b/pyrogram/client/types/inline_mode/inline_query_result_photo.py @@ -68,11 +68,6 @@ class InlineQueryResultPhoto(InlineQueryResult): Content of the message to be sent instead of the photo. """ - __slots__ = [ - "photo_url", "thumb_url", "title", "description", "caption", "parse_mode", "reply_markup", - "input_message_content" - ] - def __init__( self, photo_url: str, diff --git a/pyrogram/client/types/input_media/input_media.py b/pyrogram/client/types/input_media/input_media.py index 2b5d7f0f..9b89fe12 100644 --- a/pyrogram/client/types/input_media/input_media.py +++ b/pyrogram/client/types/input_media/input_media.py @@ -30,7 +30,6 @@ class InputMedia(Object): - :obj:`InputMediaPhoto` - :obj:`InputMediaVideo` """ - __slots__ = ["media", "caption", "parse_mode"] def __init__(self, media: str, caption: str, parse_mode: str): super().__init__() diff --git a/pyrogram/client/types/input_media/input_media_animation.py b/pyrogram/client/types/input_media/input_media_animation.py index d6c67d56..dc70cbec 100644 --- a/pyrogram/client/types/input_media/input_media_animation.py +++ b/pyrogram/client/types/input_media/input_media_animation.py @@ -56,8 +56,6 @@ class InputMediaAnimation(InputMedia): Animation duration. """ - __slots__ = ["thumb", "width", "height", "duration"] - def __init__( self, media: str, diff --git a/pyrogram/client/types/input_media/input_media_audio.py b/pyrogram/client/types/input_media/input_media_audio.py index f01444a8..5ed670a6 100644 --- a/pyrogram/client/types/input_media/input_media_audio.py +++ b/pyrogram/client/types/input_media/input_media_audio.py @@ -58,8 +58,6 @@ class InputMediaAudio(InputMedia): Title of the audio """ - __slots__ = ["thumb", "duration", "performer", "title"] - def __init__( self, media: str, diff --git a/pyrogram/client/types/input_media/input_media_document.py b/pyrogram/client/types/input_media/input_media_document.py index af549c81..14756e02 100644 --- a/pyrogram/client/types/input_media/input_media_document.py +++ b/pyrogram/client/types/input_media/input_media_document.py @@ -47,8 +47,6 @@ class InputMediaDocument(InputMedia): Pass None to completely disable style parsing. """ - __slots__ = ["thumb"] - def __init__( self, media: str, diff --git a/pyrogram/client/types/input_media/input_media_photo.py b/pyrogram/client/types/input_media/input_media_photo.py index 30c53777..5e18cdd6 100644 --- a/pyrogram/client/types/input_media/input_media_photo.py +++ b/pyrogram/client/types/input_media/input_media_photo.py @@ -43,8 +43,6 @@ class InputMediaPhoto(InputMedia): Pass None to completely disable style parsing. """ - __slots__ = [] - def __init__( self, media: str, diff --git a/pyrogram/client/types/input_media/input_media_video.py b/pyrogram/client/types/input_media/input_media_video.py index 3500ff55..6b64caa8 100644 --- a/pyrogram/client/types/input_media/input_media_video.py +++ b/pyrogram/client/types/input_media/input_media_video.py @@ -61,8 +61,6 @@ class InputMediaVideo(InputMedia): Pass True, if the uploaded video is suitable for streaming. """ - __slots__ = ["thumb", "width", "height", "duration", "supports_streaming"] - def __init__( self, media: str, diff --git a/pyrogram/client/types/input_media/input_phone_contact.py b/pyrogram/client/types/input_media/input_phone_contact.py index 9c03694d..7498768d 100644 --- a/pyrogram/client/types/input_media/input_phone_contact.py +++ b/pyrogram/client/types/input_media/input_phone_contact.py @@ -37,8 +37,6 @@ class InputPhoneContact(Object): Contact's last name """ - __slots__ = [] - def __init__(self, phone: str, first_name: str, last_name: str = ""): super().__init__(None) diff --git a/pyrogram/client/types/input_message_content/input_message_content.py b/pyrogram/client/types/input_message_content/input_message_content.py index b02c6b38..6561b5a8 100644 --- a/pyrogram/client/types/input_message_content/input_message_content.py +++ b/pyrogram/client/types/input_message_content/input_message_content.py @@ -31,8 +31,6 @@ class InputMessageContent(Object): - :obj:`InputTextMessageContent` """ - __slots__ = [] - def __init__(self): super().__init__() diff --git a/pyrogram/client/types/input_message_content/input_text_message_content.py b/pyrogram/client/types/input_message_content/input_text_message_content.py index f90b7096..3ab67d96 100644 --- a/pyrogram/client/types/input_message_content/input_text_message_content.py +++ b/pyrogram/client/types/input_message_content/input_text_message_content.py @@ -41,8 +41,6 @@ class InputTextMessageContent(InputMessageContent): Disables link previews for links in this message. """ - __slots__ = ["message_text", "parse_mode", "disable_web_page_preview"] - def __init__(self, message_text: str, parse_mode: Union[str, None] = object, disable_web_page_preview: bool = None): super().__init__() diff --git a/pyrogram/client/types/messages_and_media/animation.py b/pyrogram/client/types/messages_and_media/animation.py index 5441a114..ba6744ce 100644 --- a/pyrogram/client/types/messages_and_media/animation.py +++ b/pyrogram/client/types/messages_and_media/animation.py @@ -58,8 +58,6 @@ class Animation(Object): Animation thumbnails. """ - __slots__ = ["file_id", "file_name", "mime_type", "file_size", "date", "width", "height", "duration", "thumbs"] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/audio.py b/pyrogram/client/types/messages_and_media/audio.py index 3d9cf8a6..6d8a12e9 100644 --- a/pyrogram/client/types/messages_and_media/audio.py +++ b/pyrogram/client/types/messages_and_media/audio.py @@ -58,10 +58,6 @@ class Audio(Object): Thumbnails of the music file album cover. """ - __slots__ = [ - "file_id", "file_name", "mime_type", "file_size", "date", "duration", "performer", "title", "thumbs" - ] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/contact.py b/pyrogram/client/types/messages_and_media/contact.py index d18f5e18..ad263397 100644 --- a/pyrogram/client/types/messages_and_media/contact.py +++ b/pyrogram/client/types/messages_and_media/contact.py @@ -42,8 +42,6 @@ class Contact(Object): Additional data about the contact in the form of a vCard. """ - __slots__ = ["phone_number", "first_name", "last_name", "user_id", "vcard"] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/document.py b/pyrogram/client/types/messages_and_media/document.py index 45994e16..4bb40980 100644 --- a/pyrogram/client/types/messages_and_media/document.py +++ b/pyrogram/client/types/messages_and_media/document.py @@ -49,8 +49,6 @@ class Document(Object): Document thumbnails as defined by sender. """ - __slots__ = ["file_id", "file_name", "mime_type", "file_size", "date", "thumbs"] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/game.py b/pyrogram/client/types/messages_and_media/game.py index 2b400e65..38c00fdf 100644 --- a/pyrogram/client/types/messages_and_media/game.py +++ b/pyrogram/client/types/messages_and_media/game.py @@ -48,8 +48,6 @@ class Game(Object): Upload via BotFather. """ - __slots__ = ["id", "title", "short_name", "description", "photo", "animation"] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/location.py b/pyrogram/client/types/messages_and_media/location.py index 5af55f0f..4dec0277 100644 --- a/pyrogram/client/types/messages_and_media/location.py +++ b/pyrogram/client/types/messages_and_media/location.py @@ -33,8 +33,6 @@ class Location(Object): Latitude as defined by sender. """ - __slots__ = ["longitude", "latitude"] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index ed0088cd..7616a6ec 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.py @@ -264,17 +264,6 @@ class Message(Object, Update): # TODO: Add game missing field. Also invoice, successful_payment, connected_website - __slots__ = [ - "message_id", "date", "chat", "from_user", "forward_from", "forward_sender_name", "forward_from_chat", - "forward_from_message_id", "forward_signature", "forward_date", "reply_to_message", "mentioned", "empty", - "service", "media", "edit_date", "media_group_id", "author_signature", "text", "entities", "caption_entities", - "audio", "document", "photo", "sticker", "animation", "game", "video", "voice", "video_note", "caption", - "contact", "location", "venue", "web_page", "poll", "new_chat_members", "left_chat_member", "new_chat_title", - "new_chat_photo", "delete_chat_photo", "group_chat_created", "supergroup_chat_created", "channel_chat_created", - "migrate_to_chat_id", "migrate_from_chat_id", "pinned_message", "game_high_score", "views", "via_bot", - "outgoing", "matches", "command", "reply_markup" - ] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/message_entity.py b/pyrogram/client/types/messages_and_media/message_entity.py index 1c3076a2..63aeb447 100644 --- a/pyrogram/client/types/messages_and_media/message_entity.py +++ b/pyrogram/client/types/messages_and_media/message_entity.py @@ -47,8 +47,6 @@ class MessageEntity(Object): For "text_mention" only, the mentioned user. """ - __slots__ = ["type", "offset", "length", "url", "user"] - ENTITIES = { types.MessageEntityMention.ID: "mention", types.MessageEntityHashtag.ID: "hashtag", diff --git a/pyrogram/client/types/messages_and_media/photo.py b/pyrogram/client/types/messages_and_media/photo.py index 653fe4c0..8ccaaf19 100644 --- a/pyrogram/client/types/messages_and_media/photo.py +++ b/pyrogram/client/types/messages_and_media/photo.py @@ -49,8 +49,6 @@ class Photo(Object): Available thumbnails of this photo. """ - __slots__ = ["file_id", "width", "height", "file_size", "date", "thumbs"] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/poll.py b/pyrogram/client/types/messages_and_media/poll.py index 2570fdf1..fecc5f7d 100644 --- a/pyrogram/client/types/messages_and_media/poll.py +++ b/pyrogram/client/types/messages_and_media/poll.py @@ -48,8 +48,6 @@ class Poll(Object, Update): Index of your chosen option (0-9), None in case you haven't voted yet. """ - __slots__ = ["id", "question", "options", "is_closed", "total_voters", "chosen_option"] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/poll_option.py b/pyrogram/client/types/messages_and_media/poll_option.py index 35f6b071..2882860a 100644 --- a/pyrogram/client/types/messages_and_media/poll_option.py +++ b/pyrogram/client/types/messages_and_media/poll_option.py @@ -35,8 +35,6 @@ class PollOption(Object): The data this poll option is holding. """ - __slots__ = ["text", "voter_count", "data"] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/sticker.py b/pyrogram/client/types/messages_and_media/sticker.py index 78fdda38..2fc5caa1 100644 --- a/pyrogram/client/types/messages_and_media/sticker.py +++ b/pyrogram/client/types/messages_and_media/sticker.py @@ -65,10 +65,6 @@ class Sticker(Object): # TODO: Add mask position - __slots__ = [ - "file_id", "file_name", "mime_type", "file_size", "date", "width", "height", "emoji", "set_name", "thumbs" - ] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/stripped_thumbnail.py b/pyrogram/client/types/messages_and_media/stripped_thumbnail.py index 1c967042..ea24e071 100644 --- a/pyrogram/client/types/messages_and_media/stripped_thumbnail.py +++ b/pyrogram/client/types/messages_and_media/stripped_thumbnail.py @@ -29,8 +29,6 @@ class StrippedThumbnail(Object): Thumbnail data """ - __slots__ = ["data"] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/thumbnail.py b/pyrogram/client/types/messages_and_media/thumbnail.py index ee173b1c..936241c6 100644 --- a/pyrogram/client/types/messages_and_media/thumbnail.py +++ b/pyrogram/client/types/messages_and_media/thumbnail.py @@ -43,8 +43,6 @@ class Thumbnail(Object): File size. """ - __slots__ = ["file_id", "width", "height", "file_size"] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/venue.py b/pyrogram/client/types/messages_and_media/venue.py index 45d9368f..419af318 100644 --- a/pyrogram/client/types/messages_and_media/venue.py +++ b/pyrogram/client/types/messages_and_media/venue.py @@ -44,8 +44,6 @@ class Venue(Object): """ - __slots__ = ["location", "title", "address", "foursquare_id", "foursquare_type"] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/video.py b/pyrogram/client/types/messages_and_media/video.py index 0a7f47cd..d9c2c37f 100644 --- a/pyrogram/client/types/messages_and_media/video.py +++ b/pyrogram/client/types/messages_and_media/video.py @@ -61,11 +61,6 @@ class Video(Object): Video thumbnails. """ - __slots__ = [ - "file_id", "width", "height", "duration", "file_name", "mime_type", "supports_streaming", "file_size", "date", - "thumbs" - ] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/video_note.py b/pyrogram/client/types/messages_and_media/video_note.py index 54c9ec8d..e419d692 100644 --- a/pyrogram/client/types/messages_and_media/video_note.py +++ b/pyrogram/client/types/messages_and_media/video_note.py @@ -52,8 +52,6 @@ class VideoNote(Object): Video thumbnails. """ - __slots__ = ["file_id", "mime_type", "file_size", "date", "length", "duration", "thumbs"] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/voice.py b/pyrogram/client/types/messages_and_media/voice.py index e4256197..0f480ad5 100644 --- a/pyrogram/client/types/messages_and_media/voice.py +++ b/pyrogram/client/types/messages_and_media/voice.py @@ -47,8 +47,6 @@ class Voice(Object): Date the voice was sent in Unix time. """ - __slots__ = ["file_id", "duration", "waveform", "mime_type", "file_size", "date"] - def __init__( self, *, diff --git a/pyrogram/client/types/messages_and_media/webpage.py b/pyrogram/client/types/messages_and_media/webpage.py index 9ddc7c6c..d65d34d8 100644 --- a/pyrogram/client/types/messages_and_media/webpage.py +++ b/pyrogram/client/types/messages_and_media/webpage.py @@ -83,12 +83,6 @@ class WebPage(Object): Author of the webpage, eg the Twitter user for a tweet, or the author in an article. """ - __slots__ = [ - "id", "url", "display_url", "type", "site_name", "title", "description", - "audio", "document", "photo", "animation", "video", - "embed_url", "embed_type", "embed_width", "embed_height", "duration", "author" - ] - def __init__( self, *, diff --git a/pyrogram/client/types/object.py b/pyrogram/client/types/object.py index f7fc413f..5978203f 100644 --- a/pyrogram/client/types/object.py +++ b/pyrogram/client/types/object.py @@ -29,8 +29,6 @@ class Meta(type, metaclass=type("", (type,), {"__str__": lambda _: "~hi"})): class Object(metaclass=Meta): - __slots__ = ["_client"] - def __init__(self, client: "pyrogram.BaseClient" = None): self._client = client @@ -50,7 +48,7 @@ class Object(metaclass=Meta): else (attr, str(datetime.fromtimestamp(getattr(obj, attr)))) if attr.endswith("date") else (attr, getattr(obj, attr)) - for attr in getattr(obj, "__slots__", []) + for attr in filter(lambda x: not x.startswith("_"), obj.__dict__) if getattr(obj, attr) is not None ] ) @@ -63,13 +61,13 @@ class Object(metaclass=Meta): self.__class__.__name__, ", ".join( "{}={}".format(attr, repr(getattr(self, attr))) - for attr in self.__slots__ + for attr in filter(lambda x: not x.startswith("_"), self.__dict__) if getattr(self, attr) is not None ) ) def __eq__(self, other: "Object") -> bool: - for attr in self.__slots__: + for attr in self.__dict__: try: if getattr(self, attr) != getattr(other, attr): return False diff --git a/pyrogram/client/types/update.py b/pyrogram/client/types/update.py index 48179ac0..2ec22f5a 100644 --- a/pyrogram/client/types/update.py +++ b/pyrogram/client/types/update.py @@ -26,8 +26,6 @@ class ContinuePropagation(StopIteration): class Update: - __slots__ = [] - def stop_propagation(self): raise StopPropagation diff --git a/pyrogram/client/types/user_and_chats/chat.py b/pyrogram/client/types/user_and_chats/chat.py index 396831cc..cfed441f 100644 --- a/pyrogram/client/types/user_and_chats/chat.py +++ b/pyrogram/client/types/user_and_chats/chat.py @@ -95,12 +95,6 @@ class Chat(Object): Information about the chat default permissions, for groups and supergroups. """ - __slots__ = [ - "id", "type", "is_verified", "is_restricted", "is_scam", "is_support", "title", "username", "first_name", - "last_name", "photo", "description", "invite_link", "pinned_message", "sticker_set_name", "can_set_sticker_set", - "members_count", "restriction_reason", "permissions" - ] - def __init__( self, *, diff --git a/pyrogram/client/types/user_and_chats/chat_member.py b/pyrogram/client/types/user_and_chats/chat_member.py index 7451012c..42eb08f3 100644 --- a/pyrogram/client/types/user_and_chats/chat_member.py +++ b/pyrogram/client/types/user_and_chats/chat_member.py @@ -54,8 +54,6 @@ class ChatMember(Object): Information about the member permissions. """ - __slots__ = ["user", "status", "date", "is_member", "invited_by", "promoted_by", "restricted_by", "permissions"] - def __init__( self, *, diff --git a/pyrogram/client/types/user_and_chats/chat_permissions.py b/pyrogram/client/types/user_and_chats/chat_permissions.py index 84099955..551dc667 100644 --- a/pyrogram/client/types/user_and_chats/chat_permissions.py +++ b/pyrogram/client/types/user_and_chats/chat_permissions.py @@ -94,13 +94,6 @@ class ChatPermissions(Object): True, if polls can be sent, implies can_send_media_messages. """ - __slots__ = [ - "until_date", "can_be_edited", "can_change_info", "can_post_messages", "can_edit_messages", - "can_delete_messages", "can_restrict_members", "can_invite_users", "can_pin_messages", "can_promote_members", - "can_send_messages", "can_send_media_messages", "can_send_other_messages", "can_add_web_page_previews", - "can_send_polls" - ] - def __init__( self, *, diff --git a/pyrogram/client/types/user_and_chats/chat_photo.py b/pyrogram/client/types/user_and_chats/chat_photo.py index 1584a286..70e114af 100644 --- a/pyrogram/client/types/user_and_chats/chat_photo.py +++ b/pyrogram/client/types/user_and_chats/chat_photo.py @@ -35,8 +35,6 @@ class ChatPhoto(Object): Unique file identifier of big (640x640) chat photo. This file_id can be used only for photo download. """ - __slots__ = ["small_file_id", "big_file_id"] - def __init__( self, *, diff --git a/pyrogram/client/types/user_and_chats/chat_preview.py b/pyrogram/client/types/user_and_chats/chat_preview.py index 781f85c8..10754170 100644 --- a/pyrogram/client/types/user_and_chats/chat_preview.py +++ b/pyrogram/client/types/user_and_chats/chat_preview.py @@ -45,8 +45,6 @@ class ChatPreview(Object): Preview of some of the chat members. """ - __slots__ = ["title", "type", "members_count", "photo", "members"] - def __init__( self, *, diff --git a/pyrogram/client/types/user_and_chats/dialog.py b/pyrogram/client/types/user_and_chats/dialog.py index a78e501b..471c4319 100644 --- a/pyrogram/client/types/user_and_chats/dialog.py +++ b/pyrogram/client/types/user_and_chats/dialog.py @@ -47,8 +47,6 @@ class Dialog(Object): True, if the dialog is pinned. """ - __slots__ = ["chat", "top_message", "unread_messages_count", "unread_mentions_count", "unread_mark", "is_pinned"] - def __init__( self, *, diff --git a/pyrogram/client/types/user_and_chats/user.py b/pyrogram/client/types/user_and_chats/user.py index 43baca25..783c0566 100644 --- a/pyrogram/client/types/user_and_chats/user.py +++ b/pyrogram/client/types/user_and_chats/user.py @@ -106,12 +106,6 @@ class User(Object, Update): This field is available only in case *is_restricted* is True. """ - __slots__ = [ - "id", "is_self", "is_contact", "is_mutual_contact", "is_deleted", "is_bot", "is_verified", "is_restricted", - "is_scam", "is_support", "first_name", "last_name", "status", "last_online_date", "next_offline_date", - "username", "language_code", "dc_id", "phone_number", "photo", "restriction_reason" - ] - def __init__( self, *, From 64939e52892a860173c83fea7b28ec81833518b3 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Fri, 2 Aug 2019 01:15:01 +0200 Subject: [PATCH 48/55] Update Document file ids to make them compatible again with the Bot API Telegram changed something server side on 29 July, 2019 starting exactly at 04:00 AM UTC+1 (DST), logs say. Looks like Document file ids, just like Photo-like ids, are going to change as well after all, if we want to keep them compatible with the Bot API --- pyrogram/client/ext/utils.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py index fbee9ea8..cdc0684c 100644 --- a/pyrogram/client/ext/utils.py +++ b/pyrogram/client/ext/utils.py @@ -21,9 +21,8 @@ import struct from typing import List from typing import Union -from pyrogram.api.types import PeerUser, PeerChat, PeerChannel - import pyrogram +from pyrogram.api.types import PeerUser, PeerChat, PeerChannel from . import BaseClient from ...api import types @@ -32,10 +31,17 @@ def decode(s: str) -> bytes: s = base64.urlsafe_b64decode(s + "=" * (-len(s) % 4)) r = b"" - assert s[-1] == 2 + try: + assert s[-1] == 2 + skip = 1 + except AssertionError: + assert s[-2] == 22 + assert s[-1] == 4 + skip = 2 i = 0 - while i < len(s) - 1: + + while i < len(s) - skip: if s[i] != 0: r += bytes([s[i]]) else: @@ -51,7 +57,7 @@ def encode(s: bytes) -> str: r = b"" n = 0 - for i in s + bytes([2]): + for i in s + bytes([22]) + bytes([4]): if i == 0: n += 1 else: From 091552e5d9db4161c48d19523c68c94725c7ee69 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sat, 3 Aug 2019 18:05:57 +0200 Subject: [PATCH 49/55] [Bot API 4.4] Update stickers - Add is_animated field to Sticker - Remove send_animated_sticker (use send_sticker instead) - Default to 512x512 in case size is unknown (instead of 0x0) --- compiler/docs/compiler.py | 1 - pyrogram/client/methods/messages/__init__.py | 2 - .../methods/messages/send_animated_sticker.py | 144 ------------------ .../client/methods/messages/send_sticker.py | 2 +- .../types/messages_and_media/sticker.py | 10 +- 5 files changed, 9 insertions(+), 150 deletions(-) delete mode 100644 pyrogram/client/methods/messages/send_animated_sticker.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index cb3ad5a2..32674887 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -146,7 +146,6 @@ def pyrogram_api(): send_audio send_document send_sticker - send_animated_sticker send_video send_animation send_voice diff --git a/pyrogram/client/methods/messages/__init__.py b/pyrogram/client/methods/messages/__init__.py index aa0b0c94..6237b47c 100644 --- a/pyrogram/client/methods/messages/__init__.py +++ b/pyrogram/client/methods/messages/__init__.py @@ -33,7 +33,6 @@ from .get_messages import GetMessages from .iter_history import IterHistory from .read_history import ReadHistory from .retract_vote import RetractVote -from .send_animated_sticker import SendAnimatedSticker from .send_animation import SendAnimation from .send_audio import SendAudio from .send_cached_media import SendCachedMedia @@ -85,7 +84,6 @@ class Messages( IterHistory, SendCachedMedia, GetHistoryCount, - SendAnimatedSticker, ReadHistory, EditInlineText, EditInlineCaption, diff --git a/pyrogram/client/methods/messages/send_animated_sticker.py b/pyrogram/client/methods/messages/send_animated_sticker.py deleted file mode 100644 index 8e57c527..00000000 --- a/pyrogram/client/methods/messages/send_animated_sticker.py +++ /dev/null @@ -1,144 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-2019 Dan Tès -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -import os -from typing import Union - -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient, utils -from pyrogram.errors import FilePartMissing - - -class SendAnimatedSticker(BaseClient): - def send_animated_sticker( - self, - chat_id: Union[int, str], - animated_sticker: str, - disable_notification: bool = None, - reply_to_message_id: int = None, - reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" - ] = None, - progress: callable = None, - progress_args: tuple = () - ) -> Union["pyrogram.Message", None]: - """Send .tgs animated stickers. - - Parameters: - chat_id (``int`` | ``str``): - Unique identifier (int) or username (str) of the target chat. - For your personal cloud (Saved Messages) you can simply use "me" or "self". - For a contact that exists in your Telegram address book you can use his phone number (str). - - animated_sticker (``str``): - Animated sticker to send. - Pass a file_id as string to send a animated sticker that exists on the Telegram servers, - pass an HTTP URL as a string for Telegram to get a .webp animated sticker file from the Internet, or - pass a file path as string to upload a new animated sticker that exists on your local machine. - - disable_notification (``bool``, *optional*): - Sends the message silently. - Users will receive a notification with no sound. - - reply_to_message_id (``int``, *optional*): - If the message is a reply, ID of the original message. - - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): - Additional interface options. An object for an inline keyboard, custom reply keyboard, - instructions to remove reply keyboard or to force a reply from the user. - - progress (``callable``, *optional*): - Pass a callback function to view the file transmission progress. - The function must take *(current, total)* as positional arguments (look at Other Parameters below for a - detailed description) and will be called back each time a new file chunk has been successfully - transmitted. - - progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. - You can pass anything you need to be available in the progress callback scope; for example, a Message - object or a Client instance in order to edit the message with the updated progress status. - - Other Parameters: - current (``int``): - The amount of bytes transmitted so far. - - total (``int``): - The total size of the file. - - *args (``tuple``, *optional*): - Extra custom arguments as defined in the *progress_args* parameter. - You can either keep *\*args* or add every single extra argument in your function signature. - - Returns: - :obj:`Message` | ``None``: On success, the sent animated sticker message is returned, otherwise, in case the - upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. - - Example: - .. code-block:: python - - # Send animated sticker by uploading from local file - app.send_animated_sticker("me", "animated_sticker.tgs") - """ - file = None - - try: - if os.path.exists(animated_sticker): - file = self.save_file(animated_sticker, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( - mime_type=self.guess_mime_type(animated_sticker) or "application/x-tgsticker", - file=file, - attributes=[ - types.DocumentAttributeFilename(file_name=os.path.basename(animated_sticker)) - ] - ) - elif animated_sticker.startswith("http"): - media = types.InputMediaDocumentExternal( - url=animated_sticker - ) - else: - media = utils.get_input_media_from_file_id(animated_sticker, 5) - - while True: - try: - r = self.send( - functions.messages.SendMedia( - peer=self.resolve_peer(chat_id), - media=media, - silent=disable_notification or None, - reply_to_msg_id=reply_to_message_id, - random_id=self.rnd_id(), - reply_markup=reply_markup.write() if reply_markup else None, - message="" - ) - ) - except FilePartMissing as e: - self.save_file(animated_sticker, file_id=file.id, file_part=e.x) - else: - for i in r.updates: - if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): - return pyrogram.Message._parse( - self, i.message, - {i.id: i for i in r.users}, - {i.id: i for i in r.chats} - ) - except BaseClient.StopTransmission: - return None diff --git a/pyrogram/client/methods/messages/send_sticker.py b/pyrogram/client/methods/messages/send_sticker.py index a5fc7b26..ae5e8551 100644 --- a/pyrogram/client/methods/messages/send_sticker.py +++ b/pyrogram/client/methods/messages/send_sticker.py @@ -41,7 +41,7 @@ class SendSticker(BaseClient): progress: callable = None, progress_args: tuple = () ) -> Union["pyrogram.Message", None]: - """Send .webp stickers. + """Send static .webp or animated .tgs stickers. Parameters: chat_id (``int`` | ``str``): diff --git a/pyrogram/client/types/messages_and_media/sticker.py b/pyrogram/client/types/messages_and_media/sticker.py index 2fc5caa1..cb5c34b2 100644 --- a/pyrogram/client/types/messages_and_media/sticker.py +++ b/pyrogram/client/types/messages_and_media/sticker.py @@ -41,6 +41,9 @@ class Sticker(Object): height (``int``): Sticker height. + is_animated (``bool``): + True, if the sticker is animated + file_name (``str``, *optional*): Sticker file name. @@ -72,6 +75,7 @@ class Sticker(Object): file_id: str, width: int, height: int, + is_animated: bool, file_name: str = None, mime_type: str = None, file_size: int = None, @@ -89,6 +93,7 @@ class Sticker(Object): self.date = date self.width = width self.height = height + self.is_animated = is_animated self.emoji = emoji self.set_name = set_name self.thumbs = thumbs @@ -130,8 +135,9 @@ class Sticker(Object): sticker.access_hash ) ), - width=image_size_attributes.w if image_size_attributes else 0, - height=image_size_attributes.h if image_size_attributes else 0, + width=image_size_attributes.w if image_size_attributes else 512, + height=image_size_attributes.h if image_size_attributes else 512, + is_animated=sticker.mime_type == "application/x-tgsticker", # TODO: mask_position set_name=set_name, emoji=sticker_attributes.alt or None, From c6f346f83dcc91e4f88ff1ac73104609aab639ab Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sat, 3 Aug 2019 19:09:42 +0200 Subject: [PATCH 50/55] [Bot API 4.4] Update chat permissions - Move can_* permissions back to ChatMember objects - Rename restrict_chat to set_chat_permissions - Update restrict_chat_member to accept a single ChatPermissions arg. - Update ChatPermissions to be the same as the one on the Bot API --- compiler/docs/compiler.py | 2 +- pyrogram/client/methods/chats/__init__.py | 4 +- .../methods/chats/restrict_chat_member.py | 74 +++----- ...strict_chat.py => set_chat_permissions.py} | 81 ++++----- pyrogram/client/types/user_and_chats/chat.py | 2 +- .../types/user_and_chats/chat_member.py | 154 +++++++++++++++-- .../types/user_and_chats/chat_permissions.py | 162 ++++-------------- 7 files changed, 231 insertions(+), 248 deletions(-) rename pyrogram/client/methods/chats/{restrict_chat.py => set_chat_permissions.py} (56%) diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 32674887..e515dc77 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -189,6 +189,7 @@ def pyrogram_api(): delete_chat_photo set_chat_title set_chat_description + set_chat_permissions pin_chat_message unpin_chat_message get_chat @@ -199,7 +200,6 @@ def pyrogram_api(): get_dialogs iter_dialogs get_dialogs_count - restrict_chat update_chat_username archive_chats unarchive_chats diff --git a/pyrogram/client/methods/chats/__init__.py b/pyrogram/client/methods/chats/__init__.py index a7fc2792..fddb48ce 100644 --- a/pyrogram/client/methods/chats/__init__.py +++ b/pyrogram/client/methods/chats/__init__.py @@ -38,9 +38,9 @@ from .kick_chat_member import KickChatMember from .leave_chat import LeaveChat from .pin_chat_message import PinChatMessage from .promote_chat_member import PromoteChatMember -from .restrict_chat import RestrictChat from .restrict_chat_member import RestrictChatMember from .set_chat_description import SetChatDescription +from .set_chat_permissions import SetChatPermissions from .set_chat_photo import SetChatPhoto from .set_chat_title import SetChatTitle from .unarchive_chats import UnarchiveChats @@ -71,7 +71,7 @@ class Chats( IterDialogs, IterChatMembers, UpdateChatUsername, - RestrictChat, + SetChatPermissions, GetDialogsCount, ArchiveChats, UnarchiveChats, diff --git a/pyrogram/client/methods/chats/restrict_chat_member.py b/pyrogram/client/methods/chats/restrict_chat_member.py index 60787b32..f20eb348 100644 --- a/pyrogram/client/methods/chats/restrict_chat_member.py +++ b/pyrogram/client/methods/chats/restrict_chat_member.py @@ -20,7 +20,7 @@ from typing import Union from pyrogram.api import functions, types from ...ext import BaseClient -from ...types.user_and_chats import Chat +from ...types.user_and_chats import Chat, ChatPermissions class RestrictChatMember(BaseClient): @@ -28,20 +28,13 @@ class RestrictChatMember(BaseClient): self, chat_id: Union[int, str], user_id: Union[int, str], - until_date: int = 0, - can_send_messages: bool = False, - can_send_media_messages: bool = False, - can_send_other_messages: bool = False, - can_add_web_page_previews: bool = False, - can_send_polls: bool = False, - can_change_info: bool = False, - can_invite_users: bool = False, - can_pin_messages: bool = False + permissions: ChatPermissions, + until_date: int = 0 ) -> Chat: """Restrict a user in a supergroup. - The bot must be an administrator in the supergroup for this to work and must have the appropriate admin rights. - Pass True for all boolean parameters to lift restrictions from a user. + You must be an administrator in the supergroup for this to work and must have the appropriate admin rights. + Pass True for all permissions to lift restrictions from a user. Parameters: chat_id (``int`` | ``str``): @@ -51,37 +44,14 @@ class RestrictChatMember(BaseClient): Unique identifier (int) or username (str) of the target user. For a contact that exists in your Telegram address book you can use his phone number (str). + permissions (:obj:`ChatPermissions`): + New user permissions. + until_date (``int``, *optional*): Date when the user will be unbanned, unix time. If user is banned for more than 366 days or less than 30 seconds from the current time they are considered to be banned forever. Defaults to 0 (ban forever). - can_send_messages (``bool``, *optional*): - Pass True, if the user can send text messages, contacts, locations and venues. - - can_send_media_messages (``bool``, *optional*): - Pass True, if the user can send audios, documents, photos, videos, video notes and voice notes, - implies can_send_messages. - - can_send_other_messages (``bool``, *optional*): - Pass True, if the user can send animations, games, stickers and use inline bots, - implies can_send_messages. - - can_add_web_page_previews (``bool``, *optional*): - Pass True, if the user may add web page previews to their messages, implies can_send_messages. - - can_send_polls (``bool``, *optional*): - Pass True, if the user can send polls, implies can_send_messages. - - can_change_info (``bool``, *optional*): - Pass True, if the user can change the chat title, photo and other settings. - - can_invite_users (``bool``, *optional*): - Pass True, if the user can invite new users to the chat. - - can_pin_messages (``bool``, *optional*): - Pass True, if the user can pin messages. - Returns: :obj:`Chat`: On success, a chat object is returned. @@ -90,14 +60,16 @@ class RestrictChatMember(BaseClient): from time import time - # Completely restrict chat member forever - app.restrict_chat_member(chat_id, user_id) + from pyrogram import ChatPermissions - # Chat member can't send messages for 24h - app.restrict_chat_member(chat_id, user_id, int(time.time() + 86400)) + # Completely restrict chat member (mute) forever + app.restrict_chat_member(chat_id, user_id, ChatPermissions()) + + # Chat member muted for 24h + app.restrict_chat_member(chat_id, user_id, ChatPermissions(), int(time.time() + 86400)) # Chat member can only send text messages - app.restrict_chat_member(chat_id, user_id, can_send_messages=True) + app.restrict_chat_member(chat_id, user_id, ChatPermissions(can_send_messages=True)) """ send_messages = True send_media = True @@ -111,35 +83,35 @@ class RestrictChatMember(BaseClient): invite_users = True pin_messages = True - if can_send_messages: + if permissions.can_send_messages: send_messages = None - if can_send_media_messages: + if permissions.can_send_media_messages: send_messages = None send_media = None - if can_send_other_messages: + if permissions.can_send_other_messages: send_messages = None send_stickers = None send_gifs = None send_games = None send_inline = None - if can_add_web_page_previews: + if permissions.can_add_web_page_previews: send_messages = None embed_links = None - if can_send_polls: + if permissions.can_send_polls: send_messages = None send_polls = None - if can_change_info: + if permissions.can_change_info: change_info = None - if can_invite_users: + if permissions.can_invite_users: invite_users = None - if can_pin_messages: + if permissions.can_pin_messages: pin_messages = None r = self.send( diff --git a/pyrogram/client/methods/chats/restrict_chat.py b/pyrogram/client/methods/chats/set_chat_permissions.py similarity index 56% rename from pyrogram/client/methods/chats/restrict_chat.py rename to pyrogram/client/methods/chats/set_chat_permissions.py index 20acd5e1..f1ea61c7 100644 --- a/pyrogram/client/methods/chats/restrict_chat.py +++ b/pyrogram/client/methods/chats/set_chat_permissions.py @@ -20,54 +20,26 @@ from typing import Union from pyrogram.api import functions, types from ...ext import BaseClient -from ...types.user_and_chats import Chat +from ...types.user_and_chats import Chat, ChatPermissions -class RestrictChat(BaseClient): - def restrict_chat( +class SetChatPermissions(BaseClient): + def set_chat_permissions( self, chat_id: Union[int, str], - can_send_messages: bool = False, - can_send_media_messages: bool = False, - can_send_other_messages: bool = False, - can_add_web_page_previews: bool = False, - can_send_polls: bool = False, - can_change_info: bool = False, - can_invite_users: bool = False, - can_pin_messages: bool = False + permissions: ChatPermissions, ) -> Chat: - """Restrict a chat. - Pass True for all boolean parameters to lift restrictions from a chat. + """Set default chat permissions for all members. + + You must be an administrator in the group or a supergroup for this to work and must have the + *can_restrict_members* admin rights. Parameters: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. - can_send_messages (``bool``, *optional*): - Pass True, if the user can send text messages, contacts, locations and venues. - - can_send_media_messages (``bool``, *optional*): - Pass True, if the user can send audios, documents, photos, videos, video notes and voice notes, - implies can_send_messages. - - can_send_other_messages (``bool``, *optional*): - Pass True, if the user can send animations, games, stickers and use inline bots, - implies can_send_messages. - - can_add_web_page_previews (``bool``, *optional*): - Pass True, if the user may add web page previews to their messages, implies can_send_messages. - - can_send_polls (``bool``, *optional*): - Pass True, if the user can send polls, implies can_send_messages. - - can_change_info (``bool``, *optional*): - Pass True, if the user can change the chat title, photo and other settings. - - can_invite_users (``bool``, *optional*): - Pass True, if the user can invite new users to the chat. - - can_pin_messages (``bool``, *optional*): - Pass True, if the user can pin messages. + permissions (:obj:`ChatPermissions`): + New default chat permissions. Returns: :obj:`Chat`: On success, a chat object is returned. @@ -75,11 +47,20 @@ class RestrictChat(BaseClient): Example: .. code-block:: python - # Completely restrict chat - app.restrict_chat(chat_id) + from pyrogram import ChatPermissions - # All chat members can only send text messages - app.restrict_chat(chat_id, can_send_messages=True) + # Completely restrict chat + app.set_chat_permissions(chat_id, ChatPermissions()) + + # Chat members can only send text messages, media, stickers and GIFs + app.set_chat_permissions( + chat_id, + ChatPermissions( + can_send_messages=True, + can_send_media_messages=True, + can_send_other_messages=True + ) + ) """ send_messages = True send_media = True @@ -93,35 +74,35 @@ class RestrictChat(BaseClient): invite_users = True pin_messages = True - if can_send_messages: + if permissions.can_send_messages: send_messages = None - if can_send_media_messages: + if permissions.can_send_media_messages: send_messages = None send_media = None - if can_send_other_messages: + if permissions.can_send_other_messages: send_messages = None send_stickers = None send_gifs = None send_games = None send_inline = None - if can_add_web_page_previews: + if permissions.can_add_web_page_previews: send_messages = None embed_links = None - if can_send_polls: + if permissions.can_send_polls: send_messages = None send_polls = None - if can_change_info: + if permissions.can_change_info: change_info = None - if can_invite_users: + if permissions.can_invite_users: invite_users = None - if can_pin_messages: + if permissions.can_pin_messages: pin_messages = None r = self.send( diff --git a/pyrogram/client/types/user_and_chats/chat.py b/pyrogram/client/types/user_and_chats/chat.py index cfed441f..4a032a26 100644 --- a/pyrogram/client/types/user_and_chats/chat.py +++ b/pyrogram/client/types/user_and_chats/chat.py @@ -92,7 +92,7 @@ class Chat(Object): This field is available only in case *is_restricted* is True. permissions (:obj:`ChatPermissions` *optional*): - Information about the chat default permissions, for groups and supergroups. + Default chat member permissions, for groups and supergroups. """ def __init__( diff --git a/pyrogram/client/types/user_and_chats/chat_member.py b/pyrogram/client/types/user_and_chats/chat_member.py index 42eb08f3..812a3204 100644 --- a/pyrogram/client/types/user_and_chats/chat_member.py +++ b/pyrogram/client/types/user_and_chats/chat_member.py @@ -33,11 +33,13 @@ class ChatMember(Object): The member's status in the chat. Can be "creator", "administrator", "member", "restricted", "left" or "kicked". - date (``int``, *optional*): - Date when the user joined, unix time. Not available for creator. + until_date (``int``, *optional*): + Restricted and kicked only. + Date when restrictions will be lifted for this user; unix time. - is_member (``bool``, *optional*): - Restricted only. True, if the user is a member of the chat at the moment of the request. + joined_date (``int``, *optional*): + Date when the user joined, unix time. + Not available for creator. invited_by (:obj:`User`, *optional*): Administrators and self member only. Information about the user who invited this member. @@ -49,9 +51,66 @@ class ChatMember(Object): restricted_by (:obj:`User`, *optional*): Restricted and kicked only. Information about the user who restricted or kicked this member. - permissions (:obj:`ChatPermissions` *optional*): - Administrators, restricted and kicked members only. - Information about the member permissions. + is_member (``bool``, *optional*): + Restricted only. True, if the user is a member of the chat at the moment of the request. + + can_be_edited (``bool``, *optional*): + Administrators only. + True, if you are allowed to edit administrator privileges of the user. + + can_post_messages (``bool``, *optional*): + Administrators only. Channels only. + True, if the administrator can post messages in the channel. + + can_edit_messages (``bool``, *optional*): + Administrators only. Channels only. + True, if the administrator can edit messages of other users and can pin messages. + + can_delete_messages (``bool``, *optional*): + Administrators only. + True, if the administrator can delete messages of other users. + + can_restrict_members (``bool``, *optional*): + Administrators only. + True, if the administrator can restrict, ban or unban chat members. + + can_promote_members (``bool``, *optional*): + Administrators only. + True, if the administrator can add new administrators with a subset of his own privileges or demote + administrators that he has promoted, directly or indirectly (promoted by administrators that were appointed + by the user). + + can_change_info (``bool``, *optional*): + Administrators and restricted only. + True, if the user is allowed to change the chat title, photo and other settings. + + can_invite_users (``bool``, *optional*): + Administrators and restricted only. + True, if the user is allowed to invite new users to the chat. + + can_pin_messages (``bool``, *optional*): + Administrators and restricted only. Groups and supergroups only. + True, if the user is allowed to pin messages. + + can_send_messages (``bool``, *optional*): + Restricted only. + True, if the user is allowed to send text messages, contacts, locations and venues. + + can_send_media_messages (``bool``, *optional*): + Restricted only. + True, if the user is allowed to send audios, documents, photos, videos, video notes and voice notes. + + can_send_other_messages (``bool``, *optional*): + Restricted only. + True, if the user is allowed to send animations, games, stickers and use inline bots. + + can_add_web_page_previews (``bool``, *optional*): + Restricted only. + True, if the user is allowed to add web page previews to their messages. + + can_send_polls (``bool``, *optional*): + Restricted only. + True, if the user is allowed to send polls. """ def __init__( @@ -60,23 +119,57 @@ class ChatMember(Object): client: "pyrogram.BaseClient" = None, user: "pyrogram.User", status: str, - date: int = None, - is_member: bool = None, + until_date: int = None, + joined_date: int = None, invited_by: "pyrogram.User" = None, promoted_by: "pyrogram.User" = None, restricted_by: "pyrogram.User" = None, - permissions: "pyrogram.ChatPermissions" = None + is_member: bool = None, + + # Admin permissions + can_be_edited: bool = None, + can_post_messages: bool = None, # Channels only + can_edit_messages: bool = None, # Channels only + can_delete_messages: bool = None, + can_restrict_members: bool = None, + can_promote_members: bool = None, + can_change_info: bool = None, + can_invite_users: bool = None, + can_pin_messages: bool = None, # Groups and supergroups only + + # Restricted user permissions + can_send_messages: bool = None, # Text, contacts, locations and venues + can_send_media_messages: bool = None, # Audios, documents, photos, videos, video notes and voice notes + can_send_other_messages: bool = None, # Animations (GIFs), games, stickers, inline bot results + can_add_web_page_previews: bool = None, + can_send_polls: bool = None ): super().__init__(client) self.user = user self.status = status - self.date = date - self.is_member = is_member + self.until_date = until_date + self.joined_date = joined_date self.invited_by = invited_by self.promoted_by = promoted_by self.restricted_by = restricted_by - self.permissions = permissions + self.is_member = is_member + + self.can_be_edited = can_be_edited + self.can_post_messages = can_post_messages + self.can_edit_messages = can_edit_messages + self.can_delete_messages = can_delete_messages + self.can_restrict_members = can_restrict_members + self.can_promote_members = can_promote_members + self.can_change_info = can_change_info + self.can_invite_users = can_invite_users + self.can_pin_messages = can_pin_messages + + self.can_send_messages = can_send_messages + self.can_send_media_messages = can_send_media_messages + self.can_send_other_messages = can_send_other_messages + self.can_add_web_page_previews = can_add_web_page_previews + self.can_send_polls = can_send_polls @staticmethod def _parse(client, member, users) -> "ChatMember": @@ -91,7 +184,7 @@ class ChatMember(Object): return ChatMember( user=user, status="member", - date=member.date, + joined_date=member.date, invited_by=invited_by, client=client ) @@ -107,29 +200,52 @@ class ChatMember(Object): return ChatMember( user=user, status="administrator", - date=member.date, + joined_date=member.date, invited_by=invited_by, client=client ) if isinstance(member, types.ChannelParticipantAdmin): + permissions = member.admin_rights + return ChatMember( user=user, status="administrator", - date=member.date, + joined_date=member.date, invited_by=invited_by, promoted_by=pyrogram.User._parse(client, users[member.promoted_by]), - permissions=pyrogram.ChatPermissions._parse(member), + can_be_edited=member.can_edit, + can_change_info=permissions.change_info, + can_post_messages=permissions.post_messages, + can_edit_messages=permissions.edit_messages, + can_delete_messages=permissions.delete_messages, + can_restrict_members=permissions.ban_users, + can_invite_users=permissions.invite_users, + can_pin_messages=permissions.pin_messages, + can_promote_members=permissions.add_admins, client=client ) if isinstance(member, types.ChannelParticipantBanned): + denied_permissions = member.banned_rights + return ChatMember( user=user, status="kicked" if member.banned_rights.view_messages else "restricted", - date=member.date, + until_date=denied_permissions.until_date, + joined_date=member.date, is_member=not member.left, restricted_by=pyrogram.User._parse(client, users[member.kicked_by]), - permissions=pyrogram.ChatPermissions._parse(member), + can_send_messages=not denied_permissions.send_messages, + can_send_media_messages=not denied_permissions.send_media, + can_send_other_messages=( + not denied_permissions.send_stickers or not denied_permissions.send_gifs or + not denied_permissions.send_games or not denied_permissions.send_inline + ), + can_add_web_page_previews=not denied_permissions.embed_links, + can_send_polls=not denied_permissions.send_polls, + can_change_info=not denied_permissions.change_info, + can_invite_users=not denied_permissions.invite_users, + can_pin_messages=not denied_permissions.pin_messages, client=client ) diff --git a/pyrogram/client/types/user_and_chats/chat_permissions.py b/pyrogram/client/types/user_and_chats/chat_permissions.py index 551dc667..e4b0b0d0 100644 --- a/pyrogram/client/types/user_and_chats/chat_permissions.py +++ b/pyrogram/client/types/user_and_chats/chat_permissions.py @@ -16,8 +16,6 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from typing import Union - from pyrogram.api import types from ..object import Object @@ -29,154 +27,70 @@ class ChatPermissions(Object): administrators in groups or channels. Parameters: - until_date (``int``, *optional*): - Applicable to restricted and kicked members only. - Date when user restrictions will be lifted, unix time. - 0 means the restrictions will never be lifted (user restricted forever). - - can_be_edited (``bool``, *optional*): - Applicable to administrators only. - True, if you are allowed to edit administrator privileges of the user. - - can_change_info (``bool``, *optional*): - Applicable to default chat permissions in private groups and administrators in public groups only. - True, if the chat title, photo and other settings can be changed. - - can_post_messages (``bool``, *optional*): - Applicable to channel administrators only. - True, if the administrator can post messages in the channel, channels only. - - can_edit_messages (``bool``, *optional*): - Applicable to channel administrators only. - True, if the administrator can edit messages of other users and can pin messages, channels only. - - can_delete_messages (``bool``, *optional*): - Applicable to administrators only. - True, if the administrator can delete messages of other users. - - can_restrict_members (``bool``, *optional*): - Applicable to administrators only. - True, if the administrator can restrict, ban or unban chat members. - - can_invite_users (``bool``, *optional*): - Applicable to default chat permissions and administrators only. - True, if new users can be invited to the chat. - - can_pin_messages (``bool``, *optional*): - Applicable to default chat permissions in private groups and administrators in public groups only. - True, if messages can be pinned, supergroups only. - - can_promote_members (``bool``, *optional*): - Applicable to administrators only. - True, if the administrator can add new administrators with a subset of his own privileges or demote - administrators that he has promoted, directly or indirectly (promoted by administrators that were appointed - by the user). - can_send_messages (``bool``, *optional*): - Applicable to default chat permissions and restricted members only. - True, if text messages, contacts, locations and venues can be sent. + True, if the user is allowed to send text messages, contacts, locations and venues. can_send_media_messages (``bool``, *optional*): - Applicable to default chat permissions and restricted members only. - True, if audios, documents, photos, videos, video notes and voice notes can be sent, implies + True, if the user is allowed to send audios, documents, photos, videos, video notes and voice notes, implies can_send_messages. can_send_other_messages (``bool``, *optional*): - Applicable to default chat permissions and restricted members only. - True, if animations, games, stickers and inline bot results can be sent, implies can_send_media_messages. + True, if the user is allowed to send animations, games, stickers and use inline bots, implies + can_send_media_messages can_add_web_page_previews (``bool``, *optional*): - Applicable to default chat permissions and restricted members only. - True, if web page previews can be attached to text messages, implies can_send_media_messages. + True, if the user is allowed to add web page previews to their messages, implies can_send_media_messages. can_send_polls (``bool``, *optional*): - Applicable to default chat permissions and restricted members only. - True, if polls can be sent, implies can_send_media_messages. + True, if the user is allowed to send polls, implies can_send_messages. + + can_change_info (``bool``, *optional*): + True, if the user is allowed to change the chat title, photo and other settings. + Ignored in public supergroups. + + can_invite_users (``bool``, *optional*): + True, if the user is allowed to invite new users to the chat. + + can_pin_messages (``bool``, *optional*): + True, if the user is allowed to pin messages. + Ignored in public supergroups. """ def __init__( self, *, - until_date: int = None, - - # Admin permissions - can_be_edited: bool = None, - can_change_info: bool = None, - can_post_messages: bool = None, # Channels only - can_edit_messages: bool = None, # Channels only - can_delete_messages: bool = None, - can_restrict_members: bool = None, - can_invite_users: bool = None, - can_pin_messages: bool = None, # Supergroups only - can_promote_members: bool = None, - - # Restricted user permissions can_send_messages: bool = None, # Text, contacts, locations and venues can_send_media_messages: bool = None, # Audios, documents, photos, videos, video notes and voice notes can_send_other_messages: bool = None, # Animations (GIFs), games, stickers, inline bot results can_add_web_page_previews: bool = None, - can_send_polls: bool = None + can_send_polls: bool = None, + can_change_info: bool = None, + can_invite_users: bool = None, + can_pin_messages: bool = None ): super().__init__(None) - self.until_date = until_date - self.can_be_edited = can_be_edited - - self.can_change_info = can_change_info - self.can_post_messages = can_post_messages - self.can_edit_messages = can_edit_messages - self.can_delete_messages = can_delete_messages - self.can_restrict_members = can_restrict_members - self.can_invite_users = can_invite_users - self.can_pin_messages = can_pin_messages - self.can_promote_members = can_promote_members - self.can_send_messages = can_send_messages self.can_send_media_messages = can_send_media_messages self.can_send_other_messages = can_send_other_messages self.can_add_web_page_previews = can_add_web_page_previews self.can_send_polls = can_send_polls + self.can_change_info = can_change_info + self.can_invite_users = can_invite_users + self.can_pin_messages = can_pin_messages @staticmethod - def _parse( - entity: Union[ - types.ChannelParticipantAdmin, - types.ChannelParticipantBanned, - types.ChatBannedRights - ] - ) -> "ChatPermissions": - if isinstance(entity, types.ChannelParticipantAdmin): - permissions = entity.admin_rights - - return ChatPermissions( - can_be_edited=entity.can_edit, - can_change_info=permissions.change_info, - can_post_messages=permissions.post_messages, - can_edit_messages=permissions.edit_messages, - can_delete_messages=permissions.delete_messages, - can_restrict_members=permissions.ban_users, - can_invite_users=permissions.invite_users, - can_pin_messages=permissions.pin_messages, - can_promote_members=permissions.add_admins - ) - - if isinstance(entity, (types.ChannelParticipantBanned, types.ChatBannedRights)): - if isinstance(entity, types.ChannelParticipantBanned): - denied_permissions = entity.banned_rights # type: types.ChatBannedRights - else: - denied_permissions = entity - - return ChatPermissions( - until_date=0 if denied_permissions.until_date == (1 << 31) - 1 else denied_permissions.until_date, - can_send_messages=not denied_permissions.send_messages, - can_send_media_messages=not denied_permissions.send_media, - can_send_other_messages=( - not denied_permissions.send_stickers or not denied_permissions.send_gifs or - not denied_permissions.send_games or not denied_permissions.send_inline - ), - can_add_web_page_previews=not denied_permissions.embed_links, - can_send_polls=not denied_permissions.send_polls, - can_change_info=not denied_permissions.change_info, - can_invite_users=not denied_permissions.invite_users, - can_pin_messages=not denied_permissions.pin_messages - ) + def _parse(denied_permissions: types.ChatBannedRights) -> "ChatPermissions": + return ChatPermissions( + can_send_messages=not denied_permissions.send_messages, + can_send_media_messages=not denied_permissions.send_media, + can_send_other_messages=( + not denied_permissions.send_stickers or not denied_permissions.send_gifs or + not denied_permissions.send_games or not denied_permissions.send_inline + ), + can_add_web_page_previews=not denied_permissions.embed_links, + can_send_polls=not denied_permissions.send_polls, + can_change_info=not denied_permissions.change_info, + can_invite_users=not denied_permissions.invite_users, + can_pin_messages=not denied_permissions.pin_messages + ) From 360cfaa9aa5ee4732a8390129e905d2e567bf65d Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sat, 3 Aug 2019 19:30:58 +0200 Subject: [PATCH 51/55] [Bot API 4.4] Update chat photos - Update ChatPhoto fields descriptions --- pyrogram/client/types/user_and_chats/chat_photo.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyrogram/client/types/user_and_chats/chat_photo.py b/pyrogram/client/types/user_and_chats/chat_photo.py index 70e114af..623aaca8 100644 --- a/pyrogram/client/types/user_and_chats/chat_photo.py +++ b/pyrogram/client/types/user_and_chats/chat_photo.py @@ -29,10 +29,12 @@ class ChatPhoto(Object): Parameters: small_file_id (``str``): - Unique file identifier of small (160x160) chat photo. This file_id can be used only for photo download. + File identifier of small (160x160) chat photo. + This file_id can be used only for photo download and only for as long as the photo is not changed. big_file_id (``str``): - Unique file identifier of big (640x640) chat photo. This file_id can be used only for photo download. + File identifier of big (640x640) chat photo. + This file_id can be used only for photo download and only for as long as the photo is not changed. """ def __init__( From c8c93b9ce617d46c90e12f9b86c3a3975485e49f Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sat, 3 Aug 2019 19:36:15 +0200 Subject: [PATCH 52/55] Update Main API and System Messages schemas --- compiler/api/source/main_api.tl | 5 +---- compiler/api/source/sys_msgs.tl | 9 +++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index e9d099d1..fa2c7af8 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -1364,7 +1364,4 @@ langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLangua folders.editPeerFolders#6847d0ab folder_peers:Vector = Updates; folders.deleteFolder#1c295881 folder_id:int = Updates; -// LAYER 103 - -// Ports -channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; \ No newline at end of file +// LAYER 103 \ No newline at end of file diff --git a/compiler/api/source/sys_msgs.tl b/compiler/api/source/sys_msgs.tl index 067ab91e..6a3f6325 100644 --- a/compiler/api/source/sys_msgs.tl +++ b/compiler/api/source/sys_msgs.tl @@ -53,6 +53,15 @@ ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort; accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector = AccessPointRule; help.configSimple#5a592a6c date:int expires:int rules:vector = help.ConfigSimple; +// tlsClientHello blocks:vector = TlsClientHello; +// +// tlsBlockString data:string = TlsBlock; +// tlsBlockRandom length:int = TlsBlock; +// tlsBlockZero length:int = TlsBlock; +// tlsBlockDomain = TlsBlock; +// tlsBlockGrease seed:int = TlsBlock; +// tlsBlockScope entries:Vector = TlsBlock; + ---functions--- rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer; From 937987a361179491161fc75fc0b8e56efc237c48 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sat, 3 Aug 2019 19:40:45 +0200 Subject: [PATCH 53/55] Finally remove ports from older schemas and fix export_chat_invite_link --- pyrogram/client/methods/chats/export_chat_invite_link.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pyrogram/client/methods/chats/export_chat_invite_link.py b/pyrogram/client/methods/chats/export_chat_invite_link.py index bf5d3a38..46886469 100644 --- a/pyrogram/client/methods/chats/export_chat_invite_link.py +++ b/pyrogram/client/methods/chats/export_chat_invite_link.py @@ -57,17 +57,11 @@ class ExportChatInviteLink(BaseClient): """ peer = self.resolve_peer(chat_id) - if isinstance(peer, types.InputPeerChat): + if isinstance(peer, (types.InputPeerChat, types.InputPeerChannel)): return self.send( functions.messages.ExportChatInvite( peer=peer ) ).link - elif isinstance(peer, types.InputPeerChannel): - return self.send( - functions.channels.ExportInvite( - channel=peer - ) - ).link else: raise ValueError('The chat_id "{}" belongs to a user'.format(chat_id)) From 8a99f996ab95d99404e937f4f3c0370b76d267df Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sat, 3 Aug 2019 19:50:12 +0200 Subject: [PATCH 54/55] Handle cases where denied_permissions might be None --- .../types/user_and_chats/chat_permissions.py | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/pyrogram/client/types/user_and_chats/chat_permissions.py b/pyrogram/client/types/user_and_chats/chat_permissions.py index e4b0b0d0..09c33089 100644 --- a/pyrogram/client/types/user_and_chats/chat_permissions.py +++ b/pyrogram/client/types/user_and_chats/chat_permissions.py @@ -81,16 +81,17 @@ class ChatPermissions(Object): @staticmethod def _parse(denied_permissions: types.ChatBannedRights) -> "ChatPermissions": - return ChatPermissions( - can_send_messages=not denied_permissions.send_messages, - can_send_media_messages=not denied_permissions.send_media, - can_send_other_messages=( - not denied_permissions.send_stickers or not denied_permissions.send_gifs or - not denied_permissions.send_games or not denied_permissions.send_inline - ), - can_add_web_page_previews=not denied_permissions.embed_links, - can_send_polls=not denied_permissions.send_polls, - can_change_info=not denied_permissions.change_info, - can_invite_users=not denied_permissions.invite_users, - can_pin_messages=not denied_permissions.pin_messages - ) + if isinstance(denied_permissions, types.ChatBannedRights): + return ChatPermissions( + can_send_messages=not denied_permissions.send_messages, + can_send_media_messages=not denied_permissions.send_media, + can_send_other_messages=( + not denied_permissions.send_stickers or not denied_permissions.send_gifs or + not denied_permissions.send_games or not denied_permissions.send_inline + ), + can_add_web_page_previews=not denied_permissions.embed_links, + can_send_polls=not denied_permissions.send_polls, + can_change_info=not denied_permissions.change_info, + can_invite_users=not denied_permissions.invite_users, + can_pin_messages=not denied_permissions.pin_messages + ) From 3dc2a81d7242e1ae40c2c25beaf93e87a1ea70dd Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sat, 3 Aug 2019 19:54:14 +0200 Subject: [PATCH 55/55] Add Chat.description for basic chats --- pyrogram/client/types/user_and_chats/chat.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyrogram/client/types/user_and_chats/chat.py b/pyrogram/client/types/user_and_chats/chat.py index 4a032a26..546485f6 100644 --- a/pyrogram/client/types/user_and_chats/chat.py +++ b/pyrogram/client/types/user_and_chats/chat.py @@ -231,6 +231,7 @@ class Chat(Object): if isinstance(full_chat, types.ChatFull): parsed_chat = Chat._parse_chat_chat(client, chat) + parsed_chat.description = full_chat.about or None if isinstance(full_chat.participants, types.ChatParticipants): parsed_chat.members_count = len(full_chat.participants.participants)