2023-09-13 20:01:16 +03:00
|
|
|
Updates
|
|
|
|
=======
|
|
|
|
|
|
|
|
.. currentmodule:: telethon
|
|
|
|
|
|
|
|
Updates are an important topic in a messaging platform like Telegram.
|
|
|
|
After all, you want to be notified as soon as certain events happen, such as new message arrives.
|
|
|
|
|
|
|
|
Telethon abstracts away Telegram updates with :mod:`~telethon.events`.
|
|
|
|
|
|
|
|
.. important::
|
|
|
|
|
|
|
|
It is strongly advised to configure logging when working with events:
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
import logging
|
|
|
|
logging.basicConfig(
|
|
|
|
format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s',
|
|
|
|
level=logging.WARNING
|
|
|
|
)
|
|
|
|
|
|
|
|
With the above, you will see all warnings and errors and when they happened.
|
|
|
|
|
|
|
|
|
|
|
|
Filtering events
|
|
|
|
----------------
|
|
|
|
|
|
|
|
There is no way to tell Telegram to only send certain updates.
|
2023-09-16 20:13:00 +03:00
|
|
|
Telegram sends all updates to connected active clients as they occur.
|
2023-09-13 20:01:16 +03:00
|
|
|
Telethon must be received and process all updates to ensure correct ordering.
|
|
|
|
|
|
|
|
Filters are not magic.
|
|
|
|
They work all the same as ``if`` conditions inside your event handlers.
|
|
|
|
However, they offer a more convenient and consistent way to check for certain conditions.
|
|
|
|
|
|
|
|
All built-in filters can be found in :mod:`telethon.events.filters`.
|
|
|
|
|
|
|
|
When registering an event handler, you can optionally define the filter to use.
|
|
|
|
You can retrieve a handler's filter with :meth:`~Client.get_handler_filter`.
|
|
|
|
You can set (and overwrite) a handler's filter with :meth:`~Client.set_handler_filter`.
|
|
|
|
|
|
|
|
Filters are meant to be fast and never raise exceptions.
|
|
|
|
For this reason, filters cannot be asynchronous.
|
|
|
|
This reduces the chance a filter will do slow IO and potentially fail.
|
|
|
|
|
|
|
|
A filter is simply a callable function that takes an event as input and returns a boolean.
|
2023-10-01 14:37:28 +03:00
|
|
|
If the filter returns :data:`True`, the handler will be called.
|
2023-09-13 20:01:16 +03:00
|
|
|
Using this knowledge, you can create custom filters too.
|
|
|
|
If you need state, you can use a class with a ``__call__`` method defined:
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
def only_odd_messages(event):
|
|
|
|
"A filter that only handles messages when their ID is divisible by 2"
|
|
|
|
return event.id % 2 == 0
|
|
|
|
|
|
|
|
client.add_event_handler(handler, events.NewMessage, only_odd_messages)
|
|
|
|
|
|
|
|
# ...
|
|
|
|
|
|
|
|
class OnlyDivisibleMessages:
|
|
|
|
"A filter that only handles messages when their ID is divisible by some amount"
|
|
|
|
def __init__(self, divisible_by):
|
|
|
|
self.divisible_by = divisible_by
|
|
|
|
|
|
|
|
def __call__(self, event):
|
|
|
|
return event.id % self.divisible_by == 0
|
|
|
|
|
|
|
|
client.add_event_handler(handler, events.NewMessage, OnlyDivisibleMessages(7))
|
|
|
|
|
|
|
|
Custom filters should accept any :class:`~events.Event`.
|
|
|
|
You can use :func:`isinstance` if your filter can only deal with certain types of events.
|
|
|
|
|
|
|
|
If you need to perform asynchronous operations, you can't use a filter.
|
|
|
|
Instead, manually check for those conditions inside your handler.
|
2023-10-01 14:37:28 +03:00
|
|
|
|
|
|
|
|
|
|
|
Setting priority on handlers
|
|
|
|
----------------------------
|
|
|
|
|
|
|
|
There is no explicit way to define a different priority for different handlers.
|
|
|
|
|
|
|
|
Instead, the library will call all your handlers in the order you added them.
|
|
|
|
This means that, if you want a "catch-all" handler, it should be registered last.
|
|
|
|
|
|
|
|
By default, the library will stop calling the rest of handlers after one is called:
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
@client.on(events.NewMessage)
|
|
|
|
async def first(event):
|
|
|
|
print('This is always called on new messages!')
|
|
|
|
|
|
|
|
@client.on(events.NewMessage)
|
|
|
|
async def second(event):
|
|
|
|
print('This will never be called, because "first" already ran.')
|
|
|
|
|
|
|
|
This is often the desired behaviour if you're using filters.
|
|
|
|
|
|
|
|
If you have more complicated filters executed *inside* the handler,
|
|
|
|
Telethon believes your handler completed and will stop calling the rest.
|
|
|
|
If that's the case, you can instruct Telethon to check all your handlers:
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
client = Client(..., check_all_handlers=True)
|
|
|
|
# ^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
# Now the code above will call both handlers
|
|
|
|
|
|
|
|
If you need a more complicated setup, consider sorting all your handlers beforehand.
|
|
|
|
Then, use :meth:`Client.add_event_handler` on all of them to ensure the correct order.
|