Skip to content

Commit

Permalink
Replace Serializer class with simple parameterized type alias and fix…
Browse files Browse the repository at this point in the history
… documentation
  • Loading branch information
skloibi committed Dec 1, 2023
1 parent 23f652c commit e5859e4
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 38 deletions.
33 changes: 10 additions & 23 deletions src/tex_paper_toolkit/serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@
"""

from abc import abstractmethod, ABCMeta
from typing import Generic, TypeVar, Optional, Union
from typing import Callable, Generic, TypeVar, Optional, Union
from pathlib import Path

T = TypeVar("T")

SerTarget = Union[str, Path, "Serializer"]
"""
By default, we can either specify a string or Path path or define a custom
serialization handler.
"""
SerTarget = Union[str, Path, "Serializer"]


class Serializable(Generic[T], metaclass=ABCMeta):
"""
Expand Down Expand Up @@ -61,7 +60,7 @@ def get_path_or_default(self, default_path: Path) -> "Path | Serializer":
return target
if isinstance(target, str):
return Path(target)
if isinstance(target, Serializer):
if target is not None:
return target

assert target is None, f"Unexpected target {target}"
Expand Down Expand Up @@ -103,27 +102,15 @@ def id(self) -> str:
str
A (ideally) unique string representing this `Serializable`
"""
return f"{type(self)}:{self.key}"
return f"{type(self).__name__}:{self.key}"


S = TypeVar("S", bound=Serializable)


# pylint: disable=too-few-public-methods
class Serializer(Generic[S], metaclass=ABCMeta):
"""
A base class for custom serializers that can be provided to `Serializable`s.
This is an alternative to default serialization which simply writes the
strings to a file.
"""

@abstractmethod
def serialize(self, serializable: S) -> None:
"""
Serializes the given `Serializable`.
Parameters
----------
serializable : S
The target that should be serialized
"""
Serializer = Callable[[S], None]
"""
A base type for custom serializers that can be provided to `Serializable`s.
This is an alternative to default serialization which simply writes the
strings to a file.
"""
8 changes: 4 additions & 4 deletions src/tex_paper_toolkit/toolkit.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from typing import Self
from pathlib import Path
from abc import ABCMeta
from tex_paper_toolkit.serialization import Serializable, Serializer
from tex_paper_toolkit.serialization import Serializable
from tex_paper_toolkit.mixins import AnyStringMixin, NewCommandMixin, ToolkitMixin


Expand Down Expand Up @@ -46,10 +46,10 @@ def serialize(self, to_file: str | Path) -> None:

for target in self._targets.values():
ser_target = target.get_path_or_default(path)
if isinstance(ser_target, Serializer):
ser_target.serialize(target)
else:
if isinstance(ser_target, Path):
target_locations[ser_target].append(target)
else:
ser_target(target)

for path, entries in target_locations.items():
with open(path, "w", encoding="UTF-8") as outfile:
Expand Down
47 changes: 36 additions & 11 deletions tests/test_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,23 @@
# pylint: disable=too-few-public-methods

from pathlib import Path
from typing import Callable, Optional
from typing import Callable, Optional, TypeVar

from tex_paper_toolkit import SerTarget, Serializable, Serializer


class CustomSerializable(Serializable[str]):
def __init__(self, key: str, target: Optional[SerTarget], action: Callable) -> None:
def __init__(
self,
key: str,
target: Optional[SerTarget],
action: Callable[["CustomSerializable"], str],
) -> None:
super().__init__(key, target)
self.__action = action

def serialize(self):
self.__action(self)
def serialize(self) -> str:
return self.__action(self)


class NopSerializable(Serializable[str]):
Expand All @@ -26,23 +31,43 @@ def serialize(self) -> str:
return self.key


class CustomSerializer(Serializer[NopSerializable]):
def __init__(self, action: Callable) -> None:
super().__init__()
self.__action = action
T = TypeVar("T", bound=Serializable)

def serialize(self, serializable: NopSerializable):
return self.__action(serializable)

def create_printer(action: Callable[[T], str]) -> Serializer[T]:
return lambda serializable: print(action(serializable))


def test_get_path_or_default():
default_path = Path("/tmp/default_file")
t0 = "str_target"
t1 = Path("/tmp/test_file")
t2 = CustomSerializer(lambda s: s.key)
t2 = create_printer(lambda s: s.key)
assert (
NopSerializable("key", None).get_path_or_default(default_path) == default_path
)
assert NopSerializable("key", t0).get_path_or_default(default_path) == Path(t0)
assert NopSerializable("key", t1).get_path_or_default(default_path) == t1
assert NopSerializable("key", t2).get_path_or_default(default_path) == t2


def test_key():
target = create_printer(lambda s: s.key)
s1 = CustomSerializable("mykey", None, target)
s2 = NopSerializable("mykey")
s3 = CustomSerializable("anotherkey", None, target)
s4 = NopSerializable("ID01233")
assert s1.key == "mykey"
assert s2.key == "mykey"
assert s3.key == "anotherkey"
assert s4.key == "ID01233"


def test_id():
target = create_printer(lambda s: s.key)
s1 = CustomSerializable("mykey", None, target)
s2 = NopSerializable("mykey")
s3 = CustomSerializable("anotherkey", None, target)
assert s1.id == "CustomSerializable:mykey"
assert s2.id == "NopSerializable:mykey"
assert s3.id == "CustomSerializable:anotherkey"

0 comments on commit e5859e4

Please sign in to comment.