So far we've seen how to register a callback function that executes every time a specific update comes from the server, but there's much more than that to come.
Here we'll discuss about :class:`Filters <pyrogram.Filters>`. Filters enable a fine-grain control over what kind of updates are allowed or not to be passed in your callback functions, based on their inner details.
Let's start right away with a simple example:
This example will show you how to only handle messages containing an :obj:`Audio <pyrogram.Audio>` object and ignore any other message. Filters are passed as the first argument of the decorator:
from pyrogram import Filters @app.on_message(Filters.audio) def my_handler(client, message): print(message)
or, without decorators. Here filters are passed as the second argument of the handler constructor:
from pyrogram import Filters, MessageHandler def my_handler(client, message): print(message) app.add_handler(MessageHandler(my_handler, Filters.audio))
Filters can also be used in a more advanced way by inverting and combining more filters together using bitwise
operators ~, & and |:
- Use
~to invert a filter (behaves like thenotoperator). - Use
&and|to merge two filters (behave likeand,oroperators respectively).
Here are some examples:
Message is a text message and is not edited.
@app.on_message(Filters.text & ~Filters.edited) def my_handler(client, message): print(message)
Message is a sticker and is coming from a channel or a private chat.
@app.on_message(Filters.sticker & (Filters.channel | Filters.private)) def my_handler(client, message): print(message)
Some filters, like :meth:`command() <pyrogram.Filters.command>` or :meth:`regex() <pyrogram.Filters.regex>` can also accept arguments:
Message is either a /start or /help command.
@app.on_message(Filters.command(["start", "help"])) def my_handler(client, message): print(message)
Message is a text message or a media caption matching the given regex pattern.
@app.on_message(Filters.regex("pyrogram")) def my_handler(client, message): print(message)
More handlers using different filters can also live together.
@app.on_message(Filters.command("start"))
def start_command(client, message):
print("This is the /start command")
@app.on_message(Filters.command("help"))
def help_command(client, message):
print("This is the /help command")
@app.on_message(Filters.chat("PyrogramChat"))
def from_pyrogramchat(client, message):
print("New message in @PyrogramChat")Pyrogram already provides lots of built-in :class:`Filters <pyrogram.Filters>` to work with, but in case you can't find a specific one for your needs or want to build a custom filter by yourself (to be used in a different kind of handler, for example) you can use :meth:`Filters.create() <pyrogram.Filters.create>`.
Note
At the moment, the built-in filters are intended to be used with the :obj:`MessageHandler <pyrogram.MessageHandler>` only.
An example to demonstrate how custom filters work is to show how to create and use one for the :obj:`CallbackQueryHandler <pyrogram.CallbackQueryHandler>`. Note that callback queries updates are only received by bots; create and authorize your bot, then send a message with an inline keyboard to yourself. This allows you to test your filter by pressing the inline button:
from pyrogram import InlineKeyboardMarkup, InlineKeyboardButton
app.send_message(
"username", # Change this to your username or id
"Pyrogram's custom filter test",
reply_markup=InlineKeyboardMarkup(
[[InlineKeyboardButton("Press me", b"pyrogram")]]
)
)For this basic filter we will be using only the first two parameters of :meth:`Filters.create() <pyrogram.Filters.create>`.
The code below creates a simple filter for hardcoded, static callback data. This filter will only allow callback queries
containing "Pyrogram" as data, that is, the function func you pass returns True in case the callback query data
equals to b"Pyrogram".
static_data = Filters.create(
name="StaticdData",
func=lambda flt, callback_query: callback_query.data == b"Pyrogram"
)The lambda operator in python is used to create small anonymous functions and is perfect for this example, the same
could be achieved with a normal function, but we don't really need it as it makes sense only inside the filter's scope:
def func(flt, callback_query):
return callback_query.data == b"Pyrogram"
static_data = Filters.create(
name="StaticData",
func=func
)The filter usage remains the same:
@app.on_callback_query(static_data)
def pyrogram_data(client, callback_query):
client.answer_callback_query(callback_query.id, "it works!")A much cooler filter would be one that accepts "Pyrogram" or any other data as argument at usage time. A dynamic filter like this will make use of the third parameter of :meth:`Filters.create() <pyrogram.Filters.create>`.
This is how a dynamic custom filter looks like:
def dynamic_data(data):
return Filters.create(
name="DynamicData",
func=lambda flt, callback_query: flt.data == callback_query.data,
data=data # "data" kwarg is accessed with "filter.data"
)And its usage:
@app.on_callback_query(dynamic_data(b"Pyrogram"))
def pyrogram_data(client, callback_query):
client.answer_callback_query(callback_query.id, "it works!")