From 5f7735346897f3b0bf8259f6c8737fcb5494cdd2 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Wed, 9 Sep 2009 22:43:25 +0300 Subject: [PATCH 1/3] Implement safe_eval() in order to armour eval() bzr revid: p_christ@hol.gr-20090909194325-hpn4cfhwehxg9dzk --- bin/tools/safe_eval.py | 63 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 bin/tools/safe_eval.py diff --git a/bin/tools/safe_eval.py b/bin/tools/safe_eval.py new file mode 100644 index 00000000000..6f0a9b88fde --- /dev/null +++ b/bin/tools/safe_eval.py @@ -0,0 +1,63 @@ +# -*- encoding: utf-8 -*- +# +# Copyright P. Christeas 2008,2009 +# +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# 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 the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +############################################################################### + +__export_bis = {} + +def __init_ebis(): + global __export_bis + + _evars = [ 'abs', 'all', 'any', 'basestring' , 'bin', 'bool', + 'chr', 'cmp','complex', 'dict', 'divmod', 'enumerate', + 'float','format', 'frozenset', 'getattr', 'hasattr', 'hash', + 'hex', 'id','int', 'iter', 'len', 'list', 'long', 'map', 'max', + 'min','next', 'oct', 'ord','pow', 'range', 'reduce', 'repr', + 'reversed', 'round', 'set', 'setattr', 'slice','sorted', 'str', + 'sum', 'tuple','type', 'unichr','unicode', 'xrange', + 'True','False', 'None', 'NotImplemented', 'Ellipsis', ] + + for v in _evars: + __export_bis[v] = __builtins__[v] + + +__init_ebis() + + +def safe_eval(expr,sglobals,slocals = None): + """ A little safer version of eval(). + This one, will use fewer builtin functions, so that only + arithmetic and logic expressions can really work """ + + global __export_bis + + if not sglobals.has_key('__builtins__'): + # we copy, because we wouldn't want successive calls to safe_eval + # to be able to alter the builtins. + sglobals['__builtins__'] = __export_bis.copy() + + return eval(expr,sglobals,slocals) + +#eof \ No newline at end of file From 2a16b998922d901a33dc0859ebf5afe7382cca47 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Wed, 9 Sep 2009 23:35:17 +0300 Subject: [PATCH 2/3] [Feature]: add condition to ir.sequence, let it be partitioned. With this feature, multiple sequences may be defined per type. A weight parameter will primarily order them. Then, the one whose condition is true will be used. This would let us write modules (calls to get() must be upgraded), where the sequence numbering will depend on the data. Note that this is not straghtforward, as the context passed must be carefully constructed. One problem is that not all object data (eg category) may exist when the sequence is called for a /new/ object (as a call for 'default'). The current code should be backwards compatible with old calls to get() without a context. bzr revid: p_christ@hol.gr-20090909203517-qahww8hika9t3zl8 --- bin/addons/base/ir/ir.xml | 2 ++ bin/addons/base/ir/ir_sequence.py | 33 ++++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/bin/addons/base/ir/ir.xml b/bin/addons/base/ir/ir.xml index 9c94c8179f9..2e8ff31af99 100644 --- a/bin/addons/base/ir/ir.xml +++ b/bin/addons/base/ir/ir.xml @@ -114,6 +114,8 @@ + + diff --git a/bin/addons/base/ir/ir_sequence.py b/bin/addons/base/ir/ir_sequence.py index f48ea0f25c4..71675f5b6ae 100644 --- a/bin/addons/base/ir/ir_sequence.py +++ b/bin/addons/base/ir/ir_sequence.py @@ -22,6 +22,7 @@ import time from osv import fields,osv +from tools.safe_eval import safe_eval import pooler class ir_sequence_type(osv.osv): @@ -47,12 +48,15 @@ class ir_sequence(osv.osv): 'number_next': fields.integer('Next Number', required=True), 'number_increment': fields.integer('Increment Number', required=True), 'padding' : fields.integer('Number padding', required=True), + 'condition': fields.char('Condition', size=250, help="If set, sequence will only be used in case this python expression matches, and will precede other sequences."), + 'weight': fields.integer('Weight',required=True, help="If two sequences match, the highest weight will be used.") } _defaults = { 'active': lambda *a: True, 'number_increment': lambda *a: 1, 'number_next': lambda *a: 1, 'padding' : lambda *a : 0, + 'weight' : lambda *a: 10, } def _process(self, s): @@ -71,10 +75,29 @@ class ir_sequence(osv.osv): } def get_id(self, cr, uid, sequence_id, test='id=%s', context=None): + if not context: + context = {} try: - cr.execute('SELECT id, number_next, prefix, suffix, padding FROM ir_sequence WHERE '+test+' AND active=%s FOR UPDATE', (sequence_id, True)) - res = cr.dictfetchone() - if res: + cr.execute('SELECT id, number_next, prefix, suffix, padding, condition \ + FROM ir_sequence \ + WHERE '+test+' AND active=%s ORDER BY weight DESC, length(COALESCE(condition,\'\')) DESC \ + FOR UPDATE', (sequence_id, True)) + for res in cr.dictfetchall(): + if res['condition']: + print "ir_seq: %s has condition:" %res['id'], res['condition'], + try: + bo = safe_eval(res['condition'],context) + if not bo: + print "not matched" + continue + except Exception,e: + # it would be normal to have exceptions, because + # the domain may contain errors + print "Exception.\ne:",e + print "Context:", context + continue + print "Matched!" + cr.execute('UPDATE ir_sequence SET number_next=number_next+number_increment WHERE id=%s AND active=%s', (res['id'], True)) if res['number_next']: return self._process(res['prefix']) + '%%0%sd' % res['padding'] % res['number_next'] + self._process(res['suffix']) @@ -84,8 +107,8 @@ class ir_sequence(osv.osv): cr.commit() return False - def get(self, cr, uid, code): - return self.get_id(cr, uid, code, test='code=%s') + def get(self, cr, uid, code, context = None): + return self.get_id(cr, uid, code, test='code=%s',context=context) ir_sequence() From c65b07debb024771e38cc45b68f9363f4f8d6f63 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Thu, 10 Sep 2009 02:48:00 +0300 Subject: [PATCH 3/3] safe_eval: make python 2.5 compatible. bzr revid: p_christ@hol.gr-20090909234800-3u0a2fyi6673js4z --- bin/tools/safe_eval.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bin/tools/safe_eval.py b/bin/tools/safe_eval.py index 6f0a9b88fde..7c4da78375c 100644 --- a/bin/tools/safe_eval.py +++ b/bin/tools/safe_eval.py @@ -26,19 +26,22 @@ ############################################################################### __export_bis = {} +import sys def __init_ebis(): global __export_bis - _evars = [ 'abs', 'all', 'any', 'basestring' , 'bin', 'bool', + _evars = [ 'abs', 'all', 'any', 'basestring' , 'bool', 'chr', 'cmp','complex', 'dict', 'divmod', 'enumerate', - 'float','format', 'frozenset', 'getattr', 'hasattr', 'hash', + 'float', 'frozenset', 'getattr', 'hasattr', 'hash', 'hex', 'id','int', 'iter', 'len', 'list', 'long', 'map', 'max', - 'min','next', 'oct', 'ord','pow', 'range', 'reduce', 'repr', + 'min', 'oct', 'ord','pow', 'range', 'reduce', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice','sorted', 'str', 'sum', 'tuple','type', 'unichr','unicode', 'xrange', 'True','False', 'None', 'NotImplemented', 'Ellipsis', ] + if sys.version_info[0:2] >= (2,6): + _evars.extend(['bin', 'format', 'next']) for v in _evars: __export_bis[v] = __builtins__[v]