diff -r 717dea3362c0 -r 716f0742ee7f entity.py --- 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 '' % ( 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 , 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'