mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-02-18 04:20:57 +03:00
Introduce some filters
This commit is contained in:
parent
a1fe80557a
commit
055eca49ea
150
telethon/_events/filters/__init__.py
Normal file
150
telethon/_events/filters/__init__.py
Normal file
|
@ -0,0 +1,150 @@
|
|||
from .base import Filter, And, Or, Not, Identity, Always, Never
|
||||
from .generic import Types
|
||||
from .entities import Chats, Senders
|
||||
from .messages import Incoming, Outgoing, Pattern, Data
|
||||
|
||||
|
||||
_sentinel = object()
|
||||
|
||||
|
||||
def make_filter(
|
||||
chats=_sentinel,
|
||||
blacklist_chats=_sentinel,
|
||||
func=_sentinel,
|
||||
types=_sentinel,
|
||||
incoming=_sentinel,
|
||||
outgoing=_sentinel,
|
||||
senders=_sentinel,
|
||||
blacklist_senders=_sentinel,
|
||||
forwards=_sentinel,
|
||||
pattern=_sentinel,
|
||||
data=_sentinel,
|
||||
):
|
||||
"""
|
||||
Create a new `And` filter joining all the filters specified as input parameters.
|
||||
|
||||
Not all filters may have an effect on all events.
|
||||
|
||||
chats (`entity`, optional):
|
||||
May be one or more entities (username/peer/etc.), preferably IDs.
|
||||
By default, only matching chats will be handled.
|
||||
|
||||
blacklist_chats (`bool`, optional):
|
||||
Whether to treat the chats as a blacklist instead of
|
||||
as a whitelist (default). This means that every chat
|
||||
will be handled *except* those specified in ``chats``
|
||||
which will be ignored if ``blacklist_chats=True``.
|
||||
|
||||
func (`callable`, optional):
|
||||
A callable (async or not) function that should accept the event as input
|
||||
parameter, and return a value indicating whether the event
|
||||
should be dispatched or not (any truthy value will do, it
|
||||
does not need to be a `bool`). It works like a custom filter:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@client.on(events.NewMessage(func=lambda e: e.is_private))
|
||||
async def handler(event):
|
||||
pass # code here
|
||||
|
||||
incoming (`bool`, optional):
|
||||
If set to `True`, only **incoming** messages will be handled.
|
||||
If set to `False`, incoming messages will be ignored.
|
||||
If both incoming are outgoing are set, whichever is true will be handled.
|
||||
|
||||
outgoing (`bool`, optional):
|
||||
If set to `True`, only **outgoing** messages will be handled.
|
||||
If set to `False`, outgoing messages will be ignored.
|
||||
If both incoming are outgoing are set, whichever is true will be handled.
|
||||
|
||||
senders (`entity`, optional):
|
||||
Unlike `chats`, this parameter filters the *senders* of the
|
||||
message. That is, only messages *sent by these users* will be
|
||||
handled. Use `chats` if you want private messages with this/these
|
||||
users. `senders` lets you filter by messages sent by *one or
|
||||
more* users across the desired chats (doesn't need a list).
|
||||
|
||||
blacklist_senders (`bool`):
|
||||
Whether to treat the senders as a blacklist instead of
|
||||
as a whitelist (default). This means that every sender
|
||||
will be handled *except* those specified in ``senders``
|
||||
which will be ignored if ``blacklist_senders=True``.
|
||||
|
||||
forwards (`bool`, optional):
|
||||
Whether forwarded messages should be handled or not. By default,
|
||||
both forwarded and normal messages are included. If it's `True`
|
||||
*only* forwards will be handled. If it's `False` only messages
|
||||
that are *not* forwards will be handled.
|
||||
|
||||
pattern (`str`, `callable`, `Pattern`, optional):
|
||||
If set, only messages matching this pattern will be handled.
|
||||
You can specify a regex-like string which will be matched
|
||||
against the message, a callable function that returns `True`
|
||||
if a message is acceptable, or a compiled regex pattern.
|
||||
|
||||
data (`bytes`, `str`, `callable`, optional):
|
||||
If set, the inline button payload data must match this data.
|
||||
A UTF-8 string can also be given, a regex or a callable. For
|
||||
instance, to check against ``'data_1'`` and ``'data_2'`` you
|
||||
can use ``re.compile(b'data_')``.
|
||||
|
||||
types (`list` | `tuple` | `type`, optional):
|
||||
The type or types that the :tl:`Update` instance must be.
|
||||
Equivalent to ``if not isinstance(update, types): return``.
|
||||
"""
|
||||
filters = []
|
||||
|
||||
if chats is not _sentinel:
|
||||
f = Chats(chats)
|
||||
if blacklist_chats is not _sentinel and blacklist_chats:
|
||||
f = Not(f)
|
||||
filters.append(f)
|
||||
|
||||
if func is not _sentinel:
|
||||
filters.append(Identity(func))
|
||||
|
||||
if types is not _sentinel:
|
||||
filters.append(Types(types))
|
||||
|
||||
if incoming is not _sentinel:
|
||||
if outgoing is not _sentinel:
|
||||
if incoming and outgoing:
|
||||
pass # no need to filter
|
||||
elif incoming:
|
||||
filters.append(Incoming())
|
||||
elif outgoing:
|
||||
filters.append(Outgoing())
|
||||
else:
|
||||
return Never() # why?
|
||||
elif incoming:
|
||||
filters.append(Incoming())
|
||||
else:
|
||||
filters.append(Outgoing())
|
||||
elif outgoing is not _sentinel:
|
||||
if outgoing:
|
||||
filters.append(Outgoing())
|
||||
else:
|
||||
filters.append(Incoming())
|
||||
|
||||
if senders is not _sentinel:
|
||||
f = Senders(senders)
|
||||
if blacklist_senders is not _sentinel and blacklist_senders:
|
||||
f = Not(f)
|
||||
filters.append(f)
|
||||
|
||||
if forwards is not _sentinel:
|
||||
filters.append(Forward())
|
||||
|
||||
if pattern is not _sentinel:
|
||||
filters.append(Pattern(pattern))
|
||||
|
||||
if data is not _sentinel:
|
||||
filters.append(Data(data))
|
||||
|
||||
return And(*filters) if filters else Always()
|
||||
|
||||
|
||||
class NotResolved(ValueError):
|
||||
def __init__(self, unresolved):
|
||||
super().__init__()
|
||||
self.unresolved = unresolved
|
78
telethon/_events/filters/base.py
Normal file
78
telethon/_events/filters/base.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
import abc
|
||||
|
||||
|
||||
class Filter(abc.ABC):
|
||||
@abc.abstractmethod
|
||||
def __call__(self, event):
|
||||
return True
|
||||
|
||||
def __and__(self, other):
|
||||
return And(self, other)
|
||||
|
||||
def __or__(self, other):
|
||||
return Or(self, other)
|
||||
|
||||
def __invert__(self):
|
||||
return Not(self)
|
||||
|
||||
|
||||
class And(Filter):
|
||||
"""
|
||||
All underlying filters must return `True` for this filter to be `True`.
|
||||
"""
|
||||
def __init__(self, *filters):
|
||||
self._filters = filters
|
||||
|
||||
def __call__(self, event):
|
||||
return all(f(event) for f in self._filters)
|
||||
|
||||
|
||||
class Or(Filter):
|
||||
"""
|
||||
At least one underlying filter must return `True` for this filter to be `True`.
|
||||
"""
|
||||
def __init__(self, *filters):
|
||||
self._filters = filters
|
||||
|
||||
def __call__(self, event):
|
||||
return any(f(event) for f in self._filters)
|
||||
|
||||
|
||||
class Not(Filter):
|
||||
"""
|
||||
The underlying filter must return `False` for this filter to be `True`.
|
||||
"""
|
||||
def __init__(self, filter):
|
||||
self._filter = filter
|
||||
|
||||
def __call__(self, event):
|
||||
return not self._filter(event)
|
||||
|
||||
|
||||
class Identity(Filter):
|
||||
"""
|
||||
Return the value of the underlying filter (or callable) without any modifications.
|
||||
"""
|
||||
def __init__(self, filter):
|
||||
self._filter = filter
|
||||
|
||||
def __call__(self, event):
|
||||
return self._filter(event)
|
||||
|
||||
|
||||
class Always(Filter):
|
||||
"""
|
||||
This filter always returns `True`, and is used as the "empty filter".
|
||||
"""
|
||||
def __call__(self, event):
|
||||
return True
|
||||
|
||||
|
||||
class Never(Filter):
|
||||
"""
|
||||
This filter always returns `False`, and is used when an impossible filter is made
|
||||
(for example, neither outgoing nor incoming is always false). This can be used to
|
||||
"turn off" handlers without removing them.
|
||||
"""
|
||||
def __call__(self, event):
|
||||
return False
|
25
telethon/_events/filters/entities.py
Normal file
25
telethon/_events/filters/entities.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
from .base import Filter
|
||||
|
||||
|
||||
class Chats:
|
||||
"""
|
||||
The update type must match the specified instances for the filter to return `True`.
|
||||
This is most useful for raw API.
|
||||
"""
|
||||
def __init__(self, types):
|
||||
self._types = types
|
||||
|
||||
def __call__(self, event):
|
||||
return isinstance(event, self._types)
|
||||
|
||||
|
||||
class Senders:
|
||||
"""
|
||||
The update type must match the specified instances for the filter to return `True`.
|
||||
This is most useful for raw API.
|
||||
"""
|
||||
def __init__(self, types):
|
||||
self._types = types
|
||||
|
||||
def __call__(self, event):
|
||||
return isinstance(event, self._types)
|
13
telethon/_events/filters/generic.py
Normal file
13
telethon/_events/filters/generic.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
from .base import Filter
|
||||
|
||||
|
||||
class Types:
|
||||
"""
|
||||
The update type must match the specified instances for the filter to return `True`.
|
||||
This is most useful for raw API.
|
||||
"""
|
||||
def __init__(self, types):
|
||||
self._types = types
|
||||
|
||||
def __call__(self, event):
|
||||
return isinstance(event, self._types)
|
26
telethon/_events/filters/messages.py
Normal file
26
telethon/_events/filters/messages.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
import re
|
||||
from .base import Filter
|
||||
|
||||
|
||||
class Pattern:
|
||||
"""
|
||||
The update type must match the specified instances for the filter to return `True`.
|
||||
This is most useful for raw API.
|
||||
"""
|
||||
def __init__(self, pattern):
|
||||
self._pattern = re.compile(pattern).match
|
||||
|
||||
def __call__(self, event):
|
||||
return self._pattern(event.text)
|
||||
|
||||
|
||||
class Data:
|
||||
"""
|
||||
The update type must match the specified instances for the filter to return `True`.
|
||||
This is most useful for raw API.
|
||||
"""
|
||||
def __init__(self, data):
|
||||
self._data = re.compile(data).match
|
||||
|
||||
def __call__(self, event):
|
||||
return self._data(event.data)
|
Loading…
Reference in New Issue
Block a user