entity.py
changeset 9402 2c48c091b6a2
parent 9359 31a1813d53f3
child 9440 6880674c1a26
child 9469 032825bbacab
--- 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):