mirror of
https://github.com/TeamPGM/pyrogram.git
synced 2024-11-17 21:22:40 +00:00
Merge branch 'develop' into asyncio
# Conflicts: # pyrogram/client/dispatcher/dispatcher.py # pyrogram/client/methods/messages/get_history.py
This commit is contained in:
commit
dd86aba9d3
@ -87,3 +87,4 @@ MESSAGE_POLL_CLOSED You can't interact with a closed poll
|
||||
MEDIA_INVALID The media is invalid
|
||||
BOT_SCORE_NOT_MODIFIED The bot score was not modified
|
||||
USER_BOT_REQUIRED The method can be used by bots only
|
||||
IMAGE_PROCESS_FAILED The server failed to process your image
|
|
@ -1,2 +1,3 @@
|
||||
id message
|
||||
FLOOD_WAIT_X A wait of {x} seconds is required
|
||||
TAKEOUT_INIT_DELAY_X You have to confirm the data export request using one of your mobile devices or wait {x} seconds
|
||||
|
|
@ -99,6 +99,7 @@ To get started, press the Next button.
|
||||
resources/ErrorHandling
|
||||
resources/TestServers
|
||||
resources/AdvancedUsage
|
||||
resources/VoiceCalls
|
||||
resources/Changelog
|
||||
|
||||
.. toctree::
|
||||
|
@ -91,13 +91,14 @@ Stop Propagation
|
||||
In order to prevent further propagation of an update in the dispatching phase, you can do *one* of the following:
|
||||
|
||||
- Call the update's bound-method ``.stop_propagation()`` (preferred way).
|
||||
- Manually ``raise StopPropagation`` error (more suitable for raw updates only).
|
||||
- Manually ``raise StopPropagation`` exception (more suitable for raw updates only).
|
||||
|
||||
.. note::
|
||||
|
||||
Note that ``.stop_propagation()`` is just an elegant and intuitive way to raise a ``StopPropagation`` error;
|
||||
this means that any code coming *after* calling it won't be executed as your function just raised a custom exception
|
||||
to signal the dispatcher not to propagate the update anymore.
|
||||
Internally, the propagation is stopped by handling a custom exception. ``.stop_propagation()`` is just an elegant
|
||||
and intuitive way to ``raise StopPropagation``; this also means that any code coming *after* calling the method
|
||||
won't be executed as your function just raised an exception to signal the dispatcher not to propagate the
|
||||
update anymore.
|
||||
|
||||
Example with ``stop_propagation()``:
|
||||
|
||||
@ -139,10 +140,82 @@ Example with ``raise StopPropagation``:
|
||||
def _(client, message):
|
||||
print(2)
|
||||
|
||||
The handler in group number 2 will never be executed because the propagation was stopped before. The output of both
|
||||
examples will be:
|
||||
Each handler is registered in a different group, but the handler in group number 2 will never be executed because the
|
||||
propagation was stopped earlier. The output of both (equivalent) examples will be:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
0
|
||||
1
|
||||
|
||||
Continue Propagation
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
As opposed to `stopping the update propagation <#stop-propagation>`_ and also as an alternative to the
|
||||
`handler groups <#handler-groups>`_, you can signal the internal dispatcher to continue the update propagation within
|
||||
the group regardless of the next handler's filters. This allows you to register multiple handlers with overlapping
|
||||
filters in the same group; to let the dispatcher process the next handler you can do *one* of the following in each
|
||||
handler you want to grant permission to continue:
|
||||
|
||||
- Call the update's bound-method ``.continue_propagation()`` (preferred way).
|
||||
- Manually ``raise ContinuePropagation`` exception (more suitable for raw updates only).
|
||||
|
||||
.. note::
|
||||
|
||||
Internally, the propagation is continued by handling a custom exception. ``.continue_propagation()`` is just an
|
||||
elegant and intuitive way to ``raise ContinuePropagation``; this also means that any code coming *after* calling the
|
||||
method won't be executed as your function just raised an exception to signal the dispatcher to continue with the
|
||||
next available handler.
|
||||
|
||||
|
||||
Example with ``continue_propagation()``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message(Filters.private)
|
||||
def _(client, message):
|
||||
print(0)
|
||||
message.continue_propagation()
|
||||
|
||||
|
||||
@app.on_message(Filters.private)
|
||||
def _(client, message):
|
||||
print(1)
|
||||
message.continue_propagation()
|
||||
|
||||
|
||||
@app.on_message(Filters.private)
|
||||
def _(client, message):
|
||||
print(2)
|
||||
|
||||
Example with ``raise ContinuePropagation``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import ContinuePropagation
|
||||
|
||||
@app.on_message(Filters.private)
|
||||
def _(client, message):
|
||||
print(0)
|
||||
raise ContinuePropagation
|
||||
|
||||
|
||||
@app.on_message(Filters.private)
|
||||
def _(client, message):
|
||||
print(1)
|
||||
raise ContinuePropagation
|
||||
|
||||
|
||||
@app.on_message(Filters.private)
|
||||
def _(client, message):
|
||||
print(2)
|
||||
|
||||
Three handlers are registered in the same group, and all of them will be executed because the propagation was continued
|
||||
in each handler (except in the last one, where is useless to do so since there is no more handlers after).
|
||||
The output of both (equivalent) examples will be:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
0
|
||||
1
|
||||
2
|
10
docs/source/resources/VoiceCalls.rst
Normal file
10
docs/source/resources/VoiceCalls.rst
Normal file
@ -0,0 +1,10 @@
|
||||
Voice Calls
|
||||
===========
|
||||
|
||||
A working proof-of-concept of Telegram voice calls using Pyrogram can be found here:
|
||||
https://github.com/bakatrouble/pylibtgvoip. Thanks to `@bakatrouble <https://t.me/bakatrouble>`_.
|
||||
|
||||
.. note::
|
||||
|
||||
This page will be updated with more information once voice calls become eventually more usable and more integrated
|
||||
in Pyrogram itself.
|
@ -6,13 +6,15 @@ to make it only work for specific messages in a specific chat.
|
||||
|
||||
from pyrogram import Client, Emoji, Filters
|
||||
|
||||
MENTION = "[{}](tg://user?id={})"
|
||||
MESSAGE = "{} Welcome to [Pyrogram](https://docs.pyrogram.ml/)'s group chat {}!"
|
||||
TARGET = "PyrogramChat" # Target chat. Can also be a list of multiple chat ids/usernames
|
||||
MENTION = "[{}](tg://user?id={})" # User mention markup
|
||||
MESSAGE = "{} Welcome to [Pyrogram](https://docs.pyrogram.ml/)'s group chat {}!" # Welcome message
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
@app.on_message(Filters.chat("PyrogramChat") & Filters.new_chat_members)
|
||||
# Filter in only new_chat_members updates generated in TARGET chat
|
||||
@app.on_message(Filters.chat(TARGET) & Filters.new_chat_members)
|
||||
def welcome(client, message):
|
||||
# Build the new members list (with mentions) by using their first_name
|
||||
new_members = [MENTION.format(i.first_name, i.id) for i in message.new_chat_members]
|
||||
|
@ -40,7 +40,8 @@ from .client.types import (
|
||||
Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, User, UserStatus,
|
||||
UserProfilePhotos, Venue, Animation, Video, VideoNote, Voice, CallbackQuery, Messages, ForceReply,
|
||||
InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove,
|
||||
Poll, PollOption, ChatPreview, StopPropagation, Game, CallbackGame, GameHighScore, GameHighScores
|
||||
Poll, PollOption, ChatPreview, StopPropagation, ContinuePropagation, Game, CallbackGame, GameHighScore,
|
||||
GameHighScores
|
||||
)
|
||||
from .client import (
|
||||
Client, ChatAction, ParseMode, Emoji,
|
||||
|
@ -141,8 +141,9 @@ class Client(Methods, BaseClient):
|
||||
Only applicable for new sessions.
|
||||
|
||||
first_name (``str``, *optional*):
|
||||
Pass a First Name to avoid entering it manually. It will be used to automatically
|
||||
create a new Telegram account in case the phone number you passed is not registered yet.
|
||||
Pass a First Name as string to avoid entering it manually. Or pass a callback function which accepts no
|
||||
arguments and must return the correct name as string (e.g., "Dan"). It will be used to automatically create
|
||||
a new Telegram account in case the phone number you passed is not registered yet.
|
||||
Only applicable for new sessions.
|
||||
|
||||
last_name (``str``, *optional*):
|
||||
@ -160,7 +161,8 @@ class Client(Methods, BaseClient):
|
||||
Path of the configuration file. Defaults to ./config.ini
|
||||
|
||||
plugins (``dict``, *optional*):
|
||||
TODO: doctrings
|
||||
Your Smart Plugins settings as dict, e.g.: *dict(root="plugins")*.
|
||||
This is an alternative way to setup plugins if you don't want to use the *config.ini* file.
|
||||
|
||||
no_updates (``bool``, *optional*):
|
||||
Pass True to completely disable incoming updates for the current session.
|
||||
|
@ -125,34 +125,36 @@ class Dispatcher:
|
||||
|
||||
parser = self.update_parsers.get(type(update), None)
|
||||
|
||||
if parser is None:
|
||||
continue
|
||||
|
||||
parsed_update, handler_type = await parser(update, users, chats)
|
||||
parsed_update, handler_type = (
|
||||
await parser(update, users, chats)
|
||||
if parser is not None
|
||||
else (None, type(None))
|
||||
)
|
||||
|
||||
for group in self.groups.values():
|
||||
try:
|
||||
for handler in group:
|
||||
args = None
|
||||
|
||||
if isinstance(handler, RawUpdateHandler):
|
||||
args = (update, users, chats)
|
||||
elif isinstance(handler, handler_type):
|
||||
if isinstance(handler, handler_type):
|
||||
if handler.check(parsed_update):
|
||||
args = (parsed_update,)
|
||||
elif isinstance(handler, RawUpdateHandler):
|
||||
args = (update, users, chats)
|
||||
|
||||
if args is None:
|
||||
continue
|
||||
|
||||
try:
|
||||
await handler.callback(self.client, *args)
|
||||
except StopIteration:
|
||||
except pyrogram.StopPropagation:
|
||||
raise
|
||||
except pyrogram.ContinuePropagation:
|
||||
continue
|
||||
except Exception as e:
|
||||
log.error(e, exc_info=True)
|
||||
|
||||
break
|
||||
except StopIteration:
|
||||
break
|
||||
except pyrogram.StopPropagation:
|
||||
pass
|
||||
except Exception as e:
|
||||
log.error(e, exc_info=True)
|
||||
|
@ -45,10 +45,3 @@ class CallbackQueryHandler(Handler):
|
||||
|
||||
def __init__(self, callback: callable, filters=None):
|
||||
super().__init__(callback, filters)
|
||||
|
||||
def check(self, callback_query):
|
||||
return (
|
||||
self.filters(callback_query)
|
||||
if callable(self.filters)
|
||||
else True
|
||||
)
|
||||
|
@ -48,8 +48,4 @@ class DeletedMessagesHandler(Handler):
|
||||
super().__init__(callback, filters)
|
||||
|
||||
def check(self, messages):
|
||||
return (
|
||||
self.filters(messages.messages[0])
|
||||
if callable(self.filters)
|
||||
else True
|
||||
)
|
||||
return super().check(messages.messages[0])
|
||||
|
@ -21,3 +21,10 @@ class Handler:
|
||||
def __init__(self, callback: callable, filters=None):
|
||||
self.callback = callback
|
||||
self.filters = filters
|
||||
|
||||
def check(self, update):
|
||||
return (
|
||||
self.filters(update)
|
||||
if callable(self.filters)
|
||||
else True
|
||||
)
|
||||
|
@ -46,10 +46,3 @@ class MessageHandler(Handler):
|
||||
|
||||
def __init__(self, callback: callable, filters=None):
|
||||
super().__init__(callback, filters)
|
||||
|
||||
def check(self, message):
|
||||
return (
|
||||
self.filters(message)
|
||||
if callable(self.filters)
|
||||
else True
|
||||
)
|
||||
|
@ -45,10 +45,3 @@ class UserStatusHandler(Handler):
|
||||
|
||||
def __init__(self, callback: callable, filters=None):
|
||||
super().__init__(callback, filters)
|
||||
|
||||
def check(self, user_status):
|
||||
return (
|
||||
self.filters(user_status)
|
||||
if callable(self.filters)
|
||||
else True
|
||||
)
|
||||
|
@ -16,12 +16,17 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Union
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.api import functions
|
||||
from pyrogram.api.errors import FloodWait
|
||||
from ...ext import BaseClient
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GetHistory(BaseClient):
|
||||
async def get_history(self,
|
||||
@ -66,6 +71,8 @@ class GetHistory(BaseClient):
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
|
||||
while True:
|
||||
try:
|
||||
messages = await pyrogram.Messages._parse(
|
||||
self,
|
||||
await self.send(
|
||||
@ -81,6 +88,11 @@ class GetHistory(BaseClient):
|
||||
)
|
||||
)
|
||||
)
|
||||
except FloodWait as e:
|
||||
log.warning("Sleeping for {}s".format(e.x))
|
||||
await asyncio.sleep(e.x)
|
||||
else:
|
||||
break
|
||||
|
||||
if reverse:
|
||||
messages.messages.reverse()
|
||||
|
@ -30,7 +30,7 @@ from .messages_and_media import (
|
||||
Sticker, Venue, Video, VideoNote, Voice, UserProfilePhotos,
|
||||
Message, Messages, MessageEntity, Poll, PollOption, Game
|
||||
)
|
||||
from .update import StopPropagation
|
||||
from .update import StopPropagation, ContinuePropagation
|
||||
from .user_and_chats import (
|
||||
Chat, ChatMember, ChatMembers, ChatPhoto,
|
||||
Dialog, Dialogs, User, UserStatus, ChatPreview
|
||||
|
@ -40,15 +40,15 @@ class CallbackQuery(PyrogramType, Update):
|
||||
Sender.
|
||||
|
||||
chat_instance (``str``, *optional*):
|
||||
Global identifier, uniquely corresponding to the chat to which the message with the callback button was
|
||||
sent. Useful for high scores in games.
|
||||
|
||||
message (:obj:`Message <pyrogram.Message>`, *optional*):
|
||||
Message with the callback button that originated the query. Note that message content and message date will
|
||||
not be available if the message is too old.
|
||||
|
||||
message (:obj:`Message <pyrogram.Message>`, *optional*):
|
||||
Identifier of the message sent via the bot in inline mode, that originated the query.
|
||||
|
||||
inline_message_id (``str``):
|
||||
Global identifier, uniquely corresponding to the chat to which the message with the callback button was
|
||||
sent. Useful for high scores in games.
|
||||
Identifier of the message sent via the bot in inline mode, that originated the query.
|
||||
|
||||
data (``bytes``, *optional*):
|
||||
Data associated with the callback button. Be aware that a bad client can send arbitrary data in this field.
|
||||
@ -72,9 +72,9 @@ class CallbackQuery(PyrogramType, Update):
|
||||
|
||||
self.id = id
|
||||
self.from_user = from_user
|
||||
self.chat_instance = chat_instance
|
||||
self.message = message
|
||||
self.inline_message_id = inline_message_id
|
||||
self.chat_instance = chat_instance
|
||||
self.data = data
|
||||
self.game_short_name = game_short_name
|
||||
|
||||
|
@ -21,6 +21,13 @@ class StopPropagation(StopIteration):
|
||||
pass
|
||||
|
||||
|
||||
class ContinuePropagation(StopIteration):
|
||||
pass
|
||||
|
||||
|
||||
class Update:
|
||||
def stop_propagation(self):
|
||||
raise StopPropagation
|
||||
|
||||
def continue_propagation(self):
|
||||
raise ContinuePropagation
|
||||
|
Loading…
Reference in New Issue
Block a user