Update Smart Plugins docs
This commit is contained in:
parent
be013de4d4
commit
919894cd3f
@ -1,9 +1,9 @@
|
|||||||
Smart Plugins
|
Smart Plugins
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Pyrogram embeds a **smart** (automatic) and lightweight plugin system that is meant to further simplify the organization
|
Pyrogram embeds a **smart**, lightweight yet powerful plugin system that is meant to further simplify the organization
|
||||||
of large projects and to provide a way for creating pluggable components that can be **easily shared** across different
|
of large projects and to provide a way for creating pluggable (modular) components that can be **easily shared** across
|
||||||
Pyrogram applications with **minimal boilerplate code**.
|
different Pyrogram applications with **minimal boilerplate code**.
|
||||||
|
|
||||||
.. tip::
|
.. tip::
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ Introduction
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
Prior to the Smart Plugin system, pluggable handlers were already possible. For example, if you wanted to modularize
|
Prior to the Smart Plugin system, pluggable handlers were already possible. For example, if you wanted to modularize
|
||||||
your applications, you had to do something like this...
|
your applications, you had to do something like this:
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ your applications, you had to do something like this...
|
|||||||
|
|
||||||
app.run()
|
app.run()
|
||||||
|
|
||||||
...which is already nice and doesn't add *too much* boilerplate code, but things can get boring still; you have to
|
This is already nice and doesn't add *too much* boilerplate code, but things can get boring still; you have to
|
||||||
manually ``import``, manually :meth:`add_handler <pyrogram.Client.add_handler>` and manually instantiate each
|
manually ``import``, manually :meth:`add_handler <pyrogram.Client.add_handler>` and manually instantiate each
|
||||||
:obj:`MessageHandler <pyrogram.MessageHandler>` object because **you can't use those cool decorators** for your
|
:obj:`MessageHandler <pyrogram.MessageHandler>` object because **you can't use those cool decorators** for your
|
||||||
functions. So... What if you could?
|
functions. So... What if you could?
|
||||||
@ -74,8 +74,8 @@ Using Smart Plugins
|
|||||||
Setting up your Pyrogram project to accommodate Smart Plugins is pretty straightforward:
|
Setting up your Pyrogram project to accommodate Smart Plugins is pretty straightforward:
|
||||||
|
|
||||||
#. Create a new folder to store all the plugins (e.g.: "plugins").
|
#. Create a new folder to store all the plugins (e.g.: "plugins").
|
||||||
#. Put your files full of plugins inside.
|
#. Put your files full of plugins inside. Organize them as you wish.
|
||||||
#. Enable plugins in your Client.
|
#. Enable plugins in your Client or via the *config.ini* file.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
@ -107,20 +107,187 @@ Setting up your Pyrogram project to accommodate Smart Plugins is pretty straight
|
|||||||
def echo_reversed(client, message):
|
def echo_reversed(client, message):
|
||||||
message.reply(message.text[::-1])
|
message.reply(message.text[::-1])
|
||||||
|
|
||||||
|
- ``config.ini``
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[plugins]
|
||||||
|
root = plugins
|
||||||
|
|
||||||
- ``main.py``
|
- ``main.py``
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from pyrogram import Client
|
from pyrogram import Client
|
||||||
|
|
||||||
Client("my_account", plugins_dir="plugins").run()
|
Client("my_account").run()
|
||||||
|
|
||||||
The first important thing to note is the new ``plugins`` folder, whose name is passed to the the ``plugins_dir``
|
Alternatively, without using the *config.ini* file:
|
||||||
parameter when creating a :obj:`Client <pyrogram.Client>` in the ``main.py`` file — you can put *any python file* in
|
|
||||||
there and each file can contain *any decorated function* (handlers) with only one limitation: within a single plugin
|
.. code-block:: python
|
||||||
file you must use different names for each decorated function. Your Pyrogram Client instance will **automatically**
|
|
||||||
scan the folder upon creation to search for valid handlers and register them for you.
|
from pyrogram import Client
|
||||||
|
|
||||||
|
plugins = dict(
|
||||||
|
root="plugins"
|
||||||
|
)
|
||||||
|
|
||||||
|
Client("my_account", plugins=plugins).run()
|
||||||
|
|
||||||
|
The first important thing to note is the new ``plugins`` folder. You can put *any python file* in *any subfolder* and
|
||||||
|
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 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
|
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)
|
functions in a static way, i.e. **without having the Client instance around**: simply use ``@Client`` (Client class)
|
||||||
instead of the usual ``@app`` (Client instance) namespace and things will work just the same.
|
instead of the usual ``@app`` (Client instance) and things will work just the same.
|
||||||
|
|
||||||
|
Specifying the Plugins to include
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
By default, if you don't explicitly supply a list of plugins, every valid one found inside your plugins root folder will
|
||||||
|
be included by following the alphabetical order of the directory structure (files and subfolders); the single handlers
|
||||||
|
found inside each module will be, instead, loaded in the order they are defined, from top to bottom.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Remember: there can be at most one handler, within a group, dealing with a specific update. Plugins with overlapping
|
||||||
|
filters included a second time will not work. Learn more at `More on Updates <MoreOnUpdates.html>`_.
|
||||||
|
|
||||||
|
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``
|
||||||
|
keys, either in the *config.ini* or 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.
|
||||||
|
- If ``exclude`` is given, the plugins specified here will be unloaded.
|
||||||
|
|
||||||
|
The ``include`` and ``exclude`` value is a **list of strings**. Each string containing the path of the module relative
|
||||||
|
to the plugins root folder, in Python notation (dots instead of slashes).
|
||||||
|
|
||||||
|
E.g.: ``subfolder.module`` refers to ``plugins/subfolder/module.py`` (root="plugins").
|
||||||
|
|
||||||
|
You can also choose the order in which the single handlers inside a module are loaded, thus overriding the default
|
||||||
|
top-to-bottom loading policy. You can do this by appending the name of the functions to the module path, each one
|
||||||
|
separated by a blank space.
|
||||||
|
|
||||||
|
E.g.: ``subfolder.module fn2 fn1 fn3`` will load *fn2*, *fn1* and *fn3* from *subfolder.module*, in this order.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
^^^^^^^^
|
||||||
|
|
||||||
|
Given this plugins folder structure with three modules, each containing their own handlers (fn1, fn2, etc...), which are
|
||||||
|
also organized in subfolders:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
myproject/
|
||||||
|
plugins/
|
||||||
|
subfolder1/
|
||||||
|
plugins1.py
|
||||||
|
- fn1
|
||||||
|
- fn2
|
||||||
|
- fn3
|
||||||
|
subfolder2/
|
||||||
|
plugins2.py
|
||||||
|
...
|
||||||
|
plugins0.py
|
||||||
|
...
|
||||||
|
...
|
||||||
|
|
||||||
|
- 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
Client("my_account", plugins=plugins).run()
|
||||||
|
|
||||||
|
- 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(
|
||||||
|
root="plugins",
|
||||||
|
include=[
|
||||||
|
"subfolder2.plugins2",
|
||||||
|
"plugins0"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
Client("my_account", plugins=plugins).run()
|
||||||
|
|
||||||
|
- 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(
|
||||||
|
root="plugins",
|
||||||
|
exclude=["subfolder2.plugins2"]
|
||||||
|
)
|
||||||
|
|
||||||
|
Client("my_account", plugins=plugins).run()
|
||||||
|
|
||||||
|
- 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(
|
||||||
|
root="plugins",
|
||||||
|
include=["subfolder1.plugins1 fn3 fn1 fn2"]
|
||||||
|
)
|
||||||
|
|
||||||
|
Client("my_account", plugins=plugins).run()
|
||||||
|
|
||||||
|
Load/Unload Plugins at Runtime
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
TODO
|
Loading…
Reference in New Issue
Block a user