entity.py
branchtls-sprint
changeset 1474 716f0742ee7f
parent 1471 c889c3bcf5ec
child 1498 2c6eec0b46b9
--- a/entity.py	Fri Apr 24 15:38:11 2009 +0200
+++ b/entity.py	Fri Apr 24 15:38:19 2009 +0200
@@ -62,7 +62,7 @@
 
 except ImportError:
     AutomaticEntityForm = None
-    
+
     def dispatch_rtags(*args):
         pass
 
@@ -74,7 +74,7 @@
             etype = getattr(base, 'id', None)
             if etype and etype != 'Any':
                 return etype
-            
+
 def _get_defs(attr, name, bases, classdict):
     try:
         yield name, classdict.pop(attr)
@@ -86,7 +86,7 @@
                 yield base.__name__, value
             except AttributeError:
                 continue
-            
+
 class metaentity(type):
     """this metaclass sets the relation tags on the entity class
     and deals with the `widgets` attribute
@@ -138,7 +138,7 @@
 class Entity(AppRsetObject, dict):
     """an entity instance has e_schema automagically set on
     the class and instances has access to their issuing cursor.
-    
+
     A property is set for each attribute and relation on each entity's type
     class. Becare that among attributes, 'eid' is *NEITHER* stored in the
     dict containment (which acts as a cache for other attributes dynamically
@@ -151,7 +151,7 @@
     :cvar rest_var: indicates which attribute should be used to build REST urls
                     If None is specified, the first non-meta attribute will
                     be used
-                    
+
     :type skip_copy_for: list
     :cvar skip_copy_for: a list of relations that should be skipped when copying
                          this kind of entity. Note that some relations such
@@ -162,14 +162,14 @@
     __registry__ = 'etypes'
     __select__ = yes()
 
-    # class attributes that must be set in class definition 
+    # class attributes that must be set in class definition
     id = None
     rest_attr = None
     fetch_attrs = None
     skip_copy_for = ()
     # class attributes set automatically at registration time
     e_schema = None
-    
+
     @classmethod
     def registered(cls, registry):
         """build class using descriptor at registration time"""
@@ -178,7 +178,7 @@
         if cls.id != 'Any':
             cls.__initialize__()
         return cls
-                
+
     MODE_TAGS = set(('link', 'create'))
     CATEGORY_TAGS = set(('primary', 'secondary', 'generic', 'generated')) # , 'metadata'))
     @classmethod
@@ -210,7 +210,7 @@
         if mixins:
             cls.__bases__ = tuple(mixins + [p for p in cls.__bases__ if not p is object])
             cls.debug('plugged %s mixins on %s', mixins, etype)
-    
+
     @classmethod
     def fetch_rql(cls, user, restriction=None, fetchattrs=None, mainvar='X',
                   settype=True, ordermethod='fetch_order'):
@@ -231,7 +231,7 @@
             rql +=  ' ORDERBY %s' % ','.join(orderby)
         rql += ' WHERE %s' % ', '.join(restrictions)
         return rql
-    
+
     @classmethod
     def _fetch_restrictions(cls, mainvar, varmaker, fetchattrs,
                             selection, orderby, restrictions, user,
@@ -293,7 +293,7 @@
         else:
             self.eid = None
         self._is_saved = True
-        
+
     def __repr__(self):
         return '<Entity %s %s %s at %s>' % (
             self.e_schema, self.eid, self.keys(), id(self))
@@ -308,11 +308,11 @@
         """hook called by the repository before doing anything to add the entity
         (before_add entity hooks have not been called yet). This give the
         occasion to do weird stuff such as autocast (File -> Image for instance).
-        
+
         This method must return the actual entity to be added.
         """
         return self
-    
+
     def set_eid(self, eid):
         self.eid = self['eid'] = eid
 
@@ -333,7 +333,7 @@
         saved in its source.
         """
         return self.has_eid() and self._is_saved
-    
+
     @cached
     def metainformation(self):
         res = dict(zip(('type', 'source', 'extid'), self.req.describe(self.eid)))
@@ -349,7 +349,7 @@
 
     def has_perm(self, action):
         return self.e_schema.has_perm(self.req, action, self.eid)
-        
+
     def view(self, vid, __registry='views', **kwargs):
         """shortcut to apply a view on this entity"""
         return self.vreg.render(__registry, vid, self.req, rset=self.rset,
@@ -452,9 +452,9 @@
         trdata = TransformData(data, format, encoding, appobject=self)
         data = _engine.convert(trdata, target_format).decode()
         if format == 'text/html':
-            data = soup2xhtml(data, self.req.encoding)                
+            data = soup2xhtml(data, self.req.encoding)
         return data
-    
+
     # entity cloning ##########################################################
 
     def copy_relations(self, ceid):
@@ -517,7 +517,7 @@
         rset = ResultSet([(self.eid,)], 'Any X WHERE X eid %(x)s',
                          {'x': self.eid}, [(self.id,)])
         return self.req.decorate_rset(rset)
-                       
+
     def to_complete_relations(self):
         """by default complete final relations to when calling .complete()"""
         for rschema in self.e_schema.subject_relations():
@@ -533,7 +533,7 @@
                    all(matching_groups(es.get_groups('read'))
                        for es in rschema.objects(self.e_schema)):
                     yield rschema, 'subject'
-                    
+
     def to_complete_attributes(self, skip_bytes=True):
         for rschema, attrschema in self.e_schema.attribute_definitions():
             # skip binary data by default
@@ -548,7 +548,7 @@
                 self[attr] = None
                 continue
             yield attr
-            
+
     def complete(self, attributes=None, skip_bytes=True):
         """complete this entity by adding missing attributes (i.e. query the
         repository to fill the entity)
@@ -618,7 +618,7 @@
                 else:
                     rrset = self.req.eid_rset(value)
                 self.set_related_cache(rtype, x, rrset)
-                
+
     def get_value(self, name):
         """get value for the attribute relation <name>, query the repository
         to get the value if necessary.
@@ -654,7 +654,7 @@
 
     def related(self, rtype, role='subject', limit=None, entities=False):
         """returns a resultset of related entities
-        
+
         :param role: is the role played by 'self' in the relation ('subject' or 'object')
         :param limit: resultset's maximum size
         :param entities: if True, the entites are returned; if False, a result set is returned
@@ -700,7 +700,7 @@
             args = tuple(rql.split(' WHERE ', 1))
             rql = '%s ORDERBY Z DESC WHERE X modification_date Z, %s' % args
         return rql
-    
+
     # generic vocabulary methods ##############################################
 
     @obsolete('see new form api')
@@ -708,7 +708,7 @@
         """vocabulary functions must return a list of couples
         (label, eid) that will typically be used to fill the
         edition view's combobox.
-        
+
         If `eid` is None in one of these couples, it should be
         interpreted as a separator in case vocabulary results are grouped
         """
@@ -717,7 +717,7 @@
         form = EntityFieldsForm(self.req, entity=self)
         field = mock_object(name=rtype, role=role)
         return form.form_field_vocabulary(field, limit)
-            
+
     def unrelated_rql(self, rtype, targettype, role, ordermethod=None,
                       vocabconstraints=True):
         """build a rql to fetch `targettype` entities unrelated to this entity
@@ -753,7 +753,7 @@
             before, after = rql.split(' WHERE ', 1)
             rql = '%s ORDERBY %s WHERE %s' % (before, searchedvar, after)
         return rql
-    
+
     def unrelated(self, rtype, targettype, role='subject', limit=None,
                   ordermethod=None):
         """return a result set of target type objects that may be related
@@ -766,14 +766,14 @@
         if self.has_eid():
             return self.req.execute(rql, {'x': self.eid})
         return self.req.execute(rql)
-        
+
     # relations cache handling ################################################
-    
+
     def relation_cached(self, rtype, role):
         """return true if the given relation is already cached on the instance
         """
         return '%s_%s' % (rtype, role) in self._related_cache
-    
+
     def related_cache(self, rtype, role, entities=True, limit=None):
         """return values for the given relation if it's cached on the instance,
         else raise `KeyError`
@@ -785,7 +785,7 @@
             else:
                 res = res.limit(limit)
         return res
-    
+
     def set_related_cache(self, rtype, role, rset, col=0):
         """set cached values for the given relation"""
         if rset:
@@ -805,7 +805,7 @@
         else:
             related = []
         self._related_cache['%s_%s' % (rtype, role)] = (rset, related)
-        
+
     def clear_related_cache(self, rtype=None, role=None):
         """clear cached values for the given relation or the entire cache if
         no relation is given
@@ -815,9 +815,9 @@
         else:
             assert role
             self._related_cache.pop('%s_%s' % (rtype, role), None)
-        
+
     # raw edition utilities ###################################################
-    
+
     def set_attributes(self, **kwargs):
         assert kwargs
         relations = []
@@ -829,14 +829,14 @@
         kwargs['x'] = self.eid
         self.req.execute('SET %s WHERE X eid %%(x)s' % ','.join(relations),
                          kwargs, 'x')
-            
+
     def delete(self):
         assert self.has_eid(), self.eid
         self.req.execute('DELETE %s X WHERE X eid %%(x)s' % self.e_schema,
                          {'x': self.eid})
-    
+
     # server side utilities ###################################################
-        
+
     def set_defaults(self):
         """set default values according to the schema"""
         self._default_set = set()
@@ -879,13 +879,13 @@
                 yield self
         else:
             yield self
-                    
+
     def get_words(self):
         """used by the full text indexer to get words to index
 
         this method should only be used on the repository side since it depends
         on the indexer package
-        
+
         :rtype: list
         :return: the list of indexable word of this entity
         """
@@ -902,7 +902,7 @@
                 continue
             if value:
                 words += tokenize(value)
-        
+
         for rschema, role in self.e_schema.fulltext_relations():
             if role == 'subject':
                 for entity in getattr(self, rschema.type):
@@ -947,7 +947,7 @@
             raise AttributeError('%s cannot be only be accessed from instances'
                                  % self._rtype)
         return eobj.related(self._rtype, self._role, entities=True)
-    
+
     def __set__(self, eobj, value):
         raise NotImplementedError
 
@@ -955,7 +955,7 @@
 class SubjectRelation(Relation):
     """descriptor that controls schema relation access"""
     _role = 'subject'
-    
+
 class ObjectRelation(Relation):
     """descriptor that controls schema relation access"""
     _role = 'object'