diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d26ad636..73eac1b8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,6 +11,7 @@ on: jobs: build: strategy: + fail-fast: false max-parallel: 9 matrix: os: @@ -18,8 +19,9 @@ jobs: - macos-latest - windows-latest python-version: - - 3.8 - - 3.9 + - '3.8' + - '3.9' + - '3.10' defaults: # Windows is sucks. Force use bash instead of PowerShell @@ -39,7 +41,7 @@ jobs: - name: Install and configure Poetry uses: snok/install-poetry@v1 with: - version: 1.1.8 + version: 1.1.11 virtualenvs-create: true virtualenvs-in-project: true installer-parallel: true diff --git a/CHANGES/719.misc b/CHANGES/719.misc new file mode 100644 index 00000000..bcfb4759 --- /dev/null +++ b/CHANGES/719.misc @@ -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 diff --git a/aiogram/client/bot.py b/aiogram/client/bot.py index 7e0fe0d1..96890b1f 100644 --- a/aiogram/client/bot.py +++ b/aiogram/client/bot.py @@ -17,7 +17,6 @@ from typing import ( ) import aiofiles -from async_lru import alru_cache from aiogram.utils.mixins import ContextInstanceMixin from aiogram.utils.token import extract_bot_id, validate_token @@ -178,6 +177,7 @@ class Bot(ContextInstanceMixin["Bot"]): self.session = session self.parse_mode = parse_mode self.__token = token + self._me: Optional[User] = None @property def token(self) -> str: @@ -208,9 +208,10 @@ class Bot(ContextInstanceMixin["Bot"]): await self.session.close() self.reset_current(token) - @alru_cache() # type: ignore 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 async def __download_file_binary_io( diff --git a/aiogram/utils/deep_linking.py b/aiogram/utils/deep_linking.py index caac2c26..bedaa6bc 100644 --- a/aiogram/utils/deep_linking.py +++ b/aiogram/utils/deep_linking.py @@ -65,7 +65,9 @@ async def create_start_link(bot: Bot, payload: str, encode: bool = False) -> str :return: link """ 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: @@ -82,7 +84,7 @@ async def create_startgroup_link(bot: Bot, payload: str, encode: bool = False) - """ username = (await bot.me()).username return create_deep_link( - username=username, link_type="startgroup", payload=payload, encode=encode + username=cast(str, username), link_type="startgroup", payload=payload, encode=encode ) diff --git a/poetry.lock b/poetry.lock index b4ef5c38..d952e363 100644 --- a/poetry.lock +++ b/poetry.lock @@ -81,14 +81,6 @@ python-versions = ">=3.6" aiohttp = ">=3.1.0,<4.0.0" pytest-asyncio = "*" -[[package]] -name = "async-lru" -version = "1.0.2" -description = "Simple lru_cache for asyncio" -category = "main" -optional = false -python-versions = "*" - [[package]] name = "async-timeout" version = "3.0.1" @@ -1297,7 +1289,7 @@ redis = ["aioredis"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "68e420156c8460179788d4e4828a348753606d8b2c16013b3784e7b7f36f47c3" +content-hash = "a083bb27637bba38eb39dffd3df077eac1ff615440c8e05877c128c559c33b9e" [metadata.files] aiofiles = [ @@ -1363,9 +1355,6 @@ aresponses = [ {file = "aresponses-2.1.4-py3-none-any.whl", hash = "sha256:2a5a100c9b39e559bf55c26cc837a8ce64ab160ee086afa01ee9c4ef07f245db"}, {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 = [ {file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"}, {file = "async_timeout-3.0.1-py3-none-any.whl", hash = "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"}, diff --git a/pyproject.toml b/pyproject.toml index 53a3aa34..8ec205ad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,6 @@ magic-filter = "^1.0.2" aiohttp = "^3.7.4" pydantic = "^1.8.2" aiofiles = "^0.7.0" -async_lru = "^1.0.2" # Fast uvloop = { version = "^0.16.0", markers = "sys_platform == 'darwin' or sys_platform == 'linux'", optional = true } # i18n @@ -127,7 +126,6 @@ known_third_party = [ "aiohttp", "aiohttp_socks", "aresponses", - "async_lru", "packaging", "pkg_resources", "pydantic", diff --git a/tests/conftest.py b/tests/conftest.py index 51621a43..e57ec632 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -75,4 +75,3 @@ def bot(): yield bot finally: Bot.reset_current(token) - bot.me.invalidate(bot) diff --git a/tests/mocked_bot.py b/tests/mocked_bot.py index 76abc445..0a496105 100644 --- a/tests/mocked_bot.py +++ b/tests/mocked_bot.py @@ -5,7 +5,7 @@ from aiogram import Bot from aiogram.client.session.base import BaseSession from aiogram.methods import TelegramMethod from aiogram.methods.base import Request, Response, TelegramType -from aiogram.types import UNSET, ResponseParameters +from aiogram.types import UNSET, ResponseParameters, User class MockedSession(BaseSession): @@ -46,6 +46,14 @@ class MockedBot(Bot): def __init__(self, **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( self, diff --git a/tests/test_api/test_methods/test_get_me.py b/tests/test_api/test_methods/test_get_me.py index 7da53ea8..ba51e6a6 100644 --- a/tests/test_api/test_methods/test_get_me.py +++ b/tests/test_api/test_methods/test_get_me.py @@ -30,25 +30,6 @@ class TestGetMe: assert response == prepare_result.result 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() - request: Request = bot.get_request() - assert isinstance(response, User) - assert request.method == "getMe" - 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 + assert response == bot._me diff --git a/tests/test_dispatcher/test_filters/test_command.py b/tests/test_dispatcher/test_filters/test_command.py index 51aabade..18888fe1 100644 --- a/tests/test_dispatcher/test_filters/test_command.py +++ b/tests/test_dispatcher/test_filters/test_command.py @@ -6,7 +6,6 @@ import pytest from aiogram import F from aiogram.dispatcher.filters import Command, CommandObject from aiogram.dispatcher.filters.command import CommandStart -from aiogram.methods import GetMe from aiogram.types import Chat, Message, User from tests.mocked_bot import MockedBot @@ -58,10 +57,6 @@ class TestCommandFilter: # TODO: test ignore case # 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_id=0, text=text, chat=Chat(id=42, type="private"), date=datetime.datetime.now() ) diff --git a/tests/test_utils/test_deep_linking.py b/tests/test_utils/test_deep_linking.py index 830c8149..78dce6a3 100644 --- a/tests/test_utils/test_deep_linking.py +++ b/tests/test_utils/test_deep_linking.py @@ -1,5 +1,4 @@ import pytest -from async_lru import alru_cache from aiogram.utils.deep_linking import ( create_start_link, @@ -36,60 +35,39 @@ def wrong_payload_fixture(request): 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: - 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) - 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): 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) - 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) decoded = decode_payload(encoded) 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 link = await create_start_link(bot, wrong_payload, encode=True) # define reference link 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 link = await create_start_link(bot, payload) assert link - async def test_too_long_payload(self, bot): + async def test_too_long_payload(self, bot: MockedBot): payload = "p" * 65 - print(payload, len(payload)) with pytest.raises(ValueError): await create_start_link(bot, payload)