From fd4bd754cc6a710b2bfbf7f9918a5fb78e5be94d Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 2 May 2020 21:16:52 +0200
Subject: [PATCH 1/6] Add missing update_profile to docs and Client
---
compiler/docs/compiler.py | 1 +
pyrogram/client/methods/users/__init__.py | 4 +++-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py
index ff205f9b..6b596b2f 100644
--- a/compiler/docs/compiler.py
+++ b/compiler/docs/compiler.py
@@ -226,6 +226,7 @@ def pyrogram_api():
set_profile_photo
delete_profile_photos
update_username
+ update_profile
block_user
unblock_user
""",
diff --git a/pyrogram/client/methods/users/__init__.py b/pyrogram/client/methods/users/__init__.py
index 1980303f..65171af6 100644
--- a/pyrogram/client/methods/users/__init__.py
+++ b/pyrogram/client/methods/users/__init__.py
@@ -26,6 +26,7 @@ from .get_users import GetUsers
from .iter_profile_photos import IterProfilePhotos
from .set_profile_photo import SetProfilePhoto
from .unblock_user import UnblockUser
+from .update_profile import UpdateProfile
from .update_username import UpdateUsername
@@ -40,6 +41,7 @@ class Users(
UpdateUsername,
GetProfilePhotosCount,
IterProfilePhotos,
- UnblockUser
+ UnblockUser,
+ UpdateProfile
):
pass
From 2563c1a6bedc0a71fe108b90675359649261390e Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 2 May 2020 21:17:05 +0200
Subject: [PATCH 2/6] Add copy button prompt text to ignore
---
docs/source/conf.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 0302328d..a86895ce 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -52,6 +52,8 @@ napoleon_use_rtype = False
pygments_style = "friendly"
+copybutton_prompt_text = "$ "
+
html_title = "Pyrogram Documentation"
html_theme = "sphinx_rtd_theme"
html_static_path = ["_static"]
From 4ff924bcfb720f8ca1186a649d7d779613722618 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Sat, 2 May 2020 21:17:22 +0200
Subject: [PATCH 3/6] Update Pyrogram to v0.17.1
---
pyrogram/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 13ea5ce5..301e4e64 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.17.0"
+__version__ = "0.17.1"
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
__copyright__ = "Copyright (C) 2017-2020 Dan "
From 88e42ecc0d339ca9d9df8f50b305ec82a8567332 Mon Sep 17 00:00:00 2001
From: CyanBook
Date: Mon, 4 May 2020 10:55:10 +0000
Subject: [PATCH 4/6] Update update_profile example (#395)
---
pyrogram/client/methods/users/update_profile.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pyrogram/client/methods/users/update_profile.py b/pyrogram/client/methods/users/update_profile.py
index 19ec6d66..91a7950c 100644
--- a/pyrogram/client/methods/users/update_profile.py
+++ b/pyrogram/client/methods/users/update_profile.py
@@ -50,13 +50,13 @@ class UpdateProfile(BaseClient):
.. code-block:: python
# Update your first name only
- app.update_bio(first_name="Pyrogram")
+ app.update_profile(first_name="Pyrogram")
# Update first name and bio
- app.update_bio(first_name="Pyrogram", bio="https://docs.pyrogram.org/")
+ app.update_profile(first_name="Pyrogram", bio="https://docs.pyrogram.org/")
# Remove the last name
- app.update_bio(last_name="")
+ app.update_profile(last_name="")
"""
return bool(
From c05c5c44410cb2188f1189dfdd5e9fa53f7c4676 Mon Sep 17 00:00:00 2001
From: SuperCz1 <62919067+SuperCz1@users.noreply.github.com>
Date: Thu, 7 May 2020 11:35:08 +0200
Subject: [PATCH 5/6] Add session name in "Sleeping for Xs" log lines (#401)
* Update send_media_group.py
* Update get_dialogs.py
* Update get_dialogs.py
* Update get_messages.py
* Update get_history.py
* Update get_chat_members.py
---
pyrogram/client/methods/chats/get_chat_members.py | 2 +-
pyrogram/client/methods/chats/get_dialogs.py | 2 +-
pyrogram/client/methods/messages/get_history.py | 2 +-
pyrogram/client/methods/messages/get_messages.py | 2 +-
pyrogram/client/methods/messages/send_media_group.py | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/pyrogram/client/methods/chats/get_chat_members.py b/pyrogram/client/methods/chats/get_chat_members.py
index a8ae4054..6be3408b 100644
--- a/pyrogram/client/methods/chats/get_chat_members.py
+++ b/pyrogram/client/methods/chats/get_chat_members.py
@@ -153,7 +153,7 @@ class GetChatMembers(BaseClient):
return pyrogram.List(pyrogram.ChatMember._parse(self, member, users) for member in members)
except FloodWait as e:
- log.warning("Sleeping for {}s".format(e.x))
+ log.warning("[{}] Sleeping for {}s".format(self.session_name, e.x))
time.sleep(e.x)
else:
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
diff --git a/pyrogram/client/methods/chats/get_dialogs.py b/pyrogram/client/methods/chats/get_dialogs.py
index 6234538b..ea2eec63 100644
--- a/pyrogram/client/methods/chats/get_dialogs.py
+++ b/pyrogram/client/methods/chats/get_dialogs.py
@@ -82,7 +82,7 @@ class GetDialogs(BaseClient):
)
)
except FloodWait as e:
- log.warning("Sleeping {}s".format(e.x))
+ log.warning("[{}] Sleeping for {}s".format(self.session_name, e.x))
time.sleep(e.x)
else:
break
diff --git a/pyrogram/client/methods/messages/get_history.py b/pyrogram/client/methods/messages/get_history.py
index bf348ac9..7741340c 100644
--- a/pyrogram/client/methods/messages/get_history.py
+++ b/pyrogram/client/methods/messages/get_history.py
@@ -103,7 +103,7 @@ class GetHistory(BaseClient):
)
)
except FloodWait as e:
- log.warning("Sleeping for {}s".format(e.x))
+ log.warning("[{}] Sleeping for {}s".format(self.session_name, e.x))
time.sleep(e.x)
else:
break
diff --git a/pyrogram/client/methods/messages/get_messages.py b/pyrogram/client/methods/messages/get_messages.py
index a18d84c2..f3e53b94 100644
--- a/pyrogram/client/methods/messages/get_messages.py
+++ b/pyrogram/client/methods/messages/get_messages.py
@@ -116,7 +116,7 @@ class GetMessages(BaseClient):
try:
r = self.send(rpc)
except FloodWait as e:
- log.warning("Sleeping for {}s".format(e.x))
+ log.warning("[{}] Sleeping for {}s".format(self.session_name, e.x))
time.sleep(e.x)
else:
break
diff --git a/pyrogram/client/methods/messages/send_media_group.py b/pyrogram/client/methods/messages/send_media_group.py
index 055c7b7c..725a8a84 100644
--- a/pyrogram/client/methods/messages/send_media_group.py
+++ b/pyrogram/client/methods/messages/send_media_group.py
@@ -195,7 +195,7 @@ class SendMediaGroup(BaseClient):
)
)
except FloodWait as e:
- log.warning("Sleeping for {}s".format(e.x))
+ log.warning("[{}] Sleeping for {}s".format(self.session_name, e.x))
time.sleep(e.x)
else:
break
From 99aee987bdc0154c875c3072cf368f4e9c31aee3 Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Thu, 7 May 2020 12:53:45 +0200
Subject: [PATCH 6/6] Add an automatic sleep mechanism for flood wait
exceptions
---
pyrogram/client/client.py | 30 ++++++-
.../client/methods/chats/get_chat_members.py | 29 +++----
pyrogram/client/methods/chats/get_dialogs.py | 33 +++----
.../client/methods/messages/get_history.py | 35 +++-----
.../client/methods/messages/get_messages.py | 9 +-
.../methods/messages/send_media_group.py | 87 +++++++------------
6 files changed, 101 insertions(+), 122 deletions(-)
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index 3ef82ada..daaa8669 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -154,6 +154,12 @@ class Client(Methods, BaseClient):
download_media, ...) are less prone to throw FloodWait exceptions.
Only available for users, bots will ignore this parameter.
Defaults to False (normal session).
+
+ sleep_threshold (``int``, *optional*):
+ Set a sleep threshold for flood wait exceptions happening globally in this client instance, below which any
+ request that raises a flood wait will be automatically invoked again after sleeping for the required amount
+ of time. Flood wait exceptions requiring higher waiting times will be raised.
+ Defaults to 60 (seconds).
"""
def __init__(
@@ -178,7 +184,8 @@ class Client(Methods, BaseClient):
config_file: str = BaseClient.CONFIG_FILE,
plugins: dict = None,
no_updates: bool = None,
- takeout: bool = None
+ takeout: bool = None,
+ sleep_threshold: int = 60
):
super().__init__()
@@ -204,6 +211,7 @@ class Client(Methods, BaseClient):
self.plugins = plugins
self.no_updates = no_updates
self.takeout = takeout
+ self.sleep_threshold = sleep_threshold
if isinstance(session_name, str):
if session_name == ":memory:" or len(session_name) >= MemoryStorage.SESSION_STRING_SIZE:
@@ -1401,13 +1409,31 @@ class Client(Methods, BaseClient):
if not self.is_connected:
raise ConnectionError("Client has not been started yet")
+ # Some raw methods that expect a query as argument are used here.
+ # Keep the original request query because is needed.
+ unwrapped_data = data
+
if self.no_updates:
data = functions.InvokeWithoutUpdates(query=data)
if self.takeout_id:
data = functions.InvokeWithTakeout(takeout_id=self.takeout_id, query=data)
- r = self.session.send(data, retries, timeout)
+ while True:
+ try:
+ r = self.session.send(data, retries, timeout)
+ except FloodWait as e:
+ amount = e.x
+
+ if amount > self.sleep_threshold:
+ raise
+
+ log.warning('[{}] Sleeping for {}s (required by "{}")'.format(
+ self.session_name, amount, ".".join(unwrapped_data.QUALNAME.split(".")[1:])))
+
+ time.sleep(amount)
+ else:
+ break
self.fetch_peers(getattr(r, "users", []))
self.fetch_peers(getattr(r, "chats", []))
diff --git a/pyrogram/client/methods/chats/get_chat_members.py b/pyrogram/client/methods/chats/get_chat_members.py
index 6be3408b..bf208944 100644
--- a/pyrogram/client/methods/chats/get_chat_members.py
+++ b/pyrogram/client/methods/chats/get_chat_members.py
@@ -136,24 +136,19 @@ class GetChatMembers(BaseClient):
else:
raise ValueError("Invalid filter \"{}\"".format(filter))
- while True:
- try:
- r = self.send(
- functions.channels.GetParticipants(
- channel=peer,
- filter=filter,
- offset=offset,
- limit=limit,
- hash=0
- )
- )
+ r = self.send(
+ functions.channels.GetParticipants(
+ channel=peer,
+ filter=filter,
+ offset=offset,
+ limit=limit,
+ hash=0
+ )
+ )
- members = r.participants
- users = {i.id: i for i in r.users}
+ members = r.participants
+ users = {i.id: i for i in r.users}
- return pyrogram.List(pyrogram.ChatMember._parse(self, member, users) for member in members)
- except FloodWait as e:
- log.warning("[{}] Sleeping for {}s".format(self.session_name, e.x))
- time.sleep(e.x)
+ return pyrogram.List(pyrogram.ChatMember._parse(self, member, users) for member in members)
else:
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
diff --git a/pyrogram/client/methods/chats/get_dialogs.py b/pyrogram/client/methods/chats/get_dialogs.py
index ea2eec63..f5d5f442 100644
--- a/pyrogram/client/methods/chats/get_dialogs.py
+++ b/pyrogram/client/methods/chats/get_dialogs.py
@@ -66,26 +66,19 @@ class GetDialogs(BaseClient):
app.get_dialogs(pinned_only=True)
"""
- while True:
- try:
- if pinned_only:
- r = self.send(functions.messages.GetPinnedDialogs(folder_id=0))
- else:
- r = self.send(
- functions.messages.GetDialogs(
- offset_date=offset_date,
- offset_id=0,
- offset_peer=types.InputPeerEmpty(),
- limit=limit,
- hash=0,
- exclude_pinned=True
- )
- )
- except FloodWait as e:
- log.warning("[{}] Sleeping for {}s".format(self.session_name, e.x))
- time.sleep(e.x)
- else:
- break
+ if pinned_only:
+ r = self.send(functions.messages.GetPinnedDialogs(folder_id=0))
+ else:
+ r = self.send(
+ functions.messages.GetDialogs(
+ offset_date=offset_date,
+ offset_id=0,
+ offset_peer=types.InputPeerEmpty(),
+ limit=limit,
+ hash=0,
+ exclude_pinned=True
+ )
+ )
users = {i.id: i for i in r.users}
chats = {i.id: i for i in r.chats}
diff --git a/pyrogram/client/methods/messages/get_history.py b/pyrogram/client/methods/messages/get_history.py
index 7741340c..79a1dec6 100644
--- a/pyrogram/client/methods/messages/get_history.py
+++ b/pyrogram/client/methods/messages/get_history.py
@@ -85,28 +85,21 @@ class GetHistory(BaseClient):
offset_id = offset_id or (1 if reverse else 0)
- while True:
- try:
- messages = utils.parse_messages(
- self,
- self.send(
- functions.messages.GetHistory(
- peer=self.resolve_peer(chat_id),
- offset_id=offset_id,
- offset_date=offset_date,
- add_offset=offset * (-1 if reverse else 1) - (limit if reverse else 0),
- limit=limit,
- max_id=0,
- min_id=0,
- hash=0
- )
- )
+ messages = utils.parse_messages(
+ self,
+ self.send(
+ functions.messages.GetHistory(
+ peer=self.resolve_peer(chat_id),
+ offset_id=offset_id,
+ offset_date=offset_date,
+ add_offset=offset * (-1 if reverse else 1) - (limit if reverse else 0),
+ limit=limit,
+ max_id=0,
+ min_id=0,
+ hash=0
)
- except FloodWait as e:
- log.warning("[{}] Sleeping for {}s".format(self.session_name, e.x))
- time.sleep(e.x)
- else:
- break
+ )
+ )
if reverse:
messages.reverse()
diff --git a/pyrogram/client/methods/messages/get_messages.py b/pyrogram/client/methods/messages/get_messages.py
index f3e53b94..e505b566 100644
--- a/pyrogram/client/methods/messages/get_messages.py
+++ b/pyrogram/client/methods/messages/get_messages.py
@@ -112,14 +112,7 @@ class GetMessages(BaseClient):
else:
rpc = functions.messages.GetMessages(id=ids)
- while True:
- try:
- r = self.send(rpc)
- except FloodWait as e:
- log.warning("[{}] Sleeping for {}s".format(self.session_name, e.x))
- time.sleep(e.x)
- else:
- break
+ r = self.send(rpc)
messages = utils.parse_messages(self, r, replies=replies)
diff --git a/pyrogram/client/methods/messages/send_media_group.py b/pyrogram/client/methods/messages/send_media_group.py
index 725a8a84..8571ef4f 100644
--- a/pyrogram/client/methods/messages/send_media_group.py
+++ b/pyrogram/client/methods/messages/send_media_group.py
@@ -78,21 +78,14 @@ class SendMediaGroup(BaseClient):
for i in media:
if isinstance(i, pyrogram.InputMediaPhoto):
if os.path.exists(i.media):
- while True:
- try:
- media = self.send(
- functions.messages.UploadMedia(
- peer=self.resolve_peer(chat_id),
- media=types.InputMediaUploadedPhoto(
- file=self.save_file(i.media)
- )
- )
+ media = self.send(
+ functions.messages.UploadMedia(
+ peer=self.resolve_peer(chat_id),
+ media=types.InputMediaUploadedPhoto(
+ file=self.save_file(i.media)
)
- except FloodWait as e:
- log.warning("Sleeping for {}s".format(e.x))
- time.sleep(e.x)
- else:
- break
+ )
+ )
media = types.InputMediaPhoto(
id=types.InputPhoto(
@@ -122,32 +115,25 @@ class SendMediaGroup(BaseClient):
media = utils.get_input_media_from_file_id(i.media, i.file_ref, 2)
elif isinstance(i, pyrogram.InputMediaVideo):
if os.path.exists(i.media):
- while True:
- try:
- media = self.send(
- functions.messages.UploadMedia(
- peer=self.resolve_peer(chat_id),
- media=types.InputMediaUploadedDocument(
- file=self.save_file(i.media),
- thumb=None if i.thumb is None else self.save_file(i.thumb),
- mime_type=self.guess_mime_type(i.media) or "video/mp4",
- attributes=[
- types.DocumentAttributeVideo(
- supports_streaming=i.supports_streaming or None,
- duration=i.duration,
- w=i.width,
- h=i.height
- ),
- types.DocumentAttributeFilename(file_name=os.path.basename(i.media))
- ]
- )
- )
+ media = self.send(
+ functions.messages.UploadMedia(
+ peer=self.resolve_peer(chat_id),
+ media=types.InputMediaUploadedDocument(
+ file=self.save_file(i.media),
+ thumb=None if i.thumb is None else self.save_file(i.thumb),
+ mime_type=self.guess_mime_type(i.media) or "video/mp4",
+ attributes=[
+ types.DocumentAttributeVideo(
+ supports_streaming=i.supports_streaming or None,
+ duration=i.duration,
+ w=i.width,
+ h=i.height
+ ),
+ types.DocumentAttributeFilename(file_name=os.path.basename(i.media))
+ ]
)
- except FloodWait as e:
- log.warning("Sleeping for {}s".format(e.x))
- time.sleep(e.x)
- else:
- break
+ )
+ )
media = types.InputMediaDocument(
id=types.InputDocument(
@@ -184,21 +170,14 @@ class SendMediaGroup(BaseClient):
)
)
- while True:
- try:
- r = self.send(
- functions.messages.SendMultiMedia(
- peer=self.resolve_peer(chat_id),
- multi_media=multi_media,
- silent=disable_notification or None,
- reply_to_msg_id=reply_to_message_id
- )
- )
- except FloodWait as e:
- log.warning("[{}] Sleeping for {}s".format(self.session_name, e.x))
- time.sleep(e.x)
- else:
- break
+ r = self.send(
+ functions.messages.SendMultiMedia(
+ peer=self.resolve_peer(chat_id),
+ multi_media=multi_media,
+ silent=disable_notification or None,
+ reply_to_msg_id=reply_to_message_id
+ )
+ )
return utils.parse_messages(
self,