-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added
BufferedIncrementalPacketSerializer
base class (#174)
- Loading branch information
1 parent
781739e
commit 3beb7c4
Showing
63 changed files
with
3,753 additions
and
439 deletions.
There are no files selected for viewing
Empty file.
88 changes: 88 additions & 0 deletions
88
docs/source/_include/examples/howto/serializers/buffered_incremental_serializer/example1.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
from __future__ import annotations | ||
|
||
import json | ||
from collections.abc import Generator | ||
from typing import TYPE_CHECKING, Any | ||
|
||
from easynetwork.exceptions import DeserializeError, IncrementalDeserializeError | ||
from easynetwork.serializers.abc import BufferedIncrementalPacketSerializer | ||
|
||
if TYPE_CHECKING: | ||
from _typeshed import ReadableBuffer | ||
|
||
|
||
class MyJSONSerializer(BufferedIncrementalPacketSerializer[Any, bytearray]): | ||
def __init__(self, *, ensure_ascii: bool = True) -> None: | ||
self._ensure_ascii: bool = ensure_ascii | ||
|
||
self._encoding: str | ||
if self._ensure_ascii: | ||
self._encoding = "ascii" | ||
else: | ||
self._encoding = "utf-8" | ||
|
||
def _dump(self, packet: Any) -> bytes: | ||
document = json.dumps(packet, ensure_ascii=self._ensure_ascii) | ||
return document.encode(self._encoding) | ||
|
||
def _load(self, data: bytes | bytearray) -> Any: | ||
document = data.decode(self._encoding) | ||
return json.loads(document) | ||
|
||
def serialize(self, packet: Any) -> bytes: | ||
return self._dump(packet) | ||
|
||
def deserialize(self, data: bytes) -> Any: | ||
try: | ||
return self._load(data) | ||
except (UnicodeError, json.JSONDecodeError) as exc: | ||
raise DeserializeError("JSON decode error") from exc | ||
|
||
def incremental_serialize(self, packet: Any) -> Generator[bytes, None, None]: | ||
yield self._dump(packet) + b"\r\n" | ||
|
||
def incremental_deserialize(self) -> Generator[None, bytes, tuple[Any, bytes]]: | ||
data = yield | ||
newline = b"\r\n" | ||
while (index := data.find(newline)) < 0: | ||
data += yield | ||
|
||
remainder = data[index + len(newline) :] | ||
data = data[:index] | ||
|
||
try: | ||
document = self._load(data) | ||
except (UnicodeError, json.JSONDecodeError) as exc: | ||
raise IncrementalDeserializeError("JSON decode error", remainder) from exc | ||
|
||
return document, remainder | ||
|
||
def create_deserializer_buffer(self, sizehint: int) -> bytearray: | ||
buffer_size: int = max(sizehint, 65536) | ||
return bytearray(buffer_size) | ||
|
||
def buffered_incremental_deserialize( | ||
self, | ||
buffer: bytearray, | ||
) -> Generator[int | None, int, tuple[Any, ReadableBuffer]]: | ||
buffer_size = len(buffer) | ||
newline = b"\r\n" | ||
separator_length = len(newline) | ||
|
||
nb_written_bytes: int = (yield None) | ||
|
||
while (index := buffer.find(newline, 0, nb_written_bytes)) < 0: | ||
start_idx: int = nb_written_bytes | ||
if start_idx > buffer_size - separator_length: | ||
raise IncrementalDeserializeError("Too long line", remaining_data=b"") | ||
nb_written_bytes += yield start_idx | ||
|
||
remainder: bytearray = buffer[index + separator_length : nb_written_bytes] | ||
data: bytearray = buffer[:index] | ||
|
||
try: | ||
document = self._load(data) | ||
except (UnicodeError, json.JSONDecodeError) as exc: | ||
raise IncrementalDeserializeError("JSON decode error", remainder) from exc | ||
|
||
return document, remainder |
49 changes: 49 additions & 0 deletions
49
docs/source/_include/examples/howto/serializers/buffered_incremental_serializer/example2.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
from __future__ import annotations | ||
|
||
import io | ||
from collections.abc import Generator | ||
from typing import Any | ||
|
||
from easynetwork.serializers.abc import BufferedIncrementalPacketSerializer | ||
|
||
|
||
class MySerializer(BufferedIncrementalPacketSerializer[Any, memoryview]): | ||
... | ||
|
||
# It can receive either 'bytes' from endpoint or 'memoryviews' from buffered_incremental_deserialize() | ||
def incremental_deserialize(self) -> Generator[None, bytes | memoryview, tuple[Any, bytes]]: | ||
initial_bytes = yield | ||
with io.BytesIO(initial_bytes) as buffer: | ||
while True: | ||
try: | ||
packet = self._load_from_file(buffer) | ||
except EOFError: | ||
pass | ||
else: | ||
break | ||
buffer.write((yield)) | ||
buffer.seek(0) | ||
|
||
remainder = buffer.read() | ||
return packet, remainder | ||
|
||
def _load_from_file(self, file: io.IOBase) -> Any: | ||
... | ||
|
||
def create_deserializer_buffer(self, sizehint: int) -> memoryview: | ||
# Don't care about buffer size | ||
buffer = bytearray(sizehint) | ||
return memoryview(buffer) | ||
|
||
def buffered_incremental_deserialize(self, buffer: memoryview) -> Generator[None, int, tuple[Any, bytes]]: | ||
incremental_deserialize = self.incremental_deserialize() | ||
# Start the generator | ||
next(incremental_deserialize) | ||
|
||
while True: | ||
nb_bytes_written: int = yield | ||
try: | ||
incremental_deserialize.send(buffer[:nb_bytes_written]) | ||
except StopIteration as exc: | ||
# incremental_deserialize() returned | ||
return exc.value |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
details { | ||
margin-bottom: 1rem; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.