Source code for flask_resources.serializers.base
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020-2023 CERN.
# Copyright (C) 2020-2021 Northwestern University.
#
# Flask-Resources is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
"""Serializers required interfaces."""
from abc import ABC, abstractmethod
from marshmallow import Schema, post_dump, pre_dump
[docs]class BaseSerializer(ABC):
"""Serializer Interface."""
[docs] @abstractmethod
def serialize_object(self, obj):
"""Serialize a single object according to the response ctx."""
pass
[docs] def serialize_object_list(self, obj_list):
"""Serialize a list of objects according to the response ctx."""
pass
[docs]class MarshmallowSerializer(BaseSerializer):
"""Marshmallow serializer that serializes an obj into defined schema.
:param format_serializer_cls: Serializer in charge of converting the data object into
the desired format.
:param object_schema_cls: Marshmallow Schema of the object.
:param list_schema_cls: Marshmallow Schema of the object list.
:param schema_context: Context of the Marshmallow Schema.
:param schema_kwargs: Additional arguments to be passed to marshmallow schema.
"""
def __init__(
self,
format_serializer_cls,
object_schema_cls,
list_schema_cls=None,
schema_context=None,
schema_kwargs=None,
**serializer_options
):
"""Initialize the serializer."""
self.schema_context = schema_context or {}
schema_kwargs = schema_kwargs or {}
self.format_serializer = format_serializer_cls(**serializer_options)
self.object_schema = object_schema_cls(context=schema_context, **schema_kwargs)
if list_schema_cls:
self.list_schema = list_schema_cls(
context={
"object_schema_cls": object_schema_cls,
**self.schema_context,
}
)
else:
self.list_schema = None
[docs] def dump_obj(self, obj):
"""Dump the object using object schema class."""
return self.object_schema.dump(obj)
[docs] def dump_list(self, obj_list):
"""Dump the list of objects."""
if not self.list_schema:
return self.object_schema.dump(obj_list, many=True)
return self.list_schema.dump(obj_list)
[docs] def serialize_object(self, obj):
"""Dump the object using the serializer."""
return self.format_serializer.serialize_object(self.dump_obj(obj))
[docs] def serialize_object_list(self, obj_list):
"""Dump the object list using the serializer."""
return self.format_serializer.serialize_object_list(self.dump_list(obj_list))
[docs]class DumperMixin:
"""Abstract class that defines an interface for pre_dump and post_dump methods.
It allows to extend records serialization.
"""
[docs] def post_dump(self, data, original=None, **kwargs):
"""Hook called after the marshmallow serialization of the record.
:param data: The dumped record data.
:param original: The original record data.
:param kwargs: Additional keyword arguments.
:returns: The serialized record data.
"""
return data
[docs] def pre_dump(self, data, original=None, **kwargs):
"""
Hook called before the marshmallow serialization of the record.
:param data: The record data to dump.
:param original: The original record data.
:param kwargs: Additional keyword arguments.
:returns: The data to dump.
"""
return data
# FIXME: This should be moved to the base transformer class on
# https://github.com/inveniosoftware/flask-resources/issues/117
[docs]class BaseSerializerSchema(Schema):
"""Enables the extension of Marshmallow schemas serialization."""
def __init__(self, dumpers=None, **kwargs):
"""Constructor."""
super().__init__(**kwargs)
self.dumpers = dumpers or []
[docs] @post_dump(pass_original=True)
def post_dump_pipeline(self, data, original, many, **kwargs):
"""Applies a sequence of post-dump steps to the serialized data.
:param data: The result of serialization.
:param original: The original object that was serialized.
:param many: Whether the serialization was done on a collection of objects.
:returns: The result of the pipeline processing on the serialized data.
"""
for dumper in self.dumpers:
# Data is assumed to be modified and returned by the dumper
data = dumper.post_dump(data, original)
return data
[docs] @pre_dump
def pre_dump_pipeline(self, data, many, **kwargs):
"""Applies a sequence of pre-dump steps to the input data.
:param data: The result of serialization.
:param many: Whether the serialization was done on a collection of objects.
:returns: The result of the pipeline processing on the serialized data.
"""
for dumper in self.dumpers:
# Data is assumed to be modified and returned by the dumper
data = dumper.pre_dump(data)
return data