# HG changeset patch # User Sylvain Thénault # Date 1342520686 -7200 # Node ID 4ba11607d84ad637adcddabcdd0cc83931f7121a # Parent 82272decfa9943a3059f8b86f08861bf5c7066b8 [entity api] unify set_attributes / set_relations into a cw_set method. Closes #2423719 Allowing similar usage as create_entity/cw_instantiate. Update cw code base to remove deprecated calls. diff -r 82272decfa99 -r 4ba11607d84a doc/book/en/annexes/faq.rst --- a/doc/book/en/annexes/faq.rst Tue Jul 17 17:16:28 2012 +0200 +++ b/doc/book/en/annexes/faq.rst Tue Jul 17 12:24:46 2012 +0200 @@ -364,7 +364,7 @@ >>> crypted = crypt_password('joepass') >>> rset = rql('Any U WHERE U is CWUser, U login "joe"') >>> joe = rset.get_entity(0,0) - >>> joe.set_attributes(upassword=Binary(crypted)) + >>> joe.cw_set(upassword=Binary(crypted)) Please, refer to the script example is provided in the `misc/examples/chpasswd.py` file. diff -r 82272decfa99 -r 4ba11607d84a doc/book/en/devrepo/entityclasses/application-logic.rst --- a/doc/book/en/devrepo/entityclasses/application-logic.rst Tue Jul 17 17:16:28 2012 +0200 +++ b/doc/book/en/devrepo/entityclasses/application-logic.rst Tue Jul 17 12:24:46 2012 +0200 @@ -38,7 +38,7 @@ object was built. Setting an attribute or relation value can be done in the context of a -Hook/Operation, using the obj.set_relations(x=42) notation or a plain +Hook/Operation, using the obj.cw_set(x=42) notation or a plain RQL SET expression. In views, it would be preferable to encapsulate the necessary logic in diff -r 82272decfa99 -r 4ba11607d84a doc/book/en/devrepo/entityclasses/data-as-objects.rst --- a/doc/book/en/devrepo/entityclasses/data-as-objects.rst Tue Jul 17 17:16:28 2012 +0200 +++ b/doc/book/en/devrepo/entityclasses/data-as-objects.rst Tue Jul 17 12:24:46 2012 +0200 @@ -47,16 +47,13 @@ related to the current entity by the relation given in parameter and satisfying its constraints -* `set_attributes(**kwargs)`, updates the attributes list with the corresponding - values given named parameters +* :meth:`cw_set(**kwargs)`, updates entity's attributes and/or relation with the + corresponding values given named parameters. To set a relation where this + entity is the object of the relation, use `reverse_` as argument + name. Values may be an entity, a list of entities, or None (meaning that all + relations of the given type from or to this object should be deleted). -* `set_relations(**kwargs)`, add relations to the given object. To - set a relation where this entity is the object of the relation, - use `reverse_` as argument name. Values may be an - entity, a list of entities, or None (meaning that all relations of - the given type from or to this object should be deleted). - -* `copy_relations(ceid)`, copies the relations of the entities having the eid +* :meth:`copy_relations(ceid)`, copies the relations of the entities having the eid given in the parameters on the current entity * `delete()` allows to delete the entity diff -r 82272decfa99 -r 4ba11607d84a doc/book/en/devrepo/repo/hooks.rst --- a/doc/book/en/devrepo/repo/hooks.rst Tue Jul 17 17:16:28 2012 +0200 +++ b/doc/book/en/devrepo/repo/hooks.rst Tue Jul 17 12:24:46 2012 +0200 @@ -206,10 +206,11 @@ Reminder ~~~~~~~~ -You should never use the `entity.foo = 42` notation to update an -entity. It will not do what you expect (updating the -database). Instead, use the :meth:`set_attributes` and -:meth:`set_relations` methods. +You should never use the `entity.foo = 42` notation to update an entity. It will +not do what you expect (updating the database). Instead, use the +:meth:`~cubicweb.entity.Entity.cw_set` method or direct access to entity's +:attr:`cw_edited` attribute if you're writing a hook for 'before_add_entity' or +'before_update_entity' event. How to choose between a before and an after event ? diff -r 82272decfa99 -r 4ba11607d84a doc/book/en/devrepo/testing.rst --- a/doc/book/en/devrepo/testing.rst Tue Jul 17 17:16:28 2012 +0200 +++ b/doc/book/en/devrepo/testing.rst Tue Jul 17 12:24:46 2012 +0200 @@ -70,13 +70,13 @@ def test_cannot_create_cycles(self): # direct obvious cycle - self.assertRaises(ValidationError, self.kw1.set_relations, + self.assertRaises(ValidationError, self.kw1.cw_set, subkeyword_of=self.kw1) # testing indirect cycles kw3 = self.execute('INSERT Keyword SK: SK name "kwgroup2", SK included_in C, ' 'SK subkeyword_of K WHERE C name "classif1", K eid %s' % self.kw1.eid).get_entity(0,0) - self.kw1.set_relations(subkeyword_of=kw3) + self.kw1.cw_set(subkeyword_of=kw3) self.assertRaises(ValidationError, self.commit) The test class defines a :meth:`setup_database` method which populates the @@ -192,10 +192,10 @@ description=u'cubicweb is beautiful') blog_entry_1 = req.create_entity('BlogEntry', title=u'hop', content=u'cubicweb hop') - blog_entry_1.set_relations(entry_of=cubicweb_blog) + blog_entry_1.cw_set(entry_of=cubicweb_blog) blog_entry_2 = req.create_entity('BlogEntry', title=u'yes', content=u'cubicweb yes') - blog_entry_2.set_relations(entry_of=cubicweb_blog) + blog_entry_2.cw_set(entry_of=cubicweb_blog) self.assertEqual(len(MAILBOX), 0) self.commit() self.assertEqual(len(MAILBOX), 2) diff -r 82272decfa99 -r 4ba11607d84a doc/book/en/tutorials/advanced/part02_security.rst --- a/doc/book/en/tutorials/advanced/part02_security.rst Tue Jul 17 17:16:28 2012 +0200 +++ b/doc/book/en/tutorials/advanced/part02_security.rst Tue Jul 17 12:24:46 2012 +0200 @@ -196,7 +196,7 @@ for eid in self.get_data(): entity = self.session.entity_from_eid(eid) if entity.visibility == 'parent': - entity.set_attributes(visibility=u'authenticated') + entity.cw_set(visibility=u'authenticated') class SetVisibilityHook(hook.Hook): __regid__ = 'sytweb.setvisibility' @@ -215,7 +215,7 @@ parent = self._cw.entity_from_eid(self.eidto) child = self._cw.entity_from_eid(self.eidfrom) if child.visibility == 'parent': - child.set_attributes(visibility=parent.visibility) + child.cw_set(visibility=parent.visibility) Notice: @@ -344,7 +344,7 @@ self.assertEquals(len(req.execute('Folder X')), 0) # restricted... # may_be_read_by propagation self.restore_connection() - folder.set_relations(may_be_read_by=toto) + folder.cw_set(may_be_read_by=toto) self.commit() photo1.clear_all_caches() self.failUnless(photo1.may_be_read_by) diff -r 82272decfa99 -r 4ba11607d84a entities/authobjs.py --- a/entities/authobjs.py Tue Jul 17 17:16:28 2012 +0200 +++ b/entities/authobjs.py Tue Jul 17 12:24:46 2012 +0200 @@ -101,7 +101,7 @@ kwargs['for_user'] = self self._cw.create_entity('CWProperty', **kwargs) else: - prop.set_attributes(value=value) + prop.cw_set(value=value) def matching_groups(self, groups): """return the number of the given group(s) in which the user is diff -r 82272decfa99 -r 4ba11607d84a entities/sources.py --- a/entities/sources.py Tue Jul 17 17:16:28 2012 +0200 +++ b/entities/sources.py Tue Jul 17 12:24:46 2012 +0200 @@ -51,7 +51,7 @@ continue raise cfgstr = unicode(generate_source_config(sconfig), self._cw.encoding) - self.set_attributes(config=cfgstr) + self.cw_set(config=cfgstr) class CWSource(_CWSourceCfgMixIn, AnyEntity): @@ -181,5 +181,5 @@ def write_log(self, session, **kwargs): if 'status' not in kwargs: kwargs['status'] = getattr(self, '_status', u'success') - self.set_attributes(log=u'
'.join(self._logs), **kwargs) + self.cw_set(log=u'
'.join(self._logs), **kwargs) self._logs = [] diff -r 82272decfa99 -r 4ba11607d84a entities/test/unittest_base.py --- a/entities/test/unittest_base.py Tue Jul 17 17:16:28 2012 +0200 +++ b/entities/test/unittest_base.py Tue Jul 17 12:24:46 2012 +0200 @@ -70,7 +70,7 @@ email1 = self.execute('INSERT EmailAddress X: X address "maarten.ter.huurne@philips.com"').get_entity(0, 0) email2 = self.execute('INSERT EmailAddress X: X address "maarten@philips.com"').get_entity(0, 0) email3 = self.execute('INSERT EmailAddress X: X address "toto@logilab.fr"').get_entity(0, 0) - email1.set_relations(prefered_form=email2) + email1.cw_set(prefered_form=email2) self.assertEqual(email1.prefered.eid, email2.eid) self.assertEqual(email2.prefered.eid, email2.eid) self.assertEqual(email3.prefered.eid, email3.eid) @@ -104,10 +104,10 @@ e = self.execute('CWUser U WHERE U login "member"').get_entity(0, 0) self.assertEqual(e.dc_title(), 'member') self.assertEqual(e.name(), 'member') - e.set_attributes(firstname=u'bouah') + e.cw_set(firstname=u'bouah') self.assertEqual(e.dc_title(), 'member') self.assertEqual(e.name(), u'bouah') - e.set_attributes(surname=u'lôt') + e.cw_set(surname=u'lôt') self.assertEqual(e.dc_title(), 'member') self.assertEqual(e.name(), u'bouah lôt') diff -r 82272decfa99 -r 4ba11607d84a entities/test/unittest_wfobjs.py --- a/entities/test/unittest_wfobjs.py Tue Jul 17 17:16:28 2012 +0200 +++ b/entities/test/unittest_wfobjs.py Tue Jul 17 12:24:46 2012 +0200 @@ -63,7 +63,7 @@ # gnark gnark bar = wf.add_state(u'bar') self.commit() - bar.set_attributes(name=u'foo') + bar.cw_set(name=u'foo') with self.assertRaises(ValidationError) as cm: self.commit() self.assertEqual(cm.exception.errors, {'name-subject': 'workflow already have a state of that name'}) @@ -86,7 +86,7 @@ # gnark gnark biz = wf.add_transition(u'biz', (bar,), foo) self.commit() - biz.set_attributes(name=u'baz') + biz.cw_set(name=u'baz') with self.assertRaises(ValidationError) as cm: self.commit() self.assertEqual(cm.exception.errors, {'name-subject': 'workflow already have a transition of that name'}) @@ -516,7 +516,7 @@ ['rest']) self.assertEqual(parse_hist(iworkflowable.workflow_history), [('asleep', 'asleep', 'rest', None)]) - user.set_attributes(surname=u'toto') # fulfill condition + user.cw_set(surname=u'toto') # fulfill condition self.commit() iworkflowable.fire_transition('rest') self.commit() diff -r 82272decfa99 -r 4ba11607d84a entity.py --- a/entity.py Tue Jul 17 17:16:28 2012 +0200 +++ b/entity.py Tue Jul 17 12:24:46 2012 +0200 @@ -452,26 +452,13 @@ return mainattr, needcheck @classmethod - def cw_instantiate(cls, execute, **kwargs): - """add a new entity of this given type - - Example (in a shell session): - - >>> companycls = vreg['etypes'].etype_class(('Company') - >>> personcls = vreg['etypes'].etype_class(('Person') - >>> c = companycls.cw_instantiate(session.execute, name=u'Logilab') - >>> p = personcls.cw_instantiate(session.execute, firstname=u'John', lastname=u'Doe', - ... works_for=c) - - You can also set relation where the entity has 'object' role by - prefixing the relation by 'reverse_'. - """ - rql = 'INSERT %s X' % cls.__regid__ + def _cw_build_entity_query(cls, kwargs): relations = [] restrictions = set() pending_relations = [] eschema = cls.e_schema qargs = {} + attrcache = {} for attr, value in kwargs.items(): if attr.startswith('reverse_'): attr = attr[len('reverse_'):] @@ -491,6 +478,9 @@ continue if rschema.final: # attribute relations.append('X %s %%(%s)s' % (attr, attr)) + attrcache[attr] = value + elif value is None: + pending_relations.append( (attr, role, value) ) else: rvar = attr.upper() if role == 'object': @@ -503,19 +493,51 @@ if hasattr(value, 'eid'): value = value.eid qargs[attr] = value + rql = u'' if relations: - rql = '%s: %s' % (rql, ', '.join(relations)) + rql += ', '.join(relations) if restrictions: - rql = '%s WHERE %s' % (rql, ', '.join(restrictions)) - created = execute(rql, qargs).get_entity(0, 0) + rql += ' WHERE %s' % ', '.join(restrictions) + return rql, qargs, pending_relations, attrcache + + @classmethod + def _cw_handle_pending_relations(cls, eid, pending_relations, execute): for attr, role, values in pending_relations: if role == 'object': restr = 'Y %s X' % attr else: restr = 'X %s Y' % attr + if values is None: + execute('DELETE %s WHERE X eid %%(x)s' % restr, {'x': eid}) + continue execute('SET %s WHERE X eid %%(x)s, Y eid IN (%s)' % ( restr, ','.join(str(getattr(r, 'eid', r)) for r in values)), - {'x': created.eid}, build_descr=False) + {'x': eid}, build_descr=False) + + @classmethod + def cw_instantiate(cls, execute, **kwargs): + """add a new entity of this given type + + Example (in a shell session): + + >>> companycls = vreg['etypes'].etype_class(('Company') + >>> personcls = vreg['etypes'].etype_class(('Person') + >>> c = companycls.cw_instantiate(session.execute, name=u'Logilab') + >>> p = personcls.cw_instantiate(session.execute, 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 + an entity or eid, a list of entities or eids. + """ + rql, qargs, pending_relations, attrcache = cls._cw_build_entity_query(kwargs) + if rql: + rql = 'INSERT %s X: %s' % (cls.__regid__, rql) + else: + rql = 'INSERT %s X' % (cls.__regid__) + created = execute(rql, qargs).get_entity(0, 0) + created.cw_attr_cache.update(attrcache) + cls._cw_handle_pending_relations(created.eid, pending_relations, execute) return created def __init__(self, req, rset=None, row=None, col=0): @@ -1212,54 +1234,41 @@ # raw edition utilities ################################################### - def set_attributes(self, **kwargs): # XXX cw_set_attributes + def cw_set(self, **kwargs): + """update this entity using given attributes / relation, working in the + same fashion as :meth:`cw_instantiate`. + + Example (in a shell session): + + >>> 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) + + You can also set relations where the entity has 'object' role by + prefixing the relation name by 'reverse_'. Also, relation values may be + an entity or eid, a list of entities or eids, or None (meaning that all + relations of the given type from or to this object should be deleted). + """ _check_cw_unsafe(kwargs) assert kwargs assert self.cw_is_saved(), "should not call set_attributes while entity "\ "hasn't been saved yet" - relations = ['X %s %%(%s)s' % (key, key) for key in kwargs] - # and now update the database - kwargs['x'] = self.eid - self._cw.execute('SET %s WHERE X eid %%(x)s' % ','.join(relations), - kwargs) - kwargs.pop('x') + rql, qargs, pending_relations, attrcache = self._cw_build_entity_query(kwargs) + if rql: + rql = 'SET ' + rql + qargs['x'] = self.eid + if ' WHERE ' in rql: + rql += ', X eid %(x)s' + else: + rql += ' WHERE X eid %(x)s' + self._cw.execute(rql, qargs) # update current local object _after_ the rql query to avoid # interferences between the query execution itself and the cw_edited / # skip_security machinery - self.cw_attr_cache.update(kwargs) - - def set_relations(self, **kwargs): # XXX cw_set_relations - """add relations to the given object. To set a relation where this entity - is the object of the relation, use 'reverse_' as argument name. - - Values may be an entity or eid, a list of entities or eids, or None - (meaning that all relations of the given type from or to this object - should be deleted). - """ - # XXX update cache - _check_cw_unsafe(kwargs) - for attr, values in kwargs.iteritems(): - if attr.startswith('reverse_'): - restr = 'Y %s X' % attr[len('reverse_'):] - else: - restr = 'X %s Y' % attr - if values is None: - self._cw.execute('DELETE %s WHERE X eid %%(x)s' % restr, - {'x': self.eid}) - continue - if not isinstance(values, (tuple, list, set, frozenset)): - values = (values,) - eids = [] - for val in values: - try: - eids.append(str(val.eid)) - except AttributeError: - try: - eids.append(str(typed_eid(val))) - except (ValueError, TypeError): - raise Exception('expected an Entity or eid, got %s' % val) - self._cw.execute('SET %s WHERE X eid %%(x)s, Y eid IN (%s)' % ( - restr, ','.join(eids)), {'x': self.eid}) + self.cw_attr_cache.update(attrcache) + self._cw_handle_pending_relations(self.eid, pending_relations, self._cw.execute) + # XXX update relation cache def cw_delete(self, **kwargs): assert self.has_eid(), self.eid @@ -1274,6 +1283,21 @@ # deprecated stuff ######################################################### + @deprecated('[3.15] use cw_set() instead') + def set_attributes(self, **kwargs): # XXX cw_set_attributes + self.cw_set(**kwargs) + + @deprecated('[3.15] use cw_set() instead') + def set_relations(self, **kwargs): # XXX cw_set_relations + """add relations to the given object. To set a relation where this entity + is the object of the relation, use 'reverse_' as argument name. + + Values may be an entity or eid, a list of entities or eids, or None + (meaning that all relations of the given type from or to this object + should be deleted). + """ + self.cw_set(**kwargs) + @deprecated('[3.13] use entity.cw_clear_all_caches()') def clear_all_caches(self): return self.cw_clear_all_caches() diff -r 82272decfa99 -r 4ba11607d84a hooks/test/unittest_hooks.py --- a/hooks/test/unittest_hooks.py Tue Jul 17 17:16:28 2012 +0200 +++ b/hooks/test/unittest_hooks.py Tue Jul 17 12:24:46 2012 +0200 @@ -67,9 +67,9 @@ entity = self.request().create_entity('Workflow', name=u'wf1', description_format=u'text/html', description=u'yo') - entity.set_attributes(name=u'wf2') + entity.cw_set(name=u'wf2') self.assertEqual(entity.description, u'yo') - entity.set_attributes(description=u'R&D

yo') + entity.cw_set(description=u'R&D

yo') entity.cw_attr_cache.pop('description') self.assertEqual(entity.description, u'R&D

yo

') diff -r 82272decfa99 -r 4ba11607d84a hooks/test/unittest_syncschema.py --- a/hooks/test/unittest_syncschema.py Tue Jul 17 17:16:28 2012 +0200 +++ b/hooks/test/unittest_syncschema.py Tue Jul 17 12:24:46 2012 +0200 @@ -294,7 +294,7 @@ def test_change_fulltext_container(self): req = self.request() target = req.create_entity(u'EmailAddress', address=u'rick.roll@dance.com') - target.set_relations(reverse_use_email=req.user) + target.cw_set(reverse_use_email=req.user) self.commit() rset = req.execute('Any X WHERE X has_text "rick.roll"') self.assertIn(req.user.eid, [item[0] for item in rset]) diff -r 82272decfa99 -r 4ba11607d84a hooks/workflow.py --- a/hooks/workflow.py Tue Jul 17 17:16:28 2012 +0200 +++ b/hooks/workflow.py Tue Jul 17 12:24:46 2012 +0200 @@ -335,7 +335,7 @@ return entity = self._cw.entity_from_eid(self.eidfrom) try: - entity.set_attributes(modification_date=datetime.now()) + entity.cw_set(modification_date=datetime.now()) except RepositoryError, ex: # usually occurs if entity is coming from a read-only source # (eg ldap user) diff -r 82272decfa99 -r 4ba11607d84a misc/migration/3.10.0_Any.py --- a/misc/migration/3.10.0_Any.py Tue Jul 17 17:16:28 2012 +0200 +++ b/misc/migration/3.10.0_Any.py Tue Jul 17 12:24:46 2012 +0200 @@ -34,5 +34,5 @@ for x in rql('Any X,XK WHERE X pkey XK, ' 'X pkey ~= "boxes.%" OR ' 'X pkey ~= "contentnavigation.%"').entities(): - x.set_attributes(pkey=u'ctxcomponents.' + x.pkey.split('.', 1)[1]) + x.cw_set(pkey=u'ctxcomponents.' + x.pkey.split('.', 1)[1]) diff -r 82272decfa99 -r 4ba11607d84a misc/migration/3.11.0_Any.py --- a/misc/migration/3.11.0_Any.py Tue Jul 17 17:16:28 2012 +0200 +++ b/misc/migration/3.11.0_Any.py Tue Jul 17 12:24:46 2012 +0200 @@ -81,5 +81,5 @@ rset = session.execute('Any V WHERE X is CWProperty, X value V, X pkey %(k)s', {'k': pkey}) timestamp = int(rset[0][0]) - sourceentity.set_attributes(latest_retrieval=datetime.fromtimestamp(timestamp)) + sourceentity.cw_set(latest_retrieval=datetime.fromtimestamp(timestamp)) session.execute('DELETE CWProperty X WHERE X pkey %(k)s', {'k': pkey}) diff -r 82272decfa99 -r 4ba11607d84a misc/migration/3.14.0_Any.py --- a/misc/migration/3.14.0_Any.py Tue Jul 17 17:16:28 2012 +0200 +++ b/misc/migration/3.14.0_Any.py Tue Jul 17 12:24:46 2012 +0200 @@ -9,5 +9,5 @@ expression = rqlcstr.value mainvars = guess_rrqlexpr_mainvars(expression) yamscstr = CONSTRAINTS[rqlcstr.type](expression, mainvars) - rqlcstr.set_attributes(value=yamscstr.serialize()) + rqlcstr.cw_set(value=yamscstr.serialize()) print 'updated', rqlcstr.type, rqlcstr.value.strip() diff -r 82272decfa99 -r 4ba11607d84a misc/migration/3.15.0_Any.py --- a/misc/migration/3.15.0_Any.py Tue Jul 17 17:16:28 2012 +0200 +++ b/misc/migration/3.15.0_Any.py Tue Jul 17 12:24:46 2012 +0200 @@ -4,7 +4,7 @@ config = source.dictconfig host = config.pop('host', u'ldap') protocol = config.pop('protocol', u'ldap') - source.set_attributes(url=u'%s://%s' % (protocol, host)) + source.cw_set(url=u'%s://%s' % (protocol, host)) source.update_config(skip_unknown=True, **config) commit() diff -r 82272decfa99 -r 4ba11607d84a misc/scripts/chpasswd.py --- a/misc/scripts/chpasswd.py Tue Jul 17 17:16:28 2012 +0200 +++ b/misc/scripts/chpasswd.py Tue Jul 17 12:24:46 2012 +0200 @@ -42,7 +42,7 @@ crypted = crypt_password(pass1) cwuser = rset.get_entity(0,0) -cwuser.set_attributes(upassword=Binary(crypted)) +cwuser.cw_set(upassword=Binary(crypted)) commit() print("password updated.") diff -r 82272decfa99 -r 4ba11607d84a misc/scripts/ldapuser2ldapfeed.py --- a/misc/scripts/ldapuser2ldapfeed.py Tue Jul 17 17:16:28 2012 +0200 +++ b/misc/scripts/ldapuser2ldapfeed.py Tue Jul 17 12:24:46 2012 +0200 @@ -70,7 +70,7 @@ source_ent = rql('CWSource S WHERE S eid %(s)s', {'s': source.eid}).get_entity(0, 0) -source_ent.set_attributes(type=u"ldapfeed", parser=u"ldapfeed") +source_ent.cw_set(type=u"ldapfeed", parser=u"ldapfeed") commit() diff -r 82272decfa99 -r 4ba11607d84a server/hook.py --- a/server/hook.py Tue Jul 17 17:16:28 2012 +0200 +++ b/server/hook.py Tue Jul 17 12:24:46 2012 +0200 @@ -152,7 +152,7 @@ On those events, the entity has no `cw_edited` dictionary. -.. note:: `self.entity.set_attributes(age=42)` will set the `age` attribute to +.. note:: `self.entity.cw_set(age=42)` will set the `age` attribute to 42. But to do so, it will generate a rql query that will have to be processed, hence may trigger some hooks, etc. This could lead to infinitely looping hooks. diff -r 82272decfa99 -r 4ba11607d84a server/migractions.py --- a/server/migractions.py Tue Jul 17 17:16:28 2012 +0200 +++ b/server/migractions.py Tue Jul 17 12:24:46 2012 +0200 @@ -1321,7 +1321,7 @@ except Exception: self.cmd_create_entity('CWProperty', pkey=unicode(pkey), value=value) else: - prop.set_attributes(value=value) + prop.cw_set(value=value) # other data migration commands ########################################### diff -r 82272decfa99 -r 4ba11607d84a server/sources/datafeed.py --- a/server/sources/datafeed.py Tue Jul 17 17:16:28 2012 +0200 +++ b/server/sources/datafeed.py Tue Jul 17 12:24:46 2012 +0200 @@ -389,7 +389,7 @@ attrs = dict( (k, v) for k, v in attrs.iteritems() if v != getattr(entity, k)) if attrs: - entity.set_attributes(**attrs) + entity.cw_set(**attrs) self.notify_updated(entity) class DataFeedXMLParser(DataFeedParser): diff -r 82272decfa99 -r 4ba11607d84a server/test/unittest_repository.py --- a/server/test/unittest_repository.py Tue Jul 17 17:16:28 2012 +0200 +++ b/server/test/unittest_repository.py Tue Jul 17 12:24:46 2012 +0200 @@ -521,7 +521,7 @@ self.commit() self.assertEqual(len(c.reverse_fiche), 1) - def test_set_attributes_in_before_update(self): + def test_cw_set_in_before_update(self): # local hook class DummyBeforeHook(Hook): __regid__ = 'dummy-before-hook' @@ -533,31 +533,31 @@ pendings = self._cw.transaction_data.setdefault('pending', set()) if self.entity.eid not in pendings: pendings.add(self.entity.eid) - self.entity.set_attributes(alias=u'foo') + self.entity.cw_set(alias=u'foo') with self.temporary_appobjects(DummyBeforeHook): req = self.request() addr = req.create_entity('EmailAddress', address=u'a@b.fr') - addr.set_attributes(address=u'a@b.com') + addr.cw_set(address=u'a@b.com') rset = self.execute('Any A,AA WHERE X eid %(x)s, X address A, X alias AA', {'x': addr.eid}) self.assertEqual(rset.rows, [[u'a@b.com', u'foo']]) - def test_set_attributes_in_before_add(self): + def test_cw_set_in_before_add(self): # local hook class DummyBeforeHook(Hook): __regid__ = 'dummy-before-hook' __select__ = Hook.__select__ & is_instance('EmailAddress') events = ('before_add_entity',) def __call__(self): - # set_attributes is forbidden within before_add_entity() - self.entity.set_attributes(alias=u'foo') + # cw_set is forbidden within before_add_entity() + self.entity.cw_set(alias=u'foo') with self.temporary_appobjects(DummyBeforeHook): req = self.request() # XXX will fail with python -O self.assertRaises(AssertionError, req.create_entity, 'EmailAddress', address=u'a@b.fr') - def test_multiple_edit_set_attributes(self): + def test_multiple_edit_cw_set(self): """make sure cw_edited doesn't get cluttered by previous entities on multiple set """ @@ -663,7 +663,7 @@ self.commit() rset = req.execute('Any X WHERE X has_text %(t)s', {'t': 'toto'}) self.assertEqual(rset.rows, []) - req.user.set_relations(use_email=toto) + req.user.cw_set(use_email=toto) self.commit() rset = req.execute('Any X WHERE X has_text %(t)s', {'t': 'toto'}) self.assertEqual(rset.rows, [[req.user.eid]]) @@ -673,11 +673,11 @@ rset = req.execute('Any X WHERE X has_text %(t)s', {'t': 'toto'}) self.assertEqual(rset.rows, []) tutu = req.create_entity('EmailAddress', address=u'tutu@logilab.fr') - req.user.set_relations(use_email=tutu) + req.user.cw_set(use_email=tutu) self.commit() rset = req.execute('Any X WHERE X has_text %(t)s', {'t': 'tutu'}) self.assertEqual(rset.rows, [[req.user.eid]]) - tutu.set_attributes(address=u'hip@logilab.fr') + tutu.cw_set(address=u'hip@logilab.fr') self.commit() rset = req.execute('Any X WHERE X has_text %(t)s', {'t': 'tutu'}) self.assertEqual(rset.rows, []) @@ -789,7 +789,7 @@ personnes.append(p) abraham = req.create_entity('Personne', nom=u'Abraham', prenom=u'John', sexe=u'M') for j in xrange(0, 2000, 100): - abraham.set_relations(personne_composite=personnes[j:j+100]) + abraham.cw_set(personne_composite=personnes[j:j+100]) t1 = time.time() self.info('creation: %.2gs', (t1 - t0)) req.cnx.commit() @@ -815,7 +815,7 @@ t1 = time.time() self.info('creation: %.2gs', (t1 - t0)) for j in xrange(100, 2000, 100): - abraham.set_relations(personne_composite=personnes[j:j+100]) + abraham.cw_set(personne_composite=personnes[j:j+100]) t2 = time.time() self.info('more relations: %.2gs', (t2-t1)) req.cnx.commit() @@ -835,7 +835,7 @@ t1 = time.time() self.info('creation: %.2gs', (t1 - t0)) for j in xrange(100, 2000, 100): - abraham.set_relations(personne_inlined=personnes[j:j+100]) + abraham.cw_set(personne_inlined=personnes[j:j+100]) t2 = time.time() self.info('more relations: %.2gs', (t2-t1)) req.cnx.commit() @@ -916,7 +916,7 @@ p1 = req.create_entity('Personne', nom=u'Vincent') p2 = req.create_entity('Personne', nom=u'Florent') w = req.create_entity('Affaire', ref=u'wc') - w.set_relations(todo_by=[p1,p2]) + w.cw_set(todo_by=[p1,p2]) w.cw_clear_all_caches() self.commit() self.assertEqual(len(w.todo_by), 1) @@ -927,9 +927,9 @@ p1 = req.create_entity('Personne', nom=u'Vincent') p2 = req.create_entity('Personne', nom=u'Florent') w = req.create_entity('Affaire', ref=u'wc') - w.set_relations(todo_by=p1) + w.cw_set(todo_by=p1) self.commit() - w.set_relations(todo_by=p2) + w.cw_set(todo_by=p2) w.cw_clear_all_caches() self.commit() self.assertEqual(len(w.todo_by), 1) diff -r 82272decfa99 -r 4ba11607d84a server/test/unittest_storage.py --- a/server/test/unittest_storage.py Tue Jul 17 17:16:28 2012 +0200 +++ b/server/test/unittest_storage.py Tue Jul 17 12:24:46 2012 +0200 @@ -99,7 +99,7 @@ f1 = self.create_file() self.commit() self.assertEqual(file(expected_filepath).read(), 'the-data') - f1.set_attributes(data=Binary('the new data')) + f1.cw_set(data=Binary('the new data')) self.rollback() self.assertEqual(file(expected_filepath).read(), 'the-data') f1.cw_delete() @@ -204,7 +204,7 @@ # use self.session to use server-side cache f1 = self.session.create_entity('File', data=Binary('some data'), data_format=u'text/plain', data_name=u'foo') - # NOTE: do not use set_attributes() which would automatically + # NOTE: do not use cw_set() which would automatically # update f1's local dict. We want the pure rql version to work self.execute('SET F data %(d)s WHERE F eid %(f)s', {'d': Binary('some other data'), 'f': f1.eid}) @@ -218,7 +218,7 @@ # use self.session to use server-side cache f1 = self.session.create_entity('File', data=Binary('some data'), data_format=u'text/plain', data_name=u'foo.txt') - # NOTE: do not use set_attributes() which would automatically + # NOTE: do not use cw_set() which would automatically # update f1's local dict. We want the pure rql version to work self.commit() old_path = self.fspath(f1) @@ -240,7 +240,7 @@ # use self.session to use server-side cache f1 = self.session.create_entity('File', data=Binary('some data'), data_format=u'text/plain', data_name=u'foo.txt') - # NOTE: do not use set_attributes() which would automatically + # NOTE: do not use cw_set() which would automatically # update f1's local dict. We want the pure rql version to work self.commit() old_path = self.fspath(f1) @@ -265,7 +265,7 @@ f = self.session.create_entity('Affaire', opt_attr=Binary('toto')) self.session.commit() self.session.set_cnxset() - f.set_attributes(opt_attr=None) + f.cw_set(opt_attr=None) self.session.commit() @tag('fs_importing', 'update') diff -r 82272decfa99 -r 4ba11607d84a server/test/unittest_undo.py --- a/server/test/unittest_undo.py Tue Jul 17 17:16:28 2012 +0200 +++ b/server/test/unittest_undo.py Tue Jul 17 12:24:46 2012 +0200 @@ -203,7 +203,7 @@ c.cw_delete() txuuid = self.commit() c2 = session.create_entity('Card', title=u'hip', content=u'hip') - p.set_relations(fiche=c2) + p.cw_set(fiche=c2) self.commit() self.assertUndoTransaction(txuuid, [ "Can't restore object relation fiche to entity " @@ -217,7 +217,7 @@ session = self.session g = session.create_entity('CWGroup', name=u'staff') session.execute('DELETE U in_group G WHERE U eid %(x)s', {'x': self.toto.eid}) - self.toto.set_relations(in_group=g) + self.toto.cw_set(in_group=g) self.commit() self.toto.cw_delete() txuuid = self.commit() @@ -265,7 +265,7 @@ email = self.request().create_entity('EmailAddress', address=u'tutu@cubicweb.org') prop = self.request().create_entity('CWProperty', pkey=u'ui.default-text-format', value=u'text/html') - tutu.set_relations(use_email=email, reverse_for_user=prop) + tutu.cw_set(use_email=email, reverse_for_user=prop) self.commit() with self.assertRaises(ValidationError) as cm: self.cnx.undo_transaction(txuuid) @@ -278,7 +278,7 @@ g = session.create_entity('CWGroup', name=u'staff') txuuid = self.commit() session.execute('DELETE U in_group G WHERE U eid %(x)s', {'x': self.toto.eid}) - self.toto.set_relations(in_group=g) + self.toto.cw_set(in_group=g) self.commit() with self.assertRaises(ValidationError) as cm: self.cnx.undo_transaction(txuuid) @@ -304,7 +304,7 @@ c = session.create_entity('Card', title=u'hop', content=u'hop') p = session.create_entity('Personne', nom=u'louis', fiche=c) self.commit() - p.set_relations(fiche=None) + p.cw_set(fiche=None) txuuid = self.commit() self.assertUndoTransaction(txuuid) self.commit() @@ -319,7 +319,7 @@ c = session.create_entity('Card', title=u'hop', content=u'hop') p = session.create_entity('Personne', nom=u'louis', fiche=c) self.commit() - p.set_relations(fiche=None) + p.cw_set(fiche=None) txuuid = self.commit() c.cw_delete() self.commit() @@ -339,7 +339,7 @@ c = session.create_entity('Card', title=u'hop', content=u'hop') p = session.create_entity('Personne', nom=u'louis') self.commit() - p.set_relations(fiche=c) + p.cw_set(fiche=c) txuuid = self.commit() self.assertUndoTransaction(txuuid) self.commit() @@ -354,7 +354,7 @@ c = session.create_entity('Card', title=u'hop', content=u'hop') p = session.create_entity('Personne', nom=u'louis') self.commit() - p.set_relations(fiche=c) + p.cw_set(fiche=c) txuuid = self.commit() c.cw_delete() self.commit() @@ -369,7 +369,7 @@ c2 = session.create_entity('Card', title=u'hip', content=u'hip') p = session.create_entity('Personne', nom=u'louis', fiche=c1) self.commit() - p.set_relations(fiche=c2) + p.cw_set(fiche=c2) txuuid = self.commit() self.assertUndoTransaction(txuuid) self.commit() @@ -385,7 +385,7 @@ c2 = session.create_entity('Card', title=u'hip', content=u'hip') p = session.create_entity('Personne', nom=u'louis', fiche=c1) self.commit() - p.set_relations(fiche=c2) + p.cw_set(fiche=c2) txuuid = self.commit() c1.cw_delete() self.commit() @@ -401,7 +401,7 @@ p = session.create_entity('Personne', nom=u'toto') session.commit() self.session.set_cnxset() - p.set_attributes(nom=u'titi') + p.cw_set(nom=u'titi') txuuid = self.commit() self.assertUndoTransaction(txuuid) p.cw_clear_all_caches() @@ -412,7 +412,7 @@ p = session.create_entity('Personne', nom=u'toto') session.commit() self.session.set_cnxset() - p.set_attributes(nom=u'titi') + p.cw_set(nom=u'titi') txuuid = self.commit() p.cw_delete() self.commit() diff -r 82272decfa99 -r 4ba11607d84a sobjects/ldapparser.py --- a/sobjects/ldapparser.py Tue Jul 17 17:16:28 2012 +0200 +++ b/sobjects/ldapparser.py Tue Jul 17 12:24:46 2012 +0200 @@ -81,7 +81,7 @@ attrs = dict( (k, v) for k, v in attrs.iteritems() if v != getattr(entity, k)) if attrs: - entity.set_attributes(**attrs) + entity.cw_set(**attrs) self.notify_updated(entity) def ldap2cwattrs(self, sdict, tdict=None): @@ -110,7 +110,7 @@ if entity.__regid__ == 'EmailAddress': return groups = [self._get_group(n) for n in self.source.user_default_groups] - entity.set_relations(in_group=groups) + entity.cw_set(in_group=groups) self._process_email(entity, sourceparams) def is_deleted(self, extid, etype, eid): @@ -137,9 +137,9 @@ email = self.extid2entity(emailextid, 'EmailAddress', address=emailaddr) if entity.primary_email: - entity.set_relations(use_email=email) + entity.cw_set(use_email=email) else: - entity.set_relations(primary_email=email) + entity.cw_set(primary_email=email) elif self.sourceuris: # pop from sourceuris anyway, else email may be removed by the # source once import is finished diff -r 82272decfa99 -r 4ba11607d84a test/unittest_entity.py --- a/test/unittest_entity.py Tue Jul 17 17:16:28 2012 +0200 +++ b/test/unittest_entity.py Tue Jul 17 12:24:46 2012 +0200 @@ -687,23 +687,23 @@ self.assertEqual(card4.rest_path(), unicode(card4.eid)) - def test_set_attributes(self): + def test_cw_set_attributes(self): req = self.request() person = req.create_entity('Personne', nom=u'di mascio', prenom=u'adrien') self.assertEqual(person.prenom, u'adrien') self.assertEqual(person.nom, u'di mascio') - person.set_attributes(prenom=u'sylvain', nom=u'thénault') + person.cw_set(prenom=u'sylvain', nom=u'thénault') person = self.execute('Personne P').get_entity(0, 0) # XXX retreival needed ? self.assertEqual(person.prenom, u'sylvain') self.assertEqual(person.nom, u'thénault') - def test_set_relations(self): + def test_cw_set_relations(self): req = self.request() person = req.create_entity('Personne', nom=u'chauvat', prenom=u'nicolas') note = req.create_entity('Note', type=u'x') - note.set_relations(ecrit_par=person) + note.cw_set(ecrit_par=person) note = req.create_entity('Note', type=u'y') - note.set_relations(ecrit_par=person.eid) + note.cw_set(ecrit_par=person.eid) self.assertEqual(len(person.reverse_ecrit_par), 2) def test_metainformation_and_external_absolute_url(self): diff -r 82272decfa99 -r 4ba11607d84a web/test/unittest_reledit.py --- a/web/test/unittest_reledit.py Tue Jul 17 17:16:28 2012 +0200 +++ b/web/test/unittest_reledit.py Tue Jul 17 12:24:46 2012 +0200 @@ -175,8 +175,8 @@ def setup_database(self): super(ClickAndEditFormUICFGTC, self).setup_database() - self.tick.set_relations(concerns=self.proj) - self.proj.set_relations(manager=self.toto) + self.tick.cw_set(concerns=self.proj) + self.proj.cw_set(manager=self.toto) def test_with_uicfg(self): old_rctl = reledit_ctrl._tagdefs.copy() diff -r 82272decfa99 -r 4ba11607d84a web/test/unittest_urlrewrite.py --- a/web/test/unittest_urlrewrite.py Tue Jul 17 17:16:28 2012 +0200 +++ b/web/test/unittest_urlrewrite.py Tue Jul 17 12:24:46 2012 +0200 @@ -105,9 +105,9 @@ def setup_database(self): req = self.request() self.p1 = self.create_user(req, u'user1') - self.p1.set_attributes(firstname=u'joe', surname=u'Dalton') + self.p1.cw_set(firstname=u'joe', surname=u'Dalton') self.p2 = self.create_user(req, u'user2') - self.p2.set_attributes(firstname=u'jack', surname=u'Dalton') + self.p2.cw_set(firstname=u'jack', surname=u'Dalton') def test_rgx_action_with_transforms(self): class TestSchemaBasedRewriter(SchemaBasedRewriter):