--- a/__pkginfo__.py Thu Jun 13 17:27:43 2013 +0200
+++ b/__pkginfo__.py Tue Jul 09 15:58:26 2013 +0200
@@ -22,7 +22,7 @@
modname = distname = "cubicweb"
-numversion = (3, 17, 2)
+numversion = (3, 17, 3)
version = '.'.join(str(num) for num in numversion)
description = "a repository of entities / relations for knowledge management"
--- a/cubicweb.spec Thu Jun 13 17:27:43 2013 +0200
+++ b/cubicweb.spec Tue Jul 09 15:58:26 2013 +0200
@@ -7,7 +7,7 @@
%endif
Name: cubicweb
-Version: 3.17.2
+Version: 3.17.3
Release: logilab.1%{?dist}
Summary: CubicWeb is a semantic web application framework
Source0: http://download.logilab.org/pub/cubicweb/cubicweb-%{version}.tar.gz
--- a/debian.hardy/compat Thu Jun 13 17:27:43 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-5
--- a/debian.hardy/rules Thu Jun 13 17:27:43 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-#!/usr/bin/make -f
-# Sample debian/rules that uses debhelper.
-# GNU copyright 1997 to 1999 by Joey Hess.
-
-# Uncomment this to turn on verbose mode.
-#export DH_VERBOSE=1
-
-PY_VERSION:=$(shell pyversions -d)
-
-build: build-stamp
-build-stamp:
- dh_testdir
- # XXX doesn't work if logilab-doctools, logilab-xml are not in build depends
- # and I can't get pbuilder find them in its chroot :(
- # cd doc && make
- # FIXME cleanup and use sphinx-build as build-depends ?
- NO_SETUPTOOLS=1 python setup.py build
- touch build-stamp
-
-clean:
- dh_testdir
- dh_testroot
- rm -f build-stamp configure-stamp
- rm -rf build
- #rm -rf debian/cubicweb-*/
- find . -name "*.pyc" -delete
- rm -f $(basename $(wildcard debian/*.in))
- dh_clean
-
-install: build $(basename $(wildcard debian/*.in))
- dh_testdir
- dh_testroot
- dh_clean
- dh_installdirs
-
- NO_SETUPTOOLS=1 python setup.py -q install --no-compile --prefix=debian/tmp/usr
-
- # Put all the python library and data in cubicweb-common
- # and scripts in cubicweb-server
- dh_install -vi
- # cwctl in the cubicweb-ctl package
- rm -f debian/cubicweb-common/usr/share/pyshared/cubicweb/cwctl.py
-
-
- # Remove unittests directory (should be available in cubicweb-dev only)
- rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/server/test
- rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/hooks/test
- rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/sobjects/test
- rm -rf debian/cubicweb-web/usr/lib/${PY_VERSION}/site-packages/cubicweb/web/test
- rm -rf debian/cubicweb-twisted/usr/lib/${PY_VERSION}/site-packages/cubicweb/etwist/test
- rm -rf debian/cubicweb-common/usr/lib/${PY_VERSION}/site-packages/cubicweb/ext/test
- rm -rf debian/cubicweb-common/usr/lib/${PY_VERSION}/site-packages/cubicweb/entities/test
-
- # cubes directory must be managed as a valid python module
- touch debian/cubicweb-common/usr/share/cubicweb/cubes/__init__.py
-
-%: %.in
- sed "s/PY_VERSION/${PY_VERSION}/g" < $< > $@
-
-# Build architecture-independent files here.
-binary-indep: build install
- dh_testdir
- dh_testroot -i
- dh_pycentral -i
- dh_installinit -i -n --name cubicweb -u"defaults 99"
- dh_installlogrotate -i
- dh_installdocs -i -A README
- dh_installman -i
- dh_installchangelogs -i
- dh_link -i
- dh_compress -i -X.py -X.ini -X.xml
- dh_fixperms -i
- dh_installdeb -i
- dh_gencontrol -i
- dh_md5sums -i
- dh_builddeb -i
-
-binary-arch:
-
-binary: binary-indep
-.PHONY: build clean binary binary-indep binary-arch
-
--- a/debian/changelog Thu Jun 13 17:27:43 2013 +0200
+++ b/debian/changelog Tue Jul 09 15:58:26 2013 +0200
@@ -1,3 +1,9 @@
+cubicweb (3.17.3-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- David Douard <david.douard@logilab.fr> Tue, 09 Jul 2013 15:10:16 +0200
+
cubicweb (3.17.2-1) unstable; urgency=low
* new upstream release
--- a/devtools/httptest.py Thu Jun 13 17:27:43 2013 +0200
+++ b/devtools/httptest.py Tue Jul 09 15:58:26 2013 +0200
@@ -20,6 +20,7 @@
"""
__docformat__ = "restructuredtext en"
+import random
import threading
import socket
import httplib
@@ -46,6 +47,8 @@
.. see:: :func:`test.test_support.bind_port`
"""
+ ports_scan = list(ports_scan)
+ random.shuffle(ports_scan) # lower the chance of race condition
for port in ports_scan:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
--- a/entities/adapters.py Thu Jun 13 17:27:43 2013 +0200
+++ b/entities/adapters.py Tue Jul 09 15:58:26 2013 +0200
@@ -379,6 +379,7 @@
class IUserFriendlyError(view.EntityAdapter):
__regid__ = 'IUserFriendlyError'
__abstract__ = True
+
def __init__(self, *args, **kwargs):
self.exc = kwargs.pop('exc')
super(IUserFriendlyError, self).__init__(*args, **kwargs)
@@ -386,11 +387,27 @@
class IUserFriendlyUniqueTogether(IUserFriendlyError):
__select__ = match_exception(UniqueTogetherError)
+
def raise_user_exception(self):
etype, rtypes = self.exc.args
- msg = self._cw._('violates unique_together constraints (%s)') % (
- ', '.join([self._cw._(rtype) for rtype in rtypes]))
- raise ValidationError(self.entity.eid, dict((col, msg) for col in rtypes))
+ # Because of index name size limits (e.g: postgres around 64,
+ # sqlserver around 128), we cannot be sure of what we got,
+ # especially for the rtypes part.
+ # Hence we will try to validate them, and handle invalid ones
+ # in the most user-friendly manner ...
+ _ = self._cw._
+ schema = self.entity._cw.vreg.schema
+ rtypes_msg = {}
+ for rtype in rtypes:
+ if rtype in schema:
+ rtypes_msg[rtype] = _('%s is part of violated unicity constraint') % rtype
+ globalmsg = _('some relations %sviolate a unicity constraint')
+ if len(rtypes) != len(rtypes_msg): # we got mangled/missing rtypes
+ globalmsg = globalmsg % _('(not all shown here) ')
+ else:
+ globalmsg = globalmsg % ''
+ rtypes_msg['unicity constraint'] = globalmsg
+ raise ValidationError(self.entity.eid, rtypes_msg)
# deprecated ###################################################################
--- a/hooks/security.py Thu Jun 13 17:27:43 2013 +0200
+++ b/hooks/security.py Tue Jul 09 15:58:26 2013 +0200
@@ -23,10 +23,13 @@
from logilab.common.registry import objectify_predicate
+from yams import buildobjs
+
from cubicweb import Unauthorized
from cubicweb.server import BEFORE_ADD_RELATIONS, ON_COMMIT_ADD_RELATIONS, hook
+_DEFAULT_UPDATE_ATTRPERM = buildobjs.DEFAULT_ATTRPERMS['update']
def check_entity_attributes(session, entity, editedattrs=None, creation=False):
eid = entity.eid
eschema = entity.e_schema
@@ -39,9 +42,26 @@
if attr in dontcheck:
continue
rdef = eschema.rdef(attr)
- if rdef.final: # non final relation are checked by other hooks
- # add/delete should be equivalent (XXX: unify them into 'update' ?)
- if creation and not rdef.permissions.get('update'):
+ if rdef.final: # non final relation are checked by standard hooks
+ # attributes only have a specific 'update' permission
+ updateperm = rdef.permissions.get('update')
+ # comparison below works because the default update perm is:
+ #
+ # ('managers', ERQLExpression(Any X WHERE U has_update_permission X, X eid %(x)s, U eid %(u)s))
+ #
+ # is deserialized in this order (groups first), and ERQLExpression
+ # implements comparison by expression.
+ if updateperm == _DEFAULT_UPDATE_ATTRPERM:
+ # The default update permission is to delegate to the entity
+ # update permission. This is an historical artefact but it is
+ # costly (in general). Hence we take this permission object as a
+ # marker saying "no specific" update permissions for this
+ # attribute. Thus we just do nothing.
+ continue
+ if creation and updateperm == ():
+ # That actually means an immutable attribute. We make an
+ # _exception_ to the `check attr update perms at entity create &
+ # update time` rule for this case.
continue
rdef.check_perm(session, 'update', eid=eid)
--- a/i18n/de.po Thu Jun 13 17:27:43 2013 +0200
+++ b/i18n/de.po Tue Jul 09 15:58:26 2013 +0200
@@ -114,6 +114,10 @@
msgstr "%s Fehlerbericht"
#, python-format
+msgid "%s is part of violated unicity constraint"
+msgstr ""
+
+#, python-format
msgid "%s not estimated"
msgstr "%s unbekannt(e)"
@@ -145,6 +149,9 @@
msgid "(UNEXISTANT EID)"
msgstr "(EID nicht gefunden)"
+msgid "(not all shown here) "
+msgstr ""
+
#, python-format
msgid "(suppressed) entity #%d"
msgstr ""
@@ -3861,6 +3868,10 @@
"Eine oder mehrere frühere Transaktion(en) betreffen die Tntität. Machen Sie "
"sie zuerst rückgängig."
+#, python-format
+msgid "some relations %sviolate a unicity constraint"
+msgstr ""
+
msgid "sorry, the server is unable to handle this query"
msgstr "Der Server kann diese Anfrage leider nicht bearbeiten."
--- a/i18n/en.po Thu Jun 13 17:27:43 2013 +0200
+++ b/i18n/en.po Tue Jul 09 15:58:26 2013 +0200
@@ -106,6 +106,10 @@
msgstr ""
#, python-format
+msgid "%s is part of violated unicity constraint"
+msgstr ""
+
+#, python-format
msgid "%s not estimated"
msgstr ""
@@ -137,6 +141,9 @@
msgid "(UNEXISTANT EID)"
msgstr ""
+msgid "(not all shown here) "
+msgstr ""
+
#, python-format
msgid "(suppressed) entity #%d"
msgstr ""
@@ -3766,6 +3773,10 @@
msgid "some later transaction(s) touch entity, undo them first"
msgstr ""
+#, python-format
+msgid "some relations %sviolate a unicity constraint"
+msgstr ""
+
msgid "sorry, the server is unable to handle this query"
msgstr ""
--- a/i18n/es.po Thu Jun 13 17:27:43 2013 +0200
+++ b/i18n/es.po Tue Jul 09 15:58:26 2013 +0200
@@ -115,6 +115,10 @@
msgstr "%s reporte de errores"
#, python-format
+msgid "%s is part of violated unicity constraint"
+msgstr ""
+
+#, python-format
msgid "%s not estimated"
msgstr "%s no estimado(s)"
@@ -146,6 +150,9 @@
msgid "(UNEXISTANT EID)"
msgstr "(EID INEXISTENTE"
+msgid "(not all shown here) "
+msgstr ""
+
#, python-format
msgid "(suppressed) entity #%d"
msgstr ""
@@ -3909,6 +3916,10 @@
msgstr ""
"Las transacciones más recientes modificaron esta entidad, anúlelas primero"
+#, python-format
+msgid "some relations %sviolate a unicity constraint"
+msgstr ""
+
msgid "sorry, the server is unable to handle this query"
msgstr "Lo sentimos, el servidor no puede manejar esta consulta"
--- a/i18n/fr.po Thu Jun 13 17:27:43 2013 +0200
+++ b/i18n/fr.po Tue Jul 09 15:58:26 2013 +0200
@@ -115,6 +115,10 @@
msgstr "%s rapport d'erreur"
#, python-format
+msgid "%s is part of violated unicity constraint"
+msgstr "%s appartient à une contrainte d'unicité transgressée"
+
+#, python-format
msgid "%s not estimated"
msgstr "%s non estimé(s)"
@@ -148,6 +152,9 @@
msgid "(UNEXISTANT EID)"
msgstr "(EID INTROUVABLE)"
+msgid "(not all shown here) "
+msgstr "(toutes ne sont pas montrées)"
+
#, python-format
msgid "(suppressed) entity #%d"
msgstr "entité #%d (supprimée)"
@@ -3922,6 +3929,10 @@
msgstr ""
"des transactions plus récentes modifient cette entité, annulez les d'abord"
+#, python-format
+msgid "some relations %sviolate a unicity constraint"
+msgstr "certaines relations %stransgressent une contrainte d'unicité"
+
msgid "sorry, the server is unable to handle this query"
msgstr "désolé, le serveur ne peut traiter cette requête"
--- a/server/repository.py Thu Jun 13 17:27:43 2013 +0200
+++ b/server/repository.py Tue Jul 09 15:58:26 2013 +0200
@@ -1661,7 +1661,7 @@
# client was not yet connected to the repo
return
if not session.closed:
- session.close()
+ self.close(session.id)
daemon.removeConnection = removeConnection
return daemon
--- a/server/session.py Thu Jun 13 17:27:43 2013 +0200
+++ b/server/session.py Tue Jul 09 15:58:26 2013 +0200
@@ -720,14 +720,13 @@
class Session(RequestSessionBase):
"""Repository user session
- This tie all together:
+ This ties all together:
* session id,
* user,
* connections set,
* other session data.
- About session storage / transactions
- ------------------------------------
+ **About session storage / transactions**
Here is a description of internal session attributes. Besides :attr:`data`
and :attr:`transaction_data`, you should not have to use attributes
--- a/server/sources/native.py Thu Jun 13 17:27:43 2013 +0200
+++ b/server/sources/native.py Tue Jul 09 15:58:26 2013 +0200
@@ -410,14 +410,14 @@
def init(self, activated, source_entity):
- super(NativeSQLSource, self).init(activated, source_entity)
- self.init_creating(source_entity._cw.cnxset)
try:
# test if 'asource' column exists
query = self.dbhelper.sql_add_limit_offset('SELECT asource FROM entities', 1)
source_entity._cw.system_sql(query)
except Exception as ex:
self.eid_type_source = self.eid_type_source_pre_131
+ super(NativeSQLSource, self).init(activated, source_entity)
+ self.init_creating(source_entity._cw.cnxset)
def shutdown(self):
if self._eid_creation_cnx:
@@ -757,15 +757,15 @@
if ex.__class__.__name__ == 'IntegrityError':
# need string comparison because of various backends
for arg in ex.args:
- mo = re.search('unique_cw_[^ ]+_idx', arg)
+ # postgres and sqlserver
+ mo = re.search('"unique_cw_[^ ]+"', arg)
if mo is not None:
- index_name = mo.group(0)
- # right-chop '_idx' postfix
- # (garanteed to be there, see regexp above)
- elements = index_name[:-4].split('_cw_')[1:]
+ index_name = mo.group(0)[1:-1] # eat the surrounding " pair
+ elements = index_name.split('_cw_')[1:]
etype = elements[0]
rtypes = elements[1:]
raise UniqueTogetherError(etype, rtypes)
+ # sqlite
mo = re.search('columns (.*) are not unique', arg)
if mo is not None: # sqlite in use
# we left chop the 'cw_' prefix of attribute names
--- a/server/test/unittest_ldapsource.py Thu Jun 13 17:27:43 2013 +0200
+++ b/server/test/unittest_ldapsource.py Tue Jul 09 15:58:26 2013 +0200
@@ -142,16 +142,26 @@
return self._pull(self.session)
def setup_database(self):
- if self.test_db_id == 'ldap-feed':
- with self.session.repo.internal_session(safe=True) as session:
- session.execute('DELETE Any E WHERE E cw_source S, S name "ldap"')
- session.commit()
- if self.test_db_id == 'ldap-feed':
- src = self.sexecute('CWSource S WHERE S name "ldap"').get_entity(0,0)
- src.cw_set(config=CONFIG_LDAPFEED)
- self.session.commit()
+ with self.session.repo.internal_session(safe=True) as session:
+ session.execute('DELETE Any E WHERE E cw_source S, S name "ldap"')
+ session.execute('SET S config %(conf)s, S url %(url)s '
+ 'WHERE S is CWSource, S name "ldap"',
+ {"conf": CONFIG_LDAPFEED, 'url': URL} )
+ session.commit()
self.pull()
+ def add_ldap_entry(self, dn, mods):
+ """
+ add an LDAP entity
+ """
+ modcmd = ['dn: %s'%dn, 'changetype: add']
+ for key, values in mods.iteritems():
+ if isinstance(values, basestring):
+ values = [values]
+ for value in values:
+ modcmd.append('%s: %s'%(key, value))
+ self._ldapmodify(modcmd)
+
def delete_ldap_entry(self, dn):
"""
delete an LDAP entity
@@ -328,9 +338,23 @@
'deactivated')
# check that it doesn't choke
self.pull()
- # reset the ldap database
- self.tearDownClass()
- self.setUpClass()
+ # reinsert syt
+ self.add_ldap_entry('uid=syt,ou=People,dc=cubicweb,dc=test',
+ { 'objectClass': ['OpenLDAPperson','posixAccount','top','shadowAccount'],
+ 'cn': 'Sylvain Thenault',
+ 'sn': 'Thenault',
+ 'gidNumber': '1004',
+ 'uid': 'syt',
+ 'homeDirectory': '/home/syt',
+ 'shadowFlag': '134538764',
+ 'uidNumber': '1004',
+ 'givenName': 'Sylvain',
+ 'telephoneNumber': '106',
+ 'displayName': 'sthenault',
+ 'gecos': 'Sylvain Thenault',
+ 'mail': ['sylvain.thenault@logilab.fr','syt@logilab.fr'],
+ 'userPassword': 'syt',
+ })
self.pull()
self.assertEqual(self.execute('Any N WHERE U login "syt", '
'U in_state S, S name N').rows[0][0],
@@ -429,8 +453,5 @@
-
-
-
if __name__ == '__main__':
unittest_main()
--- a/server/test/unittest_repository.py Thu Jun 13 17:27:43 2013 +0200
+++ b/server/test/unittest_repository.py Tue Jul 09 15:58:26 2013 +0200
@@ -52,16 +52,18 @@
and relation
"""
- def test_uniquetogether(self):
+ def test_unique_together_constraint(self):
self.execute('INSERT Societe S: S nom "Logilab", S type "SSLL", S cp "75013"')
with self.assertRaises(ValidationError) as wraperr:
self.execute('INSERT Societe S: S nom "Logilab", S type "SSLL", S cp "75013"')
- self.assertEqual({'nom': u'violates unique_together constraints (cp, nom, type)',
- 'cp': u'violates unique_together constraints (cp, nom, type)',
- 'type': u'violates unique_together constraints (cp, nom, type)'},
- wraperr.exception.args[1])
+ self.assertEqual(
+ {'cp': u'cp is part of violated unicity constraint',
+ 'nom': u'nom is part of violated unicity constraint',
+ 'type': u'type is part of violated unicity constraint',
+ 'unicity constraint': u'some relations violate a unicity constraint'},
+ wraperr.exception.args[1])
- def test_unique_together(self):
+ def test_unique_together_schema(self):
person = self.repo.schema.eschema('Personne')
self.assertEqual(len(person._unique_together), 1)
self.assertItemsEqual(person._unique_together[0],
@@ -272,19 +274,21 @@
def test_initial_schema(self):
schema = self.repo.schema
# check order of attributes is respected
- self.assertListEqual([r.type for r in schema.eschema('CWAttribute').ordered_relations()
- if not r.type in ('eid', 'is', 'is_instance_of', 'identity',
- 'creation_date', 'modification_date', 'cwuri',
- 'owned_by', 'created_by', 'cw_source',
- 'update_permission', 'read_permission',
- 'in_basket')],
- ['relation_type',
- 'from_entity', 'to_entity',
- 'constrained_by',
- 'cardinality', 'ordernum',
- 'indexed', 'fulltextindexed', 'internationalizable',
- 'defaultval', 'extra_props',
- 'description', 'description_format'])
+ notin = set(('eid', 'is', 'is_instance_of', 'identity',
+ 'creation_date', 'modification_date', 'cwuri',
+ 'owned_by', 'created_by', 'cw_source',
+ 'update_permission', 'read_permission',
+ 'in_basket'))
+ self.assertListEqual(['relation_type',
+ 'from_entity', 'to_entity',
+ 'constrained_by',
+ 'cardinality', 'ordernum',
+ 'indexed', 'fulltextindexed', 'internationalizable',
+ 'defaultval', 'extra_props',
+ 'description', 'description_format'],
+ [r.type
+ for r in schema.eschema('CWAttribute').ordered_relations()
+ if r.type not in notin])
self.assertEqual(schema.eschema('CWEType').main_attribute(), 'name')
self.assertEqual(schema.eschema('State').main_attribute(), 'name')
--- a/server/test/unittest_schemaserial.py Thu Jun 13 17:27:43 2013 +0200
+++ b/server/test/unittest_schemaserial.py Tue Jul 09 15:58:26 2013 +0200
@@ -28,6 +28,7 @@
from logilab.database import get_db_helper
from yams import register_base_type, unregister_base_type
+schema = config = None
def setUpModule(*args):
register_base_type('BabarTestType', ('jungle_speed',))
helper = get_db_helper('sqlite')
@@ -44,7 +45,7 @@
def tearDownModule(*args):
global schema, config
- del schema, config
+ schema = config = None
unregister_base_type('BabarTestType')
helper = get_db_helper('sqlite')
@@ -63,29 +64,29 @@
class Schema2RQLTC(TestCase):
def test_eschema2rql1(self):
- self.assertListEqual(list(eschema2rql(schema.eschema('CWAttribute'))),
- [
+ self.assertListEqual([
('INSERT CWEType X: X description %(description)s,X final %(final)s,X name %(name)s',
{'description': u'define a final relation: link a final relation type from a non final entity to a final entity type. used to build the instance schema',
- 'name': u'CWAttribute', 'final': False})
- ])
+ 'name': u'CWAttribute', 'final': False})],
+ list(eschema2rql(schema.eschema('CWAttribute'))))
def test_eschema2rql2(self):
- self.assertListEqual(list(eschema2rql(schema.eschema('String'))), [
+ self.assertListEqual([
('INSERT CWEType X: X description %(description)s,X final %(final)s,X name %(name)s',
- {'description': u'', 'final': True, 'name': u'String'})])
+ {'description': u'', 'final': True, 'name': u'String'})],
+ list(eschema2rql(schema.eschema('String'))))
def test_eschema2rql_specialization(self):
# x: None since eschema.eid are None
- self.assertListEqual(sorted(specialize2rql(schema)),
- [('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
- {'et': None, 'x': None}),
- ('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
- {'et': None, 'x': None}),
- ('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
- {'et': None, 'x': None}),
- ('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
- {'et': None, 'x': None})])
+ self.assertListEqual([('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
+ {'et': None, 'x': None}),
+ ('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
+ {'et': None, 'x': None}),
+ ('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
+ {'et': None, 'x': None}),
+ ('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
+ {'et': None, 'x': None})],
+ sorted(specialize2rql(schema)))
def test_esche2rql_custom_type(self):
expected = [('INSERT CWEType X: X description %(description)s,X final %(final)s,X name %(name)s',
@@ -95,8 +96,7 @@
self.assertListEqual(expected, got)
def test_rschema2rql1(self):
- self.assertListEqual(list(rschema2rql(schema.rschema('relation_type'), cstrtypemap)),
- [
+ self.assertListEqual([
('INSERT CWRType X: X description %(description)s,X final %(final)s,X fulltext_container %(fulltext_container)s,X inlined %(inlined)s,X name %(name)s,X symmetric %(symmetric)s',
{'description': u'link a relation definition to its relation type', 'symmetric': False, 'name': u'relation_type', 'final' : False, 'fulltext_container': None, 'inlined': True}),
@@ -113,11 +113,11 @@
'ordernum': 1, 'cardinality': u'1*'}),
('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X WHERE CT eid %(ct)s, EDEF eid %(x)s',
{'x': None, 'ct': u'RQLConstraint_eid', 'value': u';O;O final FALSE\n'}),
- ])
+ ],
+ list(rschema2rql(schema.rschema('relation_type'), cstrtypemap)))
def test_rschema2rql2(self):
- self.assertListEqual(list(rschema2rql(schema.rschema('add_permission'), cstrtypemap)),
- [
+ self.assertListEqual([
('INSERT CWRType X: X description %(description)s,X final %(final)s,X fulltext_container %(fulltext_container)s,X inlined %(inlined)s,X name %(name)s,X symmetric %(symmetric)s', {'description': u'', 'symmetric': False, 'name': u'add_permission', 'final': False, 'fulltext_container': None, 'inlined': False}),
('INSERT CWRelation X: X cardinality %(cardinality)s,X composite %(composite)s,X description %(description)s,X ordernum %(ordernum)s,X relation_type ER,X from_entity SE,X to_entity OE WHERE SE eid %(se)s,ER eid %(rt)s,OE eid %(oe)s',
@@ -132,12 +132,11 @@
'description': u'groups allowed to add entities/relations of this type', 'composite': None, 'ordernum': 9999, 'cardinality': u'**'}),
('INSERT CWRelation X: X cardinality %(cardinality)s,X composite %(composite)s,X description %(description)s,X ordernum %(ordernum)s,X relation_type ER,X from_entity SE,X to_entity OE WHERE SE eid %(se)s,ER eid %(rt)s,OE eid %(oe)s',
{'se': None, 'rt': None, 'oe': None,
- 'description': u'rql expression allowing to add entities/relations of this type', 'composite': 'subject', 'ordernum': 9999, 'cardinality': u'*?'}),
- ])
+ 'description': u'rql expression allowing to add entities/relations of this type', 'composite': 'subject', 'ordernum': 9999, 'cardinality': u'*?'})],
+ list(rschema2rql(schema.rschema('add_permission'), cstrtypemap)))
def test_rschema2rql3(self):
- self.assertListEqual(list(rschema2rql(schema.rschema('cardinality'), cstrtypemap)),
- [
+ self.assertListEqual([
('INSERT CWRType X: X description %(description)s,X final %(final)s,X fulltext_container %(fulltext_container)s,X inlined %(inlined)s,X name %(name)s,X symmetric %(symmetric)s',
{'description': u'', 'symmetric': False, 'name': u'cardinality', 'final': True, 'fulltext_container': None, 'inlined': False}),
@@ -155,8 +154,8 @@
('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X WHERE CT eid %(ct)s, EDEF eid %(x)s',
{'x': None, 'ct': u'SizeConstraint_eid', 'value': u'max=2'}),
('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X WHERE CT eid %(ct)s, EDEF eid %(x)s',
- {'x': None, 'ct': u'StaticVocabularyConstraint_eid', 'value': u"u'?*', u'1*', u'+*', u'**', u'?+', u'1+', u'++', u'*+', u'?1', u'11', u'+1', u'*1', u'??', u'1?', u'+?', u'*?'"}),
- ])
+ {'x': None, 'ct': u'StaticVocabularyConstraint_eid', 'value': u"u'?*', u'1*', u'+*', u'**', u'?+', u'1+', u'++', u'*+', u'?1', u'11', u'+1', u'*1', u'??', u'1?', u'+?', u'*?'"})],
+ list(rschema2rql(schema.rschema('cardinality'), cstrtypemap)))
def test_rschema2rql_custom_type(self):
expected = [('INSERT CWRType X: X description %(description)s,X final %(final)s,'
@@ -195,37 +194,34 @@
self.assertListEqual(expected, got)
def test_rdef2rql(self):
- self.assertListEqual(list(rdef2rql(schema['description_format'].rdefs[('CWRType', 'String')], cstrtypemap)),
- [
+ self.assertListEqual([
('INSERT CWAttribute X: X cardinality %(cardinality)s,X defaultval %(defaultval)s,X description %(description)s,X fulltextindexed %(fulltextindexed)s,X indexed %(indexed)s,X internationalizable %(internationalizable)s,X ordernum %(ordernum)s,X relation_type ER,X from_entity SE,X to_entity OE WHERE SE eid %(se)s,ER eid %(rt)s,OE eid %(oe)s',
{'se': None, 'rt': None, 'oe': None,
'description': u'', 'internationalizable': True, 'fulltextindexed': False, 'ordernum': 3, 'defaultval': u'text/plain', 'indexed': False, 'cardinality': u'?1'}),
('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X WHERE CT eid %(ct)s, EDEF eid %(x)s',
{'x': None, 'value': u'None', 'ct': 'FormatConstraint_eid'}),
('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X WHERE CT eid %(ct)s, EDEF eid %(x)s',
- {'x': None, 'value': u'max=50', 'ct': 'SizeConstraint_eid'})])
+ {'x': None, 'value': u'max=50', 'ct': 'SizeConstraint_eid'})],
+ list(rdef2rql(schema['description_format'].rdefs[('CWRType', 'String')], cstrtypemap)))
def test_updateeschema2rql1(self):
- self.assertListEqual(list(updateeschema2rql(schema.eschema('CWAttribute'), 1)),
- [('SET X description %(description)s,X final %(final)s,X name %(name)s WHERE X eid %(x)s',
- {'description': u'define a final relation: link a final relation type from a non final entity to a final entity type. used to build the instance schema', 'x': 1, 'final': False, 'name': u'CWAttribute'}),
- ])
+ self.assertListEqual([('SET X description %(description)s,X final %(final)s,X name %(name)s WHERE X eid %(x)s',
+ {'description': u'define a final relation: link a final relation type from a non final entity to a final entity type. used to build the instance schema', 'x': 1, 'final': False, 'name': u'CWAttribute'})],
+ list(updateeschema2rql(schema.eschema('CWAttribute'), 1)))
def test_updateeschema2rql2(self):
- self.assertListEqual(list(updateeschema2rql(schema.eschema('String'), 1)),
- [('SET X description %(description)s,X final %(final)s,X name %(name)s WHERE X eid %(x)s',
- {'description': u'', 'x': 1, 'final': True, 'name': u'String'})
- ])
+ self.assertListEqual([('SET X description %(description)s,X final %(final)s,X name %(name)s WHERE X eid %(x)s',
+ {'description': u'', 'x': 1, 'final': True, 'name': u'String'})],
+ list(updateeschema2rql(schema.eschema('String'), 1)))
def test_updaterschema2rql1(self):
- self.assertListEqual(list(updaterschema2rql(schema.rschema('relation_type'), 1)),
- [
+ self.assertListEqual([
('SET X description %(description)s,X final %(final)s,X fulltext_container %(fulltext_container)s,X inlined %(inlined)s,X name %(name)s,X symmetric %(symmetric)s WHERE X eid %(x)s',
{'x': 1, 'symmetric': False,
'description': u'link a relation definition to its relation type',
- 'final': False, 'fulltext_container': None, 'inlined': True, 'name': u'relation_type'})
- ])
+ 'final': False, 'fulltext_container': None, 'inlined': True, 'name': u'relation_type'})],
+ list(updaterschema2rql(schema.rschema('relation_type'), 1)))
def test_updaterschema2rql2(self):
expected = [
@@ -235,7 +231,7 @@
'inlined': False, 'name': u'add_permission'})
]
for i, (rql, args) in enumerate(updaterschema2rql(schema.rschema('add_permission'), 1)):
- yield self.assertEqual, (rql, args), expected[i]
+ yield self.assertEqual, expected[i], (rql, args)
class Perms2RQLTC(TestCase):
GROUP_MAPPING = {
@@ -246,31 +242,33 @@
}
def test_eperms2rql1(self):
- self.assertListEqual([(rql, kwargs) for rql, kwargs in erperms2rql(schema.eschema('CWEType'), self.GROUP_MAPPING)],
- [('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 1}),
- ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 2}),
- ('SET X add_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ('SET X update_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ('SET X delete_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ])
+ self.assertListEqual([('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
+ ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 1}),
+ ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 2}),
+ ('SET X add_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
+ ('SET X update_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
+ ('SET X delete_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0})],
+ [(rql, kwargs)
+ for rql, kwargs in erperms2rql(schema.eschema('CWEType'), self.GROUP_MAPPING)])
def test_rperms2rql2(self):
- self.assertListEqual([(rql, kwargs) for rql, kwargs in erperms2rql(schema.rschema('read_permission').rdef('CWEType', 'CWGroup'), self.GROUP_MAPPING)],
- [('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 1}),
- ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 2}),
- ('SET X add_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ('SET X delete_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ])
+ self.assertListEqual([('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
+ ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 1}),
+ ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 2}),
+ ('SET X add_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
+ ('SET X delete_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0})],
+ [(rql, kwargs)
+ for rql, kwargs in erperms2rql(schema.rschema('read_permission').rdef('CWEType', 'CWGroup'),
+ self.GROUP_MAPPING)])
def test_rperms2rql3(self):
- self.assertListEqual([(rql, kwargs) for rql, kwargs in erperms2rql(schema.rschema('name').rdef('CWEType', 'String'), self.GROUP_MAPPING)],
- [('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 1}),
- ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 2}),
- ('SET X update_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ])
+ self.assertListEqual([('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
+ ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 1}),
+ ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 2}),
+ ('SET X update_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0})],
+ [(rql, kwargs)
+ for rql, kwargs in erperms2rql(schema.rschema('name').rdef('CWEType', 'String'),
+ self.GROUP_MAPPING)])
#def test_perms2rql(self):
# self.assertListEqual(perms2rql(schema, self.GROUP_MAPPING),
--- a/web/data/cubicweb.facets.js Thu Jun 13 17:27:43 2013 +0200
+++ b/web/data/cubicweb.facets.js Tue Jul 09 15:58:26 2013 +0200
@@ -30,7 +30,7 @@
});
// FacetStringWidget (e.g. has-text)
$(this).find('input:text').each(function(){
- names.push(facetName);
+ names.push(this.name);
values.push(this.value);
});
});
--- a/web/facet.py Thu Jun 13 17:27:43 2013 +0200
+++ b/web/facet.py Tue Jul 09 15:58:26 2013 +0200
@@ -74,10 +74,11 @@
def rtype_facet_title(facet):
- ptypes = facet.cw_rset.column_types(0)
- if len(ptypes) == 1:
- return display_name(facet._cw, facet.rtype, form=facet.role,
- context=iter(ptypes).next())
+ if facet.cw_rset:
+ ptypes = facet.cw_rset.column_types(0)
+ if len(ptypes) == 1:
+ return display_name(facet._cw, facet.rtype, form=facet.role,
+ context=iter(ptypes).next())
return display_name(facet._cw, facet.rtype, form=facet.role)
def get_facet(req, facetid, select, filtered_variable):
@@ -1516,7 +1517,8 @@
cssclass += ' hideFacetBody'
w(u'<div class="%s" cubicweb:facetName="%s">%s</div>\n' %
(cssclass, xml_escape(self.facet.__regid__), title))
- w(u'<input name="%s" type="text" value="%s" />\n' % (facetid, self.value or u''))
+ w(u'<input name="%s" type="text" value="%s" />\n' % (
+ xml_escape(self.facet.__regid__), self.value or u''))
w(u'</div>\n')
--- a/web/formwidgets.py Thu Jun 13 17:27:43 2013 +0200
+++ b/web/formwidgets.py Tue Jul 09 15:58:26 2013 +0200
@@ -1016,6 +1016,8 @@
time, you should not give an already translated string.
"""
type = 'button'
+ css_class = 'validateButton'
+
def __init__(self, label=stdmsgs.BUTTON_OK, attrs=None,
setdomid=None, settabindex=None,
name='', value='', onclick=None, cwaction=None):
@@ -1030,7 +1032,7 @@
self.value = ''
self.onclick = onclick
self.cwaction = cwaction
- self.attrs.setdefault('class', 'validateButton')
+ self.attrs.setdefault('class', self.css_class)
def render(self, form, field=None, renderer=None):
label = form._cw._(self.label)
--- a/web/request.py Thu Jun 13 17:27:43 2013 +0200
+++ b/web/request.py Tue Jul 09 15:58:26 2013 +0200
@@ -922,7 +922,7 @@
if reset_xmldecl is not None:
warn('[3.17] reset_xmldecl is deprecated as we only serve html',
DeprecationWarning, stacklevel=2)
- self.main_stream.set_doctype(doctype, reset_xmldecl)
+ self.main_stream.set_doctype(doctype)
# page data management ####################################################
--- a/web/test/unittest_views_baseviews.py Thu Jun 13 17:27:43 2013 +0200
+++ b/web/test/unittest_views_baseviews.py Tue Jul 09 15:58:26 2013 +0200
@@ -144,7 +144,7 @@
class MyView(StartupView):
__regid__ = 'my-view'
def call(self):
- self._cw.set_doctype(html_doctype, reset_xmldecl=False)
+ self._cw.set_doctype(html_doctype)
self._cw.main_stream.set_htmlattrs([('lang', 'cz')])
with self.temporary_appobjects(MyView):
--- a/web/views/navigation.py Thu Jun 13 17:27:43 2013 +0200
+++ b/web/views/navigation.py Tue Jul 09 15:58:26 2013 +0200
@@ -398,7 +398,7 @@
title = self._cw._('i18nprevnext_previous')
icon = self.prev_icon
cssclass = u'previousEntity left'
- content = icon + content
+ content = icon + '  ' + content
else:
title = self._cw._('i18nprevnext_next')
icon = self.next_icon