Skip to content
This repository has been archived by the owner on Oct 3, 2019. It is now read-only.

Commit

Permalink
Fix runtime import to determine new attribute types
Browse files Browse the repository at this point in the history
  • Loading branch information
jacebrowning committed Feb 23, 2016
1 parent a36f4f2 commit fad419d
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 43 deletions.
5 changes: 2 additions & 3 deletions yorm/bases/mappable.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import functools

from .. import common
from ..mapper import get_mapper


log = common.logger(__name__)
Expand All @@ -22,7 +21,7 @@ def fetch_before(method):
def wrapped(self, *args, **kwargs):
"""Decorated method."""
if not _private_call(method, args):
mapper = get_mapper(self)
mapper = common.get_mapper(self)
if mapper and mapper.modified:
log.debug("Fetching before call: %s", method.__name__)
mapper.fetch()
Expand All @@ -49,7 +48,7 @@ def wrapped(self, *args, **kwargs):
result = method(self, *args, **kwargs)

if not _private_call(method, args):
mapper = get_mapper(self)
mapper = common.get_mapper(self)
if mapper and mapper.auto:
log.debug("Storing after call: %s", method.__name__)
mapper.store()
Expand Down
18 changes: 18 additions & 0 deletions yorm/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

# CONSTANTS ####################################################################

MAPPER = '__mapper__'

PRINT_VERBOSITY = 0 # minimum verbosity to using `print`
STR_VERBOSITY = 3 # minimum verbosity to use verbose `__str__`
Expand Down Expand Up @@ -49,3 +50,20 @@ def __init__(self, getter):

def __get__(self, instance, owner):
return self.getter(owner)


# FUNCTIONS ####################################################################


def get_mapper(obj):
"""Get the `Mapper` instance attached to an object."""
try:
return object.__getattribute__(obj, MAPPER)
except AttributeError:
return None


def set_mapper(obj, mapper):
"""Attach a `Mapper` instance to an object."""
setattr(obj, MAPPER, mapper)
return mapper
50 changes: 15 additions & 35 deletions yorm/mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,12 @@
import functools
from pprint import pformat

from . import common, diskutils, exceptions, settings
from . import common, diskutils, exceptions, types, settings
from .bases import Container

MAPPER = '__mapper__'

log = common.logger(__name__)


def get_mapper(obj):
"""Get `Mapper` instance attached to an object."""
try:
return object.__getattribute__(obj, MAPPER)
except AttributeError:
return None


def set_mapper(obj, *args, **kwargs):
"""Create and attach a `Mapper` instance to an object."""
mapper = Mapper(obj, *args, **kwargs)
setattr(obj, MAPPER, mapper)
return mapper


def file_required(create=False):
"""Decorator for methods that require the file to exist.
Expand Down Expand Up @@ -199,10 +182,7 @@ def fetch(self):
log.warning(msg, name, data)
continue
else:
# TODO: determine if runtime import is the best way to avoid
# cyclic import
from .types import match
converter = match(name, data)
converter = types.match(name, data)
self.attrs[name] = converter

# Convert the loaded attribute
Expand All @@ -227,6 +207,19 @@ def fetch(self):
# Set meta attributes
self.modified = False

def _remap(self, obj, root):
"""Restore mapping on nested attributes."""
if isinstance(obj, Container):
common.set_mapper(obj, root)

if isinstance(obj, dict):
for obj2 in obj.values():
self._remap(obj2, root)
else:
assert isinstance(obj, list)
for obj2 in obj:
self._remap(obj2, root)

@file_required(create=True)
@prevent_recursion
def store(self):
Expand Down Expand Up @@ -283,16 +276,3 @@ def _write(self, text):
self._fake = text
else:
diskutils.write(text, self.path)

def _remap(self, obj, root):
"""Restore mapping on nested attributes."""
if isinstance(obj, Container):
setattr(obj, MAPPER, root)

if isinstance(obj, dict):
for obj2 in obj.values():
self._remap(obj2, root)
else:
assert isinstance(obj, list)
for obj2 in obj:
self._remap(obj2, root)
11 changes: 6 additions & 5 deletions yorm/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from . import common, exceptions
from .bases.mappable import patch_methods
from .mapper import get_mapper, set_mapper
from .mapper import Mapper

log = common.logger(__name__)

Expand Down Expand Up @@ -45,7 +45,8 @@ def sync_object(instance, path, attrs=None, existing=None, **kwargs):
patch_methods(instance)

attrs = attrs or common.attrs[instance.__class__]
mapper = set_mapper(instance, path, attrs, **kwargs)
mapper = Mapper(instance, path, attrs, **kwargs)
common.set_mapper(instance, mapper)
_check_existance(mapper, existing)

if mapper.auto:
Expand Down Expand Up @@ -149,7 +150,7 @@ def update_object(instance, existing=True, force=True):
log.info("Manually updating %r from file...", instance)
_check_base(instance, mappable=True)

mapper = get_mapper(instance)
mapper = common.get_mapper(instance)
_check_existance(mapper, existing)

if mapper.modified or force:
Expand All @@ -167,7 +168,7 @@ def update_file(instance, existing=None, force=True):
log.info("Manually saving %r to file...", instance)
_check_base(instance, mappable=True)

mapper = get_mapper(instance)
mapper = common.get_mapper(instance)
_check_existance(mapper, existing)

if mapper.auto or force:
Expand All @@ -178,7 +179,7 @@ def update_file(instance, existing=None, force=True):

def synced(obj):
"""Determine if an object is already mapped to a file."""
return bool(get_mapper(obj))
return bool(common.get_mapper(obj))


def _check_base(obj, mappable=True):
Expand Down

0 comments on commit fad419d

Please sign in to comment.