From 0025489c865bebdc37beddc2587c2f863f0e381e Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 12 Oct 2018 14:12:29 +0200
Subject: [PATCH 01/15] Allow on_message to behave like a static decorator This
enabled usages like @Client.on_message(...). To preserve positional arguments
order and thus ease the static decorator usage there's a not-so-elegant hack
in place that shifts values.
---
pyrogram/client/methods/decorators/on_message.py | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/pyrogram/client/methods/decorators/on_message.py b/pyrogram/client/methods/decorators/on_message.py
index 0011e083..7a0d54a0 100644
--- a/pyrogram/client/methods/decorators/on_message.py
+++ b/pyrogram/client/methods/decorators/on_message.py
@@ -17,11 +17,12 @@
# along with Pyrogram. If not, see .
import pyrogram
+from pyrogram.client.filters.filter import Filter
from ...ext import BaseClient
class OnMessage(BaseClient):
- def on_message(self, filters=None, group: int = 0):
+ def on_message(self=None, filters=None, group: int = 0):
"""Use this decorator to automatically register a function for handling
messages. This does the same thing as :meth:`add_handler` using the
:class:`MessageHandler`.
@@ -36,7 +37,14 @@ class OnMessage(BaseClient):
"""
def decorator(func):
- self.add_handler(pyrogram.MessageHandler(func, filters), group)
- return func
+ handler = pyrogram.MessageHandler(func, filters)
+
+ if isinstance(self, Filter):
+ return pyrogram.MessageHandler(func, self), group if filters is None else filters
+
+ if self is not None:
+ self.add_handler(handler, group)
+
+ return handler, group
return decorator
From dfb841baa9dc226d4f28a48ce05de0628db9fd47 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 12 Oct 2018 14:17:03 +0200
Subject: [PATCH 02/15] Automatically scan and load plugins from a customizable
directory Defined functions found inside the directory that are also
decorated properly will be registered in the Client's dispatcher as handlers.
---
pyrogram/client/client.py | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index ee40d2bc..ebcfb02a 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -33,6 +33,7 @@ import time
from configparser import ConfigParser
from datetime import datetime
from hashlib import sha256, md5
+from importlib import import_module
from signal import signal, SIGINT, SIGTERM, SIGABRT
from threading import Thread
@@ -45,6 +46,7 @@ from pyrogram.api.errors import (
PasswordHashInvalid, FloodWait, PeerIdInvalid, FirstnameInvalid, PhoneNumberBanned,
VolumeLocNotFound, UserMigrate, FileIdInvalid, ChannelPrivate)
from pyrogram.client.handlers import DisconnectHandler
+from pyrogram.client.handlers.handler import Handler
from pyrogram.crypto import AES
from pyrogram.session import Auth, Session
from .dispatcher import Dispatcher
@@ -161,7 +163,8 @@ class Client(Methods, BaseClient):
last_name: str = None,
workers: int = 4,
workdir: str = ".",
- config_file: str = "./config.ini"):
+ config_file: str = "./config.ini",
+ plugins_dir: str = "./plugins"):
super().__init__()
self.session_name = session_name
@@ -184,6 +187,7 @@ class Client(Methods, BaseClient):
self.workers = workers
self.workdir = workdir
self.config_file = config_file
+ self.plugins_dir = plugins_dir
self.dispatcher = Dispatcher(self, workers)
@@ -226,6 +230,24 @@ class Client(Methods, BaseClient):
self.auth_key
)
+ if self.plugins_dir is not None:
+ for i in os.listdir(self.plugins_dir):
+ module = import_module("{}.{}".format(self.plugins_dir, i.split(".")[0]))
+
+ for j in dir(module):
+ # noinspection PyBroadException
+ try:
+ handler, group = getattr(module, j)
+
+ if isinstance(handler, Handler) and isinstance(group, int):
+ self.add_handler(handler, group)
+
+ log.info('{}("{}") from "{}/{}" registered in group {}'.format(
+ type(handler).__name__, j, self.plugins_dir, i, group)
+ )
+ except Exception:
+ pass
+
self.session.start()
self.is_started = True
From 0b79f96b4f5de9e2cbd580c9468f0646a7109f40 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 12 Oct 2018 14:19:26 +0200
Subject: [PATCH 03/15] Turn hardcoded plugins dir into a constant
---
pyrogram/client/client.py | 2 +-
pyrogram/client/ext/base_client.py | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index ebcfb02a..b59469d2 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -164,7 +164,7 @@ class Client(Methods, BaseClient):
workers: int = 4,
workdir: str = ".",
config_file: str = "./config.ini",
- plugins_dir: str = "./plugins"):
+ plugins_dir: str = BaseClient.PLUGINS_DIR):
super().__init__()
self.session_name = session_name
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index fa96e1db..562da2b2 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -49,6 +49,7 @@ class BaseClient:
UPDATES_WORKERS = 1
DOWNLOAD_WORKERS = 1
OFFLINE_SLEEP = 300
+ PLUGINS_DIR = "./plugins"
MEDIA_TYPE_ID = {
0: "thumbnail",
From 4e516d097f31b65e411e8c21493a114014fe0a80 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 12 Oct 2018 14:32:35 +0200
Subject: [PATCH 04/15] Don't raise exceptions in case of non-existent plugins
folder Don't even warn in case the default plugins folder doesn't exist
---
pyrogram/client/client.py | 34 +++++++++++++++++++++-------------
1 file changed, 21 insertions(+), 13 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index b59469d2..0274e59f 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -231,22 +231,30 @@ class Client(Methods, BaseClient):
)
if self.plugins_dir is not None:
- for i in os.listdir(self.plugins_dir):
- module = import_module("{}.{}".format(self.plugins_dir, i.split(".")[0]))
+ try:
+ dirs = os.listdir(self.plugins_dir)
+ except FileNotFoundError as e:
+ if self.plugins_dir == Client.PLUGINS_DIR:
+ pass
+ else:
+ log.warning(e)
+ else:
+ for i in dirs:
+ module = import_module("{}.{}".format(self.plugins_dir, i.split(".")[0]))
- for j in dir(module):
- # noinspection PyBroadException
- try:
- handler, group = getattr(module, j)
+ for j in dir(module):
+ # noinspection PyBroadException
+ try:
+ handler, group = getattr(module, j)
- if isinstance(handler, Handler) and isinstance(group, int):
- self.add_handler(handler, group)
+ if isinstance(handler, Handler) and isinstance(group, int):
+ self.add_handler(handler, group)
- log.info('{}("{}") from "{}/{}" registered in group {}'.format(
- type(handler).__name__, j, self.plugins_dir, i, group)
- )
- except Exception:
- pass
+ log.info('{}("{}") from "{}/{}" registered in group {}'.format(
+ type(handler).__name__, j, self.plugins_dir, i, group)
+ )
+ except Exception:
+ pass
self.session.start()
self.is_started = True
From 6c05f9ff428ba8522b061ed00628ecee4b1ebf90 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 12 Oct 2018 15:26:52 +0200
Subject: [PATCH 05/15] Sanitize (a bit) plugins directory
---
pyrogram/client/client.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 0274e59f..31e6ef1b 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -239,8 +239,10 @@ class Client(Methods, BaseClient):
else:
log.warning(e)
else:
+ plugins_dir = self.plugins_dir.lstrip("./").replace("/", ".")
+
for i in dirs:
- module = import_module("{}.{}".format(self.plugins_dir, i.split(".")[0]))
+ module = import_module("{}.{}".format(plugins_dir, i.split(".")[0]))
for j in dir(module):
# noinspection PyBroadException
From 4bb50ee35fd8c988d9a70cee6974d3cb0429dbaf Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 12 Oct 2018 17:54:52 +0200
Subject: [PATCH 06/15] More logs when loading plugins
---
pyrogram/client/client.py | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 31e6ef1b..48473cc2 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -233,13 +233,14 @@ class Client(Methods, BaseClient):
if self.plugins_dir is not None:
try:
dirs = os.listdir(self.plugins_dir)
- except FileNotFoundError as e:
+ except FileNotFoundError:
if self.plugins_dir == Client.PLUGINS_DIR:
- pass
+ log.info("No plugin loaded: default directory is missing")
else:
- log.warning(e)
+ log.warning('No plugin loaded: "{}" directory is missing'.format(self.plugins_dir))
else:
plugins_dir = self.plugins_dir.lstrip("./").replace("/", ".")
+ plugins_count = 0
for i in dirs:
module = import_module("{}.{}".format(plugins_dir, i.split(".")[0]))
@@ -252,12 +253,20 @@ class Client(Methods, BaseClient):
if isinstance(handler, Handler) and isinstance(group, int):
self.add_handler(handler, group)
- log.info('{}("{}") from "{}/{}" registered in group {}'.format(
+ log.info('{}("{}") from "{}/{}" loaded in group {}'.format(
type(handler).__name__, j, self.plugins_dir, i, group)
)
+
+ plugins_count += 1
except Exception:
pass
+ log.warning('Successfully loaded {} plugin{} from "{}"'.format(
+ plugins_count,
+ "s" if plugins_count > 1 else "",
+ self.plugins_dir
+ ))
+
self.session.start()
self.is_started = True
From 6a0066b8b53f9343f882393bc6011b02d55f7797 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 12 Oct 2018 17:57:34 +0200
Subject: [PATCH 07/15] Move loading plugins logic into a separate method
---
pyrogram/client/client.py | 76 ++++++++++++++++++++-------------------
1 file changed, 39 insertions(+), 37 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 48473cc2..fef929fc 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -223,6 +223,7 @@ class Client(Methods, BaseClient):
self.load_config()
self.load_session()
+ self.load_plugins()
self.session = Session(
self,
@@ -230,43 +231,6 @@ class Client(Methods, BaseClient):
self.auth_key
)
- if self.plugins_dir is not None:
- try:
- dirs = os.listdir(self.plugins_dir)
- except FileNotFoundError:
- if self.plugins_dir == Client.PLUGINS_DIR:
- log.info("No plugin loaded: default directory is missing")
- else:
- log.warning('No plugin loaded: "{}" directory is missing'.format(self.plugins_dir))
- else:
- plugins_dir = self.plugins_dir.lstrip("./").replace("/", ".")
- plugins_count = 0
-
- for i in dirs:
- module = import_module("{}.{}".format(plugins_dir, i.split(".")[0]))
-
- for j in dir(module):
- # noinspection PyBroadException
- try:
- handler, group = getattr(module, j)
-
- if isinstance(handler, Handler) and isinstance(group, int):
- self.add_handler(handler, group)
-
- log.info('{}("{}") from "{}/{}" loaded in group {}'.format(
- type(handler).__name__, j, self.plugins_dir, i, group)
- )
-
- plugins_count += 1
- except Exception:
- pass
-
- log.warning('Successfully loaded {} plugin{} from "{}"'.format(
- plugins_count,
- "s" if plugins_count > 1 else "",
- self.plugins_dir
- ))
-
self.session.start()
self.is_started = True
@@ -1009,6 +973,44 @@ class Client(Methods, BaseClient):
if peer:
self.peers_by_phone[k] = peer
+ def load_plugins(self):
+ if self.plugins_dir is not None:
+ try:
+ dirs = os.listdir(self.plugins_dir)
+ except FileNotFoundError:
+ if self.plugins_dir == Client.PLUGINS_DIR:
+ log.info("No plugin loaded: default directory is missing")
+ else:
+ log.warning('No plugin loaded: "{}" directory is missing'.format(self.plugins_dir))
+ else:
+ plugins_dir = self.plugins_dir.lstrip("./").replace("/", ".")
+ plugins_count = 0
+
+ for i in dirs:
+ module = import_module("{}.{}".format(plugins_dir, i.split(".")[0]))
+
+ for j in dir(module):
+ # noinspection PyBroadException
+ try:
+ handler, group = getattr(module, j)
+
+ if isinstance(handler, Handler) and isinstance(group, int):
+ self.add_handler(handler, group)
+
+ log.info('{}("{}") from "{}/{}" loaded in group {}'.format(
+ type(handler).__name__, j, self.plugins_dir, i, group)
+ )
+
+ plugins_count += 1
+ except Exception:
+ pass
+
+ log.warning('Successfully loaded {} plugin{} from "{}"'.format(
+ plugins_count,
+ "s" if plugins_count > 1 else "",
+ self.plugins_dir
+ ))
+
def save_session(self):
auth_key = base64.b64encode(self.auth_key).decode()
auth_key = [auth_key[i: i + 43] for i in range(0, len(auth_key), 43)]
From 1fdc757f2afd30b1f30ee64dce345e34fca73f87 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 13 Oct 2018 10:45:48 +0200
Subject: [PATCH 08/15] Allow on_raw_update to be used as a static decorator
---
pyrogram/client/methods/decorators/on_raw_update.py | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/pyrogram/client/methods/decorators/on_raw_update.py b/pyrogram/client/methods/decorators/on_raw_update.py
index 902d9854..7675a4f0 100644
--- a/pyrogram/client/methods/decorators/on_raw_update.py
+++ b/pyrogram/client/methods/decorators/on_raw_update.py
@@ -21,7 +21,7 @@ from ...ext import BaseClient
class OnRawUpdate(BaseClient):
- def on_raw_update(self, group: int = 0):
+ def on_raw_update(self=None, group: int = 0):
"""Use this decorator to automatically register a function for handling
raw updates. This does the same thing as :meth:`add_handler` using the
:class:`RawUpdateHandler`.
@@ -32,7 +32,14 @@ class OnRawUpdate(BaseClient):
"""
def decorator(func):
- self.add_handler(pyrogram.RawUpdateHandler(func), group)
- return func
+ handler = pyrogram.RawUpdateHandler(func)
+
+ if isinstance(self, int):
+ return handler, group if self is None else group
+
+ if self is not None:
+ self.add_handler(handler, group)
+
+ return handler, group
return decorator
From 54296a6fdaa9e28d4d9e06e8d446ee89c32a40b4 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 13 Oct 2018 10:47:39 +0200
Subject: [PATCH 09/15] Allow on_disconnect to be used as a static decorator
---
pyrogram/client/methods/decorators/on_disconnect.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/methods/decorators/on_disconnect.py b/pyrogram/client/methods/decorators/on_disconnect.py
index 4bc593e3..a639471b 100644
--- a/pyrogram/client/methods/decorators/on_disconnect.py
+++ b/pyrogram/client/methods/decorators/on_disconnect.py
@@ -28,7 +28,11 @@ class OnDisconnect(BaseClient):
"""
def decorator(func):
- self.add_handler(pyrogram.DisconnectHandler(func))
- return func
+ handler = pyrogram.DisconnectHandler(func)
+
+ if self is not None:
+ self.add_handler(handler)
+
+ return handler
return decorator
From 6fdb90e4a47d2a7187e195b1556edbde18686795 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 13 Oct 2018 10:54:13 +0200
Subject: [PATCH 10/15] Allow on_deleted_messages to be used as a static
decorator
---
.../client/methods/decorators/on_deleted_messages.py | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/methods/decorators/on_deleted_messages.py b/pyrogram/client/methods/decorators/on_deleted_messages.py
index 3f603c41..e4b2bc97 100644
--- a/pyrogram/client/methods/decorators/on_deleted_messages.py
+++ b/pyrogram/client/methods/decorators/on_deleted_messages.py
@@ -17,6 +17,7 @@
# along with Pyrogram. If not, see .
import pyrogram
+from pyrogram.client.filters.filter import Filter
from ...ext import BaseClient
@@ -36,7 +37,14 @@ class OnDeletedMessages(BaseClient):
"""
def decorator(func):
- self.add_handler(pyrogram.DeletedMessagesHandler(func, filters), group)
- return func
+ handler = pyrogram.DeletedMessagesHandler(func, filters)
+
+ if isinstance(self, Filter):
+ return pyrogram.DeletedMessagesHandler(func, self), group if filters is None else filters
+
+ if self is not None:
+ self.add_handler(handler, group)
+
+ return handler, group
return decorator
From 96b39970d6281e62eb57271e249af9a7dab754a7 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 13 Oct 2018 10:55:41 +0200
Subject: [PATCH 11/15] Allow on_callback_query to be used as a static
decorator
---
.../client/methods/decorators/on_callback_query.py | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/methods/decorators/on_callback_query.py b/pyrogram/client/methods/decorators/on_callback_query.py
index 5f22fc92..8413515d 100644
--- a/pyrogram/client/methods/decorators/on_callback_query.py
+++ b/pyrogram/client/methods/decorators/on_callback_query.py
@@ -17,6 +17,7 @@
# along with Pyrogram. If not, see .
import pyrogram
+from pyrogram.client.filters.filter import Filter
from ...ext import BaseClient
@@ -36,7 +37,14 @@ class OnCallbackQuery(BaseClient):
"""
def decorator(func):
- self.add_handler(pyrogram.CallbackQueryHandler(func, filters), group)
- return func
+ handler = pyrogram.CallbackQueryHandler(func, filters)
+
+ if isinstance(self, Filter):
+ return pyrogram.CallbackQueryHandler(func, self), group if filters is None else filters
+
+ if self is not None:
+ self.add_handler(handler, group)
+
+ return handler, group
return decorator
From 8e238ccc9adaf44c6443c3b51d5bf5d860474dac Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 13 Oct 2018 11:14:26 +0200
Subject: [PATCH 12/15] Add plugins_dir docstrings in Client class definition
---
pyrogram/client/client.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index a34f0967..f211cb16 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -142,6 +142,11 @@ class Client(Methods, BaseClient):
config_file (``str``, *optional*):
Path of the configuration file. Defaults to ./config.ini
+
+ plugins_dir (``str``, *optional*):
+ Define a custom directory for your plugins. The plugins directory is the location in your
+ filesystem where Pyrogram will automatically load your update handlers.
+ Defaults to "./plugins". Set to None to completely disable plugins.
"""
def __init__(self,
From c5006fcf1e38cb7d9484fb823d2f9c84f11700e2 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 13 Oct 2018 16:53:51 +0200
Subject: [PATCH 13/15] Add Plugins.rst Documentation for Plugins
---
docs/source/resources/Plugins.rst | 116 ++++++++++++++++++++++++++++++
1 file changed, 116 insertions(+)
create mode 100644 docs/source/resources/Plugins.rst
diff --git a/docs/source/resources/Plugins.rst b/docs/source/resources/Plugins.rst
new file mode 100644
index 00000000..d490b37b
--- /dev/null
+++ b/docs/source/resources/Plugins.rst
@@ -0,0 +1,116 @@
+Plugins
+=======
+
+Pyrogram embeds an **automatic** and lightweight plugin system that is meant to greatly simplify the organization of
+large projects and to provide a way for creating pluggable components that can be **easily shared** across different
+Pyrogram applications with **minimal boilerplate code**.
+
+Introduction
+------------
+
+Prior to the plugin system, pluggable handlers were already possible. For instance, if you wanted to modularize your
+applications, you had to do something like this...
+
+ .. note:: This is an example application that replies in private chats with two messages: one containing the same
+ text message you sent and the other containing the reversed text message (e.g.: "pyrogram" -> "pyrogram" and
+ "margoryp"):
+
+ .. code-block:: text
+
+ myproject/
+ config.ini
+ handlers.py
+ main.py
+
+ - ``handlers.py``
+
+ .. code-block:: python
+
+ def echo(client, message):
+ message.reply(message.text)
+
+
+ def echo_reversed(client, message):
+ message.reply(message.text[::-1])
+
+ - ``main.py``
+
+ .. code-block:: python
+
+ from pyrogram import Client, MessageHandler, Filters
+
+ from handlers import echo, echo_reversed
+
+ app = Client("my_account")
+
+ app.add_handler(
+ MessageHandler(
+ echo,
+ Filters.text & Filters.private))
+
+ app.add_handler(
+ MessageHandler(
+ echo_reversed,
+ Filters.text & Filters.private),
+ group=1)
+
+ app.run()
+
+...which 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 ` and manually instantiate each
+:obj:`MessageHandler ` object because **you can't use those cool decorators** for your
+functions. So... What if you could?
+
+Creating Plugins
+----------------
+
+Setting up your Pyrogram project to accommodate plugins is as easy as creating a folder and putting your files full of
+handlers inside.
+
+ .. note:: This is the same example application `as shown above <#introduction>`_, written using the plugin system.
+
+ .. code-block:: text
+ :emphasize-lines: 2, 3
+
+ myproject/
+ plugins/
+ handlers.py
+ config.ini
+ main.py
+
+ - ``plugins/handlers.py``
+
+ .. code-block:: python
+ :emphasize-lines: 4, 9
+
+ from pyrogram import Client, Filters
+
+
+ @Client.on_message(Filters.text & Filters.private)
+ def echo(client, message):
+ message.reply(message.text)
+
+
+ @Client.on_message(Filters.text & Filters.private, group=1)
+ def echo_reversed(client, message):
+ message.reply(message.text[::-1])
+
+ - ``main.py``
+
+ .. code-block:: python
+
+ from pyrogram import Client
+
+ Client("my_account").run()
+
+The first important thing to note is the ``plugins`` folder, whose name is default and can be changed easily by setting
+the ``plugins_dir`` parameter when creating a :obj:`Client `; you can put any python file in the
+plugins folder and each file can contain any decorated function (handlers). Your Pyrogram Client instance (in the
+``main.py`` file) will **automatically** scan the folder upon creation 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)
+instead of the usual ``@app`` (Client instance) namespace and things will work just the same.
+
+The ``main.py`` script is now at its bare minimum and cleanest state.
From 29c314295862e568d7b93ca684164111c923d68e Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 13 Oct 2018 16:54:13 +0200
Subject: [PATCH 14/15] Index Plugin.rst
---
docs/source/index.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 6e740dd0..3e0855a5 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -84,6 +84,7 @@ To get started, press the Next button.
resources/UpdateHandling
resources/UsingFilters
+ resources/Plugins
resources/AutoAuthorization
resources/CustomizeSessions
resources/TgCrypto
From f4146a87798df3d2c0be94cb48c6cf32e6ce48a1 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 13 Oct 2018 19:33:43 +0200
Subject: [PATCH 15/15] Accept None as plugins_dir
---
pyrogram/client/client.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index f211cb16..b19bb486 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -169,7 +169,7 @@ class Client(Methods, BaseClient):
workers: int = BaseClient.WORKERS,
workdir: str = BaseClient.WORKDIR,
config_file: str = BaseClient.CONFIG_FILE,
- plugins_dir: str = BaseClient.PLUGINS_DIR):
+ plugins_dir: str or None = BaseClient.PLUGINS_DIR):
super().__init__()
self.session_name = session_name