Skip to content

Commit 5f0ea5d

Browse files
committed
feat: use protocol instead of abc
1 parent b3e8443 commit 5f0ea5d

5 files changed

Lines changed: 21 additions & 39 deletions

File tree

src/duron/codec.py

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

3-
from abc import ABC, abstractmethod
4-
from typing import TYPE_CHECKING, TypeAlias, TypeGuard, cast
3+
from abc import abstractmethod
4+
from typing import TYPE_CHECKING, Protocol, TypeAlias, TypeGuard, cast
55
from typing_extensions import (
66
Any,
77
TypeAliasType,
@@ -35,7 +35,7 @@ def is_json_value(x: object) -> TypeGuard[JSONValue]:
3535
return False
3636

3737

38-
class Codec(ABC):
38+
class Codec(Protocol):
3939
__slots__: tuple[str, ...] = ()
4040

4141
@abstractmethod

src/duron/contrib/codecs.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,23 @@
33
import binascii
44
import pickle # noqa: S403
55
from typing import TYPE_CHECKING
6-
from typing_extensions import Any, final, override
7-
8-
from duron.codec import Codec
6+
from typing_extensions import Any, final
97

108
if TYPE_CHECKING:
119
from duron.codec import JSONValue
1210
from duron.typing import TypeHint
1311

1412

1513
@final
16-
class PickleCodec(Codec):
14+
class PickleCodec:
1715
__slots__ = ()
1816

19-
@override
20-
def encode_json(self, result: object) -> str:
17+
@staticmethod
18+
def encode_json(result: object) -> str:
2119
return binascii.b2a_base64(pickle.dumps(result), newline=False).decode()
2220

23-
@override
24-
def decode_json(self, encoded: JSONValue, _expected_type: TypeHint[Any]) -> object:
21+
@staticmethod
22+
def decode_json(encoded: JSONValue, _expected_type: TypeHint[Any]) -> object:
2523
if not isinstance(encoded, str):
2624
msg = f"Expected a string, got {type(encoded).__name__}"
2725
raise TypeError(msg)

src/duron/contrib/storage.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
import uuid
66
from pathlib import Path
77
from typing import TYPE_CHECKING, cast, final
8-
from typing_extensions import override
9-
10-
from duron.log import LogStorage
118

129
if TYPE_CHECKING:
1310
from collections.abc import AsyncGenerator
@@ -16,7 +13,7 @@
1613

1714

1815
@final
19-
class FileLogStorage(LogStorage):
16+
class FileLogStorage:
2017
__slots__ = ("_leases", "_lock", "_log_file")
2118

2219
_log_file: Path
@@ -29,7 +26,6 @@ def __init__(self, log_file: str | Path) -> None:
2926
self._leases = None
3027
self._lock = asyncio.Lock()
3128

32-
@override
3329
async def stream(
3430
self,
3531
start: int | None,
@@ -82,20 +78,17 @@ async def stream(
8278
else:
8379
await asyncio.sleep(0.1)
8480

85-
@override
8681
async def acquire_lease(self) -> bytes:
8782
lease_id = uuid.uuid4().bytes
8883
async with self._lock:
8984
self._leases = lease_id
9085
return lease_id
9186

92-
@override
9387
async def release_lease(self, token: bytes) -> None:
9488
async with self._lock:
9589
if token == self._leases:
9690
self._leases = None
9791

98-
@override
9992
async def append(self, token: bytes, entry: Entry) -> int:
10093
async with self._lock:
10194
if token != self._leases:
@@ -108,13 +101,12 @@ async def append(self, token: bytes, entry: Entry) -> int:
108101
_ = f.write("\n")
109102
return offset
110103

111-
@override
112-
async def flush(self, token: bytes) -> None:
104+
async def flush(self, _token: bytes) -> None:
113105
pass
114106

115107

116108
@final
117-
class MemoryLogStorage(LogStorage):
109+
class MemoryLogStorage:
118110
__slots__ = ("_condition", "_entries", "_leases", "_lock")
119111

120112
_entries: list[AnyEntry]
@@ -128,7 +120,6 @@ def __init__(self, entries: list[AnyEntry] | None = None) -> None:
128120
self._lock = asyncio.Lock()
129121
self._condition = asyncio.Condition(self._lock)
130122

131-
@override
132123
async def stream(
133124
self,
134125
start: int | None,
@@ -166,20 +157,17 @@ async def stream(
166157
)
167158
last_seen_index = index
168159

169-
@override
170160
async def acquire_lease(self) -> bytes:
171161
lease_id = uuid.uuid4().bytes
172162
async with self._lock:
173163
self._leases = lease_id
174164
return lease_id
175165

176-
@override
177166
async def release_lease(self, token: bytes) -> None:
178167
async with self._lock:
179168
if token == self._leases:
180169
self._leases = None
181170

182-
@override
183171
async def append(self, token: bytes, entry: Entry) -> int:
184172
async with self._condition:
185173
if token != self._leases:
@@ -191,7 +179,6 @@ async def append(self, token: bytes, entry: Entry) -> int:
191179
self._condition.notify_all()
192180
return offset
193181

194-
@override
195182
async def flush(self, token: bytes) -> None:
196183
pass
197184

src/duron/log.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
import binascii
44
import os
5-
from abc import ABC, abstractmethod
5+
from abc import abstractmethod
66
from hashlib import blake2b
7-
from typing import TYPE_CHECKING, Literal
7+
from typing import TYPE_CHECKING, Literal, Protocol
88
from typing_extensions import NotRequired, TypedDict
99

1010
from duron.codec import JSONValue
@@ -84,7 +84,7 @@ def is_entry(entry: Entry | AnyEntry) -> TypeGuard[Entry]:
8484
}
8585

8686

87-
class LogStorage(ABC):
87+
class LogStorage(Protocol):
8888
__slots__: tuple[str, ...] = ()
8989

9090
@abstractmethod

tests/test_pydantic.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
from __future__ import annotations
22

33
from typing import TYPE_CHECKING, cast
4-
from typing_extensions import Any, override
4+
from typing_extensions import Any
55

66
import pydantic
77
import pytest
88

99
from duron import Context, fn
10-
from duron.codec import Codec
1110
from duron.contrib.storage import MemoryLogStorage
1211

1312
if TYPE_CHECKING:
@@ -22,18 +21,16 @@ class PydanticPoint(pydantic.BaseModel):
2221

2322
@pytest.mark.asyncio
2423
async def test_pydantic_serialize() -> None:
25-
class PydanticCodec(Codec):
26-
@override
27-
def encode_json(self, result: object) -> JSONValue:
24+
class PydanticCodec:
25+
@staticmethod
26+
def encode_json(result: object) -> JSONValue:
2827
return cast(
2928
"JSONValue",
3029
pydantic.TypeAdapter(type(result)).dump_python(result, mode="json"),
3130
)
3231

33-
@override
34-
def decode_json(
35-
self, encoded: JSONValue, expected_type: TypeHint[Any]
36-
) -> object:
32+
@staticmethod
33+
def decode_json(encoded: JSONValue, expected_type: TypeHint[Any]) -> object:
3734
return cast(
3835
"object", pydantic.TypeAdapter(expected_type).validate_python(encoded)
3936
)

0 commit comments

Comments
 (0)