[server] move EditedEntity class to its own module, to avoid cyclic dependency when needed from e.g. session.py
--- a/dataimport.py Mon Mar 28 15:23:57 2011 +0200
+++ b/dataimport.py Mon Mar 28 16:39:49 2011 +0200
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -81,7 +81,7 @@
from logilab.common.deprecation import deprecated
from cubicweb.server.utils import eschema_eid
-from cubicweb.server.ssplanner import EditedEntity
+from cubicweb.server.edition import EditedEntity
def count_lines(stream_or_filename):
if isinstance(stream_or_filename, basestring):
--- a/server/querier.py Mon Mar 28 15:23:57 2011 +0200
+++ b/server/querier.py Mon Mar 28 16:39:49 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -38,7 +38,8 @@
from cubicweb.server.utils import cleanup_solutions
from cubicweb.server.rqlannotation import SQLGenAnnotator, set_qdata
-from cubicweb.server.ssplanner import READ_ONLY_RTYPES, add_types_restriction, EditedEntity
+from cubicweb.server.ssplanner import READ_ONLY_RTYPES, add_types_restriction
+from cubicweb.server.edition import EditedEntity
from cubicweb.server.session import security_enabled
def empty_rset(rql, args, rqlst=None):
--- a/server/session.py Mon Mar 28 15:23:57 2011 +0200
+++ b/server/session.py Mon Mar 28 16:39:49 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
--- a/server/sources/__init__.py Mon Mar 28 15:23:57 2011 +0200
+++ b/server/sources/__init__.py Mon Mar 28 16:39:49 2011 +0200
@@ -31,7 +31,7 @@
from cubicweb import ValidationError, set_log_methods, server
from cubicweb.schema import VIRTUAL_RTYPES
from cubicweb.server.sqlutils import SQL_PREFIX
-from cubicweb.server.ssplanner import EditedEntity
+from cubicweb.server.edition import EditedEntity
def dbg_st_search(uri, union, varmap, args, cachekey=None, prefix='rql for'):
--- a/server/sources/native.py Mon Mar 28 15:23:57 2011 +0200
+++ b/server/sources/native.py Mon Mar 28 16:39:49 2011 +0200
@@ -58,7 +58,7 @@
from cubicweb.server.rqlannotation import set_qdata
from cubicweb.server.hook import CleanupDeletedEidsCacheOp
from cubicweb.server.session import hooks_control, security_enabled
-from cubicweb.server.ssplanner import EditedEntity
+from cubicweb.server.edition import EditedEntity
from cubicweb.server.sources import AbstractSource, dbg_st_search, dbg_results
from cubicweb.server.sources.rql2sql import SQLGenerator
--- a/server/sources/storages.py Mon Mar 28 15:23:57 2011 +0200
+++ b/server/sources/storages.py Mon Mar 28 16:39:49 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -24,7 +24,7 @@
from cubicweb import Binary, ValidationError
from cubicweb.server import hook
-from cubicweb.server.ssplanner import EditedEntity
+from cubicweb.server.edition import EditedEntity
def set_attribute_storage(repo, etype, attr, storage):
--- a/server/ssplanner.py Mon Mar 28 15:23:57 2011 +0200
+++ b/server/ssplanner.py Mon Mar 28 16:39:49 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -21,8 +21,6 @@
__docformat__ = "restructuredtext en"
-from copy import copy
-
from rql.stmts import Union, Select
from rql.nodes import Constant, Relation
@@ -31,6 +29,7 @@
from cubicweb.rqlrewrite import add_types_restriction
from cubicweb.server.session import security_enabled
from cubicweb.server.hook import CleanupDeletedEidsCacheOp
+from cubicweb.server.edition import EditedEntity
READ_ONLY_RTYPES = set(('eid', 'has_text', 'is', 'is_instance_of', 'identity'))
@@ -128,132 +127,6 @@
return select
-_MARKER = object()
-
-class dict_protocol_catcher(object):
- def __init__(self, entity):
- self.__entity = entity
- def __getitem__(self, attr):
- return self.__entity.cw_edited[attr]
- def __setitem__(self, attr, value):
- self.__entity.cw_edited[attr] = value
- def __getattr__(self, attr):
- return getattr(self.__entity, attr)
-
-
-class EditedEntity(dict):
- """encapsulate entities attributes being written by an RQL query"""
- def __init__(self, entity, **kwargs):
- dict.__init__(self, **kwargs)
- self.entity = entity
- self.skip_security = set()
- self.querier_pending_relations = {}
- self.saved = False
-
- def __hash__(self):
- # dict|set keyable
- return hash(id(self))
-
- def __cmp__(self, other):
- # we don't want comparison by value inherited from dict
- return cmp(id(self), id(other))
-
- def __setitem__(self, attr, value):
- assert attr != 'eid'
- # don't add attribute into skip_security if already in edited
- # attributes, else we may accidentaly skip a desired security check
- if attr not in self:
- self.skip_security.add(attr)
- self.edited_attribute(attr, value)
-
- def __delitem__(self, attr):
- assert not self.saved, 'too late to modify edited attributes'
- super(EditedEntity, self).__delitem__(attr)
- self.entity.cw_attr_cache.pop(attr, None)
-
- def pop(self, attr, *args):
- # don't update skip_security by design (think to storage api)
- assert not self.saved, 'too late to modify edited attributes'
- value = super(EditedEntity, self).pop(attr, *args)
- self.entity.cw_attr_cache.pop(attr, *args)
- return value
-
- def setdefault(self, attr, default):
- assert attr != 'eid'
- # don't add attribute into skip_security if already in edited
- # attributes, else we may accidentaly skip a desired security check
- if attr not in self:
- self[attr] = default
- return self[attr]
-
- def update(self, values, skipsec=True):
- if skipsec:
- setitem = self.__setitem__
- else:
- setitem = self.edited_attribute
- for attr, value in values.iteritems():
- setitem(attr, value)
-
- def edited_attribute(self, attr, value):
- """attribute being edited by a rql query: should'nt be added to
- skip_security
- """
- assert not self.saved, 'too late to modify edited attributes'
- super(EditedEntity, self).__setitem__(attr, value)
- self.entity.cw_attr_cache[attr] = value
-
- def oldnewvalue(self, attr):
- """returns the couple (old attr value, new attr value)
-
- NOTE: will only work in a before_update_entity hook
- """
- assert not self.saved, 'too late to get the old value'
- # get new value and remove from local dict to force a db query to
- # fetch old value
- newvalue = self.entity.cw_attr_cache.pop(attr, _MARKER)
- oldvalue = getattr(self.entity, attr)
- if newvalue is not _MARKER:
- self.entity.cw_attr_cache[attr] = newvalue
- else:
- newvalue = oldvalue
- return oldvalue, newvalue
-
- def set_defaults(self):
- """set default values according to the schema"""
- for attr, value in self.entity.e_schema.defaults():
- if not attr in self:
- self[str(attr)] = value
-
- def check(self, creation=False):
- """check the entity edition against its schema. Only final relation
- are checked here, constraint on actual relations are checked in hooks
- """
- entity = self.entity
- if creation:
- # on creations, we want to check all relations, especially
- # required attributes
- relations = [rschema for rschema in entity.e_schema.subject_relations()
- if rschema.final and rschema.type != 'eid']
- else:
- relations = [entity._cw.vreg.schema.rschema(rtype)
- for rtype in self]
- from yams import ValidationError
- try:
- entity.e_schema.check(dict_protocol_catcher(entity),
- creation=creation, _=entity._cw._,
- relations=relations)
- except ValidationError, ex:
- ex.entity = self.entity
- raise
-
- def clone(self):
- thecopy = EditedEntity(copy(self.entity))
- thecopy.entity.cw_attr_cache = copy(self.entity.cw_attr_cache)
- thecopy.entity._cw_related_cache = {}
- thecopy.update(self, skipsec=False)
- return thecopy
-
-
class SSPlanner(object):
"""SingleSourcePlanner: build execution plan for rql queries