1#!/usr/bin/env python
2#
3# A library that provides a Python interface to the Telegram Bot API
4# Copyright (C) 2015-2020
5# Leandro Toledo de Souza <devs@python-telegram-bot.org>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Lesser Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU Lesser Public License for more details.
16#
17# You should have received a copy of the GNU Lesser Public License
18# along with this program.  If not, see [http://www.gnu.org/licenses/].
19# pylint: disable=C0112, C0103, W0221
20"""This module contains the Filters for use with the MessageHandler class."""
21
22import re
23import warnings
24
25from abc import ABC, abstractmethod
26from threading import Lock
27from typing import (
28    Dict,
29    FrozenSet,
30    List,
31    Match,
32    Optional,
33    Pattern,
34    Set,
35    Tuple,
36    Union,
37    cast,
38    NoReturn,
39)
40
41from telegram import Chat, Message, MessageEntity, Update, User
42
43__all__ = [
44    'Filters',
45    'BaseFilter',
46    'MessageFilter',
47    'UpdateFilter',
48    'InvertedFilter',
49    'MergedFilter',
50    'XORFilter',
51]
52
53from telegram.utils.deprecate import TelegramDeprecationWarning
54from telegram.utils.types import SLT
55
56
57class BaseFilter(ABC):
58    """Base class for all Filters.
59
60    Filters subclassing from this class can combined using bitwise operators:
61
62    And:
63
64        >>> (Filters.text & Filters.entity(MENTION))
65
66    Or:
67
68        >>> (Filters.audio | Filters.video)
69
70    Exclusive Or:
71
72        >>> (Filters.regex('To Be') ^ Filters.regex('Not 2B'))
73
74    Not:
75
76        >>> ~ Filters.command
77
78    Also works with more than two filters:
79
80        >>> (Filters.text & (Filters.entity(URL) | Filters.entity(TEXT_LINK)))
81        >>> Filters.text & (~ Filters.forwarded)
82
83    Note:
84        Filters use the same short circuiting logic as python's `and`, `or` and `not`.
85        This means that for example:
86
87            >>> Filters.regex(r'(a?x)') | Filters.regex(r'(b?x)')
88
89        With ``message.text == x``, will only ever return the matches for the first filter,
90        since the second one is never evaluated.
91
92
93    If you want to create your own filters create a class inheriting from either
94    :class:`MessageFilter` or :class:`UpdateFilter` and implement a :meth:``filter`` method that
95    returns a boolean: :obj:`True` if the message should be
96    handled, :obj:`False` otherwise.
97    Note that the filters work only as class instances, not
98    actual class objects (so remember to
99    initialize your filter classes).
100
101    By default the filters name (what will get printed when converted to a string for display)
102    will be the class name. If you want to overwrite this assign a better name to the :attr:`name`
103    class variable.
104
105    Attributes:
106        name (:obj:`str`): Name for this filter. Defaults to the type of filter.
107        data_filter (:obj:`bool`): Whether this filter is a data filter. A data filter should
108            return a dict with lists. The dict will be merged with
109            :class:`telegram.ext.CallbackContext`'s internal dict in most cases
110            (depends on the handler).
111    """
112
113    _name = None
114    data_filter = False
115
116    @abstractmethod
117    def __call__(self, update: Update) -> Optional[Union[bool, Dict]]:
118        pass
119
120    def __and__(self, other: 'BaseFilter') -> 'BaseFilter':
121        return MergedFilter(self, and_filter=other)
122
123    def __or__(self, other: 'BaseFilter') -> 'BaseFilter':
124        return MergedFilter(self, or_filter=other)
125
126    def __xor__(self, other: 'BaseFilter') -> 'BaseFilter':
127        return XORFilter(self, other)
128
129    def __invert__(self) -> 'BaseFilter':
130        return InvertedFilter(self)
131
132    @property
133    def name(self) -> Optional[str]:
134        return self._name
135
136    @name.setter
137    def name(self, name: Optional[str]) -> None:
138        self._name = name
139
140    def __repr__(self) -> str:
141        # We do this here instead of in a __init__ so filter don't have to call __init__ or super()
142        if self.name is None:
143            self.name = self.__class__.__name__
144        return self.name
145
146
147class MessageFilter(BaseFilter, ABC):
148    """Base class for all Message Filters. In contrast to :class:`UpdateFilter`, the object passed
149    to :meth:`filter` is ``update.effective_message``.
150
151    Please see :class:`telegram.ext.BaseFilter` for details on how to create custom filters.
152
153    Attributes:
154        name (:obj:`str`): Name for this filter. Defaults to the type of filter.
155        data_filter (:obj:`bool`): Whether this filter is a data filter. A data filter should
156            return a dict with lists. The dict will be merged with
157            :class:`telegram.ext.CallbackContext`'s internal dict in most cases
158            (depends on the handler).
159
160    """
161
162    def __call__(self, update: Update) -> Optional[Union[bool, Dict]]:
163        return self.filter(update.effective_message)
164
165    @abstractmethod
166    def filter(self, message: Message) -> Optional[Union[bool, Dict]]:
167        """This method must be overwritten.
168
169        Args:
170            message (:class:`telegram.Message`): The message that is tested.
171
172        Returns:
173            :obj:`dict` or :obj:`bool`
174
175        """
176
177
178class UpdateFilter(BaseFilter, ABC):
179    """Base class for all Update Filters. In contrast to :class:`UpdateFilter`, the object
180    passed to :meth:`filter` is ``update``, which allows to create filters like
181    :attr:`Filters.update.edited_message`.
182
183    Please see :class:`telegram.ext.BaseFilter` for details on how to create custom filters.
184
185    Attributes:
186        name (:obj:`str`): Name for this filter. Defaults to the type of filter.
187        data_filter (:obj:`bool`): Whether this filter is a data filter. A data filter should
188            return a dict with lists. The dict will be merged with
189            :class:`telegram.ext.CallbackContext`'s internal dict in most cases
190            (depends on the handler).
191
192    """
193
194    def __call__(self, update: Update) -> Optional[Union[bool, Dict]]:
195        return self.filter(update)
196
197    @abstractmethod
198    def filter(self, update: Update) -> Optional[Union[bool, Dict]]:
199        """This method must be overwritten.
200
201        Args:
202            update (:class:`telegram.Update`): The update that is tested.
203
204        Returns:
205            :obj:`dict` or :obj:`bool`.
206
207        """
208
209
210class InvertedFilter(UpdateFilter):
211    """Represents a filter that has been inverted.
212
213    Args:
214        f: The filter to invert.
215
216    """
217
218    def __init__(self, f: BaseFilter):
219        self.f = f
220
221    def filter(self, update: Update) -> bool:
222        return not bool(self.f(update))
223
224    @property
225    def name(self) -> str:
226        return f"<inverted {self.f}>"
227
228    @name.setter
229    def name(self, name: str) -> NoReturn:
230        raise RuntimeError('Cannot set name for InvertedFilter')
231
232
233class MergedFilter(UpdateFilter):
234    """Represents a filter consisting of two other filters.
235
236    Args:
237        base_filter: Filter 1 of the merged filter.
238        and_filter: Optional filter to "and" with base_filter. Mutually exclusive with or_filter.
239        or_filter: Optional filter to "or" with base_filter. Mutually exclusive with and_filter.
240
241    """
242
243    def __init__(
244        self, base_filter: BaseFilter, and_filter: BaseFilter = None, or_filter: BaseFilter = None
245    ):
246        self.base_filter = base_filter
247        if self.base_filter.data_filter:
248            self.data_filter = True
249        self.and_filter = and_filter
250        if (
251            self.and_filter
252            and not isinstance(self.and_filter, bool)
253            and self.and_filter.data_filter
254        ):
255            self.data_filter = True
256        self.or_filter = or_filter
257        if self.or_filter and not isinstance(self.and_filter, bool) and self.or_filter.data_filter:
258            self.data_filter = True
259
260    @staticmethod
261    def _merge(base_output: Union[bool, Dict], comp_output: Union[bool, Dict]) -> Dict:
262        base = base_output if isinstance(base_output, dict) else {}
263        comp = comp_output if isinstance(comp_output, dict) else {}
264        for k in comp.keys():
265            # Make sure comp values are lists
266            comp_value = comp[k] if isinstance(comp[k], list) else []
267            try:
268                # If base is a list then merge
269                if isinstance(base[k], list):
270                    base[k] += comp_value
271                else:
272                    base[k] = [base[k]] + comp_value
273            except KeyError:
274                base[k] = comp_value
275        return base
276
277    def filter(self, update: Update) -> Union[bool, Dict]:  # pylint: disable=R0911
278        base_output = self.base_filter(update)
279        # We need to check if the filters are data filters and if so return the merged data.
280        # If it's not a data filter or an or_filter but no matches return bool
281        if self.and_filter:
282            # And filter needs to short circuit if base is falsey
283            if base_output:
284                comp_output = self.and_filter(update)
285                if comp_output:
286                    if self.data_filter:
287                        merged = self._merge(base_output, comp_output)
288                        if merged:
289                            return merged
290                    return True
291        elif self.or_filter:
292            # Or filter needs to short circuit if base is truthey
293            if base_output:
294                if self.data_filter:
295                    return base_output
296                return True
297
298            comp_output = self.or_filter(update)
299            if comp_output:
300                if self.data_filter:
301                    return comp_output
302                return True
303        return False
304
305    @property
306    def name(self) -> str:
307        return (
308            f"<{self.base_filter} {'and' if self.and_filter else 'or'} "
309            f"{self.and_filter or self.or_filter}>"
310        )
311
312    @name.setter
313    def name(self, name: str) -> NoReturn:
314        raise RuntimeError('Cannot set name for MergedFilter')
315
316
317class XORFilter(UpdateFilter):
318    """Convenience filter acting as wrapper for :class:`MergedFilter` representing the an XOR gate
319    for two filters
320
321    Args:
322        base_filter: Filter 1 of the merged filter.
323        xor_filter: Filter 2 of the merged filter.
324
325    """
326
327    def __init__(self, base_filter: BaseFilter, xor_filter: BaseFilter):
328        self.base_filter = base_filter
329        self.xor_filter = xor_filter
330        self.merged_filter = (base_filter & ~xor_filter) | (~base_filter & xor_filter)
331
332    def filter(self, update: Update) -> Optional[Union[bool, Dict]]:
333        return self.merged_filter(update)
334
335    @property
336    def name(self) -> str:
337        return f'<{self.base_filter} xor {self.xor_filter}>'
338
339    @name.setter
340    def name(self, name: str) -> NoReturn:
341        raise RuntimeError('Cannot set name for XORFilter')
342
343
344class _DiceEmoji(MessageFilter):
345    def __init__(self, emoji: str = None, name: str = None):
346        self.name = f'Filters.dice.{name}' if name else 'Filters.dice'
347        self.emoji = emoji
348
349    class _DiceValues(MessageFilter):
350        def __init__(
351            self,
352            values: SLT[int],
353            name: str,
354            emoji: str = None,
355        ):
356            self.values = [values] if isinstance(values, int) else values
357            self.emoji = emoji
358            self.name = f'{name}({values})'
359
360        def filter(self, message: Message) -> bool:
361            if message.dice and message.dice.value in self.values:
362                if self.emoji:
363                    return message.dice.emoji == self.emoji
364                return True
365            return False
366
367    def __call__(  # type: ignore[override]
368        self, update: Union[Update, List[int], Tuple[int]]
369    ) -> Union[bool, '_DiceValues']:
370        if isinstance(update, Update):
371            return self.filter(update.effective_message)
372        return self._DiceValues(update, self.name, emoji=self.emoji)
373
374    def filter(self, message: Message) -> bool:
375        if bool(message.dice):
376            if self.emoji:
377                return message.dice.emoji == self.emoji
378            return True
379        return False
380
381
382class Filters:
383    """Predefined filters for use as the ``filter`` argument of
384    :class:`telegram.ext.MessageHandler`.
385
386    Examples:
387        Use ``MessageHandler(Filters.video, callback_method)`` to filter all video
388        messages. Use ``MessageHandler(Filters.contact, callback_method)`` for all contacts. etc.
389
390    """
391
392    class _All(MessageFilter):
393        name = 'Filters.all'
394
395        def filter(self, message: Message) -> bool:
396            return True
397
398    all = _All()
399    """All Messages."""
400
401    class _Text(MessageFilter):
402        name = 'Filters.text'
403
404        class _TextStrings(MessageFilter):
405            def __init__(self, strings: Union[List[str], Tuple[str]]):
406                self.strings = strings
407                self.name = f'Filters.text({strings})'
408
409            def filter(self, message: Message) -> bool:
410                if message.text:
411                    return message.text in self.strings
412                return False
413
414        def __call__(  # type: ignore[override]
415            self, update: Union[Update, List[str], Tuple[str]]
416        ) -> Union[bool, '_TextStrings']:
417            if isinstance(update, Update):
418                return self.filter(update.effective_message)
419            return self._TextStrings(update)
420
421        def filter(self, message: Message) -> bool:
422            return bool(message.text)
423
424    text = _Text()
425    """Text Messages. If a list of strings is passed, it filters messages to only allow those
426    whose text is appearing in the given list.
427
428    Examples:
429        To allow any text message, simply use
430        ``MessageHandler(Filters.text, callback_method)``.
431
432        A simple use case for passing a list is to allow only messages that were sent by a
433        custom :class:`telegram.ReplyKeyboardMarkup`::
434
435            buttons = ['Start', 'Settings', 'Back']
436            markup = ReplyKeyboardMarkup.from_column(buttons)
437            ...
438            MessageHandler(Filters.text(buttons), callback_method)
439
440    Note:
441        * Dice messages don't have text. If you want to filter either text or dice messages, use
442          ``Filters.text | Filters.dice``.
443        * Messages containing a command are accepted by this filter. Use
444          ``Filters.text & (~Filters.command)``, if you want to filter only text messages without
445          commands.
446
447    Args:
448        update (List[:obj:`str`] | Tuple[:obj:`str`], optional): Which messages to allow. Only
449            exact matches are allowed. If not specified, will allow any text message.
450    """
451
452    class _Caption(MessageFilter):
453        name = 'Filters.caption'
454
455        class _CaptionStrings(MessageFilter):
456            def __init__(self, strings: Union[List[str], Tuple[str]]):
457                self.strings = strings
458                self.name = f'Filters.caption({strings})'
459
460            def filter(self, message: Message) -> bool:
461                if message.caption:
462                    return message.caption in self.strings
463                return False
464
465        def __call__(  # type: ignore[override]
466            self, update: Union[Update, List[str], Tuple[str]]
467        ) -> Union[bool, '_CaptionStrings']:
468            if isinstance(update, Update):
469                return self.filter(update.effective_message)
470            return self._CaptionStrings(update)
471
472        def filter(self, message: Message) -> bool:
473            return bool(message.caption)
474
475    caption = _Caption()
476    """Messages with a caption. If a list of strings is passed, it filters messages to only
477    allow those whose caption is appearing in the given list.
478
479    Examples:
480        ``MessageHandler(Filters.caption, callback_method)``
481
482    Args:
483        update (List[:obj:`str`] | Tuple[:obj:`str`], optional): Which captions to allow. Only
484            exact matches are allowed. If not specified, will allow any message with a caption.
485    """
486
487    class _Command(MessageFilter):
488        name = 'Filters.command'
489
490        class _CommandOnlyStart(MessageFilter):
491            def __init__(self, only_start: bool):
492                self.only_start = only_start
493                self.name = f'Filters.command({only_start})'
494
495            def filter(self, message: Message) -> bool:
496                return bool(
497                    message.entities
498                    and any([e.type == MessageEntity.BOT_COMMAND for e in message.entities])
499                )
500
501        def __call__(  # type: ignore[override]
502            self, update: Union[bool, Update]
503        ) -> Union[bool, '_CommandOnlyStart']:
504            if isinstance(update, Update):
505                return self.filter(update.effective_message)
506            return self._CommandOnlyStart(update)
507
508        def filter(self, message: Message) -> bool:
509            return bool(
510                message.entities
511                and message.entities[0].type == MessageEntity.BOT_COMMAND
512                and message.entities[0].offset == 0
513            )
514
515    command = _Command()
516    """
517    Messages with a :attr:`telegram.MessageEntity.BOT_COMMAND`. By default only allows
518    messages `starting` with a bot command. Pass :obj:`False` to also allow messages that contain a
519    bot command `anywhere` in the text.
520
521    Examples::
522
523        MessageHandler(Filters.command, command_at_start_callback)
524        MessageHandler(Filters.command(False), command_anywhere_callback)
525
526    Note:
527        ``Filters.text`` also accepts messages containing a command.
528
529    Args:
530        update (:obj:`bool`, optional): Whether to only allow messages that `start` with a bot
531            command. Defaults to :obj:`True`.
532    """
533
534    class regex(MessageFilter):
535        """
536        Filters updates by searching for an occurrence of ``pattern`` in the message text.
537        The ``re.search()`` function is used to determine whether an update should be filtered.
538
539        Refer to the documentation of the ``re`` module for more information.
540
541        To get the groups and groupdict matched, see :attr:`telegram.ext.CallbackContext.matches`.
542
543        Examples:
544            Use ``MessageHandler(Filters.regex(r'help'), callback)`` to capture all messages that
545            contain the word 'help'. You can also use
546            ``MessageHandler(Filters.regex(re.compile(r'help', re.IGNORECASE)), callback)`` if
547            you want your pattern to be case insensitive. This approach is recommended
548            if you need to specify flags on your pattern.
549
550        Note:
551            Filters use the same short circuiting logic as python's `and`, `or` and `not`.
552            This means that for example:
553
554                >>> Filters.regex(r'(a?x)') | Filters.regex(r'(b?x)')
555
556            With a message.text of `x`, will only ever return the matches for the first filter,
557            since the second one is never evaluated.
558
559        Args:
560            pattern (:obj:`str` | :obj:`Pattern`): The regex pattern.
561        """
562
563        data_filter = True
564
565        def __init__(self, pattern: Union[str, Pattern]):
566            if isinstance(pattern, str):
567                pattern = re.compile(pattern)
568            pattern = cast(Pattern, pattern)
569            self.pattern: Pattern = pattern
570            self.name = f'Filters.regex({self.pattern})'
571
572        def filter(self, message: Message) -> Optional[Dict[str, List[Match]]]:
573            """"""  # remove method from docs
574            if message.text:
575                match = self.pattern.search(message.text)
576                if match:
577                    return {'matches': [match]}
578            return {}
579
580    class caption_regex(MessageFilter):
581        """
582        Filters updates by searching for an occurrence of ``pattern`` in the message caption.
583
584        This filter works similarly to :class:`Filters.regex`, with the only exception being that
585        it applies to the message caption instead of the text.
586
587        Examples:
588            Use ``MessageHandler(Filters.photo & Filters.caption_regex(r'help'), callback)``
589            to capture all photos with caption containing the word 'help'.
590
591        Note:
592            This filter will not work on simple text messages, but only on media with caption.
593
594        Args:
595            pattern (:obj:`str` | :obj:`Pattern`): The regex pattern.
596        """
597
598        data_filter = True
599
600        def __init__(self, pattern: Union[str, Pattern]):
601            if isinstance(pattern, str):
602                pattern = re.compile(pattern)
603            pattern = cast(Pattern, pattern)
604            self.pattern: Pattern = pattern
605            self.name = f'Filters.caption_regex({self.pattern})'
606
607        def filter(self, message: Message) -> Optional[Dict[str, List[Match]]]:
608            """"""  # remove method from docs
609            if message.caption:
610                match = self.pattern.search(message.caption)
611                if match:
612                    return {'matches': [match]}
613            return {}
614
615    class _Reply(MessageFilter):
616        name = 'Filters.reply'
617
618        def filter(self, message: Message) -> bool:
619            return bool(message.reply_to_message)
620
621    reply = _Reply()
622    """Messages that are a reply to another message."""
623
624    class _Audio(MessageFilter):
625        name = 'Filters.audio'
626
627        def filter(self, message: Message) -> bool:
628            return bool(message.audio)
629
630    audio = _Audio()
631    """Messages that contain :class:`telegram.Audio`."""
632
633    class _Document(MessageFilter):
634        name = 'Filters.document'
635
636        class category(MessageFilter):
637            """Filters documents by their category in the mime-type attribute.
638
639            Note:
640                This Filter only filters by the mime_type of the document,
641                    it doesn't check the validity of the document.
642                The user can manipulate the mime-type of a message and
643                    send media with wrong types that don't fit to this handler.
644
645            Example:
646                Filters.documents.category('audio/') returns :obj:`True` for all types
647                of audio sent as file, for example 'audio/mpeg' or 'audio/x-wav'.
648            """
649
650            def __init__(self, category: Optional[str]):
651                """Initialize the category you want to filter
652
653                Args:
654                    category (str, optional): category of the media you want to filter"""
655                self.category = category
656                self.name = f"Filters.document.category('{self.category}')"
657
658            def filter(self, message: Message) -> bool:
659                """"""  # remove method from docs
660                if message.document:
661                    return message.document.mime_type.startswith(self.category)
662                return False
663
664        application = category('application/')
665        audio = category('audio/')
666        image = category('image/')
667        video = category('video/')
668        text = category('text/')
669
670        class mime_type(MessageFilter):
671            """This Filter filters documents by their mime-type attribute
672
673            Note:
674                This Filter only filters by the mime_type of the document,
675                    it doesn't check the validity of document.
676                The user can manipulate the mime-type of a message and
677                    send media with wrong types that don't fit to this handler.
678
679            Example:
680                ``Filters.documents.mime_type('audio/mpeg')`` filters all audio in mp3 format.
681            """
682
683            def __init__(self, mimetype: Optional[str]):
684                """Initialize the category you want to filter
685
686                Args:
687                    mimetype (str, optional): mime_type of the media you want to filter"""
688                self.mimetype = mimetype
689                self.name = f"Filters.document.mime_type('{self.mimetype}')"
690
691            def filter(self, message: Message) -> bool:
692                """"""  # remove method from docs
693                if message.document:
694                    return message.document.mime_type == self.mimetype
695                return False
696
697        apk = mime_type('application/vnd.android.package-archive')
698        doc = mime_type('application/msword')
699        docx = mime_type('application/vnd.openxmlformats-officedocument.wordprocessingml.document')
700        exe = mime_type('application/x-ms-dos-executable')
701        gif = mime_type('video/mp4')
702        jpg = mime_type('image/jpeg')
703        mp3 = mime_type('audio/mpeg')
704        pdf = mime_type('application/pdf')
705        py = mime_type('text/x-python')
706        svg = mime_type('image/svg+xml')
707        txt = mime_type('text/plain')
708        targz = mime_type('application/x-compressed-tar')
709        wav = mime_type('audio/x-wav')
710        xml = mime_type('application/xml')
711        zip = mime_type('application/zip')
712
713        class file_extension(MessageFilter):
714            """This filter filters documents by their file ending/extension.
715
716            Note:
717                * This Filter only filters by the file ending/extension of the document,
718                  it doesn't check the validity of document.
719                * The user can manipulate the file extension of a document and
720                  send media with wrong types that don't fit to this handler.
721                * Case insensitive by default,
722                  you may change this with the flag ``case_sensitive=True``.
723                * Extension should be passed without leading dot
724                  unless it's a part of the extension.
725                * Pass :obj:`None` to filter files with no extension,
726                  i.e. without a dot in the filename.
727
728            Example:
729                * ``Filters.document.file_extension("jpg")``
730                  filters files with extension ``".jpg"``.
731                * ``Filters.document.file_extension(".jpg")``
732                  filters files with extension ``"..jpg"``.
733                * ``Filters.document.file_extension("Dockerfile", case_sensitive=True)``
734                  filters files with extension ``".Dockerfile"`` minding the case.
735                * ``Filters.document.file_extension(None)``
736                  filters files without a dot in the filename.
737            """
738
739            def __init__(self, file_extension: Optional[str], case_sensitive: bool = False):
740                """Initialize the extension you want to filter.
741
742                Args:
743                    file_extension (:obj:`str` | :obj:`None`):
744                        media file extension you want to filter.
745                    case_sensitive (:obj:bool, optional):
746                        pass :obj:`True` to make the filter case sensitive.
747                        Default: :obj:`False`.
748                """
749                self.is_case_sensitive = case_sensitive
750                if file_extension is None:
751                    self.file_extension = None
752                    self.name = "Filters.document.file_extension(None)"
753                elif case_sensitive:
754                    self.file_extension = f".{file_extension}"
755                    self.name = (
756                        f"Filters.document.file_extension({file_extension!r},"
757                        " case_sensitive=True)"
758                    )
759                else:
760                    self.file_extension = f".{file_extension}".lower()
761                    self.name = f"Filters.document.file_extension({file_extension.lower()!r})"
762
763            def filter(self, message: Message) -> bool:
764                """"""  # remove method from docs
765                if message.document is None:
766                    return False
767                if self.file_extension is None:
768                    return "." not in message.document.file_name
769                if self.is_case_sensitive:
770                    filename = message.document.file_name
771                else:
772                    filename = message.document.file_name.lower()
773                return filename.endswith(self.file_extension)
774
775        def filter(self, message: Message) -> bool:
776            return bool(message.document)
777
778    document = _Document()
779    """
780    Subset for messages containing a document/file.
781
782    Examples:
783        Use these filters like: ``Filters.document.mp3``,
784        ``Filters.document.mime_type("text/plain")`` etc. Or use just
785        ``Filters.document`` for all document messages.
786
787    Attributes:
788        category: Filters documents by their category in the mime-type attribute
789
790            Note:
791                This Filter only filters by the mime_type of the document,
792                it doesn't check the validity of the document.
793                The user can manipulate the mime-type of a message and
794                send media with wrong types that don't fit to this handler.
795
796            Example:
797                ``Filters.documents.category('audio/')`` filters all types
798                of audio sent as file, for example 'audio/mpeg' or 'audio/x-wav'.
799        application: Same as ``Filters.document.category("application")``.
800        audio: Same as ``Filters.document.category("audio")``.
801        image: Same as ``Filters.document.category("image")``.
802        video: Same as ``Filters.document.category("video")``.
803        text: Same as ``Filters.document.category("text")``.
804        mime_type: Filters documents by their mime-type attribute
805
806            Note:
807                This Filter only filters by the mime_type of the document,
808                it doesn't check the validity of document.
809
810                The user can manipulate the mime-type of a message and
811                send media with wrong types that don't fit to this handler.
812
813            Example:
814                ``Filters.documents.mime_type('audio/mpeg')`` filters all audio in mp3 format.
815        apk: Same as ``Filters.document.mime_type("application/vnd.android.package-archive")``-
816        doc: Same as ``Filters.document.mime_type("application/msword")``-
817        docx: Same as ``Filters.document.mime_type("application/vnd.openxmlformats-\
818officedocument.wordprocessingml.document")``-
819        exe: Same as ``Filters.document.mime_type("application/x-ms-dos-executable")``-
820        gif: Same as ``Filters.document.mime_type("video/mp4")``-
821        jpg: Same as ``Filters.document.mime_type("image/jpeg")``-
822        mp3: Same as ``Filters.document.mime_type("audio/mpeg")``-
823        pdf: Same as ``Filters.document.mime_type("application/pdf")``-
824        py: Same as ``Filters.document.mime_type("text/x-python")``-
825        svg: Same as ``Filters.document.mime_type("image/svg+xml")``-
826        txt: Same as ``Filters.document.mime_type("text/plain")``-
827        targz: Same as ``Filters.document.mime_type("application/x-compressed-tar")``-
828        wav: Same as ``Filters.document.mime_type("audio/x-wav")``-
829        xml: Same as ``Filters.document.mime_type("application/xml")``-
830        zip: Same as ``Filters.document.mime_type("application/zip")``-
831        file_extension: This filter filters documents by their file ending/extension.
832
833            Note:
834                * This Filter only filters by the file ending/extension of the document,
835                  it doesn't check the validity of document.
836                * The user can manipulate the file extension of a document and
837                  send media with wrong types that don't fit to this handler.
838                * Case insensitive by default,
839                  you may change this with the flag ``case_sensitive=True``.
840                * Extension should be passed without leading dot
841                  unless it's a part of the extension.
842                * Pass :obj:`None` to filter files with no extension,
843                  i.e. without a dot in the filename.
844
845            Example:
846                * ``Filters.document.file_extension("jpg")``
847                  filters files with extension ``".jpg"``.
848                * ``Filters.document.file_extension(".jpg")``
849                  filters files with extension ``"..jpg"``.
850                * ``Filters.document.file_extension("Dockerfile", case_sensitive=True)``
851                  filters files with extension ``".Dockerfile"`` minding the case.
852                * ``Filters.document.file_extension(None)``
853                  filters files without a dot in the filename.
854    """
855
856    class _Animation(MessageFilter):
857        name = 'Filters.animation'
858
859        def filter(self, message: Message) -> bool:
860            return bool(message.animation)
861
862    animation = _Animation()
863    """Messages that contain :class:`telegram.Animation`."""
864
865    class _Photo(MessageFilter):
866        name = 'Filters.photo'
867
868        def filter(self, message: Message) -> bool:
869            return bool(message.photo)
870
871    photo = _Photo()
872    """Messages that contain :class:`telegram.PhotoSize`."""
873
874    class _Sticker(MessageFilter):
875        name = 'Filters.sticker'
876
877        def filter(self, message: Message) -> bool:
878            return bool(message.sticker)
879
880    sticker = _Sticker()
881    """Messages that contain :class:`telegram.Sticker`."""
882
883    class _Video(MessageFilter):
884        name = 'Filters.video'
885
886        def filter(self, message: Message) -> bool:
887            return bool(message.video)
888
889    video = _Video()
890    """Messages that contain :class:`telegram.Video`."""
891
892    class _Voice(MessageFilter):
893        name = 'Filters.voice'
894
895        def filter(self, message: Message) -> bool:
896            return bool(message.voice)
897
898    voice = _Voice()
899    """Messages that contain :class:`telegram.Voice`."""
900
901    class _VideoNote(MessageFilter):
902        name = 'Filters.video_note'
903
904        def filter(self, message: Message) -> bool:
905            return bool(message.video_note)
906
907    video_note = _VideoNote()
908    """Messages that contain :class:`telegram.VideoNote`."""
909
910    class _Contact(MessageFilter):
911        name = 'Filters.contact'
912
913        def filter(self, message: Message) -> bool:
914            return bool(message.contact)
915
916    contact = _Contact()
917    """Messages that contain :class:`telegram.Contact`."""
918
919    class _Location(MessageFilter):
920        name = 'Filters.location'
921
922        def filter(self, message: Message) -> bool:
923            return bool(message.location)
924
925    location = _Location()
926    """Messages that contain :class:`telegram.Location`."""
927
928    class _Venue(MessageFilter):
929        name = 'Filters.venue'
930
931        def filter(self, message: Message) -> bool:
932            return bool(message.venue)
933
934    venue = _Venue()
935    """Messages that contain :class:`telegram.Venue`."""
936
937    class _StatusUpdate(UpdateFilter):
938        """Subset for messages containing a status update.
939
940        Examples:
941            Use these filters like: ``Filters.status_update.new_chat_members`` etc. Or use just
942            ``Filters.status_update`` for all status update messages.
943
944        """
945
946        class _NewChatMembers(MessageFilter):
947            name = 'Filters.status_update.new_chat_members'
948
949            def filter(self, message: Message) -> bool:
950                return bool(message.new_chat_members)
951
952        new_chat_members = _NewChatMembers()
953        """Messages that contain :attr:`telegram.Message.new_chat_members`."""
954
955        class _LeftChatMember(MessageFilter):
956            name = 'Filters.status_update.left_chat_member'
957
958            def filter(self, message: Message) -> bool:
959                return bool(message.left_chat_member)
960
961        left_chat_member = _LeftChatMember()
962        """Messages that contain :attr:`telegram.Message.left_chat_member`."""
963
964        class _NewChatTitle(MessageFilter):
965            name = 'Filters.status_update.new_chat_title'
966
967            def filter(self, message: Message) -> bool:
968                return bool(message.new_chat_title)
969
970        new_chat_title = _NewChatTitle()
971        """Messages that contain :attr:`telegram.Message.new_chat_title`."""
972
973        class _NewChatPhoto(MessageFilter):
974            name = 'Filters.status_update.new_chat_photo'
975
976            def filter(self, message: Message) -> bool:
977                return bool(message.new_chat_photo)
978
979        new_chat_photo = _NewChatPhoto()
980        """Messages that contain :attr:`telegram.Message.new_chat_photo`."""
981
982        class _DeleteChatPhoto(MessageFilter):
983            name = 'Filters.status_update.delete_chat_photo'
984
985            def filter(self, message: Message) -> bool:
986                return bool(message.delete_chat_photo)
987
988        delete_chat_photo = _DeleteChatPhoto()
989        """Messages that contain :attr:`telegram.Message.delete_chat_photo`."""
990
991        class _ChatCreated(MessageFilter):
992            name = 'Filters.status_update.chat_created'
993
994            def filter(self, message: Message) -> bool:
995                return bool(
996                    message.group_chat_created
997                    or message.supergroup_chat_created
998                    or message.channel_chat_created
999                )
1000
1001        chat_created = _ChatCreated()
1002        """Messages that contain :attr:`telegram.Message.group_chat_created`,
1003            :attr: `telegram.Message.supergroup_chat_created` or
1004            :attr: `telegram.Message.channel_chat_created`."""
1005
1006        class _Migrate(MessageFilter):
1007            name = 'Filters.status_update.migrate'
1008
1009            def filter(self, message: Message) -> bool:
1010                return bool(message.migrate_from_chat_id or message.migrate_to_chat_id)
1011
1012        migrate = _Migrate()
1013        """Messages that contain :attr:`telegram.Message.migrate_from_chat_id` or
1014            :attr:`telegram.Message.migrate_to_chat_id`."""
1015
1016        class _PinnedMessage(MessageFilter):
1017            name = 'Filters.status_update.pinned_message'
1018
1019            def filter(self, message: Message) -> bool:
1020                return bool(message.pinned_message)
1021
1022        pinned_message = _PinnedMessage()
1023        """Messages that contain :attr:`telegram.Message.pinned_message`."""
1024
1025        class _ConnectedWebsite(MessageFilter):
1026            name = 'Filters.status_update.connected_website'
1027
1028            def filter(self, message: Message) -> bool:
1029                return bool(message.connected_website)
1030
1031        connected_website = _ConnectedWebsite()
1032        """Messages that contain :attr:`telegram.Message.connected_website`."""
1033
1034        class _ProximityAlertTriggered(MessageFilter):
1035            name = 'Filters.status_update.proximity_alert_triggered'
1036
1037            def filter(self, message: Message) -> bool:
1038                return bool(message.proximity_alert_triggered)
1039
1040        proximity_alert_triggered = _ProximityAlertTriggered()
1041        """Messages that contain :attr:`telegram.Message.proximity_alert_triggered`."""
1042
1043        name = 'Filters.status_update'
1044
1045        def filter(self, message: Update) -> bool:
1046            return bool(
1047                self.new_chat_members(message)
1048                or self.left_chat_member(message)
1049                or self.new_chat_title(message)
1050                or self.new_chat_photo(message)
1051                or self.delete_chat_photo(message)
1052                or self.chat_created(message)
1053                or self.migrate(message)
1054                or self.pinned_message(message)
1055                or self.connected_website(message)
1056                or self.proximity_alert_triggered(message)
1057            )
1058
1059    status_update = _StatusUpdate()
1060    """Subset for messages containing a status update.
1061
1062    Examples:
1063        Use these filters like: ``Filters.status_update.new_chat_members`` etc. Or use just
1064        ``Filters.status_update`` for all status update messages.
1065
1066    Attributes:
1067        chat_created: Messages that contain
1068            :attr:`telegram.Message.group_chat_created`,
1069            :attr:`telegram.Message.supergroup_chat_created` or
1070            :attr:`telegram.Message.channel_chat_created`.
1071        connected_website: Messages that contain
1072            :attr:`telegram.Message.connected_website`.
1073        delete_chat_photo: Messages that contain
1074            :attr:`telegram.Message.delete_chat_photo`.
1075        left_chat_member: Messages that contain
1076            :attr:`telegram.Message.left_chat_member`.
1077        migrate: Messages that contain
1078            :attr:`telegram.Message.migrate_from_chat_id` or
1079            :attr: `telegram.Message.migrate_from_chat_id`.
1080        new_chat_members: Messages that contain
1081            :attr:`telegram.Message.new_chat_members`.
1082        new_chat_photo: Messages that contain
1083            :attr:`telegram.Message.new_chat_photo`.
1084        new_chat_title: Messages that contain
1085            :attr:`telegram.Message.new_chat_title`.
1086        pinned_message: Messages that contain
1087            :attr:`telegram.Message.pinned_message`.
1088        proximity_alert_triggered: Messages that contain
1089            :attr:`telegram.Message.proximity_alert_triggered`.
1090    """
1091
1092    class _Forwarded(MessageFilter):
1093        name = 'Filters.forwarded'
1094
1095        def filter(self, message: Message) -> bool:
1096            return bool(message.forward_date)
1097
1098    forwarded = _Forwarded()
1099    """Messages that are forwarded."""
1100
1101    class _Game(MessageFilter):
1102        name = 'Filters.game'
1103
1104        def filter(self, message: Message) -> bool:
1105            return bool(message.game)
1106
1107    game = _Game()
1108    """Messages that contain :class:`telegram.Game`."""
1109
1110    class entity(MessageFilter):
1111        """
1112        Filters messages to only allow those which have a :class:`telegram.MessageEntity`
1113        where their `type` matches `entity_type`.
1114
1115        Examples:
1116            Example ``MessageHandler(Filters.entity("hashtag"), callback_method)``
1117
1118        Args:
1119            entity_type: Entity type to check for. All types can be found as constants
1120                in :class:`telegram.MessageEntity`.
1121
1122        """
1123
1124        def __init__(self, entity_type: str):
1125            self.entity_type = entity_type
1126            self.name = f'Filters.entity({self.entity_type})'
1127
1128        def filter(self, message: Message) -> bool:
1129            """"""  # remove method from docs
1130            return any(entity.type == self.entity_type for entity in message.entities)
1131
1132    class caption_entity(MessageFilter):
1133        """
1134        Filters media messages to only allow those which have a :class:`telegram.MessageEntity`
1135        where their `type` matches `entity_type`.
1136
1137        Examples:
1138            Example ``MessageHandler(Filters.caption_entity("hashtag"), callback_method)``
1139
1140        Args:
1141            entity_type: Caption Entity type to check for. All types can be found as constants
1142                in :class:`telegram.MessageEntity`.
1143
1144        """
1145
1146        def __init__(self, entity_type: str):
1147            self.entity_type = entity_type
1148            self.name = f'Filters.caption_entity({self.entity_type})'
1149
1150        def filter(self, message: Message) -> bool:
1151            """"""  # remove method from docs
1152            return any(entity.type == self.entity_type for entity in message.caption_entities)
1153
1154    class _Private(MessageFilter):
1155        name = 'Filters.private'
1156
1157        def filter(self, message: Message) -> bool:
1158            warnings.warn(
1159                'Filters.private is deprecated. Use Filters.chat_type.private instead.',
1160                TelegramDeprecationWarning,
1161                stacklevel=2,
1162            )
1163            return message.chat.type == Chat.PRIVATE
1164
1165    private = _Private()
1166    """
1167    Messages sent in a private chat.
1168
1169    Note:
1170        DEPRECATED. Use
1171        :attr:`telegram.ext.Filters.chat_type.private` instead.
1172    """
1173
1174    class _Group(MessageFilter):
1175        name = 'Filters.group'
1176
1177        def filter(self, message: Message) -> bool:
1178            warnings.warn(
1179                'Filters.group is deprecated. Use Filters.chat_type.groups instead.',
1180                TelegramDeprecationWarning,
1181                stacklevel=2,
1182            )
1183            return message.chat.type in [Chat.GROUP, Chat.SUPERGROUP]
1184
1185    group = _Group()
1186    """
1187    Messages sent in a group or a supergroup chat.
1188
1189    Note:
1190        DEPRECATED. Use
1191        :attr:`telegram.ext.Filters.chat_type.groups` instead.
1192    """
1193
1194    class _ChatType(MessageFilter):
1195        name = 'Filters.chat_type'
1196
1197        class _Channel(MessageFilter):
1198            name = 'Filters.chat_type.channel'
1199
1200            def filter(self, message: Message) -> bool:
1201                return message.chat.type == Chat.CHANNEL
1202
1203        channel = _Channel()
1204
1205        class _Group(MessageFilter):
1206            name = 'Filters.chat_type.group'
1207
1208            def filter(self, message: Message) -> bool:
1209                return message.chat.type == Chat.GROUP
1210
1211        group = _Group()
1212
1213        class _SuperGroup(MessageFilter):
1214            name = 'Filters.chat_type.supergroup'
1215
1216            def filter(self, message: Message) -> bool:
1217                return message.chat.type == Chat.SUPERGROUP
1218
1219        supergroup = _SuperGroup()
1220
1221        class _Groups(MessageFilter):
1222            name = 'Filters.chat_type.groups'
1223
1224            def filter(self, message: Message) -> bool:
1225                return message.chat.type in [Chat.GROUP, Chat.SUPERGROUP]
1226
1227        groups = _Groups()
1228
1229        class _Private(MessageFilter):
1230            name = 'Filters.chat_type.private'
1231
1232            def filter(self, message: Message) -> bool:
1233                return message.chat.type == Chat.PRIVATE
1234
1235        private = _Private()
1236
1237        def filter(self, message: Message) -> bool:
1238            return bool(message.chat.type)
1239
1240    chat_type = _ChatType()
1241    """Subset for filtering the type of chat.
1242
1243    Examples:
1244        Use these filters like: ``Filters.chat_type.channel`` or
1245        ``Filters.chat_type.supergroup`` etc. Or use just ``Filters.chat_type`` for all
1246        chat types.
1247
1248    Attributes:
1249        channel: Updates from channel
1250        group: Updates from group
1251        supergroup: Updates from supergroup
1252        groups: Updates from group *or* supergroup
1253        private: Updates sent in private chat
1254    """
1255
1256    class _ChatUserBaseFilter(MessageFilter):
1257        def __init__(
1258            self,
1259            chat_id: SLT[int] = None,
1260            username: SLT[str] = None,
1261            allow_empty: bool = False,
1262        ):
1263            self.chat_id_name = 'chat_id'
1264            self.username_name = 'username'
1265            self.allow_empty = allow_empty
1266            self.__lock = Lock()
1267
1268            self._chat_ids: Set[int] = set()
1269            self._usernames: Set[str] = set()
1270
1271            self._set_chat_ids(chat_id)
1272            self._set_usernames(username)
1273
1274        @abstractmethod
1275        def get_chat_or_user(self, message: Message) -> Union[Chat, User, None]:
1276            pass
1277
1278        @staticmethod
1279        def _parse_chat_id(chat_id: SLT[int]) -> Set[int]:
1280            if chat_id is None:
1281                return set()
1282            if isinstance(chat_id, int):
1283                return {chat_id}
1284            return set(chat_id)
1285
1286        @staticmethod
1287        def _parse_username(username: SLT[str]) -> Set[str]:
1288            if username is None:
1289                return set()
1290            if isinstance(username, str):
1291                return {username[1:] if username.startswith('@') else username}
1292            return {chat[1:] if chat.startswith('@') else chat for chat in username}
1293
1294        def _set_chat_ids(self, chat_id: SLT[int]) -> None:
1295            with self.__lock:
1296                if chat_id and self._usernames:
1297                    raise RuntimeError(
1298                        f"Can't set {self.chat_id_name} in conjunction with (already set) "
1299                        f"{self.username_name}s."
1300                    )
1301                self._chat_ids = self._parse_chat_id(chat_id)
1302
1303        def _set_usernames(self, username: SLT[str]) -> None:
1304            with self.__lock:
1305                if username and self._chat_ids:
1306                    raise RuntimeError(
1307                        f"Can't set {self.username_name} in conjunction with (already set) "
1308                        f"{self.chat_id_name}s."
1309                    )
1310                self._usernames = self._parse_username(username)
1311
1312        @property
1313        def chat_ids(self) -> FrozenSet[int]:
1314            with self.__lock:
1315                return frozenset(self._chat_ids)
1316
1317        @chat_ids.setter
1318        def chat_ids(self, chat_id: SLT[int]) -> None:
1319            self._set_chat_ids(chat_id)
1320
1321        @property
1322        def usernames(self) -> FrozenSet[str]:
1323            with self.__lock:
1324                return frozenset(self._usernames)
1325
1326        @usernames.setter
1327        def usernames(self, username: SLT[str]) -> None:
1328            self._set_usernames(username)
1329
1330        def add_usernames(self, username: SLT[str]) -> None:
1331            with self.__lock:
1332                if self._chat_ids:
1333                    raise RuntimeError(
1334                        f"Can't set {self.username_name} in conjunction with (already set) "
1335                        f"{self.chat_id_name}s."
1336                    )
1337
1338                parsed_username = self._parse_username(username)
1339                self._usernames |= parsed_username
1340
1341        def add_chat_ids(self, chat_id: SLT[int]) -> None:
1342            with self.__lock:
1343                if self._usernames:
1344                    raise RuntimeError(
1345                        f"Can't set {self.chat_id_name} in conjunction with (already set) "
1346                        f"{self.username_name}s."
1347                    )
1348
1349                parsed_chat_id = self._parse_chat_id(chat_id)
1350
1351                self._chat_ids |= parsed_chat_id
1352
1353        def remove_usernames(self, username: SLT[str]) -> None:
1354            with self.__lock:
1355                if self._chat_ids:
1356                    raise RuntimeError(
1357                        f"Can't set {self.username_name} in conjunction with (already set) "
1358                        f"{self.chat_id_name}s."
1359                    )
1360
1361                parsed_username = self._parse_username(username)
1362                self._usernames -= parsed_username
1363
1364        def remove_chat_ids(self, chat_id: SLT[int]) -> None:
1365            with self.__lock:
1366                if self._usernames:
1367                    raise RuntimeError(
1368                        f"Can't set {self.chat_id_name} in conjunction with (already set) "
1369                        f"{self.username_name}s."
1370                    )
1371                parsed_chat_id = self._parse_chat_id(chat_id)
1372                self._chat_ids -= parsed_chat_id
1373
1374        def filter(self, message: Message) -> bool:
1375            """"""  # remove method from docs
1376            chat_or_user = self.get_chat_or_user(message)
1377            if chat_or_user:
1378                if self.chat_ids:
1379                    return chat_or_user.id in self.chat_ids
1380                if self.usernames:
1381                    return bool(chat_or_user.username and chat_or_user.username in self.usernames)
1382                return self.allow_empty
1383            return False
1384
1385        @property
1386        def name(self) -> str:
1387            return (
1388                f'Filters.{self.__class__.__name__}('
1389                f'{", ".join(str(s) for s in (self.usernames or self.chat_ids))})'
1390            )
1391
1392        @name.setter
1393        def name(self, name: str) -> NoReturn:
1394            raise RuntimeError(f'Cannot set name for Filters.{self.__class__.__name__}')
1395
1396    class user(_ChatUserBaseFilter):
1397        # pylint: disable=W0235
1398        """Filters messages to allow only those which are from specified user ID(s) or
1399        username(s).
1400
1401        Examples:
1402            ``MessageHandler(Filters.user(1234), callback_method)``
1403
1404        Warning:
1405            :attr:`user_ids` will give a *copy* of the saved user ids as :class:`frozenset`. This
1406            is to ensure thread safety. To add/remove a user, you should use :meth:`add_usernames`,
1407            :meth:`add_user_ids`, :meth:`remove_usernames` and :meth:`remove_user_ids`. Only update
1408            the entire set by ``filter.user_ids/usernames = new_set``, if you are entirely sure
1409            that it is not causing race conditions, as this will complete replace the current set
1410            of allowed users.
1411
1412        Attributes:
1413            user_ids(set(:obj:`int`), optional): Which user ID(s) to allow through.
1414            usernames(set(:obj:`str`), optional): Which username(s) (without leading '@') to allow
1415                through.
1416            allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user
1417                is specified in :attr:`user_ids` and :attr:`usernames`.
1418
1419        Args:
1420            user_id(:class:`telegram.utils.types.SLT[int]`, optional):
1421                Which user ID(s) to allow through.
1422            username(:class:`telegram.utils.types.SLT[str]`, optional):
1423                Which username(s) to allow through. Leading '@'s in usernames will be discarded.
1424            allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user
1425                is specified in :attr:`user_ids` and :attr:`usernames`. Defaults to :obj:`False`
1426
1427        Raises:
1428            RuntimeError: If user_id and username are both present.
1429
1430        """
1431
1432        def __init__(
1433            self,
1434            user_id: SLT[int] = None,
1435            username: SLT[str] = None,
1436            allow_empty: bool = False,
1437        ):
1438            super().__init__(chat_id=user_id, username=username, allow_empty=allow_empty)
1439            self.chat_id_name = 'user_id'
1440
1441        def get_chat_or_user(self, message: Message) -> Optional[User]:
1442            return message.from_user
1443
1444        @property
1445        def user_ids(self) -> FrozenSet[int]:
1446            return self.chat_ids
1447
1448        @user_ids.setter
1449        def user_ids(self, user_id: SLT[int]) -> None:
1450            self.chat_ids = user_id  # type: ignore[assignment]
1451
1452        def add_usernames(self, username: SLT[str]) -> None:
1453            """
1454            Add one or more users to the allowed usernames.
1455
1456            Args:
1457                username(:class:`telegram.utils.types.SLT[str]`, optional):
1458                    Which username(s) to allow through.
1459                    Leading '@'s in usernames will be discarded.
1460            """
1461            return super().add_usernames(username)
1462
1463        def add_user_ids(self, user_id: SLT[int]) -> None:
1464            """
1465            Add one or more users to the allowed user ids.
1466
1467            Args:
1468                user_id(:class:`telegram.utils.types.SLT[int]`, optional):
1469                    Which user ID(s) to allow through.
1470            """
1471            return super().add_chat_ids(user_id)
1472
1473        def remove_usernames(self, username: SLT[str]) -> None:
1474            """
1475            Remove one or more users from allowed usernames.
1476
1477            Args:
1478                username(:class:`telegram.utils.types.SLT[str]`, optional):
1479                    Which username(s) to disallow through.
1480                    Leading '@'s in usernames will be discarded.
1481            """
1482            return super().remove_usernames(username)
1483
1484        def remove_user_ids(self, user_id: SLT[int]) -> None:
1485            """
1486            Remove one or more users from allowed user ids.
1487
1488            Args:
1489                user_id(:class:`telegram.utils.types.SLT[int]`, optional):
1490                    Which user ID(s) to disallow through.
1491            """
1492            return super().remove_chat_ids(user_id)
1493
1494    class via_bot(_ChatUserBaseFilter):
1495        # pylint: disable=W0235
1496        """Filters messages to allow only those which are from specified via_bot ID(s) or
1497        username(s).
1498
1499        Examples:
1500            ``MessageHandler(Filters.via_bot(1234), callback_method)``
1501
1502        Warning:
1503            :attr:`bot_ids` will give a *copy* of the saved bot ids as :class:`frozenset`. This
1504            is to ensure thread safety. To add/remove a bot, you should use :meth:`add_usernames`,
1505            :meth:`add_bot_ids`, :meth:`remove_usernames` and :meth:`remove_bot_ids`. Only update
1506            the entire set by ``filter.bot_ids/usernames = new_set``, if you are entirely sure
1507            that it is not causing race conditions, as this will complete replace the current set
1508            of allowed bots.
1509
1510        Attributes:
1511            bot_ids(set(:obj:`int`), optional): Which bot ID(s) to allow through.
1512            usernames(set(:obj:`str`), optional): Which username(s) (without leading '@') to allow
1513                through.
1514            allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no bot
1515                is specified in :attr:`bot_ids` and :attr:`usernames`.
1516
1517        Args:
1518            bot_id(:class:`telegram.utils.types.SLT[int]`, optional):
1519                Which bot ID(s) to allow through.
1520            username(:class:`telegram.utils.types.SLT[str]`, optional):
1521                Which username(s) to allow through. Leading '@'s in usernames will be discarded.
1522            allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user
1523                is specified in :attr:`bot_ids` and :attr:`usernames`. Defaults to :obj:`False`
1524
1525        Raises:
1526            RuntimeError: If bot_id and username are both present.
1527        """
1528
1529        def __init__(
1530            self,
1531            bot_id: SLT[int] = None,
1532            username: SLT[str] = None,
1533            allow_empty: bool = False,
1534        ):
1535            super().__init__(chat_id=bot_id, username=username, allow_empty=allow_empty)
1536            self.chat_id_name = 'bot_id'
1537
1538        def get_chat_or_user(self, message: Message) -> Optional[User]:
1539            return message.via_bot
1540
1541        @property
1542        def bot_ids(self) -> FrozenSet[int]:
1543            return self.chat_ids
1544
1545        @bot_ids.setter
1546        def bot_ids(self, bot_id: SLT[int]) -> None:
1547            self.chat_ids = bot_id  # type: ignore[assignment]
1548
1549        def add_usernames(self, username: SLT[str]) -> None:
1550            """
1551            Add one or more users to the allowed usernames.
1552
1553            Args:
1554                username(:class:`telegram.utils.types.SLT[str]`, optional):
1555                    Which username(s) to allow through.
1556                    Leading '@'s in usernames will be discarded.
1557            """
1558            return super().add_usernames(username)
1559
1560        def add_bot_ids(self, bot_id: SLT[int]) -> None:
1561            """
1562
1563            Add one or more users to the allowed user ids.
1564
1565            Args:
1566                bot_id(:class:`telegram.utils.types.SLT[int]`, optional):
1567                    Which bot ID(s) to allow through.
1568            """
1569            return super().add_chat_ids(bot_id)
1570
1571        def remove_usernames(self, username: SLT[str]) -> None:
1572            """
1573            Remove one or more users from allowed usernames.
1574
1575            Args:
1576                username(:class:`telegram.utils.types.SLT[str]`, optional):
1577                    Which username(s) to disallow through.
1578                    Leading '@'s in usernames will be discarded.
1579            """
1580            return super().remove_usernames(username)
1581
1582        def remove_bot_ids(self, bot_id: SLT[int]) -> None:
1583            """
1584            Remove one or more users from allowed user ids.
1585
1586            Args:
1587                bot_id(:class:`telegram.utils.types.SLT[int]`, optional):
1588                    Which bot ID(s) to disallow through.
1589            """
1590            return super().remove_chat_ids(bot_id)
1591
1592    class chat(_ChatUserBaseFilter):
1593        # pylint: disable=W0235
1594        """Filters messages to allow only those which are from a specified chat ID or username.
1595
1596        Examples:
1597            ``MessageHandler(Filters.chat(-1234), callback_method)``
1598
1599        Warning:
1600            :attr:`chat_ids` will give a *copy* of the saved chat ids as :class:`frozenset`. This
1601            is to ensure thread safety. To add/remove a chat, you should use :meth:`add_usernames`,
1602            :meth:`add_chat_ids`, :meth:`remove_usernames` and :meth:`remove_chat_ids`. Only update
1603            the entire set by ``filter.chat_ids/usernames = new_set``, if you are entirely sure
1604            that it is not causing race conditions, as this will complete replace the current set
1605            of allowed chats.
1606
1607        Attributes:
1608            chat_ids(set(:obj:`int`), optional): Which chat ID(s) to allow through.
1609            usernames(set(:obj:`str`), optional): Which username(s) (without leading '@') to allow
1610                through.
1611            allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat
1612                is specified in :attr:`chat_ids` and :attr:`usernames`.
1613
1614        Args:
1615            chat_id(:class:`telegram.utils.types.SLT[int]`, optional):
1616                Which chat ID(s) to allow through.
1617            username(:class:`telegram.utils.types.SLT[str]`, optional):
1618                Which username(s) to allow through.
1619                Leading `'@'` s in usernames will be discarded.
1620            allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat
1621                is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to :obj:`False`
1622
1623        Raises:
1624            RuntimeError: If chat_id and username are both present.
1625
1626        """
1627
1628        def get_chat_or_user(self, message: Message) -> Optional[Chat]:
1629            return message.chat
1630
1631        def add_usernames(self, username: SLT[str]) -> None:
1632            """
1633            Add one or more chats to the allowed usernames.
1634
1635            Args:
1636                username(:class:`telegram.utils.types.SLT[str]`, optional):
1637                    Which username(s) to allow through.
1638                    Leading `'@'` s in usernames will be discarded.
1639            """
1640            return super().add_usernames(username)
1641
1642        def add_chat_ids(self, chat_id: SLT[int]) -> None:
1643            """
1644            Add one or more chats to the allowed chat ids.
1645
1646            Args:
1647                chat_id(:class:`telegram.utils.types.SLT[int]`, optional):
1648                    Which chat ID(s) to allow through.
1649            """
1650            return super().add_chat_ids(chat_id)
1651
1652        def remove_usernames(self, username: SLT[str]) -> None:
1653            """
1654            Remove one or more chats from allowed usernames.
1655
1656            Args:
1657                username(:class:`telegram.utils.types.SLT[str]`, optional):
1658                    Which username(s) to disallow through.
1659                    Leading '@'s in usernames will be discarded.
1660            """
1661            return super().remove_usernames(username)
1662
1663        def remove_chat_ids(self, chat_id: SLT[int]) -> None:
1664            """
1665            Remove one or more chats from allowed chat ids.
1666
1667            Args:
1668                chat_id(:class:`telegram.utils.types.SLT[int]`, optional):
1669                    Which chat ID(s) to disallow through.
1670            """
1671            return super().remove_chat_ids(chat_id)
1672
1673    class sender_chat(_ChatUserBaseFilter):
1674        # pylint: disable=W0235
1675        """Filters messages to allow only those which are from a specified sender chats chat ID or
1676        username.
1677
1678        Examples:
1679            * To filter for messages forwarded from a channel with ID ``-1234``, use
1680              ``MessageHandler(Filters.sender_chat(-1234), callback_method)``.
1681            * To filter for messages of anonymous admins in a super group with username
1682              ``@anonymous``, use
1683              ``MessageHandler(Filters.sender_chat(username='anonymous'), callback_method)``.
1684            * To filter for messages forwarded from *any* channel, use
1685              ``MessageHandler(Filters.sender_chat.channel, callback_method)``.
1686            * To filter for messages of anonymous admins in *any* super group, use
1687              ``MessageHandler(Filters.sender_chat.super_group, callback_method)``.
1688
1689        Warning:
1690            :attr:`chat_ids` will return a *copy* of the saved chat ids as :class:`frozenset`. This
1691            is to ensure thread safety. To add/remove a chat, you should use :meth:`add_usernames`,
1692            :meth:`add_chat_ids`, :meth:`remove_usernames` and :meth:`remove_chat_ids`. Only update
1693            the entire set by ``filter.chat_ids/usernames = new_set``, if you are entirely sure
1694            that it is not causing race conditions, as this will complete replace the current set
1695            of allowed chats.
1696
1697        Attributes:
1698            chat_ids(set(:obj:`int`), optional): Which sender chat chat ID(s) to allow through.
1699            usernames(set(:obj:`str`), optional): Which sender chat username(s) (without leading
1700                '@') to allow through.
1701            allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no sender
1702                chat is specified in :attr:`chat_ids` and :attr:`usernames`.
1703            super_group: Messages whose sender chat is a super group.
1704
1705                Examples:
1706                    ``Filters.sender_chat.supergroup``
1707            channel: Messages whose sender chat is a channel.
1708
1709                Examples:
1710                    ``Filters.sender_chat.channel``
1711
1712        Args:
1713            chat_id(:class:`telegram.utils.types.SLT[int]`, optional):
1714                Which sender chat chat ID(s) to allow through.
1715            username(:class:`telegram.utils.types.SLT[str]`, optional):
1716                Which sender chat sername(s) to allow through.
1717                Leading `'@'` s in usernames will be discarded.
1718            allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no sender
1719                chat is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to
1720                :obj:`False`
1721
1722        Raises:
1723            RuntimeError: If chat_id and username are both present.
1724
1725        """
1726
1727        def get_chat_or_user(self, message: Message) -> Optional[Chat]:
1728            return message.sender_chat
1729
1730        def add_usernames(self, username: SLT[str]) -> None:
1731            """
1732            Add one or more sender chats to the allowed usernames.
1733
1734            Args:
1735                username(:class:`telegram.utils.types.SLT[str]`, optional):
1736                    Which sender chat username(s) to allow through.
1737                    Leading `'@'` s in usernames will be discarded.
1738            """
1739            return super().add_usernames(username)
1740
1741        def add_chat_ids(self, chat_id: SLT[int]) -> None:
1742            """
1743            Add one or more sender chats to the allowed chat ids.
1744
1745            Args:
1746                chat_id(:class:`telegram.utils.types.SLT[int]`, optional):
1747                    Which sender chat ID(s) to allow through.
1748            """
1749            return super().add_chat_ids(chat_id)
1750
1751        def remove_usernames(self, username: SLT[str]) -> None:
1752            """
1753            Remove one or more sender chats from allowed usernames.
1754
1755            Args:
1756                username(:class:`telegram.utils.types.SLT[str]`, optional):
1757                    Which sender chat username(s) to disallow through.
1758                    Leading '@'s in usernames will be discarded.
1759            """
1760            return super().remove_usernames(username)
1761
1762        def remove_chat_ids(self, chat_id: SLT[int]) -> None:
1763            """
1764            Remove one or more sender chats from allowed chat ids.
1765
1766            Args:
1767                chat_id(:class:`telegram.utils.types.SLT[int]`, optional):
1768                    Which sender chat ID(s) to disallow through.
1769            """
1770            return super().remove_chat_ids(chat_id)
1771
1772        class _SuperGroup(MessageFilter):
1773            def filter(self, message: Message) -> bool:
1774                if message.sender_chat:
1775                    return message.sender_chat.type == Chat.SUPERGROUP
1776                return False
1777
1778        class _Channel(MessageFilter):
1779            def filter(self, message: Message) -> bool:
1780                if message.sender_chat:
1781                    return message.sender_chat.type == Chat.CHANNEL
1782                return False
1783
1784        super_group = _SuperGroup()
1785        channel = _Channel()
1786
1787    class _Invoice(MessageFilter):
1788        name = 'Filters.invoice'
1789
1790        def filter(self, message: Message) -> bool:
1791            return bool(message.invoice)
1792
1793    invoice = _Invoice()
1794    """Messages that contain :class:`telegram.Invoice`."""
1795
1796    class _SuccessfulPayment(MessageFilter):
1797        name = 'Filters.successful_payment'
1798
1799        def filter(self, message: Message) -> bool:
1800            return bool(message.successful_payment)
1801
1802    successful_payment = _SuccessfulPayment()
1803    """Messages that confirm a :class:`telegram.SuccessfulPayment`."""
1804
1805    class _PassportData(MessageFilter):
1806        name = 'Filters.passport_data'
1807
1808        def filter(self, message: Message) -> bool:
1809            return bool(message.passport_data)
1810
1811    passport_data = _PassportData()
1812    """Messages that contain a :class:`telegram.PassportData`"""
1813
1814    class _Poll(MessageFilter):
1815        name = 'Filters.poll'
1816
1817        def filter(self, message: Message) -> bool:
1818            return bool(message.poll)
1819
1820    poll = _Poll()
1821    """Messages that contain a :class:`telegram.Poll`."""
1822
1823    class _Dice(_DiceEmoji):
1824        dice = _DiceEmoji('��', 'dice')
1825        darts = _DiceEmoji('��', 'darts')
1826        basketball = _DiceEmoji('��', 'basketball')
1827        football = _DiceEmoji('⚽')
1828        slot_machine = _DiceEmoji('��')
1829
1830    dice = _Dice()
1831    """Dice Messages. If an integer or a list of integers is passed, it filters messages to only
1832    allow those whose dice value is appearing in the given list.
1833
1834    Examples:
1835        To allow any dice message, simply use
1836        ``MessageHandler(Filters.dice, callback_method)``.
1837        To allow only dice with value 6, use
1838        ``MessageHandler(Filters.dice(6), callback_method)``.
1839        To allow only dice with value 5 `or` 6, use
1840        ``MessageHandler(Filters.dice([5, 6]), callback_method)``.
1841
1842    Args:
1843        update (:class:`telegram.utils.types.SLT[int]`, optional):
1844            Which values to allow. If not specified, will allow any dice message.
1845
1846    Note:
1847        Dice messages don't have text. If you want to filter either text or dice messages, use
1848        ``Filters.text | Filters.dice``.
1849
1850    Attributes:
1851        dice: Dice messages with the emoji ��. Passing a list of integers is supported just as for
1852            :attr:`Filters.dice`.
1853        darts: Dice messages with the emoji ��. Passing a list of integers is supported just as for
1854            :attr:`Filters.dice`.
1855        basketball: Dice messages with the emoji ��. Passing a list of integers is supported just
1856            as for :attr:`Filters.dice`.
1857        football: Dice messages with the emoji ⚽. Passing a list of integers is supported just
1858            as for :attr:`Filters.dice`.
1859        slot_machine: Dice messages with the emoji ��. Passing a list of integers is supported just
1860            as for :attr:`Filters.dice`.
1861    """
1862
1863    class language(MessageFilter):
1864        """Filters messages to only allow those which are from users with a certain language code.
1865
1866        Note:
1867            According to official Telegram API documentation, not every single user has the
1868            `language_code` attribute. Do not count on this filter working on all users.
1869
1870        Examples:
1871            ``MessageHandler(Filters.language("en"), callback_method)``
1872
1873        Args:
1874            lang (:class:`telegram.utils.types.SLT[str]`):
1875                Which language code(s) to allow through.
1876                This will be matched using ``.startswith`` meaning that
1877                'en' will match both 'en_US' and 'en_GB'.
1878
1879        """
1880
1881        def __init__(self, lang: SLT[str]):
1882            if isinstance(lang, str):
1883                lang = cast(str, lang)
1884                self.lang = [lang]
1885            else:
1886                lang = cast(List[str], lang)
1887                self.lang = lang
1888            self.name = f'Filters.language({self.lang})'
1889
1890        def filter(self, message: Message) -> bool:
1891            """"""  # remove method from docs
1892            return bool(
1893                message.from_user.language_code
1894                and any([message.from_user.language_code.startswith(x) for x in self.lang])
1895            )
1896
1897    class _UpdateType(UpdateFilter):
1898        name = 'Filters.update'
1899
1900        class _Message(UpdateFilter):
1901            name = 'Filters.update.message'
1902
1903            def filter(self, update: Update) -> bool:
1904                return update.message is not None
1905
1906        message = _Message()
1907
1908        class _EditedMessage(UpdateFilter):
1909            name = 'Filters.update.edited_message'
1910
1911            def filter(self, update: Update) -> bool:
1912                return update.edited_message is not None
1913
1914        edited_message = _EditedMessage()
1915
1916        class _Messages(UpdateFilter):
1917            name = 'Filters.update.messages'
1918
1919            def filter(self, update: Update) -> bool:
1920                return update.message is not None or update.edited_message is not None
1921
1922        messages = _Messages()
1923
1924        class _ChannelPost(UpdateFilter):
1925            name = 'Filters.update.channel_post'
1926
1927            def filter(self, update: Update) -> bool:
1928                return update.channel_post is not None
1929
1930        channel_post = _ChannelPost()
1931
1932        class _EditedChannelPost(UpdateFilter):
1933            name = 'Filters.update.edited_channel_post'
1934
1935            def filter(self, update: Update) -> bool:
1936                return update.edited_channel_post is not None
1937
1938        edited_channel_post = _EditedChannelPost()
1939
1940        class _ChannelPosts(UpdateFilter):
1941            name = 'Filters.update.channel_posts'
1942
1943            def filter(self, update: Update) -> bool:
1944                return update.channel_post is not None or update.edited_channel_post is not None
1945
1946        channel_posts = _ChannelPosts()
1947
1948        def filter(self, update: Update) -> bool:
1949            return bool(self.messages(update) or self.channel_posts(update))
1950
1951    update = _UpdateType()
1952    """Subset for filtering the type of update.
1953
1954    Examples:
1955        Use these filters like: ``Filters.update.message`` or
1956        ``Filters.update.channel_posts`` etc. Or use just ``Filters.update`` for all
1957        types.
1958
1959    Attributes:
1960        message: Updates with :attr:`telegram.Update.message`
1961        edited_message: Updates with :attr:`telegram.Update.edited_message`
1962        messages: Updates with either :attr:`telegram.Update.message` or
1963            :attr:`telegram.Update.edited_message`
1964        channel_post: Updates with :attr:`telegram.Update.channel_post`
1965        edited_channel_post: Updates with
1966            :attr:`telegram.Update.edited_channel_post`
1967        channel_posts: Updates with either :attr:`telegram.Update.channel_post` or
1968            :attr:`telegram.Update.edited_channel_post`
1969    """
1970