--- a/.hgtags Mon Feb 20 11:32:55 2012 +0100
+++ b/.hgtags Mon Feb 20 11:46:28 2012 +0100
@@ -243,3 +243,5 @@
17ebd836cee30a9f690e83af7ce98287a7216d57 cubicweb-debian-version-3.14.2-1
60efdbb455204899103c30bfa8d805c1b15161f6 cubicweb-version-3.14.3
4d0f5d18e8a07ab218efe90d758af723ea4a1b2b cubicweb-debian-version-3.14.3-1
+508645a542870cb0def9c43056e5084ff8def5ca cubicweb-version-3.14.4
+bc40991b7f13642d457f5ca80ac1486c29e25a6e cubicweb-debian-version-3.14.4-1
--- a/debian/changelog Mon Feb 20 11:32:55 2012 +0100
+++ b/debian/changelog Mon Feb 20 11:46:28 2012 +0100
@@ -1,3 +1,9 @@
+cubicweb (3.14.4-1) unstable; urgency=low
+
+ * New upstream release
+
+ -- David Douard <david.douard@logilab.fr> Fri, 17 Feb 2012 13:06:48 +0100
+
cubicweb (3.14.3-1) unstable; urgency=low
* new upstream release
--- a/devtools/devctl.py Mon Feb 20 11:32:55 2012 +0100
+++ b/devtools/devctl.py Mon Feb 20 11:46:28 2012 +0100
@@ -32,7 +32,7 @@
from logilab.common import STD_BLACKLIST
from cubicweb.__pkginfo__ import version as cubicwebversion
-from cubicweb import CW_SOFTWARE_ROOT as BASEDIR, BadCommandUsage
+from cubicweb import CW_SOFTWARE_ROOT as BASEDIR, BadCommandUsage, ExecutionError
from cubicweb.cwctl import CWCTL
from cubicweb.cwconfig import CubicWebNoAppConfiguration
from cubicweb.toolsutils import (SKEL_EXCLUDE, Command, copy_skeleton,
@@ -377,7 +377,8 @@
for cube in DevConfiguration.available_cubes()]
cubes = [cubepath for cubepath in cubes
if osp.exists(osp.join(cubepath, 'i18n'))]
- update_cubes_catalogs(cubes)
+ if not update_cubes_catalogs(cubes):
+ raise ExecutionError("update cubes i18n catalog failed")
def update_cubes_catalogs(cubes):
@@ -391,6 +392,7 @@
import traceback
traceback.print_exc()
print '-> error while updating catalogs for cube', cubedir
+ return False
else:
# instructions pour la suite
if toedit:
@@ -399,6 +401,7 @@
print '* ' + '\n* '.join(toedit)
print ('When you are done, run "cubicweb-ctl i18ninstance '
'<yourinstance>" to see changes in your instances.')
+ return True
def update_cube_catalogs(cubedir):
import shutil
--- a/i18n/de.po Mon Feb 20 11:32:55 2012 +0100
+++ b/i18n/de.po Mon Feb 20 11:46:28 2012 +0100
@@ -962,6 +962,9 @@
msgid "a float is expected"
msgstr "Eine Dezimalzahl (float) wird erwartet."
+msgid "a number (in seconds) or 20s, 10min, 24h or 4d are expected"
+msgstr ""
+
msgid ""
"a simple cache entity characterized by a name and a validity date. The "
"target application is responsible for updating timestamp when necessary to "
--- a/i18n/en.po Mon Feb 20 11:32:55 2012 +0100
+++ b/i18n/en.po Mon Feb 20 11:46:28 2012 +0100
@@ -922,6 +922,9 @@
msgid "a float is expected"
msgstr ""
+msgid "a number (in seconds) or 20s, 10min, 24h or 4d are expected"
+msgstr ""
+
msgid ""
"a simple cache entity characterized by a name and a validity date. The "
"target application is responsible for updating timestamp when necessary to "
--- a/i18n/es.po Mon Feb 20 11:32:55 2012 +0100
+++ b/i18n/es.po Mon Feb 20 11:46:28 2012 +0100
@@ -967,6 +967,9 @@
msgid "a float is expected"
msgstr "un nĂºmero flotante es requerido"
+msgid "a number (in seconds) or 20s, 10min, 24h or 4d are expected"
+msgstr ""
+
msgid ""
"a simple cache entity characterized by a name and a validity date. The "
"target application is responsible for updating timestamp when necessary to "
--- a/i18n/fr.po Mon Feb 20 11:32:55 2012 +0100
+++ b/i18n/fr.po Mon Feb 20 11:46:28 2012 +0100
@@ -967,6 +967,9 @@
msgid "a float is expected"
msgstr "un nombre flottant est attendu"
+msgid "a number (in seconds) or 20s, 10min, 24h or 4d are expected"
+msgstr "un nombre (en seconde) ou 20s, 10min, 24h ou 4d sont attendus"
+
msgid ""
"a simple cache entity characterized by a name and a validity date. The "
"target application is responsible for updating timestamp when necessary to "
--- a/server/sources/rql2sql.py Mon Feb 20 11:32:55 2012 +0100
+++ b/server/sources/rql2sql.py Mon Feb 20 11:46:28 2012 +0100
@@ -1454,6 +1454,8 @@
lhs, rhs = mexpr.get_parts()
# check for string concatenation
operator = mexpr.operator
+ if operator == '%':
+ operator = '%%'
try:
if mexpr.operator == '+' and mexpr.get_type(self._state.solution, self._args) == 'String':
return '(%s)' % self.dbhelper.sql_concat_string(lhs.accept(self),
--- a/server/test/unittest_rql2sql.py Mon Feb 20 11:32:55 2012 +0100
+++ b/server/test/unittest_rql2sql.py Mon Feb 20 11:46:28 2012 +0100
@@ -1744,6 +1744,9 @@
GROUP BY CAST(EXTRACT(YEAR from _X.cw_modification_date) AS INTEGER),CAST(EXTRACT(MONTH from _X.cw_modification_date) AS INTEGER)
ORDER BY 1'''),
+ def test_modulo(self):
+ self._check('Any 5 % 2', '''SELECT (5 % 2)''')
+
class SqlServer2005SQLGeneratorTC(PostgresSQLGeneratorTC):
backend = 'sqlserver2005'
--- a/web/formfields.py Mon Feb 20 11:32:55 2012 +0100
+++ b/web/formfields.py Mon Feb 20 11:46:28 2012 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -43,6 +43,7 @@
.. autoclass:: cubicweb.web.formfields.DateField()
.. autoclass:: cubicweb.web.formfields.DateTimeField()
.. autoclass:: cubicweb.web.formfields.TimeField()
+.. autoclass:: cubicweb.web.formfields.TimeIntervalField()
Compound fields
''''''''''''''''
@@ -63,11 +64,13 @@
__docformat__ = "restructuredtext en"
from warnings import warn
-from datetime import datetime
+from datetime import datetime, timedelta
from logilab.mtconverter import xml_escape
from logilab.common import nullobject
from logilab.common.date import ustrftime
+from logilab.common.configuration import format_time
+from logilab.common.textutils import apply_units, TIME_UNITS
from yams.schema import KNOWN_METAATTRIBUTES, role_name
from yams.constraints import (SizeConstraint, StaticVocabularyConstraint,
@@ -929,6 +932,38 @@
return None
+class TimeIntervalField(StringField):
+ """Use this field to edit time interval (`Interval` yams type).
+
+ Unless explicitly specified, the widget for this field will be a
+ :class:`~cubicweb.web.formwidgets.TextInput`.
+ """
+ widget = fw.TextInput
+
+ def format_single_value(self, req, value):
+ if value:
+ value = format_time(value.days * 24 * 3600 + value.seconds)
+ return unicode(value)
+ return u''
+
+ def example_format(self, req):
+ """return a sample string describing what can be given as input for this
+ field
+ """
+ return u'20s, 10min, 24h, 4d'
+
+ def _ensure_correctly_typed(self, form, value):
+ if isinstance(value, basestring):
+ value = value.strip()
+ if not value:
+ return None
+ try:
+ value = apply_units(value, TIME_UNITS)
+ except ValueError:
+ raise ProcessFormError(form._cw._('a number (in seconds) or 20s, 10min, 24h or 4d are expected'))
+ return timedelta(0, value)
+
+
class DateField(StringField):
"""Use this field to edit date (`Date` yams type).
@@ -1201,5 +1236,5 @@
'TZDatetime': DateTimeField,
'Time': TimeField,
'TZTime': TimeField,
- # XXX implement 'Interval': TimeIntervalField,
+ 'Interval': TimeIntervalField,
}