From ad5f009ce722db7fc70a82dd2af5d424d29ec877 Mon Sep 17 00:00:00 2001 From: Jacob Bom Date: Tue, 28 Mar 2017 18:38:44 +0200 Subject: [PATCH] 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 --- telegram/ext/filters.py | 27 +++++++++++++++++++++++++++ tests/test_filters.py | 26 ++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/telegram/ext/filters.py b/telegram/ext/filters.py index c16db36cf..4b3cbd482 100644 --- a/telegram/ext/filters.py +++ b/telegram/ext/filters.py @@ -32,9 +32,14 @@ class BaseFilter(object): >>> (Filters.audio | Filters.video) + Not: + + >>> ~ Filters.command + Also works with more than two filters: >>> (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 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): return MergedFilter(self, or_filter=other) + def __invert__(self): + return InvertedFilter(self) + def filter(self, message): 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 "".format(self.f) + + __repr__ = __str__ + + class MergedFilter(BaseFilter): """Represents a filter consisting of two other filters. diff --git a/tests/test_filters.py b/tests/test_filters.py index 814a85ae6..ec38c4ec2 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -226,6 +226,32 @@ class FiltersTest(BaseTest, unittest.TestCase): r" or " r">>") + 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): class _CustomFilter(BaseFilter):