Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def as_optional(cls):
name = 'Optional' + cls.__name__
return type(name, (cls,), {'DEFAULT': None})
@classmethod
@abstractmethod
def to_python_value(cls, deserialized_data, *, target):
raise NotImplementedError
@classmethod
@abstractmethod
def to_preserialization_data(cls, python_value, *, skip=Missing):
raise NotImplementedError
class Boolean(Converter):
"""Converter for `bool` literals."""
TYPE = bool
DEFAULT = False
_FALSY = {'false', 'f', 'no', 'n', 'disabled', 'off', '0'}
# pylint: disable=unused-argument
@classmethod
def to_python_value(cls, deserialized_data, *, target=None):
if isinstance(deserialized_data, str):
value = deserialized_data.lower() not in cls._FALSY
else:
value = cls.TYPE(deserialized_data)
return value
@classmethod
def to_python_value(cls, deserialized_data, *, target=None):
value = cls.to_preserialization_data(deserialized_data).strip()
if '\n' in value:
value = value + '\n'
return value
@classmethod
def to_preserialization_data(cls, python_value, *, skip=Missing):
data = super().to_preserialization_data(python_value).strip()
if '\n' in data:
return LiteralScalarString(data + '\n')
return data
class List(Converter):
"""Base converter for homogeneous lists of another converter."""
CONVERTER = None
@classmethod
def subclass(cls, converter: type):
name = f'{converter.__name__}List' # type: ignore
bases = (cls,)
attributes = {'CONVERTER': converter}
return type(name, bases, attributes)
@classmethod
def to_python_value(cls, deserialized_data, *, target):
if target is None:
value = [] # type: ignore
else:
# pylint: disable=unused-argument
@classmethod
def to_python_value(cls, deserialized_data, *, target=None):
value = cls.to_preserialization_data(deserialized_data)
return value
@classmethod
def to_preserialization_data(cls, python_value, *, skip=Missing):
if python_value is None:
return cls.DEFAULT
return cls.TYPE(python_value)
class Integer(Converter):
"""Converter for `int` literals."""
TYPE = int
DEFAULT = 0
# pylint: disable=unused-argument
@classmethod
def to_python_value(cls, deserialized_data, *, target=None):
value = cls.to_preserialization_data(deserialized_data)
return value
@classmethod
def to_preserialization_data(cls, python_value, *, skip=Missing):
if python_value is None:
return cls.DEFAULT
for item in value:
if not isinstance(item, item_cls):
log.warn(f'{name!r} list type cannot be inferred')
item_cls = Converter
break
else:
log.warn(f'{name!r} list type cannot be inferred')
item_cls = Converter
log.debug(f'Inferring {name!r} type: {cls} of {item_cls}')
self.attrs[name] = map_type(cls, name=name, item_cls=item_cls)
elif issubclass(cls, dict):
cls.__origin__ = dict
log.debug(f'Inferring {name!r} type: {cls}')
self.attrs[name] = map_type(cls, name=name, item_cls=Converter)
else:
log.debug(f'Inferring {name!r} type: {cls}')
self.attrs[name] = map_type(cls, name=name)
for name, converter in self.attrs.items():
log.debug(f"Converting '{name}' data with {converter}")
if getattr(converter, 'DATACLASS', None):
self._set_dataclass_value(data, name, converter)
else:
self._set_attribute_value(data, name, converter, _first)
hooks.apply(self._instance, self)
self.modified = False
@classmethod
def to_python_value(cls, deserialized_data, *, target=None):
if isinstance(deserialized_data, str):
value = deserialized_data.lower() not in cls._FALSY
else:
value = cls.TYPE(deserialized_data)
return value
@classmethod
def to_preserialization_data(cls, python_value, *, skip=Missing):
if python_value is None:
return cls.DEFAULT
return cls.TYPE(python_value)
class Float(Converter):
"""Converter for `float` literals."""
TYPE = float
DEFAULT = 0.0
# pylint: disable=unused-argument
@classmethod
def to_python_value(cls, deserialized_data, *, target=None):
value = cls.to_preserialization_data(deserialized_data)
return value
@classmethod
def to_preserialization_data(cls, python_value, *, skip=Missing):
if python_value is None:
return cls.DEFAULT
value.clear()
value.update(data)
return value
@classmethod
def to_preserialization_data(cls, python_value, *, skip=Missing):
data = dict(python_value)
if data == skip:
data.clear()
return data
class Object(Converter):
"""Base converter for dataclasses."""
DATACLASS = None
CONVERTERS = None
@classmethod
def subclass(cls, dataclass, converters: Dict[str, type]):
name = f'{dataclass.__name__}Converter'
bases = (cls,)
attributes = {'DATACLASS': dataclass, 'CONVERTERS': converters}
return type(name, bases, attributes)
@classmethod
def to_python_value(cls, deserialized_data, *, target):
if isinstance(deserialized_data, dict):
data = deserialized_data.copy()
converter = Dictionary.subclass(key, value)
elif cls.__origin__ == Union:
converter = map_type(cls.__args__[0])
assert len(cls.__args__) == 2
assert cls.__args__[1] == type(None)
converter = converter.as_optional()
if converter:
log.debug(f'Mapped {cls!r} to new converter: {converter}')
return converter
raise TypeError(f'Unsupported container type: {cls.__origin__}')
else:
for converter in Converter.__subclasses__():
if converter.TYPE == cls:
log.debug(f'Mapped {cls!r} to existing converter: {converter}')
return converter
if not isclass(cls):
raise TypeError(f'Annotation is not a type: {cls!r}')
if issubclass(cls, Converter):
log.debug(f'Mapped {cls!r} to existing converter (itself)')
return cls
raise TypeError(f'Could not map type: {cls}')
"""Configuration defaults for each model."""
from __future__ import annotations
from contextlib import suppress
from dataclasses import dataclass
from typing import TYPE_CHECKING, Dict, Optional
if TYPE_CHECKING:
from .converters import Converter
@dataclass
class Meta:
datafile_attrs: Optional[Dict[str, Converter]] = None
datafile_pattern: Optional[str] = None
datafile_manual: bool = False
datafile_defaults: bool = False
datafile_auto_load: bool = True
datafile_auto_save: bool = True
datafile_auto_attr: bool = False
def load(obj) -> Meta:
meta = Meta()
with suppress(AttributeError):
meta.datafile_attrs = obj.Meta.datafile_attrs
with suppress(AttributeError):
meta.datafile_pattern = obj.Meta.datafile_pattern
class Number(Float):
"""Converter for integers or floats."""
DEFAULT = 0
# pylint: disable=unused-argument
@classmethod
def to_preserialization_data(cls, python_value, *, skip=Missing):
data = super().to_preserialization_data(python_value)
if int(data) == data:
return int(data)
return data
class String(Converter):
"""Converter for `str` literals."""
TYPE = str
DEFAULT = ""
# pylint: disable=unused-argument
@classmethod
def to_python_value(cls, deserialized_data, *, target=None):
value = cls.to_preserialization_data(deserialized_data)
return value
@classmethod
def to_preserialization_data(cls, python_value, *, skip=Missing):
if python_value is None:
return cls.DEFAULT