Skip to content

Commit

Permalink
[PR #10037/2e369db backport][3.12] Refactor requests and responses to…
Browse files Browse the repository at this point in the history
… use classvar defaults to avoid multiple `__init__`s (#10054)
  • Loading branch information
bdraco authored Nov 27, 2024
1 parent c9eb8e7 commit e5dd82a
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 48 deletions.
1 change: 1 addition & 0 deletions CHANGES/10037.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improved performances of creating objects during the HTTP request lifecycle -- by :user:`bdraco`.
3 changes: 2 additions & 1 deletion aiohttp/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,10 +694,11 @@ def ceil_timeout(


class HeadersMixin:
"""Mixin for handling headers."""

ATTRS = frozenset(["_content_type", "_content_dict", "_stored_content_type"])

_headers: MultiMapping[str]

_content_type: Optional[str] = None
_content_dict: Optional[Dict[str, str]] = None
_stored_content_type: Union[str, None, _SENTINEL] = sentinel
Expand Down
2 changes: 2 additions & 0 deletions aiohttp/web_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,8 @@ def _make_request(
task: "asyncio.Task[None]",
_cls: Type[Request] = Request,
) -> Request:
if TYPE_CHECKING:
assert self._loop is not None
return _cls(
message,
payload,
Expand Down
21 changes: 6 additions & 15 deletions aiohttp/web_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ class BaseRequest(MutableMapping[str, Any], HeadersMixin):
"_transport_peername",
]
)
_post: Optional[MultiDictProxy[Union[str, bytes, FileField]]] = None
_read_bytes: Optional[bytes] = None

def __init__(
self,
Expand All @@ -162,8 +164,6 @@ def __init__(
host: Optional[str] = None,
remote: Optional[str] = None,
) -> None:
if state is None:
state = {}
self._message = message
self._protocol = protocol
self._payload_writer = payload_writer
Expand All @@ -187,20 +187,18 @@ def __init__(
self._cache["scheme"] = url.scheme
self._rel_url = url.relative()
else:
self._rel_url = message.url
self._rel_url = url
if scheme is not None:
self._cache["scheme"] = scheme
if host is not None:
self._cache["host"] = host
self._post: Optional[MultiDictProxy[Union[str, bytes, FileField]]] = None
self._read_bytes: Optional[bytes] = None

self._state = state
self._state = {} if state is None else state
self._task = task
self._client_max_size = client_max_size
self._loop = loop

transport = self._protocol.transport
transport = protocol.transport
assert transport is not None
self._transport_sslcontext = transport.get_extra_info("sslcontext")
self._transport_peername = transport.get_extra_info("peername")
Expand Down Expand Up @@ -847,14 +845,7 @@ class Request(BaseRequest):

ATTRS = BaseRequest.ATTRS | frozenset(["_match_info"])

def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)

# matchdict, route_name, handler
# or information about traversal lookup

# initialized after route resolving
self._match_info: Optional[UrlMappingMatchInfo] = None
_match_info: Optional["UrlMappingMatchInfo"] = None

if DEBUG:

Expand Down
32 changes: 16 additions & 16 deletions aiohttp/web_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,20 @@ class ContentCoding(enum.Enum):

class StreamResponse(BaseClass, HeadersMixin):

_length_check = True

_body: Union[None, bytes, bytearray, Payload]
_length_check = True
_body = None
_keep_alive: Optional[bool] = None
_chunked: bool = False
_compression: bool = False
_compression_strategy: int = zlib.Z_DEFAULT_STRATEGY
_compression_force: Optional[ContentCoding] = None
_req: Optional["BaseRequest"] = None
_payload_writer: Optional[AbstractStreamWriter] = None
_eof_sent: bool = False
_must_be_empty_body: Optional[bool] = None
_body_length = 0
_cookies: Optional[SimpleCookie] = None

def __init__(
self,
Expand All @@ -95,19 +106,6 @@ def __init__(
the headers when creating a new response object. It is not intended
to be used by external code.
"""
self._body = None
self._keep_alive: Optional[bool] = None
self._chunked = False
self._compression = False
self._compression_strategy: int = zlib.Z_DEFAULT_STRATEGY
self._compression_force: Optional[ContentCoding] = None
self._cookies: Optional[SimpleCookie] = None

self._req: Optional[BaseRequest] = None
self._payload_writer: Optional[AbstractStreamWriter] = None
self._eof_sent = False
self._must_be_empty_body: Optional[bool] = None
self._body_length = 0
self._state: Dict[str, Any] = {}

if _real_headers is not None:
Expand Down Expand Up @@ -613,6 +611,9 @@ def __eq__(self, other: object) -> bool:


class Response(StreamResponse):

_compressed_body: Optional[bytes] = None

def __init__(
self,
*,
Expand Down Expand Up @@ -677,7 +678,6 @@ def __init__(
else:
self.body = body

self._compressed_body: Optional[bytes] = None
self._zlib_executor_size = zlib_executor_size
self._zlib_executor = zlib_executor

Expand Down
32 changes: 16 additions & 16 deletions aiohttp/web_ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,22 @@ def __bool__(self) -> bool:

class WebSocketResponse(StreamResponse):

_length_check = False
_length_check: bool = False
_ws_protocol: Optional[str] = None
_writer: Optional[WebSocketWriter] = None
_reader: Optional[WebSocketDataQueue] = None
_closed: bool = False
_closing: bool = False
_conn_lost: int = 0
_close_code: Optional[int] = None
_loop: Optional[asyncio.AbstractEventLoop] = None
_waiting: bool = False
_close_wait: Optional[asyncio.Future[None]] = None
_exception: Optional[BaseException] = None
_heartbeat_when: float = 0.0
_heartbeat_cb: Optional[asyncio.TimerHandle] = None
_pong_response_cb: Optional[asyncio.TimerHandle] = None
_ping_task: Optional[asyncio.Task[None]] = None

def __init__(
self,
Expand All @@ -78,30 +93,15 @@ def __init__(
) -> None:
super().__init__(status=101)
self._protocols = protocols
self._ws_protocol: Optional[str] = None
self._writer: Optional[WebSocketWriter] = None
self._reader: Optional[WebSocketDataQueue] = None
self._closed = False
self._closing = False
self._conn_lost = 0
self._close_code: Optional[int] = None
self._loop: Optional[asyncio.AbstractEventLoop] = None
self._waiting: bool = False
self._close_wait: Optional[asyncio.Future[None]] = None
self._exception: Optional[BaseException] = None
self._timeout = timeout
self._receive_timeout = receive_timeout
self._autoclose = autoclose
self._autoping = autoping
self._heartbeat = heartbeat
self._heartbeat_when = 0.0
self._heartbeat_cb: Optional[asyncio.TimerHandle] = None
if heartbeat is not None:
self._pong_heartbeat = heartbeat / 2.0
self._pong_response_cb: Optional[asyncio.TimerHandle] = None
self._compress: Union[bool, int] = compress
self._max_msg_size = max_msg_size
self._ping_task: Optional[asyncio.Task[None]] = None
self._writer_limit = writer_limit

def _cancel_heartbeat(self) -> None:
Expand Down

0 comments on commit e5dd82a

Please sign in to comment.