Add the ability to invert (not) filters (#552)

* Add InvertedFilter and use it from __invert__

* Add docstrings and __str__ for inverting filters

* Tests for inverted filters
This commit is contained in:
Jacob Bom 2017-03-28 18:38:44 +02:00 committed by Jannes Höke
parent 8fe6e13ff2
commit ad5f009ce7
2 changed files with 53 additions and 0 deletions

View file

@ -32,9 +32,14 @@ class BaseFilter(object):
>>> (Filters.audio | Filters.video) >>> (Filters.audio | Filters.video)
Not:
>>> ~ Filters.command
Also works with more than two filters: Also works with more than two filters:
>>> (Filters.text & (Filters.entity(URL) | Filters.entity(TEXT_LINK))) >>> (Filters.text & (Filters.entity(URL) | Filters.entity(TEXT_LINK)))
>>> Filters.text & (~ Filters.forwarded)
If you want to create your own filters create a class inheriting from this class and implement If you want to create your own filters create a class inheriting from this class and implement
a `filter` method that returns a boolean: `True` if the message should be handled, `False` a `filter` method that returns a boolean: `True` if the message should be handled, `False`
@ -51,10 +56,32 @@ class BaseFilter(object):
def __or__(self, other): def __or__(self, other):
return MergedFilter(self, or_filter=other) return MergedFilter(self, or_filter=other)
def __invert__(self):
return InvertedFilter(self)
def filter(self, message): def filter(self, message):
raise NotImplementedError raise NotImplementedError
class InvertedFilter(BaseFilter):
"""Represents a filter that has been inverted.
Args:
f: The filter to invert
"""
def __init__(self, f):
self.f = f
def filter(self, message):
return not self.f(message)
def __str__(self):
return "<telegram.ext.filters.InvertedFilter inverting {}>".format(self.f)
__repr__ = __str__
class MergedFilter(BaseFilter): class MergedFilter(BaseFilter):
"""Represents a filter consisting of two other filters. """Represents a filter consisting of two other filters.

View file

@ -226,6 +226,32 @@ class FiltersTest(BaseTest, unittest.TestCase):
r"<telegram.ext.filters.(Filters.)?_Forwarded object at .*?> or " r"<telegram.ext.filters.(Filters.)?_Forwarded object at .*?> or "
r"<telegram.ext.filters.(Filters.)?entity object at .*?>>>") r"<telegram.ext.filters.(Filters.)?entity object at .*?>>>")
def test_inverted_filters(self):
self.message.text = '/test'
self.assertTrue((Filters.command)(self.message))
self.assertFalse((~Filters.command)(self.message))
self.message.text = 'test'
self.assertFalse((Filters.command)(self.message))
self.assertTrue((~Filters.command)(self.message))
def test_inverted_and_filters(self):
self.message.text = '/test'
self.message.forward_date = 1
self.assertTrue((Filters.forwarded & Filters.command)(self.message))
self.assertFalse((~Filters.forwarded & Filters.command)(self.message))
self.assertFalse((Filters.forwarded & ~Filters.command)(self.message))
self.assertFalse((~(Filters.forwarded & Filters.command))(self.message))
self.message.forward_date = None
self.assertFalse((Filters.forwarded & Filters.command)(self.message))
self.assertTrue((~Filters.forwarded & Filters.command)(self.message))
self.assertFalse((Filters.forwarded & ~Filters.command)(self.message))
self.assertTrue((~(Filters.forwarded & Filters.command))(self.message))
self.message.text = 'test'
self.assertFalse((Filters.forwarded & Filters.command)(self.message))
self.assertFalse((~Filters.forwarded & Filters.command)(self.message))
self.assertFalse((Filters.forwarded & ~Filters.command)(self.message))
self.assertTrue((~(Filters.forwarded & Filters.command))(self.message))
def test_faulty_custom_filter(self): def test_faulty_custom_filter(self):
class _CustomFilter(BaseFilter): class _CustomFilter(BaseFilter):