[server] always monkeypatch QuerierHelper to handle dates and times on SQLite
The patch prevents problems due to a SQLite bug causing some values to
be returned as strings instead of properly typed objects.
This should probably be improved to use SQLite connection hooks. But
the major improvement is that the monkeypatch is now done all the time,
and not just for tests.
--- a/devtools/__init__.py Thu Dec 17 15:17:45 2015 +0100
+++ b/devtools/__init__.py Fri Dec 18 09:07:33 2015 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -807,11 +807,6 @@
# traceback.print_stack(file=backup_stack_file)
return backup_file
- def _new_repo(self, config):
- repo = super(SQLiteTestDataBaseHandler, self)._new_repo(config)
- install_sqlite_patch(repo.querier)
- return repo
-
def _restore_database(self, backup_coordinates, _config):
# remove database file if it exists ?
dbfile = self.absolute_dbfile()
@@ -831,46 +826,6 @@
atexit.register(SQLiteTestDataBaseHandler._cleanup_all_tmpdb)
-def install_sqlite_patch(querier):
- """This patch hotfixes the following sqlite bug :
- - http://www.sqlite.org/cvstrac/tktview?tn=1327,33
- (some dates are returned as strings rather thant date objects)
- """
- if hasattr(querier.__class__, '_devtools_sqlite_patched'):
- return # already monkey patched
- def wrap_execute(base_execute):
- def new_execute(*args, **kwargs):
- rset = base_execute(*args, **kwargs)
- if rset.description:
- found_date = False
- for row, rowdesc in zip(rset, rset.description):
- for cellindex, (value, vtype) in enumerate(zip(row, rowdesc)):
- if vtype in ('Date', 'Datetime') and isinstance(value, text_type):
- found_date = True
- value = value.rsplit('.', 1)[0]
- try:
- row[cellindex] = strptime(value, '%Y-%m-%d %H:%M:%S')
- except Exception:
- row[cellindex] = strptime(value, '%Y-%m-%d')
- if vtype == 'Time' and isinstance(value, text_type):
- found_date = True
- try:
- row[cellindex] = strptime(value, '%H:%M:%S')
- except Exception:
- # DateTime used as Time?
- row[cellindex] = strptime(value, '%Y-%m-%d %H:%M:%S')
- if vtype == 'Interval' and isinstance(value, int):
- found_date = True
- row[cellindex] = timedelta(0, value, 0) # XXX value is in number of seconds?
- if not found_date:
- break
- return rset
- return new_execute
- querier.__class__.execute = wrap_execute(querier.__class__.execute)
- querier.__class__._devtools_sqlite_patched = True
-
-
-
HANDLERS = {}
def register_handler(handlerkls, overwrite=False):
--- a/server/sqlutils.py Thu Dec 17 15:17:45 2015 +0100
+++ b/server/sqlutils.py Fri Dec 18 09:07:33 2015 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -25,7 +25,7 @@
import subprocess
from os.path import abspath
from logging import getLogger
-from datetime import time, datetime
+from datetime import time, datetime, timedelta
from six import string_types, text_type
from six.moves import filter
@@ -34,7 +34,7 @@
from logilab.common.shellutils import ProgressBar, DummyProgressBar
from logilab.common.deprecation import deprecated
from logilab.common.logging_ext import set_log_methods
-from logilab.common.date import utctime, utcdatetime
+from logilab.common.date import utctime, utcdatetime, strptime
from logilab.database.sqlgen import SQLGenerator
from cubicweb import Binary, ConfigurationError
@@ -479,7 +479,51 @@
# connection initialization functions ##########################################
+def _install_sqlite_querier_patch():
+ """This monkey-patch hotfixes a bug sqlite causing some dates to be returned as strings rather than
+ date objects (http://www.sqlite.org/cvstrac/tktview?tn=1327,33)
+ """
+ from cubicweb.server.querier import QuerierHelper
+
+ if hasattr(QuerierHelper, '_sqlite_patched'):
+ return # already monkey patched
+
+ def wrap_execute(base_execute):
+ def new_execute(*args, **kwargs):
+ rset = base_execute(*args, **kwargs)
+ if rset.description:
+ found_date = False
+ for row, rowdesc in zip(rset, rset.description):
+ for cellindex, (value, vtype) in enumerate(zip(row, rowdesc)):
+ if vtype in ('Date', 'Datetime') and isinstance(value, text_type):
+ found_date = True
+ value = value.rsplit('.', 1)[0]
+ try:
+ row[cellindex] = strptime(value, '%Y-%m-%d %H:%M:%S')
+ except Exception:
+ row[cellindex] = strptime(value, '%Y-%m-%d')
+ if vtype == 'Time' and isinstance(value, text_type):
+ found_date = True
+ try:
+ row[cellindex] = strptime(value, '%H:%M:%S')
+ except Exception:
+ # DateTime used as Time?
+ row[cellindex] = strptime(value, '%Y-%m-%d %H:%M:%S')
+ if vtype == 'Interval' and isinstance(value, int):
+ found_date = True
+ # XXX value is in number of seconds?
+ row[cellindex] = timedelta(0, value, 0)
+ if not found_date:
+ break
+ return rset
+ return new_execute
+
+ QuerierHelper.execute = wrap_execute(QuerierHelper.execute)
+ QuerierHelper._sqlite_patched = True
+
+
def init_sqlite_connexion(cnx):
+ _install_sqlite_querier_patch()
class group_concat(object):
def __init__(self):