Skip to content
Snippets Groups Projects
Commit c06fb616ca38 authored by Sylvain Thénault's avatar Sylvain Thénault
Browse files

Propagate skiprtypes to subentities cw_skip_copy_for while cloning

We have to consider it at every levels of the container tree, not only for the
top-level entity.

While doing so, it sounded good to move creation of the list to a cached
property to avoid redoing this for each cloned entity of the tree.
parent 00a664463fdb
No related branches found
No related tags found
No related merge requests found
# copyright 2015-2016 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# copyright 2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr -- mailto:contact@logilab.fr
#
# This program is free software: you can redistribute it and/or modify it under
......@@ -29,9 +29,11 @@
from itertools import chain
from logilab.common.decorators import cachedproperty
from cubicweb.view import EntityAdapter
from cubicweb.predicates import is_instance, partial_relation_possible
from . import CompositeGraph
......@@ -32,10 +34,10 @@
from cubicweb.view import EntityAdapter
from cubicweb.predicates import is_instance, partial_relation_possible
from . import CompositeGraph
def copy_entity(original, **attributes):
def copy_entity(original, cw_skip_copy_for=None, **attributes):
"""Return a copy of an entity.
Only attributes and non-composite relations are copied (relying on
......@@ -50,7 +52,9 @@
attr = rschema.type
attrs.setdefault(attr, original.cw_attr_value(attr))
clone = original._cw.create_entity(original.cw_etype, **attrs)
if cw_skip_copy_for is not None:
_extend_skip_copy_for(clone, cw_skip_copy_for)
clone.copy_relations(original.eid)
return clone
......@@ -53,7 +57,14 @@
clone.copy_relations(original.eid)
return clone
def _extend_skip_copy_for(clone, cw_skip_copy_for):
# take care not modifying clone.cw_skip_copy_for **class attribute** to
# avoid undesired side effects (e.g. clone called with different
# skiprtypes value), so set an instance attribute.
clone.cw_skip_copy_for = set(clone.cw_skip_copy_for) | cw_skip_copy_for
class IContainer(EntityAdapter):
"""Abstract adapter for entities which are a container root."""
__abstract__ = True
......@@ -203,14 +214,9 @@
assert clone.cw_etype == self.entity.cw_etype, \
"clone entity type {} does not match with original's {}".format(
clone.cw_etype, self.entity.cw_etype)
related = self.graph.child_related(
self.entity, follow_relations=self.follow_relations)
# take care not modifying clone.cw_skip_copy_for class attribute to avoid undesired side
# effects (e.g. clone called with different skiprtypes value), set an instance attribute.
clone.cw_skip_copy_for = list(chain(
clone.cw_skip_copy_for,
((rtype, 'subject') for rtype in self.skiprtypes),
((rtype, 'object') for rtype in self.skiprtypes)))
related = list(self.graph.child_related(
self.entity, follow_relations=self.follow_relations))
_extend_skip_copy_for(clone, self.skip_swallow_copy_for)
with self._cw.deny_all_hooks_but(*self.enabled_hook_categories):
clone.copy_relations(self.entity.eid)
clones = {self.entity: clone}
......@@ -221,6 +227,7 @@
if clone is not None:
clone.cw_set(**kwargs)
else:
clones[child] = copy_entity(child, **kwargs)
clones[child] = copy_entity(
child, self.skip_swallow_copy_for, **kwargs)
return clones
......@@ -225,5 +232,13 @@
return clones
@cachedproperty
def skip_swallow_copy_for(self):
return set(chain(
# turn skiprtypes into a list suitable for Entity.cw_skip_copy_for
((rtype, 'subject') for rtype in self.skiprtypes),
((rtype, 'object') for rtype in self.skiprtypes),
))
def registration_callback(vreg):
vreg.register_all(globals().values(), __name__)
......
......@@ -107,3 +107,8 @@
"""Indicates a member of a Group."""
subject = 'Group'
object = 'Agent'
class see_also(RelationDefinition):
subject = 'Biography'
object = 'Event'
......@@ -361,6 +361,16 @@
self.assertFalse(clone.reverse_member)
self.assertIs(bob.cw_skip_copy_for, orig_cw_skip_copy_for)
def test_clone_skiprtypes_sublevel(self):
with self.admin_access.repo_cnx() as cnx:
event = cnx.create_entity('Event')
bio = cnx.create_entity('Biography', event=event, see_also=event)
cnx.create_entity('Agent', name=u'bob', biography=bio)
cnx.commit()
clone = clone_agent(cnx, u'bob', skiprtypes=('see_also',))
self.assertEqual(clone.biography[0].see_also, ())
def test_clone_full(self):
with self.admin_access.repo_cnx() as cnx:
agent = cnx.create_entity('Agent', name=u'bob')
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment