Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
import dataclasses
import log
from classproperties import classproperty
from . import config, hooks, settings
from .manager import Manager
from .mapper import create_mapper
class Model:
Meta: config.Meta = config.Meta()
def __post_init__(self):
log.debug(f'Initializing {self.__class__} object')
self.datafile = create_mapper(self)
if settings.HOOKS_ENABLED:
with hooks.disabled():
path = self.datafile.path
exists = self.datafile.exists
create = not self.datafile.manual
if path:
log.debug(f'Datafile path: {path}')
log.debug(f'Datafile exists: {exists}')
def create_mapper(obj, root=None) -> Mapper:
try:
return object.__getattribute__(obj, 'datafile')
except AttributeError:
log.debug(f"Building 'datafile' for {obj.__class__} object")
m = getattr(obj, 'Meta', None)
# TODO: Move this parsing into config.py
pattern = getattr(m, 'datafile_pattern', None)
attrs = getattr(m, 'datafile_attrs', None)
manual = getattr(m, 'datafile_manual', Meta.datafile_manual)
defaults = getattr(m, 'datafile_defaults', Meta.datafile_defaults)
auto_load = getattr(m, 'datafile_auto_load', Meta.datafile_auto_load)
auto_save = getattr(m, 'datafile_auto_save', Meta.datafile_auto_save)
auto_attr = getattr(m, 'datafile_auto_attr', Meta.datafile_auto_attr)
if attrs is None and dataclasses.is_dataclass(obj):
attrs = {}
log.debug(f'Mapping attributes for {obj.__class__} object')
for field in dataclasses.fields(obj):
self_name = f'self.{field.name}'
if pattern is None or self_name not in pattern:
attrs[field.name] = map_type(field.type, name=field.name)
return Mapper(
obj,
attrs=attrs,
manual=None,
pattern=None,
defaults=None,
auto_load=None,
auto_save=None,
auto_attr=None,
):
"""Patch model attributes on to an existing dataclass."""
log.debug(f'Converting {cls} to a datafile model')
if not dataclasses.is_dataclass(cls):
raise ValueError(f'{cls} must be a dataclass')
# Patch meta
m = getattr(cls, 'Meta', config.Meta())
if attrs is not None:
m.datafile_attrs = attrs
if pattern is not None:
m.datafile_pattern = pattern
if not hasattr(cls, 'Meta') and manual is not None:
m.datafile_manual = manual
if not hasattr(cls, 'Meta') and defaults is not None:
m.datafile_defaults = defaults
if not hasattr(cls, 'Meta') and auto_load is not None:
m.datafile_auto_load = auto_load
if not hasattr(cls, 'Meta') and auto_save is not None:
m.datafile_auto_save = auto_save
if not hasattr(cls, 'Meta') and auto_attr is not None:
m.datafile_auto_attr = auto_attr
def datafile(
pattern: Union[str, Callable, None] = None,
attrs: Optional[Dict[str, Converter]] = None,
manual: bool = Meta.datafile_manual,
defaults: bool = Meta.datafile_defaults,
auto_load: bool = Meta.datafile_auto_load,
auto_save: bool = Meta.datafile_auto_save,
auto_attr: bool = Meta.datafile_auto_attr,
**kwargs,
):
"""Synchronize a data class to the specified path."""
if pattern is None:
return dataclasses.dataclass(**kwargs)
if callable(pattern):
return dataclasses.dataclass(pattern) # type: ignore
def decorator(cls=None):
if dataclasses.is_dataclass(cls):
def datafile(
pattern: Union[str, Callable, None] = None,
attrs: Optional[Dict[str, Converter]] = None,
manual: bool = Meta.datafile_manual,
defaults: bool = Meta.datafile_defaults,
auto_load: bool = Meta.datafile_auto_load,
auto_save: bool = Meta.datafile_auto_save,
auto_attr: bool = Meta.datafile_auto_attr,
**kwargs,
):
"""Synchronize a data class to the specified path."""
if pattern is None:
return dataclasses.dataclass(**kwargs)
if callable(pattern):
return dataclasses.dataclass(pattern) # type: ignore
def decorator(cls=None):
if dataclasses.is_dataclass(cls):
dataclass = cls
else:
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
with suppress(AttributeError):
meta.datafile_manual = obj.Meta.datafile_manual
with suppress(AttributeError):
meta.datafile_defaults = obj.Meta.datafile_defaults
with suppress(AttributeError):
meta.datafile_auto_load = obj.Meta.datafile_auto_load
with suppress(AttributeError):
meta.datafile_auto_save = obj.Meta.datafile_auto_save
with suppress(AttributeError):
meta.datafile_auto_attr = obj.Meta.datafile_auto_attr
def create_mapper(obj, root=None) -> Mapper:
try:
return object.__getattribute__(obj, 'datafile')
except AttributeError:
log.debug(f"Building 'datafile' for {obj.__class__} object")
m = getattr(obj, 'Meta', None)
# TODO: Move this parsing into config.py
pattern = getattr(m, 'datafile_pattern', None)
attrs = getattr(m, 'datafile_attrs', None)
manual = getattr(m, 'datafile_manual', Meta.datafile_manual)
defaults = getattr(m, 'datafile_defaults', Meta.datafile_defaults)
auto_load = getattr(m, 'datafile_auto_load', Meta.datafile_auto_load)
auto_save = getattr(m, 'datafile_auto_save', Meta.datafile_auto_save)
auto_attr = getattr(m, 'datafile_auto_attr', Meta.datafile_auto_attr)
if attrs is None and dataclasses.is_dataclass(obj):
attrs = {}
log.debug(f'Mapping attributes for {obj.__class__} object')
for field in dataclasses.fields(obj):
self_name = f'self.{field.name}'
if pattern is None or self_name not in pattern:
attrs[field.name] = map_type(field.type, name=field.name)
return Mapper(
obj,
attrs=attrs,
pattern=pattern,