feat(timeout):

implement (class-bound, instance-bound, request-bound) session timeout
for requests. fix docs config, fix aiohttp session docs links.
This commit is contained in:
mpa 2020-05-06 02:42:54 +04:00
parent 2adc19724d
commit df4ba87dfc
6 changed files with 55 additions and 16 deletions

View file

@ -132,7 +132,9 @@ class AiohttpSession(BaseSession):
url = self.api.api_url(token=token, method=request.method)
form = self.build_form_data(request)
async with session.post(url, data=form, timeout=call.request_timeout) as resp:
async with session.post(
url, data=form, timeout=call.request_timeout or self.timeout
) as resp:
raw_result = await resp.json(loads=self.json_loads)
response = call.build_response(raw_result)

View file

@ -4,7 +4,7 @@ import abc
import datetime
import json
from types import TracebackType
from typing import Any, AsyncGenerator, Callable, Optional, Type, TypeVar, Union
from typing import Any, AsyncGenerator, Callable, ClassVar, Optional, Type, TypeVar, Union
from aiogram.utils.exceptions import TelegramAPIError
@ -12,14 +12,18 @@ from ...methods import Response, TelegramMethod
from ..telegram import PRODUCTION, TelegramAPIServer
T = TypeVar("T")
_JSON_LOADS = Callable[..., Any]
_JSON_DUMPS = Callable[..., str]
_JsonLoads = Callable[..., Any]
_JsonDumps = Callable[..., str]
class BaseSession(abc.ABC):
# global session timeout
default_timeout: ClassVar[float] = 60.0
_api: TelegramAPIServer
_json_loads: _JSON_LOADS
_json_dumps: _JSON_DUMPS
_json_loads: _JsonLoads
_json_dumps: _JsonDumps
_timeout: float
@property
def api(self) -> TelegramAPIServer:
@ -30,21 +34,33 @@ class BaseSession(abc.ABC):
self._api = value
@property
def json_loads(self) -> _JSON_LOADS:
def json_loads(self) -> _JsonLoads:
return getattr(self, "_json_loads", json.loads) # type: ignore
@json_loads.setter
def json_loads(self, value: _JSON_LOADS) -> None:
def json_loads(self, value: _JsonLoads) -> None:
self._json_loads = value # type: ignore
@property
def json_dumps(self) -> _JSON_DUMPS:
def json_dumps(self) -> _JsonDumps:
return getattr(self, "_json_dumps", json.dumps) # type: ignore
@json_dumps.setter
def json_dumps(self, value: _JSON_DUMPS) -> None:
def json_dumps(self, value: _JsonDumps) -> None:
self._json_dumps = value # type: ignore
@property
def timeout(self) -> float:
return getattr(self, "_timeout", self.__class__.default_timeout) # type: ignore
@timeout.setter
def timeout(self, value: float) -> None:
self._timeout = value
@timeout.deleter
def timeout(self) -> None:
del self._timeout
@classmethod
def raise_for_status(cls, response: Response[T]) -> None:
if response.ok:

View file

@ -13,7 +13,6 @@ if TYPE_CHECKING: # pragma: no cover
from ..client.bot import Bot
T = TypeVar("T")
DEFAULT_REQUEST_TIMEOUT_SECONDS = 60.0
class Request(BaseModel):
@ -56,7 +55,7 @@ class TelegramMethod(abc.ABC, BaseModel, Generic[T]):
def build_request(self) -> Request: # pragma: no cover
pass
request_timeout: float = DEFAULT_REQUEST_TIMEOUT_SECONDS
request_timeout: Optional[float] = None
def dict(self, **kwargs: Any) -> Any:
# override dict of pydantic.BaseModel to overcome exporting request_timeout field

View file

@ -1,6 +1,6 @@
# Aiohttp session
AiohttpSession represents a wrapper-class around `ClientSession` from [aiohttp]('https://pypi.org/project/aiohttp/')
AiohttpSession represents a wrapper-class around `ClientSession` from [aiohttp](https://pypi.org/project/aiohttp/ "PyPi repository"){target=_blank}
Currently `AiohttpSession` is a default session used in `aiogram.Bot`
@ -17,7 +17,7 @@ Bot('token', session=session)
## Proxy requests in AiohttpSession
In order to use AiohttpSession with proxy connector you have to install [aiohttp-socks]('https://pypi.org/project/aiohttp-socks/')
In order to use AiohttpSession with proxy connector you have to install [aiohttp-socks](https://pypi.org/project/aiohttp-socks/ "PyPi repository"){target=_blank}
Binding session to bot:
```python

View file

@ -35,6 +35,7 @@ markdown_extensions:
- pymdownx.inlinehilite
- markdown_include.include:
base_path: docs
- attr_list
nav:
- index.md

View file

@ -54,12 +54,33 @@ class TestBaseSession:
assert session.json_loads == custom_loads == session._json_loads
different_session = CustomSession()
assert all(not hasattr(different_session, attr) for attr in ("_json_loads", "_json_dumps", "_api"))
assert all(
not hasattr(different_session, attr) for attr in ("_json_loads", "_json_dumps", "_api")
)
def test_timeout(self):
session = CustomSession()
assert session.timeout == session.default_timeout == CustomSession.default_timeout
session.default_timeout = float(65.0_0) # mypy will complain
assert session.timeout != session.default_timeout
CustomSession.default_timeout = float(68.0_0)
assert session.timeout == CustomSession.default_timeout
session.timeout = float(71.0_0)
assert session.timeout != session.default_timeout
del session.timeout
CustomSession.default_timeout = session.default_timeout + 100
assert (
session.timeout != BaseSession.default_timeout
and session.timeout == CustomSession.default_timeout
)
def test_init_custom_api(self):
api = TelegramAPIServer(
base="http://example.com/{token}/{method}",
file="http://example.com/{token}/file/{path{",
file="http://example.com/{token}/file/{path}",
)
session = CustomSession()
session.api = api