diff --git a/docs/Makefile b/docs/Makefile
index c94d48cc..066560f8 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -21,4 +21,4 @@ help:
lhtml: # live html
sphinx-autobuild --host $(shell ifconfig | grep "inet " | grep -v 127.0.0.1 | cut -d\ -f2) \
- --watch ../pyrogram -b html "$(SOURCEDIR)" "$(BUILDDIR)/html" $(SPHINXOPTS)
+ --watch ../pyrogram --watch resources -b html "$(SOURCEDIR)" "$(BUILDDIR)/html" $(SPHINXOPTS)
diff --git a/docs/source/intro/quickstart.rst b/docs/source/intro/quickstart.rst
index 72f2dd86..cccbfbc7 100644
--- a/docs/source/intro/quickstart.rst
+++ b/docs/source/intro/quickstart.rst
@@ -50,7 +50,7 @@ Enjoy the API
That was just a quick overview. In the next few pages of the introduction, we'll take a much more in-depth look of what
we have just done above.
-If you are feeling eager to continue you can take a shortcut to :doc:`Calling Methods <../start/invoking>` and come back
+If you are feeling eager to continue you can take a shortcut to :doc:`Invoking Methods <../start/invoking>` and come back
later to learn some more details.
.. _community: https://t.me/Pyrogram
diff --git a/docs/source/start/auth.rst b/docs/source/start/auth.rst
index 39a4face..08c1875a 100644
--- a/docs/source/start/auth.rst
+++ b/docs/source/start/auth.rst
@@ -82,8 +82,8 @@ after the session name, which will be ``my_bot.session`` for the example below.
.. note::
- The API key (api_id and api_hash) and the bot_token is not needed anymore after a successful authorization.
- This means you can now simply use:
+ The API key (api_id and api_hash) and the bot_token are not required anymore after a successful authorization.
+ This means you can now simply use the following:
.. code-block:: python
diff --git a/docs/source/start/errors.rst b/docs/source/start/errors.rst
index 01881074..402fea8b 100644
--- a/docs/source/start/errors.rst
+++ b/docs/source/start/errors.rst
@@ -25,7 +25,7 @@ This error is raised every time a method call against Telegram's API was unsucce
from pyrogram.errors import RPCError
-.. note::
+.. warning::
Avoid catching this error everywhere, especially when no feedback is given (i.e. by logging/printing the full error
traceback), because it makes it impossible to understand what went wrong.
@@ -81,9 +81,6 @@ In case Pyrogram does not know anything about a specific error yet, it raises a
for example, an unknown error with error code ``400``, will be raised as a ``BadRequest``. This way you can catch the
whole category of errors and be sure to also handle these unknown errors.
-In case a whole class of errors is unknown (that is, an error code that is unknown), Pyrogram will raise a special
-``520 UnknownError`` exception.
-
Errors with Values
------------------
diff --git a/docs/source/start/updates.rst b/docs/source/start/updates.rst
index 450f0d85..685128c2 100644
--- a/docs/source/start/updates.rst
+++ b/docs/source/start/updates.rst
@@ -14,7 +14,7 @@ and how to handle new incoming messages or other events in Pyrogram.
Defining Updates
----------------
-As hinted already, updates are events that happen in your Telegram account (incoming messages, new members join,
+Updates are events that happen in your Telegram account (incoming messages, new members join,
bot button presses, etc.), which are meant to notify you about a new specific state that has changed. These updates are
handled by registering one or more callback functions in your app using :doc:`Handlers <../api/handlers>`.
diff --git a/docs/source/topics/advanced-usage.rst b/docs/source/topics/advanced-usage.rst
index c84528e4..86eb67c4 100644
--- a/docs/source/topics/advanced-usage.rst
+++ b/docs/source/topics/advanced-usage.rst
@@ -50,8 +50,8 @@ Here's some examples:
from pyrogram import Client
from pyrogram.raw import functions
- with Client("my_account") as app:
- app.send(
+ async with Client("my_account") as app:
+ await app.send(
functions.account.UpdateProfile(
first_name="First Name", last_name="Last Name",
about="New bio text"
@@ -65,12 +65,12 @@ Here's some examples:
from pyrogram import Client
from pyrogram.raw import functions, types
- with Client("my_account") as app:
+ async with Client("my_account") as app:
# Set online status
- app.send(functions.account.UpdateStatus(offline=False))
+ await app.send(functions.account.UpdateStatus(offline=False))
# Set offline status
- app.send(functions.account.UpdateStatus(offline=True))
+ await app.send(functions.account.UpdateStatus(offline=True))
- Get chat info:
@@ -79,8 +79,8 @@ Here's some examples:
from pyrogram import Client
from pyrogram.raw import functions, types
- with Client("my_account") as app:
- r = app.send(
+ async with Client("my_account") as app:
+ r = await app.send(
functions.channels.GetFullChannel(
channel=app.resolve_peer("username")
)
diff --git a/docs/source/topics/client-settings.rst b/docs/source/topics/client-settings.rst
index 1b93d99d..02dce713 100644
--- a/docs/source/topics/client-settings.rst
+++ b/docs/source/topics/client-settings.rst
@@ -18,16 +18,7 @@ settings. By default you will see something like the following:
Set Custom Values
-----------------
-To set custom values, you can either make use of the ``config.ini`` file, this way:
-
-.. code-block:: ini
-
- [pyrogram]
- app_version = 1.2.3
- device_model = PC
- system_version = Linux
-
-Or, pass the arguments directly in the Client's constructor.
+To set custom values, you can pass the arguments directly in the Client's constructor.
.. code-block:: python
@@ -47,11 +38,6 @@ English).
With the following code we make Telegram know we want it to speak in Italian (it):
-.. code-block:: ini
-
- [pyrogram]
- lang_code = it
-
.. code-block:: python
app = Client(
diff --git a/docs/source/topics/create-filters.rst b/docs/source/topics/create-filters.rst
index ae7bd5ec..f8c05af6 100644
--- a/docs/source/topics/create-filters.rst
+++ b/docs/source/topics/create-filters.rst
@@ -25,7 +25,7 @@ button:
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
- app.send_message(
+ await app.send_message(
"username", # Change this to your username or id
"Pyrogram custom filter test",
reply_markup=InlineKeyboardMarkup(
@@ -44,29 +44,6 @@ either ``True``, in case you want the update to pass the filter or ``False`` oth
In this example we are matching the query data to "pyrogram", which means that the filter will only allow callback
queries containing "pyrogram" as data:
-.. code-block:: python
-
- from pyrogram import filters
-
- static_data_filter = filters.create(lambda _, __, query: query.data == "pyrogram")
-
-The first two arguments of the callback function are unused here and because of this we named them using underscores.
-
-The ``lambda`` operator in python is used to create small anonymous functions and is perfect for this example. The same
-can be achieved with a normal function, but we don't really need it as it makes sense only inside the filter's scope:
-
-.. code-block:: python
-
- from pyrogram import filters
-
- def func(_, __, query):
- return query.data == "pyrogram"
-
- static_data_filter = filters.create(func)
-
-Asynchronous filters are also possible. Sadly, Python itself doesn't have an ``async lambda``, so we are left with
-using a named function:
-
.. code-block:: python
from pyrogram import filters
@@ -76,12 +53,15 @@ using a named function:
static_data_filter = filters.create(func)
+
+The first two arguments of the callback function are unused here and because of this we named them using underscores.
+
Finally, the filter usage remains the same:
.. code-block:: python
@app.on_callback_query(static_data_filter)
- def pyrogram_data(_, query):
+ async def pyrogram_data(_, query):
query.answer("it works!")
Filters with Arguments
@@ -94,18 +74,6 @@ via named arguments.
This is how a dynamic custom filter looks like:
-.. code-block:: python
-
- from pyrogram import filters
-
- def dynamic_data_filter(data):
- return filters.create(
- lambda flt, _, query: flt.data == query.data,
- data=data # "data" kwarg is accessed with "flt.data" above
- )
-
-And its asynchronous variant:
-
.. code-block:: python
from pyrogram import filters
@@ -122,7 +90,7 @@ And finally its usage:
.. code-block:: python
@app.on_callback_query(dynamic_data_filter("pyrogram"))
- def pyrogram_data(_, query):
+ async def pyrogram_data(_, query):
query.answer("it works!")
@@ -133,16 +101,6 @@ The missing piece we haven't covered yet is the second argument of a filter call
argument. This is a reference to the :obj:`~pyrogram.Client` instance that is running the filter and it is useful in
case you would like to make some API calls before deciding whether the filter should allow the update or not:
-.. code-block:: python
-
- def func(_, client, query):
- # r = client.some_api_method()
- # check response "r" and decide to return True or False
- ...
-
-Asynchronous filters making API calls work fine as well. Just remember that you need to put ``async`` in front of
-function definitions and ``await`` in front of method calls:
-
.. code-block:: python
async def func(_, client, query):
diff --git a/docs/source/topics/debugging.rst b/docs/source/topics/debugging.rst
index 6e6e6d5e..1c0ac069 100644
--- a/docs/source/topics/debugging.rst
+++ b/docs/source/topics/debugging.rst
@@ -27,7 +27,7 @@ Consider the following code:
.. code-block:: python
- me = app.get_users("me")
+ me = await app.get_users("me")
print(me) # User
This will show a JSON representation of the object returned by :meth:`~pyrogram.Client.get_users`, which is a
diff --git a/docs/source/topics/more-on-updates.rst b/docs/source/topics/more-on-updates.rst
index 81a46f3b..18c1a68a 100644
--- a/docs/source/topics/more-on-updates.rst
+++ b/docs/source/topics/more-on-updates.rst
@@ -26,12 +26,12 @@ For example, take these two handlers:
.. code-block:: python
@app.on_message(filters.text | filters.sticker)
- def text_or_sticker(client, message):
+ async def text_or_sticker(client, message):
print("Text or Sticker")
@app.on_message(filters.text)
- def just_text(client, message):
+ async def just_text(client, message):
print("Just Text")
Here, ``just_text`` is never executed because ``text_or_sticker``, which has been registered first, already handles
@@ -40,7 +40,7 @@ texts (``filters.text`` is shared and conflicting). To enable it, register the h
.. code-block:: python
@app.on_message(filters.text, group=1)
- def just_text(client, message):
+ async def just_text(client, message):
print("Just Text")
Or, if you want ``just_text`` to be executed *before* ``text_or_sticker`` (note ``-1``, which is less than ``0``):
@@ -48,7 +48,7 @@ Or, if you want ``just_text`` to be executed *before* ``text_or_sticker`` (note
.. code-block:: python
@app.on_message(filters.text, group=-1)
- def just_text(client, message):
+ async def just_text(client, message):
print("Just Text")
With :meth:`~pyrogram.Client.add_handler` (without decorators) the same can be achieved with:
@@ -68,17 +68,17 @@ continue to propagate the same update to the next groups until all the handlers
.. code-block:: python
@app.on_message(filters.private)
- def _(client, message):
+ async def _(client, message):
print(0)
@app.on_message(filters.private, group=1)
- def _(client, message):
+ async def _(client, message):
raise Exception("Unhandled exception!") # Simulate an unhandled exception
@app.on_message(filters.private, group=2)
- def _(client, message):
+ async def _(client, message):
print(2)
All these handlers will handle the same kind of messages, that are, messages sent or received in private chats.
@@ -110,18 +110,18 @@ Example with ``stop_propagation()``:
.. code-block:: python
@app.on_message(filters.private)
- def _(client, message):
+ async def _(client, message):
print(0)
@app.on_message(filters.private, group=1)
- def _(client, message):
+ async def _(client, message):
print(1)
message.stop_propagation()
@app.on_message(filters.private, group=2)
- def _(client, message):
+ async def _(client, message):
print(2)
Example with ``raise StopPropagation``:
@@ -131,18 +131,18 @@ Example with ``raise StopPropagation``:
from pyrogram import StopPropagation
@app.on_message(filters.private)
- def _(client, message):
+ async def _(client, message):
print(0)
@app.on_message(filters.private, group=1)
- def _(client, message):
+ async ef _(client, message):
print(1)
raise StopPropagation
@app.on_message(filters.private, group=2)
- def _(client, message):
+ async def _(client, message):
print(2)
Each handler is registered in a different group, but the handler in group number 2 will never be executed because the
@@ -178,19 +178,19 @@ Example with ``continue_propagation()``:
.. code-block:: python
@app.on_message(filters.private)
- def _(client, message):
+ async def _(client, message):
print(0)
message.continue_propagation()
@app.on_message(filters.private)
- def _(client, message):
+ async def _(client, message):
print(1)
message.continue_propagation()
@app.on_message(filters.private)
- def _(client, message):
+ async def _(client, message):
print(2)
Example with ``raise ContinuePropagation``:
@@ -200,19 +200,19 @@ Example with ``raise ContinuePropagation``:
from pyrogram import ContinuePropagation
@app.on_message(filters.private)
- def _(client, message):
+ async def _(client, message):
print(0)
raise ContinuePropagation
@app.on_message(filters.private)
- def _(client, message):
+ async def _(client, message):
print(1)
raise ContinuePropagation
@app.on_message(filters.private)
- def _(client, message):
+ async def _(client, message):
print(2)
Three handlers are registered in the same group, and all of them will be executed because the propagation was continued
diff --git a/docs/source/topics/serializing.rst b/docs/source/topics/serializing.rst
index 6a8082b1..3dc644f8 100644
--- a/docs/source/topics/serializing.rst
+++ b/docs/source/topics/serializing.rst
@@ -21,8 +21,8 @@ If you want a nicely formatted, human readable JSON representation of any object
...
- with app:
- r = app.get_chat("me")
+ async with app:
+ r = await app.get_chat("me")
print(str(r))
.. tip::
@@ -44,8 +44,8 @@ as the process requires the package to be in scope.
...
- with app:
- r = app.get_chat("me")
+ async with app:
+ r = await app.get_chat("me")
print(repr(r))
print(eval(repr(r)) == r) # True
diff --git a/docs/source/topics/smart-plugins.rst b/docs/source/topics/smart-plugins.rst
index a94e3212..c378c9d8 100644
--- a/docs/source/topics/smart-plugins.rst
+++ b/docs/source/topics/smart-plugins.rst
@@ -33,7 +33,6 @@ after importing your modules, like this:
.. code-block:: text
myproject/
- config.ini
handlers.py
main.py
@@ -41,12 +40,12 @@ after importing your modules, like this:
.. code-block:: python
- def echo(client, message):
- message.reply(message.text)
+ async def echo(client, message):
+ await message.reply(message.text)
- def echo_reversed(client, message):
- message.reply(message.text[::-1])
+ async def echo_reversed(client, message):
+ await message.reply(message.text[::-1])
- ``main.py``
@@ -84,7 +83,7 @@ Setting up your Pyrogram project to accommodate Smart Plugins is pretty straight
#. Create a new folder to store all the plugins (e.g.: "plugins", "handlers", ...).
#. Put your python files full of plugins inside. Organize them as you wish.
-#. Enable plugins in your Client or via the *config.ini* file.
+#. Enable plugins in your Client.
.. note::
@@ -95,7 +94,6 @@ Setting up your Pyrogram project to accommodate Smart Plugins is pretty straight
myproject/
plugins/
handlers.py
- config.ini
main.py
- ``plugins/handlers.py``
@@ -106,31 +104,16 @@ Setting up your Pyrogram project to accommodate Smart Plugins is pretty straight
@Client.on_message(filters.text & filters.private)
- def echo(client, message):
- message.reply(message.text)
+ async def echo(client, message):
+ await message.reply(message.text)
@Client.on_message(filters.text & filters.private, group=1)
- def echo_reversed(client, message):
- message.reply(message.text[::-1])
-
-- ``config.ini``
-
- .. code-block:: ini
-
- [plugins]
- root = plugins
+ async def echo_reversed(client, message):
+ await message.reply(message.text[::-1])
- ``main.py``
- .. code-block:: python
-
- from pyrogram import Client
-
- Client("my_account").run()
-
- Alternatively, without using the *config.ini* file:
-
.. code-block:: python
from pyrogram import Client
@@ -144,9 +127,9 @@ The first important thing to note is the new ``plugins`` folder. You can put *an
each file can contain *any decorated function* (handlers) with one limitation: within a single module (file) you must
use different names for each decorated function.
-The second thing is telling Pyrogram where to look for your plugins: you can either use the *config.ini* file or
-the Client parameter "plugins"; the *root* value must match the name of your plugins root folder. Your Pyrogram Client
-instance will **automatically** scan the folder upon starting to search for valid handlers and register them for you.
+The second thing is telling Pyrogram where to look for your plugins: you can use the Client parameter "plugins";
+the *root* value must match the name of your plugins root folder. Your Pyrogram Client instance will **automatically**
+scan the folder upon starting to search for valid handlers and register them for you.
Then you'll notice you can now use decorators. That's right, you can apply the usual decorators to your callback
functions in a static way, i.e. **without having the Client instance around**: simply use ``@Client`` (Client class)
@@ -166,7 +149,7 @@ found inside each module will be, instead, loaded in the order they are defined,
This default loading behaviour is usually enough, but sometimes you want to have more control on what to include (or
exclude) and in which exact order to load plugins. The way to do this is to make use of ``include`` and ``exclude``
-directives, either in the *config.ini* file or in the dictionary passed as Client argument. Here's how they work:
+directives in the dictionary passed as Client argument. Here's how they work:
- If both ``include`` and ``exclude`` are omitted, all plugins are loaded as described above.
- If ``include`` is given, only the specified plugins will be loaded, in the order they are passed.
@@ -208,15 +191,6 @@ also organized in subfolders:
- Load every handler from every module, namely *plugins0.py*, *plugins1.py* and *plugins2.py* in alphabetical order
(files) and definition order (handlers inside files):
- Using *config.ini* file:
-
- .. code-block:: ini
-
- [plugins]
- root = plugins
-
- Using *Client*'s parameter:
-
.. code-block:: python
plugins = dict(root="plugins")
@@ -225,18 +199,6 @@ also organized in subfolders:
- Load only handlers defined inside *plugins2.py* and *plugins0.py*, in this order:
- Using *config.ini* file:
-
- .. code-block:: ini
-
- [plugins]
- root = plugins
- include =
- subfolder2.plugins2
- plugins0
-
- Using *Client*'s parameter:
-
.. code-block:: python
plugins = dict(
@@ -251,16 +213,6 @@ also organized in subfolders:
- Load everything except the handlers inside *plugins2.py*:
- Using *config.ini* file:
-
- .. code-block:: ini
-
- [plugins]
- root = plugins
- exclude = subfolder2.plugins2
-
- Using *Client*'s parameter:
-
.. code-block:: python
plugins = dict(
@@ -272,16 +224,6 @@ also organized in subfolders:
- Load only *fn3*, *fn1* and *fn2* (in this order) from *plugins1.py*:
- Using *config.ini* file:
-
- .. code-block:: ini
-
- [plugins]
- root = plugins
- include = subfolder1.plugins1 fn3 fn1 fn2
-
- Using *Client*'s parameter:
-
.. code-block:: python
plugins = dict(
@@ -306,8 +248,8 @@ updates) will be modified in such a way that a special ``handlers`` attribute po
.. code-block:: python
@Client.on_message(filters.text & filters.private)
- def echo(client, message):
- message.reply(message.text)
+ async def echo(client, message):
+ await message.reply(message.text)
print(echo)
print(echo.handlers)
diff --git a/docs/source/topics/test-servers.rst b/docs/source/topics/test-servers.rst
index cba5e709..1ccfe286 100644
--- a/docs/source/topics/test-servers.rst
+++ b/docs/source/topics/test-servers.rst
@@ -9,8 +9,8 @@ Telegram's test servers without hassle. All you need to do is start a new sessio
from pyrogram import Client
- with Client("my_account_test", test_mode=True) as app:
- print(app.get_me())
+ async with Client("my_account_test", test_mode=True) as app:
+ print(await app.get_me())
.. note::
diff --git a/docs/source/topics/text-formatting.rst b/docs/source/topics/text-formatting.rst
index 8ad2b4db..4e11fb74 100644
--- a/docs/source/topics/text-formatting.rst
+++ b/docs/source/topics/text-formatting.rst
@@ -80,7 +80,7 @@ To strictly use this mode, pass :obj:`~pyrogram.enums.ParseMode.MARKDOWN` to the
from pyrogram import enums
- app.send_message(
+ await app.send_message(
"me",
(
"**bold**, "
@@ -134,7 +134,7 @@ To strictly use this mode, pass :obj:`~pyrogram.enums.HTML` to the *parse_mode*
from pyrogram import enums
- app.send_message(
+ await app.send_message(
"me",
(
"bold, "
@@ -179,7 +179,7 @@ This means you can combine together both syntaxes in the same text:
.. code-block:: python
- app.send_message("me", "**bold**, italic")
+ await app.send_message("me", "**bold**, italic")
Result:
@@ -192,8 +192,8 @@ If you don't like this behaviour you can always choose to only enable either Mar
from pyrogram import enums
- app.send_message("me", "**bold**, italic", parse_mode=enums.ParseMode.MARKDOWN)
- app.send_message("me", "**bold**, italic", parse_mode=enums.ParseMode.HTML)
+ await app.send_message("me", "**bold**, italic", parse_mode=enums.ParseMode.MARKDOWN)
+ await app.send_message("me", "**bold**, italic", parse_mode=enums.ParseMode.HTML)
Result:
@@ -208,7 +208,7 @@ The text will be sent as-is.
from pyrogram import enums
- app.send_message("me", "**bold**, italic", parse_mode=enums.ParseMode.DISABLED)
+ await app.send_message("me", "**bold**, italic", parse_mode=enums.ParseMode.DISABLED)
Result:
diff --git a/docs/source/topics/use-filters.rst b/docs/source/topics/use-filters.rst
index 62e94d27..ab7296af 100644
--- a/docs/source/topics/use-filters.rst
+++ b/docs/source/topics/use-filters.rst
@@ -28,7 +28,7 @@ Let's start right away with a simple example:
@app.on_message(filters.sticker)
- def my_handler(client, message):
+ async def my_handler(client, message):
print(message)
- or, without decorators. Here filters are passed as the second argument of the handler constructor; the first is the
@@ -40,7 +40,7 @@ Let's start right away with a simple example:
from pyrogram.handlers import MessageHandler
- def my_handler(client, message):
+ async def my_handler(client, message):
print(message)
@@ -62,7 +62,7 @@ Here are some examples:
.. code-block:: python
@app.on_message(filters.text | filters.photo)
- def my_handler(client, message):
+ async def my_handler(client, message):
print(message)
- Message is a **sticker** **and** is coming from a **channel or** a **private** chat.
@@ -70,7 +70,7 @@ Here are some examples:
.. code-block:: python
@app.on_message(filters.sticker & (filters.channel | filters.private))
- def my_handler(client, message):
+ async def my_handler(client, message):
print(message)
Advanced Filters
@@ -84,7 +84,7 @@ can also accept arguments:
.. code-block:: python
@app.on_message(filters.command(["start", "help"]))
- def my_handler(client, message):
+ async def my_handler(client, message):
print(message)
- Message is a **text** message or a media **caption** matching the given **regex** pattern.
@@ -92,7 +92,7 @@ can also accept arguments:
.. code-block:: python
@app.on_message(filters.regex("pyrogram"))
- def my_handler(client, message):
+ async def my_handler(client, message):
print(message)
More handlers using different filters can also live together.
@@ -100,15 +100,15 @@ More handlers using different filters can also live together.
.. code-block:: python
@app.on_message(filters.command("start"))
- def start_command(client, message):
+ async def start_command(client, message):
print("This is the /start command")
@app.on_message(filters.command("help"))
- def help_command(client, message):
+ async def help_command(client, message):
print("This is the /help command")
@app.on_message(filters.chat("PyrogramChat"))
- def from_pyrogramchat(client, message):
+ async def from_pyrogramchat(client, message):
print("New message in @PyrogramChat")