mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-22 06:25:12 +01:00
Add Python 3.11 to Test Suite & Adapt Enum Behaviour (#3168)
This commit is contained in:
parent
2c84122654
commit
90c0fe948b
7 changed files with 72 additions and 16 deletions
14
.github/workflows/test.yml
vendored
14
.github/workflows/test.yml
vendored
|
@ -4,7 +4,7 @@ on:
|
|||
branches:
|
||||
- master
|
||||
push:
|
||||
branches:
|
||||
branches:
|
||||
- master
|
||||
schedule:
|
||||
# Run monday and friday morning at 03:07 - odd time to spread load on GitHub Actions
|
||||
|
@ -14,10 +14,22 @@ jobs:
|
|||
pytest:
|
||||
name: pytest
|
||||
runs-on: ${{matrix.os}}
|
||||
continue-on-error: ${{ matrix.experimental }}
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.7', '3.8', '3.9', '3.10']
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
experimental: [false]
|
||||
include:
|
||||
- python-version: 3.11.0-rc.1
|
||||
os: ubuntu-latest
|
||||
experimental: true
|
||||
- python-version: 3.11.0-rc.1
|
||||
os: windows-latest
|
||||
experimental: true
|
||||
- python-version: 3.11.0-rc.1
|
||||
os: macos-latest
|
||||
experimental: true
|
||||
fail-fast: False
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
|
|
@ -478,6 +478,10 @@ def autodoc_process_bases(app, name, obj, option, bases: list):
|
|||
bases.insert(0, ":class:`str`")
|
||||
continue
|
||||
|
||||
if "IntEnum" in base:
|
||||
bases[idx] = ":class:`enum.IntEnum`"
|
||||
continue
|
||||
|
||||
# Drop generics (at least for now)
|
||||
if base.endswith("]"):
|
||||
base = base.split("[", maxsplit=1)[0]
|
||||
|
|
1
setup.py
1
setup.py
|
@ -89,6 +89,7 @@ def get_setup_kwargs(raw=False):
|
|||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
],
|
||||
python_requires=">=3.7",
|
||||
)
|
||||
|
|
|
@ -23,30 +23,54 @@ Warning:
|
|||
user. Changes to this module are not considered breaking changes and may not be documented in
|
||||
the changelog.
|
||||
"""
|
||||
from enum import Enum
|
||||
import enum as _enum
|
||||
import sys
|
||||
from typing import Type, TypeVar, Union
|
||||
|
||||
_A = TypeVar("_A")
|
||||
_B = TypeVar("_B")
|
||||
_Enum = TypeVar("_Enum", bound=Enum)
|
||||
_Enum = TypeVar("_Enum", bound=_enum.Enum)
|
||||
|
||||
|
||||
def get_member(enum: Type[_Enum], value: _A, default: _B) -> Union[_Enum, _A, _B]:
|
||||
"""Tries to call ``enum(value)`` to convert the value into an enumeration member.
|
||||
def get_member(enum_cls: Type[_Enum], value: _A, default: _B) -> Union[_Enum, _A, _B]:
|
||||
"""Tries to call ``enum_cls(value)`` to convert the value into an enumeration member.
|
||||
If that fails, the ``default`` is returned.
|
||||
"""
|
||||
try:
|
||||
return enum(value)
|
||||
return enum_cls(value)
|
||||
except ValueError:
|
||||
return default
|
||||
|
||||
|
||||
class StringEnum(str, Enum):
|
||||
"""Helper class for string enums where the value is not important to be displayed on
|
||||
stringification.
|
||||
# Python 3.11 and above has a different output for mixin classes for IntEnum, StrEnum and IntFlag
|
||||
# see https://docs.python.org/3.11/library/enum.html#notes. We want e.g. str(StrEnumTest.FOO) to
|
||||
# return "foo" instead of "StrEnumTest.FOO", which is not the case < py3.11
|
||||
class StringEnum(str, _enum.Enum):
|
||||
"""Helper class for string enums where ``str(member)`` prints the value, but ``repr(member)``
|
||||
gives ``EnumName.MEMBER_NAME``.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<{self.__class__.__name__}.{self.name}>"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return str.__str__(self)
|
||||
|
||||
|
||||
# Apply the __repr__ modification and __str__ fix to IntEnum
|
||||
class IntEnum(_enum.IntEnum):
|
||||
"""Helper class for int enums where ``str(member)`` prints the value, but ``repr(member)``
|
||||
gives ``EnumName.MEMBER_NAME``.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<{self.__class__.__name__}.{self.name}>"
|
||||
|
||||
if sys.version_info < (3, 11):
|
||||
|
||||
def __str__(self) -> str:
|
||||
return str(self.value)
|
||||
|
|
|
@ -25,7 +25,8 @@ enums. If they are related to a specific class, then they are also available as
|
|||
those classes.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
Since v20.0, most of the constants in this module are grouped into enums.
|
||||
|
||||
* Most of the constants in this module are grouped into enums.
|
||||
"""
|
||||
|
||||
__all__ = [
|
||||
|
@ -61,10 +62,9 @@ __all__ = [
|
|||
"UpdateType",
|
||||
]
|
||||
|
||||
from enum import IntEnum
|
||||
from typing import List, NamedTuple
|
||||
|
||||
from telegram._utils.enum import StringEnum
|
||||
from telegram._utils.enum import IntEnum, StringEnum
|
||||
|
||||
|
||||
class _BotAPIVersion(NamedTuple):
|
||||
|
|
|
@ -58,7 +58,7 @@ def get(name, fallback):
|
|||
if GITHUB_ACTION is not None and BOTS is not None and JOB_INDEX is not None:
|
||||
try:
|
||||
return BOTS[JOB_INDEX][name]
|
||||
except KeyError:
|
||||
except (KeyError, IndexError):
|
||||
pass
|
||||
|
||||
# Otherwise go with the fallback
|
||||
|
|
|
@ -17,13 +17,12 @@
|
|||
# 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 json
|
||||
from enum import IntEnum
|
||||
|
||||
import pytest
|
||||
from flaky import flaky
|
||||
|
||||
from telegram import constants
|
||||
from telegram._utils.enum import StringEnum
|
||||
from telegram._utils.enum import IntEnum, StringEnum
|
||||
from telegram.error import BadRequest
|
||||
from tests.conftest import data_file
|
||||
|
||||
|
@ -62,8 +61,24 @@ class TestConstants:
|
|||
assert json.dumps(IntEnumTest.FOO) == json.dumps(1)
|
||||
|
||||
def test_string_representation(self):
|
||||
# test __repr__
|
||||
assert repr(StrEnumTest.FOO) == "<StrEnumTest.FOO>"
|
||||
assert str(StrEnumTest.FOO) == "StrEnumTest.FOO"
|
||||
|
||||
# test __format__
|
||||
assert f"{StrEnumTest.FOO} this {StrEnumTest.BAR}" == "foo this bar"
|
||||
assert f"{StrEnumTest.FOO:*^10}" == "***foo****"
|
||||
|
||||
# test __str__
|
||||
assert str(StrEnumTest.FOO) == "foo"
|
||||
|
||||
def test_int_representation(self):
|
||||
# test __repr__
|
||||
assert repr(IntEnumTest.FOO) == "<IntEnumTest.FOO>"
|
||||
# test __format__
|
||||
assert f"{IntEnumTest.FOO}/0 is undefined!" == "1/0 is undefined!"
|
||||
assert f"{IntEnumTest.FOO:*^10}" == "****1*****"
|
||||
# test __str__
|
||||
assert str(IntEnumTest.FOO) == "1"
|
||||
|
||||
def test_string_inheritance(self):
|
||||
assert isinstance(StrEnumTest.FOO, str)
|
||||
|
|
Loading…
Reference in a new issue