Skip to content

databind.json

databind.json

The #databind.json package implements the capabilities to bind JSON payloads to objects and the reverse.

JsonConverter

Bases: ClassDecoratorSetting

Use this setting to decorate a class or to annotate a type hint to inform the JSON module to use the specified convert when deserialize the type instead of any converter that would otherwise match the type.

Example:

from databind.json.settings import JsonConverter



class MyCustomConverter(Converter):
    def __init__(self, direction: Direction) -> None:
        self.direction = direction
    def convert(self, ctx: Context) -> Any:
        ...

@JsonConverter.using_classmethods(serialize="__str__", deserialize="of")
class MyCustomType:

    def __str__(self) -> str:
        ...

    @staticmethod
    def of(s: str) -> MyCustomType:
        ...

The same override can also be achieved by attaching the setting to an Annotated type hint:

Annotated[MyCustomType, JsonConverter(MyCustomConverter)]
Source code in databind/json/settings.py
class JsonConverter(ClassDecoratorSetting):
    """Use this setting to decorate a class or to annotate a type hint to inform the JSON module to use the
    specified convert when deserialize the type instead of any converter that would otherwise match the type.

    Example:

    ```py
    from databind.json.settings import JsonConverter



    class MyCustomConverter(Converter):
        def __init__(self, direction: Direction) -> None:
            self.direction = direction
        def convert(self, ctx: Context) -> Any:
            ...

    @JsonConverter.using_classmethods(serialize="__str__", deserialize="of")
    class MyCustomType:

        def __str__(self) -> str:
            ...

        @staticmethod
        def of(s: str) -> MyCustomType:
            ...
    ```

    The same override can also be achieved by attaching the setting to an `Annotated` type hint:


    ```py
    Annotated[MyCustomType, JsonConverter(MyCustomConverter)]
    ```
    """

    supplier: ConverterSupplier

    def __init__(self, supplier: t.Union[ConverterSupplier, Converter]) -> None:
        super().__init__()
        if isinstance(supplier, Converter):
            self.supplier = lambda: supplier
        else:
            self.supplier = supplier

    @staticmethod
    def using_classmethods(
        serialized_type: t.Union[t.Type[t.Any], t.Tuple[t.Type[t.Any], ...], None] = None,
        *,
        serialize: "str | None" = None,
        deserialize: "str | None" = None
    ) -> "JsonConverter":
        return JsonConverter(
            DelegateToClassmethodConverter(serialized_type, serialize=serialize, deserialize=deserialize)
        )

JsonModule

Bases: Module

The JSON module combines all converters provided by the #databind.json package in one usable module. The direction in which the converters should convert must be specified with the direction argument. Alternatively, use one of the convenience static methods #serializing() and #deserializing().

Source code in databind/json/module.py
class JsonModule(Module):
    """The JSON module combines all converters provided by the #databind.json package in one usable module. The
    direction in which the converters should convert must be specified with the *direction* argument. Alternatively,
    use one of the convenience static methods #serializing() and #deserializing()."""

    def __init__(self) -> None:
        super().__init__(__name__ + ".JsonModule")

        import pathlib
        import uuid

        from nr.date import duration

        from databind.json.converters import (
            AnyConverter,
            CollectionConverter,
            DatetimeConverter,
            DecimalConverter,
            EnumConverter,
            LiteralConverter,
            MappingConverter,
            OptionalConverter,
            PlainDatatypeConverter,
            SchemaConverter,
            StringifyConverter,
            UnionConverter,
        )

        self.register(AnyConverter())
        self.register(CollectionConverter())
        self.register(DatetimeConverter())
        self.register(DecimalConverter())
        self.register(EnumConverter())
        self.register(MappingConverter())
        self.register(OptionalConverter())
        self.register(PlainDatatypeConverter())
        self.register(UnionConverter())
        self.register(SchemaConverter())
        self.register(StringifyConverter(uuid.UUID, name="JsonModule:uuid.UUID"), first=True)

        # NOTE(NiklasRosenstein): It is important that we have the converter for `Path` appear before the converter
        #       for `PurePath` for the `issubclass()` checks in the converter to match appropriately due to Liskov
        #       substition principle (otherwise you would end up deserializing a `Path` field as a `PurePath` but
        #       then actually serialize it as a `Path` which causes an error, "expected Path, got PurePath").
        self.register(StringifyConverter(pathlib.PurePath, name="JsonModule:pathlib.PurePath"), first=True)
        self.register(StringifyConverter(pathlib.Path, name="JsonModule:pathlib.Path"), first=True)
        self.register(StringifyConverter(duration, duration.parse, name="JsonModule:nr.date.duration"), first=True)
        self.register(LiteralConverter())

        self.register(JsonConverterSupport(), first=True)
__init__
__init__() -> None
Source code in databind/json/module.py
def __init__(self) -> None:
    super().__init__(__name__ + ".JsonModule")

    import pathlib
    import uuid

    from nr.date import duration

    from databind.json.converters import (
        AnyConverter,
        CollectionConverter,
        DatetimeConverter,
        DecimalConverter,
        EnumConverter,
        LiteralConverter,
        MappingConverter,
        OptionalConverter,
        PlainDatatypeConverter,
        SchemaConverter,
        StringifyConverter,
        UnionConverter,
    )

    self.register(AnyConverter())
    self.register(CollectionConverter())
    self.register(DatetimeConverter())
    self.register(DecimalConverter())
    self.register(EnumConverter())
    self.register(MappingConverter())
    self.register(OptionalConverter())
    self.register(PlainDatatypeConverter())
    self.register(UnionConverter())
    self.register(SchemaConverter())
    self.register(StringifyConverter(uuid.UUID, name="JsonModule:uuid.UUID"), first=True)

    # NOTE(NiklasRosenstein): It is important that we have the converter for `Path` appear before the converter
    #       for `PurePath` for the `issubclass()` checks in the converter to match appropriately due to Liskov
    #       substition principle (otherwise you would end up deserializing a `Path` field as a `PurePath` but
    #       then actually serialize it as a `Path` which causes an error, "expected Path, got PurePath").
    self.register(StringifyConverter(pathlib.PurePath, name="JsonModule:pathlib.PurePath"), first=True)
    self.register(StringifyConverter(pathlib.Path, name="JsonModule:pathlib.Path"), first=True)
    self.register(StringifyConverter(duration, duration.parse, name="JsonModule:nr.date.duration"), first=True)
    self.register(LiteralConverter())

    self.register(JsonConverterSupport(), first=True)