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