import typing from apollo_utils.service.exceptions import BadRequest from apollo_utils.service.schemas.fields.list import SplitUniqueListField from marshmallow import EXCLUDE, Schema, ValidationError, fields, missing, post_load from marshmallow import utils as marsh_utils from marshmallow import validate from multidict import MultiDictProxy from server.constants.core import Service from server.legacy.core.constants import GLOBAL_MARKET_CODE from server.legacy.core.utils import convert_market class OneOrListField(fields.List): """Custom field for handling one flat item or list of items of specific type. a -> [a] [a, b] -> [a, b] """ def __init__(self, *args, **kwargs): self._unify = kwargs.pop("unify", False) super(OneOrListField, self).__init__(*args, **kwargs) def _deserialize(self, value, attr, data, **kwargs) -> typing.List[typing.Any]: if value is not None: if value is not missing and not marsh_utils.is_collection(value): value = [value] data = super()._deserialize(value, attr, data, **kwargs) if data and self._unify: data = list(set(data)) return data class GlobalMarketOutputField(fields.Str): """Custom field for replacing various Global country codes values to _gl.""" def _serialize(self, value, attr, obj, **kwargs) -> typing.Optional[str]: value = super()._deserialize(value, attr, obj, **kwargs) if value: value = convert_market(value, GLOBAL_MARKET_CODE) return value class BaseSchema(Schema): def validate(self, data: MultiDictProxy, raise_exception: bool = False, **kwargs): try: data = self.load(data) except ValidationError as error: data = error.messages if raise_exception: raise BadRequest(detail=data) return data class Meta: unknown = EXCLUDE class HealthCheckParams(BaseSchema): """Health check endpoint params.""" include = SplitUniqueListField(fields.String(validate=validate.OneOf(Service.ALL_VALUES)), missing=[]) class BaseLimitOffsetDeserializer(BaseSchema): limit = fields.Integer(min=0) offset = fields.Integer(min=0) @post_load def set_offset_limit_default(self, data, **kwargs): if "limit" in data and "offset" not in data: data["offset"] = 0 if "limit" not in data and "offset" in data: data["limit"] = 20 return data