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/53] 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/53] 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/53] 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/53] 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/53] 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/53] 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/53] 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 a32009a79d86085bb188a3afc73724096b348c39 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 13 Oct 2018 10:38:44 +0200
Subject: [PATCH 08/53] Don't make use of hardcoded default string values
---
pyrogram/client/client.py | 4 ++--
pyrogram/client/ext/base_client.py | 2 ++
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index ee40d2bc..e3433b3a 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -160,8 +160,8 @@ class Client(Methods, BaseClient):
first_name: str = None,
last_name: str = None,
workers: int = 4,
- workdir: str = ".",
- config_file: str = "./config.ini"):
+ workdir: str = BaseClient.WORKDIR,
+ config_file: str = BaseClient.CONFIG_FILE):
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..e7296236 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -49,6 +49,8 @@ class BaseClient:
UPDATES_WORKERS = 1
DOWNLOAD_WORKERS = 1
OFFLINE_SLEEP = 300
+ WORKDIR = "."
+ CONFIG_FILE = "./config.ini"
MEDIA_TYPE_ID = {
0: "thumbnail",
From 9649b1457cc3be512a63b70664620c1180098af8 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 13 Oct 2018 10:41:58 +0200
Subject: [PATCH 09/53] Don't make use of hardcoded default int values too
---
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 e3433b3a..c607207f 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -159,7 +159,7 @@ class Client(Methods, BaseClient):
force_sms: bool = False,
first_name: str = None,
last_name: str = None,
- workers: int = 4,
+ workers: int = BaseClient.WORKERS,
workdir: str = BaseClient.WORKDIR,
config_file: str = BaseClient.CONFIG_FILE):
super().__init__()
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index e7296236..c18c4050 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
+ WORKERS = 4
WORKDIR = "."
CONFIG_FILE = "./config.ini"
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 10/53] 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 11/53] 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 12/53] 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 13/53] 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 14/53] 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 15/53] 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 16/53] 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 17/53] 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
From d5097f0b3995b7050b0f276d1d72de55afab28a5 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 10:48:17 +0200
Subject: [PATCH 18/53] Change badge style and rename scheme to schema
---
docs/source/index.rst | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 6e740dd0..ee00e682 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -23,13 +23,13 @@ Welcome to Pyrogram
Community
-
+
-
-
From d576cdffb385e4bdf89cc56481ce62e5a2ba3f51 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 10:48:39 +0200
Subject: [PATCH 19/53] Fix reported schema layer
---
docs/source/index.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/source/index.rst b/docs/source/index.rst
index ee00e682..b3015201 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -64,7 +64,7 @@ Features
- **Easy to use**: You can easily install Pyrogram using pip and start building your app right away.
- **High-level**: The low-level details of MTProto are abstracted and automatically handled.
- **Fast**: Crypto parts are boosted up by TgCrypto_, a high-performance library written in pure C.
-- **Updated** to the latest Telegram API version, currently Layer 81 on top of MTProto 2.0.
+- **Updated** to the latest Telegram API version, currently Layer 82 on top of MTProto 2.0.
- **Documented**: The Pyrogram API is well documented and resembles the Telegram Bot API.
- **Full API**, allowing to execute any advanced action an official client is able to do, and more.
From 317f584a2adae713c81c4a389a9ac1270232faf7 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 11:14:10 +0200
Subject: [PATCH 20/53] Yet another badge style change
---
docs/source/index.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/source/index.rst b/docs/source/index.rst
index b3015201..d4883ce8 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -25,11 +25,11 @@ Welcome to Pyrogram
-
-
From f063726d93f8ef1bafa015921e5f0baf098d7aa5 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 11:46:44 +0200
Subject: [PATCH 21/53] Update index.rst
---
docs/source/index.rst | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/docs/source/index.rst b/docs/source/index.rst
index d4883ce8..94a14228 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -49,14 +49,14 @@ Welcome to Pyrogram
app.run()
Welcome to Pyrogram's Documentation! Here you can find resources for learning how to use the library.
-Contents are organized by topic and can be accessed from the sidebar, or by following them one by one using the Next
-button at the end of each page. But first, here's a brief overview of what is this all about.
+Contents are organized into self-contained topics and can be accessed from the sidebar, or by following them in order
+using the Next button at the end of each page. But first, here's a brief overview of what is this all about.
About
-----
-**Pyrogram** is a brand new Telegram_ Client Library written from the ground up in Python and C. It can be used for building
-custom Telegram applications that interact with the MTProto API as both User and Bot.
+**Pyrogram** is a brand new Telegram_ Client Library written from the ground up in Python and C. It can be used for
+building custom Telegram applications that interact with the MTProto API as both User and Bot.
Features
--------
From a3272d28d4d97a170783ce944c5a345b64725552 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 11:47:30 +0200
Subject: [PATCH 22/53] Update installation.rst
---
docs/source/start/Installation.rst | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/docs/source/start/Installation.rst b/docs/source/start/Installation.rst
index d3ddfe7d..41a7ccac 100644
--- a/docs/source/start/Installation.rst
+++ b/docs/source/start/Installation.rst
@@ -4,11 +4,12 @@ Installation
Being a Python library, Pyrogram requires Python to be installed in your system.
We recommend using the latest version of Python 3 and pip.
-Get Python 3 from https://www.python.org/downloads/ or with your package manager and pip
+Get Python 3 from https://www.python.org/downloads/ (or with your package manager) and pip
by following the instructions at https://pip.pypa.io/en/latest/installing/.
-.. note::
- Pyrogram supports Python 3 only, starting from version 3.4 and PyPy.
+.. important::
+
+ Pyrogram supports **Python 3** only, starting from version 3.4. **PyPy** is supported too.
Install Pyrogram
----------------
@@ -29,7 +30,7 @@ Bleeding Edge
-------------
If you want the latest development version of Pyrogram, you can install it straight from the develop_
-branch using this command:
+branch using this command (you might need to install **git** first):
.. code-block:: bash
From 3659ea82fb3ca0696f8c77f4f0145a42beec4c13 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 11:58:23 +0200
Subject: [PATCH 23/53] Small fixes to the Setup.rst page
---
docs/source/start/Setup.rst | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/docs/source/start/Setup.rst b/docs/source/start/Setup.rst
index e0cccc2c..24caa1f4 100644
--- a/docs/source/start/Setup.rst
+++ b/docs/source/start/Setup.rst
@@ -53,6 +53,7 @@ fits better for you:
)
.. note::
+
The examples below assume you have created a ``config.ini`` file, thus they won't show the *api_id*
and *api_hash* parameters usage.
@@ -74,7 +75,7 @@ the :class:`Client ` class by passing to it a ``session_name``
This starts an interactive shell asking you to input your **phone number** (including your `Country Code`_)
and the **phone code** you will receive:
-.. code::
+.. code-block:: text
Enter phone number: +39**********
Is "+39**********" correct? (y/n): y
@@ -84,7 +85,9 @@ After successfully authorizing yourself, a new file called ``my_account.session`
Pyrogram executing API calls with your identity. This file will be loaded again when you restart your app,
and as long as you keep the session alive, Pyrogram won't ask you again to enter your phone number.
-.. important:: Your ``*.session`` files are personal and must be kept secret.
+.. important::
+
+ Your ``*.session`` files are personal and must be kept secret.
Bot Authorization
-----------------
From d03f04a560a5427976ca5d8fde5b79ce8de26dfe Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 11:59:33 +0200
Subject: [PATCH 24/53] Add more and clearer examples in the Usage.rst page
---
docs/source/start/Usage.rst | 87 +++++++++++++++++++------------------
1 file changed, 44 insertions(+), 43 deletions(-)
diff --git a/docs/source/start/Usage.rst b/docs/source/start/Usage.rst
index 6eac5cd1..4809df0b 100644
--- a/docs/source/start/Usage.rst
+++ b/docs/source/start/Usage.rst
@@ -10,25 +10,36 @@ High-level API
The easiest and recommended way to interact with Telegram is via the high-level Pyrogram methods_ and types_, which are
named after the `Telegram Bot API`_.
-Examples (more on `GitHub `_):
-
-- Get information about the authorized user:
+Here's a simple example:
.. code-block:: python
+ from pyrogram import Client
+
+ app = Client("my_account")
+
+ app.start()
+
print(app.get_me())
+ app.send_message("me", "Hi there! I'm using **Pyrogram**")
+ app.send_location("me", 51.500729, -0.124583)
-- Send a message to yourself (Saved Messages):
+ app.stop()
+
+You can also use the Client instance in a context manager with the ``with`` statement:
.. code-block:: python
- app.send_message("me", "Hi there! I'm using Pyrogram")
+ from pyrogram import Client
-- Upload a new photo (with caption):
+ app = Client("my_account")
- .. code-block:: python
+ with app:
+ print(app.get_me())
+ app.send_message("me", "Hi there! I'm using **Pyrogram**")
+ app.send_location("me", 51.500729, -0.124583)
- app.send_photo("me", "/home/dan/perla.jpg", "Cute!")
+More examples on `GitHub `_.
Raw Functions
-------------
@@ -38,7 +49,9 @@ you have to use the raw :mod:`functions ` and :mod:`type
``pyrogram.api`` package and call any Telegram API method you wish using the :meth:`send() `
method provided by the Client class.
-.. hint:: Every high-level method mentioned in the section above is built on top of these raw functions.
+.. hint::
+
+ Every high-level method mentioned in the section above is built on top of these raw functions.
Nothing stops you from using the raw functions only, but they are rather complex and `plenty of them`_ are already
re-implemented by providing a much simpler and cleaner interface which is very similar to the Bot API.
@@ -54,17 +67,13 @@ Examples (more on `GitHub
Date: Sun, 14 Oct 2018 12:02:48 +0200
Subject: [PATCH 25/53] Add clearer details
---
docs/source/start/Usage.rst | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/docs/source/start/Usage.rst b/docs/source/start/Usage.rst
index 4809df0b..6c1697b9 100644
--- a/docs/source/start/Usage.rst
+++ b/docs/source/start/Usage.rst
@@ -26,7 +26,9 @@ Here's a simple example:
app.stop()
-You can also use the Client instance in a context manager with the ``with`` statement:
+You can also use Pyrogram in a context manager with the ``with`` statement. The Client will automatically
+:meth:`start ` and :meth:`stop ` gracefully, even in case of unhandled
+exceptions in your code:
.. code-block:: python
From 474388d8a4d391252bfa5a26db3527c2c94fb2fa Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 12:28:00 +0200
Subject: [PATCH 26/53] Small improvements on UpdateHandling.rst
---
docs/source/resources/UpdateHandling.rst | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/source/resources/UpdateHandling.rst b/docs/source/resources/UpdateHandling.rst
index 781a48af..12afe324 100644
--- a/docs/source/resources/UpdateHandling.rst
+++ b/docs/source/resources/UpdateHandling.rst
@@ -2,15 +2,15 @@ Update Handling
===============
Updates are events that happen in your Telegram account (incoming messages, new channel posts, new members join, ...)
-and can be handled by registering one or more callback functions in your app by using an `Handler <../pyrogram/Handlers.html>`_.
+and can be handled by registering one or more callback functions in your app by using `Handlers <../pyrogram/Handlers.html>`_.
To put it simply, whenever an update is received from Telegram it will be dispatched and your previously defined callback
-function(s) will be called back with the update itself as argument.
+function(s) matching it will be called back with the update itself as argument.
Registering an Handler
----------------------
-To explain how `Handlers <../pyrogram/Handlers.html>`_ work let's have a look at the most used one, the
+To explain how handlers work let's have a look at the most used one, the
:obj:`MessageHandler `, which will be in charge for handling :obj:`Message `
updates coming from all around your chats. Every other handler shares the same setup logic; you should not have troubles
settings them up once you learn from this section.
From b79df81f14dcb1cb1cb08ce609d7f3e634d9408a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 14:24:53 +0200
Subject: [PATCH 27/53] Allow specifying more than one prefix in
Filters.command
---
pyrogram/client/filters/filters.py | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py
index 79ab0f5f..93322e1d 100644
--- a/pyrogram/client/filters/filters.py
+++ b/pyrogram/client/filters/filters.py
@@ -168,7 +168,7 @@ class Filters:
@staticmethod
def command(command: str or list,
- prefix: str = "/",
+ prefix: str or list = "/",
separator: str = " ",
case_sensitive: bool = False):
"""Filter commands, i.e.: text messages starting with "/" or any other custom prefix.
@@ -180,8 +180,8 @@ class Filters:
a command arrives, the command itself and its arguments will be stored in the *command*
field of the :class:`Message `.
- prefix (``str``, *optional*):
- The command prefix. Defaults to "/" (slash).
+ prefix (``str`` | ``list``, *optional*):
+ A prefix or a list of prefixes as string. Defaults to "/" (slash).
Examples: /start, .help, !settings.
separator (``str``, *optional*):
@@ -194,11 +194,14 @@ class Filters:
"""
def f(_, m):
- if m.text and m.text.startswith(_.p):
- t = m.text.split(_.s)
- c, a = t[0][len(_.p):], t[1:]
- c = c if _.cs else c.lower()
- m.command = ([c] + a) if c in _.c else None
+ if m.text:
+ for i in _.p:
+ if m.text.startswith(i):
+ t = m.text.split(_.s)
+ c, a = t[0][len(i):], t[1:]
+ c = c if _.cs else c.lower()
+ m.command = ([c] + a) if c in _.c else None
+ break
return bool(m.command)
@@ -211,7 +214,7 @@ class Filters:
else {c if case_sensitive
else c.lower()
for c in command},
- p=prefix,
+ p=set(prefix),
s=separator,
cs=case_sensitive
)
From 465dcac630fd07990225e55761a69862fb1ce28d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 17:08:49 +0200
Subject: [PATCH 28/53] Create LastSeen class
---
compiler/api/compiler.py | 1 +
pyrogram/__init__.py | 2 +-
pyrogram/client/types/__init__.py | 2 +-
.../client/types/user_and_chats/__init__.py | 1 +
.../client/types/user_and_chats/last_seen.py | 46 +++++++++++++++++++
5 files changed, 50 insertions(+), 2 deletions(-)
create mode 100644 pyrogram/client/types/user_and_chats/last_seen.py
diff --git a/compiler/api/compiler.py b/compiler/api/compiler.py
index bcb96ea4..4cce310a 100644
--- a/compiler/api/compiler.py
+++ b/compiler/api/compiler.py
@@ -506,6 +506,7 @@ def start():
f.write("\n 0xb0700028: \"pyrogram.client.types.Dialog\",")
f.write("\n 0xb0700029: \"pyrogram.client.types.Dialogs\",")
f.write("\n 0xb0700030: \"pyrogram.client.types.ChatMembers\",")
+ f.write("\n 0xb0700031: \"pyrogram.client.types.LastSeen\"")
f.write("\n}\n")
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 6fb6fff4..cc6e9899 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -29,7 +29,7 @@ from .api.errors import Error
from .client.types import (
Audio, Chat, ChatMember, ChatMembers, ChatPhoto, Contact, Document, InputMediaPhoto,
InputMediaVideo, InputMediaDocument, InputMediaAudio, InputMediaAnimation, InputPhoneContact,
- Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, Update, User,
+ Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, Update, User, LastSeen,
UserProfilePhotos, Venue, Animation, Video, VideoNote, Voice, CallbackQuery, Messages, ForceReply,
InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove
)
diff --git a/pyrogram/client/types/__init__.py b/pyrogram/client/types/__init__.py
index 230d5e5d..a4b33e40 100644
--- a/pyrogram/client/types/__init__.py
+++ b/pyrogram/client/types/__init__.py
@@ -36,5 +36,5 @@ from .messages_and_media import (
from .update import Update
from .user_and_chats import (
Chat, ChatMember, ChatMembers, ChatPhoto,
- Dialog, Dialogs, User
+ Dialog, Dialogs, User, LastSeen
)
diff --git a/pyrogram/client/types/user_and_chats/__init__.py b/pyrogram/client/types/user_and_chats/__init__.py
index 45915edc..6711ab2c 100644
--- a/pyrogram/client/types/user_and_chats/__init__.py
+++ b/pyrogram/client/types/user_and_chats/__init__.py
@@ -22,4 +22,5 @@ from .chat_members import ChatMembers
from .chat_photo import ChatPhoto
from .dialog import Dialog
from .dialogs import Dialogs
+from .last_seen import LastSeen
from .user import User
diff --git a/pyrogram/client/types/user_and_chats/last_seen.py b/pyrogram/client/types/user_and_chats/last_seen.py
new file mode 100644
index 00000000..7403039b
--- /dev/null
+++ b/pyrogram/client/types/user_and_chats/last_seen.py
@@ -0,0 +1,46 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# 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 .
+
+from pyrogram.api.core import Object
+
+
+class LastSeen(Object):
+ """This object represents a User last seen status
+ """
+
+ ID = 0xb0700031
+
+ def __init__(
+ self,
+ online: bool = None,
+ offline: bool = None,
+ recently: bool = None,
+ within_week: bool = None,
+ within_month: bool = None,
+ long_time_ago: bool = None,
+ bot: bool = None,
+ date: int = None,
+ ):
+ self.online = online
+ self.offline = offline
+ self.recently = recently
+ self.within_week = within_week
+ self.within_month = within_month
+ self.long_time_ago = long_time_ago
+ self.bot = bot
+ self.date = date
From d2f47d7e5976da9d10de0447d85219be6984b28a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 17:11:01 +0200
Subject: [PATCH 29/53] Add last_seen field to User parse_last_seen
---
pyrogram/client/types/user_and_chats/user.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/pyrogram/client/types/user_and_chats/user.py b/pyrogram/client/types/user_and_chats/user.py
index 9ae5dab2..fd4730c3 100644
--- a/pyrogram/client/types/user_and_chats/user.py
+++ b/pyrogram/client/types/user_and_chats/user.py
@@ -70,6 +70,7 @@ class User(Object):
is_mutual_contact: bool,
is_deleted: bool,
is_bot: bool,
+ last_seen,
first_name: str,
last_name: str = None,
username: str = None,
@@ -83,6 +84,7 @@ class User(Object):
self.is_mutual_contact = is_mutual_contact
self.is_deleted = is_deleted
self.is_bot = is_bot
+ self.last_seen = last_seen
self.first_name = first_name
self.last_name = last_name
self.username = username
From 7b369a73bbcc80061eae73eabe7bbc3aef721d96 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 17:11:27 +0200
Subject: [PATCH 30/53] Add parse_last_seen util method
---
pyrogram/client/ext/utils.py | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index a497e3c9..82322d07 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -129,6 +129,30 @@ def parse_chat_photo(photo):
)
+def parse_last_seen(user: types.User) -> pyrogram_types.LastSeen:
+ status = user.status
+ last_seen = pyrogram_types.LastSeen()
+
+ if isinstance(status, types.UserStatusOnline):
+ last_seen.online = True
+ last_seen.date = status.expires
+ elif isinstance(status, types.UserStatusOffline):
+ last_seen.offline = True
+ last_seen.date = status.was_online
+ elif isinstance(status, types.UserStatusRecently):
+ last_seen.recently = True
+ elif isinstance(status, types.UserStatusLastWeek):
+ last_seen.within_week = True
+ elif isinstance(status, types.UserStatusLastMonth):
+ last_seen.within_month = True
+ elif user.bot:
+ last_seen.bot = True
+ else:
+ last_seen.long_time_ago = True
+
+ return last_seen
+
+
def parse_user(user: types.User) -> pyrogram_types.User or None:
return pyrogram_types.User(
id=user.id,
@@ -142,7 +166,8 @@ def parse_user(user: types.User) -> pyrogram_types.User or None:
username=user.username,
language_code=user.lang_code,
phone_number=user.phone,
- photo=parse_chat_photo(user.photo)
+ photo=parse_chat_photo(user.photo),
+ last_seen=parse_last_seen(user),
) if user else None
From 69c1532eaebfedcd369e1d7271621b4f5e350e8f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 17:17:50 +0200
Subject: [PATCH 31/53] Rename LastSeen to UserStatus It will make more sense
later on when I add UserStatus updates handler.
---
compiler/api/compiler.py | 2 +-
pyrogram/__init__.py | 2 +-
pyrogram/client/ext/utils.py | 4 ++--
pyrogram/client/types/__init__.py | 2 +-
pyrogram/client/types/user_and_chats/__init__.py | 2 +-
.../types/user_and_chats/{last_seen.py => user_status.py} | 2 +-
6 files changed, 7 insertions(+), 7 deletions(-)
rename pyrogram/client/types/user_and_chats/{last_seen.py => user_status.py} (98%)
diff --git a/compiler/api/compiler.py b/compiler/api/compiler.py
index 4cce310a..cacd9342 100644
--- a/compiler/api/compiler.py
+++ b/compiler/api/compiler.py
@@ -506,7 +506,7 @@ def start():
f.write("\n 0xb0700028: \"pyrogram.client.types.Dialog\",")
f.write("\n 0xb0700029: \"pyrogram.client.types.Dialogs\",")
f.write("\n 0xb0700030: \"pyrogram.client.types.ChatMembers\",")
- f.write("\n 0xb0700031: \"pyrogram.client.types.LastSeen\"")
+ f.write("\n 0xb0700031: \"pyrogram.client.types.UserStatus\"")
f.write("\n}\n")
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index cc6e9899..1f717a84 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -29,7 +29,7 @@ from .api.errors import Error
from .client.types import (
Audio, Chat, ChatMember, ChatMembers, ChatPhoto, Contact, Document, InputMediaPhoto,
InputMediaVideo, InputMediaDocument, InputMediaAudio, InputMediaAnimation, InputPhoneContact,
- Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, Update, User, LastSeen,
+ Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, Update, User, UserStatus,
UserProfilePhotos, Venue, Animation, Video, VideoNote, Voice, CallbackQuery, Messages, ForceReply,
InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove
)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 82322d07..5c80264b 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -129,9 +129,9 @@ def parse_chat_photo(photo):
)
-def parse_last_seen(user: types.User) -> pyrogram_types.LastSeen:
+def parse_last_seen(user: types.User) -> pyrogram_types.UserStatus:
status = user.status
- last_seen = pyrogram_types.LastSeen()
+ last_seen = pyrogram_types.UserStatus()
if isinstance(status, types.UserStatusOnline):
last_seen.online = True
diff --git a/pyrogram/client/types/__init__.py b/pyrogram/client/types/__init__.py
index a4b33e40..74c97ca1 100644
--- a/pyrogram/client/types/__init__.py
+++ b/pyrogram/client/types/__init__.py
@@ -36,5 +36,5 @@ from .messages_and_media import (
from .update import Update
from .user_and_chats import (
Chat, ChatMember, ChatMembers, ChatPhoto,
- Dialog, Dialogs, User, LastSeen
+ Dialog, Dialogs, User, UserStatus
)
diff --git a/pyrogram/client/types/user_and_chats/__init__.py b/pyrogram/client/types/user_and_chats/__init__.py
index 6711ab2c..f4742d83 100644
--- a/pyrogram/client/types/user_and_chats/__init__.py
+++ b/pyrogram/client/types/user_and_chats/__init__.py
@@ -22,5 +22,5 @@ from .chat_members import ChatMembers
from .chat_photo import ChatPhoto
from .dialog import Dialog
from .dialogs import Dialogs
-from .last_seen import LastSeen
+from .user_status import UserStatus
from .user import User
diff --git a/pyrogram/client/types/user_and_chats/last_seen.py b/pyrogram/client/types/user_and_chats/user_status.py
similarity index 98%
rename from pyrogram/client/types/user_and_chats/last_seen.py
rename to pyrogram/client/types/user_and_chats/user_status.py
index 7403039b..bb42dc45 100644
--- a/pyrogram/client/types/user_and_chats/last_seen.py
+++ b/pyrogram/client/types/user_and_chats/user_status.py
@@ -19,7 +19,7 @@
from pyrogram.api.core import Object
-class LastSeen(Object):
+class UserStatus(Object):
"""This object represents a User last seen status
"""
From c9ce188bbe9c898dc1988f9c21b0fdb9ff7a7f6d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 17:56:10 +0200
Subject: [PATCH 32/53] Remove "bot" property from UserStatus
---
pyrogram/client/ext/utils.py | 5 +++--
pyrogram/client/types/user_and_chats/user_status.py | 2 --
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 5c80264b..15db2e73 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -130,6 +130,9 @@ def parse_chat_photo(photo):
def parse_last_seen(user: types.User) -> pyrogram_types.UserStatus:
+ if user.bot:
+ return None
+
status = user.status
last_seen = pyrogram_types.UserStatus()
@@ -145,8 +148,6 @@ def parse_last_seen(user: types.User) -> pyrogram_types.UserStatus:
last_seen.within_week = True
elif isinstance(status, types.UserStatusLastMonth):
last_seen.within_month = True
- elif user.bot:
- last_seen.bot = True
else:
last_seen.long_time_ago = True
diff --git a/pyrogram/client/types/user_and_chats/user_status.py b/pyrogram/client/types/user_and_chats/user_status.py
index bb42dc45..90399f43 100644
--- a/pyrogram/client/types/user_and_chats/user_status.py
+++ b/pyrogram/client/types/user_and_chats/user_status.py
@@ -33,7 +33,6 @@ class UserStatus(Object):
within_week: bool = None,
within_month: bool = None,
long_time_ago: bool = None,
- bot: bool = None,
date: int = None,
):
self.online = online
@@ -42,5 +41,4 @@ class UserStatus(Object):
self.within_week = within_week
self.within_month = within_month
self.long_time_ago = long_time_ago
- self.bot = bot
self.date = date
From 2d65eb3dc7e3e12904f1c7c0f79807ebb0b99ba1 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 17:56:51 +0200
Subject: [PATCH 33/53] Add UserStatus docstrings
---
.../types/user_and_chats/user_status.py | 37 ++++++++++++++++++-
1 file changed, 36 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/types/user_and_chats/user_status.py b/pyrogram/client/types/user_and_chats/user_status.py
index 90399f43..8792a4df 100644
--- a/pyrogram/client/types/user_and_chats/user_status.py
+++ b/pyrogram/client/types/user_and_chats/user_status.py
@@ -20,7 +20,42 @@ from pyrogram.api.core import Object
class UserStatus(Object):
- """This object represents a User last seen status
+ """This object represents a User status (Last Seen privacy)
+
+ .. note::
+
+ You won't see exact last seen timestamps for people with whom you don't share your own. Instead, you get
+ "recently", "within_week", "within_month" or "long_time_ago" fields set.
+
+ Args:
+ online (``bool``):
+ True if the user is online in this moment, None otherwise.
+ If True, the "date" field will be also set containing the online expiration date (i.e.: the date when a
+ user will automatically go offline in case of no action by his client).
+
+ offline (``bool``):
+ True if the user is offline and has the Last Seen privacy setting visible for everybody, None otherwise.
+ If True, the "date" field will be also set containing the last seen date (i.e.: the date when a user
+ was online the last time).
+
+ recently (``bool``):
+ True for users with hidden Last Seen privacy that have been online between 1 second and 2-3 days ago,
+ None otherwise.
+
+ within_week (``bool``):
+ True for users with hidden Last Seen privacy that have been online between 2-3 and seven days ago,
+ None otherwise.
+
+ within_month (``bool``):
+ True for users with hidden Last Seen privacy that have been online between 6-7 days and a month ago,
+ None otherwise.
+
+ long_time_ago (``bool``):
+ True for users with hidden Last Seen privacy that have been online more than a month ago (this is also
+ always shown to blocked users), None otherwise.
+
+ date (``int``):
+ Exact date in unix time. Available only in case "online" or "offline" equals to True.
"""
ID = 0xb0700031
From b00604dbc93ab5c5f17d6b4dc63db70fbf899d25 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 18:00:31 +0200
Subject: [PATCH 34/53] Move date field
---
pyrogram/client/types/user_and_chats/user_status.py | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/pyrogram/client/types/user_and_chats/user_status.py b/pyrogram/client/types/user_and_chats/user_status.py
index 8792a4df..24b30d68 100644
--- a/pyrogram/client/types/user_and_chats/user_status.py
+++ b/pyrogram/client/types/user_and_chats/user_status.py
@@ -38,6 +38,9 @@ class UserStatus(Object):
If True, the "date" field will be also set containing the last seen date (i.e.: the date when a user
was online the last time).
+ date (``int``):
+ Exact date in unix time. Available only in case "online" or "offline" equals to True.
+
recently (``bool``):
True for users with hidden Last Seen privacy that have been online between 1 second and 2-3 days ago,
None otherwise.
@@ -53,9 +56,6 @@ class UserStatus(Object):
long_time_ago (``bool``):
True for users with hidden Last Seen privacy that have been online more than a month ago (this is also
always shown to blocked users), None otherwise.
-
- date (``int``):
- Exact date in unix time. Available only in case "online" or "offline" equals to True.
"""
ID = 0xb0700031
@@ -64,16 +64,16 @@ class UserStatus(Object):
self,
online: bool = None,
offline: bool = None,
+ date: int = None,
recently: bool = None,
within_week: bool = None,
within_month: bool = None,
- long_time_ago: bool = None,
- date: int = None,
+ long_time_ago: bool = None
):
self.online = online
self.offline = offline
+ self.date = date
self.recently = recently
self.within_week = within_week
self.within_month = within_month
self.long_time_ago = long_time_ago
- self.date = date
From 7ff4c340f767c06662c0abd080345cb86e7119c0 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Oct 2018 18:00:41 +0200
Subject: [PATCH 35/53] Add UserStatus to docs
---
docs/source/pyrogram/Types.rst | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/docs/source/pyrogram/Types.rst b/docs/source/pyrogram/Types.rst
index e8dc709c..8763c0e1 100644
--- a/docs/source/pyrogram/Types.rst
+++ b/docs/source/pyrogram/Types.rst
@@ -10,6 +10,7 @@ Users & Chats
:nosignatures:
User
+ UserStatus
Chat
ChatPhoto
ChatMember
@@ -73,6 +74,9 @@ Input Media
.. autoclass:: User
:members:
+.. autoclass:: UserStatus
+ :members:
+
.. autoclass:: Chat
:members:
From 86e4fc4e62786cbd0632f196be7eeb22dec05e4b Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 15 Oct 2018 09:20:13 +0200
Subject: [PATCH 36/53] Rename last_seen field to status in User class Also add
docstrings for status
---
pyrogram/client/types/user_and_chats/user.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/types/user_and_chats/user.py b/pyrogram/client/types/user_and_chats/user.py
index fd4730c3..9c7eec1f 100644
--- a/pyrogram/client/types/user_and_chats/user.py
+++ b/pyrogram/client/types/user_and_chats/user.py
@@ -41,6 +41,9 @@ class User(Object):
is_bot (``bool``):
True, if this user is a bot.
+ status (:obj:`UserStatus `):
+ User's Last Seen status. Empty for bots.
+
first_name (``str``):
User's or bot's first name.
@@ -70,7 +73,7 @@ class User(Object):
is_mutual_contact: bool,
is_deleted: bool,
is_bot: bool,
- last_seen,
+ status,
first_name: str,
last_name: str = None,
username: str = None,
@@ -84,7 +87,7 @@ class User(Object):
self.is_mutual_contact = is_mutual_contact
self.is_deleted = is_deleted
self.is_bot = is_bot
- self.last_seen = last_seen
+ self.status = status
self.first_name = first_name
self.last_name = last_name
self.username = username
From b2b599e211cade878e4d4dc8267bf9f636ecd9ba Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 15 Oct 2018 09:47:47 +0200
Subject: [PATCH 37/53] Rework user status parsing to also accommodate
user_status updates
---
pyrogram/client/ext/utils.py | 41 +++++++++++++++++++-----------------
1 file changed, 22 insertions(+), 19 deletions(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 15db2e73..c169f54f 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -129,29 +129,32 @@ def parse_chat_photo(photo):
)
-def parse_last_seen(user: types.User) -> pyrogram_types.UserStatus:
- if user.bot:
+def parse_update_user_status(update: types.UpdateUserStatus) -> pyrogram_types.User:
+ return pyrogram_types.User(id=update.user_id, status=parse_user_status(update.status))
+
+
+def parse_user_status(user_status, is_bot: bool = False) -> pyrogram_types.UserStatus or None:
+ if is_bot:
return None
- status = user.status
- last_seen = pyrogram_types.UserStatus()
+ status = pyrogram_types.UserStatus()
- if isinstance(status, types.UserStatusOnline):
- last_seen.online = True
- last_seen.date = status.expires
- elif isinstance(status, types.UserStatusOffline):
- last_seen.offline = True
- last_seen.date = status.was_online
- elif isinstance(status, types.UserStatusRecently):
- last_seen.recently = True
- elif isinstance(status, types.UserStatusLastWeek):
- last_seen.within_week = True
- elif isinstance(status, types.UserStatusLastMonth):
- last_seen.within_month = True
+ if isinstance(user_status, types.UserStatusOnline):
+ status.online = True
+ status.date = user_status.expires
+ elif isinstance(user_status, types.UserStatusOffline):
+ status.offline = True
+ status.date = user_status.was_online
+ elif isinstance(user_status, types.UserStatusRecently):
+ status.recently = True
+ elif isinstance(user_status, types.UserStatusLastWeek):
+ status.within_week = True
+ elif isinstance(user_status, types.UserStatusLastMonth):
+ status.within_month = True
else:
- last_seen.long_time_ago = True
+ status.long_time_ago = True
- return last_seen
+ return status
def parse_user(user: types.User) -> pyrogram_types.User or None:
@@ -168,7 +171,7 @@ def parse_user(user: types.User) -> pyrogram_types.User or None:
language_code=user.lang_code,
phone_number=user.phone,
photo=parse_chat_photo(user.photo),
- last_seen=parse_last_seen(user),
+ status=parse_user_status(user.status, user.bot),
) if user else None
From 79a9ddfab5d67e5927a237cf2e2bcd3094ad4719 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 15 Oct 2018 10:07:46 +0200
Subject: [PATCH 38/53] Some more changed in order to enhance UserStatus API
design
---
pyrogram/client/ext/utils.py | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index c169f54f..c7a10db9 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -129,15 +129,11 @@ def parse_chat_photo(photo):
)
-def parse_update_user_status(update: types.UpdateUserStatus) -> pyrogram_types.User:
- return pyrogram_types.User(id=update.user_id, status=parse_user_status(update.status))
-
-
-def parse_user_status(user_status, is_bot: bool = False) -> pyrogram_types.UserStatus or None:
+def parse_user_status(user_status, user_id: int = None, is_bot: bool = False) -> pyrogram_types.UserStatus or None:
if is_bot:
return None
- status = pyrogram_types.UserStatus()
+ status = pyrogram_types.UserStatus(user_id)
if isinstance(user_status, types.UserStatusOnline):
status.online = True
@@ -171,7 +167,7 @@ def parse_user(user: types.User) -> pyrogram_types.User or None:
language_code=user.lang_code,
phone_number=user.phone,
photo=parse_chat_photo(user.photo),
- status=parse_user_status(user.status, user.bot),
+ status=parse_user_status(user.status, is_bot=user.bot),
) if user else None
From 4b04910197a320a4b6f81f441bf553e917d1731b Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 15 Oct 2018 10:08:56 +0200
Subject: [PATCH 39/53] Add user_id field to UserStatus
---
pyrogram/client/types/user_and_chats/user_status.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/pyrogram/client/types/user_and_chats/user_status.py b/pyrogram/client/types/user_and_chats/user_status.py
index 24b30d68..17b73ea1 100644
--- a/pyrogram/client/types/user_and_chats/user_status.py
+++ b/pyrogram/client/types/user_and_chats/user_status.py
@@ -28,6 +28,9 @@ class UserStatus(Object):
"recently", "within_week", "within_month" or "long_time_ago" fields set.
Args:
+ user_id (``int``):
+ User's id. Only available for UserStatus updates.
+
online (``bool``):
True if the user is online in this moment, None otherwise.
If True, the "date" field will be also set containing the online expiration date (i.e.: the date when a
@@ -62,6 +65,7 @@ class UserStatus(Object):
def __init__(
self,
+ user_id: int = None,
online: bool = None,
offline: bool = None,
date: int = None,
@@ -70,6 +74,7 @@ class UserStatus(Object):
within_month: bool = None,
long_time_ago: bool = None
):
+ self.user_id = user_id
self.online = online
self.offline = offline
self.date = date
From 471b5c33340604348ebc67a8ba23f68a0987ce94 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 15 Oct 2018 10:10:49 +0200
Subject: [PATCH 40/53] Add user_status field to Update class
---
pyrogram/client/types/update.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/types/update.py b/pyrogram/client/types/update.py
index c8959708..748108de 100644
--- a/pyrogram/client/types/update.py
+++ b/pyrogram/client/types/update.py
@@ -58,6 +58,9 @@ class Update(Object):
pre_checkout_query (:obj:`PreCheckoutQuery `, *optional*):
New incoming pre-checkout query. Contains full information about checkout.
+
+ user_status (:obj:`UserStatus `, *optional*):
+ User status (last seen date) update.
"""
ID = 0xb0700000
@@ -74,7 +77,8 @@ class Update(Object):
chosen_inline_result=None,
callback_query=None,
shipping_query=None,
- pre_checkout_query=None
+ pre_checkout_query=None,
+ user_status=None
):
self.message = message
self.edited_message = edited_message
@@ -87,3 +91,4 @@ class Update(Object):
self.callback_query = callback_query
self.shipping_query = shipping_query
self.pre_checkout_query = pre_checkout_query
+ self.user_status = user_status
From ff9be53a95def291b363ba877a73830b48656437 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 15 Oct 2018 10:14:40 +0200
Subject: [PATCH 41/53] Add UserStatusHandler class
---
.../client/handlers/user_status_handler.py | 54 +++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100644 pyrogram/client/handlers/user_status_handler.py
diff --git a/pyrogram/client/handlers/user_status_handler.py b/pyrogram/client/handlers/user_status_handler.py
new file mode 100644
index 00000000..2442d7eb
--- /dev/null
+++ b/pyrogram/client/handlers/user_status_handler.py
@@ -0,0 +1,54 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# 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 .
+
+from .handler import Handler
+
+
+class UserStatusHandler(Handler):
+ """The UserStatus handler class. Used to handle user status updates (user going online or offline).
+ It is intended to be used with :meth:`add_handler() `
+
+ For a nicer way to register this handler, have a look at the
+ :meth:`on_user_status() ` decorator.
+
+ Args:
+ callback (``callable``):
+ Pass a function that will be called when a new UserStatus update arrives. It takes *(client, user_status)*
+ as positional arguments (look at the section below for a detailed description).
+
+ filters (:obj:`Filters `):
+ Pass one or more filters to allow only a subset of messages to be passed
+ in your callback function.
+
+ Other parameters:
+ client (:obj:`Client `):
+ The Client itself, useful when you want to call other API methods inside the user status handler.
+
+ user_status (:obj:`UserStatus `):
+ The received UserStatus update.
+ """
+
+ def __init__(self, callback: callable, filters=None):
+ super().__init__(callback, filters)
+
+ def check(self, user_status):
+ return (
+ self.filters(user_status)
+ if callable(self.filters)
+ else True
+ )
From 2eae08aaa642d742cfc888b543501316188f2bad Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 15 Oct 2018 10:16:19 +0200
Subject: [PATCH 42/53] Add on_user_status decorator
---
.../methods/decorators/on_user_status.py | 41 +++++++++++++++++++
1 file changed, 41 insertions(+)
create mode 100644 pyrogram/client/methods/decorators/on_user_status.py
diff --git a/pyrogram/client/methods/decorators/on_user_status.py b/pyrogram/client/methods/decorators/on_user_status.py
new file mode 100644
index 00000000..81367c3e
--- /dev/null
+++ b/pyrogram/client/methods/decorators/on_user_status.py
@@ -0,0 +1,41 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# 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 .
+
+import pyrogram
+from ...ext import BaseClient
+
+
+class OnUserStatus(BaseClient):
+ def on_user_status(self, filters=None, group: int = 0):
+ """Use this decorator to automatically register a function for handling
+ user status updates. This does the same thing as :meth:`add_handler` using the
+ :class:`UserStatusHandler`.
+
+ Args:
+ filters (:obj:`Filters `):
+ Pass one or more filters to allow only a subset of UserStatus updated to be passed in your function.
+
+ group (``int``, *optional*):
+ The group identifier, defaults to 0.
+ """
+
+ def decorator(func):
+ self.add_handler(pyrogram.UserStatusHandler(func, filters), group)
+ return func
+
+ return decorator
From d567b878b1b70528c9cb22718c1faccfefd78148 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 15 Oct 2018 10:17:00 +0200
Subject: [PATCH 43/53] Expose UserStatusHandler and on_user_status
---
pyrogram/__init__.py | 2 +-
pyrogram/client/__init__.py | 2 +-
pyrogram/client/handlers/__init__.py | 3 ++-
pyrogram/client/methods/decorators/__init__.py | 12 ++++++++++--
4 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 1f717a84..12f181c3 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -36,5 +36,5 @@ from .client.types import (
from .client import (
Client, ChatAction, ParseMode, Emoji,
MessageHandler, DeletedMessagesHandler, CallbackQueryHandler,
- RawUpdateHandler, DisconnectHandler, Filters
+ RawUpdateHandler, DisconnectHandler, UserStatusHandler, Filters
)
diff --git a/pyrogram/client/__init__.py b/pyrogram/client/__init__.py
index b345de94..00b9905a 100644
--- a/pyrogram/client/__init__.py
+++ b/pyrogram/client/__init__.py
@@ -22,5 +22,5 @@ from .filters import Filters
from .handlers import (
MessageHandler, DeletedMessagesHandler,
CallbackQueryHandler, RawUpdateHandler,
- DisconnectHandler
+ DisconnectHandler, UserStatusHandler
)
diff --git a/pyrogram/client/handlers/__init__.py b/pyrogram/client/handlers/__init__.py
index d06b2a76..ff1ead7a 100644
--- a/pyrogram/client/handlers/__init__.py
+++ b/pyrogram/client/handlers/__init__.py
@@ -17,7 +17,8 @@
# along with Pyrogram. If not, see .
from .callback_query_handler import CallbackQueryHandler
+from .deleted_messages_handler import DeletedMessagesHandler
from .disconnect_handler import DisconnectHandler
from .message_handler import MessageHandler
-from .deleted_messages_handler import DeletedMessagesHandler
from .raw_update_handler import RawUpdateHandler
+from .user_status_handler import UserStatusHandler
diff --git a/pyrogram/client/methods/decorators/__init__.py b/pyrogram/client/methods/decorators/__init__.py
index f84a922c..6cf9940a 100644
--- a/pyrogram/client/methods/decorators/__init__.py
+++ b/pyrogram/client/methods/decorators/__init__.py
@@ -17,11 +17,19 @@
# along with Pyrogram. If not, see .
from .on_callback_query import OnCallbackQuery
+from .on_deleted_messages import OnDeletedMessages
from .on_disconnect import OnDisconnect
from .on_message import OnMessage
-from .on_deleted_messages import OnDeletedMessages
from .on_raw_update import OnRawUpdate
+from .on_user_status import OnUserStatus
-class Decorators(OnMessage, OnDeletedMessages, OnCallbackQuery, OnRawUpdate, OnDisconnect):
+class Decorators(
+ OnMessage,
+ OnDeletedMessages,
+ OnCallbackQuery,
+ OnRawUpdate,
+ OnDisconnect,
+ OnUserStatus
+):
pass
From 5b173768013a5ee7d50fa3cfd955bdad913eec16 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 15 Oct 2018 10:18:22 +0200
Subject: [PATCH 44/53] Enable dispatching of user status updates
---
pyrogram/client/dispatcher/dispatcher.py | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py
index 5506cbdd..a0c5e365 100644
--- a/pyrogram/client/dispatcher/dispatcher.py
+++ b/pyrogram/client/dispatcher/dispatcher.py
@@ -25,7 +25,7 @@ from threading import Thread
import pyrogram
from pyrogram.api import types
from ..ext import utils
-from ..handlers import RawUpdateHandler, CallbackQueryHandler, MessageHandler, DeletedMessagesHandler
+from ..handlers import RawUpdateHandler, CallbackQueryHandler, MessageHandler, DeletedMessagesHandler, UserStatusHandler
log = logging.getLogger(__name__)
@@ -108,6 +108,8 @@ class Dispatcher:
callback_query = update.callback_query
+ user_status = update.user_status
+
if message and isinstance(handler, MessageHandler):
if not handler.check(message):
continue
@@ -123,6 +125,11 @@ class Dispatcher:
continue
args = (self.client, callback_query)
+ elif user_status and isinstance(handler, UserStatusHandler):
+ if not handler.check(user_status):
+ continue
+
+ args = (self.client, user_status)
else:
continue
@@ -209,6 +216,14 @@ class Dispatcher:
)
)
)
+ elif isinstance(update, types.UpdateUserStatus):
+ self.dispatch(
+ pyrogram.Update(
+ user_status=utils.parse_user_status(
+ update.status, update.user_id
+ )
+ )
+ )
else:
continue
except Exception as e:
From 93018a7f6cea7ef099cb0d1ee3957b5cf3c1c458 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 15 Oct 2018 11:03:07 +0200
Subject: [PATCH 45/53] Add set_profile_photo method
---
pyrogram/client/methods/users/__init__.py | 2 +
.../client/methods/users/set_profile_photo.py | 47 +++++++++++++++++++
2 files changed, 49 insertions(+)
create mode 100644 pyrogram/client/methods/users/set_profile_photo.py
diff --git a/pyrogram/client/methods/users/__init__.py b/pyrogram/client/methods/users/__init__.py
index f7c32b3b..9813b744 100644
--- a/pyrogram/client/methods/users/__init__.py
+++ b/pyrogram/client/methods/users/__init__.py
@@ -20,10 +20,12 @@ from .delete_profile_photos import DeleteProfilePhotos
from .get_me import GetMe
from .get_user_profile_photos import GetUserProfilePhotos
from .get_users import GetUsers
+from .set_profile_photo import SetProfilePhoto
class Users(
GetUserProfilePhotos,
+ SetProfilePhoto,
DeleteProfilePhotos,
GetUsers,
GetMe
diff --git a/pyrogram/client/methods/users/set_profile_photo.py b/pyrogram/client/methods/users/set_profile_photo.py
new file mode 100644
index 00000000..8ed9dc7b
--- /dev/null
+++ b/pyrogram/client/methods/users/set_profile_photo.py
@@ -0,0 +1,47 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2018 Dan Tès
+#
+# 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 .
+
+from pyrogram.api import functions
+from ...ext import BaseClient
+
+
+class SetProfilePhoto(BaseClient):
+ def set_profile_photo(self, photo: str):
+ """Use this method to set a new profile photo.
+
+ This method only works for Users. Bots profile photos must be set using BotFather.
+
+ Args:
+ photo (``str``):
+ Profile photo to set.
+ Pass a file path as string to upload a new photo that exists on your local machine.
+
+ Returns:
+ True on success.
+
+ Raises:
+ :class:`Error `
+ """
+
+ return bool(
+ self.send(
+ functions.photos.UploadProfilePhoto(
+ self.save_file(photo)
+ )
+ )
+ )
From 8fc5b8a545df80cf1097f676282e51bbee4d15ee Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 16 Oct 2018 11:43:54 +0200
Subject: [PATCH 46/53] Rename set_profile_photo to set_user_profile_photo
---
pyrogram/client/methods/users/__init__.py | 4 ++--
.../{set_profile_photo.py => set_user_profile_photo.py} | 9 +++++----
2 files changed, 7 insertions(+), 6 deletions(-)
rename pyrogram/client/methods/users/{set_profile_photo.py => set_user_profile_photo.py} (84%)
diff --git a/pyrogram/client/methods/users/__init__.py b/pyrogram/client/methods/users/__init__.py
index 9813b744..ed6f1a83 100644
--- a/pyrogram/client/methods/users/__init__.py
+++ b/pyrogram/client/methods/users/__init__.py
@@ -20,12 +20,12 @@ from .delete_profile_photos import DeleteProfilePhotos
from .get_me import GetMe
from .get_user_profile_photos import GetUserProfilePhotos
from .get_users import GetUsers
-from .set_profile_photo import SetProfilePhoto
+from .set_user_profile_photo import SetUserProfilePhoto
class Users(
GetUserProfilePhotos,
- SetProfilePhoto,
+ SetUserProfilePhoto,
DeleteProfilePhotos,
GetUsers,
GetMe
diff --git a/pyrogram/client/methods/users/set_profile_photo.py b/pyrogram/client/methods/users/set_user_profile_photo.py
similarity index 84%
rename from pyrogram/client/methods/users/set_profile_photo.py
rename to pyrogram/client/methods/users/set_user_profile_photo.py
index 8ed9dc7b..5167348f 100644
--- a/pyrogram/client/methods/users/set_profile_photo.py
+++ b/pyrogram/client/methods/users/set_user_profile_photo.py
@@ -20,11 +20,12 @@ from pyrogram.api import functions
from ...ext import BaseClient
-class SetProfilePhoto(BaseClient):
- def set_profile_photo(self, photo: str):
- """Use this method to set a new profile photo.
+class SetUserProfilePhoto(BaseClient):
+ def set_user_profile_photo(self, photo: str):
+ """Use this method to set a new user profile photo.
- This method only works for Users. Bots profile photos must be set using BotFather.
+ This method only works for Users.
+ Bots profile photos must be set using BotFather.
Args:
photo (``str``):
From 29201674ef03cc3c2bdab28d1e34171e5d5cca4f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 16 Oct 2018 11:45:20 +0200
Subject: [PATCH 47/53] Rename delete_profile_photos to
delete_user_profile_photos For consistency with other method names
---
pyrogram/client/methods/users/__init__.py | 4 ++--
...delete_profile_photos.py => delete_user_profile_photos.py} | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
rename pyrogram/client/methods/users/{delete_profile_photos.py => delete_user_profile_photos.py} (94%)
diff --git a/pyrogram/client/methods/users/__init__.py b/pyrogram/client/methods/users/__init__.py
index ed6f1a83..11f51d19 100644
--- a/pyrogram/client/methods/users/__init__.py
+++ b/pyrogram/client/methods/users/__init__.py
@@ -16,7 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from .delete_profile_photos import DeleteProfilePhotos
+from .delete_user_profile_photos import DeleteUserProfilePhotos
from .get_me import GetMe
from .get_user_profile_photos import GetUserProfilePhotos
from .get_users import GetUsers
@@ -26,7 +26,7 @@ from .set_user_profile_photo import SetUserProfilePhoto
class Users(
GetUserProfilePhotos,
SetUserProfilePhoto,
- DeleteProfilePhotos,
+ DeleteUserProfilePhotos,
GetUsers,
GetMe
):
diff --git a/pyrogram/client/methods/users/delete_profile_photos.py b/pyrogram/client/methods/users/delete_user_profile_photos.py
similarity index 94%
rename from pyrogram/client/methods/users/delete_profile_photos.py
rename to pyrogram/client/methods/users/delete_user_profile_photos.py
index 47a6682a..58c2deb4 100644
--- a/pyrogram/client/methods/users/delete_profile_photos.py
+++ b/pyrogram/client/methods/users/delete_user_profile_photos.py
@@ -23,8 +23,8 @@ from pyrogram.api import functions, types
from ...ext import BaseClient
-class DeleteProfilePhotos(BaseClient):
- def delete_profile_photos(self, id: str or list):
+class DeleteUserProfilePhotos(BaseClient):
+ def delete_user_profile_photos(self, id: str or list):
"""Use this method to delete your own profile photos
Args:
From 22998af784a7d2cb6db0b0a423d492488e529da1 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 16 Oct 2018 11:45:39 +0200
Subject: [PATCH 48/53] Fix docstrings
---
pyrogram/client/methods/users/set_user_profile_photo.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/methods/users/set_user_profile_photo.py b/pyrogram/client/methods/users/set_user_profile_photo.py
index 5167348f..b107a968 100644
--- a/pyrogram/client/methods/users/set_user_profile_photo.py
+++ b/pyrogram/client/methods/users/set_user_profile_photo.py
@@ -22,7 +22,7 @@ from ...ext import BaseClient
class SetUserProfilePhoto(BaseClient):
def set_user_profile_photo(self, photo: str):
- """Use this method to set a new user profile photo.
+ """Use this method to set a new profile photo.
This method only works for Users.
Bots profile photos must be set using BotFather.
From 1f5f339f6f9e04f75309a3fcd99f8f0b08380598 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 16 Oct 2018 11:49:12 +0200
Subject: [PATCH 49/53] Reflect changes to docs
---
docs/source/pyrogram/Client.rst | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/docs/source/pyrogram/Client.rst b/docs/source/pyrogram/Client.rst
index 1cd1a072..72844987 100644
--- a/docs/source/pyrogram/Client.rst
+++ b/docs/source/pyrogram/Client.rst
@@ -96,7 +96,8 @@ Users
get_me
get_users
get_user_profile_photos
- delete_profile_photos
+ set_user_profile_photos
+ delete_userprofile_photos
Contacts
--------
From 841141077f663c393186e6f18a21a96ff0e34e44 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 16 Oct 2018 11:53:05 +0200
Subject: [PATCH 50/53] Add better examples to Filters.command
---
pyrogram/client/filters/filters.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py
index 93322e1d..e80e230e 100644
--- a/pyrogram/client/filters/filters.py
+++ b/pyrogram/client/filters/filters.py
@@ -181,8 +181,8 @@ class Filters:
field of the :class:`Message `.
prefix (``str`` | ``list``, *optional*):
- A prefix or a list of prefixes as string. Defaults to "/" (slash).
- Examples: /start, .help, !settings.
+ A prefix or a list of prefixes as string the filter should look for.
+ Defaults to "/" (slash). Examples: ".", "!", ["/", "!", "."].
separator (``str``, *optional*):
The command arguments separator. Defaults to " " (white space).
From b34aca0c6f568212d91588306b630cb512eb2317 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 16 Oct 2018 12:15:31 +0200
Subject: [PATCH 51/53] Fix wrong method names in docs
---
docs/source/pyrogram/Client.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/source/pyrogram/Client.rst b/docs/source/pyrogram/Client.rst
index 72844987..29bee7ea 100644
--- a/docs/source/pyrogram/Client.rst
+++ b/docs/source/pyrogram/Client.rst
@@ -96,8 +96,8 @@ Users
get_me
get_users
get_user_profile_photos
- set_user_profile_photos
- delete_userprofile_photos
+ set_user_profile_photo
+ delete_user_profile_photos
Contacts
--------
From a163c2b4e969eb2ac5075d726f57474ec7a29390 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 16 Oct 2018 12:16:40 +0200
Subject: [PATCH 52/53] Add UserStatusHandler in docs
---
docs/source/pyrogram/Handlers.rst | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/docs/source/pyrogram/Handlers.rst b/docs/source/pyrogram/Handlers.rst
index 9f69c2c9..3b748e9d 100644
--- a/docs/source/pyrogram/Handlers.rst
+++ b/docs/source/pyrogram/Handlers.rst
@@ -9,6 +9,7 @@ Handlers
MessageHandler
DeletedMessagesHandler
CallbackQueryHandler
+ UserStatusHandler
DisconnectHandler
RawUpdateHandler
@@ -21,6 +22,9 @@ Handlers
.. autoclass:: CallbackQueryHandler
:members:
+.. autoclass:: UserStatusHandler
+ :members:
+
.. autoclass:: DisconnectHandler
:members:
From 2ae1d522f39317add11ac18d15d83adfa82e362a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 16 Oct 2018 12:17:39 +0200
Subject: [PATCH 53/53] Add on_user_status decorator to docs
---
docs/source/pyrogram/Client.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/docs/source/pyrogram/Client.rst b/docs/source/pyrogram/Client.rst
index 29bee7ea..50e213ea 100644
--- a/docs/source/pyrogram/Client.rst
+++ b/docs/source/pyrogram/Client.rst
@@ -30,6 +30,7 @@ Decorators
on_message
on_callback_query
on_deleted_messages
+ on_user_status
on_disconnect
on_raw_update