mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-22 06:25:12 +01:00
Type Hinting (#1920)
This commit is contained in:
parent
103b115486
commit
5fd7606084
151 changed files with 3694 additions and 2700 deletions
6
.github/CONTRIBUTING.rst
vendored
6
.github/CONTRIBUTING.rst
vendored
|
@ -68,7 +68,9 @@ Here's how to make a one-off code change.
|
|||
- You can refer to relevant issues in the commit message by writing, e.g., "#105".
|
||||
|
||||
- Your code should adhere to the `PEP 8 Style Guide`_, with the exception that we have a maximum line length of 99.
|
||||
|
||||
|
||||
- Provide static typing with signature annotations. The documentation of `MyPy`_ will be a good start, the cheat sheet is `here`_. We also have some custom type aliases in ``telegram.utils.helpers.typing``.
|
||||
|
||||
- Document your code. This project uses `sphinx`_ to generate static HTML docs. To build them, first make sure you have the required dependencies:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -251,3 +253,5 @@ break the API classes. For example:
|
|||
.. _`Google Python Style Guide`: http://google.github.io/styleguide/pyguide.html
|
||||
.. _`Google Python Style Docstrings`: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html
|
||||
.. _AUTHORS.rst: ../AUTHORS.rst
|
||||
.. _`MyPy`: https://mypy.readthedocs.io/en/stable/index.html
|
||||
.. _`here`: https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -46,6 +46,7 @@ htmlcov/
|
|||
.coverage.*
|
||||
.cache
|
||||
.pytest_cache
|
||||
.mypy_cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
|
|
|
@ -7,7 +7,7 @@ repos:
|
|||
args:
|
||||
- --diff
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.7.1
|
||||
rev: 3.8.1
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: git://github.com/pre-commit/mirrors-pylint
|
||||
|
@ -18,3 +18,8 @@ repos:
|
|||
args:
|
||||
- --errors-only
|
||||
- --disable=import-error
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: 'v0.770'
|
||||
hooks:
|
||||
- id: mypy
|
||||
files: ^telegram/.*\.py$
|
||||
|
|
6
Makefile
6
Makefile
|
@ -6,6 +6,7 @@ PYTEST := pytest
|
|||
PEP257 := pep257
|
||||
PEP8 := flake8
|
||||
YAPF := yapf
|
||||
MYPY := mypy
|
||||
PIP := pip
|
||||
|
||||
clean:
|
||||
|
@ -28,6 +29,9 @@ yapf:
|
|||
lint:
|
||||
$(PYLINT) -E telegram --disable=no-name-in-module,import-error
|
||||
|
||||
mypy:
|
||||
$(MYPY) -p telegram
|
||||
|
||||
test:
|
||||
$(PYTEST) -v
|
||||
|
||||
|
@ -41,6 +45,7 @@ help:
|
|||
@echo "- pep8 Check style with flake8"
|
||||
@echo "- lint Check style with pylint"
|
||||
@echo "- yapf Check style with yapf"
|
||||
@echo "- mypy Check type hinting with mypy"
|
||||
@echo "- test Run tests using pytest"
|
||||
@echo
|
||||
@echo "Available variables:"
|
||||
|
@ -49,4 +54,5 @@ help:
|
|||
@echo "- PEP257 default: $(PEP257)"
|
||||
@echo "- PEP8 default: $(PEP8)"
|
||||
@echo "- YAPF default: $(YAPF)"
|
||||
@echo "- MYPY default: $(MYPY)"
|
||||
@echo "- PIP default: $(PIP)"
|
||||
|
|
|
@ -6,3 +6,4 @@ telegram.utils package
|
|||
telegram.utils.helpers
|
||||
telegram.utils.promise
|
||||
telegram.utils.request
|
||||
telegram.utils.types
|
||||
|
|
6
docs/source/telegram.utils.types.rst
Normal file
6
docs/source/telegram.utils.types.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
telegram.utils.types Module
|
||||
===========================
|
||||
|
||||
.. automodule:: telegram.utils.types
|
||||
:members:
|
||||
:show-inheritance:
|
|
@ -3,6 +3,7 @@ pep257
|
|||
pylint
|
||||
flaky
|
||||
yapf
|
||||
mypy==0.770
|
||||
pre-commit
|
||||
beautifulsoup4
|
||||
pytest==4.2.0
|
||||
|
|
19
setup.cfg
19
setup.cfg
|
@ -40,3 +40,22 @@ omit =
|
|||
telegram/__main__.py
|
||||
telegram/vendor/*
|
||||
|
||||
[coverage:report]
|
||||
exclude_lines =
|
||||
if TYPE_CHECKING:
|
||||
|
||||
[mypy]
|
||||
warn_unused_ignores = True
|
||||
warn_unused_configs = True
|
||||
disallow_untyped_defs = True
|
||||
disallow_incomplete_defs = True
|
||||
disallow_untyped_decorators = True
|
||||
show_error_codes = True
|
||||
|
||||
[mypy-telegram.vendor.*]
|
||||
ignore_errors = True
|
||||
|
||||
# Disable strict optional for telegram objects with class methods
|
||||
# We don't want to clutter the code with 'if self.bot is None: raise RuntimeError()'
|
||||
[mypy-telegram.callbackquery,telegram.chat,telegram.message,telegram.user,telegram.files.*,telegram.inline.inlinequery,telegram.payment.precheckoutquery,telegram.payment.shippingquery,telegram.passport.passportdata,telegram.passport.credentials,telegram.passport.passportfile,telegram.ext.filters]
|
||||
strict_optional = False
|
||||
|
|
|
@ -104,7 +104,6 @@ from .games.gamehighscore import GameHighScore
|
|||
from .update import Update
|
||||
from .files.inputmedia import (InputMedia, InputMediaVideo, InputMediaPhoto, InputMediaAnimation,
|
||||
InputMediaAudio, InputMediaDocument)
|
||||
from .bot import Bot
|
||||
from .constants import (MAX_MESSAGE_LENGTH, MAX_CAPTION_LENGTH, SUPPORTED_WEBHOOK_PORTS,
|
||||
MAX_FILESIZE_DOWNLOAD, MAX_FILESIZE_UPLOAD,
|
||||
MAX_MESSAGES_PER_SECOND_PER_CHAT, MAX_MESSAGES_PER_SECOND,
|
||||
|
@ -124,6 +123,7 @@ from .passport.credentials import (Credentials,
|
|||
SecureData,
|
||||
FileCredentials,
|
||||
TelegramDecryptionError)
|
||||
from .bot import Bot
|
||||
from .version import __version__ # noqa: F401
|
||||
|
||||
__author__ = 'devs@python-telegram-bot.org'
|
||||
|
|
|
@ -21,11 +21,12 @@ import subprocess
|
|||
|
||||
import certifi
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from . import __version__ as telegram_ver
|
||||
|
||||
|
||||
def _git_revision():
|
||||
def _git_revision() -> Optional[str]:
|
||||
try:
|
||||
output = subprocess.check_output(["git", "describe", "--long", "--tags"],
|
||||
stderr=subprocess.STDOUT)
|
||||
|
@ -34,15 +35,15 @@ def _git_revision():
|
|||
return output.decode().strip()
|
||||
|
||||
|
||||
def print_ver_info():
|
||||
def print_ver_info() -> None:
|
||||
git_revision = _git_revision()
|
||||
print('python-telegram-bot {}'.format(telegram_ver) + (' ({})'.format(git_revision)
|
||||
if git_revision else ''))
|
||||
print('certifi {}'.format(certifi.__version__))
|
||||
print('certifi {}'.format(certifi.__version__)) # type: ignore[attr-defined]
|
||||
print('Python {}'.format(sys.version.replace('\n', ' ')))
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
print_ver_info()
|
||||
|
||||
|
||||
|
|
|
@ -17,36 +17,64 @@
|
|||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""Base class for Telegram Objects."""
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ImportError:
|
||||
import json
|
||||
import json # type: ignore[no-redef]
|
||||
|
||||
import warnings
|
||||
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Tuple, Any, Optional, Type, TypeVar, TYPE_CHECKING, List
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
TO = TypeVar('TO', bound='TelegramObject', covariant=True)
|
||||
|
||||
|
||||
class TelegramObject:
|
||||
"""Base class for most telegram objects."""
|
||||
|
||||
_id_attrs = ()
|
||||
# def __init__(self, *args: Any, **kwargs: Any):
|
||||
# pass
|
||||
|
||||
def __str__(self):
|
||||
_id_attrs: Tuple[Any, ...] = ()
|
||||
|
||||
def __str__(self) -> str:
|
||||
return str(self.to_dict())
|
||||
|
||||
def __getitem__(self, item):
|
||||
def __getitem__(self, item: str) -> Any:
|
||||
return self.__dict__[item]
|
||||
|
||||
@staticmethod
|
||||
def parse_data(data: Optional[JSONDict]) -> Optional[JSONDict]:
|
||||
if not data:
|
||||
return None
|
||||
return data.copy()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls: Type[TO], data: Optional[JSONDict], bot: 'Bot') -> Optional[TO]:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = data.copy()
|
||||
if cls == TelegramObject:
|
||||
return cls()
|
||||
else:
|
||||
return cls(bot=bot, **data) # type: ignore[call-arg]
|
||||
|
||||
return data
|
||||
@classmethod
|
||||
def de_list(cls: Type[TO],
|
||||
data: Optional[List[JSONDict]],
|
||||
bot: 'Bot') -> List[Optional[TO]]:
|
||||
if not data:
|
||||
return []
|
||||
|
||||
def to_json(self):
|
||||
return [cls.de_json(d, bot) for d in data]
|
||||
|
||||
def to_json(self) -> str:
|
||||
"""
|
||||
Returns:
|
||||
:obj:`str`
|
||||
|
@ -55,7 +83,7 @@ class TelegramObject:
|
|||
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
def to_dict(self):
|
||||
def to_dict(self) -> JSONDict:
|
||||
data = dict()
|
||||
|
||||
for key in iter(self.__dict__):
|
||||
|
@ -73,7 +101,7 @@ class TelegramObject:
|
|||
data['from'] = data.pop('from_user', None)
|
||||
return data
|
||||
|
||||
def __eq__(self, other):
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if isinstance(other, self.__class__):
|
||||
if self._id_attrs == ():
|
||||
warnings.warn("Objects of type {} can not be meaningfully tested for "
|
||||
|
@ -84,7 +112,7 @@ class TelegramObject:
|
|||
return self._id_attrs == other._id_attrs
|
||||
return super().__eq__(other) # pylint: disable=no-member
|
||||
|
||||
def __hash__(self):
|
||||
def __hash__(self) -> int:
|
||||
if self._id_attrs:
|
||||
return hash((self.__class__, self._id_attrs)) # pylint: disable=no-member
|
||||
return super().__hash__()
|
||||
|
|
1384
telegram/bot.py
1384
telegram/bot.py
File diff suppressed because it is too large
Load diff
|
@ -19,6 +19,7 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram Bot Command."""
|
||||
from telegram import TelegramObject
|
||||
from typing import Any
|
||||
|
||||
|
||||
class BotCommand(TelegramObject):
|
||||
|
@ -37,15 +38,8 @@ class BotCommand(TelegramObject):
|
|||
English letters, digits and underscores.
|
||||
description (:obj:`str`): Description of the command, 3-256 characters.
|
||||
"""
|
||||
def __init__(self, command, description, **kwargs):
|
||||
def __init__(self, command: str, description: str, **kwargs: Any):
|
||||
self.command = command
|
||||
self.description = description
|
||||
|
||||
self._id_attrs = (self.command, self.description)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return cls(**data)
|
||||
|
|
|
@ -17,9 +17,14 @@
|
|||
# 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 an object that represents a Telegram CallbackQuery"""
|
||||
|
||||
from telegram import TelegramObject, Message, User
|
||||
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Optional, Any, Union, TYPE_CHECKING, List
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, InlineKeyboardMarkup, GameHighScore
|
||||
|
||||
|
||||
class CallbackQuery(TelegramObject):
|
||||
"""
|
||||
|
@ -74,15 +79,15 @@ class CallbackQuery(TelegramObject):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
from_user,
|
||||
chat_instance,
|
||||
message=None,
|
||||
data=None,
|
||||
inline_message_id=None,
|
||||
game_short_name=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
id: str,
|
||||
from_user: User,
|
||||
chat_instance: str,
|
||||
message: Message = None,
|
||||
data: str = None,
|
||||
inline_message_id: str = None,
|
||||
game_short_name: str = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.id = id
|
||||
self.from_user = from_user
|
||||
|
@ -98,18 +103,18 @@ class CallbackQuery(TelegramObject):
|
|||
self._id_attrs = (self.id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['CallbackQuery']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super().de_json(data, bot)
|
||||
|
||||
data['from_user'] = User.de_json(data.get('from'), bot)
|
||||
data['message'] = Message.de_json(data.get('message'), bot)
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def answer(self, *args, **kwargs):
|
||||
def answer(self, *args: Any, **kwargs: Any) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.answer_callback_query(update.callback_query.id, *args, **kwargs)
|
||||
|
@ -118,9 +123,9 @@ class CallbackQuery(TelegramObject):
|
|||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
|
||||
"""
|
||||
return self.bot.answerCallbackQuery(self.id, *args, **kwargs)
|
||||
return self.bot.answer_callback_query(self.id, *args, **kwargs)
|
||||
|
||||
def edit_message_text(self, text, *args, **kwargs):
|
||||
def edit_message_text(self, text: str, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
bot.edit_message_text(text, chat_id=update.callback_query.message.chat_id,
|
||||
|
@ -144,7 +149,8 @@ class CallbackQuery(TelegramObject):
|
|||
return self.bot.edit_message_text(text, chat_id=self.message.chat_id,
|
||||
message_id=self.message.message_id, *args, **kwargs)
|
||||
|
||||
def edit_message_caption(self, caption, *args, **kwargs):
|
||||
def edit_message_caption(self, caption: str, *args: Any,
|
||||
**kwargs: Any) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
bot.edit_message_caption(caption=caption,
|
||||
|
@ -172,7 +178,8 @@ class CallbackQuery(TelegramObject):
|
|||
message_id=self.message.message_id,
|
||||
*args, **kwargs)
|
||||
|
||||
def edit_message_reply_markup(self, reply_markup, *args, **kwargs):
|
||||
def edit_message_reply_markup(self, reply_markup: 'InlineKeyboardMarkup', *args: Any,
|
||||
**kwargs: Any) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
bot.edit_message_reply_markup(chat_id=update.callback_query.message.chat_id,
|
||||
|
@ -201,7 +208,7 @@ class CallbackQuery(TelegramObject):
|
|||
message_id=self.message.message_id,
|
||||
*args, **kwargs)
|
||||
|
||||
def edit_message_media(self, *args, **kwargs):
|
||||
def edit_message_media(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
bot.edit_message_media(chat_id=update.callback_query.message.chat_id,
|
||||
|
@ -228,7 +235,7 @@ class CallbackQuery(TelegramObject):
|
|||
message_id=self.message.message_id,
|
||||
*args, **kwargs)
|
||||
|
||||
def edit_message_live_location(self, *args, **kwargs):
|
||||
def edit_message_live_location(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
bot.edit_message_live_location(chat_id=update.callback_query.message.chat_id,
|
||||
|
@ -257,7 +264,7 @@ class CallbackQuery(TelegramObject):
|
|||
message_id=self.message.message_id,
|
||||
*args, **kwargs)
|
||||
|
||||
def stop_message_live_location(self, *args, **kwargs):
|
||||
def stop_message_live_location(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
bot.stop_message_live_location(chat_id=update.callback_query.message.chat_id,
|
||||
|
@ -286,7 +293,7 @@ class CallbackQuery(TelegramObject):
|
|||
message_id=self.message.message_id,
|
||||
*args, **kwargs)
|
||||
|
||||
def set_game_score(self, *args, **kwargs):
|
||||
def set_game_score(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
bot.set_game_score(chat_id=update.callback_query.message.chat_id,
|
||||
|
@ -313,7 +320,7 @@ class CallbackQuery(TelegramObject):
|
|||
message_id=self.message.message_id,
|
||||
*args, **kwargs)
|
||||
|
||||
def get_game_high_scores(self, *args, **kwargs):
|
||||
def get_game_high_scores(self, *args: Any, **kwargs: Any) -> List['GameHighScore']:
|
||||
"""Shortcut for either::
|
||||
|
||||
bot.get_game_high_scores(chat_id=update.callback_query.message.chat_id,
|
||||
|
@ -328,8 +335,7 @@ class CallbackQuery(TelegramObject):
|
|||
*args, **kwargs)
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
|
||||
edited Message is returned, otherwise :obj:`True` is returned.
|
||||
List[:class:`telegram.GameHighScore`]
|
||||
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
|
|
109
telegram/chat.py
109
telegram/chat.py
|
@ -22,6 +22,11 @@
|
|||
from telegram import TelegramObject, ChatPhoto
|
||||
from .chatpermissions import ChatPermissions
|
||||
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, List, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, Message, ChatMember
|
||||
|
||||
|
||||
class Chat(TelegramObject):
|
||||
"""This object represents a chat.
|
||||
|
@ -41,7 +46,7 @@ class Chat(TelegramObject):
|
|||
invite_link (:obj:`str`): Optional. Chat invite link, for supergroups and channel chats.
|
||||
pinned_message (:class:`telegram.Message`): Optional. Pinned message, for supergroups.
|
||||
Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
permissions (:class:`telegram.ChatPermission`): Optional. Default chat member permissions,
|
||||
permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions,
|
||||
for groups and supergroups. Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
slow_mode_delay (:obj:`int`): Optional. For supergroups, the minimum allowed delay between
|
||||
consecutive messages sent by each unprivileged user. Returned only in
|
||||
|
@ -72,7 +77,7 @@ class Chat(TelegramObject):
|
|||
in :meth:`telegram.Bot.get_chat`.
|
||||
pinned_message (:class:`telegram.Message`, optional): Pinned message, for groups,
|
||||
supergroups and channels. Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
permissions (:class:`telegram.ChatPermission`): Optional. Default chat member permissions,
|
||||
permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions,
|
||||
for groups and supergroups. Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
slow_mode_delay (:obj:`int`, optional): For supergroups, the minimum allowed delay between
|
||||
consecutive messages sent by each unprivileged user.
|
||||
|
@ -86,32 +91,32 @@ class Chat(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
PRIVATE = 'private'
|
||||
PRIVATE: str = 'private'
|
||||
""":obj:`str`: 'private'"""
|
||||
GROUP = 'group'
|
||||
GROUP: str = 'group'
|
||||
""":obj:`str`: 'group'"""
|
||||
SUPERGROUP = 'supergroup'
|
||||
SUPERGROUP: str = 'supergroup'
|
||||
""":obj:`str`: 'supergroup'"""
|
||||
CHANNEL = 'channel'
|
||||
CHANNEL: str = 'channel'
|
||||
""":obj:`str`: 'channel'"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
type,
|
||||
title=None,
|
||||
username=None,
|
||||
first_name=None,
|
||||
last_name=None,
|
||||
bot=None,
|
||||
photo=None,
|
||||
description=None,
|
||||
invite_link=None,
|
||||
pinned_message=None,
|
||||
permissions=None,
|
||||
sticker_set_name=None,
|
||||
can_set_sticker_set=None,
|
||||
slow_mode_delay=None,
|
||||
**kwargs):
|
||||
id: int,
|
||||
type: str,
|
||||
title: str = None,
|
||||
username: str = None,
|
||||
first_name: str = None,
|
||||
last_name: str = None,
|
||||
bot: 'Bot' = None,
|
||||
photo: ChatPhoto = None,
|
||||
description: str = None,
|
||||
invite_link: str = None,
|
||||
pinned_message: 'Message' = None,
|
||||
permissions: ChatPermissions = None,
|
||||
sticker_set_name: str = None,
|
||||
can_set_sticker_set: bool = None,
|
||||
slow_mode_delay: int = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.id = int(id)
|
||||
self.type = type
|
||||
|
@ -135,7 +140,7 @@ class Chat(TelegramObject):
|
|||
self._id_attrs = (self.id,)
|
||||
|
||||
@property
|
||||
def link(self):
|
||||
def link(self) -> Optional[str]:
|
||||
""":obj:`str`: Convenience property. If the chat has a :attr:`username`, returns a t.me
|
||||
link of the chat."""
|
||||
if self.username:
|
||||
|
@ -143,7 +148,9 @@ class Chat(TelegramObject):
|
|||
return None
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: JSONDict, bot: 'Bot') -> Optional['Chat']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
|
@ -154,7 +161,7 @@ class Chat(TelegramObject):
|
|||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def leave(self, *args, **kwargs):
|
||||
def leave(self, *args: Any, **kwargs: Any) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.leave_chat(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -165,7 +172,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.leave_chat(self.id, *args, **kwargs)
|
||||
|
||||
def get_administrators(self, *args, **kwargs):
|
||||
def get_administrators(self, *args: Any, **kwargs: Any) -> List['ChatMember']:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.get_chat_administrators(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -179,7 +186,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.get_chat_administrators(self.id, *args, **kwargs)
|
||||
|
||||
def get_members_count(self, *args, **kwargs):
|
||||
def get_members_count(self, *args: Any, **kwargs: Any) -> int:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.get_chat_members_count(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -190,7 +197,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.get_chat_members_count(self.id, *args, **kwargs)
|
||||
|
||||
def get_member(self, *args, **kwargs):
|
||||
def get_member(self, *args: Any, **kwargs: Any) -> 'ChatMember':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.get_chat_member(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -201,7 +208,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.get_chat_member(self.id, *args, **kwargs)
|
||||
|
||||
def kick_member(self, *args, **kwargs):
|
||||
def kick_member(self, *args: Any, **kwargs: Any) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.kick_chat_member(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -217,7 +224,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.kick_chat_member(self.id, *args, **kwargs)
|
||||
|
||||
def unban_member(self, *args, **kwargs):
|
||||
def unban_member(self, *args: Any, **kwargs: Any) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.unban_chat_member(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -228,18 +235,18 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.unban_chat_member(self.id, *args, **kwargs)
|
||||
|
||||
def set_permissions(self, *args, **kwargs):
|
||||
def set_permissions(self, *args: Any, **kwargs: Any) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.set_chat_permissions(update.effective_chat.id, *args, **kwargs)
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: If the action was sent successfully.
|
||||
:obj:`bool`: If the action was sent successfully.
|
||||
|
||||
"""
|
||||
return self.bot.set_chat_permissions(self.id, *args, **kwargs)
|
||||
|
||||
def set_administrator_custom_title(self, *args, **kwargs):
|
||||
def set_administrator_custom_title(self, *args: Any, **kwargs: Any) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.set_chat_administrator_custom_title(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -250,7 +257,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.set_chat_administrator_custom_title(self.id, *args, **kwargs)
|
||||
|
||||
def send_message(self, *args, **kwargs):
|
||||
def send_message(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_message(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -261,7 +268,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_message(self.id, *args, **kwargs)
|
||||
|
||||
def send_media_group(self, *args, **kwargs):
|
||||
def send_media_group(self, *args: Any, **kwargs: Any) -> List['Message']:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_media_group(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -272,7 +279,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_media_group(self.id, *args, **kwargs)
|
||||
|
||||
def send_chat_action(self, *args, **kwargs):
|
||||
def send_chat_action(self, *args: Any, **kwargs: Any) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_chat_action(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -286,7 +293,7 @@ class Chat(TelegramObject):
|
|||
send_action = send_chat_action
|
||||
"""Alias for :attr:`send_chat_action`"""
|
||||
|
||||
def send_photo(self, *args, **kwargs):
|
||||
def send_photo(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_photo(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -297,7 +304,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_photo(self.id, *args, **kwargs)
|
||||
|
||||
def send_contact(self, *args, **kwargs):
|
||||
def send_contact(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_contact(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -308,7 +315,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_contact(self.id, *args, **kwargs)
|
||||
|
||||
def send_audio(self, *args, **kwargs):
|
||||
def send_audio(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_audio(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -319,7 +326,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_audio(self.id, *args, **kwargs)
|
||||
|
||||
def send_document(self, *args, **kwargs):
|
||||
def send_document(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_document(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -330,7 +337,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_document(self.id, *args, **kwargs)
|
||||
|
||||
def send_dice(self, *args, **kwargs):
|
||||
def send_dice(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_dice(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -341,7 +348,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_dice(self.id, *args, **kwargs)
|
||||
|
||||
def send_game(self, *args, **kwargs):
|
||||
def send_game(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_game(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -352,7 +359,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_game(self.id, *args, **kwargs)
|
||||
|
||||
def send_invoice(self, *args, **kwargs):
|
||||
def send_invoice(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_invoice(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -363,7 +370,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_invoice(self.id, *args, **kwargs)
|
||||
|
||||
def send_location(self, *args, **kwargs):
|
||||
def send_location(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_location(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -374,7 +381,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_location(self.id, *args, **kwargs)
|
||||
|
||||
def send_animation(self, *args, **kwargs):
|
||||
def send_animation(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_animation(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -385,7 +392,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_animation(self.id, *args, **kwargs)
|
||||
|
||||
def send_sticker(self, *args, **kwargs):
|
||||
def send_sticker(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_sticker(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -396,7 +403,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_sticker(self.id, *args, **kwargs)
|
||||
|
||||
def send_venue(self, *args, **kwargs):
|
||||
def send_venue(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_venue(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -407,7 +414,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_venue(self.id, *args, **kwargs)
|
||||
|
||||
def send_video(self, *args, **kwargs):
|
||||
def send_video(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_video(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -418,7 +425,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_video(self.id, *args, **kwargs)
|
||||
|
||||
def send_video_note(self, *args, **kwargs):
|
||||
def send_video_note(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_video_note(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -429,7 +436,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_video_note(self.id, *args, **kwargs)
|
||||
|
||||
def send_voice(self, *args, **kwargs):
|
||||
def send_voice(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_voice(update.effective_chat.id, *args, **kwargs)
|
||||
|
@ -440,7 +447,7 @@ class Chat(TelegramObject):
|
|||
"""
|
||||
return self.bot.send_voice(self.id, *args, **kwargs)
|
||||
|
||||
def send_poll(self, *args, **kwargs):
|
||||
def send_poll(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_poll(update.effective_chat.id, *args, **kwargs)
|
||||
|
|
|
@ -23,23 +23,23 @@
|
|||
class ChatAction:
|
||||
"""Helper class to provide constants for different chat actions."""
|
||||
|
||||
FIND_LOCATION = 'find_location'
|
||||
FIND_LOCATION: str = 'find_location'
|
||||
""":obj:`str`: 'find_location'"""
|
||||
RECORD_AUDIO = 'record_audio'
|
||||
RECORD_AUDIO: str = 'record_audio'
|
||||
""":obj:`str`: 'record_audio'"""
|
||||
RECORD_VIDEO = 'record_video'
|
||||
RECORD_VIDEO: str = 'record_video'
|
||||
""":obj:`str`: 'record_video'"""
|
||||
RECORD_VIDEO_NOTE = 'record_video_note'
|
||||
RECORD_VIDEO_NOTE: str = 'record_video_note'
|
||||
""":obj:`str`: 'record_video_note'"""
|
||||
TYPING = 'typing'
|
||||
TYPING: str = 'typing'
|
||||
""":obj:`str`: 'typing'"""
|
||||
UPLOAD_AUDIO = 'upload_audio'
|
||||
UPLOAD_AUDIO: str = 'upload_audio'
|
||||
""":obj:`str`: 'upload_audio'"""
|
||||
UPLOAD_DOCUMENT = 'upload_document'
|
||||
UPLOAD_DOCUMENT: str = 'upload_document'
|
||||
""":obj:`str`: 'upload_document'"""
|
||||
UPLOAD_PHOTO = 'upload_photo'
|
||||
UPLOAD_PHOTO: str = 'upload_photo'
|
||||
""":obj:`str`: 'upload_photo'"""
|
||||
UPLOAD_VIDEO = 'upload_video'
|
||||
UPLOAD_VIDEO: str = 'upload_video'
|
||||
""":obj:`str`: 'upload_video'"""
|
||||
UPLOAD_VIDEO_NOTE = 'upload_video_note'
|
||||
UPLOAD_VIDEO_NOTE: str = 'upload_video_note'
|
||||
""":obj:`str`: 'upload_video_note'"""
|
||||
|
|
|
@ -17,10 +17,16 @@
|
|||
# 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 an object that represents a Telegram ChatMember."""
|
||||
import datetime
|
||||
|
||||
from telegram import User, TelegramObject
|
||||
from telegram.utils.helpers import to_timestamp, from_timestamp
|
||||
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class ChatMember(TelegramObject):
|
||||
"""This object contains information about one member of a chat.
|
||||
|
@ -104,26 +110,40 @@ class ChatMember(TelegramObject):
|
|||
may add web page previews to his messages.
|
||||
|
||||
"""
|
||||
ADMINISTRATOR = 'administrator'
|
||||
ADMINISTRATOR: str = 'administrator'
|
||||
""":obj:`str`: 'administrator'"""
|
||||
CREATOR = 'creator'
|
||||
CREATOR: str = 'creator'
|
||||
""":obj:`str`: 'creator'"""
|
||||
KICKED = 'kicked'
|
||||
KICKED: str = 'kicked'
|
||||
""":obj:`str`: 'kicked'"""
|
||||
LEFT = 'left'
|
||||
LEFT: str = 'left'
|
||||
""":obj:`str`: 'left'"""
|
||||
MEMBER = 'member'
|
||||
MEMBER: str = 'member'
|
||||
""":obj:`str`: 'member'"""
|
||||
RESTRICTED = 'restricted'
|
||||
RESTRICTED: str = 'restricted'
|
||||
""":obj:`str`: 'restricted'"""
|
||||
|
||||
def __init__(self, user, status, until_date=None, can_be_edited=None,
|
||||
can_change_info=None, can_post_messages=None, can_edit_messages=None,
|
||||
can_delete_messages=None, can_invite_users=None,
|
||||
can_restrict_members=None, can_pin_messages=None,
|
||||
can_promote_members=None, can_send_messages=None,
|
||||
can_send_media_messages=None, can_send_polls=None, can_send_other_messages=None,
|
||||
can_add_web_page_previews=None, is_member=None, custom_title=None, **kwargs):
|
||||
def __init__(self,
|
||||
user: User,
|
||||
status: str,
|
||||
until_date: datetime.datetime = None,
|
||||
can_be_edited: bool = None,
|
||||
can_change_info: bool = None,
|
||||
can_post_messages: bool = None,
|
||||
can_edit_messages: bool = None,
|
||||
can_delete_messages: bool = None,
|
||||
can_invite_users: bool = None,
|
||||
can_restrict_members: bool = None,
|
||||
can_pin_messages: bool = None,
|
||||
can_promote_members: bool = None,
|
||||
can_send_messages: bool = None,
|
||||
can_send_media_messages: bool = None,
|
||||
can_send_polls: bool = None,
|
||||
can_send_other_messages: bool = None,
|
||||
can_add_web_page_previews: bool = None,
|
||||
is_member: bool = None,
|
||||
custom_title: str = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.user = user
|
||||
self.status = status
|
||||
|
@ -148,18 +168,18 @@ class ChatMember(TelegramObject):
|
|||
self._id_attrs = (self.user, self.status)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatMember']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super().de_json(data, bot)
|
||||
|
||||
data['user'] = User.de_json(data.get('user'), bot)
|
||||
data['until_date'] = from_timestamp(data.get('until_date', None))
|
||||
|
||||
return cls(**data)
|
||||
|
||||
def to_dict(self):
|
||||
def to_dict(self) -> JSONDict:
|
||||
data = super().to_dict()
|
||||
|
||||
data['until_date'] = to_timestamp(self.until_date)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"""This module contains an object that represents a Telegram ChatPermission."""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from typing import Any
|
||||
|
||||
|
||||
class ChatPermissions(TelegramObject):
|
||||
|
@ -76,9 +77,16 @@ class ChatPermissions(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, can_send_messages=None, can_send_media_messages=None, can_send_polls=None,
|
||||
can_send_other_messages=None, can_add_web_page_previews=None,
|
||||
can_change_info=None, can_invite_users=None, can_pin_messages=None, **kwargs):
|
||||
def __init__(self,
|
||||
can_send_messages: bool = None,
|
||||
can_send_media_messages: bool = None,
|
||||
can_send_polls: bool = None,
|
||||
can_send_other_messages: bool = None,
|
||||
can_add_web_page_previews: bool = None,
|
||||
can_change_info: bool = None,
|
||||
can_invite_users: bool = None,
|
||||
can_pin_messages: bool = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.can_send_messages = can_send_messages
|
||||
self.can_send_media_messages = can_send_media_messages
|
||||
|
@ -99,10 +107,3 @@ class ChatPermissions(TelegramObject):
|
|||
self.can_invite_users,
|
||||
self.can_pin_messages
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return cls(**data)
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
"""This module contains an object that represents a Telegram ChosenInlineResult."""
|
||||
|
||||
from telegram import TelegramObject, User, Location
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class ChosenInlineResult(TelegramObject):
|
||||
|
@ -58,12 +62,12 @@ class ChosenInlineResult(TelegramObject):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
result_id,
|
||||
from_user,
|
||||
query,
|
||||
location=None,
|
||||
inline_message_id=None,
|
||||
**kwargs):
|
||||
result_id: str,
|
||||
from_user: User,
|
||||
query: str,
|
||||
location: Location = None,
|
||||
inline_message_id: str = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.result_id = result_id
|
||||
self.from_user = from_user
|
||||
|
@ -75,11 +79,12 @@ class ChosenInlineResult(TelegramObject):
|
|||
self._id_attrs = (self.result_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChosenInlineResult']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super().de_json(data, bot)
|
||||
# Required
|
||||
data['from_user'] = User.de_json(data.pop('from'), bot)
|
||||
# Optionals
|
||||
|
|
|
@ -40,18 +40,19 @@ Attributes:
|
|||
formatting styles)
|
||||
|
||||
"""
|
||||
from typing import List
|
||||
|
||||
MAX_MESSAGE_LENGTH = 4096
|
||||
MAX_CAPTION_LENGTH = 1024
|
||||
MAX_MESSAGE_LENGTH: int = 4096
|
||||
MAX_CAPTION_LENGTH: int = 1024
|
||||
|
||||
# constants above this line are tested
|
||||
|
||||
SUPPORTED_WEBHOOK_PORTS = [443, 80, 88, 8443]
|
||||
MAX_FILESIZE_DOWNLOAD = int(20E6) # (20MB)
|
||||
MAX_FILESIZE_UPLOAD = int(50E6) # (50MB)
|
||||
MAX_PHOTOSIZE_UPLOAD = int(10E6) # (10MB)
|
||||
MAX_MESSAGES_PER_SECOND_PER_CHAT = 1
|
||||
MAX_MESSAGES_PER_SECOND = 30
|
||||
MAX_MESSAGES_PER_MINUTE_PER_GROUP = 20
|
||||
MAX_MESSAGE_ENTITIES = 100
|
||||
MAX_INLINE_QUERY_RESULTS = 50
|
||||
SUPPORTED_WEBHOOK_PORTS: List[int] = [443, 80, 88, 8443]
|
||||
MAX_FILESIZE_DOWNLOAD: int = int(20E6) # (20MB)
|
||||
MAX_FILESIZE_UPLOAD: int = int(50E6) # (50MB)
|
||||
MAX_PHOTOSIZE_UPLOAD: int = int(10E6) # (10MB)
|
||||
MAX_MESSAGES_PER_SECOND_PER_CHAT: int = 1
|
||||
MAX_MESSAGES_PER_SECOND: int = 30
|
||||
MAX_MESSAGES_PER_MINUTE_PER_GROUP: int = 20
|
||||
MAX_MESSAGE_ENTITIES: int = 100
|
||||
MAX_INLINE_QUERY_RESULTS: int = 50
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram Dice."""
|
||||
from telegram import TelegramObject
|
||||
from typing import Any, List
|
||||
|
||||
|
||||
class Dice(TelegramObject):
|
||||
|
@ -47,25 +48,18 @@ class Dice(TelegramObject):
|
|||
value (:obj:`int`): Value of the dice. 1-6 for dice and darts, 1-5 for basketball.
|
||||
emoji (:obj:`str`): Emoji on which the dice throw animation is based.
|
||||
"""
|
||||
def __init__(self, value, emoji, **kwargs):
|
||||
def __init__(self, value: int, emoji: str, **kwargs: Any):
|
||||
self.value = value
|
||||
self.emoji = emoji
|
||||
|
||||
self._id_attrs = (self.value, self.emoji)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return cls(**data)
|
||||
|
||||
DICE = '🎲'
|
||||
DICE: str = '🎲'
|
||||
""":obj:`str`: '🎲'"""
|
||||
DARTS = '🎯'
|
||||
DARTS: str = '🎯'
|
||||
""":obj:`str`: '🎯'"""
|
||||
BASKETBALL = '🏀'
|
||||
""":obj:`str`: '🏀'"""
|
||||
ALL_EMOJI = [DICE, DARTS, BASKETBALL]
|
||||
ALL_EMOJI: List[str] = [DICE, DARTS, BASKETBALL]
|
||||
"""List[:obj:`str`]: List of all supported base emoji. Currently :attr:`DICE`,
|
||||
:attr:`DARTS` and :attr:`BASKETBALL`."""
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
# 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 an object that represents Telegram errors."""
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
def _lstrip_str(in_s, lstr):
|
||||
def _lstrip_str(in_s: str, lstr: str) -> str:
|
||||
"""
|
||||
Args:
|
||||
in_s (:obj:`str`): in string
|
||||
|
@ -37,7 +38,7 @@ def _lstrip_str(in_s, lstr):
|
|||
|
||||
|
||||
class TelegramError(Exception):
|
||||
def __init__(self, message):
|
||||
def __init__(self, message: str):
|
||||
super().__init__()
|
||||
|
||||
msg = _lstrip_str(message, 'Error: ')
|
||||
|
@ -48,10 +49,10 @@ class TelegramError(Exception):
|
|||
msg = msg.capitalize()
|
||||
self.message = msg
|
||||
|
||||
def __str__(self):
|
||||
return '%s' % (self.message)
|
||||
def __str__(self) -> str:
|
||||
return '%s' % self.message
|
||||
|
||||
def __reduce__(self):
|
||||
def __reduce__(self) -> Tuple[type, Tuple[str]]:
|
||||
return self.__class__, (self.message,)
|
||||
|
||||
|
||||
|
@ -60,10 +61,10 @@ class Unauthorized(TelegramError):
|
|||
|
||||
|
||||
class InvalidToken(TelegramError):
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
super().__init__('Invalid token')
|
||||
|
||||
def __reduce__(self):
|
||||
def __reduce__(self) -> Tuple[type, Tuple]: # type: ignore[override]
|
||||
return self.__class__, ()
|
||||
|
||||
|
||||
|
@ -76,10 +77,10 @@ class BadRequest(NetworkError):
|
|||
|
||||
|
||||
class TimedOut(NetworkError):
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
super().__init__('Timed out')
|
||||
|
||||
def __reduce__(self):
|
||||
def __reduce__(self) -> Tuple[type, Tuple]: # type: ignore[override]
|
||||
return self.__class__, ()
|
||||
|
||||
|
||||
|
@ -90,11 +91,11 @@ class ChatMigrated(TelegramError):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, new_chat_id):
|
||||
def __init__(self, new_chat_id: int):
|
||||
super().__init__('Group migrated to supergroup. New chat id: {}'.format(new_chat_id))
|
||||
self.new_chat_id = new_chat_id
|
||||
|
||||
def __reduce__(self):
|
||||
def __reduce__(self) -> Tuple[type, Tuple[int]]: # type: ignore[override]
|
||||
return self.__class__, (self.new_chat_id,)
|
||||
|
||||
|
||||
|
@ -105,11 +106,11 @@ class RetryAfter(TelegramError):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, retry_after):
|
||||
def __init__(self, retry_after: int):
|
||||
super().__init__('Flood control exceeded. Retry in {} seconds'.format(float(retry_after)))
|
||||
self.retry_after = float(retry_after)
|
||||
|
||||
def __reduce__(self):
|
||||
def __reduce__(self) -> Tuple[type, Tuple[float]]: # type: ignore[override]
|
||||
return self.__class__, (self.retry_after,)
|
||||
|
||||
|
||||
|
@ -122,8 +123,8 @@ class Conflict(TelegramError):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg):
|
||||
def __init__(self, msg: str):
|
||||
super().__init__(msg)
|
||||
|
||||
def __reduce__(self):
|
||||
def __reduce__(self) -> Tuple[type, Tuple[str]]:
|
||||
return self.__class__, (self.message,)
|
||||
|
|
|
@ -24,6 +24,9 @@ from copy import copy
|
|||
|
||||
from telegram import Bot
|
||||
|
||||
from typing import DefaultDict, Dict, Any, Tuple, Optional, cast
|
||||
from telegram.utils.types import ConversationDict
|
||||
|
||||
|
||||
class BasePersistence(ABC):
|
||||
"""Interface class for adding persistence to your bot.
|
||||
|
@ -70,7 +73,7 @@ class BasePersistence(ABC):
|
|||
persistence class. Default is :obj:`True` .
|
||||
"""
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
def __new__(cls, *args: Any, **kwargs: Any) -> 'BasePersistence':
|
||||
instance = super().__new__(cls)
|
||||
get_user_data = instance.get_user_data
|
||||
get_chat_data = instance.get_chat_data
|
||||
|
@ -79,22 +82,22 @@ class BasePersistence(ABC):
|
|||
update_chat_data = instance.update_chat_data
|
||||
update_bot_data = instance.update_bot_data
|
||||
|
||||
def get_user_data_insert_bot():
|
||||
def get_user_data_insert_bot() -> DefaultDict[int, Dict[Any, Any]]:
|
||||
return instance.insert_bot(get_user_data())
|
||||
|
||||
def get_chat_data_insert_bot():
|
||||
def get_chat_data_insert_bot() -> DefaultDict[int, Dict[Any, Any]]:
|
||||
return instance.insert_bot(get_chat_data())
|
||||
|
||||
def get_bot_data_insert_bot():
|
||||
def get_bot_data_insert_bot() -> Dict[Any, Any]:
|
||||
return instance.insert_bot(get_bot_data())
|
||||
|
||||
def update_user_data_replace_bot(user_id, data):
|
||||
def update_user_data_replace_bot(user_id: int, data: Dict) -> None:
|
||||
return update_user_data(user_id, instance.replace_bot(data))
|
||||
|
||||
def update_chat_data_replace_bot(chat_id, data):
|
||||
def update_chat_data_replace_bot(chat_id: int, data: Dict) -> None:
|
||||
return update_chat_data(chat_id, instance.replace_bot(data))
|
||||
|
||||
def update_bot_data_replace_bot(data):
|
||||
def update_bot_data_replace_bot(data: Dict) -> None:
|
||||
return update_bot_data(instance.replace_bot(data))
|
||||
|
||||
instance.get_user_data = get_user_data_insert_bot
|
||||
|
@ -105,13 +108,16 @@ class BasePersistence(ABC):
|
|||
instance.update_bot_data = update_bot_data_replace_bot
|
||||
return instance
|
||||
|
||||
def __init__(self, store_user_data=True, store_chat_data=True, store_bot_data=True):
|
||||
def __init__(self,
|
||||
store_user_data: bool = True,
|
||||
store_chat_data: bool = True,
|
||||
store_bot_data: bool = True):
|
||||
self.store_user_data = store_user_data
|
||||
self.store_chat_data = store_chat_data
|
||||
self.store_bot_data = store_bot_data
|
||||
self.bot = None
|
||||
self.bot: Bot = None # type: ignore[assignment]
|
||||
|
||||
def set_bot(self, bot):
|
||||
def set_bot(self, bot: Bot) -> None:
|
||||
"""Set the Bot to be used by this persistence instance.
|
||||
|
||||
Args:
|
||||
|
@ -120,7 +126,7 @@ class BasePersistence(ABC):
|
|||
self.bot = bot
|
||||
|
||||
@classmethod
|
||||
def replace_bot(cls, obj):
|
||||
def replace_bot(cls, obj: object) -> object:
|
||||
"""
|
||||
Replaces all instances of :class:`telegram.Bot` that occur within the passed object with
|
||||
:attr:`REPLACED_BOT`. Currently, this handles objects of type ``list``, ``tuple``, ``set``,
|
||||
|
@ -140,6 +146,7 @@ class BasePersistence(ABC):
|
|||
|
||||
new_obj = copy(obj)
|
||||
if isinstance(obj, (dict, defaultdict)):
|
||||
new_obj = cast(dict, new_obj)
|
||||
new_obj.clear()
|
||||
for k, v in obj.items():
|
||||
new_obj[cls.replace_bot(k)] = cls.replace_bot(v)
|
||||
|
@ -156,7 +163,7 @@ class BasePersistence(ABC):
|
|||
|
||||
return obj
|
||||
|
||||
def insert_bot(self, obj):
|
||||
def insert_bot(self, obj: object) -> object:
|
||||
"""
|
||||
Replaces all instances of :attr:`REPLACED_BOT` that occur within the passed object with
|
||||
:attr:`bot`. Currently, this handles objects of type ``list``, ``tuple``, ``set``,
|
||||
|
@ -178,6 +185,7 @@ class BasePersistence(ABC):
|
|||
|
||||
new_obj = copy(obj)
|
||||
if isinstance(obj, (dict, defaultdict)):
|
||||
new_obj = cast(dict, new_obj)
|
||||
new_obj.clear()
|
||||
for k, v in obj.items():
|
||||
new_obj[self.insert_bot(k)] = self.insert_bot(v)
|
||||
|
@ -194,7 +202,7 @@ class BasePersistence(ABC):
|
|||
return obj
|
||||
|
||||
@abstractmethod
|
||||
def get_user_data(self):
|
||||
def get_user_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
||||
""""Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
||||
persistence object. It should return the user_data if stored, or an empty
|
||||
``defaultdict(dict)``.
|
||||
|
@ -204,7 +212,7 @@ class BasePersistence(ABC):
|
|||
"""
|
||||
|
||||
@abstractmethod
|
||||
def get_chat_data(self):
|
||||
def get_chat_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
||||
""""Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
||||
persistence object. It should return the chat_data if stored, or an empty
|
||||
``defaultdict(dict)``.
|
||||
|
@ -214,7 +222,7 @@ class BasePersistence(ABC):
|
|||
"""
|
||||
|
||||
@abstractmethod
|
||||
def get_bot_data(self):
|
||||
def get_bot_data(self) -> Dict[Any, Any]:
|
||||
""""Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
||||
persistence object. It should return the bot_data if stored, or an empty
|
||||
:obj:`dict`.
|
||||
|
@ -224,7 +232,7 @@ class BasePersistence(ABC):
|
|||
"""
|
||||
|
||||
@abstractmethod
|
||||
def get_conversations(self, name):
|
||||
def get_conversations(self, name: str) -> ConversationDict:
|
||||
""""Will be called by :class:`telegram.ext.Dispatcher` when a
|
||||
:class:`telegram.ext.ConversationHandler` is added if
|
||||
:attr:`telegram.ext.ConversationHandler.persistent` is :obj:`True`.
|
||||
|
@ -238,7 +246,9 @@ class BasePersistence(ABC):
|
|||
"""
|
||||
|
||||
@abstractmethod
|
||||
def update_conversation(self, name, key, new_state):
|
||||
def update_conversation(self,
|
||||
name: str, key: Tuple[int, ...],
|
||||
new_state: Optional[object]) -> None:
|
||||
"""Will be called when a :attr:`telegram.ext.ConversationHandler.update_state`
|
||||
is called. This allows the storage of the new state in the persistence.
|
||||
|
||||
|
@ -249,7 +259,7 @@ class BasePersistence(ABC):
|
|||
"""
|
||||
|
||||
@abstractmethod
|
||||
def update_user_data(self, user_id, data):
|
||||
def update_user_data(self, user_id: int, data: Dict) -> None:
|
||||
"""Will be called by the :class:`telegram.ext.Dispatcher` after a handler has
|
||||
handled an update.
|
||||
|
||||
|
@ -259,7 +269,7 @@ class BasePersistence(ABC):
|
|||
"""
|
||||
|
||||
@abstractmethod
|
||||
def update_chat_data(self, chat_id, data):
|
||||
def update_chat_data(self, chat_id: int, data: Dict) -> None:
|
||||
"""Will be called by the :class:`telegram.ext.Dispatcher` after a handler has
|
||||
handled an update.
|
||||
|
||||
|
@ -269,7 +279,7 @@ class BasePersistence(ABC):
|
|||
"""
|
||||
|
||||
@abstractmethod
|
||||
def update_bot_data(self, data):
|
||||
def update_bot_data(self, data: Dict) -> None:
|
||||
"""Will be called by the :class:`telegram.ext.Dispatcher` after a handler has
|
||||
handled an update.
|
||||
|
||||
|
@ -277,7 +287,7 @@ class BasePersistence(ABC):
|
|||
data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.bot_data` .
|
||||
"""
|
||||
|
||||
def flush(self):
|
||||
def flush(self) -> None:
|
||||
"""Will be called by :class:`telegram.ext.Updater` upon receiving a stop signal. Gives the
|
||||
persistence a chance to finish up saving or close a database connection gracefully. If this
|
||||
is not of any importance just pass will be sufficient.
|
||||
|
|
|
@ -17,8 +17,13 @@
|
|||
# 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 the CallbackContext class."""
|
||||
from queue import Queue
|
||||
from typing import Dict, Any, Tuple, TYPE_CHECKING, Optional, Match, List, NoReturn, Union
|
||||
|
||||
from telegram import Update
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
from telegram.ext import Dispatcher, Job, JobQueue
|
||||
|
||||
|
||||
class CallbackContext:
|
||||
|
@ -80,7 +85,7 @@ class CallbackContext:
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, dispatcher):
|
||||
def __init__(self, dispatcher: 'Dispatcher'):
|
||||
"""
|
||||
Args:
|
||||
dispatcher (:class:`telegram.ext.Dispatcher`):
|
||||
|
@ -90,49 +95,54 @@ class CallbackContext:
|
|||
'dispatcher!')
|
||||
self._dispatcher = dispatcher
|
||||
self._bot_data = dispatcher.bot_data
|
||||
self._chat_data = None
|
||||
self._user_data = None
|
||||
self.args = None
|
||||
self.matches = None
|
||||
self.error = None
|
||||
self.job = None
|
||||
self.async_args = None
|
||||
self.async_kwargs = None
|
||||
self._chat_data: Optional[Dict[Any, Any]] = None
|
||||
self._user_data: Optional[Dict[Any, Any]] = None
|
||||
self.args: Optional[List[str]] = None
|
||||
self.matches: Optional[List[Match]] = None
|
||||
self.error: Optional[Exception] = None
|
||||
self.job: Optional['Job'] = None
|
||||
self.async_args: Optional[Union[List, Tuple]] = None
|
||||
self.async_kwargs: Optional[Dict[str, Any]] = None
|
||||
|
||||
@property
|
||||
def dispatcher(self):
|
||||
def dispatcher(self) -> 'Dispatcher':
|
||||
""":class:`telegram.ext.Dispatcher`: The dispatcher associated with this context."""
|
||||
return self._dispatcher
|
||||
|
||||
@property
|
||||
def bot_data(self):
|
||||
def bot_data(self) -> Dict:
|
||||
return self._bot_data
|
||||
|
||||
@bot_data.setter
|
||||
def bot_data(self, value):
|
||||
def bot_data(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to bot_data, see "
|
||||
"https://git.io/fjxKe")
|
||||
|
||||
@property
|
||||
def chat_data(self):
|
||||
def chat_data(self) -> Optional[Dict]:
|
||||
return self._chat_data
|
||||
|
||||
@chat_data.setter
|
||||
def chat_data(self, value):
|
||||
def chat_data(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to chat_data, see "
|
||||
"https://git.io/fjxKe")
|
||||
|
||||
@property
|
||||
def user_data(self):
|
||||
def user_data(self) -> Optional[Dict]:
|
||||
return self._user_data
|
||||
|
||||
@user_data.setter
|
||||
def user_data(self, value):
|
||||
def user_data(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to user_data, see "
|
||||
"https://git.io/fjxKe")
|
||||
|
||||
@classmethod
|
||||
def from_error(cls, update, error, dispatcher, async_args=None, async_kwargs=None):
|
||||
def from_error(cls,
|
||||
update: object,
|
||||
error: Exception,
|
||||
dispatcher: 'Dispatcher',
|
||||
async_args: Union[List, Tuple] = None,
|
||||
async_kwargs: Dict[str, Any] = None) -> 'CallbackContext':
|
||||
self = cls.from_update(update, dispatcher)
|
||||
self.error = error
|
||||
self.async_args = async_args
|
||||
|
@ -140,7 +150,7 @@ class CallbackContext:
|
|||
return self
|
||||
|
||||
@classmethod
|
||||
def from_update(cls, update, dispatcher):
|
||||
def from_update(cls, update: object, dispatcher: 'Dispatcher') -> 'CallbackContext':
|
||||
self = cls(dispatcher)
|
||||
|
||||
if update is not None and isinstance(update, Update):
|
||||
|
@ -154,21 +164,21 @@ class CallbackContext:
|
|||
return self
|
||||
|
||||
@classmethod
|
||||
def from_job(cls, job, dispatcher):
|
||||
def from_job(cls, job: 'Job', dispatcher: 'Dispatcher') -> 'CallbackContext':
|
||||
self = cls(dispatcher)
|
||||
self.job = job
|
||||
return self
|
||||
|
||||
def update(self, data):
|
||||
def update(self, data: Dict[str, Any]) -> None:
|
||||
self.__dict__.update(data)
|
||||
|
||||
@property
|
||||
def bot(self):
|
||||
def bot(self) -> 'Bot':
|
||||
""":class:`telegram.Bot`: The bot associated with this context."""
|
||||
return self._dispatcher.bot
|
||||
|
||||
@property
|
||||
def job_queue(self):
|
||||
def job_queue(self) -> Optional['JobQueue']:
|
||||
"""
|
||||
:class:`telegram.ext.JobQueue`: The ``JobQueue`` used by the
|
||||
:class:`telegram.ext.Dispatcher` and (usually) the :class:`telegram.ext.Updater`
|
||||
|
@ -178,7 +188,7 @@ class CallbackContext:
|
|||
return self._dispatcher.job_queue
|
||||
|
||||
@property
|
||||
def update_queue(self):
|
||||
def update_queue(self) -> Queue:
|
||||
"""
|
||||
:class:`queue.Queue`: The ``Queue`` instance used by the
|
||||
:class:`telegram.ext.Dispatcher` and (usually) the :class:`telegram.ext.Updater`
|
||||
|
@ -188,13 +198,13 @@ class CallbackContext:
|
|||
return self._dispatcher.update_queue
|
||||
|
||||
@property
|
||||
def match(self):
|
||||
def match(self) -> Optional[Match[str]]:
|
||||
"""
|
||||
`Regex match type`: The first match from :attr:`matches`.
|
||||
Useful if you are only filtering using a single regex filter.
|
||||
Returns `None` if :attr:`matches` is empty.
|
||||
"""
|
||||
try:
|
||||
return self.matches[0] # pylint: disable=unsubscriptable-object
|
||||
return self.matches[0] # type: ignore[index] # pylint: disable=unsubscriptable-object
|
||||
except (IndexError, TypeError):
|
||||
return None
|
||||
|
|
|
@ -23,6 +23,15 @@ import re
|
|||
from telegram import Update
|
||||
from .handler import Handler
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Pattern, Match, Dict, \
|
||||
cast
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class CallbackQueryHandler(Handler):
|
||||
"""Handler class to handle Telegram callback queries. Optionally based on a regex.
|
||||
|
@ -102,15 +111,15 @@ class CallbackQueryHandler(Handler):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
callback,
|
||||
pass_update_queue=False,
|
||||
pass_job_queue=False,
|
||||
pattern=None,
|
||||
pass_groups=False,
|
||||
pass_groupdict=False,
|
||||
pass_user_data=False,
|
||||
pass_chat_data=False,
|
||||
run_async=False):
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pattern: Union[str, Pattern] = None,
|
||||
pass_groups: bool = False,
|
||||
pass_groupdict: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False):
|
||||
super().__init__(
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
|
@ -126,7 +135,7 @@ class CallbackQueryHandler(Handler):
|
|||
self.pass_groups = pass_groups
|
||||
self.pass_groupdict = pass_groupdict
|
||||
|
||||
def check_update(self, update):
|
||||
def check_update(self, update: HandlerArg) -> Optional[Union[bool, object]]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
|
@ -144,16 +153,26 @@ class CallbackQueryHandler(Handler):
|
|||
return match
|
||||
else:
|
||||
return True
|
||||
return None
|
||||
|
||||
def collect_optional_args(self, dispatcher, update=None, check_result=None):
|
||||
def collect_optional_args(self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Union[bool, Match] = None) -> Dict[str, Any]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if self.pattern:
|
||||
check_result = cast(Match, check_result)
|
||||
if self.pass_groups:
|
||||
optional_args['groups'] = check_result.groups()
|
||||
if self.pass_groupdict:
|
||||
optional_args['groupdict'] = check_result.groupdict()
|
||||
return optional_args
|
||||
|
||||
def collect_additional_context(self, context, update, dispatcher, check_result):
|
||||
def collect_additional_context(self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Union[bool, Match]) -> None:
|
||||
if self.pattern:
|
||||
check_result = cast(Match, check_result)
|
||||
context.matches = [check_result]
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
from telegram import Update
|
||||
from .handler import Handler
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from typing import Optional, Union, TypeVar
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class ChosenInlineResultHandler(Handler):
|
||||
"""Handler class to handle Telegram updates that contain a chosen inline result.
|
||||
|
@ -80,7 +84,7 @@ class ChosenInlineResultHandler(Handler):
|
|||
|
||||
"""
|
||||
|
||||
def check_update(self, update):
|
||||
def check_update(self, update: HandlerArg) -> Optional[Union[bool, object]]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
|
|
|
@ -20,12 +20,19 @@
|
|||
import re
|
||||
import warnings
|
||||
|
||||
from telegram.ext import Filters
|
||||
from telegram.ext import Filters, BaseFilter
|
||||
from telegram.utils.deprecate import TelegramDeprecationWarning
|
||||
|
||||
from telegram import Update, MessageEntity
|
||||
from .handler import Handler
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict, List, Tuple
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class CommandHandler(Handler):
|
||||
"""Handler class to handle Telegram commands.
|
||||
|
@ -124,16 +131,16 @@ class CommandHandler(Handler):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
command,
|
||||
callback,
|
||||
filters=None,
|
||||
allow_edited=None,
|
||||
pass_args=False,
|
||||
pass_update_queue=False,
|
||||
pass_job_queue=False,
|
||||
pass_user_data=False,
|
||||
pass_chat_data=False,
|
||||
run_async=False):
|
||||
command: Union[str, List[str]],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
filters: BaseFilter = None,
|
||||
allow_edited: bool = None,
|
||||
pass_args: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False):
|
||||
super().__init__(
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
|
@ -163,7 +170,10 @@ class CommandHandler(Handler):
|
|||
self.filters &= ~Filters.update.edited_message
|
||||
self.pass_args = pass_args
|
||||
|
||||
def check_update(self, update):
|
||||
def check_update(
|
||||
self,
|
||||
update: HandlerArg) -> Optional[Union[bool, Tuple[List[str],
|
||||
Optional[Union[bool, Dict]]]]]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
|
@ -177,14 +187,14 @@ class CommandHandler(Handler):
|
|||
message = update.effective_message
|
||||
|
||||
if (message.entities and message.entities[0].type == MessageEntity.BOT_COMMAND
|
||||
and message.entities[0].offset == 0):
|
||||
and message.entities[0].offset == 0 and message.text and message.bot):
|
||||
command = message.text[1:message.entities[0].length]
|
||||
args = message.text.split()[1:]
|
||||
command = command.split('@')
|
||||
command.append(message.bot.username)
|
||||
command_parts = command.split('@')
|
||||
command_parts.append(message.bot.username)
|
||||
|
||||
if not (command[0].lower() in self.command
|
||||
and command[1].lower() == message.bot.username.lower()):
|
||||
if not (command_parts[0].lower() in self.command
|
||||
and command_parts[1].lower() == message.bot.username.lower()):
|
||||
return None
|
||||
|
||||
filter_result = self.filters(update)
|
||||
|
@ -192,17 +202,29 @@ class CommandHandler(Handler):
|
|||
return args, filter_result
|
||||
else:
|
||||
return False
|
||||
return None
|
||||
|
||||
def collect_optional_args(self, dispatcher, update=None, check_result=None):
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[Union[bool, Tuple[List[str],
|
||||
Optional[bool]]]] = None) -> Dict[str, Any]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update)
|
||||
if self.pass_args:
|
||||
if self.pass_args and isinstance(check_result, tuple):
|
||||
optional_args['args'] = check_result[0]
|
||||
return optional_args
|
||||
|
||||
def collect_additional_context(self, context, update, dispatcher, check_result):
|
||||
context.args = check_result[0]
|
||||
if isinstance(check_result[1], dict):
|
||||
context.update(check_result[1])
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]]) -> None:
|
||||
if isinstance(check_result, tuple):
|
||||
context.args = check_result[0]
|
||||
if isinstance(check_result[1], dict):
|
||||
context.update(check_result[1])
|
||||
|
||||
|
||||
class PrefixHandler(CommandHandler):
|
||||
|
@ -309,20 +331,20 @@ class PrefixHandler(CommandHandler):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
prefix,
|
||||
command,
|
||||
callback,
|
||||
filters=None,
|
||||
pass_args=False,
|
||||
pass_update_queue=False,
|
||||
pass_job_queue=False,
|
||||
pass_user_data=False,
|
||||
pass_chat_data=False,
|
||||
run_async=False):
|
||||
prefix: Union[str, List[str]],
|
||||
command: Union[str, List[str]],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
filters: BaseFilter = None,
|
||||
pass_args: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False):
|
||||
|
||||
self._prefix = list()
|
||||
self._command = list()
|
||||
self._commands = list()
|
||||
self._prefix: List[str] = list()
|
||||
self._command: List[str] = list()
|
||||
self._commands: List[str] = list()
|
||||
|
||||
super().__init__(
|
||||
'nocommand', callback, filters=filters, allow_edited=None, pass_args=pass_args,
|
||||
|
@ -332,38 +354,39 @@ class PrefixHandler(CommandHandler):
|
|||
pass_chat_data=pass_chat_data,
|
||||
run_async=run_async)
|
||||
|
||||
self.prefix = prefix
|
||||
self.command = command
|
||||
self.prefix = prefix # type: ignore[assignment]
|
||||
self.command = command # type: ignore[assignment]
|
||||
self._build_commands()
|
||||
|
||||
@property
|
||||
def prefix(self):
|
||||
def prefix(self) -> List[str]:
|
||||
return self._prefix
|
||||
|
||||
@prefix.setter
|
||||
def prefix(self, prefix):
|
||||
def prefix(self, prefix: Union[str, List[str]]) -> None:
|
||||
if isinstance(prefix, str):
|
||||
self._prefix = [prefix.lower()]
|
||||
else:
|
||||
self._prefix = prefix
|
||||
self._build_commands()
|
||||
|
||||
@property
|
||||
def command(self):
|
||||
@property # type: ignore[override]
|
||||
def command(self) -> List[str]: # type: ignore[override]
|
||||
return self._command
|
||||
|
||||
@command.setter
|
||||
def command(self, command):
|
||||
def command(self, command: Union[str, List[str]]) -> None:
|
||||
if isinstance(command, str):
|
||||
self._command = [command.lower()]
|
||||
else:
|
||||
self._command = command
|
||||
self._build_commands()
|
||||
|
||||
def _build_commands(self):
|
||||
def _build_commands(self) -> None:
|
||||
self._commands = [x.lower() + y.lower() for x in self.prefix for y in self.command]
|
||||
|
||||
def check_update(self, update):
|
||||
def check_update(self, update: HandlerArg) -> Optional[Union[bool, Tuple[List[str],
|
||||
Optional[Union[bool, Dict]]]]]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
|
@ -385,8 +408,15 @@ class PrefixHandler(CommandHandler):
|
|||
return text_list[1:], filter_result
|
||||
else:
|
||||
return False
|
||||
return None
|
||||
|
||||
def collect_additional_context(self, context, update, dispatcher, check_result):
|
||||
context.args = check_result[0]
|
||||
if isinstance(check_result[1], dict):
|
||||
context.update(check_result[1])
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]]) -> None:
|
||||
if isinstance(check_result, tuple):
|
||||
context.args = check_result[0]
|
||||
if isinstance(check_result[1], dict):
|
||||
context.update(check_result[1])
|
||||
|
|
|
@ -24,12 +24,24 @@ from threading import Lock
|
|||
|
||||
from telegram import Update
|
||||
from telegram.ext import (Handler, CallbackQueryHandler, InlineQueryHandler,
|
||||
ChosenInlineResultHandler, CallbackContext, DispatcherHandlerStop)
|
||||
ChosenInlineResultHandler, CallbackContext, BasePersistence,
|
||||
DispatcherHandlerStop)
|
||||
from telegram.utils.promise import Promise
|
||||
|
||||
from telegram.utils.types import ConversationDict, HandlerArg
|
||||
from typing import Dict, Any, List, Optional, Tuple, TYPE_CHECKING, cast, NoReturn
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import Dispatcher, Job
|
||||
CheckUpdateType = Optional[Tuple[Tuple[int, ...], Handler, object]]
|
||||
|
||||
|
||||
class _ConversationTimeoutContext:
|
||||
def __init__(self, conversation_key, update, dispatcher, callback_context):
|
||||
def __init__(self,
|
||||
conversation_key: Tuple[int, ...],
|
||||
update: Update,
|
||||
dispatcher: 'Dispatcher',
|
||||
callback_context: Optional[CallbackContext]):
|
||||
self.conversation_key = conversation_key
|
||||
self.update = update
|
||||
self.dispatcher = dispatcher
|
||||
|
@ -157,17 +169,17 @@ class ConversationHandler(Handler):
|
|||
previous ``@run_sync`` decorated running handler to finish."""
|
||||
|
||||
def __init__(self,
|
||||
entry_points,
|
||||
states,
|
||||
fallbacks,
|
||||
allow_reentry=False,
|
||||
per_chat=True,
|
||||
per_user=True,
|
||||
per_message=False,
|
||||
conversation_timeout=None,
|
||||
name=None,
|
||||
persistent=False,
|
||||
map_to_parent=None):
|
||||
entry_points: List[Handler],
|
||||
states: Dict[object, List[Handler]],
|
||||
fallbacks: List[Handler],
|
||||
allow_reentry: bool = False,
|
||||
per_chat: bool = True,
|
||||
per_user: bool = True,
|
||||
per_message: bool = False,
|
||||
conversation_timeout: int = None,
|
||||
name: str = None,
|
||||
persistent: bool = False,
|
||||
map_to_parent: Dict[object, object] = None):
|
||||
self.run_async = False
|
||||
|
||||
self._entry_points = entry_points
|
||||
|
@ -182,15 +194,15 @@ class ConversationHandler(Handler):
|
|||
self._name = name
|
||||
if persistent and not self.name:
|
||||
raise ValueError("Conversations can't be persistent when handler is unnamed.")
|
||||
self.persistent = persistent
|
||||
self._persistence = None
|
||||
self.persistent: bool = persistent
|
||||
self._persistence: Optional[BasePersistence] = None
|
||||
""":obj:`telegram.ext.BasePersistence`: The persistence used to store conversations.
|
||||
Set by dispatcher"""
|
||||
self._map_to_parent = map_to_parent
|
||||
|
||||
self.timeout_jobs = dict()
|
||||
self.timeout_jobs: Dict[Tuple[int, ...], 'Job'] = dict()
|
||||
self._timeout_jobs_lock = Lock()
|
||||
self._conversations = dict()
|
||||
self._conversations: ConversationDict = dict()
|
||||
self._conversations_lock = Lock()
|
||||
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
@ -231,92 +243,92 @@ class ConversationHandler(Handler):
|
|||
break
|
||||
|
||||
@property
|
||||
def entry_points(self):
|
||||
def entry_points(self) -> List[Handler]:
|
||||
return self._entry_points
|
||||
|
||||
@entry_points.setter
|
||||
def entry_points(self, value):
|
||||
def entry_points(self, value: Any) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to entry_points after initialization.')
|
||||
|
||||
@property
|
||||
def states(self):
|
||||
def states(self) -> Dict[object, List[Handler]]:
|
||||
return self._states
|
||||
|
||||
@states.setter
|
||||
def states(self, value):
|
||||
def states(self, value: Any) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to states after initialization.')
|
||||
|
||||
@property
|
||||
def fallbacks(self):
|
||||
def fallbacks(self) -> List[Handler]:
|
||||
return self._fallbacks
|
||||
|
||||
@fallbacks.setter
|
||||
def fallbacks(self, value):
|
||||
def fallbacks(self, value: Any) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to fallbacks after initialization.')
|
||||
|
||||
@property
|
||||
def allow_reentry(self):
|
||||
def allow_reentry(self) -> bool:
|
||||
return self._allow_reentry
|
||||
|
||||
@allow_reentry.setter
|
||||
def allow_reentry(self, value):
|
||||
def allow_reentry(self, value: Any) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to allow_reentry after initialization.')
|
||||
|
||||
@property
|
||||
def per_user(self):
|
||||
def per_user(self) -> bool:
|
||||
return self._per_user
|
||||
|
||||
@per_user.setter
|
||||
def per_user(self, value):
|
||||
def per_user(self, value: Any) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to per_user after initialization.')
|
||||
|
||||
@property
|
||||
def per_chat(self):
|
||||
def per_chat(self) -> bool:
|
||||
return self._per_chat
|
||||
|
||||
@per_chat.setter
|
||||
def per_chat(self, value):
|
||||
def per_chat(self, value: Any) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to per_chat after initialization.')
|
||||
|
||||
@property
|
||||
def per_message(self):
|
||||
def per_message(self) -> bool:
|
||||
return self._per_message
|
||||
|
||||
@per_message.setter
|
||||
def per_message(self, value):
|
||||
def per_message(self, value: Any) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to per_message after initialization.')
|
||||
|
||||
@property
|
||||
def conversation_timeout(self):
|
||||
def conversation_timeout(self) -> Optional[int]:
|
||||
return self._conversation_timeout
|
||||
|
||||
@conversation_timeout.setter
|
||||
def conversation_timeout(self, value):
|
||||
def conversation_timeout(self, value: Any) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to conversation_timeout after '
|
||||
'initialization.')
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
def name(self) -> Optional[str]:
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, value):
|
||||
def name(self, value: Any) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to name after initialization.')
|
||||
|
||||
@property
|
||||
def map_to_parent(self):
|
||||
def map_to_parent(self) -> Optional[Dict[object, object]]:
|
||||
return self._map_to_parent
|
||||
|
||||
@map_to_parent.setter
|
||||
def map_to_parent(self, value):
|
||||
def map_to_parent(self, value: Any) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to map_to_parent after initialization.')
|
||||
|
||||
@property
|
||||
def persistence(self):
|
||||
def persistence(self) -> Optional[BasePersistence]:
|
||||
return self._persistence
|
||||
|
||||
@persistence.setter
|
||||
def persistence(self, persistence):
|
||||
def persistence(self, persistence: BasePersistence) -> None:
|
||||
self._persistence = persistence
|
||||
# Set persistence for nested conversations
|
||||
for handlers in self.states.values():
|
||||
|
@ -325,37 +337,37 @@ class ConversationHandler(Handler):
|
|||
handler.persistence = self.persistence
|
||||
|
||||
@property
|
||||
def conversations(self):
|
||||
def conversations(self) -> ConversationDict:
|
||||
return self._conversations
|
||||
|
||||
@conversations.setter
|
||||
def conversations(self, value):
|
||||
def conversations(self, value: ConversationDict) -> None:
|
||||
self._conversations = value
|
||||
# Set conversations for nested conversations
|
||||
for handlers in self.states.values():
|
||||
for handler in handlers:
|
||||
if isinstance(handler, ConversationHandler):
|
||||
if isinstance(handler, ConversationHandler) and self.persistence and handler.name:
|
||||
handler.conversations = self.persistence.get_conversations(handler.name)
|
||||
|
||||
def _get_key(self, update):
|
||||
def _get_key(self, update: Update) -> Tuple[int, ...]:
|
||||
chat = update.effective_chat
|
||||
user = update.effective_user
|
||||
|
||||
key = list()
|
||||
|
||||
if self.per_chat:
|
||||
key.append(chat.id)
|
||||
key.append(chat.id) # type: ignore[union-attr]
|
||||
|
||||
if self.per_user and user is not None:
|
||||
key.append(user.id)
|
||||
|
||||
if self.per_message:
|
||||
key.append(update.callback_query.inline_message_id
|
||||
or update.callback_query.message.message_id)
|
||||
key.append(update.callback_query.inline_message_id # type: ignore[union-attr]
|
||||
or update.callback_query.message.message_id) # type: ignore[union-attr]
|
||||
|
||||
return tuple(key)
|
||||
|
||||
def check_update(self, update):
|
||||
def check_update(self, update: HandlerArg) -> CheckUpdateType:
|
||||
"""
|
||||
Determines whether an update should be handled by this conversationhandler, and if so in
|
||||
which state the conversation currently is.
|
||||
|
@ -399,11 +411,11 @@ class ConversationHandler(Handler):
|
|||
with self._conversations_lock:
|
||||
state = self.conversations.get(key)
|
||||
else:
|
||||
handlers = self.states.get(self.WAITING, [])
|
||||
for handler in handlers:
|
||||
check = handler.check_update(update)
|
||||
hdlrs = self.states.get(self.WAITING, [])
|
||||
for hdlr in hdlrs:
|
||||
check = hdlr.check_update(update)
|
||||
if check is not None and check is not False:
|
||||
return key, handler, check
|
||||
return key, hdlr, check
|
||||
return None
|
||||
|
||||
self.logger.debug('selecting conversation {} with state {}'.format(str(key), str(state)))
|
||||
|
@ -443,9 +455,13 @@ class ConversationHandler(Handler):
|
|||
else:
|
||||
return None
|
||||
|
||||
return key, handler, check
|
||||
return key, handler, check # type: ignore[return-value]
|
||||
|
||||
def handle_update(self, update, dispatcher, check_result, context=None):
|
||||
def handle_update(self, # type: ignore[override]
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: CheckUpdateType,
|
||||
context: CallbackContext = None) -> Optional[object]:
|
||||
"""Send the update to the callback for the current state and Handler
|
||||
|
||||
Args:
|
||||
|
@ -453,9 +469,12 @@ class ConversationHandler(Handler):
|
|||
handler, and the handler's check result.
|
||||
update (:class:`telegram.Update`): Incoming telegram update.
|
||||
dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that originated the Update.
|
||||
context (:class:`telegram.ext.CallbackContext`, optional): The context as provided by
|
||||
the dispatcher.
|
||||
|
||||
"""
|
||||
conversation_key, handler, check_result = check_result
|
||||
update = cast(Update, update) # for mypy
|
||||
conversation_key, handler, check_result = check_result # type: ignore[assignment,misc]
|
||||
raise_dp_handler_stop = False
|
||||
|
||||
with self._timeout_jobs_lock:
|
||||
|
@ -464,18 +483,16 @@ class ConversationHandler(Handler):
|
|||
|
||||
if timeout_job is not None:
|
||||
timeout_job.schedule_removal()
|
||||
|
||||
try:
|
||||
new_state = handler.handle_update(update, dispatcher, check_result, context)
|
||||
except DispatcherHandlerStop as e:
|
||||
new_state = e.state
|
||||
raise_dp_handler_stop = True
|
||||
|
||||
with self._timeout_jobs_lock:
|
||||
if self.conversation_timeout and new_state != self.END:
|
||||
if self.conversation_timeout and new_state != self.END and dispatcher.job_queue:
|
||||
# Add the new timeout job
|
||||
self.timeout_jobs[conversation_key] = dispatcher.job_queue.run_once(
|
||||
self._trigger_timeout, self.conversation_timeout,
|
||||
self._trigger_timeout, self.conversation_timeout, # type: ignore[arg-type]
|
||||
context=_ConversationTimeoutContext(conversation_key, update,
|
||||
dispatcher, context))
|
||||
|
||||
|
@ -491,30 +508,35 @@ class ConversationHandler(Handler):
|
|||
# Don't pass the new state here. If we're in a nested conversation, the parent is
|
||||
# expecting None as return value.
|
||||
raise DispatcherHandlerStop()
|
||||
return None
|
||||
|
||||
def update_state(self, new_state, key):
|
||||
def update_state(self,
|
||||
new_state: object,
|
||||
key: Tuple[int, ...]) -> None:
|
||||
if new_state == self.END:
|
||||
with self._conversations_lock:
|
||||
if key in self.conversations:
|
||||
# If there is no key in conversations, nothing is done.
|
||||
del self.conversations[key]
|
||||
if self.persistent:
|
||||
if self.persistent and self.persistence and self.name:
|
||||
self.persistence.update_conversation(self.name, key, None)
|
||||
|
||||
elif isinstance(new_state, Promise):
|
||||
with self._conversations_lock:
|
||||
self.conversations[key] = (self.conversations.get(key), new_state)
|
||||
if self.persistent:
|
||||
if self.persistent and self.persistence and self.name:
|
||||
self.persistence.update_conversation(self.name, key,
|
||||
(self.conversations.get(key), new_state))
|
||||
|
||||
elif new_state is not None:
|
||||
with self._conversations_lock:
|
||||
self.conversations[key] = new_state
|
||||
if self.persistent:
|
||||
if self.persistent and self.persistence and self.name:
|
||||
self.persistence.update_conversation(self.name, key, new_state)
|
||||
|
||||
def _trigger_timeout(self, context, job=None):
|
||||
def _trigger_timeout(self,
|
||||
context: _ConversationTimeoutContext,
|
||||
job: 'Job' = None) -> None:
|
||||
self.logger.debug('conversation timeout was triggered!')
|
||||
|
||||
# Backward compatibility with bots that do not use CallbackContext
|
||||
|
@ -522,7 +544,7 @@ class ConversationHandler(Handler):
|
|||
if isinstance(context, CallbackContext):
|
||||
job = context.job
|
||||
|
||||
context = job.context
|
||||
context = job.context # type:ignore[union-attr,assignment]
|
||||
callback_context = context.callback_context
|
||||
|
||||
with self._timeout_jobs_lock:
|
||||
|
|
|
@ -18,8 +18,9 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the class Defaults, which allows to pass default values to Updater."""
|
||||
import pytz
|
||||
from typing import Union, Optional, Any, NoReturn
|
||||
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
|
||||
|
||||
class Defaults:
|
||||
|
@ -60,14 +61,14 @@ class Defaults:
|
|||
``pytz`` module. Defaults to UTC.
|
||||
"""
|
||||
def __init__(self,
|
||||
parse_mode=None,
|
||||
disable_notification=None,
|
||||
disable_web_page_preview=None,
|
||||
parse_mode: str = None,
|
||||
disable_notification: bool = None,
|
||||
disable_web_page_preview: bool = None,
|
||||
# Timeout needs special treatment, since the bot methods have two different
|
||||
# default values for timeout (None and 20s)
|
||||
timeout=DEFAULT_NONE,
|
||||
quote=None,
|
||||
tzinfo=pytz.utc):
|
||||
timeout: Union[float, DefaultValue] = DEFAULT_NONE,
|
||||
quote: bool = None,
|
||||
tzinfo: pytz.BaseTzInfo = pytz.utc):
|
||||
self._parse_mode = parse_mode
|
||||
self._disable_notification = disable_notification
|
||||
self._disable_web_page_preview = disable_web_page_preview
|
||||
|
@ -76,60 +77,60 @@ class Defaults:
|
|||
self._tzinfo = tzinfo
|
||||
|
||||
@property
|
||||
def parse_mode(self):
|
||||
def parse_mode(self) -> Optional[str]:
|
||||
return self._parse_mode
|
||||
|
||||
@parse_mode.setter
|
||||
def parse_mode(self, value):
|
||||
def parse_mode(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
||||
"not have any effect.")
|
||||
|
||||
@property
|
||||
def disable_notification(self):
|
||||
def disable_notification(self) -> Optional[bool]:
|
||||
return self._disable_notification
|
||||
|
||||
@disable_notification.setter
|
||||
def disable_notification(self, value):
|
||||
def disable_notification(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
||||
"not have any effect.")
|
||||
|
||||
@property
|
||||
def disable_web_page_preview(self):
|
||||
def disable_web_page_preview(self) -> Optional[bool]:
|
||||
return self._disable_web_page_preview
|
||||
|
||||
@disable_web_page_preview.setter
|
||||
def disable_web_page_preview(self, value):
|
||||
def disable_web_page_preview(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
||||
"not have any effect.")
|
||||
|
||||
@property
|
||||
def timeout(self):
|
||||
def timeout(self) -> Union[float, DefaultValue]:
|
||||
return self._timeout
|
||||
|
||||
@timeout.setter
|
||||
def timeout(self, value):
|
||||
def timeout(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
||||
"not have any effect.")
|
||||
|
||||
@property
|
||||
def quote(self):
|
||||
def quote(self) -> Optional[bool]:
|
||||
return self._quote
|
||||
|
||||
@quote.setter
|
||||
def quote(self, value):
|
||||
def quote(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
||||
"not have any effect.")
|
||||
|
||||
@property
|
||||
def tzinfo(self):
|
||||
def tzinfo(self) -> pytz.BaseTzInfo:
|
||||
return self._tzinfo
|
||||
|
||||
@tzinfo.setter
|
||||
def tzinfo(self, value):
|
||||
def tzinfo(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
||||
"not have any effect.")
|
||||
|
||||
def __hash__(self):
|
||||
def __hash__(self) -> int:
|
||||
return hash((self._parse_mode,
|
||||
self._disable_notification,
|
||||
self._disable_web_page_preview,
|
||||
|
@ -137,10 +138,10 @@ class Defaults:
|
|||
self._quote,
|
||||
self._tzinfo))
|
||||
|
||||
def __eq__(self, other):
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if isinstance(other, Defaults):
|
||||
return self.__dict__ == other.__dict__
|
||||
return False
|
||||
|
||||
def __ne__(self, other):
|
||||
def __ne__(self, other: object) -> bool:
|
||||
return not self == other
|
||||
|
|
|
@ -25,10 +25,13 @@ from telegram.utils.helpers import decode_user_chat_data_from_json,\
|
|||
try:
|
||||
import ujson as json
|
||||
except ImportError:
|
||||
import json
|
||||
import json # type: ignore[no-redef]
|
||||
from collections import defaultdict
|
||||
from telegram.ext import BasePersistence
|
||||
|
||||
from typing import DefaultDict, Dict, Any, Tuple, Optional
|
||||
from telegram.utils.types import ConversationDict
|
||||
|
||||
|
||||
class DictPersistence(BasePersistence):
|
||||
"""Using python's dicts and json for making your bot persistent.
|
||||
|
@ -74,13 +77,13 @@ class DictPersistence(BasePersistence):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
store_user_data=True,
|
||||
store_chat_data=True,
|
||||
store_bot_data=True,
|
||||
user_data_json='',
|
||||
chat_data_json='',
|
||||
bot_data_json='',
|
||||
conversations_json=''):
|
||||
store_user_data: bool = True,
|
||||
store_chat_data: bool = True,
|
||||
store_bot_data: bool = True,
|
||||
user_data_json: str = '',
|
||||
chat_data_json: str = '',
|
||||
bot_data_json: str = '',
|
||||
conversations_json: str = ''):
|
||||
super().__init__(store_user_data=store_user_data,
|
||||
store_chat_data=store_chat_data,
|
||||
store_bot_data=store_bot_data)
|
||||
|
@ -121,12 +124,12 @@ class DictPersistence(BasePersistence):
|
|||
raise TypeError("Unable to deserialize conversations_json. Not valid JSON")
|
||||
|
||||
@property
|
||||
def user_data(self):
|
||||
def user_data(self) -> Optional[DefaultDict[int, Dict]]:
|
||||
""":obj:`dict`: The user_data as a dict."""
|
||||
return self._user_data
|
||||
|
||||
@property
|
||||
def user_data_json(self):
|
||||
def user_data_json(self) -> str:
|
||||
""":obj:`str`: The user_data serialized as a JSON-string."""
|
||||
if self._user_data_json:
|
||||
return self._user_data_json
|
||||
|
@ -134,12 +137,12 @@ class DictPersistence(BasePersistence):
|
|||
return json.dumps(self.user_data)
|
||||
|
||||
@property
|
||||
def chat_data(self):
|
||||
def chat_data(self) -> Optional[DefaultDict[int, Dict]]:
|
||||
""":obj:`dict`: The chat_data as a dict."""
|
||||
return self._chat_data
|
||||
|
||||
@property
|
||||
def chat_data_json(self):
|
||||
def chat_data_json(self) -> str:
|
||||
""":obj:`str`: The chat_data serialized as a JSON-string."""
|
||||
if self._chat_data_json:
|
||||
return self._chat_data_json
|
||||
|
@ -147,12 +150,12 @@ class DictPersistence(BasePersistence):
|
|||
return json.dumps(self.chat_data)
|
||||
|
||||
@property
|
||||
def bot_data(self):
|
||||
def bot_data(self) -> Optional[Dict]:
|
||||
""":obj:`dict`: The bot_data as a dict."""
|
||||
return self._bot_data
|
||||
|
||||
@property
|
||||
def bot_data_json(self):
|
||||
def bot_data_json(self) -> str:
|
||||
""":obj:`str`: The bot_data serialized as a JSON-string."""
|
||||
if self._bot_data_json:
|
||||
return self._bot_data_json
|
||||
|
@ -160,19 +163,19 @@ class DictPersistence(BasePersistence):
|
|||
return json.dumps(self.bot_data)
|
||||
|
||||
@property
|
||||
def conversations(self):
|
||||
def conversations(self) -> Optional[Dict[str, Dict[Tuple, Any]]]:
|
||||
""":obj:`dict`: The conversations as a dict."""
|
||||
return self._conversations
|
||||
|
||||
@property
|
||||
def conversations_json(self):
|
||||
def conversations_json(self) -> str:
|
||||
""":obj:`str`: The conversations serialized as a JSON-string."""
|
||||
if self._conversations_json:
|
||||
return self._conversations_json
|
||||
else:
|
||||
return encode_conversations_to_json(self.conversations)
|
||||
return encode_conversations_to_json(self.conversations) # type: ignore[arg-type]
|
||||
|
||||
def get_user_data(self):
|
||||
def get_user_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
||||
"""Returns the user_data created from the ``user_data_json`` or an empty
|
||||
:obj:`defaultdict`.
|
||||
|
||||
|
@ -183,9 +186,9 @@ class DictPersistence(BasePersistence):
|
|||
pass
|
||||
else:
|
||||
self._user_data = defaultdict(dict)
|
||||
return deepcopy(self.user_data)
|
||||
return deepcopy(self.user_data) # type: ignore[arg-type]
|
||||
|
||||
def get_chat_data(self):
|
||||
def get_chat_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
||||
"""Returns the chat_data created from the ``chat_data_json`` or an empty
|
||||
:obj:`defaultdict`.
|
||||
|
||||
|
@ -196,9 +199,9 @@ class DictPersistence(BasePersistence):
|
|||
pass
|
||||
else:
|
||||
self._chat_data = defaultdict(dict)
|
||||
return deepcopy(self.chat_data)
|
||||
return deepcopy(self.chat_data) # type: ignore[arg-type]
|
||||
|
||||
def get_bot_data(self):
|
||||
def get_bot_data(self) -> Dict[Any, Any]:
|
||||
"""Returns the bot_data created from the ``bot_data_json`` or an empty :obj:`dict`.
|
||||
|
||||
Returns:
|
||||
|
@ -208,9 +211,9 @@ class DictPersistence(BasePersistence):
|
|||
pass
|
||||
else:
|
||||
self._bot_data = {}
|
||||
return deepcopy(self.bot_data)
|
||||
return deepcopy(self.bot_data) # type: ignore[arg-type]
|
||||
|
||||
def get_conversations(self, name):
|
||||
def get_conversations(self, name: str) -> ConversationDict:
|
||||
"""Returns the conversations created from the ``conversations_json`` or an empty
|
||||
:obj:`dict`.
|
||||
|
||||
|
@ -221,9 +224,11 @@ class DictPersistence(BasePersistence):
|
|||
pass
|
||||
else:
|
||||
self._conversations = {}
|
||||
return self.conversations.get(name, {}).copy()
|
||||
return self.conversations.get(name, {}).copy() # type: ignore[union-attr]
|
||||
|
||||
def update_conversation(self, name, key, new_state):
|
||||
def update_conversation(self,
|
||||
name: str, key: Tuple[int, ...],
|
||||
new_state: Optional[object]) -> None:
|
||||
"""Will update the conversations for the given handler.
|
||||
|
||||
Args:
|
||||
|
@ -231,12 +236,14 @@ class DictPersistence(BasePersistence):
|
|||
key (:obj:`tuple`): The key the state is changed for.
|
||||
new_state (:obj:`tuple` | :obj:`any`): The new state for the given key.
|
||||
"""
|
||||
if not self._conversations:
|
||||
self._conversations = {}
|
||||
if self._conversations.setdefault(name, {}).get(key) == new_state:
|
||||
return
|
||||
self._conversations[name][key] = new_state
|
||||
self._conversations_json = None
|
||||
|
||||
def update_user_data(self, user_id, data):
|
||||
def update_user_data(self, user_id: int, data: Dict) -> None:
|
||||
"""Will update the user_data (if changed).
|
||||
|
||||
Args:
|
||||
|
@ -250,7 +257,7 @@ class DictPersistence(BasePersistence):
|
|||
self._user_data[user_id] = data
|
||||
self._user_data_json = None
|
||||
|
||||
def update_chat_data(self, chat_id, data):
|
||||
def update_chat_data(self, chat_id: int, data: Dict) -> None:
|
||||
"""Will update the chat_data (if changed).
|
||||
|
||||
Args:
|
||||
|
@ -264,7 +271,7 @@ class DictPersistence(BasePersistence):
|
|||
self._chat_data[chat_id] = data
|
||||
self._chat_data_json = None
|
||||
|
||||
def update_bot_data(self, data):
|
||||
def update_bot_data(self, data: Dict) -> None:
|
||||
"""Will update the bot_data (if changed).
|
||||
|
||||
Args:
|
||||
|
|
|
@ -36,10 +36,19 @@ from telegram.utils.deprecate import TelegramDeprecationWarning
|
|||
from telegram.utils.promise import Promise
|
||||
from telegram.ext import BasePersistence
|
||||
|
||||
from typing import Any, Callable, TYPE_CHECKING, Optional, Union, DefaultDict, Dict, List, Set
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
from telegram.ext import JobQueue
|
||||
|
||||
DEFAULT_GROUP = 0
|
||||
|
||||
|
||||
def run_async(func):
|
||||
def run_async(func: Callable[[Update, CallbackContext],
|
||||
Any]) -> Callable[[Update, CallbackContext], Any]:
|
||||
"""
|
||||
Function decorator that will run the function in a new thread.
|
||||
|
||||
|
@ -57,7 +66,7 @@ def run_async(func):
|
|||
"""
|
||||
|
||||
@wraps(func)
|
||||
def async_func(*args, **kwargs):
|
||||
def async_func(*args: Any, **kwargs: Any) -> Any:
|
||||
warnings.warn('The @run_async decorator is deprecated. Use the `run_async` parameter of'
|
||||
'`Dispatcher.add_handler` or `Dispatcher.run_async` instead.',
|
||||
TelegramDeprecationWarning,
|
||||
|
@ -87,7 +96,7 @@ class DispatcherHandlerStop(Exception):
|
|||
Args:
|
||||
state (:obj:`object`, optional): The next state of the conversation.
|
||||
"""
|
||||
def __init__(self, state=None):
|
||||
def __init__(self, state: object = None) -> None:
|
||||
super().__init__()
|
||||
self.state = state
|
||||
|
||||
|
@ -129,13 +138,13 @@ class Dispatcher:
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
def __init__(self,
|
||||
bot,
|
||||
update_queue,
|
||||
workers=4,
|
||||
exception_event=None,
|
||||
job_queue=None,
|
||||
persistence=None,
|
||||
use_context=True):
|
||||
bot: 'Bot',
|
||||
update_queue: Queue,
|
||||
workers: int = 4,
|
||||
exception_event: Event = None,
|
||||
job_queue: 'JobQueue' = None,
|
||||
persistence: BasePersistence = None,
|
||||
use_context: bool = True):
|
||||
self.bot = bot
|
||||
self.update_queue = update_queue
|
||||
self.job_queue = job_queue
|
||||
|
@ -146,9 +155,10 @@ class Dispatcher:
|
|||
warnings.warn('Old Handler API is deprecated - see https://git.io/fxJuV for details',
|
||||
TelegramDeprecationWarning, stacklevel=3)
|
||||
|
||||
self.user_data = defaultdict(dict)
|
||||
self.chat_data = defaultdict(dict)
|
||||
self.user_data: DefaultDict[int, Dict[Any, Any]] = defaultdict(dict)
|
||||
self.chat_data: DefaultDict[int, Dict[Any, Any]] = defaultdict(dict)
|
||||
self.bot_data = {}
|
||||
self.persistence: Optional[BasePersistence] = None
|
||||
self._update_persistence_lock = Lock()
|
||||
if persistence:
|
||||
if not isinstance(persistence, BasePersistence):
|
||||
|
@ -170,11 +180,11 @@ class Dispatcher:
|
|||
else:
|
||||
self.persistence = None
|
||||
|
||||
self.handlers = {}
|
||||
self.handlers: Dict[int, List[Handler]] = {}
|
||||
"""Dict[:obj:`int`, List[:class:`telegram.ext.Handler`]]: Holds the handlers per group."""
|
||||
self.groups = []
|
||||
self.groups: List[int] = []
|
||||
"""List[:obj:`int`]: A list with all groups."""
|
||||
self.error_handlers = {}
|
||||
self.error_handlers: Dict[Callable, bool] = {}
|
||||
"""Dict[:obj:`callable`, :obj:`bool`]: A dict, where the keys are error handlers and the
|
||||
values indicate whether they are to be run asynchronously."""
|
||||
|
||||
|
@ -182,22 +192,22 @@ class Dispatcher:
|
|||
""":obj:`bool`: Indicates if this dispatcher is running."""
|
||||
self.__stop_event = Event()
|
||||
self.__exception_event = exception_event or Event()
|
||||
self.__async_queue = Queue()
|
||||
self.__async_threads = set()
|
||||
self.__async_queue: Queue = Queue()
|
||||
self.__async_threads: Set[Thread] = set()
|
||||
|
||||
# For backward compatibility, we allow a "singleton" mode for the dispatcher. When there's
|
||||
# only one instance of Dispatcher, it will be possible to use the `run_async` decorator.
|
||||
with self.__singleton_lock:
|
||||
if self.__singleton_semaphore.acquire(blocking=0):
|
||||
if self.__singleton_semaphore.acquire(blocking=False):
|
||||
self._set_singleton(self)
|
||||
else:
|
||||
self._set_singleton(None)
|
||||
|
||||
@property
|
||||
def exception_event(self):
|
||||
def exception_event(self) -> Event:
|
||||
return self.__exception_event
|
||||
|
||||
def _init_async_threads(self, base_name, workers):
|
||||
def _init_async_threads(self, base_name: str, workers: int) -> None:
|
||||
base_name = '{}_'.format(base_name) if base_name else ''
|
||||
|
||||
for i in range(workers):
|
||||
|
@ -207,12 +217,12 @@ class Dispatcher:
|
|||
thread.start()
|
||||
|
||||
@classmethod
|
||||
def _set_singleton(cls, val):
|
||||
def _set_singleton(cls, val: Optional['Dispatcher']) -> None:
|
||||
cls.logger.debug('Setting singleton dispatcher as %s', val)
|
||||
cls.__singleton = weakref.ref(val) if val else None
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls):
|
||||
def get_instance(cls) -> 'Dispatcher':
|
||||
"""Get the singleton instance of this class.
|
||||
|
||||
Returns:
|
||||
|
@ -223,12 +233,12 @@ class Dispatcher:
|
|||
|
||||
"""
|
||||
if cls.__singleton is not None:
|
||||
return cls.__singleton() # pylint: disable=not-callable
|
||||
return cls.__singleton() # type: ignore[return-value] # pylint: disable=not-callable
|
||||
else:
|
||||
raise RuntimeError('{} not initialized or multiple instances exist'.format(
|
||||
cls.__name__))
|
||||
|
||||
def _pooled(self):
|
||||
def _pooled(self) -> None:
|
||||
thr_name = current_thread().getName()
|
||||
while 1:
|
||||
promise = self.__async_queue.get()
|
||||
|
@ -270,7 +280,11 @@ class Dispatcher:
|
|||
except Exception:
|
||||
self.logger.exception('An uncaught error was raised while handling the error.')
|
||||
|
||||
def run_async(self, func, *args, update=None, **kwargs):
|
||||
def run_async(self,
|
||||
func: Callable[..., Any],
|
||||
*args: Any,
|
||||
update: HandlerArg = None,
|
||||
**kwargs: Any) -> Promise:
|
||||
"""
|
||||
Queue a function (with given args/kwargs) to be run asynchronously. Exceptions raised
|
||||
by the function will be handled by the error handlers registered with
|
||||
|
@ -296,13 +310,18 @@ class Dispatcher:
|
|||
"""
|
||||
return self._run_async(func, *args, update=update, error_handling=True, **kwargs)
|
||||
|
||||
def _run_async(self, func, *args, update=None, error_handling=True, **kwargs):
|
||||
def _run_async(self,
|
||||
func: Callable[..., Any],
|
||||
*args: Any,
|
||||
update: HandlerArg = None,
|
||||
error_handling: bool = True,
|
||||
**kwargs: Any) -> Promise:
|
||||
# TODO: Remove error_handling parameter once we drop the @run_async decorator
|
||||
promise = Promise(func, args, kwargs, update=update, error_handling=error_handling)
|
||||
self.__async_queue.put(promise)
|
||||
return promise
|
||||
|
||||
def start(self, ready=None):
|
||||
def start(self, ready: Event = None) -> None:
|
||||
"""Thread target of thread 'dispatcher'.
|
||||
|
||||
Runs in background and processes the update queue.
|
||||
|
@ -323,7 +342,7 @@ class Dispatcher:
|
|||
self.logger.error(msg)
|
||||
raise TelegramError(msg)
|
||||
|
||||
self._init_async_threads(uuid4(), self.workers)
|
||||
self._init_async_threads(str(uuid4()), self.workers)
|
||||
self.running = True
|
||||
self.logger.debug('Dispatcher started')
|
||||
|
||||
|
@ -350,7 +369,7 @@ class Dispatcher:
|
|||
self.running = False
|
||||
self.logger.debug('Dispatcher thread stopped')
|
||||
|
||||
def stop(self):
|
||||
def stop(self) -> None:
|
||||
"""Stops the thread."""
|
||||
if self.running:
|
||||
self.__stop_event.set()
|
||||
|
@ -374,10 +393,10 @@ class Dispatcher:
|
|||
self.logger.debug('async thread {}/{} has ended'.format(i + 1, total))
|
||||
|
||||
@property
|
||||
def has_running_threads(self):
|
||||
def has_running_threads(self) -> bool:
|
||||
return self.running or bool(self.__async_threads)
|
||||
|
||||
def process_update(self, update):
|
||||
def process_update(self, update: Union[str, Update, TelegramError]) -> None:
|
||||
"""Processes a single update.
|
||||
|
||||
Args:
|
||||
|
@ -427,7 +446,7 @@ class Dispatcher:
|
|||
except Exception:
|
||||
self.logger.exception('An uncaught error was raised while handling the error.')
|
||||
|
||||
def add_handler(self, handler, group=DEFAULT_GROUP):
|
||||
def add_handler(self, handler: Handler, group: int = DEFAULT_GROUP) -> None:
|
||||
"""Register a handler.
|
||||
|
||||
TL;DR: Order and priority counts. 0 or 1 handlers per group will be used. End handling of
|
||||
|
@ -459,7 +478,7 @@ class Dispatcher:
|
|||
raise TypeError('handler is not an instance of {}'.format(Handler.__name__))
|
||||
if not isinstance(group, int):
|
||||
raise TypeError('group is not int')
|
||||
if isinstance(handler, ConversationHandler) and handler.persistent:
|
||||
if isinstance(handler, ConversationHandler) and handler.persistent and handler.name:
|
||||
if not self.persistence:
|
||||
raise ValueError(
|
||||
"ConversationHandler {} can not be persistent if dispatcher has no "
|
||||
|
@ -474,7 +493,7 @@ class Dispatcher:
|
|||
|
||||
self.handlers[group].append(handler)
|
||||
|
||||
def remove_handler(self, handler, group=DEFAULT_GROUP):
|
||||
def remove_handler(self, handler: Handler, group: int = DEFAULT_GROUP) -> None:
|
||||
"""Remove a handler from the specified group.
|
||||
|
||||
Args:
|
||||
|
@ -488,7 +507,7 @@ class Dispatcher:
|
|||
del self.handlers[group]
|
||||
self.groups.remove(group)
|
||||
|
||||
def update_persistence(self, update=None):
|
||||
def update_persistence(self, update: HandlerArg = None) -> None:
|
||||
"""Update :attr:`user_data`, :attr:`chat_data` and :attr:`bot_data` in :attr:`persistence`.
|
||||
|
||||
Args:
|
||||
|
@ -498,7 +517,7 @@ class Dispatcher:
|
|||
with self._update_persistence_lock:
|
||||
self.__update_persistence(update)
|
||||
|
||||
def __update_persistence(self, update):
|
||||
def __update_persistence(self, update: HandlerArg = None) -> None:
|
||||
if self.persistence:
|
||||
# We use list() here in order to decouple chat_ids from self.chat_data, as dict view
|
||||
# objects will change, when the dict does and we want to loop over chat_ids
|
||||
|
@ -551,7 +570,9 @@ class Dispatcher:
|
|||
'the error with an error_handler'
|
||||
self.logger.exception(message)
|
||||
|
||||
def add_error_handler(self, callback, run_async=False):
|
||||
def add_error_handler(self,
|
||||
callback: Callable[[Any, CallbackContext], None],
|
||||
run_async: bool = False) -> None:
|
||||
"""Registers an error handler in the Dispatcher. This handler will receive every error
|
||||
which happens in your bot.
|
||||
|
||||
|
@ -580,7 +601,7 @@ class Dispatcher:
|
|||
return
|
||||
self.error_handlers[callback] = run_async
|
||||
|
||||
def remove_error_handler(self, callback):
|
||||
def remove_error_handler(self, callback: Callable[[Any, CallbackContext], None]) -> None:
|
||||
"""Removes an error handler.
|
||||
|
||||
Args:
|
||||
|
@ -589,7 +610,10 @@ class Dispatcher:
|
|||
"""
|
||||
self.error_handlers.pop(callback, None)
|
||||
|
||||
def dispatch_error(self, update, error, promise=None):
|
||||
def dispatch_error(self,
|
||||
update: Optional[HandlerArg],
|
||||
error: Exception,
|
||||
promise: Promise = None) -> None:
|
||||
"""Dispatches an error.
|
||||
|
||||
Args:
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -20,6 +20,15 @@
|
|||
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from telegram.utils.promise import Promise
|
||||
from telegram.utils.types import HandlerArg
|
||||
from telegram import Update
|
||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class Handler(ABC):
|
||||
"""The base class for all update handlers. Create custom handlers by inheriting from it.
|
||||
|
@ -78,15 +87,14 @@ class Handler(ABC):
|
|||
Defaults to :obj:`False`.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
callback,
|
||||
pass_update_queue=False,
|
||||
pass_job_queue=False,
|
||||
pass_user_data=False,
|
||||
pass_chat_data=False,
|
||||
run_async=False):
|
||||
self.callback = callback
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False):
|
||||
self.callback: Callable[[HandlerArg, 'CallbackContext'], RT] = callback
|
||||
self.pass_update_queue = pass_update_queue
|
||||
self.pass_job_queue = pass_job_queue
|
||||
self.pass_user_data = pass_user_data
|
||||
|
@ -94,7 +102,7 @@ class Handler(ABC):
|
|||
self.run_async = run_async
|
||||
|
||||
@abstractmethod
|
||||
def check_update(self, update):
|
||||
def check_update(self, update: HandlerArg) -> Optional[Union[bool, object]]:
|
||||
"""
|
||||
This method is called to determine if an update should be handled by
|
||||
this handler instance. It should always be overridden.
|
||||
|
@ -109,7 +117,11 @@ class Handler(ABC):
|
|||
|
||||
"""
|
||||
|
||||
def handle_update(self, update, dispatcher, check_result, context=None):
|
||||
def handle_update(self,
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: object,
|
||||
context: 'CallbackContext' = None) -> Union[RT, Promise]:
|
||||
"""
|
||||
This method is called if it was determined that an update should indeed
|
||||
be handled by this instance. Calls :attr:`callback` along with its respectful
|
||||
|
@ -120,7 +132,9 @@ class Handler(ABC):
|
|||
Args:
|
||||
update (:obj:`str` | :class:`telegram.Update`): The update to be handled.
|
||||
dispatcher (:class:`telegram.ext.Dispatcher`): The calling dispatcher.
|
||||
check_result: The result from :attr:`check_update`.
|
||||
check_result (:obj:`obj`): The result from :attr:`check_update`.
|
||||
context (:class:`telegram.ext.CallbackContext`, optional): The context as provided by
|
||||
the dispatcher.
|
||||
|
||||
"""
|
||||
if context:
|
||||
|
@ -135,9 +149,13 @@ class Handler(ABC):
|
|||
return dispatcher.run_async(self.callback, dispatcher.bot, update, update=update,
|
||||
**optional_args)
|
||||
else:
|
||||
return self.callback(dispatcher.bot, update, **optional_args)
|
||||
return self.callback(dispatcher.bot, update, **optional_args) # type: ignore
|
||||
|
||||
def collect_additional_context(self, context, update, dispatcher, check_result):
|
||||
def collect_additional_context(self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Any) -> None:
|
||||
"""Prepares additional arguments for the context. Override if needed.
|
||||
|
||||
Args:
|
||||
|
@ -149,7 +167,10 @@ class Handler(ABC):
|
|||
"""
|
||||
pass
|
||||
|
||||
def collect_optional_args(self, dispatcher, update=None, check_result=None):
|
||||
def collect_optional_args(self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Any = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Prepares the optional arguments. If the handler has additional optional args,
|
||||
it should subclass this method, but remember to call this super method.
|
||||
|
@ -163,17 +184,19 @@ class Handler(ABC):
|
|||
check_result: The result from check_update
|
||||
|
||||
"""
|
||||
optional_args = dict()
|
||||
optional_args: Dict[str, Any] = dict()
|
||||
|
||||
if self.pass_update_queue:
|
||||
optional_args['update_queue'] = dispatcher.update_queue
|
||||
if self.pass_job_queue:
|
||||
optional_args['job_queue'] = dispatcher.job_queue
|
||||
if self.pass_user_data:
|
||||
if self.pass_user_data and isinstance(update, Update):
|
||||
user = update.effective_user
|
||||
optional_args['user_data'] = dispatcher.user_data[user.id if user else None]
|
||||
if self.pass_chat_data:
|
||||
optional_args['user_data'] = dispatcher.user_data[
|
||||
user.id if user else None] # type: ignore[index]
|
||||
if self.pass_chat_data and isinstance(update, Update):
|
||||
chat = update.effective_chat
|
||||
optional_args['chat_data'] = dispatcher.chat_data[chat.id if chat else None]
|
||||
optional_args['chat_data'] = dispatcher.chat_data[
|
||||
chat.id if chat else None] # type: ignore[index]
|
||||
|
||||
return optional_args
|
||||
|
|
|
@ -23,6 +23,15 @@ from telegram import Update
|
|||
|
||||
from .handler import Handler
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict, Pattern, Match, \
|
||||
cast
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class InlineQueryHandler(Handler):
|
||||
"""
|
||||
|
@ -102,22 +111,22 @@ class InlineQueryHandler(Handler):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
callback,
|
||||
pass_update_queue=False,
|
||||
pass_job_queue=False,
|
||||
pattern=None,
|
||||
pass_groups=False,
|
||||
pass_groupdict=False,
|
||||
pass_user_data=False,
|
||||
pass_chat_data=False,
|
||||
run_async=False):
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pattern: Union[str, Pattern] = None,
|
||||
pass_groups: bool = False,
|
||||
pass_groupdict: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False):
|
||||
super().__init__(
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
pass_job_queue=pass_job_queue,
|
||||
pass_user_data=pass_user_data,
|
||||
pass_chat_data=pass_chat_data,
|
||||
run_async=False)
|
||||
run_async=run_async)
|
||||
|
||||
if isinstance(pattern, str):
|
||||
pattern = re.compile(pattern)
|
||||
|
@ -126,7 +135,7 @@ class InlineQueryHandler(Handler):
|
|||
self.pass_groups = pass_groups
|
||||
self.pass_groupdict = pass_groupdict
|
||||
|
||||
def check_update(self, update):
|
||||
def check_update(self, update: HandlerArg) -> Optional[Union[bool, Match]]:
|
||||
"""
|
||||
Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
|
@ -146,16 +155,26 @@ class InlineQueryHandler(Handler):
|
|||
return match
|
||||
else:
|
||||
return True
|
||||
return None
|
||||
|
||||
def collect_optional_args(self, dispatcher, update=None, check_result=None):
|
||||
def collect_optional_args(self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[Union[bool, Match]] = None) -> Dict[str, Any]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if self.pattern:
|
||||
check_result = cast(Match, check_result)
|
||||
if self.pass_groups:
|
||||
optional_args['groups'] = check_result.groups()
|
||||
if self.pass_groupdict:
|
||||
optional_args['groupdict'] = check_result.groupdict()
|
||||
return optional_args
|
||||
|
||||
def collect_additional_context(self, context, update, dispatcher, check_result):
|
||||
def collect_additional_context(self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Match]]) -> None:
|
||||
if self.pattern:
|
||||
check_result = cast(Match, check_result)
|
||||
context.matches = [check_result]
|
||||
|
|
|
@ -25,10 +25,16 @@ import pytz
|
|||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from apscheduler.triggers.combining import OrTrigger
|
||||
from apscheduler.events import EVENT_JOB_EXECUTED, EVENT_JOB_ERROR
|
||||
from apscheduler.events import EVENT_JOB_EXECUTED, EVENT_JOB_ERROR, JobEvent
|
||||
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
|
||||
from typing import TYPE_CHECKING, Union, Callable, Tuple, Optional, List, Any, cast, overload
|
||||
from telegram.utils.types import JSONDict
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import Dispatcher
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class Days:
|
||||
MON, TUE, WED, THU, FRI, SAT, SUN = range(7)
|
||||
|
@ -46,32 +52,32 @@ class JobQueue:
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._dispatcher = None
|
||||
def __init__(self) -> None:
|
||||
self._dispatcher: 'Dispatcher' = None # type: ignore[assignment]
|
||||
self.logger = logging.getLogger(self.__class__.__name__)
|
||||
self.scheduler = BackgroundScheduler(timezone=pytz.utc)
|
||||
self.scheduler.add_listener(self._update_persistence,
|
||||
mask=EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
|
||||
|
||||
# Dispatch errors and don't log them in the APS logger
|
||||
def aps_log_filter(record):
|
||||
def aps_log_filter(record): # type: ignore
|
||||
return 'raised an exception' not in record.msg
|
||||
|
||||
logging.getLogger('apscheduler.executors.default').addFilter(aps_log_filter)
|
||||
self.scheduler.add_listener(self._dispatch_error, EVENT_JOB_ERROR)
|
||||
|
||||
def _build_args(self, job):
|
||||
def _build_args(self, job: 'Job') -> List[Union[CallbackContext, 'Bot', 'Job']]:
|
||||
if self._dispatcher.use_context:
|
||||
return [CallbackContext.from_job(job, self._dispatcher)]
|
||||
return [self._dispatcher.bot, job]
|
||||
|
||||
def _tz_now(self):
|
||||
def _tz_now(self) -> datetime.datetime:
|
||||
return datetime.datetime.now(self.scheduler.timezone)
|
||||
|
||||
def _update_persistence(self, event):
|
||||
def _update_persistence(self, event: JobEvent) -> None:
|
||||
self._dispatcher.update_persistence()
|
||||
|
||||
def _dispatch_error(self, event):
|
||||
def _dispatch_error(self, event: JobEvent) -> None:
|
||||
try:
|
||||
self._dispatcher.dispatch_error(None, event.exception)
|
||||
# Errors should not stop the thread.
|
||||
|
@ -80,7 +86,21 @@ class JobQueue:
|
|||
'uncaught error was raised while handling the error '
|
||||
'with an error_handler.')
|
||||
|
||||
def _parse_time_input(self, time, shift_day=False):
|
||||
@overload
|
||||
def _parse_time_input(self, time: None, shift_day: bool = False) -> None:
|
||||
...
|
||||
|
||||
@overload
|
||||
def _parse_time_input(self,
|
||||
time: Union[float, int, datetime.timedelta, datetime.datetime,
|
||||
datetime.time],
|
||||
shift_day: bool = False) -> datetime.datetime:
|
||||
...
|
||||
|
||||
def _parse_time_input(self,
|
||||
time: Union[float, int, datetime.timedelta, datetime.datetime,
|
||||
datetime.time, None],
|
||||
shift_day: bool = False) -> Optional[datetime.datetime]:
|
||||
if time is None:
|
||||
return None
|
||||
if isinstance(time, (int, float)):
|
||||
|
@ -98,7 +118,7 @@ class JobQueue:
|
|||
# isinstance(time, datetime.datetime):
|
||||
return time
|
||||
|
||||
def set_dispatcher(self, dispatcher):
|
||||
def set_dispatcher(self, dispatcher: 'Dispatcher') -> None:
|
||||
"""Set the dispatcher to be used by this JobQueue. Use this instead of passing a
|
||||
:class:`telegram.Bot` to the JobQueue, which is deprecated.
|
||||
|
||||
|
@ -111,7 +131,12 @@ class JobQueue:
|
|||
if dispatcher.bot.defaults:
|
||||
self.scheduler.configure(timezone=dispatcher.bot.defaults.tzinfo or pytz.utc)
|
||||
|
||||
def run_once(self, callback, when, context=None, name=None, job_kwargs=None):
|
||||
def run_once(self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
when: Union[float, datetime.timedelta, datetime.datetime, datetime.time],
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
job_kwargs: JSONDict = None) -> 'Job':
|
||||
"""Creates a new ``Job`` that runs once and adds it to the queue.
|
||||
|
||||
Args:
|
||||
|
@ -169,8 +194,16 @@ class JobQueue:
|
|||
job.job = j
|
||||
return job
|
||||
|
||||
def run_repeating(self, callback, interval, first=None, last=None, context=None, name=None,
|
||||
job_kwargs=None):
|
||||
def run_repeating(self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
interval: Union[float, datetime.timedelta],
|
||||
first: Union[float, datetime.timedelta, datetime.datetime,
|
||||
datetime.time] = None,
|
||||
last: Union[float, datetime.timedelta, datetime.datetime,
|
||||
datetime.time] = None,
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
job_kwargs: JSONDict = None) -> 'Job':
|
||||
"""Creates a new ``Job`` that runs at specified intervals and adds it to the queue.
|
||||
|
||||
Args:
|
||||
|
@ -256,8 +289,14 @@ class JobQueue:
|
|||
job.job = j
|
||||
return job
|
||||
|
||||
def run_monthly(self, callback, when, day, context=None, name=None, day_is_strict=True,
|
||||
job_kwargs=None):
|
||||
def run_monthly(self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
when: datetime.time,
|
||||
day: int,
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
day_is_strict: bool = True,
|
||||
job_kwargs: JSONDict = None) -> 'Job':
|
||||
"""Creates a new ``Job`` that runs on a monthly basis and adds it to the queue.
|
||||
|
||||
Args:
|
||||
|
@ -325,8 +364,13 @@ class JobQueue:
|
|||
job.job = j
|
||||
return job
|
||||
|
||||
def run_daily(self, callback, time, days=Days.EVERY_DAY, context=None, name=None,
|
||||
job_kwargs=None):
|
||||
def run_daily(self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
time: datetime.time,
|
||||
days: Tuple[int, ...] = Days.EVERY_DAY,
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
job_kwargs: JSONDict = None) -> 'Job':
|
||||
"""Creates a new ``Job`` that runs on a daily basis and adds it to the queue.
|
||||
|
||||
Args:
|
||||
|
@ -379,7 +423,11 @@ class JobQueue:
|
|||
job.job = j
|
||||
return job
|
||||
|
||||
def run_custom(self, callback, job_kwargs, context=None, name=None):
|
||||
def run_custom(self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
job_kwargs: JSONDict,
|
||||
context: object = None,
|
||||
name: str = None) -> 'Job':
|
||||
"""Creates a new customly defined ``Job``.
|
||||
|
||||
Args:
|
||||
|
@ -393,7 +441,7 @@ class JobQueue:
|
|||
job_kwargs (:obj:`dict`): Arbitrary keyword arguments. Used as arguments for
|
||||
``scheduler.add_job``.
|
||||
context (:obj:`object`, optional): Additional data needed for the callback function.
|
||||
Can be accessed through ``job.context`` in the callback. Defaults to :obj:`None`.
|
||||
Can be accessed through ``job.context`` in the callback. Defaults to ``None``.
|
||||
name (:obj:`str`, optional): The name of the new job. Defaults to
|
||||
``callback.__name__``.
|
||||
|
||||
|
@ -413,21 +461,21 @@ class JobQueue:
|
|||
job.job = j
|
||||
return job
|
||||
|
||||
def start(self):
|
||||
def start(self) -> None:
|
||||
"""Starts the job_queue thread."""
|
||||
if not self.scheduler.running:
|
||||
self.scheduler.start()
|
||||
|
||||
def stop(self):
|
||||
def stop(self) -> None:
|
||||
"""Stops the thread."""
|
||||
if self.scheduler.running:
|
||||
self.scheduler.shutdown()
|
||||
|
||||
def jobs(self):
|
||||
def jobs(self) -> Tuple['Job', ...]:
|
||||
"""Returns a tuple of all jobs that are currently in the ``JobQueue``."""
|
||||
return tuple(Job.from_aps_job(job, self) for job in self.scheduler.get_jobs())
|
||||
|
||||
def get_jobs_by_name(self, name):
|
||||
def get_jobs_by_name(self, name: str) -> Tuple['Job', ...]:
|
||||
"""Returns a tuple of jobs with the given name that are currently in the ``JobQueue``"""
|
||||
return tuple(job for job in self.jobs() if job.name == name)
|
||||
|
||||
|
@ -469,11 +517,11 @@ class Job:
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
callback,
|
||||
context=None,
|
||||
name=None,
|
||||
job_queue=None,
|
||||
job=None):
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
job_queue: JobQueue = None,
|
||||
job: 'Job' = None):
|
||||
|
||||
self.callback = callback
|
||||
self.context = context
|
||||
|
@ -483,15 +531,15 @@ class Job:
|
|||
self._removed = False
|
||||
self._enabled = False
|
||||
|
||||
self.job = job
|
||||
self.job = cast('Job', job)
|
||||
|
||||
def run(self, dispatcher):
|
||||
def run(self, dispatcher: 'Dispatcher') -> None:
|
||||
"""Executes the callback function independently of the jobs schedule."""
|
||||
try:
|
||||
if dispatcher.use_context:
|
||||
self.callback(CallbackContext.from_job(self, dispatcher))
|
||||
else:
|
||||
self.callback(dispatcher.bot, self)
|
||||
self.callback(dispatcher.bot, self) # type: ignore[arg-type,call-arg]
|
||||
except Exception as e:
|
||||
try:
|
||||
dispatcher.dispatch_error(None, e)
|
||||
|
@ -501,7 +549,7 @@ class Job:
|
|||
'uncaught error was raised while handling the error '
|
||||
'with an error_handler.')
|
||||
|
||||
def schedule_removal(self):
|
||||
def schedule_removal(self) -> None:
|
||||
"""
|
||||
Schedules this job for removal from the ``JobQueue``. It will be removed without executing
|
||||
its callback function again.
|
||||
|
@ -510,17 +558,17 @@ class Job:
|
|||
self._removed = True
|
||||
|
||||
@property
|
||||
def removed(self):
|
||||
def removed(self) -> bool:
|
||||
""":obj:`bool`: Whether this job is due to be removed."""
|
||||
return self._removed
|
||||
|
||||
@property
|
||||
def enabled(self):
|
||||
def enabled(self) -> bool:
|
||||
""":obj:`bool`: Whether this job is enabled."""
|
||||
return self._enabled
|
||||
|
||||
@enabled.setter
|
||||
def enabled(self, status):
|
||||
def enabled(self, status: bool) -> None:
|
||||
if status:
|
||||
self.job.resume()
|
||||
else:
|
||||
|
@ -528,7 +576,7 @@ class Job:
|
|||
self._enabled = status
|
||||
|
||||
@property
|
||||
def next_t(self):
|
||||
def next_t(self) -> Optional[datetime.datetime]:
|
||||
"""
|
||||
:obj:`datetime.datetime`: Datetime for the next job execution.
|
||||
Datetime is localized according to :attr:`tzinfo`.
|
||||
|
@ -537,7 +585,7 @@ class Job:
|
|||
return self.job.next_run_time
|
||||
|
||||
@classmethod
|
||||
def from_aps_job(cls, job, job_queue):
|
||||
def from_aps_job(cls, job: 'Job', job_queue: JobQueue) -> 'Job':
|
||||
# context based callbacks
|
||||
if len(job.args) == 1:
|
||||
context = job.args[0].job.context
|
||||
|
@ -545,13 +593,13 @@ class Job:
|
|||
context = job.args[1].context
|
||||
return cls(job.func, context=context, name=job.name, job_queue=job_queue, job=job)
|
||||
|
||||
def __getattr__(self, item):
|
||||
def __getattr__(self, item: str) -> Any:
|
||||
return getattr(self.job, item)
|
||||
|
||||
def __lt__(self, other):
|
||||
def __lt__(self, other: object) -> bool:
|
||||
return False
|
||||
|
||||
def __eq__(self, other):
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if isinstance(other, self.__class__):
|
||||
return self.id == other.id
|
||||
return False
|
||||
|
|
|
@ -23,9 +23,16 @@ import warnings
|
|||
from telegram.utils.deprecate import TelegramDeprecationWarning
|
||||
|
||||
from telegram import Update
|
||||
from telegram.ext import Filters
|
||||
from telegram.ext import Filters, BaseFilter
|
||||
from .handler import Handler
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class MessageHandler(Handler):
|
||||
"""Handler class to handle telegram messages. They might contain text, media or status updates.
|
||||
|
@ -114,16 +121,16 @@ class MessageHandler(Handler):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
filters,
|
||||
callback,
|
||||
pass_update_queue=False,
|
||||
pass_job_queue=False,
|
||||
pass_user_data=False,
|
||||
pass_chat_data=False,
|
||||
message_updates=None,
|
||||
channel_post_updates=None,
|
||||
edited_updates=None,
|
||||
run_async=False):
|
||||
filters: BaseFilter,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
message_updates: bool = None,
|
||||
channel_post_updates: bool = None,
|
||||
edited_updates: bool = None,
|
||||
run_async: bool = False):
|
||||
|
||||
super().__init__(
|
||||
callback,
|
||||
|
@ -162,7 +169,7 @@ class MessageHandler(Handler):
|
|||
self.filters &= ~(Filters.update.edited_message
|
||||
| Filters.update.edited_channel_post)
|
||||
|
||||
def check_update(self, update):
|
||||
def check_update(self, update: HandlerArg) -> Optional[Union[bool, Dict[str, Any]]]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
|
@ -174,7 +181,12 @@ class MessageHandler(Handler):
|
|||
"""
|
||||
if isinstance(update, Update) and update.effective_message:
|
||||
return self.filters(update)
|
||||
return None
|
||||
|
||||
def collect_additional_context(self, context, update, dispatcher, check_result):
|
||||
def collect_additional_context(self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Dict[str, Any]]]) -> None:
|
||||
if isinstance(check_result, dict):
|
||||
context.update(check_result)
|
||||
|
|
|
@ -27,6 +27,14 @@ import time
|
|||
import threading
|
||||
import queue as q
|
||||
|
||||
from typing import Callable, Any, TYPE_CHECKING, List, NoReturn
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
# We need to count < 1s intervals, so the most accurate timer is needed
|
||||
curtime = time.perf_counter
|
||||
|
||||
|
||||
class DelayQueueError(RuntimeError):
|
||||
"""Indicates processing errors."""
|
||||
|
@ -68,12 +76,12 @@ class DelayQueue(threading.Thread):
|
|||
_instcnt = 0 # instance counter
|
||||
|
||||
def __init__(self,
|
||||
queue=None,
|
||||
burst_limit=30,
|
||||
time_limit_ms=1000,
|
||||
exc_route=None,
|
||||
autostart=True,
|
||||
name=None):
|
||||
queue: q.Queue = None,
|
||||
burst_limit: int = 30,
|
||||
time_limit_ms: int = 1000,
|
||||
exc_route: Callable[[Exception], None] = None,
|
||||
autostart: bool = True,
|
||||
name: str = None):
|
||||
self._queue = queue if queue is not None else q.Queue()
|
||||
self.burst_limit = burst_limit
|
||||
self.time_limit = time_limit_ms / 1000
|
||||
|
@ -87,14 +95,14 @@ class DelayQueue(threading.Thread):
|
|||
if autostart: # immediately start processing
|
||||
super().start()
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
"""
|
||||
Do not use the method except for unthreaded testing purposes, the method normally is
|
||||
automatically called by autostart argument.
|
||||
|
||||
"""
|
||||
|
||||
times = [] # used to store each callable processing time
|
||||
times: List[float] = [] # used to store each callable processing time
|
||||
while True:
|
||||
item = self._queue.get()
|
||||
if self.__exit_req:
|
||||
|
@ -119,7 +127,7 @@ class DelayQueue(threading.Thread):
|
|||
except Exception as exc: # re-route any exceptions
|
||||
self.exc_route(exc) # to prevent thread exit
|
||||
|
||||
def stop(self, timeout=None):
|
||||
def stop(self, timeout: float = None) -> None:
|
||||
"""Used to gently stop processor and shutdown its thread.
|
||||
|
||||
Args:
|
||||
|
@ -136,7 +144,7 @@ class DelayQueue(threading.Thread):
|
|||
super().join(timeout=timeout)
|
||||
|
||||
@staticmethod
|
||||
def _default_exception_handler(exc):
|
||||
def _default_exception_handler(exc: Exception) -> NoReturn:
|
||||
"""
|
||||
Dummy exception handler which re-raises exception in thread. Could be possibly overwritten
|
||||
by subclasses.
|
||||
|
@ -145,7 +153,7 @@ class DelayQueue(threading.Thread):
|
|||
|
||||
raise exc
|
||||
|
||||
def __call__(self, func, *args, **kwargs):
|
||||
def __call__(self, func: Callable, *args: Any, **kwargs: Any) -> None:
|
||||
"""Used to process callbacks in throughput-limiting thread through queue.
|
||||
|
||||
Args:
|
||||
|
@ -194,12 +202,12 @@ class MessageQueue:
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
all_burst_limit=30,
|
||||
all_time_limit_ms=1000,
|
||||
group_burst_limit=20,
|
||||
group_time_limit_ms=60000,
|
||||
exc_route=None,
|
||||
autostart=True):
|
||||
all_burst_limit: int = 30,
|
||||
all_time_limit_ms: int = 1000,
|
||||
group_burst_limit: int = 20,
|
||||
group_time_limit_ms: int = 60000,
|
||||
exc_route: Callable[[Exception], None] = None,
|
||||
autostart: bool = True):
|
||||
# create according delay queues, use composition
|
||||
self._all_delayq = DelayQueue(
|
||||
burst_limit=all_burst_limit,
|
||||
|
@ -212,18 +220,18 @@ class MessageQueue:
|
|||
exc_route=exc_route,
|
||||
autostart=autostart)
|
||||
|
||||
def start(self):
|
||||
def start(self) -> None:
|
||||
"""Method is used to manually start the ``MessageQueue`` processing."""
|
||||
self._all_delayq.start()
|
||||
self._group_delayq.start()
|
||||
|
||||
def stop(self, timeout=None):
|
||||
def stop(self, timeout: float = None) -> None:
|
||||
self._group_delayq.stop(timeout=timeout)
|
||||
self._all_delayq.stop(timeout=timeout)
|
||||
|
||||
stop.__doc__ = DelayQueue.stop.__doc__ or '' # reuse docstring if any
|
||||
|
||||
def __call__(self, promise, is_group_msg=False):
|
||||
def __call__(self, promise: Callable, is_group_msg: bool = False) -> Callable:
|
||||
"""
|
||||
Processes callables in throughput-limiting queues to avoid hitting limits (specified with
|
||||
:attr:`burst_limit` and :attr:`time_limit`.
|
||||
|
@ -255,7 +263,7 @@ class MessageQueue:
|
|||
return promise
|
||||
|
||||
|
||||
def queuedmessage(method):
|
||||
def queuedmessage(method: Callable) -> Callable:
|
||||
"""A decorator to be used with :attr:`telegram.Bot` send* methods.
|
||||
|
||||
Note:
|
||||
|
@ -288,12 +296,13 @@ def queuedmessage(method):
|
|||
"""
|
||||
|
||||
@functools.wraps(method)
|
||||
def wrapped(self, *args, **kwargs):
|
||||
queued = kwargs.pop('queued', self._is_messages_queued_default)
|
||||
def wrapped(self: 'Bot', *args: Any, **kwargs: Any) -> Any:
|
||||
queued = kwargs.pop('queued',
|
||||
self._is_messages_queued_default) # type: ignore[attr-defined]
|
||||
isgroup = kwargs.pop('isgroup', False)
|
||||
if queued:
|
||||
prom = promise.Promise(method, (self, ) + args, kwargs)
|
||||
return self._msg_queue(prom, isgroup)
|
||||
return self._msg_queue(prom, isgroup) # type: ignore[attr-defined]
|
||||
return method(self, *args, **kwargs)
|
||||
|
||||
return wrapped
|
||||
|
|
|
@ -23,6 +23,9 @@ from copy import deepcopy
|
|||
|
||||
from telegram.ext import BasePersistence
|
||||
|
||||
from typing import DefaultDict, Dict, Any, Tuple, Optional
|
||||
from telegram.utils.types import ConversationDict
|
||||
|
||||
|
||||
class PicklePersistence(BasePersistence):
|
||||
"""Using python's builtin pickle for making you bot persistent.
|
||||
|
@ -71,24 +74,25 @@ class PicklePersistence(BasePersistence):
|
|||
Default is :obj:`False`.
|
||||
"""
|
||||
|
||||
def __init__(self, filename,
|
||||
store_user_data=True,
|
||||
store_chat_data=True,
|
||||
store_bot_data=True,
|
||||
single_file=True,
|
||||
on_flush=False):
|
||||
def __init__(self,
|
||||
filename: str,
|
||||
store_user_data: bool = True,
|
||||
store_chat_data: bool = True,
|
||||
store_bot_data: bool = True,
|
||||
single_file: bool = True,
|
||||
on_flush: bool = False):
|
||||
super().__init__(store_user_data=store_user_data,
|
||||
store_chat_data=store_chat_data,
|
||||
store_bot_data=store_bot_data)
|
||||
self.filename = filename
|
||||
self.single_file = single_file
|
||||
self.on_flush = on_flush
|
||||
self.user_data = None
|
||||
self.chat_data = None
|
||||
self.bot_data = None
|
||||
self.conversations = None
|
||||
self.user_data: Optional[DefaultDict[int, Dict]] = None
|
||||
self.chat_data: Optional[DefaultDict[int, Dict]] = None
|
||||
self.bot_data: Optional[Dict] = None
|
||||
self.conversations: Optional[Dict[str, Dict[Tuple, Any]]] = None
|
||||
|
||||
def load_singlefile(self):
|
||||
def load_singlefile(self) -> None:
|
||||
try:
|
||||
filename = self.filename
|
||||
with open(self.filename, "rb") as f:
|
||||
|
@ -99,7 +103,7 @@ class PicklePersistence(BasePersistence):
|
|||
self.bot_data = data.get('bot_data', {})
|
||||
self.conversations = data['conversations']
|
||||
except IOError:
|
||||
self.conversations = {}
|
||||
self.conversations = dict()
|
||||
self.user_data = defaultdict(dict)
|
||||
self.chat_data = defaultdict(dict)
|
||||
self.bot_data = {}
|
||||
|
@ -108,7 +112,7 @@ class PicklePersistence(BasePersistence):
|
|||
except Exception:
|
||||
raise TypeError("Something went wrong unpickling {}".format(filename))
|
||||
|
||||
def load_file(self, filename):
|
||||
def load_file(self, filename: str) -> Any:
|
||||
try:
|
||||
with open(filename, "rb") as f:
|
||||
return pickle.load(f)
|
||||
|
@ -119,17 +123,17 @@ class PicklePersistence(BasePersistence):
|
|||
except Exception:
|
||||
raise TypeError("Something went wrong unpickling {}".format(filename))
|
||||
|
||||
def dump_singlefile(self):
|
||||
def dump_singlefile(self) -> None:
|
||||
with open(self.filename, "wb") as f:
|
||||
data = {'conversations': self.conversations, 'user_data': self.user_data,
|
||||
'chat_data': self.chat_data, 'bot_data': self.bot_data}
|
||||
pickle.dump(data, f)
|
||||
|
||||
def dump_file(self, filename, data):
|
||||
def dump_file(self, filename: str, data: Any) -> None:
|
||||
with open(filename, "wb") as f:
|
||||
pickle.dump(data, f)
|
||||
|
||||
def get_user_data(self):
|
||||
def get_user_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
||||
"""Returns the user_data from the pickle file if it exists or an empty :obj:`defaultdict`.
|
||||
|
||||
Returns:
|
||||
|
@ -147,9 +151,9 @@ class PicklePersistence(BasePersistence):
|
|||
self.user_data = data
|
||||
else:
|
||||
self.load_singlefile()
|
||||
return deepcopy(self.user_data)
|
||||
return deepcopy(self.user_data) # type: ignore[arg-type]
|
||||
|
||||
def get_chat_data(self):
|
||||
def get_chat_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
||||
"""Returns the chat_data from the pickle file if it exists or an empty :obj:`defaultdict`.
|
||||
|
||||
Returns:
|
||||
|
@ -167,9 +171,9 @@ class PicklePersistence(BasePersistence):
|
|||
self.chat_data = data
|
||||
else:
|
||||
self.load_singlefile()
|
||||
return deepcopy(self.chat_data)
|
||||
return deepcopy(self.chat_data) # type: ignore[arg-type]
|
||||
|
||||
def get_bot_data(self):
|
||||
def get_bot_data(self) -> Dict[Any, Any]:
|
||||
"""Returns the bot_data from the pickle file if it exists or an empty :obj:`dict`.
|
||||
|
||||
Returns:
|
||||
|
@ -185,10 +189,10 @@ class PicklePersistence(BasePersistence):
|
|||
self.bot_data = data
|
||||
else:
|
||||
self.load_singlefile()
|
||||
return deepcopy(self.bot_data)
|
||||
return deepcopy(self.bot_data) # type: ignore[arg-type]
|
||||
|
||||
def get_conversations(self, name):
|
||||
"""Returns the conversations from the pickle file if it exists or an empty :obj:`dict`.
|
||||
def get_conversations(self, name: str) -> ConversationDict:
|
||||
"""Returns the conversations from the pickle file if it exsists or an empty dict.
|
||||
|
||||
Args:
|
||||
name (:obj:`str`): The handlers name.
|
||||
|
@ -206,9 +210,11 @@ class PicklePersistence(BasePersistence):
|
|||
self.conversations = data
|
||||
else:
|
||||
self.load_singlefile()
|
||||
return self.conversations.get(name, {}).copy()
|
||||
return self.conversations.get(name, {}).copy() # type: ignore[union-attr]
|
||||
|
||||
def update_conversation(self, name, key, new_state):
|
||||
def update_conversation(self,
|
||||
name: str, key: Tuple[int, ...],
|
||||
new_state: Optional[object]) -> None:
|
||||
"""Will update the conversations for the given handler and depending on :attr:`on_flush`
|
||||
save the pickle file.
|
||||
|
||||
|
@ -217,6 +223,8 @@ class PicklePersistence(BasePersistence):
|
|||
key (:obj:`tuple`): The key the state is changed for.
|
||||
new_state (:obj:`tuple` | :obj:`any`): The new state for the given key.
|
||||
"""
|
||||
if not self.conversations:
|
||||
self.conversations = dict()
|
||||
if self.conversations.setdefault(name, {}).get(key) == new_state:
|
||||
return
|
||||
self.conversations[name][key] = new_state
|
||||
|
@ -227,7 +235,7 @@ class PicklePersistence(BasePersistence):
|
|||
else:
|
||||
self.dump_singlefile()
|
||||
|
||||
def update_user_data(self, user_id, data):
|
||||
def update_user_data(self, user_id: int, data: Dict) -> None:
|
||||
"""Will update the user_data and depending on :attr:`on_flush` save the pickle file.
|
||||
|
||||
Args:
|
||||
|
@ -246,7 +254,7 @@ class PicklePersistence(BasePersistence):
|
|||
else:
|
||||
self.dump_singlefile()
|
||||
|
||||
def update_chat_data(self, chat_id, data):
|
||||
def update_chat_data(self, chat_id: int, data: Dict) -> None:
|
||||
"""Will update the chat_data and depending on :attr:`on_flush` save the pickle file.
|
||||
|
||||
Args:
|
||||
|
@ -265,7 +273,7 @@ class PicklePersistence(BasePersistence):
|
|||
else:
|
||||
self.dump_singlefile()
|
||||
|
||||
def update_bot_data(self, data):
|
||||
def update_bot_data(self, data: Dict) -> None:
|
||||
"""Will update the bot_data and depending on :attr:`on_flush` save the pickle file.
|
||||
|
||||
Args:
|
||||
|
@ -281,7 +289,7 @@ class PicklePersistence(BasePersistence):
|
|||
else:
|
||||
self.dump_singlefile()
|
||||
|
||||
def flush(self):
|
||||
def flush(self) -> None:
|
||||
""" Will save all data in memory to pickle file(s).
|
||||
"""
|
||||
if self.single_file:
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
from telegram import Update
|
||||
from .handler import Handler
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
|
||||
|
||||
class PollAnswerHandler(Handler):
|
||||
"""Handler class to handle Telegram updates that contain a poll answer.
|
||||
|
@ -79,7 +81,7 @@ class PollAnswerHandler(Handler):
|
|||
|
||||
"""
|
||||
|
||||
def check_update(self, update):
|
||||
def check_update(self, update: HandlerArg) -> bool:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
|
@ -89,4 +91,4 @@ class PollAnswerHandler(Handler):
|
|||
:obj:`bool`
|
||||
|
||||
"""
|
||||
return isinstance(update, Update) and update.poll_answer
|
||||
return isinstance(update, Update) and bool(update.poll_answer)
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
from telegram import Update
|
||||
from .handler import Handler
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
|
||||
|
||||
class PollHandler(Handler):
|
||||
"""Handler class to handle Telegram updates that contain a poll.
|
||||
|
@ -79,7 +81,7 @@ class PollHandler(Handler):
|
|||
|
||||
"""
|
||||
|
||||
def check_update(self, update):
|
||||
def check_update(self, update: HandlerArg) -> bool:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
|
@ -89,4 +91,4 @@ class PollHandler(Handler):
|
|||
:obj:`bool`
|
||||
|
||||
"""
|
||||
return isinstance(update, Update) and update.poll
|
||||
return isinstance(update, Update) and bool(update.poll)
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
from telegram import Update
|
||||
from .handler import Handler
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
|
||||
|
||||
class PreCheckoutQueryHandler(Handler):
|
||||
"""Handler class to handle Telegram PreCheckout callback queries.
|
||||
|
@ -80,7 +82,7 @@ class PreCheckoutQueryHandler(Handler):
|
|||
|
||||
"""
|
||||
|
||||
def check_update(self, update):
|
||||
def check_update(self, update: HandlerArg) -> bool:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
|
@ -90,4 +92,4 @@ class PreCheckoutQueryHandler(Handler):
|
|||
:obj:`bool`
|
||||
|
||||
"""
|
||||
return isinstance(update, Update) and update.pre_checkout_query
|
||||
return isinstance(update, Update) and bool(update.pre_checkout_query)
|
||||
|
|
|
@ -25,6 +25,13 @@ from telegram.utils.deprecate import TelegramDeprecationWarning
|
|||
|
||||
from telegram.ext import MessageHandler, Filters
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict, Pattern
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class RegexHandler(MessageHandler):
|
||||
"""Handler class to handle Telegram updates based on a regex.
|
||||
|
@ -102,19 +109,19 @@ class RegexHandler(MessageHandler):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
pattern,
|
||||
callback,
|
||||
pass_groups=False,
|
||||
pass_groupdict=False,
|
||||
pass_update_queue=False,
|
||||
pass_job_queue=False,
|
||||
pass_user_data=False,
|
||||
pass_chat_data=False,
|
||||
allow_edited=False,
|
||||
message_updates=True,
|
||||
channel_post_updates=False,
|
||||
edited_updates=False,
|
||||
run_async=False):
|
||||
pattern: Union[str, Pattern],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_groups: bool = False,
|
||||
pass_groupdict: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
allow_edited: bool = False,
|
||||
message_updates: bool = True,
|
||||
channel_post_updates: bool = False,
|
||||
edited_updates: bool = False,
|
||||
run_async: bool = False):
|
||||
warnings.warn('RegexHandler is deprecated. See https://git.io/fxJuV for more info',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2)
|
||||
|
@ -131,10 +138,15 @@ class RegexHandler(MessageHandler):
|
|||
self.pass_groups = pass_groups
|
||||
self.pass_groupdict = pass_groupdict
|
||||
|
||||
def collect_optional_args(self, dispatcher, update=None, check_result=None):
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[Union[bool, Dict[str, Any]]] = None) -> Dict[str, Any]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if self.pass_groups:
|
||||
optional_args['groups'] = check_result['matches'][0].groups()
|
||||
if self.pass_groupdict:
|
||||
optional_args['groupdict'] = check_result['matches'][0].groupdict()
|
||||
if isinstance(check_result, dict):
|
||||
if self.pass_groups:
|
||||
optional_args['groups'] = check_result['matches'][0].groups()
|
||||
if self.pass_groupdict:
|
||||
optional_args['groupdict'] = check_result['matches'][0].groupdict()
|
||||
return optional_args
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
from telegram import Update
|
||||
from .handler import Handler
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
|
||||
|
||||
class ShippingQueryHandler(Handler):
|
||||
"""Handler class to handle Telegram shipping callback queries.
|
||||
|
@ -80,7 +82,7 @@ class ShippingQueryHandler(Handler):
|
|||
|
||||
"""
|
||||
|
||||
def check_update(self, update):
|
||||
def check_update(self, update: HandlerArg) -> bool:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
|
@ -90,4 +92,4 @@ class ShippingQueryHandler(Handler):
|
|||
:obj:`bool`
|
||||
|
||||
"""
|
||||
return isinstance(update, Update) and update.shipping_query
|
||||
return isinstance(update, Update) and bool(update.shipping_query)
|
||||
|
|
|
@ -20,6 +20,13 @@
|
|||
|
||||
from .handler import Handler
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from typing import Callable, TYPE_CHECKING, Any, Optional, TypeVar, Dict, List
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class StringCommandHandler(Handler):
|
||||
"""Handler class to handle string commands. Commands are string updates that start with ``/``.
|
||||
|
@ -44,6 +51,7 @@ class StringCommandHandler(Handler):
|
|||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
Args:
|
||||
command (:obj:`str`): The command 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:
|
||||
|
@ -73,12 +81,12 @@ class StringCommandHandler(Handler):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
command,
|
||||
callback,
|
||||
pass_args=False,
|
||||
pass_update_queue=False,
|
||||
pass_job_queue=False,
|
||||
run_async=False):
|
||||
command: str,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_args: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
run_async: bool = False):
|
||||
super().__init__(
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
|
@ -87,7 +95,7 @@ class StringCommandHandler(Handler):
|
|||
self.command = command
|
||||
self.pass_args = pass_args
|
||||
|
||||
def check_update(self, update):
|
||||
def check_update(self, update: HandlerArg) -> Optional[List[str]]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
|
@ -101,12 +109,20 @@ class StringCommandHandler(Handler):
|
|||
args = update[1:].split(' ')
|
||||
if args[0] == self.command:
|
||||
return args[1:]
|
||||
return None
|
||||
|
||||
def collect_optional_args(self, dispatcher, update=None, check_result=None):
|
||||
def collect_optional_args(self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[List[str]] = None) -> Dict[str, Any]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if self.pass_args:
|
||||
optional_args['args'] = check_result
|
||||
return optional_args
|
||||
|
||||
def collect_additional_context(self, context, update, dispatcher, check_result):
|
||||
def collect_additional_context(self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[List[str]]) -> None:
|
||||
context.args = check_result
|
||||
|
|
|
@ -22,6 +22,13 @@ import re
|
|||
|
||||
from .handler import Handler
|
||||
|
||||
from typing import Callable, TYPE_CHECKING, Optional, TypeVar, Match, Dict, Any, Union, Pattern
|
||||
from telegram.utils.types import HandlerArg
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class StringRegexHandler(Handler):
|
||||
"""Handler class to handle string updates based on a regex which checks the update content.
|
||||
|
@ -84,13 +91,13 @@ class StringRegexHandler(Handler):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
pattern,
|
||||
callback,
|
||||
pass_groups=False,
|
||||
pass_groupdict=False,
|
||||
pass_update_queue=False,
|
||||
pass_job_queue=False,
|
||||
run_async=False):
|
||||
pattern: Union[str, Pattern],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_groups: bool = False,
|
||||
pass_groupdict: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
run_async: bool = False):
|
||||
super().__init__(
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
|
@ -104,7 +111,7 @@ class StringRegexHandler(Handler):
|
|||
self.pass_groups = pass_groups
|
||||
self.pass_groupdict = pass_groupdict
|
||||
|
||||
def check_update(self, update):
|
||||
def check_update(self, update: HandlerArg) -> Optional[Match]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
|
@ -118,16 +125,24 @@ class StringRegexHandler(Handler):
|
|||
match = re.match(self.pattern, update)
|
||||
if match:
|
||||
return match
|
||||
return None
|
||||
|
||||
def collect_optional_args(self, dispatcher, update=None, check_result=None):
|
||||
def collect_optional_args(self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[Match] = None) -> Dict[str, Any]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if self.pattern:
|
||||
if self.pass_groups:
|
||||
if self.pass_groups and check_result:
|
||||
optional_args['groups'] = check_result.groups()
|
||||
if self.pass_groupdict:
|
||||
if self.pass_groupdict and check_result:
|
||||
optional_args['groupdict'] = check_result.groupdict()
|
||||
return optional_args
|
||||
|
||||
def collect_additional_context(self, context, update, dispatcher, check_result):
|
||||
if self.pattern:
|
||||
def collect_additional_context(self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Match]) -> None:
|
||||
if self.pattern and check_result:
|
||||
context.matches = [check_result]
|
||||
|
|
|
@ -21,6 +21,14 @@
|
|||
from .handler import Handler
|
||||
|
||||
|
||||
from typing import Callable, TYPE_CHECKING, TypeVar, Type, Any
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext
|
||||
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class TypeHandler(Handler):
|
||||
"""Handler class to handle updates of custom types.
|
||||
|
||||
|
@ -67,12 +75,12 @@ class TypeHandler(Handler):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
type,
|
||||
callback,
|
||||
strict=False,
|
||||
pass_update_queue=False,
|
||||
pass_job_queue=False,
|
||||
run_async=False):
|
||||
type: Type,
|
||||
callback: Callable[[Any, 'CallbackContext'], RT],
|
||||
strict: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
run_async: bool = False):
|
||||
super().__init__(
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
|
@ -81,7 +89,7 @@ class TypeHandler(Handler):
|
|||
self.type = type
|
||||
self.strict = strict
|
||||
|
||||
def check_update(self, update):
|
||||
def check_update(self, update: Any) -> bool:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
|
|
|
@ -34,6 +34,11 @@ from telegram.utils.helpers import get_signal_name
|
|||
from telegram.utils.request import Request
|
||||
from telegram.utils.webhookhandler import (WebhookServer, WebhookAppClass)
|
||||
|
||||
from typing import Callable, Dict, TYPE_CHECKING, Any, List, Union, Tuple, no_type_check, Optional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import BasePersistence, Defaults
|
||||
|
||||
|
||||
class Updater:
|
||||
"""
|
||||
|
@ -104,19 +109,19 @@ class Updater:
|
|||
_request = None
|
||||
|
||||
def __init__(self,
|
||||
token=None,
|
||||
base_url=None,
|
||||
workers=4,
|
||||
bot=None,
|
||||
private_key=None,
|
||||
private_key_password=None,
|
||||
user_sig_handler=None,
|
||||
request_kwargs=None,
|
||||
persistence=None,
|
||||
defaults=None,
|
||||
use_context=True,
|
||||
dispatcher=None,
|
||||
base_file_url=None):
|
||||
token: str = None,
|
||||
base_url: str = None,
|
||||
workers: int = 4,
|
||||
bot: Bot = None,
|
||||
private_key: bytes = None,
|
||||
private_key_password: bytes = None,
|
||||
user_sig_handler: Callable = None,
|
||||
request_kwargs: Dict[str, Any] = None,
|
||||
persistence: 'BasePersistence' = None,
|
||||
defaults: 'Defaults' = None,
|
||||
use_context: bool = True,
|
||||
dispatcher: Dispatcher = None,
|
||||
base_file_url: str = None):
|
||||
|
||||
if defaults and bot:
|
||||
warnings.warn('Passing defaults to an Updater has no effect when a Bot is passed '
|
||||
|
@ -164,14 +169,14 @@ class Updater:
|
|||
if 'con_pool_size' not in request_kwargs:
|
||||
request_kwargs['con_pool_size'] = con_pool_size
|
||||
self._request = Request(**request_kwargs)
|
||||
self.bot = Bot(token,
|
||||
self.bot = Bot(token, # type: ignore[arg-type]
|
||||
base_url,
|
||||
base_file_url=base_file_url,
|
||||
request=self._request,
|
||||
private_key=private_key,
|
||||
private_key_password=private_key_password,
|
||||
defaults=defaults)
|
||||
self.update_queue = Queue()
|
||||
self.update_queue: Queue = Queue()
|
||||
self.job_queue = JobQueue()
|
||||
self.__exception_event = Event()
|
||||
self.persistence = persistence
|
||||
|
@ -203,9 +208,9 @@ class Updater:
|
|||
self.is_idle = False
|
||||
self.httpd = None
|
||||
self.__lock = Lock()
|
||||
self.__threads = []
|
||||
self.__threads: List[Thread] = []
|
||||
|
||||
def _init_thread(self, target, name, *args, **kwargs):
|
||||
def _init_thread(self, target: Callable, name: str, *args: Any, **kwargs: Any) -> None:
|
||||
thr = Thread(target=self._thread_wrapper,
|
||||
name="Bot:{}:{}".format(self.bot.id, name),
|
||||
args=(target,) + args,
|
||||
|
@ -213,7 +218,7 @@ class Updater:
|
|||
thr.start()
|
||||
self.__threads.append(thr)
|
||||
|
||||
def _thread_wrapper(self, target, *args, **kwargs):
|
||||
def _thread_wrapper(self, target: Callable, *args: Any, **kwargs: Any) -> None:
|
||||
thr_name = current_thread().name
|
||||
self.logger.debug('{} - started'.format(thr_name))
|
||||
try:
|
||||
|
@ -225,12 +230,12 @@ class Updater:
|
|||
self.logger.debug('{} - ended'.format(thr_name))
|
||||
|
||||
def start_polling(self,
|
||||
poll_interval=0.0,
|
||||
timeout=10,
|
||||
clean=False,
|
||||
bootstrap_retries=-1,
|
||||
read_latency=2.,
|
||||
allowed_updates=None):
|
||||
poll_interval: float = 0.0,
|
||||
timeout: float = 10,
|
||||
clean: bool = False,
|
||||
bootstrap_retries: int = -1,
|
||||
read_latency: float = 2.,
|
||||
allowed_updates: List[str] = None) -> Optional[Queue]:
|
||||
"""Starts polling updates from Telegram.
|
||||
|
||||
Args:
|
||||
|
@ -275,18 +280,19 @@ class Updater:
|
|||
|
||||
# Return the update queue so the main thread can insert updates
|
||||
return self.update_queue
|
||||
return None
|
||||
|
||||
def start_webhook(self,
|
||||
listen='127.0.0.1',
|
||||
port=80,
|
||||
url_path='',
|
||||
cert=None,
|
||||
key=None,
|
||||
clean=False,
|
||||
bootstrap_retries=0,
|
||||
webhook_url=None,
|
||||
allowed_updates=None,
|
||||
force_event_loop=False):
|
||||
listen: str = '127.0.0.1',
|
||||
port: int = 80,
|
||||
url_path: str = '',
|
||||
cert: str = None,
|
||||
key: str = None,
|
||||
clean: bool = False,
|
||||
bootstrap_retries: int = 0,
|
||||
webhook_url: str = None,
|
||||
allowed_updates: List[str] = None,
|
||||
force_event_loop: bool = False) -> Optional[Queue]:
|
||||
"""
|
||||
Starts a small http server to listen for updates via webhook. If cert
|
||||
and key are not provided, the webhook will be started directly on
|
||||
|
@ -348,7 +354,9 @@ class Updater:
|
|||
|
||||
# Return the update queue so the main thread can insert updates
|
||||
return self.update_queue
|
||||
return None
|
||||
|
||||
@no_type_check
|
||||
def _start_polling(self, poll_interval, timeout, read_latency, bootstrap_retries, clean,
|
||||
allowed_updates, ready=None): # pragma: no cover
|
||||
# Thread target of thread 'updater'. Runs in background, pulls
|
||||
|
@ -388,6 +396,7 @@ class Updater:
|
|||
self._network_loop_retry(polling_action_cb, polling_onerr_cb, 'getting Updates',
|
||||
poll_interval)
|
||||
|
||||
@no_type_check
|
||||
def _network_loop_retry(self, action_cb, onerr_cb, description, interval):
|
||||
"""Perform a loop calling `action_cb`, retrying after network errors.
|
||||
|
||||
|
@ -430,7 +439,7 @@ class Updater:
|
|||
sleep(cur_interval)
|
||||
|
||||
@staticmethod
|
||||
def _increase_poll_interval(current_interval):
|
||||
def _increase_poll_interval(current_interval: float) -> float:
|
||||
# increase waiting times on subsequent errors up to 30secs
|
||||
if current_interval == 0:
|
||||
current_interval = 1
|
||||
|
@ -440,6 +449,7 @@ class Updater:
|
|||
current_interval = 30
|
||||
return current_interval
|
||||
|
||||
@no_type_check
|
||||
def _start_webhook(self, listen, port, url_path, cert, key, bootstrap_retries, clean,
|
||||
webhook_url, allowed_updates, ready=None, force_event_loop=False):
|
||||
self.logger.debug('Updater thread started (webhook)')
|
||||
|
@ -481,9 +491,10 @@ class Updater:
|
|||
self.httpd.serve_forever(force_event_loop=force_event_loop, ready=ready)
|
||||
|
||||
@staticmethod
|
||||
def _gen_webhook_url(listen, port, url_path):
|
||||
def _gen_webhook_url(listen: str, port: int, url_path: str) -> str:
|
||||
return 'https://{listen}:{port}{path}'.format(listen=listen, port=port, path=url_path)
|
||||
|
||||
@no_type_check
|
||||
def _bootstrap(self,
|
||||
max_retries,
|
||||
clean,
|
||||
|
@ -541,7 +552,7 @@ class Updater:
|
|||
self._network_loop_retry(bootstrap_set_webhook, bootstrap_onerr_cb,
|
||||
'bootstrap set webhook', bootstrap_interval)
|
||||
|
||||
def stop(self):
|
||||
def stop(self) -> None:
|
||||
"""Stops the polling/webhook thread, the dispatcher and the job queue."""
|
||||
|
||||
self.job_queue.stop()
|
||||
|
@ -559,7 +570,8 @@ class Updater:
|
|||
if self._request:
|
||||
self._request.stop()
|
||||
|
||||
def _stop_httpd(self):
|
||||
@no_type_check
|
||||
def _stop_httpd(self) -> None:
|
||||
if self.httpd:
|
||||
self.logger.debug('Waiting for current webhook connection to be '
|
||||
'closed... Send a Telegram message to the bot to exit '
|
||||
|
@ -567,18 +579,21 @@ class Updater:
|
|||
self.httpd.shutdown()
|
||||
self.httpd = None
|
||||
|
||||
def _stop_dispatcher(self):
|
||||
@no_type_check
|
||||
def _stop_dispatcher(self) -> None:
|
||||
self.logger.debug('Requesting Dispatcher to stop...')
|
||||
self.dispatcher.stop()
|
||||
|
||||
def _join_threads(self):
|
||||
@no_type_check
|
||||
def _join_threads(self) -> None:
|
||||
for thr in self.__threads:
|
||||
self.logger.debug('Waiting for {} thread to end'.format(thr.name))
|
||||
thr.join()
|
||||
self.logger.debug('{} thread has ended'.format(thr.name))
|
||||
self.__threads = []
|
||||
|
||||
def signal_handler(self, signum, frame):
|
||||
@no_type_check
|
||||
def signal_handler(self, signum, frame) -> None:
|
||||
self.is_idle = False
|
||||
if self.running:
|
||||
self.logger.info('Received signal {} ({}), stopping...'.format(
|
||||
|
@ -595,7 +610,7 @@ class Updater:
|
|||
import os
|
||||
os._exit(1)
|
||||
|
||||
def idle(self, stop_signals=(SIGINT, SIGTERM, SIGABRT)):
|
||||
def idle(self, stop_signals: Union[List, Tuple] = (SIGINT, SIGTERM, SIGABRT)) -> None:
|
||||
"""Blocks until one of the signals are received and stops the updater.
|
||||
|
||||
Args:
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
from telegram import PhotoSize
|
||||
from telegram import TelegramObject
|
||||
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
||||
class Animation(TelegramObject):
|
||||
"""This object represents an animation file (GIF or H.264/MPEG-4 AVC video without sound).
|
||||
|
@ -60,17 +65,17 @@ class Animation(TelegramObject):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
width,
|
||||
height,
|
||||
duration,
|
||||
thumb=None,
|
||||
file_name=None,
|
||||
mime_type=None,
|
||||
file_size=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
width: int,
|
||||
height: int,
|
||||
duration: int,
|
||||
thumb: PhotoSize = None,
|
||||
file_name: str = None,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
@ -87,17 +92,17 @@ class Animation(TelegramObject):
|
|||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Animation']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super().de_json(data, bot)
|
||||
|
||||
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def get_file(self, timeout=None, api_kwargs=None):
|
||||
def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
|
||||
|
||||
Args:
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
|
||||
from telegram import TelegramObject, PhotoSize
|
||||
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
||||
class Audio(TelegramObject):
|
||||
"""This object represents an audio file to be treated as music by the Telegram clients.
|
||||
|
@ -61,16 +66,16 @@ class Audio(TelegramObject):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
duration,
|
||||
performer=None,
|
||||
title=None,
|
||||
mime_type=None,
|
||||
file_size=None,
|
||||
thumb=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
duration: int,
|
||||
performer: str = None,
|
||||
title: str = None,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
thumb: PhotoSize = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
@ -86,7 +91,9 @@ class Audio(TelegramObject):
|
|||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Audio']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
|
@ -94,7 +101,7 @@ class Audio(TelegramObject):
|
|||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def get_file(self, timeout=None, api_kwargs=None):
|
||||
def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
|
||||
|
||||
Args:
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
"""This module contains an object that represents a Telegram ChatPhoto."""
|
||||
from telegram import TelegramObject
|
||||
|
||||
from typing import Any, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
||||
class ChatPhoto(TelegramObject):
|
||||
"""This object represents a chat photo.
|
||||
|
@ -58,11 +62,12 @@ class ChatPhoto(TelegramObject):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
small_file_id,
|
||||
small_file_unique_id,
|
||||
big_file_id,
|
||||
big_file_unique_id,
|
||||
bot=None, **kwargs):
|
||||
small_file_id: str,
|
||||
small_file_unique_id: str,
|
||||
big_file_id: str,
|
||||
big_file_unique_id: str,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
self.small_file_id = small_file_id
|
||||
self.small_file_unique_id = small_file_unique_id
|
||||
self.big_file_id = big_file_id
|
||||
|
@ -72,14 +77,7 @@ class ChatPhoto(TelegramObject):
|
|||
|
||||
self._id_attrs = (self.small_file_unique_id, self.big_file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def get_small_file(self, timeout=None, **kwargs):
|
||||
def get_small_file(self, timeout: int = None, **kwargs: Any) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the
|
||||
small (160x160) chat photo
|
||||
|
||||
|
@ -99,7 +97,7 @@ class ChatPhoto(TelegramObject):
|
|||
"""
|
||||
return self.bot.get_file(self.small_file_id, timeout=timeout, **kwargs)
|
||||
|
||||
def get_big_file(self, timeout=None, **kwargs):
|
||||
def get_big_file(self, timeout: int = None, **kwargs: Any) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the
|
||||
big (640x640) chat photo
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"""This module contains an object that represents a Telegram Contact."""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from typing import Any
|
||||
|
||||
|
||||
class Contact(TelegramObject):
|
||||
|
@ -44,8 +45,13 @@ class Contact(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, phone_number, first_name, last_name=None, user_id=None, vcard=None,
|
||||
**kwargs):
|
||||
def __init__(self,
|
||||
phone_number: str,
|
||||
first_name: str,
|
||||
last_name: str = None,
|
||||
user_id: int = None,
|
||||
vcard: str = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.phone_number = str(phone_number)
|
||||
self.first_name = first_name
|
||||
|
@ -55,10 +61,3 @@ class Contact(TelegramObject):
|
|||
self.vcard = vcard
|
||||
|
||||
self._id_attrs = (self.phone_number,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return cls(**data)
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
|
||||
from telegram import PhotoSize, TelegramObject
|
||||
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
||||
class Document(TelegramObject):
|
||||
"""This object represents a general file
|
||||
|
@ -55,14 +60,14 @@ class Document(TelegramObject):
|
|||
_id_keys = ('file_id',)
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
thumb=None,
|
||||
file_name=None,
|
||||
mime_type=None,
|
||||
file_size=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
thumb: PhotoSize = None,
|
||||
file_name: str = None,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
@ -76,17 +81,17 @@ class Document(TelegramObject):
|
|||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Document']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super().de_json(data, bot)
|
||||
|
||||
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def get_file(self, timeout=None, api_kwargs=None):
|
||||
def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
|
||||
|
||||
Args:
|
||||
|
|
|
@ -26,6 +26,10 @@ import urllib.parse as urllib_parse
|
|||
from telegram import TelegramObject
|
||||
from telegram.passport.credentials import decrypt
|
||||
|
||||
from typing import Any, Optional, IO, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, FileCredentials
|
||||
|
||||
|
||||
class File(TelegramObject):
|
||||
"""
|
||||
|
@ -65,12 +69,12 @@ class File(TelegramObject):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
bot=None,
|
||||
file_size=None,
|
||||
file_path=None,
|
||||
**kwargs):
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
bot: 'Bot' = None,
|
||||
file_size: int = None,
|
||||
file_path: str = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
@ -78,18 +82,14 @@ class File(TelegramObject):
|
|||
self.file_size = file_size
|
||||
self.file_path = file_path
|
||||
self.bot = bot
|
||||
self._credentials = None
|
||||
self._credentials: Optional['FileCredentials'] = None
|
||||
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def download(self, custom_path=None, out=None, timeout=None):
|
||||
def download(self,
|
||||
custom_path: str = None,
|
||||
out: IO = None,
|
||||
timeout: int = None) -> Union[str, IO]:
|
||||
"""
|
||||
Download this file. By default, the file is saved in the current working directory with its
|
||||
original filename as reported by Telegram. If the file has no filename, it the file ID will
|
||||
|
@ -147,13 +147,13 @@ class File(TelegramObject):
|
|||
fobj.write(buf)
|
||||
return filename
|
||||
|
||||
def _get_encoded_url(self):
|
||||
def _get_encoded_url(self) -> str:
|
||||
"""Convert any UTF-8 char in :obj:`File.file_path` into a url encoded ASCII string."""
|
||||
sres = urllib_parse.urlsplit(self.file_path)
|
||||
return urllib_parse.urlunsplit(urllib_parse.SplitResult(
|
||||
sres.scheme, sres.netloc, urllib_parse.quote(sres.path), sres.query, sres.fragment))
|
||||
|
||||
def download_as_bytearray(self, buf=None):
|
||||
def download_as_bytearray(self, buf: bytearray = None) -> bytes:
|
||||
"""Download this file and return it as a bytearray.
|
||||
|
||||
Args:
|
||||
|
@ -170,5 +170,5 @@ class File(TelegramObject):
|
|||
buf.extend(self.bot.request.retrieve(self._get_encoded_url()))
|
||||
return buf
|
||||
|
||||
def set_credentials(self, credentials):
|
||||
def set_credentials(self, credentials: 'FileCredentials') -> None:
|
||||
self._credentials = credentials
|
||||
|
|
|
@ -26,6 +26,8 @@ from uuid import uuid4
|
|||
|
||||
from telegram import TelegramError
|
||||
|
||||
from typing import IO, Tuple, Optional
|
||||
|
||||
DEFAULT_MIME_TYPE = 'application/octet-stream'
|
||||
|
||||
|
||||
|
@ -48,7 +50,7 @@ class InputFile:
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, obj, filename=None, attach=None):
|
||||
def __init__(self, obj: IO, filename: str = None, attach: bool = None):
|
||||
self.filename = None
|
||||
self.input_file_content = obj.read()
|
||||
self.attach = 'attached' + uuid4().hex if attach else None
|
||||
|
@ -70,15 +72,15 @@ class InputFile:
|
|||
self.filename = self.mimetype.replace('/', '.')
|
||||
|
||||
@property
|
||||
def field_tuple(self):
|
||||
def field_tuple(self) -> Tuple[str, bytes, str]:
|
||||
return self.filename, self.input_file_content, self.mimetype
|
||||
|
||||
@staticmethod
|
||||
def is_image(stream):
|
||||
def is_image(stream: bytes) -> str:
|
||||
"""Check if the content file is an image by analyzing its headers.
|
||||
|
||||
Args:
|
||||
stream (:obj:`str`): A str representing the content of a file.
|
||||
stream (:obj:`bytes`): A byte stream representing the content of a file.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: The str mime-type of an image.
|
||||
|
@ -91,9 +93,10 @@ class InputFile:
|
|||
raise TelegramError('Could not parse file content')
|
||||
|
||||
@staticmethod
|
||||
def is_file(obj):
|
||||
def is_file(obj: object) -> bool:
|
||||
return hasattr(obj, 'read')
|
||||
|
||||
def to_dict(self):
|
||||
def to_dict(self) -> Optional[str]:
|
||||
if self.attach:
|
||||
return 'attach://' + self.attach
|
||||
return None
|
||||
|
|
|
@ -19,7 +19,11 @@
|
|||
"""Base class for Telegram InputMedia Objects."""
|
||||
|
||||
from telegram import TelegramObject, InputFile, PhotoSize, Animation, Video, Audio, Document
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
|
||||
from typing import Union, IO, cast
|
||||
|
||||
from telegram.utils.types import FileLike
|
||||
|
||||
|
||||
class InputMedia(TelegramObject):
|
||||
|
@ -73,29 +77,32 @@ class InputMediaAnimation(InputMedia):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
media,
|
||||
thumb=None,
|
||||
caption=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
width=None,
|
||||
height=None,
|
||||
duration=None):
|
||||
media: Union[str, FileLike, Animation],
|
||||
thumb: FileLike = None,
|
||||
caption: str = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
width: int = None,
|
||||
height: int = None,
|
||||
duration: int = None):
|
||||
self.type = 'animation'
|
||||
|
||||
if isinstance(media, Animation):
|
||||
self.media = media.file_id
|
||||
self.media: Union[str, InputFile] = media.file_id
|
||||
self.width = media.width
|
||||
self.height = media.height
|
||||
self.duration = media.duration
|
||||
elif InputFile.is_file(media):
|
||||
media = cast(IO, media)
|
||||
self.media = InputFile(media, attach=True)
|
||||
else:
|
||||
self.media = media
|
||||
self.media = media # type: ignore[assignment]
|
||||
|
||||
if thumb:
|
||||
self.thumb = thumb
|
||||
if InputFile.is_file(self.thumb):
|
||||
self.thumb = InputFile(self.thumb, attach=True)
|
||||
if InputFile.is_file(thumb):
|
||||
thumb = cast(IO, thumb)
|
||||
self.thumb = InputFile(thumb, attach=True)
|
||||
else:
|
||||
self.thumb = thumb # type: ignore[assignment]
|
||||
|
||||
if caption:
|
||||
self.caption = caption
|
||||
|
@ -129,15 +136,19 @@ class InputMediaPhoto(InputMedia):
|
|||
in :class:`telegram.ParseMode` for the available modes.
|
||||
"""
|
||||
|
||||
def __init__(self, media, caption=None, parse_mode=DEFAULT_NONE):
|
||||
def __init__(self,
|
||||
media: Union[str, FileLike, PhotoSize],
|
||||
caption: str = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE):
|
||||
self.type = 'photo'
|
||||
|
||||
if isinstance(media, PhotoSize):
|
||||
self.media = media.file_id
|
||||
self.media: Union[str, InputFile] = media.file_id
|
||||
elif InputFile.is_file(media):
|
||||
media = cast(IO, media)
|
||||
self.media = InputFile(media, attach=True)
|
||||
else:
|
||||
self.media = media
|
||||
self.media = media # type: ignore[assignment]
|
||||
|
||||
if caption:
|
||||
self.caption = caption
|
||||
|
@ -189,24 +200,34 @@ class InputMediaVideo(InputMedia):
|
|||
by Telegram.
|
||||
"""
|
||||
|
||||
def __init__(self, media, caption=None, width=None, height=None, duration=None,
|
||||
supports_streaming=None, parse_mode=DEFAULT_NONE, thumb=None):
|
||||
def __init__(self,
|
||||
media: Union[str, FileLike, Video],
|
||||
caption: str = None,
|
||||
width: int = None,
|
||||
height: int = None,
|
||||
duration: int = None,
|
||||
supports_streaming: bool = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
thumb: FileLike = None):
|
||||
self.type = 'video'
|
||||
|
||||
if isinstance(media, Video):
|
||||
self.media = media.file_id
|
||||
self.media: Union[str, InputFile] = media.file_id
|
||||
self.width = media.width
|
||||
self.height = media.height
|
||||
self.duration = media.duration
|
||||
elif InputFile.is_file(media):
|
||||
media = cast(IO, media)
|
||||
self.media = InputFile(media, attach=True)
|
||||
else:
|
||||
self.media = media
|
||||
self.media = media # type: ignore[assignment]
|
||||
|
||||
if thumb:
|
||||
self.thumb = thumb
|
||||
if InputFile.is_file(self.thumb):
|
||||
self.thumb = InputFile(self.thumb, attach=True)
|
||||
if InputFile.is_file(thumb):
|
||||
thumb = cast(IO, thumb)
|
||||
self.thumb = InputFile(thumb, attach=True)
|
||||
else:
|
||||
self.thumb = thumb # type: ignore[assignment]
|
||||
|
||||
if caption:
|
||||
self.caption = caption
|
||||
|
@ -261,24 +282,33 @@ class InputMediaAudio(InputMedia):
|
|||
optional arguments.
|
||||
"""
|
||||
|
||||
def __init__(self, media, thumb=None, caption=None, parse_mode=DEFAULT_NONE,
|
||||
duration=None, performer=None, title=None):
|
||||
def __init__(self,
|
||||
media: Union[str, FileLike, Audio],
|
||||
thumb: FileLike = None,
|
||||
caption: str = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
duration: int = None,
|
||||
performer: str = None,
|
||||
title: str = None):
|
||||
self.type = 'audio'
|
||||
|
||||
if isinstance(media, Audio):
|
||||
self.media = media.file_id
|
||||
self.media: Union[str, InputFile] = media.file_id
|
||||
self.duration = media.duration
|
||||
self.performer = media.performer
|
||||
self.title = media.title
|
||||
elif InputFile.is_file(media):
|
||||
media = cast(IO, media)
|
||||
self.media = InputFile(media, attach=True)
|
||||
else:
|
||||
self.media = media
|
||||
self.media = media # type: ignore[assignment]
|
||||
|
||||
if thumb:
|
||||
self.thumb = thumb
|
||||
if InputFile.is_file(self.thumb):
|
||||
self.thumb = InputFile(self.thumb, attach=True)
|
||||
if InputFile.is_file(thumb):
|
||||
thumb = cast(IO, thumb)
|
||||
self.thumb = InputFile(thumb, attach=True)
|
||||
else:
|
||||
self.thumb = thumb # type: ignore[assignment]
|
||||
|
||||
if caption:
|
||||
self.caption = caption
|
||||
|
@ -318,20 +348,27 @@ class InputMediaDocument(InputMedia):
|
|||
Thumbnails can't be reused and can be only uploaded as a new file.
|
||||
"""
|
||||
|
||||
def __init__(self, media, thumb=None, caption=None, parse_mode=DEFAULT_NONE):
|
||||
def __init__(self,
|
||||
media: Union[str, FileLike, Document],
|
||||
thumb: FileLike = None,
|
||||
caption: str = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE):
|
||||
self.type = 'document'
|
||||
|
||||
if isinstance(media, Document):
|
||||
self.media = media.file_id
|
||||
self.media: Union[str, InputFile] = media.file_id
|
||||
elif InputFile.is_file(media):
|
||||
media = cast(IO, media)
|
||||
self.media = InputFile(media, attach=True)
|
||||
else:
|
||||
self.media = media
|
||||
self.media = media # type: ignore[assignment]
|
||||
|
||||
if thumb:
|
||||
self.thumb = thumb
|
||||
if InputFile.is_file(self.thumb):
|
||||
self.thumb = InputFile(self.thumb, attach=True)
|
||||
if InputFile.is_file(thumb):
|
||||
thumb = cast(IO, thumb)
|
||||
self.thumb = InputFile(thumb, attach=True)
|
||||
else:
|
||||
self.thumb = thumb # type: ignore[assignment]
|
||||
|
||||
if caption:
|
||||
self.caption = caption
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"""This module contains an object that represents a Telegram Location."""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from typing import Any
|
||||
|
||||
|
||||
class Location(TelegramObject):
|
||||
|
@ -38,16 +39,9 @@ class Location(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, longitude, latitude, **kwargs):
|
||||
def __init__(self, longitude: float, latitude: float, **kwargs: Any):
|
||||
# Required
|
||||
self.longitude = float(longitude)
|
||||
self.latitude = float(latitude)
|
||||
|
||||
self._id_attrs = (self.longitude, self.latitude)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return cls(**data)
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
"""This module contains an object that represents a Telegram PhotoSize."""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
||||
class PhotoSize(TelegramObject):
|
||||
|
@ -52,13 +56,13 @@ class PhotoSize(TelegramObject):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
width,
|
||||
height,
|
||||
file_size=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
width: int,
|
||||
height: int,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
@ -70,25 +74,7 @@ class PhotoSize(TelegramObject):
|
|||
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
@classmethod
|
||||
def de_list(cls, data, bot):
|
||||
if not data:
|
||||
return []
|
||||
|
||||
photos = list()
|
||||
for photo in data:
|
||||
photos.append(cls.de_json(photo, bot))
|
||||
|
||||
return photos
|
||||
|
||||
def get_file(self, timeout=None, api_kwargs=None):
|
||||
def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
|
||||
|
||||
Args:
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
"""This module contains objects that represents stickers."""
|
||||
|
||||
from telegram import PhotoSize, TelegramObject
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, List, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
||||
class Sticker(TelegramObject):
|
||||
|
@ -68,18 +72,18 @@ class Sticker(TelegramObject):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
width,
|
||||
height,
|
||||
is_animated,
|
||||
thumb=None,
|
||||
emoji=None,
|
||||
file_size=None,
|
||||
set_name=None,
|
||||
mask_position=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
width: int,
|
||||
height: int,
|
||||
is_animated: bool,
|
||||
thumb: PhotoSize = None,
|
||||
emoji: str = None,
|
||||
file_size: int = None,
|
||||
set_name: str = None,
|
||||
mask_position: 'MaskPosition' = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
@ -97,25 +101,18 @@ class Sticker(TelegramObject):
|
|||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Sticker']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super().de_json(data, bot)
|
||||
|
||||
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
|
||||
data['mask_position'] = MaskPosition.de_json(data.get('mask_position'), bot)
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
@classmethod
|
||||
def de_list(cls, data, bot):
|
||||
if not data:
|
||||
return list()
|
||||
|
||||
return [cls.de_json(d, bot) for d in data]
|
||||
|
||||
def get_file(self, timeout=None, api_kwargs=None):
|
||||
def get_file(self, timeout: str = None, api_kwargs: JSONDict = None) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
|
||||
|
||||
Args:
|
||||
|
@ -161,8 +158,15 @@ class StickerSet(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, name, title, is_animated, contains_masks, stickers, bot=None, thumb=None,
|
||||
**kwargs):
|
||||
def __init__(self,
|
||||
name: str,
|
||||
title: str,
|
||||
is_animated: bool,
|
||||
contains_masks: bool,
|
||||
stickers: List[Sticker],
|
||||
bot: 'Bot' = None,
|
||||
thumb: PhotoSize = None,
|
||||
**kwargs: Any):
|
||||
self.name = name
|
||||
self.title = title
|
||||
self.is_animated = is_animated
|
||||
|
@ -174,18 +178,16 @@ class StickerSet(TelegramObject):
|
|||
self._id_attrs = (self.name,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['StickerSet']:
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super().de_json(data, bot)
|
||||
|
||||
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
|
||||
data['stickers'] = Sticker.de_list(data.get('stickers'), bot)
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def to_dict(self):
|
||||
def to_dict(self) -> JSONDict:
|
||||
data = super().to_dict()
|
||||
|
||||
data['stickers'] = [s.to_dict() for s in data.get('stickers')]
|
||||
|
@ -225,16 +227,16 @@ class MaskPosition(TelegramObject):
|
|||
scale (:obj:`float`): Mask scaling coefficient. For example, 2.0 means double size.
|
||||
|
||||
"""
|
||||
FOREHEAD = 'forehead'
|
||||
FOREHEAD: str = 'forehead'
|
||||
""":obj:`str`: 'forehead'"""
|
||||
EYES = 'eyes'
|
||||
EYES: str = 'eyes'
|
||||
""":obj:`str`: 'eyes'"""
|
||||
MOUTH = 'mouth'
|
||||
MOUTH: str = 'mouth'
|
||||
""":obj:`str`: 'mouth'"""
|
||||
CHIN = 'chin'
|
||||
CHIN: str = 'chin'
|
||||
""":obj:`str`: 'chin'"""
|
||||
|
||||
def __init__(self, point, x_shift, y_shift, scale, **kwargs):
|
||||
def __init__(self, point: str, x_shift: float, y_shift: float, scale: float, **kwargs: Any):
|
||||
self.point = point
|
||||
self.x_shift = x_shift
|
||||
self.y_shift = y_shift
|
||||
|
@ -243,7 +245,9 @@ class MaskPosition(TelegramObject):
|
|||
self._id_attrs = (self.point, self.x_shift, self.y_shift, self.scale)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['MaskPosition']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if data is None:
|
||||
return None
|
||||
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
"""This module contains an object that represents a Telegram Venue."""
|
||||
|
||||
from telegram import TelegramObject, Location
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class Venue(TelegramObject):
|
||||
|
@ -46,8 +50,13 @@ class Venue(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, location, title, address, foursquare_id=None, foursquare_type=None,
|
||||
**kwargs):
|
||||
def __init__(self,
|
||||
location: Location,
|
||||
title: str,
|
||||
address: str,
|
||||
foursquare_id: str = None,
|
||||
foursquare_type: str = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.location = location
|
||||
self.title = title
|
||||
|
@ -59,8 +68,8 @@ class Venue(TelegramObject):
|
|||
self._id_attrs = (self.location, self.title)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
data = super().de_json(data, bot)
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Venue']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
"""This module contains an object that represents a Telegram Video."""
|
||||
|
||||
from telegram import PhotoSize, TelegramObject
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
||||
class Video(TelegramObject):
|
||||
|
@ -58,16 +62,16 @@ class Video(TelegramObject):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
width,
|
||||
height,
|
||||
duration,
|
||||
thumb=None,
|
||||
mime_type=None,
|
||||
file_size=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
width: int,
|
||||
height: int,
|
||||
duration: int,
|
||||
thumb: PhotoSize = None,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
@ -83,17 +87,17 @@ class Video(TelegramObject):
|
|||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Video']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super().de_json(data, bot)
|
||||
|
||||
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def get_file(self, timeout=None, api_kwargs=None):
|
||||
def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
|
||||
|
||||
Args:
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
"""This module contains an object that represents a Telegram VideoNote."""
|
||||
|
||||
from telegram import PhotoSize, TelegramObject
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
||||
class VideoNote(TelegramObject):
|
||||
|
@ -55,14 +59,14 @@ class VideoNote(TelegramObject):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
length,
|
||||
duration,
|
||||
thumb=None,
|
||||
file_size=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
length: int,
|
||||
duration: int,
|
||||
thumb: PhotoSize = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
@ -76,17 +80,17 @@ class VideoNote(TelegramObject):
|
|||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['VideoNote']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super().de_json(data, bot)
|
||||
|
||||
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def get_file(self, timeout=None, api_kwargs=None):
|
||||
def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
|
||||
|
||||
Args:
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
"""This module contains an object that represents a Telegram Voice."""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
||||
class Voice(TelegramObject):
|
||||
|
@ -52,13 +56,13 @@ class Voice(TelegramObject):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
file_unique_id,
|
||||
duration,
|
||||
mime_type=None,
|
||||
file_size=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
duration: int,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
@ -70,16 +74,7 @@ class Voice(TelegramObject):
|
|||
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super().de_json(data, bot)
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def get_file(self, timeout=None, api_kwargs=None):
|
||||
def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
|
||||
|
||||
Args:
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"""This module contains an object that represents a Telegram ForceReply."""
|
||||
|
||||
from telegram import ReplyMarkup
|
||||
from typing import Any
|
||||
|
||||
|
||||
class ForceReply(ReplyMarkup):
|
||||
|
@ -48,7 +49,7 @@ class ForceReply(ReplyMarkup):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, force_reply=True, selective=False, **kwargs):
|
||||
def __init__(self, force_reply: bool = True, selective: bool = False, **kwargs: Any):
|
||||
# Required
|
||||
self.force_reply = bool(force_reply)
|
||||
# Optionals
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
import sys
|
||||
|
||||
from telegram import MessageEntity, TelegramObject, Animation, PhotoSize
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import List, Any, Dict, Optional, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class Game(TelegramObject):
|
||||
|
@ -63,13 +67,13 @@ class Game(TelegramObject):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
title,
|
||||
description,
|
||||
photo,
|
||||
text=None,
|
||||
text_entities=None,
|
||||
animation=None,
|
||||
**kwargs):
|
||||
title: str,
|
||||
description: str,
|
||||
photo: List[PhotoSize],
|
||||
text: str = None,
|
||||
text_entities: List[MessageEntity] = None,
|
||||
animation: Animation = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.title = title
|
||||
self.description = description
|
||||
|
@ -82,19 +86,19 @@ class Game(TelegramObject):
|
|||
self._id_attrs = (self.title, self.description, self.photo)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Game']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super().de_json(data, bot)
|
||||
|
||||
data['photo'] = PhotoSize.de_list(data.get('photo'), bot)
|
||||
data['text_entities'] = MessageEntity.de_list(data.get('text_entities'), bot)
|
||||
data['animation'] = Animation.de_json(data.get('animation'), bot)
|
||||
|
||||
return cls(**data)
|
||||
|
||||
def to_dict(self):
|
||||
def to_dict(self) -> JSONDict:
|
||||
data = super().to_dict()
|
||||
|
||||
data['photo'] = [p.to_dict() for p in self.photo]
|
||||
|
@ -103,7 +107,7 @@ class Game(TelegramObject):
|
|||
|
||||
return data
|
||||
|
||||
def parse_text_entity(self, entity):
|
||||
def parse_text_entity(self, entity: MessageEntity) -> str:
|
||||
"""Returns the text from a given :class:`telegram.MessageEntity`.
|
||||
|
||||
Note:
|
||||
|
@ -118,7 +122,13 @@ class Game(TelegramObject):
|
|||
Returns:
|
||||
:obj:`str`: The text of the given entity.
|
||||
|
||||
Raises:
|
||||
RuntimeError: If this game has no text.
|
||||
|
||||
"""
|
||||
if not self.text:
|
||||
raise RuntimeError("This Game has no 'text'.")
|
||||
|
||||
# Is it a narrow build, if so we don't need to convert
|
||||
if sys.maxunicode == 0xffff:
|
||||
return self.text[entity.offset:entity.offset + entity.length]
|
||||
|
@ -128,7 +138,7 @@ class Game(TelegramObject):
|
|||
|
||||
return entity_text.decode('utf-16-le')
|
||||
|
||||
def parse_text_entities(self, types=None):
|
||||
def parse_text_entities(self, types: List[str] = None) -> Dict[MessageEntity, str]:
|
||||
"""
|
||||
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
|
||||
It contains entities from this message filtered by their ``type`` attribute as the key, and
|
||||
|
@ -154,8 +164,8 @@ class Game(TelegramObject):
|
|||
|
||||
return {
|
||||
entity: self.parse_text_entity(entity)
|
||||
for entity in self.text_entities if entity.type in types
|
||||
for entity in (self.text_entities or []) if entity.type in types
|
||||
}
|
||||
|
||||
def __hash__(self):
|
||||
def __hash__(self) -> int:
|
||||
return hash((self.title, self.description, tuple(p for p in self.photo)))
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
"""This module contains an object that represents a Telegram GameHighScore."""
|
||||
|
||||
from telegram import TelegramObject, User
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class GameHighScore(TelegramObject):
|
||||
|
@ -39,7 +43,7 @@ class GameHighScore(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, position, user, score):
|
||||
def __init__(self, position: int, user: User, score: int):
|
||||
self.position = position
|
||||
self.user = user
|
||||
self.score = score
|
||||
|
@ -47,12 +51,12 @@ class GameHighScore(TelegramObject):
|
|||
self._id_attrs = (self.position, self.user, self.score)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['GameHighScore']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super().de_json(data, bot)
|
||||
|
||||
data['user'] = User.de_json(data.get('user'), bot)
|
||||
|
||||
return cls(**data)
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
"""This module contains an object that represents a Telegram InlineKeyboardButton."""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from typing import Any, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import CallbackGame, LoginUrl
|
||||
|
||||
|
||||
class InlineKeyboardButton(TelegramObject):
|
||||
|
@ -79,15 +82,15 @@ class InlineKeyboardButton(TelegramObject):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
text,
|
||||
url=None,
|
||||
callback_data=None,
|
||||
switch_inline_query=None,
|
||||
switch_inline_query_current_chat=None,
|
||||
callback_game=None,
|
||||
pay=None,
|
||||
login_url=None,
|
||||
**kwargs):
|
||||
text: str,
|
||||
url: str = None,
|
||||
callback_data: str = None,
|
||||
switch_inline_query: str = None,
|
||||
switch_inline_query_current_chat: str = None,
|
||||
callback_game: 'CallbackGame' = None,
|
||||
pay: bool = None,
|
||||
login_url: 'LoginUrl' = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.text = text
|
||||
|
||||
|
@ -110,10 +113,3 @@ class InlineKeyboardButton(TelegramObject):
|
|||
self.callback_game,
|
||||
self.pay,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return cls(**data)
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
"""This module contains an object that represents a Telegram InlineKeyboardMarkup."""
|
||||
|
||||
from telegram import ReplyMarkup, InlineKeyboardButton
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, List, Optional, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class InlineKeyboardMarkup(ReplyMarkup):
|
||||
|
@ -39,11 +43,11 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, inline_keyboard, **kwargs):
|
||||
def __init__(self, inline_keyboard: List[List[InlineKeyboardButton]], **kwargs: Any):
|
||||
# Required
|
||||
self.inline_keyboard = inline_keyboard
|
||||
|
||||
def to_dict(self):
|
||||
def to_dict(self) -> JSONDict:
|
||||
data = super().to_dict()
|
||||
|
||||
data['inline_keyboard'] = []
|
||||
|
@ -53,20 +57,26 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
|||
return data
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict],
|
||||
bot: 'Bot') -> Optional['InlineKeyboardMarkup']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
keyboard = []
|
||||
for row in data['inline_keyboard']:
|
||||
tmp = []
|
||||
for col in row:
|
||||
tmp.append(InlineKeyboardButton.de_json(col, bot))
|
||||
btn = InlineKeyboardButton.de_json(col, bot)
|
||||
if btn:
|
||||
tmp.append(btn)
|
||||
keyboard.append(tmp)
|
||||
|
||||
return cls(keyboard)
|
||||
|
||||
@classmethod
|
||||
def from_button(cls, button, **kwargs):
|
||||
def from_button(cls, button: InlineKeyboardButton, **kwargs: Any) -> 'InlineKeyboardMarkup':
|
||||
"""Shortcut for::
|
||||
|
||||
InlineKeyboardMarkup([[button]], **kwargs)
|
||||
|
@ -81,7 +91,8 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
|||
return cls([[button]], **kwargs)
|
||||
|
||||
@classmethod
|
||||
def from_row(cls, button_row, **kwargs):
|
||||
def from_row(cls, button_row: List[InlineKeyboardButton],
|
||||
**kwargs: Any) -> 'InlineKeyboardMarkup':
|
||||
"""Shortcut for::
|
||||
|
||||
InlineKeyboardMarkup([button_row], **kwargs)
|
||||
|
@ -97,7 +108,8 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
|||
return cls([button_row], **kwargs)
|
||||
|
||||
@classmethod
|
||||
def from_column(cls, button_column, **kwargs):
|
||||
def from_column(cls, button_column: List[InlineKeyboardButton],
|
||||
**kwargs: Any) -> 'InlineKeyboardMarkup':
|
||||
"""Shortcut for::
|
||||
|
||||
InlineKeyboardMarkup([[button] for button in button_column], **kwargs)
|
||||
|
@ -113,7 +125,7 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
|||
button_grid = [[button] for button in button_column]
|
||||
return cls(button_grid, **kwargs)
|
||||
|
||||
def __eq__(self, other):
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if isinstance(other, self.__class__):
|
||||
if len(self.inline_keyboard) != len(other.inline_keyboard):
|
||||
return False
|
||||
|
@ -126,5 +138,5 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
|||
return True
|
||||
return super(InlineKeyboardMarkup, self).__eq__(other) # pylint: disable=no-member
|
||||
|
||||
def __hash__(self):
|
||||
def __hash__(self) -> int:
|
||||
return hash(tuple(tuple(button for button in row) for row in self.inline_keyboard))
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
"""This module contains an object that represents a Telegram InlineQuery."""
|
||||
|
||||
from telegram import TelegramObject, User, Location
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class InlineQuery(TelegramObject):
|
||||
|
@ -53,7 +57,14 @@ class InlineQuery(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, id, from_user, query, offset, location=None, bot=None, **kwargs):
|
||||
def __init__(self,
|
||||
id: str,
|
||||
from_user: User,
|
||||
query: str,
|
||||
offset: str,
|
||||
location: Location = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.id = id
|
||||
self.from_user = from_user
|
||||
|
@ -67,8 +78,8 @@ class InlineQuery(TelegramObject):
|
|||
self._id_attrs = (self.id,)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
data = super().de_json(data, bot)
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['InlineQuery']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
@ -78,7 +89,7 @@ class InlineQuery(TelegramObject):
|
|||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
def answer(self, *args, auto_pagination=False, **kwargs):
|
||||
def answer(self, *args: Any, auto_pagination: bool = False, **kwargs: Any) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.answer_inline_query(update.inline_query.id,
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResult."""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from typing import Any
|
||||
|
||||
|
||||
class InlineQueryResult(TelegramObject):
|
||||
|
@ -38,7 +39,7 @@ class InlineQueryResult(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, type, id, **kwargs):
|
||||
def __init__(self, type: str, id: str, **kwargs: Any):
|
||||
# Required
|
||||
self.type = str(type)
|
||||
self.id = str(id)
|
||||
|
@ -46,9 +47,9 @@ class InlineQueryResult(TelegramObject):
|
|||
self._id_attrs = (self.id,)
|
||||
|
||||
@property
|
||||
def _has_parse_mode(self):
|
||||
def _has_parse_mode(self) -> bool:
|
||||
return hasattr(self, 'parse_mode')
|
||||
|
||||
@property
|
||||
def _has_input_message_content(self):
|
||||
def _has_input_message_content(self) -> bool:
|
||||
return hasattr(self, 'input_message_content')
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultArticle."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from typing import Any, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultArticle(InlineQueryResult):
|
||||
|
@ -59,17 +62,17 @@ class InlineQueryResultArticle(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
title,
|
||||
input_message_content,
|
||||
reply_markup=None,
|
||||
url=None,
|
||||
hide_url=None,
|
||||
description=None,
|
||||
thumb_url=None,
|
||||
thumb_width=None,
|
||||
thumb_height=None,
|
||||
**kwargs):
|
||||
id: str,
|
||||
title: str,
|
||||
input_message_content: 'InputMessageContent',
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
url: str = None,
|
||||
hide_url: bool = None,
|
||||
description: str = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
**kwargs: Any):
|
||||
|
||||
# Required
|
||||
super().__init__('article', id)
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultAudio."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultAudio(InlineQueryResult):
|
||||
|
@ -63,16 +66,16 @@ class InlineQueryResultAudio(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
audio_url,
|
||||
title,
|
||||
performer=None,
|
||||
audio_duration=None,
|
||||
caption=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
**kwargs):
|
||||
id: str,
|
||||
audio_url: str,
|
||||
title: str,
|
||||
performer: str = None,
|
||||
audio_duration: int = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
|
||||
# Required
|
||||
super().__init__('audio', id)
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultCachedAudio."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultCachedAudio(InlineQueryResult):
|
||||
|
@ -57,13 +60,13 @@ class InlineQueryResultCachedAudio(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
audio_file_id,
|
||||
caption=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
**kwargs):
|
||||
id: str,
|
||||
audio_file_id: str,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
super().__init__('audio', id)
|
||||
self.audio_file_id = audio_file_id
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultCachedDocument."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultCachedDocument(InlineQueryResult):
|
||||
|
@ -63,15 +66,15 @@ class InlineQueryResultCachedDocument(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
title,
|
||||
document_file_id,
|
||||
description=None,
|
||||
caption=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
**kwargs):
|
||||
id: str,
|
||||
title: str,
|
||||
document_file_id: str,
|
||||
description: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
super().__init__('document', id)
|
||||
self.title = title
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultCachedGif."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultCachedGif(InlineQueryResult):
|
||||
|
@ -62,14 +65,14 @@ class InlineQueryResultCachedGif(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
gif_file_id,
|
||||
title=None,
|
||||
caption=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
**kwargs):
|
||||
id: str,
|
||||
gif_file_id: str,
|
||||
title: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
super().__init__('gif', id)
|
||||
self.gif_file_id = gif_file_id
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
|
||||
|
@ -62,14 +65,14 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
mpeg4_file_id,
|
||||
title=None,
|
||||
caption=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
**kwargs):
|
||||
id: str,
|
||||
mpeg4_file_id: str,
|
||||
title: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
super().__init__('mpeg4_gif', id)
|
||||
self.mpeg4_file_id = mpeg4_file_id
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultPhoto"""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultCachedPhoto(InlineQueryResult):
|
||||
|
@ -64,15 +67,15 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
photo_file_id,
|
||||
title=None,
|
||||
description=None,
|
||||
caption=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
**kwargs):
|
||||
id: str,
|
||||
photo_file_id: str,
|
||||
title: str = None,
|
||||
description: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
super().__init__('photo', id)
|
||||
self.photo_file_id = photo_file_id
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultCachedSticker."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from typing import Any, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import ReplyMarkup, InputMessageContent
|
||||
|
||||
|
||||
class InlineQueryResultCachedSticker(InlineQueryResult):
|
||||
|
@ -48,11 +51,11 @@ class InlineQueryResultCachedSticker(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
sticker_file_id,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
**kwargs):
|
||||
id: str,
|
||||
sticker_file_id: str,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
super().__init__('sticker', id)
|
||||
self.sticker_file_id = sticker_file_id
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultCachedVideo."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultCachedVideo(InlineQueryResult):
|
||||
|
@ -64,15 +67,15 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
video_file_id,
|
||||
title,
|
||||
description=None,
|
||||
caption=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
**kwargs):
|
||||
id: str,
|
||||
video_file_id: str,
|
||||
title: str,
|
||||
description: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
super().__init__('video', id)
|
||||
self.video_file_id = video_file_id
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultCachedVoice."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultCachedVoice(InlineQueryResult):
|
||||
|
@ -59,14 +62,14 @@ class InlineQueryResultCachedVoice(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
voice_file_id,
|
||||
title,
|
||||
caption=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
**kwargs):
|
||||
id: str,
|
||||
voice_file_id: str,
|
||||
title: str,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
super().__init__('voice', id)
|
||||
self.voice_file_id = voice_file_id
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultContact."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from typing import Any, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import ReplyMarkup, InputMessageContent
|
||||
|
||||
|
||||
class InlineQueryResultContact(InlineQueryResult):
|
||||
|
@ -62,17 +65,17 @@ class InlineQueryResultContact(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
phone_number,
|
||||
first_name,
|
||||
last_name=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
thumb_url=None,
|
||||
thumb_width=None,
|
||||
thumb_height=None,
|
||||
vcard=None,
|
||||
**kwargs):
|
||||
id: str,
|
||||
phone_number: str,
|
||||
first_name: str,
|
||||
last_name: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
vcard: str = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
super().__init__('contact', id)
|
||||
self.phone_number = phone_number
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultDocument"""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultDocument(InlineQueryResult):
|
||||
|
@ -74,19 +77,19 @@ class InlineQueryResultDocument(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
document_url,
|
||||
title,
|
||||
mime_type,
|
||||
caption=None,
|
||||
description=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
thumb_url=None,
|
||||
thumb_width=None,
|
||||
thumb_height=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
**kwargs):
|
||||
id: str,
|
||||
document_url: str,
|
||||
title: str,
|
||||
mime_type: str,
|
||||
caption: str = None,
|
||||
description: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
super().__init__('document', id)
|
||||
self.document_url = document_url
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultGame."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from typing import Any, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultGame(InlineQueryResult):
|
||||
|
@ -40,7 +43,11 @@ class InlineQueryResultGame(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, id, game_short_name, reply_markup=None, **kwargs):
|
||||
def __init__(self,
|
||||
id: str,
|
||||
game_short_name: str,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
super().__init__('game', id)
|
||||
self.id = id
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultGif."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultGif(InlineQueryResult):
|
||||
|
@ -74,19 +77,19 @@ class InlineQueryResultGif(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
gif_url,
|
||||
thumb_url,
|
||||
gif_width=None,
|
||||
gif_height=None,
|
||||
title=None,
|
||||
caption=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
gif_duration=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
thumb_mime_type=None,
|
||||
**kwargs):
|
||||
id: str,
|
||||
gif_url: str,
|
||||
thumb_url: str,
|
||||
gif_width: int = None,
|
||||
gif_height: int = None,
|
||||
title: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
gif_duration: int = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
thumb_mime_type: str = None,
|
||||
**kwargs: Any):
|
||||
|
||||
# Required
|
||||
super().__init__('gif', id)
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultLocation."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from typing import Any, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import ReplyMarkup, InputMessageContent
|
||||
|
||||
|
||||
class InlineQueryResultLocation(InlineQueryResult):
|
||||
|
@ -62,17 +65,17 @@ class InlineQueryResultLocation(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
latitude,
|
||||
longitude,
|
||||
title,
|
||||
live_period=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
thumb_url=None,
|
||||
thumb_width=None,
|
||||
thumb_height=None,
|
||||
**kwargs):
|
||||
id: str,
|
||||
latitude: float,
|
||||
longitude: float,
|
||||
title: str,
|
||||
live_period: int = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
super().__init__('location', id)
|
||||
self.latitude = latitude
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
||||
|
@ -74,19 +77,19 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
mpeg4_url,
|
||||
thumb_url,
|
||||
mpeg4_width=None,
|
||||
mpeg4_height=None,
|
||||
title=None,
|
||||
caption=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
mpeg4_duration=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
thumb_mime_type=None,
|
||||
**kwargs):
|
||||
id: str,
|
||||
mpeg4_url: str,
|
||||
thumb_url: str,
|
||||
mpeg4_width: int = None,
|
||||
mpeg4_height: int = None,
|
||||
title: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
mpeg4_duration: int = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
thumb_mime_type: str = None,
|
||||
**kwargs: Any):
|
||||
|
||||
# Required
|
||||
super().__init__('mpeg4_gif', id)
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultPhoto."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultPhoto(InlineQueryResult):
|
||||
|
@ -71,18 +74,18 @@ class InlineQueryResultPhoto(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
photo_url,
|
||||
thumb_url,
|
||||
photo_width=None,
|
||||
photo_height=None,
|
||||
title=None,
|
||||
description=None,
|
||||
caption=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
**kwargs):
|
||||
id: str,
|
||||
photo_url: str,
|
||||
thumb_url: str,
|
||||
photo_width: int = None,
|
||||
photo_height: int = None,
|
||||
title: str = None,
|
||||
description: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
super().__init__('photo', id)
|
||||
self.photo_url = photo_url
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultVenue."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from typing import Any, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import ReplyMarkup, InputMessageContent
|
||||
|
||||
|
||||
class InlineQueryResultVenue(InlineQueryResult):
|
||||
|
@ -68,19 +71,19 @@ class InlineQueryResultVenue(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
latitude,
|
||||
longitude,
|
||||
title,
|
||||
address,
|
||||
foursquare_id=None,
|
||||
foursquare_type=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
thumb_url=None,
|
||||
thumb_width=None,
|
||||
thumb_height=None,
|
||||
**kwargs):
|
||||
id: str,
|
||||
latitude: float,
|
||||
longitude: float,
|
||||
title: str,
|
||||
address: str,
|
||||
foursquare_id: str = None,
|
||||
foursquare_type: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
**kwargs: Any):
|
||||
|
||||
# Required
|
||||
super().__init__('venue', id)
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultVideo."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultVideo(InlineQueryResult):
|
||||
|
@ -81,20 +84,20 @@ class InlineQueryResultVideo(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
video_url,
|
||||
mime_type,
|
||||
thumb_url,
|
||||
title,
|
||||
caption=None,
|
||||
video_width=None,
|
||||
video_height=None,
|
||||
video_duration=None,
|
||||
description=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
**kwargs):
|
||||
id: str,
|
||||
video_url: str,
|
||||
mime_type: str,
|
||||
thumb_url: str,
|
||||
title: str,
|
||||
caption: str = None,
|
||||
video_width: int = None,
|
||||
video_height: int = None,
|
||||
video_duration: int = None,
|
||||
description: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
|
||||
# Required
|
||||
super().__init__('video', id)
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
"""This module contains the classes that represent Telegram InlineQueryResultVoice."""
|
||||
|
||||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
||||
class InlineQueryResultVoice(InlineQueryResult):
|
||||
|
@ -62,15 +65,15 @@ class InlineQueryResultVoice(InlineQueryResult):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
voice_url,
|
||||
title,
|
||||
voice_duration=None,
|
||||
caption=None,
|
||||
reply_markup=None,
|
||||
input_message_content=None,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
**kwargs):
|
||||
id: str,
|
||||
voice_url: str,
|
||||
title: str,
|
||||
voice_duration: int = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
|
||||
# Required
|
||||
super().__init__('voice', id)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"""This module contains the classes that represent Telegram InputContactMessageContent."""
|
||||
|
||||
from telegram import InputMessageContent
|
||||
from typing import Any
|
||||
|
||||
|
||||
class InputContactMessageContent(InputMessageContent):
|
||||
|
@ -44,7 +45,12 @@ class InputContactMessageContent(InputMessageContent):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, phone_number, first_name, last_name=None, vcard=None, **kwargs):
|
||||
def __init__(self,
|
||||
phone_number: str,
|
||||
first_name: str,
|
||||
last_name: str = None,
|
||||
vcard: str = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.phone_number = phone_number
|
||||
self.first_name = first_name
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"""This module contains the classes that represent Telegram InputLocationMessageContent."""
|
||||
|
||||
from telegram import InputMessageContent
|
||||
from typing import Any
|
||||
|
||||
|
||||
class InputLocationMessageContent(InputMessageContent):
|
||||
|
@ -43,7 +44,7 @@ class InputLocationMessageContent(InputMessageContent):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, latitude, longitude, live_period=None, **kwargs):
|
||||
def __init__(self, latitude: float, longitude: float, live_period: int = None, **kwargs: Any):
|
||||
# Required
|
||||
self.latitude = latitude
|
||||
self.longitude = longitude
|
||||
|
|
|
@ -30,9 +30,9 @@ class InputMessageContent(TelegramObject):
|
|||
|
||||
"""
|
||||
@property
|
||||
def _has_parse_mode(self):
|
||||
def _has_parse_mode(self) -> bool:
|
||||
return hasattr(self, 'parse_mode')
|
||||
|
||||
@property
|
||||
def _has_disable_web_page_preview(self):
|
||||
def _has_disable_web_page_preview(self) -> bool:
|
||||
return hasattr(self, 'disable_web_page_preview')
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
"""This module contains the classes that represent Telegram InputTextMessageContent."""
|
||||
|
||||
from telegram import InputMessageContent
|
||||
from telegram.utils.helpers import DEFAULT_NONE
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union
|
||||
|
||||
|
||||
class InputTextMessageContent(InputMessageContent):
|
||||
|
@ -51,10 +52,10 @@ class InputTextMessageContent(InputMessageContent):
|
|||
"""
|
||||
|
||||
def __init__(self,
|
||||
message_text,
|
||||
parse_mode=DEFAULT_NONE,
|
||||
disable_web_page_preview=DEFAULT_NONE,
|
||||
**kwargs):
|
||||
message_text: str,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
disable_web_page_preview: Union[bool, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.message_text = message_text
|
||||
# Optionals
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"""This module contains the classes that represent Telegram InputVenueMessageContent."""
|
||||
|
||||
from telegram import InputMessageContent
|
||||
from typing import Any
|
||||
|
||||
|
||||
class InputVenueMessageContent(InputMessageContent):
|
||||
|
@ -51,8 +52,14 @@ class InputVenueMessageContent(InputMessageContent):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, latitude, longitude, title, address, foursquare_id=None,
|
||||
foursquare_type=None, **kwargs):
|
||||
def __init__(self,
|
||||
latitude: float,
|
||||
longitude: float,
|
||||
title: str,
|
||||
address: str,
|
||||
foursquare_id: str = None,
|
||||
foursquare_type: str = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.latitude = latitude
|
||||
self.longitude = longitude
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"""This module contains an object that represents a Telegram KeyboardButton."""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from typing import Any
|
||||
|
||||
|
||||
class KeyboardButton(TelegramObject):
|
||||
|
@ -59,8 +60,12 @@ class KeyboardButton(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, text, request_contact=None, request_location=None, request_poll=None,
|
||||
**kwargs):
|
||||
def __init__(self,
|
||||
text: str,
|
||||
request_contact: bool = None,
|
||||
request_location: bool = None,
|
||||
request_poll: bool = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.text = text
|
||||
# Optionals
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a type of a Telegram Poll."""
|
||||
from telegram import TelegramObject
|
||||
from typing import Any
|
||||
|
||||
|
||||
class KeyboardButtonPollType(TelegramObject):
|
||||
|
@ -34,7 +35,7 @@ class KeyboardButtonPollType(TelegramObject):
|
|||
passed, only regular polls will be allowed. Otherwise, the user will be allowed to
|
||||
create a poll of any type.
|
||||
"""
|
||||
def __init__(self, type=None):
|
||||
def __init__(self, type: str = None, **kwargs: Any):
|
||||
self.type = type
|
||||
|
||||
self._id_attrs = (self.type,)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram LoginUrl."""
|
||||
from telegram import TelegramObject
|
||||
from typing import Any
|
||||
|
||||
|
||||
class LoginUrl(TelegramObject):
|
||||
|
@ -66,7 +67,12 @@ class LoginUrl(TelegramObject):
|
|||
`Checking authorization <https://core.telegram.org/widgets/login#checking-authorization>`_
|
||||
"""
|
||||
|
||||
def __init__(self, url, forward_text=None, bot_username=None, request_write_access=None):
|
||||
def __init__(self,
|
||||
url: str,
|
||||
forward_text: bool = None,
|
||||
bot_username: str = None,
|
||||
request_write_access: bool = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.url = url
|
||||
# Optional
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram Message."""
|
||||
import sys
|
||||
import datetime
|
||||
from html import escape
|
||||
|
||||
from telegram import (Animation, Audio, Contact, Document, Chat, Location, PhotoSize, Sticker,
|
||||
|
@ -27,6 +28,11 @@ from telegram import (Animation, Audio, Contact, Document, Chat, Location, Photo
|
|||
from telegram import ParseMode
|
||||
from telegram.utils.helpers import escape_markdown, to_timestamp, from_timestamp
|
||||
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, List, Dict, Optional, Union, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, InputMedia, GameHighScore
|
||||
|
||||
_UNDEFINED = object()
|
||||
|
||||
|
||||
|
@ -203,7 +209,7 @@ class Message(TelegramObject):
|
|||
programming languages may have difficulty/silent defects in interpreting it. But it is
|
||||
smaller than 52 bits, so a signed 64 bit integer or double-precision float type are
|
||||
safe for storing this identifier.
|
||||
pinned_message (:class:`telegram.message`, optional): Specified message was pinned. Note
|
||||
pinned_message (:class:`telegram.Message`, optional): Specified message was pinned. Note
|
||||
that the Message object in this field will not contain further :attr:`reply_to_message`
|
||||
fields even if it is itself a reply.
|
||||
invoice (:class:`telegram.Invoice`, optional): Message is an invoice for a payment,
|
||||
|
@ -239,57 +245,57 @@ class Message(TelegramObject):
|
|||
'passport_data'] + ATTACHMENT_TYPES
|
||||
|
||||
def __init__(self,
|
||||
message_id,
|
||||
from_user,
|
||||
date,
|
||||
chat,
|
||||
forward_from=None,
|
||||
forward_from_chat=None,
|
||||
forward_from_message_id=None,
|
||||
forward_date=None,
|
||||
reply_to_message=None,
|
||||
edit_date=None,
|
||||
text=None,
|
||||
entities=None,
|
||||
caption_entities=None,
|
||||
audio=None,
|
||||
document=None,
|
||||
game=None,
|
||||
photo=None,
|
||||
sticker=None,
|
||||
video=None,
|
||||
voice=None,
|
||||
video_note=None,
|
||||
new_chat_members=None,
|
||||
caption=None,
|
||||
contact=None,
|
||||
location=None,
|
||||
venue=None,
|
||||
left_chat_member=None,
|
||||
new_chat_title=None,
|
||||
new_chat_photo=None,
|
||||
delete_chat_photo=False,
|
||||
group_chat_created=False,
|
||||
supergroup_chat_created=False,
|
||||
channel_chat_created=False,
|
||||
migrate_to_chat_id=None,
|
||||
migrate_from_chat_id=None,
|
||||
pinned_message=None,
|
||||
invoice=None,
|
||||
successful_payment=None,
|
||||
forward_signature=None,
|
||||
author_signature=None,
|
||||
media_group_id=None,
|
||||
connected_website=None,
|
||||
animation=None,
|
||||
passport_data=None,
|
||||
poll=None,
|
||||
forward_sender_name=None,
|
||||
reply_markup=None,
|
||||
bot=None,
|
||||
dice=None,
|
||||
via_bot=None,
|
||||
**kwargs):
|
||||
message_id: int,
|
||||
date: datetime.datetime,
|
||||
chat: Chat,
|
||||
from_user: User = None,
|
||||
forward_from: User = None,
|
||||
forward_from_chat: Chat = None,
|
||||
forward_from_message_id: int = None,
|
||||
forward_date: datetime.datetime = None,
|
||||
reply_to_message: 'Message' = None,
|
||||
edit_date: datetime.datetime = None,
|
||||
text: str = None,
|
||||
entities: List[MessageEntity] = None,
|
||||
caption_entities: List[MessageEntity] = None,
|
||||
audio: Audio = None,
|
||||
document: Document = None,
|
||||
game: Game = None,
|
||||
photo: List[PhotoSize] = None,
|
||||
sticker: Sticker = None,
|
||||
video: Video = None,
|
||||
voice: Voice = None,
|
||||
video_note: VideoNote = None,
|
||||
new_chat_members: List[User] = None,
|
||||
caption: str = None,
|
||||
contact: Contact = None,
|
||||
location: Location = None,
|
||||
venue: Venue = None,
|
||||
left_chat_member: User = None,
|
||||
new_chat_title: str = None,
|
||||
new_chat_photo: List[PhotoSize] = None,
|
||||
delete_chat_photo: bool = False,
|
||||
group_chat_created: bool = False,
|
||||
supergroup_chat_created: bool = False,
|
||||
channel_chat_created: bool = False,
|
||||
migrate_to_chat_id: int = None,
|
||||
migrate_from_chat_id: int = None,
|
||||
pinned_message: 'Message' = None,
|
||||
invoice: Invoice = None,
|
||||
successful_payment: SuccessfulPayment = None,
|
||||
forward_signature: str = None,
|
||||
author_signature: str = None,
|
||||
media_group_id: str = None,
|
||||
connected_website: str = None,
|
||||
animation: Animation = None,
|
||||
passport_data: PassportData = None,
|
||||
poll: Poll = None,
|
||||
forward_sender_name: str = None,
|
||||
reply_markup: InlineKeyboardMarkup = None,
|
||||
bot: 'Bot' = None,
|
||||
dice: Dice = None,
|
||||
via_bot: User = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.message_id = int(message_id)
|
||||
self.from_user = from_user
|
||||
|
@ -346,12 +352,12 @@ class Message(TelegramObject):
|
|||
self._id_attrs = (self.message_id, self.chat)
|
||||
|
||||
@property
|
||||
def chat_id(self):
|
||||
def chat_id(self) -> int:
|
||||
""":obj:`int`: Shortcut for :attr:`telegram.Chat.id` for :attr:`chat`."""
|
||||
return self.chat.id
|
||||
|
||||
@property
|
||||
def link(self):
|
||||
def link(self) -> Optional[str]:
|
||||
""":obj:`str`: Convenience property. If the chat of the message is not
|
||||
a private chat or normal group, returns a t.me link of the message."""
|
||||
if self.chat.type not in [Chat.PRIVATE, Chat.GROUP]:
|
||||
|
@ -364,12 +370,12 @@ class Message(TelegramObject):
|
|||
return None
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> 'Message':
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super().de_json(data, bot)
|
||||
|
||||
data['from_user'] = User.de_json(data.get('from'), bot)
|
||||
data['date'] = from_timestamp(data['date'])
|
||||
data['chat'] = Chat.de_json(data.get('chat'), bot)
|
||||
|
@ -407,7 +413,9 @@ class Message(TelegramObject):
|
|||
return cls(bot=bot, **data)
|
||||
|
||||
@property
|
||||
def effective_attachment(self):
|
||||
def effective_attachment(self) -> Union[Contact, Document, Animation, Game, Invoice, Location,
|
||||
List[PhotoSize], Sticker, SuccessfulPayment, Venue,
|
||||
Video, VideoNote, Voice, None]:
|
||||
"""
|
||||
:class:`telegram.Audio`
|
||||
or :class:`telegram.Contact`
|
||||
|
@ -427,7 +435,7 @@ class Message(TelegramObject):
|
|||
|
||||
"""
|
||||
if self._effective_attachment is not _UNDEFINED:
|
||||
return self._effective_attachment
|
||||
return self._effective_attachment # type: ignore
|
||||
|
||||
for i in Message.ATTACHMENT_TYPES:
|
||||
if getattr(self, i, None):
|
||||
|
@ -436,15 +444,15 @@ class Message(TelegramObject):
|
|||
else:
|
||||
self._effective_attachment = None
|
||||
|
||||
return self._effective_attachment
|
||||
return self._effective_attachment # type: ignore
|
||||
|
||||
def __getitem__(self, item):
|
||||
def __getitem__(self, item: str) -> Any:
|
||||
if item in self.__dict__.keys():
|
||||
return self.__dict__[item]
|
||||
elif item == 'chat_id':
|
||||
return self.chat.id
|
||||
|
||||
def to_dict(self):
|
||||
def to_dict(self) -> JSONDict:
|
||||
data = super().to_dict()
|
||||
|
||||
# Required
|
||||
|
@ -467,7 +475,7 @@ class Message(TelegramObject):
|
|||
|
||||
return data
|
||||
|
||||
def _quote(self, kwargs):
|
||||
def _quote(self, kwargs: JSONDict) -> None:
|
||||
"""Modify kwargs for replying with or without quoting."""
|
||||
if 'reply_to_message_id' in kwargs:
|
||||
if 'quote' in kwargs:
|
||||
|
@ -487,7 +495,7 @@ class Message(TelegramObject):
|
|||
if (default_quote is None and self.chat.type != Chat.PRIVATE) or default_quote:
|
||||
kwargs['reply_to_message_id'] = self.message_id
|
||||
|
||||
def reply_text(self, *args, **kwargs):
|
||||
def reply_text(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_message(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -505,7 +513,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_message(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_markdown(self, *args, **kwargs):
|
||||
def reply_markdown(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_message(update.message.chat_id, parse_mode=ParseMode.MARKDOWN, *args,
|
||||
|
@ -533,7 +541,7 @@ class Message(TelegramObject):
|
|||
|
||||
return self.bot.send_message(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_markdown_v2(self, *args, **kwargs):
|
||||
def reply_markdown_v2(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_message(update.message.chat_id, parse_mode=ParseMode.MARKDOWN_V2, *args,
|
||||
|
@ -557,7 +565,7 @@ class Message(TelegramObject):
|
|||
|
||||
return self.bot.send_message(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_html(self, *args, **kwargs):
|
||||
def reply_html(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_message(update.message.chat_id, parse_mode=ParseMode.HTML, *args, **kwargs)
|
||||
|
@ -580,7 +588,7 @@ class Message(TelegramObject):
|
|||
|
||||
return self.bot.send_message(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_media_group(self, *args, **kwargs):
|
||||
def reply_media_group(self, *args: Any, **kwargs: Any) -> List[Optional['Message']]:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_media_group(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -600,7 +608,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_media_group(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_photo(self, *args, **kwargs):
|
||||
def reply_photo(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_photo(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -618,7 +626,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_photo(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_audio(self, *args, **kwargs):
|
||||
def reply_audio(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_audio(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -636,7 +644,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_audio(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_document(self, *args, **kwargs):
|
||||
def reply_document(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_document(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -654,7 +662,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_document(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_animation(self, *args, **kwargs):
|
||||
def reply_animation(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_animation(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -672,7 +680,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_animation(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_sticker(self, *args, **kwargs):
|
||||
def reply_sticker(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_sticker(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -690,7 +698,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_sticker(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_video(self, *args, **kwargs):
|
||||
def reply_video(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_video(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -708,7 +716,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_video(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_video_note(self, *args, **kwargs):
|
||||
def reply_video_note(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_video_note(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -726,7 +734,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_video_note(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_voice(self, *args, **kwargs):
|
||||
def reply_voice(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_voice(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -744,7 +752,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_voice(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_location(self, *args, **kwargs):
|
||||
def reply_location(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_location(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -762,7 +770,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_location(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_venue(self, *args, **kwargs):
|
||||
def reply_venue(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_venue(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -780,7 +788,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_venue(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_contact(self, *args, **kwargs):
|
||||
def reply_contact(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_contact(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -798,7 +806,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_contact(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_poll(self, *args, **kwargs):
|
||||
def reply_poll(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_poll(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -816,7 +824,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_poll(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_dice(self, *args, **kwargs):
|
||||
def reply_dice(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.send_dice(update.message.chat_id, *args, **kwargs)
|
||||
|
@ -834,7 +842,7 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.send_dice(self.chat_id, *args, **kwargs)
|
||||
|
||||
def forward(self, chat_id, *args, **kwargs):
|
||||
def forward(self, chat_id: int, *args: Any, **kwargs: Any) -> 'Message':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.forward_message(chat_id=chat_id,
|
||||
|
@ -854,7 +862,7 @@ class Message(TelegramObject):
|
|||
*args,
|
||||
**kwargs)
|
||||
|
||||
def edit_text(self, *args, **kwargs):
|
||||
def edit_text(self, *args: Any, **kwargs: Any) -> Union['Message', bool]:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.edit_message_text(chat_id=message.chat_id,
|
||||
|
@ -868,13 +876,14 @@ class Message(TelegramObject):
|
|||
behaviour is undocumented and might be changed by Telegram.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, instance representing the edited message.
|
||||
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
|
||||
edited Message is returned, otherwise ``True`` is returned.
|
||||
|
||||
"""
|
||||
return self.bot.edit_message_text(
|
||||
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
|
||||
|
||||
def edit_caption(self, *args, **kwargs):
|
||||
def edit_caption(self, *args: Any, **kwargs: Any) -> Union['Message', bool]:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.edit_message_caption(chat_id=message.chat_id,
|
||||
|
@ -888,34 +897,35 @@ class Message(TelegramObject):
|
|||
behaviour is undocumented and might be changed by Telegram.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, instance representing the edited message.
|
||||
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
|
||||
edited Message is returned, otherwise ``True`` is returned.
|
||||
|
||||
"""
|
||||
return self.bot.edit_message_caption(
|
||||
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
|
||||
|
||||
def edit_media(self, media, *args, **kwargs):
|
||||
def edit_media(self, media: 'InputMedia', *args: Any, **kwargs: Any) -> Union['Message', bool]:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.edit_message_media(chat_id=message.chat_id,
|
||||
message_id=message.message_id,
|
||||
*args,
|
||||
**kwargs)
|
||||
message_id=message.message_id,
|
||||
*args,
|
||||
**kwargs)
|
||||
|
||||
Note:
|
||||
You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family
|
||||
You can only edit messages that the bot sent itself(i.e. of the ``bot.send_*`` family
|
||||
of methods) or channel posts, if the bot is an admin in that channel. However, this
|
||||
behaviour is undocumented and might be changed by Telegram.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, instance representing the edited
|
||||
message.
|
||||
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
|
||||
edited Message is returned, otherwise ``True`` is returned.
|
||||
|
||||
"""
|
||||
return self.bot.edit_message_media(
|
||||
chat_id=self.chat_id, message_id=self.message_id, media=media, *args, **kwargs)
|
||||
|
||||
def edit_reply_markup(self, *args, **kwargs):
|
||||
def edit_reply_markup(self, *args: Any, **kwargs: Any) -> Union['Message', bool]:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.edit_message_reply_markup(chat_id=message.chat_id,
|
||||
|
@ -929,12 +939,13 @@ class Message(TelegramObject):
|
|||
behaviour is undocumented and might be changed by Telegram.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, instance representing the edited message.
|
||||
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
|
||||
edited Message is returned, otherwise ``True`` is returned.
|
||||
"""
|
||||
return self.bot.edit_message_reply_markup(
|
||||
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
|
||||
|
||||
def edit_live_location(self, *args, **kwargs):
|
||||
def edit_live_location(self, *args: Any, **kwargs: Any) -> Union['Message', bool]:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.edit_message_live_location(chat_id=message.chat_id,
|
||||
|
@ -954,7 +965,7 @@ class Message(TelegramObject):
|
|||
return self.bot.edit_message_live_location(
|
||||
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
|
||||
|
||||
def stop_live_location(self, *args, **kwargs):
|
||||
def stop_live_location(self, *args: Any, **kwargs: Any) -> Union['Message', bool]:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.stop_message_live_location(chat_id=message.chat_id,
|
||||
|
@ -974,7 +985,7 @@ class Message(TelegramObject):
|
|||
return self.bot.stop_message_live_location(
|
||||
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
|
||||
|
||||
def set_game_score(self, *args, **kwargs):
|
||||
def set_game_score(self, *args: Any, **kwargs: Any) -> Union['Message', bool]:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.set_game_score(chat_id=message.chat_id,
|
||||
|
@ -994,7 +1005,7 @@ class Message(TelegramObject):
|
|||
return self.bot.set_game_score(
|
||||
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
|
||||
|
||||
def get_game_high_scores(self, *args, **kwargs):
|
||||
def get_game_high_scores(self, *args: Any, **kwargs: Any) -> List['GameHighScore']:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.get_game_high_scores(chat_id=message.chat_id,
|
||||
|
@ -1008,13 +1019,12 @@ class Message(TelegramObject):
|
|||
behaviour is undocumented and might be changed by Telegram.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
|
||||
edited Message is returned, otherwise :obj:`True` is returned.
|
||||
List[:class:`telegram.GameHighScore`]
|
||||
"""
|
||||
return self.bot.get_game_high_scores(
|
||||
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
def delete(self, *args: Any, **kwargs: Any) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.delete_message(chat_id=message.chat_id,
|
||||
|
@ -1029,7 +1039,7 @@ class Message(TelegramObject):
|
|||
return self.bot.delete_message(
|
||||
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
|
||||
|
||||
def stop_poll(self, *args, **kwargs):
|
||||
def stop_poll(self, *args: Any, **kwargs: Any) -> Poll:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.stop_poll(chat_id=message.chat_id,
|
||||
|
@ -1045,7 +1055,7 @@ class Message(TelegramObject):
|
|||
return self.bot.stop_poll(
|
||||
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
|
||||
|
||||
def pin(self, *args, **kwargs):
|
||||
def pin(self, *args: Any, **kwargs: Any) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.pin_chat_message(chat_id=message.chat_id,
|
||||
|
@ -1060,7 +1070,7 @@ class Message(TelegramObject):
|
|||
return self.bot.pin_chat_message(
|
||||
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
|
||||
|
||||
def parse_entity(self, entity):
|
||||
def parse_entity(self, entity: MessageEntity) -> str:
|
||||
"""Returns the text from a given :class:`telegram.MessageEntity`.
|
||||
|
||||
Note:
|
||||
|
@ -1075,7 +1085,13 @@ class Message(TelegramObject):
|
|||
Returns:
|
||||
:obj:`str`: The text of the given entity.
|
||||
|
||||
Raises:
|
||||
RuntimeError: If the message has no text.
|
||||
|
||||
"""
|
||||
if not self.text:
|
||||
raise RuntimeError("This Message has no 'text'.")
|
||||
|
||||
# Is it a narrow build, if so we don't need to convert
|
||||
if sys.maxunicode == 0xffff:
|
||||
return self.text[entity.offset:entity.offset + entity.length]
|
||||
|
@ -1085,7 +1101,7 @@ class Message(TelegramObject):
|
|||
|
||||
return entity_text.decode('utf-16-le')
|
||||
|
||||
def parse_caption_entity(self, entity):
|
||||
def parse_caption_entity(self, entity: MessageEntity) -> str:
|
||||
"""Returns the text from a given :class:`telegram.MessageEntity`.
|
||||
|
||||
Note:
|
||||
|
@ -1100,7 +1116,13 @@ class Message(TelegramObject):
|
|||
Returns:
|
||||
:obj:`str`: The text of the given entity.
|
||||
|
||||
Raises:
|
||||
RuntimeError: If the message has no caption.
|
||||
|
||||
"""
|
||||
if not self.caption:
|
||||
raise RuntimeError("This Message has no 'caption'.")
|
||||
|
||||
# Is it a narrow build, if so we don't need to convert
|
||||
if sys.maxunicode == 0xffff:
|
||||
return self.caption[entity.offset:entity.offset + entity.length]
|
||||
|
@ -1110,7 +1132,7 @@ class Message(TelegramObject):
|
|||
|
||||
return entity_text.decode('utf-16-le')
|
||||
|
||||
def parse_entities(self, types=None):
|
||||
def parse_entities(self, types: List[str] = None) -> Dict[MessageEntity, str]:
|
||||
"""
|
||||
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
|
||||
It contains entities from this message filtered by their
|
||||
|
@ -1138,10 +1160,10 @@ class Message(TelegramObject):
|
|||
|
||||
return {
|
||||
entity: self.parse_entity(entity)
|
||||
for entity in self.entities if entity.type in types
|
||||
for entity in (self.entities or []) if entity.type in types
|
||||
}
|
||||
|
||||
def parse_caption_entities(self, types=None):
|
||||
def parse_caption_entities(self, types: List[str] = None) -> Dict[MessageEntity, str]:
|
||||
"""
|
||||
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
|
||||
It contains entities from this message's caption filtered by their
|
||||
|
@ -1169,16 +1191,19 @@ class Message(TelegramObject):
|
|||
|
||||
return {
|
||||
entity: self.parse_caption_entity(entity)
|
||||
for entity in self.caption_entities if entity.type in types
|
||||
for entity in (self.caption_entities or []) if entity.type in types
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _parse_html(message_text, entities, urled=False, offset=0):
|
||||
def _parse_html(message_text: Optional[str],
|
||||
entities: Dict[MessageEntity, str],
|
||||
urled: bool = False,
|
||||
offset: int = 0) -> Optional[str]:
|
||||
if message_text is None:
|
||||
return None
|
||||
|
||||
if not sys.maxunicode == 0xffff:
|
||||
message_text = message_text.encode('utf-16-le')
|
||||
message_text = message_text.encode('utf-16-le') # type: ignore
|
||||
|
||||
html_text = ''
|
||||
last_offset = 0
|
||||
|
@ -1232,15 +1257,16 @@ class Message(TelegramObject):
|
|||
html_text += escape(message_text[last_offset:entity.offset
|
||||
- offset]) + insert
|
||||
else:
|
||||
html_text += escape(message_text[last_offset * 2:(entity.offset
|
||||
- offset) * 2]
|
||||
.decode('utf-16-le')) + insert
|
||||
html_text += escape(message_text[ # type: ignore
|
||||
last_offset * 2:(entity.offset - offset) * 2].decode('utf-16-le')
|
||||
) + insert
|
||||
else:
|
||||
if sys.maxunicode == 0xffff:
|
||||
html_text += message_text[last_offset:entity.offset - offset] + insert
|
||||
else:
|
||||
html_text += message_text[last_offset * 2:(entity.offset
|
||||
- offset) * 2].decode('utf-16-le') + insert
|
||||
html_text += message_text[ # type: ignore
|
||||
last_offset * 2:(entity.offset - offset) * 2
|
||||
].decode('utf-16-le') + insert
|
||||
|
||||
last_offset = entity.offset - offset + entity.length
|
||||
|
||||
|
@ -1248,17 +1274,18 @@ class Message(TelegramObject):
|
|||
if sys.maxunicode == 0xffff:
|
||||
html_text += escape(message_text[last_offset:])
|
||||
else:
|
||||
html_text += escape(message_text[last_offset * 2:].decode('utf-16-le'))
|
||||
html_text += escape(
|
||||
message_text[last_offset * 2:].decode('utf-16-le')) # type: ignore
|
||||
else:
|
||||
if sys.maxunicode == 0xffff:
|
||||
html_text += message_text[last_offset:]
|
||||
else:
|
||||
html_text += message_text[last_offset * 2:].decode('utf-16-le')
|
||||
html_text += message_text[last_offset * 2:].decode('utf-16-le') # type: ignore
|
||||
|
||||
return html_text
|
||||
|
||||
@property
|
||||
def text_html(self):
|
||||
def text_html(self) -> str:
|
||||
"""Creates an HTML-formatted string from the markup entities found in the message.
|
||||
|
||||
Use this if you want to retrieve the message text with the entities formatted as HTML in
|
||||
|
@ -1271,7 +1298,7 @@ class Message(TelegramObject):
|
|||
return self._parse_html(self.text, self.parse_entities(), urled=False)
|
||||
|
||||
@property
|
||||
def text_html_urled(self):
|
||||
def text_html_urled(self) -> str:
|
||||
"""Creates an HTML-formatted string from the markup entities found in the message.
|
||||
|
||||
Use this if you want to retrieve the message text with the entities formatted as HTML.
|
||||
|
@ -1284,7 +1311,7 @@ class Message(TelegramObject):
|
|||
return self._parse_html(self.text, self.parse_entities(), urled=True)
|
||||
|
||||
@property
|
||||
def caption_html(self):
|
||||
def caption_html(self) -> str:
|
||||
"""Creates an HTML-formatted string from the markup entities found in the message's
|
||||
caption.
|
||||
|
||||
|
@ -1298,7 +1325,7 @@ class Message(TelegramObject):
|
|||
return self._parse_html(self.caption, self.parse_caption_entities(), urled=False)
|
||||
|
||||
@property
|
||||
def caption_html_urled(self):
|
||||
def caption_html_urled(self) -> str:
|
||||
"""Creates an HTML-formatted string from the markup entities found in the message's
|
||||
caption.
|
||||
|
||||
|
@ -1312,14 +1339,18 @@ class Message(TelegramObject):
|
|||
return self._parse_html(self.caption, self.parse_caption_entities(), urled=True)
|
||||
|
||||
@staticmethod
|
||||
def _parse_markdown(message_text, entities, urled=False, version=1, offset=0):
|
||||
def _parse_markdown(message_text: Optional[str],
|
||||
entities: Dict[MessageEntity, str],
|
||||
urled: bool = False,
|
||||
version: int = 1,
|
||||
offset: int = 0) -> Optional[str]:
|
||||
version = int(version)
|
||||
|
||||
if message_text is None:
|
||||
return None
|
||||
|
||||
if not sys.maxunicode == 0xffff:
|
||||
message_text = message_text.encode('utf-16-le')
|
||||
message_text = message_text.encode('utf-16-le') # type: ignore
|
||||
|
||||
markdown_text = ''
|
||||
last_offset = 0
|
||||
|
@ -1404,16 +1435,18 @@ class Message(TelegramObject):
|
|||
- offset],
|
||||
version=version) + insert
|
||||
else:
|
||||
markdown_text += escape_markdown(message_text[last_offset * 2:
|
||||
(entity.offset - offset) * 2]
|
||||
.decode('utf-16-le'),
|
||||
version=version) + insert
|
||||
markdown_text += escape_markdown(
|
||||
message_text[ # type: ignore
|
||||
last_offset * 2: (entity.offset - offset) * 2
|
||||
].decode('utf-16-le'),
|
||||
version=version) + insert
|
||||
else:
|
||||
if sys.maxunicode == 0xffff:
|
||||
markdown_text += message_text[last_offset:entity.offset - offset] + insert
|
||||
else:
|
||||
markdown_text += message_text[last_offset * 2:(entity.offset
|
||||
- offset) * 2].decode('utf-16-le') + insert
|
||||
markdown_text += message_text[ # type: ignore
|
||||
last_offset * 2:(entity.offset - offset) * 2
|
||||
].decode('utf-16-le') + insert
|
||||
|
||||
last_offset = entity.offset - offset + entity.length
|
||||
|
||||
|
@ -1421,18 +1454,19 @@ class Message(TelegramObject):
|
|||
if sys.maxunicode == 0xffff:
|
||||
markdown_text += escape_markdown(message_text[last_offset:], version=version)
|
||||
else:
|
||||
markdown_text += escape_markdown(message_text[last_offset * 2:]
|
||||
.decode('utf-16-le'), version=version)
|
||||
markdown_text += escape_markdown(
|
||||
message_text[last_offset * 2:] .decode('utf-16-le'), # type: ignore
|
||||
version=version)
|
||||
else:
|
||||
if sys.maxunicode == 0xffff:
|
||||
markdown_text += message_text[last_offset:]
|
||||
else:
|
||||
markdown_text += message_text[last_offset * 2:].decode('utf-16-le')
|
||||
markdown_text += message_text[last_offset * 2:].decode('utf-16-le') # type: ignore
|
||||
|
||||
return markdown_text
|
||||
|
||||
@property
|
||||
def text_markdown(self):
|
||||
def text_markdown(self) -> str:
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message
|
||||
using :class:`telegram.ParseMode.MARKDOWN`.
|
||||
|
||||
|
@ -1450,7 +1484,7 @@ class Message(TelegramObject):
|
|||
return self._parse_markdown(self.text, self.parse_entities(), urled=False)
|
||||
|
||||
@property
|
||||
def text_markdown_v2(self):
|
||||
def text_markdown_v2(self) -> str:
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message
|
||||
using :class:`telegram.ParseMode.MARKDOWN_V2`.
|
||||
|
||||
|
@ -1464,7 +1498,7 @@ class Message(TelegramObject):
|
|||
return self._parse_markdown(self.text, self.parse_entities(), urled=False, version=2)
|
||||
|
||||
@property
|
||||
def text_markdown_urled(self):
|
||||
def text_markdown_urled(self) -> str:
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message
|
||||
using :class:`telegram.ParseMode.MARKDOWN`.
|
||||
|
||||
|
@ -1482,7 +1516,7 @@ class Message(TelegramObject):
|
|||
return self._parse_markdown(self.text, self.parse_entities(), urled=True)
|
||||
|
||||
@property
|
||||
def text_markdown_v2_urled(self):
|
||||
def text_markdown_v2_urled(self) -> str:
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message
|
||||
using :class:`telegram.ParseMode.MARKDOWN_V2`.
|
||||
|
||||
|
@ -1496,7 +1530,7 @@ class Message(TelegramObject):
|
|||
return self._parse_markdown(self.text, self.parse_entities(), urled=True, version=2)
|
||||
|
||||
@property
|
||||
def caption_markdown(self):
|
||||
def caption_markdown(self) -> str:
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message's
|
||||
caption using :class:`telegram.ParseMode.MARKDOWN`.
|
||||
|
||||
|
@ -1514,7 +1548,7 @@ class Message(TelegramObject):
|
|||
return self._parse_markdown(self.caption, self.parse_caption_entities(), urled=False)
|
||||
|
||||
@property
|
||||
def caption_markdown_v2(self):
|
||||
def caption_markdown_v2(self) -> str:
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message's
|
||||
caption using :class:`telegram.ParseMode.MARKDOWN_V2`.
|
||||
|
||||
|
@ -1529,7 +1563,7 @@ class Message(TelegramObject):
|
|||
urled=False, version=2)
|
||||
|
||||
@property
|
||||
def caption_markdown_urled(self):
|
||||
def caption_markdown_urled(self) -> str:
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message's
|
||||
caption using :class:`telegram.ParseMode.MARKDOWN`.
|
||||
|
||||
|
@ -1547,7 +1581,7 @@ class Message(TelegramObject):
|
|||
return self._parse_markdown(self.caption, self.parse_caption_entities(), urled=True)
|
||||
|
||||
@property
|
||||
def caption_markdown_v2_urled(self):
|
||||
def caption_markdown_v2_urled(self) -> str:
|
||||
"""Creates an Markdown-formatted string from the markup entities found in the message's
|
||||
caption using :class:`telegram.ParseMode.MARKDOWN_V2`.
|
||||
|
||||
|
|
|
@ -19,6 +19,11 @@
|
|||
"""This module contains an object that represents a Telegram MessageEntity."""
|
||||
|
||||
from telegram import User, TelegramObject
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, List, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class MessageEntity(TelegramObject):
|
||||
|
@ -53,7 +58,14 @@ class MessageEntity(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, type, offset, length, url=None, user=None, language=None, **kwargs):
|
||||
def __init__(self,
|
||||
type: str,
|
||||
offset: int,
|
||||
length: int,
|
||||
url: str = None,
|
||||
user: User = None,
|
||||
language: str = None,
|
||||
**kwargs: Any):
|
||||
# Required
|
||||
self.type = type
|
||||
self.offset = offset
|
||||
|
@ -66,8 +78,8 @@ class MessageEntity(TelegramObject):
|
|||
self._id_attrs = (self.type, self.offset, self.length)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
data = super().de_json(data, bot)
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['MessageEntity']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
@ -76,48 +88,37 @@ class MessageEntity(TelegramObject):
|
|||
|
||||
return cls(**data)
|
||||
|
||||
@classmethod
|
||||
def de_list(cls, data, bot):
|
||||
if not data:
|
||||
return list()
|
||||
|
||||
entities = list()
|
||||
for entity in data:
|
||||
entities.append(cls.de_json(entity, bot))
|
||||
|
||||
return entities
|
||||
|
||||
MENTION = 'mention'
|
||||
MENTION: str = 'mention'
|
||||
""":obj:`str`: 'mention'"""
|
||||
HASHTAG = 'hashtag'
|
||||
HASHTAG: str = 'hashtag'
|
||||
""":obj:`str`: 'hashtag'"""
|
||||
CASHTAG = 'cashtag'
|
||||
CASHTAG: str = 'cashtag'
|
||||
""":obj:`str`: 'cashtag'"""
|
||||
PHONE_NUMBER = 'phone_number'
|
||||
PHONE_NUMBER: str = 'phone_number'
|
||||
""":obj:`str`: 'phone_number'"""
|
||||
BOT_COMMAND = 'bot_command'
|
||||
BOT_COMMAND: str = 'bot_command'
|
||||
""":obj:`str`: 'bot_command'"""
|
||||
URL = 'url'
|
||||
URL: str = 'url'
|
||||
""":obj:`str`: 'url'"""
|
||||
EMAIL = 'email'
|
||||
EMAIL: str = 'email'
|
||||
""":obj:`str`: 'email'"""
|
||||
BOLD = 'bold'
|
||||
BOLD: str = 'bold'
|
||||
""":obj:`str`: 'bold'"""
|
||||
ITALIC = 'italic'
|
||||
ITALIC: str = 'italic'
|
||||
""":obj:`str`: 'italic'"""
|
||||
CODE = 'code'
|
||||
CODE: str = 'code'
|
||||
""":obj:`str`: 'code'"""
|
||||
PRE = 'pre'
|
||||
PRE: str = 'pre'
|
||||
""":obj:`str`: 'pre'"""
|
||||
TEXT_LINK = 'text_link'
|
||||
TEXT_LINK: str = 'text_link'
|
||||
""":obj:`str`: 'text_link'"""
|
||||
TEXT_MENTION = 'text_mention'
|
||||
TEXT_MENTION: str = 'text_mention'
|
||||
""":obj:`str`: 'text_mention'"""
|
||||
UNDERLINE = 'underline'
|
||||
UNDERLINE: str = 'underline'
|
||||
""":obj:`str`: 'underline'"""
|
||||
STRIKETHROUGH = 'strikethrough'
|
||||
STRIKETHROUGH: str = 'strikethrough'
|
||||
""":obj:`str`: 'strikethrough'"""
|
||||
ALL_TYPES = [
|
||||
ALL_TYPES: List[str] = [
|
||||
MENTION, HASHTAG, CASHTAG, PHONE_NUMBER, BOT_COMMAND, URL,
|
||||
EMAIL, BOLD, ITALIC, CODE, PRE, TEXT_LINK, TEXT_MENTION, UNDERLINE, STRIKETHROUGH
|
||||
]
|
||||
|
|
|
@ -23,14 +23,14 @@
|
|||
class ParseMode:
|
||||
"""This object represents a Telegram Message Parse Modes."""
|
||||
|
||||
MARKDOWN = 'Markdown'
|
||||
MARKDOWN: str = 'Markdown'
|
||||
""":obj:`str`: 'Markdown'
|
||||
|
||||
Note:
|
||||
:attr:`MARKDOWN` is a legacy mode, retained by Telegram for backward compatibility.
|
||||
You should use :attr:`MARKDOWN_V2` instead.
|
||||
"""
|
||||
MARKDOWN_V2 = 'MarkdownV2'
|
||||
MARKDOWN_V2: str = 'MarkdownV2'
|
||||
""":obj:`str`: 'MarkdownV2'"""
|
||||
HTML = 'HTML'
|
||||
HTML: str = 'HTML'
|
||||
""":obj:`str`: 'HTML'"""
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue