2
0
mirror of https://github.com/pyrogram/pyrogram synced 2025-08-29 13:27:47 +00:00

Merge develop -> asyncio

This commit is contained in:
Dan 2019-07-30 00:06:06 +02:00
commit 0f9029202e
127 changed files with 2189 additions and 562 deletions

View File

@ -136,6 +136,7 @@ def pyrogram_api():
remove_handler remove_handler
stop_transmission stop_transmission
export_session_string export_session_string
set_parse_mode
""", """,
messages=""" messages="""
Messages Messages
@ -203,6 +204,12 @@ def pyrogram_api():
update_chat_username update_chat_username
archive_chats archive_chats
unarchive_chats unarchive_chats
add_chat_members
create_channel
create_group
create_supergroup
delete_channel
delete_supergroup
""", """,
users=""" users="""
Users Users
@ -334,6 +341,8 @@ def pyrogram_api():
InlineQuery InlineQuery
InlineQueryResult InlineQueryResult
InlineQueryResultArticle InlineQueryResultArticle
InlineQueryResultPhoto
InlineQueryResultAnimation
""", """,
input_message_content=""" input_message_content="""
InputMessageContent InputMessageContent
@ -412,11 +421,15 @@ def pyrogram_api():
Chat.unban_member Chat.unban_member
Chat.restrict_member Chat.restrict_member
Chat.promote_member Chat.promote_member
Chat.join
Chat.leave
""", """,
user=""" user="""
User User
User.archive User.archive
User.unarchive User.unarchive
User.block
User.unblock
""", """,
callback_query=""" callback_query="""
Callback Query Callback Query

View File

@ -114,3 +114,12 @@ 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_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_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} 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
1 id message
114 FILE_PART_SIZE_INVALID 512 KB cannot be evenly divided by part_size
115 FILE_PART_SIZE_CHANGED The part size is different from the size of one of the previous parts in the same file
116 FILE_MIGRATE_X The file is in Data Center No. {x}
117 RESULT_TYPE_INVALID The result type is invalid
118 PHOTO_THUMB_URL_EMPTY The photo thumb URL is empty
119 PHOTO_THUMB_URL_INVALID The photo thumb URL is invalid
120 PHOTO_CONTENT_URL_EMPTY The photo content URL is empty
121 PHOTO_CONTENT_TYPE_INVALID The photo content type is invalid
122 WEBDOCUMENT_INVALID The web document is invalid
123 WEBDOCUMENT_URL_EMPTY The web document URL is empty
124 WEBDOCUMENT_URL_INVALID The web document URL is invalid
125 WEBDOCUMENT_MIME_INVALID The web document mime type is invalid

View File

@ -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 <topics/proxy>`, because Telegram could be If you are connecting from Russia, China or Iran :doc:`you need a proxy <topics/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 <https://en.wikipedia.org/wiki/Blocking_Telegram_in_Russia>`_.
Another possible cause might be network issues, either yours or Telegram's. To confirm this, add the following code on 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 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? 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 The Telegram cloud is currently composed by a decentralized, multi-DC infrastructure (currently 5 DCs, each of which can
independently) spread in 5 different locations. However, some of the less busy DCs have been lately dismissed and their work independently) spread in different locations worldwide. However, some of the less busy DCs have been lately
IP addresses are now kept as aliases. dismissed and their IP addresses are now kept as aliases to the nearest one.
.. csv-table:: Production Environment .. csv-table:: Production Environment
:header: ID, Location, IPv4, IPv6 :header: ID, Location, IPv4, IPv6

View File

@ -316,9 +316,9 @@ attribute. Here's an example:
Unloading 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 In order to unload a plugin, all you need to do is obtain a reference to it by importing the relevant module and call
relevant module and call :meth:`~pyrogram.Client.remove_handler` Client's method with your function :meth:`~pyrogram.Client.remove_handler` Client's method with your function's *handler* special attribute preceded by the
name preceded by the star ``*`` operator as argument. Example: star ``*`` operator as argument. Example:
- ``main.py`` - ``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 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: exactly what is needed. The same could have been achieved with:
.. code-block:: python .. code-block:: python
handler, group = echo handler, group = echo.handler
app.remove_handler(handler, group) app.remove_handler(handler, group)
Loading Loading
@ -352,4 +352,4 @@ using :meth:`~pyrogram.Client.add_handler` instead. Example:
... ...
app.add_handler(*echo) app.add_handler(*echo.handler)

View File

@ -174,6 +174,17 @@ class Client(Methods, BaseClient):
download_media, ...) are less prone to throw FloodWait exceptions. download_media, ...) are less prone to throw FloodWait exceptions.
Only available for users, bots will ignore this parameter. Only available for users, bots will ignore this parameter.
Defaults to False (normal session). 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 terms_of_service_displayed = False
@ -275,11 +286,28 @@ class Client(Methods, BaseClient):
self._proxy.update(value) self._proxy.update(value)
async def start(self): 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: 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: if self.is_started:
raise ConnectionError("Client has already been started") raise ConnectionError("Client has already been started")
@ -346,8 +374,25 @@ class Client(Methods, BaseClient):
async def stop(self): async def stop(self):
"""Stop the Client. """Stop the Client.
This method disconnects the client from Telegram and stops the underlying tasks.
Has no parameters.
Raises: 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: if not self.is_started:
raise ConnectionError("Client is already stopped") raise ConnectionError("Client is already stopped")
@ -392,61 +437,118 @@ class Client(Methods, BaseClient):
async def restart(self): async def restart(self):
"""Restart the Client. """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: Raises:
ConnectionError: In case you try to restart a stopped Client. 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.stop()
await self.start() 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. """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 This static method will run an infinite loop in order to block the main script execution and prevent it from
continue its execution. 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, It is useful for event-driven application only, that are, applications which react upon incoming Telegram
applications which react upon incoming Telegram updates through handlers, rather than executing a set of methods updates through handlers, rather than executing a set of methods sequentially.
sequentially.
The way Pyrogram works, will keep your handlers in a pool of workers, which are executed concurrently outside The way Pyrogram works, it will keep your handlers in a pool of worker threads, which are executed concurrently
the main script; calling idle() will ensure the client(s) will be kept alive by not letting the main script to outside the main thread; calling idle() will ensure the client(s) will be kept alive by not letting the main
end, until you decide to quit. 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: Parameters:
stop_signals (``tuple``, *optional*): stop_signals (``tuple``, *optional*):
Iterable containing signals the signal handler will listen to. 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): def signal_handler(*args):
log.info("Stop signal received ({}). Exiting...".format(args[0])) log.info("Stop signal received ({}). Exiting...".format(args[0]))
self.is_idle = False Client.is_idling = False
for s in stop_signals: for s in stop_signals:
signal(s, signal_handler) 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 asyncio.sleep(1)
await self.stop()
def run(self, coroutine=None): 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 This is a convenience method that calls :meth:`~Client.start`, :meth:`~Client.idle` and :meth:`~Client.stop` in
running a client less verbose, but is not suitable in case you want to run more than one client in a single main sequence. It makes running a client less verbose, but is not suitable in case you want to run more than one
script, since :meth:`~Client.idle` will block. client in a single main script, since idle() will block after starting the own client.
Has no parameters.
Args: Args:
coroutine: (``Coroutine``, *optional*): coroutine: (``Coroutine``, *optional*):
Pass a coroutine to run it until is complete. Pass a coroutine to run it until is complete.
Raises: 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() loop = asyncio.get_event_loop()
run = loop.run_until_complete run = loop.run_until_complete
@ -455,19 +557,18 @@ class Client(Methods, BaseClient):
run(coroutine) run(coroutine)
else: else:
run(self.start()) run(self.start())
run(self.idle()) run(Client.idle())
run(self.stop())
# TODO: Uncomment this once idle() gets refactored
# run(self.stop())
loop.close() loop.close()
def add_handler(self, handler: Handler, group: int = 0): def add_handler(self, handler: Handler, group: int = 0):
"""Register an update handler. """Register an update handler.
You can register multiple handlers, but at most one handler within a group You can register multiple handlers, but at most one handler within a group will be used for a single update.
will be used for a single update. To handle the same update more than once, register To handle the same update more than once, register your handler using a different group id (lower group id
your handler using a different group id (lower group id == higher priority). == higher priority). This mechanism is explained in greater details at
:doc:`More on Updates <../../topics/more-on-updates>`.
Parameters: Parameters:
handler (``Handler``): handler (``Handler``):
@ -477,7 +578,22 @@ class Client(Methods, BaseClient):
The group identifier, defaults to 0. The group identifier, defaults to 0.
Returns: 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): if isinstance(handler, DisconnectHandler):
self.disconnect_handler = handler.callback self.disconnect_handler = handler.callback
@ -489,9 +605,8 @@ class Client(Methods, BaseClient):
def remove_handler(self, handler: Handler, group: int = 0): def remove_handler(self, handler: Handler, group: int = 0):
"""Remove a previously-registered update handler. """Remove a previously-registered update handler.
Make sure to provide the right group that the handler was added in. You can use Make sure to provide the right group where the handler was added in. You can use the return value of the
the return value of the :meth:`~Client.add_handler` method, a tuple of (handler, group), and :meth:`~Client.add_handler` method, a tuple of *(handler, group)*, and pass it directly.
pass it directly.
Parameters: Parameters:
handler (``Handler``): handler (``Handler``):
@ -499,6 +614,24 @@ class Client(Methods, BaseClient):
group (``int``, *optional*): group (``int``, *optional*):
The group identifier, defaults to 0. 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): if isinstance(handler, DisconnectHandler):
self.disconnect_handler = None self.disconnect_handler = None
@ -507,10 +640,109 @@ class Client(Methods, BaseClient):
def stop_transmission(self): def stop_transmission(self):
"""Stop downloading or uploading a file. """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 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 <i>html</i>")
# Force Markdown-only, HTML is disabled
app.set_parse_mode("markdown")
app.send_message("haskell", "2. **markdown** and <i>html</i>")
# Force HTML-only, Markdown is disabled
app.set_parse_mode("html")
app.send_message("haskell", "3. **markdown** and <i>html</i>")
# Disable the parser completely
app.set_parse_mode(None)
app.send_message("haskell", "4. **markdown** and <i>html</i>")
# Bring back the default combined mode
app.set_parse_mode()
app.send_message("haskell", "5. **markdown** and <i>html</i>")
"""
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): async def authorize_bot(self):
try: try:
r = await self.send( r = await self.send(
@ -1084,7 +1316,7 @@ class Client(Methods, BaseClient):
]) ])
if session_empty: if session_empty:
self.storage.dc_id = 1 self.storage.dc_id = 4
self.storage.date = 0 self.storage.date = 0
self.storage.test_mode = self.test_mode self.storage.test_mode = self.test_mode
@ -1120,7 +1352,7 @@ class Client(Methods, BaseClient):
for name in vars(module).keys(): for name in vars(module).keys():
# noinspection PyBroadException # noinspection PyBroadException
try: try:
handler, group = getattr(module, name).pyrogram_plugin handler, group = getattr(module, name).handler
if isinstance(handler, Handler) and isinstance(group, int): if isinstance(handler, Handler) and isinstance(group, int):
self.add_handler(handler, group) self.add_handler(handler, group)
@ -1155,7 +1387,7 @@ class Client(Methods, BaseClient):
for name in handlers: for name in handlers:
# noinspection PyBroadException # noinspection PyBroadException
try: try:
handler, group = getattr(module, name).pyrogram_plugin handler, group = getattr(module, name).handler
if isinstance(handler, Handler) and isinstance(group, int): if isinstance(handler, Handler) and isinstance(group, int):
self.add_handler(handler, group) self.add_handler(handler, group)
@ -1193,7 +1425,7 @@ class Client(Methods, BaseClient):
for name in handlers: for name in handlers:
# noinspection PyBroadException # noinspection PyBroadException
try: try:
handler, group = getattr(module, name).pyrogram_plugin handler, group = getattr(module, name).handler
if isinstance(handler, Handler) and isinstance(group, int): if isinstance(handler, Handler) and isinstance(group, int):
self.remove_handler(handler, group) 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. In case a file part expired, pass the file_id and the file_part to retry uploading that specific chunk.
progress (``callable``, *optional*): progress (``callable``, *optional*):
Pass a callback function to view the upload progress. Pass a callback function to view the file transmission progress.
The function must take *(client, current, total, \*args)* as positional arguments (look at the section The function must take *(current, total)* as positional arguments (look at Other Parameters below for a
below for a detailed description). detailed description) and will be called back each time a new file chunk has been successfully
transmitted.
progress_args (``tuple``, *optional*): progress_args (``tuple``, *optional*):
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass Extra custom arguments for the progress callback function.
a chat_id and a message_id in order to edit a message with the updated progress. 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: Other Parameters:
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the callback function.
current (``int``): current (``int``):
The amount of bytes uploaded so far. The amount of bytes transmitted so far.
total (``int``): total (``int``):
The size of the file. The total size of the file.
*args (``tuple``, *optional*): *args (``tuple``, *optional*):
Extra custom arguments as defined in the *progress_args* parameter. Extra custom arguments as defined in the *progress_args* parameter.
@ -1709,11 +1940,3 @@ class Client(Methods, BaseClient):
if extensions: if extensions:
return extensions.split(" ")[0] 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()

View File

@ -58,6 +58,8 @@ class BaseClient:
WORKDIR = PARENT_DIR WORKDIR = PARENT_DIR
CONFIG_FILE = PARENT_DIR / "config.ini" CONFIG_FILE = PARENT_DIR / "config.ini"
PARSE_MODES = ["combined", "markdown", "md", "html", None]
MEDIA_TYPE_ID = { MEDIA_TYPE_ID = {
0: "photo_thumbnail", 0: "photo_thumbnail",
1: "chat_photo", 1: "chat_photo",
@ -86,19 +88,21 @@ class BaseClient:
mime_types_to_extensions[mime_type] = " ".join(extensions) mime_types_to_extensions[mime_type] = " ".join(extensions)
is_idling = False
def __init__(self): def __init__(self):
self.storage = None self.storage = None
self.rnd_id = MsgId self.rnd_id = MsgId
self.parser = Parser(self) self.parser = Parser(self)
self.parse_mode = "combined"
self.session = None self.session = None
self.media_sessions = {} self.media_sessions = {}
self.media_sessions_lock = asyncio.Lock() self.media_sessions_lock = asyncio.Lock()
self.is_started = None self.is_started = None
self.is_idle = None
self.takeout_id = None self.takeout_id = None

View File

@ -136,7 +136,7 @@ class Filters:
poll = create(lambda _, m: m.poll, "PollFilter") poll = create(lambda _, m: m.poll, "PollFilter")
"""Filter messages that contain :obj:`Poll` objects.""" """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.""" """Filter messages sent in private chats."""
group = create(lambda _, m: bool(m.chat and m.chat.type in {"group", "supergroup"}), "GroupFilter") 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): def func(flt, message):
text = message.text or message.caption text = message.text or message.caption
message.command = None
if text: if text:
for p in flt.p: for p in flt.p:
@ -272,11 +273,15 @@ class Filters:
RegEx flags. RegEx flags.
""" """
def f(_, m): def func(flt, message):
m.matches = [i for i in _.p.finditer(m.text or m.caption or "")] text = message.text or message.caption
return bool(m.matches)
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 # noinspection PyPep8Naming
class user(Filter, set): class user(Filter, set):

View File

@ -56,8 +56,14 @@ class AnswerCallbackQuery(BaseClient):
Returns: Returns:
``bool``: True, on success. ``bool``: True, on success.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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( return await self.send(
functions.messages.SetBotCallbackAnswer( functions.messages.SetBotCallbackAnswer(

View File

@ -29,28 +29,34 @@ class AnswerInlineQuery(BaseClient):
inline_query_id: str, inline_query_id: str,
results: List[InlineQueryResult], results: List[InlineQueryResult],
cache_time: int = 300, cache_time: int = 300,
is_personal: bool = None, is_gallery: bool = False,
is_personal: bool = False,
next_offset: str = "", next_offset: str = "",
switch_pm_text: str = "", switch_pm_text: str = "",
switch_pm_parameter: str = "" switch_pm_parameter: str = ""
): ):
"""Send answers to an inline query. """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: Parameters:
inline_query_id (``str``): inline_query_id (``str``):
Unique identifier for the answered query. Unique identifier for the answered query.
results (List of :obj:`InlineQueryResult <pyrogram.InlineQueryResult>`): results (List of :obj:`InlineQueryResult`):
A list of results for the inline query. A list of results for the inline query.
cache_time (``int``, *optional*): cache_time (``int``, *optional*):
The maximum amount of time in seconds that the result of the inline query may be cached on the server. The maximum amount of time in seconds that the result of the inline query may be cached on the server.
Defaults to 300. 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*): is_personal (``bool``, *optional*):
Pass True, if results may be cached on the server side only for the user that sent the query. 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*): next_offset (``str``, *optional*):
Pass the offset that a client should send in the next query with the same text to receive more results. 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: Returns:
``bool``: True, on success. ``bool``: True, on success.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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 written_results = [] # Py 3.5 doesn't support await inside comprehensions
@ -88,7 +103,7 @@ class AnswerInlineQuery(BaseClient):
query_id=int(inline_query_id), query_id=int(inline_query_id),
results=written_results, results=written_results,
cache_time=cache_time, cache_time=cache_time,
gallery=None, gallery=is_gallery or None,
private=is_personal or None, private=is_personal or None,
next_offset=next_offset or None, next_offset=next_offset or None,
switch_pm=types.InlineBotSwitchPM( switch_pm=types.InlineBotSwitchPM(

View File

@ -51,8 +51,11 @@ class GetGameHighScores(BaseClient):
Returns: Returns:
List of :obj:`GameHighScore`: On success. List of :obj:`GameHighScore`: On success.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
scores = app.get_game_high_scores(user_id, chat_id, message_id)
print(scores)
""" """
# TODO: inline_message_id # TODO: inline_message_id

View File

@ -27,7 +27,7 @@ class GetInlineBotResults(BaseClient):
async def get_inline_bot_results( async def get_inline_bot_results(
self, self,
bot: Union[int, str], bot: Union[int, str],
query: str, query: str = "",
offset: str = "", offset: str = "",
latitude: float = None, latitude: float = None,
longitude: 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 Unique identifier of the inline bot you want to get results from. You can specify
a @username (str) or a bot ID (int). a @username (str) or a bot ID (int).
query (``str``): query (``str``, *optional*):
Text of the query (up to 512 characters). Text of the query (up to 512 characters).
Defaults to "" (empty string).
offset (``str``, *optional*): offset (``str``, *optional*):
Offset of the results to be returned. Offset of the results to be returned.
@ -58,8 +59,13 @@ class GetInlineBotResults(BaseClient):
:obj:`BotResults <pyrogram.api.types.messages.BotResults>`: On Success. :obj:`BotResults <pyrogram.api.types.messages.BotResults>`: On Success.
Raises: Raises:
RPCError: In case of a Telegram RPC error.
TimeoutError: In case the bot fails to answer within 10 seconds. 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 # TODO: Don't return the raw type

View File

@ -53,8 +53,12 @@ class RequestCallbackAnswer(BaseClient):
or as an alert. or as an alert.
Raises: Raises:
RPCError: In case of a Telegram RPC error.
TimeoutError: In case the bot fails to answer within 10 seconds. 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. # Telegram only wants bytes, but we are allowed to pass strings too.

View File

@ -62,8 +62,10 @@ class SendGame(BaseClient):
Returns: Returns:
:obj:`Message`: On success, the sent game message is returned. :obj:`Message`: On success, the sent game message is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
app.send_game(chat_id, "gamename")
""" """
r = await self.send( r = await self.send(
functions.messages.SendMedia( functions.messages.SendMedia(

View File

@ -60,8 +60,10 @@ class SendInlineBotResult(BaseClient):
Returns: Returns:
:obj:`Message`: On success, the sent inline result message is returned. :obj:`Message`: On success, the sent inline result message is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
app.send_inline_bot_result(chat_id, query_id, result_id)
""" """
return await self.send( return await self.send(
functions.messages.SendInlineBotResult( functions.messages.SendInlineBotResult(

View File

@ -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, :obj:`Message` | ``bool``: On success, if the message was sent by the bot, the edited message is returned,
True otherwise. True otherwise.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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( r = await self.send(
functions.messages.SetGameScore( functions.messages.SetGameScore(

View File

@ -16,8 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from .add_chat_members import AddChatMembers
from .archive_chats import ArchiveChats 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_chat_photo import DeleteChatPhoto
from .delete_supergroup import DeleteSupergroup
from .export_chat_invite_link import ExportChatInviteLink from .export_chat_invite_link import ExportChatInviteLink
from .get_chat import GetChat from .get_chat import GetChat
from .get_chat_member import GetChatMember from .get_chat_member import GetChatMember
@ -68,6 +74,12 @@ class Chats(
RestrictChat, RestrictChat,
GetDialogsCount, GetDialogsCount,
ArchiveChats, ArchiveChats,
UnarchiveChats UnarchiveChats,
CreateGroup,
CreateSupergroup,
CreateChannel,
AddChatMembers,
DeleteChannel,
DeleteSupergroup
): ):
pass pass

View File

@ -0,0 +1,88 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2019 Dan Tès <https://github.com/delivrance>
#
# 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 <http://www.gnu.org/licenses/>.
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

View File

@ -37,8 +37,14 @@ class ArchiveChats(BaseClient):
Returns: Returns:
``bool``: On success, True is returned. ``bool``: On success, True is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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): if not isinstance(chat_ids, list):

View File

@ -0,0 +1,55 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2019 Dan Tès <https://github.com/delivrance>
#
# 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 <http://www.gnu.org/licenses/>.
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])

View File

@ -0,0 +1,65 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2019 Dan Tès <https://github.com/delivrance>
#
# 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 <http://www.gnu.org/licenses/>.
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])

View File

@ -0,0 +1,59 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2019 Dan Tès <https://github.com/delivrance>
#
# 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 <http://www.gnu.org/licenses/>.
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])

View File

@ -0,0 +1,48 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2019 Dan Tès <https://github.com/delivrance>
#
# 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 <http://www.gnu.org/licenses/>.
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

View File

@ -28,12 +28,8 @@ class DeleteChatPhoto(BaseClient):
chat_id: Union[int, str] chat_id: Union[int, str]
) -> bool: ) -> bool:
"""Delete a chat photo. """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: You must be an administrator in the chat for this to work and must have the appropriate admin rights.
In regular groups (non-supergroups), this method will only work if the "All Members Are Admins"
setting is off.
Parameters: Parameters:
chat_id (``int`` | ``str``): chat_id (``int`` | ``str``):
@ -43,8 +39,12 @@ class DeleteChatPhoto(BaseClient):
``bool``: True on success. ``bool``: True on success.
Raises: 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) peer = await self.resolve_peer(chat_id)

View File

@ -0,0 +1,48 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2019 Dan Tès <https://github.com/delivrance>
#
# 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 <http://www.gnu.org/licenses/>.
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

View File

@ -47,8 +47,13 @@ class ExportChatInviteLink(BaseClient):
``str``: On success, the exported invite link is returned. ``str``: On success, the exported invite link is returned.
Raises: Raises:
RPCError: In case of a Telegram RPC error.
ValueError: In case the chat_id belongs to a user. 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) peer = await self.resolve_peer(chat_id)

View File

@ -44,8 +44,13 @@ class GetChat(BaseClient):
otherwise, a chat preview object is returned. otherwise, a chat preview object is returned.
Raises: 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. 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)) match = self.INVITE_LINK_RE.match(str(chat_id))

View File

@ -45,8 +45,11 @@ class GetChatMember(BaseClient):
Returns: Returns:
:obj:`ChatMember`: On success, a chat member is returned. :obj:`ChatMember`: On success, a chat member is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
dan = app.get_chat_member("pyrogramchat", "haskell")
print(dan)
""" """
chat = await self.resolve_peer(chat_id) chat = await self.resolve_peer(chat_id)
user = await self.resolve_peer(user_id) user = await self.resolve_peer(user_id)

View File

@ -92,8 +92,19 @@ class GetChatMembers(BaseClient):
List of :obj:`ChatMember`: On success, a list of chat members is returned. List of :obj:`ChatMember`: On success, a list of chat members is returned.
Raises: 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. 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) peer = await self.resolve_peer(chat_id)

View File

@ -37,8 +37,13 @@ class GetChatMembersCount(BaseClient):
``int``: On success, the chat members count is returned. ``int``: On success, the chat members count is returned.
Raises: Raises:
RPCError: In case of a Telegram RPC error.
ValueError: In case a chat id belongs to user. 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) peer = await self.resolve_peer(chat_id)

View File

@ -57,8 +57,14 @@ class GetDialogs(BaseClient):
Returns: Returns:
List of :obj:`Dialog`: On success, a list of dialogs is returned. List of :obj:`Dialog`: On success, a list of dialogs is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
# Get first 100 dialogs
app.get_dialogs()
# Get pinned dialogs
app.get_dialogs(pinned_only=True)
""" """
while True: while True:

View File

@ -31,8 +31,11 @@ class GetDialogsCount(BaseClient):
Returns: Returns:
``int``: On success, the dialogs count is returned. ``int``: On success, the dialogs count is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
count = app.get_dialogs_count()
print(count)
""" """
if pinned_only: if pinned_only:

View File

@ -80,8 +80,20 @@ class IterChatMembers(BaseClient):
Returns: Returns:
``Generator``: A generator yielding :obj:`ChatMember` objects. ``Generator``: A generator yielding :obj:`ChatMember` objects.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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 current = 0
yielded = set() yielded = set()

View File

@ -49,8 +49,12 @@ class IterDialogs(BaseClient):
Returns: Returns:
``Generator``: A generator yielding :obj:`Dialog` objects. ``Generator``: A generator yielding :obj:`Dialog` objects.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
# Iterate through all dialogs
for dialog in app.iter_dialogs():
print(dialog.chat.first_name or dialog.chat.title)
""" """
current = 0 current = 0
total = limit or (1 << 31) - 1 total = limit or (1 << 31) - 1

View File

@ -36,8 +36,14 @@ class JoinChat(BaseClient):
Returns: Returns:
:obj:`Chat`: On success, a chat object is returned. :obj:`Chat`: On success, a chat object is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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) match = self.INVITE_LINK_RE.match(chat_id)

View File

@ -57,8 +57,16 @@ class KickChatMember(BaseClient):
:obj:`Message` | ``bool``: On success, a service message will be returned (when applicable), otherwise, in :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. case a message object couldn't be returned, True is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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) chat_peer = await self.resolve_peer(chat_id)
user_peer = await self.resolve_peer(user_id) user_peer = await self.resolve_peer(user_id)

View File

@ -37,9 +37,16 @@ class LeaveChat(BaseClient):
delete (``bool``, *optional*): delete (``bool``, *optional*):
Deletes the group chat dialog after leaving (for simple group chats, not supergroups). Deletes the group chat dialog after leaving (for simple group chats, not supergroups).
Defaults to False.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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) peer = await self.resolve_peer(chat_id)

View File

@ -47,8 +47,14 @@ class PinChatMessage(BaseClient):
Returns: Returns:
``bool``: True on success. ``bool``: True on success.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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( await self.send(
functions.messages.UpdatePinnedMessage( functions.messages.UpdatePinnedMessage(

View File

@ -78,8 +78,11 @@ class PromoteChatMember(BaseClient):
Returns: Returns:
``bool``: True on success. ``bool``: True on success.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
# Promote chat member to supergroup admin
app.promote_chat_member(chat_id, user_id)
""" """
await self.send( await self.send(
functions.channels.EditAdmin( functions.channels.EditAdmin(

View File

@ -72,8 +72,14 @@ class RestrictChat(BaseClient):
Returns: Returns:
:obj:`Chat`: On success, a chat object is returned. :obj:`Chat`: On success, a chat object is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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_messages = True
send_media = True send_media = True

View File

@ -85,8 +85,19 @@ class RestrictChatMember(BaseClient):
Returns: Returns:
:obj:`Chat`: On success, a chat object is returned. :obj:`Chat`: On success, a chat object is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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_messages = True
send_media = True send_media = True

View File

@ -42,8 +42,12 @@ class SetChatDescription(BaseClient):
``bool``: True on success. ``bool``: True on success.
Raises: 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) peer = await self.resolve_peer(chat_id)

View File

@ -17,12 +17,11 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import os import os
from base64 import b64decode
from struct import unpack from struct import unpack
from typing import Union from typing import Union
from pyrogram.api import functions, types from pyrogram.api import functions, types
from ...ext import BaseClient from ...ext import BaseClient, utils
class SetChatPhoto(BaseClient): class SetChatPhoto(BaseClient):
@ -32,38 +31,43 @@ class SetChatPhoto(BaseClient):
photo: str photo: str
) -> bool: ) -> bool:
"""Set a new profile photo for the chat. """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: You must be an administrator in the chat for this to work and must have the appropriate admin rights.
In regular groups (non-supergroups), this method will only work if the "All Members Are Admins"
setting is off.
Parameters: Parameters:
chat_id (``int`` | ``str``): chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat. Unique identifier (int) or username (str) of the target chat.
photo (``str``): 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: Returns:
``bool``: True on success. ``bool``: True on success.
Raises: 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
# 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) peer = await self.resolve_peer(chat_id)
if os.path.exists(photo): if os.path.exists(photo):
photo = types.InputChatUploadedPhoto(file=self.save_file(photo)) photo = types.InputChatUploadedPhoto(file=self.save_file(photo))
else: else:
s = unpack("<qq", b64decode(photo + "=" * (-len(photo) % 4), "-_")) unpacked = unpack("<iiqqc", utils.decode(photo))
photo = types.InputChatPhoto( photo = types.InputChatPhoto(
id=types.InputPhoto( id=types.InputPhoto(
id=s[0], id=unpacked[2],
access_hash=s[1], access_hash=unpacked[3],
file_reference=b"" file_reference=b""
) )
) )

View File

@ -47,8 +47,12 @@ class SetChatTitle(BaseClient):
``bool``: True on success. ``bool``: True on success.
Raises: Raises:
RPCError: In case of a Telegram RPC error.
ValueError: In case a chat id belongs to user. ValueError: In case a chat id belongs to user.
Example:
.. code-block:: python
app.set_chat_title(chat_id, "New Title")
""" """
peer = await self.resolve_peer(chat_id) peer = await self.resolve_peer(chat_id)

View File

@ -37,8 +37,14 @@ class UnarchiveChats(BaseClient):
Returns: Returns:
``bool``: On success, True is returned. ``bool``: On success, True is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
# Unarchive chat
app.unarchive_chats(chat_id)
# Unarchive multiple chats at once
app.unarchive_chats([chat_id1, chat_id2, chat_id3])
""" """
if not isinstance(chat_ids, list): if not isinstance(chat_ids, list):

View File

@ -43,8 +43,11 @@ class UnbanChatMember(BaseClient):
Returns: Returns:
``bool``: True on success. ``bool``: True on success.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
# Unban chat member right now
app.unban_chat_member(chat_id, user_id)
""" """
await self.send( await self.send(
functions.channels.EditBanned( functions.channels.EditBanned(

View File

@ -38,8 +38,10 @@ class UnpinChatMessage(BaseClient):
Returns: Returns:
``bool``: True on success. ``bool``: True on success.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
app.unpin_chat_message(chat_id)
""" """
await self.send( await self.send(
functions.messages.UpdatePinnedMessage( functions.messages.UpdatePinnedMessage(

View File

@ -42,8 +42,12 @@ class UpdateChatUsername(BaseClient):
``bool``: True on success. ``bool``: True on success.
Raises: Raises:
RPCError: In case of a Telegram RPC error.
ValueError: In case a chat id belongs to a user or chat. ValueError: In case a chat id belongs to a user or chat.
Example:
.. code-block:: python
app.update_chat_username(chat_id, "new_username")
""" """
peer = await self.resolve_peer(chat_id) peer = await self.resolve_peer(chat_id)

View File

@ -37,8 +37,15 @@ class AddContacts(BaseClient):
Returns: Returns:
:obj:`types.contacts.ImportedContacts` :obj:`types.contacts.ImportedContacts`
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
from pyrogram import InputPhoneContact
app.add_contacts([
InputPhoneContact("39123456789", "Foo"),
InputPhoneContact("38987654321", "Bar"),
InputPhoneContact("01234567891", "Baz")])
""" """
imported_contacts = await self.send( imported_contacts = await self.send(
functions.contacts.ImportContacts( functions.contacts.ImportContacts(

View File

@ -38,8 +38,10 @@ class DeleteContacts(BaseClient):
Returns: Returns:
``bool``: True on success. ``bool``: True on success.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
app.delete_contacts([user_id1, user_id2, user_id3])
""" """
contacts = [] contacts = []

View File

@ -30,14 +30,16 @@ log = logging.getLogger(__name__)
class GetContacts(BaseClient): class GetContacts(BaseClient):
async def get_contacts(self) -> List["pyrogram.User"]: async def get_contacts(self) -> List["pyrogram.User"]:
# TODO: Create a Users object and return that
"""Get contacts from your Telegram address book. """Get contacts from your Telegram address book.
Returns: Returns:
List of :obj:`User`: On success, a list of users is returned. List of :obj:`User`: On success, a list of users is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
contacts = app.get_contacts()
print(contacts)
""" """
while True: while True:
try: try:

View File

@ -27,8 +27,11 @@ class GetContactsCount(BaseClient):
Returns: Returns:
``int``: On success, the contacts count is returned. ``int``: On success, the contacts count is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
count = app.get_contacts_count()
print(count)
""" """
return len((await self.send(functions.contacts.GetContacts(hash=0))).contacts) return len((await self.send(functions.contacts.GetContacts(hash=0))).contacts)

View File

@ -47,7 +47,7 @@ class OnCallbackQuery(BaseClient):
if isinstance(self, pyrogram.Client): if isinstance(self, pyrogram.Client):
self.add_handler(pyrogram.CallbackQueryHandler(func, filters), group) self.add_handler(pyrogram.CallbackQueryHandler(func, filters), group)
elif isinstance(self, Filter) or self is None: elif isinstance(self, Filter) or self is None:
func.pyrogram_plugin = ( func.handler = (
pyrogram.CallbackQueryHandler(func, self), pyrogram.CallbackQueryHandler(func, self),
group if filters is None else filters group if filters is None else filters
) )

View File

@ -47,7 +47,7 @@ class OnDeletedMessages(BaseClient):
if isinstance(self, pyrogram.Client): if isinstance(self, pyrogram.Client):
self.add_handler(pyrogram.DeletedMessagesHandler(func, filters), group) self.add_handler(pyrogram.DeletedMessagesHandler(func, filters), group)
elif isinstance(self, Filter) or self is None: elif isinstance(self, Filter) or self is None:
func.pyrogram_plugin = ( func.handler = (
pyrogram.DeletedMessagesHandler(func, self), pyrogram.DeletedMessagesHandler(func, self),
group if filters is None else filters group if filters is None else filters
) )

View File

@ -46,7 +46,7 @@ class OnInlineQuery(BaseClient):
if isinstance(self, pyrogram.Client): if isinstance(self, pyrogram.Client):
self.add_handler(pyrogram.InlineQueryHandler(func, filters), group) self.add_handler(pyrogram.InlineQueryHandler(func, filters), group)
elif isinstance(self, Filter) or self is None: elif isinstance(self, Filter) or self is None:
func.pyrogram_plugin = ( func.handler = (
pyrogram.InlineQueryHandler(func, self), pyrogram.InlineQueryHandler(func, self),
group if filters is None else filters group if filters is None else filters
) )

View File

@ -46,7 +46,7 @@ class OnMessage(BaseClient):
if isinstance(self, pyrogram.Client): if isinstance(self, pyrogram.Client):
self.add_handler(pyrogram.MessageHandler(func, filters), group) self.add_handler(pyrogram.MessageHandler(func, filters), group)
elif isinstance(self, Filter) or self is None: elif isinstance(self, Filter) or self is None:
func.pyrogram_plugin = ( func.handler = (
pyrogram.MessageHandler(func, self), pyrogram.MessageHandler(func, self),
group if filters is None else filters group if filters is None else filters
) )

View File

@ -46,7 +46,7 @@ class OnPoll(BaseClient):
if isinstance(self, pyrogram.Client): if isinstance(self, pyrogram.Client):
self.add_handler(pyrogram.PollHandler(func, filters), group) self.add_handler(pyrogram.PollHandler(func, filters), group)
elif isinstance(self, Filter) or self is None: elif isinstance(self, Filter) or self is None:
func.pyrogram_plugin = ( func.handler = (
pyrogram.PollHandler(func, self), pyrogram.PollHandler(func, self),
group if filters is None else filters group if filters is None else filters
) )

View File

@ -40,7 +40,7 @@ class OnRawUpdate(BaseClient):
if isinstance(self, pyrogram.Client): if isinstance(self, pyrogram.Client):
self.add_handler(pyrogram.RawUpdateHandler(func), group) self.add_handler(pyrogram.RawUpdateHandler(func), group)
else: else:
func.pyrogram_plugin = ( func.handler = (
pyrogram.RawUpdateHandler(func), pyrogram.RawUpdateHandler(func),
group if self is None else group group if self is None else group
) )

View File

@ -44,7 +44,7 @@ class OnUserStatus(BaseClient):
if isinstance(self, pyrogram.Client): if isinstance(self, pyrogram.Client):
self.add_handler(pyrogram.UserStatusHandler(func, filters), group) self.add_handler(pyrogram.UserStatusHandler(func, filters), group)
elif isinstance(self, Filter) or self is None: elif isinstance(self, Filter) or self is None:
func.pyrogram_plugin = ( func.handler = (
pyrogram.UserStatusHandler(func, self), pyrogram.UserStatusHandler(func, self),
group if filters is None else filters group if filters is None else filters
) )

View File

@ -50,8 +50,17 @@ class DeleteMessages(BaseClient):
Returns: Returns:
``bool``: True on success, False otherwise. ``bool``: True on success, False otherwise.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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) peer = await self.resolve_peer(chat_id)
message_ids = list(message_ids) if not isinstance(message_ids, int) else [message_ids] message_ids = list(message_ids) if not isinstance(message_ids, int) else [message_ids]

View File

@ -58,24 +58,23 @@ class DownloadMedia(BaseClient):
Blocks the code execution until the file has been downloaded. Blocks the code execution until the file has been downloaded.
Defaults to True. Defaults to True.
progress (``callable``): progress (``callable``, *optional*):
Pass a callback function to view the download progress. Pass a callback function to view the file transmission progress.
The function must take *(client, current, total, \*args)* as positional arguments (look at the section The function must take *(current, total)* as positional arguments (look at Other Parameters below for a
below for a detailed description). detailed description) and will be called back each time a new file chunk has been successfully
transmitted.
progress_args (``tuple``): progress_args (``tuple``, *optional*):
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass Extra custom arguments for the progress callback function.
a chat_id and a message_id in order to edit a message with the updated progress. 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: Other Parameters:
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the callback function.
current (``int``): current (``int``):
The amount of bytes downloaded so far. The amount of bytes transmitted so far.
total (``int``): total (``int``):
The size of the file. The total size of the file.
*args (``tuple``, *optional*): *args (``tuple``, *optional*):
Extra custom arguments as defined in the *progress_args* parameter. 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. the download failed or was deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises: Raises:
RPCError: In case of a Telegram RPC error.
ValueError: if the message doesn't contain any downloadable media 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" error_message = "This message doesn't contain any downloadable media"
available_media = ("audio", "document", "photo", "sticker", "animation", "video", "voice", "video_note") available_media = ("audio", "document", "photo", "sticker", "animation", "video", "voice", "video_note")
@ -208,7 +215,8 @@ class DownloadMedia(BaseClient):
extension 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: if block:
await done.wait() await done.wait()

View File

@ -16,6 +16,8 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union
import pyrogram import pyrogram
from pyrogram.client.ext import BaseClient from pyrogram.client.ext import BaseClient
@ -25,10 +27,10 @@ class EditInlineCaption(BaseClient):
self, self,
inline_message_id: str, inline_message_id: str,
caption: str, caption: str,
parse_mode: str = "", parse_mode: Union[str, None] = object,
reply_markup: "pyrogram.InlineKeyboardMarkup" = None reply_markup: "pyrogram.InlineKeyboardMarkup" = None
) -> bool: ) -> bool:
"""Edit the caption of **inline** media messages. """Edit the caption of inline media messages.
Parameters: Parameters:
inline_message_id (``str``): inline_message_id (``str``):
@ -50,8 +52,11 @@ class EditInlineCaption(BaseClient):
Returns: Returns:
``bool``: On success, True is returned. ``bool``: On success, True is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
# Bots only
app.edit_inline_caption(inline_message_id, "new media caption")
""" """
return await self.edit_inline_text( return await self.edit_inline_text(
inline_message_id=inline_message_id, inline_message_id=inline_message_id,

View File

@ -33,7 +33,7 @@ class EditInlineMedia(BaseClient):
media: InputMedia, media: InputMedia,
reply_markup: "pyrogram.InlineKeyboardMarkup" = None reply_markup: "pyrogram.InlineKeyboardMarkup" = None
) -> bool: ) -> 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 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. or specify a URL.
@ -52,8 +52,21 @@ class EditInlineMedia(BaseClient):
Returns: Returns:
``bool``: On success, True is returned. ``bool``: On success, True is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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 caption = media.caption
parse_mode = media.parse_mode parse_mode = media.parse_mode

View File

@ -27,7 +27,7 @@ class EditInlineReplyMarkup(BaseClient):
inline_message_id: str, inline_message_id: str,
reply_markup: "pyrogram.InlineKeyboardMarkup" = None reply_markup: "pyrogram.InlineKeyboardMarkup" = None
) -> bool: ) -> 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: Parameters:
inline_message_id (``str``): inline_message_id (``str``):
@ -39,8 +39,16 @@ class EditInlineReplyMarkup(BaseClient):
Returns: Returns:
``bool``: On success, True is returned. ``bool``: On success, True is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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( return await self.send(
functions.messages.EditInlineBotMessage( functions.messages.EditInlineBotMessage(

View File

@ -28,11 +28,11 @@ class EditInlineText(BaseClient):
self, self,
inline_message_id: str, inline_message_id: str,
text: str, text: str,
parse_mode: Union[str, None] = "", parse_mode: Union[str, None] = object,
disable_web_page_preview: bool = None, disable_web_page_preview: bool = None,
reply_markup: "pyrogram.InlineKeyboardMarkup" = None reply_markup: "pyrogram.InlineKeyboardMarkup" = None
) -> bool: ) -> bool:
"""Edit the text of **inline** messages. """Edit the text of inline messages.
Parameters: Parameters:
inline_message_id (``str``): inline_message_id (``str``):
@ -57,8 +57,18 @@ class EditInlineText(BaseClient):
Returns: Returns:
``bool``: On success, True is returned. ``bool``: On success, True is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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( return await self.send(

View File

@ -28,7 +28,7 @@ class EditMessageCaption(BaseClient):
chat_id: Union[int, str], chat_id: Union[int, str],
message_id: int, message_id: int,
caption: str, caption: str,
parse_mode: str = "", parse_mode: Union[str, None] = object,
reply_markup: "pyrogram.InlineKeyboardMarkup" = None reply_markup: "pyrogram.InlineKeyboardMarkup" = None
) -> "pyrogram.Message": ) -> "pyrogram.Message":
"""Edit the caption of media messages. """Edit the caption of media messages.
@ -58,8 +58,10 @@ class EditMessageCaption(BaseClient):
Returns: Returns:
:obj:`Message`: On success, the edited message is returned. :obj:`Message`: On success, the edited message is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
app.edit_message_caption(chat_id, message_id, "new media caption")
""" """
return await self.edit_message_text( return await self.edit_message_text(
chat_id=chat_id, chat_id=chat_id,

View File

@ -60,8 +60,19 @@ class EditMessageMedia(BaseClient):
Returns: Returns:
:obj:`Message`: On success, the edited message is returned. :obj:`Message`: On success, the edited message is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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 caption = media.caption
parse_mode = media.parse_mode parse_mode = media.parse_mode

View File

@ -47,8 +47,16 @@ class EditMessageReplyMarkup(BaseClient):
Returns: Returns:
:obj:`Message`: On success, the edited message is returned. :obj:`Message`: On success, the edited message is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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( r = await self.send(
functions.messages.EditMessage( functions.messages.EditMessage(

View File

@ -29,7 +29,7 @@ class EditMessageText(BaseClient):
chat_id: Union[int, str], chat_id: Union[int, str],
message_id: int, message_id: int,
text: str, text: str,
parse_mode: Union[str, None] = "", parse_mode: Union[str, None] = object,
disable_web_page_preview: bool = None, disable_web_page_preview: bool = None,
reply_markup: "pyrogram.InlineKeyboardMarkup" = None reply_markup: "pyrogram.InlineKeyboardMarkup" = None
) -> "pyrogram.Message": ) -> "pyrogram.Message":
@ -63,8 +63,16 @@ class EditMessageText(BaseClient):
Returns: Returns:
:obj:`Message`: On success, the edited message is returned. :obj:`Message`: On success, the edited message is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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( r = await self.send(

View File

@ -56,7 +56,8 @@ class ForwardMessages(BaseClient):
Users will receive a notification with no sound. Users will receive a notification with no sound.
as_copy (``bool``, *optional*): 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. Defaults to False.
remove_caption (``bool``, *optional*): 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 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. messages, even if such iterable contained just a single element.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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) is_iterable = not isinstance(message_ids, int)

View File

@ -71,8 +71,17 @@ class GetHistory(BaseClient):
Returns: Returns:
List of :obj:`Message` - On success, a list of the retrieved messages is returned. List of :obj:`Message` - On success, a list of the retrieved messages is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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) offset_id = offset_id or (1 if reverse else 0)

View File

@ -45,8 +45,10 @@ class GetHistoryCount(BaseClient):
Returns: Returns:
``int``: On success, the chat history count is returned. ``int``: On success, the chat history count is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
app.get_history_count("pyrogramchat")
""" """
r = await self.send( r = await self.send(

View File

@ -29,6 +29,9 @@ from ...ext import BaseClient, utils
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
# TODO: Rewrite using a flag for replied messages and have message_ids non-optional
class GetMessages(BaseClient): class GetMessages(BaseClient):
async def get_messages( async def get_messages(
self, self,
@ -37,7 +40,8 @@ class GetMessages(BaseClient):
reply_to_message_ids: Union[int, Iterable[int]] = None, reply_to_message_ids: Union[int, Iterable[int]] = None,
replies: int = 1 replies: int = 1
) -> Union["pyrogram.Message", List["pyrogram.Message"]]: ) -> 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. You can retrieve up to 200 messages at once.
Parameters: 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, 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. 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: Raises:
RPCError: In case of a Telegram RPC error. ValueError: In case of invalid arguments.
""" """
ids, ids_type = ( ids, ids_type = (
(message_ids, types.InputMessageID) if message_ids (message_ids, types.InputMessageID) if message_ids
@ -75,7 +97,7 @@ class GetMessages(BaseClient):
) )
if ids is None: 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) peer = await self.resolve_peer(chat_id)

View File

@ -67,8 +67,11 @@ class IterHistory(BaseClient):
Returns: Returns:
``Generator``: A generator yielding :obj:`Message` objects. ``Generator``: A generator yielding :obj:`Message` objects.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
for message in app.iter_history("pyrogram"):
print(message.text)
""" """
offset_id = offset_id or (1 if reverse else 0) offset_id = offset_id or (1 if reverse else 0)
current = 0 current = 0

View File

@ -43,8 +43,14 @@ class ReadHistory(BaseClient):
Returns: Returns:
``bool`` - On success, True is returned. ``bool`` - On success, True is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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) peer = self.resolve_peer(chat_id)

View File

@ -43,8 +43,10 @@ class RetractVote(BaseClient):
Returns: Returns:
:obj:`Poll`: On success, the poll with the retracted vote is returned. :obj:`Poll`: On success, the poll with the retracted vote is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
app.retract_vote(chat_id, message_id)
""" """
r = await self.send( r = await self.send(
functions.messages.SendVote( functions.messages.SendVote(

View File

@ -67,23 +67,22 @@ class SendAnimatedSticker(BaseClient):
instructions to remove reply keyboard or to force a reply from the user. instructions to remove reply keyboard or to force a reply from the user.
progress (``callable``, *optional*): progress (``callable``, *optional*):
Pass a callback function to view the upload progress. Pass a callback function to view the file transmission progress.
The function must take *(client, current, total, \*args)* as positional arguments (look at the section The function must take *(current, total)* as positional arguments (look at Other Parameters below for a
below for a detailed description). detailed description) and will be called back each time a new file chunk has been successfully
transmitted.
progress_args (``tuple``, *optional*): progress_args (``tuple``, *optional*):
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass Extra custom arguments for the progress callback function.
a chat_id and a message_id in order to edit a message with the updated progress. 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: Other Parameters:
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the callback function.
current (``int``): current (``int``):
The amount of bytes uploaded so far. The amount of bytes transmitted so far.
total (``int``): total (``int``):
The size of the file. The total size of the file.
*args (``tuple``, *optional*): *args (``tuple``, *optional*):
Extra custom arguments as defined in the *progress_args* parameter. Extra custom arguments as defined in the *progress_args* parameter.
@ -92,8 +91,12 @@ class SendAnimatedSticker(BaseClient):
Returns: Returns:
:obj:`Message` | ``None``: On success, the sent animated sticker message is returned, otherwise, in case the :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. 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 file = None

View File

@ -32,7 +32,7 @@ class SendAnimation(BaseClient):
animation: str, animation: str,
caption: str = "", caption: str = "",
unsave: bool = False, unsave: bool = False,
parse_mode: Union[str, None] = "", parse_mode: Union[str, None] = object,
duration: int = 0, duration: int = 0,
width: int = 0, width: int = 0,
height: int = 0, height: int = 0,
@ -66,7 +66,7 @@ class SendAnimation(BaseClient):
Animation caption, 0-1024 characters. Animation caption, 0-1024 characters.
unsave (``bool``, *optional*): 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. Pass True to automatically unsave the sent animation. Defaults to False.
parse_mode (``str``, *optional*): parse_mode (``str``, *optional*):
@ -103,23 +103,22 @@ class SendAnimation(BaseClient):
instructions to remove reply keyboard or to force a reply from the user. instructions to remove reply keyboard or to force a reply from the user.
progress (``callable``, *optional*): progress (``callable``, *optional*):
Pass a callback function to view the upload progress. Pass a callback function to view the file transmission progress.
The function must take *(client, current, total, \*args)* as positional arguments (look at the section The function must take *(current, total)* as positional arguments (look at Other Parameters below for a
below for a detailed description). detailed description) and will be called back each time a new file chunk has been successfully
transmitted.
progress_args (``tuple``, *optional*): progress_args (``tuple``, *optional*):
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass Extra custom arguments for the progress callback function.
a chat_id and a message_id in order to edit a message with the updated progress. 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: Other Parameters:
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the callback function.
current (``int``): current (``int``):
The amount of bytes uploaded so far. The amount of bytes transmitted so far.
total (``int``): total (``int``):
The size of the file. The total size of the file.
*args (``tuple``, *optional*): *args (``tuple``, *optional*):
Extra custom arguments as defined in the *progress_args* parameter. 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 :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. is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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 file = None

View File

@ -31,7 +31,7 @@ class SendAudio(BaseClient):
chat_id: Union[int, str], chat_id: Union[int, str],
audio: str, audio: str,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = "", parse_mode: Union[str, None] = object,
duration: int = 0, duration: int = 0,
performer: str = None, performer: str = None,
title: 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. instructions to remove reply keyboard or to force a reply from the user.
progress (``callable``, *optional*): progress (``callable``, *optional*):
Pass a callback function to view the upload progress. Pass a callback function to view the file transmission progress.
The function must take *(client, current, total, \*args)* as positional arguments (look at the section The function must take *(current, total)* as positional arguments (look at Other Parameters below for a
below for a detailed description). detailed description) and will be called back each time a new file chunk has been successfully
transmitted.
progress_args (``tuple``, *optional*): progress_args (``tuple``, *optional*):
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass Extra custom arguments for the progress callback function.
a chat_id and a message_id in order to edit a message with the updated progress. 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: Other Parameters:
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the callback function.
current (``int``): current (``int``):
The amount of bytes uploaded so far. The amount of bytes transmitted so far.
total (``int``): total (``int``):
The size of the file. The total size of the file.
*args (``tuple``, *optional*): *args (``tuple``, *optional*):
Extra custom arguments as defined in the *progress_args* parameter. 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 :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. is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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 file = None

View File

@ -29,7 +29,7 @@ class SendCachedMedia(BaseClient):
chat_id: Union[int, str], chat_id: Union[int, str],
file_id: str, file_id: str,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = "", parse_mode: Union[str, None] = object,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
reply_markup: Union[ reply_markup: Union[
@ -79,8 +79,10 @@ class SendCachedMedia(BaseClient):
Returns: Returns:
:obj:`Message`: On success, the sent media message is returned. :obj:`Message`: On success, the sent media message is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
app.send_cached_media("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI")
""" """
r = await self.send( r = await self.send(

View File

@ -64,8 +64,22 @@ class SendChatAction(BaseClient):
``bool``: On success, True is returned. ``bool``: On success, True is returned.
Raises: Raises:
RPCError: In case of a Telegram RPC error. ValueError: In case the provided string is not a valid chat action.
ValueError: In case the provided string is not a valid ChatAction.
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: try:

View File

@ -73,8 +73,10 @@ class SendContact(BaseClient):
Returns: Returns:
:obj:`Message`: On success, the sent contact message is returned. :obj:`Message`: On success, the sent contact message is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
app.send_contact("me", "+39 123 456 7890", "Dan")
""" """
r = await self.send( r = await self.send(
functions.messages.SendMedia( functions.messages.SendMedia(

View File

@ -31,7 +31,7 @@ class SendDocument(BaseClient):
chat_id: Union[int, str], chat_id: Union[int, str],
document: str, document: str,
thumb: str = None, caption: str = "", thumb: str = None, caption: str = "",
parse_mode: Union[str, None] = "", parse_mode: Union[str, None] = object,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
reply_markup: Union[ reply_markup: Union[
@ -85,23 +85,22 @@ class SendDocument(BaseClient):
instructions to remove reply keyboard or to force a reply from the user. instructions to remove reply keyboard or to force a reply from the user.
progress (``callable``, *optional*): progress (``callable``, *optional*):
Pass a callback function to view the upload progress. Pass a callback function to view the file transmission progress.
The function must take *(client, current, total, \*args)* as positional arguments (look at the section The function must take *(current, total)* as positional arguments (look at Other Parameters below for a
below for a detailed description). detailed description) and will be called back each time a new file chunk has been successfully
transmitted.
progress_args (``tuple``, *optional*): progress_args (``tuple``, *optional*):
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass Extra custom arguments for the progress callback function.
a chat_id and a message_id in order to edit a message with the updated progress. 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: Other Parameters:
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the callback function.
current (``int``): current (``int``):
The amount of bytes uploaded so far. The amount of bytes transmitted so far.
total (``int``): total (``int``):
The size of the file. The total size of the file.
*args (``tuple``, *optional*): *args (``tuple``, *optional*):
Extra custom arguments as defined in the *progress_args* parameter. 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 :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. is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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 file = None

View File

@ -66,8 +66,10 @@ class SendLocation(BaseClient):
Returns: Returns:
:obj:`Message`: On success, the sent location message is returned. :obj:`Message`: On success, the sent location message is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
app.send_location("me", 51.500729, -0.124583)
""" """
r = await self.send( r = await self.send(
functions.messages.SendMedia( functions.messages.SendMedia(

View File

@ -31,7 +31,6 @@ log = logging.getLogger(__name__)
class SendMediaGroup(BaseClient): class SendMediaGroup(BaseClient):
# TODO: Add progress parameter # TODO: Add progress parameter
# TODO: Figure out how to send albums using URLs
async def send_media_group( async def send_media_group(
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
@ -60,8 +59,19 @@ class SendMediaGroup(BaseClient):
Returns: Returns:
List of :obj:`Message`: On success, a list of the sent messages is returned. List of :obj:`Message`: On success, a list of the sent messages is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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 = [] multi_media = []
@ -88,7 +98,24 @@ class SendMediaGroup(BaseClient):
id=types.InputPhoto( id=types.InputPhoto(
id=media.photo.id, id=media.photo.id,
access_hash=media.photo.access_hash, 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: else:
@ -126,7 +153,24 @@ class SendMediaGroup(BaseClient):
id=types.InputDocument( id=types.InputDocument(
id=media.document.id, id=media.document.id,
access_hash=media.document.access_hash, 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: else:

View File

@ -28,7 +28,7 @@ class SendMessage(BaseClient):
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
text: str, text: str,
parse_mode: Union[str, None] = "", parse_mode: Union[str, None] = object,
disable_web_page_preview: bool = None, disable_web_page_preview: bool = None,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
@ -74,9 +74,44 @@ class SendMessage(BaseClient):
Returns: Returns:
:obj:`Message`: On success, the sent text message is returned. :obj:`Message`: On success, the sent text message is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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**, <i>italic<i>", 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() message, entities = (await self.parser.parse(text, parse_mode)).values()
r = await self.send( r = await self.send(

View File

@ -31,7 +31,7 @@ class SendPhoto(BaseClient):
chat_id: Union[int, str], chat_id: Union[int, str],
photo: str, photo: str,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = "", parse_mode: Union[str, None] = object,
ttl_seconds: int = None, ttl_seconds: int = None,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = 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. instructions to remove reply keyboard or to force a reply from the user.
progress (``callable``, *optional*): progress (``callable``, *optional*):
Pass a callback function to view the upload progress. Pass a callback function to view the file transmission progress.
The function must take *(client, current, total, \*args)* as positional arguments (look at the section The function must take *(current, total)* as positional arguments (look at Other Parameters below for a
below for a detailed description). detailed description) and will be called back each time a new file chunk has been successfully
transmitted.
progress_args (``tuple``, *optional*): progress_args (``tuple``, *optional*):
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass Extra custom arguments for the progress callback function.
a chat_id and a message_id in order to edit a message with the updated progress. 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: Other Parameters:
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the callback function.
current (``int``): current (``int``):
The amount of bytes uploaded so far. The amount of bytes transmitted so far.
total (``int``): total (``int``):
The size of the file. The total size of the file.
*args (``tuple``, *optional*): *args (``tuple``, *optional*):
Extra custom arguments as defined in the *progress_args* parameter. 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 :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. is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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 file = None

View File

@ -66,8 +66,10 @@ class SendPoll(BaseClient):
Returns: Returns:
:obj:`Message`: On success, the sent poll message is returned. :obj:`Message`: On success, the sent poll message is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
app.send_poll(chat_id, "Is this a poll question?", ["Yes", "No", "Maybe"])
""" """
r = self.send( r = self.send(
functions.messages.SendMedia( functions.messages.SendMedia(

View File

@ -67,23 +67,22 @@ class SendSticker(BaseClient):
instructions to remove reply keyboard or to force a reply from the user. instructions to remove reply keyboard or to force a reply from the user.
progress (``callable``, *optional*): progress (``callable``, *optional*):
Pass a callback function to view the upload progress. Pass a callback function to view the file transmission progress.
The function must take *(client, current, total, \*args)* as positional arguments (look at the section The function must take *(current, total)* as positional arguments (look at Other Parameters below for a
below for a detailed description). detailed description) and will be called back each time a new file chunk has been successfully
transmitted.
progress_args (``tuple``, *optional*): progress_args (``tuple``, *optional*):
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass Extra custom arguments for the progress callback function.
a chat_id and a message_id in order to edit a message with the updated progress. 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: Other Parameters:
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the callback function.
current (``int``): current (``int``):
The amount of bytes uploaded so far. The amount of bytes transmitted so far.
total (``int``): total (``int``):
The size of the file. The total size of the file.
*args (``tuple``, *optional*): *args (``tuple``, *optional*):
Extra custom arguments as defined in the *progress_args* parameter. Extra custom arguments as defined in the *progress_args* parameter.
@ -92,8 +91,15 @@ class SendSticker(BaseClient):
Returns: Returns:
:obj:`Message` | ``None``: On success, the sent sticker message is returned, otherwise, in case the upload :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. 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 file = None

View File

@ -83,8 +83,12 @@ class SendVenue(BaseClient):
Returns: Returns:
:obj:`Message`: On success, the sent venue message is returned. :obj:`Message`: On success, the sent venue message is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
app.send_venue(
"me", 51.500729, -0.124583,
"Elizabeth Tower", "Westminster, London SW1A 0AA, UK")
""" """
r = await self.send( r = await self.send(
functions.messages.SendMedia( functions.messages.SendMedia(

View File

@ -31,7 +31,7 @@ class SendVideo(BaseClient):
chat_id: Union[int, str], chat_id: Union[int, str],
video: str, video: str,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = "", parse_mode: Union[str, None] = object,
duration: int = 0, duration: int = 0,
width: int = 0, width: int = 0,
height: 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. instructions to remove reply keyboard or to force a reply from the user.
progress (``callable``, *optional*): progress (``callable``, *optional*):
Pass a callback function to view the upload progress. Pass a callback function to view the file transmission progress.
The function must take *(client, current, total, \*args)* as positional arguments (look at the section The function must take *(current, total)* as positional arguments (look at Other Parameters below for a
below for a detailed description). detailed description) and will be called back each time a new file chunk has been successfully
transmitted.
progress_args (``tuple``, *optional*): progress_args (``tuple``, *optional*):
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass Extra custom arguments for the progress callback function.
a chat_id and a message_id in order to edit a message with the updated progress. 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: Other Parameters:
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the callback function.
current (``int``): current (``int``):
The amount of bytes uploaded so far. The amount of bytes transmitted so far.
total (``int``): total (``int``):
The size of the file. The total size of the file.
*args (``tuple``, *optional*): *args (``tuple``, *optional*):
Extra custom arguments as defined in the *progress_args* parameter. 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 :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. is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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 file = None

View File

@ -82,23 +82,22 @@ class SendVideoNote(BaseClient):
instructions to remove reply keyboard or to force a reply from the user. instructions to remove reply keyboard or to force a reply from the user.
progress (``callable``, *optional*): progress (``callable``, *optional*):
Pass a callback function to view the upload progress. Pass a callback function to view the file transmission progress.
The function must take *(client, current, total, \*args)* as positional arguments (look at the section The function must take *(current, total)* as positional arguments (look at Other Parameters below for a
below for a detailed description). detailed description) and will be called back each time a new file chunk has been successfully
transmitted.
progress_args (``tuple``, *optional*): progress_args (``tuple``, *optional*):
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass Extra custom arguments for the progress callback function.
a chat_id and a message_id in order to edit a message with the updated progress. 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: Other Parameters:
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the callback function.
current (``int``): current (``int``):
The amount of bytes uploaded so far. The amount of bytes transmitted so far.
total (``int``): total (``int``):
The size of the file. The total size of the file.
*args (``tuple``, *optional*): *args (``tuple``, *optional*):
Extra custom arguments as defined in the *progress_args* parameter. 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 :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. upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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 file = None

View File

@ -31,7 +31,7 @@ class SendVoice(BaseClient):
chat_id: Union[int, str], chat_id: Union[int, str],
voice: str, voice: str,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = "", parse_mode: Union[str, None] = object,
duration: int = 0, duration: int = 0,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = 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. instructions to remove reply keyboard or to force a reply from the user.
progress (``callable``, *optional*): progress (``callable``, *optional*):
Pass a callback function to view the upload progress. Pass a callback function to view the file transmission progress.
The function must take *(client, current, total, \*args)* as positional arguments (look at the section The function must take *(current, total)* as positional arguments (look at Other Parameters below for a
below for a detailed description). detailed description) and will be called back each time a new file chunk has been successfully
transmitted.
progress_args (``tuple``, *optional*): progress_args (``tuple``, *optional*):
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass Extra custom arguments for the progress callback function.
a chat_id and a message_id in order to edit a message with the updated progress. 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: Other Parameters:
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the callback function.
current (``int``): current (``int``):
The amount of bytes uploaded so far. The amount of bytes transmitted so far.
total (``int``): total (``int``):
The size of the file. The total size of the file.
*args (``tuple``, *optional*): *args (``tuple``, *optional*):
Extra custom arguments as defined in the *progress_args* parameter. 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 :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. is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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 file = None

View File

@ -49,8 +49,10 @@ class StopPoll(BaseClient):
Returns: Returns:
:obj:`Poll`: On success, the stopped poll with the final results is returned. :obj:`Poll`: On success, the stopped poll with the final results is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
app.stop_poll(chat_id, message_id)
""" """
poll = (await self.get_messages(chat_id, message_id)).poll poll = (await self.get_messages(chat_id, message_id)).poll

View File

@ -47,8 +47,10 @@ class VotePoll(BaseClient):
Returns: Returns:
:obj:`Poll` - On success, the poll with the chosen option is returned. :obj:`Poll` - On success, the poll with the chosen option is returned.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
app.vote_poll(chat_id, message_id, 6)
""" """
poll = (await self.get_messages(chat_id, message_id)).poll poll = (await self.get_messages(chat_id, message_id)).poll

View File

@ -46,8 +46,16 @@ class ChangeCloudPassword(BaseClient):
``bool``: True on success. ``bool``: True on success.
Raises: Raises:
RPCError: In case of a Telegram RPC error.
ValueError: In case there is no cloud password to change. 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()) r = await self.send(functions.account.GetPassword())

View File

@ -48,8 +48,19 @@ class EnableCloudPassword(BaseClient):
``bool``: True on success. ``bool``: True on success.
Raises: Raises:
RPCError: In case of a Telegram RPC error.
ValueError: In case there is already a cloud password enabled. 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()) r = await self.send(functions.account.GetPassword())

View File

@ -36,8 +36,12 @@ class RemoveCloudPassword(BaseClient):
``bool``: True on success. ``bool``: True on success.
Raises: Raises:
RPCError: In case of a Telegram RPC error.
ValueError: In case there is no cloud password to remove. 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()) r = await self.send(functions.account.GetPassword())

View File

@ -30,11 +30,19 @@ class BlockUser(BaseClient):
) -> bool: ) -> bool:
"""Block a user. """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: Returns:
``bool``: True on success ``bool``: True on success
Raises: Example:
RPCError: In case of Telegram RPC Error. .. code-block:: python
app.block_user(user_id)
""" """
return bool( return bool(
await self.send( await self.send(

View File

@ -40,8 +40,17 @@ class DeleteProfilePhotos(BaseClient):
Returns: Returns:
``bool``: True on success. ``bool``: True on success.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. 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] photo_ids = photo_ids if isinstance(photo_ids, list) else [photo_ids]
input_photos = [] input_photos = []

View File

@ -26,10 +26,13 @@ class GetMe(BaseClient):
"""Get your own user identity. """Get your own user identity.
Returns: Returns:
:obj:`User`: Basic information about the user or bot. :obj:`User`: Information about the own logged in user/bot.
Raises: Example:
RPCError: In case of a Telegram RPC error. .. code-block:: python
me = app.get_me()
print(me)
""" """
return pyrogram.User._parse( return pyrogram.User._parse(
self, self,

Some files were not shown because too many files have changed in this diff Show More