--- a/entity.py Tue Jul 02 17:09:04 2013 +0200
+++ b/entity.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -42,7 +42,6 @@
from cubicweb.rqlrewrite import RQLRewriter
from cubicweb.uilib import soup2xhtml
-from cubicweb.mixins import MI_REL_TRIGGERS
from cubicweb.mttransforms import ENGINE
_marker = object()
@@ -194,31 +193,11 @@
setattr(cls, rschema.type, Attribute(rschema.type))
mixins = []
for rschema, _, role in eschema.relation_definitions():
- if (rschema, role) in MI_REL_TRIGGERS:
- mixin = MI_REL_TRIGGERS[(rschema, role)]
- if not (issubclass(cls, mixin) or mixin in mixins): # already mixed ?
- mixins.append(mixin)
- for iface in getattr(mixin, '__implements__', ()):
- if not interface.implements(cls, iface):
- interface.extend(cls, iface)
if role == 'subject':
attr = rschema.type
else:
attr = 'reverse_%s' % rschema.type
setattr(cls, attr, Relation(rschema, role))
- if mixins:
- # see etype class instantation in cwvreg.ETypeRegistry.etype_class method:
- # due to class dumping, cls is the generated top level class with actual
- # user class as (only) parent. Since we want to be able to override mixins
- # method from this user class, we have to take care to insert mixins after that
- # class
- #
- # note that we don't plug mixins as user class parent since it causes pb
- # with some cases of entity classes inheritance.
- mixins.insert(0, cls.__bases__[0])
- mixins += cls.__bases__[1:]
- cls.__bases__ = tuple(mixins)
- cls.info('plugged %s mixins on %s', mixins, cls)
fetch_attrs = ('modification_date',)
@@ -308,7 +287,10 @@
select._varmaker = rqlvar_maker(defined=select.defined_vars,
aliases=select.aliases, index=26)
if settype:
- select.add_type_restriction(mainvar, cls.__regid__)
+ rel = select.add_type_restriction(mainvar, cls.__regid__)
+ # should use 'is_instance_of' instead of 'is' so we retrieve
+ # subclasses instances as well
+ rel.r_type = 'is_instance_of'
if fetchattrs is None:
fetchattrs = cls.fetch_attrs
cls._fetch_restrictions(mainvar, select, fetchattrs, user, ordermethod)
@@ -558,7 +540,14 @@
raise NotImplementedError('comparison not implemented for %s' % self.__class__)
def __eq__(self, other):
- raise NotImplementedError('comparison not implemented for %s' % self.__class__)
+ if isinstance(self.eid, (int, long)):
+ return self.eid == other.eid
+ return self is other
+
+ def __hash__(self):
+ if isinstance(self.eid, (int, long)):
+ return self.eid
+ return super(Entity, self).__hash__()
def _cw_update_attr_cache(self, attrcache):
# if context is a repository session, don't consider dont-cache-attrs as
@@ -983,7 +972,7 @@
return value
def related(self, rtype, role='subject', limit=None, entities=False, # XXX .cw_related
- safe=False):
+ safe=False, targettypes=None):
"""returns a resultset of related entities
:param rtype:
@@ -997,10 +986,13 @@
:param safe:
if True, an empty rset/list of entities will be returned in case of
:exc:`Unauthorized`, else (the default), the exception is propagated
+ :param targettypes:
+ a tuple of target entity types to restrict the query
"""
rtype = str(rtype)
- if limit is None:
- # we cannot do much wrt cache on limited queries
+ # Caching restricted/limited results is best avoided.
+ cacheable = limit is None and targettypes is None
+ if cacheable:
cache_key = '%s_%s' % (rtype, role)
if cache_key in self._cw_related_cache:
return self._cw_related_cache[cache_key][entities]
@@ -1008,7 +1000,7 @@
if entities:
return []
return self._cw.empty_rset()
- rql = self.cw_related_rql(rtype, role, limit=limit)
+ rql = self.cw_related_rql(rtype, role, limit=limit, targettypes=targettypes)
try:
rset = self._cw.execute(rql, {'x': self.eid})
except Unauthorized:
@@ -1016,9 +1008,9 @@
raise
rset = self._cw.empty_rset()
if entities:
- if limit is None:
+ if cacheable:
self.cw_set_relation_cache(rtype, role, rset)
- return self.related(rtype, role, limit, entities)
+ return self.related(rtype, role, entities=entities)
return list(rset.entities())
else:
return rset
@@ -1181,8 +1173,7 @@
if v in select.defined_vars and v in cstr.mainvars)
# rewrite constraint by constraint since we want a AND between
# expressions.
- rewriter.rewrite(select, [(varmap, (cstr,))], select.solutions,
- args, existant)
+ rewriter.rewrite(select, [(varmap, (cstr,))], args, existant)
# insert security RQL expressions granting the permission to 'add' the
# relation into the rql syntax tree, if necessary
rqlexprs = rdef.get_rqlexprs('add')
@@ -1194,8 +1185,7 @@
varmap = dict((v, v) for v in (searchedvar.name, evar.name)
if v in select.defined_vars)
# rewrite all expressions at once since we want a OR between them.
- rewriter.rewrite(select, [(varmap, rqlexprs)], select.solutions,
- args, existant)
+ rewriter.rewrite(select, [(varmap, rqlexprs)], args, existant)
# ensure we have an order defined
if not select.orderby:
select.add_sort_var(select.defined_vars[searchedvar.name])
@@ -1281,8 +1271,8 @@
>>> c = rql('Any X WHERE X is Company').get_entity(0, 0)
>>> p = rql('Any X WHERE X is Person').get_entity(0, 0)
- >>> c.set(name=u'Logilab')
- >>> p.set(firstname=u'John', lastname=u'Doe', works_for=c)
+ >>> c.cw_set(name=u'Logilab')
+ >>> p.cw_set(firstname=u'John', lastname=u'Doe', works_for=c)
You can also set relations where the entity has 'object' role by
prefixing the relation name by 'reverse_'. Also, relation values may be
@@ -1323,7 +1313,8 @@
@deprecated('[3.16] use cw_set() instead of set_attributes()')
def set_attributes(self, **kwargs): # XXX cw_set_attributes
- self.cw_set(**kwargs)
+ if kwargs:
+ self.cw_set(**kwargs)
@deprecated('[3.16] use cw_set() instead of set_relations()')
def set_relations(self, **kwargs): # XXX cw_set_relations
@@ -1334,40 +1325,13 @@
(meaning that all relations of the given type from or to this object
should be deleted).
"""
- self.cw_set(**kwargs)
+ if kwargs:
+ self.cw_set(**kwargs)
@deprecated('[3.13] use entity.cw_clear_all_caches()')
def clear_all_caches(self):
return self.cw_clear_all_caches()
- @deprecated('[3.9] use entity.cw_attr_value(attr)')
- def get_value(self, name):
- return self.cw_attr_value(name)
-
- @deprecated('[3.9] use entity.cw_delete()')
- def delete(self, **kwargs):
- return self.cw_delete(**kwargs)
-
- @deprecated('[3.9] use entity.cw_attr_metadata(attr, metadata)')
- def attr_metadata(self, attr, metadata):
- return self.cw_attr_metadata(attr, metadata)
-
- @deprecated('[3.9] use entity.cw_has_perm(action)')
- def has_perm(self, action):
- return self.cw_has_perm(action)
-
- @deprecated('[3.9] use entity.cw_set_relation_cache(rtype, role, rset)')
- def set_related_cache(self, rtype, role, rset):
- self.cw_set_relation_cache(rtype, role, rset)
-
- @deprecated('[3.9] use entity.cw_clear_relation_cache(rtype, role)')
- def clear_related_cache(self, rtype=None, role=None):
- self.cw_clear_relation_cache(rtype, role)
-
- @deprecated('[3.9] use entity.cw_related_rql(rtype, [role, [targettypes]])')
- def related_rql(self, rtype, role='subject', targettypes=None):
- return self.cw_related_rql(rtype, role, targettypes)
-
@property
@deprecated('[3.10] use entity.cw_edited')
def edited_attributes(self):