mirror of
https://github.com/aiogram/aiogram.git
synced 2026-04-08 16:37:47 +00:00
Reworked request builder (#1142)
* Reworked request builder * Added more default values * Update tests * Fixed timestamp * Fixed Py3.8 support * Describe changes
This commit is contained in:
parent
924a83966d
commit
fea1b7b0a3
300 changed files with 1003 additions and 3448 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import asyncio
|
||||
from typing import AsyncContextManager, AsyncGenerator
|
||||
from typing import Any, AsyncContextManager, AsyncGenerator, Dict, List
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import aiohttp_socks
|
||||
|
|
@ -11,8 +11,8 @@ from aiogram import Bot
|
|||
from aiogram.client.session import aiohttp
|
||||
from aiogram.client.session.aiohttp import AiohttpSession
|
||||
from aiogram.exceptions import TelegramNetworkError
|
||||
from aiogram.methods import Request, TelegramMethod
|
||||
from aiogram.types import UNSET, InputFile
|
||||
from aiogram.methods import TelegramMethod
|
||||
from aiogram.types import UNSET_PARSE_MODE, InputFile
|
||||
from tests.mocked_bot import MockedBot
|
||||
|
||||
|
||||
|
|
@ -103,44 +103,60 @@ class TestAiohttpSession:
|
|||
await session.close()
|
||||
mocked_close.assert_called_once()
|
||||
|
||||
def test_build_form_data_with_data_only(self):
|
||||
request = Request(
|
||||
method="method",
|
||||
data={
|
||||
"str": "value",
|
||||
"int": 42,
|
||||
"bool": True,
|
||||
"unset": UNSET,
|
||||
"null": None,
|
||||
"list": ["foo"],
|
||||
"dict": {"bar": "baz"},
|
||||
},
|
||||
)
|
||||
def test_build_form_data_with_data_only(self, bot: MockedBot):
|
||||
class TestMethod(TelegramMethod[bool]):
|
||||
__api_method__ = "test"
|
||||
__returning__ = bool
|
||||
|
||||
str_: str
|
||||
int_: int
|
||||
bool_: bool
|
||||
unset_: str = UNSET_PARSE_MODE
|
||||
null_: None
|
||||
list_: List[str]
|
||||
dict_: Dict[str, Any]
|
||||
|
||||
session = AiohttpSession()
|
||||
form = session.build_form_data(request)
|
||||
form = session.build_form_data(
|
||||
bot,
|
||||
TestMethod(
|
||||
str_="value",
|
||||
int_=42,
|
||||
bool_=True,
|
||||
unset_=UNSET_PARSE_MODE,
|
||||
null_=None,
|
||||
list_=["foo"],
|
||||
dict_={"bar": "baz"},
|
||||
),
|
||||
)
|
||||
|
||||
fields = form._fields
|
||||
assert len(fields) == 5
|
||||
assert all(isinstance(field[2], str) for field in fields)
|
||||
assert "null" not in [item[0]["name"] for item in fields]
|
||||
assert "null_" not in [item[0]["name"] for item in fields]
|
||||
|
||||
def test_build_form_data_with_files(self):
|
||||
request = Request(
|
||||
method="method",
|
||||
data={"key": "value"},
|
||||
files={"document": BareInputFile(filename="file.txt")},
|
||||
)
|
||||
def test_build_form_data_with_files(self, bot: Bot):
|
||||
class TestMethod(TelegramMethod[bool]):
|
||||
__api_method__ = "test"
|
||||
__returning__ = bool
|
||||
|
||||
key: str
|
||||
document: InputFile
|
||||
|
||||
session = AiohttpSession()
|
||||
form = session.build_form_data(request)
|
||||
form = session.build_form_data(
|
||||
bot,
|
||||
TestMethod(key="value", document=BareInputFile(filename="file.txt")),
|
||||
)
|
||||
|
||||
fields = form._fields
|
||||
|
||||
assert len(fields) == 2
|
||||
assert len(fields) == 3
|
||||
assert fields[1][0]["name"] == "document"
|
||||
assert fields[1][0]["filename"] == "file.txt"
|
||||
assert isinstance(fields[1][2], BareInputFile)
|
||||
assert fields[1][2].startswith("attach://")
|
||||
assert fields[2][0]["name"] == fields[1][2][9:]
|
||||
assert fields[2][0]["filename"] == "file.txt"
|
||||
assert isinstance(fields[2][2], BareInputFile)
|
||||
|
||||
async def test_make_request(self, bot: MockedBot, aresponses: ResponsesMockServer):
|
||||
aresponses.add(
|
||||
|
|
@ -158,9 +174,7 @@ class TestAiohttpSession:
|
|||
|
||||
class TestMethod(TelegramMethod[int]):
|
||||
__returning__ = int
|
||||
|
||||
def build_request(self, bot: Bot) -> Request:
|
||||
return Request(method="method", data={})
|
||||
__api_method__ = "method"
|
||||
|
||||
call = TestMethod()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
import datetime
|
||||
import json
|
||||
from typing import AsyncContextManager, AsyncGenerator, Optional
|
||||
from typing import Any, AsyncContextManager, AsyncGenerator, Optional
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
from pytz import utc
|
||||
|
||||
from aiogram import Bot
|
||||
from aiogram.client.session.base import BaseSession, TelegramType
|
||||
from aiogram.client.telegram import PRODUCTION, TelegramAPIServer
|
||||
from aiogram.enums import ChatType, TopicIconColor
|
||||
from aiogram.enums import ChatType, ParseMode, TopicIconColor
|
||||
from aiogram.exceptions import (
|
||||
ClientDecodeError,
|
||||
RestartingTelegram,
|
||||
|
|
@ -24,7 +25,8 @@ from aiogram.exceptions import (
|
|||
TelegramUnauthorizedError,
|
||||
)
|
||||
from aiogram.methods import DeleteMessage, GetMe, TelegramMethod
|
||||
from aiogram.types import UNSET, User
|
||||
from aiogram.types import UNSET_PARSE_MODE, User
|
||||
from aiogram.types.base import UNSET_DISABLE_WEB_PAGE_PREVIEW, UNSET_PROTECT_CONTENT
|
||||
from tests.mocked_bot import MockedBot
|
||||
|
||||
|
||||
|
|
@ -33,17 +35,21 @@ class CustomSession(BaseSession):
|
|||
pass
|
||||
|
||||
async def make_request(
|
||||
self, token: str, method: TelegramMethod[TelegramType], timeout: Optional[int] = UNSET
|
||||
self,
|
||||
token: str,
|
||||
method: TelegramMethod[TelegramType],
|
||||
timeout: Optional[int] = UNSET_PARSE_MODE,
|
||||
) -> None: # type: ignore
|
||||
assert isinstance(token, str)
|
||||
assert isinstance(method, TelegramMethod)
|
||||
|
||||
async def stream_content(
|
||||
self, url: str, timeout: int, chunk_size: int
|
||||
self, url: str, timeout: int, chunk_size: int, raise_for_status: bool
|
||||
) -> AsyncGenerator[bytes, None]: # pragma: no cover
|
||||
assert isinstance(url, str)
|
||||
assert isinstance(timeout, int)
|
||||
assert isinstance(chunk_size, int)
|
||||
assert isinstance(raise_for_status, bool)
|
||||
yield b"\f" * 10
|
||||
|
||||
|
||||
|
|
@ -79,58 +85,56 @@ class TestBaseSession:
|
|||
assert session.api == api
|
||||
assert "example.com" in session.api.base
|
||||
|
||||
def test_prepare_value(self):
|
||||
@pytest.mark.parametrize(
|
||||
"value,result",
|
||||
[
|
||||
[None, None],
|
||||
["text", "text"],
|
||||
[ChatType.PRIVATE, "private"],
|
||||
[TopicIconColor.RED, "16478047"],
|
||||
[42, "42"],
|
||||
[True, "true"],
|
||||
[["test"], '["test"]'],
|
||||
[["test", ["test"]], '["test", ["test"]]'],
|
||||
[[{"test": "pass", "spam": None}], '[{"test": "pass"}]'],
|
||||
[{"test": "pass", "number": 42, "spam": None}, '{"test": "pass", "number": 42}'],
|
||||
[{"foo": {"test": "pass", "spam": None}}, '{"foo": {"test": "pass"}}'],
|
||||
[
|
||||
datetime.datetime(
|
||||
year=2017, month=5, day=17, hour=4, minute=11, second=42, tzinfo=utc
|
||||
),
|
||||
"1494994302",
|
||||
],
|
||||
],
|
||||
)
|
||||
def test_prepare_value(self, value: Any, result: str, bot: MockedBot):
|
||||
session = CustomSession()
|
||||
|
||||
now = datetime.datetime.now()
|
||||
assert session.prepare_value(value, bot=bot, files={}) == result
|
||||
|
||||
assert session.prepare_value("text") == "text"
|
||||
assert session.prepare_value(["test"]) == '["test"]'
|
||||
assert session.prepare_value({"test": "ok"}) == '{"test": "ok"}'
|
||||
assert session.prepare_value(now) == str(round(now.timestamp()))
|
||||
assert isinstance(session.prepare_value(datetime.timedelta(minutes=2)), str)
|
||||
assert session.prepare_value(42) == "42"
|
||||
assert session.prepare_value(ChatType.PRIVATE) == "private"
|
||||
assert session.prepare_value(TopicIconColor.RED) == "16478047"
|
||||
|
||||
def test_clean_json(self):
|
||||
def test_prepare_value_timedelta(self, bot: MockedBot):
|
||||
session = CustomSession()
|
||||
|
||||
cleaned_dict = session.clean_json({"key": "value", "null": None})
|
||||
assert "key" in cleaned_dict
|
||||
assert "null" not in cleaned_dict
|
||||
value = session.prepare_value(datetime.timedelta(minutes=2), bot=bot, files={})
|
||||
assert isinstance(value, str)
|
||||
|
||||
cleaned_list = session.clean_json(["kaboom", 42, None])
|
||||
assert len(cleaned_list) == 2
|
||||
assert 42 in cleaned_list
|
||||
assert None not in cleaned_list
|
||||
assert cleaned_list[0] == "kaboom"
|
||||
|
||||
def test_clean_json_with_nested_json(self):
|
||||
session = CustomSession()
|
||||
|
||||
cleaned = session.clean_json(
|
||||
{
|
||||
"key": "value",
|
||||
"null": None,
|
||||
"nested_list": ["kaboom", 42, None],
|
||||
"nested_dict": {"key": "value", "null": None},
|
||||
}
|
||||
def test_prepare_value_defaults_replace(self):
|
||||
bot = MockedBot(
|
||||
parse_mode=ParseMode.HTML,
|
||||
protect_content=True,
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
assert bot.session.prepare_value(UNSET_PARSE_MODE, bot=bot, files={}) == "HTML"
|
||||
assert (
|
||||
bot.session.prepare_value(UNSET_DISABLE_WEB_PAGE_PREVIEW, bot=bot, files={}) == "true"
|
||||
)
|
||||
assert bot.session.prepare_value(UNSET_PROTECT_CONTENT, bot=bot, files={}) == "true"
|
||||
|
||||
assert len(cleaned) == 3
|
||||
assert "null" not in cleaned
|
||||
|
||||
assert isinstance(cleaned["nested_list"], list)
|
||||
assert cleaned["nested_list"] == ["kaboom", 42]
|
||||
|
||||
assert isinstance(cleaned["nested_dict"], dict)
|
||||
assert cleaned["nested_dict"] == {"key": "value"}
|
||||
|
||||
def test_clean_json_not_json(self):
|
||||
session = CustomSession()
|
||||
|
||||
assert session.clean_json(42) == 42
|
||||
def test_prepare_value_defaults_unset(self):
|
||||
bot = MockedBot()
|
||||
assert bot.session.prepare_value(UNSET_PARSE_MODE, bot=bot, files={}) is None
|
||||
assert bot.session.prepare_value(UNSET_DISABLE_WEB_PAGE_PREVIEW, bot=bot, files={}) is None
|
||||
assert bot.session.prepare_value(UNSET_PROTECT_CONTENT, bot=bot, files={}) is None
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"status_code,content,error",
|
||||
|
|
@ -210,7 +214,10 @@ class TestBaseSession:
|
|||
async def test_stream_content(self):
|
||||
session = CustomSession()
|
||||
stream = session.stream_content(
|
||||
"https://www.python.org/static/img/python-logo.png", timeout=5, chunk_size=65536
|
||||
"https://www.python.org/static/img/python-logo.png",
|
||||
timeout=5,
|
||||
chunk_size=65536,
|
||||
raise_for_status=True,
|
||||
)
|
||||
assert isinstance(stream, AsyncGenerator)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue