Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add slots to dataclasses with Python 3.10+ #9413

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES/9413.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Reduced memory required many small objects by adding ``__slots__`` to dataclasses -- by :user:`bdraco`.
3 changes: 2 additions & 1 deletion aiohttp/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
BasicAuth,
TimeoutHandle,
ceil_timeout,
frozen_dataclass_decorator,
get_env_proxy_for_url,
method_must_be_empty_body,
sentinel,
Expand Down Expand Up @@ -191,7 +192,7 @@ class _RequestOptions(TypedDict, total=False):
max_field_size: Union[int, None]


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class ClientTimeout:
total: Optional[float] = None
connect: Optional[float] = None
Expand Down
6 changes: 3 additions & 3 deletions aiohttp/client_reqrep.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import asyncio
import codecs
import contextlib
import dataclasses
import functools
import io
import re
Expand Down Expand Up @@ -49,6 +48,7 @@
HeadersMixin,
TimerNoop,
basicauth_from_netrc,
frozen_dataclass_decorator,
is_expected_content_type,
netrc_from_env,
parse_mimetype,
Expand Down Expand Up @@ -98,14 +98,14 @@ def _gen_default_accept_encoding() -> str:
return "gzip, deflate, br" if HAS_BROTLI else "gzip, deflate"


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class ContentDisposition:
type: Optional[str]
parameters: "MappingProxyType[str, str]"
filename: Optional[str]


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class RequestInfo:
url: URL
method: str
Expand Down
5 changes: 2 additions & 3 deletions aiohttp/client_ws.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
"""WebSocket client for asyncio."""

import asyncio
import dataclasses
import sys
from types import TracebackType
from typing import Any, Final, Optional, Type, cast

from .client_exceptions import ClientError, ServerTimeoutError
from .client_reqrep import ClientResponse
from .helpers import calculate_timeout_when, set_result
from .helpers import calculate_timeout_when, frozen_dataclass_decorator, set_result
from .http import (
WS_CLOSED_MESSAGE,
WS_CLOSING_MESSAGE,
Expand All @@ -32,7 +31,7 @@
import async_timeout


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class ClientWSTimeout:
ws_receive: Optional[float] = None
ws_close: Optional[float] = None
Expand Down
18 changes: 14 additions & 4 deletions aiohttp/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from pathlib import Path
from types import TracebackType
from typing import (
TYPE_CHECKING,
Any,
Callable,
ContextManager,
Expand Down Expand Up @@ -60,7 +61,16 @@
else:
import async_timeout

__all__ = ("BasicAuth", "ChainMapProxy", "ETag")
if TYPE_CHECKING:
from dataclasses import dataclass as frozen_dataclass_decorator
elif sys.version_info < (3, 10):
frozen_dataclass_decorator = functools.partial(dataclasses.dataclass, frozen=True)
else:
frozen_dataclass_decorator = functools.partial(
dataclasses.dataclass, frozen=True, slots=True
)

__all__ = ("BasicAuth", "ChainMapProxy", "ETag", "frozen_dataclass_decorator")

PY_310 = sys.version_info >= (3, 10)

Expand Down Expand Up @@ -227,7 +237,7 @@ def netrc_from_env() -> Optional[netrc.netrc]:
return None


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class ProxyInfo:
proxy: URL
proxy_auth: Optional[BasicAuth]
Expand Down Expand Up @@ -302,7 +312,7 @@ def get_env_proxy_for_url(url: URL) -> Tuple[URL, Optional[BasicAuth]]:
return proxy_info.proxy, proxy_info.proxy_auth


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class MimeType:
type: str
subtype: str
Expand Down Expand Up @@ -1072,7 +1082,7 @@ def populate_with_cookies(headers: "CIMultiDict[str]", cookies: SimpleCookie) ->
ETAG_ANY = "*"


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class ETag:
value: str
is_weak: bool = False
Expand Down
34 changes: 17 additions & 17 deletions aiohttp/tracing.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import dataclasses
from types import SimpleNamespace
from typing import TYPE_CHECKING, Any, Awaitable, Generic, Protocol, TypeVar, overload

Expand All @@ -7,6 +6,7 @@
from yarl import URL

from .client_reqrep import ClientResponse
from .helpers import frozen_dataclass_decorator

if TYPE_CHECKING:
from .client import ClientSession
Expand Down Expand Up @@ -221,7 +221,7 @@ def on_request_headers_sent(
return self._on_request_headers_sent


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceRequestStartParams:
"""Parameters sent by the `on_request_start` signal"""

Expand All @@ -230,7 +230,7 @@ class TraceRequestStartParams:
headers: "CIMultiDict[str]"


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceRequestChunkSentParams:
"""Parameters sent by the `on_request_chunk_sent` signal"""

Expand All @@ -239,7 +239,7 @@ class TraceRequestChunkSentParams:
chunk: bytes


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceResponseChunkReceivedParams:
"""Parameters sent by the `on_response_chunk_received` signal"""

Expand All @@ -248,7 +248,7 @@ class TraceResponseChunkReceivedParams:
chunk: bytes


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceRequestEndParams:
"""Parameters sent by the `on_request_end` signal"""

Expand All @@ -258,7 +258,7 @@ class TraceRequestEndParams:
response: ClientResponse


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceRequestExceptionParams:
"""Parameters sent by the `on_request_exception` signal"""

Expand All @@ -268,7 +268,7 @@ class TraceRequestExceptionParams:
exception: BaseException


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceRequestRedirectParams:
"""Parameters sent by the `on_request_redirect` signal"""

Expand All @@ -278,60 +278,60 @@ class TraceRequestRedirectParams:
response: ClientResponse


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceConnectionQueuedStartParams:
"""Parameters sent by the `on_connection_queued_start` signal"""


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceConnectionQueuedEndParams:
"""Parameters sent by the `on_connection_queued_end` signal"""


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceConnectionCreateStartParams:
"""Parameters sent by the `on_connection_create_start` signal"""


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceConnectionCreateEndParams:
"""Parameters sent by the `on_connection_create_end` signal"""


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceConnectionReuseconnParams:
"""Parameters sent by the `on_connection_reuseconn` signal"""


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceDnsResolveHostStartParams:
"""Parameters sent by the `on_dns_resolvehost_start` signal"""

host: str


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceDnsResolveHostEndParams:
"""Parameters sent by the `on_dns_resolvehost_end` signal"""

host: str


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceDnsCacheHitParams:
"""Parameters sent by the `on_dns_cache_hit` signal"""

host: str


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceDnsCacheMissParams:
"""Parameters sent by the `on_dns_cache_miss` signal"""

host: str


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class TraceRequestHeadersSentParams:
"""Parameters sent by the `on_request_headers_sent` signal"""

Expand Down
5 changes: 2 additions & 3 deletions aiohttp/web_protocol.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import asyncio
import asyncio.streams
import dataclasses
import sys
import traceback
from collections import deque
Expand Down Expand Up @@ -28,7 +27,7 @@

from .abc import AbstractAccessLogger, AbstractAsyncAccessLogger, AbstractStreamWriter
from .base_protocol import BaseProtocol
from .helpers import ceil_timeout
from .helpers import ceil_timeout, frozen_dataclass_decorator
from .http import (
HttpProcessingError,
HttpRequestParser,
Expand Down Expand Up @@ -109,7 +108,7 @@ async def log(
self.access_logger.log(request, response, self._loop.time() - request_start)


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class _ErrInfo:
status: int
exc: BaseException
Expand Down
4 changes: 2 additions & 2 deletions aiohttp/web_request.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import asyncio
import dataclasses
import datetime
import io
import re
Expand Down Expand Up @@ -38,6 +37,7 @@
ChainMapProxy,
ETag,
HeadersMixin,
frozen_dataclass_decorator,
is_expected_content_type,
parse_http_date,
reify,
Expand Down Expand Up @@ -76,7 +76,7 @@
from .web_urldispatcher import UrlMappingMatchInfo


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class FileField:
name: str
filename: str
Expand Down
10 changes: 7 additions & 3 deletions aiohttp/web_ws.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import asyncio
import base64
import binascii
import dataclasses
import hashlib
import json
import sys
Expand All @@ -11,7 +10,12 @@

from . import hdrs
from .abc import AbstractStreamWriter
from .helpers import calculate_timeout_when, set_exception, set_result
from .helpers import (
calculate_timeout_when,
frozen_dataclass_decorator,
set_exception,
set_result,
)
from .http import (
WS_CLOSED_MESSAGE,
WS_CLOSING_MESSAGE,
Expand Down Expand Up @@ -46,7 +50,7 @@
THRESHOLD_CONNLOST_ACCESS: Final[int] = 5


@dataclasses.dataclass(frozen=True)
@frozen_dataclass_decorator
class WebSocketReady:
ok: bool
protocol: Optional[str]
Expand Down
Loading