# HG changeset patch # User Sylvain Thénault # Date 1270728709 -7200 # Node ID d14bfd477c4465123738356a2f9107886a3a2adc # Parent e8235b2789fcdf30fb611dad713a459993b43594# Parent f3c2cb460ad9f2cdf8f100b8c42fafb1335c5a35 backport stable diff -r e8235b2789fc -r d14bfd477c44 devtools/__init__.py --- a/devtools/__init__.py Thu Apr 08 13:38:36 2010 +0200 +++ b/devtools/__init__.py Thu Apr 08 14:11:49 2010 +0200 @@ -155,6 +155,9 @@ sources = super(TestServerConfiguration, self).sources() if not sources: sources = DEFAULT_SOURCES + if sources['system']['db-driver'] == 'sqlite': + # we need an abspath in case tests are changing the cwd + sources['system']['db-name'] = abspath(sources['system']['db-name']) return sources diff -r e8235b2789fc -r d14bfd477c44 doc/book/en/development/devweb/js.rst --- a/doc/book/en/development/devweb/js.rst Thu Apr 08 13:38:36 2010 +0200 +++ b/doc/book/en/development/devweb/js.rst Thu Apr 08 14:11:49 2010 +0200 @@ -5,7 +5,7 @@ *CubicWeb* uses quite a bit of javascript in its user interface and ships with jquery (1.3.x) and parts of the jquery UI library, plus a -number of homegrown files and also other thir party libraries. +number of homegrown files and also other third party libraries. All javascript files are stored in cubicweb/web/data/. There are around thirty js files there. In a cube it goes to data/. diff -r e8235b2789fc -r d14bfd477c44 doc/book/en/development/testing.rst --- a/doc/book/en/development/testing.rst Thu Apr 08 13:38:36 2010 +0200 +++ b/doc/book/en/development/testing.rst Thu Apr 08 14:11:49 2010 +0200 @@ -24,6 +24,10 @@ In most of the cases, you will inherit `EnvBasedTC` to write Unittest or functional tests for your entities, views, hooks, etc... +XXX pytestconf.py & options (e.g --source to use a different db +backend than sqlite) + + Managing connections or users +++++++++++++++++++++++++++++ @@ -33,10 +37,12 @@ By default, tests run with a user with admin privileges. This user/connection must never be closed. -qwq -Before a self.login, one has to release the connection pool in use with a self.commit, self.rollback or self.close. -When one is logged in as a normal user and wants to switch back to the admin user, one has to use self.restore_connection(). +Before a self.login, one has to release the connection pool in use +with a self.commit, self.rollback or self.close. + +When one is logged in as a normal user and wants to switch back to the +admin user, one has to use self.restore_connection(). Usually it looks like this: diff -r e8235b2789fc -r d14bfd477c44 misc/migration/3.7.4_Any.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/migration/3.7.4_Any.py Thu Apr 08 14:11:49 2010 +0200 @@ -0,0 +1,1 @@ +sync_schema_props_perms('TrInfo', syncprops=False) diff -r e8235b2789fc -r d14bfd477c44 schemas/bootstrap.py --- a/schemas/bootstrap.py Thu Apr 08 13:38:36 2010 +0200 +++ b/schemas/bootstrap.py Thu Apr 08 14:11:49 2010 +0200 @@ -311,8 +311,9 @@ def post_build_callback(schema): """set attributes permissions for schema/workflow entities""" from cubicweb.schema import SCHEMA_TYPES, WORKFLOW_TYPES, META_RTYPES + wftypes = WORKFLOW_TYPES - set(('TrInfo',)) for eschema in schema.entities(): - if eschema in SCHEMA_TYPES or eschema in WORKFLOW_TYPES: + if eschema in SCHEMA_TYPES or eschema in wftypes: for rschema in eschema.subject_relations(): if rschema.final and not rschema in META_RTYPES: rdef = eschema.rdef(rschema) diff -r e8235b2789fc -r d14bfd477c44 server/sources/storages.py --- a/server/sources/storages.py Thu Apr 08 13:38:36 2010 +0200 +++ b/server/sources/storages.py Thu Apr 08 14:11:49 2010 +0200 @@ -85,9 +85,16 @@ def entity_updated(self, entity, attr): """an entity using this storage for attr has been updatded""" - binary = entity.pop(attr) - fpath = self.current_fs_path(entity, attr) - UpdateFileOp(entity._cw, filepath=fpath, filedata=binary.getvalue()) + if entity._cw.transaction_data.get('fs_importing'): + oldpath = self.current_fs_path(entity, attr) + fpath = entity[attr].getvalue() + if oldpath != fpath: + DeleteFileOp(entity._cw, filepath=oldpath) + binary = Binary(file(fpath).read()) + else: + binary = entity.pop(attr) + fpath = self.current_fs_path(entity, attr) + UpdateFileOp(entity._cw, filepath=fpath, filedata=binary.getvalue()) return binary def entity_deleted(self, entity, attr): diff -r e8235b2789fc -r d14bfd477c44 server/test/unittest_storage.py --- a/server/test/unittest_storage.py Thu Apr 08 13:38:36 2010 +0200 +++ b/server/test/unittest_storage.py Thu Apr 08 14:11:49 2010 +0200 @@ -57,6 +57,11 @@ return req.create_entity('File', data=Binary(content), data_format=u'text/plain', data_name=u'foo') + def fspath(self, entity): + fspath = self.execute('Any fspath(D) WHERE F eid %(f)s, F data D', + {'f': entity.eid})[0][0] + return fspath.getvalue() + def test_bfss_storage(self): f1 = self.create_file() expected_filepath = osp.join(self.tempdir, '%s_data' % f1.eid) @@ -81,18 +86,14 @@ def test_bfss_sqlite_fspath(self): f1 = self.create_file() expected_filepath = osp.join(self.tempdir, '%s_data' % f1.eid) - fspath = self.execute('Any fspath(D) WHERE F eid %(f)s, F data D', - {'f': f1.eid})[0][0] - self.assertEquals(fspath.getvalue(), expected_filepath) + self.assertEquals(self.fspath(f1), expected_filepath) def test_bfss_fs_importing_doesnt_touch_path(self): self.session.transaction_data['fs_importing'] = True filepath = osp.abspath(__file__) f1 = self.session.create_entity('File', data=Binary(filepath), data_format=u'text/plain', data_name=u'foo') - fspath = self.execute('Any fspath(D) WHERE F eid %(f)s, F data D', - {'f': f1.eid})[0][0] - self.assertEquals(fspath.getvalue(), filepath) + self.assertEquals(self.fspath(f1), filepath) def test_source_storage_transparency(self): with self.temporary_appobjects(DummyBeforeHook, DummyAfterHook): @@ -180,5 +181,21 @@ self.assertEquals(f2.data.getvalue(), 'some other data') + def test_bfss_update_with_fs_importing(self): + # 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') + old_fspath = self.fspath(f1) + self.session.transaction_data['fs_importing'] = True + new_fspath = osp.join(self.tempdir, 'newfile.txt') + file(new_fspath, 'w').write('the new data') + self.execute('SET F data %(d)s WHERE F eid %(f)s', + {'d': Binary(new_fspath), 'f': f1.eid}) + self.commit() + self.assertEquals(f1.data.getvalue(), 'the new data') + self.assertEquals(self.fspath(f1), new_fspath) + self.failIf(osp.isfile(old_fspath)) + + if __name__ == '__main__': unittest_main() diff -r e8235b2789fc -r d14bfd477c44 test/unittest_schema.py --- a/test/unittest_schema.py Thu Apr 08 13:38:36 2010 +0200 +++ b/test/unittest_schema.py Thu Apr 08 14:11:49 2010 +0200 @@ -241,6 +241,17 @@ self.failUnless('has_text' in schema['CWUser'].subject_relations()) self.failIf('has_text' in schema['EmailAddress'].subject_relations()) + def test_permission_settings(self): + schema = loader.load(config) + aschema = schema['TrInfo'].rdef('comment') + self.assertEquals(aschema.get_groups('read'), + set(('managers', 'users', 'guests'))) + self.assertEquals(aschema.get_rqlexprs('read'), + ()) + self.assertEquals(aschema.get_groups('update'), + set(('managers',))) + self.assertEquals([x.expression for x in aschema.get_rqlexprs('update')], + ['U has_update_permission X']) class BadSchemaRQLExprTC(TestCase): def setUp(self): @@ -257,16 +268,20 @@ self.assertEquals(str(ex), msg) def test_rrqlexpr_on_etype(self): - self._test('rrqlexpr_on_eetype.py', "can't use RRQLExpression on ToTo, use an ERQLExpression") + self._test('rrqlexpr_on_eetype.py', + "can't use RRQLExpression on ToTo, use an ERQLExpression") def test_erqlexpr_on_rtype(self): - self._test('erqlexpr_on_ertype.py', "can't use ERQLExpression on relation ToTo toto TuTu, use a RRQLExpression") + self._test('erqlexpr_on_ertype.py', + "can't use ERQLExpression on relation ToTo toto TuTu, use a RRQLExpression") def test_rqlexpr_on_rtype_read(self): - self._test('rqlexpr_on_ertype_read.py', "can't use rql expression for read permission of relation ToTo toto TuTu") + self._test('rqlexpr_on_ertype_read.py', + "can't use rql expression for read permission of relation ToTo toto TuTu") def test_rrqlexpr_on_attr(self): - self._test('rrqlexpr_on_attr.py', "can't use RRQLExpression on attribute ToTo.attr[String], use an ERQLExpression") + self._test('rrqlexpr_on_attr.py', + "can't use RRQLExpression on attribute ToTo.attr[String], use an ERQLExpression") class NormalizeExpressionTC(TestCase): @@ -277,8 +292,10 @@ class RQLExpressionTC(TestCase): def test_comparison(self): - self.assertEquals(ERQLExpression('X is CWUser', 'X', 0), ERQLExpression('X is CWUser', 'X', 0)) - self.assertNotEquals(ERQLExpression('X is CWUser', 'X', 0), ERQLExpression('X is CWGroup', 'X', 0)) + self.assertEquals(ERQLExpression('X is CWUser', 'X', 0), + ERQLExpression('X is CWUser', 'X', 0)) + self.assertNotEquals(ERQLExpression('X is CWUser', 'X', 0), + ERQLExpression('X is CWGroup', 'X', 0)) class GuessRrqlExprMainVarsTC(TestCase): def test_exists(self): diff -r e8235b2789fc -r d14bfd477c44 web/_exceptions.py --- a/web/_exceptions.py Thu Apr 08 13:38:36 2010 +0200 +++ b/web/_exceptions.py Thu Apr 08 14:11:49 2010 +0200 @@ -53,8 +53,7 @@ """raised when a json remote call fails """ def __init__(self, reason=''): - #super(RequestError, self).__init__() # XXX require py >= 2.5 - RequestError.__init__(self) + super(RequestError, self).__init__() self.reason = reason def dumps(self): diff -r e8235b2789fc -r d14bfd477c44 web/data/cubicweb.ajax.js --- a/web/data/cubicweb.ajax.js Thu Apr 08 13:38:36 2010 +0200 +++ b/web/data/cubicweb.ajax.js Thu Apr 08 14:11:49 2010 +0200 @@ -240,6 +240,7 @@ setProgressCursor(); var props = {'fname' : fname, 'pageid' : pageid, 'arg': map(jQuery.toJSON, sliceList(arguments, 1))}; + // XXX we should inline the content of loadRemote here var deferred = loadRemote(JSON_BASE_URL, props, 'POST'); deferred = deferred.addErrback(remoteCallFailed); deferred = deferred.addErrback(resetCursor); diff -r e8235b2789fc -r d14bfd477c44 web/data/cubicweb.compat.js --- a/web/data/cubicweb.compat.js Thu Apr 08 13:38:36 2010 +0200 +++ b/web/data/cubicweb.compat.js Thu Apr 08 14:11:49 2010 +0200 @@ -6,22 +6,26 @@ } } +// XXX looks completely unused (candidate for removal) function getElementsByTagAndClassName(tag, klass, root) { root = root || document; // FIXME root is not used in this compat implementation return jQuery(tag + '.' + klass); } +/* jQUery flattens arrays returned by the mapping function: + >>> y = ['a:b:c', 'd:e'] + >>> jQuery.map(y, function(y) { return y.split(':');}) + ["a", "b", "c", "d", "e"] + // where one would expect: + [ ["a", "b", "c"], ["d", "e"] ] + XXX why not the same argument order as $.map and forEach ? +*/ function map(func, array) { - // XXX jQUery tends to simplify lists with only one element : - // >>> y = ['a:b:c'] - // >>> jQuery.map(y, function(y) { return y.split(':');}) - // ["a", "b", "c"] - // where I would expect : - // [ ["a", "b", "c"] ] - // return jQuery.map(array, func); var result = []; - for (var i=0,length=array.length;i' u'' - % (short_title.replace(' ',' '), cid)) + % (xml_escape(short_title), cid)) diff -r e8235b2789fc -r d14bfd477c44 web/views/primary.py --- a/web/views/primary.py Thu Apr 08 13:38:36 2010 +0200 +++ b/web/views/primary.py Thu Apr 08 14:11:49 2010 +0200 @@ -115,11 +115,8 @@ return u'' def render_entity_attributes(self, entity, siderelations=None): - entity_attributes = self._section_def(entity, 'attributes') - if not entity_attributes: - return - self.w(u'') - for rschema, tschemas, role, dispctrl in entity_attributes: + display_attributes = [] + for rschema, _, role, dispctrl in self._section_def(entity, 'attributes'): vid = dispctrl.get('vid', 'reledit') if rschema.final or vid == 'reledit': value = entity.view(vid, rtype=rschema.type, role=role) @@ -129,16 +126,19 @@ value = self._cw.view(vid, rset) else: value = None - if self.skip_none and (value is None or value == ''): - continue - try: - self._render_attribute(dispctrl, rschema, value, - role=role, table=True) - except TypeError: - warn('[3.6] _render_attribute prototype has changed, ' - 'please update %s' % self.__class___, DeprecationWarning) - self._render_attribute(rschema, value, role=role, table=True) - self.w(u'
') + if not self.skip_none or (value is not None and value != ''): + display_attributes.append( (rschema, role, dispctrl, value) ) + if display_attributes: + self.w(u'') + for rschema, role, dispctrl, value in display_attributes: + try: + self._render_attribute(dispctrl, rschema, value, + role=role, table=True) + except TypeError: + warn('[3.6] _render_attribute prototype has changed, please' + ' update %s' % self.__class___, DeprecationWarning) + self._render_attribute(rschema, value, role=role, table=True) + self.w(u'
') def render_entity_relations(self, entity, siderelations=None): for rschema, tschemas, role, dispctrl in self._section_def(entity, 'relations'):