from abc import abstractmethod from typing import Type from marshmallow import Schema, fields, post_dump, pre_dump class DumpToObjectMixin: """Mixin for saving data to objects of specific class after dumping. Attributes: dump_cls: class of objects to save data to. """ def __init__(self, *args, dump_cls=None, **kwargs): super().__init__(*args, **kwargs) self.dump_cls = dump_cls @post_dump def to_object(self, data, *args, **kwargs): if self.dump_cls is None: return data return self.dump_cls(**data) class GetMessageIdMixin: """Mixin to get message id from schema context.""" id = fields.Method("get_id") def get_id(self, track): return self.context["message_id"] class PushDataBaseSchema(GetMessageIdMixin, DumpToObjectMixin, Schema): """Base PushData schema for push notifications.""" pass class PushBaseSchema(GetMessageIdMixin, DumpToObjectMixin, Schema): """Base Push schema for push notifications. Attributes: _data_schema_cls: schema class for inner push data dumping. Arguments: push_cls: class of object to dump push message to. push_data_cls: class of object to dump inner push message data to. """ _data_schema_cls: Type[PushDataBaseSchema] data = fields.Method("get_data") def __init__(self, *args, push_cls=None, push_data_cls=None, **kwargs): super().__init__(*args, dump_cls=push_cls, **kwargs) self._data_schema = self._data_schema_cls(dump_cls=push_data_cls) @pre_dump def set_message_id(self, track, *args, **kwargs): self.context["message_id"] = self._get_message_key(track) return track @abstractmethod def _get_message_key(self, track) -> str: pass def get_data(self, track): self._data_schema.context = self.context return self._data_schema.dump(track)