Skip to content

Commit

Permalink
Add mapping support in Encoder and Decoder
Browse files Browse the repository at this point in the history
  • Loading branch information
dkraczkowski committed Nov 8, 2023
1 parent beb4817 commit 102d56a
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 12 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,15 @@ assert encoded == {
}
```

Alternatively you can set mapper in `Encoder` and `Decoder` classes:

```python
encoder = Encoder[Pet](mapper=mapper)

pet = Pet("Max", 3, ["cute", "furry"])
encoded = encoder.encode(pet)
```

## Error handling
The library raises errors if an invalid type is passed to the Encoder or Decoder, or if an invalid dictionary is passed to the Decoder.

Expand Down
10 changes: 5 additions & 5 deletions chili/decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,9 +536,10 @@ class Decoder(Generic[T]):
__generic__: Type[T]
_decoders: Dict[str, TypeDecoder]

def __init__(self, decoders: Union[TypeDecoders, Dict[Any, TypeDecoder]] = None):
def __init__(self, decoders: Union[TypeDecoders, Dict[Any, TypeDecoder]] = None, mapper: Optional[Mapper] = None):
if decoders and not isinstance(decoders, TypeDecoders):
decoders = TypeDecoders(decoders)
self.mapper = mapper
self.type_decoders = decoders

@property
Expand All @@ -554,6 +555,8 @@ def decode(self, obj: Dict[str, StateObject]) -> T:
if hasattr(self.__generic__, _DECODE_MAPPER):
mapper = getattr(self.__generic__, _DECODE_MAPPER)
obj = mapper.map(obj)
elif self.mapper:
obj = self.mapper.map(obj)

for key, prop in self.schema.items():
if key not in obj:
Expand Down Expand Up @@ -600,10 +603,7 @@ def __class_getitem__(cls, item: Type) -> Type[Decoder]: # noqa: E501


def decode(
obj: StateObject,
a_type: Type[T],
decoders: Union[TypeDecoders, Dict[Any, TypeDecoder]] = None,
force: bool = False
obj: StateObject, a_type: Type[T], decoders: Union[TypeDecoders, Dict[Any, TypeDecoder]] = None, force: bool = False
) -> T:
if decoders and not isinstance(decoders, TypeDecoders):
decoders = TypeDecoders(decoders)
Expand Down
6 changes: 4 additions & 2 deletions chili/encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,10 +443,10 @@ class Encoder(Generic[T]):
__generic__: Type[T]
_encoders: Dict[str, TypeEncoder]

def __init__(self, encoders: Union[Dict, TypeEncoders] = None):
def __init__(self, encoders: Union[Dict, TypeEncoders] = None, mapper: Optional[Mapper] = None):
if encoders and not isinstance(encoders, TypeEncoders):
encoders = TypeEncoders(encoders)

self.mapper = mapper
self.type_encoders = encoders

def encode(self, obj: T) -> StateObject:
Expand All @@ -466,6 +466,8 @@ def encode(self, obj: T) -> StateObject:
if hasattr(self.__generic__, _ENCODE_MAPPER):
mapper = getattr(self.__generic__, _ENCODE_MAPPER)
return mapper.map(result)
elif self.mapper:
return self.mapper.map(result)

return result

Expand Down
34 changes: 33 additions & 1 deletion tests/test_decoder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from chili import Decoder, decodable
from chili import Decoder, Mapper, decodable


def test_can_instantiate() -> None:
Expand All @@ -13,3 +13,35 @@ class Example:
# then
assert isinstance(instance, Decoder)
assert instance.__generic__ == Example


def test_dencode_and_map() -> None:
# given
class Example:
name: str
age: int

def __init__(self, name: str, age: int):
self.name = name
self.age = age

mapper = Mapper(
{
"name": "_name",
"age": "_age",
}
)
encoder = Decoder[Example](mapper=mapper)

# when
data = encoder.decode(
{
"_name": "Bobik",
"_age": 11,
}
)

# then
assert isinstance(data, Example)
assert data.name == "Bobik"
assert data.age == 11
33 changes: 29 additions & 4 deletions tests/test_encoder.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from collections import UserString

import pytest

from chili import Encoder, encodable
from chili.error import EncoderError
from chili import Encoder, Mapper, encodable


def test_can_instantiate() -> None:
Expand Down Expand Up @@ -63,3 +60,31 @@ def __init__(self, name: ExampleName, age: int):
"name": "bob",
"age": 33,
}


def test_encode_and_map() -> None:
# given
class Example:
name: str
age: int

def __init__(self, name: str, age: int):
self.name = name
self.age = age

mapper = Mapper(
{
"_name": "name",
"_age": "age",
}
)
encoder = Encoder[Example](mapper=mapper)

# when
data = encoder.encode(Example("Bobik", 11))

# then
assert data == {
"_name": "Bobik",
"_age": 11,
}

0 comments on commit 102d56a

Please sign in to comment.