diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index d678b370..cb3ad5a2 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 @@ -203,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 @@ -334,6 +341,8 @@ def pyrogram_api(): InlineQuery InlineQueryResult InlineQueryResultArticle + InlineQueryResultPhoto + InlineQueryResultAnimation """, input_message_content=""" InputMessageContent @@ -412,11 +421,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 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 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 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 diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index c1065a42..8b71312d 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 @@ -275,11 +286,28 @@ class Client(Methods, BaseClient): self._proxy.update(value) async 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): async 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") @@ -392,61 +437,118 @@ class Client(Methods, BaseClient): async 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() """ await self.stop() await self.start() - async def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)): + @staticmethod + async 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)*. - # TODO: Maybe make this method static and don't automatically stop + 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() + """ def signal_handler(*args): log.info("Stop signal received ({}). Exiting...".format(args[0])) - 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: await asyncio.sleep(1) - await self.stop() - def run(self, coroutine=None): - """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. Args: coroutine: (``Coroutine``, *optional*): Pass a coroutine to run it until is complete. 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() """ loop = asyncio.get_event_loop() run = loop.run_until_complete @@ -455,19 +557,18 @@ class Client(Methods, BaseClient): run(coroutine) else: run(self.start()) - run(self.idle()) - - # TODO: Uncomment this once idle() gets refactored - # run(self.stop()) + run(Client.idle()) + run(self.stop()) loop.close() 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``): @@ -477,7 +578,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 @@ -489,9 +605,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``): @@ -499,6 +614,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 @@ -507,10 +640,109 @@ 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 + 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 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``): + 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 + async def authorize_bot(self): try: r = await self.send( @@ -1084,7 +1316,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 @@ -1120,7 +1352,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) @@ -1155,7 +1387,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) @@ -1193,7 +1425,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) @@ -1355,23 +1587,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. @@ -1709,11 +1940,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() diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py index a25dac23..640e7e65 100644 --- a/pyrogram/client/ext/base_client.py +++ b/pyrogram/client/ext/base_client.py @@ -58,6 +58,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", @@ -86,19 +88,21 @@ class BaseClient: mime_types_to_extensions[mime_type] = " ".join(extensions) + is_idling = False + def __init__(self): self.storage = None self.rnd_id = MsgId self.parser = Parser(self) + self.parse_mode = "combined" self.session = None self.media_sessions = {} self.media_sessions_lock = asyncio.Lock() self.is_started = None - self.is_idle = None self.takeout_id = None diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py index d8768b3b..f80127c2 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") @@ -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: @@ -272,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): diff --git a/pyrogram/client/methods/bots/answer_callback_query.py b/pyrogram/client/methods/bots/answer_callback_query.py index 3dab25d2..c81d8554 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 await 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 daf8423b..3e04630e 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. @@ -75,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"))]) """ written_results = [] # Py 3.5 doesn't support await inside comprehensions @@ -88,7 +103,7 @@ class AnswerInlineQuery(BaseClient): query_id=int(inline_query_id), results=written_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/methods/bots/get_game_high_scores.py b/pyrogram/client/methods/bots/get_game_high_scores.py index 81f6a265..58266b34 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 9291ea6b..1dfc04b3 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): async 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 86855a92..8d6ec6c5 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 f579630d..1e25a4b9 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 = await 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 64f90529..9174378f 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 await 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 757eba3f..be9600db 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 = await self.send( functions.messages.SetGameScore( 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..8dbad1a3 --- /dev/null +++ b/pyrogram/client/methods/chats/add_chat_members.py @@ -0,0 +1,88 @@ +# 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. + + 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) + + 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/archive_chats.py b/pyrogram/client/methods/chats/archive_chats.py index 379860d5..9dcadc58 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 new file mode 100644 index 00000000..9520ceef --- /dev/null +++ b/pyrogram/client/methods/chats/create_channel.py @@ -0,0 +1,55 @@ +# 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. + + Example: + .. code-block:: python + + app.create_channel("Channel Title", "Channel Description") + """ + 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..4e1d63bd --- /dev/null +++ b/pyrogram/client/methods/chats/create_group.py @@ -0,0 +1,65 @@ +# 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. + + Example: + .. code-block:: python + + app.create_group("Group Title", user_id) + """ + 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..0ad14d06 --- /dev/null +++ b/pyrogram/client/methods/chats/create_supergroup.py @@ -0,0 +1,59 @@ +# 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. + + Example: + .. code-block:: python + + app.create_supergroup("Supergroup Title", "Supergroup Description") + """ + 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..74fbea13 --- /dev/null +++ b/pyrogram/client/methods/chats/delete_channel.py @@ -0,0 +1,48 @@ +# 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. + + Example: + .. code-block:: python + + app.delete_channel(channel_id) + """ + self.send( + functions.channels.DeleteChannel( + channel=self.resolve_peer(chat_id) + ) + ) + + return True diff --git a/pyrogram/client/methods/chats/delete_chat_photo.py b/pyrogram/client/methods/chats/delete_chat_photo.py index 49f8e5fa..c2fb7e20 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 = await self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/chats/delete_supergroup.py b/pyrogram/client/methods/chats/delete_supergroup.py new file mode 100644 index 00000000..a1eb198d --- /dev/null +++ b/pyrogram/client/methods/chats/delete_supergroup.py @@ -0,0 +1,48 @@ +# 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. + + Example: + .. code-block:: python + + app.delete_supergroup(supergroup_id) + """ + self.send( + functions.channels.DeleteChannel( + channel=self.resolve_peer(chat_id) + ) + ) + + return True diff --git a/pyrogram/client/methods/chats/export_chat_invite_link.py b/pyrogram/client/methods/chats/export_chat_invite_link.py index e231ab02..22586ae6 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 = await self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/chats/get_chat.py b/pyrogram/client/methods/chats/get_chat.py index 37a7ba13..6def6aea 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 46f2f571..924909c2 100644 --- a/pyrogram/client/methods/chats/get_chat_member.py +++ b/pyrogram/client/methods/chats/get_chat_member.py @@ -45,8 +45,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 = await self.resolve_peer(chat_id) user = await 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 9190e2f3..ad7d2218 100644 --- a/pyrogram/client/methods/chats/get_chat_members.py +++ b/pyrogram/client/methods/chats/get_chat_members.py @@ -92,8 +92,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 = await 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 118ff072..c3c9740e 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 = await self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/chats/get_dialogs.py b/pyrogram/client/methods/chats/get_dialogs.py index f9042a79..907ee41c 100644 --- a/pyrogram/client/methods/chats/get_dialogs.py +++ b/pyrogram/client/methods/chats/get_dialogs.py @@ -57,8 +57,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 9a645e9f..d754dc96 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 bdd613fd..3d1b5d7a 100644 --- a/pyrogram/client/methods/chats/iter_chat_members.py +++ b/pyrogram/client/methods/chats/iter_chat_members.py @@ -80,8 +80,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 3162d31d..8265a9df 100644 --- a/pyrogram/client/methods/chats/iter_dialogs.py +++ b/pyrogram/client/methods/chats/iter_dialogs.py @@ -49,8 +49,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 8e38d4ff..1ec5e1ea 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 72a8b5d0..e1af99e2 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 = await self.resolve_peer(chat_id) user_peer = await self.resolve_peer(user_id) diff --git a/pyrogram/client/methods/chats/leave_chat.py b/pyrogram/client/methods/chats/leave_chat.py index e2b5cb4b..a6cc3774 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 = await 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 6023f459..419227ee 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) """ await 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 c7db62a5..bc02c183 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) """ await 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 35593f24..35c5da72 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 aedc3805..84da82ea 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 = await 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 7b71009c..bbcbe6d6 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 = await 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 45a7eb77..bc74d9f7 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((await self.send(functions.contacts.GetContacts(hash=0))).contacts) 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 ) diff --git a/pyrogram/client/methods/messages/delete_messages.py b/pyrogram/client/methods/messages/delete_messages.py index e139a270..0f6fb6fc 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 = await 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 011735c2..f5b44ce7 100644 --- a/pyrogram/client/methods/messages/download_media.py +++ b/pyrogram/client/methods/messages/download_media.py @@ -58,24 +58,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. @@ -86,8 +85,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") @@ -208,7 +215,8 @@ class DownloadMedia(BaseClient): extension ) - self.download_queue.put_nowait((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_nowait((data, str(directory), str(file_name), done, progress, progress_args, path)) if block: await done.wait() diff --git a/pyrogram/client/methods/messages/edit_inline_caption.py b/pyrogram/client/methods/messages/edit_inline_caption.py index 4f96c10d..eed06d3e 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,10 +27,10 @@ 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. + """Edit the caption of inline media messages. Parameters: inline_message_id (``str``): @@ -50,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 await 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 75eddf39..8cb94d2e 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 1c7b2487..920a7741 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 await 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 42c4d917..24951832 100644 --- a/pyrogram/client/methods/messages/edit_inline_text.py +++ b/pyrogram/client/methods/messages/edit_inline_text.py @@ -28,11 +28,11 @@ 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: - """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 await self.send( diff --git a/pyrogram/client/methods/messages/edit_message_caption.py b/pyrogram/client/methods/messages/edit_message_caption.py index ba6b5db3..bba7e7cb 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. @@ -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 await 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 32e4eabf..a4b6f218 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 b2d47701..77e546f7 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 = await 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 8cc12f4a..a1bfe85a 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": @@ -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 = await self.send( diff --git a/pyrogram/client/methods/messages/forward_messages.py b/pyrogram/client/methods/messages/forward_messages.py index 1830f137..3af576b0 100644 --- a/pyrogram/client/methods/messages/forward_messages.py +++ b/pyrogram/client/methods/messages/forward_messages.py @@ -56,7 +56,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*): @@ -69,8 +70,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 f6936591..50bc4b8f 100644 --- a/pyrogram/client/methods/messages/get_history.py +++ b/pyrogram/client/methods/messages/get_history.py @@ -71,8 +71,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 e8ca3380..d235e79b 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 = await self.send( diff --git a/pyrogram/client/methods/messages/get_messages.py b/pyrogram/client/methods/messages/get_messages.py index d705a0c6..c6c89af6 100644 --- a/pyrogram/client/methods/messages/get_messages.py +++ b/pyrogram/client/methods/messages/get_messages.py @@ -29,6 +29,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): async def get_messages( self, @@ -37,7 +40,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: @@ -65,8 +69,26 @@ 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 = ( (message_ids, types.InputMessageID) if message_ids @@ -75,7 +97,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 = await self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/messages/iter_history.py b/pyrogram/client/methods/messages/iter_history.py index 6d69273b..bb1d6611 100644 --- a/pyrogram/client/methods/messages/iter_history.py +++ b/pyrogram/client/methods/messages/iter_history.py @@ -67,8 +67,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 490f0ad0..3734c958 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 = await 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 d1e98915..22e349ff 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, @@ -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 113d6a9c..3d4d9689 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, @@ -99,23 +99,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. @@ -125,8 +124,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 f93a9ae1..c95df576 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[ @@ -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 = await self.send( diff --git a/pyrogram/client/methods/messages/send_chat_action.py b/pyrogram/client/methods/messages/send_chat_action.py index 3a2faeee..dcd85ed7 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 c8f56c5c..598d5ef2 100644 --- a/pyrogram/client/methods/messages/send_contact.py +++ b/pyrogram/client/methods/messages/send_contact.py @@ -73,8 +73,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 = await self.send( functions.messages.SendMedia( diff --git a/pyrogram/client/methods/messages/send_document.py b/pyrogram/client/methods/messages/send_document.py index 2618baa9..b0810a0b 100644 --- a/pyrogram/client/methods/messages/send_document.py +++ b/pyrogram/client/methods/messages/send_document.py @@ -31,7 +31,7 @@ class SendDocument(BaseClient): chat_id: Union[int, str], 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[ @@ -85,23 +85,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. @@ -111,8 +110,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 0e6f0feb..977d4362 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 = await 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 104db7dd..1e16d0d3 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 async def send_media_group( self, chat_id: Union[int, str], @@ -60,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 = [] @@ -88,7 +98,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 = await self.send( + functions.messages.UploadMedia( + peer=await 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 +153,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 = await self.send( + functions.messages.UploadMedia( + peer=await 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: diff --git a/pyrogram/client/methods/messages/send_message.py b/pyrogram/client/methods/messages/send_message.py index bc74a761..3e790537 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, @@ -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 = (await self.parser.parse(text, parse_mode)).values() r = await self.send( diff --git a/pyrogram/client/methods/messages/send_photo.py b/pyrogram/client/methods/messages/send_photo.py index 0e869673..1e4a888d 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, @@ -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 94a421cb..845b12bd 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 76594848..ba6b9bb7 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 = await self.send( functions.messages.SendMedia( diff --git a/pyrogram/client/methods/messages/send_video.py b/pyrogram/client/methods/messages/send_video.py index cab387fc..46cdc995 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, @@ -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 04df6c52..5ab00a9e 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 b3b67ee8..1577622d 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, @@ -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 054229c2..44098b2f 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 = (await 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 88bdc83f..1a8224bf 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 = (await 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 a8f9bcfa..04f95e42 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 = await 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 964e5559..06e8ee76 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 = await 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 969e8c78..4fbe78d7 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 = await self.send(functions.account.GetPassword()) diff --git a/pyrogram/client/methods/users/block_user.py b/pyrogram/client/methods/users/block_user.py index 98774e12..77ffcaba 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( await self.send( diff --git a/pyrogram/client/methods/users/delete_profile_photos.py b/pyrogram/client/methods/users/delete_profile_photos.py index 2f82d37e..ce919eb7 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 66ab999d..19463ff2 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 71fd6056..49f6a713 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 = await 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 82f41dd9..87348194 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 = await self.resolve_peer(chat_id) diff --git a/pyrogram/client/methods/users/get_users.py b/pyrogram/client/methods/users/get_users.py index e997c887..fb26aa8f 100644 --- a/pyrogram/client/methods/users/get_users.py +++ b/pyrogram/client/methods/users/get_users.py @@ -25,7 +25,6 @@ from ...ext import BaseClient class GetUsers(BaseClient): - # TODO: Add Users type and use that async def get_users( self, user_ids: Union[Iterable[Union[int, str]], int, str] @@ -44,8 +43,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 4e703e07..bb86be5a 100644 --- a/pyrogram/client/methods/users/iter_profile_photos.py +++ b/pyrogram/client/methods/users/iter_profile_photos.py @@ -54,8 +54,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 0a437534..00f8d8d2 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 417597e9..e9433b8a 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( await self.send( diff --git a/pyrogram/client/methods/users/update_username.py b/pyrogram/client/methods/users/update_username.py index 92ee1ddd..cd975d9a 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( diff --git a/pyrogram/client/parser/html.py b/pyrogram/client/parser/html.py index b955037a..57726f5b 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 diff --git a/pyrogram/client/parser/parser.py b/pyrogram/client/parser/parser.py index 8fde46bd..371c4791 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,11 +26,18 @@ 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 = ""): - text = str(text or "").strip() + def parse(self, text: str, mode: Union[str, None] = object): + text = str(text).strip() + + if mode == object: + if self.client: + mode = self.client.parse_mode + else: + mode = "combined" if mode is None: return OrderedDict([ @@ -41,7 +47,7 @@ class Parser: mode = mode.lower() - if mode == "": + if mode == "combined": return self.markdown.parse(text) if mode in ["markdown", "md"]: @@ -50,6 +56,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 pyrogram.Client.PARSE_MODES[:-1]), + mode + )) + @staticmethod def unparse(text: str, entities: list, is_html: bool): if is_html: diff --git a/pyrogram/client/types/bots_and_keyboards/callback_query.py b/pyrogram/client/types/bots_and_keyboards/callback_query.py index 6b68b109..0264a67c 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/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.py b/pyrogram/client/types/inline_mode/inline_query.py index 34fead63..12f1bbaf 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, diff --git a/pyrogram/client/types/inline_mode/inline_query_result.py b/pyrogram/client/types/inline_mode/inline_query_result.py index d27b8b85..e7f5904e 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 async 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 94861c79..a887a0ba 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 async def write(self): return types.InputBotInlineResult( - id=str(self.id), + id=self.id, type=self.type, send_message=await 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) + ) + ) + ) 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_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 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 21c7af8c..7fa9d9dd 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 diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index 9d591374..43041ee6 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, @@ -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. @@ -873,7 +872,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, @@ -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. @@ -1010,7 +1008,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 +1216,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[ @@ -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. @@ -1613,7 +1610,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, @@ -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. @@ -2007,7 +2002,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, @@ -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. @@ -2267,7 +2260,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, @@ -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. @@ -2384,7 +2376,7 @@ class Message(Object, Update): async 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 +2434,7 @@ class Message(Object, Update): async 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`. @@ -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 await self._client.send_message( chat_id, @@ -2631,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, @@ -2869,6 +2858,37 @@ class Message(Object, Update): else: await self.reply(button, quote=quote) + async def retract_vote( + self, + ) -> "pyrogram.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 await self._client.retract_vote( + chat_id=self.chat.id, + message_id=self.message_id + ) + async def download( self, file_name: str = "", @@ -2900,14 +2920,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. @@ -2924,6 +2957,44 @@ class Message(Object, Update): progress_args=progress_args, ) + async def vote( + self, + option: int, + ) -> "pyrogram.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: + :obj:`Poll`: On success, the poll with the chosen option is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + + return await self._client.vote_poll( + chat_id=self.chat.id, + message_id=self.message_id, + option=option + ) + async def pin(self, disable_notification: bool = None) -> "Message": """Bound method *pin* of :obj:`Message`. diff --git a/pyrogram/client/types/user_and_chats/chat.py b/pyrogram/client/types/user_and_chats/chat.py index 2d02c754..a4d51d1f 100644 --- a/pyrogram/client/types/user_and_chats/chat.py +++ b/pyrogram/client/types/user_and_chats/chat.py @@ -672,3 +672,49 @@ class Chat(Object): can_pin_messages=can_pin_messages, can_promote_members=can_promote_members ) + + async def join(self): + """Bound method *join* of :obj:`Chat`. + + Use as a shortcut for: + + .. code-block:: python + + client.join_chat(123456789) + + Example: + .. code-block:: python + + chat.join() + + Note: + This only works for public groups and channels that have set a username. + + Returns: + :obj:`Chat`: On success, a chat object is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + + return await self._client.join_chat(self.username) + + async def leave(self): + """Bound method *leave* of :obj:`Chat`. + + Use as a shortcut for: + + .. code-block:: python + + client.leave_chat(123456789) + + Example: + .. code-block:: python + + chat.leave() + + Raises: + RPCError: In case of a Telegram RPC error. + """ + + return await self._client.leave_chat(self.id) 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 ) diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index 429de199..b1377064 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -412,9 +412,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))) await asyncio.sleep(0.5)