turbo_broccoli.user

User provided encoder/decoder methods.

 1"""User provided encoder/decoder methods."""
 2
 3from typing import Any, Callable, TypeAlias
 4
 5from .context import Context
 6
 7Encoder: TypeAlias = Callable[[Any, Context], dict]
 8Decoder: TypeAlias = Callable[[dict, Context], Any]
 9ClassOrClasses: TypeAlias = (
10    type | str | list[type | str] | tuple[type | str] | set[type | str]
11)
12
13encoders: dict[str, Encoder] = {}
14decoders: dict[str, Decoder] = {}
15
16
17def register_encoder(encoder: Encoder | None, class_or_tuple: ClassOrClasses):
18    """
19    Register a custom encoder for the given type(s). An encoder is a function
20    that takes an object and a `Context` and returns a dict with the following
21    structure:
22
23    ```py
24    {
25        "__type__": "user.<a_type_name>",
26        ...
27    }
28    ```
29
30    `a_type_name` should be a name used when registering the corresponding
31    decoder.
32
33    The dict can be/contain types that are not readily JSON serializable as
34    long as they can be serialized by TurboBroccoli or by other user-provided
35    encoders.
36
37    Args:
38        encoder (Encoder | None): If `None`, the encoder is removed.
39        class_or_tuple (ClassOrClasses): See `ClassOrClasses`
40    """
41    if not isinstance(class_or_tuple, (list, tuple, set)):
42        class_or_tuple = [class_or_tuple]
43    if len(class_or_tuple) == 0:
44        raise ValueError(
45            "At least one class must be provided to register an encoder"
46        )
47    for cls in class_or_tuple:
48        name = cls if isinstance(cls, str) else cls.__name__
49        if encoder is None and name in encoders:
50            del encoders[name]
51        elif encoder is not None:
52            encoders[name] = encoder
53
54
55def register_decoder(decoder: Decoder | None, class_or_tuple: ClassOrClasses):
56    """
57    Register a custom encoder for the given type(s). An decoder is a function
58    that takes a dict and a `Context` and returns an object. The dict will have
59    the form specified in `register_encoder`. It contains data that have
60    already been deserialized by TurboBroccoli or by other user-provided
61    decoders.
62
63    Args:
64        decoder (Decoder | None): If `None`, the decoder is removed.
65        class_or_tuple (ClassOrClasses): See `ClassOrClasses`
66    """
67    if not isinstance(class_or_tuple, (list, tuple, set)):
68        class_or_tuple = [class_or_tuple]
69    if len(class_or_tuple) == 0:
70        raise ValueError(
71            "At least one class must be provided to register a decoder"
72        )
73    for cls in class_or_tuple:
74        name = cls if isinstance(cls, str) else cls.__name__
75        if decoder is None and name in decoders:
76            del decoders[name]
77        elif decoder is not None:
78            decoders[name] = decoder
Encoder: TypeAlias = Callable[[Any, turbo_broccoli.context.Context], dict]
Decoder: TypeAlias = Callable[[dict, turbo_broccoli.context.Context], Any]
ClassOrClasses: TypeAlias = type | str | list[type | str] | tuple[type | str] | set[type | str]
encoders: dict[str, typing.Callable[[typing.Any, turbo_broccoli.context.Context], dict]] = {}
decoders: dict[str, typing.Callable[[dict, turbo_broccoli.context.Context], typing.Any]] = {}
def register_encoder( encoder: Optional[Callable[[Any, turbo_broccoli.context.Context], dict]], class_or_tuple: type | str | list[type | str] | tuple[type | str] | set[type | str]):
18def register_encoder(encoder: Encoder | None, class_or_tuple: ClassOrClasses):
19    """
20    Register a custom encoder for the given type(s). An encoder is a function
21    that takes an object and a `Context` and returns a dict with the following
22    structure:
23
24    ```py
25    {
26        "__type__": "user.<a_type_name>",
27        ...
28    }
29    ```
30
31    `a_type_name` should be a name used when registering the corresponding
32    decoder.
33
34    The dict can be/contain types that are not readily JSON serializable as
35    long as they can be serialized by TurboBroccoli or by other user-provided
36    encoders.
37
38    Args:
39        encoder (Encoder | None): If `None`, the encoder is removed.
40        class_or_tuple (ClassOrClasses): See `ClassOrClasses`
41    """
42    if not isinstance(class_or_tuple, (list, tuple, set)):
43        class_or_tuple = [class_or_tuple]
44    if len(class_or_tuple) == 0:
45        raise ValueError(
46            "At least one class must be provided to register an encoder"
47        )
48    for cls in class_or_tuple:
49        name = cls if isinstance(cls, str) else cls.__name__
50        if encoder is None and name in encoders:
51            del encoders[name]
52        elif encoder is not None:
53            encoders[name] = encoder

Register a custom encoder for the given type(s). An encoder is a function that takes an object and a Context and returns a dict with the following structure:

{
    "__type__": "user.<a_type_name>",
    ...
}

a_type_name should be a name used when registering the corresponding decoder.

The dict can be/contain types that are not readily JSON serializable as long as they can be serialized by TurboBroccoli or by other user-provided encoders.

Args: encoder (Encoder | None): If None, the encoder is removed. class_or_tuple (ClassOrClasses): See ClassOrClasses

def register_decoder( decoder: Optional[Callable[[dict, turbo_broccoli.context.Context], Any]], class_or_tuple: type | str | list[type | str] | tuple[type | str] | set[type | str]):
56def register_decoder(decoder: Decoder | None, class_or_tuple: ClassOrClasses):
57    """
58    Register a custom encoder for the given type(s). An decoder is a function
59    that takes a dict and a `Context` and returns an object. The dict will have
60    the form specified in `register_encoder`. It contains data that have
61    already been deserialized by TurboBroccoli or by other user-provided
62    decoders.
63
64    Args:
65        decoder (Decoder | None): If `None`, the decoder is removed.
66        class_or_tuple (ClassOrClasses): See `ClassOrClasses`
67    """
68    if not isinstance(class_or_tuple, (list, tuple, set)):
69        class_or_tuple = [class_or_tuple]
70    if len(class_or_tuple) == 0:
71        raise ValueError(
72            "At least one class must be provided to register a decoder"
73        )
74    for cls in class_or_tuple:
75        name = cls if isinstance(cls, str) else cls.__name__
76        if decoder is None and name in decoders:
77            del decoders[name]
78        elif decoder is not None:
79            decoders[name] = decoder

Register a custom encoder for the given type(s). An decoder is a function that takes a dict and a Context and returns an object. The dict will have the form specified in register_encoder. It contains data that have already been deserialized by TurboBroccoli or by other user-provided decoders.

Args: decoder (Decoder | None): If None, the decoder is removed. class_or_tuple (ClassOrClasses): See ClassOrClasses