From de39c181ef7b0b54e70b95f7848d2c1272ad2b9a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 8 Jun 2018 13:10:07 +0200
Subject: [PATCH 0001/1185] Start refactoring Connection to accommodate asyncio
---
pyrogram/connection/connection.py | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index a53295ce7c..b03e885282 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -16,9 +16,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
import logging
-import threading
-import time
from .transport import *
@@ -36,23 +35,23 @@ class Connection:
4: TCPIntermediateO
}
- def __init__(self, address: tuple, proxy: dict, mode: int = 1):
+ def __init__(self, address: tuple, proxy: dict, mode: int = 2):
self.address = address
self.proxy = proxy
self.mode = self.MODES.get(mode, TCPAbridged)
- self.lock = threading.Lock()
+
self.connection = None
- def connect(self):
+ async def connect(self):
for i in range(Connection.MAX_RETRIES):
self.connection = self.mode(self.proxy)
try:
log.info("Connecting...")
- self.connection.connect(self.address)
+ await self.connection.connect(self.address)
except OSError:
self.connection.close()
- time.sleep(1)
+ await asyncio.sleep(1)
else:
break
else:
@@ -62,9 +61,8 @@ def close(self):
self.connection.close()
log.info("Disconnected")
- def send(self, data: bytes):
- with self.lock:
- self.connection.sendall(data)
+ async def send(self, data: bytes):
+ await self.connection.send(data)
- def recv(self) -> bytes or None:
- return self.connection.recvall()
+ async def recv(self) -> bytes or None:
+ return await self.connection.recv()
From 7a6d7d003798cf26450b347c6d4c9743309fc47f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 9 Jun 2018 19:36:23 +0200
Subject: [PATCH 0002/1185] Implement async TCP protocol
---
pyrogram/connection/transport/tcp/tcp.py | 86 ++++++++++++++++++++----
1 file changed, 73 insertions(+), 13 deletions(-)
diff --git a/pyrogram/connection/transport/tcp/tcp.py b/pyrogram/connection/transport/tcp/tcp.py
index 5df8aacb0a..f006cadd28 100644
--- a/pyrogram/connection/transport/tcp/tcp.py
+++ b/pyrogram/connection/transport/tcp/tcp.py
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
import logging
import socket
@@ -32,14 +33,18 @@
log = logging.getLogger(__name__)
-class TCP(socks.socksocket):
+class TCP:
def __init__(self, proxy: dict):
- super().__init__()
- self.settimeout(10)
+ self.proxy = proxy
+
+ self.socket = socks.socksocket()
+ self.reader = None # type: asyncio.StreamReader
+ self.writer = None # type: asyncio.StreamWriter
+
self.proxy_enabled = proxy.get("enabled", False)
if proxy and self.proxy_enabled:
- self.set_proxy(
+ self.socket.set_proxy(
proxy_type=socks.SOCKS5,
addr=proxy.get("hostname", None),
port=proxy.get("port", None),
@@ -52,26 +57,81 @@ def __init__(self, proxy: dict):
proxy.get("port", None)
))
+ async def connect(self, address: tuple):
+ self.socket.connect(address)
+ self.reader, self.writer = await asyncio.open_connection(sock=self.socket)
+
def close(self):
try:
- self.shutdown(socket.SHUT_RDWR)
- except OSError:
- pass
- finally:
- super().close()
+ self.writer.close()
+ except AttributeError:
+ try:
+ self.socket.shutdown(socket.SHUT_RDWR)
+ except OSError:
+ pass
+ finally:
+ self.socket.close()
+
+ async def send(self, data: bytes):
+ self.writer.write(data)
+ await self.writer.drain()
- def recvall(self, length: int) -> bytes or None:
+ async def recv(self, length: int = 0):
data = b""
while len(data) < length:
try:
- packet = super().recv(length - len(data))
+ chunk = await self.reader.read(length - len(data))
except OSError:
return None
else:
- if packet:
- data += packet
+ if chunk:
+ data += chunk
else:
return None
return data
+
+# class TCP(socks.socksocket):
+# def __init__(self, proxy: dict):
+# super().__init__()
+# self.settimeout(10)
+# self.proxy_enabled = proxy.get("enabled", False)
+#
+# if proxy and self.proxy_enabled:
+# self.set_proxy(
+# proxy_type=socks.SOCKS5,
+# addr=proxy.get("hostname", None),
+# port=proxy.get("port", None),
+# username=proxy.get("username", None),
+# password=proxy.get("password", None)
+# )
+#
+# log.info("Using proxy {}:{}".format(
+# proxy.get("hostname", None),
+# proxy.get("port", None)
+# ))
+#
+# def close(self):
+# try:
+# self.shutdown(socket.SHUT_RDWR)
+# except OSError:
+# pass
+# finally:
+# super().close()
+#
+# def recvall(self, length: int) -> bytes or None:
+# data = b""
+#
+# while len(data) < length:
+# try:
+# packet = super().recv(length - len(data))
+# except OSError:
+# return None
+# else:
+# if packet:
+# data += packet
+# else:
+# return None
+#
+# return data
From dc322ddf1a6ee07aad0264f8d35e1a55b0958064 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 10 Jun 2018 16:14:30 +0200
Subject: [PATCH 0003/1185] Expose TCP class
---
pyrogram/connection/transport/tcp/__init__.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyrogram/connection/transport/tcp/__init__.py b/pyrogram/connection/transport/tcp/__init__.py
index ce662e61f4..016e91e4d3 100644
--- a/pyrogram/connection/transport/tcp/__init__.py
+++ b/pyrogram/connection/transport/tcp/__init__.py
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+from .tcp import TCP
from .tcp_abridged import TCPAbridged
from .tcp_abridged_o import TCPAbridgedO
from .tcp_full import TCPFull
From 6ab60c0d3609493627caef9fcbf7f08a9034132d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 10 Jun 2018 16:14:42 +0200
Subject: [PATCH 0004/1185] Add type hint
---
pyrogram/connection/connection.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index b03e885282..cab31b62d9 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -40,7 +40,7 @@ def __init__(self, address: tuple, proxy: dict, mode: int = 2):
self.proxy = proxy
self.mode = self.MODES.get(mode, TCPAbridged)
- self.connection = None
+ self.connection = None # type: TCP
async def connect(self):
for i in range(Connection.MAX_RETRIES):
From ead0b4f029561fa55e57805de25425fa98ca6c09 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 10 Jun 2018 16:15:19 +0200
Subject: [PATCH 0005/1185] Use more relevant names for Connection fields
---
pyrogram/connection/connection.py | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index cab31b62d9..b4705fca46 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -40,17 +40,17 @@ def __init__(self, address: tuple, proxy: dict, mode: int = 2):
self.proxy = proxy
self.mode = self.MODES.get(mode, TCPAbridged)
- self.connection = None # type: TCP
+ self.protocol = None # type: TCP
async def connect(self):
for i in range(Connection.MAX_RETRIES):
- self.connection = self.mode(self.proxy)
+ self.protocol = self.mode(self.proxy)
try:
log.info("Connecting...")
- await self.connection.connect(self.address)
+ await self.protocol.connect(self.address)
except OSError:
- self.connection.close()
+ self.protocol.close()
await asyncio.sleep(1)
else:
break
@@ -58,11 +58,11 @@ async def connect(self):
raise TimeoutError
def close(self):
- self.connection.close()
+ self.protocol.close()
log.info("Disconnected")
async def send(self, data: bytes):
- await self.connection.send(data)
+ await self.protocol.send(data)
async def recv(self) -> bytes or None:
- return await self.connection.recv()
+ return await self.protocol.recv()
From d64337bf90466efc57d6da7665d97002fb73c014 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 11 Jun 2018 12:25:30 +0200
Subject: [PATCH 0006/1185] Implement Intermediate protocol using asyncio
---
.../transport/tcp/tcp_intermediate.py | 22 +++++++++++--------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/pyrogram/connection/transport/tcp/tcp_intermediate.py b/pyrogram/connection/transport/tcp/tcp_intermediate.py
index 4b2e25961d..82c7b6052d 100644
--- a/pyrogram/connection/transport/tcp/tcp_intermediate.py
+++ b/pyrogram/connection/transport/tcp/tcp_intermediate.py
@@ -28,19 +28,23 @@ class TCPIntermediate(TCP):
def __init__(self, proxy: dict):
super().__init__(proxy)
- def connect(self, address: tuple):
- super().connect(address)
- super().sendall(b"\xee" * 4)
+ async def connect(self, address: tuple):
+ await super().connect(address)
+ await super().send(b"\xee" * 4)
- log.info("Connected{}!".format(" with proxy" if self.proxy_enabled else ""))
+ log.info("Connected{}!".format(
+ " with proxy"
+ if self.proxy_enabled
+ else ""
+ ))
- def sendall(self, data: bytes, *args):
- super().sendall(pack(" bytes or None:
- length = super().recvall(4)
+ async def recv(self, length: int = 0) -> bytes or None:
+ length = await super().recv(4)
if length is None:
return None
- return super().recvall(unpack("
Date: Tue, 12 Jun 2018 15:56:33 +0200
Subject: [PATCH 0007/1185] Start rewriting Session using asyncio
---
pyrogram/session/session.py | 547 +++++++++++++++++++++++++++++++-----
1 file changed, 473 insertions(+), 74 deletions(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 7e90cfff5c..173e884610 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -16,16 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
import logging
import platform
import threading
-import time
-from datetime import timedelta, datetime
+from datetime import datetime, timedelta
from hashlib import sha1, sha256
from io import BytesIO
from os import urandom
-from queue import Queue
-from threading import Event, Thread
import pyrogram
from pyrogram import __copyright__, __license__, __version__
@@ -43,7 +41,7 @@
class Result:
def __init__(self):
self.value = None
- self.event = Event()
+ self.event = asyncio.Event()
class Session:
@@ -115,47 +113,38 @@ def __init__(self,
self.pending_acks = set()
- self.recv_queue = Queue()
+ self.recv_queue = asyncio.Queue()
self.results = {}
- self.ping_thread = None
- self.ping_thread_event = Event()
+ self.ping_task = None
+ self.ping_task_event = asyncio.Event()
- self.next_salt_thread = None
- self.next_salt_thread_event = Event()
+ self.next_salt_task = None
+ self.next_salt_task_event = asyncio.Event()
- self.net_worker_list = []
+ self.net_worker_task = None
+ self.recv_task = None
- self.is_connected = Event()
+ self.is_connected = asyncio.Event()
- def start(self):
+ async def start(self):
while True:
self.connection = Connection(DataCenter(self.dc_id, self.test_mode), self.proxy)
try:
- self.connection.connect()
+ await self.connection.connect()
- for i in range(self.NET_WORKERS):
- self.net_worker_list.append(
- Thread(
- target=self.net_worker,
- name="NetWorker#{}".format(i + 1)
- )
- )
-
- self.net_worker_list[-1].start()
-
- Thread(target=self.recv, name="RecvThread").start()
+ self.net_worker_task = asyncio.ensure_future(self.net_worker())
+ self.recv_task = asyncio.ensure_future(self.recv())
self.current_salt = FutureSalt(0, 0, self.INITIAL_SALT)
- self.current_salt = FutureSalt(0, 0, self._send(functions.Ping(0)).new_server_salt)
- self.current_salt = self._send(functions.GetFutureSalts(1)).salts[0]
+ self.current_salt = FutureSalt(0, 0, (await self._send(functions.Ping(0))).new_server_salt)
+ self.current_salt = (await self._send(functions.GetFutureSalts(1))).salts[0]
- self.next_salt_thread = Thread(target=self.next_salt, name="NextSaltThread")
- self.next_salt_thread.start()
+ self.next_salt_task = asyncio.ensure_future(self.next_salt())
if not self.is_cdn:
- self._send(
+ await self._send(
functions.InvokeWithLayer(
layer,
functions.InitConnection(
@@ -169,14 +158,13 @@ def start(self):
)
)
- self.ping_thread = Thread(target=self.ping, name="PingThread")
- self.ping_thread.start()
+ self.ping_task = asyncio.ensure_future(self.ping())
log.info("Connection inited: Layer {}".format(layer))
except (OSError, TimeoutError, Error):
- self.stop()
+ await self.stop()
except Exception as e:
- self.stop()
+ await self.stop()
raise e
else:
break
@@ -185,30 +173,28 @@ def start(self):
log.debug("Session started")
- def stop(self):
+ async def stop(self):
self.is_connected.clear()
- self.ping_thread_event.set()
- self.next_salt_thread_event.set()
+ self.ping_task_event.set()
+ self.next_salt_task_event.set()
- if self.ping_thread is not None:
- self.ping_thread.join()
+ if self.ping_task is not None:
+ await self.ping_task
- if self.next_salt_thread is not None:
- self.next_salt_thread.join()
+ if self.next_salt_task is not None:
+ await self.next_salt_task
- self.ping_thread_event.clear()
- self.next_salt_thread_event.clear()
+ self.ping_task_event.clear()
+ self.next_salt_task_event.clear()
self.connection.close()
- for i in range(self.NET_WORKERS):
- self.recv_queue.put(None)
+ await self.recv_task
- for i in self.net_worker_list:
- i.join()
+ self.recv_queue.put_nowait(None)
- self.net_worker_list.clear()
+ await self.net_worker_task
for i in self.results.values():
i.event.set()
@@ -260,12 +246,12 @@ def unpack(self, b: BytesIO) -> Message:
return message
- def net_worker(self):
+ async def net_worker(self):
name = threading.current_thread().name
log.debug("{} started".format(name))
while True:
- packet = self.recv_queue.get()
+ packet = await self.recv_queue.get()
if packet is None:
break
@@ -315,7 +301,7 @@ def net_worker(self):
log.info("Send {} acks".format(len(self.pending_acks)))
try:
- self._send(types.MsgsAck(list(self.pending_acks)), False)
+ await self._send(types.MsgsAck(list(self.pending_acks)), False)
except (OSError, TimeoutError):
pass
else:
@@ -325,13 +311,16 @@ def net_worker(self):
log.debug("{} stopped".format(name))
- def ping(self):
- log.debug("PingThread started")
+ async def ping(self):
+ log.debug("Ping Task started")
while True:
- self.ping_thread_event.wait(self.PING_INTERVAL)
+ try:
+ await asyncio.wait_for(self.ping_task_event.wait(), self.PING_INTERVAL)
+ except asyncio.TimeoutError:
+ pass
- if self.ping_thread_event.is_set():
+ if self.ping_task_event.is_set():
break
try:
@@ -341,9 +330,9 @@ def ping(self):
except (OSError, TimeoutError, Error):
pass
- log.debug("PingThread stopped")
+ log.debug("Ping Task stopped")
- def next_salt(self):
+ async def next_salt(self):
log.debug("NextSaltThread started")
while True:
@@ -360,38 +349,42 @@ def next_salt(self):
now + timedelta(seconds=dt)
))
- self.next_salt_thread_event.wait(dt)
+ try:
+ await asyncio.wait_for(self.next_salt_task_event.wait(), dt)
+ except asyncio.TimeoutError:
+ pass
- if self.next_salt_thread_event.is_set():
+ if self.next_salt_task_event.is_set():
break
try:
- self.current_salt = self._send(functions.GetFutureSalts(1)).salts[0]
+ self.current_salt = (await self._send(functions.GetFutureSalts(1))).salts[0]
except (OSError, TimeoutError, Error):
self.connection.close()
break
log.debug("NextSaltThread stopped")
- def recv(self):
- log.debug("RecvThread started")
+ async def recv(self):
+ log.debug("Recv Task started")
while True:
- packet = self.connection.recv()
+ packet = await self.connection.recv()
if packet is None or len(packet) == 4:
if packet:
log.warning("Server sent \"{}\"".format(Int.read(BytesIO(packet))))
if self.is_connected.is_set():
- Thread(target=self.restart, name="RestartThread").start()
+ asyncio.ensure_future(self.restart())
+
break
- self.recv_queue.put(packet)
+ self.recv_queue.put_nowait(packet)
- log.debug("RecvThread stopped")
+ log.debug("Recv Task stopped")
- def _send(self, data: Object, wait_response: bool = True):
+ async def _send(self, data: Object, wait_response: bool = True):
message = self.msg_factory(data)
msg_id = message.msg_id
@@ -401,13 +394,17 @@ def _send(self, data: Object, wait_response: bool = True):
payload = self.pack(message)
try:
- self.connection.send(payload)
+ await self.connection.send(payload)
except OSError as e:
self.results.pop(msg_id, None)
raise e
if wait_response:
- self.results[msg_id].event.wait(self.WAIT_TIMEOUT)
+ try:
+ await asyncio.wait_for(self.results[msg_id].event.wait(), self.WAIT_TIMEOUT)
+ except asyncio.TimeoutError:
+ pass
+
result = self.results.pop(msg_id).value
if result is None:
@@ -422,11 +419,14 @@ def _send(self, data: Object, wait_response: bool = True):
else:
return result
- def send(self, data: Object, retries: int = MAX_RETRIES):
- self.is_connected.wait(self.WAIT_TIMEOUT)
+ async def send(self, data: Object, retries: int = MAX_RETRIES):
+ try:
+ await asyncio.wait_for(self.is_connected.wait(), self.WAIT_TIMEOUT)
+ except asyncio.TimeoutError:
+ pass
try:
- return self._send(data)
+ return await self._send(data)
except (OSError, TimeoutError, InternalServerError) as e:
if retries == 0:
raise e from None
@@ -436,5 +436,404 @@ def send(self, data: Object, retries: int = MAX_RETRIES):
Session.MAX_RETRIES - retries,
datetime.now(), type(data)))
- time.sleep(0.5)
- return self.send(data, retries - 1)
+ await asyncio.sleep(0.5)
+ return await self.send(data, retries - 1)
+
+# class Result:
+# def __init__(self):
+# self.value = None
+# self.event = Event()
+#
+#
+# class Session:
+# VERSION = __version__
+# APP_VERSION = "Pyrogram \U0001f525 {}".format(VERSION)
+#
+# DEVICE_MODEL = "{} {}".format(
+# platform.python_implementation(),
+# platform.python_version()
+# )
+#
+# SYSTEM_VERSION = "{} {}".format(
+# platform.system(),
+# platform.release()
+# )
+#
+# INITIAL_SALT = 0x616e67656c696361
+# NET_WORKERS = 1
+# WAIT_TIMEOUT = 15
+# MAX_RETRIES = 5
+# ACKS_THRESHOLD = 8
+# PING_INTERVAL = 5
+#
+# notice_displayed = False
+#
+# BAD_MSG_DESCRIPTION = {
+# 16: "[16] msg_id too low, the client time has to be synchronized",
+# 17: "[17] msg_id too high, the client time has to be synchronized",
+# 18: "[18] incorrect two lower order msg_id bits, the server expects client message msg_id to be divisible by 4",
+# 19: "[19] container msg_id is the same as msg_id of a previously received message",
+# 20: "[20] message too old, it cannot be verified by the server",
+# 32: "[32] msg_seqno too low",
+# 33: "[33] msg_seqno too high",
+# 34: "[34] an even msg_seqno expected, but odd received",
+# 35: "[35] odd msg_seqno expected, but even received",
+# 48: "[48] incorrect server salt",
+# 64: "[64] invalid container"
+# }
+#
+# def __init__(self,
+# dc_id: int,
+# test_mode: bool,
+# proxy: dict,
+# auth_key: bytes,
+# api_id: int,
+# is_cdn: bool = False,
+# client: pyrogram = None):
+# if not Session.notice_displayed:
+# print("Pyrogram v{}, {}".format(__version__, __copyright__))
+# print("Licensed under the terms of the " + __license__, end="\n\n")
+# Session.notice_displayed = True
+#
+# self.dc_id = dc_id
+# self.test_mode = test_mode
+# self.proxy = proxy
+# self.api_id = api_id
+# self.is_cdn = is_cdn
+# self.client = client
+#
+# self.connection = None
+#
+# self.auth_key = auth_key
+# self.auth_key_id = sha1(auth_key).digest()[-8:]
+#
+# self.session_id = Long(MsgId())
+# self.msg_factory = MsgFactory()
+#
+# self.current_salt = None
+#
+# self.pending_acks = set()
+#
+# self.recv_queue = Queue()
+# self.results = {}
+#
+# self.ping_thread = None
+# self.ping_thread_event = Event()
+#
+# self.next_salt_thread = None
+# self.next_salt_thread_event = Event()
+#
+# self.net_worker_list = []
+#
+# self.is_connected = Event()
+#
+# def start(self):
+# while True:
+# self.connection = Connection(DataCenter(self.dc_id, self.test_mode), self.proxy)
+#
+# try:
+# self.connection.connect()
+#
+# for i in range(self.NET_WORKERS):
+# self.net_worker_list.append(
+# Thread(
+# target=self.net_worker,
+# name="NetWorker#{}".format(i + 1)
+# )
+# )
+#
+# self.net_worker_list[-1].start()
+#
+# Thread(target=self.recv, name="RecvThread").start()
+#
+# self.current_salt = FutureSalt(0, 0, self.INITIAL_SALT)
+# self.current_salt = FutureSalt(0, 0, self._send(functions.Ping(0)).new_server_salt)
+# self.current_salt = self._send(functions.GetFutureSalts(1)).salts[0]
+#
+# self.next_salt_thread = Thread(target=self.next_salt, name="NextSaltThread")
+# self.next_salt_thread.start()
+#
+# if not self.is_cdn:
+# self._send(
+# functions.InvokeWithLayer(
+# layer,
+# functions.InitConnection(
+# self.api_id,
+# self.DEVICE_MODEL,
+# self.SYSTEM_VERSION,
+# self.APP_VERSION,
+# "en", "", "en",
+# functions.help.GetConfig(),
+# )
+# )
+# )
+#
+# self.ping_thread = Thread(target=self.ping, name="PingThread")
+# self.ping_thread.start()
+#
+# log.info("Connection inited: Layer {}".format(layer))
+# except (OSError, TimeoutError, Error):
+# self.stop()
+# except Exception as e:
+# self.stop()
+# raise e
+# else:
+# break
+#
+# self.is_connected.set()
+#
+# log.debug("Session started")
+#
+# def stop(self):
+# self.is_connected.clear()
+#
+# self.ping_thread_event.set()
+# self.next_salt_thread_event.set()
+#
+# if self.ping_thread is not None:
+# self.ping_thread.join()
+#
+# if self.next_salt_thread is not None:
+# self.next_salt_thread.join()
+#
+# self.ping_thread_event.clear()
+# self.next_salt_thread_event.clear()
+#
+# self.connection.close()
+#
+# for i in range(self.NET_WORKERS):
+# self.recv_queue.put(None)
+#
+# for i in self.net_worker_list:
+# i.join()
+#
+# self.net_worker_list.clear()
+#
+# for i in self.results.values():
+# i.event.set()
+#
+# if self.client and callable(self.client.disconnect_handler):
+# try:
+# self.client.disconnect_handler(self.client)
+# except Exception as e:
+# log.error(e, exc_info=True)
+#
+# log.debug("Session stopped")
+#
+# def restart(self):
+# self.stop()
+# self.start()
+#
+# def pack(self, message: Message):
+# data = Long(self.current_salt.salt) + self.session_id + message.write()
+# padding = urandom(-(len(data) + 12) % 16 + 12)
+#
+# # 88 = 88 + 0 (outgoing message)
+# msg_key_large = sha256(self.auth_key[88: 88 + 32] + data + padding).digest()
+# msg_key = msg_key_large[8:24]
+# aes_key, aes_iv = KDF(self.auth_key, msg_key, True)
+#
+# return self.auth_key_id + msg_key + AES.ige256_encrypt(data + padding, aes_key, aes_iv)
+#
+# def unpack(self, b: BytesIO) -> Message:
+# assert b.read(8) == self.auth_key_id, b.getvalue()
+#
+# msg_key = b.read(16)
+# aes_key, aes_iv = KDF(self.auth_key, msg_key, False)
+# data = BytesIO(AES.ige256_decrypt(b.read(), aes_key, aes_iv))
+# data.read(8)
+#
+# # https://core.telegram.org/mtproto/security_guidelines#checking-session-id
+# assert data.read(8) == self.session_id
+#
+# message = Message.read(data)
+#
+# # https://core.telegram.org/mtproto/security_guidelines#checking-sha256-hash-value-of-msg-key
+# # https://core.telegram.org/mtproto/security_guidelines#checking-message-length
+# # 96 = 88 + 8 (incoming message)
+# assert msg_key == sha256(self.auth_key[96:96 + 32] + data.getvalue()).digest()[8:24]
+#
+# # https://core.telegram.org/mtproto/security_guidelines#checking-msg-id
+# # TODO: check for lower msg_ids
+# assert message.msg_id % 2 != 0
+#
+# return message
+#
+# def net_worker(self):
+# name = threading.current_thread().name
+# log.debug("{} started".format(name))
+#
+# while True:
+# packet = self.recv_queue.get()
+#
+# if packet is None:
+# break
+#
+# try:
+# data = self.unpack(BytesIO(packet))
+#
+# messages = (
+# data.body.messages
+# if isinstance(data.body, MsgContainer)
+# else [data]
+# )
+#
+# log.debug(data)
+#
+# for msg in messages:
+# if msg.seq_no % 2 != 0:
+# if msg.msg_id in self.pending_acks:
+# continue
+# else:
+# self.pending_acks.add(msg.msg_id)
+#
+# if isinstance(msg.body, (types.MsgDetailedInfo, types.MsgNewDetailedInfo)):
+# self.pending_acks.add(msg.body.answer_msg_id)
+# continue
+#
+# if isinstance(msg.body, types.NewSessionCreated):
+# continue
+#
+# msg_id = None
+#
+# if isinstance(msg.body, (types.BadMsgNotification, types.BadServerSalt)):
+# msg_id = msg.body.bad_msg_id
+# elif isinstance(msg.body, (core.FutureSalts, types.RpcResult)):
+# msg_id = msg.body.req_msg_id
+# elif isinstance(msg.body, types.Pong):
+# msg_id = msg.body.msg_id
+# else:
+# if self.client is not None:
+# self.client.updates_queue.put(msg.body)
+#
+# if msg_id in self.results:
+# self.results[msg_id].value = getattr(msg.body, "result", msg.body)
+# self.results[msg_id].event.set()
+#
+# if len(self.pending_acks) >= self.ACKS_THRESHOLD:
+# log.info("Send {} acks".format(len(self.pending_acks)))
+#
+# try:
+# self._send(types.MsgsAck(list(self.pending_acks)), False)
+# except (OSError, TimeoutError):
+# pass
+# else:
+# self.pending_acks.clear()
+# except Exception as e:
+# log.error(e, exc_info=True)
+#
+# log.debug("{} stopped".format(name))
+#
+# def ping(self):
+# log.debug("PingThread started")
+#
+# while True:
+# self.ping_thread_event.wait(self.PING_INTERVAL)
+#
+# if self.ping_thread_event.is_set():
+# break
+#
+# try:
+# self._send(functions.PingDelayDisconnect(
+# 0, self.WAIT_TIMEOUT + 10
+# ), False)
+# except (OSError, TimeoutError, Error):
+# pass
+#
+# log.debug("PingThread stopped")
+#
+# def next_salt(self):
+# log.debug("NextSaltThread started")
+#
+# while True:
+# now = datetime.now()
+#
+# # Seconds to wait until middle-overlap, which is
+# # 15 minutes before/after the current/next salt end/start time
+# dt = (self.current_salt.valid_until - now).total_seconds() - 900
+#
+# log.debug("Current salt: {} | Next salt in {:.0f}m {:.0f}s ({})".format(
+# self.current_salt.salt,
+# dt // 60,
+# dt % 60,
+# now + timedelta(seconds=dt)
+# ))
+#
+# self.next_salt_thread_event.wait(dt)
+#
+# if self.next_salt_thread_event.is_set():
+# break
+#
+# try:
+# self.current_salt = self._send(functions.GetFutureSalts(1)).salts[0]
+# except (OSError, TimeoutError, Error):
+# self.connection.close()
+# break
+#
+# log.debug("NextSaltThread stopped")
+#
+# def recv(self):
+# log.debug("RecvThread started")
+#
+# while True:
+# packet = self.connection.recv()
+#
+# if packet is None or len(packet) == 4:
+# if packet:
+# log.warning("Server sent \"{}\"".format(Int.read(BytesIO(packet))))
+#
+# if self.is_connected.is_set():
+# Thread(target=self.restart, name="RestartThread").start()
+# break
+#
+# self.recv_queue.put(packet)
+#
+# log.debug("RecvThread stopped")
+#
+# def _send(self, data: Object, wait_response: bool = True):
+# message = self.msg_factory(data)
+# msg_id = message.msg_id
+#
+# if wait_response:
+# self.results[msg_id] = Result()
+#
+# payload = self.pack(message)
+#
+# try:
+# self.connection.send(payload)
+# except OSError as e:
+# self.results.pop(msg_id, None)
+# raise e
+#
+# if wait_response:
+# self.results[msg_id].event.wait(self.WAIT_TIMEOUT)
+# result = self.results.pop(msg_id).value
+#
+# if result is None:
+# raise TimeoutError
+# elif isinstance(result, types.RpcError):
+# Error.raise_it(result, type(data))
+# elif isinstance(result, types.BadMsgNotification):
+# raise Exception(self.BAD_MSG_DESCRIPTION.get(
+# result.error_code,
+# "Error code {}".format(result.error_code)
+# ))
+# else:
+# return result
+#
+# def send(self, data: Object, retries: int = MAX_RETRIES):
+# self.is_connected.wait(self.WAIT_TIMEOUT)
+#
+# try:
+# return self._send(data)
+# except (OSError, TimeoutError, InternalServerError) as e:
+# if retries == 0:
+# raise e from None
+#
+# (log.warning if retries < 3 else log.info)(
+# "{}: {} Retrying {}".format(
+# Session.MAX_RETRIES - retries,
+# datetime.now(), type(data)))
+#
+# time.sleep(0.5)
+# return self.send(data, retries - 1)
From e333e8dada2d887f582cf3a8c0abb62ed11b41ec Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 13 Jun 2018 20:00:19 +0200
Subject: [PATCH 0008/1185] First step of Client conversion using asyncio
---
pyrogram/client/client.py | 107 +++++++++++++++++++-------------------
1 file changed, 53 insertions(+), 54 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 73f459660e..8eba760a1d 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -34,7 +34,6 @@
from datetime import datetime
from hashlib import sha256, md5
from signal import signal, SIGINT, SIGTERM, SIGABRT
-from threading import Thread
from pyrogram.api import functions, types
from pyrogram.api.core import Object
@@ -169,7 +168,7 @@ def proxy(self, value):
self._proxy["enabled"] = True
self._proxy.update(value)
- def start(self, debug: bool = False):
+ async def start(self, debug: bool = False):
"""Use this method to start the Client after creating it.
Requires no parameters.
@@ -200,7 +199,7 @@ def start(self, debug: bool = False):
client=self
)
- self.session.start()
+ await self.session.start()
self.is_started = True
if self.user_id is None:
@@ -224,66 +223,66 @@ def start(self, debug: bool = False):
self.send(functions.messages.GetPinnedDialogs())
self.get_dialogs_chunk(0)
else:
- self.send(functions.updates.GetState())
-
- for i in range(self.UPDATES_WORKERS):
- self.updates_workers_list.append(
- Thread(
- target=self.updates_worker,
- name="UpdatesWorker#{}".format(i + 1)
- )
- )
-
- self.updates_workers_list[-1].start()
-
- for i in range(self.DOWNLOAD_WORKERS):
- self.download_workers_list.append(
- Thread(
- target=self.download_worker,
- name="DownloadWorker#{}".format(i + 1)
- )
- )
-
- self.download_workers_list[-1].start()
-
- self.dispatcher.start()
+ await self.send(functions.updates.GetState())
+
+ # for i in range(self.UPDATES_WORKERS):
+ # self.updates_workers_list.append(
+ # Thread(
+ # target=self.updates_worker,
+ # name="UpdatesWorker#{}".format(i + 1)
+ # )
+ # )
+ #
+ # self.updates_workers_list[-1].start()
+ #
+ # for i in range(self.DOWNLOAD_WORKERS):
+ # self.download_workers_list.append(
+ # Thread(
+ # target=self.download_worker,
+ # name="DownloadWorker#{}".format(i + 1)
+ # )
+ # )
+ #
+ # self.download_workers_list[-1].start()
+ #
+ # self.dispatcher.start()
mimetypes.init()
- Syncer.add(self)
+ # Syncer.add(self)
- def stop(self):
+ async def stop(self):
"""Use this method to manually stop the Client.
Requires no parameters.
"""
if not self.is_started:
raise ConnectionError("Client is already stopped")
- Syncer.remove(self)
- self.dispatcher.stop()
-
- for _ in range(self.DOWNLOAD_WORKERS):
- self.download_queue.put(None)
-
- for i in self.download_workers_list:
- i.join()
-
- self.download_workers_list.clear()
-
- for _ in range(self.UPDATES_WORKERS):
- self.updates_queue.put(None)
-
- for i in self.updates_workers_list:
- i.join()
-
- self.updates_workers_list.clear()
-
- for i in self.media_sessions.values():
- i.stop()
-
- self.media_sessions.clear()
+ # Syncer.remove(self)
+ # self.dispatcher.stop()
+ #
+ # for _ in range(self.DOWNLOAD_WORKERS):
+ # self.download_queue.put(None)
+ #
+ # for i in self.download_workers_list:
+ # i.join()
+ #
+ # self.download_workers_list.clear()
+ #
+ # for _ in range(self.UPDATES_WORKERS):
+ # self.updates_queue.put(None)
+ #
+ # for i in self.updates_workers_list:
+ # i.join()
+ #
+ # self.updates_workers_list.clear()
+ #
+ # for i in self.media_sessions.values():
+ # i.stop()
+ #
+ # self.media_sessions.clear()
self.is_started = False
- self.session.stop()
+ await self.session.stop()
def add_handler(self, handler, group: int = 0):
"""Use this method to register an update handler.
@@ -812,7 +811,7 @@ def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)):
self.stop()
- def send(self, data: Object):
+ async def send(self, data: Object):
"""Use this method to send Raw Function queries.
This method makes possible to manually call every single Telegram API method in a low-level manner.
@@ -829,7 +828,7 @@ def send(self, data: Object):
if not self.is_started:
raise ConnectionError("Client has not been started")
- r = self.session.send(data)
+ r = await self.session.send(data)
self.fetch_peers(getattr(r, "users", []))
self.fetch_peers(getattr(r, "chats", []))
From f76c654548cc958be89176d4d83ab7f7fc20377d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 13 Jun 2018 20:02:02 +0200
Subject: [PATCH 0009/1185] Add TODO
---
pyrogram/connection/connection.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index b4705fca46..a9aba7c142 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -28,6 +28,7 @@ class Connection:
MAX_RETRIES = 3
MODES = {
+ # TODO: Implement other protocols using asyncio
0: TCPFull,
1: TCPAbridged,
2: TCPIntermediate,
From a9ccbaca19e61669fa4f6b33d8fa65f505132252 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 13 Jun 2018 20:03:54 +0200
Subject: [PATCH 0010/1185] Fix ping request not awaiting
---
pyrogram/session/session.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 173e884610..1cd27c5e6f 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -324,7 +324,7 @@ async def ping(self):
break
try:
- self._send(functions.PingDelayDisconnect(
+ await self._send(functions.PingDelayDisconnect(
0, self.WAIT_TIMEOUT + 10
), False)
except (OSError, TimeoutError, Error):
From 0b03612bc7c985d0af69f806447abf77dd84e9af Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 13 Jun 2018 21:01:28 +0200
Subject: [PATCH 0011/1185] Make restart async
---
pyrogram/session/session.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 1cd27c5e6f..20d3c81aed 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -207,9 +207,9 @@ async def stop(self):
log.debug("Session stopped")
- def restart(self):
- self.stop()
- self.start()
+ async def restart(self):
+ await self.stop()
+ await self.start()
def pack(self, message: Message):
data = Long(self.current_salt.salt) + self.session_id + message.write()
From 75121c9c57cc1ce96a282c00e721b22e68f56a79 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 14 Jun 2018 03:18:38 +0200
Subject: [PATCH 0012/1185] Move MTProto related methods into a separate module
---
pyrogram/crypto/__init__.py | 1 +
pyrogram/crypto/mtproto.py | 65 +++++++++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+)
create mode 100644 pyrogram/crypto/mtproto.py
diff --git a/pyrogram/crypto/__init__.py b/pyrogram/crypto/__init__.py
index 08ed44f008..3112729d64 100644
--- a/pyrogram/crypto/__init__.py
+++ b/pyrogram/crypto/__init__.py
@@ -18,5 +18,6 @@
from .aes import AES
from .kdf import KDF
+from .mtproto import MTProto
from .prime import Prime
from .rsa import RSA
diff --git a/pyrogram/crypto/mtproto.py b/pyrogram/crypto/mtproto.py
new file mode 100644
index 0000000000..d42caf7cf2
--- /dev/null
+++ b/pyrogram/crypto/mtproto.py
@@ -0,0 +1,65 @@
+# 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 hashlib import sha256
+from io import BytesIO
+from os import urandom
+
+from pyrogram.api.core import Message, Long
+from . import AES, KDF
+
+
+class MTProto:
+ INITIAL_SALT = 0x616e67656c696361
+
+ @staticmethod
+ def pack(message: Message, salt: int, session_id: bytes, auth_key: bytes, auth_key_id: bytes) -> bytes:
+ data = Long(salt) + session_id + message.write()
+ padding = urandom(-(len(data) + 12) % 16 + 12)
+
+ # 88 = 88 + 0 (outgoing message)
+ msg_key_large = sha256(auth_key[88: 88 + 32] + data + padding).digest()
+ msg_key = msg_key_large[8:24]
+ aes_key, aes_iv = KDF(auth_key, msg_key, True)
+
+ return auth_key_id + msg_key + AES.ige256_encrypt(data + padding, aes_key, aes_iv)
+
+ @staticmethod
+ def unpack(b: BytesIO, salt: int, session_id: bytes, auth_key: bytes, auth_key_id: bytes) -> Message:
+ assert b.read(8) == auth_key_id, b.getvalue()
+
+ msg_key = b.read(16)
+ aes_key, aes_iv = KDF(auth_key, msg_key, False)
+ data = BytesIO(AES.ige256_decrypt(b.read(), aes_key, aes_iv))
+
+ assert data.read(8) == Long(salt) or Long(salt) == Long(MTProto.INITIAL_SALT)
+
+ # https://core.telegram.org/mtproto/security_guidelines#checking-session-id
+ assert data.read(8) == session_id
+
+ message = Message.read(data)
+
+ # https://core.telegram.org/mtproto/security_guidelines#checking-sha256-hash-value-of-msg-key
+ # https://core.telegram.org/mtproto/security_guidelines#checking-message-length
+ # 96 = 88 + 8 (incoming message)
+ assert msg_key == sha256(auth_key[96:96 + 32] + data.getvalue()).digest()[8:24]
+
+ # https://core.telegram.org/mtproto/security_guidelines#checking-msg-id
+ assert message.msg_id % 2 != 0
+
+ return message
From 11ddf5f99d61dd5b623a6c68714d9d98378d7d8e Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 14 Jun 2018 03:22:52 +0200
Subject: [PATCH 0013/1185] Reorganize Session to make use of the MTProto
module
---
pyrogram/session/session.py | 91 +++++++++++++++++++++----------------
1 file changed, 52 insertions(+), 39 deletions(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 20d3c81aed..7b7942f974 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -19,20 +19,18 @@
import asyncio
import logging
import platform
-import threading
from datetime import datetime, timedelta
-from hashlib import sha1, sha256
+from hashlib import sha1
from io import BytesIO
-from os import urandom
import pyrogram
from pyrogram import __copyright__, __license__, __version__
from pyrogram.api import functions, types, core
from pyrogram.api.all import layer
-from pyrogram.api.core import Message, Object, MsgContainer, Long, FutureSalt, Int
+from pyrogram.api.core import Object, MsgContainer, Long, FutureSalt, Int
from pyrogram.api.errors import Error, InternalServerError
from pyrogram.connection import Connection
-from pyrogram.crypto import AES, KDF
+from pyrogram.crypto import MTProto
from .internals import MsgId, MsgFactory, DataCenter
log = logging.getLogger(__name__)
@@ -58,7 +56,6 @@ class Session:
platform.release()
)
- INITIAL_SALT = 0x616e67656c696361
NET_WORKERS = 1
WAIT_TIMEOUT = 15
MAX_RETRIES = 5
@@ -137,7 +134,7 @@ async def start(self):
self.net_worker_task = asyncio.ensure_future(self.net_worker())
self.recv_task = asyncio.ensure_future(self.recv())
- self.current_salt = FutureSalt(0, 0, self.INITIAL_SALT)
+ self.current_salt = FutureSalt(0, 0, MTProto.INITIAL_SALT)
self.current_salt = FutureSalt(0, 0, (await self._send(functions.Ping(0))).new_server_salt)
self.current_salt = (await self._send(functions.GetFutureSalts(1))).salts[0]
@@ -215,36 +212,40 @@ def pack(self, message: Message):
data = Long(self.current_salt.salt) + self.session_id + message.write()
padding = urandom(-(len(data) + 12) % 16 + 12)
- # 88 = 88 + 0 (outgoing message)
- msg_key_large = sha256(self.auth_key[88: 88 + 32] + data + padding).digest()
- msg_key = msg_key_large[8:24]
- aes_key, aes_iv = KDF(self.auth_key, msg_key, True)
-
- return self.auth_key_id + msg_key + AES.ige256_encrypt(data + padding, aes_key, aes_iv)
-
- def unpack(self, b: BytesIO) -> Message:
- assert b.read(8) == self.auth_key_id, b.getvalue()
-
- msg_key = b.read(16)
- aes_key, aes_iv = KDF(self.auth_key, msg_key, False)
- data = BytesIO(AES.ige256_decrypt(b.read(), aes_key, aes_iv))
- data.read(8)
-
- # https://core.telegram.org/mtproto/security_guidelines#checking-session-id
- assert data.read(8) == self.session_id
-
- message = Message.read(data)
-
- # https://core.telegram.org/mtproto/security_guidelines#checking-sha256-hash-value-of-msg-key
- # https://core.telegram.org/mtproto/security_guidelines#checking-message-length
- # 96 = 88 + 8 (incoming message)
- assert msg_key == sha256(self.auth_key[96:96 + 32] + data.getvalue()).digest()[8:24]
-
- # https://core.telegram.org/mtproto/security_guidelines#checking-msg-id
- # TODO: check for lower msg_ids
- assert message.msg_id % 2 != 0
-
- return message
+ # def pack(self, message: Message):
+ # data = Long(self.current_salt.salt) + self.session_id + message.write()
+ # padding = urandom(-(len(data) + 12) % 16 + 12)
+ #
+ # # 88 = 88 + 0 (outgoing message)
+ # msg_key_large = sha256(self.auth_key[88: 88 + 32] + data + padding).digest()
+ # msg_key = msg_key_large[8:24]
+ # aes_key, aes_iv = KDF(self.auth_key, msg_key, True)
+ #
+ # return self.auth_key_id + msg_key + AES.ige256_encrypt(data + padding, aes_key, aes_iv)
+ #
+ # def unpack(self, b: BytesIO) -> Message:
+ # assert b.read(8) == self.auth_key_id, b.getvalue()
+ #
+ # msg_key = b.read(16)
+ # aes_key, aes_iv = KDF(self.auth_key, msg_key, False)
+ # data = BytesIO(AES.ige256_decrypt(b.read(), aes_key, aes_iv))
+ # data.read(8)
+ #
+ # # https://core.telegram.org/mtproto/security_guidelines#checking-session-id
+ # assert data.read(8) == self.session_id
+ #
+ # message = Message.read(data)
+ #
+ # # https://core.telegram.org/mtproto/security_guidelines#checking-sha256-hash-value-of-msg-key
+ # # https://core.telegram.org/mtproto/security_guidelines#checking-message-length
+ # # 96 = 88 + 8 (incoming message)
+ # assert msg_key == sha256(self.auth_key[96:96 + 32] + data.getvalue()).digest()[8:24]
+ #
+ # # https://core.telegram.org/mtproto/security_guidelines#checking-msg-id
+ # # TODO: check for lower msg_ids
+ # assert message.msg_id % 2 != 0
+ #
+ # return message
async def net_worker(self):
name = threading.current_thread().name
@@ -257,7 +258,13 @@ async def net_worker(self):
break
try:
- data = self.unpack(BytesIO(packet))
+ data = MTProto.unpack(
+ BytesIO(packet),
+ self.current_salt.salt,
+ self.session_id,
+ self.auth_key,
+ self.auth_key_id
+ )
messages = (
data.body.messages
@@ -391,7 +398,13 @@ async def _send(self, data: Object, wait_response: bool = True):
if wait_response:
self.results[msg_id] = Result()
- payload = self.pack(message)
+ payload = MTProto.pack(
+ message,
+ self.current_salt.salt,
+ self.session_id,
+ self.auth_key,
+ self.auth_key_id
+ )
try:
await self.connection.send(payload)
From 2cf930bea08ed71392a84c0332800fd7352ea930 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 14 Jun 2018 03:24:39 +0200
Subject: [PATCH 0014/1185] Remove commented MTProto methods
---
pyrogram/session/session.py | 43 ++-----------------------------------
1 file changed, 2 insertions(+), 41 deletions(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 7b7942f974..ece4b6625c 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -205,47 +205,8 @@ async def stop(self):
log.debug("Session stopped")
async def restart(self):
- await self.stop()
- await self.start()
-
- def pack(self, message: Message):
- data = Long(self.current_salt.salt) + self.session_id + message.write()
- padding = urandom(-(len(data) + 12) % 16 + 12)
-
- # def pack(self, message: Message):
- # data = Long(self.current_salt.salt) + self.session_id + message.write()
- # padding = urandom(-(len(data) + 12) % 16 + 12)
- #
- # # 88 = 88 + 0 (outgoing message)
- # msg_key_large = sha256(self.auth_key[88: 88 + 32] + data + padding).digest()
- # msg_key = msg_key_large[8:24]
- # aes_key, aes_iv = KDF(self.auth_key, msg_key, True)
- #
- # return self.auth_key_id + msg_key + AES.ige256_encrypt(data + padding, aes_key, aes_iv)
- #
- # def unpack(self, b: BytesIO) -> Message:
- # assert b.read(8) == self.auth_key_id, b.getvalue()
- #
- # msg_key = b.read(16)
- # aes_key, aes_iv = KDF(self.auth_key, msg_key, False)
- # data = BytesIO(AES.ige256_decrypt(b.read(), aes_key, aes_iv))
- # data.read(8)
- #
- # # https://core.telegram.org/mtproto/security_guidelines#checking-session-id
- # assert data.read(8) == self.session_id
- #
- # message = Message.read(data)
- #
- # # https://core.telegram.org/mtproto/security_guidelines#checking-sha256-hash-value-of-msg-key
- # # https://core.telegram.org/mtproto/security_guidelines#checking-message-length
- # # 96 = 88 + 8 (incoming message)
- # assert msg_key == sha256(self.auth_key[96:96 + 32] + data.getvalue()).digest()[8:24]
- #
- # # https://core.telegram.org/mtproto/security_guidelines#checking-msg-id
- # # TODO: check for lower msg_ids
- # assert message.msg_id % 2 != 0
- #
- # return message
+ self.stop()
+ self.start()
async def net_worker(self):
name = threading.current_thread().name
From 463ef828c25f5d1647d8071348bebf1a892b44fa Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 14 Jun 2018 03:25:15 +0200
Subject: [PATCH 0015/1185] Use put_nowait instead of put
---
pyrogram/session/session.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index ece4b6625c..ba224f46ae 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -259,7 +259,7 @@ async def net_worker(self):
msg_id = msg.body.msg_id
else:
if self.client is not None:
- self.client.updates_queue.put(msg.body)
+ self.client.updates_queue.put_nowait(msg.body)
if msg_id in self.results:
self.results[msg_id].value = getattr(msg.body, "result", msg.body)
From 68133e8be5cf63b6d90c8c38a3a4ff7954f67674 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 14 Jun 2018 03:26:08 +0200
Subject: [PATCH 0016/1185] Better logs
---
pyrogram/session/session.py | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index ba224f46ae..ba0013cc01 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -209,8 +209,7 @@ async def restart(self):
self.start()
async def net_worker(self):
- name = threading.current_thread().name
- log.debug("{} started".format(name))
+ log.info("NetWorkerTask started")
while True:
packet = await self.recv_queue.get()
@@ -277,10 +276,10 @@ async def net_worker(self):
except Exception as e:
log.error(e, exc_info=True)
- log.debug("{} stopped".format(name))
+ log.info("NetWorkerTask stopped")
async def ping(self):
- log.debug("Ping Task started")
+ log.info("PingTask started")
while True:
try:
@@ -298,10 +297,10 @@ async def ping(self):
except (OSError, TimeoutError, Error):
pass
- log.debug("Ping Task stopped")
+ log.info("PingTask stopped")
async def next_salt(self):
- log.debug("NextSaltThread started")
+ log.info("NextSaltTask started")
while True:
now = datetime.now()
@@ -331,10 +330,10 @@ async def next_salt(self):
self.connection.close()
break
- log.debug("NextSaltThread stopped")
+ log.info("NextSaltTask stopped")
async def recv(self):
- log.debug("Recv Task started")
+ log.info("RecvTask started")
while True:
packet = await self.connection.recv()
@@ -350,7 +349,7 @@ async def recv(self):
self.recv_queue.put_nowait(packet)
- log.debug("Recv Task stopped")
+ log.info("RecvTask stopped")
async def _send(self, data: Object, wait_response: bool = True):
message = self.msg_factory(data)
From 775cbb568f2a1f4faee6abb85c69dbf82148b887 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 14 Jun 2018 03:27:30 +0200
Subject: [PATCH 0017/1185] Small fixes
---
pyrogram/session/session.py | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index ba0013cc01..30d4412d2b 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -286,8 +286,7 @@ async def ping(self):
await asyncio.wait_for(self.ping_task_event.wait(), self.PING_INTERVAL)
except asyncio.TimeoutError:
pass
-
- if self.ping_task_event.is_set():
+ else:
break
try:
@@ -320,8 +319,7 @@ async def next_salt(self):
await asyncio.wait_for(self.next_salt_task_event.wait(), dt)
except asyncio.TimeoutError:
pass
-
- if self.next_salt_task_event.is_set():
+ else:
break
try:
From b1f6131971db314a29930a452683f61cef27c39c Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 14 Jun 2018 13:04:52 +0200
Subject: [PATCH 0018/1185] Remove unused constant
---
pyrogram/session/session.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 30d4412d2b..f16081dfb7 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -56,7 +56,6 @@ class Session:
platform.release()
)
- NET_WORKERS = 1
WAIT_TIMEOUT = 15
MAX_RETRIES = 5
ACKS_THRESHOLD = 8
From eeaf01654ba7aa22bc9ede8f6aca2011db7f8b2c Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 14 Jun 2018 13:05:22 +0200
Subject: [PATCH 0019/1185] Code style
---
pyrogram/session/session.py | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index f16081dfb7..2dfa022194 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -289,9 +289,11 @@ async def ping(self):
break
try:
- await self._send(functions.PingDelayDisconnect(
- 0, self.WAIT_TIMEOUT + 10
- ), False)
+ await self._send(
+ functions.PingDelayDisconnect(
+ 0, self.WAIT_TIMEOUT + 10
+ ), False
+ )
except (OSError, TimeoutError, Error):
pass
From d06e486c8ba13f373773d9f3f9f9af7055d0e705 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 14 Jun 2018 13:30:46 +0200
Subject: [PATCH 0020/1185] Reorganize imports
---
pyrogram/session/session.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 2dfa022194..b5def9a0a1 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -25,9 +25,9 @@
import pyrogram
from pyrogram import __copyright__, __license__, __version__
-from pyrogram.api import functions, types, core
+from pyrogram.api import functions, types
from pyrogram.api.all import layer
-from pyrogram.api.core import Object, MsgContainer, Long, FutureSalt, Int
+from pyrogram.api.core import Object, MsgContainer, Int, Long, FutureSalt, FutureSalts
from pyrogram.api.errors import Error, InternalServerError
from pyrogram.connection import Connection
from pyrogram.crypto import MTProto
@@ -251,7 +251,7 @@ async def net_worker(self):
if isinstance(msg.body, (types.BadMsgNotification, types.BadServerSalt)):
msg_id = msg.body.bad_msg_id
- elif isinstance(msg.body, (core.FutureSalts, types.RpcResult)):
+ elif isinstance(msg.body, (FutureSalts, types.RpcResult)):
msg_id = msg.body.req_msg_id
elif isinstance(msg.body, types.Pong):
msg_id = msg.body.msg_id
From d1d789bf20c31b70980f4ccb95c15f4b9c1e98ff Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 15 Jun 2018 14:30:13 +0200
Subject: [PATCH 0021/1185] Fix restart not awaiting
---
pyrogram/session/session.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index b5def9a0a1..993ad2fa1e 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -204,8 +204,8 @@ async def stop(self):
log.debug("Session stopped")
async def restart(self):
- self.stop()
- self.start()
+ await self.stop()
+ await self.start()
async def net_worker(self):
log.info("NetWorkerTask started")
From 39b66b51d64a0fbfbcbca8244cf0a732f58063d2 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 16 Jun 2018 22:05:54 +0200
Subject: [PATCH 0022/1185] Remove salt assertion
---
pyrogram/crypto/mtproto.py | 5 ++---
pyrogram/session/session.py | 1 -
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/pyrogram/crypto/mtproto.py b/pyrogram/crypto/mtproto.py
index d42caf7cf2..1083912663 100644
--- a/pyrogram/crypto/mtproto.py
+++ b/pyrogram/crypto/mtproto.py
@@ -40,14 +40,13 @@ def pack(message: Message, salt: int, session_id: bytes, auth_key: bytes, auth_k
return auth_key_id + msg_key + AES.ige256_encrypt(data + padding, aes_key, aes_iv)
@staticmethod
- def unpack(b: BytesIO, salt: int, session_id: bytes, auth_key: bytes, auth_key_id: bytes) -> Message:
+ def unpack(b: BytesIO, session_id: bytes, auth_key: bytes, auth_key_id: bytes) -> Message:
assert b.read(8) == auth_key_id, b.getvalue()
msg_key = b.read(16)
aes_key, aes_iv = KDF(auth_key, msg_key, False)
data = BytesIO(AES.ige256_decrypt(b.read(), aes_key, aes_iv))
-
- assert data.read(8) == Long(salt) or Long(salt) == Long(MTProto.INITIAL_SALT)
+ data.read(8)
# https://core.telegram.org/mtproto/security_guidelines#checking-session-id
assert data.read(8) == session_id
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 993ad2fa1e..c3dec02e3b 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -219,7 +219,6 @@ async def net_worker(self):
try:
data = MTProto.unpack(
BytesIO(packet),
- self.current_salt.salt,
self.session_id,
self.auth_key,
self.auth_key_id
From 2b0746a140fcc7b2ea152ae5b5fe377b1f6f44b0 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 17 Jun 2018 18:33:23 +0200
Subject: [PATCH 0023/1185] Add timeout on recv loop
---
pyrogram/session/session.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index c3dec02e3b..6027694720 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -334,7 +334,10 @@ async def recv(self):
log.info("RecvTask started")
while True:
- packet = await self.connection.recv()
+ try:
+ packet = await asyncio.wait_for(self.connection.recv(), self.connection.TIMEOUT)
+ except asyncio.TimeoutError:
+ packet = None
if packet is None or len(packet) == 4:
if packet:
From 6da15b266d894e02a54ece61d27bedb54c88c228 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 17 Jun 2018 18:34:10 +0200
Subject: [PATCH 0024/1185] Await tasks before stopping the session
---
pyrogram/session/session.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 6027694720..f06264c081 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -186,11 +186,11 @@ async def stop(self):
self.connection.close()
- await self.recv_task
+ if self.recv_task:
+ await self.recv_task
- self.recv_queue.put_nowait(None)
-
- await self.net_worker_task
+ if self.net_worker_task:
+ await self.net_worker_task
for i in self.results.values():
i.event.set()
From f983baf5cdc98d9baedd168769e7e19c99d230d1 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 17 Jun 2018 18:34:37 +0200
Subject: [PATCH 0025/1185] Add some more logs
---
pyrogram/session/session.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index f06264c081..3a1fefd861 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -167,7 +167,7 @@ async def start(self):
self.is_connected.set()
- log.debug("Session started")
+ log.info("Session started")
async def stop(self):
self.is_connected.clear()
@@ -201,7 +201,7 @@ async def stop(self):
except Exception as e:
log.error(e, exc_info=True)
- log.debug("Session stopped")
+ log.info("Session stopped")
async def restart(self):
await self.stop()
From 57f917e6df19004550fa92cf3aefe6a2c4257f0b Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 17 Jun 2018 18:35:49 +0200
Subject: [PATCH 0026/1185] Don't print out the current salt
---
pyrogram/session/session.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 3a1fefd861..d58eae379f 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -308,10 +308,8 @@ async def next_salt(self):
# 15 minutes before/after the current/next salt end/start time
dt = (self.current_salt.valid_until - now).total_seconds() - 900
- log.debug("Current salt: {} | Next salt in {:.0f}m {:.0f}s ({})".format(
- self.current_salt.salt,
- dt // 60,
- dt % 60,
+ log.info("Next salt in {:.0f}m {:.0f}s ({})".format(
+ dt // 60, dt % 60,
now + timedelta(seconds=dt)
))
@@ -340,6 +338,8 @@ async def recv(self):
packet = None
if packet is None or len(packet) == 4:
+ self.recv_queue.put_nowait(None)
+
if packet:
log.warning("Server sent \"{}\"".format(Int.read(BytesIO(packet))))
From 0a6583a43cae82e7a7584b1352fd4a61b1d6a225 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 17 Jun 2018 18:41:07 +0200
Subject: [PATCH 0027/1185] Turn the Dispatcher async
---
pyrogram/client/dispatcher/dispatcher.py | 66 +++++++++++-------------
1 file changed, 29 insertions(+), 37 deletions(-)
diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py
index 51be2ebb0e..8efb6584d9 100644
--- a/pyrogram/client/dispatcher/dispatcher.py
+++ b/pyrogram/client/dispatcher/dispatcher.py
@@ -16,11 +16,9 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
import logging
-import threading
from collections import OrderedDict
-from queue import Queue
-from threading import Thread
import pyrogram
from pyrogram.api import types
@@ -46,29 +44,17 @@ class Dispatcher:
def __init__(self, client, workers):
self.client = client
self.workers = workers
- self.workers_list = []
- self.updates = Queue()
- self.groups = OrderedDict()
-
- def start(self):
- for i in range(self.workers):
- self.workers_list.append(
- Thread(
- target=self.update_worker,
- name="UpdateWorker#{}".format(i + 1)
- )
- )
-
- self.workers_list[-1].start()
- def stop(self):
- for _ in range(self.workers):
- self.updates.put(None)
+ self.update_worker_task = None
+ self.updates = asyncio.Queue()
+ self.groups = OrderedDict()
- for i in self.workers_list:
- i.join()
+ async def start(self):
+ self.update_worker_task = asyncio.ensure_future(self.update_worker())
- self.workers_list.clear()
+ async def stop(self):
+ self.updates.put_nowait(None)
+ await self.update_worker_task
def add_handler(self, handler, group: int):
if group not in self.groups:
@@ -83,7 +69,9 @@ def remove_handler(self, handler, group: int):
"Handler was not removed.".format(group))
self.groups[group].remove(handler)
- def dispatch(self, update, users: dict = None, chats: dict = None, is_raw: bool = False):
+ async def dispatch(self, update, users: dict = None, chats: dict = None, is_raw: bool = False):
+ tasks = []
+
for group in self.groups.values():
for handler in group:
if is_raw:
@@ -112,15 +100,17 @@ def dispatch(self, update, users: dict = None, chats: dict = None, is_raw: bool
else:
continue
- handler.callback(*args)
+ tasks.append(handler.callback(*args))
break
- def update_worker(self):
- name = threading.current_thread().name
- log.debug("{} started".format(name))
+ await asyncio.gather(*tasks)
+
+ async def update_worker(self):
+ log.info("UpdateWorkerTask started")
while True:
- update = self.updates.get()
+ tasks = []
+ update = await self.updates.get()
if update is None:
break
@@ -130,7 +120,7 @@ def update_worker(self):
chats = {i.id: i for i in update[2]}
update = update[0]
- self.dispatch(update, users=users, chats=chats, is_raw=True)
+ tasks.append(self.dispatch(update, users=users, chats=chats, is_raw=True))
if isinstance(update, Dispatcher.MESSAGE_UPDATES):
if isinstance(update.message, types.MessageEmpty):
@@ -145,7 +135,7 @@ def update_worker(self):
is_edited_message = isinstance(update, Dispatcher.EDIT_MESSAGE_UPDATES)
- self.dispatch(
+ tasks.append(self.dispatch(
pyrogram.Update(
message=((message if message.chat.type != "channel"
else None) if not is_edited_message
@@ -160,26 +150,28 @@ def update_worker(self):
else None) if is_edited_message
else None)
)
- )
+ ))
elif isinstance(update, types.UpdateBotCallbackQuery):
- self.dispatch(
+ tasks.append(self.dispatch(
pyrogram.Update(
callback_query=utils.parse_callback_query(
self.client, update, users
)
)
- )
+ ))
elif isinstance(update, types.UpdateInlineBotCallbackQuery):
- self.dispatch(
+ tasks.append(self.dispatch(
pyrogram.Update(
callback_query=utils.parse_inline_callback_query(
update, users
)
)
- )
+ ))
else:
continue
+
+ await asyncio.gather(*tasks)
except Exception as e:
log.error(e, exc_info=True)
- log.debug("{} stopped".format(name))
+ log.info("UpdateWorkerTask stopped")
From 52354b93d06e6085a79ccfe5ac9f57fded066c50 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 17 Jun 2018 18:44:45 +0200
Subject: [PATCH 0028/1185] Add timeout when connecting
---
pyrogram/connection/connection.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index a9aba7c142..4a25b72e17 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -25,6 +25,7 @@
class Connection:
+ TIMEOUT = 10
MAX_RETRIES = 3
MODES = {
@@ -49,8 +50,8 @@ async def connect(self):
try:
log.info("Connecting...")
- await self.protocol.connect(self.address)
- except OSError:
+ await asyncio.wait_for(self.protocol.connect(self.address), Connection.TIMEOUT)
+ except (OSError, asyncio.TimeoutError):
self.protocol.close()
await asyncio.sleep(1)
else:
From 5d58ff2d941686e8da845b520e805783f572b867 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 17 Jun 2018 18:45:08 +0200
Subject: [PATCH 0029/1185] Raise OSError in case "send" fails
---
pyrogram/connection/connection.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index 4a25b72e17..746dbf06b5 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -64,7 +64,10 @@ def close(self):
log.info("Disconnected")
async def send(self, data: bytes):
- await self.protocol.send(data)
+ try:
+ await self.protocol.send(data)
+ except Exception:
+ raise OSError
async def recv(self) -> bytes or None:
return await self.protocol.recv()
From b249062d2539c29a5a8fe8f5c3ec0a20243799b9 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 17 Jun 2018 19:17:56 +0200
Subject: [PATCH 0030/1185] Add a warning in case the connection failed
---
pyrogram/connection/connection.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index 746dbf06b5..c7210ad6a9 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -57,6 +57,7 @@ async def connect(self):
else:
break
else:
+ log.warning("Connection failed! Trying again...")
raise TimeoutError
def close(self):
From 1bc599e26ca7d905c6b6d1fd57881f3a991da02a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 17 Jun 2018 19:20:22 +0200
Subject: [PATCH 0031/1185] Delegate timeout to TCP
---
pyrogram/connection/connection.py | 5 ++---
pyrogram/connection/transport/tcp/tcp.py | 10 ++++++++--
pyrogram/session/session.py | 5 +----
3 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index c7210ad6a9..3e27638b9b 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -25,7 +25,6 @@
class Connection:
- TIMEOUT = 10
MAX_RETRIES = 3
MODES = {
@@ -50,8 +49,8 @@ async def connect(self):
try:
log.info("Connecting...")
- await asyncio.wait_for(self.protocol.connect(self.address), Connection.TIMEOUT)
- except (OSError, asyncio.TimeoutError):
+ await self.protocol.connect(self.address)
+ except OSError:
self.protocol.close()
await asyncio.sleep(1)
else:
diff --git a/pyrogram/connection/transport/tcp/tcp.py b/pyrogram/connection/transport/tcp/tcp.py
index f006cadd28..f541153eaa 100644
--- a/pyrogram/connection/transport/tcp/tcp.py
+++ b/pyrogram/connection/transport/tcp/tcp.py
@@ -34,6 +34,8 @@
class TCP:
+ TIMEOUT = 10
+
def __init__(self, proxy: dict):
self.proxy = proxy
@@ -41,6 +43,7 @@ def __init__(self, proxy: dict):
self.reader = None # type: asyncio.StreamReader
self.writer = None # type: asyncio.StreamWriter
+ self.socket.settimeout(TCP.TIMEOUT)
self.proxy_enabled = proxy.get("enabled", False)
if proxy and self.proxy_enabled:
@@ -81,8 +84,11 @@ async def recv(self, length: int = 0):
while len(data) < length:
try:
- chunk = await self.reader.read(length - len(data))
- except OSError:
+ chunk = await asyncio.wait_for(
+ self.reader.read(length - len(data)),
+ TCP.TIMEOUT
+ )
+ except (OSError, asyncio.TimeoutError):
return None
else:
if chunk:
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index d58eae379f..6479dfdd07 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -332,10 +332,7 @@ async def recv(self):
log.info("RecvTask started")
while True:
- try:
- packet = await asyncio.wait_for(self.connection.recv(), self.connection.TIMEOUT)
- except asyncio.TimeoutError:
- packet = None
+ packet = await self.connection.recv()
if packet is None or len(packet) == 4:
self.recv_queue.put_nowait(None)
From 9a5ce0fe2d26b38a384dec90178d992a1b8e6e15 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 18 Jun 2018 13:06:07 +0200
Subject: [PATCH 0032/1185] Clean up dispatcher and fix workers not being
stopped correctly
---
pyrogram/client/dispatcher/dispatcher.py | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py
index 8efb6584d9..a77418c17a 100644
--- a/pyrogram/client/dispatcher/dispatcher.py
+++ b/pyrogram/client/dispatcher/dispatcher.py
@@ -45,16 +45,28 @@ def __init__(self, client, workers):
self.client = client
self.workers = workers
- self.update_worker_task = None
+ self.update_worker_tasks = []
self.updates = asyncio.Queue()
self.groups = OrderedDict()
async def start(self):
- self.update_worker_task = asyncio.ensure_future(self.update_worker())
+ for i in range(self.workers):
+ self.update_worker_tasks.append(
+ asyncio.ensure_future(self.update_worker())
+ )
+
+ log.info("Started {} UpdateWorkerTasks".format(self.workers))
async def stop(self):
- self.updates.put_nowait(None)
- await self.update_worker_task
+ for i in range(self.workers):
+ self.updates.put_nowait(None)
+
+ for i in self.update_worker_tasks:
+ await i
+
+ self.update_worker_tasks.clear()
+
+ log.info("Stopped {} UpdateWorkerTasks".format(self.workers))
def add_handler(self, handler, group: int):
if group not in self.groups:
@@ -106,8 +118,6 @@ async def dispatch(self, update, users: dict = None, chats: dict = None, is_raw:
await asyncio.gather(*tasks)
async def update_worker(self):
- log.info("UpdateWorkerTask started")
-
while True:
tasks = []
update = await self.updates.get()
@@ -173,5 +183,3 @@ async def update_worker(self):
await asyncio.gather(*tasks)
except Exception as e:
log.error(e, exc_info=True)
-
- log.info("UpdateWorkerTask stopped")
From 8049c9129bfdf518d8716d846ec9f4faffb01953 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 18 Jun 2018 13:07:02 +0200
Subject: [PATCH 0033/1185] Make Auth asynchronous
---
pyrogram/session/auth.py | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/pyrogram/session/auth.py b/pyrogram/session/auth.py
index 809561875e..a41991fbae 100644
--- a/pyrogram/session/auth.py
+++ b/pyrogram/session/auth.py
@@ -67,14 +67,14 @@ def unpack(b: BytesIO):
b.seek(20) # Skip auth_key_id (8), message_id (8) and message_length (4)
return Object.read(b)
- def send(self, data: Object):
+ async def send(self, data: Object):
data = self.pack(data)
- self.connection.send(data)
- response = BytesIO(self.connection.recv())
+ await self.connection.send(data)
+ response = BytesIO(await self.connection.recv())
return self.unpack(response)
- def create(self):
+ async def create(self):
"""
https://core.telegram.org/mtproto/auth_key
https://core.telegram.org/mtproto/samples-auth_key
@@ -89,12 +89,12 @@ def create(self):
try:
log.info("Start creating a new auth key on DC{}".format(self.dc_id))
- self.connection.connect()
+ await self.connection.connect()
# Step 1; Step 2
nonce = int.from_bytes(urandom(16), "little", signed=True)
log.debug("Send req_pq: {}".format(nonce))
- res_pq = self.send(functions.ReqPqMulti(nonce))
+ res_pq = await self.send(functions.ReqPqMulti(nonce))
log.debug("Got ResPq: {}".format(res_pq.server_nonce))
log.debug("Server public key fingerprints: {}".format(res_pq.server_public_key_fingerprints))
@@ -138,7 +138,7 @@ def create(self):
# Step 5. TODO: Handle "server_DH_params_fail". Code assumes response is ok
log.debug("Send req_DH_params")
- server_dh_params = self.send(
+ server_dh_params = await self.send(
functions.ReqDHParams(
nonce,
server_nonce,
@@ -198,7 +198,7 @@ def create(self):
encrypted_data = AES.ige256_encrypt(data_with_hash, tmp_aes_key, tmp_aes_iv)
log.debug("Send set_client_DH_params")
- set_client_dh_params_answer = self.send(
+ set_client_dh_params_answer = await self.send(
functions.SetClientDHParams(
nonce,
server_nonce,
From e3a667a8fead262acd57a1265ed3564829ebc3d9 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 18 Jun 2018 21:11:28 +0200
Subject: [PATCH 0034/1185] Make Syncer asynchronous (lol)
---
pyrogram/client/ext/syncer.py | 34 ++++++++++++++++------------------
1 file changed, 16 insertions(+), 18 deletions(-)
diff --git a/pyrogram/client/ext/syncer.py b/pyrogram/client/ext/syncer.py
index 125c5ce051..66d28da1a8 100644
--- a/pyrogram/client/ext/syncer.py
+++ b/pyrogram/client/ext/syncer.py
@@ -16,13 +16,13 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
import base64
import json
import logging
import os
import shutil
import time
-from threading import Thread, Event, Lock
from . import utils
@@ -33,13 +33,12 @@ class Syncer:
INTERVAL = 20
clients = {}
- thread = None
- event = Event()
- lock = Lock()
+ event = asyncio.Event()
+ lock = asyncio.Lock()
@classmethod
- def add(cls, client):
- with cls.lock:
+ async def add(cls, client):
+ with await cls.lock:
cls.sync(client)
cls.clients[id(client)] = client
@@ -48,8 +47,8 @@ def add(cls, client):
cls.start()
@classmethod
- def remove(cls, client):
- with cls.lock:
+ async def remove(cls, client):
+ with await cls.lock:
cls.sync(client)
del cls.clients[id(client)]
@@ -60,25 +59,24 @@ def remove(cls, client):
@classmethod
def start(cls):
cls.event.clear()
- cls.thread = Thread(target=cls.worker, name=cls.__name__)
- cls.thread.start()
+ asyncio.ensure_future(cls.worker())
@classmethod
def stop(cls):
cls.event.set()
@classmethod
- def worker(cls):
+ async def worker(cls):
while True:
- cls.event.wait(cls.INTERVAL)
-
- if cls.event.is_set():
+ try:
+ await asyncio.wait_for(cls.event.wait(), cls.INTERVAL)
+ except asyncio.TimeoutError:
+ with await cls.lock:
+ for client in cls.clients.values():
+ cls.sync(client)
+ else:
break
- with cls.lock:
- for client in cls.clients.values():
- cls.sync(client)
-
@classmethod
def sync(cls, client):
temporary = os.path.join(client.workdir, "{}.sync".format(client.session_name))
From 09dd7155562dc24841b78fdf443c1d35f99fabba Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 18 Jun 2018 21:12:04 +0200
Subject: [PATCH 0035/1185] Small tweaks
---
pyrogram/client/dispatcher/dispatcher.py | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py
index a77418c17a..79480dfb52 100644
--- a/pyrogram/client/dispatcher/dispatcher.py
+++ b/pyrogram/client/dispatcher/dispatcher.py
@@ -119,7 +119,6 @@ async def dispatch(self, update, users: dict = None, chats: dict = None, is_raw:
async def update_worker(self):
while True:
- tasks = []
update = await self.updates.get()
if update is None:
@@ -130,13 +129,13 @@ async def update_worker(self):
chats = {i.id: i for i in update[2]}
update = update[0]
- tasks.append(self.dispatch(update, users=users, chats=chats, is_raw=True))
+ await self.dispatch(update, users=users, chats=chats, is_raw=True)
if isinstance(update, Dispatcher.MESSAGE_UPDATES):
if isinstance(update.message, types.MessageEmpty):
continue
- message = utils.parse_messages(
+ message = await utils.parse_messages(
self.client,
update.message,
users,
@@ -145,7 +144,7 @@ async def update_worker(self):
is_edited_message = isinstance(update, Dispatcher.EDIT_MESSAGE_UPDATES)
- tasks.append(self.dispatch(
+ await self.dispatch(
pyrogram.Update(
message=((message if message.chat.type != "channel"
else None) if not is_edited_message
@@ -160,26 +159,24 @@ async def update_worker(self):
else None) if is_edited_message
else None)
)
- ))
+ )
elif isinstance(update, types.UpdateBotCallbackQuery):
- tasks.append(self.dispatch(
+ await self.dispatch(
pyrogram.Update(
- callback_query=utils.parse_callback_query(
+ callback_query=await utils.parse_callback_query(
self.client, update, users
)
)
- ))
+ )
elif isinstance(update, types.UpdateInlineBotCallbackQuery):
- tasks.append(self.dispatch(
+ await self.dispatch(
pyrogram.Update(
- callback_query=utils.parse_inline_callback_query(
+ callback_query=await utils.parse_inline_callback_query(
update, users
)
)
- ))
+ )
else:
continue
-
- await asyncio.gather(*tasks)
except Exception as e:
log.error(e, exc_info=True)
From 26e828b9566ed3ba13b47705c0df488514ca91e8 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 18 Jun 2018 21:21:26 +0200
Subject: [PATCH 0036/1185] Make BaseClient asynchronous and default
DOWNLOAD_WORKERS to 4
---
pyrogram/client/ext/base_client.py | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index 9c0fb26b9e..04a6ac12bc 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -16,9 +16,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
import re
-from queue import Queue
-from threading import Lock
from ..style import Markdown, HTML
from ...api.core import Object
@@ -30,7 +29,7 @@ class BaseClient:
BOT_TOKEN_RE = re.compile(r"^\d+:[\w-]+$")
DIALOGS_AT_ONCE = 100
UPDATES_WORKERS = 1
- DOWNLOAD_WORKERS = 1
+ DOWNLOAD_WORKERS = 4
OFFLINE_SLEEP = 300
MEDIA_TYPE_ID = {
@@ -65,15 +64,15 @@ def __init__(self):
self.session = None
self.media_sessions = {}
- self.media_sessions_lock = Lock()
+ self.media_sessions_lock = asyncio.Lock()
self.is_started = None
self.is_idle = None
- self.updates_queue = Queue()
- self.updates_workers_list = []
- self.download_queue = Queue()
- self.download_workers_list = []
+ self.updates_queue = asyncio.Queue()
+ self.updates_worker_task = None
+ self.download_queue = asyncio.Queue()
+ self.download_worker_tasks = []
self.disconnect_handler = None
From 21af0f3e821c244ca779040795fb22f75f466962 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 18 Jun 2018 21:22:33 +0200
Subject: [PATCH 0037/1185] More async chore
---
pyrogram/client/ext/utils.py | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index d7a09ee149..bb4efb4c5e 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -249,7 +249,7 @@ def encode(s: bytes) -> str:
# TODO: Reorganize code, maybe split parts as well
-def parse_messages(
+async def parse_messages(
client,
messages: list or types.Message or types.MessageService or types.MessageEmpty,
users: dict,
@@ -484,9 +484,9 @@ def parse_messages(
if isinstance(sticker_attribute.stickerset, types.InputStickerSetID):
try:
- set_name = client.send(
+ set_name = (await client.send(
functions.messages.GetStickerSet(sticker_attribute.stickerset)
- ).set.short_name
+ )).set.short_name
except StickersetInvalid:
set_name = None
else:
@@ -591,7 +591,7 @@ def parse_messages(
if message.reply_to_msg_id and replies:
while True:
try:
- m.reply_to_message = client.get_messages(
+ m.reply_to_message = await client.get_messages(
m.chat.id, message.reply_to_msg_id,
replies=replies - 1
)
@@ -693,7 +693,7 @@ def parse_messages(
if isinstance(action, types.MessageActionPinMessage):
while True:
try:
- m.pinned_message = client.get_messages(
+ m.pinned_message = await client.get_messages(
m.chat.id, message.reply_to_msg_id,
replies=0
)
@@ -790,7 +790,7 @@ def parse_photos(photos):
)
-def parse_callback_query(client, callback_query, users):
+async def parse_callback_query(client, callback_query, users):
peer = callback_query.peer
if isinstance(peer, types.PeerUser):
@@ -803,14 +803,14 @@ def parse_callback_query(client, callback_query, users):
return pyrogram_types.CallbackQuery(
id=str(callback_query.query_id),
from_user=parse_user(users[callback_query.user_id]),
- message=client.get_messages(peer_id, callback_query.msg_id),
+ message=await client.get_messages(peer_id, callback_query.msg_id),
chat_instance=str(callback_query.chat_instance),
data=callback_query.data.decode(),
game_short_name=callback_query.game_short_name
)
-def parse_inline_callback_query(callback_query, users):
+async def parse_inline_callback_query(callback_query, users):
return pyrogram_types.CallbackQuery(
id=str(callback_query.query_id),
from_user=parse_user(users[callback_query.user_id]),
@@ -828,7 +828,7 @@ def parse_inline_callback_query(callback_query, users):
)
-def parse_chat_full(
+async def parse_chat_full(
client,
chat_full: types.messages.ChatFull or types.UserFull
) -> pyrogram_types.Chat:
@@ -853,7 +853,7 @@ def parse_chat_full(
chat.sticker_set_name = full_chat.stickerset
if full_chat.pinned_msg_id:
- chat.pinned_message = client.get_messages(
+ chat.pinned_message = await client.get_messages(
int("-100" + str(full_chat.id)),
full_chat.pinned_msg_id
)
From 4d72f84991e27f0678e1ef428b2568f980abd36d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 18 Jun 2018 21:30:13 +0200
Subject: [PATCH 0038/1185] Even more async chore
---
.../callback_query/answer_callback_query.py | 14 +++----
.../bots/inline/get_inline_bot_results.py | 16 ++++----
.../bots/inline/send_inline_bot_result.py | 16 ++++----
.../methods/chats/export_chat_invite_link.py | 8 ++--
pyrogram/client/methods/chats/get_chat.py | 12 +++---
pyrogram/client/methods/chats/join_chat.py | 8 ++--
.../client/methods/chats/kick_chat_member.py | 16 ++++----
pyrogram/client/methods/chats/leave_chat.py | 12 +++---
.../methods/chats/promote_chat_member.py | 28 ++++++-------
.../methods/chats/restrict_chat_member.py | 22 +++++-----
.../client/methods/chats/unban_chat_member.py | 12 +++---
.../client/methods/contacts/add_contacts.py | 4 +-
.../methods/contacts/delete_contacts.py | 6 +--
.../client/methods/contacts/get_contacts.py | 8 ++--
pyrogram/client/methods/download_media.py | 20 +++++-----
.../messages/action/send_chat_action.py | 12 +++---
.../methods/messages/forward_messages.py | 18 ++++-----
.../client/methods/messages/get_history.py | 20 +++++-----
.../client/methods/messages/get_messages.py | 14 +++----
.../methods/messages/media/send_audio.py | 36 ++++++++---------
.../methods/messages/media/send_contact.py | 22 +++++-----
.../methods/messages/media/send_document.py | 30 +++++++-------
.../client/methods/messages/media/send_gif.py | 14 +++----
.../methods/messages/media/send_location.py | 20 +++++-----
.../messages/media/send_media_group.py | 26 ++++++------
.../methods/messages/media/send_photo.py | 32 +++++++--------
.../methods/messages/media/send_sticker.py | 26 ++++++------
.../methods/messages/media/send_venue.py | 26 ++++++------
.../methods/messages/media/send_video.py | 40 +++++++++----------
.../methods/messages/media/send_video_note.py | 30 +++++++-------
.../methods/messages/media/send_voice.py | 32 +++++++--------
.../client/methods/messages/send_message.py | 22 +++++-----
.../messages/update/delete_messages.py | 14 +++----
.../messages/update/edit_message_caption.py | 18 ++++-----
.../update/edit_message_reply_markup.py | 14 +++----
.../messages/update/edit_message_text.py | 20 +++++-----
36 files changed, 344 insertions(+), 344 deletions(-)
diff --git a/pyrogram/client/methods/bots/callback_query/answer_callback_query.py b/pyrogram/client/methods/bots/callback_query/answer_callback_query.py
index a4baa166cc..be6fbc0cea 100644
--- a/pyrogram/client/methods/bots/callback_query/answer_callback_query.py
+++ b/pyrogram/client/methods/bots/callback_query/answer_callback_query.py
@@ -21,12 +21,12 @@
class AnswerCallbackQuery(BaseClient):
- def answer_callback_query(self,
- callback_query_id: str,
- text: str = None,
- show_alert: bool = None,
- url: str = None,
- cache_time: int = 0):
+ async def answer_callback_query(self,
+ callback_query_id: str,
+ text: str = None,
+ show_alert: bool = None,
+ url: str = None,
+ cache_time: int = 0):
"""Use this method to send answers to callback queries sent from inline keyboards.
The answer will be displayed to the user as a notification at the top of the chat screen or as an alert.
@@ -51,7 +51,7 @@ def answer_callback_query(self,
The maximum amount of time in seconds that the result of the callback query may be cached client-side.
Telegram apps will support caching starting in version 3.14. Defaults to 0.
"""
- return self.send(
+ return await self.send(
functions.messages.SetBotCallbackAnswer(
query_id=int(callback_query_id),
cache_time=cache_time,
diff --git a/pyrogram/client/methods/bots/inline/get_inline_bot_results.py b/pyrogram/client/methods/bots/inline/get_inline_bot_results.py
index 52c3b0051c..86ab18b5db 100644
--- a/pyrogram/client/methods/bots/inline/get_inline_bot_results.py
+++ b/pyrogram/client/methods/bots/inline/get_inline_bot_results.py
@@ -22,12 +22,12 @@
class GetInlineBotResults(BaseClient):
- def get_inline_bot_results(self,
- bot: int or str,
- query: str,
- offset: str = "",
- latitude: float = None,
- longitude: float = None):
+ async def get_inline_bot_results(self,
+ bot: int or str,
+ query: str,
+ offset: str = "",
+ latitude: float = None,
+ longitude: float = None):
"""Use this method to get bot results via inline queries.
You can then send a result using :obj:`send_inline_bot_result `
@@ -60,9 +60,9 @@ def get_inline_bot_results(self,
# TODO: Don't return the raw type
try:
- return self.send(
+ return await self.send(
functions.messages.GetInlineBotResults(
- bot=self.resolve_peer(bot),
+ bot=await self.resolve_peer(bot),
peer=types.InputPeerSelf(),
query=query,
offset=offset,
diff --git a/pyrogram/client/methods/bots/inline/send_inline_bot_result.py b/pyrogram/client/methods/bots/inline/send_inline_bot_result.py
index 947433cddb..3ce58cd813 100644
--- a/pyrogram/client/methods/bots/inline/send_inline_bot_result.py
+++ b/pyrogram/client/methods/bots/inline/send_inline_bot_result.py
@@ -21,12 +21,12 @@
class SendInlineBotResult(BaseClient):
- def send_inline_bot_result(self,
- chat_id: int or str,
- query_id: int,
- result_id: str,
- disable_notification: bool = None,
- reply_to_message_id: int = None):
+ async def send_inline_bot_result(self,
+ chat_id: int or str,
+ query_id: int,
+ result_id: str,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None):
"""Use this method to send an inline bot result.
Bot results can be retrieved using :obj:`get_inline_bot_results `
@@ -56,9 +56,9 @@ def send_inline_bot_result(self,
Raises:
:class:`Error `
"""
- return self.send(
+ return await self.send(
functions.messages.SendInlineBotResult(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
query_id=query_id,
id=result_id,
random_id=self.rnd_id(),
diff --git a/pyrogram/client/methods/chats/export_chat_invite_link.py b/pyrogram/client/methods/chats/export_chat_invite_link.py
index dc289af326..26febf1d2d 100644
--- a/pyrogram/client/methods/chats/export_chat_invite_link.py
+++ b/pyrogram/client/methods/chats/export_chat_invite_link.py
@@ -21,7 +21,7 @@
class ExportChatInviteLink(BaseClient):
- def export_chat_invite_link(self, chat_id: int or str):
+ async def export_chat_invite_link(self, chat_id: int or str):
"""Use this method to generate a new invite link for a chat; any previously generated link is revoked.
You must be an administrator in the chat for this to work and have the appropriate admin rights.
@@ -37,16 +37,16 @@ def export_chat_invite_link(self, chat_id: int or str):
Raises:
:class:`Error `
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChat):
- return self.send(
+ return await self.send(
functions.messages.ExportChatInvite(
chat_id=peer.chat_id
)
).link
elif isinstance(peer, types.InputPeerChannel):
- return self.send(
+ return await self.send(
functions.channels.ExportInvite(
channel=peer
)
diff --git a/pyrogram/client/methods/chats/get_chat.py b/pyrogram/client/methods/chats/get_chat.py
index 194e6171d6..9b5a5fe8fc 100644
--- a/pyrogram/client/methods/chats/get_chat.py
+++ b/pyrogram/client/methods/chats/get_chat.py
@@ -21,7 +21,7 @@
class GetChat(BaseClient):
- def get_chat(self, chat_id: int or str):
+ async def get_chat(self, chat_id: int or str):
"""Use this method to get up to date information about the chat (current name of the user for
one-on-one conversations, current username of a user, group or channel, etc.)
@@ -31,13 +31,13 @@ def get_chat(self, chat_id: int or str):
Raises:
:class:`Error `
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChannel):
- r = self.send(functions.channels.GetFullChannel(peer))
+ r = await self.send(functions.channels.GetFullChannel(peer))
elif isinstance(peer, (types.InputPeerUser, types.InputPeerSelf)):
- r = self.send(functions.users.GetFullUser(peer))
+ r = await self.send(functions.users.GetFullUser(peer))
else:
- r = self.send(functions.messages.GetFullChat(peer.chat_id))
+ r = await self.send(functions.messages.GetFullChat(peer.chat_id))
- return utils.parse_chat_full(self, r)
+ return await utils.parse_chat_full(self, r)
diff --git a/pyrogram/client/methods/chats/join_chat.py b/pyrogram/client/methods/chats/join_chat.py
index b7b8d42c67..75f8033fa1 100644
--- a/pyrogram/client/methods/chats/join_chat.py
+++ b/pyrogram/client/methods/chats/join_chat.py
@@ -21,7 +21,7 @@
class JoinChat(BaseClient):
- def join_chat(self, chat_id: str):
+ async def join_chat(self, chat_id: str):
"""Use this method to join a group chat or channel.
Args:
@@ -35,13 +35,13 @@ def join_chat(self, chat_id: str):
match = self.INVITE_LINK_RE.match(chat_id)
if match:
- return self.send(
+ return await self.send(
functions.messages.ImportChatInvite(
hash=match.group(1)
)
)
else:
- resolved_peer = self.send(
+ resolved_peer = await self.send(
functions.contacts.ResolveUsername(
username=chat_id.lower().strip("@")
)
@@ -52,7 +52,7 @@ def join_chat(self, chat_id: str):
access_hash=resolved_peer.chats[0].access_hash
)
- return self.send(
+ return await self.send(
functions.channels.JoinChannel(
channel=channel
)
diff --git a/pyrogram/client/methods/chats/kick_chat_member.py b/pyrogram/client/methods/chats/kick_chat_member.py
index 6275718c80..5b8dda53e7 100644
--- a/pyrogram/client/methods/chats/kick_chat_member.py
+++ b/pyrogram/client/methods/chats/kick_chat_member.py
@@ -21,10 +21,10 @@
class KickChatMember(BaseClient):
- def kick_chat_member(self,
- chat_id: int or str,
- user_id: int or str,
- until_date: int = 0):
+ async def kick_chat_member(self,
+ chat_id: int or str,
+ user_id: int or str,
+ until_date: int = 0):
"""Use this method to kick a user from a group, a supergroup or a channel.
In the case of supergroups and channels, the user will not be able to return to the group on their own using
invite links, etc., unless unbanned first. You must be an administrator in the chat for this to work and must
@@ -55,11 +55,11 @@ def kick_chat_member(self,
Raises:
:class:`Error `
"""
- chat_peer = self.resolve_peer(chat_id)
- user_peer = self.resolve_peer(user_id)
+ chat_peer = await self.resolve_peer(chat_id)
+ user_peer = await self.resolve_peer(user_id)
if isinstance(chat_peer, types.InputPeerChannel):
- self.send(
+ await self.send(
functions.channels.EditBanned(
channel=chat_peer,
user_id=user_peer,
@@ -77,7 +77,7 @@ def kick_chat_member(self,
)
)
else:
- self.send(
+ await self.send(
functions.messages.DeleteChatUser(
chat_id=abs(chat_id),
user_id=user_peer
diff --git a/pyrogram/client/methods/chats/leave_chat.py b/pyrogram/client/methods/chats/leave_chat.py
index 55d6ef218d..9d7dfcef36 100644
--- a/pyrogram/client/methods/chats/leave_chat.py
+++ b/pyrogram/client/methods/chats/leave_chat.py
@@ -21,7 +21,7 @@
class LeaveChat(BaseClient):
- def leave_chat(self, chat_id: int or str, delete: bool = False):
+ async def leave_chat(self, chat_id: int or str, delete: bool = False):
"""Use this method to leave a group chat or channel.
Args:
@@ -35,16 +35,16 @@ def leave_chat(self, chat_id: int or str, delete: bool = False):
Raises:
:class:`Error `
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChannel):
- return self.send(
+ return await self.send(
functions.channels.LeaveChannel(
- channel=self.resolve_peer(chat_id)
+ channel=await self.resolve_peer(chat_id)
)
)
elif isinstance(peer, types.InputPeerChat):
- r = self.send(
+ r = await self.send(
functions.messages.DeleteChatUser(
chat_id=peer.chat_id,
user_id=types.InputPeerSelf()
@@ -52,7 +52,7 @@ def leave_chat(self, chat_id: int or str, delete: bool = False):
)
if delete:
- self.send(
+ await self.send(
functions.messages.DeleteHistory(
peer=peer,
max_id=0
diff --git a/pyrogram/client/methods/chats/promote_chat_member.py b/pyrogram/client/methods/chats/promote_chat_member.py
index eb70578a3d..9cfe426b8a 100644
--- a/pyrogram/client/methods/chats/promote_chat_member.py
+++ b/pyrogram/client/methods/chats/promote_chat_member.py
@@ -21,17 +21,17 @@
class PromoteChatMember(BaseClient):
- def promote_chat_member(self,
- chat_id: int or str,
- user_id: int or str,
- can_change_info: bool = True,
- can_post_messages: bool = True,
- can_edit_messages: bool = True,
- can_delete_messages: bool = True,
- can_invite_users: bool = True,
- can_restrict_members: bool = True,
- can_pin_messages: bool = True,
- can_promote_members: bool = False):
+ async def promote_chat_member(self,
+ chat_id: int or str,
+ user_id: int or str,
+ can_change_info: bool = True,
+ can_post_messages: bool = True,
+ can_edit_messages: bool = True,
+ can_delete_messages: bool = True,
+ can_invite_users: bool = True,
+ can_restrict_members: bool = True,
+ can_pin_messages: bool = True,
+ can_promote_members: bool = False):
"""Use this method to promote or demote a user in a supergroup or a channel.
You must be an administrator in the chat for this to work and must have the appropriate admin rights.
Pass False for all boolean parameters to demote a user.
@@ -77,10 +77,10 @@ def promote_chat_member(self,
Raises:
:class:`Error `
"""
- self.send(
+ await self.send(
functions.channels.EditAdmin(
- channel=self.resolve_peer(chat_id),
- user_id=self.resolve_peer(user_id),
+ channel=await self.resolve_peer(chat_id),
+ user_id=await self.resolve_peer(user_id),
admin_rights=types.ChannelAdminRights(
change_info=can_change_info or None,
post_messages=can_post_messages or None,
diff --git a/pyrogram/client/methods/chats/restrict_chat_member.py b/pyrogram/client/methods/chats/restrict_chat_member.py
index ae1e4d9c11..a9439ed1b5 100644
--- a/pyrogram/client/methods/chats/restrict_chat_member.py
+++ b/pyrogram/client/methods/chats/restrict_chat_member.py
@@ -21,14 +21,14 @@
class RestrictChatMember(BaseClient):
- def restrict_chat_member(self,
- chat_id: int or str,
- user_id: int or str,
- until_date: int = 0,
- can_send_messages: bool = False,
- can_send_media_messages: bool = False,
- can_send_other_messages: bool = False,
- can_add_web_page_previews: bool = False):
+ async def restrict_chat_member(self,
+ chat_id: int or str,
+ user_id: int or str,
+ until_date: int = 0,
+ can_send_messages: bool = False,
+ can_send_media_messages: bool = False,
+ can_send_other_messages: bool = False,
+ can_add_web_page_previews: bool = False):
"""Use this method to restrict a user in a supergroup. The bot must be an administrator in the supergroup for
this to work and must have the appropriate admin rights. Pass True for all boolean parameters to lift
restrictions from a user.
@@ -93,10 +93,10 @@ def restrict_chat_member(self,
send_media = None
embed_links = None
- self.send(
+ await self.send(
functions.channels.EditBanned(
- channel=self.resolve_peer(chat_id),
- user_id=self.resolve_peer(user_id),
+ channel=await self.resolve_peer(chat_id),
+ user_id=await self.resolve_peer(user_id),
banned_rights=types.ChannelBannedRights(
until_date=until_date,
send_messages=send_messages,
diff --git a/pyrogram/client/methods/chats/unban_chat_member.py b/pyrogram/client/methods/chats/unban_chat_member.py
index b0916eb4de..ed00f4283a 100644
--- a/pyrogram/client/methods/chats/unban_chat_member.py
+++ b/pyrogram/client/methods/chats/unban_chat_member.py
@@ -21,9 +21,9 @@
class UnbanChatMember(BaseClient):
- def unban_chat_member(self,
- chat_id: int or str,
- user_id: int or str):
+ async def unban_chat_member(self,
+ chat_id: int or str,
+ user_id: int or str):
"""Use this method to unban a previously kicked user in a supergroup or channel.
The user will **not** return to the group or channel automatically, but will be able to join via link, etc.
You must be an administrator for this to work.
@@ -43,10 +43,10 @@ def unban_chat_member(self,
Raises:
:class:`Error `
"""
- self.send(
+ await self.send(
functions.channels.EditBanned(
- channel=self.resolve_peer(chat_id),
- user_id=self.resolve_peer(user_id),
+ channel=await self.resolve_peer(chat_id),
+ user_id=await self.resolve_peer(user_id),
banned_rights=types.ChannelBannedRights(
until_date=0
)
diff --git a/pyrogram/client/methods/contacts/add_contacts.py b/pyrogram/client/methods/contacts/add_contacts.py
index 10b5e41506..75f4f8a80f 100644
--- a/pyrogram/client/methods/contacts/add_contacts.py
+++ b/pyrogram/client/methods/contacts/add_contacts.py
@@ -21,7 +21,7 @@
class AddContacts(BaseClient):
- def add_contacts(self, contacts: list):
+ async def add_contacts(self, contacts: list):
"""Use this method to add contacts to your Telegram address book.
Args:
@@ -34,7 +34,7 @@ def add_contacts(self, contacts: list):
Raises:
:class:`Error `
"""
- imported_contacts = self.send(
+ imported_contacts = await self.send(
functions.contacts.ImportContacts(
contacts=contacts
)
diff --git a/pyrogram/client/methods/contacts/delete_contacts.py b/pyrogram/client/methods/contacts/delete_contacts.py
index ed3d67f93b..ef133d8cd8 100644
--- a/pyrogram/client/methods/contacts/delete_contacts.py
+++ b/pyrogram/client/methods/contacts/delete_contacts.py
@@ -22,7 +22,7 @@
class DeleteContacts(BaseClient):
- def delete_contacts(self, ids: list):
+ async def delete_contacts(self, ids: list):
"""Use this method to delete contacts from your Telegram address book
Args:
@@ -40,14 +40,14 @@ def delete_contacts(self, ids: list):
for i in ids:
try:
- input_user = self.resolve_peer(i)
+ input_user = await self.resolve_peer(i)
except PeerIdInvalid:
continue
else:
if isinstance(input_user, types.InputPeerUser):
contacts.append(input_user)
- return self.send(
+ return await self.send(
functions.contacts.DeleteContacts(
id=contacts
)
diff --git a/pyrogram/client/methods/contacts/get_contacts.py b/pyrogram/client/methods/contacts/get_contacts.py
index 376e8be2a7..b73a1f2c90 100644
--- a/pyrogram/client/methods/contacts/get_contacts.py
+++ b/pyrogram/client/methods/contacts/get_contacts.py
@@ -16,8 +16,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
import logging
-import time
from pyrogram.api import functions, types
from pyrogram.api.errors import FloodWait
@@ -27,7 +27,7 @@
class GetContacts(BaseClient):
- def get_contacts(self):
+ async def get_contacts(self):
"""Use this method to get contacts from your Telegram address book
Requires no parameters.
@@ -40,10 +40,10 @@ def get_contacts(self):
"""
while True:
try:
- contacts = self.send(functions.contacts.GetContacts(0))
+ contacts = await self.send(functions.contacts.GetContacts(0))
except FloodWait as e:
log.warning("get_contacts flood: waiting {} seconds".format(e.x))
- time.sleep(e.x)
+ await asyncio.sleep(e.x)
continue
else:
if isinstance(contacts, types.contacts.Contacts):
diff --git a/pyrogram/client/methods/download_media.py b/pyrogram/client/methods/download_media.py
index 5eb04fbc9d..56a89472a6 100644
--- a/pyrogram/client/methods/download_media.py
+++ b/pyrogram/client/methods/download_media.py
@@ -16,19 +16,19 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from threading import Event
+import asyncio
from pyrogram.client import types as pyrogram_types
from ..ext import BaseClient
class DownloadMedia(BaseClient):
- def download_media(self,
- message: pyrogram_types.Message or str,
- file_name: str = "",
- block: bool = True,
- progress: callable = None,
- progress_args: tuple = None):
+ async def download_media(self,
+ message: pyrogram_types.Message or str,
+ file_name: str = "",
+ block: bool = True,
+ progress: callable = None,
+ progress_args: tuple = None):
"""Use this method to download the media from a Message.
Args:
@@ -114,12 +114,12 @@ def download_media(self,
else:
return
- done = Event()
+ done = asyncio.Event()
path = [None]
- self.download_queue.put((media, file_name, done, progress, progress_args, path))
+ self.download_queue.put_nowait((media, file_name, done, progress, progress_args, path))
if block:
- done.wait()
+ await done.wait()
return path[0]
diff --git a/pyrogram/client/methods/messages/action/send_chat_action.py b/pyrogram/client/methods/messages/action/send_chat_action.py
index 4b34dd406b..b770f60e1b 100644
--- a/pyrogram/client/methods/messages/action/send_chat_action.py
+++ b/pyrogram/client/methods/messages/action/send_chat_action.py
@@ -21,10 +21,10 @@
class SendChatAction(BaseClient):
- def send_chat_action(self,
- chat_id: int or str,
- action: ChatAction or str,
- progress: int = 0):
+ async def send_chat_action(self,
+ chat_id: int or str,
+ action: ChatAction or str,
+ progress: int = 0):
"""Use this method when you need to tell the other party that something is happening on your side.
Args:
@@ -63,9 +63,9 @@ def send_chat_action(self,
else:
action = action()
- return self.send(
+ return await self.send(
functions.messages.SetTyping(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
action=action
)
)
diff --git a/pyrogram/client/methods/messages/forward_messages.py b/pyrogram/client/methods/messages/forward_messages.py
index 606e54b567..03ca948792 100644
--- a/pyrogram/client/methods/messages/forward_messages.py
+++ b/pyrogram/client/methods/messages/forward_messages.py
@@ -21,11 +21,11 @@
class ForwardMessages(BaseClient):
- def forward_messages(self,
- chat_id: int or str,
- from_chat_id: int or str,
- message_ids,
- disable_notification: bool = None):
+ async def forward_messages(self,
+ chat_id: int or str,
+ from_chat_id: int or str,
+ message_ids,
+ disable_notification: bool = None):
"""Use this method to forward messages of any kind.
Args:
@@ -61,10 +61,10 @@ def forward_messages(self,
is_iterable = not isinstance(message_ids, int)
message_ids = list(message_ids) if is_iterable else [message_ids]
- r = self.send(
+ r = await self.send(
functions.messages.ForwardMessages(
- to_peer=self.resolve_peer(chat_id),
- from_peer=self.resolve_peer(from_chat_id),
+ to_peer=await self.resolve_peer(chat_id),
+ from_peer=await self.resolve_peer(from_chat_id),
id=message_ids,
silent=disable_notification or None,
random_id=[self.rnd_id() for _ in message_ids]
@@ -79,7 +79,7 @@ def forward_messages(self,
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
messages.append(
- utils.parse_messages(
+ await utils.parse_messages(
self, i.message,
users, chats
)
diff --git a/pyrogram/client/methods/messages/get_history.py b/pyrogram/client/methods/messages/get_history.py
index 4089dde924..d6c6479a32 100644
--- a/pyrogram/client/methods/messages/get_history.py
+++ b/pyrogram/client/methods/messages/get_history.py
@@ -22,12 +22,12 @@
class GetHistory(BaseClient):
- def get_history(self,
- chat_id: int or str,
- offset: int = 0,
- limit: int = 100,
- offset_id: int = 0,
- offset_date: int = 0):
+ async def get_history(self,
+ chat_id: int or str,
+ offset: int = 0,
+ limit: int = 100,
+ offset_id: int = 0,
+ offset_date: int = 0):
"""Use this method to retrieve the history of a chat.
You can get up to 100 messages at once.
@@ -60,9 +60,9 @@ def get_history(self,
:class:`Error `
"""
- r = self.send(
+ r = await self.send(
functions.messages.GetHistory(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
offset_id=offset_id,
offset_date=offset_date,
add_offset=offset,
@@ -83,7 +83,7 @@ def get_history(self,
}
if reply_to_messages:
- temp = self.get_messages(
+ temp = await self.get_messages(
chat_id, reply_to_messages,
replies=0
)
@@ -93,7 +93,7 @@ def get_history(self,
for i in range(len(temp)):
reply_to_messages[temp[i].message_id] = temp[i]
- messages = utils.parse_messages(
+ messages = await utils.parse_messages(
self, r.messages,
users, chats,
replies=0
diff --git a/pyrogram/client/methods/messages/get_messages.py b/pyrogram/client/methods/messages/get_messages.py
index 49535a406c..54c11830c9 100644
--- a/pyrogram/client/methods/messages/get_messages.py
+++ b/pyrogram/client/methods/messages/get_messages.py
@@ -21,10 +21,10 @@
class GetMessages(BaseClient):
- def get_messages(self,
- chat_id: int or str,
- message_ids,
- replies: int = 1):
+ async def get_messages(self,
+ chat_id: int or str,
+ message_ids,
+ replies: int = 1):
"""Use this method to get messages that belong to a specific chat.
You can retrieve up to 200 messages at once.
@@ -51,7 +51,7 @@ def get_messages(self,
Raises:
:class:`Error `
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
is_iterable = not isinstance(message_ids, int)
message_ids = list(message_ids) if is_iterable else [message_ids]
message_ids = [types.InputMessageID(i) for i in message_ids]
@@ -66,9 +66,9 @@ def get_messages(self,
id=message_ids
)
- r = self.send(rpc)
+ r = await self.send(rpc)
- messages = utils.parse_messages(
+ messages = await utils.parse_messages(
self, r.messages,
{i.id: i for i in r.users},
{i.id: i for i in r.chats},
diff --git a/pyrogram/client/methods/messages/media/send_audio.py b/pyrogram/client/methods/messages/media/send_audio.py
index 41f4457f60..00ccbe4d41 100644
--- a/pyrogram/client/methods/messages/media/send_audio.py
+++ b/pyrogram/client/methods/messages/media/send_audio.py
@@ -27,19 +27,19 @@
class SendAudio(BaseClient):
- def send_audio(self,
- chat_id: int or str,
- audio: str,
- caption: str = "",
- parse_mode: str = "",
- duration: int = 0,
- performer: str = None,
- title: str = None,
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None,
- progress: callable = None,
- progress_args: tuple = ()):
+ async def send_audio(self,
+ chat_id: int or str,
+ audio: str,
+ caption: str = "",
+ parse_mode: str = "",
+ duration: int = 0,
+ performer: str = None,
+ title: str = None,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None,
+ progress: callable = None,
+ progress_args: tuple = ()):
"""Use this method to send audio files.
For sending voice messages, use the :obj:`send_voice()` method instead.
@@ -118,7 +118,7 @@ def send_audio(self,
style = self.html if parse_mode.lower() == "html" else self.markdown
if os.path.exists(audio):
- file = self.save_file(audio, progress=progress, progress_args=progress_args)
+ file = await self.save_file(audio, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map.get("." + audio.split(".")[-1], "audio/mpeg"),
file=file,
@@ -160,9 +160,9 @@ def send_audio(self,
while True:
try:
- r = self.send(
+ r = await self.send(
functions.messages.SendMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
@@ -172,11 +172,11 @@ def send_audio(self,
)
)
except FilePartMissing as e:
- self.save_file(audio, file_id=file.id, file_part=e.x)
+ await self.save_file(audio, file_id=file.id, file_part=e.x)
else:
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/media/send_contact.py b/pyrogram/client/methods/messages/media/send_contact.py
index eb1bb6c450..2965fb5a5d 100644
--- a/pyrogram/client/methods/messages/media/send_contact.py
+++ b/pyrogram/client/methods/messages/media/send_contact.py
@@ -21,14 +21,14 @@
class SendContact(BaseClient):
- def send_contact(self,
- chat_id: int or str,
- phone_number: str,
- first_name: str,
- last_name: str = "",
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None):
+ async def send_contact(self,
+ chat_id: int or str,
+ phone_number: str,
+ first_name: str,
+ last_name: str = "",
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None):
"""Use this method to send phone contacts.
Args:
@@ -64,9 +64,9 @@ def send_contact(self,
Raises:
:class:`Error `
"""
- r = self.send(
+ r = await self.send(
functions.messages.SendMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=types.InputMediaContact(
phone_number,
first_name,
@@ -82,7 +82,7 @@ def send_contact(self,
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/media/send_document.py b/pyrogram/client/methods/messages/media/send_document.py
index 1092147f7a..f32f78c6eb 100644
--- a/pyrogram/client/methods/messages/media/send_document.py
+++ b/pyrogram/client/methods/messages/media/send_document.py
@@ -27,16 +27,16 @@
class SendDocument(BaseClient):
- def send_document(self,
- chat_id: int or str,
- document: str,
- caption: str = "",
- parse_mode: str = "",
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None,
- progress: callable = None,
- progress_args: tuple = ()):
+ async def send_document(self,
+ chat_id: int or str,
+ document: str,
+ caption: str = "",
+ parse_mode: str = "",
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None,
+ progress: callable = None,
+ progress_args: tuple = ()):
"""Use this method to send general files.
Args:
@@ -104,7 +104,7 @@ def send_document(self,
style = self.html if parse_mode.lower() == "html" else self.markdown
if os.path.exists(document):
- file = self.save_file(document, progress=progress, progress_args=progress_args)
+ file = await self.save_file(document, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map.get("." + document.split(".")[-1], "text/plain"),
file=file,
@@ -141,9 +141,9 @@ def send_document(self,
while True:
try:
- r = self.send(
+ r = await self.send(
functions.messages.SendMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
@@ -153,11 +153,11 @@ def send_document(self,
)
)
except FilePartMissing as e:
- self.save_file(document, file_id=file.id, file_part=e.x)
+ await self.save_file(document, file_id=file.id, file_part=e.x)
else:
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/media/send_gif.py b/pyrogram/client/methods/messages/media/send_gif.py
index 0d4bb4b97a..bdda234ed9 100644
--- a/pyrogram/client/methods/messages/media/send_gif.py
+++ b/pyrogram/client/methods/messages/media/send_gif.py
@@ -27,7 +27,7 @@
class SendGIF(BaseClient):
- def send_gif(self,
+ async def send_gif(self,
chat_id: int or str,
gif: str,
caption: str = "",
@@ -122,8 +122,8 @@ def send_gif(self,
style = self.html if parse_mode.lower() == "html" else self.markdown
if os.path.exists(gif):
- thumb = None if thumb is None else self.save_file(thumb)
- file = self.save_file(gif, progress=progress, progress_args=progress_args)
+ thumb = None if thumb is None else await self.save_file(thumb)
+ file = await self.save_file(gif, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map[".mp4"],
file=file,
@@ -168,9 +168,9 @@ def send_gif(self,
while True:
try:
- r = self.send(
+ r = await self.send(
functions.messages.SendMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
@@ -180,11 +180,11 @@ def send_gif(self,
)
)
except FilePartMissing as e:
- self.save_file(gif, file_id=file.id, file_part=e.x)
+ await self.save_file(gif, file_id=file.id, file_part=e.x)
else:
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/media/send_location.py b/pyrogram/client/methods/messages/media/send_location.py
index 08dac02b38..0a1a1776af 100644
--- a/pyrogram/client/methods/messages/media/send_location.py
+++ b/pyrogram/client/methods/messages/media/send_location.py
@@ -21,13 +21,13 @@
class SendLocation(BaseClient):
- def send_location(self,
- chat_id: int or str,
- latitude: float,
- longitude: float,
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None):
+ async def send_location(self,
+ chat_id: int or str,
+ latitude: float,
+ longitude: float,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None):
"""Use this method to send points on the map.
Args:
@@ -60,9 +60,9 @@ def send_location(self,
Raises:
:class:`Error `
"""
- r = self.send(
+ r = await self.send(
functions.messages.SendMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=types.InputMediaGeoPoint(
types.InputGeoPoint(
latitude,
@@ -79,7 +79,7 @@ def send_location(self,
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/media/send_media_group.py b/pyrogram/client/methods/messages/media/send_media_group.py
index 6d004d9fa9..f0af01becd 100644
--- a/pyrogram/client/methods/messages/media/send_media_group.py
+++ b/pyrogram/client/methods/messages/media/send_media_group.py
@@ -31,11 +31,11 @@ class SendMediaGroup(BaseClient):
# TODO: Add progress parameter
# TODO: Return new Message object
# TODO: Figure out how to send albums using URLs
- def send_media_group(self,
- chat_id: int or str,
- media: list,
- disable_notification: bool = None,
- reply_to_message_id: int = None):
+ async def send_media_group(self,
+ chat_id: int or str,
+ media: list,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None):
"""Use this method to send a group of photos or videos as an album.
On success, an Update containing the sent Messages is returned.
@@ -65,11 +65,11 @@ def send_media_group(self,
if isinstance(i, pyrogram_types.InputMediaPhoto):
if os.path.exists(i.media):
- media = self.send(
+ media = await self.send(
functions.messages.UploadMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=types.InputMediaUploadedPhoto(
- file=self.save_file(i.media)
+ file=await self.save_file(i.media)
)
)
)
@@ -104,11 +104,11 @@ def send_media_group(self,
)
elif isinstance(i, pyrogram_types.InputMediaVideo):
if os.path.exists(i.media):
- media = self.send(
+ media = await self.send(
functions.messages.UploadMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=types.InputMediaUploadedDocument(
- file=self.save_file(i.media),
+ file=await self.save_file(i.media),
mime_type=mimetypes.types_map[".mp4"],
attributes=[
types.DocumentAttributeVideo(
@@ -160,9 +160,9 @@ def send_media_group(self,
)
)
- return self.send(
+ return await self.send(
functions.messages.SendMultiMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
multi_media=multi_media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id
diff --git a/pyrogram/client/methods/messages/media/send_photo.py b/pyrogram/client/methods/messages/media/send_photo.py
index 52e98ff14b..e066deef06 100644
--- a/pyrogram/client/methods/messages/media/send_photo.py
+++ b/pyrogram/client/methods/messages/media/send_photo.py
@@ -26,17 +26,17 @@
class SendPhoto(BaseClient):
- def send_photo(self,
- chat_id: int or str,
- photo: str,
- caption: str = "",
- parse_mode: str = "",
- ttl_seconds: int = None,
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None,
- progress: callable = None,
- progress_args: tuple = ()):
+ async def send_photo(self,
+ chat_id: int or str,
+ photo: str,
+ caption: str = "",
+ parse_mode: str = "",
+ ttl_seconds: int = None,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None,
+ progress: callable = None,
+ progress_args: tuple = ()):
"""Use this method to send photos.
Args:
@@ -109,7 +109,7 @@ def send_photo(self,
style = self.html if parse_mode.lower() == "html" else self.markdown
if os.path.exists(photo):
- file = self.save_file(photo, progress=progress, progress_args=progress_args)
+ file = await self.save_file(photo, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedPhoto(
file=file,
ttl_seconds=ttl_seconds
@@ -145,9 +145,9 @@ def send_photo(self,
while True:
try:
- r = self.send(
+ r = await self.send(
functions.messages.SendMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
@@ -157,11 +157,11 @@ def send_photo(self,
)
)
except FilePartMissing as e:
- self.save_file(photo, file_id=file.id, file_part=e.x)
+ await self.save_file(photo, file_id=file.id, file_part=e.x)
else:
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/media/send_sticker.py b/pyrogram/client/methods/messages/media/send_sticker.py
index 639e360093..7d559d1c15 100644
--- a/pyrogram/client/methods/messages/media/send_sticker.py
+++ b/pyrogram/client/methods/messages/media/send_sticker.py
@@ -26,14 +26,14 @@
class SendSticker(BaseClient):
- def send_sticker(self,
- chat_id: int or str,
- sticker: str,
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None,
- progress: callable = None,
- progress_args: tuple = ()):
+ async def send_sticker(self,
+ chat_id: int or str,
+ sticker: str,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None,
+ progress: callable = None,
+ progress_args: tuple = ()):
"""Use this method to send .webp stickers.
Args:
@@ -92,7 +92,7 @@ def send_sticker(self,
file = None
if os.path.exists(sticker):
- file = self.save_file(sticker, progress=progress, progress_args=progress_args)
+ file = await self.save_file(sticker, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument(
mime_type="image/webp",
file=file,
@@ -129,9 +129,9 @@ def send_sticker(self,
while True:
try:
- r = self.send(
+ r = await self.send(
functions.messages.SendMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
@@ -141,11 +141,11 @@ def send_sticker(self,
)
)
except FilePartMissing as e:
- self.save_file(sticker, file_id=file.id, file_part=e.x)
+ await self.save_file(sticker, file_id=file.id, file_part=e.x)
else:
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/media/send_venue.py b/pyrogram/client/methods/messages/media/send_venue.py
index d65ea43bcb..dcb3639d89 100644
--- a/pyrogram/client/methods/messages/media/send_venue.py
+++ b/pyrogram/client/methods/messages/media/send_venue.py
@@ -21,16 +21,16 @@
class SendVenue(BaseClient):
- def send_venue(self,
- chat_id: int or str,
- latitude: float,
- longitude: float,
- title: str,
- address: str,
- foursquare_id: str = "",
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None):
+ async def send_venue(self,
+ chat_id: int or str,
+ latitude: float,
+ longitude: float,
+ title: str,
+ address: str,
+ foursquare_id: str = "",
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None):
"""Use this method to send information about a venue.
Args:
@@ -72,9 +72,9 @@ def send_venue(self,
Raises:
:class:`Error `
"""
- r = self.send(
+ r = await self.send(
functions.messages.SendMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=types.InputMediaVenue(
geo_point=types.InputGeoPoint(
lat=latitude,
@@ -96,7 +96,7 @@ def send_venue(self,
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/media/send_video.py b/pyrogram/client/methods/messages/media/send_video.py
index a4cc03093f..f7c7d66d89 100644
--- a/pyrogram/client/methods/messages/media/send_video.py
+++ b/pyrogram/client/methods/messages/media/send_video.py
@@ -27,21 +27,21 @@
class SendVideo(BaseClient):
- def send_video(self,
- chat_id: int or str,
- video: str,
- caption: str = "",
- parse_mode: str = "",
- duration: int = 0,
- width: int = 0,
- height: int = 0,
- thumb: str = None,
- supports_streaming: bool = True,
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None,
- progress: callable = None,
- progress_args: tuple = ()):
+ async def send_video(self,
+ chat_id: int or str,
+ video: str,
+ caption: str = "",
+ parse_mode: str = "",
+ duration: int = 0,
+ width: int = 0,
+ height: int = 0,
+ thumb: str = None,
+ supports_streaming: bool = True,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None,
+ progress: callable = None,
+ progress_args: tuple = ()):
"""Use this method to send video files.
Args:
@@ -127,7 +127,7 @@ def send_video(self,
if os.path.exists(video):
thumb = None if thumb is None else self.save_file(thumb)
- file = self.save_file(video, progress=progress, progress_args=progress_args)
+ file = await self.save_file(video, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map[".mp4"],
file=file,
@@ -171,9 +171,9 @@ def send_video(self,
while True:
try:
- r = self.send(
+ r = await self.send(
functions.messages.SendMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
@@ -183,11 +183,11 @@ def send_video(self,
)
)
except FilePartMissing as e:
- self.save_file(video, file_id=file.id, file_part=e.x)
+ await self.save_file(video, file_id=file.id, file_part=e.x)
else:
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/media/send_video_note.py b/pyrogram/client/methods/messages/media/send_video_note.py
index d7b417d580..6eb2c25269 100644
--- a/pyrogram/client/methods/messages/media/send_video_note.py
+++ b/pyrogram/client/methods/messages/media/send_video_note.py
@@ -27,16 +27,16 @@
class SendVideoNote(BaseClient):
- def send_video_note(self,
- chat_id: int or str,
- video_note: str,
- duration: int = 0,
- length: int = 1,
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None,
- progress: callable = None,
- progress_args: tuple = ()):
+ async def send_video_note(self,
+ chat_id: int or str,
+ video_note: str,
+ duration: int = 0,
+ length: int = 1,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None,
+ progress: callable = None,
+ progress_args: tuple = ()):
"""Use this method to send video messages.
Args:
@@ -101,7 +101,7 @@ def send_video_note(self,
file = None
if os.path.exists(video_note):
- file = self.save_file(video_note, progress=progress, progress_args=progress_args)
+ file = await self.save_file(video_note, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map[".mp4"],
file=file,
@@ -139,9 +139,9 @@ def send_video_note(self,
while True:
try:
- r = self.send(
+ r = await self.send(
functions.messages.SendMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
@@ -151,11 +151,11 @@ def send_video_note(self,
)
)
except FilePartMissing as e:
- self.save_file(video_note, file_id=file.id, file_part=e.x)
+ await self.save_file(video_note, file_id=file.id, file_part=e.x)
else:
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/media/send_voice.py b/pyrogram/client/methods/messages/media/send_voice.py
index ae21de6d63..114ee0730c 100644
--- a/pyrogram/client/methods/messages/media/send_voice.py
+++ b/pyrogram/client/methods/messages/media/send_voice.py
@@ -27,17 +27,17 @@
class SendVoice(BaseClient):
- def send_voice(self,
- chat_id: int or str,
- voice: str,
- caption: str = "",
- parse_mode: str = "",
- duration: int = 0,
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None,
- progress: callable = None,
- progress_args: tuple = ()):
+ async def send_voice(self,
+ chat_id: int or str,
+ voice: str,
+ caption: str = "",
+ parse_mode: str = "",
+ duration: int = 0,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None,
+ progress: callable = None,
+ progress_args: tuple = ()):
"""Use this method to send audio files.
Args:
@@ -108,7 +108,7 @@ def send_voice(self,
style = self.html if parse_mode.lower() == "html" else self.markdown
if os.path.exists(voice):
- file = self.save_file(voice, progress=progress, progress_args=progress_args)
+ file = await self.save_file(voice, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map.get("." + voice.split(".")[-1], "audio/mpeg"),
file=file,
@@ -148,9 +148,9 @@ def send_voice(self,
while True:
try:
- r = self.send(
+ r = await self.send(
functions.messages.SendMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
@@ -160,11 +160,11 @@ def send_voice(self,
)
)
except FilePartMissing as e:
- self.save_file(voice, file_id=file.id, file_part=e.x)
+ await self.save_file(voice, file_id=file.id, file_part=e.x)
else:
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/send_message.py b/pyrogram/client/methods/messages/send_message.py
index 44acaa2ecc..0009d4998d 100644
--- a/pyrogram/client/methods/messages/send_message.py
+++ b/pyrogram/client/methods/messages/send_message.py
@@ -22,14 +22,14 @@
class SendMessage(BaseClient):
- def send_message(self,
- chat_id: int or str,
- text: str,
- parse_mode: str = "",
- disable_web_page_preview: bool = None,
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None):
+ async def send_message(self,
+ chat_id: int or str,
+ text: str,
+ parse_mode: str = "",
+ disable_web_page_preview: bool = None,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None):
"""Use this method to send text messages.
Args:
@@ -69,9 +69,9 @@ def send_message(self,
"""
style = self.html if parse_mode.lower() == "html" else self.markdown
- r = self.send(
+ r = await self.send(
functions.messages.SendMessage(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
no_webpage=disable_web_page_preview or None,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
@@ -91,7 +91,7 @@ def send_message(self,
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/update/delete_messages.py b/pyrogram/client/methods/messages/update/delete_messages.py
index 3d29bf55f6..2853ce2577 100644
--- a/pyrogram/client/methods/messages/update/delete_messages.py
+++ b/pyrogram/client/methods/messages/update/delete_messages.py
@@ -21,10 +21,10 @@
class DeleteMessages(BaseClient):
- def delete_messages(self,
- chat_id: int or str,
- message_ids,
- revoke: bool = True):
+ async def delete_messages(self,
+ chat_id: int or str,
+ message_ids,
+ revoke: bool = True):
"""Use this method to delete messages, including service messages, with the following limitations:
- A message can only be deleted if it was sent less than 48 hours ago.
@@ -56,18 +56,18 @@ def delete_messages(self,
Raises:
:class:`Error `
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
message_ids = list(message_ids) if not isinstance(message_ids, int) else [message_ids]
if isinstance(peer, types.InputPeerChannel):
- self.send(
+ await self.send(
functions.channels.DeleteMessages(
channel=peer,
id=message_ids
)
)
else:
- self.send(
+ await self.send(
functions.messages.DeleteMessages(
id=message_ids,
revoke=revoke or None
diff --git a/pyrogram/client/methods/messages/update/edit_message_caption.py b/pyrogram/client/methods/messages/update/edit_message_caption.py
index 90bf26f788..e2bade978d 100644
--- a/pyrogram/client/methods/messages/update/edit_message_caption.py
+++ b/pyrogram/client/methods/messages/update/edit_message_caption.py
@@ -21,12 +21,12 @@
class EditMessageCaption(BaseClient):
- def edit_message_caption(self,
- chat_id: int or str,
- message_id: int,
- caption: str,
- parse_mode: str = "",
- reply_markup=None):
+ async def edit_message_caption(self,
+ chat_id: int or str,
+ message_id: int,
+ caption: str,
+ parse_mode: str = "",
+ reply_markup=None):
"""Use this method to edit captions of messages.
Args:
@@ -58,9 +58,9 @@ def edit_message_caption(self,
"""
style = self.html if parse_mode.lower() == "html" else self.markdown
- r = self.send(
+ r = await self.send(
functions.messages.EditMessage(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
id=message_id,
reply_markup=reply_markup.write() if reply_markup else None,
**style.parse(caption)
@@ -69,7 +69,7 @@ def edit_message_caption(self,
for i in r.updates:
if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/update/edit_message_reply_markup.py b/pyrogram/client/methods/messages/update/edit_message_reply_markup.py
index 295eb2588f..ec7c76382c 100644
--- a/pyrogram/client/methods/messages/update/edit_message_reply_markup.py
+++ b/pyrogram/client/methods/messages/update/edit_message_reply_markup.py
@@ -21,10 +21,10 @@
class EditMessageReplyMarkup(BaseClient):
- def edit_message_reply_markup(self,
- chat_id: int or str,
- message_id: int,
- reply_markup=None):
+ async def edit_message_reply_markup(self,
+ chat_id: int or str,
+ message_id: int,
+ reply_markup=None):
"""Use this method to edit only the reply markup of messages sent by the bot or via the bot (for inline bots).
Args:
@@ -48,9 +48,9 @@ def edit_message_reply_markup(self,
:class:`Error `
"""
- r = self.send(
+ r = await self.send(
functions.messages.EditMessage(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
id=message_id,
reply_markup=reply_markup.write() if reply_markup else None
)
@@ -58,7 +58,7 @@ def edit_message_reply_markup(self,
for i in r.updates:
if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/update/edit_message_text.py b/pyrogram/client/methods/messages/update/edit_message_text.py
index be7b380cfb..6fa50e71ac 100644
--- a/pyrogram/client/methods/messages/update/edit_message_text.py
+++ b/pyrogram/client/methods/messages/update/edit_message_text.py
@@ -21,13 +21,13 @@
class EditMessageText(BaseClient):
- def edit_message_text(self,
- chat_id: int or str,
- message_id: int,
- text: str,
- parse_mode: str = "",
- disable_web_page_preview: bool = None,
- reply_markup=None):
+ async def edit_message_text(self,
+ chat_id: int or str,
+ message_id: int,
+ text: str,
+ parse_mode: str = "",
+ disable_web_page_preview: bool = None,
+ reply_markup=None):
"""Use this method to edit text messages.
Args:
@@ -62,9 +62,9 @@ def edit_message_text(self,
"""
style = self.html if parse_mode.lower() == "html" else self.markdown
- r = self.send(
+ r = await self.send(
functions.messages.EditMessage(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
id=message_id,
no_webpage=disable_web_page_preview or None,
reply_markup=reply_markup.write() if reply_markup else None,
@@ -74,7 +74,7 @@ def edit_message_text(self,
for i in r.updates:
if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
From e0fe9d3525ab6edeb3d4d2108f06a52a6d3caffb Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 19 Jun 2018 13:48:49 +0200
Subject: [PATCH 0039/1185] Fix some methods not being async
---
.../client/methods/password/change_cloud_password.py | 6 +++---
.../client/methods/password/enable_cloud_password.py | 6 +++---
.../client/methods/password/remove_cloud_password.py | 6 +++---
pyrogram/client/methods/users/get_me.py | 4 ++--
.../client/methods/users/get_user_profile_photos.py | 12 ++++++------
pyrogram/client/methods/users/get_users.py | 8 +++++---
6 files changed, 22 insertions(+), 20 deletions(-)
diff --git a/pyrogram/client/methods/password/change_cloud_password.py b/pyrogram/client/methods/password/change_cloud_password.py
index 045a0cc9e1..e066d8ba8a 100644
--- a/pyrogram/client/methods/password/change_cloud_password.py
+++ b/pyrogram/client/methods/password/change_cloud_password.py
@@ -24,7 +24,7 @@
class ChangeCloudPassword(BaseClient):
- def change_cloud_password(self, current_password: str, new_password: str, new_hint: str = ""):
+ async def change_cloud_password(self, current_password: str, new_password: str, new_hint: str = ""):
"""Use this method to change your Two-Step Verification password (Cloud Password) with a new one.
Args:
@@ -43,7 +43,7 @@ def change_cloud_password(self, current_password: str, new_password: str, new_hi
Raises:
:class:`Error `
"""
- r = self.send(functions.account.GetPassword())
+ r = await self.send(functions.account.GetPassword())
if isinstance(r, types.account.Password):
current_password_hash = sha256(r.current_salt + current_password.encode() + r.current_salt).digest()
@@ -51,7 +51,7 @@ def change_cloud_password(self, current_password: str, new_password: str, new_hi
new_salt = r.new_salt + os.urandom(8)
new_password_hash = sha256(new_salt + new_password.encode() + new_salt).digest()
- return self.send(
+ return await self.send(
functions.account.UpdatePasswordSettings(
current_password_hash=current_password_hash,
new_settings=types.account.PasswordInputSettings(
diff --git a/pyrogram/client/methods/password/enable_cloud_password.py b/pyrogram/client/methods/password/enable_cloud_password.py
index 639879cb11..496430ad4c 100644
--- a/pyrogram/client/methods/password/enable_cloud_password.py
+++ b/pyrogram/client/methods/password/enable_cloud_password.py
@@ -24,7 +24,7 @@
class EnableCloudPassword(BaseClient):
- def enable_cloud_password(self, password: str, hint: str = "", email: str = ""):
+ async def enable_cloud_password(self, password: str, hint: str = "", email: str = ""):
"""Use this method to enable the Two-Step Verification security feature (Cloud Password) on your account.
This password will be asked when you log in on a new device in addition to the SMS code.
@@ -45,13 +45,13 @@ def enable_cloud_password(self, password: str, hint: str = "", email: str = ""):
Raises:
:class:`Error `
"""
- r = self.send(functions.account.GetPassword())
+ r = await self.send(functions.account.GetPassword())
if isinstance(r, types.account.NoPassword):
salt = r.new_salt + os.urandom(8)
password_hash = sha256(salt + password.encode() + salt).digest()
- return self.send(
+ return await self.send(
functions.account.UpdatePasswordSettings(
current_password_hash=salt,
new_settings=types.account.PasswordInputSettings(
diff --git a/pyrogram/client/methods/password/remove_cloud_password.py b/pyrogram/client/methods/password/remove_cloud_password.py
index bfbb2c8bf9..5392433f7c 100644
--- a/pyrogram/client/methods/password/remove_cloud_password.py
+++ b/pyrogram/client/methods/password/remove_cloud_password.py
@@ -23,7 +23,7 @@
class RemoveCloudPassword(BaseClient):
- def remove_cloud_password(self, password: str):
+ async def remove_cloud_password(self, password: str):
"""Use this method to turn off the Two-Step Verification security feature (Cloud Password) on your account.
Args:
@@ -36,12 +36,12 @@ def remove_cloud_password(self, password: str):
Raises:
:class:`Error `
"""
- r = self.send(functions.account.GetPassword())
+ r = await self.send(functions.account.GetPassword())
if isinstance(r, types.account.Password):
password_hash = sha256(r.current_salt + password.encode() + r.current_salt).digest()
- return self.send(
+ return await self.send(
functions.account.UpdatePasswordSettings(
current_password_hash=password_hash,
new_settings=types.account.PasswordInputSettings(
diff --git a/pyrogram/client/methods/users/get_me.py b/pyrogram/client/methods/users/get_me.py
index 80ee65e931..f191e29863 100644
--- a/pyrogram/client/methods/users/get_me.py
+++ b/pyrogram/client/methods/users/get_me.py
@@ -21,7 +21,7 @@
class GetMe(BaseClient):
- def get_me(self):
+ async def get_me(self):
"""A simple method for testing your authorization. Requires no parameters.
Returns:
@@ -31,7 +31,7 @@ def get_me(self):
:class:`Error `
"""
return utils.parse_user(
- self.send(
+ await self.send(
functions.users.GetFullUser(
types.InputPeerSelf()
)
diff --git a/pyrogram/client/methods/users/get_user_profile_photos.py b/pyrogram/client/methods/users/get_user_profile_photos.py
index 42fb84bb03..a58e9d52e3 100644
--- a/pyrogram/client/methods/users/get_user_profile_photos.py
+++ b/pyrogram/client/methods/users/get_user_profile_photos.py
@@ -21,10 +21,10 @@
class GetUserProfilePhotos(BaseClient):
- def get_user_profile_photos(self,
- user_id: int or str,
- offset: int = 0,
- limit: int = 100):
+ async def get_user_profile_photos(self,
+ user_id: int or str,
+ offset: int = 0,
+ limit: int = 100):
"""Use this method to get a list of profile pictures for a user.
Args:
@@ -49,9 +49,9 @@ def get_user_profile_photos(self,
:class:`Error `
"""
return utils.parse_photos(
- self.send(
+ await self.send(
functions.photos.GetUserPhotos(
- user_id=self.resolve_peer(user_id),
+ user_id=await self.resolve_peer(user_id),
offset=offset,
max_id=0,
limit=limit
diff --git a/pyrogram/client/methods/users/get_users.py b/pyrogram/client/methods/users/get_users.py
index 400e35a173..33c38900ef 100644
--- a/pyrogram/client/methods/users/get_users.py
+++ b/pyrogram/client/methods/users/get_users.py
@@ -16,12 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
+
from pyrogram.api import functions
from ...ext import BaseClient, utils
class GetUsers(BaseClient):
- def get_users(self, user_ids):
+ async def get_users(self, user_ids):
"""Use this method to get information about a user.
You can retrieve up to 200 users at once.
@@ -41,9 +43,9 @@ def get_users(self, user_ids):
"""
is_iterable = not isinstance(user_ids, (int, str))
user_ids = list(user_ids) if is_iterable else [user_ids]
- user_ids = [self.resolve_peer(i) for i in user_ids]
+ user_ids = await asyncio.gather(*[self.resolve_peer(i) for i in user_ids])
- r = self.send(
+ r = await self.send(
functions.users.GetUsers(
id=user_ids
)
From 399a7b6403329199c3726229b338e51ef3e359f6 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 19 Jun 2018 14:02:49 +0200
Subject: [PATCH 0040/1185] Make Message bound methods async
---
pyrogram/client/types/message.py | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/pyrogram/client/types/message.py b/pyrogram/client/types/message.py
index 74f2a0a6db..9b712c1f78 100644
--- a/pyrogram/client/types/message.py
+++ b/pyrogram/client/types/message.py
@@ -310,14 +310,14 @@ def __init__(
self.command = command
self.reply_markup = reply_markup
- def reply_text(self,
- text: str,
- quote: bool = None,
- parse_mode: str = "",
- disable_web_page_preview: bool = None,
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None):
+ async def reply_text(self,
+ text: str,
+ quote: bool = None,
+ parse_mode: str = "",
+ disable_web_page_preview: bool = None,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None):
"""Use this method as a shortcut for:
.. code-block:: python
@@ -373,7 +373,7 @@ def reply_text(self,
if reply_to_message_id is None and quote:
reply_to_message_id = self.message_id
- return self._client.send_message(
+ return await self._client.send_message(
chat_id=self.chat.id,
text=text,
parse_mode=parse_mode,
@@ -383,9 +383,9 @@ def reply_text(self,
reply_markup=reply_markup
)
- def forward(self,
- chat_id: int or str,
- disable_notification: bool = None):
+ async def forward(self,
+ chat_id: int or str,
+ disable_notification: bool = None):
"""Use this method as a shortcut for:
.. code-block:: python
@@ -418,14 +418,14 @@ def forward(self,
Raises:
:class:`Error `
"""
- return self._client.forward_messages(
+ return await self._client.forward_messages(
chat_id=chat_id,
from_chat_id=self.chat.id,
message_ids=self.message_id,
disable_notification=disable_notification
)
- def delete(self, revoke: bool = True):
+ async def delete(self, revoke: bool = True):
"""Use this method as a shortcut for:
.. code-block:: python
@@ -453,7 +453,7 @@ def delete(self, revoke: bool = True):
Raises:
:class:`Error `
"""
- self._client.delete_messages(
+ await self._client.delete_messages(
chat_id=self.chat.id,
message_ids=self.message_id,
revoke=revoke
From 6fcf41d8572e5d64d31ae97f3b40dccc232ab5bd Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 20 Jun 2018 11:41:22 +0200
Subject: [PATCH 0041/1185] Client becomes async
---
pyrogram/client/client.py | 278 +++++++++++++++++---------------------
1 file changed, 127 insertions(+), 151 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 8eba760a1d..a3197d0c55 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
import base64
import binascii
import getpass
@@ -28,7 +29,6 @@
import shutil
import struct
import tempfile
-import threading
import time
from configparser import ConfigParser
from datetime import datetime
@@ -43,11 +43,11 @@
PhoneCodeExpired, PhoneCodeEmpty, SessionPasswordNeeded,
PasswordHashInvalid, FloodWait, PeerIdInvalid, FirstnameInvalid, PhoneNumberBanned,
VolumeLocNotFound, UserMigrate, FileIdInvalid)
-from pyrogram.client.handlers import DisconnectHandler
from pyrogram.crypto import AES
from pyrogram.session import Auth, Session
from .dispatcher import Dispatcher
-from .ext import utils, Syncer, BaseClient
+from .ext import BaseClient, Syncer, utils
+from .handlers import DisconnectHandler
from .methods import Methods
# Custom format for nice looking log lines
@@ -114,7 +114,7 @@ class Client(Methods, BaseClient):
be an empty string: "". Only applicable for new sessions.
workers (``int``, *optional*):
- Thread pool size for handling incoming updates. Defaults to 4.
+ Number of maximum concurrent workers for handling incoming updates. Defaults to 4.
workdir (``str``, *optional*):
Define a custom working directory. The working directory is the location in your filesystem
@@ -168,15 +168,10 @@ def proxy(self, value):
self._proxy["enabled"] = True
self._proxy.update(value)
- async def start(self, debug: bool = False):
+ async def start(self):
"""Use this method to start the Client after creating it.
Requires no parameters.
- Args:
- debug (``bool``, *optional*):
- Enable or disable debug mode. When enabled, extra logging
- lines will be printed out on your console.
-
Raises:
:class:`Error `
"""
@@ -188,7 +183,7 @@ async def start(self, debug: bool = False):
self.session_name = self.session_name.split(":")[0]
self.load_config()
- self.load_session()
+ await self.load_session()
self.session = Session(
self.dc_id,
@@ -204,9 +199,9 @@ async def start(self, debug: bool = False):
if self.user_id is None:
if self.token is None:
- self.authorize_user()
+ await self.authorize_user()
else:
- self.authorize_bot()
+ await self.authorize_bot()
self.save_session()
@@ -217,38 +212,27 @@ async def start(self, debug: bool = False):
self.peers_by_username = {}
self.peers_by_phone = {}
- self.get_dialogs()
- self.get_contacts()
+ await self.get_dialogs()
+ await self.get_contacts()
else:
- self.send(functions.messages.GetPinnedDialogs())
- self.get_dialogs_chunk(0)
+ await self.send(functions.messages.GetPinnedDialogs())
+ await self.get_dialogs_chunk(0)
else:
await self.send(functions.updates.GetState())
- # for i in range(self.UPDATES_WORKERS):
- # self.updates_workers_list.append(
- # Thread(
- # target=self.updates_worker,
- # name="UpdatesWorker#{}".format(i + 1)
- # )
- # )
- #
- # self.updates_workers_list[-1].start()
- #
- # for i in range(self.DOWNLOAD_WORKERS):
- # self.download_workers_list.append(
- # Thread(
- # target=self.download_worker,
- # name="DownloadWorker#{}".format(i + 1)
- # )
- # )
- #
- # self.download_workers_list[-1].start()
- #
- # self.dispatcher.start()
+ self.updates_worker_task = asyncio.ensure_future(self.updates_worker())
+
+ for _ in range(Client.DOWNLOAD_WORKERS):
+ self.download_worker_tasks.append(
+ asyncio.ensure_future(self.download_worker())
+ )
+
+ log.info("Started {} DownloadWorkerTasks".format(Client.DOWNLOAD_WORKERS))
+
+ await self.dispatcher.start()
+ await Syncer.add(self)
mimetypes.init()
- # Syncer.add(self)
async def stop(self):
"""Use this method to manually stop the Client.
@@ -257,29 +241,26 @@ async def stop(self):
if not self.is_started:
raise ConnectionError("Client is already stopped")
- # Syncer.remove(self)
- # self.dispatcher.stop()
- #
- # for _ in range(self.DOWNLOAD_WORKERS):
- # self.download_queue.put(None)
- #
- # for i in self.download_workers_list:
- # i.join()
- #
- # self.download_workers_list.clear()
- #
- # for _ in range(self.UPDATES_WORKERS):
- # self.updates_queue.put(None)
- #
- # for i in self.updates_workers_list:
- # i.join()
- #
- # self.updates_workers_list.clear()
- #
- # for i in self.media_sessions.values():
- # i.stop()
- #
- # self.media_sessions.clear()
+ await Syncer.remove(self)
+ await self.dispatcher.stop()
+
+ for _ in range(Client.DOWNLOAD_WORKERS):
+ self.download_queue.put_nowait(None)
+
+ for task in self.download_worker_tasks:
+ await task
+
+ self.download_worker_tasks.clear()
+
+ log.info("Stopped {} DownloadWorkerTasks".format(Client.DOWNLOAD_WORKERS))
+
+ self.updates_queue.put_nowait(None)
+ await self.updates_worker_task
+
+ for media_session in self.media_sessions.values():
+ await media_session.stop()
+
+ self.media_sessions.clear()
self.is_started = False
await self.session.stop()
@@ -327,9 +308,9 @@ def remove_handler(self, handler, group: int = 0):
else:
self.dispatcher.remove_handler(handler, group)
- def authorize_bot(self):
+ async def authorize_bot(self):
try:
- r = self.send(
+ r = await self.send(
functions.auth.ImportBotAuthorization(
flags=0,
api_id=self.api_id,
@@ -338,10 +319,10 @@ def authorize_bot(self):
)
)
except UserMigrate as e:
- self.session.stop()
+ await self.session.stop()
self.dc_id = e.x
- self.auth_key = Auth(self.dc_id, self.test_mode, self._proxy).create()
+ self.auth_key = await Auth(self.dc_id, self.test_mode, self._proxy).create()
self.session = Session(
self.dc_id,
@@ -352,12 +333,12 @@ def authorize_bot(self):
client=self
)
- self.session.start()
- self.authorize_bot()
+ await self.session.start()
+ await self.authorize_bot()
else:
self.user_id = r.user.id
- def authorize_user(self):
+ async def authorize_user(self):
phone_number_invalid_raises = self.phone_number is not None
phone_code_invalid_raises = self.phone_code is not None
password_hash_invalid_raises = self.password is not None
@@ -378,7 +359,7 @@ def authorize_user(self):
self.phone_number = self.phone_number.strip("+")
try:
- r = self.send(
+ r = await self.send(
functions.auth.SendCode(
self.phone_number,
self.api_id,
@@ -386,10 +367,10 @@ def authorize_user(self):
)
)
except (PhoneMigrate, NetworkMigrate) as e:
- self.session.stop()
+ await self.session.stop()
self.dc_id = e.x
- self.auth_key = Auth(self.dc_id, self.test_mode, self._proxy).create()
+ self.auth_key = await Auth(self.dc_id, self.test_mode, self._proxy).create()
self.session = Session(
self.dc_id,
@@ -399,9 +380,9 @@ def authorize_user(self):
self.api_id,
client=self
)
- self.session.start()
+ await self.session.start()
- r = self.send(
+ r = await self.send(
functions.auth.SendCode(
self.phone_number,
self.api_id,
@@ -430,7 +411,7 @@ def authorize_user(self):
phone_code_hash = r.phone_code_hash
if self.force_sms:
- self.send(
+ await self.send(
functions.auth.ResendCode(
phone_number=self.phone_number,
phone_code_hash=phone_code_hash
@@ -446,7 +427,7 @@ def authorize_user(self):
try:
if phone_registered:
- r = self.send(
+ r = await self.send(
functions.auth.SignIn(
self.phone_number,
phone_code_hash,
@@ -455,7 +436,7 @@ def authorize_user(self):
)
else:
try:
- self.send(
+ await self.send(
functions.auth.SignIn(
self.phone_number,
phone_code_hash,
@@ -468,7 +449,7 @@ def authorize_user(self):
self.first_name = self.first_name if self.first_name is not None else input("First name: ")
self.last_name = self.last_name if self.last_name is not None else input("Last name: ")
- r = self.send(
+ r = await self.send(
functions.auth.SignUp(
self.phone_number,
phone_code_hash,
@@ -491,7 +472,7 @@ def authorize_user(self):
self.first_name = None
except SessionPasswordNeeded as e:
print(e.MESSAGE)
- r = self.send(functions.account.GetPassword())
+ r = await self.send(functions.account.GetPassword())
while True:
try:
@@ -505,7 +486,7 @@ def authorize_user(self):
password_hash = sha256(self.password).digest()
- r = self.send(functions.auth.CheckPassword(password_hash))
+ r = await self.send(functions.auth.CheckPassword(password_hash))
except PasswordHashInvalid as e:
if password_hash_invalid_raises:
raise
@@ -594,12 +575,9 @@ def fetch_peers(self, entities: list):
if username is not None:
self.peers_by_username[username.lower()] = input_peer
- def download_worker(self):
- name = threading.current_thread().name
- log.debug("{} started".format(name))
-
+ async def download_worker(self):
while True:
- media = self.download_queue.get()
+ media = await self.download_queue.get()
if media is None:
break
@@ -666,7 +644,7 @@ def download_worker(self):
extension
)
- temp_file_path = self.get_file(
+ temp_file_path = await self.get_file(
dc_id=dc_id,
id=id,
access_hash=access_hash,
@@ -697,14 +675,11 @@ def download_worker(self):
finally:
done.set()
- log.debug("{} stopped".format(name))
-
- def updates_worker(self):
- name = threading.current_thread().name
- log.debug("{} started".format(name))
+ async def updates_worker(self):
+ log.info("UpdatesWorkerTask started")
while True:
- updates = self.updates_queue.get()
+ updates = await self.updates_queue.get()
if updates is None:
break
@@ -730,9 +705,9 @@ def updates_worker(self):
message = update.message
if not isinstance(message, types.MessageEmpty):
- diff = self.send(
+ diff = await self.send(
functions.updates.GetChannelDifference(
- channel=self.resolve_peer(int("-100" + str(channel_id))),
+ channel=await self.resolve_peer(int("-100" + str(channel_id))),
filter=types.ChannelMessagesFilter(
ranges=[types.MessageRange(
min_id=update.message.id,
@@ -760,9 +735,9 @@ def updates_worker(self):
if len(self.channels_pts[channel_id]) > 50:
self.channels_pts[channel_id] = self.channels_pts[channel_id][25:]
- self.dispatcher.updates.put((update, updates.users, updates.chats))
+ self.dispatcher.updates.put_nowait((update, updates.users, updates.chats))
elif isinstance(updates, (types.UpdateShortMessage, types.UpdateShortChatMessage)):
- diff = self.send(
+ diff = await self.send(
functions.updates.GetDifference(
pts=updates.pts - updates.pts_count,
date=updates.date,
@@ -771,7 +746,7 @@ def updates_worker(self):
)
if diff.new_messages:
- self.dispatcher.updates.put((
+ self.dispatcher.updates.put_nowait((
types.UpdateNewMessage(
message=diff.new_messages[0],
pts=updates.pts,
@@ -781,18 +756,19 @@ def updates_worker(self):
diff.chats
))
else:
- self.dispatcher.updates.put((diff.other_updates[0], [], []))
+ self.dispatcher.updates.put_nowait((diff.other_updates[0], [], []))
elif isinstance(updates, types.UpdateShort):
- self.dispatcher.updates.put((updates.update, [], []))
+ self.dispatcher.updates.put_nowait((updates.update, [], []))
except Exception as e:
log.error(e, exc_info=True)
- log.debug("{} stopped".format(name))
+ log.info("UpdatesWorkerTask stopped")
def signal_handler(self, *args):
+ log.info("Stop signal received ({}). Exiting...".format(args[0]))
self.is_idle = False
- def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)):
+ async def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)):
"""Blocks the program execution until one of the signals are received,
then gently stop the Client by closing the underlying connection.
@@ -807,9 +783,9 @@ def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)):
self.is_idle = True
while self.is_idle:
- time.sleep(1)
+ await asyncio.sleep(1)
- self.stop()
+ await self.stop()
async def send(self, data: Object):
"""Use this method to send Raw Function queries.
@@ -863,14 +839,14 @@ def load_config(self):
self._proxy["username"] = parser.get("proxy", "username", fallback=None) or None
self._proxy["password"] = parser.get("proxy", "password", fallback=None) or None
- def load_session(self):
+ async def load_session(self):
try:
with open(os.path.join(self.workdir, "{}.session".format(self.session_name)), encoding="utf-8") as f:
s = json.load(f)
except FileNotFoundError:
self.dc_id = 1
self.date = 0
- self.auth_key = Auth(self.dc_id, self.test_mode, self._proxy).create()
+ self.auth_key = await Auth(self.dc_id, self.test_mode, self._proxy).create()
else:
self.dc_id = s["dc_id"]
self.test_mode = s["test_mode"]
@@ -912,10 +888,10 @@ def save_session(self):
indent=4
)
- def get_dialogs_chunk(self, offset_date):
+ async def get_dialogs_chunk(self, offset_date):
while True:
try:
- r = self.send(
+ r = await self.send(
functions.messages.GetDialogs(
offset_date, 0, types.InputPeerEmpty(),
self.DIALOGS_AT_ONCE, True
@@ -923,24 +899,24 @@ def get_dialogs_chunk(self, offset_date):
)
except FloodWait as e:
log.warning("get_dialogs flood: waiting {} seconds".format(e.x))
- time.sleep(e.x)
+ await asyncio.sleep(e.x)
else:
log.info("Total peers: {}".format(len(self.peers_by_id)))
return r
- def get_dialogs(self):
- self.send(functions.messages.GetPinnedDialogs())
+ async def get_dialogs(self):
+ await self.send(functions.messages.GetPinnedDialogs())
- dialogs = self.get_dialogs_chunk(0)
+ dialogs = await self.get_dialogs_chunk(0)
offset_date = utils.get_offset_date(dialogs)
while len(dialogs.dialogs) == self.DIALOGS_AT_ONCE:
- dialogs = self.get_dialogs_chunk(offset_date)
+ dialogs = await self.get_dialogs_chunk(offset_date)
offset_date = utils.get_offset_date(dialogs)
- self.get_dialogs_chunk(0)
+ await self.get_dialogs_chunk(0)
- def resolve_peer(self, peer_id: int or str):
+ async def resolve_peer(self, peer_id: int or str):
"""Use this method to get the *InputPeer* of a known *peer_id*.
It is intended to be used when working with Raw Functions (i.e: a Telegram API method you wish to use which is
@@ -968,7 +944,7 @@ def resolve_peer(self, peer_id: int or str):
try:
decoded = base64.b64decode(match.group(1) + "=" * (-len(match.group(1)) % 4), "-_")
- return self.resolve_peer(struct.unpack(">2iq", decoded)[1])
+ return await self.resolve_peer(struct.unpack(">2iq", decoded)[1])
except (AttributeError, binascii.Error, struct.error):
pass
@@ -980,7 +956,7 @@ def resolve_peer(self, peer_id: int or str):
try:
return self.peers_by_username[peer_id]
except KeyError:
- self.send(functions.contacts.ResolveUsername(peer_id))
+ await self.send(functions.contacts.ResolveUsername(peer_id))
return self.peers_by_username[peer_id]
else:
try:
@@ -1007,12 +983,12 @@ def resolve_peer(self, peer_id: int or str):
except (KeyError, ValueError):
raise PeerIdInvalid
- def save_file(self,
- path: str,
- file_id: int = None,
- file_part: int = 0,
- progress: callable = None,
- progress_args: tuple = ()):
+ async def save_file(self,
+ path: str,
+ file_id: int = None,
+ file_part: int = 0,
+ progress: callable = None,
+ progress_args: tuple = ()):
part_size = 512 * 1024
file_size = os.path.getsize(path)
file_total_parts = int(math.ceil(file_size / part_size))
@@ -1022,7 +998,7 @@ def save_file(self,
md5_sum = md5() if not is_big and not is_missing_part else None
session = Session(self.dc_id, self.test_mode, self._proxy, self.auth_key, self.api_id)
- session.start()
+ await session.start()
try:
with open(path, "rb") as f:
@@ -1050,7 +1026,7 @@ def save_file(self,
bytes=chunk
)
- assert self.send(rpc), "Couldn't upload file"
+ assert await session.send(rpc), "Couldn't upload file"
if is_missing_part:
return
@@ -1080,25 +1056,25 @@ def save_file(self,
md5_checksum=md5_sum
)
finally:
- session.stop()
-
- def get_file(self,
- dc_id: int,
- id: int = None,
- access_hash: int = None,
- volume_id: int = None,
- local_id: int = None,
- secret: int = None,
- version: int = 0,
- size: int = None,
- progress: callable = None,
- progress_args: tuple = None) -> str:
- with self.media_sessions_lock:
+ await session.stop()
+
+ async def get_file(self,
+ dc_id: int,
+ id: int = None,
+ access_hash: int = None,
+ volume_id: int = None,
+ local_id: int = None,
+ secret: int = None,
+ version: int = 0,
+ size: int = None,
+ progress: callable = None,
+ progress_args: tuple = None) -> str:
+ with await self.media_sessions_lock:
session = self.media_sessions.get(dc_id, None)
if session is None:
if dc_id != self.dc_id:
- exported_auth = self.send(
+ exported_auth = await self.send(
functions.auth.ExportAuthorization(
dc_id=dc_id
)
@@ -1108,15 +1084,15 @@ def get_file(self,
dc_id,
self.test_mode,
self._proxy,
- Auth(dc_id, self.test_mode, self._proxy).create(),
+ await Auth(dc_id, self.test_mode, self._proxy).create(),
self.api_id
)
- session.start()
+ await session.start()
self.media_sessions[dc_id] = session
- session.send(
+ await session.send(
functions.auth.ImportAuthorization(
id=exported_auth.id,
bytes=exported_auth.bytes
@@ -1131,7 +1107,7 @@ def get_file(self,
self.api_id
)
- session.start()
+ await session.start()
self.media_sessions[dc_id] = session
@@ -1153,7 +1129,7 @@ def get_file(self,
file_name = ""
try:
- r = session.send(
+ r = await session.send(
functions.upload.GetFile(
location=location,
offset=offset,
@@ -1180,7 +1156,7 @@ def get_file(self,
if progress:
progress(self, min(offset, size), size, *progress_args)
- r = session.send(
+ r = await session.send(
functions.upload.GetFile(
location=location,
offset=offset,
@@ -1189,7 +1165,7 @@ def get_file(self,
)
elif isinstance(r, types.upload.FileCdnRedirect):
- with self.media_sessions_lock:
+ with await self.media_sessions_lock:
cdn_session = self.media_sessions.get(r.dc_id, None)
if cdn_session is None:
@@ -1197,12 +1173,12 @@ def get_file(self,
r.dc_id,
self.test_mode,
self._proxy,
- Auth(r.dc_id, self.test_mode, self._proxy).create(),
+ await Auth(r.dc_id, self.test_mode, self._proxy).create(),
self.api_id,
is_cdn=True
)
- cdn_session.start()
+ await cdn_session.start()
self.media_sessions[r.dc_id] = cdn_session
@@ -1211,7 +1187,7 @@ def get_file(self,
file_name = f.name
while True:
- r2 = cdn_session.send(
+ r2 = await cdn_session.send(
functions.upload.GetCdnFile(
file_token=r.file_token,
offset=offset,
@@ -1221,7 +1197,7 @@ def get_file(self,
if isinstance(r2, types.upload.CdnFileReuploadNeeded):
try:
- session.send(
+ await session.send(
functions.upload.ReuploadCdnFile(
file_token=r.file_token,
request_token=r2.request_token
@@ -1244,7 +1220,7 @@ def get_file(self,
)
)
- hashes = session.send(
+ hashes = await session.send(
functions.upload.GetCdnFileHashes(
r.file_token,
offset
From 532ad6bd81346c9eb46bacb3eccc9627465dfe6c Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 21 Jun 2018 18:02:16 +0200
Subject: [PATCH 0042/1185] Fix develop merge issues with asyncio branch
---
pyrogram/client/dispatcher/dispatcher.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py
index 69425c08dc..2b597a72df 100644
--- a/pyrogram/client/dispatcher/dispatcher.py
+++ b/pyrogram/client/dispatcher/dispatcher.py
@@ -182,13 +182,12 @@ async def update_worker(self):
(update.channel_id if is_channel else None)
)
- self.dispatch(
+ await self.dispatch(
pyrogram.Update(
deleted_messages=(messages if not is_channel else None),
deleted_channel_posts=(messages if is_channel else None)
)
)
-
elif isinstance(update, types.UpdateBotCallbackQuery):
await self.dispatch(
pyrogram.Update(
From f5659841c2d8895d1a1117c255d9617254f4bef8 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 21 Jun 2018 20:01:05 +0200
Subject: [PATCH 0043/1185] Reformat files
---
pyrogram/client/handlers/__init__.py | 2 +-
.../client/methods/decorators/__init__.py | 2 +-
.../client/methods/messages/media/send_gif.py | 26 +++++++++----------
3 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/pyrogram/client/handlers/__init__.py b/pyrogram/client/handlers/__init__.py
index d06b2a76c4..0b5058e9c7 100644
--- a/pyrogram/client/handlers/__init__.py
+++ b/pyrogram/client/handlers/__init__.py
@@ -17,7 +17,7 @@
# 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
diff --git a/pyrogram/client/methods/decorators/__init__.py b/pyrogram/client/methods/decorators/__init__.py
index f84a922c72..d45a9ee605 100644
--- a/pyrogram/client/methods/decorators/__init__.py
+++ b/pyrogram/client/methods/decorators/__init__.py
@@ -17,9 +17,9 @@
# 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
diff --git a/pyrogram/client/methods/messages/media/send_gif.py b/pyrogram/client/methods/messages/media/send_gif.py
index bdda234ed9..5c19a19b6a 100644
--- a/pyrogram/client/methods/messages/media/send_gif.py
+++ b/pyrogram/client/methods/messages/media/send_gif.py
@@ -28,19 +28,19 @@
class SendGIF(BaseClient):
async def send_gif(self,
- chat_id: int or str,
- gif: str,
- caption: str = "",
- parse_mode: str = "",
- duration: int = 0,
- width: int = 0,
- height: int = 0,
- thumb: str = None,
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None,
- progress: callable = None,
- progress_args: tuple = ()):
+ chat_id: int or str,
+ gif: str,
+ caption: str = "",
+ parse_mode: str = "",
+ duration: int = 0,
+ width: int = 0,
+ height: int = 0,
+ thumb: str = None,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None,
+ progress: callable = None,
+ progress_args: tuple = ()):
"""Use this method to send GIF files.
Args:
From 5446801c14c8789657c8b9b7fba276a350f34a54 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:39:29 +0200
Subject: [PATCH 0044/1185] Make run() run the event loop
---
pyrogram/client/client.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index ddfc3dc2a5..26b688de25 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -294,8 +294,12 @@ def run(self):
Raises:
:class:`Error `
"""
- self.start()
- self.idle()
+ asyncio.get_event_loop().run_until_complete(
+ asyncio.gather(
+ self.start(),
+ self.idle()
+ )
+ )
def add_handler(self, handler, group: int = 0):
"""Use this method to register an update handler.
From 7ba29065327de11c117af83dc135cd61aaa1c7b5 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 14:31:21 +0200
Subject: [PATCH 0045/1185] Make request_callback_answer async
---
.../client/methods/bots/request_callback_answer.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/pyrogram/client/methods/bots/request_callback_answer.py b/pyrogram/client/methods/bots/request_callback_answer.py
index 5bc31efd34..4ca725924e 100644
--- a/pyrogram/client/methods/bots/request_callback_answer.py
+++ b/pyrogram/client/methods/bots/request_callback_answer.py
@@ -21,10 +21,10 @@
class RequestCallbackAnswer(BaseClient):
- def request_callback_answer(self,
- chat_id: int or str,
- message_id: int,
- callback_data: str):
+ async def request_callback_answer(self,
+ chat_id: int or str,
+ message_id: int,
+ callback_data: str):
"""Use this method to request a callback answer from bots. This is the equivalent of clicking an inline button
containing callback data. The answer contains info useful for clients to display a notification at the top of
the chat screen or as an alert.
@@ -42,7 +42,7 @@ def request_callback_answer(self,
callback_data (``str``):
Callback data associated with the inline button you want to get the answer from.
"""
- return self.send(
+ return await self.send(
functions.messages.GetBotCallbackAnswer(
peer=self.resolve_peer(chat_id),
msg_id=message_id,
From c9cd79cb0566e9f21a9e813e374a96cc606516d2 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 15:49:56 +0200
Subject: [PATCH 0046/1185] Fix merge mess with duplicated idle() methods
---
pyrogram/client/client.py | 30 ++++--------------------------
1 file changed, 4 insertions(+), 26 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 23c2abcc04..2025c52428 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -265,7 +265,7 @@ async def stop(self):
self.is_started = False
await self.session.stop()
- def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)):
+ async def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)):
"""Blocks the program execution until one of the signals are received,
then gently stop the Client by closing the underlying connection.
@@ -275,6 +275,7 @@ def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)):
Defaults to (SIGINT, SIGTERM, SIGABRT).
"""
def signal_handler(*args):
+ log.info("Stop signal received ({}). Exiting...".format(args[0]))
self.is_idle = False
for s in stop_signals:
@@ -283,9 +284,9 @@ def signal_handler(*args):
self.is_idle = True
while self.is_idle:
- time.sleep(1)
+ await asyncio.sleep(1)
- self.stop()
+ await self.stop()
def run(self):
"""Use this method to automatically start and idle a Client.
@@ -800,29 +801,6 @@ async def updates_worker(self):
log.info("UpdatesWorkerTask stopped")
- def signal_handler(self, *args):
- log.info("Stop signal received ({}). Exiting...".format(args[0]))
- self.is_idle = False
-
- async def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)):
- """Blocks the program execution until one of the signals are received,
- then gently stop the Client by closing the underlying connection.
-
- Args:
- stop_signals (``tuple``, *optional*):
- Iterable containing signals the signal handler will listen to.
- Defaults to (SIGINT, SIGTERM, SIGABRT).
- """
- for s in stop_signals:
- signal(s, self.signal_handler)
-
- self.is_idle = True
-
- while self.is_idle:
- await asyncio.sleep(1)
-
- await self.stop()
-
async def send(self, data: Object):
"""Use this method to send Raw Function queries.
From d06097c68abb2a00a9c1b819ecf73c53cbd249eb Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 15:53:56 +0200
Subject: [PATCH 0047/1185] Use uvloop, if available
---
pyrogram/__init__.py | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 531da7229f..f6bd53210a 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
import sys
__copyright__ = "Copyright (C) 2017-2018 Dan Tès ".replace(
@@ -41,3 +42,10 @@
MessageHandler, DeletedMessagesHandler, CallbackQueryHandler,
RawUpdateHandler, DisconnectHandler, Filters
)
+
+try:
+ import uvloop
+except ImportError:
+ pass
+else:
+ asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
From 06cb2a1168da1a7b91dd960723492482c355d5b0 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Jun 2018 16:00:37 +0200
Subject: [PATCH 0048/1185] Move try..except block at the top
---
pyrogram/__init__.py | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index f6bd53210a..298b52c230 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -19,6 +19,13 @@
import asyncio
import sys
+try:
+ import uvloop
+except ImportError:
+ pass
+else:
+ asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
+
__copyright__ = "Copyright (C) 2017-2018 Dan Tès ".replace(
"\xe8",
"e" if sys.getfilesystemencoding() != "utf-8" else "\xe8"
@@ -42,10 +49,3 @@
MessageHandler, DeletedMessagesHandler, CallbackQueryHandler,
RawUpdateHandler, DisconnectHandler, Filters
)
-
-try:
- import uvloop
-except ImportError:
- pass
-else:
- asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
From 5834e38f14162c6ceb25f06106989912a41f7584 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 11:39:50 +0200
Subject: [PATCH 0049/1185] Make run() accept a coroutine
---
pyrogram/client/client.py | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 2025c52428..e60807387e 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -288,19 +288,25 @@ def signal_handler(*args):
await self.stop()
- def run(self):
+ def run(self, coroutine=None):
"""Use this method to automatically start and idle a Client.
- Requires no parameters.
+ If a coroutine is passed as argument this method will start the client, run the coroutine
+ until is complete and then stop the client automatically.
+
+ Args:
+ coroutine: (``Coroutine``, *optional*):
+ Pass a coroutine to run it until is complete.
Raises:
:class:`Error `
"""
- asyncio.get_event_loop().run_until_complete(
- asyncio.gather(
- self.start(),
- self.idle()
- )
- )
+ run = asyncio.get_event_loop().run_until_complete
+
+ run(self.start())
+ run(coroutine or self.idle())
+
+ if coroutine:
+ run(self.stop())
def add_handler(self, handler, group: int = 0):
"""Use this method to register an update handler.
From 81c8fca11c2485257828538e13c51d745ef17bf3 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 24 Jun 2018 11:40:43 +0200
Subject: [PATCH 0050/1185] Make the on_disconnect callback function a
coroutine
---
pyrogram/session/session.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 6479dfdd07..a41ff5fab6 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -197,7 +197,7 @@ async def stop(self):
if self.client and callable(self.client.disconnect_handler):
try:
- self.client.disconnect_handler(self.client)
+ await self.client.disconnect_handler(self.client)
except Exception as e:
log.error(e, exc_info=True)
From 9dff15bd4f364c03fabdc8905e7dd755ecba2c7c Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 26 Jun 2018 13:45:31 +0200
Subject: [PATCH 0051/1185] Make run() accept coroutine functions
---
pyrogram/client/client.py | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 8c34ea2977..61b499a38f 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -20,6 +20,7 @@
import base64
import binascii
import getpass
+import inspect
import json
import logging
import math
@@ -328,11 +329,18 @@ def run(self, coroutine=None):
run = asyncio.get_event_loop().run_until_complete
run(self.start())
- run(coroutine or self.idle())
- if coroutine:
+ run(
+ coroutine if inspect.iscoroutine(coroutine)
+ else coroutine() if coroutine
+ else self.idle()
+ )
+
+ if self.is_started:
run(self.stop())
+ return coroutine
+
def add_handler(self, handler, group: int = 0):
"""Use this method to register an update handler.
From 2f1d44778330218e36a65adeac0241fea86b8327 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 28 Jun 2018 17:50:37 +0200
Subject: [PATCH 0052/1185] Move INITIAL_SALT to Session
---
pyrogram/crypto/mtproto.py | 2 --
pyrogram/session/session.py | 2 +-
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/pyrogram/crypto/mtproto.py b/pyrogram/crypto/mtproto.py
index 1083912663..539976d66e 100644
--- a/pyrogram/crypto/mtproto.py
+++ b/pyrogram/crypto/mtproto.py
@@ -25,8 +25,6 @@
class MTProto:
- INITIAL_SALT = 0x616e67656c696361
-
@staticmethod
def pack(message: Message, salt: int, session_id: bytes, auth_key: bytes, auth_key_id: bytes) -> bytes:
data = Long(salt) + session_id + message.write()
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index ca12c92b28..981e61cda7 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -117,7 +117,7 @@ async def start(self):
self.net_worker_task = asyncio.ensure_future(self.net_worker())
self.recv_task = asyncio.ensure_future(self.recv())
- self.current_salt = FutureSalt(0, 0, MTProto.INITIAL_SALT)
+ self.current_salt = FutureSalt(0, 0, Session.INITIAL_SALT)
self.current_salt = FutureSalt(0, 0, (await self._send(functions.Ping(0))).new_server_salt)
self.current_salt = (await self._send(functions.GetFutureSalts(1))).salts[0]
From 335a2e06c82b83bb38ad5c4d18efbdd8d484e098 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 28 Jun 2018 20:14:38 +0200
Subject: [PATCH 0053/1185] Make delete_profile_photos async
---
pyrogram/client/methods/users/delete_profile_photos.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/methods/users/delete_profile_photos.py b/pyrogram/client/methods/users/delete_profile_photos.py
index 47a6682a26..cbbf3c2078 100644
--- a/pyrogram/client/methods/users/delete_profile_photos.py
+++ b/pyrogram/client/methods/users/delete_profile_photos.py
@@ -24,7 +24,7 @@
class DeleteProfilePhotos(BaseClient):
- def delete_profile_photos(self, id: str or list):
+ async def delete_profile_photos(self, id: str or list):
"""Use this method to delete your own profile photos
Args:
@@ -51,7 +51,7 @@ def delete_profile_photos(self, id: str or list):
)
)
- return bool(self.send(
+ return bool(await self.send(
functions.photos.DeletePhotos(
id=input_photos
)
From 984e989a4b032dc4af6f3da74dd83310bb78f033 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 30 Jun 2018 11:03:55 +0200
Subject: [PATCH 0054/1185] Lock TCP send()
---
pyrogram/connection/transport/tcp/tcp.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/pyrogram/connection/transport/tcp/tcp.py b/pyrogram/connection/transport/tcp/tcp.py
index f541153eaa..7ca479a5d5 100644
--- a/pyrogram/connection/transport/tcp/tcp.py
+++ b/pyrogram/connection/transport/tcp/tcp.py
@@ -39,6 +39,8 @@ class TCP:
def __init__(self, proxy: dict):
self.proxy = proxy
+ self.lock = asyncio.Lock()
+
self.socket = socks.socksocket()
self.reader = None # type: asyncio.StreamReader
self.writer = None # type: asyncio.StreamWriter
@@ -76,8 +78,9 @@ def close(self):
self.socket.close()
async def send(self, data: bytes):
- self.writer.write(data)
- await self.writer.drain()
+ with await self.lock:
+ self.writer.write(data)
+ await self.writer.drain()
async def recv(self, length: int = 0):
data = b""
From aa800c3ebc671d492376f9428da7674f2d9adb3f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 30 Jun 2018 11:04:17 +0200
Subject: [PATCH 0055/1185] Reformat code
---
pyrogram/connection/transport/tcp/tcp.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pyrogram/connection/transport/tcp/tcp.py b/pyrogram/connection/transport/tcp/tcp.py
index 7ca479a5d5..062f1d2b20 100644
--- a/pyrogram/connection/transport/tcp/tcp.py
+++ b/pyrogram/connection/transport/tcp/tcp.py
@@ -42,10 +42,11 @@ def __init__(self, proxy: dict):
self.lock = asyncio.Lock()
self.socket = socks.socksocket()
+ self.socket.settimeout(TCP.TIMEOUT)
+
self.reader = None # type: asyncio.StreamReader
self.writer = None # type: asyncio.StreamWriter
- self.socket.settimeout(TCP.TIMEOUT)
self.proxy_enabled = proxy.get("enabled", False)
if proxy and self.proxy_enabled:
From d28f795acaa05a88eb0c713dc5dad689af8ff0e8 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 30 Jun 2018 11:26:45 +0200
Subject: [PATCH 0056/1185] Make save_file more efficient
---
pyrogram/client/client.py | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 39a91db34b..c4fc7e3a77 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -1070,6 +1070,15 @@ async def save_file(self,
file_part: int = 0,
progress: callable = None,
progress_args: tuple = ()):
+ async def worker():
+ while True:
+ data = await queue.get()
+
+ if data is None:
+ return
+
+ await asyncio.ensure_future(session.send(data))
+
part_size = 512 * 1024
file_size = os.path.getsize(path)
file_total_parts = int(math.ceil(file_size / part_size))
@@ -1077,11 +1086,13 @@ async def save_file(self,
is_missing_part = True if file_id is not None else False
file_id = file_id or self.rnd_id()
md5_sum = md5() if not is_big and not is_missing_part else None
-
session = Session(self, self.dc_id, self.auth_key, is_media=True)
- await session.start()
+ workers = [asyncio.ensure_future(worker()) for _ in range(4)]
+ queue = asyncio.Queue(16)
try:
+ await session.start()
+
with open(path, "rb") as f:
f.seek(part_size * file_part)
@@ -1107,7 +1118,7 @@ async def save_file(self,
bytes=chunk
)
- assert await session.send(rpc), "Couldn't upload file"
+ await queue.put(rpc)
if is_missing_part:
return
@@ -1137,6 +1148,10 @@ async def save_file(self,
md5_checksum=md5_sum
)
finally:
+ for _ in workers:
+ await queue.put(None)
+
+ await asyncio.gather(*workers)
await session.stop()
async def get_file(self,
From b49030eb10b8a2fc7c737683e53f29c115591f23 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 30 Jun 2018 11:30:32 +0200
Subject: [PATCH 0057/1185] Shorter conditions
---
pyrogram/client/client.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index c4fc7e3a77..cee391410f 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -1082,8 +1082,8 @@ async def worker():
part_size = 512 * 1024
file_size = os.path.getsize(path)
file_total_parts = int(math.ceil(file_size / part_size))
- is_big = True if file_size > 10 * 1024 * 1024 else False
- is_missing_part = True if file_id is not None else False
+ is_big = file_size > 10 * 1024 * 1024
+ is_missing_part = file_id is not None
file_id = file_id or self.rnd_id()
md5_sum = md5() if not is_big and not is_missing_part else None
session = Session(self, self.dc_id, self.auth_key, is_media=True)
From 26bb97af466748764e76e59198302037e7ec3236 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 2 Jul 2018 14:10:26 +0200
Subject: [PATCH 0058/1185] Add ainput function
---
pyrogram/client/ext/utils.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index be4848238c..3a27594221 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -16,9 +16,12 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
import logging
+import sys
import time
from base64 import b64decode, b64encode
+from concurrent.futures.thread import ThreadPoolExecutor
from struct import pack
from weakref import proxy
@@ -57,6 +60,13 @@ def html(self):
return self._client.html.unparse(self, self._entities)
+async def ainput(prompt: str = ""):
+ with ThreadPoolExecutor(1, "AsyncInput", lambda x: print(x, end="", flush=True), (prompt,)) as executor:
+ return (await asyncio.get_event_loop().run_in_executor(
+ executor, sys.stdin.readline
+ )).rstrip()
+
+
ENTITIES = {
types.MessageEntityMention.ID: "mention",
types.MessageEntityHashtag.ID: "hashtag",
From af5c5d20cff97cf1fe3594794880db1354a5f967 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 2 Jul 2018 14:10:48 +0200
Subject: [PATCH 0059/1185] Replace input() with ainput() in Client
---
pyrogram/client/client.py | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 867cd3f6df..fb14d37949 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -48,6 +48,7 @@
from pyrogram.session import Auth, Session
from .dispatcher import Dispatcher
from .ext import BaseClient, Syncer, utils
+from .ext.utils import ainput
from .handlers import DisconnectHandler
from .methods import Methods
@@ -413,15 +414,15 @@ async def authorize_user(self):
while True:
if self.phone_number is None:
- self.phone_number = input("Enter phone number: ")
+ self.phone_number = await ainput("Enter phone number: ")
while True:
- confirm = input("Is \"{}\" correct? (y/n): ".format(self.phone_number))
+ confirm = await ainput("Is \"{}\" correct? (y/n): ".format(self.phone_number))
if confirm in ("y", "1"):
break
elif confirm in ("n", "2"):
- self.phone_number = input("Enter phone number: ")
+ self.phone_number = await ainput("Enter phone number: ")
self.phone_number = self.phone_number.strip("+")
@@ -488,7 +489,7 @@ async def authorize_user(self):
while True:
self.phone_code = (
- input("Enter phone code: ") if self.phone_code is None
+ await ainput("Enter phone code: ") if self.phone_code is None
else self.phone_code if type(self.phone_code) is str
else str(self.phone_code(self.phone_number))
)
@@ -514,8 +515,8 @@ async def authorize_user(self):
except PhoneNumberUnoccupied:
pass
- self.first_name = self.first_name if self.first_name is not None else input("First name: ")
- self.last_name = self.last_name if self.last_name is not None else input("Last name: ")
+ self.first_name = self.first_name if self.first_name is not None else await ainput("First name: ")
+ self.last_name = self.last_name if self.last_name is not None else await ainput("Last name: ")
r = await self.send(
functions.auth.SignUp(
From ed562edb9f93155a6bd5de3351c12a371871e2a9 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 2 Jul 2018 14:11:02 +0200
Subject: [PATCH 0060/1185] Fix send AcceptTermsOfService not being awaited
---
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 fb14d37949..e56a023321 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -585,7 +585,7 @@ async def authorize_user(self):
break
if terms_of_service:
- assert self.send(functions.help.AcceptTermsOfService(terms_of_service.id))
+ assert await self.send(functions.help.AcceptTermsOfService(terms_of_service.id))
self.password = None
self.user_id = r.user.id
From ec82b4f994aa955e209efb69f19efc4c197e5e52 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 2 Jul 2018 17:21:42 +0200
Subject: [PATCH 0061/1185] Don't use getpass anymore (for now) The reason is
that getpass is blocking. Let's use ainput() until a proper way of reading
from stdin without echoing is found.
---
pyrogram/client/client.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index e56a023321..6ab9b17a1b 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -19,7 +19,6 @@
import asyncio
import base64
import binascii
-import getpass
import inspect
import json
import logging
@@ -548,7 +547,7 @@ async def authorize_user(self):
if self.password is None:
print("Hint: {}".format(r.hint))
- self.password = getpass.getpass("Enter password: ")
+ self.password = await ainput("Enter password: ")
if type(self.password) is str:
self.password = r.current_salt + self.password.encode() + r.current_salt
From f4c583664a5a28fa7cc81f35301943197745473a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 2 Jul 2018 19:14:30 +0200
Subject: [PATCH 0062/1185] Remove unsupported arguments for Python <3.7
---
pyrogram/client/ext/utils.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 3a27594221..5161d3703b 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -61,7 +61,9 @@ def html(self):
async def ainput(prompt: str = ""):
- with ThreadPoolExecutor(1, "AsyncInput", lambda x: print(x, end="", flush=True), (prompt,)) as executor:
+ print(prompt, end="", flush=True)
+
+ with ThreadPoolExecutor(1, "AsyncInput") as executor:
return (await asyncio.get_event_loop().run_in_executor(
executor, sys.stdin.readline
)).rstrip()
From 219988740c2b5e0a4ff8fd265745062053efd30d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 2 Jul 2018 19:16:01 +0200
Subject: [PATCH 0063/1185] Remove unsupported argument for Python <3.6
---
pyrogram/client/ext/utils.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 5161d3703b..ae3a976333 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -63,7 +63,7 @@ def html(self):
async def ainput(prompt: str = ""):
print(prompt, end="", flush=True)
- with ThreadPoolExecutor(1, "AsyncInput") as executor:
+ with ThreadPoolExecutor(1) as executor:
return (await asyncio.get_event_loop().run_in_executor(
executor, sys.stdin.readline
)).rstrip()
From dc7c9af826498cdbefb7eba4d7e04de279ae6f45 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 2 Jul 2018 20:47:45 +0200
Subject: [PATCH 0064/1185] Set v0.8.0dev1 for the asyncio branch This way
people can easily tell whether they are running the correct branch or not
(pip is misbehaving lately and installations from git don't replace files).
---
pyrogram/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 5122cab9f4..635ec3751c 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -31,7 +31,7 @@
"e" if sys.getfilesystemencoding() != "utf-8" else "\xe8"
)
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
-__version__ = "0.7.5"
+__version__ = "0.8.0dev1"
from .api.errors import Error
from .client.types import (
From f6886bd0e4a2bfb82fe7f7ee17e811445e4bc57d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 3 Jul 2018 16:34:55 +0200
Subject: [PATCH 0065/1185] Further improve save_file
---
pyrogram/client/client.py | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 6ab9b17a1b..8ea4b62963 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -1072,14 +1072,17 @@ async def save_file(self,
file_part: int = 0,
progress: callable = None,
progress_args: tuple = ()):
- async def worker():
+ async def worker(session):
while True:
data = await queue.get()
if data is None:
return
- await asyncio.ensure_future(session.send(data))
+ try:
+ await asyncio.ensure_future(session.send(data))
+ except Exception as e:
+ log.error(e)
part_size = 512 * 1024
file_size = os.path.getsize(path)
@@ -1088,12 +1091,13 @@ async def worker():
is_missing_part = file_id is not None
file_id = file_id or self.rnd_id()
md5_sum = md5() if not is_big and not is_missing_part else None
- session = Session(self, self.dc_id, self.auth_key, is_media=True)
- workers = [asyncio.ensure_future(worker()) for _ in range(4)]
+ pool = [Session(self, self.dc_id, self.auth_key, is_media=True) for _ in range(3)]
+ workers = [asyncio.ensure_future(worker(session)) for session in pool for _ in range(4)]
queue = asyncio.Queue(16)
try:
- await session.start()
+ for session in pool:
+ await session.start()
with open(path, "rb") as f:
f.seek(part_size * file_part)
@@ -1154,7 +1158,9 @@ async def worker():
await queue.put(None)
await asyncio.gather(*workers)
- await session.stop()
+
+ for session in pool:
+ await session.stop()
async def get_file(self,
dc_id: int,
From f2d64b25737866bb4d52e1baf2b62cea5c0d639f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 5 Jul 2018 15:06:25 +0200
Subject: [PATCH 0066/1185] Make get_dialogs async
---
pyrogram/client/methods/messages/get_dialogs.py | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/pyrogram/client/methods/messages/get_dialogs.py b/pyrogram/client/methods/messages/get_dialogs.py
index f43ca6a517..d8f470599e 100644
--- a/pyrogram/client/methods/messages/get_dialogs.py
+++ b/pyrogram/client/methods/messages/get_dialogs.py
@@ -24,12 +24,12 @@
class GetDialogs(BaseClient):
# TODO docstrings
- def get_dialogs(self,
- limit: int = 100,
- pinned_only: bool = False,
- last_chunk=None):
+ async def get_dialogs(self,
+ limit: int = 100,
+ pinned_only: bool = False,
+ last_chunk=None):
if pinned_only:
- r = self.send(functions.messages.GetPinnedDialogs())
+ r = await self.send(functions.messages.GetPinnedDialogs())
else:
offset_date = 0
@@ -44,7 +44,7 @@ def get_dialogs(self,
offset_date = message_date
break
- r = self.send(
+ r = await self.send(
functions.messages.GetDialogs(
offset_date=offset_date,
offset_id=0,
@@ -72,7 +72,7 @@ def get_dialogs(self,
else:
chat_id = int("-100" + str(to_id.channel_id))
- messages[chat_id] = utils.parse_messages(self, message, users, chats)
+ messages[chat_id] = await utils.parse_messages(self, message, users, chats)
dialogs = []
From ccd651f1fcd7d42070d062112827423e29f307b4 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 17 Jul 2018 08:28:28 +0200
Subject: [PATCH 0067/1185] Make the new methods async
---
.../client/methods/chats/delete_chat_photo.py | 8 ++++----
.../client/methods/chats/get_chat_members.py | 18 +++++++++---------
.../client/methods/chats/pin_chat_message.py | 6 +++---
.../methods/chats/set_chat_description.py | 6 +++---
.../client/methods/chats/set_chat_photo.py | 8 ++++----
.../client/methods/chats/set_chat_title.py | 8 ++++----
.../client/methods/chats/unpin_chat_message.py | 6 +++---
pyrogram/client/types/message.py | 4 ++--
8 files changed, 32 insertions(+), 32 deletions(-)
diff --git a/pyrogram/client/methods/chats/delete_chat_photo.py b/pyrogram/client/methods/chats/delete_chat_photo.py
index 57d90b1126..d8eff6a4f8 100644
--- a/pyrogram/client/methods/chats/delete_chat_photo.py
+++ b/pyrogram/client/methods/chats/delete_chat_photo.py
@@ -21,7 +21,7 @@
class DeleteChatPhoto(BaseClient):
- def delete_chat_photo(self, chat_id: int or str):
+ async def delete_chat_photo(self, chat_id: int or str):
"""Use this method to delete a chat photo.
Photos can't be changed for private chats.
You must be an administrator in the chat for this to work and must have the appropriate admin rights.
@@ -42,17 +42,17 @@ def delete_chat_photo(self, chat_id: int or str):
:class:`Error `
``ValueError``: If a chat_id belongs to user.
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChat):
- self.send(
+ await self.send(
functions.messages.EditChatPhoto(
chat_id=peer.chat_id,
photo=types.InputChatPhotoEmpty()
)
)
elif isinstance(peer, types.InputPeerChannel):
- self.send(
+ await self.send(
functions.channels.EditPhoto(
channel=peer,
photo=types.InputChatPhotoEmpty()
diff --git a/pyrogram/client/methods/chats/get_chat_members.py b/pyrogram/client/methods/chats/get_chat_members.py
index a851ef584e..295a32c552 100644
--- a/pyrogram/client/methods/chats/get_chat_members.py
+++ b/pyrogram/client/methods/chats/get_chat_members.py
@@ -30,17 +30,17 @@ class Filters:
class GetChatMembers(BaseClient):
- def get_chat_members(self,
- chat_id: int or str,
- offset: int = 0,
- limit: int = 200,
- query: str = "",
- filter: str = Filters.ALL):
- peer = self.resolve_peer(chat_id)
+ async def get_chat_members(self,
+ chat_id: int or str,
+ offset: int = 0,
+ limit: int = 200,
+ query: str = "",
+ filter: str = Filters.ALL):
+ peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChat):
return utils.parse_chat_members(
- self.send(
+ await self.send(
functions.messages.GetFullChat(
peer.chat_id
)
@@ -65,7 +65,7 @@ def get_chat_members(self,
raise ValueError("Invalid filter \"{}\"".format(filter))
return utils.parse_chat_members(
- self.send(
+ await self.send(
functions.channels.GetParticipants(
channel=peer,
filter=filter,
diff --git a/pyrogram/client/methods/chats/pin_chat_message.py b/pyrogram/client/methods/chats/pin_chat_message.py
index e9bc533e6e..9e6f49c954 100644
--- a/pyrogram/client/methods/chats/pin_chat_message.py
+++ b/pyrogram/client/methods/chats/pin_chat_message.py
@@ -21,7 +21,7 @@
class PinChatMessage(BaseClient):
- def pin_chat_message(self, chat_id: int or str, message_id: int, disable_notification: bool = None):
+ async def pin_chat_message(self, chat_id: int or str, message_id: int, disable_notification: bool = None):
"""Use this method to pin a message in a supergroup or a channel.
You must be an administrator in the chat for this to work and must have the "can_pin_messages" admin right in
the supergroup or "can_edit_messages" admin right in the channel.
@@ -45,10 +45,10 @@ def pin_chat_message(self, chat_id: int or str, message_id: int, disable_notific
:class:`Error `
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChannel):
- self.send(
+ await self.send(
functions.channels.UpdatePinnedMessage(
channel=peer,
id=message_id,
diff --git a/pyrogram/client/methods/chats/set_chat_description.py b/pyrogram/client/methods/chats/set_chat_description.py
index c9597a62e7..8f647818ac 100644
--- a/pyrogram/client/methods/chats/set_chat_description.py
+++ b/pyrogram/client/methods/chats/set_chat_description.py
@@ -21,7 +21,7 @@
class SetChatDescription(BaseClient):
- def set_chat_description(self, chat_id: int or str, description: str):
+ async def set_chat_description(self, chat_id: int or str, description: str):
"""Use this method to change the description of a supergroup or a channel.
You must be an administrator in the chat for this to work and must have the appropriate admin rights.
@@ -40,10 +40,10 @@ def set_chat_description(self, chat_id: int or str, description: str):
:class:`Error `
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChannel):
- self.send(
+ await self.send(
functions.channels.EditAbout(
channel=peer,
about=description
diff --git a/pyrogram/client/methods/chats/set_chat_photo.py b/pyrogram/client/methods/chats/set_chat_photo.py
index d98fefde44..558671b725 100644
--- a/pyrogram/client/methods/chats/set_chat_photo.py
+++ b/pyrogram/client/methods/chats/set_chat_photo.py
@@ -25,7 +25,7 @@
class SetChatPhoto(BaseClient):
- def set_chat_photo(self, chat_id: int or str, photo: str):
+ async def set_chat_photo(self, chat_id: int or str, photo: str):
"""Use this method to set a new profile photo for the chat.
Photos can't be changed for private chats.
You must be an administrator in the chat for this to work and must have the appropriate admin rights.
@@ -49,7 +49,7 @@ def set_chat_photo(self, chat_id: int or str, photo: str):
:class:`Error `
``ValueError``: If a chat_id belongs to user.
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
if os.path.exists(photo):
photo = types.InputChatUploadedPhoto(file=self.save_file(photo))
@@ -64,14 +64,14 @@ def set_chat_photo(self, chat_id: int or str, photo: str):
)
if isinstance(peer, types.InputPeerChat):
- self.send(
+ await self.send(
functions.messages.EditChatPhoto(
chat_id=peer.chat_id,
photo=photo
)
)
elif isinstance(peer, types.InputPeerChannel):
- self.send(
+ await self.send(
functions.channels.EditPhoto(
channel=peer,
photo=photo
diff --git a/pyrogram/client/methods/chats/set_chat_title.py b/pyrogram/client/methods/chats/set_chat_title.py
index f6644a01ca..2769ccb92b 100644
--- a/pyrogram/client/methods/chats/set_chat_title.py
+++ b/pyrogram/client/methods/chats/set_chat_title.py
@@ -21,7 +21,7 @@
class SetChatTitle(BaseClient):
- def set_chat_title(self, chat_id: int or str, title: str):
+ async def set_chat_title(self, chat_id: int or str, title: str):
"""Use this method to change the title of a chat.
Titles can't be changed for private chats.
You must be an administrator in the chat for this to work and must have the appropriate admin rights.
@@ -45,17 +45,17 @@ def set_chat_title(self, chat_id: int or str, title: str):
:class:`Error `
``ValueError``: If a chat_id belongs to user.
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChat):
- self.send(
+ await self.send(
functions.messages.EditChatTitle(
chat_id=peer.chat_id,
title=title
)
)
elif isinstance(peer, types.InputPeerChannel):
- self.send(
+ await self.send(
functions.channels.EditTitle(
channel=peer,
title=title
diff --git a/pyrogram/client/methods/chats/unpin_chat_message.py b/pyrogram/client/methods/chats/unpin_chat_message.py
index b1eeec793d..9b6b414468 100644
--- a/pyrogram/client/methods/chats/unpin_chat_message.py
+++ b/pyrogram/client/methods/chats/unpin_chat_message.py
@@ -21,7 +21,7 @@
class UnpinChatMessage(BaseClient):
- def unpin_chat_message(self, chat_id: int or str):
+ async def unpin_chat_message(self, chat_id: int or str):
"""Use this method to unpin a message in a supergroup or a channel.
You must be an administrator in the chat for this to work and must have the "can_pin_messages" admin
right in the supergroup or "can_edit_messages" admin right in the channel.
@@ -38,10 +38,10 @@ def unpin_chat_message(self, chat_id: int or str):
:class:`Error `
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChannel):
- self.send(
+ await self.send(
functions.channels.UpdatePinnedMessage(
channel=peer,
id=0
diff --git a/pyrogram/client/types/message.py b/pyrogram/client/types/message.py
index c913732865..51de2a6fb2 100644
--- a/pyrogram/client/types/message.py
+++ b/pyrogram/client/types/message.py
@@ -572,7 +572,7 @@ async def click(self, x: int or str, y: int = None, quote: bool = None):
else:
raise ValueError("The message doesn't contain any keyboard")
- def download(self, file_name: str = "", block: bool = True):
+ async def download(self, file_name: str = "", block: bool = True):
"""Use this method as a shortcut for:
.. code-block:: python
@@ -602,7 +602,7 @@ def download(self, file_name: str = "", block: bool = True):
:class:`Error `
``ValueError``: If the message doesn't contain any downloadable media
"""
- return self._client.download_media(
+ return await self._client.download_media(
message=self,
file_name=file_name,
block=block
From c3cf924ddd8017d2aff8c729b4207922459cf5e1 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 22 Aug 2018 10:32:57 +0200
Subject: [PATCH 0068/1185] Fix small merge issues
---
pyrogram/client/methods/chats/get_dialogs.py | 8 ++---
.../client/methods/messages/send_animation.py | 30 +++++++++----------
2 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/pyrogram/client/methods/chats/get_dialogs.py b/pyrogram/client/methods/chats/get_dialogs.py
index 8d9ad00f54..13d4678782 100644
--- a/pyrogram/client/methods/chats/get_dialogs.py
+++ b/pyrogram/client/methods/chats/get_dialogs.py
@@ -22,10 +22,10 @@
class GetDialogs(BaseClient):
- def get_dialogs(self,
- offset_dialogs=None,
- limit: int = 100,
- pinned_only: bool = False):
+ async def get_dialogs(self,
+ offset_dialogs=None,
+ limit: int = 100,
+ pinned_only: bool = False):
"""Use this method to get the user's dialogs
You can get up to 100 dialogs at once.
diff --git a/pyrogram/client/methods/messages/send_animation.py b/pyrogram/client/methods/messages/send_animation.py
index ba68c77b96..bd9cd0fde3 100644
--- a/pyrogram/client/methods/messages/send_animation.py
+++ b/pyrogram/client/methods/messages/send_animation.py
@@ -27,21 +27,21 @@
class SendAnimation(BaseClient):
- asyncdef send_animation(self,
- chat_id: int or str,
- animation: str,
- caption: str = "",
- parse_mode: str = "",
- duration: int = 0,
- width: int = 0,
- height: int = 0,
- thumb: str = None,
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup=None,
- progress: callable = None,
- progress_args: tuple = ()):
- """Use this method to send animation files(animation or H.264/MPEG-4 AVC video without sound).
+ async def send_animation(self,
+ chat_id: int or str,
+ animation: str,
+ caption: str = "",
+ parse_mode: str = "",
+ duration: int = 0,
+ width: int = 0,
+ height: int = 0,
+ thumb: str = None,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup=None,
+ progress: callable = None,
+ progress_args: tuple = ()):
+ """Use this method to send animation files (animation or H.264/MPEG-4 AVC video without sound).
Args:
chat_id (``int`` | ``str``):
From aaaba4b84798e5afc69cc9d956058601e8183bcf Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 23 Aug 2018 20:43:46 +0200
Subject: [PATCH 0069/1185] Update async branch version
---
pyrogram/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 02170ab9ec..ee6372688f 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -31,7 +31,7 @@
"e" if sys.getfilesystemencoding() != "utf-8" else "\xe8"
)
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
-__version__ = "0.8.0dev1"
+__version__ = "0.8.0async1"
from .api.errors import Error
from .client.types import (
From 4f9b38765e0c820b7bfd38e8731a4e2c6280b1fd Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 23 Aug 2018 21:07:19 +0200
Subject: [PATCH 0070/1185] Add missing async/await keywords
---
.../client/methods/chats/get_chat_member.py | 10 +++---
.../methods/messages/edit_message_media.py | 32 +++++++++----------
2 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/pyrogram/client/methods/chats/get_chat_member.py b/pyrogram/client/methods/chats/get_chat_member.py
index 51e07f9199..bd43808f23 100644
--- a/pyrogram/client/methods/chats/get_chat_member.py
+++ b/pyrogram/client/methods/chats/get_chat_member.py
@@ -21,7 +21,7 @@
class GetChatMember(BaseClient):
- def get_chat_member(self,
+ async def get_chat_member(self,
chat_id: int or str,
user_id: int or str):
"""Use this method to get information about one member of a chat.
@@ -41,11 +41,11 @@ def get_chat_member(self,
Raises:
:class:`Error `
"""
- chat_id = self.resolve_peer(chat_id)
- user_id = self.resolve_peer(user_id)
+ chat_id = await self.resolve_peer(chat_id)
+ user_id = await self.resolve_peer(user_id)
if isinstance(chat_id, types.InputPeerChat):
- full_chat = self.send(
+ full_chat = await self.send(
functions.messages.GetFullChat(
chat_id=chat_id.chat_id
)
@@ -57,7 +57,7 @@ def get_chat_member(self,
else:
raise errors.UserNotParticipant
elif isinstance(chat_id, types.InputPeerChannel):
- r = self.send(
+ r = await self.send(
functions.channels.GetParticipant(
channel=chat_id,
user_id=user_id
diff --git a/pyrogram/client/methods/messages/edit_message_media.py b/pyrogram/client/methods/messages/edit_message_media.py
index 086d8dc21d..5993f1c992 100644
--- a/pyrogram/client/methods/messages/edit_message_media.py
+++ b/pyrogram/client/methods/messages/edit_message_media.py
@@ -31,7 +31,7 @@
class EditMessageMedia(BaseClient):
- def edit_message_media(self,
+ async def edit_message_media(self,
chat_id: int or str,
message_id: int,
media,
@@ -41,11 +41,11 @@ def edit_message_media(self,
if isinstance(media, InputMediaPhoto):
if os.path.exists(media.media):
- media = self.send(
+ media = await self.send(
functions.messages.UploadMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=types.InputMediaUploadedPhoto(
- file=self.save_file(media.media)
+ file=await self.save_file(media.media)
)
)
)
@@ -85,12 +85,12 @@ def edit_message_media(self,
if isinstance(media, InputMediaVideo):
if os.path.exists(media.media):
- media = self.send(
+ media = await self.send(
functions.messages.UploadMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map[".mp4"],
- file=self.save_file(media.media),
+ file=await self.save_file(media.media),
attributes=[
types.DocumentAttributeVideo(
supports_streaming=media.supports_streaming or None,
@@ -139,12 +139,12 @@ def edit_message_media(self,
if isinstance(media, InputMediaAudio):
if os.path.exists(media.media):
- media = self.send(
+ media = await self.send(
functions.messages.UploadMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map.get("." + media.media.split(".")[-1], "audio/mpeg"),
- file=self.save_file(media.media),
+ file=await self.save_file(media.media),
attributes=[
types.DocumentAttributeAudio(
duration=media.duration,
@@ -192,12 +192,12 @@ def edit_message_media(self,
if isinstance(media, InputMediaAnimation):
if os.path.exists(media.media):
- media = self.send(
+ media = await self.send(
functions.messages.UploadMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map[".mp4"],
- file=self.save_file(media.media),
+ file=await self.save_file(media.media),
attributes=[
types.DocumentAttributeVideo(
supports_streaming=True,
@@ -245,9 +245,9 @@ def edit_message_media(self,
)
)
- r = self.send(
+ r = await self.send(
functions.messages.EditMessage(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
id=message_id,
reply_markup=reply_markup.write() if reply_markup else None,
media=media,
@@ -257,7 +257,7 @@ def edit_message_media(self,
for i in r.updates:
if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
- return utils.parse_messages(
+ return await utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
From 38442bf3c1acf418dc2030c4996cd95aae0bd89d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 7 Sep 2018 00:41:01 +0200
Subject: [PATCH 0071/1185] Add missing await
---
pyrogram/session/session.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index 34e892e01d..fb3b559400 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -147,7 +147,7 @@ async def start(self):
log.info("System: {} ({})".format(self.client.system_version, self.client.lang_code.upper()))
except AuthKeyDuplicated as e:
- self.stop()
+ await self.stop()
raise e
except (OSError, TimeoutError, Error):
await self.stop()
From 45a32ddd8894c3c7efad6070024c52ff8cce6566 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 7 Sep 2018 00:42:45 +0200
Subject: [PATCH 0072/1185] Remove old commented code on session.py
---
pyrogram/session/session.py | 399 ------------------------------------
1 file changed, 399 deletions(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index fb3b559400..fcd8f8e173 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -401,402 +401,3 @@ async def send(self, data: Object, retries: int = MAX_RETRIES, timeout: float =
await asyncio.sleep(0.5)
return await self.send(data, retries - 1, timeout)
-
-# class Result:
-# def __init__(self):
-# self.value = None
-# self.event = Event()
-#
-#
-# class Session:
-# VERSION = __version__
-# APP_VERSION = "Pyrogram \U0001f525 {}".format(VERSION)
-#
-# DEVICE_MODEL = "{} {}".format(
-# platform.python_implementation(),
-# platform.python_version()
-# )
-#
-# SYSTEM_VERSION = "{} {}".format(
-# platform.system(),
-# platform.release()
-# )
-#
-# INITIAL_SALT = 0x616e67656c696361
-# NET_WORKERS = 1
-# WAIT_TIMEOUT = 15
-# MAX_RETRIES = 5
-# ACKS_THRESHOLD = 8
-# PING_INTERVAL = 5
-#
-# notice_displayed = False
-#
-# BAD_MSG_DESCRIPTION = {
-# 16: "[16] msg_id too low, the client time has to be synchronized",
-# 17: "[17] msg_id too high, the client time has to be synchronized",
-# 18: "[18] incorrect two lower order msg_id bits, the server expects client message msg_id to be divisible by 4",
-# 19: "[19] container msg_id is the same as msg_id of a previously received message",
-# 20: "[20] message too old, it cannot be verified by the server",
-# 32: "[32] msg_seqno too low",
-# 33: "[33] msg_seqno too high",
-# 34: "[34] an even msg_seqno expected, but odd received",
-# 35: "[35] odd msg_seqno expected, but even received",
-# 48: "[48] incorrect server salt",
-# 64: "[64] invalid container"
-# }
-#
-# def __init__(self,
-# dc_id: int,
-# test_mode: bool,
-# proxy: dict,
-# auth_key: bytes,
-# api_id: int,
-# is_cdn: bool = False,
-# client: pyrogram = None):
-# if not Session.notice_displayed:
-# print("Pyrogram v{}, {}".format(__version__, __copyright__))
-# print("Licensed under the terms of the " + __license__, end="\n\n")
-# Session.notice_displayed = True
-#
-# self.dc_id = dc_id
-# self.test_mode = test_mode
-# self.proxy = proxy
-# self.api_id = api_id
-# self.is_cdn = is_cdn
-# self.client = client
-#
-# self.connection = None
-#
-# self.auth_key = auth_key
-# self.auth_key_id = sha1(auth_key).digest()[-8:]
-#
-# self.session_id = Long(MsgId())
-# self.msg_factory = MsgFactory()
-#
-# self.current_salt = None
-#
-# self.pending_acks = set()
-#
-# self.recv_queue = Queue()
-# self.results = {}
-#
-# self.ping_thread = None
-# self.ping_thread_event = Event()
-#
-# self.next_salt_thread = None
-# self.next_salt_thread_event = Event()
-#
-# self.net_worker_list = []
-#
-# self.is_connected = Event()
-#
-# def start(self):
-# while True:
-# self.connection = Connection(DataCenter(self.dc_id, self.test_mode), self.proxy)
-#
-# try:
-# self.connection.connect()
-#
-# for i in range(self.NET_WORKERS):
-# self.net_worker_list.append(
-# Thread(
-# target=self.net_worker,
-# name="NetWorker#{}".format(i + 1)
-# )
-# )
-#
-# self.net_worker_list[-1].start()
-#
-# Thread(target=self.recv, name="RecvThread").start()
-#
-# self.current_salt = FutureSalt(0, 0, self.INITIAL_SALT)
-# self.current_salt = FutureSalt(0, 0, self._send(functions.Ping(0)).new_server_salt)
-# self.current_salt = self._send(functions.GetFutureSalts(1)).salts[0]
-#
-# self.next_salt_thread = Thread(target=self.next_salt, name="NextSaltThread")
-# self.next_salt_thread.start()
-#
-# if not self.is_cdn:
-# self._send(
-# functions.InvokeWithLayer(
-# layer,
-# functions.InitConnection(
-# self.api_id,
-# self.DEVICE_MODEL,
-# self.SYSTEM_VERSION,
-# self.APP_VERSION,
-# "en", "", "en",
-# functions.help.GetConfig(),
-# )
-# )
-# )
-#
-# self.ping_thread = Thread(target=self.ping, name="PingThread")
-# self.ping_thread.start()
-#
-# log.info("Connection inited: Layer {}".format(layer))
-# except (OSError, TimeoutError, Error):
-# self.stop()
-# except Exception as e:
-# self.stop()
-# raise e
-# else:
-# break
-#
-# self.is_connected.set()
-#
-# log.debug("Session started")
-#
-# def stop(self):
-# self.is_connected.clear()
-#
-# self.ping_thread_event.set()
-# self.next_salt_thread_event.set()
-#
-# if self.ping_thread is not None:
-# self.ping_thread.join()
-#
-# if self.next_salt_thread is not None:
-# self.next_salt_thread.join()
-#
-# self.ping_thread_event.clear()
-# self.next_salt_thread_event.clear()
-#
-# self.connection.close()
-#
-# for i in range(self.NET_WORKERS):
-# self.recv_queue.put(None)
-#
-# for i in self.net_worker_list:
-# i.join()
-#
-# self.net_worker_list.clear()
-#
-# for i in self.results.values():
-# i.event.set()
-#
-# if self.client and callable(self.client.disconnect_handler):
-# try:
-# self.client.disconnect_handler(self.client)
-# except Exception as e:
-# log.error(e, exc_info=True)
-#
-# log.debug("Session stopped")
-#
-# def restart(self):
-# self.stop()
-# self.start()
-#
-# def pack(self, message: Message):
-# data = Long(self.current_salt.salt) + self.session_id + message.write()
-# padding = urandom(-(len(data) + 12) % 16 + 12)
-#
-# # 88 = 88 + 0 (outgoing message)
-# msg_key_large = sha256(self.auth_key[88: 88 + 32] + data + padding).digest()
-# msg_key = msg_key_large[8:24]
-# aes_key, aes_iv = KDF(self.auth_key, msg_key, True)
-#
-# return self.auth_key_id + msg_key + AES.ige256_encrypt(data + padding, aes_key, aes_iv)
-#
-# def unpack(self, b: BytesIO) -> Message:
-# assert b.read(8) == self.auth_key_id, b.getvalue()
-#
-# msg_key = b.read(16)
-# aes_key, aes_iv = KDF(self.auth_key, msg_key, False)
-# data = BytesIO(AES.ige256_decrypt(b.read(), aes_key, aes_iv))
-# data.read(8)
-#
-# # https://core.telegram.org/mtproto/security_guidelines#checking-session-id
-# assert data.read(8) == self.session_id
-#
-# message = Message.read(data)
-#
-# # https://core.telegram.org/mtproto/security_guidelines#checking-sha256-hash-value-of-msg-key
-# # https://core.telegram.org/mtproto/security_guidelines#checking-message-length
-# # 96 = 88 + 8 (incoming message)
-# assert msg_key == sha256(self.auth_key[96:96 + 32] + data.getvalue()).digest()[8:24]
-#
-# # https://core.telegram.org/mtproto/security_guidelines#checking-msg-id
-# # TODO: check for lower msg_ids
-# assert message.msg_id % 2 != 0
-#
-# return message
-#
-# def net_worker(self):
-# name = threading.current_thread().name
-# log.debug("{} started".format(name))
-#
-# while True:
-# packet = self.recv_queue.get()
-#
-# if packet is None:
-# break
-#
-# try:
-# data = self.unpack(BytesIO(packet))
-#
-# messages = (
-# data.body.messages
-# if isinstance(data.body, MsgContainer)
-# else [data]
-# )
-#
-# log.debug(data)
-#
-# for msg in messages:
-# if msg.seq_no % 2 != 0:
-# if msg.msg_id in self.pending_acks:
-# continue
-# else:
-# self.pending_acks.add(msg.msg_id)
-#
-# if isinstance(msg.body, (types.MsgDetailedInfo, types.MsgNewDetailedInfo)):
-# self.pending_acks.add(msg.body.answer_msg_id)
-# continue
-#
-# if isinstance(msg.body, types.NewSessionCreated):
-# continue
-#
-# msg_id = None
-#
-# if isinstance(msg.body, (types.BadMsgNotification, types.BadServerSalt)):
-# msg_id = msg.body.bad_msg_id
-# elif isinstance(msg.body, (core.FutureSalts, types.RpcResult)):
-# msg_id = msg.body.req_msg_id
-# elif isinstance(msg.body, types.Pong):
-# msg_id = msg.body.msg_id
-# else:
-# if self.client is not None:
-# self.client.updates_queue.put(msg.body)
-#
-# if msg_id in self.results:
-# self.results[msg_id].value = getattr(msg.body, "result", msg.body)
-# self.results[msg_id].event.set()
-#
-# if len(self.pending_acks) >= self.ACKS_THRESHOLD:
-# log.info("Send {} acks".format(len(self.pending_acks)))
-#
-# try:
-# self._send(types.MsgsAck(list(self.pending_acks)), False)
-# except (OSError, TimeoutError):
-# pass
-# else:
-# self.pending_acks.clear()
-# except Exception as e:
-# log.error(e, exc_info=True)
-#
-# log.debug("{} stopped".format(name))
-#
-# def ping(self):
-# log.debug("PingThread started")
-#
-# while True:
-# self.ping_thread_event.wait(self.PING_INTERVAL)
-#
-# if self.ping_thread_event.is_set():
-# break
-#
-# try:
-# self._send(functions.PingDelayDisconnect(
-# 0, self.WAIT_TIMEOUT + 10
-# ), False)
-# except (OSError, TimeoutError, Error):
-# pass
-#
-# log.debug("PingThread stopped")
-#
-# def next_salt(self):
-# log.debug("NextSaltThread started")
-#
-# while True:
-# now = datetime.now()
-#
-# # Seconds to wait until middle-overlap, which is
-# # 15 minutes before/after the current/next salt end/start time
-# dt = (self.current_salt.valid_until - now).total_seconds() - 900
-#
-# log.debug("Current salt: {} | Next salt in {:.0f}m {:.0f}s ({})".format(
-# self.current_salt.salt,
-# dt // 60,
-# dt % 60,
-# now + timedelta(seconds=dt)
-# ))
-#
-# self.next_salt_thread_event.wait(dt)
-#
-# if self.next_salt_thread_event.is_set():
-# break
-#
-# try:
-# self.current_salt = self._send(functions.GetFutureSalts(1)).salts[0]
-# except (OSError, TimeoutError, Error):
-# self.connection.close()
-# break
-#
-# log.debug("NextSaltThread stopped")
-#
-# def recv(self):
-# log.debug("RecvThread started")
-#
-# while True:
-# packet = self.connection.recv()
-#
-# if packet is None or len(packet) == 4:
-# if packet:
-# log.warning("Server sent \"{}\"".format(Int.read(BytesIO(packet))))
-#
-# if self.is_connected.is_set():
-# Thread(target=self.restart, name="RestartThread").start()
-# break
-#
-# self.recv_queue.put(packet)
-#
-# log.debug("RecvThread stopped")
-#
-# def _send(self, data: Object, wait_response: bool = True):
-# message = self.msg_factory(data)
-# msg_id = message.msg_id
-#
-# if wait_response:
-# self.results[msg_id] = Result()
-#
-# payload = self.pack(message)
-#
-# try:
-# self.connection.send(payload)
-# except OSError as e:
-# self.results.pop(msg_id, None)
-# raise e
-#
-# if wait_response:
-# self.results[msg_id].event.wait(self.WAIT_TIMEOUT)
-# result = self.results.pop(msg_id).value
-#
-# if result is None:
-# raise TimeoutError
-# elif isinstance(result, types.RpcError):
-# Error.raise_it(result, type(data))
-# elif isinstance(result, types.BadMsgNotification):
-# raise Exception(self.BAD_MSG_DESCRIPTION.get(
-# result.error_code,
-# "Error code {}".format(result.error_code)
-# ))
-# else:
-# return result
-#
-# def send(self, data: Object, retries: int = MAX_RETRIES):
-# self.is_connected.wait(self.WAIT_TIMEOUT)
-#
-# try:
-# return self._send(data)
-# except (OSError, TimeoutError, InternalServerError) as e:
-# if retries == 0:
-# raise e from None
-#
-# (log.warning if retries < 3 else log.info)(
-# "{}: {} Retrying {}".format(
-# Session.MAX_RETRIES - retries,
-# datetime.now(), type(data)))
-#
-# time.sleep(0.5)
-# return self.send(data, retries - 1, timeout)
From b588b553584e6f7df77797e594842661c62dda9d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 7 Sep 2018 00:44:31 +0200
Subject: [PATCH 0073/1185] Remove old commented (non-async) code from tcp.py
---
pyrogram/connection/transport/tcp/tcp.py | 44 ------------------------
1 file changed, 44 deletions(-)
diff --git a/pyrogram/connection/transport/tcp/tcp.py b/pyrogram/connection/transport/tcp/tcp.py
index 9e09a8b1b3..91f3dd451f 100644
--- a/pyrogram/connection/transport/tcp/tcp.py
+++ b/pyrogram/connection/transport/tcp/tcp.py
@@ -101,47 +101,3 @@ async def recv(self, length: int = 0):
return None
return data
-
-# class TCP(socks.socksocket):
-# def __init__(self, proxy: dict):
-# super().__init__()
-# self.settimeout(10)
-# self.proxy_enabled = proxy.get("enabled", False)
-#
-# if proxy and self.proxy_enabled:
-# self.set_proxy(
-# proxy_type=socks.SOCKS5,
-# addr=proxy.get("hostname", None),
-# port=proxy.get("port", None),
-# username=proxy.get("username", None),
-# password=proxy.get("password", None)
-# )
-#
-# log.info("Using proxy {}:{}".format(
-# proxy.get("hostname", None),
-# proxy.get("port", None)
-# ))
-#
-# def close(self):
-# try:
-# self.shutdown(socket.SHUT_RDWR)
-# except OSError:
-# pass
-# finally:
-# super().close()
-#
-# def recvall(self, length: int) -> bytes or None:
-# data = b""
-#
-# while len(data) < length:
-# try:
-# packet = super().recv(length - len(data))
-# except OSError:
-# return None
-# else:
-# if packet:
-# data += packet
-# else:
-# return None
-#
-# return data
From 8ff413c7e71f2b52973def2590e834b334d68408 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 8 Sep 2018 19:30:12 +0200
Subject: [PATCH 0074/1185] Make get_chat_members_count async
---
.../methods/chats/get_chat_members_count.py | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/pyrogram/client/methods/chats/get_chat_members_count.py b/pyrogram/client/methods/chats/get_chat_members_count.py
index efe53c19ee..11aa5d1f1c 100644
--- a/pyrogram/client/methods/chats/get_chat_members_count.py
+++ b/pyrogram/client/methods/chats/get_chat_members_count.py
@@ -21,7 +21,7 @@
class GetChatMembersCount(BaseClient):
- def get_chat_members_count(self, chat_id: int or str):
+ async def get_chat_members_count(self, chat_id: int or str):
"""Use this method to get the number of members in a chat.
Args:
@@ -35,19 +35,23 @@ def get_chat_members_count(self, chat_id: int or str):
:class:`Error
``ValueError``: If a chat_id belongs to user.
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChat):
- return self.send(
+ r = await self.send(
functions.messages.GetChats(
id=[peer.chat_id]
)
- ).chats[0].participants_count
+ )
+
+ return r.chats[0].participants_count
elif isinstance(peer, types.InputPeerChannel):
- return self.send(
+ r = await self.send(
functions.channels.GetFullChannel(
channel=peer
)
- ).full_chat.participants_count
+ )
+
+ return r.full_chat.participants_count
else:
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
From dbd60765f695d6fa99d81d4a1e4712ba78895108 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 11 Sep 2018 19:39:46 +0200
Subject: [PATCH 0075/1185] Fix get_me not being properly awaited
---
pyrogram/client/methods/users/get_me.py | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/pyrogram/client/methods/users/get_me.py b/pyrogram/client/methods/users/get_me.py
index f191e29863..a8aac70f01 100644
--- a/pyrogram/client/methods/users/get_me.py
+++ b/pyrogram/client/methods/users/get_me.py
@@ -30,10 +30,10 @@ async def get_me(self):
Raises:
:class:`Error `
"""
- return utils.parse_user(
- await self.send(
- functions.users.GetFullUser(
- types.InputPeerSelf()
- )
- ).user
+ r = await self.send(
+ functions.users.GetFullUser(
+ types.InputPeerSelf()
+ )
)
+
+ return utils.parse_user(r.user)
From 8070bf4cd40af0e953e395fcd439b6dd24466cb7 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 22 Sep 2018 19:41:33 +0200
Subject: [PATCH 0076/1185] Fix bad merge after editing tcp.py
---
pyrogram/connection/transport/tcp/tcp.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/connection/transport/tcp/tcp.py b/pyrogram/connection/transport/tcp/tcp.py
index 55e9fea6ed..625879003b 100644
--- a/pyrogram/connection/transport/tcp/tcp.py
+++ b/pyrogram/connection/transport/tcp/tcp.py
@@ -17,9 +17,9 @@
# along with Pyrogram. If not, see .
import asyncio
+import ipaddress
import logging
import socket
-import ipaddress
try:
import socks
@@ -69,7 +69,7 @@ def __init__(self, ipv6: bool, proxy: dict):
log.info("Using proxy {}:{}".format(hostname, port))
else:
- super().__init__(
+ self.socket = socks.socksocket(
socket.AF_INET6 if ipv6
else socket.AF_INET
)
From ee06907bdabc008b61af8a094373b49d68478e51 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 8 Oct 2018 20:16:04 +0200
Subject: [PATCH 0077/1185] Make TCPAbridged async
---
.../connection/transport/tcp/tcp_abridged.py | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/pyrogram/connection/transport/tcp/tcp_abridged.py b/pyrogram/connection/transport/tcp/tcp_abridged.py
index 5566b17979..49bba1c7c1 100644
--- a/pyrogram/connection/transport/tcp/tcp_abridged.py
+++ b/pyrogram/connection/transport/tcp/tcp_abridged.py
@@ -27,30 +27,30 @@ class TCPAbridged(TCP):
def __init__(self, ipv6: bool, proxy: dict):
super().__init__(ipv6, proxy)
- def connect(self, address: tuple):
- super().connect(address)
- super().sendall(b"\xef")
+ async def connect(self, address: tuple):
+ await super().connect(address)
+ await super().send(b"\xef")
- def sendall(self, data: bytes, *args):
+ async def send(self, data: bytes, *args):
length = len(data) // 4
- super().sendall(
+ await super().send(
(bytes([length])
if length <= 126
else b"\x7f" + length.to_bytes(3, "little"))
+ data
)
- def recvall(self, length: int = 0) -> bytes or None:
- length = super().recvall(1)
+ async def recv(self, length: int = 0) -> bytes or None:
+ length = await super().recv(1)
if length is None:
return None
if length == b"\x7f":
- length = super().recvall(3)
+ length = await super().recv(3)
if length is None:
return None
- return super().recvall(int.from_bytes(length, "little") * 4)
+ return await super().recv(int.from_bytes(length, "little") * 4)
From 1bf0d931400cd17aa1de694e1326cddadc9af67c Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 8 Oct 2018 20:16:44 +0200
Subject: [PATCH 0078/1185] Make TCPFull async
---
pyrogram/connection/transport/tcp/tcp_full.py | 23 +++++++++----------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/pyrogram/connection/transport/tcp/tcp_full.py b/pyrogram/connection/transport/tcp/tcp_full.py
index 8704247bba..f6a099531d 100644
--- a/pyrogram/connection/transport/tcp/tcp_full.py
+++ b/pyrogram/connection/transport/tcp/tcp_full.py
@@ -31,34 +31,33 @@ def __init__(self, ipv6: bool, proxy: dict):
self.seq_no = None
- def connect(self, address: tuple):
- super().connect(address)
+ async def connect(self, address: tuple):
+ await super().connect(address)
self.seq_no = 0
- def sendall(self, data: bytes, *args):
- # 12 = packet_length (4), seq_no (4), crc32 (4) (at the end)
+ async def send(self, data: bytes, *args):
data = pack(" bytes or None:
- length = super().recvall(4)
+ async def recv(self, length: int = 0) -> bytes or None:
+ length = await super().recv(4)
if length is None:
return None
- packet = super().recvall(unpack("
Date: Mon, 8 Oct 2018 20:17:04 +0200
Subject: [PATCH 0079/1185] Make TCPAbridgedO async
---
.../connection/transport/tcp/tcp_abridged_o.py | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/pyrogram/connection/transport/tcp/tcp_abridged_o.py b/pyrogram/connection/transport/tcp/tcp_abridged_o.py
index 91ee8375ac..c6d38153a5 100644
--- a/pyrogram/connection/transport/tcp/tcp_abridged_o.py
+++ b/pyrogram/connection/transport/tcp/tcp_abridged_o.py
@@ -34,8 +34,8 @@ def __init__(self, ipv6: bool, proxy: dict):
self.encrypt = None
self.decrypt = None
- def connect(self, address: tuple):
- super().connect(address)
+ async def connect(self, address: tuple):
+ await super().connect(address)
while True:
nonce = bytearray(os.urandom(64))
@@ -53,12 +53,12 @@ def connect(self, address: tuple):
nonce[56:64] = AES.ctr256_encrypt(nonce, *self.encrypt)[56:64]
- super().sendall(nonce)
+ await super().send(nonce)
- def sendall(self, data: bytes, *args):
+ async def send(self, data: bytes, *args):
length = len(data) // 4
- super().sendall(
+ await super().send(
AES.ctr256_encrypt(
(bytes([length])
if length <= 126
@@ -68,8 +68,8 @@ def sendall(self, data: bytes, *args):
)
)
- def recvall(self, length: int = 0) -> bytes or None:
- length = super().recvall(1)
+ async def recv(self, length: int = 0) -> bytes or None:
+ length = await super().recv(1)
if length is None:
return None
@@ -77,14 +77,14 @@ def recvall(self, length: int = 0) -> bytes or None:
length = AES.ctr256_decrypt(length, *self.decrypt)
if length == b"\x7f":
- length = super().recvall(3)
+ length = await super().recv(3)
if length is None:
return None
length = AES.ctr256_decrypt(length, *self.decrypt)
- data = super().recvall(int.from_bytes(length, "little") * 4)
+ data = await super().recv(int.from_bytes(length, "little") * 4)
if data is None:
return None
From 1fc160c5664e75a95dd486299d6968540295ec53 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 8 Oct 2018 20:17:31 +0200
Subject: [PATCH 0080/1185] Make TCPIntermediateO async
---
.../transport/tcp/tcp_intermediate_o.py | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/pyrogram/connection/transport/tcp/tcp_intermediate_o.py b/pyrogram/connection/transport/tcp/tcp_intermediate_o.py
index f0598d128b..3aefe341a5 100644
--- a/pyrogram/connection/transport/tcp/tcp_intermediate_o.py
+++ b/pyrogram/connection/transport/tcp/tcp_intermediate_o.py
@@ -35,8 +35,8 @@ def __init__(self, ipv6: bool, proxy: dict):
self.encrypt = None
self.decrypt = None
- def connect(self, address: tuple):
- super().connect(address)
+ async def connect(self, address: tuple):
+ await super().connect(address)
while True:
nonce = bytearray(os.urandom(64))
@@ -54,25 +54,25 @@ def connect(self, address: tuple):
nonce[56:64] = AES.ctr256_encrypt(nonce, *self.encrypt)[56:64]
- super().sendall(nonce)
+ await super().send(nonce)
- def sendall(self, data: bytes, *args):
- super().sendall(
+ async def send(self, data: bytes, *args):
+ await super().send(
AES.ctr256_encrypt(
pack(" bytes or None:
- length = super().recvall(4)
+ async def recv(self, length: int = 0) -> bytes or None:
+ length = await super().recv(4)
if length is None:
return None
length = AES.ctr256_decrypt(length, *self.decrypt)
- data = super().recvall(unpack("
Date: Mon, 8 Oct 2018 20:17:47 +0200
Subject: [PATCH 0081/1185] Remove TODO
---
pyrogram/connection/connection.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index fe8b5d5d5f..17ed949532 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -29,7 +29,6 @@ class Connection:
MAX_RETRIES = 3
MODES = {
- # TODO: Implement other protocols using asyncio
0: TCPFull,
1: TCPAbridged,
2: TCPIntermediate,
From d5c2ca2e1df511eac7c1f67216b70df595deb649 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 8 Oct 2018 20:18:20 +0200
Subject: [PATCH 0082/1185] Use TCPAbridged (async) connection mode
---
pyrogram/connection/connection.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/connection/connection.py b/pyrogram/connection/connection.py
index 17ed949532..58bf4fdc12 100644
--- a/pyrogram/connection/connection.py
+++ b/pyrogram/connection/connection.py
@@ -36,7 +36,7 @@ class Connection:
4: TCPIntermediateO
}
- def __init__(self, dc_id: int, test_mode: bool, ipv6: bool, proxy: dict, mode: int = 2):
+ def __init__(self, dc_id: int, test_mode: bool, ipv6: bool, proxy: dict, mode: int = 1):
self.dc_id = dc_id
self.ipv6 = ipv6
self.proxy = proxy
From 418eb0b01a77017325db09d6e323277c29852fcb Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 16 Oct 2018 12:38:50 +0200
Subject: [PATCH 0083/1185] Fix asyncio dispatcher
---
pyrogram/client/dispatcher/dispatcher.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py
index 095b08abcf..61cd8c7c3b 100644
--- a/pyrogram/client/dispatcher/dispatcher.py
+++ b/pyrogram/client/dispatcher/dispatcher.py
@@ -215,7 +215,7 @@ async def update_worker(self):
)
)
elif isinstance(update, types.UpdateUserStatus):
- self.dispatch(
+ await self.dispatch(
pyrogram.Update(
user_status=utils.parse_user_status(
update.status, update.user_id
From 301ba799cf90507dab9d573506f904a79f9657fe Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 9 Nov 2018 09:41:49 +0100
Subject: [PATCH 0084/1185] Fix update_worker not being async
---
pyrogram/client/dispatcher/dispatcher.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py
index 26a0011b54..38b01fe9a1 100644
--- a/pyrogram/client/dispatcher/dispatcher.py
+++ b/pyrogram/client/dispatcher/dispatcher.py
@@ -108,9 +108,9 @@ def remove_handler(self, handler, group: int):
self.groups[group].remove(handler)
- def update_worker(self):
+ async def update_worker(self):
while True:
- update = self.updates.get()
+ update = await self.updates.get()
if update is None:
break
From 7bc4490680afa2f355761051f877de4b8400cd67 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 9 Nov 2018 10:10:26 +0100
Subject: [PATCH 0085/1185] Rework dispatcher for asyncio
---
pyrogram/client/dispatcher/dispatcher.py | 30 +++++++++++++-----------
1 file changed, 16 insertions(+), 14 deletions(-)
diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py
index 38b01fe9a1..74ea37fd6c 100644
--- a/pyrogram/client/dispatcher/dispatcher.py
+++ b/pyrogram/client/dispatcher/dispatcher.py
@@ -60,18 +60,23 @@ def __init__(self, client, workers: int):
self.updates = asyncio.Queue()
self.groups = OrderedDict()
- Dispatcher.UPDATES = {
- Dispatcher.MESSAGE_UPDATES:
- lambda upd, usr, cht: (utils.parse_messages(self.client, upd.message, usr, cht), MessageHandler),
+ async def message_parser(update, users, chats):
+ return await utils.parse_messages(self.client, update.message, users, chats), MessageHandler
+
+ async def deleted_messages_parser(update, users, chats):
+ return utils.parse_deleted_messages(update), DeletedMessagesHandler
- Dispatcher.DELETE_MESSAGE_UPDATES:
- lambda upd, usr, cht: (utils.parse_deleted_messages(upd), DeletedMessagesHandler),
+ async def callback_query_parser(update, users, chats):
+ return await utils.parse_callback_query(self.client, update, users), CallbackQueryHandler
- Dispatcher.CALLBACK_QUERY_UPDATES:
- lambda upd, usr, cht: (utils.parse_callback_query(self.client, upd, usr), CallbackQueryHandler),
+ async def user_status_parser(update, users, chats):
+ return utils.parse_user_status(update.status, update.user_id), UserStatusHandler
- (types.UpdateUserStatus,):
- lambda upd, usr, cht: (utils.parse_user_status(upd.status, upd.user_id), UserStatusHandler)
+ Dispatcher.UPDATES = {
+ Dispatcher.MESSAGE_UPDATES: message_parser,
+ Dispatcher.DELETE_MESSAGE_UPDATES: deleted_messages_parser,
+ Dispatcher.CALLBACK_QUERY_UPDATES: callback_query_parser,
+ (types.UpdateUserStatus,): user_status_parser
}
Dispatcher.UPDATES = {key: value for key_tuple, value in Dispatcher.UPDATES.items() for key in key_tuple}
@@ -125,8 +130,7 @@ async def update_worker(self):
if parser is None:
continue
- update, handler_type = parser(update, users, chats)
- tasks = []
+ update, handler_type = await parser(update, users, chats)
for group in self.groups.values():
for handler in group:
@@ -142,12 +146,10 @@ async def update_worker(self):
continue
try:
- tasks.append(handler.callback(self.client, *args))
+ await handler.callback(self.client, *args)
except Exception as e:
log.error(e, exc_info=True)
finally:
break
-
- await asyncio.gather(*tasks)
except Exception as e:
log.error(e, exc_info=True)
From 8dfa80ef61085c0f8f2fc31737b154aea361a98b Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 10 Nov 2018 15:29:37 +0100
Subject: [PATCH 0086/1185] Add missing await keyword
---
pyrogram/client/ext/utils.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 3dc78c607d..f01a523c53 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -896,7 +896,7 @@ async def parse_callback_query(client, update, users):
else:
peer_id = int("-100" + str(peer.channel_id))
- message = client.get_messages(peer_id, update.msg_id)
+ message = await client.get_messages(peer_id, update.msg_id)
elif isinstance(update, types.UpdateInlineBotCallbackQuery):
inline_message_id = b64encode(
pack(
From 40047877fe73d8fd134c5c6495659ac146e15623 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 20 Nov 2018 19:47:41 +0100
Subject: [PATCH 0087/1185] Add missing await
---
pyrogram/client/methods/messages/send_message.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/methods/messages/send_message.py b/pyrogram/client/methods/messages/send_message.py
index 772132ce3d..ebea756a2c 100644
--- a/pyrogram/client/methods/messages/send_message.py
+++ b/pyrogram/client/methods/messages/send_message.py
@@ -85,7 +85,7 @@ async def send_message(self,
if isinstance(r, types.UpdateShortSentMessage):
return pyrogram_types.Message(
message_id=r.id,
- chat=pyrogram_types.Chat(id=list(self.resolve_peer(chat_id).__dict__.values())[0], type="private"),
+ chat=pyrogram_types.Chat(id=list((await self.resolve_peer(chat_id)).__dict__.values())[0], type="private"),
text=message,
date=r.date,
outgoing=r.out,
From 6292fe8f86cd3af6bc1ce0ab7b74a9be19d1fe34 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 15 Dec 2018 11:24:31 +0100
Subject: [PATCH 0088/1185] Fix progress callbacks in asyncio
---
pyrogram/client/client.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 924c5df7d4..3c0081a7b5 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -1202,7 +1202,7 @@ async def worker(session):
file_part += 1
if progress:
- progress(self, min(file_part * part_size, file_size), file_size, *progress_args)
+ await progress(self, min(file_part * part_size, file_size), file_size, *progress_args)
except Exception as e:
log.error(e, exc_info=True)
else:
@@ -1321,7 +1321,7 @@ async def get_file(self,
offset += limit
if progress:
- progress(self, min(offset, size) if size != 0 else offset, size, *progress_args)
+ await progress(self, min(offset, size) if size != 0 else offset, size, *progress_args)
r = await session.send(
functions.upload.GetFile(
@@ -1403,7 +1403,7 @@ async def get_file(self,
offset += limit
if progress:
- progress(self, min(offset, size) if size != 0 else offset, size, *progress_args)
+ await progress(self, min(offset, size) if size != 0 else offset, size, *progress_args)
if len(chunk) < limit:
break
From 17b166e6a683f666b7cb837e1758e018a01b335b Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 15 Dec 2018 11:35:53 +0100
Subject: [PATCH 0089/1185] CallbackQuery must deal with bytes instead of
strings
---
pyrogram/client/ext/utils.py | 2 +-
pyrogram/client/types/bots/callback_query.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index e687ced15f..a8b5b07bc8 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -917,7 +917,7 @@ async def parse_callback_query(client, update, users):
message=message,
inline_message_id=inline_message_id,
chat_instance=str(update.chat_instance),
- data=update.data.decode(),
+ data=update.data,
game_short_name=update.game_short_name,
client=client
)
diff --git a/pyrogram/client/types/bots/callback_query.py b/pyrogram/client/types/bots/callback_query.py
index 843a9bb8bf..447d13eacb 100644
--- a/pyrogram/client/types/bots/callback_query.py
+++ b/pyrogram/client/types/bots/callback_query.py
@@ -60,7 +60,7 @@ def __init__(
client=None,
message=None,
inline_message_id: str = None,
- data: str = None,
+ data: bytes = None,
game_short_name: str = None
):
self._client = client
From f5ce49b7b22f3a68560813464aa95c592736f794 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 22 Dec 2018 14:08:29 +0100
Subject: [PATCH 0090/1185] - Fix small glitches introduced when merging. -
Remove typing requirement, asyncio branch already needs Python 3.5+. - Add
async_lru as extra requirement because the standard lru_cache doesn't work
in asyncio world.
---
pyrogram/client/dispatcher/dispatcher.py | 2 +-
pyrogram/client/ext/utils.py | 12 ++++++++++++
pyrogram/client/methods/messages/get_messages.py | 2 +-
pyrogram/client/methods/users/get_me.py | 4 ++--
pyrogram/client/types/bots/callback_query.py | 4 ++--
pyrogram/client/types/messages_and_media/sticker.py | 9 +++++----
requirements.txt | 2 +-
7 files changed, 24 insertions(+), 11 deletions(-)
diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py
index e6dcd4b663..8a22ad7e82 100644
--- a/pyrogram/client/dispatcher/dispatcher.py
+++ b/pyrogram/client/dispatcher/dispatcher.py
@@ -72,7 +72,7 @@ async def user_status_parser(update, users, chats):
self.update_parsers = {
Dispatcher.MESSAGE_UPDATES: message_parser,
- Dispatcher.DELETE_MESSAGE_UPDATES: deleted_messages_parser,
+ Dispatcher.DELETE_MESSAGES_UPDATES: deleted_messages_parser,
Dispatcher.CALLBACK_QUERY_UPDATES: callback_query_parser,
(types.UpdateUserStatus,): user_status_parser
}
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 3e67e3cdbc..cb2dda3963 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -16,7 +16,10 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
+import sys
from base64 import b64decode, b64encode
+from concurrent.futures.thread import ThreadPoolExecutor
from ...api import types
@@ -57,6 +60,15 @@ def encode(s: bytes) -> str:
return b64encode(r, b"-_").decode().rstrip("=")
+async def ainput(prompt: str = ""):
+ print(prompt, end="", flush=True)
+
+ with ThreadPoolExecutor(1) as executor:
+ return (await asyncio.get_event_loop().run_in_executor(
+ executor, sys.stdin.readline
+ )).rstrip()
+
+
def get_peer_id(input_peer) -> int:
return (
input_peer.user_id if isinstance(input_peer, types.InputPeerUser)
diff --git a/pyrogram/client/methods/messages/get_messages.py b/pyrogram/client/methods/messages/get_messages.py
index edcad039e3..b1ee933962 100644
--- a/pyrogram/client/methods/messages/get_messages.py
+++ b/pyrogram/client/methods/messages/get_messages.py
@@ -78,6 +78,6 @@ async def get_messages(self,
else:
rpc = functions.messages.GetMessages(id=ids)
- messages = await pyrogram.Messages._parse(self, self.send(rpc))
+ messages = await pyrogram.Messages._parse(self, await self.send(rpc))
return messages if is_iterable else messages.messages[0]
diff --git a/pyrogram/client/methods/users/get_me.py b/pyrogram/client/methods/users/get_me.py
index 390c3b2c0f..11dd657f37 100644
--- a/pyrogram/client/methods/users/get_me.py
+++ b/pyrogram/client/methods/users/get_me.py
@@ -33,9 +33,9 @@ async def get_me(self) -> "pyrogram.User":
"""
return pyrogram.User._parse(
self,
- await self.send(
+ (await self.send(
functions.users.GetFullUser(
types.InputPeerSelf()
)
- ).user
+ )).user
)
diff --git a/pyrogram/client/types/bots/callback_query.py b/pyrogram/client/types/bots/callback_query.py
index c3c23333eb..3c046cf962 100644
--- a/pyrogram/client/types/bots/callback_query.py
+++ b/pyrogram/client/types/bots/callback_query.py
@@ -78,7 +78,7 @@ def __init__(self,
self.game_short_name = game_short_name
@staticmethod
- def _parse(client, callback_query, users) -> "CallbackQuery":
+ async def _parse(client, callback_query, users) -> "CallbackQuery":
message = None
inline_message_id = None
@@ -92,7 +92,7 @@ def _parse(client, callback_query, users) -> "CallbackQuery":
else:
peer_id = int("-100" + str(peer.channel_id))
- message = client.get_messages(peer_id, callback_query.msg_id)
+ message = await client.get_messages(peer_id, callback_query.msg_id)
elif isinstance(callback_query, types.UpdateInlineBotCallbackQuery):
inline_message_id = b64encode(
pack(
diff --git a/pyrogram/client/types/messages_and_media/sticker.py b/pyrogram/client/types/messages_and_media/sticker.py
index 943856818d..c84acd2391 100644
--- a/pyrogram/client/types/messages_and_media/sticker.py
+++ b/pyrogram/client/types/messages_and_media/sticker.py
@@ -16,9 +16,10 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from functools import lru_cache
from struct import pack
+from async_lru import alru_cache
+
import pyrogram
from pyrogram.api import types, functions
from pyrogram.api.errors import StickersetInvalid
@@ -92,14 +93,14 @@ def __init__(self,
# self.mask_position = mask_position
@staticmethod
- @lru_cache(maxsize=256)
+ @alru_cache(maxsize=256)
async def get_sticker_set_name(send, input_sticker_set_id):
try:
- return await send(
+ return (await send(
functions.messages.GetStickerSet(
types.InputStickerSetID(*input_sticker_set_id)
)
- ).set.short_name
+ )).set.short_name
except StickersetInvalid:
return None
diff --git a/requirements.txt b/requirements.txt
index 8f1eea9568..ccfa89ee2b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,3 @@
pyaes==1.6.1
pysocks==1.6.8
-typing==3.6.6
\ No newline at end of file
+async_lru==1.0.1
\ No newline at end of file
From 4d8c76463c4d84464226c11a53e245503dc9c5f5 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 7 Jan 2019 09:34:08 +0100
Subject: [PATCH 0091/1185] Add async_generator requirement
---
requirements.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/requirements.txt b/requirements.txt
index f9c6874cfb..81df21efaf 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,5 @@
pyaes==1.6.1
pysocks==1.6.8
typing==3.6.6; python_version<"3.5"
-async_lru==1.0.1
\ No newline at end of file
+async_lru==1.0.1
+async_generator==1.10
\ No newline at end of file
From 0bae143d5db5c54208c478875e89079f9d95c039 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 7 Jan 2019 09:37:26 +0100
Subject: [PATCH 0092/1185] Fix asyncio merge issues
---
pyrogram/client/client.py | 2 +-
pyrogram/client/methods/chats/get_dialogs.py | 2 +-
.../client/methods/chats/iter_chat_members.py | 21 +++++++------
pyrogram/client/methods/chats/iter_dialogs.py | 31 ++++++++++---------
.../client/methods/messages/iter_history.py | 25 ++++++++-------
.../types/messages_and_media/messages.py | 2 +-
.../client/types/user_and_chats/dialogs.py | 4 +--
7 files changed, 48 insertions(+), 39 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index fb4552b761..2dacc26ed5 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -321,7 +321,7 @@ async def stop(self):
raise ConnectionError("Client is already stopped")
if self.takeout_id:
- self.send(functions.account.FinishTakeoutSession())
+ await self.send(functions.account.FinishTakeoutSession())
log.warning("Takeout session {} finished".format(self.takeout_id))
await Syncer.remove(self)
diff --git a/pyrogram/client/methods/chats/get_dialogs.py b/pyrogram/client/methods/chats/get_dialogs.py
index 4d5974252b..7d2f44e338 100644
--- a/pyrogram/client/methods/chats/get_dialogs.py
+++ b/pyrogram/client/methods/chats/get_dialogs.py
@@ -78,4 +78,4 @@ async def get_dialogs(self,
else:
break
- return pyrogram.Dialogs._parse(self, r)
+ return await pyrogram.Dialogs._parse(self, r)
diff --git a/pyrogram/client/methods/chats/iter_chat_members.py b/pyrogram/client/methods/chats/iter_chat_members.py
index bdd8d1177c..f521ebc6be 100644
--- a/pyrogram/client/methods/chats/iter_chat_members.py
+++ b/pyrogram/client/methods/chats/iter_chat_members.py
@@ -17,7 +17,9 @@
# along with Pyrogram. If not, see .
from string import ascii_lowercase
-from typing import Union, Generator
+from typing import Union, AsyncGenerator, Optional
+
+from async_generator import async_generator, yield_
import pyrogram
from ...ext import BaseClient
@@ -37,11 +39,12 @@ class Filters:
class IterChatMembers(BaseClient):
- def iter_chat_members(self,
- chat_id: Union[int, str],
- limit: int = 0,
- query: str = "",
- filter: str = Filters.ALL) -> Generator["pyrogram.ChatMember", None, None]:
+ @async_generator
+ async def iter_chat_members(self,
+ chat_id: Union[int, str],
+ limit: int = 0,
+ query: str = "",
+ filter: str = Filters.ALL) -> Optional[AsyncGenerator["pyrogram.ChatMember", None]]:
"""Use this method to iterate through the members of a chat sequentially.
This convenience method does the same as repeatedly calling :meth:`get_chat_members` in a loop, thus saving you
@@ -95,13 +98,13 @@ def iter_chat_members(self,
offset = 0
while True:
- chat_members = self.get_chat_members(
+ chat_members = (await self.get_chat_members(
chat_id=chat_id,
offset=offset,
limit=limit,
query=q,
filter=filter
- ).chat_members
+ )).chat_members
if not chat_members:
break
@@ -114,7 +117,7 @@ def iter_chat_members(self,
if user_id in yielded:
continue
- yield chat_member
+ await yield_(chat_member)
yielded.add(chat_member.user.id)
diff --git a/pyrogram/client/methods/chats/iter_dialogs.py b/pyrogram/client/methods/chats/iter_dialogs.py
index 6058cd17b0..712254e9ef 100644
--- a/pyrogram/client/methods/chats/iter_dialogs.py
+++ b/pyrogram/client/methods/chats/iter_dialogs.py
@@ -16,30 +16,33 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from typing import Generator
+from typing import AsyncGenerator, Optional
+
+from async_generator import async_generator, yield_
import pyrogram
from ...ext import BaseClient
class IterDialogs(BaseClient):
- def iter_dialogs(self,
- offset_date: int = 0,
- limit: int = 0) -> Generator["pyrogram.Dialog", None, None]:
+ @async_generator
+ async def iter_dialogs(self,
+ limit: int = 0,
+ offset_date: int = 0) -> Optional[AsyncGenerator["pyrogram.Dialog", None]]:
"""Use this method to iterate through a user's dialogs sequentially.
This convenience method does the same as repeatedly calling :meth:`get_dialogs` in a loop, thus saving you from
the hassle of setting up boilerplate code. It is useful for getting the whole dialogs list with a single call.
Args:
- offset_date (``int``):
- The offset date in Unix time taken from the top message of a :obj:`Dialog`.
- Defaults to 0 (most recent dialog).
-
limit (``str``, *optional*):
Limits the number of dialogs to be retrieved.
By default, no limit is applied and all dialogs are returned.
+ offset_date (``int``):
+ The offset date in Unix time taken from the top message of a :obj:`Dialog`.
+ Defaults to 0 (most recent dialog).
+
Returns:
A generator yielding :obj:`Dialog ` objects.
@@ -50,12 +53,12 @@ def iter_dialogs(self,
total = limit or (1 << 31) - 1
limit = min(100, total)
- pinned_dialogs = self.get_dialogs(
+ pinned_dialogs = (await self.get_dialogs(
pinned_only=True
- ).dialogs
+ )).dialogs
for dialog in pinned_dialogs:
- yield dialog
+ await yield_(dialog)
current += 1
@@ -63,10 +66,10 @@ def iter_dialogs(self,
return
while True:
- dialogs = self.get_dialogs(
+ dialogs = (await self.get_dialogs(
offset_date=offset_date,
limit=limit
- ).dialogs
+ )).dialogs
if not dialogs:
return
@@ -74,7 +77,7 @@ def iter_dialogs(self,
offset_date = dialogs[-1].top_message.date
for dialog in dialogs:
- yield dialog
+ await yield_(dialog)
current += 1
diff --git a/pyrogram/client/methods/messages/iter_history.py b/pyrogram/client/methods/messages/iter_history.py
index ab5879885a..1a97799864 100644
--- a/pyrogram/client/methods/messages/iter_history.py
+++ b/pyrogram/client/methods/messages/iter_history.py
@@ -16,20 +16,23 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from typing import Union, Generator
+from typing import Union, Optional, AsyncGenerator
+
+from async_generator import async_generator, yield_
import pyrogram
from ...ext import BaseClient
class IterHistory(BaseClient):
- def iter_history(self,
- chat_id: Union[int, str],
- limit: int = 0,
- offset: int = 0,
- offset_id: int = 0,
- offset_date: int = 0,
- reverse: bool = False) -> Generator["pyrogram.Message", None, None]:
+ @async_generator
+ async def iter_history(self,
+ chat_id: Union[int, str],
+ limit: int = 0,
+ offset: int = 0,
+ offset_id: int = 0,
+ offset_date: int = 0,
+ reverse: bool = False) -> Optional[AsyncGenerator["pyrogram.Message", None]]:
"""Use this method to iterate through a chat history sequentially.
This convenience method does the same as repeatedly calling :meth:`get_history` in a loop, thus saving you from
@@ -70,14 +73,14 @@ def iter_history(self,
limit = min(100, total)
while True:
- messages = self.get_history(
+ messages = (await self.get_history(
chat_id=chat_id,
limit=limit,
offset=offset,
offset_id=offset_id,
offset_date=offset_date,
reverse=reverse
- ).messages
+ )).messages
if not messages:
return
@@ -85,7 +88,7 @@ def iter_history(self,
offset_id = messages[-1].message_id + (1 if reverse else 0)
for message in messages:
- yield message
+ await yield_(message)
current += 1
diff --git a/pyrogram/client/types/messages_and_media/messages.py b/pyrogram/client/types/messages_and_media/messages.py
index 5b12da4543..a48b6acf4f 100644
--- a/pyrogram/client/types/messages_and_media/messages.py
+++ b/pyrogram/client/types/messages_and_media/messages.py
@@ -65,7 +65,7 @@ async def _parse(client, messages: types.messages.Messages, replies: int = 1) ->
parsed_messages = []
for message in messages.messages:
- parsed_messages.appen(await Message._parse(client, message, users, chats, replies=0))
+ parsed_messages.append(await Message._parse(client, message, users, chats, replies=0))
if replies:
messages_with_replies = {i.id: getattr(i, "reply_to_msg_id", None) for i in messages.messages}
diff --git a/pyrogram/client/types/user_and_chats/dialogs.py b/pyrogram/client/types/user_and_chats/dialogs.py
index 394ddd28bc..b3c2d773c0 100644
--- a/pyrogram/client/types/user_and_chats/dialogs.py
+++ b/pyrogram/client/types/user_and_chats/dialogs.py
@@ -47,7 +47,7 @@ def __init__(self,
self.dialogs = dialogs
@staticmethod
- def _parse(client, dialogs) -> "Dialogs":
+ async def _parse(client, dialogs) -> "Dialogs":
users = {i.id: i for i in dialogs.users}
chats = {i.id: i for i in dialogs.chats}
@@ -66,7 +66,7 @@ def _parse(client, dialogs) -> "Dialogs":
else:
chat_id = int("-100" + str(to_id.channel_id))
- messages[chat_id] = Message._parse(client, message, users, chats)
+ messages[chat_id] = await Message._parse(client, message, users, chats)
return Dialogs(
total_count=getattr(dialogs, "count", len(dialogs.dialogs)),
From 35096a28c3960e8775d945493d5e9d4aed3ea428 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 7 Jan 2019 22:57:19 +0100
Subject: [PATCH 0093/1185] Fix asyncio merge
---
pyrogram/client/ext/base_client.py | 18 +++++++-------
.../methods/bots/get_game_high_scores.py | 14 +++++------
pyrogram/client/methods/bots/send_game.py | 24 +++++++++----------
.../client/methods/bots/set_game_score.py | 22 ++++++++---------
.../types/messages_and_media/message.py | 8 +++++--
5 files changed, 45 insertions(+), 41 deletions(-)
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index 45bab7388b..7d5e7a4b0b 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -96,29 +96,29 @@ def __init__(self):
self.disconnect_handler = None
- def send(self, *args, **kwargs):
+ async def send(self, *args, **kwargs):
pass
- def resolve_peer(self, *args, **kwargs):
+ async def resolve_peer(self, *args, **kwargs):
pass
- def fetch_peers(self, *args, **kwargs):
+ async def fetch_peers(self, *args, **kwargs):
pass
- def add_handler(self, *args, **kwargs):
+ async def add_handler(self, *args, **kwargs):
pass
- def save_file(self, *args, **kwargs):
+ async def save_file(self, *args, **kwargs):
pass
- def get_messages(self, *args, **kwargs):
+ async def get_messages(self, *args, **kwargs):
pass
- def get_history(self, *args, **kwargs):
+ async def get_history(self, *args, **kwargs):
pass
- def get_dialogs(self, *args, **kwargs):
+ async def get_dialogs(self, *args, **kwargs):
pass
- def get_chat_members(self, *args, **kwargs):
+ async def get_chat_members(self, *args, **kwargs):
pass
diff --git a/pyrogram/client/methods/bots/get_game_high_scores.py b/pyrogram/client/methods/bots/get_game_high_scores.py
index ad4f8b4a0d..e58bc17e03 100644
--- a/pyrogram/client/methods/bots/get_game_high_scores.py
+++ b/pyrogram/client/methods/bots/get_game_high_scores.py
@@ -24,10 +24,10 @@
class GetGameHighScores(BaseClient):
- def get_game_high_scores(self,
- user_id: Union[int, str],
- chat_id: Union[int, str],
- message_id: int = None):
+ async def get_game_high_scores(self,
+ user_id: Union[int, str],
+ chat_id: Union[int, str],
+ message_id: int = None):
"""Use this method to get data for high score tables.
Args:
@@ -56,11 +56,11 @@ def get_game_high_scores(self,
return pyrogram.GameHighScores._parse(
self,
- self.send(
+ await self.send(
functions.messages.GetGameHighScores(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
id=message_id,
- user_id=self.resolve_peer(user_id)
+ user_id=await self.resolve_peer(user_id)
)
)
)
diff --git a/pyrogram/client/methods/bots/send_game.py b/pyrogram/client/methods/bots/send_game.py
index 401a5aa686..0f3593b058 100644
--- a/pyrogram/client/methods/bots/send_game.py
+++ b/pyrogram/client/methods/bots/send_game.py
@@ -24,15 +24,15 @@
class SendGame(BaseClient):
- def send_game(self,
- chat_id: Union[int, str],
- game_short_name: str,
- disable_notification: bool = None,
- reply_to_message_id: int = None,
- reply_markup: Union["pyrogram.InlineKeyboardMarkup",
- "pyrogram.ReplyKeyboardMarkup",
- "pyrogram.ReplyKeyboardRemove",
- "pyrogram.ForceReply"] = None) -> "pyrogram.Message":
+ async def send_game(self,
+ chat_id: Union[int, str],
+ game_short_name: str,
+ disable_notification: bool = None,
+ reply_to_message_id: int = None,
+ reply_markup: Union["pyrogram.InlineKeyboardMarkup",
+ "pyrogram.ReplyKeyboardMarkup",
+ "pyrogram.ReplyKeyboardRemove",
+ "pyrogram.ForceReply"] = None) -> "pyrogram.Message":
"""Use this method to send a game.
Args:
@@ -61,9 +61,9 @@ def send_game(self,
Raises:
:class:`Error ` in case of a Telegram RPC error.
"""
- r = self.send(
+ r = await self.send(
functions.messages.SendMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=types.InputMediaGame(
id=types.InputGameShortName(
bot_id=types.InputUserSelf(),
@@ -80,7 +80,7 @@ def send_game(self,
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return pyrogram.Message._parse(
+ return await pyrogram.Message._parse(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/bots/set_game_score.py b/pyrogram/client/methods/bots/set_game_score.py
index e9d2084477..f90b7f46fa 100644
--- a/pyrogram/client/methods/bots/set_game_score.py
+++ b/pyrogram/client/methods/bots/set_game_score.py
@@ -24,13 +24,13 @@
class SetGameScore(BaseClient):
- def set_game_score(self,
- user_id: Union[int, str],
- score: int,
- force: bool = None,
- disable_edit_message: bool = None,
- chat_id: Union[int, str] = None,
- message_id: int = None):
+ async def set_game_score(self,
+ user_id: Union[int, str],
+ score: int,
+ force: bool = None,
+ disable_edit_message: bool = None,
+ chat_id: Union[int, str] = None,
+ message_id: int = None):
# inline_message_id: str = None): TODO Add inline_message_id
"""Use this method to set the score of the specified user in a game.
@@ -68,12 +68,12 @@ def set_game_score(self,
:class:`Error ` in case of a Telegram RPC error.
:class:`BotScoreNotModified` if the new score is not greater than the user's current score in the chat and force is False.
"""
- r = self.send(
+ r = await self.send(
functions.messages.SetGameScore(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
score=score,
id=message_id,
- user_id=self.resolve_peer(user_id),
+ user_id=await self.resolve_peer(user_id),
force=force or None,
edit_message=not disable_edit_message or None
)
@@ -81,7 +81,7 @@ def set_game_score(self,
for i in r.updates:
if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
- return pyrogram.Message._parse(
+ return await pyrogram.Message._parse(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py
index 772814255f..f17eac930d 100644
--- a/pyrogram/client/types/messages_and_media/message.py
+++ b/pyrogram/client/types/messages_and_media/message.py
@@ -423,7 +423,7 @@ async def _parse(client, message: types.Message or types.MessageService or types
if message.reply_to_msg_id and replies:
try:
- parsed_message.reply_to_message = client.get_messages(
+ parsed_message.reply_to_message = await client.get_messages(
parsed_message.chat.id,
reply_to_message_ids=message.id,
replies=0
@@ -912,7 +912,11 @@ async def click(self, x: int or str, y: int = None, quote: bool = None):
else:
raise ValueError("The message doesn't contain any keyboard")
- async def download(self, file_name: str = "", block: bool = True, progress: callable = None, progress_args: tuple = None):
+ async def download(self,
+ file_name: str = "",
+ block: bool = True,
+ progress: callable = None,
+ progress_args: tuple = None):
"""Bound method *download* of :obj:`Message `.
Use as a shortcut for:
From 63cb4b412e77cb95cef611a5f6ab7d099a5acc45 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 13 Jan 2019 11:21:31 +0100
Subject: [PATCH 0094/1185] Fix PyCharm mess when merged develop into asyncio
---
.../client/methods/messages/send_animation.py | 38 +++++++++----------
.../client/methods/messages/send_audio.py | 38 +++++++++----------
.../client/methods/messages/send_document.py | 38 +++++++++----------
.../client/methods/messages/send_photo.py | 38 +++++++++----------
.../client/methods/messages/send_sticker.py | 38 +++++++++----------
.../client/methods/messages/send_video.py | 38 +++++++++----------
.../methods/messages/send_video_note.py | 38 +++++++++----------
.../client/methods/messages/send_voice.py | 38 +++++++++----------
8 files changed, 152 insertions(+), 152 deletions(-)
diff --git a/pyrogram/client/methods/messages/send_animation.py b/pyrogram/client/methods/messages/send_animation.py
index 1bf0255b0c..44d7d13736 100644
--- a/pyrogram/client/methods/messages/send_animation.py
+++ b/pyrogram/client/methods/messages/send_animation.py
@@ -177,25 +177,25 @@ async def send_animation(self,
while True:
try:
r = await self.send(
- functions.messages.SendMedia(
- peer=await self.resolve_peer(chat_id),
- media=media,
- silent=disable_notification or None,
- reply_to_msg_id=reply_to_message_id,
- random_id=self.rnd_id(),
- reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(caption)
- )
- )
- except FilePartMissing as e:
- await self.save_file(animation, file_id=file.id, file_part=e.x)
- else:
- for i in r.updates:
- if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return await pyrogram.Message._parse(
- self, i.message,
- {i.id: i for i in r.users},
- {i.id: i for i in r.chats}
+ functions.messages.SendMedia(
+ peer=await self.resolve_peer(chat_id),
+ media=media,
+ silent=disable_notification or None,
+ reply_to_msg_id=reply_to_message_id,
+ random_id=self.rnd_id(),
+ reply_markup=reply_markup.write() if reply_markup else None,
+ **style.parse(caption)
)
+ )
+ except FilePartMissing as e:
+ await self.save_file(animation, file_id=file.id, file_part=e.x)
+ else:
+ for i in r.updates:
+ if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
+ return await pyrogram.Message._parse(
+ self, i.message,
+ {i.id: i for i in r.users},
+ {i.id: i for i in r.chats}
+ )
except BaseClient.StopTransmission:
return None
diff --git a/pyrogram/client/methods/messages/send_audio.py b/pyrogram/client/methods/messages/send_audio.py
index ea23f8d385..e333dee41d 100644
--- a/pyrogram/client/methods/messages/send_audio.py
+++ b/pyrogram/client/methods/messages/send_audio.py
@@ -176,25 +176,25 @@ async def send_audio(self,
while True:
try:
r = await self.send(
- functions.messages.SendMedia(
- peer=await self.resolve_peer(chat_id),
- media=media,
- silent=disable_notification or None,
- reply_to_msg_id=reply_to_message_id,
- random_id=self.rnd_id(),
- reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(caption)
- )
- )
- except FilePartMissing as e:
- await self.save_file(audio, file_id=file.id, file_part=e.x)
- else:
- for i in r.updates:
- if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return await pyrogram.Message._parse(
- self, i.message,
- {i.id: i for i in r.users},
- {i.id: i for i in r.chats}
+ functions.messages.SendMedia(
+ peer=await self.resolve_peer(chat_id),
+ media=media,
+ silent=disable_notification or None,
+ reply_to_msg_id=reply_to_message_id,
+ random_id=self.rnd_id(),
+ reply_markup=reply_markup.write() if reply_markup else None,
+ **style.parse(caption)
)
+ )
+ except FilePartMissing as e:
+ await self.save_file(audio, file_id=file.id, file_part=e.x)
+ else:
+ for i in r.updates:
+ if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
+ return await pyrogram.Message._parse(
+ self, i.message,
+ {i.id: i for i in r.users},
+ {i.id: i for i in r.chats}
+ )
except BaseClient.StopTransmission:
return None
diff --git a/pyrogram/client/methods/messages/send_document.py b/pyrogram/client/methods/messages/send_document.py
index f60f7815e8..e9ab937592 100644
--- a/pyrogram/client/methods/messages/send_document.py
+++ b/pyrogram/client/methods/messages/send_document.py
@@ -157,25 +157,25 @@ async def send_document(self,
while True:
try:
r = await self.send(
- functions.messages.SendMedia(
- peer=await self.resolve_peer(chat_id),
- media=media,
- silent=disable_notification or None,
- reply_to_msg_id=reply_to_message_id,
- random_id=self.rnd_id(),
- reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(caption)
- )
- )
- except FilePartMissing as e:
- await self.save_file(document, file_id=file.id, file_part=e.x)
- else:
- for i in r.updates:
- if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return await pyrogram.Message._parse(
- self, i.message,
- {i.id: i for i in r.users},
- {i.id: i for i in r.chats}
+ functions.messages.SendMedia(
+ peer=await self.resolve_peer(chat_id),
+ media=media,
+ silent=disable_notification or None,
+ reply_to_msg_id=reply_to_message_id,
+ random_id=self.rnd_id(),
+ reply_markup=reply_markup.write() if reply_markup else None,
+ **style.parse(caption)
)
+ )
+ except FilePartMissing as e:
+ await self.save_file(document, file_id=file.id, file_part=e.x)
+ else:
+ for i in r.updates:
+ if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
+ return await pyrogram.Message._parse(
+ self, i.message,
+ {i.id: i for i in r.users},
+ {i.id: i for i in r.chats}
+ )
except BaseClient.StopTransmission:
return None
diff --git a/pyrogram/client/methods/messages/send_photo.py b/pyrogram/client/methods/messages/send_photo.py
index d734ee3557..267a71362a 100644
--- a/pyrogram/client/methods/messages/send_photo.py
+++ b/pyrogram/client/methods/messages/send_photo.py
@@ -153,25 +153,25 @@ async def send_photo(self,
while True:
try:
r = await self.send(
- functions.messages.SendMedia(
- peer=await self.resolve_peer(chat_id),
- media=media,
- silent=disable_notification or None,
- reply_to_msg_id=reply_to_message_id,
- random_id=self.rnd_id(),
- reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(caption)
- )
- )
- except FilePartMissing as e:
- await self.save_file(photo, file_id=file.id, file_part=e.x)
- else:
- for i in r.updates:
- if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return await pyrogram.Message._parse(
- self, i.message,
- {i.id: i for i in r.users},
- {i.id: i for i in r.chats}
+ functions.messages.SendMedia(
+ peer=await self.resolve_peer(chat_id),
+ media=media,
+ silent=disable_notification or None,
+ reply_to_msg_id=reply_to_message_id,
+ random_id=self.rnd_id(),
+ reply_markup=reply_markup.write() if reply_markup else None,
+ **style.parse(caption)
)
+ )
+ except FilePartMissing as e:
+ await self.save_file(photo, file_id=file.id, file_part=e.x)
+ else:
+ for i in r.updates:
+ if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
+ return await pyrogram.Message._parse(
+ self, i.message,
+ {i.id: i for i in r.users},
+ {i.id: i for i in r.chats}
+ )
except BaseClient.StopTransmission:
return None
diff --git a/pyrogram/client/methods/messages/send_sticker.py b/pyrogram/client/methods/messages/send_sticker.py
index 172d7c80b4..7525e2f934 100644
--- a/pyrogram/client/methods/messages/send_sticker.py
+++ b/pyrogram/client/methods/messages/send_sticker.py
@@ -137,25 +137,25 @@ async def send_sticker(self,
while True:
try:
r = await self.send(
- functions.messages.SendMedia(
- peer=await self.resolve_peer(chat_id),
- media=media,
- silent=disable_notification or None,
- reply_to_msg_id=reply_to_message_id,
- random_id=self.rnd_id(),
- reply_markup=reply_markup.write() if reply_markup else None,
- message=""
- )
- )
- except FilePartMissing as e:
- await self.save_file(sticker, file_id=file.id, file_part=e.x)
- else:
- for i in r.updates:
- if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return await pyrogram.Message._parse(
- self, i.message,
- {i.id: i for i in r.users},
- {i.id: i for i in r.chats}
+ functions.messages.SendMedia(
+ peer=await self.resolve_peer(chat_id),
+ media=media,
+ silent=disable_notification or None,
+ reply_to_msg_id=reply_to_message_id,
+ random_id=self.rnd_id(),
+ reply_markup=reply_markup.write() if reply_markup else None,
+ message=""
)
+ )
+ except FilePartMissing as e:
+ await self.save_file(sticker, file_id=file.id, file_part=e.x)
+ else:
+ for i in r.updates:
+ if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
+ return await pyrogram.Message._parse(
+ self, i.message,
+ {i.id: i for i in r.users},
+ {i.id: i for i in r.chats}
+ )
except BaseClient.StopTransmission:
return None
diff --git a/pyrogram/client/methods/messages/send_video.py b/pyrogram/client/methods/messages/send_video.py
index ff6020df98..3c202b55dc 100644
--- a/pyrogram/client/methods/messages/send_video.py
+++ b/pyrogram/client/methods/messages/send_video.py
@@ -180,25 +180,25 @@ async def send_video(self,
while True:
try:
r = await self.send(
- functions.messages.SendMedia(
- peer=await self.resolve_peer(chat_id),
- media=media,
- silent=disable_notification or None,
- reply_to_msg_id=reply_to_message_id,
- random_id=self.rnd_id(),
- reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(caption)
- )
- )
- except FilePartMissing as e:
- await self.save_file(video, file_id=file.id, file_part=e.x)
- else:
- for i in r.updates:
- if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return await pyrogram.Message._parse(
- self, i.message,
- {i.id: i for i in r.users},
- {i.id: i for i in r.chats}
+ functions.messages.SendMedia(
+ peer=await self.resolve_peer(chat_id),
+ media=media,
+ silent=disable_notification or None,
+ reply_to_msg_id=reply_to_message_id,
+ random_id=self.rnd_id(),
+ reply_markup=reply_markup.write() if reply_markup else None,
+ **style.parse(caption)
)
+ )
+ except FilePartMissing as e:
+ await self.save_file(video, file_id=file.id, file_part=e.x)
+ else:
+ for i in r.updates:
+ if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
+ return await pyrogram.Message._parse(
+ self, i.message,
+ {i.id: i for i in r.users},
+ {i.id: i for i in r.chats}
+ )
except BaseClient.StopTransmission:
return None
diff --git a/pyrogram/client/methods/messages/send_video_note.py b/pyrogram/client/methods/messages/send_video_note.py
index 712c09f10d..fbc6c98407 100644
--- a/pyrogram/client/methods/messages/send_video_note.py
+++ b/pyrogram/client/methods/messages/send_video_note.py
@@ -155,25 +155,25 @@ async def send_video_note(self,
while True:
try:
r = await self.send(
- functions.messages.SendMedia(
- peer=await self.resolve_peer(chat_id),
- media=media,
- silent=disable_notification or None,
- reply_to_msg_id=reply_to_message_id,
- random_id=self.rnd_id(),
- reply_markup=reply_markup.write() if reply_markup else None,
- message=""
- )
- )
- except FilePartMissing as e:
- await self.save_file(video_note, file_id=file.id, file_part=e.x)
- else:
- for i in r.updates:
- if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return await pyrogram.Message._parse(
- self, i.message,
- {i.id: i for i in r.users},
- {i.id: i for i in r.chats}
+ functions.messages.SendMedia(
+ peer=await self.resolve_peer(chat_id),
+ media=media,
+ silent=disable_notification or None,
+ reply_to_msg_id=reply_to_message_id,
+ random_id=self.rnd_id(),
+ reply_markup=reply_markup.write() if reply_markup else None,
+ message=""
)
+ )
+ except FilePartMissing as e:
+ await self.save_file(video_note, file_id=file.id, file_part=e.x)
+ else:
+ for i in r.updates:
+ if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
+ return await pyrogram.Message._parse(
+ self, i.message,
+ {i.id: i for i in r.users},
+ {i.id: i for i in r.chats}
+ )
except BaseClient.StopTransmission:
return None
diff --git a/pyrogram/client/methods/messages/send_voice.py b/pyrogram/client/methods/messages/send_voice.py
index 458192b8f4..8b6c8e6137 100644
--- a/pyrogram/client/methods/messages/send_voice.py
+++ b/pyrogram/client/methods/messages/send_voice.py
@@ -156,25 +156,25 @@ async def send_voice(self,
while True:
try:
r = await self.send(
- functions.messages.SendMedia(
- peer=await self.resolve_peer(chat_id),
- media=media,
- silent=disable_notification or None,
- reply_to_msg_id=reply_to_message_id,
- random_id=self.rnd_id(),
- reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(caption)
- )
- )
- except FilePartMissing as e:
- await self.save_file(voice, file_id=file.id, file_part=e.x)
- else:
- for i in r.updates:
- if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return await pyrogram.Message._parse(
- self, i.message,
- {i.id: i for i in r.users},
- {i.id: i for i in r.chats}
+ functions.messages.SendMedia(
+ peer=await self.resolve_peer(chat_id),
+ media=media,
+ silent=disable_notification or None,
+ reply_to_msg_id=reply_to_message_id,
+ random_id=self.rnd_id(),
+ reply_markup=reply_markup.write() if reply_markup else None,
+ **style.parse(caption)
)
+ )
+ except FilePartMissing as e:
+ await self.save_file(voice, file_id=file.id, file_part=e.x)
+ else:
+ for i in r.updates:
+ if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
+ return await pyrogram.Message._parse(
+ self, i.message,
+ {i.id: i for i in r.users},
+ {i.id: i for i in r.chats}
+ )
except BaseClient.StopTransmission:
return None
From d72754be1ede4b7c1ffd88a5e1908f634230fff9 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 17 Jan 2019 12:30:40 +0100
Subject: [PATCH 0095/1185] Add missing await
---
pyrogram/client/methods/chats/get_chat.py | 2 +-
pyrogram/client/types/user_and_chats/chat.py | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/pyrogram/client/methods/chats/get_chat.py b/pyrogram/client/methods/chats/get_chat.py
index c868acb524..422cc34d77 100644
--- a/pyrogram/client/methods/chats/get_chat.py
+++ b/pyrogram/client/methods/chats/get_chat.py
@@ -73,4 +73,4 @@ async def get_chat(self,
else:
r = await self.send(functions.messages.GetFullChat(peer.chat_id))
- return pyrogram.Chat._parse_full(self, r)
+ return await pyrogram.Chat._parse_full(self, r)
diff --git a/pyrogram/client/types/user_and_chats/chat.py b/pyrogram/client/types/user_and_chats/chat.py
index ec30b866dc..de1cd63391 100644
--- a/pyrogram/client/types/user_and_chats/chat.py
+++ b/pyrogram/client/types/user_and_chats/chat.py
@@ -174,7 +174,7 @@ def _parse_dialog(client, peer, users: dict, chats: dict):
return Chat._parse_channel_chat(client, chats[peer.channel_id])
@staticmethod
- def _parse_full(client, chat_full: types.messages.ChatFull or types.UserFull) -> "Chat":
+ async def _parse_full(client, chat_full: types.messages.ChatFull or types.UserFull) -> "Chat":
if isinstance(chat_full, types.UserFull):
parsed_chat = Chat._parse_user_chat(client, chat_full.user)
parsed_chat.description = chat_full.about
@@ -200,7 +200,7 @@ def _parse_full(client, chat_full: types.messages.ChatFull or types.UserFull) ->
parsed_chat.sticker_set_name = full_chat.stickerset
if full_chat.pinned_msg_id:
- parsed_chat.pinned_message = client.get_messages(
+ parsed_chat.pinned_message = await client.get_messages(
parsed_chat.id,
message_ids=full_chat.pinned_msg_id
)
From 652b3f90bc8170a41b04b589d147d366a7858424 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 17 Jan 2019 12:34:30 +0100
Subject: [PATCH 0096/1185] Remove async from some method signatures. They are
not asynchronous
---
pyrogram/client/ext/base_client.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index 15d7637b68..d33b5bb995 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -105,10 +105,10 @@ async def send(self, *args, **kwargs):
async def resolve_peer(self, *args, **kwargs):
pass
- async def fetch_peers(self, *args, **kwargs):
+ def fetch_peers(self, *args, **kwargs):
pass
- async def add_handler(self, *args, **kwargs):
+ def add_handler(self, *args, **kwargs):
pass
async def save_file(self, *args, **kwargs):
From e83012bfb844d55c1386f5281a6edc0d75766ffc Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 25 Jan 2019 10:24:04 +0100
Subject: [PATCH 0097/1185] Add missing await keywords
---
pyrogram/client/ext/base_client.py | 2 +-
pyrogram/client/methods/chats/iter_chat_members.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index 80b719af24..d7414530aa 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -126,5 +126,5 @@ async def get_dialogs(self, *args, **kwargs):
async def get_chat_members(self, *args, **kwargs):
pass
- def get_chat_members_count(self, *args, **kwargs):
+ async def get_chat_members_count(self, *args, **kwargs):
pass
diff --git a/pyrogram/client/methods/chats/iter_chat_members.py b/pyrogram/client/methods/chats/iter_chat_members.py
index d1ac8d6af0..ce923b658b 100644
--- a/pyrogram/client/methods/chats/iter_chat_members.py
+++ b/pyrogram/client/methods/chats/iter_chat_members.py
@@ -88,7 +88,7 @@ async def iter_chat_members(self,
filter = (
Filters.RECENT
- if self.get_chat_members_count(chat_id) <= 10000 and filter == Filters.ALL
+ if await self.get_chat_members_count(chat_id) <= 10000 and filter == Filters.ALL
else filter
)
From 58cb30d97cf5b2ea57f2d809f5d9273fa0c7e82c Mon Sep 17 00:00:00 2001
From: MBRCTV <39084010+MBRCTV@users.noreply.github.com>
Date: Tue, 29 Jan 2019 16:36:21 -0500
Subject: [PATCH 0098/1185] Added missing 'await' on thumb
---
pyrogram/client/methods/messages/send_video.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/methods/messages/send_video.py b/pyrogram/client/methods/messages/send_video.py
index 3c202b55dc..aecffe288a 100644
--- a/pyrogram/client/methods/messages/send_video.py
+++ b/pyrogram/client/methods/messages/send_video.py
@@ -133,7 +133,7 @@ async def send_video(self,
try:
if os.path.exists(video):
- thumb = None if thumb is None else self.save_file(thumb)
+ thumb = None if thumb is None else await self.save_file(thumb)
file = await self.save_file(video, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map[".mp4"],
From cc7cb27858255a465fcf46babe48d4bb91b4498b Mon Sep 17 00:00:00 2001
From: MBRCTV <39084010+MBRCTV@users.noreply.github.com>
Date: Wed, 30 Jan 2019 09:45:30 -0500
Subject: [PATCH 0099/1185] Add missing await for send_audio thumbnail upload
(#210)
---
pyrogram/client/methods/messages/send_audio.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/methods/messages/send_audio.py b/pyrogram/client/methods/messages/send_audio.py
index e333dee41d..73208b25c8 100644
--- a/pyrogram/client/methods/messages/send_audio.py
+++ b/pyrogram/client/methods/messages/send_audio.py
@@ -130,7 +130,7 @@ async def send_audio(self,
try:
if os.path.exists(audio):
- thumb = None if thumb is None else self.save_file(thumb)
+ thumb = None if thumb is None else await self.save_file(thumb)
file = await self.save_file(audio, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map.get("." + audio.split(".")[-1], "audio/mpeg"),
From 4eb26c5b9276894b30d4025b14ff22609fcc5609 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 4 Feb 2019 18:34:58 +0100
Subject: [PATCH 0100/1185] Fix sleep method calls in asyncio: time.sleep ->
asyncio.sleep
---
pyrogram/client/client.py | 7 +++----
pyrogram/client/methods/chats/get_dialogs.py | 6 +++---
pyrogram/client/methods/messages/get_history.py | 2 +-
pyrogram/client/methods/messages/get_messages.py | 4 ++--
pyrogram/session/auth.py | 3 ++-
5 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 863856f35a..267aade492 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -48,7 +48,6 @@
VolumeLocNotFound, UserMigrate, FileIdInvalid, ChannelPrivate, PhoneNumberOccupied,
PasswordRecoveryNa, PasswordEmpty
)
-from pyrogram.client.handlers import DisconnectHandler
from pyrogram.client.handlers.handler import Handler
from pyrogram.client.methods.password.utils import compute_check
from pyrogram.crypto import AES
@@ -571,7 +570,7 @@ async def default_phone_number_callback():
raise
else:
print(e.MESSAGE.format(x=e.x))
- time.sleep(e.x)
+ await asyncio.sleep(e.x)
except Exception as e:
log.error(e, exc_info=True)
raise
@@ -707,7 +706,7 @@ async def default_recovery_callback(email_pattern: str) -> str:
raise
else:
print(e.MESSAGE.format(x=e.x))
- time.sleep(e.x)
+ await asyncio.sleep(e.x)
self.password = None
self.recovery_code = None
except Exception as e:
@@ -721,7 +720,7 @@ async def default_recovery_callback(email_pattern: str) -> str:
raise
else:
print(e.MESSAGE.format(x=e.x))
- time.sleep(e.x)
+ await asyncio.sleep(e.x)
except Exception as e:
log.error(e, exc_info=True)
raise
diff --git a/pyrogram/client/methods/chats/get_dialogs.py b/pyrogram/client/methods/chats/get_dialogs.py
index 7d2f44e338..aa6ca91236 100644
--- a/pyrogram/client/methods/chats/get_dialogs.py
+++ b/pyrogram/client/methods/chats/get_dialogs.py
@@ -16,8 +16,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
import logging
-import time
import pyrogram
from pyrogram.api import functions, types
@@ -73,8 +73,8 @@ async def get_dialogs(self,
)
)
except FloodWait as e:
- log.warning("Sleeping {}s".format(e.x))
- time.sleep(e.x)
+ log.warning("Sleeping for {}s".format(e.x))
+ await asyncio.sleep(e.x)
else:
break
diff --git a/pyrogram/client/methods/messages/get_history.py b/pyrogram/client/methods/messages/get_history.py
index ae9925eb86..88e6924460 100644
--- a/pyrogram/client/methods/messages/get_history.py
+++ b/pyrogram/client/methods/messages/get_history.py
@@ -16,8 +16,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
import logging
-import time
from typing import Union
import pyrogram
diff --git a/pyrogram/client/methods/messages/get_messages.py b/pyrogram/client/methods/messages/get_messages.py
index 09a132b6b8..a7b9b75165 100644
--- a/pyrogram/client/methods/messages/get_messages.py
+++ b/pyrogram/client/methods/messages/get_messages.py
@@ -16,8 +16,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
import logging
-import time
from typing import Union, Iterable
import pyrogram
@@ -88,7 +88,7 @@ async def get_messages(self,
r = await self.send(rpc)
except FloodWait as e:
log.warning("Sleeping for {}s".format(e.x))
- time.sleep(e.x)
+ await asyncio.sleep(e.x)
else:
break
diff --git a/pyrogram/session/auth.py b/pyrogram/session/auth.py
index 17b22d6fe1..f966705fac 100644
--- a/pyrogram/session/auth.py
+++ b/pyrogram/session/auth.py
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+import asyncio
import logging
import time
from hashlib import sha1
@@ -254,7 +255,7 @@ async def create(self):
else:
raise e
- time.sleep(1)
+ await asyncio.sleep(1)
continue
else:
return auth_key
From bd56c428c632d3f44d0a1b3df8842dc074092bbd Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 23 Feb 2019 12:09:27 +0100
Subject: [PATCH 0101/1185] Inherit from StopAsyncIteration
---
pyrogram/client/types/update.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/types/update.py b/pyrogram/client/types/update.py
index 2ec22f5a6c..37307111e1 100644
--- a/pyrogram/client/types/update.py
+++ b/pyrogram/client/types/update.py
@@ -17,11 +17,11 @@
# along with Pyrogram. If not, see .
-class StopPropagation(StopIteration):
+class StopPropagation(StopAsyncIteration):
pass
-class ContinuePropagation(StopIteration):
+class ContinuePropagation(StopAsyncIteration):
pass
From 99af3a4180077518d1115e43bee59f92fbb48529 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 3 Mar 2019 17:11:55 +0100
Subject: [PATCH 0102/1185] Tune upload pool size and workers count Use 1
worker only in case of small files
---
pyrogram/client/client.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index f58d3ceb57..5181b0299d 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -1447,11 +1447,13 @@ async def worker(session):
file_total_parts = int(math.ceil(file_size / part_size))
is_big = file_size > 10 * 1024 * 1024
+ pool_size = 3 if is_big else 1
+ workers_count = 4 if is_big else 1
is_missing_part = file_id is not None
file_id = file_id or self.rnd_id()
md5_sum = md5() if not is_big and not is_missing_part else None
- pool = [Session(self, self.dc_id, self.auth_key, is_media=True) for _ in range(3)]
- workers = [asyncio.ensure_future(worker(session)) for session in pool for _ in range(4)]
+ pool = [Session(self, self.dc_id, self.auth_key, is_media=True) for _ in range(pool_size)]
+ workers = [asyncio.ensure_future(worker(session)) for session in pool for _ in range(workers_count)]
queue = asyncio.Queue(16)
try:
From 2078e6da282d29320aa7336f2a5fdca8b0cb1b01 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 11 Mar 2019 21:27:25 +0100
Subject: [PATCH 0103/1185] Turn send_cached_media async
---
pyrogram/client/methods/messages/send_cached_media.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/pyrogram/client/methods/messages/send_cached_media.py b/pyrogram/client/methods/messages/send_cached_media.py
index 843b719771..afcde68d8b 100644
--- a/pyrogram/client/methods/messages/send_cached_media.py
+++ b/pyrogram/client/methods/messages/send_cached_media.py
@@ -27,7 +27,7 @@
class SendCachedMedia(BaseClient):
- def send_cached_media(
+ async def send_cached_media(
self,
chat_id: Union[int, str],
file_id: str,
@@ -114,9 +114,9 @@ def send_cached_media(
)
)
- r = self.send(
+ r = await self.send(
functions.messages.SendMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
@@ -128,7 +128,7 @@ def send_cached_media(
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
- return pyrogram.Message._parse(
+ return await pyrogram.Message._parse(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
From 3d23b681e3387daffa1f95aa684cbd04649f4b77 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 12 Mar 2019 16:48:34 +0100
Subject: [PATCH 0104/1185] Add missing await
---
pyrogram/client/methods/chats/iter_chat_members.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/methods/chats/iter_chat_members.py b/pyrogram/client/methods/chats/iter_chat_members.py
index 5b91e81cf2..f9e3294fdb 100644
--- a/pyrogram/client/methods/chats/iter_chat_members.py
+++ b/pyrogram/client/methods/chats/iter_chat_members.py
@@ -86,7 +86,7 @@ async def iter_chat_members(self,
queries = [query] if query else QUERIES
total = limit or (1 << 31) - 1
limit = min(200, total)
- resolved_chat_id = self.resolve_peer(chat_id)
+ resolved_chat_id = await self.resolve_peer(chat_id)
filter = (
Filters.RECENT
From a329e56259484cdf79b061a9e56a3112a5c9a9ad Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 16 Mar 2019 19:56:04 +0100
Subject: [PATCH 0105/1185] Fix import order causing errors
---
pyrogram/api/errors/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/api/errors/__init__.py b/pyrogram/api/errors/__init__.py
index 8a1dc699fa..ca65619ccc 100644
--- a/pyrogram/api/errors/__init__.py
+++ b/pyrogram/api/errors/__init__.py
@@ -16,5 +16,5 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from .error import UnknownError
from .exceptions import *
+from .error import UnknownError
From a06885dd14956029c76e4554b122829dbc068b48 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 16 Mar 2019 19:56:25 +0100
Subject: [PATCH 0106/1185] Add support for "async with" context manager
---
pyrogram/client/client.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index bf0401da63..0327615ac0 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -243,6 +243,12 @@ def __enter__(self):
def __exit__(self, *args):
self.stop()
+ async def __aenter__(self):
+ return await self.start()
+
+ async def __aexit__(self, *args):
+ await self.stop()
+
@property
def proxy(self):
return self._proxy
From ac318831dc0feb6151e63da1bf2ff28ed8ed036a Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 22 Mar 2019 13:47:31 +0100
Subject: [PATCH 0107/1185] Add missing awaits
---
pyrogram/client/ext/base_client.py | 2 +-
pyrogram/client/methods/bots/answer_inline_query.py | 4 ++--
pyrogram/client/types/inline_mode/inline_query.py | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index 1e10a7b33a..3432858940 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -129,5 +129,5 @@ async def get_chat_members(self, *args, **kwargs):
async def get_chat_members_count(self, *args, **kwargs):
pass
- def answer_inline_query(self, *args, **kwargs):
+ async def answer_inline_query(self, *args, **kwargs):
pass
diff --git a/pyrogram/client/methods/bots/answer_inline_query.py b/pyrogram/client/methods/bots/answer_inline_query.py
index 7b3524b23d..65f2ff3a6d 100644
--- a/pyrogram/client/methods/bots/answer_inline_query.py
+++ b/pyrogram/client/methods/bots/answer_inline_query.py
@@ -24,7 +24,7 @@
class AnswerInlineQuery(BaseClient):
- def answer_inline_query(
+ async def answer_inline_query(
self,
inline_query_id: str,
results: List[InlineQueryResult],
@@ -75,7 +75,7 @@ def answer_inline_query(
Returns:
On success, True is returned.
"""
- return self.send(
+ return await self.send(
functions.messages.SetInlineBotResults(
query_id=int(inline_query_id),
results=[r.write() for r in results],
diff --git a/pyrogram/client/types/inline_mode/inline_query.py b/pyrogram/client/types/inline_mode/inline_query.py
index 9c1c02aceb..737960ca72 100644
--- a/pyrogram/client/types/inline_mode/inline_query.py
+++ b/pyrogram/client/types/inline_mode/inline_query.py
@@ -83,7 +83,7 @@ def _parse(client, inline_query: types.UpdateBotInlineQuery, users: dict) -> "In
client=client
)
- def answer(
+ async def answer(
self,
results: List[InlineQueryResult],
cache_time: int = 300,
@@ -141,7 +141,7 @@ def answer(
where they wanted to use the bot's inline capabilities.
"""
- return self._client.answer_inline_query(
+ return await self._client.answer_inline_query(
inline_query_id=self.id,
results=results,
cache_time=cache_time,
From 7f7f9768fd9c150b2ba8db72228455a64c6fe25f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 27 Mar 2019 14:59:55 +0100
Subject: [PATCH 0108/1185] Add missing awaits
---
pyrogram/client/client.py | 6 +++---
pyrogram/client/methods/messages/edit_message_caption.py | 2 +-
pyrogram/client/methods/messages/edit_message_media.py | 2 +-
pyrogram/client/methods/messages/edit_message_text.py | 2 +-
pyrogram/client/methods/messages/send_animation.py | 2 +-
pyrogram/client/methods/messages/send_audio.py | 2 +-
pyrogram/client/methods/messages/send_cached_media.py | 2 +-
pyrogram/client/methods/messages/send_document.py | 2 +-
pyrogram/client/methods/messages/send_media_group.py | 2 +-
pyrogram/client/methods/messages/send_message.py | 2 +-
pyrogram/client/methods/messages/send_photo.py | 2 +-
pyrogram/client/methods/messages/send_video.py | 2 +-
pyrogram/client/methods/messages/send_voice.py | 2 +-
pyrogram/client/style/html.py | 6 +++---
pyrogram/client/style/markdown.py | 4 ++--
15 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 6f654099b9..bda5f4372a 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -1362,7 +1362,7 @@ async def resolve_peer(self,
if peer_id > 0:
self.fetch_peers(
- self.send(
+ await self.send(
functions.users.GetUsers(
id=[types.InputUser(user_id=peer_id, access_hash=0)]
)
@@ -1370,13 +1370,13 @@ async def resolve_peer(self,
)
else:
if str(peer_id).startswith("-100"):
- self.send(
+ await self.send(
functions.channels.GetChannels(
id=[types.InputChannel(channel_id=int(str(peer_id)[4:]), access_hash=0)]
)
)
else:
- self.send(
+ await self.send(
functions.messages.GetChats(
id=[-peer_id]
)
diff --git a/pyrogram/client/methods/messages/edit_message_caption.py b/pyrogram/client/methods/messages/edit_message_caption.py
index 22e090fc58..8fd89dc6ee 100644
--- a/pyrogram/client/methods/messages/edit_message_caption.py
+++ b/pyrogram/client/methods/messages/edit_message_caption.py
@@ -67,7 +67,7 @@ async def edit_message_caption(
peer=await self.resolve_peer(chat_id),
id=message_id,
reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(caption)
+ **await style.parse(caption)
)
)
diff --git a/pyrogram/client/methods/messages/edit_message_media.py b/pyrogram/client/methods/messages/edit_message_media.py
index 2d9aa23baa..a5ae56fe1c 100644
--- a/pyrogram/client/methods/messages/edit_message_media.py
+++ b/pyrogram/client/methods/messages/edit_message_media.py
@@ -353,7 +353,7 @@ async def edit_message_media(
id=message_id,
reply_markup=reply_markup.write() if reply_markup else None,
media=media,
- **style.parse(caption)
+ **await style.parse(caption)
)
)
diff --git a/pyrogram/client/methods/messages/edit_message_text.py b/pyrogram/client/methods/messages/edit_message_text.py
index b37255a22a..fac74f8953 100644
--- a/pyrogram/client/methods/messages/edit_message_text.py
+++ b/pyrogram/client/methods/messages/edit_message_text.py
@@ -72,7 +72,7 @@ async def edit_message_text(
id=message_id,
no_webpage=disable_web_page_preview or None,
reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(text)
+ **await style.parse(text)
)
)
diff --git a/pyrogram/client/methods/messages/send_animation.py b/pyrogram/client/methods/messages/send_animation.py
index 507cf6f935..ffe70fd9c4 100644
--- a/pyrogram/client/methods/messages/send_animation.py
+++ b/pyrogram/client/methods/messages/send_animation.py
@@ -187,7 +187,7 @@ async def send_animation(
reply_to_msg_id=reply_to_message_id,
random_id=self.rnd_id(),
reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(caption)
+ **await style.parse(caption)
)
)
except FilePartMissing as e:
diff --git a/pyrogram/client/methods/messages/send_audio.py b/pyrogram/client/methods/messages/send_audio.py
index ea3a0ac476..f620b25b6b 100644
--- a/pyrogram/client/methods/messages/send_audio.py
+++ b/pyrogram/client/methods/messages/send_audio.py
@@ -186,7 +186,7 @@ async def send_audio(
reply_to_msg_id=reply_to_message_id,
random_id=self.rnd_id(),
reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(caption)
+ **await style.parse(caption)
)
)
except FilePartMissing as e:
diff --git a/pyrogram/client/methods/messages/send_cached_media.py b/pyrogram/client/methods/messages/send_cached_media.py
index 9511c548b6..b9f004958a 100644
--- a/pyrogram/client/methods/messages/send_cached_media.py
+++ b/pyrogram/client/methods/messages/send_cached_media.py
@@ -122,7 +122,7 @@ async def send_cached_media(
reply_to_msg_id=reply_to_message_id,
random_id=self.rnd_id(),
reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(caption)
+ **await style.parse(caption)
)
)
diff --git a/pyrogram/client/methods/messages/send_document.py b/pyrogram/client/methods/messages/send_document.py
index 123a79fc24..ebdae53471 100644
--- a/pyrogram/client/methods/messages/send_document.py
+++ b/pyrogram/client/methods/messages/send_document.py
@@ -167,7 +167,7 @@ async def send_document(
reply_to_msg_id=reply_to_message_id,
random_id=self.rnd_id(),
reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(caption)
+ **await style.parse(caption)
)
)
except FilePartMissing as e:
diff --git a/pyrogram/client/methods/messages/send_media_group.py b/pyrogram/client/methods/messages/send_media_group.py
index 40c5306635..32b6af5934 100644
--- a/pyrogram/client/methods/messages/send_media_group.py
+++ b/pyrogram/client/methods/messages/send_media_group.py
@@ -183,7 +183,7 @@ async def send_media_group(
types.InputSingleMedia(
media=media,
random_id=self.rnd_id(),
- **style.parse(i.caption)
+ **await style.parse(i.caption)
)
)
diff --git a/pyrogram/client/methods/messages/send_message.py b/pyrogram/client/methods/messages/send_message.py
index 7c36800e29..090bd63cb1 100644
--- a/pyrogram/client/methods/messages/send_message.py
+++ b/pyrogram/client/methods/messages/send_message.py
@@ -76,7 +76,7 @@ async def send_message(
:class:`RPCError ` in case of a Telegram RPC error.
"""
style = self.html if parse_mode.lower() == "html" else self.markdown
- message, entities = style.parse(text).values()
+ message, entities = (await style.parse(text)).values()
r = await self.send(
functions.messages.SendMessage(
diff --git a/pyrogram/client/methods/messages/send_photo.py b/pyrogram/client/methods/messages/send_photo.py
index 5686dfdc50..0030223368 100644
--- a/pyrogram/client/methods/messages/send_photo.py
+++ b/pyrogram/client/methods/messages/send_photo.py
@@ -164,7 +164,7 @@ async def send_photo(
reply_to_msg_id=reply_to_message_id,
random_id=self.rnd_id(),
reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(caption)
+ **await style.parse(caption)
)
)
except FilePartMissing as e:
diff --git a/pyrogram/client/methods/messages/send_video.py b/pyrogram/client/methods/messages/send_video.py
index 00a717e467..a9c72df858 100644
--- a/pyrogram/client/methods/messages/send_video.py
+++ b/pyrogram/client/methods/messages/send_video.py
@@ -190,7 +190,7 @@ async def send_video(
reply_to_msg_id=reply_to_message_id,
random_id=self.rnd_id(),
reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(caption)
+ **await style.parse(caption)
)
)
except FilePartMissing as e:
diff --git a/pyrogram/client/methods/messages/send_voice.py b/pyrogram/client/methods/messages/send_voice.py
index 588bb446fb..3d8bfaf2b0 100644
--- a/pyrogram/client/methods/messages/send_voice.py
+++ b/pyrogram/client/methods/messages/send_voice.py
@@ -166,7 +166,7 @@ async def send_voice(
reply_to_msg_id=reply_to_message_id,
random_id=self.rnd_id(),
reply_markup=reply_markup.write() if reply_markup else None,
- **style.parse(caption)
+ **await style.parse(caption)
)
)
except FilePartMissing as e:
diff --git a/pyrogram/client/style/html.py b/pyrogram/client/style/html.py
index 9c0a372c49..d9aec531ac 100644
--- a/pyrogram/client/style/html.py
+++ b/pyrogram/client/style/html.py
@@ -40,9 +40,9 @@ class HTML:
def __init__(self, client: "pyrogram.BaseClient" = None):
self.client = client
- def parse(self, message: str):
- entities = []
+ async def parse(self, message: str):
message = utils.add_surrogates(str(message or ""))
+ entities = []
offset = 0
for match in self.HTML_RE.finditer(message):
@@ -56,7 +56,7 @@ def parse(self, message: str):
user_id = int(mention.group(1))
try:
- input_user = self.client.resolve_peer(user_id)
+ input_user = await self.client.resolve_peer(user_id)
except PeerIdInvalid:
input_user = None
diff --git a/pyrogram/client/style/markdown.py b/pyrogram/client/style/markdown.py
index adb86e94fc..1174c639c0 100644
--- a/pyrogram/client/style/markdown.py
+++ b/pyrogram/client/style/markdown.py
@@ -57,7 +57,7 @@ class Markdown:
def __init__(self, client: "pyrogram.BaseClient" = None):
self.client = client
- def parse(self, message: str):
+ async def parse(self, message: str):
message = utils.add_surrogates(str(message or "")).strip()
entities = []
offset = 0
@@ -73,7 +73,7 @@ def parse(self, message: str):
user_id = int(mention.group(1))
try:
- input_user = self.client.resolve_peer(user_id)
+ input_user = await self.client.resolve_peer(user_id)
except PeerIdInvalid:
input_user = None
From 29940fbc662d5906977a8718ca98a62d61e1bec3 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 27 Mar 2019 15:44:29 +0100
Subject: [PATCH 0109/1185] Fix StopTransmission in asyncio by inheriting from
StopAsyncIteration Instead of StopIteration
---
pyrogram/client/ext/base_client.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index 7e9f51a1e2..ae05c1f2d7 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -26,7 +26,7 @@
class BaseClient:
- class StopTransmission(StopIteration):
+ class StopTransmission(StopAsyncIteration):
pass
APP_VERSION = "Pyrogram \U0001f525 {}".format(__version__)
From 95a7befed50d8094b95e12d29c2c95301c0f3b8c Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 8 Apr 2019 16:50:48 +0200
Subject: [PATCH 0110/1185] Update async version
---
pyrogram/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index d1e195fab6..962b8782bf 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -18,7 +18,7 @@
import sys
-__version__ = "0.12.0.develop"
+__version__ = "0.12.0.async"
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
__copyright__ = "Copyright (C) 2017-2019 Dan Tès ".replace(
"\xe8", "e" if sys.getfilesystemencoding() != "utf-8" else "\xe8"
From ad49e72f02757618d51d89dfd518370bf48f579f Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 13 Apr 2019 17:32:18 +0200
Subject: [PATCH 0111/1185] Fix inline_query_parser in asyncio branch
---
pyrogram/client/ext/dispatcher.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/ext/dispatcher.py b/pyrogram/client/ext/dispatcher.py
index 8ecb092904..f1358b86b5 100644
--- a/pyrogram/client/ext/dispatcher.py
+++ b/pyrogram/client/ext/dispatcher.py
@@ -74,7 +74,7 @@ async def user_status_parser(update, users, chats):
return pyrogram.UserStatus._parse(self.client, update.status, update.user_id), UserStatusHandler
async def inline_query_parser(update, users, chats):
- return pyrogram.InlineQuery._parse(self.client, update.status, update.user_id), UserStatusHandler
+ return pyrogram.InlineQuery._parse(self.client, update, users), InlineQueryHandler
self.update_parsers = {
Dispatcher.MESSAGE_UPDATES: message_parser,
From 1750300ab93ea04d3058b51e8843f080eb18671d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 13 Apr 2019 17:51:47 +0200
Subject: [PATCH 0112/1185] Add missing awaits
---
pyrogram/client/methods/bots/answer_inline_query.py | 7 ++++++-
pyrogram/client/types/inline_mode/inline_query_result.py | 2 +-
.../types/inline_mode/inline_query_result_article.py | 4 ++--
.../input_message_content/input_text_message_content.py | 4 ++--
4 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/pyrogram/client/methods/bots/answer_inline_query.py b/pyrogram/client/methods/bots/answer_inline_query.py
index 65f2ff3a6d..88a661d0d9 100644
--- a/pyrogram/client/methods/bots/answer_inline_query.py
+++ b/pyrogram/client/methods/bots/answer_inline_query.py
@@ -75,10 +75,15 @@ async def answer_inline_query(
Returns:
On success, True is returned.
"""
+ written_results = [] # Py 3.5 doesn't support await inside comprehensions
+
+ for r in results:
+ written_results.append(await r.write())
+
return await self.send(
functions.messages.SetInlineBotResults(
query_id=int(inline_query_id),
- results=[r.write() for r in results],
+ results=written_results,
cache_time=cache_time,
gallery=None,
private=is_personal or None,
diff --git a/pyrogram/client/types/inline_mode/inline_query_result.py b/pyrogram/client/types/inline_mode/inline_query_result.py
index 3e7fcb02b2..6fd1975ddb 100644
--- a/pyrogram/client/types/inline_mode/inline_query_result.py
+++ b/pyrogram/client/types/inline_mode/inline_query_result.py
@@ -55,5 +55,5 @@ def __init__(self, type: str, id: str):
self.type = type
self.id = id
- def write(self):
+ async def write(self):
pass
diff --git a/pyrogram/client/types/inline_mode/inline_query_result_article.py b/pyrogram/client/types/inline_mode/inline_query_result_article.py
index 8d0089c331..3f0c299770 100644
--- a/pyrogram/client/types/inline_mode/inline_query_result_article.py
+++ b/pyrogram/client/types/inline_mode/inline_query_result_article.py
@@ -84,11 +84,11 @@ def __init__(
self.thumb_width = thumb_width
self.thumb_height = thumb_height
- def write(self):
+ async def write(self):
return types.InputBotInlineResult(
id=str(self.id),
type=self.type,
- send_message=self.input_message_content.write(self.reply_markup),
+ send_message=await self.input_message_content.write(self.reply_markup),
title=self.title,
description=self.description,
url=self.url,
diff --git a/pyrogram/client/types/input_message_content/input_text_message_content.py b/pyrogram/client/types/input_message_content/input_text_message_content.py
index 0e6ffa8b71..dda1f3f3b9 100644
--- a/pyrogram/client/types/input_message_content/input_text_message_content.py
+++ b/pyrogram/client/types/input_message_content/input_text_message_content.py
@@ -46,9 +46,9 @@ def __init__(self, message_text: str, parse_mode: str = "", disable_web_page_pre
self.parse_mode = parse_mode
self.disable_web_page_preview = disable_web_page_preview
- def write(self, reply_markup):
+ async def write(self, reply_markup):
return types.InputBotInlineMessageText(
no_webpage=self.disable_web_page_preview or None,
reply_markup=reply_markup.write() if reply_markup else None,
- **(HTML() if self.parse_mode.lower() == "html" else Markdown()).parse(self.message_text)
+ **await(HTML() if self.parse_mode.lower() == "html" else Markdown()).parse(self.message_text)
)
From 1dd3ba4133258c81b8cbcee37b35bfb60d9e55d2 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 14 Apr 2019 18:47:45 +0200
Subject: [PATCH 0113/1185] Add missing awaits
---
pyrogram/client/methods/users/set_user_profile_photo.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pyrogram/client/methods/users/set_user_profile_photo.py b/pyrogram/client/methods/users/set_user_profile_photo.py
index af02a12dc2..5a155b94af 100644
--- a/pyrogram/client/methods/users/set_user_profile_photo.py
+++ b/pyrogram/client/methods/users/set_user_profile_photo.py
@@ -21,7 +21,7 @@
class SetUserProfilePhoto(BaseClient):
- def set_user_profile_photo(
+ async def set_user_profile_photo(
self,
photo: str
) -> bool:
@@ -43,9 +43,9 @@ def set_user_profile_photo(
"""
return bool(
- self.send(
+ await self.send(
functions.photos.UploadProfilePhoto(
- file=self.save_file(photo)
+ file=await self.save_file(photo)
)
)
)
From 8dd99a868378d7b1109342fb0d71d01560ce90ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Joscha=20G=C3=B6tzer?=
Date: Tue, 30 Apr 2019 11:49:18 +0200
Subject: [PATCH 0114/1185] Use str or bytes for callback_data and
CallbackQuery.data (#241)
---
pyrogram/client/types/bots/callback_query.py | 2 +-
pyrogram/client/types/bots/inline_keyboard_button.py | 5 +++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/pyrogram/client/types/bots/callback_query.py b/pyrogram/client/types/bots/callback_query.py
index 30a5333fe3..767d768c0b 100644
--- a/pyrogram/client/types/bots/callback_query.py
+++ b/pyrogram/client/types/bots/callback_query.py
@@ -79,7 +79,7 @@ def __init__(
self.chat_instance = chat_instance
self.message = message
self.inline_message_id = inline_message_id
- self.data = data
+ self.data: str = str(data, "utf-8")
self.game_short_name = game_short_name
@staticmethod
diff --git a/pyrogram/client/types/bots/inline_keyboard_button.py b/pyrogram/client/types/bots/inline_keyboard_button.py
index c0c3eb8cbf..5e225846c3 100644
--- a/pyrogram/client/types/bots/inline_keyboard_button.py
+++ b/pyrogram/client/types/bots/inline_keyboard_button.py
@@ -15,6 +15,7 @@
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
+from typing import Union
from pyrogram.api.types import (
KeyboardButtonUrl, KeyboardButtonCallback,
@@ -61,7 +62,7 @@ class InlineKeyboardButton(PyrogramType):
def __init__(
self,
text: str,
- callback_data: bytes = None,
+ callback_data: Union[str, bytes] = None,
url: str = None,
switch_inline_query: str = None,
switch_inline_query_current_chat: str = None,
@@ -71,7 +72,7 @@ def __init__(
self.text = str(text)
self.url = url
- self.callback_data = callback_data
+ self.callback_data = bytes(callback_data, "utf-8") if isinstance(callback_data, str) else callback_data
self.switch_inline_query = switch_inline_query
self.switch_inline_query_current_chat = switch_inline_query_current_chat
self.callback_game = callback_game
From ec258312dd5af2958d845adf202060493f0638d8 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 3 May 2019 22:47:51 +0200
Subject: [PATCH 0115/1185] Add missing awaits
---
pyrogram/client/methods/chats/update_chat_username.py | 6 +++---
pyrogram/client/methods/users/update_username.py | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/pyrogram/client/methods/chats/update_chat_username.py b/pyrogram/client/methods/chats/update_chat_username.py
index 39cdfaeb99..12f5fe12ff 100644
--- a/pyrogram/client/methods/chats/update_chat_username.py
+++ b/pyrogram/client/methods/chats/update_chat_username.py
@@ -23,7 +23,7 @@
class UpdateChatUsername(BaseClient):
- def update_chat_username(
+ async def update_chat_username(
self,
chat_id: Union[int, str],
username: Union[str, None]
@@ -46,11 +46,11 @@ def update_chat_username(
``ValueError`` if a chat_id belongs to a user or chat.
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChannel):
return bool(
- self.send(
+ await self.send(
functions.channels.UpdateUsername(
channel=peer,
username=username or ""
diff --git a/pyrogram/client/methods/users/update_username.py b/pyrogram/client/methods/users/update_username.py
index d0c87eb2f1..15877992b4 100644
--- a/pyrogram/client/methods/users/update_username.py
+++ b/pyrogram/client/methods/users/update_username.py
@@ -23,7 +23,7 @@
class UpdateUsername(BaseClient):
- def update_username(
+ async def update_username(
self,
username: Union[str, None]
) -> bool:
@@ -45,7 +45,7 @@ def update_username(
"""
return bool(
- self.send(
+ await self.send(
functions.account.UpdateUsername(
username=username or ""
)
From a6198921c3ec66fc53b6921b991b9739071679ac Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 3 May 2019 22:55:00 +0200
Subject: [PATCH 0116/1185] Fix an unresolved reference
---
pyrogram/client/methods/messages/delete_messages.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/methods/messages/delete_messages.py b/pyrogram/client/methods/messages/delete_messages.py
index 9dc4cf3983..9eb42867c9 100644
--- a/pyrogram/client/methods/messages/delete_messages.py
+++ b/pyrogram/client/methods/messages/delete_messages.py
@@ -57,14 +57,14 @@ async def delete_messages(
message_ids = list(message_ids) if not isinstance(message_ids, int) else [message_ids]
if isinstance(peer, types.InputPeerChannel):
- await self.send(
+ r = await self.send(
functions.channels.DeleteMessages(
channel=peer,
id=message_ids
)
)
else:
- await self.send(
+ r = await self.send(
functions.messages.DeleteMessages(
id=message_ids,
revoke=revoke or None
From 762ea3e62ef6de512c7df74511196aef9be25925 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 6 May 2019 17:39:57 +0200
Subject: [PATCH 0117/1185] Add an hint about which client is loading the
plugins
---
pyrogram/client/client.py | 40 ++++++++++++++++++++++-----------------
1 file changed, 23 insertions(+), 17 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index b1366b2625..ce8ae2fd80 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -53,8 +53,8 @@
PasswordRecoveryNa, PasswordEmpty
)
from pyrogram.session import Auth, Session
-from .ext.utils import ainput
from .ext import utils, Syncer, BaseClient, Dispatcher
+from .ext.utils import ainput
from .methods import Methods
log = logging.getLogger(__name__)
@@ -1181,8 +1181,8 @@ def load_plugins(self):
if isinstance(handler, Handler) and isinstance(group, int):
self.add_handler(handler, group)
- log.info('[LOAD] {}("{}") in group {} from "{}"'.format(
- type(handler).__name__, name, group, module_path))
+ log.info('[{}] [LOAD] {}("{}") in group {} from "{}"'.format(
+ self.session_name, type(handler).__name__, name, group, module_path))
count += 1
except Exception:
@@ -1195,11 +1195,13 @@ def load_plugins(self):
try:
module = import_module(module_path)
except ImportError:
- log.warning('[LOAD] Ignoring non-existent module "{}"'.format(module_path))
+ log.warning('[{}] [LOAD] Ignoring non-existent module "{}"'.format(
+ self.session_name, module_path))
continue
if "__path__" in dir(module):
- log.warning('[LOAD] Ignoring namespace "{}"'.format(module_path))
+ log.warning('[{}] [LOAD] Ignoring namespace "{}"'.format(
+ self.session_name, module_path))
continue
if handlers is None:
@@ -1214,14 +1216,14 @@ def load_plugins(self):
if isinstance(handler, Handler) and isinstance(group, int):
self.add_handler(handler, group)
- log.info('[LOAD] {}("{}") in group {} from "{}"'.format(
- type(handler).__name__, name, group, module_path))
+ log.info('[{}] [LOAD] {}("{}") in group {} from "{}"'.format(
+ self.session_name, type(handler).__name__, name, group, module_path))
count += 1
except Exception:
if warn_non_existent_functions:
- log.warning('[LOAD] Ignoring non-existent function "{}" from "{}"'.format(
- name, module_path))
+ log.warning('[{}] [LOAD] Ignoring non-existent function "{}" from "{}"'.format(
+ self.session_name, name, module_path))
if exclude is not None:
for path, handlers in exclude:
@@ -1231,11 +1233,13 @@ def load_plugins(self):
try:
module = import_module(module_path)
except ImportError:
- log.warning('[UNLOAD] Ignoring non-existent module "{}"'.format(module_path))
+ log.warning('[{}] [UNLOAD] Ignoring non-existent module "{}"'.format(
+ self.session_name, module_path))
continue
if "__path__" in dir(module):
- log.warning('[UNLOAD] Ignoring namespace "{}"'.format(module_path))
+ log.warning('[{}] [UNLOAD] Ignoring namespace "{}"'.format(
+ self.session_name, module_path))
continue
if handlers is None:
@@ -1250,19 +1254,21 @@ def load_plugins(self):
if isinstance(handler, Handler) and isinstance(group, int):
self.remove_handler(handler, group)
- log.info('[UNLOAD] {}("{}") from group {} in "{}"'.format(
- type(handler).__name__, name, group, module_path))
+ log.info('[{}] [UNLOAD] {}("{}") from group {} in "{}"'.format(
+ self.session_name, type(handler).__name__, name, group, module_path))
count -= 1
except Exception:
if warn_non_existent_functions:
- log.warning('[UNLOAD] Ignoring non-existent function "{}" from "{}"'.format(
- name, module_path))
+ log.warning('[{}] [UNLOAD] Ignoring non-existent function "{}" from "{}"'.format(
+ self.session_name, name, module_path))
if count > 0:
- log.warning('Successfully loaded {} plugin{} from "{}"'.format(count, "s" if count > 1 else "", root))
+ log.warning('[{}] Successfully loaded {} plugin{} from "{}"'.format(
+ self.session_name, count, "s" if count > 1 else "", root))
else:
- log.warning('No plugin loaded from "{}"'.format(root))
+ log.warning('[{}] No plugin loaded from "{}"'.format(
+ self.session_name, root))
def save_session(self):
auth_key = base64.b64encode(self.auth_key).decode()
From b3d6b41ca8fda79c60b43d5dfb214ab0fa20a8df Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 5 Jun 2019 11:28:29 +0200
Subject: [PATCH 0118/1185] Fix Syncer not creating Event and Lock objects
inside the current loop
---
pyrogram/client/ext/syncer.py | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/ext/syncer.py b/pyrogram/client/ext/syncer.py
index a9fc422187..c5f15c1a4c 100644
--- a/pyrogram/client/ext/syncer.py
+++ b/pyrogram/client/ext/syncer.py
@@ -33,11 +33,17 @@ class Syncer:
INTERVAL = 20
clients = {}
- event = asyncio.Event()
- lock = asyncio.Lock()
+ event = None
+ lock = None
@classmethod
async def add(cls, client):
+ if cls.event is None:
+ cls.event = asyncio.Event()
+
+ if cls.lock is None:
+ cls.lock = asyncio.Lock()
+
with await cls.lock:
cls.sync(client)
From 9bd9d7797b0e6bc1f29563506e7749f5cbf8ccdd Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 5 Jun 2019 11:58:29 +0200
Subject: [PATCH 0119/1185] Replace "with await" with "async with"
---
pyrogram/client/client.py | 4 ++--
pyrogram/client/ext/syncer.py | 6 +++---
pyrogram/connection/transport/tcp/tcp.py | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index b624174619..d81c3707e8 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -1555,7 +1555,7 @@ async def get_file(self, media_type: int,
is_big: bool,
progress: callable,
progress_args: tuple = ()) -> str:
- with await self.media_sessions_lock:
+ async with self.media_sessions_lock:
session = self.media_sessions.get(dc_id, None)
if session is None:
@@ -1670,7 +1670,7 @@ async def get_file(self, media_type: int,
)
elif isinstance(r, types.upload.FileCdnRedirect):
- with await self.media_sessions_lock:
+ async with self.media_sessions_lock:
cdn_session = self.media_sessions.get(r.dc_id, None)
if cdn_session is None:
diff --git a/pyrogram/client/ext/syncer.py b/pyrogram/client/ext/syncer.py
index c5f15c1a4c..88caa1606f 100644
--- a/pyrogram/client/ext/syncer.py
+++ b/pyrogram/client/ext/syncer.py
@@ -44,7 +44,7 @@ async def add(cls, client):
if cls.lock is None:
cls.lock = asyncio.Lock()
- with await cls.lock:
+ async with cls.lock:
cls.sync(client)
cls.clients[id(client)] = client
@@ -54,7 +54,7 @@ async def add(cls, client):
@classmethod
async def remove(cls, client):
- with await cls.lock:
+ async with cls.lock:
cls.sync(client)
del cls.clients[id(client)]
@@ -77,7 +77,7 @@ async def worker(cls):
try:
await asyncio.wait_for(cls.event.wait(), cls.INTERVAL)
except asyncio.TimeoutError:
- with await cls.lock:
+ async with cls.lock:
for client in cls.clients.values():
cls.sync(client)
else:
diff --git a/pyrogram/connection/transport/tcp/tcp.py b/pyrogram/connection/transport/tcp/tcp.py
index 237c5c599c..0d33fcd97c 100644
--- a/pyrogram/connection/transport/tcp/tcp.py
+++ b/pyrogram/connection/transport/tcp/tcp.py
@@ -92,7 +92,7 @@ def close(self):
self.socket.close()
async def send(self, data: bytes):
- with await self.lock:
+ async with self.lock:
self.writer.write(data)
await self.writer.drain()
From 2ba445d21e2dff947e7d1e7d0fcfd71b597cf306 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 21 Jun 2019 21:48:35 +0200
Subject: [PATCH 0120/1185] Fix asyncio lock not being awaited properly
---
pyrogram/client/ext/dispatcher.py | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/pyrogram/client/ext/dispatcher.py b/pyrogram/client/ext/dispatcher.py
index 92b1d64054..a2a81495f1 100644
--- a/pyrogram/client/ext/dispatcher.py
+++ b/pyrogram/client/ext/dispatcher.py
@@ -114,19 +114,25 @@ async def stop(self):
log.info("Stopped {} UpdateWorkerTasks".format(self.workers))
def add_handler(self, handler, group: int):
- with self.lock:
- if group not in self.groups:
- self.groups[group] = []
- self.groups = OrderedDict(sorted(self.groups.items()))
+ async def fn():
+ async with self.lock:
+ if group not in self.groups:
+ self.groups[group] = []
+ self.groups = OrderedDict(sorted(self.groups.items()))
- self.groups[group].append(handler)
+ self.groups[group].append(handler)
+
+ asyncio.get_event_loop().run_until_complete(fn())
def remove_handler(self, handler, group: int):
- with self.lock:
- if group not in self.groups:
- raise ValueError("Group {} does not exist. Handler was not removed.".format(group))
+ async def fn():
+ async with self.lock:
+ if group not in self.groups:
+ raise ValueError("Group {} does not exist. Handler was not removed.".format(group))
+
+ self.groups[group].remove(handler)
- self.groups[group].remove(handler)
+ asyncio.get_event_loop().run_until_complete(fn())
async def update_worker(self):
while True:
@@ -145,7 +151,7 @@ async def update_worker(self):
else (None, type(None))
)
- with self.lock:
+ async with self.lock:
for group in self.groups.values():
for handler in group:
args = None
From 633e11531a882d0cd9cafdf437f9e99e43a21271 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sun, 23 Jun 2019 13:56:12 +0200
Subject: [PATCH 0121/1185] Fix coroutine scheduling when adding/removing
handlers
---
pyrogram/client/ext/dispatcher.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/ext/dispatcher.py b/pyrogram/client/ext/dispatcher.py
index c2c3556992..167e9d6725 100644
--- a/pyrogram/client/ext/dispatcher.py
+++ b/pyrogram/client/ext/dispatcher.py
@@ -130,7 +130,7 @@ async def fn():
for lock in self.locks_list:
lock.release()
- asyncio.get_event_loop().run_until_complete(fn())
+ asyncio.get_event_loop().create_task(fn())
def remove_handler(self, handler, group: int):
async def fn():
@@ -146,7 +146,7 @@ async def fn():
for lock in self.locks_list:
lock.release()
- asyncio.get_event_loop().run_until_complete(fn())
+ asyncio.get_event_loop().create_task(fn())
async def update_worker(self, lock):
while True:
From 656aa4a7cacf3fa55393aea8daf2f393b801ed17 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 24 Jun 2019 17:33:33 +0200
Subject: [PATCH 0122/1185] Enable scheduling of more than 1 updates worker
---
pyrogram/client/client.py | 24 +++++++++++++++---------
pyrogram/client/ext/base_client.py | 3 +--
2 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 99ba180590..e7da91172a 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -17,9 +17,7 @@
# along with Pyrogram. If not, see .
import asyncio
-import base64
import inspect
-import json
import logging
import math
import mimetypes
@@ -325,7 +323,12 @@ async def start(self):
await self.session.stop()
raise e
- self.updates_worker_task = asyncio.ensure_future(self.updates_worker())
+ for _ in range(Client.UPDATES_WORKERS):
+ self.updates_worker_tasks.append(
+ asyncio.ensure_future(self.updates_worker())
+ )
+
+ log.info("Started {} UpdatesWorkerTasks".format(Client.UPDATES_WORKERS))
for _ in range(Client.DOWNLOAD_WORKERS):
self.download_worker_tasks.append(
@@ -367,8 +370,15 @@ async def stop(self):
log.info("Stopped {} DownloadWorkerTasks".format(Client.DOWNLOAD_WORKERS))
- self.updates_queue.put_nowait(None)
- await self.updates_worker_task
+ for _ in range(Client.UPDATES_WORKERS):
+ self.updates_queue.put_nowait(None)
+
+ for task in self.updates_worker_tasks:
+ await task
+
+ self.updates_worker_tasks.clear()
+
+ log.info("Stopped {} UpdatesWorkerTasks".format(Client.UPDATES_WORKERS))
for media_session in self.media_sessions.values():
await media_session.stop()
@@ -862,8 +872,6 @@ async def download_worker(self):
done.set()
async def updates_worker(self):
- log.info("UpdatesWorkerTask started")
-
while True:
updates = await self.updates_queue.get()
@@ -946,8 +954,6 @@ async def updates_worker(self):
except Exception as e:
log.error(e, exc_info=True)
- log.info("UpdatesWorkerTask stopped")
-
async def send(self,
data: TLObject,
retries: int = Session.MAX_RETRIES,
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index 0b1f9bff52..3d51303184 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -24,7 +24,6 @@
from pathlib import Path
from pyrogram import __version__
-
from ..style import Markdown, HTML
from ...session.internals import MsgId
@@ -105,7 +104,7 @@ def __init__(self):
self.takeout_id = None
self.updates_queue = asyncio.Queue()
- self.updates_worker_task = None
+ self.updates_worker_tasks = []
self.download_queue = asyncio.Queue()
self.download_worker_tasks = []
From ee1f6e2c9f421d0fddc1e88a5d12d9120d444456 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 4 Jul 2019 12:57:07 +0200
Subject: [PATCH 0123/1185] Fix errors and warnings when using Pyrogram async
with Python <3.5.3
---
pyrogram/client/client.py | 5 ++++-
pyrogram/client/methods/chats/archive_chats.py | 18 +++++++++++-------
.../client/methods/chats/iter_chat_members.py | 4 ++--
pyrogram/client/methods/chats/iter_dialogs.py | 4 ++--
.../client/methods/chats/unarchive_chats.py | 18 +++++++++++-------
.../client/methods/messages/iter_history.py | 4 ++--
.../methods/users/iter_profile_photos.py | 4 ++--
7 files changed, 34 insertions(+), 23 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index e7da91172a..faac9051fe 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -447,7 +447,8 @@ def run(self, coroutine=None):
Raises:
RPCError: In case of a Telegram RPC error.
"""
- run = asyncio.get_event_loop().run_until_complete
+ loop = asyncio.get_event_loop()
+ run = loop.run_until_complete
run(self.start())
@@ -460,6 +461,8 @@ def run(self, coroutine=None):
if self.is_started:
run(self.stop())
+ loop.close()
+
return coroutine
def add_handler(self, handler: Handler, group: int = 0):
diff --git a/pyrogram/client/methods/chats/archive_chats.py b/pyrogram/client/methods/chats/archive_chats.py
index 3f53b25e3b..379860d59c 100644
--- a/pyrogram/client/methods/chats/archive_chats.py
+++ b/pyrogram/client/methods/chats/archive_chats.py
@@ -19,7 +19,6 @@
from typing import Union, List
from pyrogram.api import functions, types
-
from ...ext import BaseClient
@@ -45,14 +44,19 @@ async def archive_chats(
if not isinstance(chat_ids, list):
chat_ids = [chat_ids]
+ folder_peers = []
+
+ for chat in chat_ids:
+ folder_peers.append(
+ types.InputFolderPeer(
+ peer=await self.resolve_peer(chat),
+ folder_id=1
+ )
+ )
+
await self.send(
functions.folders.EditPeerFolders(
- folder_peers=[
- types.InputFolderPeer(
- peer=await self.resolve_peer(chat),
- folder_id=1
- ) for chat in chat_ids
- ]
+ folder_peers=folder_peers
)
)
diff --git a/pyrogram/client/methods/chats/iter_chat_members.py b/pyrogram/client/methods/chats/iter_chat_members.py
index c4db15214d..bdd613fdc3 100644
--- a/pyrogram/client/methods/chats/iter_chat_members.py
+++ b/pyrogram/client/methods/chats/iter_chat_members.py
@@ -17,7 +17,7 @@
# along with Pyrogram. If not, see .
from string import ascii_lowercase
-from typing import Union, AsyncGenerator, Optional
+from typing import Union, Generator, Optional
import pyrogram
from async_generator import async_generator, yield_
@@ -47,7 +47,7 @@ async def iter_chat_members(
limit: int = 0,
query: str = "",
filter: str = Filters.ALL
- ) -> Optional[AsyncGenerator["pyrogram.ChatMember", None]]:
+ ) -> Optional[Generator["pyrogram.ChatMember", None, None]]:
"""Iterate through the members of a chat sequentially.
This convenience method does the same as repeatedly calling :meth:`~Client.get_chat_members` in a loop, thus saving you
diff --git a/pyrogram/client/methods/chats/iter_dialogs.py b/pyrogram/client/methods/chats/iter_dialogs.py
index bbad9b35ee..3162d31d92 100644
--- a/pyrogram/client/methods/chats/iter_dialogs.py
+++ b/pyrogram/client/methods/chats/iter_dialogs.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 typing import AsyncGenerator, Optional
+from typing import Generator, Optional
import pyrogram
from async_generator import async_generator, yield_
@@ -30,7 +30,7 @@ async def iter_dialogs(
self,
limit: int = 0,
offset_date: int = None
- ) -> Optional[AsyncGenerator["pyrogram.Dialog", None]]:
+ ) -> Optional[Generator["pyrogram.Dialog", None, None]]:
"""Iterate through a user's dialogs sequentially.
This convenience method does the same as repeatedly calling :meth:`~Client.get_dialogs` in a loop, thus saving
diff --git a/pyrogram/client/methods/chats/unarchive_chats.py b/pyrogram/client/methods/chats/unarchive_chats.py
index 56768dba3b..8c47557e4b 100644
--- a/pyrogram/client/methods/chats/unarchive_chats.py
+++ b/pyrogram/client/methods/chats/unarchive_chats.py
@@ -19,7 +19,6 @@
from typing import Union, List
from pyrogram.api import functions, types
-
from ...ext import BaseClient
@@ -45,14 +44,19 @@ async def unarchive_chats(
if not isinstance(chat_ids, list):
chat_ids = [chat_ids]
+ folder_peers = []
+
+ for chat in chat_ids:
+ folder_peers.append(
+ types.InputFolderPeer(
+ peer=await self.resolve_peer(chat),
+ folder_id=0
+ )
+ )
+
await self.send(
functions.folders.EditPeerFolders(
- folder_peers=[
- types.InputFolderPeer(
- peer=await self.resolve_peer(chat),
- folder_id=0
- ) for chat in chat_ids
- ]
+ folder_peers=folder_peers
)
)
diff --git a/pyrogram/client/methods/messages/iter_history.py b/pyrogram/client/methods/messages/iter_history.py
index 2dca96fe66..6d69273b31 100644
--- a/pyrogram/client/methods/messages/iter_history.py
+++ b/pyrogram/client/methods/messages/iter_history.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 typing import Union, Optional, AsyncGenerator
+from typing import Union, Optional, Generator
import pyrogram
from async_generator import async_generator, yield_
@@ -34,7 +34,7 @@ async def iter_history(
offset_id: int = 0,
offset_date: int = 0,
reverse: bool = False
- ) -> Optional[AsyncGenerator["pyrogram.Message", None]]:
+ ) -> Optional[Generator["pyrogram.Message", None, None]]:
"""Iterate through a chat history sequentially.
This convenience method does the same as repeatedly calling :meth:`~Client.get_history` in a loop, thus saving
diff --git a/pyrogram/client/methods/users/iter_profile_photos.py b/pyrogram/client/methods/users/iter_profile_photos.py
index bfe3e7f023..4e703e0725 100644
--- a/pyrogram/client/methods/users/iter_profile_photos.py
+++ b/pyrogram/client/methods/users/iter_profile_photos.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 typing import Union, AsyncGenerator, Optional
+from typing import Union, Generator, Optional
import pyrogram
from async_generator import async_generator, yield_
@@ -31,7 +31,7 @@ async def iter_profile_photos(
chat_id: Union[int, str],
offset: int = 0,
limit: int = 0,
- ) -> Optional[AsyncGenerator["pyrogram.Message", None]]:
+ ) -> Optional[Generator["pyrogram.Message", None, None]]:
"""Iterate through a chat or a user profile photos sequentially.
This convenience method does the same as repeatedly calling :meth:`~Client.get_profile_photos` in a loop, thus
From d5f31a8473e788de115b428569b3204ebf0baddd Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 11 Jul 2019 04:20:23 +0200
Subject: [PATCH 0124/1185] Update asyncio-dev version
---
pyrogram/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index f98d0ad5a5..7b4ece92c8 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -24,7 +24,7 @@
# Monkey patch the standard "typing" module because Python versions from 3.5.0 to 3.5.2 have a broken one.
sys.modules["typing"] = typing
-__version__ = "0.15.1-asyncio"
+__version__ = "0.16.0.asyncio-dev"
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
__copyright__ = "Copyright (C) 2017-2019 Dan "
From 9940dd678fd4f982e066488eb5595871e79b309c Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 15 Jul 2019 00:51:32 +0200
Subject: [PATCH 0125/1185] Replace ensure_future usages to create_task
---
pyrogram/client/client.py | 8 ++++----
pyrogram/client/ext/dispatcher.py | 2 +-
pyrogram/client/ext/syncer.py | 2 +-
pyrogram/session/session.py | 10 +++++-----
4 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 2376aa362f..3590261187 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -325,14 +325,14 @@ async def start(self):
for _ in range(Client.UPDATES_WORKERS):
self.updates_worker_tasks.append(
- asyncio.ensure_future(self.updates_worker())
+ asyncio.create_task(self.updates_worker())
)
log.info("Started {} UpdatesWorkerTasks".format(Client.UPDATES_WORKERS))
for _ in range(Client.DOWNLOAD_WORKERS):
self.download_worker_tasks.append(
- asyncio.ensure_future(self.download_worker())
+ asyncio.create_task(self.download_worker())
)
log.info("Started {} DownloadWorkerTasks".format(Client.DOWNLOAD_WORKERS))
@@ -1397,7 +1397,7 @@ async def worker(session):
return
try:
- await asyncio.ensure_future(session.send(data))
+ await asyncio.create_task(session.send(data))
except Exception as e:
log.error(e)
@@ -1418,7 +1418,7 @@ async def worker(session):
file_id = file_id or self.rnd_id()
md5_sum = md5() if not is_big and not is_missing_part else None
pool = [Session(self, self.storage.dc_id, self.storage.auth_key, is_media=True) for _ in range(pool_size)]
- workers = [asyncio.ensure_future(worker(session)) for session in pool for _ in range(workers_count)]
+ workers = [asyncio.create_task(worker(session)) for session in pool for _ in range(workers_count)]
queue = asyncio.Queue(16)
try:
diff --git a/pyrogram/client/ext/dispatcher.py b/pyrogram/client/ext/dispatcher.py
index 70bee2464d..98d9b86552 100644
--- a/pyrogram/client/ext/dispatcher.py
+++ b/pyrogram/client/ext/dispatcher.py
@@ -98,7 +98,7 @@ async def start(self):
self.locks_list.append(asyncio.Lock())
self.update_worker_tasks.append(
- asyncio.ensure_future(self.update_worker(self.locks_list[-1]))
+ asyncio.create_task(self.update_worker(self.locks_list[-1]))
)
log.info("Started {} UpdateWorkerTasks".format(self.workers))
diff --git a/pyrogram/client/ext/syncer.py b/pyrogram/client/ext/syncer.py
index 8b48e6e2ab..bf54f57b6f 100644
--- a/pyrogram/client/ext/syncer.py
+++ b/pyrogram/client/ext/syncer.py
@@ -59,7 +59,7 @@ async def remove(cls, client):
@classmethod
def start(cls):
cls.event.clear()
- asyncio.ensure_future(cls.worker())
+ asyncio.create_task(cls.worker())
@classmethod
def stop(cls):
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index ff65483cfe..429de1998c 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -123,8 +123,8 @@ async def start(self):
try:
await self.connection.connect()
- self.net_worker_task = asyncio.ensure_future(self.net_worker())
- self.recv_task = asyncio.ensure_future(self.recv())
+ self.net_worker_task = asyncio.create_task(self.net_worker())
+ self.recv_task = asyncio.create_task(self.recv())
self.current_salt = FutureSalt(0, 0, Session.INITIAL_SALT)
self.current_salt = FutureSalt(
@@ -137,7 +137,7 @@ async def start(self):
self.current_salt = \
(await self._send(functions.GetFutureSalts(num=1), timeout=self.START_TIMEOUT)).salts[0]
- self.next_salt_task = asyncio.ensure_future(self.next_salt())
+ self.next_salt_task = asyncio.create_task(self.next_salt())
if not self.is_cdn:
await self._send(
@@ -157,7 +157,7 @@ async def start(self):
timeout=self.START_TIMEOUT
)
- self.ping_task = asyncio.ensure_future(self.ping())
+ self.ping_task = asyncio.create_task(self.ping())
log.info("Session initialized: Layer {}".format(layer))
log.info("Device: {} - {}".format(self.client.device_model, self.client.app_version))
@@ -351,7 +351,7 @@ async def recv(self):
log.warning("Server sent \"{}\"".format(Int.read(BytesIO(packet))))
if self.is_connected.is_set():
- asyncio.ensure_future(self.restart())
+ asyncio.create_task(self.restart())
break
From 4d324abbb5d11040028ef6aa62572b52e1e39a38 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 15 Jul 2019 00:54:35 +0200
Subject: [PATCH 0126/1185] Don't automatically install uvloop. Let people do
that People are reporting uvloop would crash with weird core-dumped errors
when using other asyncio libs, such as aiohttp. Plus, this was a bad idea and
people should install uvloop themselves before running their codes.
---
pyrogram/__init__.py | 7 -------
1 file changed, 7 deletions(-)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 7b4ece92c8..407bbcff7f 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -28,13 +28,6 @@
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
__copyright__ = "Copyright (C) 2017-2019 Dan "
-try:
- import uvloop
-except ImportError:
- pass
-else:
- uvloop.install()
-
from .errors import RPCError
from .client import *
from .client.handlers import *
From c30e8f9c551ce89efbef1e23cf192467ac8afdce Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 15 Jul 2019 01:26:29 +0200
Subject: [PATCH 0127/1185] Don't start the client in case run() is called with
a coroutine as arg
---
pyrogram/client/client.py | 19 +++++++------------
1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 3590261187..c1065a42b1 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -17,7 +17,6 @@
# along with Pyrogram. If not, see .
import asyncio
-import inspect
import logging
import math
import mimetypes
@@ -452,21 +451,17 @@ def run(self, coroutine=None):
loop = asyncio.get_event_loop()
run = loop.run_until_complete
- run(self.start())
-
- run(
- coroutine if inspect.iscoroutine(coroutine)
- else coroutine() if coroutine
- else self.idle()
- )
+ if coroutine is not None:
+ run(coroutine)
+ else:
+ run(self.start())
+ run(self.idle())
- if self.is_started:
- run(self.stop())
+ # TODO: Uncomment this once idle() gets refactored
+ # run(self.stop())
loop.close()
- return coroutine
-
def add_handler(self, handler: Handler, group: int = 0):
"""Register an update handler.
From 8700e3a0f3a2e4e12c9c5dfaa5382e765e1149ba Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 31 Jul 2019 13:33:04 +0200
Subject: [PATCH 0128/1185] Fix some methods not being defined using async
---
pyrogram/client/ext/base_client.py | 18 ++++++-------
.../bots_and_keyboards/callback_query.py | 26 +++++++++----------
2 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index 640e7e6557..230c681f72 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -146,29 +146,29 @@ async def get_chat_members_count(self, *args, **kwargs):
async def answer_inline_query(self, *args, **kwargs):
pass
- def guess_mime_type(self, *args, **kwargs):
+ async def get_profile_photos(self, *args, **kwargs):
pass
- def guess_extension(self, *args, **kwargs):
+ async def edit_message_text(self, *args, **kwargs):
pass
- def get_profile_photos(self, *args, **kwargs):
+ async def edit_inline_text(self, *args, **kwargs):
pass
- def edit_message_text(self, *args, **kwargs):
+ async def edit_message_media(self, *args, **kwargs):
pass
- def edit_inline_text(self, *args, **kwargs):
+ async def edit_inline_media(self, *args, **kwargs):
pass
- def edit_message_media(self, *args, **kwargs):
+ async def edit_message_reply_markup(self, *args, **kwargs):
pass
- def edit_inline_media(self, *args, **kwargs):
+ async def edit_inline_reply_markup(self, *args, **kwargs):
pass
- def edit_message_reply_markup(self, *args, **kwargs):
+ def guess_mime_type(self, *args, **kwargs):
pass
- def edit_inline_reply_markup(self, *args, **kwargs):
+ def guess_extension(self, *args, **kwargs):
pass
diff --git a/pyrogram/client/types/bots_and_keyboards/callback_query.py b/pyrogram/client/types/bots_and_keyboards/callback_query.py
index 0264a67c6d..27cebd7e46 100644
--- a/pyrogram/client/types/bots_and_keyboards/callback_query.py
+++ b/pyrogram/client/types/bots_and_keyboards/callback_query.py
@@ -129,7 +129,7 @@ async def _parse(client, callback_query, users) -> "CallbackQuery":
client=client
)
- def answer(self, text: str = None, show_alert: bool = None, url: str = None, cache_time: int = 0):
+ async def answer(self, text: str = None, show_alert: bool = None, url: str = None, cache_time: int = 0):
"""Bound method *answer* of :obj:`CallbackQuery`.
Use this method as a shortcut for:
@@ -165,7 +165,7 @@ def answer(self, text: str = None, show_alert: bool = None, url: str = None, cac
The maximum amount of time in seconds that the result of the callback query may be cached client-side.
Telegram apps will support caching starting in version 3.14. Defaults to 0.
"""
- return self._client.answer_callback_query(
+ return await self._client.answer_callback_query(
callback_query_id=self.id,
text=text,
show_alert=show_alert,
@@ -173,7 +173,7 @@ def answer(self, text: str = None, show_alert: bool = None, url: str = None, cac
cache_time=cache_time
)
- def edit_message_text(
+ async def edit_message_text(
self,
text: str,
parse_mode: Union[str, None] = object,
@@ -209,7 +209,7 @@ def edit_message_text(
RPCError: In case of a Telegram RPC error.
"""
if self.inline_message_id is None:
- return self._client.edit_message_text(
+ return await self._client.edit_message_text(
chat_id=self.message.chat.id,
message_id=self.message.message_id,
text=text,
@@ -218,7 +218,7 @@ def edit_message_text(
reply_markup=reply_markup
)
else:
- return self._client.edit_inline_text(
+ return await self._client.edit_inline_text(
inline_message_id=self.inline_message_id,
text=text,
parse_mode=parse_mode,
@@ -226,7 +226,7 @@ def edit_message_text(
reply_markup=reply_markup
)
- def edit_message_caption(
+ async def edit_message_caption(
self,
caption: str,
parse_mode: Union[str, None] = object,
@@ -257,9 +257,9 @@ def edit_message_caption(
Raises:
RPCError: In case of a Telegram RPC error.
"""
- return self.edit_message_text(caption, parse_mode, reply_markup)
+ return await self.edit_message_text(caption, parse_mode, reply_markup)
- def edit_message_media(
+ async def edit_message_media(
self,
media: "pyrogram.InputMedia",
reply_markup: "pyrogram.InlineKeyboardMarkup" = None
@@ -283,20 +283,20 @@ def edit_message_media(
RPCError: In case of a Telegram RPC error.
"""
if self.inline_message_id is None:
- return self._client.edit_message_media(
+ return await self._client.edit_message_media(
chat_id=self.message.chat.id,
message_id=self.message.message_id,
media=media,
reply_markup=reply_markup
)
else:
- return self._client.edit_inline_media(
+ return await self._client.edit_inline_media(
inline_message_id=self.inline_message_id,
media=media,
reply_markup=reply_markup
)
- def edit_message_reply_markup(
+ async def edit_message_reply_markup(
self,
reply_markup: "pyrogram.InlineKeyboardMarkup" = None
) -> Union["pyrogram.Message", bool]:
@@ -316,13 +316,13 @@ def edit_message_reply_markup(
RPCError: In case of a Telegram RPC error.
"""
if self.inline_message_id is None:
- return self._client.edit_message_reply_markup(
+ return await self._client.edit_message_reply_markup(
chat_id=self.message.chat.id,
message_id=self.message.message_id,
reply_markup=reply_markup
)
else:
- return self._client.edit_inline_reply_markup(
+ return await self._client.edit_inline_reply_markup(
inline_message_id=self.inline_message_id,
reply_markup=reply_markup
)
From eddff4769cd2098bb51f82e674e78a9050b535c9 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 1 Aug 2019 10:43:09 +0200
Subject: [PATCH 0129/1185] Add missing async/await
---
pyrogram/client/parser/parser.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/pyrogram/client/parser/parser.py b/pyrogram/client/parser/parser.py
index 371c47912c..21d09b42aa 100644
--- a/pyrogram/client/parser/parser.py
+++ b/pyrogram/client/parser/parser.py
@@ -30,7 +30,7 @@ def __init__(self, client: Union["pyrogram.BaseClient", None]):
self.html = HTML(client)
self.markdown = Markdown(client)
- def parse(self, text: str, mode: Union[str, None] = object):
+ async def parse(self, text: str, mode: Union[str, None] = object):
text = str(text).strip()
if mode == object:
@@ -48,13 +48,13 @@ def parse(self, text: str, mode: Union[str, None] = object):
mode = mode.lower()
if mode == "combined":
- return self.markdown.parse(text)
+ return await self.markdown.parse(text)
if mode in ["markdown", "md"]:
- return self.markdown.parse(text, True)
+ return await self.markdown.parse(text, True)
if mode == "html":
- return self.html.parse(text)
+ return await self.html.parse(text)
raise ValueError('parse_mode must be one of {} or None. Not "{}"'.format(
", ".join('"{}"'.format(m) for m in pyrogram.Client.PARSE_MODES[:-1]),
From 73e8b8c66e10ce4ab6bd1d75c62e935ae83d33ba Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 1 Aug 2019 20:18:17 +0200
Subject: [PATCH 0130/1185] Update read_history.py
---
pyrogram/client/methods/messages/read_history.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pyrogram/client/methods/messages/read_history.py b/pyrogram/client/methods/messages/read_history.py
index f5dc8630ee..7fa99dc920 100644
--- a/pyrogram/client/methods/messages/read_history.py
+++ b/pyrogram/client/methods/messages/read_history.py
@@ -23,7 +23,7 @@
class ReadHistory(BaseClient):
- def read_history(
+ async def read_history(
self,
chat_id: Union[int, str],
max_id: int = 0
@@ -53,7 +53,7 @@ def read_history(
app.read_history("pyrogramlounge", 123456)
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChannel):
q = functions.channels.ReadHistory(
@@ -66,6 +66,6 @@ def read_history(
max_id=max_id
)
- self.send(q)
+ await self.send(q)
return True
From 94603f1ff255f3b44158a4f1b4acb2dad8ac5542 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 3 Aug 2019 10:36:57 +0200
Subject: [PATCH 0131/1185] Replace create_task with ensure_future for
compatibility
---
pyrogram/client/ext/dispatcher.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/ext/dispatcher.py b/pyrogram/client/ext/dispatcher.py
index 98d9b86552..855fefe7d2 100644
--- a/pyrogram/client/ext/dispatcher.py
+++ b/pyrogram/client/ext/dispatcher.py
@@ -130,7 +130,7 @@ async def fn():
for lock in self.locks_list:
lock.release()
- asyncio.get_event_loop().create_task(fn())
+ asyncio.ensure_future(fn())
def remove_handler(self, handler, group: int):
async def fn():
@@ -146,7 +146,7 @@ async def fn():
for lock in self.locks_list:
lock.release()
- asyncio.get_event_loop().create_task(fn())
+ asyncio.ensure_future(fn())
async def update_worker(self, lock):
while True:
From adda199c779ccad60eb91f7cc07df57071939954 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 3 Aug 2019 10:37:48 +0200
Subject: [PATCH 0132/1185] Revert "Replace ensure_future usages to
create_task"
This reverts commit 9940dd67
---
pyrogram/client/client.py | 8 ++++----
pyrogram/client/ext/dispatcher.py | 2 +-
pyrogram/client/ext/syncer.py | 2 +-
pyrogram/session/session.py | 10 +++++-----
4 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 8b71312d7d..55f207433c 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -352,14 +352,14 @@ async def start(self):
for _ in range(Client.UPDATES_WORKERS):
self.updates_worker_tasks.append(
- asyncio.create_task(self.updates_worker())
+ asyncio.ensure_future(self.updates_worker())
)
log.info("Started {} UpdatesWorkerTasks".format(Client.UPDATES_WORKERS))
for _ in range(Client.DOWNLOAD_WORKERS):
self.download_worker_tasks.append(
- asyncio.create_task(self.download_worker())
+ asyncio.ensure_future(self.download_worker())
)
log.info("Started {} DownloadWorkerTasks".format(Client.DOWNLOAD_WORKERS))
@@ -1623,7 +1623,7 @@ async def worker(session):
return
try:
- await asyncio.create_task(session.send(data))
+ await asyncio.ensure_future(session.send(data))
except Exception as e:
log.error(e)
@@ -1644,7 +1644,7 @@ async def worker(session):
file_id = file_id or self.rnd_id()
md5_sum = md5() if not is_big and not is_missing_part else None
pool = [Session(self, self.storage.dc_id, self.storage.auth_key, is_media=True) for _ in range(pool_size)]
- workers = [asyncio.create_task(worker(session)) for session in pool for _ in range(workers_count)]
+ workers = [asyncio.ensure_future(worker(session)) for session in pool for _ in range(workers_count)]
queue = asyncio.Queue(16)
try:
diff --git a/pyrogram/client/ext/dispatcher.py b/pyrogram/client/ext/dispatcher.py
index 855fefe7d2..d4388dddfe 100644
--- a/pyrogram/client/ext/dispatcher.py
+++ b/pyrogram/client/ext/dispatcher.py
@@ -98,7 +98,7 @@ async def start(self):
self.locks_list.append(asyncio.Lock())
self.update_worker_tasks.append(
- asyncio.create_task(self.update_worker(self.locks_list[-1]))
+ asyncio.ensure_future(self.update_worker(self.locks_list[-1]))
)
log.info("Started {} UpdateWorkerTasks".format(self.workers))
diff --git a/pyrogram/client/ext/syncer.py b/pyrogram/client/ext/syncer.py
index bf54f57b6f..8b48e6e2ab 100644
--- a/pyrogram/client/ext/syncer.py
+++ b/pyrogram/client/ext/syncer.py
@@ -59,7 +59,7 @@ async def remove(cls, client):
@classmethod
def start(cls):
cls.event.clear()
- asyncio.create_task(cls.worker())
+ asyncio.ensure_future(cls.worker())
@classmethod
def stop(cls):
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index b137706473..e4699f7d38 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -123,8 +123,8 @@ async def start(self):
try:
await self.connection.connect()
- self.net_worker_task = asyncio.create_task(self.net_worker())
- self.recv_task = asyncio.create_task(self.recv())
+ self.net_worker_task = asyncio.ensure_future(self.net_worker())
+ self.recv_task = asyncio.ensure_future(self.recv())
self.current_salt = FutureSalt(0, 0, Session.INITIAL_SALT)
self.current_salt = FutureSalt(
@@ -137,7 +137,7 @@ async def start(self):
self.current_salt = \
(await self._send(functions.GetFutureSalts(num=1), timeout=self.START_TIMEOUT)).salts[0]
- self.next_salt_task = asyncio.create_task(self.next_salt())
+ self.next_salt_task = asyncio.ensure_future(self.next_salt())
if not self.is_cdn:
await self._send(
@@ -157,7 +157,7 @@ async def start(self):
timeout=self.START_TIMEOUT
)
- self.ping_task = asyncio.create_task(self.ping())
+ self.ping_task = asyncio.ensure_future(self.ping())
log.info("Session initialized: Layer {}".format(layer))
log.info("Device: {} - {}".format(self.client.device_model, self.client.app_version))
@@ -351,7 +351,7 @@ async def recv(self):
log.warning("Server sent \"{}\"".format(Int.read(BytesIO(packet))))
if self.is_connected.is_set():
- asyncio.create_task(self.restart())
+ asyncio.ensure_future(self.restart())
break
From 5cfc412af22c72867cf7593adbb7d225566aec96 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 7 Aug 2019 14:08:06 +0200
Subject: [PATCH 0133/1185] Add missing await
---
pyrogram/client/methods/messages/edit_inline_text.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/methods/messages/edit_inline_text.py b/pyrogram/client/methods/messages/edit_inline_text.py
index 2495183278..3e2ab5d2b8 100644
--- a/pyrogram/client/methods/messages/edit_inline_text.py
+++ b/pyrogram/client/methods/messages/edit_inline_text.py
@@ -76,6 +76,6 @@ async def edit_inline_text(
id=utils.unpack_inline_message_id(inline_message_id),
no_webpage=disable_web_page_preview or None,
reply_markup=reply_markup.write() if reply_markup else None,
- **self.parser.parse(text, parse_mode)
+ **await self.parser.parse(text, parse_mode)
)
)
From 2031df15fe061067564fcb6b88199351a0db1134 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 23 Aug 2019 11:52:12 +0200
Subject: [PATCH 0134/1185] Update inline_query_result_photo.py
---
pyrogram/client/types/inline_mode/inline_query_result_photo.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/types/inline_mode/inline_query_result_photo.py b/pyrogram/client/types/inline_mode/inline_query_result_photo.py
index ffcc21c019..df06a2a9e9 100644
--- a/pyrogram/client/types/inline_mode/inline_query_result_photo.py
+++ b/pyrogram/client/types/inline_mode/inline_query_result_photo.py
@@ -121,7 +121,7 @@ def write(self):
if self.input_message_content
else types.InputBotInlineMessageMediaAuto(
reply_markup=self.reply_markup.write() if self.reply_markup else None,
- **(Parser(None)).parse(self.caption, self.parse_mode)
+ **await(Parser(None)).parse(self.caption, self.parse_mode)
)
)
)
From fe6c5e542d8c0dcc65913bf63758df506475532b Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 23 Aug 2019 12:25:09 +0200
Subject: [PATCH 0135/1185] Add missing async and await keywords
---
.../client/types/inline_mode/inline_query_result_photo.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/types/inline_mode/inline_query_result_photo.py b/pyrogram/client/types/inline_mode/inline_query_result_photo.py
index df06a2a9e9..35b8a87475 100644
--- a/pyrogram/client/types/inline_mode/inline_query_result_photo.py
+++ b/pyrogram/client/types/inline_mode/inline_query_result_photo.py
@@ -91,7 +91,7 @@ def __init__(
self.reply_markup = reply_markup
self.input_message_content = input_message_content
- def write(self):
+ async def write(self):
photo = types.InputWebDocument(
url=self.photo_url,
size=0,
@@ -117,7 +117,7 @@ def write(self):
thumb=thumb,
content=photo,
send_message=(
- self.input_message_content.write(self.reply_markup)
+ await self.input_message_content.write(self.reply_markup)
if self.input_message_content
else types.InputBotInlineMessageMediaAuto(
reply_markup=self.reply_markup.write() if self.reply_markup else None,
From 1ade49a13a887d0f0cd76bc85dc0e789624187a6 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Mon, 26 Aug 2019 22:09:36 +0200
Subject: [PATCH 0136/1185] Fix error on serializing None when int is expected
---
pyrogram/client/methods/chats/iter_dialogs.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/methods/chats/iter_dialogs.py b/pyrogram/client/methods/chats/iter_dialogs.py
index 8265a9df03..80ce44f57e 100644
--- a/pyrogram/client/methods/chats/iter_dialogs.py
+++ b/pyrogram/client/methods/chats/iter_dialogs.py
@@ -29,7 +29,7 @@ class IterDialogs(BaseClient):
async def iter_dialogs(
self,
limit: int = 0,
- offset_date: int = None
+ offset_date: int = 0
) -> Optional[Generator["pyrogram.Dialog", None, None]]:
"""Iterate through a user's dialogs sequentially.
From aa937a704d0bad9fdf2f893b2a85cc1a9a40d9b4 Mon Sep 17 00:00:00 2001
From: YoilyL
Date: Mon, 9 Sep 2019 16:56:57 +0300
Subject: [PATCH 0137/1185] fixed memory leak when session.send coroutine is
cancelled (#311)
added that when session.send coroutine is cancelled (or if any other exception is raised) the result should still be removed from the results list
---
pyrogram/session/session.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py
index b5f690815d..3dbedef43f 100644
--- a/pyrogram/session/session.py
+++ b/pyrogram/session/session.py
@@ -382,8 +382,8 @@ async def _send(self, data: TLObject, wait_response: bool = True, timeout: float
await asyncio.wait_for(self.results[msg_id].event.wait(), timeout)
except asyncio.TimeoutError:
pass
-
- result = self.results.pop(msg_id).value
+ finally:
+ result = self.results.pop(msg_id).value
if result is None:
raise TimeoutError
From bc7d29237d40dba92c3cbd1254b3d2561b313814 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 25 Sep 2019 18:41:06 +0200
Subject: [PATCH 0138/1185] Small style fix
---
pyrogram/client/client.py | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index cb1abcaac8..a0bf5af5b2 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -1881,19 +1881,23 @@ async def worker(session):
for session in pool:
await session.stop()
- async def get_file(self, media_type: int,
- dc_id: int,
- document_id: int,
- access_hash: int,
- thumb_size: str,
- peer_id: int,
- peer_access_hash: int, volume_id: int,
- local_id: int,
- file_ref: str,file_size: int,
-
- is_big: bool,
- progress: callable,
- progress_args: tuple = ()) -> str:
+ async def get_file(
+ self,
+ media_type: int,
+ dc_id: int,
+ document_id: int,
+ access_hash: int,
+ thumb_size: str,
+ peer_id: int,
+ peer_access_hash: int,
+ volume_id: int,
+ local_id: int,
+ file_ref: str,
+ file_size: int,
+ is_big: bool,
+ progress: callable,
+ progress_args: tuple = ()
+ ) -> str:
async with self.media_sessions_lock:
session = self.media_sessions.get(dc_id, None)
From 353811ebd3afb65d442a807de6e4e7a2a112f47e Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Fri, 6 Dec 2019 21:14:15 +0100
Subject: [PATCH 0139/1185] Add missing await
---
pyrogram/client/methods/chats/set_chat_photo.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/client/methods/chats/set_chat_photo.py b/pyrogram/client/methods/chats/set_chat_photo.py
index df67923e4f..4c91247585 100644
--- a/pyrogram/client/methods/chats/set_chat_photo.py
+++ b/pyrogram/client/methods/chats/set_chat_photo.py
@@ -59,7 +59,7 @@ async def set_chat_photo(
peer = await self.resolve_peer(chat_id)
if os.path.exists(photo):
- photo = types.InputChatUploadedPhoto(file=self.save_file(photo))
+ photo = types.InputChatUploadedPhoto(file=await self.save_file(photo))
else:
photo = utils.get_input_media_from_file_id(photo)
photo = types.InputChatPhoto(id=photo.id)
From 8e9a7a33bd7113f7773669a421c70f8adcfdb61f Mon Sep 17 00:00:00 2001
From: Alisson Lauffer
Date: Wed, 20 Nov 2019 02:51:42 -0300
Subject: [PATCH 0140/1185] Add missing awaits
---
pyrogram/client/methods/chats/add_chat_members.py | 12 ++++++------
pyrogram/client/methods/chats/create_channel.py | 4 ++--
pyrogram/client/methods/chats/create_group.py | 6 +++---
pyrogram/client/methods/chats/create_supergroup.py | 4 ++--
pyrogram/client/methods/chats/delete_channel.py | 6 +++---
pyrogram/client/methods/chats/delete_supergroup.py | 6 +++---
.../client/methods/chats/set_chat_permissions.py | 2 +-
pyrogram/client/methods/messages/send_poll.py | 6 +++---
pyrogram/client/methods/users/get_common_chats.py | 6 +++---
9 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/pyrogram/client/methods/chats/add_chat_members.py b/pyrogram/client/methods/chats/add_chat_members.py
index 8dbad1a387..ace35cf854 100644
--- a/pyrogram/client/methods/chats/add_chat_members.py
+++ b/pyrogram/client/methods/chats/add_chat_members.py
@@ -23,7 +23,7 @@
class AddChatMembers(BaseClient):
- def add_chat_members(
+ async def add_chat_members(
self,
chat_id: Union[int, str],
user_ids: Union[Union[int, str], List[Union[int, str]]],
@@ -60,26 +60,26 @@ def add_chat_members(
# Change forward_limit (for basic groups only)
app.add_chat_members(chat_id, user_id, forward_limit=25)
"""
- peer = self.resolve_peer(chat_id)
+ peer = await self.resolve_peer(chat_id)
if not isinstance(user_ids, list):
user_ids = [user_ids]
if isinstance(peer, types.InputPeerChat):
for user_id in user_ids:
- self.send(
+ await self.send(
functions.messages.AddChatUser(
chat_id=peer.chat_id,
- user_id=self.resolve_peer(user_id),
+ user_id=await self.resolve_peer(user_id),
fwd_limit=forward_limit
)
)
else:
- self.send(
+ await self.send(
functions.channels.InviteToChannel(
channel=peer,
users=[
- self.resolve_peer(user_id)
+ await self.resolve_peer(user_id)
for user_id in user_ids
]
)
diff --git a/pyrogram/client/methods/chats/create_channel.py b/pyrogram/client/methods/chats/create_channel.py
index 9dde878143..c768ccceb3 100644
--- a/pyrogram/client/methods/chats/create_channel.py
+++ b/pyrogram/client/methods/chats/create_channel.py
@@ -22,7 +22,7 @@
class CreateChannel(BaseClient):
- def create_channel(
+ async def create_channel(
self,
title: str,
description: str = ""
@@ -44,7 +44,7 @@ def create_channel(
app.create_channel("Channel Title", "Channel Description")
"""
- r = self.send(
+ r = await self.send(
functions.channels.CreateChannel(
title=title,
about=description,
diff --git a/pyrogram/client/methods/chats/create_group.py b/pyrogram/client/methods/chats/create_group.py
index a9013d8103..c69d8ff8af 100644
--- a/pyrogram/client/methods/chats/create_group.py
+++ b/pyrogram/client/methods/chats/create_group.py
@@ -24,7 +24,7 @@
class CreateGroup(BaseClient):
- def create_group(
+ async def create_group(
self,
title: str,
users: Union[Union[int, str], List[Union[int, str]]]
@@ -55,10 +55,10 @@ def create_group(
if not isinstance(users, list):
users = [users]
- r = self.send(
+ r = await self.send(
functions.messages.CreateChat(
title=title,
- users=[self.resolve_peer(u) for u in users]
+ users=[await self.resolve_peer(u) for u in users]
)
)
diff --git a/pyrogram/client/methods/chats/create_supergroup.py b/pyrogram/client/methods/chats/create_supergroup.py
index 28b3fd1b90..ddeb42bfcd 100644
--- a/pyrogram/client/methods/chats/create_supergroup.py
+++ b/pyrogram/client/methods/chats/create_supergroup.py
@@ -22,7 +22,7 @@
class CreateSupergroup(BaseClient):
- def create_supergroup(
+ async def create_supergroup(
self,
title: str,
description: str = ""
@@ -48,7 +48,7 @@ def create_supergroup(
app.create_supergroup("Supergroup Title", "Supergroup Description")
"""
- r = self.send(
+ r = await self.send(
functions.channels.CreateChannel(
title=title,
about=description,
diff --git a/pyrogram/client/methods/chats/delete_channel.py b/pyrogram/client/methods/chats/delete_channel.py
index 74fbea13c0..b306773b5a 100644
--- a/pyrogram/client/methods/chats/delete_channel.py
+++ b/pyrogram/client/methods/chats/delete_channel.py
@@ -24,7 +24,7 @@
class DeleteChannel(BaseClient):
- def delete_channel(self, chat_id: Union[int, str]) -> bool:
+ async def delete_channel(self, chat_id: Union[int, str]) -> bool:
"""Delete a channel.
Parameters:
@@ -39,9 +39,9 @@ def delete_channel(self, chat_id: Union[int, str]) -> bool:
app.delete_channel(channel_id)
"""
- self.send(
+ await self.send(
functions.channels.DeleteChannel(
- channel=self.resolve_peer(chat_id)
+ channel=await self.resolve_peer(chat_id)
)
)
diff --git a/pyrogram/client/methods/chats/delete_supergroup.py b/pyrogram/client/methods/chats/delete_supergroup.py
index a1eb198d95..3c291424b4 100644
--- a/pyrogram/client/methods/chats/delete_supergroup.py
+++ b/pyrogram/client/methods/chats/delete_supergroup.py
@@ -24,7 +24,7 @@
class DeleteSupergroup(BaseClient):
- def delete_supergroup(self, chat_id: Union[int, str]) -> bool:
+ async def delete_supergroup(self, chat_id: Union[int, str]) -> bool:
"""Delete a supergroup.
Parameters:
@@ -39,9 +39,9 @@ def delete_supergroup(self, chat_id: Union[int, str]) -> bool:
app.delete_supergroup(supergroup_id)
"""
- self.send(
+ await self.send(
functions.channels.DeleteChannel(
- channel=self.resolve_peer(chat_id)
+ channel=await self.resolve_peer(chat_id)
)
)
diff --git a/pyrogram/client/methods/chats/set_chat_permissions.py b/pyrogram/client/methods/chats/set_chat_permissions.py
index 158cc26960..e1494ac3ea 100644
--- a/pyrogram/client/methods/chats/set_chat_permissions.py
+++ b/pyrogram/client/methods/chats/set_chat_permissions.py
@@ -107,7 +107,7 @@ async def set_chat_permissions(
r = await self.send(
functions.messages.EditChatDefaultBannedRights(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
banned_rights=types.ChatBannedRights(
until_date=0,
send_messages=send_messages,
diff --git a/pyrogram/client/methods/messages/send_poll.py b/pyrogram/client/methods/messages/send_poll.py
index a684dda909..50ba9cc10c 100644
--- a/pyrogram/client/methods/messages/send_poll.py
+++ b/pyrogram/client/methods/messages/send_poll.py
@@ -24,7 +24,7 @@
class SendPoll(BaseClient):
- def send_poll(
+ async def send_poll(
self,
chat_id: Union[int, str],
question: str,
@@ -75,9 +75,9 @@ def send_poll(
app.send_poll(chat_id, "Is this a poll question?", ["Yes", "No", "Maybe"])
"""
- r = self.send(
+ r = await self.send(
functions.messages.SendMedia(
- peer=self.resolve_peer(chat_id),
+ peer=await self.resolve_peer(chat_id),
media=types.InputMediaPoll(
poll=types.Poll(
id=0,
diff --git a/pyrogram/client/methods/users/get_common_chats.py b/pyrogram/client/methods/users/get_common_chats.py
index f2c9ac00e8..2207e09fad 100644
--- a/pyrogram/client/methods/users/get_common_chats.py
+++ b/pyrogram/client/methods/users/get_common_chats.py
@@ -24,7 +24,7 @@
class GetCommonChats(BaseClient):
- def get_common_chats(self, user_id: Union[int, str]) -> list:
+ async def get_common_chats(self, user_id: Union[int, str]) -> list:
"""Get the common chats you have with a user.
Parameters:
@@ -46,10 +46,10 @@ def get_common_chats(self, user_id: Union[int, str]) -> list:
print(common)
"""
- peer = self.resolve_peer(user_id)
+ peer = await self.resolve_peer(user_id)
if isinstance(peer, types.InputPeerUser):
- r = self.send(
+ r = await self.send(
functions.messages.GetCommonChats(
user_id=peer,
max_id=0,
From 2daa5932c6641f8c3d3fa2445d64a731d7b77fdd Mon Sep 17 00:00:00 2001
From: Shrimadhav U K
Date: Mon, 23 Dec 2019 19:44:58 +0530
Subject: [PATCH 0141/1185] Add missing asyncio keywords (#319)
* fix missing await
* fix empty file reference
* one more await, and file reference
---
.../client/methods/messages/edit_message_media.py | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/pyrogram/client/methods/messages/edit_message_media.py b/pyrogram/client/methods/messages/edit_message_media.py
index 579e3c4473..2042a6751c 100644
--- a/pyrogram/client/methods/messages/edit_message_media.py
+++ b/pyrogram/client/methods/messages/edit_message_media.py
@@ -108,7 +108,7 @@ async def edit_message_media(
peer=await self.resolve_peer(chat_id),
media=types.InputMediaUploadedDocument(
mime_type=self.guess_mime_type(media.media) or "video/mp4",
- thumb=None if media.thumb is None else self.save_file(media.thumb),
+ thumb=None if media.thumb is None else await self.save_file(media.thumb),
file=await self.save_file(media.media),
attributes=[
types.DocumentAttributeVideo(
@@ -145,7 +145,7 @@ async def edit_message_media(
peer=await self.resolve_peer(chat_id),
media=types.InputMediaUploadedDocument(
mime_type=self.guess_mime_type(media.media) or "audio/mpeg",
- thumb=None if media.thumb is None else self.save_file(media.thumb),
+ thumb=None if media.thumb is None else await self.save_file(media.thumb),
file=await self.save_file(media.media),
attributes=[
types.DocumentAttributeAudio(
@@ -165,7 +165,7 @@ async def edit_message_media(
id=types.InputDocument(
id=media.document.id,
access_hash=media.document.access_hash,
- file_reference=b""
+ file_reference=media.document.file_reference
)
)
elif media.media.startswith("http"):
@@ -203,7 +203,7 @@ async def edit_message_media(
id=types.InputDocument(
id=media.document.id,
access_hash=media.document.access_hash,
- file_reference=b""
+ file_reference=media.document.file_reference
)
)
elif media.media.startswith("http"):
@@ -219,7 +219,7 @@ async def edit_message_media(
peer=await self.resolve_peer(chat_id),
media=types.InputMediaUploadedDocument(
mime_type=self.guess_mime_type(media.media) or "application/zip",
- thumb=None if media.thumb is None else self.save_file(media.thumb),
+ thumb=None if media.thumb is None else await self.save_file(media.thumb),
file=await self.save_file(media.media),
attributes=[
types.DocumentAttributeFilename(
@@ -234,7 +234,7 @@ async def edit_message_media(
id=types.InputDocument(
id=media.document.id,
access_hash=media.document.access_hash,
- file_reference=b""
+ file_reference=media.document.file_reference
)
)
elif media.media.startswith("http"):
From e316d18bf4bfcae7113588abcc5e021577a39f12 Mon Sep 17 00:00:00 2001
From: Yusuf_M_Thon_iD <32301831+Sunda001@users.noreply.github.com>
Date: Sat, 1 Feb 2020 20:10:46 +0700
Subject: [PATCH 0142/1185] Add missing file_ref in set_chat_photo (#343)
---
pyrogram/client/methods/chats/set_chat_photo.py | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/pyrogram/client/methods/chats/set_chat_photo.py b/pyrogram/client/methods/chats/set_chat_photo.py
index 4c91247585..689cc15f79 100644
--- a/pyrogram/client/methods/chats/set_chat_photo.py
+++ b/pyrogram/client/methods/chats/set_chat_photo.py
@@ -27,7 +27,8 @@ class SetChatPhoto(BaseClient):
async def set_chat_photo(
self,
chat_id: Union[int, str],
- photo: str
+ photo: str,
+ file_ref: str = None,
) -> bool:
"""Set a new profile photo for the chat.
@@ -40,6 +41,10 @@ async def set_chat_photo(
photo (``str``):
New chat photo. You can pass a :obj:`Photo` file_id or a file path to upload a new photo from your local
machine.
+
+ file_ref (``str``, *optional*):
+ A valid file reference obtained by a recently fetched media message.
+ To be used in combination with a file id in case a file reference is needed.
Returns:
``bool``: True on success.
@@ -54,14 +59,14 @@ async def set_chat_photo(
app.set_chat_photo(chat_id, "photo.jpg")
# Set chat photo using an exiting Photo file_id
- app.set_chat_photo(chat_id, photo.file_id)
+ app.set_chat_photo(chat_id, photo.file_id, photo.file_ref)
"""
peer = await self.resolve_peer(chat_id)
if os.path.exists(photo):
photo = types.InputChatUploadedPhoto(file=await self.save_file(photo))
else:
- photo = utils.get_input_media_from_file_id(photo)
+ photo = utils.get_input_media_from_file_id(photo, file_ref, 2)
photo = types.InputChatPhoto(id=photo.id)
if isinstance(peer, types.InputPeerChat):
From df5de3e5836e77792aca22509d8f94bd041ae9b5 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Tue, 4 Feb 2020 17:03:33 +0100
Subject: [PATCH 0143/1185] Revert "Add missing file_ref in set_chat_photo
(#343)" (#366)
This reverts commit e316d18bf4bfcae7113588abcc5e021577a39f12.
---
pyrogram/client/methods/chats/set_chat_photo.py | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
diff --git a/pyrogram/client/methods/chats/set_chat_photo.py b/pyrogram/client/methods/chats/set_chat_photo.py
index 689cc15f79..4c91247585 100644
--- a/pyrogram/client/methods/chats/set_chat_photo.py
+++ b/pyrogram/client/methods/chats/set_chat_photo.py
@@ -27,8 +27,7 @@ class SetChatPhoto(BaseClient):
async def set_chat_photo(
self,
chat_id: Union[int, str],
- photo: str,
- file_ref: str = None,
+ photo: str
) -> bool:
"""Set a new profile photo for the chat.
@@ -41,10 +40,6 @@ async def set_chat_photo(
photo (``str``):
New chat photo. You can pass a :obj:`Photo` file_id or a file path to upload a new photo from your local
machine.
-
- file_ref (``str``, *optional*):
- A valid file reference obtained by a recently fetched media message.
- To be used in combination with a file id in case a file reference is needed.
Returns:
``bool``: True on success.
@@ -59,14 +54,14 @@ async def set_chat_photo(
app.set_chat_photo(chat_id, "photo.jpg")
# Set chat photo using an exiting Photo file_id
- app.set_chat_photo(chat_id, photo.file_id, photo.file_ref)
+ app.set_chat_photo(chat_id, photo.file_id)
"""
peer = await self.resolve_peer(chat_id)
if os.path.exists(photo):
photo = types.InputChatUploadedPhoto(file=await self.save_file(photo))
else:
- photo = utils.get_input_media_from_file_id(photo, file_ref, 2)
+ photo = utils.get_input_media_from_file_id(photo)
photo = types.InputChatPhoto(id=photo.id)
if isinstance(peer, types.InputPeerChat):
From 73d9af51efe10e86dc35f579d4ec79eac99f3ae2 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 20 Feb 2020 13:54:51 +0100
Subject: [PATCH 0144/1185] Don't use the "recent" filter when passing a query
argument
---
pyrogram/client/methods/chats/iter_chat_members.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/pyrogram/client/methods/chats/iter_chat_members.py b/pyrogram/client/methods/chats/iter_chat_members.py
index ba621d3ec6..aaa7ab06a2 100644
--- a/pyrogram/client/methods/chats/iter_chat_members.py
+++ b/pyrogram/client/methods/chats/iter_chat_members.py
@@ -101,7 +101,9 @@ def iter_chat_members(
filter = (
Filters.RECENT
- if self.get_chat_members_count(chat_id) <= 10000 and filter == Filters.ALL
+ if (not query
+ and filter == Filters.ALL
+ and self.get_chat_members_count(chat_id) <= 10000)
else filter
)
From 7be86f8ea38a9e9caf5124ebc5632a9eaf38a886 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 20 Feb 2020 20:07:00 +0100
Subject: [PATCH 0145/1185] Update development version
---
pyrogram/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 8739fe118f..5e56f41d43 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__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 .
-__version__ = "0.16.0"
+__version__ = "0.17.0-dev"
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
__copyright__ = "Copyright (C) 2017-2020 Dan "
From 28cee8d01f8f0e97de4cf1ddb86029ea79c5ced3 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 20 Feb 2020 20:41:08 +0100
Subject: [PATCH 0146/1185] Do not ever use "recent" filtering automatically
That code existed to improve members fetching performance for
channels/supergroups with less than 10k+1 members, but it was causing
troubles when fetching members based on a query string and for channels with
less than 10k+1 subscribers
---
pyrogram/client/methods/chats/iter_chat_members.py | 8 --------
1 file changed, 8 deletions(-)
diff --git a/pyrogram/client/methods/chats/iter_chat_members.py b/pyrogram/client/methods/chats/iter_chat_members.py
index aaa7ab06a2..0f71c9ad01 100644
--- a/pyrogram/client/methods/chats/iter_chat_members.py
+++ b/pyrogram/client/methods/chats/iter_chat_members.py
@@ -99,14 +99,6 @@ def iter_chat_members(
limit = min(200, total)
resolved_chat_id = self.resolve_peer(chat_id)
- filter = (
- Filters.RECENT
- if (not query
- and filter == Filters.ALL
- and self.get_chat_members_count(chat_id) <= 10000)
- else filter
- )
-
if filter not in QUERYABLE_FILTERS:
queries = [""]
From f867c660832765811a889bb4c3a4fa749c6ac4ec Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 26 Feb 2020 23:31:01 +0100
Subject: [PATCH 0147/1185] Fix stop_transmission example
---
pyrogram/client/client.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index ecb65da0ef..d212e5c9ee 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -1101,12 +1101,12 @@ def stop_transmission(self):
# Example to stop transmission once the upload progress reaches 50%
# Useless in practice, but shows how to stop on command
- def progress(client, current, total):
+ def progress(current, total, client):
if (current * 100 / total) > 50:
client.stop_transmission()
with app:
- app.send_document("me", "files.zip", progress=progress)
+ app.send_document("me", "files.zip", progress=progress, progress_args=(app,))
"""
raise Client.StopTransmission
From 4a3b1a0e37809b9d63a95837bb035c011894041d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 21 Mar 2020 15:30:12 +0100
Subject: [PATCH 0148/1185] Update .gitignore
---
.gitignore | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index ce3407dd4a..eb4fcccc55 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
-# User's personal information
+# Development
*.session
config.ini
+main.py
+unknown_errors.txt
# Pyrogram generated code
pyrogram/errors/exceptions/
From 1996fb1481d3de784139afb68241ec26fc5b27ef Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 21 Mar 2020 15:43:32 +0100
Subject: [PATCH 0149/1185] Update Copyright
---
compiler/api/compiler.py | 26 ++++++-------
compiler/docs/compiler.py | 26 ++++++-------
compiler/error/compiler.py | 26 ++++++-------
docs/releases.py | 26 ++++++-------
docs/sitemap.py | 26 ++++++-------
docs/source/conf.py | 26 ++++++-------
examples/bot_keyboards.py | 18 ---------
examples/callback_queries.py | 18 ---------
examples/echobot.py | 18 ---------
examples/get_chat_members.py | 18 ---------
examples/get_dialogs.py | 18 ---------
examples/get_history.py | 18 ---------
examples/hello_world.py | 18 ---------
examples/inline_queries.py | 18 ---------
examples/raw_updates.py | 18 ---------
examples/use_inline_bots.py | 18 ---------
examples/welcomebot.py | 18 ---------
pyrogram/__init__.py | 26 ++++++-------
pyrogram/api/__init__.py | 26 ++++++-------
pyrogram/api/core/__init__.py | 26 ++++++-------
pyrogram/api/core/future_salt.py | 26 ++++++-------
pyrogram/api/core/future_salts.py | 26 ++++++-------
pyrogram/api/core/gzip_packed.py | 26 ++++++-------
pyrogram/api/core/list.py | 26 ++++++-------
pyrogram/api/core/message.py | 26 ++++++-------
pyrogram/api/core/msg_container.py | 26 ++++++-------
pyrogram/api/core/primitives/__init__.py | 26 ++++++-------
pyrogram/api/core/primitives/bool.py | 26 ++++++-------
pyrogram/api/core/primitives/bytes.py | 26 ++++++-------
pyrogram/api/core/primitives/double.py | 26 ++++++-------
pyrogram/api/core/primitives/int.py | 26 ++++++-------
pyrogram/api/core/primitives/string.py | 26 ++++++-------
pyrogram/api/core/primitives/vector.py | 26 ++++++-------
pyrogram/api/core/tl_object.py | 26 ++++++-------
pyrogram/client/__init__.py | 26 ++++++-------
pyrogram/client/client.py | 26 ++++++-------
pyrogram/client/ext/__init__.py | 26 ++++++-------
pyrogram/client/ext/base_client.py | 26 ++++++-------
pyrogram/client/ext/dispatcher.py | 26 ++++++-------
pyrogram/client/ext/emoji.py | 27 +++++++------
pyrogram/client/ext/file_data.py | 27 +++++++------
pyrogram/client/ext/syncer.py | 26 ++++++-------
pyrogram/client/ext/utils.py | 39 +++++++++----------
pyrogram/client/filters/__init__.py | 26 ++++++-------
pyrogram/client/filters/filter.py | 27 +++++++------
pyrogram/client/filters/filters.py | 26 ++++++-------
pyrogram/client/handlers/__init__.py | 26 ++++++-------
.../client/handlers/callback_query_handler.py | 26 ++++++-------
.../handlers/deleted_messages_handler.py | 26 ++++++-------
.../client/handlers/disconnect_handler.py | 26 ++++++-------
pyrogram/client/handlers/handler.py | 27 +++++++------
.../client/handlers/inline_query_handler.py | 26 ++++++-------
pyrogram/client/handlers/message_handler.py | 26 ++++++-------
pyrogram/client/handlers/poll_handler.py | 26 ++++++-------
.../client/handlers/raw_update_handler.py | 26 ++++++-------
.../client/handlers/user_status_handler.py | 26 ++++++-------
pyrogram/client/methods/__init__.py | 26 ++++++-------
pyrogram/client/methods/bots/__init__.py | 26 ++++++-------
.../methods/bots/answer_callback_query.py | 26 ++++++-------
.../methods/bots/answer_inline_query.py | 26 ++++++-------
.../methods/bots/get_game_high_scores.py | 26 ++++++-------
.../methods/bots/get_inline_bot_results.py | 26 ++++++-------
.../methods/bots/request_callback_answer.py | 26 ++++++-------
pyrogram/client/methods/bots/send_game.py | 26 ++++++-------
.../methods/bots/send_inline_bot_result.py | 26 ++++++-------
.../client/methods/bots/set_game_score.py | 26 ++++++-------
pyrogram/client/methods/chats/__init__.py | 26 ++++++-------
.../client/methods/chats/add_chat_members.py | 26 ++++++-------
.../client/methods/chats/archive_chats.py | 26 ++++++-------
.../client/methods/chats/create_channel.py | 26 ++++++-------
pyrogram/client/methods/chats/create_group.py | 26 ++++++-------
.../client/methods/chats/create_supergroup.py | 26 ++++++-------
.../client/methods/chats/delete_channel.py | 26 ++++++-------
.../client/methods/chats/delete_chat_photo.py | 26 ++++++-------
.../client/methods/chats/delete_supergroup.py | 26 ++++++-------
.../methods/chats/delete_user_history.py | 26 ++++++-------
.../methods/chats/export_chat_invite_link.py | 26 ++++++-------
pyrogram/client/methods/chats/get_chat.py | 26 ++++++-------
.../client/methods/chats/get_chat_member.py | 26 ++++++-------
.../client/methods/chats/get_chat_members.py | 26 ++++++-------
.../methods/chats/get_chat_members_count.py | 26 ++++++-------
pyrogram/client/methods/chats/get_dialogs.py | 26 ++++++-------
.../client/methods/chats/get_dialogs_count.py | 26 ++++++-------
.../client/methods/chats/get_nearby_chats.py | 26 ++++++-------
.../client/methods/chats/iter_chat_members.py | 26 ++++++-------
pyrogram/client/methods/chats/iter_dialogs.py | 26 ++++++-------
pyrogram/client/methods/chats/join_chat.py | 26 ++++++-------
.../client/methods/chats/kick_chat_member.py | 26 ++++++-------
pyrogram/client/methods/chats/leave_chat.py | 26 ++++++-------
.../client/methods/chats/pin_chat_message.py | 26 ++++++-------
.../methods/chats/promote_chat_member.py | 26 ++++++-------
.../methods/chats/restrict_chat_member.py | 26 ++++++-------
.../methods/chats/set_administrator_title.py | 26 ++++++-------
.../methods/chats/set_chat_description.py | 26 ++++++-------
.../methods/chats/set_chat_permissions.py | 26 ++++++-------
.../client/methods/chats/set_chat_photo.py | 26 ++++++-------
.../client/methods/chats/set_chat_title.py | 26 ++++++-------
.../client/methods/chats/set_slow_mode.py | 26 ++++++-------
.../client/methods/chats/unarchive_chats.py | 26 ++++++-------
.../client/methods/chats/unban_chat_member.py | 26 ++++++-------
.../methods/chats/unpin_chat_message.py | 26 ++++++-------
.../methods/chats/update_chat_username.py | 26 ++++++-------
pyrogram/client/methods/contacts/__init__.py | 26 ++++++-------
.../client/methods/contacts/add_contacts.py | 26 ++++++-------
.../methods/contacts/delete_contacts.py | 26 ++++++-------
.../client/methods/contacts/get_contacts.py | 26 ++++++-------
.../methods/contacts/get_contacts_count.py | 26 ++++++-------
.../client/methods/decorators/__init__.py | 26 ++++++-------
.../methods/decorators/on_callback_query.py | 26 ++++++-------
.../methods/decorators/on_deleted_messages.py | 26 ++++++-------
.../methods/decorators/on_disconnect.py | 26 ++++++-------
.../methods/decorators/on_inline_query.py | 26 ++++++-------
.../client/methods/decorators/on_message.py | 26 ++++++-------
pyrogram/client/methods/decorators/on_poll.py | 26 ++++++-------
.../methods/decorators/on_raw_update.py | 26 ++++++-------
.../methods/decorators/on_user_status.py | 26 ++++++-------
pyrogram/client/methods/messages/__init__.py | 26 ++++++-------
.../methods/messages/delete_messages.py | 26 ++++++-------
.../client/methods/messages/download_media.py | 26 ++++++-------
.../methods/messages/edit_inline_caption.py | 26 ++++++-------
.../methods/messages/edit_inline_media.py | 26 ++++++-------
.../messages/edit_inline_reply_markup.py | 26 ++++++-------
.../methods/messages/edit_inline_text.py | 26 ++++++-------
.../methods/messages/edit_message_caption.py | 26 ++++++-------
.../methods/messages/edit_message_media.py | 26 ++++++-------
.../messages/edit_message_reply_markup.py | 26 ++++++-------
.../methods/messages/edit_message_text.py | 26 ++++++-------
.../methods/messages/forward_messages.py | 26 ++++++-------
.../client/methods/messages/get_history.py | 26 ++++++-------
.../methods/messages/get_history_count.py | 26 ++++++-------
.../client/methods/messages/get_messages.py | 26 ++++++-------
.../client/methods/messages/iter_history.py | 26 ++++++-------
.../client/methods/messages/read_history.py | 26 ++++++-------
.../client/methods/messages/retract_vote.py | 26 ++++++-------
.../client/methods/messages/send_animation.py | 26 ++++++-------
.../client/methods/messages/send_audio.py | 26 ++++++-------
.../methods/messages/send_cached_media.py | 26 ++++++-------
.../methods/messages/send_chat_action.py | 26 ++++++-------
.../client/methods/messages/send_contact.py | 26 ++++++-------
.../client/methods/messages/send_document.py | 26 ++++++-------
.../client/methods/messages/send_location.py | 26 ++++++-------
.../methods/messages/send_media_group.py | 26 ++++++-------
.../client/methods/messages/send_message.py | 26 ++++++-------
.../client/methods/messages/send_photo.py | 26 ++++++-------
pyrogram/client/methods/messages/send_poll.py | 26 ++++++-------
.../client/methods/messages/send_sticker.py | 26 ++++++-------
.../client/methods/messages/send_venue.py | 26 ++++++-------
.../client/methods/messages/send_video.py | 26 ++++++-------
.../methods/messages/send_video_note.py | 26 ++++++-------
.../client/methods/messages/send_voice.py | 26 ++++++-------
pyrogram/client/methods/messages/stop_poll.py | 26 ++++++-------
pyrogram/client/methods/messages/vote_poll.py | 26 ++++++-------
pyrogram/client/methods/password/__init__.py | 26 ++++++-------
.../methods/password/change_cloud_password.py | 26 ++++++-------
.../methods/password/enable_cloud_password.py | 26 ++++++-------
.../methods/password/remove_cloud_password.py | 26 ++++++-------
pyrogram/client/methods/password/utils.py | 26 ++++++-------
pyrogram/client/methods/users/__init__.py | 26 ++++++-------
pyrogram/client/methods/users/block_user.py | 26 ++++++-------
.../methods/users/delete_profile_photos.py | 26 ++++++-------
.../client/methods/users/get_common_chats.py | 26 ++++++-------
pyrogram/client/methods/users/get_me.py | 26 ++++++-------
.../methods/users/get_profile_photos.py | 26 ++++++-------
.../methods/users/get_profile_photos_count.py | 26 ++++++-------
pyrogram/client/methods/users/get_users.py | 26 ++++++-------
.../methods/users/iter_profile_photos.py | 26 ++++++-------
.../client/methods/users/set_profile_photo.py | 26 ++++++-------
pyrogram/client/methods/users/unblock_user.py | 26 ++++++-------
.../client/methods/users/update_profile.py | 26 ++++++-------
.../client/methods/users/update_username.py | 26 ++++++-------
pyrogram/client/parser/__init__.py | 26 ++++++-------
pyrogram/client/parser/html.py | 26 ++++++-------
pyrogram/client/parser/markdown.py | 26 ++++++-------
pyrogram/client/parser/parser.py | 26 ++++++-------
pyrogram/client/parser/utils.py | 26 ++++++-------
pyrogram/client/storage/__init__.py | 26 ++++++-------
pyrogram/client/storage/file_storage.py | 26 ++++++-------
pyrogram/client/storage/memory_storage.py | 26 ++++++-------
pyrogram/client/storage/schema.sql | 20 ++++++++++
pyrogram/client/storage/sqlite_storage.py | 26 ++++++-------
pyrogram/client/storage/storage.py | 26 ++++++-------
pyrogram/client/types/__init__.py | 26 ++++++-------
.../client/types/authorization/__init__.py | 26 ++++++-------
.../client/types/authorization/sent_code.py | 26 ++++++-------
.../types/authorization/terms_of_service.py | 26 ++++++-------
.../types/bots_and_keyboards/__init__.py | 26 ++++++-------
.../types/bots_and_keyboards/callback_game.py | 26 ++++++-------
.../bots_and_keyboards/callback_query.py | 26 ++++++-------
.../types/bots_and_keyboards/force_reply.py | 26 ++++++-------
.../bots_and_keyboards/game_high_score.py | 26 ++++++-------
.../inline_keyboard_button.py | 26 ++++++-------
.../inline_keyboard_markup.py | 26 ++++++-------
.../bots_and_keyboards/keyboard_button.py | 26 ++++++-------
.../reply_keyboard_markup.py | 26 ++++++-------
.../reply_keyboard_remove.py | 26 ++++++-------
pyrogram/client/types/inline_mode/__init__.py | 26 ++++++-------
.../client/types/inline_mode/inline_query.py | 26 ++++++-------
.../types/inline_mode/inline_query_result.py | 26 ++++++-------
.../inline_query_result_animation.py | 26 ++++++-------
.../inline_query_result_article.py | 26 ++++++-------
.../inline_mode/inline_query_result_photo.py | 26 ++++++-------
pyrogram/client/types/input_media/__init__.py | 26 ++++++-------
.../client/types/input_media/input_media.py | 26 ++++++-------
.../input_media/input_media_animation.py | 26 ++++++-------
.../types/input_media/input_media_audio.py | 26 ++++++-------
.../types/input_media/input_media_document.py | 26 ++++++-------
.../types/input_media/input_media_photo.py | 26 ++++++-------
.../types/input_media/input_media_video.py | 26 ++++++-------
.../types/input_media/input_phone_contact.py | 26 ++++++-------
.../types/input_message_content/__init__.py | 26 ++++++-------
.../input_message_content.py | 26 ++++++-------
.../input_text_message_content.py | 26 ++++++-------
pyrogram/client/types/list.py | 26 ++++++-------
.../types/messages_and_media/__init__.py | 26 ++++++-------
.../types/messages_and_media/animation.py | 26 ++++++-------
.../client/types/messages_and_media/audio.py | 26 ++++++-------
.../types/messages_and_media/contact.py | 26 ++++++-------
.../types/messages_and_media/document.py | 26 ++++++-------
.../client/types/messages_and_media/game.py | 26 ++++++-------
.../types/messages_and_media/location.py | 26 ++++++-------
.../types/messages_and_media/message.py | 26 ++++++-------
.../messages_and_media/message_entity.py | 26 ++++++-------
.../client/types/messages_and_media/photo.py | 26 ++++++-------
.../client/types/messages_and_media/poll.py | 26 ++++++-------
.../types/messages_and_media/poll_option.py | 26 ++++++-------
.../types/messages_and_media/sticker.py | 26 ++++++-------
.../messages_and_media/stripped_thumbnail.py | 26 ++++++-------
.../types/messages_and_media/thumbnail.py | 26 ++++++-------
.../client/types/messages_and_media/venue.py | 26 ++++++-------
.../client/types/messages_and_media/video.py | 26 ++++++-------
.../types/messages_and_media/video_note.py | 26 ++++++-------
.../client/types/messages_and_media/voice.py | 26 ++++++-------
.../types/messages_and_media/webpage.py | 26 ++++++-------
pyrogram/client/types/object.py | 26 ++++++-------
pyrogram/client/types/update.py | 27 +++++++------
.../client/types/user_and_chats/__init__.py | 26 ++++++-------
pyrogram/client/types/user_and_chats/chat.py | 26 ++++++-------
.../types/user_and_chats/chat_member.py | 26 ++++++-------
.../types/user_and_chats/chat_permissions.py | 26 ++++++-------
.../client/types/user_and_chats/chat_photo.py | 26 ++++++-------
.../types/user_and_chats/chat_preview.py | 26 ++++++-------
.../client/types/user_and_chats/dialog.py | 26 ++++++-------
.../types/user_and_chats/restriction.py | 26 ++++++-------
pyrogram/client/types/user_and_chats/user.py | 26 ++++++-------
pyrogram/connection/__init__.py | 26 ++++++-------
pyrogram/connection/connection.py | 26 ++++++-------
pyrogram/connection/transport/__init__.py | 26 ++++++-------
pyrogram/connection/transport/tcp/__init__.py | 26 ++++++-------
pyrogram/connection/transport/tcp/tcp.py | 26 ++++++-------
.../connection/transport/tcp/tcp_abridged.py | 26 ++++++-------
.../transport/tcp/tcp_abridged_o.py | 26 ++++++-------
pyrogram/connection/transport/tcp/tcp_full.py | 26 ++++++-------
.../transport/tcp/tcp_intermediate.py | 26 ++++++-------
.../transport/tcp/tcp_intermediate_o.py | 26 ++++++-------
pyrogram/crypto/__init__.py | 26 ++++++-------
pyrogram/crypto/aes.py | 26 ++++++-------
pyrogram/crypto/kdf.py | 26 ++++++-------
pyrogram/crypto/prime.py | 26 ++++++-------
pyrogram/crypto/rsa.py | 26 ++++++-------
pyrogram/errors/__init__.py | 26 ++++++-------
pyrogram/errors/rpc_error.py | 26 ++++++-------
pyrogram/session/__init__.py | 26 ++++++-------
pyrogram/session/auth.py | 26 ++++++-------
pyrogram/session/internals/__init__.py | 26 ++++++-------
pyrogram/session/internals/data_center.py | 27 +++++++------
pyrogram/session/internals/msg_factory.py | 26 ++++++-------
pyrogram/session/internals/msg_id.py | 26 ++++++-------
pyrogram/session/internals/seq_no.py | 26 ++++++-------
pyrogram/session/session.py | 26 ++++++-------
setup.py | 26 ++++++-------
270 files changed, 3380 insertions(+), 3565 deletions(-)
diff --git a/compiler/api/compiler.py b/compiler/api/compiler.py
index 7c6d8ffd61..f6cb57423b 100644
--- a/compiler/api/compiler.py
+++ b/compiler/api/compiler.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import os
import re
diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py
index db3fec546f..346b47c739 100644
--- a/compiler/docs/compiler.py
+++ b/compiler/docs/compiler.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import ast
import os
diff --git a/compiler/error/compiler.py b/compiler/error/compiler.py
index 3730ec26a3..222fdfcabc 100644
--- a/compiler/error/compiler.py
+++ b/compiler/error/compiler.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import csv
import os
diff --git a/docs/releases.py b/docs/releases.py
index 164c7d2f4d..9b7388f994 100644
--- a/docs/releases.py
+++ b/docs/releases.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import shutil
from datetime import datetime
diff --git a/docs/sitemap.py b/docs/sitemap.py
index 9f4c7758ac..4b08f218a5 100644
--- a/docs/sitemap.py
+++ b/docs/sitemap.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import datetime
import os
diff --git a/docs/source/conf.py b/docs/source/conf.py
index e60d4822fe..40caccb0d3 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import os
import sys
diff --git a/examples/bot_keyboards.py b/examples/bot_keyboards.py
index 9cdbb16b6e..e1ff1e7e3f 100644
--- a/examples/bot_keyboards.py
+++ b/examples/bot_keyboards.py
@@ -1,21 +1,3 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
-#
-# 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 .
-
"""This example will show you how to send normal and inline keyboards (as bot).
You must log-in as a regular bot in order to send keyboards (use the token from @BotFather).
diff --git a/examples/callback_queries.py b/examples/callback_queries.py
index 77cf5b3416..f4a87b0041 100644
--- a/examples/callback_queries.py
+++ b/examples/callback_queries.py
@@ -1,21 +1,3 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
-#
-# 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 .
-
"""This example shows how to handle callback queries, i.e.: queries coming from inline button presses.
It uses the @on_callback_query decorator to register a CallbackQueryHandler.
diff --git a/examples/echobot.py b/examples/echobot.py
index b8386e1561..c60ae2917b 100644
--- a/examples/echobot.py
+++ b/examples/echobot.py
@@ -1,21 +1,3 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
-#
-# 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 .
-
"""This simple echo bot replies to every private text message.
It uses the @on_message decorator to register a MessageHandler and applies two filters on it:
diff --git a/examples/get_chat_members.py b/examples/get_chat_members.py
index 3eb7d98bfa..468ac7dec5 100644
--- a/examples/get_chat_members.py
+++ b/examples/get_chat_members.py
@@ -1,21 +1,3 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
-#
-# 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 .
-
"""This example shows how to get all the members of a chat."""
from pyrogram import Client
diff --git a/examples/get_dialogs.py b/examples/get_dialogs.py
index 2efdade209..92da8834c9 100644
--- a/examples/get_dialogs.py
+++ b/examples/get_dialogs.py
@@ -1,21 +1,3 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
-#
-# 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 .
-
"""This example shows how to get the full dialogs list (as user)."""
from pyrogram import Client
diff --git a/examples/get_history.py b/examples/get_history.py
index b94b2c8b9e..e8bb14e31d 100644
--- a/examples/get_history.py
+++ b/examples/get_history.py
@@ -1,21 +1,3 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
-#
-# 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 .
-
"""This example shows how to get the full message history of a chat, starting from the latest message"""
from pyrogram import Client
diff --git a/examples/hello_world.py b/examples/hello_world.py
index 925d354277..19d0ffe76f 100644
--- a/examples/hello_world.py
+++ b/examples/hello_world.py
@@ -1,21 +1,3 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
-#
-# 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 .
-
"""This example demonstrates a basic API usage"""
from pyrogram import Client
diff --git a/examples/inline_queries.py b/examples/inline_queries.py
index 84c1357e74..d86d90d5c7 100644
--- a/examples/inline_queries.py
+++ b/examples/inline_queries.py
@@ -1,21 +1,3 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
-#
-# 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 .
-
"""This example shows how to handle inline queries.
Two results are generated when users invoke the bot inline mode, e.g.: @pyrogrambot hi.
It uses the @on_inline_query decorator to register an InlineQueryHandler.
diff --git a/examples/raw_updates.py b/examples/raw_updates.py
index 26c9254543..27d87eb37b 100644
--- a/examples/raw_updates.py
+++ b/examples/raw_updates.py
@@ -1,21 +1,3 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
-#
-# 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 .
-
"""This example shows how to handle raw updates"""
from pyrogram import Client
diff --git a/examples/use_inline_bots.py b/examples/use_inline_bots.py
index 041ad5cf3c..5681df8778 100644
--- a/examples/use_inline_bots.py
+++ b/examples/use_inline_bots.py
@@ -1,21 +1,3 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
-#
-# 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 .
-
"""This example shows how to query an inline bot (as user)"""
from pyrogram import Client
diff --git a/examples/welcomebot.py b/examples/welcomebot.py
index 9252ad85f6..35f72afff8 100644
--- a/examples/welcomebot.py
+++ b/examples/welcomebot.py
@@ -1,21 +1,3 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
-#
-# 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 .
-
"""This is the Welcome Bot in @PyrogramChat.
It uses the Emoji module to easily add emojis in your text messages and Filters
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 5e56f41d43..60db23254e 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
__version__ = "0.17.0-dev"
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
diff --git a/pyrogram/api/__init__.py b/pyrogram/api/__init__.py
index 2d3a54ca8f..da5b075e7b 100644
--- a/pyrogram/api/__init__.py
+++ b/pyrogram/api/__init__.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from importlib import import_module
diff --git a/pyrogram/api/core/__init__.py b/pyrogram/api/core/__init__.py
index 65af114d22..22484f6fb2 100644
--- a/pyrogram/api/core/__init__.py
+++ b/pyrogram/api/core/__init__.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .future_salt import FutureSalt
from .future_salts import FutureSalts
diff --git a/pyrogram/api/core/future_salt.py b/pyrogram/api/core/future_salt.py
index a175244eb8..cc9f7bc0fa 100644
--- a/pyrogram/api/core/future_salt.py
+++ b/pyrogram/api/core/future_salt.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from io import BytesIO
diff --git a/pyrogram/api/core/future_salts.py b/pyrogram/api/core/future_salts.py
index 80cd775e43..f22b464301 100644
--- a/pyrogram/api/core/future_salts.py
+++ b/pyrogram/api/core/future_salts.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from io import BytesIO
diff --git a/pyrogram/api/core/gzip_packed.py b/pyrogram/api/core/gzip_packed.py
index 693c497456..1920c67de7 100644
--- a/pyrogram/api/core/gzip_packed.py
+++ b/pyrogram/api/core/gzip_packed.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from gzip import compress, decompress
from io import BytesIO
diff --git a/pyrogram/api/core/list.py b/pyrogram/api/core/list.py
index bf8670d007..0e083f17a6 100644
--- a/pyrogram/api/core/list.py
+++ b/pyrogram/api/core/list.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .tl_object import TLObject
diff --git a/pyrogram/api/core/message.py b/pyrogram/api/core/message.py
index 23b1e1c4d8..787aa3785d 100644
--- a/pyrogram/api/core/message.py
+++ b/pyrogram/api/core/message.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from io import BytesIO
diff --git a/pyrogram/api/core/msg_container.py b/pyrogram/api/core/msg_container.py
index 06e412cbfb..dc6f755d74 100644
--- a/pyrogram/api/core/msg_container.py
+++ b/pyrogram/api/core/msg_container.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from io import BytesIO
diff --git a/pyrogram/api/core/primitives/__init__.py b/pyrogram/api/core/primitives/__init__.py
index 6621102b0a..f7b1c89ec8 100644
--- a/pyrogram/api/core/primitives/__init__.py
+++ b/pyrogram/api/core/primitives/__init__.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .bool import Bool, BoolFalse, BoolTrue
from .bytes import Bytes
diff --git a/pyrogram/api/core/primitives/bool.py b/pyrogram/api/core/primitives/bool.py
index d62e3fb98d..966372255f 100644
--- a/pyrogram/api/core/primitives/bool.py
+++ b/pyrogram/api/core/primitives/bool.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from io import BytesIO
diff --git a/pyrogram/api/core/primitives/bytes.py b/pyrogram/api/core/primitives/bytes.py
index 429eb4eb39..298ea5440a 100644
--- a/pyrogram/api/core/primitives/bytes.py
+++ b/pyrogram/api/core/primitives/bytes.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from io import BytesIO
diff --git a/pyrogram/api/core/primitives/double.py b/pyrogram/api/core/primitives/double.py
index 4d7261aa92..42cf0031ee 100644
--- a/pyrogram/api/core/primitives/double.py
+++ b/pyrogram/api/core/primitives/double.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from io import BytesIO
from struct import unpack, pack
diff --git a/pyrogram/api/core/primitives/int.py b/pyrogram/api/core/primitives/int.py
index a71cd5b209..bbaf7f2fcf 100644
--- a/pyrogram/api/core/primitives/int.py
+++ b/pyrogram/api/core/primitives/int.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from io import BytesIO
diff --git a/pyrogram/api/core/primitives/string.py b/pyrogram/api/core/primitives/string.py
index 4f25d1047a..a0995c5b9a 100644
--- a/pyrogram/api/core/primitives/string.py
+++ b/pyrogram/api/core/primitives/string.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from io import BytesIO
diff --git a/pyrogram/api/core/primitives/vector.py b/pyrogram/api/core/primitives/vector.py
index b7b95f09e8..2c60f5766c 100644
--- a/pyrogram/api/core/primitives/vector.py
+++ b/pyrogram/api/core/primitives/vector.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from io import BytesIO
diff --git a/pyrogram/api/core/tl_object.py b/pyrogram/api/core/tl_object.py
index 94c0a47fa8..d9d5722f1b 100644
--- a/pyrogram/api/core/tl_object.py
+++ b/pyrogram/api/core/tl_object.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from collections import OrderedDict
from io import BytesIO
diff --git a/pyrogram/client/__init__.py b/pyrogram/client/__init__.py
index 6285eed1f1..d0b82f9184 100644
--- a/pyrogram/client/__init__.py
+++ b/pyrogram/client/__init__.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .client import Client
from .ext import BaseClient, Emoji
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index d212e5c9ee..42a3f3304d 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import logging
import math
diff --git a/pyrogram/client/ext/__init__.py b/pyrogram/client/ext/__init__.py
index c00a925f13..8b44ca5805 100644
--- a/pyrogram/client/ext/__init__.py
+++ b/pyrogram/client/ext/__init__.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .base_client import BaseClient
from .dispatcher import Dispatcher
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index c1e85e96bb..750dc3fc19 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import os
import platform
diff --git a/pyrogram/client/ext/dispatcher.py b/pyrogram/client/ext/dispatcher.py
index 2026365348..20be359eef 100644
--- a/pyrogram/client/ext/dispatcher.py
+++ b/pyrogram/client/ext/dispatcher.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import logging
import threading
diff --git a/pyrogram/client/ext/emoji.py b/pyrogram/client/ext/emoji.py
index 7845569888..97bfc52961 100644
--- a/pyrogram/client/ext/emoji.py
+++ b/pyrogram/client/ext/emoji.py
@@ -1,21 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
-
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
class Emoji:
HELMET_WITH_WHITE_CROSS_TYPE_1_2 = "\u26d1\U0001f3fb"
diff --git a/pyrogram/client/ext/file_data.py b/pyrogram/client/ext/file_data.py
index 5839e68b59..ea9de6e1ba 100644
--- a/pyrogram/client/ext/file_data.py
+++ b/pyrogram/client/ext/file_data.py
@@ -1,21 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
-
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
class FileData:
def __init__(
diff --git a/pyrogram/client/ext/syncer.py b/pyrogram/client/ext/syncer.py
index 1011596b58..bfe99c9814 100644
--- a/pyrogram/client/ext/syncer.py
+++ b/pyrogram/client/ext/syncer.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import logging
import time
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index 39e5fd0f91..b46a8038fb 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import base64
import struct
@@ -31,13 +31,12 @@ def decode_file_id(s: str) -> bytes:
s = base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))
r = b""
- try:
- assert s[-1] == 2
- skip = 1
- except AssertionError:
- assert s[-2] == 22
- assert s[-1] == 4
- skip = 2
+ major = s[-1]
+ minor = s[-2] if major != 2 else 0
+
+ assert minor in (0, 22, 24)
+
+ skip = 2 if minor else 1
i = 0
diff --git a/pyrogram/client/filters/__init__.py b/pyrogram/client/filters/__init__.py
index 37a9e3c3ac..bdb72abc79 100644
--- a/pyrogram/client/filters/__init__.py
+++ b/pyrogram/client/filters/__init__.py
@@ -1,19 +1,19 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .filters import Filters
diff --git a/pyrogram/client/filters/filter.py b/pyrogram/client/filters/filter.py
index 112a814d16..eb89b3c387 100644
--- a/pyrogram/client/filters/filter.py
+++ b/pyrogram/client/filters/filter.py
@@ -1,21 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
-
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
class Filter:
def __call__(self, message):
diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py
index ba63434ab4..2463764074 100644
--- a/pyrogram/client/filters/filters.py
+++ b/pyrogram/client/filters/filters.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import re
from typing import Callable
diff --git a/pyrogram/client/handlers/__init__.py b/pyrogram/client/handlers/__init__.py
index df1fcd4e48..25acbedc9f 100644
--- a/pyrogram/client/handlers/__init__.py
+++ b/pyrogram/client/handlers/__init__.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .callback_query_handler import CallbackQueryHandler
from .deleted_messages_handler import DeletedMessagesHandler
diff --git a/pyrogram/client/handlers/callback_query_handler.py b/pyrogram/client/handlers/callback_query_handler.py
index 2f3ffd5c8d..99aa2e70b7 100644
--- a/pyrogram/client/handlers/callback_query_handler.py
+++ b/pyrogram/client/handlers/callback_query_handler.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .handler import Handler
diff --git a/pyrogram/client/handlers/deleted_messages_handler.py b/pyrogram/client/handlers/deleted_messages_handler.py
index 14896505c3..7312ba90f3 100644
--- a/pyrogram/client/handlers/deleted_messages_handler.py
+++ b/pyrogram/client/handlers/deleted_messages_handler.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .handler import Handler
diff --git a/pyrogram/client/handlers/disconnect_handler.py b/pyrogram/client/handlers/disconnect_handler.py
index 27f18d65db..f4aec6b22d 100644
--- a/pyrogram/client/handlers/disconnect_handler.py
+++ b/pyrogram/client/handlers/disconnect_handler.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .handler import Handler
diff --git a/pyrogram/client/handlers/handler.py b/pyrogram/client/handlers/handler.py
index 5604124eef..0eb132d1e9 100644
--- a/pyrogram/client/handlers/handler.py
+++ b/pyrogram/client/handlers/handler.py
@@ -1,21 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
-
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
class Handler:
def __init__(self, callback: callable, filters=None):
diff --git a/pyrogram/client/handlers/inline_query_handler.py b/pyrogram/client/handlers/inline_query_handler.py
index 51cf9888c0..aaa63c351c 100644
--- a/pyrogram/client/handlers/inline_query_handler.py
+++ b/pyrogram/client/handlers/inline_query_handler.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .handler import Handler
diff --git a/pyrogram/client/handlers/message_handler.py b/pyrogram/client/handlers/message_handler.py
index df82086037..f5a3b6e935 100644
--- a/pyrogram/client/handlers/message_handler.py
+++ b/pyrogram/client/handlers/message_handler.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .handler import Handler
diff --git a/pyrogram/client/handlers/poll_handler.py b/pyrogram/client/handlers/poll_handler.py
index e5649c8fb3..9dc90c4f56 100644
--- a/pyrogram/client/handlers/poll_handler.py
+++ b/pyrogram/client/handlers/poll_handler.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .handler import Handler
diff --git a/pyrogram/client/handlers/raw_update_handler.py b/pyrogram/client/handlers/raw_update_handler.py
index 936ec4f95f..fa01ced53c 100644
--- a/pyrogram/client/handlers/raw_update_handler.py
+++ b/pyrogram/client/handlers/raw_update_handler.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .handler import Handler
diff --git a/pyrogram/client/handlers/user_status_handler.py b/pyrogram/client/handlers/user_status_handler.py
index 538d1dabb7..94404d69f2 100644
--- a/pyrogram/client/handlers/user_status_handler.py
+++ b/pyrogram/client/handlers/user_status_handler.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .handler import Handler
diff --git a/pyrogram/client/methods/__init__.py b/pyrogram/client/methods/__init__.py
index f753bb5a17..54516e98fd 100644
--- a/pyrogram/client/methods/__init__.py
+++ b/pyrogram/client/methods/__init__.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .bots import Bots
from .chats import Chats
diff --git a/pyrogram/client/methods/bots/__init__.py b/pyrogram/client/methods/bots/__init__.py
index be933b0bb0..215df97c05 100644
--- a/pyrogram/client/methods/bots/__init__.py
+++ b/pyrogram/client/methods/bots/__init__.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .answer_callback_query import AnswerCallbackQuery
from .answer_inline_query import AnswerInlineQuery
diff --git a/pyrogram/client/methods/bots/answer_callback_query.py b/pyrogram/client/methods/bots/answer_callback_query.py
index 54c2f5df31..53cd6c4991 100644
--- a/pyrogram/client/methods/bots/answer_callback_query.py
+++ b/pyrogram/client/methods/bots/answer_callback_query.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# 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 pyrogram.client.ext import BaseClient
diff --git a/pyrogram/client/methods/bots/answer_inline_query.py b/pyrogram/client/methods/bots/answer_inline_query.py
index 4b43e89c60..2f95c9b9f7 100644
--- a/pyrogram/client/methods/bots/answer_inline_query.py
+++ b/pyrogram/client/methods/bots/answer_inline_query.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import List
diff --git a/pyrogram/client/methods/bots/get_game_high_scores.py b/pyrogram/client/methods/bots/get_game_high_scores.py
index 25d87ae5f4..1cebc8a624 100644
--- a/pyrogram/client/methods/bots/get_game_high_scores.py
+++ b/pyrogram/client/methods/bots/get_game_high_scores.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union, List
diff --git a/pyrogram/client/methods/bots/get_inline_bot_results.py b/pyrogram/client/methods/bots/get_inline_bot_results.py
index 5db1904f1e..aa27b7c9f3 100644
--- a/pyrogram/client/methods/bots/get_inline_bot_results.py
+++ b/pyrogram/client/methods/bots/get_inline_bot_results.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/bots/request_callback_answer.py b/pyrogram/client/methods/bots/request_callback_answer.py
index 9c9e6412b0..6178b94064 100644
--- a/pyrogram/client/methods/bots/request_callback_answer.py
+++ b/pyrogram/client/methods/bots/request_callback_answer.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/bots/send_game.py b/pyrogram/client/methods/bots/send_game.py
index 1a4bc40ed1..e9513ac8b8 100644
--- a/pyrogram/client/methods/bots/send_game.py
+++ b/pyrogram/client/methods/bots/send_game.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/bots/send_inline_bot_result.py b/pyrogram/client/methods/bots/send_inline_bot_result.py
index 4d6d92073a..9b2cdf605e 100644
--- a/pyrogram/client/methods/bots/send_inline_bot_result.py
+++ b/pyrogram/client/methods/bots/send_inline_bot_result.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/bots/set_game_score.py b/pyrogram/client/methods/bots/set_game_score.py
index 62ee052d3f..25d8fc0b5a 100644
--- a/pyrogram/client/methods/bots/set_game_score.py
+++ b/pyrogram/client/methods/bots/set_game_score.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/__init__.py b/pyrogram/client/methods/chats/__init__.py
index 76a456cfbc..8c7fb3402c 100644
--- a/pyrogram/client/methods/chats/__init__.py
+++ b/pyrogram/client/methods/chats/__init__.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from .add_chat_members import AddChatMembers
from .archive_chats import ArchiveChats
diff --git a/pyrogram/client/methods/chats/add_chat_members.py b/pyrogram/client/methods/chats/add_chat_members.py
index 33af6f46a4..b04d5555b0 100644
--- a/pyrogram/client/methods/chats/add_chat_members.py
+++ b/pyrogram/client/methods/chats/add_chat_members.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union, List
diff --git a/pyrogram/client/methods/chats/archive_chats.py b/pyrogram/client/methods/chats/archive_chats.py
index 1aea591ed7..3c1cabf74a 100644
--- a/pyrogram/client/methods/chats/archive_chats.py
+++ b/pyrogram/client/methods/chats/archive_chats.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union, List
diff --git a/pyrogram/client/methods/chats/create_channel.py b/pyrogram/client/methods/chats/create_channel.py
index d63aa614f6..5986f7035b 100644
--- a/pyrogram/client/methods/chats/create_channel.py
+++ b/pyrogram/client/methods/chats/create_channel.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import pyrogram
from pyrogram.api import functions
diff --git a/pyrogram/client/methods/chats/create_group.py b/pyrogram/client/methods/chats/create_group.py
index aa2585c4bd..43ec6e7fd3 100644
--- a/pyrogram/client/methods/chats/create_group.py
+++ b/pyrogram/client/methods/chats/create_group.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union, List
diff --git a/pyrogram/client/methods/chats/create_supergroup.py b/pyrogram/client/methods/chats/create_supergroup.py
index c51922c7ed..139064ec5b 100644
--- a/pyrogram/client/methods/chats/create_supergroup.py
+++ b/pyrogram/client/methods/chats/create_supergroup.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import pyrogram
from pyrogram.api import functions
diff --git a/pyrogram/client/methods/chats/delete_channel.py b/pyrogram/client/methods/chats/delete_channel.py
index 149d8f142b..fd07b0e6da 100644
--- a/pyrogram/client/methods/chats/delete_channel.py
+++ b/pyrogram/client/methods/chats/delete_channel.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/delete_chat_photo.py b/pyrogram/client/methods/chats/delete_chat_photo.py
index 3909bb6c53..655d6fd6a9 100644
--- a/pyrogram/client/methods/chats/delete_chat_photo.py
+++ b/pyrogram/client/methods/chats/delete_chat_photo.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/delete_supergroup.py b/pyrogram/client/methods/chats/delete_supergroup.py
index a0d361178b..df4649e561 100644
--- a/pyrogram/client/methods/chats/delete_supergroup.py
+++ b/pyrogram/client/methods/chats/delete_supergroup.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/delete_user_history.py b/pyrogram/client/methods/chats/delete_user_history.py
index 1b569497aa..03d87ca43e 100644
--- a/pyrogram/client/methods/chats/delete_user_history.py
+++ b/pyrogram/client/methods/chats/delete_user_history.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/export_chat_invite_link.py b/pyrogram/client/methods/chats/export_chat_invite_link.py
index ab4b08c567..671c1ade9b 100644
--- a/pyrogram/client/methods/chats/export_chat_invite_link.py
+++ b/pyrogram/client/methods/chats/export_chat_invite_link.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/get_chat.py b/pyrogram/client/methods/chats/get_chat.py
index eab49529df..14adc1a78c 100644
--- a/pyrogram/client/methods/chats/get_chat.py
+++ b/pyrogram/client/methods/chats/get_chat.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/get_chat_member.py b/pyrogram/client/methods/chats/get_chat_member.py
index 261caf2d09..9a7bdeff33 100644
--- a/pyrogram/client/methods/chats/get_chat_member.py
+++ b/pyrogram/client/methods/chats/get_chat_member.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/get_chat_members.py b/pyrogram/client/methods/chats/get_chat_members.py
index 7b184be173..a8ae405487 100644
--- a/pyrogram/client/methods/chats/get_chat_members.py
+++ b/pyrogram/client/methods/chats/get_chat_members.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import logging
import time
diff --git a/pyrogram/client/methods/chats/get_chat_members_count.py b/pyrogram/client/methods/chats/get_chat_members_count.py
index e82d4bda7d..ad77acc1bf 100644
--- a/pyrogram/client/methods/chats/get_chat_members_count.py
+++ b/pyrogram/client/methods/chats/get_chat_members_count.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/get_dialogs.py b/pyrogram/client/methods/chats/get_dialogs.py
index 4c55c57b02..6234538b72 100644
--- a/pyrogram/client/methods/chats/get_dialogs.py
+++ b/pyrogram/client/methods/chats/get_dialogs.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import logging
import time
diff --git a/pyrogram/client/methods/chats/get_dialogs_count.py b/pyrogram/client/methods/chats/get_dialogs_count.py
index 5d49815646..7b81182eda 100644
--- a/pyrogram/client/methods/chats/get_dialogs_count.py
+++ b/pyrogram/client/methods/chats/get_dialogs_count.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from pyrogram.api import functions, types
from ...ext import BaseClient
diff --git a/pyrogram/client/methods/chats/get_nearby_chats.py b/pyrogram/client/methods/chats/get_nearby_chats.py
index 75f7a88ad2..1ccab72976 100644
--- a/pyrogram/client/methods/chats/get_nearby_chats.py
+++ b/pyrogram/client/methods/chats/get_nearby_chats.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import List
diff --git a/pyrogram/client/methods/chats/iter_chat_members.py b/pyrogram/client/methods/chats/iter_chat_members.py
index 0f71c9ad01..0bc903052b 100644
--- a/pyrogram/client/methods/chats/iter_chat_members.py
+++ b/pyrogram/client/methods/chats/iter_chat_members.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from string import ascii_lowercase
from typing import Union, Generator
diff --git a/pyrogram/client/methods/chats/iter_dialogs.py b/pyrogram/client/methods/chats/iter_dialogs.py
index 8bf3468d22..a2eddcb9d8 100644
--- a/pyrogram/client/methods/chats/iter_dialogs.py
+++ b/pyrogram/client/methods/chats/iter_dialogs.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Generator
diff --git a/pyrogram/client/methods/chats/join_chat.py b/pyrogram/client/methods/chats/join_chat.py
index f0b942a18c..c379bf03c5 100644
--- a/pyrogram/client/methods/chats/join_chat.py
+++ b/pyrogram/client/methods/chats/join_chat.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import pyrogram
from pyrogram.api import functions, types
diff --git a/pyrogram/client/methods/chats/kick_chat_member.py b/pyrogram/client/methods/chats/kick_chat_member.py
index eb2b66286d..55a177f466 100644
--- a/pyrogram/client/methods/chats/kick_chat_member.py
+++ b/pyrogram/client/methods/chats/kick_chat_member.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/leave_chat.py b/pyrogram/client/methods/chats/leave_chat.py
index d70b4fae84..2cc1c05755 100644
--- a/pyrogram/client/methods/chats/leave_chat.py
+++ b/pyrogram/client/methods/chats/leave_chat.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/pin_chat_message.py b/pyrogram/client/methods/chats/pin_chat_message.py
index ce1b080cac..44191a2d8b 100644
--- a/pyrogram/client/methods/chats/pin_chat_message.py
+++ b/pyrogram/client/methods/chats/pin_chat_message.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/promote_chat_member.py b/pyrogram/client/methods/chats/promote_chat_member.py
index 3e28a1177c..70b4f4e26c 100644
--- a/pyrogram/client/methods/chats/promote_chat_member.py
+++ b/pyrogram/client/methods/chats/promote_chat_member.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/restrict_chat_member.py b/pyrogram/client/methods/chats/restrict_chat_member.py
index 0c432c5f4d..528ad1bca4 100644
--- a/pyrogram/client/methods/chats/restrict_chat_member.py
+++ b/pyrogram/client/methods/chats/restrict_chat_member.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/set_administrator_title.py b/pyrogram/client/methods/chats/set_administrator_title.py
index fb2265c508..361a4e1c2f 100644
--- a/pyrogram/client/methods/chats/set_administrator_title.py
+++ b/pyrogram/client/methods/chats/set_administrator_title.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/set_chat_description.py b/pyrogram/client/methods/chats/set_chat_description.py
index 736e493c1d..312b63eb86 100644
--- a/pyrogram/client/methods/chats/set_chat_description.py
+++ b/pyrogram/client/methods/chats/set_chat_description.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/set_chat_permissions.py b/pyrogram/client/methods/chats/set_chat_permissions.py
index 225bda5336..ce2851f8ed 100644
--- a/pyrogram/client/methods/chats/set_chat_permissions.py
+++ b/pyrogram/client/methods/chats/set_chat_permissions.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/set_chat_photo.py b/pyrogram/client/methods/chats/set_chat_photo.py
index 788d726df7..461b3474aa 100644
--- a/pyrogram/client/methods/chats/set_chat_photo.py
+++ b/pyrogram/client/methods/chats/set_chat_photo.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
import os
from typing import Union
diff --git a/pyrogram/client/methods/chats/set_chat_title.py b/pyrogram/client/methods/chats/set_chat_title.py
index 389e868ee0..9d6a2d246a 100644
--- a/pyrogram/client/methods/chats/set_chat_title.py
+++ b/pyrogram/client/methods/chats/set_chat_title.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/set_slow_mode.py b/pyrogram/client/methods/chats/set_slow_mode.py
index 3ff8fc1714..cf6c7096a3 100644
--- a/pyrogram/client/methods/chats/set_slow_mode.py
+++ b/pyrogram/client/methods/chats/set_slow_mode.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/unarchive_chats.py b/pyrogram/client/methods/chats/unarchive_chats.py
index d58996c604..b004e4bbb9 100644
--- a/pyrogram/client/methods/chats/unarchive_chats.py
+++ b/pyrogram/client/methods/chats/unarchive_chats.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union, List
diff --git a/pyrogram/client/methods/chats/unban_chat_member.py b/pyrogram/client/methods/chats/unban_chat_member.py
index dbe3f1cbe6..fc0c975116 100644
--- a/pyrogram/client/methods/chats/unban_chat_member.py
+++ b/pyrogram/client/methods/chats/unban_chat_member.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/unpin_chat_message.py b/pyrogram/client/methods/chats/unpin_chat_message.py
index abe7dde9aa..6defd99f9d 100644
--- a/pyrogram/client/methods/chats/unpin_chat_message.py
+++ b/pyrogram/client/methods/chats/unpin_chat_message.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/chats/update_chat_username.py b/pyrogram/client/methods/chats/update_chat_username.py
index 03002e8dd7..ff4db61b75 100644
--- a/pyrogram/client/methods/chats/update_chat_username.py
+++ b/pyrogram/client/methods/chats/update_chat_username.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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 .
+# You should have received a copy of the GNU Lesser General Public License
+# along with Pyrogram. If not, see .
from typing import Union
diff --git a/pyrogram/client/methods/contacts/__init__.py b/pyrogram/client/methods/contacts/__init__.py
index f1371e7e06..7c84decce4 100644
--- a/pyrogram/client/methods/contacts/__init__.py
+++ b/pyrogram/client/methods/contacts/__init__.py
@@ -1,20 +1,20 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2020 Dan
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2020 Dan
#
-# This file is part of Pyrogram.
+# 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 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.
+# 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