Enable Python 3.10 for tests (#719)

* Try to test on Python 3.10

* Prevent to YAML type cast

* Bump poetry

* Removed async_lru

* Disable fail-fast on tests

* Fixed typing

* Added patch-notes
This commit is contained in:
Alex Root Junior 2021-10-06 22:49:14 +03:00 committed by GitHub
parent 99c99cec78
commit 7405db2ad3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 36 additions and 81 deletions

View file

@ -11,6 +11,7 @@ on:
jobs: jobs:
build: build:
strategy: strategy:
fail-fast: false
max-parallel: 9 max-parallel: 9
matrix: matrix:
os: os:
@ -18,8 +19,9 @@ jobs:
- macos-latest - macos-latest
- windows-latest - windows-latest
python-version: python-version:
- 3.8 - '3.8'
- 3.9 - '3.9'
- '3.10'
defaults: defaults:
# Windows is sucks. Force use bash instead of PowerShell # Windows is sucks. Force use bash instead of PowerShell
@ -39,7 +41,7 @@ jobs:
- name: Install and configure Poetry - name: Install and configure Poetry
uses: snok/install-poetry@v1 uses: snok/install-poetry@v1
with: with:
version: 1.1.8 version: 1.1.11
virtualenvs-create: true virtualenvs-create: true
virtualenvs-in-project: true virtualenvs-in-project: true
installer-parallel: true installer-parallel: true

2
CHANGES/719.misc Normal file
View file

@ -0,0 +1,2 @@
Enabled testing on Python 3.10
Removed `async_lru` dependency (is incompatible with Python 3.10) and replaced usage with protected property

View file

@ -17,7 +17,6 @@ from typing import (
) )
import aiofiles import aiofiles
from async_lru import alru_cache
from aiogram.utils.mixins import ContextInstanceMixin from aiogram.utils.mixins import ContextInstanceMixin
from aiogram.utils.token import extract_bot_id, validate_token from aiogram.utils.token import extract_bot_id, validate_token
@ -178,6 +177,7 @@ class Bot(ContextInstanceMixin["Bot"]):
self.session = session self.session = session
self.parse_mode = parse_mode self.parse_mode = parse_mode
self.__token = token self.__token = token
self._me: Optional[User] = None
@property @property
def token(self) -> str: def token(self) -> str:
@ -208,9 +208,10 @@ class Bot(ContextInstanceMixin["Bot"]):
await self.session.close() await self.session.close()
self.reset_current(token) self.reset_current(token)
@alru_cache() # type: ignore
async def me(self) -> User: async def me(self) -> User:
return await self.get_me() if self._me is None: # pragma: no cover
self._me = await self.get_me()
return self._me
@classmethod @classmethod
async def __download_file_binary_io( async def __download_file_binary_io(

View file

@ -65,7 +65,9 @@ async def create_start_link(bot: Bot, payload: str, encode: bool = False) -> str
:return: link :return: link
""" """
username = (await bot.me()).username username = (await bot.me()).username
return create_deep_link(username=username, link_type="start", payload=payload, encode=encode) return create_deep_link(
username=cast(str, username), link_type="start", payload=payload, encode=encode
)
async def create_startgroup_link(bot: Bot, payload: str, encode: bool = False) -> str: async def create_startgroup_link(bot: Bot, payload: str, encode: bool = False) -> str:
@ -82,7 +84,7 @@ async def create_startgroup_link(bot: Bot, payload: str, encode: bool = False) -
""" """
username = (await bot.me()).username username = (await bot.me()).username
return create_deep_link( return create_deep_link(
username=username, link_type="startgroup", payload=payload, encode=encode username=cast(str, username), link_type="startgroup", payload=payload, encode=encode
) )

13
poetry.lock generated
View file

@ -81,14 +81,6 @@ python-versions = ">=3.6"
aiohttp = ">=3.1.0,<4.0.0" aiohttp = ">=3.1.0,<4.0.0"
pytest-asyncio = "*" pytest-asyncio = "*"
[[package]]
name = "async-lru"
version = "1.0.2"
description = "Simple lru_cache for asyncio"
category = "main"
optional = false
python-versions = "*"
[[package]] [[package]]
name = "async-timeout" name = "async-timeout"
version = "3.0.1" version = "3.0.1"
@ -1297,7 +1289,7 @@ redis = ["aioredis"]
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.8" python-versions = "^3.8"
content-hash = "68e420156c8460179788d4e4828a348753606d8b2c16013b3784e7b7f36f47c3" content-hash = "a083bb27637bba38eb39dffd3df077eac1ff615440c8e05877c128c559c33b9e"
[metadata.files] [metadata.files]
aiofiles = [ aiofiles = [
@ -1363,9 +1355,6 @@ aresponses = [
{file = "aresponses-2.1.4-py3-none-any.whl", hash = "sha256:2a5a100c9b39e559bf55c26cc837a8ce64ab160ee086afa01ee9c4ef07f245db"}, {file = "aresponses-2.1.4-py3-none-any.whl", hash = "sha256:2a5a100c9b39e559bf55c26cc837a8ce64ab160ee086afa01ee9c4ef07f245db"},
{file = "aresponses-2.1.4.tar.gz", hash = "sha256:39674af90700f1bfe2c7c9049cd8116f5c10d34d2e2427fd744b88d9e8644c94"}, {file = "aresponses-2.1.4.tar.gz", hash = "sha256:39674af90700f1bfe2c7c9049cd8116f5c10d34d2e2427fd744b88d9e8644c94"},
] ]
async-lru = [
{file = "async_lru-1.0.2.tar.gz", hash = "sha256:baa898027619f5cc31b7966f96f00e4fc0df43ba206a8940a5d1af5336a477cb"},
]
async-timeout = [ async-timeout = [
{file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"}, {file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"},
{file = "async_timeout-3.0.1-py3-none-any.whl", hash = "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"}, {file = "async_timeout-3.0.1-py3-none-any.whl", hash = "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"},

View file

@ -36,7 +36,6 @@ magic-filter = "^1.0.2"
aiohttp = "^3.7.4" aiohttp = "^3.7.4"
pydantic = "^1.8.2" pydantic = "^1.8.2"
aiofiles = "^0.7.0" aiofiles = "^0.7.0"
async_lru = "^1.0.2"
# Fast # Fast
uvloop = { version = "^0.16.0", markers = "sys_platform == 'darwin' or sys_platform == 'linux'", optional = true } uvloop = { version = "^0.16.0", markers = "sys_platform == 'darwin' or sys_platform == 'linux'", optional = true }
# i18n # i18n
@ -127,7 +126,6 @@ known_third_party = [
"aiohttp", "aiohttp",
"aiohttp_socks", "aiohttp_socks",
"aresponses", "aresponses",
"async_lru",
"packaging", "packaging",
"pkg_resources", "pkg_resources",
"pydantic", "pydantic",

View file

@ -75,4 +75,3 @@ def bot():
yield bot yield bot
finally: finally:
Bot.reset_current(token) Bot.reset_current(token)
bot.me.invalidate(bot)

View file

@ -5,7 +5,7 @@ from aiogram import Bot
from aiogram.client.session.base import BaseSession from aiogram.client.session.base import BaseSession
from aiogram.methods import TelegramMethod from aiogram.methods import TelegramMethod
from aiogram.methods.base import Request, Response, TelegramType from aiogram.methods.base import Request, Response, TelegramType
from aiogram.types import UNSET, ResponseParameters from aiogram.types import UNSET, ResponseParameters, User
class MockedSession(BaseSession): class MockedSession(BaseSession):
@ -46,6 +46,14 @@ class MockedBot(Bot):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(MockedBot, self).__init__("42:TEST", session=MockedSession(), **kwargs) super(MockedBot, self).__init__("42:TEST", session=MockedSession(), **kwargs)
self._me = User(
id=self.id,
is_bot=True,
first_name="FirstName",
last_name="LastName",
username="tbot",
language_code="uk-UA",
)
def add_result_for( def add_result_for(
self, self,

View file

@ -30,25 +30,6 @@ class TestGetMe:
assert response == prepare_result.result assert response == prepare_result.result
async def test_me_property(self, bot: MockedBot): async def test_me_property(self, bot: MockedBot):
prepare_result = bot.add_result_for(
GetMe, ok=True, result=User(id=42, is_bot=False, first_name="User")
)
response: User = await bot.me() response: User = await bot.me()
request: Request = bot.get_request()
assert isinstance(response, User) assert isinstance(response, User)
assert request.method == "getMe" assert response == bot._me
assert request.data == {}
assert response == prepare_result.result
response2: User = await bot.me()
assert response2 == response
response3: User = await bot.me()
assert response3 == response
assert response2 == response3
cache_info = bot.me.cache_info()
assert cache_info.hits == 2
assert cache_info.misses == 1

View file

@ -6,7 +6,6 @@ import pytest
from aiogram import F from aiogram import F
from aiogram.dispatcher.filters import Command, CommandObject from aiogram.dispatcher.filters import Command, CommandObject
from aiogram.dispatcher.filters.command import CommandStart from aiogram.dispatcher.filters.command import CommandStart
from aiogram.methods import GetMe
from aiogram.types import Chat, Message, User from aiogram.types import Chat, Message, User
from tests.mocked_bot import MockedBot from tests.mocked_bot import MockedBot
@ -58,10 +57,6 @@ class TestCommandFilter:
# TODO: test ignore case # TODO: test ignore case
# TODO: test ignore mention # TODO: test ignore mention
bot.add_result_for(
GetMe, ok=True, result=User(id=42, is_bot=True, first_name="The bot", username="tbot")
)
message = Message( message = Message(
message_id=0, text=text, chat=Chat(id=42, type="private"), date=datetime.datetime.now() message_id=0, text=text, chat=Chat(id=42, type="private"), date=datetime.datetime.now()
) )

View file

@ -1,5 +1,4 @@
import pytest import pytest
from async_lru import alru_cache
from aiogram.utils.deep_linking import ( from aiogram.utils.deep_linking import (
create_start_link, create_start_link,
@ -36,60 +35,39 @@ def wrong_payload_fixture(request):
return request.param return request.param
@pytest.fixture(autouse=True)
def get_bot_user_fixture(monkeypatch):
"""Monkey patching of bot.me calling."""
@alru_cache()
async def get_bot_user_mock(self):
from aiogram.types import User
return User(
id=12345678,
is_bot=True,
first_name="FirstName",
last_name="LastName",
username="username",
language_code="uk-UA",
)
monkeypatch.setattr(MockedBot, "me", get_bot_user_mock)
class TestDeepLinking: class TestDeepLinking:
async def test_get_start_link(self, bot, payload): async def test_get_start_link(self, bot: MockedBot, payload: str):
link = await create_start_link(bot=bot, payload=payload) link = await create_start_link(bot=bot, payload=payload)
assert link == f"https://t.me/username?start={payload}" assert link == f"https://t.me/tbot?start={payload}"
async def test_wrong_symbols(self, bot, wrong_payload): async def test_wrong_symbols(self, bot: MockedBot, wrong_payload: str):
with pytest.raises(ValueError): with pytest.raises(ValueError):
await create_start_link(bot, wrong_payload) await create_start_link(bot, wrong_payload)
async def test_get_startgroup_link(self, bot, payload): async def test_get_startgroup_link(self, bot: MockedBot, payload: str):
link = await create_startgroup_link(bot, payload) link = await create_startgroup_link(bot, payload)
assert link == f"https://t.me/username?startgroup={payload}" assert link == f"https://t.me/tbot?startgroup={payload}"
async def test_filter_encode_and_decode(self, payload): async def test_filter_encode_and_decode(self, payload: str):
encoded = encode_payload(payload) encoded = encode_payload(payload)
decoded = decode_payload(encoded) decoded = decode_payload(encoded)
assert decoded == str(payload) assert decoded == str(payload)
async def test_get_start_link_with_encoding(self, bot, wrong_payload): async def test_get_start_link_with_encoding(self, bot: MockedBot, wrong_payload: str):
# define link # define link
link = await create_start_link(bot, wrong_payload, encode=True) link = await create_start_link(bot, wrong_payload, encode=True)
# define reference link # define reference link
encoded_payload = encode_payload(wrong_payload) encoded_payload = encode_payload(wrong_payload)
assert link == f"https://t.me/username?start={encoded_payload}" assert link == f"https://t.me/tbot?start={encoded_payload}"
async def test_64_len_payload(self, bot): async def test_64_len_payload(self, bot: MockedBot):
payload = "p" * 64 payload = "p" * 64
link = await create_start_link(bot, payload) link = await create_start_link(bot, payload)
assert link assert link
async def test_too_long_payload(self, bot): async def test_too_long_payload(self, bot: MockedBot):
payload = "p" * 65 payload = "p" * 65
print(payload, len(payload))
with pytest.raises(ValueError): with pytest.raises(ValueError):
await create_start_link(bot, payload) await create_start_link(bot, payload)