mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2024-11-22 17:36:34 +03:00
Create events.register and siblings for "handler templates"
This can be thought of as a different approach to Flask's blueprints.
This commit is contained in:
parent
cb6f980277
commit
d5d3733fd4
|
@ -216,7 +216,7 @@ Will show a much better:
|
|||
Now it's easy to see how we could get, for example,
|
||||
the ``was_online`` time. It's inside ``status``:
|
||||
|
||||
.. code-block::
|
||||
.. code-block:: python
|
||||
|
||||
online_at = user.status.was_online
|
||||
|
||||
|
|
|
@ -181,7 +181,7 @@ random number, while if you say ``'eval 4+4'``, you will reply with the
|
|||
solution. Try it!
|
||||
|
||||
|
||||
Properties vs. methods
|
||||
Properties vs. Methods
|
||||
**********************
|
||||
|
||||
The event shown above acts just like a `custom.Message
|
||||
|
@ -220,26 +220,91 @@ methods (`message.get_sender
|
|||
and you should use methods in events for these properties that may need network.
|
||||
|
||||
|
||||
Events without decorators
|
||||
Events Without the client
|
||||
*************************
|
||||
|
||||
If for any reason you can't use the `@client.on
|
||||
<telethon.client.updates.UpdateMethods.on>` syntax, don't worry.
|
||||
You can call `client.add_event_handler(callback, event)
|
||||
<telethon.client.updates.UpdateMethods.add_event_handler>` to achieve
|
||||
the same effect.
|
||||
The code of your application starts getting big, so you decide to
|
||||
separate the handlers into different files. But how can you access
|
||||
the client from these files? You don't need to! Just `events.register
|
||||
<telethon.events.register>` them:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# handlers/welcome.py
|
||||
from telethon import events
|
||||
|
||||
@events.register(events.NewMessage('(?i)hello'))
|
||||
async def handler(event):
|
||||
client = event.client
|
||||
await event.respond('Hey!')
|
||||
await client.send_message('me', 'I said hello to someone')
|
||||
|
||||
|
||||
Registering events is a way of saying "this method is an event handler".
|
||||
You can use `telethon.events.is_handler` to check if any method is a handler.
|
||||
You can think of them as a different approach to Flask's blueprints.
|
||||
|
||||
It's important to note that this does **not** add the handler to any client!
|
||||
You never specified the client on which the handler should be used. You only
|
||||
declared that it is a handler, and its type.
|
||||
|
||||
To actually use the handler, you need to `client.add_event_handler
|
||||
<telethon.client.updates.UpdateMethods.add_event_handler>` to the
|
||||
client (or clients) where they should be added to:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# main.py
|
||||
from telethon import TelegramClient
|
||||
import handlers.welcome
|
||||
|
||||
with TelegramClient(...) as client:
|
||||
client.add_event_handler(handlers.welcome.handler)
|
||||
client.run_until_disconnected()
|
||||
|
||||
|
||||
This also means that you can register an event handler once and
|
||||
then add it to many clients without re-declaring the event.
|
||||
|
||||
|
||||
Events Without Decorators
|
||||
*************************
|
||||
|
||||
If for any reason you don't want to use `telethon.events.register`,
|
||||
you can explicitly pass the event handler to use to the mentioned
|
||||
`client.add_event_handler
|
||||
<telethon.client.updates.UpdateMethods.add_event_handler>`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from telethon import TelegramClient, events
|
||||
|
||||
async def handler(event):
|
||||
...
|
||||
|
||||
with TelegramClient(...) as client:
|
||||
client.add_event_handler(handler, events.NewMessage)
|
||||
client.run_until_disconnected()
|
||||
|
||||
|
||||
Similarly, you also have `client.remove_event_handler
|
||||
<telethon.client.updates.UpdateMethods.remove_event_handler>`
|
||||
and `client.list_event_handlers
|
||||
<telethon.client.updates.UpdateMethods.list_event_handlers>`.
|
||||
|
||||
The ``event`` type is optional in all methods and defaults to
|
||||
The ``event`` argument is optional in all three methods and defaults to
|
||||
`events.Raw <telethon.events.raw.Raw>` for adding, and ``None`` when
|
||||
removing (so all callbacks would be removed).
|
||||
|
||||
.. note::
|
||||
|
||||
Stopping propagation of Updates
|
||||
The ``event`` type is ignored in `client.add_event_handler
|
||||
<telethon.client.updates.UpdateMethods.add_event_handler>`
|
||||
if you have used `telethon.events.register` on the ``callback``
|
||||
before, since that's the point of using such method at all.
|
||||
|
||||
|
||||
Stopping Propagation of Updates
|
||||
*******************************
|
||||
|
||||
There might be cases when an event handler is supposed to be used solitary and
|
||||
|
|
|
@ -51,6 +51,7 @@ The current winner is `issue
|
|||
**Issue:**
|
||||
|
||||
.. figure:: https://user-images.githubusercontent.com/6297805/29822978-9a9a6ef0-8ccd-11e7-9ec5-934ea0f57681.jpg
|
||||
|
||||
:alt: Winner issue
|
||||
|
||||
Winner issue
|
||||
|
@ -58,6 +59,7 @@ Winner issue
|
|||
**Answer:**
|
||||
|
||||
.. figure:: https://user-images.githubusercontent.com/6297805/29822983-9d523402-8ccd-11e7-9fb1-5783740ee366.jpg
|
||||
|
||||
:alt: Winner issue answer
|
||||
|
||||
Winner issue answer
|
||||
|
|
|
@ -76,6 +76,10 @@ class UpdateMethods(UserMethods):
|
|||
callback (`callable`):
|
||||
The callable function accepting one parameter to be used.
|
||||
|
||||
Note that if you have used `telethon.events.register` in
|
||||
the callback, ``event`` will be ignored, and instead the
|
||||
events you previously registered will be used.
|
||||
|
||||
event (`_EventBuilder` | `type`, optional):
|
||||
The event builder class or instance to be used,
|
||||
for instance ``events.NewMessage``.
|
||||
|
@ -84,6 +88,12 @@ class UpdateMethods(UserMethods):
|
|||
:tl:`Update` objects with no further processing) will
|
||||
be passed instead.
|
||||
"""
|
||||
builders = events._get_handlers(callback)
|
||||
if builders is not None:
|
||||
for event in builders:
|
||||
self._event_builders.append((event, callback))
|
||||
return
|
||||
|
||||
if isinstance(event, type):
|
||||
event = event()
|
||||
elif not event:
|
||||
|
|
|
@ -9,6 +9,9 @@ from .callbackquery import CallbackQuery
|
|||
from .inlinequery import InlineQuery
|
||||
|
||||
|
||||
_HANDLERS_ATTRIBUTE = '__tl.handlers'
|
||||
|
||||
|
||||
class StopPropagation(Exception):
|
||||
"""
|
||||
If this exception is raised in any of the handlers for a given event,
|
||||
|
@ -16,6 +19,7 @@ class StopPropagation(Exception):
|
|||
It can be seen as the ``StopIteration`` in a for loop but for events.
|
||||
|
||||
Example usage:
|
||||
|
||||
>>> from telethon import TelegramClient, events
|
||||
>>> client = TelegramClient(...)
|
||||
>>>
|
||||
|
@ -33,3 +37,103 @@ class StopPropagation(Exception):
|
|||
# For some reason Sphinx wants the silly >>> or
|
||||
# it will show warnings and look bad when generated.
|
||||
pass
|
||||
|
||||
|
||||
def register(event=None):
|
||||
"""
|
||||
Decorator method to *register* event handlers. This is the client-less
|
||||
`add_event_handler
|
||||
<telethon.client.updates.UpdateMethods.add_event_handler>` variant.
|
||||
|
||||
Note that this method only registers callbacks as handlers,
|
||||
and does not attach them to any client. This is useful for
|
||||
external modules that don't have access to the client, but
|
||||
still want to define themselves as a handler. Example:
|
||||
|
||||
>>> from telethon import events
|
||||
>>> @events.register(events.NewMessage)
|
||||
... async def handler(event):
|
||||
... ...
|
||||
...
|
||||
>>> # (somewhere else)
|
||||
...
|
||||
>>> from telethon import TelegramClient
|
||||
>>> client = TelegramClient(...)
|
||||
>>> client.add_event_handler(handler)
|
||||
|
||||
Remember that you can use this as a non-decorator
|
||||
through ``register(event)(callback)``.
|
||||
|
||||
Args:
|
||||
event (`_EventBuilder` | `type`):
|
||||
The event builder class or instance to be used,
|
||||
for instance ``events.NewMessage``.
|
||||
"""
|
||||
if isinstance(event, type):
|
||||
event = event()
|
||||
elif not event:
|
||||
event = Raw()
|
||||
|
||||
def decorator(callback):
|
||||
handlers = getattr(callback, _HANDLERS_ATTRIBUTE, [])
|
||||
handlers.append(event)
|
||||
setattr(callback, _HANDLERS_ATTRIBUTE, handlers)
|
||||
return callback
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def unregister(callback, event=None):
|
||||
"""
|
||||
Inverse operation of `register` (though not a decorator). Client-less
|
||||
`remove_event_handler
|
||||
<telethon.client.updates.UpdateMethods.remove_event_handler>`
|
||||
variant. **Note that this won't remove handlers from the client**,
|
||||
because it simply can't, so you would generally use this before
|
||||
adding the handlers to the client.
|
||||
|
||||
This method is here for symmetry. You will rarely need to
|
||||
unregister events, since you can simply just not add them
|
||||
to any client.
|
||||
|
||||
If no event is given, all events for this callback are removed.
|
||||
Returns how many callbacks were removed.
|
||||
"""
|
||||
found = 0
|
||||
if event and not isinstance(event, type):
|
||||
event = type(event)
|
||||
|
||||
handlers = getattr(callback, _HANDLERS_ATTRIBUTE, [])
|
||||
handlers.append((event, callback))
|
||||
i = len(handlers)
|
||||
while i:
|
||||
i -= 1
|
||||
ev = handlers[i]
|
||||
if not event or isinstance(ev, event):
|
||||
del handlers[i]
|
||||
found += 1
|
||||
|
||||
return found
|
||||
|
||||
|
||||
def is_handler(callback):
|
||||
"""
|
||||
Returns ``True`` if the given callback is an
|
||||
event handler (i.e. you used `register` on it).
|
||||
"""
|
||||
return hasattr(callback, _HANDLERS_ATTRIBUTE)
|
||||
|
||||
|
||||
def list(callback):
|
||||
"""
|
||||
Returns a list containing the registered event
|
||||
builders inside the specified callback handler.
|
||||
"""
|
||||
return getattr(callback, _HANDLERS_ATTRIBUTE, [])[:]
|
||||
|
||||
|
||||
def _get_handlers(callback):
|
||||
"""
|
||||
Like ``list`` but returns ``None`` if the callback was never registered.
|
||||
"""
|
||||
return getattr(callback, _HANDLERS_ATTRIBUTE, None)
|
||||
|
|
Loading…
Reference in New Issue
Block a user