Skip to content

Commit 1555806

Browse files
committed
Update filters: Make the name argument optional
1 parent 506253e commit 1555806

File tree

2 files changed

+92
-96
lines changed

2 files changed

+92
-96
lines changed

docs/source/topics/create-filters.rst

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ button:
2424
2525
app.send_message(
2626
"username", # Change this to your username or id
27-
"Pyrogram's custom filter test",
27+
"Pyrogram custom filter test",
2828
reply_markup=InlineKeyboardMarkup(
2929
[[InlineKeyboardButton("Press me", "pyrogram")]]
3030
)
@@ -33,61 +33,54 @@ button:
3333
Basic Filters
3434
-------------
3535

36-
For this basic filter we will be using only the first two parameters of :meth:`~pyrogram.Filters.create`.
36+
For this basic filter we will be using only the first parameter of :meth:`~pyrogram.Filters.create`.
3737

3838
The code below creates a simple filter for hardcoded, static callback data. This filter will only allow callback queries
39-
containing "Pyrogram" as data, that is, the function *func* you pass returns True in case the callback query data
40-
equals to ``"Pyrogram"``.
39+
containing "pyrogram" as data, that is, the function *func* you pass returns True in case the callback query data
40+
equals to ``"pyrogram"``.
4141

4242
.. code-block:: python
4343
44-
static_data = Filters.create(
45-
name="StaticdData",
46-
func=lambda flt, query: query.data == "Pyrogram"
47-
)
44+
static_data_filter = Filters.create(lambda _, query: query.data == "pyrogram")
4845
4946
The ``lambda`` operator in python is used to create small anonymous functions and is perfect for this example, the same
50-
could be achieved with a normal function, but we don't really need it as it makes sense only inside the filter's scope:
47+
could be achieved with a normal function, but we don't really need it as it makes sense only inside the filter scope:
5148

5249
.. code-block:: python
5350
54-
def func(flt, query):
55-
return query.data == "Pyrogram"
51+
def func(_, query):
52+
return query.data == "pyrogram"
5653
57-
static_data = Filters.create(
58-
name="StaticData",
59-
func=func
60-
)
54+
static_data_filter = Filters.create(func)
6155
6256
The filter usage remains the same:
6357

6458
.. code-block:: python
6559
66-
@app.on_callback_query(static_data)
60+
@app.on_callback_query(static_data_filter)
6761
def pyrogram_data(_, query):
6862
query.answer("it works!")
6963
7064
Filters with Arguments
7165
----------------------
7266

73-
A much cooler filter would be one that accepts "Pyrogram" or any other data as argument at usage time.
74-
A dynamic filter like this will make use of the third parameter of :meth:`~pyrogram.Filters.create`.
67+
A much cooler filter would be one that accepts "pyrogram" or any other data as argument at usage time.
68+
A dynamic filter like this will make use of named arguments for the :meth:`~pyrogram.Filters.create` method.
7569

7670
This is how a dynamic custom filter looks like:
7771

7872
.. code-block:: python
7973
80-
def dynamic_data(data):
74+
def dynamic_data_filter(data):
8175
return Filters.create(
82-
name="DynamicData",
83-
func=lambda flt, query: flt.data == query.data,
84-
data=data # "data" kwarg is accessed with "flt.data"
76+
lambda flt, query: flt.data == query.data,
77+
data=data # "data" kwarg is accessed with "flt.data" above
8578
)
8679
8780
And its usage:
8881

8982
.. code-block:: python
9083
91-
@app.on_callback_query(dynamic_data("Pyrogram"))
84+
@app.on_callback_query(dynamic_data_filter("pyrogram"))
9285
def pyrogram_data(_, query):
9386
query.answer("it works!")

pyrogram/client/filters/filters.py

Lines changed: 76 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -17,190 +17,193 @@
1717
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
1818

1919
import re
20+
from typing import Callable
2021

2122
from .filter import Filter
2223
from ..types.bots_and_keyboards import InlineKeyboardMarkup, ReplyKeyboardMarkup
2324

25+
CUSTOM_FILTER_NAME = "CustomFilter"
2426

25-
def create(name: str, func: callable, **kwargs) -> type:
26-
"""Create a Filter.
27+
28+
def create(func: Callable, name: str = None, **kwargs) -> Filter:
29+
"""Easily create a custom filter.
2730
2831
Custom filters give you extra control over which updates are allowed or not to be processed by your handlers.
2932
3033
Parameters:
31-
name (``str``):
32-
Your filter's name. Can be anything you like.
33-
3434
func (``callable``):
35-
A function that accepts two arguments *(filter, update)* and returns a Boolean: True if the update should be
36-
handled, False otherwise.
37-
The "update" argument type will vary depending on which `Handler <Handlers.html>`_ is coming from.
38-
For example, in a :obj:`MessageHandler` the update type will be
39-
a :obj:`Message`; in a :obj:`CallbackQueryHandler` the
40-
update type will be a :obj:`CallbackQuery`. Your function body can then access the
41-
incoming update and decide whether to allow it or not.
35+
A function that accepts two positional arguments *(filter, update)* and returns a boolean: True if the
36+
update should be handled, False otherwise. The *filter* argument refers to the filter itself and can be used
37+
to access keyword arguments (read below). The *update* argument type will vary depending on which
38+
`Handler <handlers>`_ is coming from. For example, in a :obj:`MessageHandler` the *update* argument will be
39+
a :obj:`Message`; in a :obj:`CallbackQueryHandler` the *update* will be a :obj:`CallbackQuery`. Your
40+
function body can then access the incoming update attributes and decide whether to allow it or not.
41+
42+
name (``str``, *optional*):
43+
Your filter's name. Can be anything you like.
44+
Defaults to "CustomFilter".
4245
4346
**kwargs (``any``, *optional*):
44-
Any keyword argument you would like to pass. Useful for custom filters that accept parameters (e.g.:
45-
:meth:`~Filters.command`, :meth:`~Filters.regex`).
47+
Any keyword argument you would like to pass. Useful when creating parameterized custom filters, such as
48+
:meth:`~Filters.command` or :meth:`~Filters.regex`.
4649
"""
4750
# TODO: unpack kwargs using **kwargs into the dict itself. For Python 3.5+ only
4851
d = {"__call__": func}
4952
d.update(kwargs)
5053

51-
return type(name, (Filter,), d)()
54+
return type(name or CUSTOM_FILTER_NAME, (Filter,), d)()
5255

5356

5457
class Filters:
5558
"""This class provides access to all library-defined Filters available in Pyrogram.
5659
57-
The Filters listed here are intended to be used with the :obj:`MessageHandler` only.
60+
The Filters listed here are currently intended to be used with the :obj:`MessageHandler` only.
5861
At the moment, if you want to filter updates coming from different `Handlers <Handlers.html>`_ you have to create
5962
your own filters with :meth:`~Filters.create` and use them in the same way.
6063
"""
6164

6265
create = create
6366

64-
me = create("Me", lambda _, m: bool(m.from_user and m.from_user.is_self))
67+
me = create(lambda _, m: bool(m.from_user and m.from_user.is_self), "MeFilter")
6568
"""Filter messages generated by you yourself."""
6669

67-
bot = create("Bot", lambda _, m: bool(m.from_user and m.from_user.is_bot))
70+
bot = create(lambda _, m: bool(m.from_user and m.from_user.is_bot), "BotFilter")
6871
"""Filter messages coming from bots."""
6972

70-
incoming = create("Incoming", lambda _, m: not m.outgoing)
73+
incoming = create(lambda _, m: not m.outgoing, "IncomingFilter")
7174
"""Filter incoming messages. Messages sent to your own chat (Saved Messages) are also recognised as incoming."""
7275

73-
outgoing = create("Outgoing", lambda _, m: m.outgoing)
76+
outgoing = create(lambda _, m: m.outgoing, "OutgoingFilter")
7477
"""Filter outgoing messages. Messages sent to your own chat (Saved Messages) are not recognized as outgoing."""
7578

76-
text = create("Text", lambda _, m: bool(m.text))
79+
text = create(lambda _, m: bool(m.text), "TextFilter")
7780
"""Filter text messages."""
7881

79-
reply = create("Reply", lambda _, m: bool(m.reply_to_message))
82+
reply = create(lambda _, m: bool(m.reply_to_message), "ReplyFilter")
8083
"""Filter messages that are replies to other messages."""
8184

82-
forwarded = create("Forwarded", lambda _, m: bool(m.forward_date))
85+
forwarded = create(lambda _, m: bool(m.forward_date), "ForwardedFilter")
8386
"""Filter messages that are forwarded."""
8487

85-
caption = create("Caption", lambda _, m: bool(m.caption))
88+
caption = create(lambda _, m: bool(m.caption), "CaptionFilter")
8689
"""Filter media messages that contain captions."""
8790

88-
edited = create("Edited", lambda _, m: bool(m.edit_date))
91+
edited = create(lambda _, m: bool(m.edit_date), "EditedFilter")
8992
"""Filter edited messages."""
9093

91-
audio = create("Audio", lambda _, m: bool(m.audio))
94+
audio = create(lambda _, m: bool(m.audio), "AudioFilter")
9295
"""Filter messages that contain :obj:`Audio` objects."""
9396

94-
document = create("Document", lambda _, m: bool(m.document))
97+
document = create(lambda _, m: bool(m.document), "DocumentFilter")
9598
"""Filter messages that contain :obj:`Document` objects."""
9699

97-
photo = create("Photo", lambda _, m: bool(m.photo))
100+
photo = create(lambda _, m: bool(m.photo), "PhotoFilter")
98101
"""Filter messages that contain :obj:`Photo` objects."""
99102

100-
sticker = create("Sticker", lambda _, m: bool(m.sticker))
103+
sticker = create(lambda _, m: bool(m.sticker), "StickerFilter")
101104
"""Filter messages that contain :obj:`Sticker` objects."""
102105

103-
animation = create("Animation", lambda _, m: bool(m.animation))
106+
animation = create(lambda _, m: bool(m.animation), "AnimationFilter")
104107
"""Filter messages that contain :obj:`Animation` objects."""
105108

106-
game = create("Game", lambda _, m: bool(m.game))
109+
game = create(lambda _, m: bool(m.game), "GameFilter")
107110
"""Filter messages that contain :obj:`Game` objects."""
108111

109-
video = create("Video", lambda _, m: bool(m.video))
112+
video = create(lambda _, m: bool(m.video), "VideoFilter")
110113
"""Filter messages that contain :obj:`Video` objects."""
111114

112-
media_group = create("MediaGroup", lambda _, m: bool(m.media_group_id))
115+
media_group = create(lambda _, m: bool(m.media_group_id), "MediaGroupFilter")
113116
"""Filter messages containing photos or videos being part of an album."""
114117

115-
voice = create("Voice", lambda _, m: bool(m.voice))
118+
voice = create(lambda _, m: bool(m.voice), "VoiceFilter")
116119
"""Filter messages that contain :obj:`Voice` note objects."""
117120

118-
video_note = create("VideoNote", lambda _, m: bool(m.video_note))
121+
video_note = create(lambda _, m: bool(m.video_note), "VideoNoteFilter")
119122
"""Filter messages that contain :obj:`VideoNote` objects."""
120123

121-
contact = create("Contact", lambda _, m: bool(m.contact))
124+
contact = create(lambda _, m: bool(m.contact), "ContactFilter")
122125
"""Filter messages that contain :obj:`Contact` objects."""
123126

124-
location = create("Location", lambda _, m: bool(m.location))
127+
location = create(lambda _, m: bool(m.location), "LocationFilter")
125128
"""Filter messages that contain :obj:`Location` objects."""
126129

127-
venue = create("Venue", lambda _, m: bool(m.venue))
130+
venue = create(lambda _, m: bool(m.venue), "VenueFilter")
128131
"""Filter messages that contain :obj:`Venue` objects."""
129132

130-
web_page = create("WebPage", lambda _, m: m.web_page)
133+
web_page = create(lambda _, m: m.web_page, "WebPageFilter")
131134
"""Filter messages sent with a webpage preview."""
132135

133-
poll = create("Poll", lambda _, m: m.poll)
136+
poll = create(lambda _, m: m.poll, "PollFilter")
134137
"""Filter messages that contain :obj:`Poll` objects."""
135138

136-
private = create("Private", lambda _, m: bool(m.chat and m.chat.type == "private"))
139+
private = create(lambda _, m: bool(m.chat and m.chat.type == "private"), "PrivateFilter")
137140
"""Filter messages sent in private chats."""
138141

139-
group = create("Group", lambda _, m: bool(m.chat and m.chat.type in {"group", "supergroup"}))
142+
group = create(lambda _, m: bool(m.chat and m.chat.type in {"group", "supergroup"}), "GroupFilter")
140143
"""Filter messages sent in group or supergroup chats."""
141144

142-
channel = create("Channel", lambda _, m: bool(m.chat and m.chat.type == "channel"))
145+
channel = create(lambda _, m: bool(m.chat and m.chat.type == "channel"), "ChannelFilter")
143146
"""Filter messages sent in channels."""
144147

145-
new_chat_members = create("NewChatMembers", lambda _, m: bool(m.new_chat_members))
148+
new_chat_members = create(lambda _, m: bool(m.new_chat_members), "NewChatMembersFilter")
146149
"""Filter service messages for new chat members."""
147150

148-
left_chat_member = create("LeftChatMember", lambda _, m: bool(m.left_chat_member))
151+
left_chat_member = create(lambda _, m: bool(m.left_chat_member), "LeftChatMemberFilter")
149152
"""Filter service messages for members that left the chat."""
150153

151-
new_chat_title = create("NewChatTitle", lambda _, m: bool(m.new_chat_title))
154+
new_chat_title = create(lambda _, m: bool(m.new_chat_title), "NewChatTitleFilter")
152155
"""Filter service messages for new chat titles."""
153156

154-
new_chat_photo = create("NewChatPhoto", lambda _, m: bool(m.new_chat_photo))
157+
new_chat_photo = create(lambda _, m: bool(m.new_chat_photo), "NewChatPhotoFilter")
155158
"""Filter service messages for new chat photos."""
156159

157-
delete_chat_photo = create("DeleteChatPhoto", lambda _, m: bool(m.delete_chat_photo))
160+
delete_chat_photo = create(lambda _, m: bool(m.delete_chat_photo), "DeleteChatPhotoFilter")
158161
"""Filter service messages for deleted photos."""
159162

160-
group_chat_created = create("GroupChatCreated", lambda _, m: bool(m.group_chat_created))
163+
group_chat_created = create(lambda _, m: bool(m.group_chat_created), "GroupChatCreatedFilter")
161164
"""Filter service messages for group chat creations."""
162165

163-
supergroup_chat_created = create("SupergroupChatCreated", lambda _, m: bool(m.supergroup_chat_created))
166+
supergroup_chat_created = create(lambda _, m: bool(m.supergroup_chat_created), "SupergroupChatCreatedFilter")
164167
"""Filter service messages for supergroup chat creations."""
165168

166-
channel_chat_created = create("ChannelChatCreated", lambda _, m: bool(m.channel_chat_created))
169+
channel_chat_created = create(lambda _, m: bool(m.channel_chat_created), "ChannelChatCreatedFilter")
167170
"""Filter service messages for channel chat creations."""
168171

169-
migrate_to_chat_id = create("MigrateToChatId", lambda _, m: bool(m.migrate_to_chat_id))
172+
migrate_to_chat_id = create(lambda _, m: bool(m.migrate_to_chat_id), "MigrateToChatIdFilter")
170173
"""Filter service messages that contain migrate_to_chat_id."""
171174

172-
migrate_from_chat_id = create("MigrateFromChatId", lambda _, m: bool(m.migrate_from_chat_id))
175+
migrate_from_chat_id = create(lambda _, m: bool(m.migrate_from_chat_id), "MigrateFromChatIdFilter")
173176
"""Filter service messages that contain migrate_from_chat_id."""
174177

175-
pinned_message = create("PinnedMessage", lambda _, m: bool(m.pinned_message))
178+
pinned_message = create(lambda _, m: bool(m.pinned_message), "PinnedMessageFilter")
176179
"""Filter service messages for pinned messages."""
177180

178-
game_high_score = create("GameHighScore", lambda _, m: bool(m.game_high_score))
181+
game_high_score = create(lambda _, m: bool(m.game_high_score), "GameHighScoreFilter")
179182
"""Filter service messages for game high scores."""
180183

181-
reply_keyboard = create("ReplyKeyboard", lambda _, m: isinstance(m.reply_markup, ReplyKeyboardMarkup))
184+
reply_keyboard = create(lambda _, m: isinstance(m.reply_markup, ReplyKeyboardMarkup), "ReplyKeyboardFilter")
182185
"""Filter messages containing reply keyboard markups"""
183186

184-
inline_keyboard = create("InlineKeyboard", lambda _, m: isinstance(m.reply_markup, InlineKeyboardMarkup))
187+
inline_keyboard = create(lambda _, m: isinstance(m.reply_markup, InlineKeyboardMarkup), "InlineKeyboardFilter")
185188
"""Filter messages containing inline keyboard markups"""
186189

187-
mentioned = create("Mentioned", lambda _, m: bool(m.mentioned))
190+
mentioned = create(lambda _, m: bool(m.mentioned), "MentionedFilter")
188191
"""Filter messages containing mentions"""
189192

190-
via_bot = create("ViaBot", lambda _, m: bool(m.via_bot))
193+
via_bot = create(lambda _, m: bool(m.via_bot), "ViaBotFilter")
191194
"""Filter messages sent via inline bots"""
192195

193-
service = create("Service", lambda _, m: bool(m.service))
196+
service = create(lambda _, m: bool(m.service), "ServiceFilter")
194197
"""Filter service messages.
195-
198+
196199
A service message contains any of the following fields set: *left_chat_member*,
197200
*new_chat_title*, *new_chat_photo*, *delete_chat_photo*, *group_chat_created*, *supergroup_chat_created*,
198201
*channel_chat_created*, *migrate_to_chat_id*, *migrate_from_chat_id*, *pinned_message*, *game_score*.
199202
"""
200203

201-
media = create("Media", lambda _, m: bool(m.media))
204+
media = create(lambda _, m: bool(m.media), "MediaFilter")
202205
"""Filter media messages.
203-
206+
204207
A media message contains any of the following fields set: *audio*, *document*, *photo*, *sticker*, *video*,
205208
*animation*, *voice*, *video_note*, *contact*, *location*, *venue*, *poll*.
206209
"""
@@ -253,17 +256,17 @@ def func(flt, message):
253256
commands = {c if case_sensitive else c.lower() for c in commands}
254257
prefixes = set(prefix) if prefix else {""}
255258

256-
return create("Command", func=func, c=commands, p=prefixes, s=separator, cs=case_sensitive)
259+
return create(func, "CommandFilter", c=commands, p=prefixes, s=separator, cs=case_sensitive)
257260

258261
@staticmethod
259262
def regex(pattern, flags: int = 0):
260-
"""Filter messages that match a given RegEx pattern.
263+
"""Filter message texts or captions that match a given regular expression pattern.
261264
262265
Parameters:
263266
pattern (``str``):
264-
The RegEx pattern as string, it will be applied to the text of a message. When a pattern matches,
265-
all the `Match Objects <https://docs.python.org/3/library/re.html#match-objects>`_
266-
are stored in the *matches* field of the :obj:`Message` itself.
267+
The RegEx pattern as string, it will be applied to the text or the caption of a message. When a pattern
268+
matches, all the `Match Objects <https://docs.python.org/3/library/re.html#match-objects>`_ are stored
269+
in the *matches* field of the :obj:`Message` itself.
267270
268271
flags (``int``, *optional*):
269272
RegEx flags.
@@ -273,7 +276,7 @@ def f(_, m):
273276
m.matches = [i for i in _.p.finditer(m.text or m.caption or "")]
274277
return bool(m.matches)
275278

276-
return create("Regex", f, p=re.compile(pattern, flags))
279+
return create(f, "RegexFilter", p=re.compile(pattern, flags))
277280

278281
# noinspection PyPep8Naming
279282
class user(Filter, set):
@@ -285,7 +288,7 @@ class user(Filter, set):
285288
Parameters:
286289
users (``int`` | ``str`` | ``list``):
287290
Pass one or more user ids/usernames to filter users.
288-
For you yourself, "me" or "self" can be used as well.
291+
For you yourself, "me" or "self" can be used as well.
289292
Defaults to None (no users).
290293
"""
291294

@@ -342,12 +345,12 @@ def __call__(self, message):
342345
@staticmethod
343346
def callback_data(data: str or bytes):
344347
"""Filter callback queries for their data.
345-
348+
346349
Parameters:
347350
data (``str`` | ``bytes``):
348351
Pass the data you want to filter for.
349352
"""
350353

351-
return create("CallbackData", lambda flt, cb: cb.data == flt.data, data=data)
354+
return create(lambda flt, cb: cb.data == flt.data, "CallbackDataFilter", data=data)
352355

353-
dan = create("Dan", lambda _, m: bool(m.from_user and m.from_user.id == 23122162))
356+
dan = create(lambda _, m: bool(m.from_user and m.from_user.id == 23122162), "DanFilter")

0 commit comments

Comments
 (0)