mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-06-06 06:33:10 +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,
|
Now it's easy to see how we could get, for example,
|
||||||
the ``was_online`` time. It's inside ``status``:
|
the ``was_online`` time. It's inside ``status``:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: python
|
||||||
|
|
||||||
online_at = user.status.was_online
|
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!
|
solution. Try it!
|
||||||
|
|
||||||
|
|
||||||
Properties vs. methods
|
Properties vs. Methods
|
||||||
**********************
|
**********************
|
||||||
|
|
||||||
The event shown above acts just like a `custom.Message
|
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.
|
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
|
The code of your application starts getting big, so you decide to
|
||||||
<telethon.client.updates.UpdateMethods.on>` syntax, don't worry.
|
separate the handlers into different files. But how can you access
|
||||||
You can call `client.add_event_handler(callback, event)
|
the client from these files? You don't need to! Just `events.register
|
||||||
<telethon.client.updates.UpdateMethods.add_event_handler>` to achieve
|
<telethon.events.register>` them:
|
||||||
the same effect.
|
|
||||||
|
.. 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
|
Similarly, you also have `client.remove_event_handler
|
||||||
<telethon.client.updates.UpdateMethods.remove_event_handler>`
|
<telethon.client.updates.UpdateMethods.remove_event_handler>`
|
||||||
and `client.list_event_handlers
|
and `client.list_event_handlers
|
||||||
<telethon.client.updates.UpdateMethods.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
|
`events.Raw <telethon.events.raw.Raw>` for adding, and ``None`` when
|
||||||
removing (so all callbacks would be removed).
|
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
|
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:**
|
**Issue:**
|
||||||
|
|
||||||
.. figure:: https://user-images.githubusercontent.com/6297805/29822978-9a9a6ef0-8ccd-11e7-9ec5-934ea0f57681.jpg
|
.. figure:: https://user-images.githubusercontent.com/6297805/29822978-9a9a6ef0-8ccd-11e7-9ec5-934ea0f57681.jpg
|
||||||
|
|
||||||
:alt: Winner issue
|
:alt: Winner issue
|
||||||
|
|
||||||
Winner issue
|
Winner issue
|
||||||
|
@ -58,6 +59,7 @@ Winner issue
|
||||||
**Answer:**
|
**Answer:**
|
||||||
|
|
||||||
.. figure:: https://user-images.githubusercontent.com/6297805/29822983-9d523402-8ccd-11e7-9fb1-5783740ee366.jpg
|
.. figure:: https://user-images.githubusercontent.com/6297805/29822983-9d523402-8ccd-11e7-9fb1-5783740ee366.jpg
|
||||||
|
|
||||||
:alt: Winner issue answer
|
:alt: Winner issue answer
|
||||||
|
|
||||||
Winner issue answer
|
Winner issue answer
|
||||||
|
|
|
@ -76,6 +76,10 @@ class UpdateMethods(UserMethods):
|
||||||
callback (`callable`):
|
callback (`callable`):
|
||||||
The callable function accepting one parameter to be used.
|
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):
|
event (`_EventBuilder` | `type`, optional):
|
||||||
The event builder class or instance to be used,
|
The event builder class or instance to be used,
|
||||||
for instance ``events.NewMessage``.
|
for instance ``events.NewMessage``.
|
||||||
|
@ -84,6 +88,12 @@ class UpdateMethods(UserMethods):
|
||||||
:tl:`Update` objects with no further processing) will
|
:tl:`Update` objects with no further processing) will
|
||||||
be passed instead.
|
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):
|
if isinstance(event, type):
|
||||||
event = event()
|
event = event()
|
||||||
elif not event:
|
elif not event:
|
||||||
|
|
|
@ -9,6 +9,9 @@ from .callbackquery import CallbackQuery
|
||||||
from .inlinequery import InlineQuery
|
from .inlinequery import InlineQuery
|
||||||
|
|
||||||
|
|
||||||
|
_HANDLERS_ATTRIBUTE = '__tl.handlers'
|
||||||
|
|
||||||
|
|
||||||
class StopPropagation(Exception):
|
class StopPropagation(Exception):
|
||||||
"""
|
"""
|
||||||
If this exception is raised in any of the handlers for a given event,
|
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.
|
It can be seen as the ``StopIteration`` in a for loop but for events.
|
||||||
|
|
||||||
Example usage:
|
Example usage:
|
||||||
|
|
||||||
>>> from telethon import TelegramClient, events
|
>>> from telethon import TelegramClient, events
|
||||||
>>> client = TelegramClient(...)
|
>>> client = TelegramClient(...)
|
||||||
>>>
|
>>>
|
||||||
|
@ -33,3 +37,103 @@ class StopPropagation(Exception):
|
||||||
# For some reason Sphinx wants the silly >>> or
|
# For some reason Sphinx wants the silly >>> or
|
||||||
# it will show warnings and look bad when generated.
|
# it will show warnings and look bad when generated.
|
||||||
pass
|
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