From 0a573446e152563f9ef8053a9a32630966fc3302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 18 Nov 2008 17:24:10 +0100 Subject: [PATCH 001/164] Increase version number --- doc/conf.py | 2 +- trytond/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index e7b0db2478..9526935030 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -46,7 +46,7 @@ copyright = '2008, B2CK' # The short X.Y version. version = '1.0' # The full version, including alpha/beta/rc tags. -release = '1.0.0' +release = '1.0.1' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: diff --git a/trytond/version.py b/trytond/version.py index 8b69a96a1b..d7526f3d53 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.0.0" +VERSION = "1.0.1" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From ebf76e919a5e9e4307536cef66a83d2af773d230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 18 Nov 2008 17:40:30 +0100 Subject: [PATCH 002/164] Allow egg installation working --- setup.py | 6 +-- trytond/config.py | 4 ++ trytond/ir/module/module.py | 61 ++++++++++++++---------------- trytond/modules/__init__.py | 75 +++++++++++++++++++++++++------------ trytond/server.py | 4 +- trytond/tools/misc.py | 13 ++++++- 6 files changed, 101 insertions(+), 62 deletions(-) diff --git a/setup.py b/setup.py index 0b804f1fc4..5719afc044 100644 --- a/setup.py +++ b/setup.py @@ -13,6 +13,8 @@ setup(name=PACKAGE, author='B2CK', author_email='info@b2ck.com', url=WEBSITE, + download_url="http://downloads.tryton.org/" + \ + VERSION.rsplit('.', 1)[0] + '/', packages=find_packages(exclude=['*.modules.*', 'modules.*', 'modules']), package_data={ 'trytond': ['init.sql'], @@ -23,9 +25,6 @@ setup(name=PACKAGE, 'trytond.webdav': ['*.xml', '*.csv'], 'trytond.workflow': ['*.xml', '*.csv'], }, - data_files=[ - ('/etc', ['etc/trytond.conf']), - ], scripts=['bin/trytond'], classifiers=[ 'Development Status :: 5 - Production/Stable', @@ -54,4 +53,5 @@ setup(name=PACKAGE, 'graphviz': ['pydot'], 'timezone': ['pytz'], }, + zip_safe = False, ) diff --git a/trytond/config.py b/trytond/config.py index c0300c629d..febacf7cd8 100644 --- a/trytond/config.py +++ b/trytond/config.py @@ -73,6 +73,8 @@ class ConfigManager(object): configdir = os.path.abspath(os.path.normpath(os.path.join( os.path.dirname(__file__), '..'))) self.configfile = os.path.join(configdir, 'etc', 'trytond.conf') + if not os.path.isfile(self.configfile): + self.configfile = None self.load() # Verify that we want to log or not, if not the output will go to stdout @@ -113,6 +115,8 @@ class ConfigManager(object): def load(self): parser = ConfigParser.ConfigParser() + if not self.configfile: + return try: parser.read([self.configfile]) for (name, value) in parser.items('options'): diff --git a/trytond/ir/module/module.py b/trytond/ir/module/module.py index 4990dca01e..686743a251 100644 --- a/trytond/ir/module/module.py +++ b/trytond/ir/module/module.py @@ -175,11 +175,9 @@ class Module(OSV): "Return the content of the __tryton__.py" try: if name in ['ir', 'workflow', 'res', 'webdav']: - file_p = tools.file_open(os.path.join( - os.path.dirname(MODULES_PATH), name, '__tryton__.py')) + file_p = tools.file_open(os.path.join(name, '__tryton__.py')) else: - file_p = tools.file_open(os.path.join(MODULES_PATH, name, - '__tryton__.py')) + file_p = tools.file_open(os.path.join(name, '__tryton__.py')) data = file_p.read() info = eval(data) file_p.close() @@ -336,9 +334,7 @@ class Module(OSV): lang_codes = [x.code for x in lang_obj.browse(cursor, user, lang_ids, context=context)] - module_names = ['ir', 'workflow', 'res', 'webdav'] - if os.path.isdir(MODULES_PATH): - module_names += os.listdir(MODULES_PATH) + module_names = get_module_list() module_ids = self.search(cursor, user, [], context=context) modules = self.browse(cursor, user, module_ids, context=context) @@ -396,37 +392,36 @@ class Module(OSV): self._update_dependencies(cursor, user, mod, tryton.get('depends', []), context=context) continue + if name in ['ir', 'workflow', 'res', 'webdav']: mod_path = os.path.join( os.path.dirname(MODULES_PATH), name) else: mod_path = os.path.join(MODULES_PATH, name) - if os.path.isdir(mod_path) \ - or os.path.islink(mod_path) \ - or zipfile.is_zipfile(mod_path): - tryton = Module.get_module_info(mod_name) - if not tryton: - continue - new_id = self.create(cursor, user, { - 'name': mod_name, - 'state': 'uninstalled', - 'description': tryton.get('description', ''), - 'shortdesc': tryton.get('name', ''), - 'author': tryton.get('author', 'Unknown'), - 'website': tryton.get('website', ''), - }, context=context) - for code in lang_codes: - ctx = context.copy() - ctx['language'] = code - self.write(cursor, user, new_id, { - 'description': tryton.get('description_' + code, ''), - 'shortdesc': tryton.get('name_' + code, ''), - }, context=ctx) - res += 1 - name2module[mod_name] = self.browse(cursor, user, new_id, - context=context) - self._update_dependencies(cursor, user, name2module[mod_name], - tryton.get('depends', []), context=context) + + tryton = Module.get_module_info(mod_name) + if not tryton: + continue + new_id = self.create(cursor, user, { + 'name': mod_name, + 'state': 'uninstalled', + 'description': tryton.get('description', ''), + 'shortdesc': tryton.get('name', ''), + 'author': tryton.get('author', 'Unknown'), + 'website': tryton.get('website', ''), + }, context=context) + for code in lang_codes: + ctx = context.copy() + ctx['language'] = code + self.write(cursor, user, new_id, { + 'description': tryton.get('description_' + code, ''), + 'shortdesc': tryton.get('name_' + code, ''), + }, context=ctx) + res += 1 + name2module[mod_name] = self.browse(cursor, user, new_id, + context=context) + self._update_dependencies(cursor, user, name2module[mod_name], + tryton.get('depends', []), context=context) return res def _update_dependencies(self, cursor, user, module, depends=None, diff --git a/trytond/modules/__init__.py b/trytond/modules/__init__.py index 9c8614940d..040d81e943 100644 --- a/trytond/modules/__init__.py +++ b/trytond/modules/__init__.py @@ -16,6 +16,15 @@ sys.path.insert(1, MODULES_PATH) MODULES = [] +EGG_MODULES = {} +try: + import pkg_resources + for ep in pkg_resources.iter_entry_points('trytond.modules'): + mod_name = ep.module_name.split('.')[-1] + EGG_MODULES[mod_name] = ep +except ImportError: + pass + class Graph(dict): @@ -126,9 +135,14 @@ def create_graph(module_list, force=None): root_path = os.path.dirname(os.path.dirname(__file__)) tryton_file = OPJ(root_path, module, '__tryton__.py') mod_path = OPJ(root_path, module) + elif module in EGG_MODULES: + ep = EGG_MODULES[module] + tryton_file = OPJ(ep.dist.location, 'trytond', 'modules', module, + '__tryton__.py') + mod_path = OPJ(ep.dist.location, 'trytond', 'modules', module) if os.path.isfile(tryton_file) or zipfile.is_zipfile(mod_path+'.zip'): try: - info = eval(tools.file_open(tryton_file).read()) + info = eval(tools.file_open(tryton_file, subdir='').read()) except: logging.getLogger('init').error( 'module:%s:eval file %s' % (module, tryton_file)) @@ -272,6 +286,9 @@ def get_module_list(): module_list.append(file) elif file[-4:] == '.zip': module_list.append(file) + for ep in pkg_resources.iter_entry_points('trytond.modules'): + mod_name = ep.module_name.split('.')[-1] + module_list.append(mod_name) module_list.append('ir') module_list.append('workflow') module_list.append('res') @@ -283,6 +300,7 @@ def register_classes(): import trytond.workflow import trytond.res import trytond.webdav + for package in create_graph(get_module_list())[0]: module = package.name logging.getLogger('init').info( @@ -292,29 +310,8 @@ def register_classes(): MODULES.append(module) continue - if not os.path.isfile(OPJ(MODULES_PATH, module+'.zip')): - try: - imp.load_module(module, *imp.find_module(module, - [MODULES_PATH])) - except ImportError: - tb_s = '' - for line in traceback.format_exception(*sys.exc_info()): - try: - line = line.encode('utf-8', 'ignore') - except: - continue - tb_s += line - for path in sys.path: - tb_s = tb_s.replace(path, '') - if CONFIG['debug_mode']: - import pdb - traceb = sys.exc_info()[2] - pdb.post_mortem(traceb) - logging.getLogger('init').error( - 'Couldn\'t import module %s:\n%s' % (module, tb_s)) - break - else: - mod_path = OPJ(MODULES_PATH, module+'.zip') + if os.path.isfile(OPJ(MODULES_PATH, module + '.zip')): + mod_path = OPJ(MODULES_PATH, module + '.zip') try: zimp = zipimport.zipimporter(mod_path) zimp.load_module(module) @@ -335,6 +332,36 @@ def register_classes(): logging.getLogger('init').error( 'Couldn\'t import module %s:\n%s' % (module, tb_s)) break + elif os.path.isdir(OPJ(MODULES_PATH, module)): + try: + imp.load_module(module, *imp.find_module(module, + [MODULES_PATH])) + except ImportError: + tb_s = '' + for line in traceback.format_exception(*sys.exc_info()): + try: + line = line.encode('utf-8', 'ignore') + except: + continue + tb_s += line + for path in sys.path: + tb_s = tb_s.replace(path, '') + if CONFIG['debug_mode']: + import pdb + traceb = sys.exc_info()[2] + pdb.post_mortem(traceb) + logging.getLogger('init').error( + 'Couldn\'t import module %s:\n%s' % (module, tb_s)) + break + elif module in EGG_MODULES: + ep = EGG_MODULES[module] + mod_path = os.path.join(ep.dist.location, + *ep.module_name.split('.')[:-1]) + imp.load_module(module, *imp.find_module(module, [mod_path])) + else: + logging.getLogger('init').error( + 'Couldn\'t find module %s' % module) + break MODULES.append(module) def load_modules(database, pool, pool_wizard, pool_report, update_module=False, diff --git a/trytond/server.py b/trytond/server.py index 74a43be95c..c614afeeb5 100644 --- a/trytond/server.py +++ b/trytond/server.py @@ -62,7 +62,9 @@ class TrytonServer(object): self.logger = logging.getLogger("init") - self.logger.info('using %s as configuration file' % CONFIG.configfile) + if CONFIG.configfile: + self.logger.info('using %s as configuration file' % \ + CONFIG.configfile) self.logger.info('initialising distributed objects services') self.dispatcher = netsvc.Dispatcher() diff --git a/trytond/tools/misc.py b/trytond/tools/misc.py index e7fe6941ec..56da2906f2 100644 --- a/trytond/tools/misc.py +++ b/trytond/tools/misc.py @@ -64,7 +64,18 @@ def exec_command_pipe(name, *args): def file_open(name, mode="r", subdir='modules'): """Open a file from the root dir, using a subdir folder.""" + from trytond.modules import EGG_MODULES root_path = os.path.dirname(os.path.dirname(__file__)) + + name3 = False + if subdir == 'modules': + module_name = name.split(os.sep)[0] + if module_name in EGG_MODULES: + ep = EGG_MODULES[module_name] + mod_path = os.path.join(ep.dist.location, + *ep.module_name.split('.')[:-1]) + name3 = os.path.join(mod_path, name) + if subdir: if subdir == 'modules'\ and (name.startswith('ir' + os.sep) \ @@ -97,7 +108,7 @@ def file_open(name, mode="r", subdir='modules'): os.sep, '/'))) except: name2 = os.path.normpath(os.path.join(head + '.zip', zipname)) - for i in (name2, name): + for i in (name2, name, name3): if i and os.path.isfile(i): return file(i, mode) From 5edb0d48ce6ac1c4a2acb0f7d9f41fd84abfece2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 18 Nov 2008 17:45:55 +0100 Subject: [PATCH 003/164] Add missing changelog --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index eacaaefa7d..44de11f380 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,2 +1,4 @@ +* Allow egg installation + Version 1.0.0 - 2008-11-17 * Initial release From 75df5148e5840f6b83a05ba7fe61a8bfc38b30b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 20 Nov 2008 18:46:25 +0100 Subject: [PATCH 004/164] Handle _inherit_field in EvalEnvironment --- trytond/osv/orm.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 717f5098fa..9b3625602d 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -250,9 +250,14 @@ class EvalEnvironment(dict): def __getitem__(self, item): if item.startswith('_parent_'): field = item[8:] - obj = self.obj.pool.get(self.obj._columns[field]._obj) + if field in self.obj._columns: + _obj = self.obj._columns[field]._obj + else: + _obj = self.obj._inherit_fields[field][2]._obj + obj = self.obj.pool.get(_obj) return EvalEnvironment(self.record[field], obj) - if item in self.obj._columns: + if item in self.obj._columns \ + or item in self.obj._inherit_fields: return self.record.get_eval(item) return super(EvalEnvironment, self).__getitem__(item) From 000e8719128227f524cb03c6f858f74a762eefb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 20 Nov 2008 18:48:33 +0100 Subject: [PATCH 005/164] Add join for inherit_field in where_calc Use the right object when calling search function Add join table when searching on many2one of inherit_fields --- trytond/osv/orm.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 9b3625602d..d88465ef27 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2375,8 +2375,9 @@ class ORM(object): % args[i][1]) table = self - if args[i][0] in self._inherit_fields: - itable = self.pool.get(self._inherit_fields[args[i][0]][0]) + fargs = args[i][0].split('.', 1) + if fargs[0] in self._inherit_fields: + itable = self.pool.get(self._inherit_fields[fargs[0]][0]) table_query = '' table_arg = [] if itable.table_query(context): @@ -2387,20 +2388,19 @@ class ORM(object): tables_args += table_arg joins.append(('id', 'join', '%s.%s' % \ (self._table, self._inherits[itable._name]), itable)) - fargs = args[i][0].split('.', 1) field = table._columns.get(fargs[0], False) if not field: if not fargs[0] in self._inherit_fields: raise Exception('ValidateError', 'Field "%s" doesn\'t ' \ 'exist on "%s"' % (fargs[0], self._name)) - table = self.pool.get(self._inherit_fields[args[i][0]][0]) + table = self.pool.get(self._inherit_fields[fargs[0]][0]) field = table._columns.get(fargs[0], False) if len(fargs) > 1: if field._type == 'many2one': args[i] = (fargs[0], 'inselect', self.pool.get(field._obj).search(cursor, user, [(fargs[1], args[i][1], args[i][2])], - context=context, query_string=True)) + context=context, query_string=True), table) i += 1 continue else: @@ -2415,7 +2415,7 @@ class ORM(object): else: j += 1 if field._fnct_search: - args.extend(field.search(cursor, user, self, + args.extend(field.search(cursor, user, table, arg[0][0], arg, context=context)) elif field._type == 'one2many': field_obj = self.pool.get(field._obj) From b61214636588736a22b13724e0909c6bbb010067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 23 Nov 2008 01:53:58 +0100 Subject: [PATCH 006/164] Compare the description with the standard if there is no translation --- trytond/ir/module/module.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/trytond/ir/module/module.py b/trytond/ir/module/module.py index 686743a251..138b58c3f2 100644 --- a/trytond/ir/module/module.py +++ b/trytond/ir/module/module.py @@ -377,10 +377,12 @@ class Module(OSV): mod2 = name2module[mod_name][code] if mod2.description != \ tryton.get('description_' + code, - '').decode('utf-8', 'ignore') \ + tryton.get('description', '') + ).decode('utf-8', 'ignore') \ or mod2.shortdesc != \ tryton.get('name_' + code, - '').decode('utf-8', 'ignore'): + tryton.get('name', '') + ).decode('utf-8', 'ignore'): ctx = context.copy() ctx['language'] = code self.write(cursor, user, mod.id, { From 39f89b83a23fa7cb1d1bf5b5356b0ab6e517466f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 23 Nov 2008 01:55:03 +0100 Subject: [PATCH 007/164] Force fuzzy to False when setting translation with _set_ids --- trytond/ir/translation.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index 77253cb437..c2fe64f1c3 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -177,11 +177,13 @@ class Translation(OSV, Cacheable): 'type': ttype, 'src': field[field_name], 'value': value, + 'fuzzy': False, }) else: self.write(cursor, user, ids, { 'src': field[field_name], 'value': value, + 'fuzzy': False, }) return len(ids) model_obj = self.pool.get(model_name) @@ -200,11 +202,13 @@ class Translation(OSV, Cacheable): 'res_id': record.id, 'value': value, 'src': record[field_name], + 'fuzzy': False, }) else: self.write(cursor, user, ids2, { 'value': value, 'src': record[field_name], + 'fuzzy': False, }) return len(ids) From 9a159c7c8f6293c485909819322221a8aed4df17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 22 Nov 2008 14:29:46 +0100 Subject: [PATCH 008/164] Remove old module category and create record for only base modules --- trytond/init.sql | 13 ------- trytond/sql_db.py | 91 +++++++++++++---------------------------------- 2 files changed, 24 insertions(+), 80 deletions(-) diff --git a/trytond/init.sql b/trytond/init.sql index 41d942b071..471abcdd22 100644 --- a/trytond/init.sql +++ b/trytond/init.sql @@ -181,18 +181,6 @@ create table wkf_witm_trans -- Modules --------------------------------- -CREATE TABLE ir_module_category ( - id serial NOT NULL, - create_uid integer references res_user on delete set null, - create_date timestamp without time zone, - write_date timestamp without time zone, - write_uid integer references res_user on delete set null, - parent integer REFERENCES ir_module_category ON DELETE SET NULL, - name varchar NOT NULL, - primary key(id) -); - - CREATE TABLE ir_module_module ( id serial NOT NULL, create_uid integer references res_user on delete set null, @@ -205,7 +193,6 @@ CREATE TABLE ir_module_module ( url varchar, state varchar, shortdesc varchar, - category integer REFERENCES ir_module_category ON DELETE SET NULL, description text, primary key(id) ); diff --git a/trytond/sql_db.py b/trytond/sql_db.py index 5c67814a6b..07dba9f413 100644 --- a/trytond/sql_db.py +++ b/trytond/sql_db.py @@ -183,73 +183,30 @@ def init_db(cursor): if (len(line)>0) and (not line.isspace()): cursor.execute(line) - opj = os.path.join - modules_path = os.path.join(os.path.dirname(__file__), 'modules') - modules = [] - if os.path.exists(modules_path) and os.path.isdir(modules_path): - modules = os.listdir(modules_path) - - for i in (modules + ['ir', 'workflow', 'res', 'webdav']): - tryton_file = opj(modules_path, i, '__tryton__.py') - mod_path = opj(modules_path, i) - if i in ('ir', 'workflow', 'res', 'webdav'): - root_path = os.path.dirname(__file__) - tryton_file = opj(root_path, i, '__tryton__.py') - mod_path = opj(root_path, i) - info = {} - if os.path.isfile(tryton_file) \ - and not os.path.isfile(opj(modules_path, i + '.zip')): - info = eval(file(tryton_file).read()) - elif zipfile.is_zipfile(mod_path): - zfile = zipfile.ZipFile(mod_path) - i = os.path.splitext(i)[0] - info = eval(zfile.read(opj(i, '__tryton__.py'))) - if info: - categs = info.get('category', 'Uncategorized').split('/') - p_id = None - while categs: - if p_id is not None: - cursor.execute('SELECT id ' \ - 'FROM ir_module_category ' \ - 'WHERE name = %s AND parent = %s', - (categs[0], p_id)) - else: - cursor.execute('SELECT id ' \ - 'FROM ir_module_category ' \ - 'WHERE name = %s AND parent is NULL', - (categs[0],)) - c_id = cursor.fetchone() - if not c_id: - cursor.execute( - 'SELECT NEXTVAL(\'ir_module_category_id_seq\')') - c_id = cursor.fetchone()[0] - cursor.execute('INSERT INTO ir_module_category ' \ - '(id, name, parent) ' \ - 'VALUES (%s, %s, %s)', (c_id, categs[0], p_id)) - else: - c_id = c_id[0] - p_id = c_id - categs = categs[1:] - - active = info.get('active', False) - if active: - state = 'to install' - else: - state = 'uninstalled' - cursor.execute('SELECT NEXTVAL(\'ir_module_module_id_seq\')') - module_id = cursor.fetchone()[0] - cursor.execute('INSERT INTO ir_module_module ' \ - '(id, author, website, name, shortdesc, ' \ - 'description, category, state) ' \ - 'VALUES (%s, %s, %s, %s, %s, %s, %s, %s)', - (module_id, info.get('author', ''), - info.get('website', ''), i, info.get('name', False), - info.get('description', ''), p_id, state)) - dependencies = info.get('depends', []) - for dependency in dependencies: - cursor.execute('INSERT INTO ir_module_module_dependency ' \ - '(module, name) VALUES (%s, %s)', - (module_id, dependency)) + for i in ('ir', 'workflow', 'res', 'webdav'): + root_path = os.path.dirname(__file__) + tryton_file = os.path.join(root_path, i, '__tryton__.py') + mod_path = os.path.join(root_path, i) + info = eval(file(tryton_file).read()) + active = info.get('active', False) + if active: + state = 'to install' + else: + state = 'uninstalled' + cursor.execute('SELECT NEXTVAL(\'ir_module_module_id_seq\')') + module_id = cursor.fetchone()[0] + cursor.execute('INSERT INTO ir_module_module ' \ + '(id, author, website, name, shortdesc, ' \ + 'description, state) ' \ + 'VALUES (%s, %s, %s, %s, %s, %s, %s)', + (module_id, info.get('author', ''), + info.get('website', ''), i, info.get('name', False), + info.get('description', ''), state)) + dependencies = info.get('depends', []) + for dependency in dependencies: + cursor.execute('INSERT INTO ir_module_module_dependency ' \ + '(module, name) VALUES (%s, %s)', + (module_id, dependency)) psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) From aad2cd9efeb77291665632f67d4ca3efc31daf15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 22 Nov 2008 16:08:24 +0100 Subject: [PATCH 009/164] Remove test on ir_module_category --- trytond/sql_db.py | 1 - 1 file changed, 1 deletion(-) diff --git a/trytond/sql_db.py b/trytond/sql_db.py index 07dba9f413..8e557f1584 100644 --- a/trytond/sql_db.py +++ b/trytond/sql_db.py @@ -141,7 +141,6 @@ class FakeCursor(object): "'wkf_instance', " "'wkf_workitem', " "'wkf_witm_trans', " - "'ir_module_category', " "'ir_module_module', " "'ir_module_module_dependency, '" "'ir_translation, '" From 3656e82dbc19237cc3a96fcd627b4203d257a741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 24 Nov 2008 17:12:51 +0100 Subject: [PATCH 010/164] Fix for host with IPv6 enable but without default IPv6 route --- CHANGELOG | 1 + trytond/pysocket.py | 17 +++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 44de11f380..1f1742018e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Fix for host with IPv6 enable but without default IPv6 route * Allow egg installation Version 1.0.0 - 2008-11-17 diff --git a/trytond/pysocket.py b/trytond/pysocket.py index c418e5f728..e2358f96ec 100644 --- a/trytond/pysocket.py +++ b/trytond/pysocket.py @@ -10,6 +10,7 @@ except ImportError: DNS_CACHE = {} MAX_SIZE = 999999999 MAX_LENGHT = len(str(MAX_SIZE)) +TIMEOUT = 120 _ALLOWED_MODULES = {'datetime': ['datetime', 'date'], 'decimal': ['Decimal']} @@ -44,12 +45,14 @@ class PySocket: socket.getaddrinfo(host, int(port), socket.AF_INET6) self.sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + self.sock.settimeout(TIMEOUT) + self.sock.connect((host, int(port))) except: - pass + self.sock = None if self.sock is None: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.sock.settimeout(120) - self.sock.connect((host, int(port))) + self.sock.settimeout(TIMEOUT) + self.sock.connect((host, int(port))) DNS_CACHE[hostname], port = self.sock.getpeername()[:2] try: sock = None @@ -57,12 +60,14 @@ class PySocket: try: socket.getaddrinfo(host, int(port), socket.AF_INET6) sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + sock.settimeout(TIMEOUT) + sock.connect((host, int(port))) except: - pass + sock = None if sock is None: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.settimeout(120) - sock.connect((host, int(port))) + sock.settimeout(TIMEOUT) + sock.connect((host, int(port))) if hasattr(socket, 'ssl'): ssl_sock = socket.ssl(sock) self.ssl = True From a2ebe1e0302a08931b6f0836e59c5b4df417aad9 Mon Sep 17 00:00:00 2001 From: Bertrand Chenal Date: Mon, 24 Nov 2008 21:55:11 +0100 Subject: [PATCH 011/164] Fix: escape fields name for m2m columns --- trytond/osv/fields.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trytond/osv/fields.py b/trytond/osv/fields.py index 5e72c78376..4af51e332b 100644 --- a/trytond/osv/fields.py +++ b/trytond/osv/fields.py @@ -542,8 +542,8 @@ class Many2Many(Column): continue cursor.execute('SELECT "' + self.target + '" ' \ 'FROM "' + self._rel + '" ' \ - 'WHERE ' + self.origin + ' = %s ' \ - 'AND ' + self.target + ' IN (' + \ + 'WHERE "' + self.origin + '" = %s ' \ + 'AND "' + self.target + '" IN (' + \ ','.join(['%s' for x in ids]) + ')', [obj_id] + ids) existing_ids = [] From 735c8255a6b45ebab2b673efe11ba7a3e50c9032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 25 Nov 2008 12:36:51 +0100 Subject: [PATCH 012/164] Handle default value in context for ir.sequence for issue609 --- trytond/ir/sequence.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/trytond/ir/sequence.py b/trytond/ir/sequence.py index 7a3cb2717a..0f142c83bd 100644 --- a/trytond/ir/sequence.py +++ b/trytond/ir/sequence.py @@ -20,7 +20,10 @@ class Sequence(OSV): _name = 'ir.sequence' _description = __doc__ name = fields.Char('Sequence Name', required=True, translate=True) - code = fields.Selection('code_get', 'Sequence Code', required=True) + code = fields.Selection('code_get', 'Sequence Code', required=True, + states={ + 'readonly': "context.get('code')", + }) active = fields.Boolean('Active') prefix = fields.Char('Prefix') suffix = fields.Char('Suffix') @@ -50,6 +53,11 @@ class Sequence(OSV): def default_padding(self, cursor, user, context=None): return 0 + def default_code(self, cursor, user, context=None): + if context is None: + context = {} + return context.get('code', False) + def code_get(self, cursor, user, context=None): sequence_type_obj = self.pool.get('ir.sequence.type') sequence_type_ids = sequence_type_obj.search(cursor, user, [], From e4a3c3d159188f7835ec4275f4f219bfa938cdc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 25 Nov 2008 00:11:56 +0100 Subject: [PATCH 013/164] Use explicit join in search SQL query --- CHANGELOG | 1 + trytond/osv/orm.py | 68 +++++++++++++++++++++------------------------- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1f1742018e..97cf3119e0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Use explicit join in search SQL query * Fix for host with IPv6 enable but without default IPv6 route * Allow egg installation diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index d88465ef27..5097561394 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2383,11 +2383,13 @@ class ORM(object): if itable.table_query(context): table_query, table_args = self.table_query(context) table_query = '(' + table_query + ') AS ' - if (table_query + '"' + itable._table + '"' not in tables): - tables.append(table_query + '"' + itable._table + '"') + table_join = 'LEFT JOIN ' + table_query + \ + '"' + itable._table + '" ON ' \ + '%s.id = %s.%s' % (itable._table, self._table, + self._inherits[itable._name]) + if table_join not in tables: + tables.append(table_join) tables_args += table_arg - joins.append(('id', 'join', '%s.%s' % \ - (self._table, self._inherits[itable._name]), itable)) field = table._columns.get(fargs[0], False) if not field: if not fargs[0] in self._inherit_fields: @@ -2707,13 +2709,9 @@ class ORM(object): (table._table, arg[0])) else: if arg[0] == 'id': - if arg[1] == 'join': - qu1.append('(%s.%s = %s)' % \ - (table._table, arg[0], arg[2])) - else: - qu1.append('(%s.%s %s %%s)' % \ - (table._table, arg[0], arg[1])) - qu2.append(arg[2]) + qu1.append('(%s.%s %s %%s)' % \ + (table._table, arg[0], arg[1])) + qu2.append(arg[2]) else: add_null = False if arg[1] in ('like', 'ilike', 'not like', 'not ilike'): @@ -2798,12 +2796,11 @@ class ORM(object): if field_name: order_by, tables, clause = obj._order_calc(cursor, user, field_name, otype, context=context) - if '"' + table_name + '"' not in tables: - tables.append('"' + table_name + '"') - if clause: - clause += ' AND ' - clause += ' %s.%s = %s.id' % (self._table, link_field, - table_name) + table_join = 'LEFT JOIN "' + table_name + '" ON ' \ + '%s.%s = %s.id' % (self._table, link_field, + table_name) + if table_join not in tables: + tables.append(table_join) return order_by, tables, clause obj2 = None @@ -2821,19 +2818,17 @@ class ORM(object): order_by, tables, clause = obj2._order_calc(cursor, user, field_name, otype, context=context) - if '"' + table_name + '"' not in tables: - tables.append('"' + table_name + '"') - if clause: - clause += ' AND ' - clause += ' %s.%s = %s.id' % (self._table, link_field, - table_name) + table_join = 'LEFT JOIN "' + table_name + '" ON ' \ + '%s.%s = %s.id' % \ + (self._table, link_field, table_name) + if table_join not in tables: + tables.append(table_join) - if '"' + table_name2 + '"' not in tables: - tables.append('"' + table_name2 + '"') - if clause: - clause += ' AND ' - clause += ' %s.%s = %s.id' % (obj._table, link_field2, - table_name2) + table_join2 = 'LEFT JOIN "' + table_name2 + '" ON ' \ + '%s.%s = %s.id' % \ + (obj._table, link_field2, table_name2) + if table_join2 not in tables: + tables.append(table_join2) return order_by, tables, clause if field_name: @@ -2852,12 +2847,11 @@ class ORM(object): link_field = self._inherits[obj._name] order_by, tables, clause = obj._order_calc(cursor, user, field, otype, context=context) - if '"' + table_name + '"' not in tables: - tables.append('"' + table_name + '"') - if clause: - clause += ' AND ' - clause += ' %s.%s = %s.id' % (self._table, link_field, - table_name) + table_join = 'LEFT JOIN "' + table_name + '" ON ' \ + '%s.%s = %s.id' % \ + (self._table, link_field, table_name) + if table_join not in tables: + tables.append(table_join) return order_by, tables, clause raise Exception('Error', 'Wrong field name (%s) in order!' \ @@ -2929,13 +2923,13 @@ class ORM(object): if count: cursor.execute('SELECT COUNT(%s.id) FROM ' % self._table + - ','.join(tables) + ' WHERE ' + (qu1 or 'True') + + ' '.join(tables) + ' WHERE ' + (qu1 or 'True') + limit_str + offset_str, tables_args + qu2) res = cursor.fetchall() return res[0][0] # execute the "main" query to fetch the ids we were searching for query_str = 'SELECT %s.id FROM ' % self._table + \ - ','.join(tables) + ' WHERE ' + (qu1 or 'True') + \ + ' '.join(tables) + ' WHERE ' + (qu1 or 'True') + \ ' ORDER BY ' + order_by + limit_str + offset_str if query_string: return (query_str, tables_args + qu2) From c4b28cc2a24aea292aed56c49375a2ffda00a778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 25 Nov 2008 18:23:35 +0100 Subject: [PATCH 014/164] Add missing table name in SQL clause to remove ambiguity --- trytond/osv/orm.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 5097561394..2ea2d3aa86 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2683,14 +2683,16 @@ class ORM(object): _symbol_set[0]] * len(arg[2])))) if todel: if arg[1] == 'in': - qu1[-1] = '(' + qu1[-1] + ' or ' \ - + arg[0] + ' is null)' + qu1[-1] = '(' + qu1[-1] + ' OR ' \ + '%s.%s IS NULL)' % \ + (table._table, arg[0]) else: - qu1[-1] = '(' + qu1[-1] + ' or ' \ - + arg[0] + ' is not null)' + qu1[-1] = '(' + qu1[-1] + ' OR ' \ + '%s.%s IS NOT NULL)' % \ + (table._table, arg[0]) qu2 += arg[2] elif todel: - qu1.append('(' + arg[0] + ' IS NULL)') + qu1.append('(%s.%s IS NULL)' % (table._table, arg[0])) else: if arg[1] == 'in': qu1.append(' false') From 0a00f3d0f7990fe9f82705c8b12991fcaa2a5156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 27 Nov 2008 14:06:28 +0100 Subject: [PATCH 015/164] Use the creation date of the log file as starting point for rotation --- trytond/server.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/trytond/server.py b/trytond/server.py index c614afeeb5..74bfc2939f 100644 --- a/trytond/server.py +++ b/trytond/server.py @@ -39,8 +39,12 @@ class TrytonServer(object): logf = CONFIG['logfile'] # test if the directories exist, else create them try: + diff = 0 + if os.path.isfile(logf): + diff = int(time.time()) - int(os.stat(logf)[-1]) handler = logging.handlers.TimedRotatingFileHandler( logf, 'D', 1, 30) + handler.rolloverAt -= diff except Exception, exception: sys.stderr.write("ERROR: couldn't create the logfile directory:" \ + str(exception)) From 00ebb25391b2f1af130318c1fa259ca39d8a1008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 27 Nov 2008 15:49:01 +0100 Subject: [PATCH 016/164] Log exception that are not 'UserError', 'ConcurrencyException' nor 'NotLogged' --- trytond/osv/osv.py | 3 ++- trytond/report/report.py | 3 ++- trytond/wizard/wizard.py | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/trytond/osv/osv.py b/trytond/osv/osv.py index 11035c800e..2f85a0c4e4 100644 --- a/trytond/osv/osv.py +++ b/trytond/osv/osv.py @@ -46,7 +46,8 @@ class OSVService(Service): res = getattr(obj, method)(cursor, user, *args, **kargs) return res except Exception, exception: - if CONFIG['verbose']: + if CONFIG['verbose'] or str(exception.args[0]) not in \ + ('NotLogged', 'ConcurrencyException', 'UserError'): tb_s = reduce(lambda x, y: x+y, traceback.format_exception(*sys.exc_info())) logger = logging.getLogger("web-service") diff --git a/trytond/report/report.py b/trytond/report/report.py index b32b8c1d16..667444cd28 100644 --- a/trytond/report/report.py +++ b/trytond/report/report.py @@ -56,7 +56,8 @@ class ReportService(Service): res = report.execute(cursor, user, ids, datas, context) return res except Exception, exception: - if CONFIG['verbose']: + if CONFIG['verbose'] or str(exception.args[0]) not in \ + ('NotLogged', 'ConcurrencyException', 'UserError'): tb_s = reduce(lambda x, y: x+y, traceback.format_exception(*sys.exc_info())) logging.getLogger("web-service").error( diff --git a/trytond/wizard/wizard.py b/trytond/wizard/wizard.py index 2c09d886d0..e003ba4db0 100644 --- a/trytond/wizard/wizard.py +++ b/trytond/wizard/wizard.py @@ -34,7 +34,8 @@ class WizardService(Service): res = wizard.execute(cursor, user, data, state, context) return res except Exception, exception: - if CONFIG['verbose']: + if CONFIG['verbose'] or str(exception.args[0]) not in \ + ('NotLogged', 'ConcurrencyException', 'UserError'): tb_s = reduce(lambda x, y: x+y, traceback.format_exception(*sys.exc_info())) logging.getLogger("web-service").error( From 76b7442a339bc5e44c531c0537c8777e736b58b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 27 Nov 2008 19:52:11 +0100 Subject: [PATCH 017/164] Fix replace method for inherit view --- trytond/osv/orm.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 2ea2d3aa86..5d61245680 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2148,8 +2148,14 @@ class ORM(object): pos = element2.get('position', 'inside') if pos == 'replace': parent = element.getparent() + next = element.getnext() + if next is not None: + for child in element2: + index = parent.index(next) + parent.insert(index, child) + else: + parent.extend(element2.getchildren()) parent.remove(element) - parent.extend(element2.getchildren()) elif pos == 'inside': element.extend(element2.getchildren()) elif pos == 'after': From ff46fc4f40e61212c0cb972be3ec878e73c6c11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 29 Nov 2008 21:03:56 +0100 Subject: [PATCH 018/164] Use the same clause order for LEFT JOIN for issue630 --- trytond/osv/orm.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 5d61245680..ebe1833805 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2805,8 +2805,8 @@ class ORM(object): order_by, tables, clause = obj._order_calc(cursor, user, field_name, otype, context=context) table_join = 'LEFT JOIN "' + table_name + '" ON ' \ - '%s.%s = %s.id' % (self._table, link_field, - table_name) + '%s.id = %s.%s' % (table_name, self._table, + link_field) if table_join not in tables: tables.append(table_join) return order_by, tables, clause @@ -2827,14 +2827,14 @@ class ORM(object): field_name, otype, context=context) table_join = 'LEFT JOIN "' + table_name + '" ON ' \ - '%s.%s = %s.id' % \ - (self._table, link_field, table_name) + '%s.id = %s.%s' % \ + (table_name, self._table, link_field) if table_join not in tables: tables.append(table_join) table_join2 = 'LEFT JOIN "' + table_name2 + '" ON ' \ - '%s.%s = %s.id' % \ - (obj._table, link_field2, table_name2) + '%s.id = %s.%s' % \ + (table_name2, obj._table, link_field2) if table_join2 not in tables: tables.append(table_join2) return order_by, tables, clause @@ -2856,8 +2856,8 @@ class ORM(object): order_by, tables, clause = obj._order_calc(cursor, user, field, otype, context=context) table_join = 'LEFT JOIN "' + table_name + '" ON ' \ - '%s.%s = %s.id' % \ - (self._table, link_field, table_name) + '%s.id = %s.%s' % \ + (table_name, self._table, link_field) if table_join not in tables: tables.append(table_join) return order_by, tables, clause From f20872a4287e6794dbd30e6798017858a7764af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 30 Nov 2008 17:22:10 +0100 Subject: [PATCH 019/164] Improve pysocket to reduce the number of call to recv/read --- trytond/pysocket.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/trytond/pysocket.py b/trytond/pysocket.py index e2358f96ec..8018479e78 100644 --- a/trytond/pysocket.py +++ b/trytond/pysocket.py @@ -31,6 +31,7 @@ class PySocket: self.ssl = False self.ssl_sock = None self.connected = False + self.buffer = '' def connect(self, host, port=False): if not port: @@ -79,6 +80,7 @@ class PySocket: self.hostname = hostname self.port = port self.connected = True + self.buffer = '' def disconnect(self): try: @@ -104,6 +106,7 @@ class PySocket: pass self.sock = None self.connected = False + self.buffer = '' def reconnect(self): if self.host and self.port: @@ -113,14 +116,8 @@ class PySocket: def send(self, msg, exception=False, traceback=None): msg = cPickle.dumps([msg, traceback], protocol=2) size = len(msg) - if self.ssl: - self.ssl_sock.write(str(size) + ' ') - else: - self.sock.send(str(size) + ' ') - if self.ssl: - self.ssl_sock.write(exception and "1" or "0") - else: - self.sock.send(exception and "1" or "0") + msg = str(size) + ' ' + (exception and "1" or "0") + msg + size = len(msg) totalsent = 0 while totalsent < size: if self.ssl: @@ -132,12 +129,12 @@ class PySocket: totalsent = totalsent + sent def receive(self): - buf = '' + buf = self.buffer while len(buf) < MAX_LENGHT: if self.ssl: - chunk = self.ssl_sock.read(MAX_LENGHT - len(buf)) + chunk = self.ssl_sock.read(4096) else: - chunk = self.sock.recv(MAX_LENGHT - len(buf)) + chunk = self.sock.recv(4096) if chunk == '': raise RuntimeError, "socket connection broken" buf += chunk @@ -147,9 +144,9 @@ class PySocket: size = int(size) if msg == '': if self.ssl: - msg = self.ssl_sock.read(1) + msg = self.ssl_sock.read(4096) else: - msg = self.sock.recv(1) + msg = self.sock.recv(4096) if msg == '': raise RuntimeError, "socket connection broken" if msg[0] != "0": @@ -165,6 +162,8 @@ class PySocket: if chunk == '': raise RuntimeError, "socket connection broken" msg = msg + chunk + self.buffer = msg[size:] + msg = msg[:size] msgio = StringIO.StringIO(msg) unpickler = cPickle.Unpickler(msgio) # cPickle mechanism to import instances (pickle differs here) From 07cf5ff4e112b2a0a795e32099567fe50299e6c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 30 Nov 2008 17:52:53 +0100 Subject: [PATCH 020/164] Add missing changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 97cf3119e0..de4d29382d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Improve netrpc communication speed * Use explicit join in search SQL query * Fix for host with IPv6 enable but without default IPv6 route * Allow egg installation From 05c940a4179efa422f956ff4b4bb4e4ea5f9298e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 1 Dec 2008 13:30:51 +0100 Subject: [PATCH 021/164] Prepare changelog for release 1.0.1 --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index de4d29382d..57fb94e8ba 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +Version 1.0.1 - 2008-12-01 * Improve netrpc communication speed * Use explicit join in search SQL query * Fix for host with IPv6 enable but without default IPv6 route From cf8b975245efe019cb77bc6211262e2b57d757eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 1 Dec 2008 13:31:38 +0100 Subject: [PATCH 022/164] Added tag 1.0.1 for changeset eeb6a351bc3e --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 67fa398183..85e63e4c29 100644 --- a/.hgtags +++ b/.hgtags @@ -1 +1,2 @@ 951bb3311b916cb893adc5294cfb3216d2940169 1.0.0 +eeb6a351bc3e82fd856161c01c8add6a4b7d5e66 1.0.1 From ae22aecd4f477c99922f677dfef3691400f5bc55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 1 Dec 2008 13:33:50 +0100 Subject: [PATCH 023/164] Increase version number --- doc/conf.py | 2 +- trytond/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 9526935030..489f33c1d7 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -46,7 +46,7 @@ copyright = '2008, B2CK' # The short X.Y version. version = '1.0' # The full version, including alpha/beta/rc tags. -release = '1.0.1' +release = '1.0.2' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: diff --git a/trytond/version.py b/trytond/version.py index d7526f3d53..bec63a72fc 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.0.1" +VERSION = "1.0.2" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From a11dcc98eb5ddbec73556c6b433fa8a2d3e2fdb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 1 Dec 2008 20:19:03 +0100 Subject: [PATCH 024/164] Fill correctly name2module in update_list of ir.module --- trytond/ir/module/module.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/trytond/ir/module/module.py b/trytond/ir/module/module.py index 138b58c3f2..ebf20b8653 100644 --- a/trytond/ir/module/module.py +++ b/trytond/ir/module/module.py @@ -420,9 +420,10 @@ class Module(OSV): 'shortdesc': tryton.get('name_' + code, ''), }, context=ctx) res += 1 - name2module[mod_name] = self.browse(cursor, user, new_id, + name2module.setdefault(mod_name, {}) + name2module[mod_name]['en_US'] = self.browse(cursor, user, new_id, context=context) - self._update_dependencies(cursor, user, name2module[mod_name], + self._update_dependencies(cursor, user, name2module[mod_name]['en_US'], tryton.get('depends', []), context=context) return res From be29352fea3f28e87451c32d08be3ddfb4ad910f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 1 Dec 2008 20:25:09 +0100 Subject: [PATCH 025/164] Use a set in get_module_list --- trytond/modules/__init__.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/trytond/modules/__init__.py b/trytond/modules/__init__.py index 040d81e943..776b5086c9 100644 --- a/trytond/modules/__init__.py +++ b/trytond/modules/__init__.py @@ -279,21 +279,21 @@ def load_module_graph(cursor, graph, pool, pool_wizard, pool_report, lang=None): cursor.commit() def get_module_list(): - module_list = [] + module_list = set() if os.path.exists(MODULES_PATH) and os.path.isdir(MODULES_PATH): for file in os.listdir(MODULES_PATH): if os.path.isdir(OPJ(MODULES_PATH, file)): - module_list.append(file) + module_list.add(file) elif file[-4:] == '.zip': - module_list.append(file) + module_list.add(file) for ep in pkg_resources.iter_entry_points('trytond.modules'): mod_name = ep.module_name.split('.')[-1] - module_list.append(mod_name) - module_list.append('ir') - module_list.append('workflow') - module_list.append('res') - module_list.append('webdav') - return module_list + module_list.add(mod_name) + module_list.add('ir') + module_list.add('workflow') + module_list.add('res') + module_list.add('webdav') + return list(module_list) def register_classes(): import trytond.ir From 33724699805078f84def42d6bc20bdac82477476 Mon Sep 17 00:00:00 2001 From: Bertrand Chenal Date: Tue, 2 Dec 2008 14:31:24 +0100 Subject: [PATCH 026/164] Added doc meta-data --- doc/conf.py | 2 +- doc/index.rst | 8 +++++--- doc/models.rst | 3 +++ doc/modules.rst | 3 +++ doc/views.rst | 3 +++ 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 489f33c1d7..18a252e017 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -86,7 +86,7 @@ html_style = 'default.css' # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +html_title = 'Tryton 1.0: Server Documentation' # The name of an image file (within the static path) to place at the top of # the sidebar. diff --git a/doc/index.rst b/doc/index.rst index bbb2bcbff8..e80952a23e 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -2,8 +2,10 @@ completely to your liking, but it should at least contain the root `toctree` directive. -Index -##### +:tocdepth: 2 + +Tryton Server +############# Contents: @@ -22,7 +24,7 @@ Contents: protocols Indices and tables -################## +****************** * :ref:`genindex` * :ref:`modindex` diff --git a/doc/models.rst b/doc/models.rst index 239708cb53..15d6351474 100644 --- a/doc/models.rst +++ b/doc/models.rst @@ -1,3 +1,6 @@ + +:tocdepth: 2 + Models ###### diff --git a/doc/modules.rst b/doc/modules.rst index 5ee5325ded..5dd8871115 100644 --- a/doc/modules.rst +++ b/doc/modules.rst @@ -1,3 +1,6 @@ + +:tocdepth: 2 + Modules ####### diff --git a/doc/views.rst b/doc/views.rst index 56da9c4581..ce3f00e90a 100644 --- a/doc/views.rst +++ b/doc/views.rst @@ -1,3 +1,6 @@ + +:tocdepth: 2 + Views ##### From ba72b44f56b0be513617a2d120a4e0203c827dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 3 Dec 2008 00:23:19 +0100 Subject: [PATCH 027/164] Remove unused "Indices and tables" --- doc/index.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/doc/index.rst b/doc/index.rst index bbb2bcbff8..fd6cd9aa90 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -20,11 +20,3 @@ Contents: workflows unittest protocols - -Indices and tables -################## - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - From 74570c970bdfc1e1efe46a9a60dbe024d1e34e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 3 Dec 2008 17:30:12 +0100 Subject: [PATCH 028/164] Fix query to fetch constrains definitions --- trytond/sql_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/sql_db.py b/trytond/sql_db.py index 8e557f1584..c21fdd7c86 100644 --- a/trytond/sql_db.py +++ b/trytond/sql_db.py @@ -269,7 +269,7 @@ class table_handler: "LEFT JOIN pg_class cl on (co.conrelid = cl.oid) "\ "LEFT JOIN pg_class cl2 on (co.confrelid = cl2.oid) "\ "LEFT JOIN pg_attribute at on (co.conkey[1] = at.attnum) "\ - "WHERE cl.relname = %s", + "WHERE cl.relname = %s AND at.attrelid = cl.oid", (self.table_name,)) self.constraint = [] self.fk_deltype = {} From 9eb34fc64b0d862a39231f488afd7f07e9965ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 3 Dec 2008 21:18:59 +0100 Subject: [PATCH 029/164] Fix check_xml_record for inherited model data for issue639 --- trytond/osv/orm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index ebe1833805..a5124fcc75 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -1528,6 +1528,8 @@ class ORM(object): if values == None: return False for line in cursor.fetchall(): + if not line[0]: + continue xml_values = eval(line[0], { 'Decimal': Decimal, 'datetime': datetime, From 06217af30d2b7f1a962672e43cca5f1219e1ad5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 9 Dec 2008 15:47:46 +0100 Subject: [PATCH 030/164] Fix typo for user.id operand --- trytond/ir/rule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/ir/rule.py b/trytond/ir/rule.py index b673640e20..d3cd7d4677 100644 --- a/trytond/ir/rule.py +++ b/trytond/ir/rule.py @@ -88,7 +88,7 @@ class Rule(OSV): res = {} if not obj_name: obj_name = 'res.user' - res.update({"False": "False", "True": "True", "user.id": "User"}) + res.update({"False": "False", "True": "True", "User": "user.id"}) if not recur: recur = [] obj_fields = self.pool.get(obj_name).fields_get(cursor, user) From 193ed8db34a3f7b9193f058fe419ab6c406f8a5a Mon Sep 17 00:00:00 2001 From: Bertrand Chenal Date: Wed, 10 Dec 2008 01:51:41 +0100 Subject: [PATCH 031/164] Fix cron messages: fallback to default langage if missing on the user --- trytond/ir/cron.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/ir/cron.py b/trytond/ir/cron.py index 693c567fdd..a7f74ce1d4 100644 --- a/trytond/ir/cron.py +++ b/trytond/ir/cron.py @@ -126,7 +126,8 @@ class Cron(OSV): cursor, cron['user'], {'name': self.raise_user_error( cursor, 'request_title', raise_exception=False, - context={'language': req_user.language.code}), + context={'language': req_user.language and \ + req_user.language.code or "en_US"}), 'priority': '2', 'act_from': cron['user'], 'act_to': cron['request_user'], From f3fb25d3b78229b42c9657fe16fd3cd89dc4252c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 11 Dec 2008 00:46:10 +0100 Subject: [PATCH 032/164] Improve action_inv on ir.ui.menu for issue659 --- trytond/ir/ui/menu.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/trytond/ir/ui/menu.py b/trytond/ir/ui/menu.py index 78fcb74f6a..f6dcd45ce9 100644 --- a/trytond/ir/ui/menu.py +++ b/trytond/ir/ui/menu.py @@ -154,6 +154,8 @@ class UIMenu(OSV): context=None): if context is None: context = {} + if not value: + return ctx = context.copy() if '_timestamp' in ctx: del ctx['_timestamp'] @@ -166,6 +168,8 @@ class UIMenu(OSV): action_keyword_obj.delete(cursor, user, action_keyword_ids, context=ctx) action_type, action_id = value.split(',') + if not int(action_id): + return action_obj = self.pool.get(action_type) action = action_obj.browse(cursor, user, int(action_id), context=context) From 2a4f1e6deea606692302bb6a7ea9b9ee21d50b6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 11 Dec 2008 01:02:20 +0100 Subject: [PATCH 033/164] Add missing module in context when updating xml record for issue657 --- trytond/tools/convert.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/tools/convert.py b/trytond/tools/convert.py index 452034ccba..83e16d6438 100644 --- a/trytond/tools/convert.py +++ b/trytond/tools/convert.py @@ -646,7 +646,8 @@ class TrytondXmlHandler(sax.handler.ContentHandler): # if there is values to update: if to_update: # write the values in the db: - object_ref.write(cursor, user, db_id, to_update) + object_ref.write(cursor, user, db_id, to_update, + context={'module': module}) if not inherit_db_ids: From 3314ea94c6e0519f1c1e41dea5a58b833fe96485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 11 Dec 2008 13:56:45 +0100 Subject: [PATCH 034/164] Quote the url for html page of webdav collection --- trytond/webdavsvc.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/trytond/webdavsvc.py b/trytond/webdavsvc.py index b51fe50f5e..b028e6c2f7 100644 --- a/trytond/webdavsvc.py +++ b/trytond/webdavsvc.py @@ -1,4 +1,5 @@ -#This file is part of Tryton. The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms. +#This file is part of Tryton. The COPYRIGHT file at the top level of +#this repository contains the full copyright notices and license terms. import urlparse import socket import base64 @@ -6,7 +7,7 @@ import time from DAV import AuthServer, WebDAVServer, iface from DAV.errors import * from DAV.constants import COLLECTION, OBJECT -from DAV.utils import get_uriparentpath, get_urifilename +from DAV.utils import get_uriparentpath, get_urifilename, quote_uri from DAV.davcmd import copyone, copytree, moveone, movetree, delone, deltree from netsvc import LocalService, SSLSocket import security @@ -103,16 +104,16 @@ class TrytonDAVInterface(iface.dav_interface): res += '
    ' if dbname: res += '
  • ..
  • ' \ - % (get_uriparentpath(uri) or '/') + % (quote_uri(get_uriparentpath(uri) or '/')) childs = self.get_childs(uri) childs.sort() for child in childs: res += '
  • %s
  • ' \ - % (child, get_urifilename(child)) + % (quote_uri(child), get_urifilename(child)) res += '
' res += '
' res += 'Powered by %s version %s' \ - % (WEBSITE, PACKAGE, VERSION) + % (quote_uri(WEBSITE), PACKAGE, VERSION) res += '' res += '' return res From fe9b838fcfb51185dc7b1f9150dcd154487771c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 11 Dec 2008 17:31:19 +0100 Subject: [PATCH 035/164] Add a default clause for the inselect query of child_of with left and right for issue660 --- trytond/osv/orm.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index a5124fcc75..94c0d15db5 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2589,10 +2589,9 @@ class ORM(object): 'WHERE id IN ' + \ '(' + ','.join(['%s' for x in ids2]) + ')', ids2) - clause = '' + clause = 'false ' for left, right in cursor.fetchall(): - if clause: - clause += 'OR ' + clause += 'OR ' clause += '( "' + field.left + '" >= ' + \ str(left) + ' ' + \ 'AND "' + field.right + '" <= ' + \ From 31fb929a0da495d4f30251c2f4efcc47b364ab92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 12 Dec 2008 13:31:22 +0100 Subject: [PATCH 036/164] Add fields view and multi for issue669 --- trytond/ir/action.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/trytond/ir/action.py b/trytond/ir/action.py index 7fa5adf4ba..1e78a1bc21 100644 --- a/trytond/ir/action.py +++ b/trytond/ir/action.py @@ -350,6 +350,8 @@ class ActionActWindow(OSV): help='Use the action name as window name') search_value = fields.Char('Search Criteria', help='Default search criteria for the list view') + #XXX add field for issue669 + view = fields.Function('get_view', type='char') def default_type(self, cursor, user, context=None): return 'ir.action.act_window' @@ -372,6 +374,9 @@ class ActionActWindow(OSV): def default_search_value(self, cursor, user, context=None): return '{}' + def get_view(self, cursor, user, ids, name, arg, context=None): + return dict.fromkeys(ids, '') + def views_get_fnc(self, cursor, user, ids, name, arg, context=None): res = {} for act in self.browse(cursor, user, ids, context=context): @@ -429,10 +434,15 @@ class ActionWizard(OSV): action = fields.Many2One('ir.action', 'Action', required=True, ondelete='CASCADE') model = fields.Char('Model') + #XXX add field for issue669 + multi = fields.Function('get_multi', type='boolean') def default_type(self, cursor, user, context=None): return 'ir.action.wizard' + def get_multi(self, cursor, user, ids, name, arg, context=None): + return dict.fromkeys(ids, False) + def delete(self, cursor, user, ids, context=None): action_obj = self.pool.get('ir.action') From 2c59aba84d4af2a44945300ae13c3594ba99c15c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 13 Dec 2008 00:35:20 +0100 Subject: [PATCH 037/164] Fix typo in rnc files --- trytond/ir/ui/board.rnc | 12 ++++++------ trytond/ir/ui/board.rng | 12 ++++++------ trytond/ir/ui/form.rnc | 2 +- trytond/ir/ui/form.rng | 12 ++++++------ trytond/ir/ui/tree.rnc | 2 +- trytond/ir/ui/tree.rng | 12 ++++++------ 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/trytond/ir/ui/board.rnc b/trytond/ir/ui/board.rnc index 9bd3d79d56..d6364d8b5f 100644 --- a/trytond/ir/ui/board.rnc +++ b/trytond/ir/ui/board.rnc @@ -5,7 +5,7 @@ board = attlist.board, (image | separator - | labe + | label | newline | notebook | group @@ -61,7 +61,7 @@ page = attlist.page, (image | separator - | labe + | label | newline | notebook | group @@ -78,7 +78,7 @@ group = attlist.group, (image | separator - | labe + | label | newline | notebook | group @@ -104,7 +104,7 @@ child1 = attlist.child1, (image | separator - | labe + | label | newline | notebook | group @@ -118,7 +118,7 @@ child2 = attlist.child2, (image | separator - | labe + | label | newline | notebook | group @@ -135,7 +135,7 @@ attlist.xpath &= [ a:defaultValue = "inside" ] attribute position { "inside" | "replace" | "after" | "before" }? action |= notAllowed -labe |= notAllowed +label |= notAllowed start = data | board | label any = (element * { diff --git a/trytond/ir/ui/board.rng b/trytond/ir/ui/board.rng index 8534f60a4d..bfcfcf8707 100644 --- a/trytond/ir/ui/board.rng +++ b/trytond/ir/ui/board.rng @@ -7,7 +7,7 @@ - + @@ -245,7 +245,7 @@ - + @@ -278,7 +278,7 @@ - + @@ -378,7 +378,7 @@ - + @@ -399,7 +399,7 @@ - + @@ -448,7 +448,7 @@ - + diff --git a/trytond/ir/ui/form.rnc b/trytond/ir/ui/form.rnc index 860cb575f6..1c6ebf2d56 100644 --- a/trytond/ir/ui/form.rnc +++ b/trytond/ir/ui/form.rnc @@ -122,7 +122,7 @@ attlist.field &= | "right_to_left" | "bottom_to_top" | "top_to_bottom" - } + }? attlist.field &= attribute spell { text }? image = element image { attlist.image, empty } attlist.image &= attribute name { text } diff --git a/trytond/ir/ui/form.rng b/trytond/ir/ui/form.rng index d85f277dd2..1343285cb5 100644 --- a/trytond/ir/ui/form.rng +++ b/trytond/ir/ui/form.rng @@ -79,12 +79,12 @@ - - - 0 - 1 - - + + + 0 + 1 + + diff --git a/trytond/ir/ui/tree.rnc b/trytond/ir/ui/tree.rnc index 04f81eeabe..6cd9f6e86d 100644 --- a/trytond/ir/ui/tree.rnc +++ b/trytond/ir/ui/tree.rnc @@ -51,7 +51,7 @@ attlist.field &= | "right_to_left" | "bottom_to_top" | "top_to_bottom" - } + }? button = element button { attlist.button, empty } attlist.button &= attribute help { text }? attlist.button &= diff --git a/trytond/ir/ui/tree.rng b/trytond/ir/ui/tree.rng index 41647878b6..d853e5a95d 100644 --- a/trytond/ir/ui/tree.rng +++ b/trytond/ir/ui/tree.rng @@ -43,12 +43,12 @@ - - - 0 - 1 - - + + + 0 + 1 + + From cbeedd61850413852e701f7cfd355dbbe94a27ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 13 Dec 2008 15:52:29 +0100 Subject: [PATCH 038/164] Fix dead lock when reseting cache for issue673 --- trytond/tools/misc.py | 54 +++++++++++++++++++++++++---------- trytond/web_service/common.py | 1 + trytond/web_service/object.py | 3 ++ trytond/web_service/report.py | 4 ++- trytond/web_service/wizard.py | 6 +++- trytond/webdavsvc.py | 1 + 6 files changed, 52 insertions(+), 17 deletions(-) diff --git a/trytond/tools/misc.py b/trytond/tools/misc.py index 56da2906f2..2dfd1bf62b 100644 --- a/trytond/tools/misc.py +++ b/trytond/tools/misc.py @@ -236,6 +236,8 @@ class Cache(object): Timeout: 0 = no timeout, otherwise in seconds """ _cache_instance = [] + _resets = {} + _resets_lock = Lock() def __init__(self, name, timeout=3600, max_len=1024): self.timeout = timeout @@ -320,11 +322,14 @@ class Cache(object): if not CONFIG['multi_server']: return cursor = pooler.get_db(dbname).cursor() - cursor.execute('SELECT "timestamp", "name" FROM ir_cache') - timestamps = {} - for timestamp, name in cursor.fetchall(): - timestamps[name] = timestamp - cursor.close() + try: + cursor.execute('SELECT "timestamp", "name" FROM ir_cache') + timestamps = {} + for timestamp, name in cursor.fetchall(): + timestamps[name] = timestamp + finally: + cursor.commit() + cursor.close() for obj in Cache._cache_instance: if obj.name in timestamps: if not obj.timestamp or timestamps[obj.name] > obj.timestamp: @@ -337,19 +342,38 @@ class Cache(object): @staticmethod def reset(dbname, name): + if not CONFIG['multi_server']: + return + Cache._resets_lock.acquire() + try: + Cache._resets.setdefault(dbname, set()) + Cache._resets[dbname].add(name) + finally: + Cache._resets_lock.release() + return + + @staticmethod + def resets(dbname): if not CONFIG['multi_server']: return cursor = pooler.get_db(dbname).cursor() - cursor.execute('SELECT name FROM ir_cache WHERE name = %s', - (name,)) - if cursor.rowcount: - cursor.execute('UPDATE ir_cache SET "timestamp" = now() '\ - 'WHERE name = %s', (name,)) - else: - cursor.execute('INSERT INTO ir_cache ("timestamp", "name") ' \ - 'VALUES (now(), %s)', (name,)) - cursor.commit() - cursor.close() + Cache._resets_lock.acquire() + Cache._resets.setdefault(dbname, set()) + try: + for name in Cache._resets[dbname]: + cursor.execute('SELECT name FROM ir_cache WHERE name = %s', + (name,)) + if cursor.rowcount: + cursor.execute('UPDATE ir_cache SET "timestamp" = now() '\ + 'WHERE name = %s', (name,)) + else: + cursor.execute('INSERT INTO ir_cache ("timestamp", "name") ' \ + 'VALUES (now(), %s)', (name,)) + Cache._resets[dbname].clear() + finally: + cursor.commit() + cursor.close() + Cache._resets_lock.release() def mod10r(number): diff --git a/trytond/web_service/common.py b/trytond/web_service/common.py index ac18c194da..595ccbfc2c 100644 --- a/trytond/web_service/common.py +++ b/trytond/web_service/common.py @@ -22,6 +22,7 @@ class Common(Service): logger = logging.getLogger("web-service") msg = res and 'successful login' or 'bad login or password' logger.info("%s from '%s' using database '%s'" % (msg, login, database)) + Cache.resets(database) return res or False def about(self): diff --git a/trytond/web_service/object.py b/trytond/web_service/object.py index 5ed9e4b041..b94825da15 100644 --- a/trytond/web_service/object.py +++ b/trytond/web_service/object.py @@ -19,6 +19,7 @@ class Object(Service): service = LocalService("object_proxy") res = service.exec_workflow(database, user, object_name, method, object_id, *args) + Cache.resets(database) return res def execute(self, database, user, session, object_name, method, *args): @@ -29,6 +30,7 @@ class Object(Service): Cache.clean(database) service = LocalService("object_proxy") res = service.execute(database, user, object_name, method, *args) + Cache.resets(database) return res def obj_list(self, database, user, session): @@ -36,4 +38,5 @@ class Object(Service): Cache.clean(database) service = LocalService("object_proxy") res = service.obj_list() + Cache.resets(database) return res diff --git a/trytond/web_service/report.py b/trytond/web_service/report.py index cddec6e0be..5d5bf72610 100644 --- a/trytond/web_service/report.py +++ b/trytond/web_service/report.py @@ -16,4 +16,6 @@ class Report(Service): security.check(database, user, passwd) Cache.clean(database) report = LocalService('report_proxy') - return report.execute(database, user, report_name, ids, datas, context) + res = report.execute(database, user, report_name, ids, datas, context) + Cache.resets(database) + return res diff --git a/trytond/web_service/wizard.py b/trytond/web_service/wizard.py index d3c6d14e60..8528c2fc3a 100644 --- a/trytond/web_service/wizard.py +++ b/trytond/web_service/wizard.py @@ -39,6 +39,7 @@ class Wizard(Service): self.wiz_name[wiz_id] = wiz_name self.wiz_uid[wiz_id] = user self.lock.release() + Cache.resets(database) return wiz_id def execute(self, database, user, passwd, wiz_id, datas, *args): @@ -46,7 +47,9 @@ class Wizard(Service): Cache.clean(database) if wiz_id in self.wiz_uid: if self.wiz_uid[wiz_id] == user: - return self._execute(database, user, wiz_id, datas, *args) + res = self._execute(database, user, wiz_id, datas, *args) + Cache.resets(database) + return res else: raise Exception, 'AccessDenied' else: @@ -62,6 +65,7 @@ class Wizard(Service): del self.wiz_name[wiz_id] del self.wiz_uid[wiz_id] self.lock.release() + Cache.resets(database) return wiz_id else: raise Exception, 'AccessDenied' diff --git a/trytond/webdavsvc.py b/trytond/webdavsvc.py index b028e6c2f7..062b090cf9 100644 --- a/trytond/webdavsvc.py +++ b/trytond/webdavsvc.py @@ -311,6 +311,7 @@ class WebDAVAuthRequestHandler(AuthServer.BufferedAuthRequestHandler, return 1 USER_ID = security.login(dbname, user, password, cache=False) Cache.clean(dbname) + Cache.resets(database) if int(USER_ID): return 1 return 0 From 7ed622edf243fc59da21fdbf76bbbf2de21a817a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 13 Dec 2008 17:21:41 +0100 Subject: [PATCH 039/164] Fix typo --- trytond/ir/translation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index c2fe64f1c3..07675cc6fd 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -224,7 +224,7 @@ class Translation(OSV, Cacheable): 'WHERE lang = %s ' \ 'AND type = %s ' \ 'AND name = %s ' \ - 'AND src = %s' \ + 'AND src = %s ' \ 'AND value != \'\' ' \ 'AND value IS NOT NULL ' \ 'AND fuzzy = false ', @@ -234,7 +234,7 @@ class Translation(OSV, Cacheable): 'FROM ir_translation ' \ 'WHERE lang = %s ' \ 'AND type = %s ' \ - 'AND name = %s' \ + 'AND name = %s ' \ 'AND value != \'\' ' \ 'AND value IS NOT NULL ' \ 'AND fuzzy = false ', From 14dc82e545d7bbb4b0c34b9f87d64b91c3600231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 13 Dec 2008 17:22:27 +0100 Subject: [PATCH 040/164] Call add for each arguments of _get_sources --- trytond/ir/translation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index 07675cc6fd..38624a6df9 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -267,6 +267,7 @@ class Translation(OSV, Cacheable): res[(name, ttype, lang, source)] = trans else: res[(name, ttype, lang, source)] = False + self.add(cursor, (lang, ttype, name, source), False) if clause: clause += ' OR ' if source: From 31f33223e9be29cf25241f6ff7d204f4911d9ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 15 Dec 2008 09:51:53 +0100 Subject: [PATCH 041/164] Add domain on user language for issue674 --- trytond/res/user.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/trytond/res/user.py b/trytond/res/user.py index b499e2d389..8e2f154e68 100644 --- a/trytond/res/user.py +++ b/trytond/res/user.py @@ -24,7 +24,8 @@ class User(OSV): rule_groups = fields.Many2Many('ir.rule.group', 'user_rule_group_rel', 'user_id', 'rule_group_id', 'Rules', domain=[('global_p', '!=', True), ('default_p', '!=', True)]) - language = fields.Many2One('ir.lang', 'Language') + language = fields.Many2One('ir.lang', 'Language', + domain=['OR', ('translatable', '=', True), ('code', '=', 'en_US')]) language_direction = fields.Function('get_language_direction', type='char', string='Language Direction') timezone = fields.Selection('timezones', 'Timezone') @@ -252,7 +253,10 @@ class User(OSV): if 'language' in fields: del fields['language']['relation'] fields['language']['selection'] = [] - lang_ids = lang_obj.search(cursor, user, [], context=None) + lang_ids = lang_obj.search(cursor, user, ['OR', + ('translatable', '=', True), + ('code', '=', 'en_US'), + ], context=None) for lang in lang_obj.browse(cursor, user, lang_ids, context=context): fields['language']['selection'].append((lang.code, lang.name)) res['fields'] = fields From 4d7bc7329908d736c4c3606eabac0f7daf5cc349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 16 Dec 2008 13:50:02 +0100 Subject: [PATCH 042/164] Fix creation of translation in xml import --- trytond/tools/convert.py | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/trytond/tools/convert.py b/trytond/tools/convert.py index 83e16d6438..42a715199b 100644 --- a/trytond/tools/convert.py +++ b/trytond/tools/convert.py @@ -562,13 +562,28 @@ class TrytondXmlHandler(sax.handler.ContentHandler): object_ref._inherit_fields[field_name][0])._name res_id = inherit_db_ids[table_name] if field.translate and values.get(field_name): - cursor.execute('INSERT INTO ir_translation ' \ - '(name, lang, type, src, res_id, ' \ - 'value, module, fuzzy) ' \ - 'VALUES (%s, %s, %s, %s, %s, %s, %s, false)', + cursor.execute('SELECT id FROM ir_translation ' \ + 'WHERE name = %s ' \ + 'AND lang = %s ' \ + 'AND type = %s ' \ + 'AND res_id = %s ' \ + 'AND module = %s', (table_name + ',' + field_name, - 'en_US', 'model', values[field_name], - res_id, '', module)) + 'en_US', 'model', res_id, module)) + if cursor.rowcount: + trans_id = cursor.fetchone()[0] + cursor.execute('UPDATE ir_translation ' \ + 'SET src = %s, module = %s ' \ + 'WHERE id = %s', + (values[field_name], module, trans_id)) + else: + cursor.execute('INSERT INTO ir_translation ' \ + '(name, lang, type, src, res_id, ' \ + 'value, module, fuzzy) ' \ + 'VALUES (%s, %s, %s, %s, %s, %s, %s, false)', + (table_name + ',' + field_name, + 'en_US', 'model', values[field_name], + res_id, '', module)) for table in inherit_db_ids.keys(): data_id = self.modeldata_obj.search(cursor, user, [ @@ -670,12 +685,13 @@ class TrytondXmlHandler(sax.handler.ContentHandler): res_id = inherit_db_ids[table_name] if field.translate: cursor.execute('SELECT id FROM ir_translation ' \ - 'WHERE name = %s' \ + 'WHERE name = %s ' \ 'AND lang = %s ' \ 'AND type = %s ' \ - 'AND res_id = %s', + 'AND res_id = %s ' \ + 'AND module = %s', (table_name + ',' + field_name, - 'en_US', 'model', res_id)) + 'en_US', 'model', res_id, module)) if cursor.rowcount: if to_update.get(field_name): trans_id = cursor.fetchone()[0] From 6e88cc5aa5b7e8a78a7a4b47d4c6e6d6e42c9c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 18 Dec 2008 00:55:51 +0100 Subject: [PATCH 043/164] Add missing strip and replace '\n' for source --- trytond/ir/translation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index 38624a6df9..eb60649077 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -271,6 +271,7 @@ class Translation(OSV, Cacheable): if clause: clause += ' OR ' if source: + source = source.strip().replace('\n',' ') clause += '(lang = %s ' \ 'AND type = %s ' \ 'AND name = %s ' \ From 3e6bfd070ac3f4c0cd7937be0dff7349116370ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 18 Dec 2008 00:57:35 +0100 Subject: [PATCH 044/164] Fix typo for src -> source for issue680 --- trytond/ir/translation.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index eb60649077..3ce6946074 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -292,10 +292,9 @@ class Translation(OSV, Cacheable): cursor.execute('SELECT lang, type, name, src, value ' \ 'FROM ir_translation ' \ 'WHERE ' + clause, value) - for lang, ttype, name, src, value in cursor.fetchall(): + for lang, ttype, name, source, value in cursor.fetchall(): res[(name, ttype, lang, source)] = value - self.add(cursor, (lang, ttype, name, source), - res[(name, ttype, lang, source)]) + self.add(cursor, (lang, ttype, name, source), value) return res def delete(self, cursor, user, ids, context=None): From c5deffde034d7b03978f50aed1f3b0f6b5f78379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 18 Dec 2008 23:29:33 +0100 Subject: [PATCH 045/164] Add missing context in get_full_name --- trytond/ir/ui/menu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/ir/ui/menu.py b/trytond/ir/ui/menu.py index f6dcd45ce9..a3a3a2a41c 100644 --- a/trytond/ir/ui/menu.py +++ b/trytond/ir/ui/menu.py @@ -110,7 +110,7 @@ class UIMenu(OSV): def get_full_name(self, cursor, user, ids, name, args, context): res = {} - for menu in self.browse(cursor, user, ids): + for menu in self.browse(cursor, user, ids, context=context): res[menu.id] = self._get_one_full_name(menu) return res From 4f151a55c606702f1e106c50147417d0ea3aa9e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 19 Dec 2008 14:39:12 +0100 Subject: [PATCH 046/164] Always use unicode keys for translation cache for issue687 --- trytond/ir/translation.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index 3ce6946074..45d7cf2e64 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -107,6 +107,9 @@ class Translation(OSV, Cacheable): def _get_ids(self, cursor, name, ttype, lang, ids): translations, to_fetch = {}, [] + name = unicode(name) + ttype = unicode(ttype) + lang = unicode(lang) if name.split(',')[0] == 'ir.model.field': model_fields_obj = self.pool.get('ir.model.field') field_name = name.split(',')[1] @@ -213,6 +216,11 @@ class Translation(OSV, Cacheable): return len(ids) def _get_source(self, cursor, name, ttype, lang, source=None): + name = unicode(name) + ttype = unicode(ttype) + lang = unicode(lang) + if source is not None: + source = unicode(source) trans = self.get(cursor, (lang, ttype, name, source)) if trans is not None: return trans @@ -262,6 +270,10 @@ class Translation(OSV, Cacheable): res.update(self._get_sources(cursor, sub_args)) return res for name, ttype, lang, source in args: + name = unicode(name) + ttype = unicode(ttype) + lang = unicode(lang) + source = unicode(source) trans = self.get(cursor, (lang, ttype, name, source)) if trans is not None: res[(name, ttype, lang, source)] = trans From 7a347af3742fac4e49426606351c9135f2809c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 23 Dec 2008 19:03:59 +0100 Subject: [PATCH 047/164] Add test on SIGQUIT and SIGUSR1 as it is not defined on win32 --- trytond/server.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/trytond/server.py b/trytond/server.py index 74bfc2939f..49068fa86b 100644 --- a/trytond/server.py +++ b/trytond/server.py @@ -228,7 +228,10 @@ class TrytonServer(object): signal.signal(signal.SIGINT, handler) signal.signal(signal.SIGTERM, handler) - signal.signal(signal.SIGUSR1, handler) + if hasattr(signal, 'SIGQUIT'): + signal.signal(signal.SIGQUIT, handler) + if hasattr(signal, 'SIGUSR1'): + signal.signal(signal.SIGUSR1, handler) self.logger.info('the server is running, waiting for connections...') if CONFIG['netrpc']: From 4a6421c2527d80b48d389213783ae0446a6edaff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 23 Dec 2008 19:06:26 +0100 Subject: [PATCH 048/164] Improve test on SIGUSR1 --- trytond/server.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/trytond/server.py b/trytond/server.py index 49068fa86b..9f61b17c27 100644 --- a/trytond/server.py +++ b/trytond/server.py @@ -206,10 +206,11 @@ class TrytonServer(object): ' service, port ' + str(port)) def handler(signum, frame): - if signum == signal.SIGUSR1: - for db_name in pooler.get_db_list(): - pooler.restart_pool(db_name) - return + if hasattr(signal, 'SIGUSR1'): + if signum == signal.SIGUSR1: + for db_name in pooler.get_db_list(): + pooler.restart_pool(db_name) + return if CONFIG['netrpc']: tinysocket.stop() if CONFIG['xmlrpc']: From c596bc95c7ffa20e7dcef85bf7ff9a7459158ad3 Mon Sep 17 00:00:00 2001 From: Bertrand Chenal Date: Tue, 23 Dec 2008 22:41:17 +0100 Subject: [PATCH 049/164] Doc: typo --- doc/models.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/models.rst b/doc/models.rst index 15d6351474..42a2475bcb 100644 --- a/doc/models.rst +++ b/doc/models.rst @@ -50,7 +50,7 @@ The following snippet gives a first idea of what can be done: 'party', 'category', 'Categories') Party() -Instantiating the class make it alive for the framework. Actually +Instantiating the class makes it alive for the framework. Actually there will be only one instance per class and per database. So model instances are essentially accessors to the underlying table. Columns of the table correspond to the fields of the class. Rows of the table From 96d9e1d991a0d430ab7d9df4a6dcade3fcaeb619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 24 Dec 2008 01:05:31 +0100 Subject: [PATCH 050/164] Fix typo --- doc/models.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/models.rst b/doc/models.rst index 42a2475bcb..d34b800834 100644 --- a/doc/models.rst +++ b/doc/models.rst @@ -192,7 +192,7 @@ Or one of these relation types: 'Addresses')``. This correspond in the database to a foreign key (who's name is ``party``) from the ``relationship_address`` table to the table of the current model. A ``One2Many`` alone will not - work, it rely on the ``Many2One`` to create the foreign key. + work, it relies on the ``Many2One`` to create the foreign key. * ``Many2Many``: A relation from the current model to another one where many record of the current model can be linked to many From 9fb52a6fd64e4f1f564531b49203fb699ff1189a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 24 Dec 2008 13:55:01 +0100 Subject: [PATCH 051/164] Fix order_calc to handle translated fields for issue697 --- trytond/osv/orm.py | 64 +++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 94c0d15db5..1e571adb7a 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2776,10 +2776,13 @@ class ORM(object): def _order_calc(self, cursor, user, field, otype, context=None): order_by = [] tables = [] + tables_args = {} field_name = None table_name = None link_field = None - clause = '' + + if context is None: + context = {} if field in self._columns: table_name = self._table @@ -2803,42 +2806,64 @@ class ORM(object): field_name = obj._order_name if field_name: - order_by, tables, clause = obj._order_calc(cursor, user, - field_name, otype, context=context) + order_by, tables, tables_args = obj._order_calc(cursor, + user, field_name, otype, context=context) table_join = 'LEFT JOIN "' + table_name + '" ON ' \ '%s.id = %s.%s' % (table_name, self._table, link_field) if table_join not in tables: - tables.append(table_join) - return order_by, tables, clause + tables.insert(0, table_join) + return order_by, tables, tables_args obj2 = None if obj._rec_name in obj._inherit_fields.keys(): - obj2 = self.pool.get(obj._inherit_fields[obj._rec_name][0]) + obj2 = self.pool.get( + obj._inherit_fields[obj._rec_name][0]) field_name = obj._rec_name if obj._order_name in obj._inherit_fields.keys(): - obj2 = self.pool.get(obj._inherit_fields[obj._order_name][0]) + obj2 = self.pool.get( + obj._inherit_fields[obj._order_name][0]) field_name = obj._order_name if obj2 and field_name: table_name2 = obj2._table link_field2 = obj._inherits[obj2._name] - order_by, tables, clause = obj2._order_calc(cursor, user, - field_name, otype, context=context) + order_by, tables, tables_args = obj2._order_calc(cursor, + user, field_name, otype, context=context) table_join = 'LEFT JOIN "' + table_name + '" ON ' \ '%s.id = %s.%s' % \ (table_name, self._table, link_field) if table_join not in tables: - tables.append(table_join) + tables.insert(0, table_join) table_join2 = 'LEFT JOIN "' + table_name2 + '" ON ' \ '%s.id = %s.%s' % \ (table_name2, obj._table, link_field2) if table_join2 not in tables: - tables.append(table_join2) - return order_by, tables, clause + tables.insert(0, table_join2) + return order_by, tables, tables_args + + if field_name in self._columns \ + and self._columns[field_name].translate: + translation_table = 'ir_translation_%s_%s' % \ + (table_name, field_name) + table_join = 'LEFT JOIN "ir_translation" ' \ + 'AS "%s" ON ' \ + '(%s.res_id = %s.id ' \ + 'AND %s.name = \'%s,%s\' ' \ + 'AND %s.lang = %%s ' \ + 'AND %s.type = \'model\')' % \ + (translation_table, translation_table, table_name, + translation_table, self._name, field_name, + translation_table, translation_table) + if table_join not in tables: + tables.append(table_join) + tables_args[table_join] = [context.get('language') or 'en_US'] + order_by.append('COALESCE(' + translation_table + '.value, ' \ + + table_name + '.' + field_name + ') ' + otype) + return order_by, tables, tables_args if field_name: if '%(table)s' in field_name or '%(order)s' in field_name: @@ -2848,20 +2873,20 @@ class ORM(object): }) else: order_by.append(table_name + '.' + field_name + ' ' + otype) - return order_by, tables, clause + return order_by, tables, tables_args if field in self._inherit_fields.keys(): obj = self.pool.get(self._inherit_fields[field][0]) table_name = obj._table link_field = self._inherits[obj._name] - order_by, tables, clause = obj._order_calc(cursor, user, field, + order_by, tables, tables_args = obj._order_calc(cursor, user, field, otype, context=context) table_join = 'LEFT JOIN "' + table_name + '" ON ' \ '%s.id = %s.%s' % \ (table_name, self._table, link_field) if table_join not in tables: tables.append(table_join) - return order_by, tables, clause + return order_by, tables, tables_args raise Exception('Error', 'Wrong field name (%s) in order!' \ % field) @@ -2900,17 +2925,14 @@ class ORM(object): for field, otype in (order or self._order): if otype.upper() not in ('DESC', 'ASC'): raise Exception('Error', 'Wrong order type (%s)!' % otype) - order_by2, tables2, clause = self._order_calc(cursor, user, + order_by2, tables2, tables2_args = self._order_calc(cursor, user, field, otype, context=context) order_by += order_by2 for table in tables2: if table not in tables: tables.append(table) - if clause: - if qu1: - qu1 += ' AND ' + clause - else: - qu1 = clause + if tables2_args.get(table): + tables_args.extend(tables2_args.get(table)) order_by = ','.join(order_by) From d89a3fd395e367b9051d2d2b16698d73eca3af52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 24 Dec 2008 14:17:16 +0100 Subject: [PATCH 052/164] Fix join tables order in _order_calc for issue700 --- trytond/osv/orm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 1e571adb7a..b2fe50de9d 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2842,7 +2842,7 @@ class ORM(object): '%s.id = %s.%s' % \ (table_name2, obj._table, link_field2) if table_join2 not in tables: - tables.insert(0, table_join2) + tables.insert(1, table_join2) return order_by, tables, tables_args if field_name in self._columns \ @@ -2885,7 +2885,7 @@ class ORM(object): '%s.id = %s.%s' % \ (table_name, self._table, link_field) if table_join not in tables: - tables.append(table_join) + tables.insert(0, table_join) return order_by, tables, tables_args raise Exception('Error', 'Wrong field name (%s) in order!' \ From 427c39ec625bf91f52d60f34b949d73bc2d9ce59 Mon Sep 17 00:00:00 2001 From: syn Date: Wed, 24 Dec 2008 11:27:23 -0800 Subject: [PATCH 053/164] document changes --- doc/models.rst | 84 +++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/doc/models.rst b/doc/models.rst index d34b800834..d11e850f08 100644 --- a/doc/models.rst +++ b/doc/models.rst @@ -206,18 +206,17 @@ Or one of these relation types: Or one of these composed types: - * ``Property``: Like a ``Many2One`` but allow complex usage of + * ``Property``: Like a ``Many2One`` but allows complex usage of default value: when the default value is updated, all the fields with this default value are updated. When the company module is - installed it also allow to define different value for the same - field depending on the company of the user. + installed it also allows the definition of different values for + the same field depending on the company of the user. - * ``Reference``: Also like a ``Many2One``. It allow to create a - link to an arbitrary selection of other model. This selection is + * ``Reference``: Also like a ``Many2One``. It allows the creation of + a link to an arbitrary selection of other models. This selection is defined by the records of ``res.request.link``. - Function field can be used to mimic any other type: * ``Function``: A computed field. E.g. ``total = @@ -256,14 +255,14 @@ Let's take the following model as an example of the first option: ], "Color") Truck () -The selection define a list of couple, the first member of each tuple -will be the value to store in the database if selected. The second -member is the string (or one of his translations) that the user will -see . +The selection is defined as list of tuples. The first member of each tuple +will be the value to store in the database when the second value is selected +through the user interface. The second member is the string (or one of it's +translations) that will be displayed in the UI. By default the selection is sorted when presented to the user. In some -case it could be useful to avoid this behaviour. In this case one can -use the ``sort`` argument, like: +cases it could be useful to avoid this behaviour. In such a case one can +use the ``sort`` argument: .. highlight:: python @@ -290,9 +289,9 @@ following will work as expected (See :ref:`define_inheritance`): Truck () But this can create problems if a third module wants to add other -colors or if the base module evolve. +colors or if the base module evolves. -The solution is to extend the list: +A better solution for this case would be to extend the list: .. highlight:: python @@ -353,8 +352,9 @@ each id in ``ids``. One method to rule them all ```````````````````````````` -The first variant we can use is tho define a unique function for -several fields. Let's consider this new field: +The first variant of this we'll look at is defining a unique function for +several fields. Let's consider this new field which returns the total for +the invoice lines of kind *service*: .. highlight:: python @@ -364,8 +364,7 @@ several fields. Let's consider this new field: -Which return the total for the invoice lines of kind *service*. Thus -the method ``get_total`` can be defined this way: +For this field the method ``get_total`` can be defined this way: .. highlight:: python @@ -437,10 +436,11 @@ to the function call: Search on function fields ````````````````````````` -Another improvement is to provide a search function. Indeed without it -the user will not be able to search across invoice for a certain -amount. If we forget about the ``total_service`` field a first -solution could be something like this: +Another improvement would be to provide a search function. +Indeed without it the user will not be able to search across +invoices for a certain amount. If we forget about the +``total_service`` field, solution could be something like the +following: .. highlight:: python @@ -480,7 +480,7 @@ solution could be something like this: return res -One should note that this implementation will be very slow for a big +One should note that such an implementation would be very slow for a large number of invoices. @@ -506,44 +506,44 @@ It's also possible to allow the user to write on a function field: return res -This naive example is another (inefficient) way to handle default value on the -``name`` field. +This simplistic (and inefficient) example is another way to handle a default +value on the ``name`` field. Fields options ^^^^^^^^^^^^^^ -Options are available on all type of fields, except when stated +The following options are available on all type of fields, except when stated otherwise in the description. - * ``readonly``: A boolean, when set to ``True`` the field is not + * ``readonly``: A boolean. when set to ``True`` the field is not editable in the interface. * ``required``: A boolean. When a field is required a ``NOT NULL`` - constraint is added in the database. It appear with a blue + constraint is added in the database. It will appear with a blue background in the interface. - * ``help``: A text to be show in the interface on mouse-over. + * ``help``: A text field shown in the interface on mouse-over. * ``select``: An integer. When equal to ``1``, an index is - created in the database and the field appear in the search box on + created in the database and the field will appear in the search box on list view. When equal to ``2`` the field appear in the *Advanced Search* part of the search box. * ``on_change``: A list of values. If set, the client will call - the method ``on_change_`` when a user change the field - and pass this list of values as argument. This method must return - a dictionary ``{field_name: new_value}`` for all the field that - must be updated. + the method ``on_change_`` when a user changes the field. + It then passes this list of values as arguments to the function. + This method must return a dictionary ``{field_name: new_value}`` + for all the field that must be updated. * ``states``: A dictionary. Keys are name of other options and - values are python expression. This allow to update dynamically - options for the current field. E.g.: ``states={"readonly": + values are python expression. This allows options to update + dynamically the current field. E.g.: ``states={"readonly": "total > 10"}``. * ``domain``: A domain on the current field. E.g.: ``[('name', '!=', 'Steve')]`` on the ``party`` field of the - ``relationship.address`` model will forbid to link the current + ``relationship.address`` model will forbid linking the current address to a Party for which ``name`` is equal to ``Steve``. See :ref:`search_clause` for a more complete explanation. @@ -551,11 +551,11 @@ otherwise in the description. interface will allow users to change translate the field for the defined language. - * ``priority``: An integer. Allow to force the order in which - fields are written in the database. This is used only for fields + * ``priority``: An integer. Force the order in which fields are + written in the database. This is used only for fields that are not in the table, like One2Many. - * ``change_default``: When the user choose a default value for a + * ``change_default``: When the user chooses a default value for a field in the current model, the current field with ``change_default`` equal to ``True`` can be used as a a condition to the default value. @@ -566,7 +566,7 @@ otherwise in the description. * ``size``: A maximum size on ``Char`` fields. - * ``digits``: A couple of integer which define the total number of + * ``digits``: A pair of integers which define the total number of digit and the number of decimal to show in the interface. Only for ``Float`` and ``Numeric``. @@ -575,7 +575,7 @@ otherwise in the description. ``CASCADE``, ``NO ACTION``, ``RESTRICT``, ``SET DEFAULT``, ``SET NULL`` (default). - * ``context``: A string defining a diction nay which will be given + * ``context``: A string defining a dictionary which will be given to evaluate the relation fields. * ``ondelete_origin`` and ``ondelete_target``: Like ``on_delete`` From 3e59726e7520e1fa79f043d91d09b0623ddc1021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 26 Dec 2008 15:25:49 +0100 Subject: [PATCH 054/164] Fix order on selection field to order with selection values --- trytond/osv/orm.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index b2fe50de9d..54e4565654 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2865,6 +2865,17 @@ class ORM(object): + table_name + '.' + field_name + ') ' + otype) return order_by, tables, tables_args + if field_name in self._columns \ + and self._columns[field_name]._type == 'selection': + selections = self.fields_get(cursor, user, [field_name], + context=context)[field_name]['selection'] + order = 'CASE ' + table_name + '.' + field_name + for selection in selections: + order += ' WHEN \'%s\' THEN \'%s\'' % selection + order += ' ELSE ' + table_name + '.' + field_name + ' END' + order_by.append(order + ' ' + otype) + return order_by, tables, tables_args + if field_name: if '%(table)s' in field_name or '%(order)s' in field_name: order_by.append(field_name % { From 8b4783981559c854befa4b0dc97a7c7da79b8da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 26 Dec 2008 15:36:17 +0100 Subject: [PATCH 055/164] Fix unicode conversion of source in _get_sources if it is None --- trytond/ir/translation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index 45d7cf2e64..e6d0bb73fb 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -273,7 +273,8 @@ class Translation(OSV, Cacheable): name = unicode(name) ttype = unicode(ttype) lang = unicode(lang) - source = unicode(source) + if source is not None: + source = unicode(source) trans = self.get(cursor, (lang, ttype, name, source)) if trans is not None: res[(name, ttype, lang, source)] = trans From ac700043603a684a506637bfd6c016d5a8195ef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 30 Dec 2008 14:11:38 +0100 Subject: [PATCH 056/164] Add missing translation of confirm attribute for issue706 --- trytond/osv/orm.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 54e4565654..de8b470647 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2064,18 +2064,13 @@ class ORM(object): # translate view if ('language' in context) and not result: - if element.get('string'): - trans = translation_obj._get_source(cursor, - self._name, 'view', context['language'], - element.get('string')) - if trans: - element.set('string', trans) - if element.get('sum'): - trans = translation_obj._get_source(cursor, - self._name, 'view', context['language'], - element.get('sum')) - if trans: - element.set('sum', trans) + for attr in ('string', 'sum', 'confirm'): + if element.get(attr): + trans = translation_obj._get_source(cursor, + self._name, 'view', context['language'], + element.get(attr)) + if trans: + element.set(attr, trans) if element.tag in ('form', 'tree', 'graph'): value = '' From 43c2ea99133e6d2f81f4b1de2c7e6938127eac57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 30 Dec 2008 20:05:04 +0100 Subject: [PATCH 057/164] Fix cache of ir.translation when source is None --- trytond/ir/translation.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index e6d0bb73fb..0401d28564 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -306,6 +306,8 @@ class Translation(OSV, Cacheable): 'FROM ir_translation ' \ 'WHERE ' + clause, value) for lang, ttype, name, source, value in cursor.fetchall(): + if (name, ttype, lang, source) not in args: + source = None res[(name, ttype, lang, source)] = value self.add(cursor, (lang, ttype, name, source), value) return res From 5f9d1f050880acee4e8b9a6f6cf4e083ff7a431e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 30 Dec 2008 20:42:02 +0100 Subject: [PATCH 058/164] Add logging shutdown before exit --- trytond/server.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/trytond/server.py b/trytond/server.py index 9f61b17c27..08a19b0caa 100644 --- a/trytond/server.py +++ b/trytond/server.py @@ -155,6 +155,7 @@ class TrytonServer(object): if update_module: self.logger.info('Update/Init succeed!') + logging.shutdown() sys.exit(0) # Launch Server @@ -164,6 +165,7 @@ class TrytonServer(object): port = int(CONFIG["xmlport"]) except: self.logger.error("invalid port '%s'!" % (CONFIG["xmlport"],)) + logging.shutdown() sys.exit(1) httpd = netsvc.HttpDaemon(interface, port, CONFIG['secure_xmlrpc']) @@ -181,6 +183,7 @@ class TrytonServer(object): port = int(CONFIG["netport"]) except: self.logger.error("invalid port '%s'!" % (CONFIG["netport"],)) + logging.shutdown() sys.exit(1) tinysocket = netsvc.TinySocketServerThread(interface, port, @@ -196,6 +199,7 @@ class TrytonServer(object): port = int(CONFIG['webdavport']) except: self.logger.error("invalid port '%s'!" % (CONFIG['webdavport'],)) + logging.shutdown() sys.exit(1) webdavd = netsvc.WebDAVServerThread(interface, port, @@ -219,6 +223,7 @@ class TrytonServer(object): webdavd.stop() if CONFIG['pidfile']: os.unlink(CONFIG['pidfile']) + logging.shutdown() sys.exit(0) if CONFIG['pidfile']: From 4f2af813e3f5f031f7275d50ea6dd30332f6d913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 6 Jan 2009 13:26:01 +0100 Subject: [PATCH 059/164] Prepare changelog for release 1.0.2 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 57fb94e8ba..2574a05c55 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 1.0.2 - 2008-01-06 +* Some bug fixes (see mercurial logs for details) + Version 1.0.1 - 2008-12-01 * Improve netrpc communication speed * Use explicit join in search SQL query From 3e174455b6887741594e57b6d0b5e19965874fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 6 Jan 2009 13:26:25 +0100 Subject: [PATCH 060/164] Added tag 1.0.2 for changeset 6f52a2f63288 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 85e63e4c29..8a199cd472 100644 --- a/.hgtags +++ b/.hgtags @@ -1,2 +1,3 @@ 951bb3311b916cb893adc5294cfb3216d2940169 1.0.0 eeb6a351bc3e82fd856161c01c8add6a4b7d5e66 1.0.1 +6f52a2f6328837727c65eeb5ddf2de0c146e33a9 1.0.2 From a873d7023e5039a7686ebb25366b817325913597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 6 Jan 2009 13:28:10 +0100 Subject: [PATCH 061/164] Increase version number --- doc/conf.py | 2 +- trytond/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 18a252e017..31678f36d8 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -46,7 +46,7 @@ copyright = '2008, B2CK' # The short X.Y version. version = '1.0' # The full version, including alpha/beta/rc tags. -release = '1.0.2' +release = '1.0.3' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: diff --git a/trytond/version.py b/trytond/version.py index bec63a72fc..ef3033a743 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.0.2" +VERSION = "1.0.3" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 348afb179ff5194d5b70e866947f0ad49f45afca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 7 Jan 2009 12:31:53 +0100 Subject: [PATCH 062/164] Don't strip nor replace '\n' when searching translation for issue732 --- trytond/ir/translation.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index 0401d28564..04d1dc12de 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -226,7 +226,6 @@ class Translation(OSV, Cacheable): return trans if source: - source = source.strip().replace('\n',' ') cursor.execute('SELECT value ' \ 'FROM ir_translation ' \ 'WHERE lang = %s ' \ @@ -284,7 +283,6 @@ class Translation(OSV, Cacheable): if clause: clause += ' OR ' if source: - source = source.strip().replace('\n',' ') clause += '(lang = %s ' \ 'AND type = %s ' \ 'AND name = %s ' \ From 6f6512245caa68ea887b2f0301717ed3cc59c7be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 7 Jan 2009 12:41:11 +0100 Subject: [PATCH 063/164] Test exception.args before using it for issue734 --- trytond/osv/osv.py | 5 +++-- trytond/report/report.py | 5 +++-- trytond/wizard/wizard.py | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/trytond/osv/osv.py b/trytond/osv/osv.py index 2f85a0c4e4..cdac5a43af 100644 --- a/trytond/osv/osv.py +++ b/trytond/osv/osv.py @@ -46,8 +46,9 @@ class OSVService(Service): res = getattr(obj, method)(cursor, user, *args, **kargs) return res except Exception, exception: - if CONFIG['verbose'] or str(exception.args[0]) not in \ - ('NotLogged', 'ConcurrencyException', 'UserError'): + if CONFIG['verbose'] or (exception.args \ + and str(exception.args[0]) not in \ + ('NotLogged', 'ConcurrencyException', 'UserError')): tb_s = reduce(lambda x, y: x+y, traceback.format_exception(*sys.exc_info())) logger = logging.getLogger("web-service") diff --git a/trytond/report/report.py b/trytond/report/report.py index 667444cd28..4c8c56f252 100644 --- a/trytond/report/report.py +++ b/trytond/report/report.py @@ -56,8 +56,9 @@ class ReportService(Service): res = report.execute(cursor, user, ids, datas, context) return res except Exception, exception: - if CONFIG['verbose'] or str(exception.args[0]) not in \ - ('NotLogged', 'ConcurrencyException', 'UserError'): + if CONFIG['verbose'] or (exception.args \ + and str(exception.args[0]) not in \ + ('NotLogged', 'ConcurrencyException', 'UserError')): tb_s = reduce(lambda x, y: x+y, traceback.format_exception(*sys.exc_info())) logging.getLogger("web-service").error( diff --git a/trytond/wizard/wizard.py b/trytond/wizard/wizard.py index e003ba4db0..2ca25a475a 100644 --- a/trytond/wizard/wizard.py +++ b/trytond/wizard/wizard.py @@ -34,8 +34,9 @@ class WizardService(Service): res = wizard.execute(cursor, user, data, state, context) return res except Exception, exception: - if CONFIG['verbose'] or str(exception.args[0]) not in \ - ('NotLogged', 'ConcurrencyException', 'UserError'): + if CONFIG['verbose'] or (exception.args \ + and str(exception.args[0]) not in \ + ('NotLogged', 'ConcurrencyException', 'UserError')): tb_s = reduce(lambda x, y: x+y, traceback.format_exception(*sys.exc_info())) logging.getLogger("web-service").error( From 88d3d8444f90c0642b9bcff6f0df3276aa6c4b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 5 Jan 2009 20:43:03 +0100 Subject: [PATCH 064/164] Add log for wrong SQL --- trytond/sql_db.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/trytond/sql_db.py b/trytond/sql_db.py index c21fdd7c86..17e11efa93 100644 --- a/trytond/sql_db.py +++ b/trytond/sql_db.py @@ -66,10 +66,15 @@ class FakeCursor(object): if self.sql_log: now = mdt.now() - if params: - res = self.cursor.execute(sql, params) - else: - res = self.cursor.execute(sql) + try: + if params: + res = self.cursor.execute(sql, params) + else: + res = self.cursor.execute(sql) + except: + logger = logging.getLogger('sql') + logger.error('Wrong SQL: ' + sql % tuple("'%s'" % x for x in params or [])) + raise if self.sql_log: self.count += 1 res_from = RE_FROM.match(sql.lower()) From 709ef712fd2e136abb9b8281351ced74435f4cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 13 Jan 2009 13:16:51 +0100 Subject: [PATCH 065/164] Add exponential timeout on failed login attempts. Thanks to Bruce's comment about the Twitter issue. --- trytond/security.py | 46 ++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/trytond/security.py b/trytond/security.py index aec7829afd..5553ff9032 100644 --- a/trytond/security.py +++ b/trytond/security.py @@ -1,4 +1,5 @@ -#This file is part of Tryton. The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms. +#This file is part of Tryton. The COPYRIGHT file at the top level of +#this repository contains the full copyright notices and license terms. import pooler from config import CONFIG import sha @@ -6,30 +7,41 @@ import time import random _USER_CACHE = {} +_USER_TRY = {} def login(dbname, loginname, password, cache=True): + _USER_TRY.setdefault(dbname, {}) cursor = pooler.get_db(dbname).cursor() password_sha = sha.new(password).hexdigest() - cursor.execute('SELECT id FROM res_user ' - 'WHERE login = %s and password = %s and active', - (loginname, password_sha)) - res = cursor.fetchone() - cursor.close() - if res: + cursor.execute('SELECT id, password, active FROM res_user ' + 'WHERE login = %s', (loginname,)) + if cursor.rowcount: + res = cursor.fetchone() + cursor.close() user_id = res[0] if user_id == 0: return False - if cache: - _USER_CACHE.setdefault(dbname, {}) - timestamp = time.time() - session = str(random.random()) - _USER_CACHE[dbname].setdefault(user_id, []) - _USER_CACHE[dbname][user_id].append((timestamp, session)) - return (user_id, session) - else: - return user_id - else: + + _USER_TRY[dbname].setdefault(user_id, 0) + if res[1] == password_sha and res[2]: + _USER_TRY[dbname][user_id] = 0 + if cache: + _USER_CACHE.setdefault(dbname, {}) + timestamp = time.time() + session = str(random.random()) + _USER_CACHE[dbname].setdefault(user_id, []) + _USER_CACHE[dbname][user_id].append((timestamp, session)) + return (user_id, session) + else: + return user_id + time.sleep(2 ** _USER_TRY[dbname][user_id]) + _USER_TRY[dbname][user_id] += 1 return False + cursor.close() + _USER_TRY[dbname].setdefault(0, 0) + time.sleep(2 ** _USER_TRY[dbname][0]) + _USER_TRY[dbname][0] += 1 + return False def check_super(passwd): if passwd == CONFIG['admin_passwd']: From 5f284da85b7a733a68d40db422bbc638683190d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 13 Jan 2009 13:50:19 +0100 Subject: [PATCH 066/164] Use repr to convert key instead of str in the case of key is an unicode --- trytond/tools/misc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trytond/tools/misc.py b/trytond/tools/misc.py index 2dfd1bf62b..cd86fead38 100644 --- a/trytond/tools/misc.py +++ b/trytond/tools/misc.py @@ -289,8 +289,8 @@ class Cache(object): finally: self.lock.release() - # Work out key as a tuple of ('argname', value) pairs - key = (id(self2), str(kwargs)) + # Work out key as a tuple + key = (id(self2), repr(kwargs)) # Check cache and return cached value if possible self.lock.acquire() From 8cdfd456702f485896a629d352197323465bd0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 13 Jan 2009 14:07:21 +0100 Subject: [PATCH 067/164] Fix order for selection fields that use a function instead of list. --- trytond/osv/orm.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index de8b470647..84079f77c7 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2864,6 +2864,10 @@ class ORM(object): and self._columns[field_name]._type == 'selection': selections = self.fields_get(cursor, user, [field_name], context=context)[field_name]['selection'] + if not isinstance(selections, (tuple, list)): + selections = getattr(self, + self._columns[field_name].selection)(cursor, + user, context=context) order = 'CASE ' + table_name + '.' + field_name for selection in selections: order += ' WHEN \'%s\' THEN \'%s\'' % selection From ffd87639a3b37b958264450dd36d058b1c0c9c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 13 Jan 2009 23:02:13 +0100 Subject: [PATCH 068/164] Fix in clause on boolean fields and prevent to modify args --- trytond/osv/orm.py | 50 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 84079f77c7..0df8040858 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2670,31 +2670,55 @@ class ORM(object): if arg[2][xitem] == False \ and isinstance(arg[2][xitem],bool): todel.append(xitem) + arg2 = arg[2][:] for xitem in todel[::-1]: - del arg[2][xitem] + del arg2[xitem] #TODO fix max_stack_depth - if len(arg[2]): + if len(arg2): if arg[0] == 'id': qu1.append(('(%s.id ' + arg[1] + ' (%s))') % \ (table._table, - ','.join(['%s'] * len(arg[2])),)) + ','.join(['%s'] * len(arg2)),)) else: qu1.append(('(%s.%s ' + arg[1] + ' (%s))') % \ (table._table, arg[0], ','.join( [table._columns[arg[0]].\ - _symbol_set[0]] * len(arg[2])))) + _symbol_set[0]] * len(arg2)))) if todel: - if arg[1] == 'in': - qu1[-1] = '(' + qu1[-1] + ' OR ' \ - '%s.%s IS NULL)' % \ - (table._table, arg[0]) + if table._columns[arg[0]]._type == 'boolean': + if arg[1] == 'in': + qu1[-1] = '(' + qu1[-1] + ' OR ' \ + '%s.%s = false)' % \ + (table._table, arg[0]) + else: + qu1[-1] = '(' + qu1[-1] + ' OR ' \ + '%s.%s != false)' % \ + (table._table, arg[0]) else: - qu1[-1] = '(' + qu1[-1] + ' OR ' \ - '%s.%s IS NOT NULL)' % \ - (table._table, arg[0]) - qu2 += arg[2] + if arg[1] == 'in': + qu1[-1] = '(' + qu1[-1] + ' OR ' \ + '%s.%s IS NULL)' % \ + (table._table, arg[0]) + else: + qu1[-1] = '(' + qu1[-1] + ' OR ' \ + '%s.%s IS NOT NULL)' % \ + (table._table, arg[0]) + qu2 += arg2 elif todel: - qu1.append('(%s.%s IS NULL)' % (table._table, arg[0])) + if table._columns[arg[0]]._type == 'boolean': + if arg[1] == 'in': + qu1.append('(%s.%s = false)' % \ + (table._table, arg[0])) + else: + qu1.append('(%s.%s != false)' % \ + (table._table, arg[0])) + else: + if arg[1] == 'in': + qu1.append('(%s.%s IS NULL)' % \ + (table._table, arg[0])) + else: + qu1.append('(%s.%s IS NOT NULL)' % \ + (table._table, arg[0])) else: if arg[1] == 'in': qu1.append(' false') From 236b698d2bd46f5e24ae4620eda24b0d65e3ac11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 17 Jan 2009 18:28:04 +0100 Subject: [PATCH 069/164] Handle join on the same table in order_calc --- trytond/osv/orm.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 0df8040858..9fdf3c5b67 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2827,9 +2827,20 @@ class ORM(object): if field_name: order_by, tables, tables_args = obj._order_calc(cursor, user, field_name, otype, context=context) - table_join = 'LEFT JOIN "' + table_name + '" ON ' \ - '%s.id = %s.%s' % (table_name, self._table, - link_field) + if table_name == self._table: + table_join = 'LEFT JOIN "' + table_name + '" AS ' \ + '"' + table_name + '.' + link_field + '" ON ' \ + '"%s.%s".id = %s.%s' % (table_name, link_field, + self._table, link_field) + for i in range(len(order_by)): + if table_name in order_by[i]: + order_by[i] = order_by[i].replace(table_name, + '"' + table_name + '.' + \ + link_field + '"') + else: + table_join = 'LEFT JOIN "' + table_name + '" ON ' \ + '%s.id = %s.%s' % (table_name, self._table, + link_field) if table_join not in tables: tables.insert(0, table_join) return order_by, tables, tables_args From 231aa97be5bce03088906a691f2739fe5196c8cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 20 Jan 2009 14:25:25 +0100 Subject: [PATCH 070/164] Use root user to delete, create property in set function for issue754 --- trytond/ir/property.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/trytond/ir/property.py b/trytond/ir/property.py index a9792cee58..eae10885ce 100644 --- a/trytond/ir/property.py +++ b/trytond/ir/property.py @@ -106,6 +106,12 @@ class Property(OSV): Set property value for res_id """ model_field_obj = self.pool.get('ir.model.field') + + if context is None: + context = {} + ctx = context.copy() + ctx['user'] = user + field_id = model_field_obj.search(cursor, user, [ ('name', '=', name), ('model.model', '=', model), @@ -115,7 +121,7 @@ class Property(OSV): ('field', '=', field_id), ('res', '=', model + ',' + str(res_id)), ], context=context) - self.delete(cursor, user, property_ids, context=context) + self.delete(cursor, 0, property_ids, context=ctx) default_id = self.search(cursor, user, [ ('field', '=', field_id), @@ -128,12 +134,12 @@ class Property(OSV): res = False if (val != default_val): - res = self.create(cursor, user, { + res = self.create(cursor, 0, { 'name': name, 'value': val, 'res': model + ',' + str(res_id), 'field': field_id, - }, context=context) + }, context=ctx) return res Property() From 5ebe16e148ff240ed676c07cd7dc2ce47d8bc104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 20 Jan 2009 21:21:18 +0100 Subject: [PATCH 071/164] Fix order for translation that are empty --- trytond/osv/orm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 9fdf3c5b67..4c93f5dbe4 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2891,7 +2891,8 @@ class ORM(object): if table_join not in tables: tables.append(table_join) tables_args[table_join] = [context.get('language') or 'en_US'] - order_by.append('COALESCE(' + translation_table + '.value, ' \ + order_by.append('COALESCE(NULLIF(' \ + + translation_table + '.value, \'\'), ' \ + table_name + '.' + field_name + ') ' + otype) return order_by, tables, tables_args From 8d23df699d4b79ce6dd3eb30a108600d438dea6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 21 Jan 2009 14:20:42 +0100 Subject: [PATCH 072/164] Add id in order to select views --- trytond/osv/orm.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 4c93f5dbe4..0356f17366 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2192,7 +2192,7 @@ class ORM(object): 'inherit ' \ 'FROM ir_ui_view ' \ 'WHERE model = %s AND type = %s AND inherit IS NULL ' \ - 'ORDER BY priority', + 'ORDER BY priority ASC, id ASC', (self._name,view_type)) sql_res = cursor.fetchone() if not sql_res: @@ -2211,7 +2211,8 @@ class ORM(object): # get all views which inherit from (ie modify) this view cursor.execute('SELECT arch, id FROM ir_ui_view ' \ 'WHERE inherit = %s AND model = %s ' \ - 'ORDER BY priority', (inherit_id, self._name)) + 'ORDER BY priority ASC, id ASC', + (inherit_id, self._name)) sql_inherit = cursor.fetchall() for (inherit, view_id) in sql_inherit: result = _inherit_apply(result, inherit) From 4f45098a0c2fccd248409ae996866916eb332b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 22 Jan 2009 12:17:50 +0100 Subject: [PATCH 073/164] Restart cache on fields_view_get after model access change --- trytond/ir/model.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/trytond/ir/model.py b/trytond/ir/model.py index e189881674..bd2d0c7840 100644 --- a/trytond/ir/model.py +++ b/trytond/ir/model.py @@ -142,18 +142,36 @@ class ModelAccess(OSV): res = super(ModelAccess, self).write(cursor, user, ids, vals, context=context) self.check(cursor.dbname) + # Restart the cache + for model in self.pool.object_name_list(): + try: + self.pool.get(model).fields_view_get(cursor.dbname) + except: + pass return res def create(self, cursor, user, vals, context=None): res = super(ModelAccess, self).create(cursor, user, vals, context=context) self.check(cursor.dbname) + # Restart the cache + for model in self.pool.object_name_list(): + try: + self.pool.get(model).fields_view_get(cursor.dbname) + except: + pass return res def delete(self, cursor, user, ids, context=None): res = super(ModelAccess, self).delete(cursor, user, ids, context=context) self.check(cursor.dbname) + # Restart the cache + for model in self.pool.object_name_list(): + try: + self.pool.get(model).fields_view_get(cursor.dbname) + except: + pass return res ModelAccess() From 287988437f3d8cce4db5acadbf5b36e5e65448df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 24 Jan 2009 19:48:18 +0100 Subject: [PATCH 074/164] Add missing fuzzy test in _where_calc and _order_calc for issue697 --- trytond/osv/orm.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 0356f17366..cb321c4fb8 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2627,6 +2627,7 @@ class ORM(object): query1 = '(SELECT res_id FROM ir_translation ' \ 'WHERE name = %s AND lang = %s ' \ 'AND type = %s ' \ + 'AND fuzzy = false ' \ 'AND (value ' + args[i][1] + ' %s ' \ + oper +' value ' + args[i][1] + ' %s))' query2 = [table._name + ',' + args[i][0], @@ -2885,10 +2886,12 @@ class ORM(object): '(%s.res_id = %s.id ' \ 'AND %s.name = \'%s,%s\' ' \ 'AND %s.lang = %%s ' \ - 'AND %s.type = \'model\')' % \ + 'AND %s.type = \'model\' ' \ + 'AND %s.fuzzy = false)' % \ (translation_table, translation_table, table_name, translation_table, self._name, field_name, - translation_table, translation_table) + translation_table, translation_table, + translation_table) if table_join not in tables: tables.append(table_join) tables_args[table_join] = [context.get('language') or 'en_US'] From 2b3f3ef6a8e6b3d8e02e6495a16044ccc6344881 Mon Sep 17 00:00:00 2001 From: Bertrand Chenal Date: Sun, 25 Jan 2009 00:47:00 +0100 Subject: [PATCH 075/164] xml import: Fetch the correct default value when a field belongs to the parent model of the record. --- trytond/tools/convert.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/trytond/tools/convert.py b/trytond/tools/convert.py index 42a715199b..416eca0334 100644 --- a/trytond/tools/convert.py +++ b/trytond/tools/convert.py @@ -638,8 +638,14 @@ class TrytondXmlHandler(sax.handler.ContentHandler): # we cannot update a field if it was changed by a user... if key not in old_values: - expected_value = object_ref._defaults.get( - key, lambda *a:None)(cursor, user) + if key in object_ref._inherit_fields: + parent_obj = self.pool.get( + object_ref._inherit_fields[key][0]) + expected_value = parent_obj._defaults.get( + key, lambda *a: None)(cursor, user) + else: + expected_value = object_ref._defaults.get( + key, lambda *a: None)(cursor, user) else: expected_value = old_values[key] From 0f66007beabbf409dcb7cbf26719c289b320050e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 25 Jan 2009 01:36:25 +0100 Subject: [PATCH 076/164] Use default value from base model before of inherit model for xml import --- trytond/tools/convert.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/trytond/tools/convert.py b/trytond/tools/convert.py index 416eca0334..19b5624855 100644 --- a/trytond/tools/convert.py +++ b/trytond/tools/convert.py @@ -638,13 +638,13 @@ class TrytondXmlHandler(sax.handler.ContentHandler): # we cannot update a field if it was changed by a user... if key not in old_values: - if key in object_ref._inherit_fields: - parent_obj = self.pool.get( - object_ref._inherit_fields[key][0]) - expected_value = parent_obj._defaults.get( + if key in object_ref._columns: + expected_value = object_ref._defaults.get( key, lambda *a: None)(cursor, user) else: - expected_value = object_ref._defaults.get( + inherit_obj = self.pool.get( + object_ref._inherit_fields[key][0]) + expected_value = inherit_obj._defaults.get( key, lambda *a: None)(cursor, user) else: expected_value = old_values[key] From 6e478ac281ed3f2de06219fa207b76dee2dc7abb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 26 Jan 2009 09:53:02 +0100 Subject: [PATCH 077/164] Reset cache for check and fields_view_get when writing res.user --- trytond/res/user.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/trytond/res/user.py b/trytond/res/user.py index 8e2f154e68..81e3dffbfe 100644 --- a/trytond/res/user.py +++ b/trytond/res/user.py @@ -123,6 +123,14 @@ class User(OSV): res = super(User, self).write(cursor, user, ids, vals, context=context) # Restart the cache for domain_get method self.pool.get('ir.rule').domain_get(cursor.dbname) + # Restart the cache of check + self.pool.get('ir.model.access').check(cursor.dbname) + # Restart the cache + for model in self.pool.object_name_list(): + try: + self.pool.get(model).fields_view_get(cursor.dbname) + except: + pass return res def delete(self, cursor, user, ids, context=None): From 1b59f9292a871bd1cdd2020a0f434bbecae7aa63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 27 Jan 2009 00:46:53 +0100 Subject: [PATCH 078/164] Disable by default sort on One2Many fields --- trytond/osv/orm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index cb321c4fb8..bf5a04f708 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -1939,7 +1939,8 @@ class ORM(object): if hasattr(self._columns[field], arg) \ and getattr(self._columns[field], arg): res[field][arg] = getattr(self._columns[field], arg) - if isinstance(self._columns[field], fields.Function) \ + if isinstance(self._columns[field], + (fields.Function, fields.One2Many)) \ and not self._columns[field].order_field: res[field]['sortable'] = False From dda52b2eec4773a9bdccbd57ef89b9c66e49a9a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 28 Jan 2009 12:35:05 +0100 Subject: [PATCH 079/164] Fix Modified Preorder Tree Traversal - _update_tree works if only one record has changed - can not use child_number in update but instead old_right - old_left - set old_left if the same than old_right - pre-select ids before update to prevent collision --- trytond/osv/orm.py | 130 ++++++++++++++++++++++++++++++--------------- 1 file changed, 87 insertions(+), 43 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index bf5a04f708..73888f8343 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -1413,6 +1413,20 @@ class ORM(object): return True if isinstance(ids, (int, long)): ids = [ids] + else: + # _update_tree works if only one record has changed + update_tree = False + for k in self._columns: + field = self._columns[k] + if isinstance(field, fields.Many2One) \ + and field._obj == self._name \ + and field.left and field.right: + update_tree = True + if update_tree: + for object_id in ids: + self.delete(cursor, user, object_id, context=context) + return True + if self.table_query(context): return True @@ -1498,9 +1512,11 @@ class ORM(object): for k in tree_ids.keys(): field = self._columns[k] - for object_id in tree_ids[k]: - self._update_tree(cursor, user, object_id, k, + if len(tree_ids[k]) == 1: + self._update_tree(cursor, user, tree_ids[k][0], k, field.left, field.right) + else: + self._rebuild_tree(cursor, 0, k, False, 0) return True @@ -1556,6 +1572,19 @@ class ORM(object): if isinstance(ids, (int, long)): ids = [ids] + else: + # _update_tree works if only one record has changed + update_tree = False + for k in self._columns: + field = self._columns[k] + if isinstance(field, fields.Many2One) \ + and field._obj == self._name \ + and field.left and field.right: + update_tree = True + if update_tree: + for object_id in ids: + self.write(cursor, user, object_id, vals, context=context) + return True if context.get('_timestamp', False): for i in range(0, len(ids), cursor.IN_MAX): @@ -1720,9 +1749,11 @@ class ORM(object): raise Exception('ValidateError', 'You can not update fields: ' \ '"%s", "%s"' % (field.left, field.right)) if k in vals: - for object_id in ids: + if len(ids) == 1: self._update_tree(cursor, user, object_id, k, field.left, field.right) + else: + self._rebuild_tree(cursor, 0, k, False, 0) # Restart rule cache if self.pool.get('ir.rule.group').search(cursor, 0, [ @@ -3222,54 +3253,67 @@ class ORM(object): if not cursor.rowcount: return old_left, old_right = cursor.fetchone() + if old_left == old_right: + cursor.execute('UPDATE "' + self._table + '" ' \ + 'SET "' + right + '" = "' + right + '" + 1 ' \ + 'WHERE id = %s', (object_id,)) + old_right += 1 - cursor.execute('SELECT "' + right + '" ' \ + parent_right = 1 + + cursor.execute('SELECT "' + field_name + '" ' \ 'FROM "' + self._table + '" ' \ - 'WHERE id IN (' \ - 'SELECT "' + field_name + '" FROM "' + self._table + '" ' \ - 'WHERE id = %s)', (object_id,)) - if cursor.rowcount: + 'WHERE id = %s', (object_id,)) + parent_id = cursor.fetchone()[0] or False + + if parent_id: + cursor.execute('SELECT "' + right + '" ' \ + 'FROM "' + self._table + '" ' \ + 'WHERE id = %s', (parent_id,)) parent_right = cursor.fetchone()[0] - - cursor.execute('SELECT count(1) FROM "' + self._table + '" ' \ - 'WHERE "' + left + '" >= %s AND "' + right + '" <= %s', - (old_left, old_right)) - child_number = cursor.fetchone()[0] - - cursor.execute('UPDATE "' + self._table + '" ' \ - 'SET "' + left + '" = "' + left + '" + ' \ - + str(2 * child_number) + ' ' \ - 'WHERE "' + left + '" >= %s ' \ - 'AND NOT ("' + left + '" >= %s AND ' \ - '"' + right + '" <= %s)', - (parent_right, old_left, old_right)) - cursor.execute('UPDATE "' + self._table + '" ' \ - 'SET "' + right + '" = "' + right + '" + ' \ - + str(2 * child_number) + ' ' \ - 'WHERE "' + right + '" >= %s ' \ - 'AND NOT ("' + left + '" >= %s AND ' \ - '"' + right + '" <= %s)', - (parent_right, old_left, old_right)) - - cursor.execute('UPDATE "' + self._table + '" ' \ - 'SET "' + left + '" = "' + left + '" + ' \ - + str(parent_right - old_left) + ', ' \ - '"' + right + '" = "' + right + '" + ' \ - + str(parent_right - (old_left or -1)) + ' ' \ - 'WHERE "' + left + '" >= %s AND "' + right + '" <= %s', - (old_left, old_right)) else: - max_right = 0 cursor.execute('SELECT MAX("' + right + '") ' \ 'FROM "' + self._table + '" ' \ 'WHERE "' + field_name + '" IS NULL') if cursor.rowcount: - max_right = cursor.fetchone()[0] + parent_right = cursor.fetchone()[0] + 1 + cursor.execute('SELECT id FROM "' + self._table + '" ' \ + 'WHERE "' + left + '" >= %s AND "' + right + '" <= %s', + (old_left, old_right)) + child_ids = [x[0] for x in cursor.fetchall()] + + # ids for left update + cursor.execute('SELECT id FROM "' + self._table + '" ' \ + 'WHERE "' + left + '" >= %s ' \ + 'AND id NOT IN (' + ','.join(['%s' for x in child_ids]) + ')', + [parent_right] + child_ids) + left_ids = [x[0] for x in cursor.fetchall()] + + # ids for right update + cursor.execute('SELECT id FROM "' + self._table + '" ' \ + 'WHERE "' + right + '" >= %s ' \ + 'AND id NOT IN (' + ','.join(['%s' for x in child_ids]) + ')', + [parent_right] + child_ids) + right_ids = [x[0] for x in cursor.fetchall()] + + if left_ids: cursor.execute('UPDATE "' + self._table + '" ' \ 'SET "' + left + '" = "' + left + '" + ' \ - + str(max_right + 1 - old_left) + ', ' \ - '"' + right + '" = "' + right + '" + ' \ - + str(max_right + 1 - (old_left or -1)) + ' ' \ - 'WHERE "' + left + '" >= %s AND "' + right + '" <= %s', - (old_left, old_right)) + + str(old_right - old_left + 1) + ' ' \ + 'WHERE id IN (' + ','.join(['%s' for x in left_ids]) + ')', + left_ids) + if right_ids: + cursor.execute('UPDATE "' + self._table + '" ' \ + 'SET "' + right + '" = "' + right + '" + ' \ + + str(old_right - old_left + 1) + ' ' \ + 'WHERE id IN (' + ','.join(['%s' for x in right_ids]) + ')', + right_ids) + + cursor.execute('UPDATE "' + self._table + '" ' \ + 'SET "' + left + '" = "' + left + '" + ' \ + + str(parent_right - old_left) + ', ' \ + '"' + right + '" = "' + right + '" + ' \ + + str(parent_right - old_left) + ' ' \ + 'WHERE id IN (' + ','.join(['%s' for x in child_ids]) + ')', + child_ids) From 3cf5f308261a768b203fe8272b120a0e4fc50ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 28 Jan 2009 16:00:15 +0100 Subject: [PATCH 080/164] Don't loop on id in delete for _update_tree because _rebuild_tree will be called many times. --- trytond/osv/orm.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 73888f8343..9b054580d7 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -1413,19 +1413,6 @@ class ORM(object): return True if isinstance(ids, (int, long)): ids = [ids] - else: - # _update_tree works if only one record has changed - update_tree = False - for k in self._columns: - field = self._columns[k] - if isinstance(field, fields.Many2One) \ - and field._obj == self._name \ - and field.left and field.right: - update_tree = True - if update_tree: - for object_id in ids: - self.delete(cursor, user, object_id, context=context) - return True if self.table_query(context): return True From c451aa6b36fb43985ce36ef573d4ab369f22ffb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 29 Jan 2009 19:04:58 +0100 Subject: [PATCH 081/164] Fix Cacheable to prevent attributes collision --- trytond/ir/translation.py | 3 +-- trytond/osv/osv.py | 28 +++++++++++++--------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index 04d1dc12de..4eda6ce28b 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -53,13 +53,12 @@ class Translation(OSV, Cacheable): def __init__(self): super(Translation, self).__init__() - Cacheable.__init__(self) self._sql_constraints += [ ('translation_uniq', 'UNIQUE (name, res_id, lang, type, src, module)', 'Translation must be unique'), ] - self.max_len = 10240 + self._max_len = 10240 def _auto_init(self, cursor, module_name): super(Translation, self)._auto_init(cursor, module_name) diff --git a/trytond/osv/osv.py b/trytond/osv/osv.py index cdac5a43af..40caeea829 100644 --- a/trytond/osv/osv.py +++ b/trytond/osv/osv.py @@ -201,21 +201,19 @@ class Cacheable(object): def __init__(self): super(Cacheable, self).__init__() self._cache = {} - self.name = self._table - self.timestamp = None - self.max_len = 1024 - self.timeout = 3600 - self.lock = Lock() + self._max_len = 1024 + self._timeout = 3600 + self._lock = Lock() Cache._cache_instance.append(self) def add(self, cursor, key, value): - self.lock.acquire() + self._lock.acquire() try: self._cache.setdefault(cursor.dbname, {}) lower = None - if len(self._cache[cursor.dbname]) > self.max_len: - mintime = time.time() - self.timeout + if len(self._cache[cursor.dbname]) > self._max_len: + mintime = time.time() - self._timeout for key2 in self._cache[cursor.dbname].keys(): last_time = self._cache[cursor.dbname][key2][1] if mintime > last_time: @@ -223,19 +221,19 @@ class Cacheable(object): else: if not lower or lower[1] > last_time: lower = (key2, last_time) - if len(self._cache[cursor.dbname]) > self.max_len and lower: + if len(self._cache[cursor.dbname]) > self._max_len and lower: del self._cache[cursor.dbname][lower[0]] self._cache[cursor.dbname][key] = (value, time.time()) finally: - self.lock.release() + self._lock.release() def invalidate(self, cursor, key): - self.lock.acquire() + self._lock.acquire() try: del self._cache[cursor.dbname][key] finally: - self.lock.release() + self._lock.release() def get(self, cursor, key): try: @@ -244,10 +242,10 @@ class Cacheable(object): return None def clear(self, cursor): - self.lock.acquire() + self._lock.acquire() try: self._cache.setdefault(cursor.dbname, {}) self._cache[cursor.dbname].clear() - Cache.reset(cursor.dbname, self.name) + Cache.reset(cursor.dbname, self._name) finally: - self.lock.release() + self._lock.release() From b5268b0b8bde4e63c9f2c74ab698439a5e4d4fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 30 Jan 2009 17:31:52 +0100 Subject: [PATCH 082/164] Use template0 when restoring database --- trytond/web_service/db.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/web_service/db.py b/trytond/web_service/db.py index cb077313cd..742007e3da 100644 --- a/trytond/web_service/db.py +++ b/trytond/web_service/db.py @@ -148,7 +148,8 @@ class DB(Service): database = sql_db.db_connect('template1') cursor = database.cursor() cursor.conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) - cursor.execute('CREATE DATABASE "' + db_name + '" ENCODING \'unicode\'') + cursor.execute('CREATE DATABASE "' + db_name + '" ' \ + 'TEMPLATE template0 ENCODING \'unicode\'') cursor.commit() cursor.close() From 7e2d65bef8b47accc719e71fb3c768704589cfb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 3 Feb 2009 18:46:30 +0100 Subject: [PATCH 083/164] Fix tree view of res.request.link --- trytond/res/request.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/res/request.xml b/trytond/res/request.xml index 79b0c15a32..996c1f8333 100644 --- a/trytond/res/request.xml +++ b/trytond/res/request.xml @@ -115,7 +115,7 @@ - + ]]> From 6f9aec1b50beffd11c94423dfa0888345737069d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 3 Feb 2009 18:56:17 +0100 Subject: [PATCH 084/164] Use unicode instead of str to format wrong queries --- trytond/sql_db.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/sql_db.py b/trytond/sql_db.py index 17e11efa93..ed94e69f8e 100644 --- a/trytond/sql_db.py +++ b/trytond/sql_db.py @@ -73,7 +73,8 @@ class FakeCursor(object): res = self.cursor.execute(sql) except: logger = logging.getLogger('sql') - logger.error('Wrong SQL: ' + sql % tuple("'%s'" % x for x in params or [])) + logger.error('Wrong SQL: ' + sql % tuple("'%s'" % unicode(x) + for x in params or [])) raise if self.sql_log: self.count += 1 From 6687affff0bdc2ad5ff6ede3a22f5e427b05ecdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 3 Feb 2009 22:11:26 +0100 Subject: [PATCH 085/164] Force __init__ of Cacheable --- trytond/ir/translation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index 4eda6ce28b..a161639260 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -53,6 +53,7 @@ class Translation(OSV, Cacheable): def __init__(self): super(Translation, self).__init__() + Cacheable.__init__(self) self._sql_constraints += [ ('translation_uniq', 'UNIQUE (name, res_id, lang, type, src, module)', From c9b5332f764703815d0fe8c19bd745a70cc92685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 3 Feb 2009 22:29:21 +0100 Subject: [PATCH 086/164] Fix search in reference to allow inactive records --- trytond/osv/fields.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/trytond/osv/fields.py b/trytond/osv/fields.py index 4af51e332b..baed2e1c59 100644 --- a/trytond/osv/fields.py +++ b/trytond/osv/fields.py @@ -125,6 +125,8 @@ class Reference(Column): def get(self, cursor, obj, ids, name, user=None, offset=0, context=None, values=None): + if context is None: + context = {} if values is None: values = {} res = {} @@ -150,10 +152,12 @@ class Reference(Column): ref_id = int(ref_id) except: continue + ctx = context.copy() + ctx['active_test'] = False if ref_id \ and not ref_obj.search(cursor, user, [ ('id', '=', ref_id), - ], context=context): + ], context=ctx): ref_id = False if ref_id: ref_name = ref_obj.name_get(cursor, user, ref_id, From b7bc059787a61082f2f63090380bb84bb82bd826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 4 Feb 2009 15:34:03 +0100 Subject: [PATCH 087/164] Use cursor query to display wrong SQL --- trytond/sql_db.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/trytond/sql_db.py b/trytond/sql_db.py index ed94e69f8e..c251c509b5 100644 --- a/trytond/sql_db.py +++ b/trytond/sql_db.py @@ -73,8 +73,7 @@ class FakeCursor(object): res = self.cursor.execute(sql) except: logger = logging.getLogger('sql') - logger.error('Wrong SQL: ' + sql % tuple("'%s'" % unicode(x) - for x in params or [])) + logger.error('Wrong SQL: ' + self.cursor.query) raise if self.sql_log: self.count += 1 From 3bde4ab6c71ebd1ce786bf7dd519dbdd6c9febc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 6 Feb 2009 10:09:07 +0100 Subject: [PATCH 088/164] Fix typo for issue769 --- trytond/osv/orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 9b054580d7..8b06cda459 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -1737,7 +1737,7 @@ class ORM(object): '"%s", "%s"' % (field.left, field.right)) if k in vals: if len(ids) == 1: - self._update_tree(cursor, user, object_id, k, + self._update_tree(cursor, user, ids[0], k, field.left, field.right) else: self._rebuild_tree(cursor, 0, k, False, 0) From 287fa381fd3ea137f41b6edcc1500e408ea77ff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 11 Feb 2009 12:23:56 +0100 Subject: [PATCH 089/164] Fix typo --- trytond/webdavsvc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/webdavsvc.py b/trytond/webdavsvc.py index 062b090cf9..75bfa0932b 100644 --- a/trytond/webdavsvc.py +++ b/trytond/webdavsvc.py @@ -311,7 +311,7 @@ class WebDAVAuthRequestHandler(AuthServer.BufferedAuthRequestHandler, return 1 USER_ID = security.login(dbname, user, password, cache=False) Cache.clean(dbname) - Cache.resets(database) + Cache.resets(dbname) if int(USER_ID): return 1 return 0 From 2e3f8d7b5e1118361e0165dc94c841aa054ff566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 11 Feb 2009 19:02:52 +0100 Subject: [PATCH 090/164] join ir.cron threads on SIGTERM for issue604 --- trytond/server.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/trytond/server.py b/trytond/server.py index 08a19b0caa..ffc348aa0f 100644 --- a/trytond/server.py +++ b/trytond/server.py @@ -209,6 +209,8 @@ class TrytonServer(object): (CONFIG['secure_webdav'] and ' Secure' or '') + \ ' service, port ' + str(port)) + threads = [] + def handler(signum, frame): if hasattr(signal, 'SIGUSR1'): if signum == signal.SIGUSR1: @@ -223,6 +225,8 @@ class TrytonServer(object): webdavd.stop() if CONFIG['pidfile']: os.unlink(CONFIG['pidfile']) + for thread in threads: + thread.join() logging.shutdown() sys.exit(0) @@ -263,9 +267,13 @@ class TrytonServer(object): target=cron_obj.pool_jobs, args=(dbname,), kwargs={}) thread.start() + threads.append(thread) if time.time() - now >= 60: now = time.time() time.sleep(1) + for thread in threads[:]: + if not thread.isAlive(): + threads.remove(thread) if __name__ == "__main__": SERVER = TrytonServer() From ba39f84236555229bcb6d14318827797995230ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 11 Feb 2009 19:13:49 +0100 Subject: [PATCH 091/164] Fix client thread stop with psyco enabled --- trytond/netsvc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/trytond/netsvc.py b/trytond/netsvc.py index c4fd3e2074..3f7dab2799 100644 --- a/trytond/netsvc.py +++ b/trytond/netsvc.py @@ -351,6 +351,7 @@ class TinySocketServerThread(threading.Thread): try: thread = self.threads[0] thread.stop() + time.sleep(0.001) #sleep to let thread running except: pass try: From 98ff9bc848018119eb6212ddf7c28b72e00673de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 12 Feb 2009 11:55:19 +0100 Subject: [PATCH 092/164] Fix _update_tree to take care of IN_MAX for issue771 --- trytond/osv/orm.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 8b06cda459..2c00eaf63c 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -3270,6 +3270,9 @@ class ORM(object): (old_left, old_right)) child_ids = [x[0] for x in cursor.fetchall()] + if len(child_ids) > cursor.IN_MAX: + return self._rebuild_tree(cursor, 0, field_name, False, 0) + # ids for left update cursor.execute('SELECT id FROM "' + self._table + '" ' \ 'WHERE "' + left + '" >= %s ' \ @@ -3285,17 +3288,21 @@ class ORM(object): right_ids = [x[0] for x in cursor.fetchall()] if left_ids: - cursor.execute('UPDATE "' + self._table + '" ' \ - 'SET "' + left + '" = "' + left + '" + ' \ - + str(old_right - old_left + 1) + ' ' \ - 'WHERE id IN (' + ','.join(['%s' for x in left_ids]) + ')', - left_ids) + for i in range(0, len(left_ids), cursor.IN_MAX): + sub_ids = left_ids[i:i + cursor.IN_MAX] + str_d = ','.join(('%s',) * len(sub_ids)) + cursor.execute('UPDATE "' + self._table + '" ' \ + 'SET "' + left + '" = "' + left + '" + ' \ + + str(old_right - old_left + 1) + ' ' \ + 'WHERE id IN (' + str_d + ')', sub_ids) if right_ids: - cursor.execute('UPDATE "' + self._table + '" ' \ - 'SET "' + right + '" = "' + right + '" + ' \ - + str(old_right - old_left + 1) + ' ' \ - 'WHERE id IN (' + ','.join(['%s' for x in right_ids]) + ')', - right_ids) + for i in range(0, len(right_ids), cursor.IN_MAX): + sub_ids = right_ids[i:i + cursor.IN_MAX] + str_d = ','.join(('%s',) * len(sub_ids)) + cursor.execute('UPDATE "' + self._table + '" ' \ + 'SET "' + right + '" = "' + right + '" + ' \ + + str(old_right - old_left + 1) + ' ' \ + 'WHERE id IN (' + str_d + ')', sub_ids) cursor.execute('UPDATE "' + self._table + '" ' \ 'SET "' + left + '" = "' + left + '" + ' \ From f78da0ff1e096ebd746ccd9c819bc8313eb5554a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 12 Feb 2009 19:27:57 +0100 Subject: [PATCH 093/164] Use at any time base64 encoding data for report_content and style_content --- trytond/ir/action.py | 7 +++++-- trytond/report/report.py | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/trytond/ir/action.py b/trytond/ir/action.py index 1e78a1bc21..68b64553c5 100644 --- a/trytond/ir/action.py +++ b/trytond/ir/action.py @@ -3,6 +3,7 @@ "Action" from trytond.osv import fields, OSV from trytond.tools import file_open +import base64 class Action(OSV): @@ -263,7 +264,8 @@ class ActionReport(OSV): data = report[name + '_data'] if not data and report[name[:-8]]: try: - data = file_open(report[name[:-8]], mode='rb').read() + data = base64.encodestring(file_open(report[name[:-8]], + mode='rb').read()) except: data = False res[report.id] = data @@ -277,7 +279,8 @@ class ActionReport(OSV): res = {} for report in self.browse(cursor, user, ids, context=context): try: - data = file_open(report.style, mode='rb').read() + data = base64.encodestring(file_open(report.style, + mode='rb').read()) except: data = False res[report.id] = data diff --git a/trytond/report/report.py b/trytond/report/report.py index 4c8c56f252..a7b7ea0376 100644 --- a/trytond/report/report.py +++ b/trytond/report/report.py @@ -245,7 +245,7 @@ class Report(object): outzip = zipfile.ZipFile(path, mode='w') content_io = StringIO.StringIO() - content_io.write(report.report_content) + content_io.write(base64.decodestring(report.report_content)) content_z = zipfile.ZipFile(content_io, mode='r') style_info = None @@ -265,7 +265,7 @@ class Report(object): #cStringIO difference: #calling StringIO() with a string parameter creates a read-only object style2_io = StringIO.StringIO() - style2_io.write(report.style_content) + style2_io.write(base64.decodestring(report.style_content)) style2_z = zipfile.ZipFile(style2_io, mode='r') style2_xml = style2_z.read('styles.xml') for file in style2_z.namelist(): From fff695002b71678080275be5de20ec321496e6b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 18 Feb 2009 19:48:29 +0100 Subject: [PATCH 094/164] Fix add_null in SQL query for issue795 --- trytond/osv/orm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 2c00eaf63c..19369760ed 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2799,7 +2799,8 @@ class ORM(object): (table._table, arg[0], arg[1], arg[2])) if add_null: - qu1[-1] = '('+qu1[-1]+' OR '+arg[0]+' is null)' + qu1[-1] = '(' + qu1[-1] + ' OR ' + \ + table._table + '.' + arg[0] +' IS NULL)' return qu1, qu2 From a0e83ab13da39f9d899164c1d528cf91823ba846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 19 Feb 2009 13:54:23 +0100 Subject: [PATCH 095/164] Use os separator in filename when calling file_open --- trytond/ir/action.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/trytond/ir/action.py b/trytond/ir/action.py index 68b64553c5..6991d68b12 100644 --- a/trytond/ir/action.py +++ b/trytond/ir/action.py @@ -4,6 +4,7 @@ from trytond.osv import fields, OSV from trytond.tools import file_open import base64 +import os class Action(OSV): @@ -264,7 +265,8 @@ class ActionReport(OSV): data = report[name + '_data'] if not data and report[name[:-8]]: try: - data = base64.encodestring(file_open(report[name[:-8]], + data = base64.encodestring(file_open( + report[name[:-8]].replace('/', os.sep), mode='rb').read()) except: data = False @@ -279,7 +281,8 @@ class ActionReport(OSV): res = {} for report in self.browse(cursor, user, ids, context=context): try: - data = base64.encodestring(file_open(report.style, + data = base64.encodestring(file_open( + report.style.replace('/', os.sep), mode='rb').read()) except: data = False From bf2b2cea2ca209e9fc3123642072c3d4e26173c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 19 Feb 2009 13:54:55 +0100 Subject: [PATCH 096/164] Clause temporary file before remove it --- trytond/report/report.py | 1 + 1 file changed, 1 insertion(+) diff --git a/trytond/report/report.py b/trytond/report/report.py index a7b7ea0376..ae9d4a0aa8 100644 --- a/trytond/report/report.py +++ b/trytond/report/report.py @@ -309,6 +309,7 @@ class Report(object): data = rel_report(**localcontext).render() if hasattr(data, 'getvalue'): data = data.getvalue() + os.close(fd) os.remove(path) output_format = report.output_format.format if output_format == 'pdf': From 449d4ecf9b203d759571871956587433098c751f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 26 Feb 2009 20:03:32 +0100 Subject: [PATCH 097/164] Encode label for pydot into ascii --- trytond/workflow/workflow.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/trytond/workflow/workflow.py b/trytond/workflow/workflow.py index d165aa673d..a6ada07ec3 100644 --- a/trytond/workflow/workflow.py +++ b/trytond/workflow/workflow.py @@ -237,7 +237,7 @@ class InstanceGraph(Report): context=context) instance_id = instance_id[0] - title = "Workflow: %s" % (workflow.name,) + title = "Workflow: %s" % (workflow.name.encode('ascii', 'replace'),) if pydot.__version__ == '1.0.2': # version 1.0.2 doesn't quote correctly label on Dot object title = '"' + title + '"' @@ -313,7 +313,8 @@ class InstanceGraph(Report): workflow = workflow_obj.browse(cursor, user, activity.subflow.id, context=context) subgraph = pydot.Cluster('subflow' + str(workflow.id), - fontsize='12', label="Subflow: " + activity.name) + fontsize='12', + label="Subflow: " + activity.name.encode('ascii', 'replace')) (substart, substop) = self.graph_get(cursor, user, subgraph, workflow.id, nested, workitem, context=context) @@ -322,7 +323,7 @@ class InstanceGraph(Report): actto[activity.id] = substop else: args = {} - args['label'] = activity.name + args['label'] = activity.name.encode('ascii', 'replace') args['fontsize'] = '10' if activity.flow_start or activity.flow_stop: args['style'] = 'filled' From d6c0a3195b6143c57751e72ba5d4dc36c8b04337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 2 Mar 2009 09:59:01 +0100 Subject: [PATCH 098/164] Prepare changelog for release 1.0.3 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 2574a05c55..bbd390989d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 1.0.3 - 2009-03-02 +* Some bug fixes (see mercurial logs for details) + Version 1.0.2 - 2008-01-06 * Some bug fixes (see mercurial logs for details) From 40e14369fea6f7812a0e726d7f3bd0b3e3b33482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 2 Mar 2009 10:00:05 +0100 Subject: [PATCH 099/164] Added tag 1.0.3 for changeset 8ee21b527f3d --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 8a199cd472..e998237b69 100644 --- a/.hgtags +++ b/.hgtags @@ -1,3 +1,4 @@ 951bb3311b916cb893adc5294cfb3216d2940169 1.0.0 eeb6a351bc3e82fd856161c01c8add6a4b7d5e66 1.0.1 6f52a2f6328837727c65eeb5ddf2de0c146e33a9 1.0.2 +8ee21b527f3de386af4f0822f5f575c9f66f90c6 1.0.3 From 3d66b5cd5fcbf19de020db6e4f3bc0d01a316e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 2 Mar 2009 10:04:50 +0100 Subject: [PATCH 100/164] Increase version number --- doc/conf.py | 2 +- trytond/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 31678f36d8..0e8c6cf5cd 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -46,7 +46,7 @@ copyright = '2008, B2CK' # The short X.Y version. version = '1.0' # The full version, including alpha/beta/rc tags. -release = '1.0.3' +release = '1.0.4' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: diff --git a/trytond/version.py b/trytond/version.py index ef3033a743..f4028ef7df 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.0.3" +VERSION = "1.0.4" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 6508d29486c71ef7e6de99e8ae566c65b58e0f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 5 Mar 2009 19:43:10 +0100 Subject: [PATCH 101/164] Fix default value for _context in BrowseRecord --- trytond/osv/orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 19369760ed..cc0b2a77f3 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -95,7 +95,7 @@ class BrowseRecord(object): self._id = object_id self._table = table self._table_name = self._table._name - self._context = context + self._context = context or {} self._language_cache = {} cache.setdefault(table._name, {}) From cdcf3961563d8cf433cf882bd04fac440a9666b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 11 Mar 2009 01:05:57 +0100 Subject: [PATCH 102/164] Fix logger when self.cursor.query is None --- trytond/sql_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/sql_db.py b/trytond/sql_db.py index c251c509b5..bc776b6657 100644 --- a/trytond/sql_db.py +++ b/trytond/sql_db.py @@ -73,7 +73,7 @@ class FakeCursor(object): res = self.cursor.execute(sql) except: logger = logging.getLogger('sql') - logger.error('Wrong SQL: ' + self.cursor.query) + logger.error('Wrong SQL: ' + (self.cursor.query or '')) raise if self.sql_log: self.count += 1 From 5153bc9e94439d7be062748f1c6657fae97cbd28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 23 Mar 2009 18:34:15 +0100 Subject: [PATCH 103/164] Don't call search with all arguments as we don't know the operator --- trytond/osv/orm.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index cc0b2a77f3..d6ac41b487 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2433,12 +2433,6 @@ class ORM(object): 'doesn\'t work on "%s"' % (args[i][0], self._name)) if field._properties: arg = [args.pop(i)] - j = i - while j < len(args): - if args[j][0] == arg[0][0]: - arg.append(args.pop(j)) - else: - j += 1 if field._fnct_search: args.extend(field.search(cursor, user, table, arg[0][0], arg, context=context)) From 25482fa0e650c34835c55ca3e7fcf104a0a96940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 27 Mar 2009 11:54:34 +0100 Subject: [PATCH 104/164] Enforce uniq name of table alias in join for order statements --- trytond/osv/orm.py | 85 ++++++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index d6ac41b487..0a78a46fac 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2843,20 +2843,21 @@ class ORM(object): if field_name: order_by, tables, tables_args = obj._order_calc(cursor, user, field_name, otype, context=context) - if table_name == self._table: - table_join = 'LEFT JOIN "' + table_name + '" AS ' \ - '"' + table_name + '.' + link_field + '" ON ' \ - '"%s.%s".id = %s.%s' % (table_name, link_field, - self._table, link_field) - for i in range(len(order_by)): - if table_name in order_by[i]: - order_by[i] = order_by[i].replace(table_name, - '"' + table_name + '.' + \ - link_field + '"') - else: - table_join = 'LEFT JOIN "' + table_name + '" ON ' \ - '%s.id = %s.%s' % (table_name, self._table, - link_field) + table_join = 'LEFT JOIN "' + table_name + '" AS ' \ + '"' + table_name + '.' + link_field + '" ON ' \ + '"%s.%s".id = "%s".%s' % (table_name, link_field, + self._table, link_field) + for i in range(len(order_by)): + if table_name in order_by[i]: + order_by[i] = order_by[i].replace(table_name, + table_name + '.' + link_field) + for i in range(len(tables)): + if table_name in tables[i]: + args = tables_args[tables[i]] + del tables_args[tables[i]] + tables[i] = tables[i].replace(table_name, + table_name + '.' + link_field) + tables_args[tables[i]] = args if table_join not in tables: tables.insert(0, table_join) return order_by, tables, tables_args @@ -2878,15 +2879,41 @@ class ORM(object): order_by, tables, tables_args = obj2._order_calc(cursor, user, field_name, otype, context=context) - table_join = 'LEFT JOIN "' + table_name + '" ON ' \ - '%s.id = %s.%s' % \ - (table_name, self._table, link_field) + table_join = 'LEFT JOIN "' + table_name + '" AS ' \ + '"' + table_name + '.' + link_field + '" ON ' \ + '"%s.%s".id = "%s".%s' % \ + (table_name, link_field, self._table, link_field) + for i in range(len(order_by)): + if table_name in order_by[i]: + order_by[i] = order_by[i].replace(table_name, + table_name + '.' + link_field) + for i in range(len(tables)): + if table_name in tables[i]: + args = tables_args[tables[i]] + del tables_args[tables[i]] + tables[i] = tables[i].replace(table_name, + table_name + '.' + link_field) + tables_args[tables[i]] = args if table_join not in tables: tables.insert(0, table_join) - table_join2 = 'LEFT JOIN "' + table_name2 + '" ON ' \ - '%s.id = %s.%s' % \ - (table_name2, obj._table, link_field2) + table_join2 = 'LEFT JOIN "' + table_name2 + '" AS ' \ + '"' + table_name2 + '.' + link_field2 + '" ON ' \ + '"%s.%s".id = "%s.%s".%s' % \ + (table_name2, link_field2, table_name, link_field, + link_field2) + for i in range(len(order_by)): + if table_name2 in order_by[i]: + order_by[i] = order_by[i].replace(table_name2, + table_name2 + '.' + link_field2) + for i in range(len(tables)): + if table_name2 in tables[i]: + args = tables_args[tables[i]] + del tables_args[tables[i]] + tables[i] = tables[i].replace(table_name2, + table_name2 + '.' + link_field2) + tables_args[tables[i]] = args + if table_join2 not in tables: tables.insert(1, table_join2) return order_by, tables, tables_args @@ -2897,11 +2924,11 @@ class ORM(object): (table_name, field_name) table_join = 'LEFT JOIN "ir_translation" ' \ 'AS "%s" ON ' \ - '(%s.res_id = %s.id ' \ - 'AND %s.name = \'%s,%s\' ' \ - 'AND %s.lang = %%s ' \ - 'AND %s.type = \'model\' ' \ - 'AND %s.fuzzy = false)' % \ + '("%s".res_id = "%s".id ' \ + 'AND "%s".name = \'%s,%s\' ' \ + 'AND "%s".lang = %%s ' \ + 'AND "%s".type = \'model\' ' \ + 'AND "%s".fuzzy = false)' % \ (translation_table, translation_table, table_name, translation_table, self._name, field_name, translation_table, translation_table, @@ -2910,8 +2937,8 @@ class ORM(object): tables.append(table_join) tables_args[table_join] = [context.get('language') or 'en_US'] order_by.append('COALESCE(NULLIF(' \ - + translation_table + '.value, \'\'), ' \ - + table_name + '.' + field_name + ') ' + otype) + + '"' + translation_table + '".value, \'\'), ' \ + + '"' + table_name + '".' + field_name + ') ' + otype) return order_by, tables, tables_args if field_name in self._columns \ @@ -2936,7 +2963,7 @@ class ORM(object): 'order': otype, }) else: - order_by.append(table_name + '.' + field_name + ' ' + otype) + order_by.append('"' + table_name + '".' + field_name + ' ' + otype) return order_by, tables, tables_args if field in self._inherit_fields.keys(): @@ -2946,7 +2973,7 @@ class ORM(object): order_by, tables, tables_args = obj._order_calc(cursor, user, field, otype, context=context) table_join = 'LEFT JOIN "' + table_name + '" ON ' \ - '%s.id = %s.%s' % \ + '"%s".id = "%s".%s' % \ (table_name, self._table, link_field) if table_join not in tables: tables.insert(0, table_join) From 804d467ce39a55be2393baf83a82565a9aa6443a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 29 Mar 2009 17:38:54 +0200 Subject: [PATCH 105/164] Remove str on exception and use traceback.format_exception for issue909 --- trytond/tools/convert.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/trytond/tools/convert.py b/trytond/tools/convert.py index 19b5624855..f33f2a2e41 100644 --- a/trytond/tools/convert.py +++ b/trytond/tools/convert.py @@ -17,6 +17,8 @@ from decimal import Decimal import datetime import time import logging +import traceback +import sys CDATA_START = re.compile('^\s*\<\!\[cdata\[', re.IGNORECASE) CDATA_END = re.compile('\]\]\>\s*$', re.IGNORECASE) @@ -889,6 +891,8 @@ def post_import(cursor, pool, module, to_delete): cursor.commit() except Exception, exception: cursor.rollback() + tb_s = reduce(lambda x, y: x + y, + traceback.format_exception(*sys.exc_info())) logging.getLogger("init").error( 'Could not delete id: %d of model %s\n' \ 'There should be some relation ' \ @@ -896,7 +900,7 @@ def post_import(cursor, pool, module, to_delete): 'You should manually fix this ' \ 'and restart --update=module\n' \ 'Exception: %s' % \ - (db_id, model, str(exception))) + (db_id, model, tb_s.decode('utf-8', 'ignore'))) transition_obj = pool.get('workflow.transition') for mdata_id, db_id in transition_delete: From d204f2928dc7470a5513c6e8267de1e6eed7598b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 30 Mar 2009 10:20:31 +0200 Subject: [PATCH 106/164] Fix "not like" and "not ilike" operator for issue423 Security fix SQL injection --- trytond/osv/orm.py | 59 +++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 0a78a46fac..f8c1cfb89c 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2757,45 +2757,40 @@ class ORM(object): qu2.append(arg[2]) else: add_null = False - if arg[1] in ('like', 'ilike', 'not like', 'not ilike'): - qu2.append('%% %s%%' % arg[2]) - qu2.append('%s%%' % arg[2]) + if arg[1] in ('like', 'ilike'): if not arg[2]: - add_null = True + qu2.append('%') + qu2.append('%') + add_null = ' AND ' + else: + qu2.append('%% %s%%' % arg[2]) + qu2.append('%s%%' % arg[2]) + elif arg[1] in ('not like', 'not ilike'): + if not arg[2]: + qu2.append('') + qu2.append('') + else: + qu2.append('%% %s%%' % arg[2]) + qu2.append('%s%%' % arg[2]) + add_null = ' OR ' else: if arg[0] in table._columns: qu2.append(table._columns[arg[0]].\ _symbol_set[1](arg[2])) - if arg[0] in table._columns: - if arg[1] in ('like', 'ilike'): - qu1.append('(%s.%s %s %s OR %s.%s %s %s)' % \ - (table._table, arg[0], arg[1], '%s', - table._table, arg[0], arg[1], '%s')) - elif arg[1] in ('not like', 'not ilike'): - qu1.append('(%s.%s %s %s AND %s.%s %s %s)' % \ - (table._table, arg[0], arg[1], '%s', - table._table, arg[0], arg[1], '%s')) - else: - qu1.append('(%s.%s %s %s)' % (table._table, - arg[0], arg[1], - table._columns[arg[0]]._symbol_set[0])) + if arg[1] in ('like', 'ilike'): + qu1.append('("%s".%s %s %s OR "%s".%s %s %s)' % \ + (table._table, arg[0], arg[1], '%s', + table._table, arg[0], arg[1], '%s')) + elif arg[1] in ('not like', 'not ilike'): + qu1.append('("%s".%s %s %s AND "%s".%s %s %s)' % \ + (table._table, arg[0], arg[1], '%s', + table._table, arg[0], arg[1], '%s')) else: - if arg[1] in ('like', 'ilike'): - qu1.append('(%s.%s %s \'%s\' or %s.%s %s \'%s\')' % \ - (table._table, arg[0], arg[1], arg[2], - table._table, arg[0], arg[1], arg[2])) - elif arg[1] in ('not like', 'not ilike'): - qu1.append('(%s.%s %s \'%s\' and %s.%s %s \'%s\')' % \ - (table._table, arg[0], arg[1], arg[2], - table._table, arg[0], arg[1], arg[2])) - else: - qu1.append('(%s.%s %s \'%s\')' % \ - (table._table, arg[0], arg[1], arg[2])) - + qu1.append('("%s".%s %s %%s)' % (table._table, + arg[0], arg[1])) if add_null: - qu1[-1] = '(' + qu1[-1] + ' OR ' + \ - table._table + '.' + arg[0] +' IS NULL)' - + qu1[-1] = '(' + qu1[-1] + add_null + \ + '"' + table._table + '".' + arg[0] +' IS NULL)' return qu1, qu2 def search_count(self, cursor, user, args, context=None): From 29bf103648313be3d0c15993b855ac3a106adcfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 30 Mar 2009 10:40:40 +0200 Subject: [PATCH 107/164] Use 'OR' for 'IS NULL' clause with 'like' operator --- trytond/osv/orm.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index f8c1cfb89c..b45eb11977 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2761,7 +2761,7 @@ class ORM(object): if not arg[2]: qu2.append('%') qu2.append('%') - add_null = ' AND ' + add_null = True else: qu2.append('%% %s%%' % arg[2]) qu2.append('%s%%' % arg[2]) @@ -2772,7 +2772,7 @@ class ORM(object): else: qu2.append('%% %s%%' % arg[2]) qu2.append('%s%%' % arg[2]) - add_null = ' OR ' + add_null = True else: if arg[0] in table._columns: qu2.append(table._columns[arg[0]].\ @@ -2789,7 +2789,7 @@ class ORM(object): qu1.append('("%s".%s %s %%s)' % (table._table, arg[0], arg[1])) if add_null: - qu1[-1] = '(' + qu1[-1] + add_null + \ + qu1[-1] = '(' + qu1[-1] + ' OR ' + \ '"' + table._table + '".' + arg[0] +' IS NULL)' return qu1, qu2 From 1e0de32aabb58c2faf540a65cae0f7ac67e4561f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 3 Apr 2009 23:30:33 +0200 Subject: [PATCH 108/164] Fix get_module_list if there is no pkg_resources --- trytond/modules/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/trytond/modules/__init__.py b/trytond/modules/__init__.py index 776b5086c9..c82334b396 100644 --- a/trytond/modules/__init__.py +++ b/trytond/modules/__init__.py @@ -286,9 +286,7 @@ def get_module_list(): module_list.add(file) elif file[-4:] == '.zip': module_list.add(file) - for ep in pkg_resources.iter_entry_points('trytond.modules'): - mod_name = ep.module_name.split('.')[-1] - module_list.add(mod_name) + module_list.update(EGG_MODULES.keys()) module_list.add('ir') module_list.add('workflow') module_list.add('res') From 720c3510497bbd2f4d66f0eb2f3ead2ed2ea0607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 7 Apr 2009 19:22:11 +0200 Subject: [PATCH 109/164] Add domain to act_to of request because active_test is in the context for issue945 --- trytond/res/request.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/trytond/res/request.py b/trytond/res/request.py index a91704873c..1f8bcf3f90 100644 --- a/trytond/res/request.py +++ b/trytond/res/request.py @@ -35,10 +35,11 @@ class Request(OSV): act_from = fields.Many2One('res.user', 'From', required=True, readonly=True) act_to = fields.Many2One('res.user', 'To', required=True, - states={ - 'readonly': "(state in ('waiting', 'closed')) or " \ - "(state == 'chatting' and act_from != _user)", - }) + domain=[('active', '=', True)], + states={ + 'readonly': "(state in ('waiting', 'closed')) or " \ + "(state == 'chatting' and act_from != _user)", + }) body = fields.Text('Body', states={ 'readonly': "(state in ('waiting', 'closed')) or " \ "(state == 'chatting' and act_from != _user)", From 7203655bd7dbfd7ab533ecd39c057b592c6389fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 7 Apr 2009 20:22:22 +0200 Subject: [PATCH 110/164] Use model browse for models_get for issue949 --- trytond/res/request.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/trytond/res/request.py b/trytond/res/request.py index 1f8bcf3f90..c892ffdee7 100644 --- a/trytond/res/request.py +++ b/trytond/res/request.py @@ -174,8 +174,11 @@ class RequestLink(OSV): return 5 def models_get(self, cursor, user, context=None): - cursor.execute('SELECT model, name FROM ir_model ORDER BY name ASC') - res = cursor.fetchall() + model_obj = self.pool.get('ir.model') + model_ids = model_obj.search(cursor, user, [], context=context) + res = [] + for model in model_obj.browse(cursor, user, model_ids, context=context): + res.append((model.model, model.name)) return res RequestLink() From 6799bf1d21d33cd22e30db406adfb3e31cbcf027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 7 Apr 2009 22:07:32 +0200 Subject: [PATCH 111/164] Fix set_default to use the right field and add missing domain on field for issue947 --- trytond/ir/default.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/ir/default.py b/trytond/ir/default.py index 6c08a0b9ea..db6898edd8 100644 --- a/trytond/ir/default.py +++ b/trytond/ir/default.py @@ -15,7 +15,7 @@ class Default(OSV): model = fields.Many2One('ir.model', 'Model', required=True, ondelete='cascade') field = fields.Many2One('ir.model.field', 'Field', required=True, - ondelete='cascade') + ondelete='cascade', domain="[('model', '=', model)]") value = fields.Text('Value') clause = fields.Text('Clause') user = fields.Many2One('res.user', 'User', ondelete='cascade') @@ -78,6 +78,7 @@ class Default(OSV): ], context=context)[0] field_id = field_obj.search(cursor, user, [ ('name', '=', field), + ('model', '=', model_id), ], context=context)[0] default_ids = self.search(cursor, user, [ ('model', '=', model_id), From 8f68668793f3fe8449e3634952f90307dc2d3d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 9 Apr 2009 11:43:00 +0200 Subject: [PATCH 112/164] Validate with the context user if user is root --- trytond/osv/orm.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index b45eb11977..24278357e2 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -1186,6 +1186,12 @@ class ORM(object): def _validate(self, cursor, user, ids, context=None): if context is None: context = {} + + if user == 0 and context.get('user'): + ctx = context.copy() + del ctx['user'] + return self._validate(cursor, context['user'], ids, context=ctx) + context = context.copy() field_error = [] field_err_str = [] From d4b03af8a20ed3f56c443248ee92ce11801d111b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 19 Apr 2009 14:08:16 +0200 Subject: [PATCH 113/164] Reset ssl socket in disconnect --- trytond/pysocket.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/trytond/pysocket.py b/trytond/pysocket.py index 8018479e78..561b58397e 100644 --- a/trytond/pysocket.py +++ b/trytond/pysocket.py @@ -105,6 +105,8 @@ class PySocket: except: pass self.sock = None + self.ssl = False + self.ssl_sock = None self.connected = False self.buffer = '' From 7600d1fc25fb28b53088a37258d80f7e2dc159e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 30 Apr 2009 13:04:53 +0200 Subject: [PATCH 114/164] Fix get_module_list with zip file for issue1024 thanks to udono --- trytond/modules/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/modules/__init__.py b/trytond/modules/__init__.py index c82334b396..098b144697 100644 --- a/trytond/modules/__init__.py +++ b/trytond/modules/__init__.py @@ -285,7 +285,7 @@ def get_module_list(): if os.path.isdir(OPJ(MODULES_PATH, file)): module_list.add(file) elif file[-4:] == '.zip': - module_list.add(file) + module_list.add(file[:-4]) module_list.update(EGG_MODULES.keys()) module_list.add('ir') module_list.add('workflow') From b71c60a77ddcbcc030da56c1099dc74ce08666c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 30 Apr 2009 17:38:39 +0200 Subject: [PATCH 115/164] Fix lastmodified to use create_date if write_date is NULL --- trytond/webdav/webdav.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trytond/webdav/webdav.py b/trytond/webdav/webdav.py index cdd650b1ca..5cdcec9c48 100644 --- a/trytond/webdav/webdav.py +++ b/trytond/webdav/webdav.py @@ -240,7 +240,8 @@ class Collection(OSV): if object_name: model_obj = self.pool.get(object_name) if object_id: - cursor.execute('SELECT EXTRACT(epoch FROM write_date) ' \ + cursor.execute('SELECT ' \ + 'EXTRACT(epoch FROM COALESCE(write_date, create_date)) ' \ 'FROM "' + model_obj._table +'" ' \ 'WHERE id = %s', (object_id,)) if cursor.rowcount: From 575dafa133b7b55703716aab5e74240a0d092814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 1 May 2009 16:05:42 +0200 Subject: [PATCH 116/164] Skip set_datas on attachment only if value is False or None --- trytond/ir/attachment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/ir/attachment.py b/trytond/ir/attachment.py index 577c86ce79..70ff3d3798 100644 --- a/trytond/ir/attachment.py +++ b/trytond/ir/attachment.py @@ -61,7 +61,7 @@ class Attachment(OSV): return res def set_datas(self, cursor, user, obj_id, name, value, args, context=None): - if not value: + if value is False or value is None: return db_name = cursor.dbname directory = os.path.join(CONFIG['data_path'], db_name) From 18fd533759fe2cb91131a498ed0abb1a041e7b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 11 May 2009 18:49:24 +0200 Subject: [PATCH 117/164] Prepare changelog for release 1.0.4 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index bbd390989d..06f1878c46 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 1.0.4 - 2009-05-11 +* Some bug fixes (see mercurial logs for details) + Version 1.0.3 - 2009-03-02 * Some bug fixes (see mercurial logs for details) From bb27463481a3ce34645f33167720eda0d581754f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 11 May 2009 18:49:32 +0200 Subject: [PATCH 118/164] Added tag 1.0.4 for changeset b0f7cf03dfb1 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index e998237b69..3bce26355b 100644 --- a/.hgtags +++ b/.hgtags @@ -2,3 +2,4 @@ eeb6a351bc3e82fd856161c01c8add6a4b7d5e66 1.0.1 6f52a2f6328837727c65eeb5ddf2de0c146e33a9 1.0.2 8ee21b527f3de386af4f0822f5f575c9f66f90c6 1.0.3 +b0f7cf03dfb13fef5101fe6ee6f6e6ed6797e5ab 1.0.4 From 4bb6c44cd550b05804155d49211eea6dec918305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 11 May 2009 18:52:14 +0200 Subject: [PATCH 119/164] Increase version number --- doc/conf.py | 2 +- trytond/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 0e8c6cf5cd..1826b10427 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -46,7 +46,7 @@ copyright = '2008, B2CK' # The short X.Y version. version = '1.0' # The full version, including alpha/beta/rc tags. -release = '1.0.4' +release = '1.0.5' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: diff --git a/trytond/version.py b/trytond/version.py index f4028ef7df..27d9961f87 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.0.4" +VERSION = "1.0.5" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From ed7f10863c78bdbf03a9eed966aa99fa53b6356c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 13 May 2009 11:17:20 +0200 Subject: [PATCH 120/164] Increase socket timeout for unittest --- trytond/pysocket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/pysocket.py b/trytond/pysocket.py index 561b58397e..77784564ce 100644 --- a/trytond/pysocket.py +++ b/trytond/pysocket.py @@ -10,7 +10,7 @@ except ImportError: DNS_CACHE = {} MAX_SIZE = 999999999 MAX_LENGHT = len(str(MAX_SIZE)) -TIMEOUT = 120 +TIMEOUT = 1200 _ALLOWED_MODULES = {'datetime': ['datetime', 'date'], 'decimal': ['Decimal']} From 31c5b7675d38e57fa24ceaa60208fc6a502e7d0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 13 May 2009 19:16:48 +0200 Subject: [PATCH 121/164] Fix "in" and "not in" clause for boolean --- trytond/osv/orm.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 24278357e2..db99cdbfc8 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2687,10 +2687,11 @@ class ORM(object): elif arg[1] in ('in', 'not in'): if len(arg[2]) > 0: todel = [] - for xitem in range(len(arg[2])): - if arg[2][xitem] == False \ - and isinstance(arg[2][xitem],bool): - todel.append(xitem) + if table._columns[arg[0]]._type != 'boolean': + for xitem in range(len(arg[2])): + if arg[2][xitem] == False \ + and isinstance(arg[2][xitem],bool): + todel.append(xitem) arg2 = arg[2][:] for xitem in todel[::-1]: del arg2[xitem] From 9cc64ce263e799fc0384690290f92fe2beea6abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 17 May 2009 17:32:22 +0200 Subject: [PATCH 122/164] Fix set_default for inherited fields for issue1050 --- trytond/ir/default.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/trytond/ir/default.py b/trytond/ir/default.py index db6898edd8..0145ac5bb2 100644 --- a/trytond/ir/default.py +++ b/trytond/ir/default.py @@ -71,12 +71,17 @@ class Default(OSV): def set_default(self, cursor, user, model, field, clause, value, user_default, context=None): - model_obj = self.pool.get('ir.model') - field_obj = self.pool.get('ir.model.field') - model_id = model_obj.search(cursor, user, [ + ir_model_obj = self.pool.get('ir.model') + ir_field_obj = self.pool.get('ir.model.field') + + model_obj = self.pool.get(model) + if field not in model_obj._columns: + model = self.pool.get(model_obj._inherit_fields[field][0])._name + + model_id = ir_model_obj.search(cursor, user, [ ('model', '=', model), ], context=context)[0] - field_id = field_obj.search(cursor, user, [ + field_id = ir_field_obj.search(cursor, user, [ ('name', '=', field), ('model', '=', model_id), ], context=context)[0] From cb89ff8887c817ebf662c2756cb7ecead0d28f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 20 May 2009 01:01:33 +0200 Subject: [PATCH 123/164] Fix setLang on BrowseRecord to keep the cached values --- trytond/osv/orm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index db99cdbfc8..f15fa0ac17 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -219,8 +219,8 @@ class BrowseRecord(object): for table in self._cache: for obj_id in self._cache[table]: self._language_cache.setdefault(prev_lang, - {}).setdefault(table, {}).update( - self._cache[table][obj_id]) + {}).setdefault(table, {})[obj_id] = \ + self._cache[table][obj_id] if lang in self._language_cache \ and table in self._language_cache[lang] \ and obj_id in self._language_cache[lang][table]: From d53497e00d03b54d688d67fe8cb68baaa8e33952 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 21 May 2009 12:21:42 +0200 Subject: [PATCH 124/164] Fix memory leak in setLang cache of BrowseRecord for issue1025 --- trytond/osv/orm.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index f15fa0ac17..6e8b5fbe25 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -96,9 +96,9 @@ class BrowseRecord(object): self._table = table self._table_name = self._table._name self._context = context or {} - self._language_cache = {} cache.setdefault(table._name, {}) + cache.setdefault('_language_cache', {}) self._data = cache[table._name] if not object_id in self._data: self._data[object_id] = {'id': object_id} @@ -216,16 +216,19 @@ class BrowseRecord(object): self._context = self._context.copy() prev_lang = self._context.get('language', 'en_US') self._context['language'] = lang + language_cache = self._cache['_language_cache'] for table in self._cache: + if model == '_language_cache': + continue for obj_id in self._cache[table]: - self._language_cache.setdefault(prev_lang, + language_cache.setdefault(prev_lang, {}).setdefault(table, {})[obj_id] = \ self._cache[table][obj_id] - if lang in self._language_cache \ - and table in self._language_cache[lang] \ - and obj_id in self._language_cache[lang][table]: + if lang in language_cache \ + and table in language_cache[lang] \ + and obj_id in language_cache[lang][table]: self._cache[table][obj_id] = \ - self._language_cache[lang][table][obj_id] + language_cache[lang][table][obj_id] else: self._cache[table][obj_id] = {'id': obj_id} From c48daa0238bad0752e049af9f56337b12d2a48fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 27 May 2009 20:43:00 +0200 Subject: [PATCH 125/164] Fix default_sequence when sequence is inherited --- trytond/osv/orm.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 6e8b5fbe25..f35729590f 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -3222,8 +3222,15 @@ class ORM(object): ''' Return the default value for sequence field. ''' + table = self._table + if 'sequence' not in self._columns: + for model in self._inherits: + model_obj = self.pool.get(model) + if 'sequence' in model_obj._columns: + table = model_obj._table + break cursor.execute('SELECT MAX(sequence) ' \ - 'FROM "' + self._table + '"') + 'FROM "' + table + '"') res = cursor.fetchone() if res: return res[0] From c54dc122017b8b4d89347198ce5c2ff33dc73b41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 6 May 2009 12:53:17 +0200 Subject: [PATCH 126/164] rollback closing cursor and commit init cursor to have a fresh cursor from the Pool --- trytond/sql_db.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/trytond/sql_db.py b/trytond/sql_db.py index bc776b6657..ddddf53734 100644 --- a/trytond/sql_db.py +++ b/trytond/sql_db.py @@ -55,6 +55,7 @@ class FakeCursor(object): self.conn = conn self.cursor_factory = cursor_factory self.cursor = conn.cursor(cursor_factory=self.cursor_factory) + self.commit() self.dbname = dbname self.sql_from_log = {} self.sql_into_log = {} @@ -114,6 +115,7 @@ class FakeCursor(object): # collected as fast as they should). The problem is probably due in # part because browse records keep a reference to the cursor. del self.cursor + self.rollback() self._connpool.putconn(self.conn) def commit(self): From a590fa3cb8af59d065c246d0863ca52bd9bcee2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 1 Jun 2009 18:59:18 +0200 Subject: [PATCH 127/164] Fix typo for issue1071 --- trytond/osv/orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index f35729590f..8ab7456dd4 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -218,7 +218,7 @@ class BrowseRecord(object): self._context['language'] = lang language_cache = self._cache['_language_cache'] for table in self._cache: - if model == '_language_cache': + if table == '_language_cache': continue for obj_id in self._cache[table]: language_cache.setdefault(prev_lang, From cd815b86466b2f8ca50a5f04f1f1dc88b93f3e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 6 Jun 2009 22:42:06 +0200 Subject: [PATCH 128/164] Use _name for Cache instead of name to work with Cacheable for issue1076 --- trytond/tools/misc.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/trytond/tools/misc.py b/trytond/tools/misc.py index cd86fead38..a2e645b229 100644 --- a/trytond/tools/misc.py +++ b/trytond/tools/misc.py @@ -244,7 +244,7 @@ class Cache(object): self.max_len = max_len self._cache = {} self._cache_instance.append(self) - self.name = name + self._name = name self.timestamp = None self.lock = Lock() @@ -254,7 +254,7 @@ class Cache(object): def cached_result(self2, cursor=None, *args, **kwargs): result = None if isinstance(cursor, basestring): - Cache.reset(cursor, self.name) + Cache.reset(cursor, self._name) self.lock.acquire() try: self._cache[cursor] = {} @@ -331,9 +331,9 @@ class Cache(object): cursor.commit() cursor.close() for obj in Cache._cache_instance: - if obj.name in timestamps: - if not obj.timestamp or timestamps[obj.name] > obj.timestamp: - obj.timestamp = timestamps[obj.name] + if obj._name in timestamps: + if not obj.timestamp or timestamps[obj._name] > obj.timestamp: + obj.timestamp = timestamps[obj._name] obj.lock.acquire() try: obj._cache[dbname] = {} From f4ef086a229592fab121206d498a7426a7708cb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 7 Jun 2009 00:09:27 +0200 Subject: [PATCH 129/164] Fix internal variable name for Cache and Cacheable for issue1076 --- trytond/osv/osv.py | 1 + trytond/tools/misc.py | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/trytond/osv/osv.py b/trytond/osv/osv.py index 40caeea829..5429a54344 100644 --- a/trytond/osv/osv.py +++ b/trytond/osv/osv.py @@ -204,6 +204,7 @@ class Cacheable(object): self._max_len = 1024 self._timeout = 3600 self._lock = Lock() + self._timestamp = None Cache._cache_instance.append(self) def add(self, cursor, key, value): diff --git a/trytond/tools/misc.py b/trytond/tools/misc.py index a2e645b229..bb148499b3 100644 --- a/trytond/tools/misc.py +++ b/trytond/tools/misc.py @@ -245,8 +245,8 @@ class Cache(object): self._cache = {} self._cache_instance.append(self) self._name = name - self.timestamp = None - self.lock = Lock() + self._timestamp = None + self._lock = Lock() def __call__(self, function): arg_names = inspect.getargspec(function)[0][2:] @@ -255,25 +255,25 @@ class Cache(object): result = None if isinstance(cursor, basestring): Cache.reset(cursor, self._name) - self.lock.acquire() + self._lock.acquire() try: self._cache[cursor] = {} finally: - self.lock.release() + self._lock.release() return True # Update named arguments with positional argument values kwargs.update(dict(zip(arg_names, args))) kwargs = kwargs.items() kwargs.sort() - self.lock.acquire() + self._lock.acquire() try: self._cache.setdefault(cursor.dbname, {}) finally: - self.lock.release() + self._lock.release() lower = None - self.lock.acquire() + self._lock.acquire() try: if len(self._cache[cursor.dbname]) > self.max_len: mintime = time.time() - self.timeout @@ -287,13 +287,13 @@ class Cache(object): if len(self._cache[cursor.dbname]) > self.max_len and lower: del self._cache[cursor.dbname][lower[0]] finally: - self.lock.release() + self._lock.release() # Work out key as a tuple key = (id(self2), repr(kwargs)) # Check cache and return cached value if possible - self.lock.acquire() + self._lock.acquire() try: if key in self._cache[cursor.dbname]: (value, last_time) = self._cache[cursor.dbname][key] @@ -301,18 +301,18 @@ class Cache(object): if self.timeout <= 0 or mintime <= last_time: result = value finally: - self.lock.release() + self._lock.release() if not result: # Work out new value, cache it and return it # Should copy() this value to avoid futur modf of the cacle ? result = function(self2, cursor, **dict(kwargs)) - self.lock.acquire() + self._lock.acquire() try: self._cache[cursor.dbname][key] = (result, time.time()) finally: - self.lock.release() + self._lock.release() return result return cached_result @@ -332,13 +332,13 @@ class Cache(object): cursor.close() for obj in Cache._cache_instance: if obj._name in timestamps: - if not obj.timestamp or timestamps[obj._name] > obj.timestamp: - obj.timestamp = timestamps[obj._name] - obj.lock.acquire() + if not obj._timestamp or timestamps[obj._name] > obj._timestamp: + obj._timestamp = timestamps[obj._name] + obj._lock.acquire() try: obj._cache[dbname] = {} finally: - obj.lock.release() + obj._lock.release() @staticmethod def reset(dbname, name): From 3b9ec5dbf1191a2d5e4dc1c4ac23d909bcb01dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 23 Jun 2009 10:24:32 +0200 Subject: [PATCH 130/164] Fix SQL clause for 'not in' with False value --- trytond/osv/orm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 8ab7456dd4..01c2318ff8 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2716,7 +2716,7 @@ class ORM(object): '%s.%s = false)' % \ (table._table, arg[0]) else: - qu1[-1] = '(' + qu1[-1] + ' OR ' \ + qu1[-1] = '(' + qu1[-1] + ' AND ' \ '%s.%s != false)' % \ (table._table, arg[0]) else: @@ -2725,7 +2725,7 @@ class ORM(object): '%s.%s IS NULL)' % \ (table._table, arg[0]) else: - qu1[-1] = '(' + qu1[-1] + ' OR ' \ + qu1[-1] = '(' + qu1[-1] + ' AND ' \ '%s.%s IS NOT NULL)' % \ (table._table, arg[0]) qu2 += arg2 From 95402ae240991924cf131d5d56b37d4cf8fc6c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 6 Jul 2009 10:18:29 +0200 Subject: [PATCH 131/164] Prepare changelog for release 1.0.5 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 06f1878c46..138ccda99b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 1.0.5 - 2009-07-06 +* Some bug fixes (see mercurial logs for details) + Version 1.0.4 - 2009-05-11 * Some bug fixes (see mercurial logs for details) From fcbe508251d13f7ff39c7cb436884e738272f0b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 6 Jul 2009 10:18:36 +0200 Subject: [PATCH 132/164] Added tag 1.0.5 for changeset a13025348097 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 3bce26355b..f6e7206711 100644 --- a/.hgtags +++ b/.hgtags @@ -3,3 +3,4 @@ eeb6a351bc3e82fd856161c01c8add6a4b7d5e66 1.0.1 6f52a2f6328837727c65eeb5ddf2de0c146e33a9 1.0.2 8ee21b527f3de386af4f0822f5f575c9f66f90c6 1.0.3 b0f7cf03dfb13fef5101fe6ee6f6e6ed6797e5ab 1.0.4 +a1302534809770f2def8bb3ab83e35c87639c8c4 1.0.5 From 996cb306d6e76d3f4b5a1eb086a4f957d0e0bf49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 6 Jul 2009 10:19:57 +0200 Subject: [PATCH 133/164] Increase version number --- doc/conf.py | 2 +- trytond/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 1826b10427..fb3b305fee 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -46,7 +46,7 @@ copyright = '2008, B2CK' # The short X.Y version. version = '1.0' # The full version, including alpha/beta/rc tags. -release = '1.0.5' +release = '1.0.6' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: diff --git a/trytond/version.py b/trytond/version.py index 27d9961f87..6dd3aa1123 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.0.5" +VERSION = "1.0.6" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From e190a567639cf4054589106bd7304aedb233a488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 15 Jul 2009 17:29:19 +0200 Subject: [PATCH 134/164] Use dump_double instead of dump_long for Decimal in xmlrpc.Marshaller --- trytond/netsvc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/netsvc.py b/trytond/netsvc.py index 3f7dab2799..dcfe45a937 100644 --- a/trytond/netsvc.py +++ b/trytond/netsvc.py @@ -26,7 +26,7 @@ from config import CONFIG # convert decimal to float before marshalling: from decimal import Decimal xmlrpclib.Marshaller.dispatch[Decimal] = \ - lambda self, value, write: self.dump_long(float(value), write) + lambda self, value, write: self.dump_double(float(value), write) class SSLSocket(object): From bfd980fe4dd5b1ddc4dcda6b05a2bce36f26595d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 30 Jul 2009 17:08:34 +0200 Subject: [PATCH 135/164] Add missing img_width and img_height in rng validation for issue1120 thanks to woakas --- trytond/ir/ui/form.rnc | 2 ++ trytond/ir/ui/form.rng | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/trytond/ir/ui/form.rnc b/trytond/ir/ui/form.rnc index 1c6ebf2d56..ff0e1dadc6 100644 --- a/trytond/ir/ui/form.rnc +++ b/trytond/ir/ui/form.rnc @@ -124,6 +124,8 @@ attlist.field &= | "top_to_bottom" }? attlist.field &= attribute spell { text }? +attlist.field &= attribute img_width { text }? +attlist.field &= attribute img_height { text }? image = element image { attlist.image, empty } attlist.image &= attribute name { text } attlist.image &= [ a:defaultValue = "1" ] attribute colspan { text }? diff --git a/trytond/ir/ui/form.rng b/trytond/ir/ui/form.rng index 1343285cb5..b20ad93982 100644 --- a/trytond/ir/ui/form.rng +++ b/trytond/ir/ui/form.rng @@ -452,6 +452,16 @@ + + + + + + + + + + From 513304cd0bce32bd74369e9c716d05ddd24608da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 20 Aug 2009 17:18:02 +0200 Subject: [PATCH 136/164] Add timeout to SimpleThreadedXMLRPCServer for Python 2.6 (transplanted from 0247f0d5ea568d5acd7ee15aa4d81003b5bf1f29) --- trytond/netsvc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/trytond/netsvc.py b/trytond/netsvc.py index dcfe45a937..296dd8605a 100644 --- a/trytond/netsvc.py +++ b/trytond/netsvc.py @@ -165,6 +165,7 @@ class SecureXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): class SimpleThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer): + timeout = 1 def server_bind(self): self.socket.setsockopt(socket.SOL_SOCKET, From 517d28d4c3b0f4b87ddb8ee73e3c026a841a854c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 24 Aug 2009 17:50:08 +0200 Subject: [PATCH 137/164] Add timeout to BaseThreadedHTTPServer for Python 2.6 (transplanted from 7079a30337573a7e028959f1e29d0707c62cbbc9) --- trytond/netsvc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/netsvc.py b/trytond/netsvc.py index 296dd8605a..bd6285c17e 100644 --- a/trytond/netsvc.py +++ b/trytond/netsvc.py @@ -368,7 +368,7 @@ class TinySocketServerThread(threading.Thread): class BaseThreadedHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): - + timeout = 1 max_children = CONFIG['max_thread'] def server_bind(self): From e46573cf5a730adb97db81caf8ea0649b9963b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 28 Aug 2009 16:31:44 +0200 Subject: [PATCH 138/164] Fix webdav get_dburi when uri is empty (transplanted from cace3d956786610574a05127fdcbaeca679ecd87) --- trytond/webdavsvc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/webdavsvc.py b/trytond/webdavsvc.py index 75bfa0932b..3fbabfb29b 100644 --- a/trytond/webdavsvc.py +++ b/trytond/webdavsvc.py @@ -66,7 +66,7 @@ class TrytonDAVInterface(iface.dav_interface): def _get_dburi(self, uri): uri = urlparse.urlsplit(uri)[2] - if uri[0] == '/': + if uri and uri[0] == '/': uri = uri[1:] dbname, uri = (uri.split('/', 1) + [None])[0:2] return dbname, uri From b12911c285107ab36b3bb323a0415197df69daf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 31 Aug 2009 10:01:45 +0200 Subject: [PATCH 139/164] Prepare changelog for release 1.0.6 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 138ccda99b..04a878bc18 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 1.0.6 - 2009-08-31 +* Some bug fixes (see mercurial logs for details) + Version 1.0.5 - 2009-07-06 * Some bug fixes (see mercurial logs for details) From 2a66f8bcd6d48f491b0eaebe0c8d3061af6187ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 31 Aug 2009 10:01:58 +0200 Subject: [PATCH 140/164] Added tag 1.0.6 for changeset ca7ad69061d6 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index f6e7206711..e8be7009ed 100644 --- a/.hgtags +++ b/.hgtags @@ -4,3 +4,4 @@ eeb6a351bc3e82fd856161c01c8add6a4b7d5e66 1.0.1 8ee21b527f3de386af4f0822f5f575c9f66f90c6 1.0.3 b0f7cf03dfb13fef5101fe6ee6f6e6ed6797e5ab 1.0.4 a1302534809770f2def8bb3ab83e35c87639c8c4 1.0.5 +ca7ad69061d6b52515f9b9b0870d99beae576034 1.0.6 From 7ec34ab0a7976c209babd31179abe9042400ea0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 31 Aug 2009 10:05:14 +0200 Subject: [PATCH 141/164] Increase version number --- doc/conf.py | 2 +- trytond/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index fb3b305fee..f37a5bca28 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -46,7 +46,7 @@ copyright = '2008, B2CK' # The short X.Y version. version = '1.0' # The full version, including alpha/beta/rc tags. -release = '1.0.6' +release = '1.0.7' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: diff --git a/trytond/version.py b/trytond/version.py index 6dd3aa1123..f9db80a806 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.0.6" +VERSION = "1.0.7" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 5ea81c7a13194d21a90b13aae9e5f124cf3bbab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 2 Sep 2009 22:51:38 +0200 Subject: [PATCH 142/164] Add missing Genshi dependency (transplanted from f77e28e77964b4105dac50c0cdedcd7a58bb6e95) --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 5719afc044..20f2fdff63 100644 --- a/setup.py +++ b/setup.py @@ -45,6 +45,7 @@ setup(name=PACKAGE, 'lxml', 'egenix-mx-base', 'relatorio >= 0.2.0', + 'Genshi', ], extras_require={ 'WebDAV': ['PyWebDAV'], From b8dbf92dd954c5636fb5f16621e0bc29ba2ace20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 14 Sep 2009 18:08:02 +0200 Subject: [PATCH 143/164] Add missing hostname initialisation in PySocket (transplanted from d2a3f0e562ddae28f9a80db449f8340310580d30) --- trytond/pysocket.py | 1 + 1 file changed, 1 insertion(+) diff --git a/trytond/pysocket.py b/trytond/pysocket.py index 77784564ce..77e12b4188 100644 --- a/trytond/pysocket.py +++ b/trytond/pysocket.py @@ -27,6 +27,7 @@ class PySocket: def __init__(self, sock=None): self.sock = sock self.host = None + self.hostname = None self.port = None self.ssl = False self.ssl_sock = None From b8b4635972fdb4fad0b3ade4154c4da9217f6e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 15 Sep 2009 23:02:27 +0200 Subject: [PATCH 144/164] Missing context in browse call for res.user in report (transplanted from 9e73df3d90b95bb330ef08ffac73f3d7e5f26aa8) --- trytond/report/report.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/report/report.py b/trytond/report/report.py index ae9d4a0aa8..02c42f621e 100644 --- a/trytond/report/report.py +++ b/trytond/report/report.py @@ -225,7 +225,7 @@ class Report(object): localcontext = {} localcontext['datas'] = datas localcontext['user'] = self.pool.get('res.user').\ - browse(cursor, user, user) + browse(cursor, user, user, context=context) localcontext['formatLang'] = self.format_lang localcontext['decodestring'] = decodestring localcontext['StringIO'] = StringIO.StringIO From 298a8074495fb7595bed39c0ab204294cee99b8d 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 145/164] 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 5cdcec9c48..9411c33b1a 100644 --- a/trytond/webdav/webdav.py +++ b/trytond/webdav/webdav.py @@ -298,7 +298,7 @@ class Collection(OSV): 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, @@ -308,7 +308,7 @@ class Collection(OSV): 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 0b54292e1478a5726d059c5f481b3ac7350fec29 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 146/164] Add new methods to webdav CONFIG for upcomming version of pywebdav (transplanted from bb463ca8bfb2e85c2b58d4ce8d45351c070c2cb4) --- trytond/webdavsvc.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/trytond/webdavsvc.py b/trytond/webdavsvc.py index 3fbabfb29b..f6bfce4bcb 100644 --- a/trytond/webdavsvc.py +++ b/trytond/webdavsvc.py @@ -47,6 +47,15 @@ if DAV_VERSION == '0.8': 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 b0a41373b612644206ea20a5eac901a324182630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 23 Nov 2009 17:48:49 +0100 Subject: [PATCH 147/164] Prepare for release 1.0.7 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 04a878bc18..ff9873aa51 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 1.0.7 - 2009-11-23 +* Some bug fixes (see mercurial logs for details) + Version 1.0.6 - 2009-08-31 * Some bug fixes (see mercurial logs for details) From 518be250ed1ebcb673c7b0f0bf97808edb6bdedb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 23 Nov 2009 17:48:53 +0100 Subject: [PATCH 148/164] Added tag 1.0.7 for changeset 9c413bf6596a --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index e8be7009ed..3b8e00475a 100644 --- a/.hgtags +++ b/.hgtags @@ -5,3 +5,4 @@ eeb6a351bc3e82fd856161c01c8add6a4b7d5e66 1.0.1 b0f7cf03dfb13fef5101fe6ee6f6e6ed6797e5ab 1.0.4 a1302534809770f2def8bb3ab83e35c87639c8c4 1.0.5 ca7ad69061d6b52515f9b9b0870d99beae576034 1.0.6 +9c413bf6596af6048332eff95b198cd36d3c66c8 1.0.7 From c3337b19ed01dfd79bc280122a24d91e898b4c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 23 Nov 2009 17:51:18 +0100 Subject: [PATCH 149/164] 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 f9db80a806..f37a81e0cc 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.0.7" +VERSION = "1.0.8" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From dc9c9c5d140c1a03f92e8b6ad367849147b32a1c 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 150/164] Fix initialization of warning in import_data if exception is raised for issue1337 (transplanted from 8265102f5fcf6bd488f4d7eb1b7881f0041b89d2) --- trytond/osv/orm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 01c2318ff8..e95d968020 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -988,6 +988,7 @@ class ORM(object): while len(datas): res = {} + warning = '' try: (res, other, warning, translate) = \ process_liness(self, datas, [], fields_def) From b4d1e79c330ecb7bf3c6e5ab89054b0ad6ae054b 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 151/164] Use root user for create/write ir.translation to bypass the model access (transplanted from 39e3839cc37c77fea51bb9aa440fca2f3655ba8d) --- trytond/ir/translation.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py index a161639260..f4f5ebffb4 100644 --- a/trytond/ir/translation.py +++ b/trytond/ir/translation.py @@ -174,7 +174,7 @@ class Translation(OSV, Cacheable): ('name', '=', name), ]) if not ids2: - self.create(cursor, user, { + self.create(cursor, 0, { 'name': name, 'lang': lang, 'type': ttype, @@ -183,7 +183,7 @@ class Translation(OSV, Cacheable): 'fuzzy': False, }) else: - self.write(cursor, user, ids, { + self.write(cursor, 0, ids, { 'src': field[field_name], 'value': value, 'fuzzy': False, @@ -198,7 +198,7 @@ class Translation(OSV, Cacheable): ('res_id', '=', record.id), ]) if not ids2: - self.create(cursor, user, { + self.create(cursor, 0, { 'name': name, 'lang': lang, 'type': ttype, @@ -208,7 +208,7 @@ class Translation(OSV, Cacheable): 'fuzzy': False, }) else: - self.write(cursor, user, ids2, { + self.write(cursor, 0, ids2, { 'value': value, 'src': record[field_name], 'fuzzy': False, @@ -428,7 +428,7 @@ class Translation(OSV, Cacheable): ids) ids2 = [x[0] for x in cursor.fetchall()] if ids2: - self.write(cursor, user, ids2, { + self.write(cursor, 0, ids2, { 'value': value, 'fuzzy': fuzzy, }, context=ctx) From 4f611cee25168663220949f5b18c691495a07beb 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 152/164] 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 ff0e1dadc6..f96c08302b 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 b20ad93982..e69dc7aa73 100644 --- a/trytond/ir/ui/form.rng +++ b/trytond/ir/ui/form.rng @@ -260,7 +260,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 6cd9f6e86d..26457c3660 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 d853e5a95d..fb8a07fd54 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 8f1a1b1fcc8951f55a0cd5542849af76279956f3 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 153/164] Use the error message of the exception in import_data for issue1376 (transplanted from 165dede84794345526a7c6fc95ab432931952aee) --- trytond/osv/orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index e95d968020..33a286c078 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -1004,7 +1004,7 @@ class ORM(object): 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 66b2b0dbfc85749297b9e621ff995d3f3ee00c90 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 154/164] Fix test on _search_domain_active for XML-RPC for issue1380 Tuple in XML-RPC are list (transplanted from f7d3fd252538ee5d5a23e178be045dbc451b838e) --- trytond/osv/orm.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 33a286c078..7f3e4338b0 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -2325,11 +2325,15 @@ class ORM(object): i = 0 active_found = False while i < len(args): - if isinstance(args[i], list): - args[i] = process_args(args[i]) - if isinstance(args[i], tuple): - if args[i][0] == 'active': + arg = args[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): + args[i] = process_args(args[i]) i += 1 if not active_found: if args and ((isinstance(args[0], basestring) \ From e5dec8859b211e88d91933c1a4ae8071b1a19a98 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 155/164] 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 bd2d0c7840..e8812f377c 100644 --- a/trytond/ir/model.py +++ b/trytond/ir/model.py @@ -219,7 +219,7 @@ class ModelData(OSV): """ ids = self.search(cursor, user, [ ('module', '=', module), - ('fs_is', '=', fs_id), + ('fs_id', '=', fs_id), ('inherit', '=', False), ]) if not ids: From e8def6fbcfcba28d60e91008c321a6628e77edf5 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 156/164] Fix typo _get_id -> get_id (transplanted from fd1acd2b09dfaa68a3c0d8634f5867cf7a0b7e32) --- trytond/osv/orm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py index 7f3e4338b0..6b7aaf6e77 100644 --- a/trytond/osv/orm.py +++ b/trytond/osv/orm.py @@ -860,7 +860,7 @@ class ORM(object): 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'] @@ -871,7 +871,7 @@ class ORM(object): 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 47d6c1d1b7c7def3fa60ac9a0f163fe1e7013b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 25 Jan 2010 09:49:03 +0100 Subject: [PATCH 157/164] Update COPYRIGHT --- COPYRIGHT | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index 973c2ed725..bab90c9e3e 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,7 +1,7 @@ Copyright (C) 2004-2008 Tiny SPRL. -Copyright (C) 2007-2008 Cédric Krier. -Copyright (C) 2007-2008 Bertrand Chenal. -Copyright (C) 2008 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 f298ec9b29ecd4707403490d607ec6e78a71ccab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 21 Feb 2010 15:00:25 +0100 Subject: [PATCH 158/164] Prepare for release 1.0.8 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index ff9873aa51..b3a63d8d68 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 1.0.8 - 2010-02-21 +* Some bug fixes (see mercurial logs for details) + Version 1.0.7 - 2009-11-23 * Some bug fixes (see mercurial logs for details) From 1b75e982bec35f1ace4401b0289fa7e558eaddee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 21 Feb 2010 15:00:30 +0100 Subject: [PATCH 159/164] Added tag 1.0.8 for changeset 43f436f3461f --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 3b8e00475a..3c65240a92 100644 --- a/.hgtags +++ b/.hgtags @@ -6,3 +6,4 @@ b0f7cf03dfb13fef5101fe6ee6f6e6ed6797e5ab 1.0.4 a1302534809770f2def8bb3ab83e35c87639c8c4 1.0.5 ca7ad69061d6b52515f9b9b0870d99beae576034 1.0.6 9c413bf6596af6048332eff95b198cd36d3c66c8 1.0.7 +43f436f3461f7cf5cc1735ed9855a215302503a8 1.0.8 From 49ecec8ebfbf65c28c155786f682b824d81a4e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 21 Feb 2010 15:02:34 +0100 Subject: [PATCH 160/164] 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 f37a81e0cc..18254ba0b7 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.0.8" +VERSION = "1.0.9" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 4c16ec3df2c91bbcc1ce0a6967e97db6383777af 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 161/164] 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 70ff3d3798..3a5bbb2e7e 100644 --- a/trytond/ir/attachment.py +++ b/trytond/ir/attachment.py @@ -48,8 +48,11 @@ class Attachment(OSV): 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 5cec8d1816feb824d1f17a87c50c1690e3c47718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 31 Mar 2010 15:55:19 +0200 Subject: [PATCH 162/164] Prepare for release 1.0.9 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index b3a63d8d68..079d4ae038 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 1.0.9 - 2010-03-31 +* Some bug fixes (see mercurial logs for details) + Version 1.0.8 - 2010-02-21 * Some bug fixes (see mercurial logs for details) From 754cd6d2d40a0072044f22ef12101362bd8703fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 31 Mar 2010 15:55:25 +0200 Subject: [PATCH 163/164] Added tag 1.0.9 for changeset ed5a555a817e --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 3c65240a92..3ec21eb650 100644 --- a/.hgtags +++ b/.hgtags @@ -7,3 +7,4 @@ a1302534809770f2def8bb3ab83e35c87639c8c4 1.0.5 ca7ad69061d6b52515f9b9b0870d99beae576034 1.0.6 9c413bf6596af6048332eff95b198cd36d3c66c8 1.0.7 43f436f3461f7cf5cc1735ed9855a215302503a8 1.0.8 +ed5a555a817ec89f79cecb7c56f2b0d315f70232 1.0.9 From 280ee02d22a2fbf948f4c6c6a13917221d790206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 31 Mar 2010 16:02:14 +0200 Subject: [PATCH 164/164] 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 18254ba0b7..b0c330de9f 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.0.9" +VERSION = "1.0.10" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/"