Merge with 3.21
authorDenis Laxalde <denis.laxalde@logilab.fr>
Thu, 23 Jun 2016 15:48:39 +0200
changeset 11373 68f0678fc543
parent 11339 67373614e125 (diff)
parent 11372 4482e94daabe (current diff)
child 11374 0e50215016f3
child 11387 51e988f9870e
Merge with 3.21
.hgtags
__pkginfo__.py
cubicweb.spec
debian/changelog
web/views/basetemplates.py
--- a/.hgtags	Tue Jun 21 07:44:35 2016 +0200
+++ b/.hgtags	Thu Jun 23 15:48:39 2016 +0200
@@ -520,6 +520,9 @@
 f66a4895759e0913b1203943fc2cd7be1a821e05 3.20.14
 f66a4895759e0913b1203943fc2cd7be1a821e05 debian/3.20.14-1
 f66a4895759e0913b1203943fc2cd7be1a821e05 centos/3.20.14-1
+636a83e65870433c2560f3c49d55ca628bc96e11 3.20.15
+636a83e65870433c2560f3c49d55ca628bc96e11 debian/3.20.15-1
+636a83e65870433c2560f3c49d55ca628bc96e11 centos/3.20.15-1
 887c6eef807781560adcd4ecd2dea9011f5a6681 3.21.0
 887c6eef807781560adcd4ecd2dea9011f5a6681 debian/3.21.0-1
 887c6eef807781560adcd4ecd2dea9011f5a6681 centos/3.21.0-1
@@ -551,6 +554,6 @@
 1b93ff37755b0588081f6fcb93da0dde772a6adb 3.22.2
 1b93ff37755b0588081f6fcb93da0dde772a6adb debian/3.22.2-1
 1b93ff37755b0588081f6fcb93da0dde772a6adb centos/3.22.2-1
-636a83e65870433c2560f3c49d55ca628bc96e11 3.20.15
-636a83e65870433c2560f3c49d55ca628bc96e11 debian/3.20.15-1
-636a83e65870433c2560f3c49d55ca628bc96e11 centos/3.20.15-1
+b1e7de00053628968ea364ee9044fb4f8714fb50 3.22.3
+b1e7de00053628968ea364ee9044fb4f8714fb50 debian/3.22.3-1
+b1e7de00053628968ea364ee9044fb4f8714fb50 centos/3.22.3-1
--- a/__pkginfo__.py	Tue Jun 21 07:44:35 2016 +0200
+++ b/__pkginfo__.py	Thu Jun 23 15:48:39 2016 +0200
@@ -22,8 +22,8 @@
 
 modname = distname = "cubicweb"
 
-numversion = (3, 22, 2)
-version = '.'.join(str(num) for num in numversion) + '.dev0'
+numversion = (3, 22, 3)
+version = '.'.join(str(num) for num in numversion)
 
 description = "a repository of entities / relations for knowledge management"
 author = "Logilab"
@@ -43,7 +43,7 @@
     'logilab-common': '>= 0.63.1',
     'logilab-mtconverter': '>= 0.8.0',
     'rql': '>= 0.34.0',
-    'yams': '>= 0.42.0',
+    'yams': '>= 0.42.0,< 0.43',
     #gettext                    # for xgettext, msgcat, etc...
     # web dependencies
     'lxml': '',
--- a/cubicweb.spec	Tue Jun 21 07:44:35 2016 +0200
+++ b/cubicweb.spec	Thu Jun 23 15:48:39 2016 +0200
@@ -8,7 +8,7 @@
 %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
 
 Name:           cubicweb
-Version:        3.22.2
+Version:        3.22.3
 Release:        logilab.1%{?dist}
 Summary:        CubicWeb is a semantic web application framework
 Source0:        https://pypi.python.org/packages/source/c/cubicweb/cubicweb-%{version}.tar.gz
@@ -26,6 +26,7 @@
 Requires:       %{python}-logilab-mtconverter >= 0.8.0
 Requires:       %{python}-rql >= 0.34.0
 Requires:       %{python}-yams >= 0.42.0
+Requires:       %{python}-yams < 0.43
 Requires:       %{python}-logilab-database >= 1.15.0
 Requires:       %{python}-passlib
 Requires:       %{python}-lxml
--- a/debian/changelog	Tue Jun 21 07:44:35 2016 +0200
+++ b/debian/changelog	Thu Jun 23 15:48:39 2016 +0200
@@ -1,3 +1,9 @@
+cubicweb (3.22.3-1) unstable; urgency=medium
+
+  * New upstream release.
+
+ -- Denis Laxalde <denis.laxalde@logilab.fr>  Tue, 21 Jun 2016 15:32:19 +0200
+
 cubicweb (3.22.2-1) unstable; urgency=medium
 
   * new upstream release
--- a/debian/control	Tue Jun 21 07:44:35 2016 +0200
+++ b/debian/control	Thu Jun 23 15:48:39 2016 +0200
@@ -17,6 +17,7 @@
  python-tz,
  python-rql (>= 0.34.0),
  python-yams (>= 0.42.0),
+ python-yams (<< 0.43),
  python-lxml,
 Standards-Version: 3.9.1
 Homepage: https://www.cubicweb.org
--- a/doc/announce.en.txt	Tue Jun 21 07:44:35 2016 +0200
+++ b/doc/announce.en.txt	Thu Jun 23 15:48:39 2016 +0200
@@ -33,10 +33,10 @@
 The impatient will move right away to installation_ and set-up of a CubicWeb
 environment.
 
-.. _cubicweb: http://www.cubicweb.org/
-.. _overview: http://www.cubicweb.org/doc/en/A020-tutorial.en.html#overview
-.. _forge: http://www.cubicweb.org/project?vtitle=All%20cubicweb%20projects
-.. _installation: http://www.cubicweb.org/doc/en/C010-setup.en.html#miseenplaceenv
+.. _cubicweb: https://www.cubicweb.org/
+.. _overview: https://docs.cubicweb.org/tutorials/base/index.html
+.. _forge: https://www.cubicweb.org/project?vtitle=All%20cubicweb%20projects
+.. _installation: https://docs.cubicweb.org/book/admin/setup.html#setupenv
 
 Home page
 ---------
--- a/doc/book/admin/config.rst	Tue Jun 21 07:44:35 2016 +0200
+++ b/doc/book/admin/config.rst	Thu Jun 23 15:48:39 2016 +0200
@@ -8,7 +8,6 @@
 You can `configure the database`_ system of your choice:
 
   - `PostgreSQL configuration`_
-  - `MySql configuration`_
   - `SQLServer configuration`_
   - `SQLite configuration`_
 
@@ -18,7 +17,6 @@
 
 .. _`configure the database`: DatabaseInstallation_
 .. _`PostgreSQL configuration`: PostgresqlConfiguration_
-.. _`MySql configuration`: MySqlConfiguration_
 .. _`SQLServer configuration`: SQLServerConfiguration_
 .. _`SQLite configuration`: SQLiteConfiguration_
 .. _`Cubicweb resources configuration`: RessourcesConfiguration_
@@ -41,7 +39,7 @@
 Each instance can be configured with its own database connection information,
 that will be stored in the instance's :file:`sources` file. The database to use
 will be chosen when creating the instance. CubicWeb is known to run with
-Postgresql (recommended), SQLServer and SQLite, and may run with MySQL.
+Postgresql (recommended), SQLServer and SQLite.
 
 Other possible sources of data include CubicWeb, Subversion, LDAP and Mercurial,
 but at least one relational database is required for CubicWeb to work. You do
@@ -89,6 +87,10 @@
 
     $ initdb -E UTF8 -D /path/to/pgsql
 
+Note: ``initdb`` might not be in the PATH, so you may have to use its
+absolute path instead (usually something like
+``/usr/lib/postgresql/9.4/bin/initdb``).
+
 Notice the encoding specification. This is necessary since |cubicweb| usually
 want UTF8 encoded database. If you use a cluster with the wrong encoding, you'll
 get error like::
@@ -105,6 +107,7 @@
 
   $ chown username /path/to/pgsql
 
+
 Database authentication
 +++++++++++++++++++++++
 
@@ -116,31 +119,42 @@
 
   $ su
   $ su - postgres
-  $ createuser -s -P username
+  $ createuser -s -P <dbuser>
 
 The option `-P` (for password prompt), will encrypt the password with the
 method set in the configuration file :file:`pg_hba.conf`.  If you do not use this
 option `-P`, then the default value will be null and you will need to set it
 with::
 
-  $ su postgres -c "echo ALTER USER username WITH PASSWORD 'userpasswd' | psql"
+  $ su postgres -c "echo ALTER USER <dbuser> WITH PASSWORD '<dbpassword>' | psql"
 
 The above login/password will be requested when you will create an instance with
 `cubicweb-ctl create` to initialize the database of your instance.
 
+
+Database creation
++++++++++++++++++
+
+If you create the database by hand (instead of using the `cubicweb-ctl
+db-create` tool), you may want to make sure that the local settings are
+properly set. For example, if you need to handle french accents
+properly for indexing and sorting, you may need to create the database
+with something like::
+
+  $ createdb --encoding=UTF-8 --locale=fr_FR.UTF-8 -t template0 -O <owner> <dbname>
+
 Notice that the `cubicweb-ctl db-create` does database initialization that
 may requires a postgres superuser. That's why a login/password is explicitly asked
 at this step, so you can use there a superuser without using this user when running
 the instance. Things that require special privileges at this step:
 
 * database creation, require the 'create database' permission
-* install the plpython extension language (require superuser)
-* install the tsearch extension for postgres version prior to 8.3 (require superuser)
+* install the `plpython` extension language (require superuser)
 
 To avoid using a super user each time you create an install, a nice trick is to
 install plpython (and tsearch when needed) on the special `template1` database,
 so they will be installed automatically when cubicweb databases are created
-without even with needs for special access rights. To do so, run ::
+without needs for special access rights. To do so, run ::
 
   # Installation of plpythonu language by default ::
   $ createlang -U pgadmin plpythonu template1
@@ -151,29 +165,6 @@
 default plpython is an 'untrusted' language and as such can't be used by non
 superuser. This update fix that problem by making it trusted.
 
-To install the tsearch plain-text index extension on postgres prior to 8.3, run::
-
-    cat /usr/share/postgresql/8.X/contrib/tsearch2.sql | psql -U username template1
-
-
-.. _MySqlConfiguration:
-
-MySql
-~~~~~
-.. warning::
-    CubicWeb's MySQL support is not commonly used, so things may or may not work properly.
-
-You must add the following lines in ``/etc/mysql/my.cnf`` file::
-
-    transaction-isolation=READ-COMMITTED
-    default-storage-engine=INNODB
-    default-character-set=utf8
-    max_allowed_packet = 128M
-
-.. Note::
-    It is unclear whether mysql supports indexed string of arbitrary length or
-    not.
-
 
 .. _SQLServerConfiguration:
 
@@ -226,4 +217,3 @@
 .. Note::
   SQLite is great for testing and to play with cubicweb but is not suited for
   production environments.
-
--- a/doc/book/devweb/internationalization.rst	Tue Jun 21 07:44:35 2016 +0200
+++ b/doc/book/devweb/internationalization.rst	Thu Jun 23 15:48:39 2016 +0200
@@ -227,3 +227,29 @@
 
 It is also possible to explicitly use the with _cw.pgettext(context,
 msgid).
+
+
+Specialize translation for an application cube
+``````````````````````````````````````````````
+
+Every cube has its own translation files. For a specific application cube
+it can be useful to specialize translations of other cubes. You can either mark
+those strings for translation using `_` in the python code, or add a
+`static-messages.pot` file into the `i18n` directory. This file
+looks like: ::
+
+    msgid ""
+    msgstr ""
+    "PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
+    "MIME-Version: 1.0\n"
+    "Content-Type: text/plain; charset=UTF-8\n"
+    "Content-Transfer-Encoding: 8bit\n"
+    "Generated-By: pygettext.py 1.5\n"
+    "Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+    msgig "expression to be translated"
+    msgstr ""
+
+Doing this, ``expression to be translated`` will be taken into account by
+the ``i18ncube`` command and additional messages will then appear in `.po` files
+of the cube.
--- a/server/sources/rql2sql.py	Tue Jun 21 07:44:35 2016 +0200
+++ b/server/sources/rql2sql.py	Thu Jun 23 15:48:39 2016 +0200
@@ -187,7 +187,8 @@
             try:
                 thisexistssols, thisexistsvars = existssols[var.scope]
             except KeyError:
-                thisexistssols = [newsols[0]]
+                # copy to avoid shared dict in newsols and exists sols
+                thisexistssols = [newsols[0].copy()]
                 thisexistsvars = set()
                 existssols[var.scope] = thisexistssols, thisexistsvars
             for i in range(len(newsols)-1, 0, -1):
@@ -199,6 +200,13 @@
             for i in range(1, len(newsols)):
                 if vtype != newsols[i][vname]:
                     unstable.add(vname)
+    # remove unstable variables from exists solutions: the possible types of these variables are not
+    # properly represented in exists solutions, so we have to remove and reinject them later
+    # according to the outer solution (see `iter_exists_sols`)
+    for sols, _ in existssols.values():
+        for vname in unstable:
+            for sol in sols:
+                sol.pop(vname, None)
     if invariants:
         # filter out duplicates
         newsols_ = []
@@ -400,24 +408,30 @@
         thisexistssols, thisexistsvars = self.existssols[exists]
         notdone_outside_vars = set()
         # when iterating other solutions inner to an EXISTS subquery, we should
-        # reset variables which have this exists node as scope at each iteration
+        # reset variables which have this EXISTS node as scope at each iteration
         for var in exists.stmt.defined_vars.values():
             if var.scope is exists:
                 thisexistsvars.add(var.name)
             elif var.name not in self.done:
                 notdone_outside_vars.add(var)
-        origsol = self.solution
+        # make a copy of the outer statement's solution for later restore
+        origsol = self.solution.copy()
         origtables = self.tables
         done = self.done
         for thisexistssol in thisexistssols:
             for vname in self.unstablevars:
-                if thisexistssol[vname] != origsol[vname] and vname in thisexistsvars:
+                # check first if variable belong to the EXISTS's scope, else it may be missing from
+                # `thisexistssol`
+                if vname in thisexistsvars and thisexistssol[vname] != origsol[vname]:
                     break
             else:
                 self.tables = origtables.copy()
-                self.solution = thisexistssol
+                # overwrite current outer solution by EXISTS solution (the later will be missing
+                # unstable outer variables)
+                self.solution.update(thisexistssol)
                 yield 1
-                # cleanup self.done from stuff specific to exists
+                # cleanup self.done from stuff specific to EXISTS, so they will be reconsidered in
+                # the next round
                 for var in thisexistsvars:
                     if var in done:
                         done.remove(var)
@@ -428,6 +442,7 @@
                 for rel in exists.iget_nodes(Relation):
                     if rel in done:
                         done.remove(rel)
+        # restore original solution
         self.solution = origsol
         self.tables = origtables
 
--- a/server/test/unittest_rql2sql.py	Tue Jun 21 07:44:35 2016 +0200
+++ b/server/test/unittest_rql2sql.py	Thu Jun 23 15:48:39 2016 +0200
@@ -574,8 +574,18 @@
     ''', '''SELECT _X.cw_eid
 FROM cw_CWSourceSchemaConfig AS _X LEFT OUTER JOIN owned_by_relation AS rel_owned_by1 ON (rel_owned_by1.eid_from=_X.cw_eid)
 WHERE EXISTS(SELECT 1 FROM created_by_relation AS rel_created_by0, cw_CWUser AS _U WHERE rel_created_by0.eid_from=_X.cw_eid AND rel_created_by0.eid_to=_U.cw_eid) AND _X.cw_cw_schema IS NOT NULL
-''')
-    ]
+'''),
+
+    ('Any X WHERE EXISTS(X in_state S, S name "state name"), X is in (Affaire, Note)',
+     '''SELECT _X.cw_eid
+FROM cw_Affaire AS _X
+WHERE EXISTS(SELECT 1 FROM cw_State AS _S WHERE _X.cw_in_state=_S.cw_eid AND _S.cw_name=state name)
+UNION ALL
+SELECT _X.cw_eid
+FROM cw_Note AS _X
+WHERE EXISTS(SELECT 1 FROM cw_State AS _S WHERE _X.cw_in_state=_S.cw_eid AND _S.cw_name=state name)'''),
+
+]
 
 ADVANCED_WITH_GROUP_CONCAT = [
         ("Any X,GROUP_CONCAT(TN) GROUPBY X ORDERBY XN WHERE T tags X, X name XN, T name TN, X is CWGroup",
--- a/web/request.py	Tue Jun 21 07:44:35 2016 +0200
+++ b/web/request.py	Thu Jun 23 15:48:39 2016 +0200
@@ -884,9 +884,15 @@
             self.session.data.pop(self.pageid, None)
         else:
             try:
-                del self.session.data[self.pageid][key]
+                page_data = self.session.data[self.pageid]
+                del page_data[key]
             except KeyError:
                 pass
+            else:
+                # make sure we write the session data value in the
+                # self.session.data dict-like object so any session
+                # handler can "detect" and manage the persistency
+                self.session.data[self.pageid] = page_data
 
     # user-agent detection ####################################################
 
--- a/web/views/autoform.py	Tue Jun 21 07:44:35 2016 +0200
+++ b/web/views/autoform.py	Thu Jun 23 15:48:39 2016 +0200
@@ -484,13 +484,19 @@
 
 def _add_pending(req, eidfrom, rel, eidto, kind):
     key = 'pending_%s' % kind
-    pendings = req.session.data.setdefault(key, set())
-    pendings.add( (int(eidfrom), rel, int(eidto)) )
+    pendings = req.session.data.get(key, [])
+    value = (int(eidfrom), rel, int(eidto))
+    if value not in pendings:
+        pendings.append(value)
+        req.session.data[key] = pendings
 
 def _remove_pending(req, eidfrom, rel, eidto, kind):
     key = 'pending_%s' % kind
     pendings = req.session.data[key]
-    pendings.remove( (int(eidfrom), rel, int(eidto)) )
+    value = (int(eidfrom), rel, int(eidto))
+    if value in pendings:
+        pendings.remove(value)
+        req.session.data[key] = pendings
 
 @ajaxfunc(output_type='json')
 def remove_pending_insert(self, args):
--- a/web/views/basetemplates.py	Tue Jun 21 07:44:35 2016 +0200
+++ b/web/views/basetemplates.py	Thu Jun 23 15:48:39 2016 +0200
@@ -46,6 +46,8 @@
         w(u'</body>')
 
     def template_header(self, content_type, view=None, page_title='', additional_headers=()):
+        self._cw.html_headers.define_var('BASE_URL', self._cw.base_url())
+        self._cw.html_headers.define_var('DATA_URL', self._cw.datadir_url)
         w = self.whead
         # explictly close the <base> tag to avoid IE 6 bugs while browsing DOM
         w(u'<base href="%s"></base>' % xml_escape(self._cw.base_url()))
--- a/web/views/editforms.py	Tue Jun 21 07:44:35 2016 +0200
+++ b/web/views/editforms.py	Thu Jun 23 15:48:39 2016 +0200
@@ -20,25 +20,21 @@
 """
 
 __docformat__ = "restructuredtext en"
-from cubicweb import _
 
 from copy import copy
 
 from six.moves import range
 
-from logilab.mtconverter import xml_escape
-from logilab.common.decorators import cached
 from logilab.common.registry import yes
 from logilab.common.deprecation import class_moved
 
+from cubicweb import _
 from cubicweb import tags
-from cubicweb.predicates import (match_kwargs, one_line_rset, non_final_entity,
-                                specified_etype_implements, is_instance)
+from cubicweb.predicates import (one_line_rset, non_final_entity,
+                                 specified_etype_implements, is_instance)
 from cubicweb.view import EntityView
-from cubicweb.schema import display_name
-from cubicweb.web import stdmsgs, eid_param, \
-     formfields as ff, formwidgets as fw
-from cubicweb.web.form import FormViewMixIn, FieldNotFound
+from cubicweb.web import stdmsgs, eid_param, formwidgets as fw
+from cubicweb.web.form import FormViewMixIn
 from cubicweb.web.views import uicfg, forms, reledit
 
 _pvdc = uicfg.primaryview_display_ctrl
@@ -52,7 +48,8 @@
     domid = 'deleteconf'
     copy_nav_params = True
     form_buttons = [fw.Button(stdmsgs.BUTTON_DELETE, cwaction='delete'),
-                    fw.Button(stdmsgs.BUTTON_CANCEL, cwaction='cancel')]
+                    fw.Button(stdmsgs.BUTTON_CANCEL,
+                              {'class': fw.Button.css_class + ' cwjs-edition-cancel'})]
 
     def __init__(self, *args, **kwargs):
         super(DeleteConfForm, self).__init__(*args, **kwargs)