Skip to content

Commit

Permalink
Sequences use the factory finder adapter.
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Jul 13, 2018
1 parent 2bcb051 commit 76fc890
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
- ``update_from_external_object`` caches certain information about the
types of the updater objects, making it 8-25% faster.

- ``update_from_external_object`` mutates sequences contained in a
dict in-place instead of overwriting with a new list.

1.0.0a2 (2018-07-05)
====================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@

from zope.schema import Object
from zope.schema import Int
from zope.schema import List

from zope.testing.cleanup import CleanUp

from nti.externalization.internalization import update_from_external_object
from nti.externalization.datastructures import InterfaceObjectIO
from nti.externalization.datastructures import ModuleScopedInterfaceObjectIO


class TestExternals(CleanUp,
unittest.TestCase):
Expand All @@ -45,10 +46,10 @@ class IO(InterfaceObjectIO):
_ext_iface_upper_bound = IRoot
component.provideAdapter(IO, adapts=(IRoot,))

class IO(InterfaceObjectIO):
class IO2(InterfaceObjectIO):
_ext_iface_upper_bound = INestedThing

component.provideAdapter(IO, adapts=(INestedThing,))
component.provideAdapter(IO2, adapts=(INestedThing,))

@interface.implementer(IRoot)
class Root(object):
Expand All @@ -72,3 +73,45 @@ def __init__(self):

assert_that(root, has_attr('field', is_(NestedThing)))
assert_that(root.field, has_attr('value', 42))


def test_sequence_object_field_names_match_non_primitive(self):
class INestedThing(interface.Interface):
value = Int(title=u"An integer")

class IRoot(interface.Interface):
field = List(Object(INestedThing))


class IO(InterfaceObjectIO):
_ext_iface_upper_bound = IRoot
component.provideAdapter(IO, adapts=(IRoot,))

class IO2(InterfaceObjectIO):
_ext_iface_upper_bound = INestedThing

component.provideAdapter(IO2, adapts=(INestedThing,))

@interface.implementer(IRoot)
class Root(object):

def __init__(self):
self.field = ()

@interface.implementer(INestedThing)
class NestedThing(object):

def __init__(self):
self.value = -1

IRoot['field'].setTaggedValue('__external_factory__', NestedThing)

external = {'field': [{'value': 42}, {'value': 2018}]}

root = Root()

update_from_external_object(root, external, require_updater=True)

assert_that(root, has_attr('field', is_(list)))
assert_that(root.field[0], has_attr('value', 42))
assert_that(root.field[1], has_attr('value', 2018))
10 changes: 5 additions & 5 deletions src/nti/externalization/internalization/updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ def update_from_external_object(containedObject, externalObject,

# We have to save the list of keys, it's common that they get popped during the update
# process, and then we have no descriptions to send
external_keys = list()
external_keys = []
for k, v in iteritems(externalObject):
external_keys.append(k)
if isinstance(v, PRIMITIVES):
Expand All @@ -283,11 +283,11 @@ def update_from_external_object(containedObject, externalObject,

if isinstance(v, MutableSequence):
# Update the sequence in-place
# XXX: This is not actually updating it.
# We need to slice externalObject[k[:]]
__traceback_info__ = k, v
v = _recall(k, (), v, kwargs)
externalObject[k] = v
for index, item in enumerate(v):
factory = get_object_to_update(k, item, registry)
if factory is not None:
v[index] = _recall(k, factory(), item, kwargs)
else:
factory = get_object_to_update(k, v, registry)
if factory is not None:
Expand Down
3 changes: 1 addition & 2 deletions src/nti/externalization/tests/test_internalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,7 @@ def test_update_mapping_of_primitives_and_sequences(self):
assert_that(result, is_(same_instance(self)))

assert_that(ext, is_({'a': 1, 'b': b, 'c': {}}))
# This should change.
assert_that(ext['b'], is_not(same_instance(b)))
assert_that(ext['b'], is_(same_instance(b)))

def test_update_mapping_with_update_on_contained_object(self):
class ContainedObject(object):
Expand Down

0 comments on commit 76fc890

Please sign in to comment.