Expand Type Hints to Tuples (#2167)

Co-authored-by: Pranjalya <pranjalyawarrior@gmail.com>
This commit is contained in:
Evgeny Denisov 2020-11-07 10:26:32 +03:00 committed by GitHub
parent ac449deb5d
commit 27b03edc59
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 119 additions and 99 deletions

View file

@ -79,6 +79,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `Paul Larsen <https://github.com/PaulSonOfLars>`_
- `Pieter Schutz <https://github.com/eldinnie>`_
- `Poolitzer <https://github.com/Poolitzer>`_
- `Pranjalya Tiwari <https://github.com/Pranjalya>`_
- `Rahiel Kasim <https://github.com/rahiel>`_
- `Riko Naka <https://github.com/rikonaka>`_
- `Rizlas <https://github.com/rizlas>`_

View file

@ -24,7 +24,7 @@ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Ty
from telegram import MessageEntity, Update
from telegram.ext import BaseFilter, Filters
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram.utils.types import HandlerArg
from telegram.utils.types import HandlerArg, SLT
from .handler import Handler
@ -49,9 +49,9 @@ class CommandHandler(Handler):
:class:`telegram.ext.CommandHandler` does *not* handle (edited) channel posts.
Attributes:
command (:obj:`str` | List[:obj:`str`]): The command or list of commands this handler
should listen for. Limitations are the same as described here
https://core.telegram.org/bots#commands
command (:class:`telegram.utils.types.SLT[str]`):
The command or list of commands this handler should listen for.
Limitations are the same as described here https://core.telegram.org/bots#commands
callback (:obj:`callable`): The callback function for this handler.
filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these
Filters.
@ -83,9 +83,9 @@ class CommandHandler(Handler):
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
Args:
command (:obj:`str` | List[:obj:`str`]): The command or list of commands this handler
should listen for. Limitations are the same as described here
https://core.telegram.org/bots#commands
command (:class:`telegram.utils.types.SLT[str]`):
The command or list of commands this handler should listen for.
Limitations are the same as described here https://core.telegram.org/bots#commands
callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API:
@ -132,7 +132,7 @@ class CommandHandler(Handler):
def __init__(
self,
command: Union[str, List[str]],
command: SLT[str],
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
filters: BaseFilter = None,
allow_edited: bool = None,
@ -297,9 +297,10 @@ class PrefixHandler(CommandHandler):
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
Args:
prefix (:obj:`str` | List[:obj:`str`]): The prefix(es) that will precede :attr:`command`.
command (:obj:`str` | List[:obj:`str`]): The command or list of commands this handler
should listen for.
prefix (:class:`telegram.utils.types.SLT[str]`):
The prefix(es) that will precede :attr:`command`.
command (:class:`telegram.utils.types.SLT[str]`):
The command or list of commands this handler should listen for.
callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API:
@ -340,8 +341,8 @@ class PrefixHandler(CommandHandler):
def __init__(
self,
prefix: Union[str, List[str]],
command: Union[str, List[str]],
prefix: SLT[str],
command: SLT[str],
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
filters: BaseFilter = None,
pass_args: bool = False,

View file

@ -24,7 +24,7 @@ import warnings
from abc import ABC, abstractmethod
from threading import Lock
from typing import Dict, FrozenSet, List, Match, Optional, Pattern, Set, Union, cast
from typing import Dict, FrozenSet, List, Match, Optional, Pattern, Set, Tuple, Union, cast
from telegram import Chat, Message, MessageEntity, Update
@ -38,6 +38,7 @@ __all__ = [
]
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram.utils.types import SLT
class BaseFilter(ABC):
@ -280,7 +281,12 @@ class _DiceEmoji(MessageFilter):
self.emoji = emoji
class _DiceValues(MessageFilter):
def __init__(self, values: Union[int, List[int]], name: str, emoji: str = None):
def __init__(
self,
values: SLT[int],
name: str,
emoji: str = None,
):
self.values = [values] if isinstance(values, int) else values
self.emoji = emoji
self.name = '{}({})'.format(name, values)
@ -293,7 +299,7 @@ class _DiceEmoji(MessageFilter):
return False
def __call__( # type: ignore[override]
self, update: Union[Update, List[int]]
self, update: Union[Update, List[int], Tuple[int]]
) -> Union[bool, '_DiceValues']:
if isinstance(update, Update):
return self.filter(update.effective_message)
@ -330,7 +336,7 @@ class Filters:
name = 'Filters.text'
class _TextStrings(MessageFilter):
def __init__(self, strings: List[str]):
def __init__(self, strings: Union[List[str], Tuple[str]]):
self.strings = strings
self.name = 'Filters.text({})'.format(strings)
@ -340,7 +346,7 @@ class Filters:
return False
def __call__( # type: ignore[override]
self, update: Union[Update, List[str]]
self, update: Union[Update, List[str], Tuple[str]]
) -> Union[bool, '_TextStrings']:
if isinstance(update, Update):
return self.filter(update.effective_message)
@ -381,7 +387,7 @@ class Filters:
name = 'Filters.caption'
class _CaptionStrings(MessageFilter):
def __init__(self, strings: List[str]):
def __init__(self, strings: Union[List[str], Tuple[str]]):
self.strings = strings
self.name = 'Filters.caption({})'.format(strings)
@ -391,7 +397,7 @@ class Filters:
return False
def __call__( # type: ignore[override]
self, update: Union[Update, List[str]]
self, update: Union[Update, List[str], Tuple[str]]
) -> Union[bool, '_CaptionStrings']:
if isinstance(update, Update):
return self.filter(update.effective_message)
@ -1190,10 +1196,10 @@ officedocument.wordprocessingml.document")``-
is specified in :attr:`user_ids` and :attr:`usernames`.
Args:
user_id(:obj:`int` | List[:obj:`int`], optional): Which user ID(s) to allow
through.
username(:obj:`str` | List[:obj:`str`], optional): Which username(s) to allow
through. Leading '@'s in usernames will be discarded.
user_id(:class:`telegram.utils.types.SLT[int]`, optional):
Which user ID(s) to allow through.
username(:class:`telegram.utils.types.SLT[str]`, optional):
Which username(s) to allow through. Leading '@'s in usernames will be discarded.
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user
is specified in :attr:`user_ids` and :attr:`usernames`. Defaults to :obj:`False`
@ -1204,8 +1210,8 @@ officedocument.wordprocessingml.document")``-
def __init__(
self,
user_id: Union[int, List[int]] = None,
username: Union[str, List[str]] = None,
user_id: SLT[int] = None,
username: SLT[str] = None,
allow_empty: bool = False,
):
self.allow_empty = allow_empty
@ -1218,7 +1224,7 @@ officedocument.wordprocessingml.document")``-
self._set_usernames(username)
@staticmethod
def _parse_user_id(user_id: Union[int, List[int]]) -> Set[int]:
def _parse_user_id(user_id: SLT[int]) -> Set[int]:
if user_id is None:
return set()
if isinstance(user_id, int):
@ -1226,14 +1232,14 @@ officedocument.wordprocessingml.document")``-
return set(user_id)
@staticmethod
def _parse_username(username: Union[str, List[str]]) -> Set[str]:
def _parse_username(username: SLT[str]) -> Set[str]:
if username is None:
return set()
if isinstance(username, str):
return {username[1:] if username.startswith('@') else username}
return {user[1:] if user.startswith('@') else user for user in username}
def _set_user_ids(self, user_id: Union[int, List[int]]) -> None:
def _set_user_ids(self, user_id: SLT[int]) -> None:
with self.__lock:
if user_id and self._usernames:
raise RuntimeError(
@ -1241,7 +1247,7 @@ officedocument.wordprocessingml.document")``-
)
self._user_ids = self._parse_user_id(user_id)
def _set_usernames(self, username: Union[str, List[str]]) -> None:
def _set_usernames(self, username: SLT[str]) -> None:
with self.__lock:
if username and self._user_ids:
raise RuntimeError(
@ -1255,7 +1261,7 @@ officedocument.wordprocessingml.document")``-
return frozenset(self._user_ids)
@user_ids.setter
def user_ids(self, user_id: Union[int, List[int]]) -> None:
def user_ids(self, user_id: SLT[int]) -> None:
self._set_user_ids(user_id)
@property
@ -1264,16 +1270,17 @@ officedocument.wordprocessingml.document")``-
return frozenset(self._usernames)
@usernames.setter
def usernames(self, username: Union[str, List[str]]) -> None:
def usernames(self, username: SLT[str]) -> None:
self._set_usernames(username)
def add_usernames(self, username: Union[str, List[str]]) -> None:
def add_usernames(self, username: SLT[str]) -> None:
"""
Add one or more users to the allowed usernames.
Args:
username(:obj:`str` | List[:obj:`str`], optional): Which username(s) to allow
through. Leading '@'s in usernames will be discarded.
username(:class:`telegram.utils.types.SLT[str]`, optional):
Which username(s) to allow through.
Leading '@'s in usernames will be discarded.
"""
with self.__lock:
if self._user_ids:
@ -1284,13 +1291,13 @@ officedocument.wordprocessingml.document")``-
parsed_username = self._parse_username(username)
self._usernames |= parsed_username
def add_user_ids(self, user_id: Union[int, List[int]]) -> None:
def add_user_ids(self, user_id: SLT[int]) -> None:
"""
Add one or more users to the allowed user ids.
Args:
user_id(:obj:`int` | List[:obj:`int`], optional): Which user ID(s) to allow
through.
user_id(:class:`telegram.utils.types.SLT[int]`, optional):
Which user ID(s) to allow through.
"""
with self.__lock:
if self._usernames:
@ -1302,13 +1309,14 @@ officedocument.wordprocessingml.document")``-
self._user_ids |= parsed_user_id
def remove_usernames(self, username: Union[str, List[str]]) -> None:
def remove_usernames(self, username: SLT[str]) -> None:
"""
Remove one or more users from allowed usernames.
Args:
username(:obj:`str` | List[:obj:`str`], optional): Which username(s) to disallow
through. Leading '@'s in usernames will be discarded.
username(:class:`telegram.utils.types.SLT[str]`, optional):
Which username(s) to disallow through.
Leading '@'s in usernames will be discarded.
"""
with self.__lock:
if self._user_ids:
@ -1319,13 +1327,13 @@ officedocument.wordprocessingml.document")``-
parsed_username = self._parse_username(username)
self._usernames -= parsed_username
def remove_user_ids(self, user_id: Union[int, List[int]]) -> None:
def remove_user_ids(self, user_id: SLT[int]) -> None:
"""
Remove one or more users from allowed user ids.
Args:
user_id(:obj:`int` | List[:obj:`int`], optional): Which user ID(s) to disallow
through.
user_id(:class:`telegram.utils.types.SLT[int]`, optional):
Which user ID(s) to disallow through.
"""
with self.__lock:
if self._usernames:
@ -1370,10 +1378,10 @@ officedocument.wordprocessingml.document")``-
is specified in :attr:`bot_ids` and :attr:`usernames`.
Args:
bot_id(:obj:`int` | List[:obj:`int`], optional): Which bot ID(s) to allow
through.
username(:obj:`str` | List[:obj:`str`], optional): Which username(s) to allow
through. Leading '@'s in usernames will be discarded.
bot_id(:class:`telegram.utils.types.SLT[int]`, optional):
Which bot ID(s) to allow through.
username(:class:`telegram.utils.types.SLT[str]`, optional):
Which username(s) to allow through. Leading '@'s in usernames will be discarded.
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user
is specified in :attr:`bot_ids` and :attr:`usernames`. Defaults to :obj:`False`
@ -1383,8 +1391,8 @@ officedocument.wordprocessingml.document")``-
def __init__(
self,
bot_id: Union[int, List[int]] = None,
username: Union[str, List[str]] = None,
bot_id: SLT[int] = None,
username: SLT[str] = None,
allow_empty: bool = False,
):
self.allow_empty = allow_empty
@ -1397,7 +1405,7 @@ officedocument.wordprocessingml.document")``-
self._set_usernames(username)
@staticmethod
def _parse_bot_id(bot_id: Union[int, List[int]]) -> Set[int]:
def _parse_bot_id(bot_id: SLT[int]) -> Set[int]:
if bot_id is None:
return set()
if isinstance(bot_id, int):
@ -1405,14 +1413,14 @@ officedocument.wordprocessingml.document")``-
return set(bot_id)
@staticmethod
def _parse_username(username: Union[str, List[str]]) -> Set[str]:
def _parse_username(username: SLT[str]) -> Set[str]:
if username is None:
return set()
if isinstance(username, str):
return {username[1:] if username.startswith('@') else username}
return {bot[1:] if bot.startswith('@') else bot for bot in username}
def _set_bot_ids(self, bot_id: Union[int, List[int]]) -> None:
def _set_bot_ids(self, bot_id: SLT[int]) -> None:
with self.__lock:
if bot_id and self._usernames:
raise RuntimeError(
@ -1420,7 +1428,7 @@ officedocument.wordprocessingml.document")``-
)
self._bot_ids = self._parse_bot_id(bot_id)
def _set_usernames(self, username: Union[str, List[str]]) -> None:
def _set_usernames(self, username: SLT[str]) -> None:
with self.__lock:
if username and self._bot_ids:
raise RuntimeError(
@ -1434,7 +1442,7 @@ officedocument.wordprocessingml.document")``-
return frozenset(self._bot_ids)
@bot_ids.setter
def bot_ids(self, bot_id: Union[int, List[int]]) -> None:
def bot_ids(self, bot_id: SLT[int]) -> None:
self._set_bot_ids(bot_id)
@property
@ -1443,16 +1451,17 @@ officedocument.wordprocessingml.document")``-
return frozenset(self._usernames)
@usernames.setter
def usernames(self, username: Union[str, List[str]]) -> None:
def usernames(self, username: SLT[str]) -> None:
self._set_usernames(username)
def add_usernames(self, username: Union[str, List[str]]) -> None:
def add_usernames(self, username: SLT[str]) -> None:
"""
Add one or more users to the allowed usernames.
Args:
username(:obj:`str` | List[:obj:`str`], optional): Which username(s) to allow
through. Leading '@'s in usernames will be discarded.
username(:class:`telegram.utils.types.SLT[str]`, optional):
Which username(s) to allow through.
Leading '@'s in usernames will be discarded.
"""
with self.__lock:
if self._bot_ids:
@ -1463,14 +1472,14 @@ officedocument.wordprocessingml.document")``-
parsed_username = self._parse_username(username)
self._usernames |= parsed_username
def add_bot_ids(self, bot_id: Union[int, List[int]]) -> None:
def add_bot_ids(self, bot_id: SLT[int]) -> None:
"""
Add one or more users to the allowed user ids.
Args:
bot_id(:obj:`int` | List[:obj:`int`], optional): Which bot ID(s) to allow
through.
bot_id(:class:`telegram.utils.types.SLT[int]`, optional):
Which bot ID(s) to allow through.
"""
with self.__lock:
if self._usernames:
@ -1482,13 +1491,14 @@ officedocument.wordprocessingml.document")``-
self._bot_ids |= parsed_bot_id
def remove_usernames(self, username: Union[str, List[str]]) -> None:
def remove_usernames(self, username: SLT[str]) -> None:
"""
Remove one or more users from allowed usernames.
Args:
username(:obj:`str` | List[:obj:`str`], optional): Which username(s) to disallow
through. Leading '@'s in usernames will be discarded.
username(:class:`telegram.utils.types.SLT[str]`, optional):
Which username(s) to disallow through.
Leading '@'s in usernames will be discarded.
"""
with self.__lock:
if self._bot_ids:
@ -1499,13 +1509,13 @@ officedocument.wordprocessingml.document")``-
parsed_username = self._parse_username(username)
self._usernames -= parsed_username
def remove_bot_ids(self, bot_id: Union[int, List[int]]) -> None:
def remove_bot_ids(self, bot_id: SLT[int]) -> None:
"""
Remove one or more users from allowed user ids.
Args:
bot_id(:obj:`int` | List[:obj:`int`], optional): Which bot ID(s) to disallow
through.
bot_id(:class:`telegram.utils.types.SLT[int]`, optional):
Which bot ID(s) to disallow through.
"""
with self.__lock:
if self._usernames:
@ -1549,10 +1559,11 @@ officedocument.wordprocessingml.document")``-
is specified in :attr:`chat_ids` and :attr:`usernames`.
Args:
chat_id(:obj:`int` | List[:obj:`int`], optional): Which chat ID(s) to allow
through.
username(:obj:`str` | List[:obj:`str`], optional): Which username(s) to allow
through. Leading `'@'` s in usernames will be discarded.
chat_id(:class:`telegram.utils.types.SLT[int]`, optional):
Which chat ID(s) to allow through.
username(:class:`telegram.utils.types.SLT[str]`, optional):
Which username(s) to allow through.
Leading `'@'` s in usernames will be discarded.
allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat
is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to :obj:`False`
@ -1563,8 +1574,8 @@ officedocument.wordprocessingml.document")``-
def __init__(
self,
chat_id: Union[int, List[int]] = None,
username: Union[str, List[str]] = None,
chat_id: SLT[int] = None,
username: SLT[str] = None,
allow_empty: bool = False,
):
self.allow_empty = allow_empty
@ -1577,7 +1588,7 @@ officedocument.wordprocessingml.document")``-
self._set_usernames(username)
@staticmethod
def _parse_chat_id(chat_id: Union[int, List[int]]) -> Set[int]:
def _parse_chat_id(chat_id: SLT[int]) -> Set[int]:
if chat_id is None:
return set()
if isinstance(chat_id, int):
@ -1585,14 +1596,14 @@ officedocument.wordprocessingml.document")``-
return set(chat_id)
@staticmethod
def _parse_username(username: Union[str, List[str]]) -> Set[str]:
def _parse_username(username: SLT[str]) -> Set[str]:
if username is None:
return set()
if isinstance(username, str):
return {username[1:] if username.startswith('@') else username}
return {chat[1:] if chat.startswith('@') else chat for chat in username}
def _set_chat_ids(self, chat_id: Union[int, List[int]]) -> None:
def _set_chat_ids(self, chat_id: SLT[int]) -> None:
with self.__lock:
if chat_id and self._usernames:
raise RuntimeError(
@ -1600,7 +1611,7 @@ officedocument.wordprocessingml.document")``-
)
self._chat_ids = self._parse_chat_id(chat_id)
def _set_usernames(self, username: Union[str, List[str]]) -> None:
def _set_usernames(self, username: SLT[str]) -> None:
with self.__lock:
if username and self._chat_ids:
raise RuntimeError(
@ -1614,7 +1625,7 @@ officedocument.wordprocessingml.document")``-
return frozenset(self._chat_ids)
@chat_ids.setter
def chat_ids(self, chat_id: Union[int, List[int]]) -> None:
def chat_ids(self, chat_id: SLT[int]) -> None:
self._set_chat_ids(chat_id)
@property
@ -1623,16 +1634,17 @@ officedocument.wordprocessingml.document")``-
return frozenset(self._usernames)
@usernames.setter
def usernames(self, username: Union[str, List[str]]) -> None:
def usernames(self, username: SLT[str]) -> None:
self._set_usernames(username)
def add_usernames(self, username: Union[str, List[str]]) -> None:
def add_usernames(self, username: SLT[str]) -> None:
"""
Add one or more chats to the allowed usernames.
Args:
username(:obj:`str` | List[:obj:`str`], optional): Which username(s) to allow
through. Leading `'@'` s in usernames will be discarded.
username(:class:`telegram.utils.types.SLT[str]`, optional):
Which username(s) to allow through.
Leading `'@'` s in usernames will be discarded.
"""
with self.__lock:
if self._chat_ids:
@ -1643,13 +1655,13 @@ officedocument.wordprocessingml.document")``-
parsed_username = self._parse_username(username)
self._usernames |= parsed_username
def add_chat_ids(self, chat_id: Union[int, List[int]]) -> None:
def add_chat_ids(self, chat_id: SLT[int]) -> None:
"""
Add one or more chats to the allowed chat ids.
Args:
chat_id(:obj:`int` | List[:obj:`int`], optional): Which chat ID(s) to allow
through.
chat_id(:class:`telegram.utils.types.SLT[int]`, optional):
Which chat ID(s) to allow through.
"""
with self.__lock:
if self._usernames:
@ -1661,13 +1673,14 @@ officedocument.wordprocessingml.document")``-
self._chat_ids |= parsed_chat_id
def remove_usernames(self, username: Union[str, List[str]]) -> None:
def remove_usernames(self, username: SLT[str]) -> None:
"""
Remove one or more chats from allowed usernames.
Args:
username(:obj:`str` | List[:obj:`str`], optional): Which username(s) to disallow
through. Leading '@'s in usernames will be discarded.
username(:class:`telegram.utils.types.SLT[str]`, optional):
Which username(s) to disallow through.
Leading '@'s in usernames will be discarded.
"""
with self.__lock:
if self._chat_ids:
@ -1678,13 +1691,13 @@ officedocument.wordprocessingml.document")``-
parsed_username = self._parse_username(username)
self._usernames -= parsed_username
def remove_chat_ids(self, chat_id: Union[int, List[int]]) -> None:
def remove_chat_ids(self, chat_id: SLT[int]) -> None:
"""
Remove one or more chats from allowed chat ids.
Args:
chat_id(:obj:`int` | List[:obj:`int`], optional): Which chat ID(s) to disallow
through.
chat_id(:class:`telegram.utils.types.SLT[int]`, optional):
Which chat ID(s) to disallow through.
"""
with self.__lock:
if self._usernames:
@ -1758,8 +1771,8 @@ officedocument.wordprocessingml.document")``-
``MessageHandler(Filters.dice([5, 6]), callback_method)``.
Args:
update (:obj:`int` | List[:obj:`int`], optional): Which values to allow. If not
specified, will allow any dice message.
update (:class:`telegram.utils.types.SLT[int]`, optional):
Which values to allow. If not specified, will allow any dice message.
Note:
Dice messages don't have text. If you want to filter either text or dice messages, use
@ -1785,13 +1798,14 @@ officedocument.wordprocessingml.document")``-
``MessageHandler(Filters.language("en"), callback_method)``
Args:
lang (:obj:`str` | List[:obj:`str`]): Which language code(s) to allow through. This
will be matched using ``.startswith`` meaning that 'en' will match both 'en_US'
and 'en_GB'.
lang (:class:`telegram.utils.types.SLT[str]`):
Which language code(s) to allow through.
This will be matched using ``.startswith`` meaning that
'en' will match both 'en_US' and 'en_GB'.
"""
def __init__(self, lang: Union[str, List[str]]):
def __init__(self, lang: SLT[str]):
if isinstance(lang, str):
lang = cast(str, lang)
self.lang = [lang]

View file

@ -17,7 +17,7 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains custom typing aliases."""
from typing import IO, TYPE_CHECKING, Any, Dict, Optional, Tuple, Union
from typing import IO, TYPE_CHECKING, Any, Dict, List, Optional, Tuple, TypeVar, Union
if TYPE_CHECKING:
from telegram import InputFile, Update
@ -33,3 +33,7 @@ HandlerArg = Union[str, 'Update']
ConversationDict = Dict[Tuple[int, ...], Optional[object]]
"""Dicts as maintained by the :class:`telegram.ext.ConversationHandler`."""
RT = TypeVar("RT")
SLT = Union[RT, List[RT], Tuple[RT, ...]]
"""Single instance or list/tuple of instances."""