mirror of
https://github.com/aiogram/aiogram.git
synced 2025-12-12 02:03:04 +00:00
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:
parent
99c99cec78
commit
7405db2ad3
11 changed files with 36 additions and 81 deletions
8
.github/workflows/tests.yml
vendored
8
.github/workflows/tests.yml
vendored
|
|
@ -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
2
CHANGES/719.misc
Normal 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
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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
13
poetry.lock
generated
|
|
@ -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"},
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -75,4 +75,3 @@ def bot():
|
||||||
yield bot
|
yield bot
|
||||||
finally:
|
finally:
|
||||||
Bot.reset_current(token)
|
Bot.reset_current(token)
|
||||||
bot.me.invalidate(bot)
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue