Skip to content

Commit 05dfbc0

Browse files
committed
OPT: add __slots__ to more dataclasses ⚡️
1 parent a968ea3 commit 05dfbc0

File tree

4 files changed

+19
-18
lines changed

4 files changed

+19
-18
lines changed

combadge/core/markers/method.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
from __future__ import annotations
22

33
from abc import ABC
4+
from dataclasses import dataclass
45
from inspect import BoundArguments
56
from typing import Any, Callable, Generic
67

78
# noinspection PyUnresolvedReferences
89
from typing_extensions import override
910

11+
from combadge._helpers.dataclasses import SLOTS
1012
from combadge.core.typevars import BackendRequestT, FunctionT
1113

1214

15+
@dataclass(**SLOTS)
1316
class MethodMarker(ABC, Generic[BackendRequestT, FunctionT]):
1417
"""Method marker that modifies an entire request based on all the call arguments."""
1518

16-
__slots__ = ()
17-
1819
def mark(self, what: FunctionT) -> FunctionT:
1920
"""
2021
Mark the function with itself.
@@ -58,15 +59,13 @@ def ensure_markers(in_: Any) -> list[MethodMarker]:
5859
return marks
5960

6061

62+
@dataclass(**SLOTS)
6163
class WrapWith(Generic[FunctionT], MethodMarker[Any, FunctionT]): # noqa: D101
62-
__slots__ = ("_decorator",)
63-
64-
def __init__(self, decorator: Callable[[FunctionT], FunctionT]) -> None: # noqa: D107
65-
self._decorator = decorator
64+
decorator: Callable[[FunctionT], FunctionT]
6665

6766
@override
6867
def wrap(self, what: FunctionT) -> FunctionT: # noqa: D102
69-
return self._decorator(what)
68+
return self.decorator(what)
7069

7170

7271
def wrap_with(decorator: Callable[[Any], Any]) -> Callable[[FunctionT], FunctionT]:
@@ -77,5 +76,10 @@ def wrap_with(decorator: Callable[[Any], Any]) -> Callable[[FunctionT], Function
7776
>>> @wrap_with(functools.cache)
7877
>>> def service_method(self, ...) -> ...:
7978
>>> ...
79+
80+
Question: Why can I not just use a decorator directly?
81+
The decorator needs to wrap a method **implementation** and a service definition is just an **interface**.
82+
If you put it directly onto an abstract method, it would wrap only this abstract method,
83+
but **not** the actual implementation which is produced by [binding][binding].
8084
"""
8185
return WrapWith(decorator).mark

combadge/core/markers/parameter.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
from __future__ import annotations
22

33
from abc import ABC, abstractmethod
4+
from dataclasses import dataclass
45
from typing import Any, Generic
56

7+
from combadge._helpers.dataclasses import SLOTS
68
from combadge.core.markers.base import AnnotatedMarker
79
from combadge.core.typevars import BackendRequestT
810

911

12+
@dataclass(**SLOTS)
1013
class ParameterMarker(AnnotatedMarker, Generic[BackendRequestT], ABC):
1114
"""Parameter marker: it modifies a request with a call-time argument."""
1215

13-
__slots__ = ()
14-
1516
@abstractmethod
1617
def __call__(self, request: BackendRequestT, value: Any) -> None:
1718
"""Update the request according to the marker and the actual argument."""

combadge/core/markers/response.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,35 @@
77
# noinspection PyUnresolvedReferences
88
from typing_extensions import override
99

10+
from combadge._helpers.dataclasses import SLOTS
1011
from combadge.core.markers.base import AnnotatedMarker
1112

1213
_InputPayloadT = TypeVar("_InputPayloadT")
1314
_OutputPayloadT = TypeVar("_OutputPayloadT")
1415

1516

17+
@dataclass(**SLOTS)
1618
class ResponseMarker(AnnotatedMarker, ABC):
1719
"""Response marker: it transforms or contructs a response."""
1820

19-
__slots__ = ()
20-
2121
@abstractmethod
2222
def __call__(self, response: Any, payload: Any) -> Any:
2323
"""Transform the response."""
2424

2525

26-
@dataclass
26+
@dataclass(**SLOTS)
2727
class Map(ResponseMarker):
2828
"""Map a payload to a dictionary under the specified key."""
2929

3030
key: Any
3131
"""Key under which the response will be mapped."""
3232

33-
__slots__ = ("key",)
34-
3533
@override
3634
def __call__(self, response: Any, payload: Any) -> Dict[Any, Any]: # noqa: D102
3735
return {self.key: payload}
3836

3937

40-
@dataclass
38+
@dataclass(**SLOTS)
4139
class Extract(ResponseMarker):
4240
"""
4341
Extract a value from the specified key.
@@ -54,8 +52,6 @@ class Extract(ResponseMarker):
5452
key: Any
5553
"""Key which will be extracted from the payload."""
5654

57-
__slots__ = ("key",)
58-
5955
@override
6056
def __call__(self, response: Any, payload: Mapping[Any, Any]) -> Any: # noqa: D102
6157
return payload[self.key]

combadge/support/http/markers/request.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ def __call__(self, request: ContainsHeaders, value: Any) -> None: # noqa: D102
4242
request.headers.append((self.name, value))
4343

4444

45+
@dataclass(init=False, **SLOTS)
4546
class Path(Generic[FunctionT], MethodMarker[ContainsUrlPath, FunctionT]): # noqa: D101
4647
_factory: Callable[[BoundArguments], str]
47-
__slots__ = ("_factory",)
4848

4949
def __init__(self, path_or_factory: str | Callable[[BoundArguments], str]) -> None: # noqa: D107
5050
if callable(path_or_factory):

0 commit comments

Comments
 (0)