From 1d1a2c84ab0cf65eacf5d86b4cddccfeb6c4fdff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 20 Oct 2009 18:39:17 +0200 Subject: [PATCH 001/144] Increase version number --- trytond/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/version.py b/trytond/version.py index dc9892f280..d28b50cd64 100644 --- a/trytond/version.py +++ b/trytond/version.py @@ -1,7 +1,7 @@ #This file is part of Tryton. The COPYRIGHT file at the top level of #this repository contains the full copyright notices and license terms. PACKAGE = "trytond" -VERSION = "1.4.0" +VERSION = "1.4.1" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 1ecd0d09702d0e717b0af2edd6d132f7255c26f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 20 Oct 2009 18:38:42 +0200 Subject: [PATCH 002/144] Add missing init.sql of SQLite for issue1255 (transplanted from 1915bafb552eb53e596f2e119bda52c631618542) --- MANIFEST.in | 2 +- setup.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index cfde8c826c..82df49f6d2 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -6,7 +6,7 @@ include TODO include CHANGELOG include doc/* include etc/* -include trytond/backend/postgresql/init.sql +include trytond/backend/*/init.sql include trytond/ir/*.xml include trytond/ir/*.csv include trytond/ir/module/*.xml diff --git a/setup.py b/setup.py index 2f82a34bb5..757d85f653 100644 --- a/setup.py +++ b/setup.py @@ -18,6 +18,7 @@ setup(name=PACKAGE, packages=find_packages(exclude=['*.modules.*', 'modules.*', 'modules']), package_data={ 'trytond.backend.postgresql': ['init.sql'], + 'trytond.backend.sqlite': ['init.sql'], 'trytond.ir': ['*.xml', '*.csv'], 'trytond.ir.module': ['*.xml'], 'trytond.ir.ui': ['*.xml', '*.rng', '*.rnc'], From 5da1111c9877780439ac88a53d6c81bf80ec88bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 20 Oct 2009 18:40:13 +0200 Subject: [PATCH 003/144] Prepare release 1.4.1 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index bba1a4cdd9..1f6d0ab149 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 1.4.1 - 2009-10-20 +* Add missing init.sql of SQLite + Version 1.4.0 - 2009-10-19 * Bug fixes (see mercurial logs for details) * Add datetime_field on xxx2Many to use a specific _datetime when reading the related record From 50acc3fe975195b00121884568dfdcc50e593b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 20 Oct 2009 18:40:21 +0200 Subject: [PATCH 004/144] Added tag 1.4.1 for changeset a2589d0064b2 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 636a63bf31..6b430be024 100644 --- a/.hgtags +++ b/.hgtags @@ -1,3 +1,4 @@ 951bb3311b916cb893adc5294cfb3216d2940169 1.0.0 9f5ce178a7c403a0865fd4b6c1a82a911df0e998 1.2.0 e2d31d59de7745de70199b7c340d78b7c4775723 1.4.0 +a2589d0064b2369c79cf2914e4f7caa8b907c6de 1.4.1 From 5cd82c11f1d44ae5d4db8e8c4428f2cd0520b620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 20 Oct 2009 18:42:49 +0200 Subject: [PATCH 005/144] Increase version number --- trytond/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/version.py b/trytond/version.py index d28b50cd64..b586fb705d 100644 --- a/trytond/version.py +++ b/trytond/version.py @@ -1,7 +1,7 @@ #This file is part of Tryton. The COPYRIGHT file at the top level of #this repository contains the full copyright notices and license terms. PACKAGE = "trytond" -VERSION = "1.4.1" +VERSION = "1.4.2" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 03c5770626a194f57bf36f8516c7255cd5ba0ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 20 Oct 2009 18:53:17 +0200 Subject: [PATCH 006/144] Don't import trytond module before CONFIG parse to load the right database engine. (transplanted from a56b4b3757519a88d21c23948eb5062ea4498e19) --- trytond/server.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/trytond/server.py b/trytond/server.py index 8e5978f046..fb98bb3f19 100644 --- a/trytond/server.py +++ b/trytond/server.py @@ -10,7 +10,6 @@ logging.basicConfig(level=logging.DEBUG, format=format, datefmt=datefmt) import logging.handlers import sys, os, signal import time -from trytond.backend import Database, DatabaseOperationalError from config import CONFIG import mx.DateTime @@ -25,16 +24,15 @@ except ImportError: hashlib = None import sha import threading -from pool import Pool import string import random -from trytond.monitor import monitor class TrytonServer(object): def __init__(self): CONFIG.parse() + from trytond.backend import Database if CONFIG['logfile']: logf = CONFIG['logfile'] @@ -76,6 +74,9 @@ class TrytonServer(object): def run(self): "Run the server and never return" + from trytond.backend import Database + from pool import Pool + from trytond.monitor import monitor update = False init = {} From 20789ac7a25de5e0cc1a035b8f9b10f86eee4b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 20 Oct 2009 22:58:51 +0200 Subject: [PATCH 007/144] Force SQLite params to be unicode (transplanted from 161de19eed56f5abf991aaf4ce148889cc4d949a) --- trytond/backend/sqlite/database.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/backend/sqlite/database.py b/trytond/backend/sqlite/database.py index f9466d1216..97fc8351b5 100644 --- a/trytond/backend/sqlite/database.py +++ b/trytond/backend/sqlite/database.py @@ -250,7 +250,8 @@ class Cursor(CursorInterface): sql = "".join(replaced)[:-2] try: if params: - res = self.cursor.execute(sql, params) + res = self.cursor.execute(sql, [isinstance(x, str) and \ + unicode(x, 'utf-8') or x for x in params]) else: res = self.cursor.execute(sql) except: From e58bf7919367444c4de2907e700e70c8e97e5010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 31 Oct 2009 15:54:59 +0100 Subject: [PATCH 008/144] Fix when using unicode in Sha field (transplanted from 96b453ee85aa404228315bfa7f72f9e13b501f3a) --- trytond/backend/postgresql/fields.py | 2 ++ trytond/backend/sqlite/fields.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/trytond/backend/postgresql/fields.py b/trytond/backend/postgresql/fields.py index 8a6a0a5d50..5814bee0f8 100644 --- a/trytond/backend/postgresql/fields.py +++ b/trytond/backend/postgresql/fields.py @@ -69,6 +69,8 @@ class Sha(Field): @staticmethod def sql_format(value): if isinstance(value, basestring): + if isinstance(value, unicode): + value = value.encode('utf-8') if hashlib: value = hashlib.sha1(value).hexdigest() else: diff --git a/trytond/backend/sqlite/fields.py b/trytond/backend/sqlite/fields.py index 0915729e8b..188c7b7c45 100644 --- a/trytond/backend/sqlite/fields.py +++ b/trytond/backend/sqlite/fields.py @@ -66,6 +66,8 @@ class Sha(Field): @staticmethod def sql_format(value): if isinstance(value, basestring): + if isinstance(value, unicode): + value = value.encode('utf-8') if hashlib: value = hashlib.sha1(value).hexdigest() else: From 728b7cb058a2daaa4ce04a25f72247e4269b7866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 2 Nov 2009 20:29:30 +0100 Subject: [PATCH 009/144] Handle extract with SQLite (transplanted from bf3b74163ce470897a9529261225f25c51324e63) --- trytond/backend/sqlite/database.py | 46 +++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/trytond/backend/sqlite/database.py b/trytond/backend/sqlite/database.py index 97fc8351b5..d58d2d1a0a 100644 --- a/trytond/backend/sqlite/database.py +++ b/trytond/backend/sqlite/database.py @@ -22,6 +22,36 @@ except ImportError: from sqlite3 import IntegrityError as DatabaseIntegrityError from sqlite3 import OperationalError as DatabaseOperationalError QUOTE_SEPARATION = re.compile(r"(.*?)('.*?')", re.DOTALL) +EXTRACT_PATTERN = re.compile(r'EXTRACT\s*\(\s*(\S*)\s+FROM', re.I) + +def extract(lookup_type, date): + if date is None: + return None + try: + date = mx.DateTime.strptime(date, '%Y-%m-%d %H:%M:%S') + except: + return None + if lookup_type.lower() == 'century': + return date.year / 100 + (date.year % 100 and 1 or 0) + elif lookup_type.lower() == 'decade': + return date.year.year / 10 + elif lookup_type.lower() == 'dow': + return (date.weekday() + 1) % 7 + elif lookup_type.lower() == 'doy': + return date.day_of_year + elif lookup_type.lower() == 'epoch': + return date.ticks() + elif lookup_type.lower() == 'microseconds': + return int(a.second * 1000000) + elif lookup_type.lower() == 'millennium': + return date.year / 1000 + (date.year % 1000 and 1 or 0) + elif lookup_type.lower() == 'milliseconds': + return int(a.second * 1000) + elif lookup_type.lower() == 'quarter': + return date.month / 4 + 1 + elif lookup_type.lower() == 'week': + return date.iso_week[1] + return getattr(date, lookup_type) def date_trunc(_type, date): if _type == 'second': @@ -71,6 +101,7 @@ class Database(DatabaseInterface): if self._conn is not None: return self self._conn = sqlite.connect(path, detect_types=sqlite.PARSE_DECLTYPES) + self._conn.create_function('extract', 2, extract) self._conn.create_function('date_trunc', 2, date_trunc) self._conn.create_function('split_part', 3, split_part) self._conn.create_function('now', 0, now) @@ -241,13 +272,14 @@ class Cursor(CursorInterface): return getattr(self.cursor, name) def execute(self, sql, params=None): - sql = sql.replace('?', '??') - notQuoted_quoted = QUOTE_SEPARATION.findall(sql+"''") - replaced = [nq\ - .replace('%s', '?')\ - .replace('ilike', 'like') \ - + q for (nq, q) in notQuoted_quoted] - sql = "".join(replaced)[:-2] + buf = "" + for nq, q in QUOTE_SEPARATION.findall(sql+"''"): + nq = nq.replace('?', '??') + nq = nq.replace('%s', '?') + nq = nq.replace('ilike', 'like') + nq = re.sub(EXTRACT_PATTERN, r'EXTRACT("\1",', nq) + buf += nq + q + sql = buf[:-2] try: if params: res = self.cursor.execute(sql, [isinstance(x, str) and \ From a7add8a511a05ccacbe7d6c5310bee9eb0a03120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 3 Nov 2009 15:19:46 +0100 Subject: [PATCH 010/144] Don't convert Date and DateTime into string (transplanted from b23f285b08ee4c94719d71cd0053d8d10fff38ec) --- trytond/backend/postgresql/fields.py | 8 ++++++++ trytond/backend/sqlite/fields.py | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/trytond/backend/postgresql/fields.py b/trytond/backend/postgresql/fields.py index 5814bee0f8..1e6f0f5fbb 100644 --- a/trytond/backend/postgresql/fields.py +++ b/trytond/backend/postgresql/fields.py @@ -109,6 +109,10 @@ class Numeric(Float): class Date(Field): + @staticmethod + def sql_format(value): + return value or None + @staticmethod def sql_type(field): return ('date', 'date') @@ -116,6 +120,10 @@ class Date(Field): class DateTime(Field): + @staticmethod + def sql_format(value): + return value or None + @staticmethod def sql_type(field): return ('timestamp', 'timestamp(0)') diff --git a/trytond/backend/sqlite/fields.py b/trytond/backend/sqlite/fields.py index 188c7b7c45..3adecb79d8 100644 --- a/trytond/backend/sqlite/fields.py +++ b/trytond/backend/sqlite/fields.py @@ -106,6 +106,10 @@ class Numeric(Float): class Date(Field): + @staticmethod + def sql_format(value): + return value or None + @staticmethod def sql_type(field): return ('DATE', 'DATE') @@ -113,6 +117,10 @@ class Date(Field): class DateTime(Field): + @staticmethod + def sql_format(value): + return value or None + @staticmethod def sql_type(field): return ('TIMESTAMP', 'TIMESTAMP') From 409c316088e5c6c6a7c8f4de0412834a2f84930f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 3 Nov 2009 15:22:17 +0100 Subject: [PATCH 011/144] Don't use now() in SQL statement as it doesn't work on SQLite (transplanted from a64ae6b1f650712743e22bb7c603fdaed4169a5c) --- trytond/backend/sqlite/database.py | 12 ++++-------- trytond/ir/cron.py | 4 ++-- trytond/model/modelsql.py | 14 ++++++-------- trytond/tools/misc.py | 7 ++++--- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/trytond/backend/sqlite/database.py b/trytond/backend/sqlite/database.py index d58d2d1a0a..5790a52d27 100644 --- a/trytond/backend/sqlite/database.py +++ b/trytond/backend/sqlite/database.py @@ -70,9 +70,6 @@ def date_trunc(_type, date): def split_part(text, delimiter, count): return (text.split(delimiter) + [''] * (count - 1))[count - 1] -def now(): - return mx.DateTime.now().strftime('%Y-%m-%d %H:%M:%S') - class Database(DatabaseInterface): @@ -104,7 +101,6 @@ class Database(DatabaseInterface): self._conn.create_function('extract', 2, extract) self._conn.create_function('date_trunc', 2, date_trunc) self._conn.create_function('split_part', 3, split_part) - self._conn.create_function('now', 0, now) return self def cursor(self, autocommit=False): @@ -212,8 +208,8 @@ class Database(DatabaseInterface): cursor.execute('INSERT INTO ir_module_module ' \ '(create_uid, create_date, author, website, name, ' \ 'shortdesc, description, state) ' \ - 'VALUES (%s, now(), %s, %s, %s, %s, %s, %s)', - (0, info.get('author', ''), + 'VALUES (%s, %s, %s, %s, %s, %s, %s, %s)', + (0, datetime.datetime.now(), info.get('author', ''), info.get('website', ''), i, info.get('name', False), info.get('description', ''), state)) cursor.execute('SELECT last_insert_rowid()') @@ -222,8 +218,8 @@ class Database(DatabaseInterface): for dependency in dependencies: cursor.execute('INSERT INTO ir_module_module_dependency ' \ '(create_uid, create_date, module, name) ' \ - 'VALUES (%s, now(), %s, %s) ', - (0, module_id, dependency)) + 'VALUES (%s, %s, %s, %s) ', + (0, datetime.datetime.now(), module_id, dependency)) class _Cursor(sqlite.Cursor): diff --git a/trytond/ir/cron.py b/trytond/ir/cron.py index 47aa58d74d..fcd8b40c00 100644 --- a/trytond/ir/cron.py +++ b/trytond/ir/cron.py @@ -160,9 +160,9 @@ class Cron(ModelSQL, ModelView): cursor.execute('SELECT * FROM ir_cron ' \ 'WHERE numbercall <> 0 ' \ 'AND active ' \ - 'AND nextcall <= now() ' \ + 'AND nextcall <= %s ' \ 'AND NOT running ' \ - 'ORDER BY priority') + 'ORDER BY priority', (datetime.datetime.now(),)) crons = cursor.dictfetchall() for cron in crons: diff --git a/trytond/model/modelsql.py b/trytond/model/modelsql.py index 4217b1238b..4c8d087121 100644 --- a/trytond/model/modelsql.py +++ b/trytond/model/modelsql.py @@ -311,8 +311,9 @@ class ModelSQL(ModelStorage): 'is not in the selection' % \ (val, field)) upd0 += ', create_uid, create_date' - upd1 += ', %s, now()' + upd1 += ', %s, %s' upd2.append(user) + upd2.append(datetime.datetime.now()) try: id_new = cursor.nextid(self._table) if id_new: @@ -483,8 +484,6 @@ class ModelSQL(ModelStorage): if not self.table_query(context): fields_pre2 += ['(COALESCE(write_date, create_date)) ' \ 'AS _timestamp'] - else: - fields_pre2 += ['now()::timestamp AS _timestamp'] for i in range(0, len(ids), in_max): sub_ids = ids[i:i + in_max] @@ -808,8 +807,9 @@ class ModelSQL(ModelStorage): (val, field)) upd0.append(('write_uid', '%s')) - upd0.append(('write_date', 'now()')) + upd0.append(('write_date', '%s')) upd1.append(user) + upd1.append(datetime.datetime.now()) domain1, domain2 = self.pool.get('ir.rule').domain_get(cursor, user, self._name, mode='write', context=context) @@ -1121,8 +1121,8 @@ class ModelSQL(ModelStorage): if self._history: for obj_id in ids: cursor.execute('INSERT INTO "' + self._table + '__history" ' \ - '(id, write_uid, write_date) VALUES (%s, %s, now())', - (obj_id, user)) + '(id, write_uid, write_date) VALUES (%s, %s, %s)', + (obj_id, user, datetime.datetime.now())) for k in tree_ids.keys(): field = self._columns[k] @@ -1205,8 +1205,6 @@ class ModelSQL(ModelStorage): select_fields += ['(COALESCE("' + self._table + '".write_date,'\ '"' + self._table + '".create_date)) ' \ 'AS _timestamp'] - else: - select_fields += ['now()::timestamp AS _timestamp'] query_str = cursor.limit_clause( 'SELECT ' + ','.join(select_fields) + ' FROM ' + \ ' '.join(tables) + (qu1 and ' WHERE ' + qu1 or '') + \ diff --git a/trytond/tools/misc.py b/trytond/tools/misc.py index 42c5f78f30..815358477e 100644 --- a/trytond/tools/misc.py +++ b/trytond/tools/misc.py @@ -19,6 +19,7 @@ try: except ImportError: import StringIO import dis +import datetime def find_in_path(name): if os.name == "nt": @@ -323,11 +324,11 @@ class Cache(object): cursor.execute('SELECT name FROM ir_cache WHERE name = %s', (name,)) if cursor.fetchone(): - cursor.execute('UPDATE ir_cache SET "timestamp" = now() '\ - 'WHERE name = %s', (name,)) + cursor.execute('UPDATE ir_cache SET "timestamp" = %s '\ + 'WHERE name = %s', (datetime.datetime.now(), name)) else: cursor.execute('INSERT INTO ir_cache ("timestamp", "name") ' \ - 'VALUES (now(), %s)', (name,)) + 'VALUES (%s, %s)', (datetime.datetime.now(), name)) Cache._resets[dbname].clear() finally: cursor.commit() From 4ba671b3eeb5821d84c6d98e9565ae92cd00a5e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 3 Nov 2009 15:23:07 +0100 Subject: [PATCH 012/144] Don't use date_trunc as it returns work type in SQLite (transplanted from c99fad19841d71e3ee73461f54d73124b4c0942c) --- trytond/model/modelsql.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/trytond/model/modelsql.py b/trytond/model/modelsql.py index 4c8d087121..a74c028f35 100644 --- a/trytond/model/modelsql.py +++ b/trytond/model/modelsql.py @@ -476,9 +476,7 @@ class ModelSQL(ModelStorage): history_limit = cursor.limit_clause('', 1) history_args = [context['_datetime']] if len(fields_pre) : - fields_pre2 = [(x in ('create_date', 'write_date')) \ - and ('date_trunc(\'second\', ' + x + ') as ' + x) \ - or '"' + x + '"' for x in fields_pre \ + fields_pre2 = ['"' + x + '"' for x in fields_pre \ if x != '_timestamp'] if '_timestamp' in fields_pre: if not self.table_query(context): @@ -1192,10 +1190,8 @@ class ModelSQL(ModelStorage): select_fields += ['COALESCE("' + self._table + '".write_date, "' + \ self._table + '".create_date) AS _datetime'] if not query_string: - select_fields += [(x[0] in ('create_date', 'write_date')) \ - and ('date_trunc(\'second\', "' + \ - self._table + '"."' + x[0] + '") AS "' + x[0] + '"') \ - or '"' + self._table + '"."' + x[0] + '" AS "' + x[0] + '"' \ + select_fields += [ + '"' + self._table + '"."' + x[0] + '" AS "' + x[0] + '"' \ for x in self._columns.iteritems() \ if not hasattr(x[1], 'get') \ and (x[0] != 'id') From 08349bdcf192543c971c1c549686490e44aafe41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 3 Nov 2009 15:24:11 +0100 Subject: [PATCH 013/144] Use custom datetime adapter that remove tzinfo for SQLite (transplanted from 285da1da43b4cc67155c380f097b62c383469bd6) --- trytond/backend/sqlite/database.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/trytond/backend/sqlite/database.py b/trytond/backend/sqlite/database.py index 5790a52d27..171493ceb6 100644 --- a/trytond/backend/sqlite/database.py +++ b/trytond/backend/sqlite/database.py @@ -9,6 +9,7 @@ import os import re import mx.DateTime from decimal import Decimal +import datetime _FIX_ROWCOUNT = False try: @@ -346,3 +347,6 @@ class Cursor(CursorInterface): sqlite.register_converter('NUMERIC', lambda val: Decimal(str(val))) sqlite.register_adapter(Decimal, lambda val: float(val)) sqlite.register_adapter(Session, lambda val: int(val)) +def adapt_datetime(val): + return val.replace(tzinfo=None).isoformat(" ") +sqlite.register_adapter(datetime.datetime, adapt_datetime) From 60d76ea97a6bc3dbd028b85ea63f7a3bdec264cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 3 Nov 2009 15:25:15 +0100 Subject: [PATCH 014/144] Fix extract to work with microseconds (transplanted from 4204a6cbcd5a03ebbaaab9e347332b2902954a28) --- trytond/backend/sqlite/database.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/trytond/backend/sqlite/database.py b/trytond/backend/sqlite/database.py index 171493ceb6..d7e8a6cc6d 100644 --- a/trytond/backend/sqlite/database.py +++ b/trytond/backend/sqlite/database.py @@ -29,7 +29,14 @@ def extract(lookup_type, date): if date is None: return None try: - date = mx.DateTime.strptime(date, '%Y-%m-%d %H:%M:%S') + datepart, timepart = date.split(" ") + year, month, day = map(int, datepart.split("-")) + timepart_full = timepart.split(".") + hours, minutes, seconds = map(int, timepart_full[0].split(":")) + if len(timepart_full) == 2: + microseconds = int(timepart_full[1]) + seconds += microseconds / 1000000.0 + date = mx.DateTime.DateTime(year, month, day, hours, minutes, seconds) except: return None if lookup_type.lower() == 'century': From dc30ed6f27068640a63e726374ea7c6b2dd57240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 3 Nov 2009 21:22:11 +0100 Subject: [PATCH 015/144] Fix base64 encodeing if data is None or False for issue1272 (transplanted from a6942d2d9ea45d5b177b0efba376922f88187fd6) --- trytond/webdav/webdav.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trytond/webdav/webdav.py b/trytond/webdav/webdav.py index 63f6c50413..ed607ae998 100644 --- a/trytond/webdav/webdav.py +++ b/trytond/webdav/webdav.py @@ -519,7 +519,7 @@ class Collection(ModelSQL, ModelView): try: attachment_obj.create(cursor, user, { 'name': name, - 'datas': base64.encodestring(data), + 'datas': base64.encodestring(data or ''), 'name': name, 'res_model': object_name, 'res_id': object_id, @@ -529,7 +529,7 @@ class Collection(ModelSQL, ModelView): else: try: attachment_obj.write(cursor, user, object_id2, { - 'datas': base64.encodestring(data), + 'datas': base64.encodestring(data or ''), }, context=context) except: raise DAV_Forbidden From fb10396e572d53825b2b579e18a23db774f3a0e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 4 Nov 2009 09:01:54 +0100 Subject: [PATCH 016/144] Don't use now() in SQL statement as it doesn't work on SQLite (transplanted from e732f5e84eafa84f51c21ec74080fe44ddf999a0) --- trytond/ir/sequence.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/trytond/ir/sequence.py b/trytond/ir/sequence.py index 9999078661..02e0e63bb5 100644 --- a/trytond/ir/sequence.py +++ b/trytond/ir/sequence.py @@ -3,6 +3,7 @@ import time from trytond.model import ModelView, ModelSQL, fields from string import Template +import datetime class SequenceType(ModelSQL, ModelView): @@ -117,8 +118,9 @@ class Sequence(ModelSQL, ModelView): cursor.execute('UPDATE "' + self._table + '" ' \ 'SET number_next = number_next + number_increment, ' \ 'write_uid = %s, ' \ - 'write_date = NOW() ' \ - 'WHERE id = %s AND active = %s', (user, sequence.id, True)) + 'write_date = %s ' \ + 'WHERE id = %s AND active = %s', + (user, datetime.datetime.now(), sequence.id, True)) if number_next: return self._process(cursor, user, sequence.prefix, date=date, context=context) + \ From 12f8b972366366632a408e4c9db4a13f85d308b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 5 Nov 2009 11:29:47 +0100 Subject: [PATCH 017/144] Use empty context for root user when validate records for issue1275 (transplanted from 71405f444b5eb5a135064565fd1c36fef554be6f) --- trytond/model/modelstorage.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py index cacf10ce94..99192e5f46 100644 --- a/trytond/model/modelstorage.py +++ b/trytond/model/modelstorage.py @@ -904,7 +904,8 @@ class ModelStorage(Model): if not getattr(self, field[0])(cursor, user, ids): self.raise_user_error(cursor, field[1], context=context) - if not 'res.user' in self.pool.object_name_list(): + if not 'res.user' in self.pool.object_name_list() \ + or user == 0: ctx_pref = { } else: From fd8597f9c752ff8833cfd4083a1707a70d0ec674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 6 Nov 2009 16:58:31 +0100 Subject: [PATCH 018/144] Prevent key error in BrowseRecord with big cache (transplanted from 8df8b60998bbf08ecea8af0ca32c9e82b422ef03) --- trytond/model/browse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/model/browse.py b/trytond/model/browse.py index 88fd916622..0265ba5d0f 100644 --- a/trytond/model/browse.py +++ b/trytond/model/browse.py @@ -135,7 +135,7 @@ class BrowseRecord(object): else: iterids = self._local_data.iterkeys() ids = [x for x in iterids \ - if not self._data[x].has_key(name) \ + if not self._data.setdefault(x, {}).has_key(name) \ and not self._local_data.setdefault(x, {}).has_key(name)] # read the data datas = self._model.read(self._cursor, self._user, ids, From d80f623695ad2562bf9e930dbadd76337572018c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 8 Nov 2009 00:29:06 +0100 Subject: [PATCH 019/144] Fix search_read for issue1257 (transplanted from 24a71ddc78216eb0c4ad005b9addc90ab3d85684) --- trytond/model/modelstorage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py index 99192e5f46..4ddb2a5f34 100644 --- a/trytond/model/modelstorage.py +++ b/trytond/model/modelstorage.py @@ -411,7 +411,7 @@ class ModelStorage(Model): for fields_name in set(fields_names): fields = fields_name.split('.') while fields: - field_name = fields.pop() + field_name = fields.pop(0) if fields_name not in record: record[fields_name] = model[field_name] else: From ea9537ec456adfcafbe1da5e62ad30eec8df2a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 10 Nov 2009 14:03:20 +0100 Subject: [PATCH 020/144] Improve exception handling for issue1180 (transplanted from 8036d3f7ae9617efd44732cf96c1155106d9ab0c) --- trytond/protocols/webdav.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/trytond/protocols/webdav.py b/trytond/protocols/webdav.py index 8db6e5e01d..bd826be0f8 100644 --- a/trytond/protocols/webdav.py +++ b/trytond/protocols/webdav.py @@ -194,6 +194,8 @@ class TrytonDAVInterface(iface.dav_interface): for child in collection_obj.get_childs(cursor, int(USER_ID), dburi, filter=filter, cache=CACHE): res.append(uri + child.encode('utf-8')) + except KeyError: + return res except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception: self._log_exception(exception) raise @@ -389,7 +391,7 @@ class TrytonDAVInterface(iface.dav_interface): def rmcol(self, uri): dbname, dburi = self._get_dburi(uri) if not dbname or not dburi: - raise DAV_Forbidden + return 403 cursor = DATABASE['cursor'] pool = Pool(DATABASE['dbname']) collection_obj = pool.get('webdav.collection') @@ -397,20 +399,16 @@ class TrytonDAVInterface(iface.dav_interface): res = collection_obj.rmcol(cursor, int(USER_ID), dburi, cache=CACHE) cursor.commit() - except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception: - self._log_exception(exception) - cursor.rollback() - raise except Exception, exception: self._log_exception(exception) cursor.rollback() - raise DAV_Error(500) + return 500 return res def rm(self, uri): dbname, dburi = self._get_dburi(uri) if not dbname or not dburi: - raise DAV_Forbidden + return 403 cursor = DATABASE['cursor'] pool = Pool(DATABASE['dbname']) collection_obj = pool.get('webdav.collection') @@ -418,14 +416,10 @@ class TrytonDAVInterface(iface.dav_interface): res = collection_obj.rm(cursor, int(USER_ID), dburi, cache=CACHE) cursor.commit() - except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception: - self._log_exception(exception) - cursor.rollback() - raise except Exception, exception: self._log_exception(exception) cursor.rollback() - raise DAV_Error(500) + return 500 return res def exists(self, uri): From 8fd525af1385b76ffe5d54ecc9443f14287fe530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 10 Nov 2009 14:13:37 +0100 Subject: [PATCH 021/144] Return value for displayname (transplanted from 355b5b9f3df5103cc735ecad70eeaddb0ab6dc69) --- trytond/protocols/webdav.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/protocols/webdav.py b/trytond/protocols/webdav.py index bd826be0f8..ab1416827d 100644 --- a/trytond/protocols/webdav.py +++ b/trytond/protocols/webdav.py @@ -311,7 +311,7 @@ class TrytonDAVInterface(iface.dav_interface): return res def _get_dav_displayname(self, uri): - raise DAV_Secret + return uri.split('/')[-1] def _get_dav_getcontentlength(self, uri): dbname, dburi = self._get_dburi(uri) From 8fddc10eda22eeb92fe814ef15cb29ce090492d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 10 Nov 2009 14:14:30 +0100 Subject: [PATCH 022/144] Add access-control to DAV header (transplanted from 6e197d54841633b9d6ce7e096f6584251b06d2c5) --- trytond/protocols/webdav.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/trytond/protocols/webdav.py b/trytond/protocols/webdav.py index ab1416827d..ae66a857ea 100644 --- a/trytond/protocols/webdav.py +++ b/trytond/protocols/webdav.py @@ -1,5 +1,6 @@ #This file is part of Tryton. The COPYRIGHT file at the top level of #this repository contains the full copyright notices and license terms. +_TRYTON_RELOAD = False from trytond.protocols.sslsocket import SSLSocket from trytond.config import CONFIG from trytond.security import login @@ -17,7 +18,7 @@ import base64 import time from DAV import AuthServer, WebDAVServer, iface from DAV.errors import * -from DAV.constants import COLLECTION, OBJECT +from DAV.constants import COLLECTION, OBJECT, DAV_VERSION_1, DAV_VERSION_2 from DAV.utils import get_uriparentpath, get_urifilename, quote_uri from DAV.davcmd import copyone, copytree, moveone, movetree, delone, deltree import urllib @@ -26,6 +27,8 @@ import traceback import logging from threading import local +DAV_VERSION_1['version'] += ',access-control' +DAV_VERSION_2['version'] += ',access-control' # Local int for multi-thread class LocalInt(local): From e4d9f548d642dcf2a5c8779648d25420818372f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 10 Nov 2009 14:15:16 +0100 Subject: [PATCH 023/144] Add current-user-privilege-set to DAV props for iPhone (transplanted from f0947321443470fff464f8652e09a41232924964) --- trytond/protocols/webdav.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/trytond/protocols/webdav.py b/trytond/protocols/webdav.py index ae66a857ea..deb60778a8 100644 --- a/trytond/protocols/webdav.py +++ b/trytond/protocols/webdav.py @@ -26,6 +26,8 @@ import sys import traceback import logging from threading import local +import xml.dom.minidom +domimpl = xml.dom.minidom.getDOMImplementation() DAV_VERSION_1['version'] += ',access-control' DAV_VERSION_2['version'] += ',access-control' @@ -474,6 +476,29 @@ class TrytonDAVInterface(iface.dav_interface): def copycol(self, src, dst): return self.mkcol(dst) + def _get_dav_current_user_privilege_set(self, uri): + doc = domimpl.createDocument(None, 'privilege', None) + privilege = doc.documentElement + privilege.tagName = 'D:privilege' + read = doc.createElement('D:read') + privilege.appendChild(read) + write = doc.createElement('D:write') + privilege.appendChild(write) + bind = doc.createElement('D:bind') + privilege.appendChild(bind) + unbind = doc.createElement('D:unbind') + privilege.appendChild(unbind) + write_content = doc.createElement('D:write-content') + privilege.appendChild(write_content) + write_properties = doc.createElement('D:write-properties') + privilege.appendChild(write_properties) + read_acl = doc.createElement('D:read-acl') + privilege.appendChild(read_acl) + return privilege + +TrytonDAVInterface.PROPS['DAV:'] = tuple(list(TrytonDAVInterface.PROPS['DAV:']) \ + + ['current-user-privilege-set']) + class WebDAVAuthRequestHandler(AuthServer.BufferedAuthRequestHandler, WebDAVServer.DAVRequestHandler): From 9e24b4d7220fe5fe2f7d10e50f6c3161a0caeb07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 13 Nov 2009 12:31:48 +0100 Subject: [PATCH 024/144] Add new methods to webdav CONFIG for upcomming version of pywebdav (transplanted from bb463ca8bfb2e85c2b58d4ce8d45351c070c2cb4) --- trytond/protocols/webdav.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/trytond/protocols/webdav.py b/trytond/protocols/webdav.py index deb60778a8..16e4147d8e 100644 --- a/trytond/protocols/webdav.py +++ b/trytond/protocols/webdav.py @@ -59,6 +59,15 @@ if not hasattr(WebDAVServer.DAVRequestHandler, '_config'): lockemulation = False verbose = False + def getboolean(self, name): + return bool(self.get(name)) + + def get(self, name, default=None): + try: + return self[name] + except: + return default + class _Config: DAV = DAV() From f3033e17ae3f216a6409763a6bb02c91f53d1793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 23 Nov 2009 17:35:40 +0100 Subject: [PATCH 025/144] Prepare release 1.4.2 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 1f6d0ab149..cc3685254e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 1.4.2 - 2009-11-23 +* Some bug fixes (see mercurial logs for details) + Version 1.4.1 - 2009-10-20 * Add missing init.sql of SQLite From 32aa226561bea37f7b36b8327194432bf621b6a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 23 Nov 2009 17:35:44 +0100 Subject: [PATCH 026/144] Added tag 1.4.2 for changeset adb88e158ef4 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 6b430be024..d37904634d 100644 --- a/.hgtags +++ b/.hgtags @@ -2,3 +2,4 @@ 9f5ce178a7c403a0865fd4b6c1a82a911df0e998 1.2.0 e2d31d59de7745de70199b7c340d78b7c4775723 1.4.0 a2589d0064b2369c79cf2914e4f7caa8b907c6de 1.4.1 +adb88e158ef4b72c67d196417ff7229cf6bd07df 1.4.2 From 04785ff21e9cf471cb3e7be7942a2a3f9502470f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 23 Nov 2009 17:40:09 +0100 Subject: [PATCH 027/144] Increase version number --- trytond/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/version.py b/trytond/version.py index b586fb705d..cfb78ebec6 100644 --- a/trytond/version.py +++ b/trytond/version.py @@ -1,7 +1,7 @@ #This file is part of Tryton. The COPYRIGHT file at the top level of #this repository contains the full copyright notices and license terms. PACKAGE = "trytond" -VERSION = "1.4.2" +VERSION = "1.4.3" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From a9a1935950b95ab9bd1e2f9e02f5787ec5786801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 25 Nov 2009 14:19:59 +0100 Subject: [PATCH 028/144] Use ascii letters instead of letters because it is not locale-dependent for issue1154 (transplanted from 0a5359cd20baed33badde73324574e5dd83983ca) --- trytond/res/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/res/user.py b/trytond/res/user.py index dd898af924..d803b745ab 100644 --- a/trytond/res/user.py +++ b/trytond/res/user.py @@ -137,7 +137,7 @@ class User(ModelSQL, ModelView): del vals['password'] elif vals['password']: vals['salt'] = ''.join(random.sample( - string.letters + string.digits, 8)) + string.ascii_letters + string.digits, 8)) vals['password'] += vals['salt'] return vals From 74b1753697d816b0be510ef37731a0261e1fb164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 9 Dec 2009 11:01:30 +0100 Subject: [PATCH 029/144] Prepare release 1.4.3 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index cc3685254e..7d9c643c01 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 1.4.3 - 2009-12-09 +* Some bug fixes (see mercurial logs for details) + Version 1.4.2 - 2009-11-23 * Some bug fixes (see mercurial logs for details) From 1a0ad1779d390180f717cf73470e0d7eb50866c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 9 Dec 2009 11:01:45 +0100 Subject: [PATCH 030/144] Added tag 1.4.3 for changeset 8dfc51bb21c0 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index d37904634d..d708639f31 100644 --- a/.hgtags +++ b/.hgtags @@ -3,3 +3,4 @@ e2d31d59de7745de70199b7c340d78b7c4775723 1.4.0 a2589d0064b2369c79cf2914e4f7caa8b907c6de 1.4.1 adb88e158ef4b72c67d196417ff7229cf6bd07df 1.4.2 +8dfc51bb21c0d8b7842c28c4a1f880e23110351b 1.4.3 From af0d7d209d1af8cb536a6a5594ab07565322eda4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 9 Dec 2009 11:04:03 +0100 Subject: [PATCH 031/144] Increase version number --- trytond/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/version.py b/trytond/version.py index cfb78ebec6..2c31f0f009 100644 --- a/trytond/version.py +++ b/trytond/version.py @@ -1,7 +1,7 @@ #This file is part of Tryton. The COPYRIGHT file at the top level of #this repository contains the full copyright notices and license terms. PACKAGE = "trytond" -VERSION = "1.4.3" +VERSION = "1.4.4" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 41898cb8644f3653f8447890a7180463e7bd2250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 17 Dec 2009 12:01:41 +0100 Subject: [PATCH 032/144] Fix initialization of warning in import_data if exception is raised for issue1337 (transplanted from 8265102f5fcf6bd488f4d7eb1b7881f0041b89d2) --- trytond/model/modelstorage.py | 1 + 1 file changed, 1 insertion(+) diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py index 4ddb2a5f34..0c84aea3ee 100644 --- a/trytond/model/modelstorage.py +++ b/trytond/model/modelstorage.py @@ -758,6 +758,7 @@ class ModelStorage(Model): while len(datas): res = {} + warning = '' try: (res, other, warning, translate) = \ process_liness(self, datas, [], fields_def) From 3b8912fc294681f608daabfcfc8142acd734eb49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 21 Dec 2009 11:57:42 +0100 Subject: [PATCH 033/144] Use root user for create/write ir.translation to bypass the model access (transplanted from 39e3839cc37c77fea51bb9aa440fca2f3655ba8d) --- trytond/ir/translation.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index 642652dacc..88630af25a 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -188,7 +188,7 @@ class Translation(ModelSQL, ModelView, Cacheable): ('name', '=', name), ]) if not ids2: - self.create(cursor, user, { + self.create(cursor, 0, { 'name': name, 'lang': lang, 'type': ttype, @@ -197,7 +197,7 @@ class Translation(ModelSQL, ModelView, Cacheable): 'fuzzy': False, }) else: - self.write(cursor, user, ids, { + self.write(cursor, 0, ids, { 'src': record[field_name], 'value': value, 'fuzzy': False, @@ -212,7 +212,7 @@ class Translation(ModelSQL, ModelView, Cacheable): ('res_id', '=', record.id), ]) if not ids2: - self.create(cursor, user, { + self.create(cursor, 0, { 'name': name, 'lang': lang, 'type': ttype, @@ -222,7 +222,7 @@ class Translation(ModelSQL, ModelView, Cacheable): 'fuzzy': False, }) else: - self.write(cursor, user, ids2, { + self.write(cursor, 0, ids2, { 'value': value, 'src': record[field_name], 'fuzzy': False, From d8271dbdd774a973ba4f38a2cdc7ea3d58c6d1eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 21 Dec 2009 16:09:18 +0100 Subject: [PATCH 034/144] Fix reduce_ids with empty list (transplanted from bd41f2847c883a0c05799c188d3a898e2632d9da) --- trytond/tests/test_tryton.py | 6 ++++++ trytond/tools/misc.py | 2 ++ 2 files changed, 8 insertions(+) diff --git a/trytond/tests/test_tryton.py b/trytond/tests/test_tryton.py index 791e73ccd7..14df963534 100644 --- a/trytond/tests/test_tryton.py +++ b/trytond/tests/test_tryton.py @@ -62,6 +62,12 @@ class ToolsTestCase(unittest.TestCase): Test tools. ''' + def test0000reduce_ids_empty(self): + ''' + Test reduce_ids empty list. + ''' + self.assert_(('(%s)', [False]) == reduce_ids('id', [])) + def test0010reduce_ids_continue(self): ''' Test reduce_ids continue list. diff --git a/trytond/tools/misc.py b/trytond/tools/misc.py index 815358477e..c0104ac2d2 100644 --- a/trytond/tools/misc.py +++ b/trytond/tools/misc.py @@ -461,6 +461,8 @@ def reduce_ids(field, ids): :param ids: the list of ids :return: sql string and sql param ''' + if not ids: + return '(%s)', [False] ids = ids[:] ids.sort() prev = ids.pop(0) From 0cf23b3d60d7eb6329c613890c1f9c282881a6f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 5 Jan 2010 14:07:33 +0100 Subject: [PATCH 035/144] Fix create on many2many Create the target record before creating the relation record (transplanted from 0ff78fce52ddcc7bca73e342bc8f4e9ef2262181) --- trytond/model/fields/many2many.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/model/fields/many2many.py b/trytond/model/fields/many2many.py index b013be79b5..0ac625bc25 100644 --- a/trytond/model/fields/many2many.py +++ b/trytond/model/fields/many2many.py @@ -107,7 +107,8 @@ class Many2Many(Field): if act[0] == 'create': relation_obj.create(cursor, user, { self.origin: record_id, - self.target: [('create', act[1])], + self.target: target_obj.create(cursor, user, act[1], + context=context), }, context=context) elif act[0] == 'write': target_obj.write(cursor, user, act[1] , act[2], context=context) From bda5082f8812cd39a867ffce237a91c48bd834bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 5 Jan 2010 14:10:03 +0100 Subject: [PATCH 036/144] Fix default_get Loop on keys instead of dictionary which can change Add test on _columns before using it (transplanted from d22eee0444506c3bdf5f2ce363b2eca593ddd73d) --- trytond/model/model.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/trytond/model/model.py b/trytond/model/model.py index 7b72067638..d0ce7405db 100644 --- a/trytond/model/model.py +++ b/trytond/model/model.py @@ -564,8 +564,9 @@ class Model(object): field_value2 = [] for i in range(len(field_value or [])): field_value2.append({}) - for field2 in field_value[i]: - if obj._columns[field2]._type \ + for field2 in field_value[i].keys(): + if field2 in obj._columns \ + and obj._columns[field2]._type \ in ('many2one',): obj2 = self.pool.get( obj._columns[field2].model_name) From dc968b793d7478294e3d8483195d19ec8e56ccb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 6 Jan 2010 00:27:13 +0100 Subject: [PATCH 037/144] Fix typo (transplanted from 41ba3f88f79d7f34d4ea0220285b861e0a8e04ec) --- trytond/ir/ui/form.rnc | 2 +- trytond/ir/ui/form.rng | 2 +- trytond/ir/ui/tree.rnc | 2 +- trytond/ir/ui/tree.rng | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/trytond/ir/ui/form.rnc b/trytond/ir/ui/form.rnc index ebd75eda8d..014021a0cc 100644 --- a/trytond/ir/ui/form.rnc +++ b/trytond/ir/ui/form.rnc @@ -76,7 +76,7 @@ attlist.field &= | "float" | "numeric" | "float_time" - | "interger" + | "integer" | "datetime" | "boolean" | "text" diff --git a/trytond/ir/ui/form.rng b/trytond/ir/ui/form.rng index 6f6ae72e0a..d808ad37d3 100644 --- a/trytond/ir/ui/form.rng +++ b/trytond/ir/ui/form.rng @@ -261,7 +261,7 @@ float numeric float_time - interger + integer datetime boolean text diff --git a/trytond/ir/ui/tree.rnc b/trytond/ir/ui/tree.rnc index 088f6567e6..5531e4fc0d 100644 --- a/trytond/ir/ui/tree.rnc +++ b/trytond/ir/ui/tree.rnc @@ -28,7 +28,7 @@ attlist.field &= | "float" | "numeric" | "float_time" - | "interger" + | "integer" | "datetime" | "boolean" | "text" diff --git a/trytond/ir/ui/tree.rng b/trytond/ir/ui/tree.rng index a6d4cf40cc..e057366852 100644 --- a/trytond/ir/ui/tree.rng +++ b/trytond/ir/ui/tree.rng @@ -92,7 +92,7 @@ float numeric float_time - interger + integer datetime boolean text From 3694a357cf8f6bf3e71b260a6a49e86b862c54fe Mon Sep 17 00:00:00 2001 From: Ian Wilson Date: Sun, 10 Jan 2010 16:18:15 -0800 Subject: [PATCH 038/144] Add index to improve performance of sorting subsequences for issue1372 (transplanted from 1f45f1707f9e193619ab6ab26288fe8e2e68cca8) --- trytond/model/fields/one2many.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/model/fields/one2many.py b/trytond/model/fields/one2many.py index 80583a8c82..31f14cd75a 100644 --- a/trytond/model/fields/one2many.py +++ b/trytond/model/fields/one2many.py @@ -85,8 +85,9 @@ class One2Many(Field): [self.field], context=context): res[i[self.field]].append(i['id']) + index_of_ids2 = dict((i, index) for index, i in enumerate(ids2)) for val in res.values(): - val.sort(lambda x, y: cmp(ids2.index(x), ids2.index(y))) + val.sort(lambda x, y: cmp(index_of_ids2[x], index_of_ids2[y])) return res def set(self, cursor, user, record_id, model, name, values, context=None): From 49a0c3a0d3c9a684cb97be62099e065f6198d00d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 13 Jan 2010 00:27:31 +0100 Subject: [PATCH 039/144] Fix import_data for field many2many for issue1373 (transplanted from 579fe80180e18110c656f3043709c8dcd3b38cd2) --- trytond/model/modelstorage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py index 0c84aea3ee..e4539eb33c 100644 --- a/trytond/model/modelstorage.py +++ b/trytond/model/modelstorage.py @@ -704,7 +704,7 @@ class ModelStorage(Model): 'Relation not found: ' + line[i] + \ ' on '+relation + ' !\n') else: - res.append(res2) + res.extend(res2) if len(res): res = [('set', res)] else: From 2e0c94ebfaf2e699d115800f45eae9f73233eb9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 17 Jan 2010 21:22:00 +0100 Subject: [PATCH 040/144] Fix wrong use of assertRaises and use assert (transplanted from 1290563a155b006b5a150644e6c1abe1e8c3ed58) --- trytond/tests/test_tryton.py | 62 ++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/trytond/tests/test_tryton.py b/trytond/tests/test_tryton.py index 14df963534..cacc39d566 100644 --- a/trytond/tests/test_tryton.py +++ b/trytond/tests/test_tryton.py @@ -1504,25 +1504,25 @@ class ModelViewTestCase(unittest.TestCase): ''' Test ir. ''' - self.assertRaises(Exception, test_view('ir')) + test_view('ir') def test0020res(self): ''' Test res. ''' - self.assertRaises(Exception, test_view('res')) + test_view('res') def test0030workflow(self): ''' Test workflow. ''' - self.assertRaises(Exception, test_view('workflow')) + test_view('workflow') def test0040webdav(self): ''' Test webdav. ''' - self.assertRaises(Exception, test_view('webdav')) + test_view('webdav') class ModelSingletonTestCase(unittest.TestCase): @@ -1645,29 +1645,29 @@ class MPTTTestCase(unittest.TestCase): childs.sort(lambda x, y: cmp(child_ids.index(x['id']), child_ids.index(y['id']))) for child in childs: - if child['left'] <= left: - raise Exception('Record (%d): left %d <= parent left %d' % \ - (child['id'], child['left'], left)) - if child['left'] >= child['right']: - raise Exception('Record (%d): left %d >= right %d' % \ - (child['id'], child['left'], child['right'])) - if right != 0 and child['right'] >= right: - raise Exception('Record (%d): right %d >= parent right %d' % \ - (child['id'], child['right'], right)) + assert child['left'] > left, \ + 'Record (%d): left %d <= parent left %d' % \ + (child['id'], child['left'], left) + assert child['left'] < child['right'], \ + 'Record (%d): left %d >= right %d' % \ + (child['id'], child['left'], child['right']) + assert right == 0 or child['right'] < right, \ + 'Record (%d): right %d >= parent right %d' % \ + (child['id'], child['right'], right) self.CheckTree(child['id'], left=child['left'], right=child['right']) next_left = 0 for child in childs: - if child['left'] <= next_left: - raise Exception('Record (%d): left %d <= next left %d' % \ - (child['id'], child['left'], next_left)) + assert child['left'] > next_left, \ + 'Record (%d): left %d <= next left %d' % \ + (child['id'], child['left'], next_left) next_left = child['right'] childs.reverse() previous_right = 0 for child in childs: - if previous_right != 0 and child['right'] >= previous_right: - raise Exception('Record (%d): right %d >= previous right %d' % \ - (child['id'] , child['right'], previous_right)) + assert previous_right == 0 or child['right'] < previous_right, \ + 'Record (%d): right %d >= previous right %d' % \ + (child['id'] , child['right'], previous_right) previous_right = child['left'] @@ -1683,11 +1683,11 @@ class MPTTTestCase(unittest.TestCase): self.mptt.write(record_id, { 'parent': record2_id, }, CONTEXT) - self.assertRaises(Exception, self.CheckTree()) + self.CheckTree() self.mptt.write(record_id, { 'parent': parent_id, }, CONTEXT) - self.assertRaises(Exception, self.CheckTree()) + self.CheckTree() for record_id in record_ids: self.ReParent(record_id) @@ -1703,14 +1703,14 @@ class MPTTTestCase(unittest.TestCase): 'sequence': i, }, CONTEXT) i -= 1 - self.assertRaises(Exception, self.CheckTree()) + self.CheckTree() i = 0 for record_id in record_ids: self.mptt.write(record_id, { 'sequence': i, }, CONTEXT) i += 1 - self.assertRaises(Exception, self.CheckTree()) + self.CheckTree() for record_id in record_ids: self.ReOrder(record_id) @@ -1718,7 +1718,7 @@ class MPTTTestCase(unittest.TestCase): self.mptt.write(record_ids, { 'sequence': 0, }, CONTEXT) - self.assertRaises(Exception, self.CheckTree()) + self.CheckTree() def test0010create(self): ''' @@ -1737,7 +1737,7 @@ class MPTTTestCase(unittest.TestCase): }, CONTEXT) new_records.append(record_id) k += 1 - self.assertRaises(Exception, self.CheckTree()) + self.CheckTree() def test0020reorder(self): ''' @@ -1758,7 +1758,7 @@ class MPTTTestCase(unittest.TestCase): self.mptt.write(record_id, { 'active': False }, CONTEXT) - self.assertRaises(Exception, self.CheckTree()) + self.CheckTree() self.ReParent() self.ReOrder() @@ -1767,7 +1767,7 @@ class MPTTTestCase(unittest.TestCase): self.mptt.write(record_ids[:len(record_ids)/2], { 'active': False }, CONTEXT) - self.assertRaises(Exception, self.CheckTree()) + self.CheckTree() record_ids = self.mptt.search([], 0, None, None, CONTEXT) self.mptt.write(record_ids, { 'active': False @@ -1783,7 +1783,7 @@ class MPTTTestCase(unittest.TestCase): self.mptt.write(record_ids, { 'active': False }, CONTEXT) - self.assertRaises(Exception, self.CheckTree()) + self.CheckTree() def test0050delete(self): ''' @@ -1793,13 +1793,13 @@ class MPTTTestCase(unittest.TestCase): for record_id in record_ids: if record_id % 2: self.mptt.delete(record_id, CONTEXT) - self.assertRaises(Exception, self.CheckTree()) + self.CheckTree() record_ids = self.mptt.search([], 0, None, None, CONTEXT) self.mptt.delete(record_ids[:len(record_ids)/2], CONTEXT) - self.assertRaises(Exception, self.CheckTree()) + self.CheckTree() record_ids = self.mptt.search([], 0, None, None, CONTEXT) self.mptt.delete(record_ids, CONTEXT) - self.assertRaises(Exception, self.CheckTree()) + self.CheckTree() class RPCProxy(object): From 2bfa0e6b4545730df29fbdc54be4a25c0bfc2214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 18 Jan 2010 23:44:10 +0100 Subject: [PATCH 041/144] Use the error message of the exception in import_data for issue1376 (transplanted from 165dede84794345526a7c6fc95ab432931952aee) --- trytond/model/modelstorage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py index e4539eb33c..bbceafef7b 100644 --- a/trytond/model/modelstorage.py +++ b/trytond/model/modelstorage.py @@ -774,7 +774,7 @@ class ModelStorage(Model): except Exception, exp: logger.error(exp) cursor.rollback() - return (-1, res, exp[0], warning) + return (-1, res, exp[1], warning) done += 1 return (done, 0, 0, 0) From ca3605e11ee2c5c0a2cdb9e6407ae3c71f3e050c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 19 Jan 2010 14:10:31 +0100 Subject: [PATCH 042/144] Fix test on _search_domain_active for XML-RPC for issue1380 Tuple in XML-RPC are list (transplanted from f7d3fd252538ee5d5a23e178be045dbc451b838e) --- trytond/model/modelstorage.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py index bbceafef7b..341f3b7f38 100644 --- a/trytond/model/modelstorage.py +++ b/trytond/model/modelstorage.py @@ -448,11 +448,15 @@ class ModelStorage(Model): i = 0 active_found = False while i < len(domain): - if isinstance(domain[i], list): - domain[i] = process(domain[i]) - if isinstance(domain[i], tuple): - if domain[i][0] == 'active': + arg = domain[i] + #add test for xmlrpc that doesn't handle tuple + if isinstance(arg, tuple) or \ + (isinstance(arg, list) and len(arg) > 2 and \ + arg[1] in OPERATORS): + if arg[0] == 'active': active_found = True + elif isinstance(arg, list): + domain[i] = process(domain[i]) i += 1 if not active_found: if domain and ((isinstance(domain[0], basestring) \ From 533b3952f26d3826dc7b1109cf90d893e7df6c0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 20 Jan 2010 18:13:30 +0100 Subject: [PATCH 043/144] Fix typo in get_id (transplanted from 006e4250151c964e7c54b526bac0ab7bc0d2e77e) --- trytond/ir/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/ir/model.py b/trytond/ir/model.py index f882ef5945..311ea8d1b1 100644 --- a/trytond/ir/model.py +++ b/trytond/ir/model.py @@ -305,7 +305,7 @@ class ModelData(ModelSQL, ModelView): """ ids = self.search(cursor, user, [ ('module', '=', module), - ('fs_is', '=', fs_id), + ('fs_id', '=', fs_id), ('inherit', '=', False), ]) if not ids: From 1879830e64ee1d07494b841dc938f0ff07c788c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 21 Jan 2010 18:24:42 +0100 Subject: [PATCH 044/144] Fix typo _get_id -> get_id (transplanted from fd1acd2b09dfaa68a3c0d8634f5867cf7a0b7e32) --- trytond/model/modelstorage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py index 341f3b7f38..6fe9916942 100644 --- a/trytond/model/modelstorage.py +++ b/trytond/model/modelstorage.py @@ -629,7 +629,7 @@ class ModelStorage(Model): module, xml_id = word.rsplit('.', 1) ir_model_data_obj = \ self.pool.get('ir.model.data') - new_id = ir_model_data_obj._get_id(cursor, + new_id = ir_model_data_obj.get_id(cursor, user, module, xml_id) res_id2 = ir_model_data_obj.read(cursor, user, [new_id], ['res_id'])[0]['res_id'] @@ -640,7 +640,7 @@ class ModelStorage(Model): else: module, xml_id = line[i].rsplit('.', 1) ir_model_data_obj = self.pool.get('ir.model.data') - new_id = ir_model_data_obj._get_id(cursor, user, + new_id = ir_model_data_obj.get_id(cursor, user, module, xml_id) res_id = ir_model_data_obj.read(cursor, user, [new_id], ['res_id'])[0]['res_id'] From 8858f726c5df295fb21e8281a3d5f871708c6be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 25 Jan 2010 09:20:50 +0100 Subject: [PATCH 045/144] Update COPYRIGHT --- COPYRIGHT | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index aa03494999..bab90c9e3e 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,7 +1,7 @@ Copyright (C) 2004-2008 Tiny SPRL. -Copyright (C) 2007-2009 Cédric Krier. -Copyright (C) 2007-2008 Bertrand Chenal. -Copyright (C) 2008-2009 B2CK SPRL. +Copyright (C) 2007-2010 Cédric Krier. +Copyright (C) 2007-2010 Bertrand Chenal. +Copyright (C) 2008-2010 B2CK SPRL. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by From b92401a4267ae81cbd430d55d0d1ae72dbde84fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 30 Jan 2010 00:17:49 +0100 Subject: [PATCH 046/144] Remove hardcoded True in SQL for issue1403 (transplanted from e94d7f4e890b6acd311f1e3c54e0433d0ab974ca) --- trytond/ir/ui/view.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trytond/ir/ui/view.py b/trytond/ir/ui/view.py index 3d6de4df52..10089ab63c 100644 --- a/trytond/ir/ui/view.py +++ b/trytond/ir/ui/view.py @@ -122,9 +122,9 @@ class View(ModelSQL, ModelView): if seqmatch.ratio() > 0.6: cursor.execute('UPDATE ir_translation ' \ 'SET src = %s, ' \ - 'fuzzy = True ' \ + 'fuzzy = %s ' \ 'WHERE id = %s ', - (string, trans_views[string_trans]['id'])) + (string, True, trans_views[string_trans]['id'])) del trans_views[string_trans] done = True break From 6819fb0a990a6aaa10469abd4557e240197122d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 3 Feb 2010 15:23:19 +0100 Subject: [PATCH 047/144] Return the same id when reading with default_get in Singleton (transplanted from e460117662829954b807c7fba4fa9dc0151ac512) --- trytond/model/modelsingleton.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/trytond/model/modelsingleton.py b/trytond/model/modelsingleton.py index 07da6d3656..4a9e79d394 100644 --- a/trytond/model/modelsingleton.py +++ b/trytond/model/modelsingleton.py @@ -29,9 +29,11 @@ class ModelSingleton(ModelStorage): if not singleton_id: res = self.default_get(cursor, user, fields_names, context=context, with_rec_name=False) - res['id'] = 1 if not isinstance(ids, (int, long)): + res['id'] = ids[0] res = [res] + else: + res['id'] = ids return res if isinstance(ids, (int, long)): ids2 = singleton_id From 154bdac2a8cf22a961851fbdd4d1cce79fa5dba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 3 Feb 2010 17:36:44 +0100 Subject: [PATCH 048/144] Fix exec_pg_command_pipe to work on windows for issue1405 (transplanted from ba33cd582094bee737824fcf8a55022a6629e83a) --- trytond/tools/misc.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/trytond/tools/misc.py b/trytond/tools/misc.py index c0104ac2d2..cf1bd0d13d 100644 --- a/trytond/tools/misc.py +++ b/trytond/tools/misc.py @@ -62,10 +62,8 @@ def exec_pg_command_pipe(name, *args): child_env = dict(os.environ) if CONFIG['db_password']: child_env['PGPASSWORD'] = CONFIG['db_password'] - pipe = subprocess.Popen(cmd, shell=True, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - close_fds=True, - env=child_env) + pipe = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, env=child_env) return pipe def exec_command_pipe(name, *args): From 31d5e77a29e31e58933587cc52b170ef18c4ae1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 9 Feb 2010 19:02:59 +0100 Subject: [PATCH 049/144] Fix get() takes no keyword arguments --- trytond/model/browse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/model/browse.py b/trytond/model/browse.py index 0265ba5d0f..c608122141 100644 --- a/trytond/model/browse.py +++ b/trytond/model/browse.py @@ -279,7 +279,7 @@ class EvalEnvironment(dict): return self.__getitem__(item) except: pass - return super(EvalEnvironment, self).get(item, default=default) + return super(EvalEnvironment, self).get(item, default) def __nonzero__(self): return bool(self._record) From 0994a5f4827120314b16c17ae6b396b6fbefeb57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 10 Feb 2010 18:44:19 +0100 Subject: [PATCH 050/144] Fix typo in sqlite database functions --- trytond/backend/sqlite/database.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/trytond/backend/sqlite/database.py b/trytond/backend/sqlite/database.py index d7e8a6cc6d..60841f3dfd 100644 --- a/trytond/backend/sqlite/database.py +++ b/trytond/backend/sqlite/database.py @@ -54,7 +54,7 @@ def extract(lookup_type, date): elif lookup_type.lower() == 'millennium': return date.year / 1000 + (date.year % 1000 and 1 or 0) elif lookup_type.lower() == 'milliseconds': - return int(a.second * 1000) + return int(date.second * 1000) elif lookup_type.lower() == 'quarter': return date.month / 4 + 1 elif lookup_type.lower() == 'week': @@ -69,11 +69,11 @@ def date_trunc(_type, date): except: return None if _type == 'year': - return "%i-01-01 00:00:00" % dt.year + return "%i-01-01 00:00:00" % date.year elif _type == 'month': - return "%i-%02i-01 00:00:00" % (dt.year, dt.month) + return "%i-%02i-01 00:00:00" % (date.year, date.month) elif _type == 'day': - return "%i-%02i-%02i 00:00:00" % (dt.year, dt.month, dt.day) + return "%i-%02i-%02i 00:00:00" % (date.year, date.month, date.day) def split_part(text, delimiter, count): return (text.split(delimiter) + [''] * (count - 1))[count - 1] From 240a46b9220d973e6110ea3f97d9f43a423a6dbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 16 Feb 2010 10:16:05 +0100 Subject: [PATCH 051/144] Prepare release 1.4.4 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 7d9c643c01..fc7381cfad 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 1.4.4 - 2010-02-16 +* Some bug fixes (see mercurial logs for details) + Version 1.4.3 - 2009-12-09 * Some bug fixes (see mercurial logs for details) From b5c77700bb6713f9456df76f46f5e95fc19932f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 16 Feb 2010 10:16:13 +0100 Subject: [PATCH 052/144] Added tag 1.4.4 for changeset 889a6b639438 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index d708639f31..27b1bb47d6 100644 --- a/.hgtags +++ b/.hgtags @@ -4,3 +4,4 @@ e2d31d59de7745de70199b7c340d78b7c4775723 1.4.0 a2589d0064b2369c79cf2914e4f7caa8b907c6de 1.4.1 adb88e158ef4b72c67d196417ff7229cf6bd07df 1.4.2 8dfc51bb21c0d8b7842c28c4a1f880e23110351b 1.4.3 +889a6b639438b138f48f9c226469da0f2b74eb7e 1.4.4 From dd2556eb1403feadf9ffcefdf1feccc95d6a11fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 16 Feb 2010 10:20:09 +0100 Subject: [PATCH 053/144] Increase version number --- trytond/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/version.py b/trytond/version.py index 2c31f0f009..a0266ded03 100644 --- a/trytond/version.py +++ b/trytond/version.py @@ -1,7 +1,7 @@ #This file is part of Tryton. The COPYRIGHT file at the top level of #this repository contains the full copyright notices and license terms. PACKAGE = "trytond" -VERSION = "1.4.4" +VERSION = "1.4.5" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 72597ea48321b4a0e538e63f6edde83a923d0f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 3 Mar 2010 18:28:58 +0100 Subject: [PATCH 054/144] Add replace python function for old sqlite for issue1432 (transplanted from 0d5666953936b0396be2b4f86eb6cdcb60d99f6b) --- trytond/backend/sqlite/database.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/trytond/backend/sqlite/database.py b/trytond/backend/sqlite/database.py index 60841f3dfd..5a86b43aa2 100644 --- a/trytond/backend/sqlite/database.py +++ b/trytond/backend/sqlite/database.py @@ -78,6 +78,9 @@ def date_trunc(_type, date): def split_part(text, delimiter, count): return (text.split(delimiter) + [''] * (count - 1))[count - 1] +def replace(text, pattern, replacement): + return str(text).replace(pattern, replacement) + class Database(DatabaseInterface): @@ -109,6 +112,8 @@ class Database(DatabaseInterface): self._conn.create_function('extract', 2, extract) self._conn.create_function('date_trunc', 2, date_trunc) self._conn.create_function('split_part', 3, split_part) + if sqlite.sqlite_version_info < (3, 3, 14): + self._conn.create_function('replace', 3, replace) return self def cursor(self, autocommit=False): From 162b674580a5133994445157d2a589cff00a1fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 17 Mar 2010 18:47:24 +0100 Subject: [PATCH 055/144] Don't copy One2Many values if relation_field is not set for issue1448 If relation_field is not set then it is a function field and the copy method will not link duplicated One2Many records to the new record. --- trytond/model/modelstorage.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py index 6fe9916942..09c6cdd50b 100644 --- a/trytond/model/modelstorage.py +++ b/trytond/model/modelstorage.py @@ -297,10 +297,11 @@ class ModelStorage(Model): new_ids[data_id] = self.create(cursor, user, data, context=context) for field_name in data_o2m: relation_model = self.pool.get(fields[field_name]['relation']) - relation_field = fields[field_name]['relation_field'] - relation_model.copy(cursor, user, data_o2m[field_name], - default={relation_field: new_ids[data_id]}, - context=context) + if 'relation_field' in fields[field_name]: + relation_field = fields[field_name]['relation_field'] + relation_model.copy(cursor, user, data_o2m[field_name], + default={relation_field: new_ids[data_id]}, + context=context) fields_translate = {} for field_name, field in fields.iteritems(): From 483732710efd22c6c5df7b5620e932494af2a352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 23 Mar 2010 10:54:27 +0100 Subject: [PATCH 056/144] Catch exception from os.stat in attachment An OSError exception can occurs if the file is no more there or if the data_path is wrong. (transplanted from 7fb9117ecc6361236eccb4c5c951bc99b65845a9) --- trytond/ir/attachment.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/trytond/ir/attachment.py b/trytond/ir/attachment.py index 420dd283de..742225b16c 100644 --- a/trytond/ir/attachment.py +++ b/trytond/ir/attachment.py @@ -48,8 +48,11 @@ class Attachment(ModelSQL, ModelView): filename = os.path.join(CONFIG['data_path'], db_name, filename[0:2], filename[2:4], filename) if name == 'datas_size': - statinfo = os.stat(filename) - value = statinfo.st_size + try: + statinfo = os.stat(filename) + value = statinfo.st_size + except OSError: + pass else: try: file_p = file(filename, 'rb') From ee919755adbd6ba64be576e379b7b04b2888bcee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 31 Mar 2010 13:24:04 +0200 Subject: [PATCH 057/144] Prepare release 1.4.5 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index fc7381cfad..9196bc7c26 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 1.4.5 - 2010-03-31 +* Some bug fixes (see mercurial logs for details) + Version 1.4.4 - 2010-02-16 * Some bug fixes (see mercurial logs for details) From 7eca42ba6690a62499e29f4324640a626d6efca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 31 Mar 2010 13:24:11 +0200 Subject: [PATCH 058/144] Added tag 1.4.5 for changeset 30bb71d12c03 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 27b1bb47d6..2b8e043ab0 100644 --- a/.hgtags +++ b/.hgtags @@ -5,3 +5,4 @@ a2589d0064b2369c79cf2914e4f7caa8b907c6de 1.4.1 adb88e158ef4b72c67d196417ff7229cf6bd07df 1.4.2 8dfc51bb21c0d8b7842c28c4a1f880e23110351b 1.4.3 889a6b639438b138f48f9c226469da0f2b74eb7e 1.4.4 +30bb71d12c0347a3f9440843439b6efa5a3571a8 1.4.5 From d49094de45bcd7befd66fc74df2ac7b38043027f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 31 Mar 2010 13:27:23 +0200 Subject: [PATCH 059/144] Increase version number --- trytond/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/version.py b/trytond/version.py index a0266ded03..fa2801c93a 100644 --- a/trytond/version.py +++ b/trytond/version.py @@ -1,7 +1,7 @@ #This file is part of Tryton. The COPYRIGHT file at the top level of #this repository contains the full copyright notices and license terms. PACKAGE = "trytond" -VERSION = "1.4.5" +VERSION = "1.4.6" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From a865e80a3fd1da41c6e5610446d3e26ce2fbe382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 10 Apr 2010 13:56:47 +0200 Subject: [PATCH 060/144] Don't use offset in second query of search for issue1496 The order between the first query is not necessary the same then the second one so using an offset can generate missing or duplicated ids in the result. (transplanted from 41c9189a8df38edca2612fb328d21d6d8b4579e9) --- trytond/model/modelsql.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/trytond/model/modelsql.py b/trytond/model/modelsql.py index a74c028f35..a2272619f7 100644 --- a/trytond/model/modelsql.py +++ b/trytond/model/modelsql.py @@ -1253,15 +1253,15 @@ class ModelSQL(ModelStorage): if self._history and context.get('_datetime') \ and not query_string: select_fields2 += [select_fields[1]] - cursor.execute(cursor.limit_clause( + cursor.execute( 'SELECT * FROM (' + \ cursor.limit_clause( 'SELECT ' + ','.join(select_fields2) + ' FROM ' + \ ' '.join(tables) + (qu1 and ' WHERE ' + qu1 or '') + \ (order_by and ' ORDER BY ' + order_by or ''), limit, offset) + ') AS "' + self._table + '"', - None, cursor.IN_MAX), tables_args + qu2) - datas += cursor.dictfetchall() + tables_args + qu2) + datas = cursor.dictfetchall() if self._history and context.get('_datetime'): res = [] From 9f078b665a2eac5dc4ca4859e34e69cb2a069634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 17 Jun 2010 20:05:59 +0200 Subject: [PATCH 061/144] Always check on delete restrict for issue1588 (transplanted from aab1c133077c144b83bbe6871fac3b2bae90eb8c) --- trytond/model/modelsql.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/trytond/model/modelsql.py b/trytond/model/modelsql.py index a2272619f7..59d98cdcf1 100644 --- a/trytond/model/modelsql.py +++ b/trytond/model/modelsql.py @@ -1084,6 +1084,18 @@ class ModelSQL(ModelStorage): if model_ids: model.delete(cursor, user, model_ids, context=delete_ctx) + for model, field_name in foreign_keys_tocheck: + if model.search(cursor, 0, [ + (field_name, 'in', sub_ids), + ], order=[], context=context): + error_args = [] + error_args.append(self._get_error_args(cursor, user, 'id', + context=context)[1]) + error_args.extend(list(model._get_error_args(cursor, + user, field_name, context=context))) + self.raise_user_error(cursor, 'foreign_model_exist', + error_args=tuple(error_args), context=context) + super(ModelSQL, self).delete(cursor, user, sub_ids, context=context) try: @@ -1093,17 +1105,6 @@ class ModelSQL(ModelStorage): database = Database(cursor.database_name).connect() cursor2 = database.cursor() try: - for model, field_name in foreign_keys_tocheck: - if model.search(cursor2, 0, [ - (field_name, 'in', sub_ids), - ], order=[], context=context): - error_args = [] - error_args.append(self._get_error_args(cursor2, - user, 'id', context=context)[1]) - error_args.extend(list(model._get_error_args(cursor2, - user, field_name, context=context))) - self.raise_user_error(cursor2, 'foreign_model_exist', - error_args=tuple(error_args), context=context) for name, _, error in self._sql_constraints: if name in exception[0]: self.raise_user_error(cursor2, error, From 9c48f7c9a8bef7713e88cb522148789b30d055f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 28 Jun 2010 21:25:33 +0200 Subject: [PATCH 062/144] Fix _clean_defaults for one2many inherited (transplanted from 1c802de12b7ad6772d9bde56cd7b079efafdf3e9) --- trytond/model/modelstorage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py index 09c6cdd50b..ad9f6d1390 100644 --- a/trytond/model/modelstorage.py +++ b/trytond/model/modelstorage.py @@ -1057,7 +1057,7 @@ class ModelStorage(Model): else: vals[field] = defaults[field] elif fld_def._type in ('one2many',): - obj = self.pool.get(self._columns[field].model_name) + obj = self.pool.get(fld_def.model_name) vals[field] = [] for defaults2 in defaults[field]: vals2 = obj._clean_defaults(defaults2) From 4c641b6747dc433be705dc7e552c21758fa8e32a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 2 Jul 2010 18:41:26 +0200 Subject: [PATCH 063/144] Update manifest with files added from style for issue1507 (transplanted from 3888542922ca3ebc0702facbd73e9d983bea57de) --- trytond/report/report.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/trytond/report/report.py b/trytond/report/report.py index 8d82b5de42..57f9b0de58 100644 --- a/trytond/report/report.py +++ b/trytond/report/report.py @@ -21,6 +21,10 @@ import warnings warnings.simplefilter("ignore") import relatorio.reporting warnings.resetwarnings() +try: + from relatorio.templates.opendocument import Manifest, MANIFEST +except ImportError: + Manifest = None import tempfile from genshi.filters import Translator @@ -150,11 +154,15 @@ class Report(object): style_info = None style_xml = None + manifest = None for f in content_z.infolist(): if f.filename == 'styles.xml' and report.style_content: style_info = f style_xml = content_z.read(f.filename) continue + elif Manifest and f.filename == MANIFEST: + manifest = Manifest(content_z.read(f.filename)) + continue outzip.writestr(f, content_z.read(f.filename)) if report.style_content: @@ -172,6 +180,7 @@ class Report(object): if file.startswith('Pictures'): picture = style2_z.read(file) pictures.append((file, picture)) + manifest.add_file_entry(file) style2_z.close() style2_io.close() dom_style2 = xml.dom.minidom.parseString(style2_xml) @@ -192,6 +201,9 @@ class Report(object): for file, picture in pictures: outzip.writestr(file, picture) + if manifest: + outzip.writestr(MANIFEST, str(manifest)) + content_z.close() content_io.close() outzip.close() From 8d777dd4847799d7ad0163e7a28737ba5c150a88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 8 Jul 2010 20:01:11 +0200 Subject: [PATCH 064/144] Fix extract function in SQLite to work with date (transplanted from faf73da610031ab5d7b49e89c4aca221846b10d9) --- trytond/backend/sqlite/database.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/trytond/backend/sqlite/database.py b/trytond/backend/sqlite/database.py index 5a86b43aa2..80a44f7370 100644 --- a/trytond/backend/sqlite/database.py +++ b/trytond/backend/sqlite/database.py @@ -29,14 +29,18 @@ def extract(lookup_type, date): if date is None: return None try: - datepart, timepart = date.split(" ") - year, month, day = map(int, datepart.split("-")) - timepart_full = timepart.split(".") - hours, minutes, seconds = map(int, timepart_full[0].split(":")) - if len(timepart_full) == 2: - microseconds = int(timepart_full[1]) - seconds += microseconds / 1000000.0 - date = mx.DateTime.DateTime(year, month, day, hours, minutes, seconds) + if len(date) == 10: + year, month, day = map(int, date.split('-')) + date = datetime.date(year, month, day) + else: + datepart, timepart = date.split(" ") + year, month, day = map(int, datepart.split("-")) + timepart_full = timepart.split(".") + hours, minutes, seconds = map(int, timepart_full[0].split(":")) + if len(timepart_full) == 2: + microseconds = int(timepart_full[1]) + date = datetime.datetime(year, month, day, hours, minutes, seconds, + microseconds) except: return None if lookup_type.lower() == 'century': From 066bf877c018ced2e468248fd5efe2450a734fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 11 Jul 2010 15:29:29 +0200 Subject: [PATCH 065/144] Fix typo in test query for PostgreSQL and SQLite thanks to Ralf Peschke (transplanted from d1bddcf64ea7cd63d7a1611a5866f1b491734076) --- trytond/backend/postgresql/database.py | 4 ++-- trytond/backend/sqlite/database.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/trytond/backend/postgresql/database.py b/trytond/backend/postgresql/database.py index 38da3f5375..6ae49c4ee3 100644 --- a/trytond/backend/postgresql/database.py +++ b/trytond/backend/postgresql/database.py @@ -371,8 +371,8 @@ class Cursor(CursorInterface): "'wkf_workitem', " "'wkf_witm_trans', " "'ir_module_module', " - "'ir_module_module_dependency, '" - "'ir_translation, '" + "'ir_module_module_dependency', " + "'ir_translation', " "'ir_lang'" ")") return len(self.cursor.fetchall()) != 0 diff --git a/trytond/backend/sqlite/database.py b/trytond/backend/sqlite/database.py index 80a44f7370..b93c925f03 100644 --- a/trytond/backend/sqlite/database.py +++ b/trytond/backend/sqlite/database.py @@ -333,8 +333,8 @@ class Cursor(CursorInterface): "'wkf_workitem', " "'wkf_witm_trans', " "'ir_module_module', " - "'ir_module_module_dependency, '" - "'ir_translation, '" + "'ir_module_module_dependency', " + "'ir_translation', " "'ir_lang'" ")") except: From eaa75ff77eddf6f72b002a922da4bec77e1ed00f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 15 Jul 2010 18:58:26 +0200 Subject: [PATCH 066/144] Fix wrong value passed to super call (transplanted from 1636812276c3fc4e38ad1831aff988feeb704958) --- trytond/model/modelsingleton.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/model/modelsingleton.py b/trytond/model/modelsingleton.py index 4a9e79d394..b451be0d90 100644 --- a/trytond/model/modelsingleton.py +++ b/trytond/model/modelsingleton.py @@ -77,7 +77,8 @@ class ModelSingleton(ModelStorage): def search(self, cursor, user, domain, offset=0, limit=None, order=None, context=None, count=False): res = super(ModelSingleton, self).search(cursor, user, domain, - offset=0, limit=None, order=None, context=None, count=False) + offset=offset, limit=limit, order=order, context=context, + count=count) if not res: if count: return 1 From 0944241fa828b419058f66b6cf8894d0a85f983e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 15 Jul 2010 19:00:21 +0200 Subject: [PATCH 067/144] Use explicit AS column name in queries that use dictfetch* SQLite return wrong column name when using query as table (transplanted from 5c38493067b4de52ece25abaf4353bc48f312299) --- trytond/model/modelsql.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/trytond/model/modelsql.py b/trytond/model/modelsql.py index 59d98cdcf1..7018620c2a 100644 --- a/trytond/model/modelsql.py +++ b/trytond/model/modelsql.py @@ -476,19 +476,21 @@ class ModelSQL(ModelStorage): history_limit = cursor.limit_clause('', 1) history_args = [context['_datetime']] if len(fields_pre) : - fields_pre2 = ['"' + x + '"' for x in fields_pre \ - if x != '_timestamp'] + fields_pre2 = ['"%s"."%s" AS "%s"' % (self._table, x, x) + for x in fields_pre if x != '_timestamp'] if '_timestamp' in fields_pre: if not self.table_query(context): - fields_pre2 += ['(COALESCE(write_date, create_date)) ' \ - 'AS _timestamp'] + fields_pre2 += [ + '(COALESCE("%s".write_date, "%s".create_date)) ' + 'AS _timestamp' % (self._table, self._table)] for i in range(0, len(ids), in_max): sub_ids = ids[i:i + in_max] red_sql, red_ids = reduce_ids('id', sub_ids) if domain1: cursor.execute('SELECT ' + \ - ','.join(fields_pre2 + ['id']) + \ + ','.join(fields_pre2 + + ['"%s".id AS id' % self._table]) + \ ' FROM ' + table_query + '\"' + self._table +'\" ' \ 'WHERE ' + red_sql + \ history_clause + \ @@ -497,7 +499,8 @@ class ModelSQL(ModelStorage): table_args + red_ids + history_args + domain2) else: cursor.execute('SELECT ' + \ - ','.join(fields_pre2 + ['id']) + \ + ','.join(fields_pre2 + + ['"%s".id AS id' % self._table]) + \ ' FROM ' + table_query + '\"' + self._table + '\" ' \ 'WHERE ' + red_sql + \ history_clause + history_order + history_limit, From 7aba1da3cd0599ef53ca6b5946c56950e4b1802c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 18 Jul 2010 22:33:49 +0200 Subject: [PATCH 068/144] Remove properties tag from documentation This tag was never used (transplanted from b6192e7460fe536991237b1de96fd01b13ea4335) --- doc/views.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/doc/views.rst b/doc/views.rst index bf2289fc09..3a05fe5d77 100644 --- a/doc/views.rst +++ b/doc/views.rst @@ -217,11 +217,6 @@ child1,child2 Contains the two childs of a hpaned or vpaned. -properties -^^^^^^^^^^ - -Display a table of 4 columns with all the properties of the object. - .. _example_form_view: Example @@ -257,9 +252,6 @@ Example