Add Tuple Based Version Info and Rename telegram.bot_api_version to telegram.__bot_api_version__ (#3030)

This commit is contained in:
Bibo-Joshi 2022-05-14 15:50:12 +02:00 committed by GitHub
parent f792102212
commit 5e924014de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 239 additions and 24 deletions

View file

@ -444,9 +444,17 @@ class TGConstXRefRole(PyXRefRole):
if isinstance(value, telegram.constants.FileSizeLimit): if isinstance(value, telegram.constants.FileSizeLimit):
return f"{int(value.value / 1e6)} MB", target return f"{int(value.value / 1e6)} MB", target
return repr(value.value), target return repr(value.value), target
# Just for Bot API version number auto add in constants: # Just for (Bot API) versions number auto add in constants:
if isinstance(value, str) and target == "telegram.constants.BOT_API_VERSION": if isinstance(value, str) and target in (
"telegram.constants.BOT_API_VERSION",
"telegram.__version__",
):
return value, target return value, target
if isinstance(value, tuple) and target in (
"telegram.constants.BOT_API_VERSION_INFO",
"telegram.__version_info__",
):
return repr(value), target
sphinx_logger.warning( sphinx_logger.warning(
f"%s:%d: WARNING: Did not convert reference %s. :{CONSTANTS_ROLE}: is not supposed" f"%s:%d: WARNING: Did not convert reference %s. :{CONSTANTS_ROLE}: is not supposed"
" to be used with this type of target.", " to be used with this type of target.",

View file

@ -1,6 +1,15 @@
telegram package telegram package
================ ================
Version Constants
-----------------
.. automodule:: telegram
:members: __version__, __version_info__, __bot_api_version__, __bot_api_version_info__
Available Types
---------------
.. toctree:: .. toctree::
telegram.animation telegram.animation

View file

@ -42,10 +42,9 @@ def get_setup_kwargs(raw=False):
raw_ext = "-raw" if raw else "" raw_ext = "-raw" if raw else ""
readme = Path(f'README{"_RAW" if raw else ""}.rst') readme = Path(f'README{"_RAW" if raw else ""}.rst')
with Path("telegram/_version.py").open() as fh: version_file = Path("telegram/_version.py").read_text()
for line in fh.readlines(): first_part = version_file.split("# SETUP.PY MARKER")[0]
if line.startswith("__version__"): exec(first_part)
exec(line)
kwargs = dict( kwargs = dict(
script_name=f"setup{raw_ext}.py", script_name=f"setup{raw_ext}.py",

View file

@ -21,10 +21,13 @@
__author__ = "devs@python-telegram-bot.org" __author__ = "devs@python-telegram-bot.org"
__all__ = ( # Keep this alphabetically ordered __all__ = ( # Keep this alphabetically ordered
"__bot_api_version__",
"__bot_api_version_info__",
"__version__",
"__version_info__",
"Animation", "Animation",
"Audio", "Audio",
"Bot", "Bot",
"bot_api_version",
"BotCommand", "BotCommand",
"BotCommandScope", "BotCommandScope",
"BotCommandScopeAllChatAdministrators", "BotCommandScopeAllChatAdministrators",
@ -308,7 +311,31 @@ from ._telegramobject import TelegramObject
from ._update import Update from ._update import Update
from ._user import User from ._user import User
from ._userprofilephotos import UserProfilePhotos from ._userprofilephotos import UserProfilePhotos
from ._version import __version__, bot_api_version # noqa: F401 from . import _version
#: :obj:`str`: The version of the `python-telegram-bot` library as string.
#: To get detailed information about the version number, please use :data:`__version_info__`
#: instead.
__version__ = _version.__version__
#: :class:`typing.NamedTuple`: A tuple containing the five components of the version number:
#: `major`, `minor`, `micro`, `releaselevel`, and `serial`.
#: All values except `releaselevel` are integers.
#: The release level is ``'alpha'``, ``'beta'``, ``'candidate'``, or ``'final'``.
#: The components can also be accessed by name, so ``__version_info__[0]`` is equivalent to
#: ``__version_info__.major`` and so on.
#:
#: .. versionadded:: 20.0
__version_info__ = _version.__version_info__
#: :obj:`str`: Shortcut for :const:`telegram.constants.BOT_API_VERSION`.
#:
#: .. versionchanged:: 20.0
#: This constant was previously named ``bot_api_version``.
__bot_api_version__ = _version.__bot_api_version__
#: :class:`typing.NamedTuple`: Shortcut for :const:`telegram.constants.BOT_API_VERSION_INFO`.
#:
#: .. versionadded:: 20.0
__bot_api_version_info__ = _version.__bot_api_version_info__
from ._videochat import ( from ._videochat import (
VideoChatEnded, VideoChatEnded,
VideoChatParticipantsInvited, VideoChatParticipantsInvited,

View file

@ -17,9 +17,47 @@
# You should have received a copy of the GNU Lesser Public License # You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
# pylint: disable=missing-module-docstring # pylint: disable=missing-module-docstring
from typing import NamedTuple
__version__ = "20.0a0" __all__ = ("__version__", "__version_info__", "__bot_api_version__", "__bot_api_version_info__")
from telegram import constants
bot_api_version = constants.BOT_API_VERSION # pylint: disable=invalid-name class Version(NamedTuple):
"""Copies the behavior of sys.version_info.
serial is always 0 for stable releases.
"""
major: int
minor: int
micro: int
releaselevel: str # Literal['alpha', 'beta', 'candidate', 'final']
serial: int
def _rl_shorthand(self) -> str:
return {
"alpha": "a",
"beta": "b",
"candidate": "rc",
}[self.releaselevel]
def __str__(self) -> str:
version = f"{self.major}.{self.minor}"
if self.micro != 0:
version = f"{version}.{self.micro}"
if self.releaselevel != "final":
version = f"{version}{self._rl_shorthand()}{self.serial}"
return version
__version_info__ = Version(major=20, minor=0, micro=0, releaselevel="alpha", serial=0)
__version__ = str(__version_info__)
# # SETUP.PY MARKER
# Lines above this line will be `exec`-cuted in setup.py. Make sure that this only contains
# std-lib imports!
from telegram import constants # noqa: E402 # pylint: disable=wrong-import-position
__bot_api_version__ = constants.BOT_API_VERSION
__bot_api_version_info__ = constants.BOT_API_VERSION_INFO

View file

@ -20,23 +20,17 @@ Unless noted otherwise, all constants in this module were extracted from the
`Telegram Bots FAQ <https://core.telegram.org/bots/faq>`_ and `Telegram Bots FAQ <https://core.telegram.org/bots/faq>`_ and
`Telegram Bots API <https://core.telegram.org/bots/api>`_. `Telegram Bots API <https://core.telegram.org/bots/api>`_.
Most of the following constants are related to specific classes or topics and are grouped into
enums. If they are related to a specific class, then they are also available as attributes of
those classes.
.. versionchanged:: 20.0 .. versionchanged:: 20.0
Since v20.0, most of the constants in this module are grouped into enums. Since v20.0, most of the constants in this module are grouped into enums.
Attributes:
BOT_API_VERSION (:obj:`str`): :tg-const:`telegram.constants.BOT_API_VERSION`. Telegram Bot API
version supported by this version of `python-telegram-bot`. Also available as
``telegram.bot_api_version``.
.. versionadded:: 13.4
SUPPORTED_WEBHOOK_PORTS (List[:obj:`int`]): [443, 80, 88, 8443]
The following constants are related to specific classes or topics and are grouped into enums. If
they are related to a specific class, then they are also available as attributes of those classes.
""" """
__all__ = [ __all__ = [
"BOT_API_VERSION", "BOT_API_VERSION",
"BOT_API_VERSION_INFO",
"BotCommandScopeType", "BotCommandScopeType",
"CallbackQueryLimit", "CallbackQueryLimit",
"ChatAction", "ChatAction",
@ -66,14 +60,48 @@ __all__ = [
] ]
from enum import IntEnum from enum import IntEnum
from typing import List from typing import List, NamedTuple
from telegram._utils.enum import StringEnum from telegram._utils.enum import StringEnum
BOT_API_VERSION = "6.0"
class _BotAPIVersion(NamedTuple):
"""Similar behavior to sys.version_info.
So far TG has only published X.Y releases. We can add X.Y.Z(a(S)) if needed.
"""
major: int
minor: int
def __repr__(self) -> str:
"""Unfortunately calling super().__repr__ doesn't work with typing.NamedTuple, so we
do this manually.
"""
return f"BotAPIVersion(major={self.major}, minor={self.minor})"
def __str__(self) -> str:
return f"{self.major}.{self.minor}"
#: :class:`typing.NamedTuple`: A tuple containing the two components of the version number:
# ``major`` and ``minor``. Both values are integers.
#: The components can also be accessed by name, so ``BOT_API_VERSION_INFO[0]`` is equivalent
#: to ``BOT_API_VERSION_INFO.major`` and so on. Also available as
#: :data:`telegram.__bot_api_version_info__`.
#:
#: .. versionadded:: 20.0
BOT_API_VERSION_INFO = _BotAPIVersion(major=6, minor=0)
#: :obj:`str`: Telegram Bot API
#: version supported by this version of `python-telegram-bot`. Also available as
#: :data:`telegram.__bot_api_version__`.
#:
#: .. versionadded:: 13.4
BOT_API_VERSION = str(BOT_API_VERSION_INFO)
# constants above this line are tested # constants above this line are tested
#: List[:obj:`int`]: Ports supported by
#: :paramref:`telegram.Bot.set_webhook.url`.
SUPPORTED_WEBHOOK_PORTS: List[int] = [443, 80, 88, 8443] SUPPORTED_WEBHOOK_PORTS: List[int] = [443, 80, 88, 8443]

View file

@ -113,3 +113,21 @@ class TestConstants:
match = "Media_caption_too_long" match = "Media_caption_too_long"
with pytest.raises(BadRequest, match=match), data_file("telegram.png").open("rb") as f: with pytest.raises(BadRequest, match=match), data_file("telegram.png").open("rb") as f:
await bot.send_photo(photo=f, caption=bad_caption, chat_id=chat_id) await bot.send_photo(photo=f, caption=bad_caption, chat_id=chat_id)
def test_bot_api_version_and_info(self):
assert constants.BOT_API_VERSION == str(constants.BOT_API_VERSION_INFO)
assert constants.BOT_API_VERSION_INFO == tuple(
int(x) for x in constants.BOT_API_VERSION.split(".")
)
def test_bot_api_version_info(self):
vi = constants.BOT_API_VERSION_INFO
assert isinstance(vi, tuple)
assert repr(vi) == f"BotAPIVersion(major={vi[0]}, minor={vi[1]})"
assert vi == (vi[0], vi[1])
assert not (vi < (vi[0], vi[1]))
assert vi < (vi[0], vi[1] + 1)
assert vi < (vi[0] + 1, vi[1])
assert vi < (vi[0] + 1, vi[1] + 1)
assert vi[0] == vi.major
assert vi[1] == vi.minor

88
tests/test_version.py Normal file
View file

@ -0,0 +1,88 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2022
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
import pytest
from telegram import (
__version_info__,
__version__,
__bot_api_version_info__,
__bot_api_version__,
constants,
)
from telegram._version import Version
class TestVersion:
def test_bot_api_version_and_info(self):
assert __bot_api_version__ is constants.BOT_API_VERSION
assert __bot_api_version_info__ is constants.BOT_API_VERSION_INFO
def test_version_and_info(self):
assert __version__ == str(__version_info__)
@pytest.mark.parametrize(
"version,expected",
[
(Version(1, 2, 3, "alpha", 4), "1.2.3a4"),
(Version(2, 3, 4, "beta", 5), "2.3.4b5"),
(Version(1, 2, 3, "candidate", 4), "1.2.3rc4"),
(Version(1, 2, 0, "alpha", 4), "1.2a4"),
(Version(2, 3, 0, "beta", 5), "2.3b5"),
(Version(1, 2, 0, "candidate", 4), "1.2rc4"),
(Version(1, 2, 3, "final", 0), "1.2.3"),
(Version(1, 2, 0, "final", 0), "1.2"),
],
)
def test_version_str(self, version, expected):
assert str(version) == expected
@pytest.mark.parametrize("use_tuple", (True, False))
def test_version_info(self, use_tuple):
version = Version(1, 2, 3, "beta", 4)
assert isinstance(version, tuple)
assert version.major == version[0]
assert version.minor == version[1]
assert version.micro == version[2]
assert version.releaselevel == version[3]
assert version.serial == version[4]
class TestClass:
def __new__(cls, *args):
if use_tuple:
return tuple(args)
return Version(*args)
assert isinstance(TestClass(1, 2, 3, "beta", 4), tuple if use_tuple else Version)
assert version == TestClass(1, 2, 3, "beta", 4)
assert not (version < TestClass(1, 2, 3, "beta", 4))
assert version > TestClass(1, 2, 3, "beta", 3)
assert version > TestClass(1, 2, 3, "alpha", 4)
assert version < TestClass(1, 2, 3, "candidate", 0)
assert version < TestClass(1, 2, 3, "final", 0)
assert version < TestClass(1, 2, 4, "final", 0)
assert version < TestClass(1, 3, 4, "final", 0)
assert version < (1, 3)
assert version >= (1, 2, 3, "alpha")
assert version > (1, 1)
assert version <= (1, 2, 3, "beta", 4)
assert version < (1, 2, 3, "candidate", 4)
assert not (version > (1, 2, 3, "candidate", 4))
assert version < (1, 2, 4)
assert version > (1, 2, 2)