Telethon/client/doc/concepts/updates.rst

113 lines
4.0 KiB
ReStructuredText
Raw Normal View History

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.
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.
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.