[MERGE] sync with trunk

bzr revid: odo@openerp.com-20110624102631-kiy8j2d1fc7heeco
This commit is contained in:
Olivier Dony
2011-06-24 12:26:31 +02:00
11 changed files with 396 additions and 259 deletions
File diff suppressed because it is too large Load Diff
+24 -30
View File
@@ -588,7 +588,6 @@ class ir_model_data(osv.osv):
def __init__(self, pool, cr):
osv.osv.__init__(self, pool, cr)
self.doinit = True
self.unlink_mark = {}
# also stored in pool to avoid being discarded along with this osv instance
if getattr(pool, 'model_data_reference_ids', None) is None:
@@ -637,6 +636,14 @@ class ir_model_data(osv.osv):
id = False
return id
def unlink(self, cr, uid, ids, context=None):
""" Regular unlink method, but make sure to clear the caches. """
ref_ids = self.browse(cr, uid, ids, context=context)
for ref_id in ref_ids:
self._get_id.clear_cache(cr.dbname, uid, ref_id.module, ref_id.name)
self.get_object_reference.clear_cache(cr.dbname, uid, ref_id.module, ref_id.name)
return super(ir_model_data,self).unlink(cr, uid, ids, context=context)
def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False, context=None):
model_obj = self.pool.get(model)
if not context:
@@ -727,12 +734,6 @@ class ir_model_data(osv.osv):
table.replace('.', '_'))] = (table, inherit_id)
return res_id
def _unlink(self, cr, uid, model, res_ids):
for res_id in res_ids:
self.unlink_mark[(model, res_id)] = False
cr.execute('delete from ir_model_data where res_id=%s and model=%s', (res_id, model))
return True
def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None, xml_id=False):
if type(models[0])==type([]) or type(models[0])==type(()):
model,res_id = models[0]
@@ -760,15 +761,25 @@ class ir_model_data(osv.osv):
return True
def _process_end(self, cr, uid, modules):
""" Clear records removed from updated module data.
This method is called at the end of the module loading process.
It is meant to removed records that are no longer present in the
updated data. Such records are recognised as the one with an xml id
and a module in ir_model_data and noupdate set to false, but not
present in self.loads.
"""
if not modules:
return True
modules = list(modules)
module_in = ",".join(["%s"] * len(modules))
cr.execute('select id,name,model,res_id,module from ir_model_data where module IN (' + module_in + ') and noupdate=%s', modules + [False])
wkf_todo = []
to_unlink = []
for (id, name, model, res_id,module) in cr.fetchall():
if (module,name) not in self.loads:
self.unlink_mark[(model,res_id)] = id
to_unlink.append((model,res_id))
if model=='workflow.activity':
cr.execute('select res_type,res_id from wkf_instance where id IN (select inst_id from wkf_workitem where act_id=%s)', (res_id,))
wkf_todo.extend(cr.fetchall())
@@ -781,36 +792,19 @@ class ir_model_data(osv.osv):
cr.commit()
if not config.get('import_partial'):
for (model, res_id) in self.unlink_mark.keys():
for (model, res_id) in to_unlink:
if self.pool.get(model):
self.__logger.info('Deleting %s@%s', res_id, model)
try:
self.pool.get(model).unlink(cr, uid, [res_id])
if id:
ids = self.search(cr, uid, [('res_id','=',res_id),
('model','=',model)])
self.__logger.debug('=> Deleting %s: %s',
self._name, ids)
if len(ids) > 1 and \
self.__logger.isEnabledFor(logging.WARNING):
self.__logger.warn(
'Got %d %s for (%s, %d): %s',
len(ids), self._name, model, res_id,
map(itemgetter('module','name'),
self.read(cr, uid, ids,
['name', 'module'])))
self.unlink(cr, uid, ids)
cr.execute(
'DELETE FROM ir_values WHERE value=%s',
('%s,%s'%(model, res_id),))
cr.commit()
except Exception:
cr.rollback()
self.__logger.warn(
'Could not delete id: %d of model %s\nThere '
'should be some relation that points to this '
'resource\nYou should manually fix this and '
'restart with --update=module', res_id, model)
'Could not delete obsolete record with id: %d of model %s\n'
'There should be some relation that points to this resource\n'
'You should manually fix this and restart with --update=module',
res_id, model)
return True
ir_model_data()
+6 -3
View File
@@ -197,10 +197,13 @@ class view_sc(osv.osv):
def get_sc(self, cr, uid, user_id, model='ir.ui.menu', context=None):
ids = self.search(cr, uid, [('user_id','=',user_id),('resource','=',model)], context=context)
results = self.read(cr, uid, ids, ['res_id','name'], context=context)
available_menus = self.pool.get(model).search(cr, uid, [], context=context)
results = self.read(cr, uid, ids, ['res_id'], context=context)
name_map = dict(self.pool.get(model).name_get(cr, uid, [x['res_id'] for x in results], context=context))
# Make sure to return only shortcuts pointing to exisintg menu items.
return filter(lambda result: result['res_id'] in available_menus, results)
filtered_results = filter(lambda result: result['res_id'] in name_map, results)
for result in filtered_results:
result.update(name=name_map[result['res_id']])
return filtered_results
_order = 'sequence,name'
_defaults = {
+3
View File
@@ -56,6 +56,9 @@ class lang(osv.osv):
default_value = ir_values_obj.get(cr, uid, 'default', False, ['res.partner'])
if not default_value:
ir_values_obj.set(cr, uid, 'default', False, 'lang', ['res.partner'], lang)
default_value = ir_values_obj.get(cr, uid, 'default', False, ['res.users'])
if not default_value:
ir_values_obj.set(cr, uid, 'default', False, 'context_lang', ['res.users'], lang)
return True
def load_lang(self, cr, uid, lang, lang_name=None):
@@ -1,3 +1,64 @@
-
Testing for hierarchical search in M2M
-
!python {model: res.partner }: |
ids = self.search(cr, uid, [('category_id', 'child_of','supplier')])
assert len(ids) >= 1, ids
-
Test hierarchical search in M2M with child ID1
-
!python {model: res.partner }: |
ids = self.search(cr, uid, [('category_id', 'child_of','Components Supplier')])
assert len(ids) >= 1, ids
-
Test hierarchical search in M2M with child ID2
-
!python {model: res.partner }: |
ids = self.search(cr, uid, [('category_id', 'child_of','Miscellaneous Suppliers')])
assert len(ids) >= 1, ids
-
"1.0 Setup test partner categories: parent root"
-
!record {model: res.partner.category, id: categ_root}:
name: Root category
-
"1.1 Setup test partner categories: parent category"
-
!record {model: res.partner.category, id: categ_0}:
name: Parent category
parent_id: categ_root
-
"1.2 Setup test partner categories: child 1"
-
!record {model: res.partner.category, id: categ_1}:
name: Child 1
parent_id: categ_0
-
Test hierarchical search in M2M with child ID (list of ids)
-
!python {model: res.partner.category }: |
ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_root')])])
assert len(ids) == 3, ids
-
Test hierarchical search in M2M with child ID (single id)
-
!python {model: res.partner.category }: |
ids = self.search(cr, uid, [('id', 'child_of',ref('categ_root'))])
assert len(ids) == 3, ids
-
Test hierarchical search in M2M with child IDs
-
!python {model: res.partner.category }: |
ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_1'), ref('categ_0')])])
assert len(ids) == 2, ids
-
Test hierarchical search in M2M with child IDs
-
!python {model: res.partner.category }: |
ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_0')])])
assert len(ids) == 1, ids
-
Testing that some domain expressions work
-
@@ -40,7 +101,7 @@
-
!assert {model: res.partner, search: "[('category_id', '=', False)]"}:
- category_id in (False, None, [])
-
-
Filtering on invalid value across x2many relationship should return an empty set
-
!assert {model: res.partner, search: "[('address.city','=','foo')]", count: 0, string: "Searching for address.city = foo should give empty results"}
+1 -2
View File
@@ -24,7 +24,6 @@
#
##############################################################################
import cgitb
import errno
import heapq
import logging
@@ -440,7 +439,7 @@ class OpenERPDispatcher:
except Exception, e:
self.log('exception', tools.exception_to_unicode(e))
tb = getattr(e, 'traceback', sys.exc_info())
tb_s = cgitb.text(tb)
tb_s = "".join(traceback.format_exception(*tb))
if tools.config['debug_mode'] and isinstance(tb, types.TracebackType):
import pdb
pdb.post_mortem(tb[2])
+23 -21
View File
@@ -173,6 +173,20 @@ class expression(object):
return ids + rg(ids2, table, parent)
return [(left, 'in', rg(ids, table, parent or table._parent_name))]
def child_of_right_to_ids(value):
""" Normalize a single id, or a string, or a list of ids to a list of ids.
This function is always used with _rec_get() above, so it should be
called directly from _rec_get instead of repeatedly before _rec_get.
"""
if isinstance(value, basestring):
return [x[0] for x in field_obj.name_search(cr, uid, value, [], 'ilike', context=context, limit=None)]
elif isinstance(value, (int, long)):
return [value]
else:
return list(value)
self.__main_table = table
self.__all_tables.add(table)
@@ -203,7 +217,8 @@ class expression(object):
field = working_table._columns.get(fargs[0], False)
if not field:
if left == 'id' and operator == 'child_of':
dom = _rec_get(right, working_table)
ids2 = child_of_right_to_ids(right)
dom = _rec_get(ids2, working_table)
self.__exp = self.__exp[:i] + dom + self.__exp[i+1:]
continue
@@ -249,10 +264,7 @@ class expression(object):
elif field._type == 'one2many':
# Applying recursivity on field(one2many)
if operator == 'child_of':
if isinstance(right, basestring):
ids2 = [x[0] for x in field_obj.name_search(cr, uid, right, [], 'like', context=context, limit=None)]
else:
ids2 = list(right)
ids2 = child_of_right_to_ids(right)
if field._obj != working_table._name:
dom = _rec_get(ids2, field_obj, left=left, prefix=field._obj)
else:
@@ -296,16 +308,12 @@ class expression(object):
elif field._type == 'many2many':
#FIXME
if operator == 'child_of':
if isinstance(right, basestring):
ids2 = [x[0] for x in field_obj.name_search(cr, uid, right, [], 'like', context=context, limit=None)]
else:
ids2 = list(right)
def _rec_convert(ids):
if field_obj == table:
return ids
return self.__execute_recursive_in(cr, field._id1, field._rel, field._id2, ids, operator, field._type)
ids2 = child_of_right_to_ids(right)
dom = _rec_get(ids2, field_obj)
ids2 = field_obj.search(cr, uid, dom, context=context)
self.__exp[i] = ('id', 'in', _rec_convert(ids2))
@@ -344,13 +352,7 @@ class expression(object):
elif field._type == 'many2one':
if operator == 'child_of':
if isinstance(right, basestring):
ids2 = [x[0] for x in field_obj.name_search(cr, uid, right, [], 'like', limit=None)]
elif isinstance(right, (int, long)):
ids2 = list([right])
else:
ids2 = list(right)
ids2 = child_of_right_to_ids(right)
self.__operator = 'in'
if field._obj != working_table._name:
dom = _rec_get(ids2, field_obj, left=left, prefix=field._obj)
@@ -360,12 +362,12 @@ class expression(object):
else:
def _get_expression(field_obj,cr, uid, left, right, operator, context=None):
if context is None:
context = {}
context = {}
c = context.copy()
c['active_test'] = False
#Special treatment to ill-formed domains
operator = ( operator in ['<','>','<=','>='] ) and 'in' or operator
dict_op = {'not in':'!=','in':'=','=':'in','!=':'not in','<>':'not in'}
if isinstance(right,tuple):
right = list(right)
@@ -387,7 +389,7 @@ class expression(object):
elif isinstance(right,(list,tuple)):
m2o_str = True
for ele in right:
if not isinstance(ele, basestring):
if not isinstance(ele, basestring):
m2o_str = False
break
elif right == []:
@@ -403,7 +405,7 @@ class expression(object):
new_op = '!='
#Is it ok to put 'left' and not 'id' ?
self.__exp[i] = (left,new_op,False)
if m2o_str:
self.__exp[i] = _get_expression(field_obj,cr, uid, left, right, operator, context=context)
else:
+3 -2
View File
@@ -3514,9 +3514,10 @@ class orm(orm_template):
# Removing the ir_model_data reference if the record being deleted is a record created by xml/csv file,
# as these are not connected with real database foreign keys, and would be dangling references.
# Step 1. Calling unlink of ir_model_data only for the affected IDS.
referenced_ids = pool_model_data.search(cr, uid, [('res_id','in',list(sub_ids)),('model','=',self._name)], context=context)
reference_ids = pool_model_data.search(cr, uid, [('res_id','in',list(sub_ids)),('model','=',self._name)], context=context)
# Step 2. Marching towards the real deletion of referenced records
pool_model_data.unlink(cr, uid, referenced_ids, context=context)
if reference_ids:
pool_model_data.unlink(cr, uid, reference_ids, context=context)
# For the same reason, removing the record relevant to ir_values
ir_value_ids = ir_values_obj.search(cr, uid,
-2
View File
@@ -301,14 +301,12 @@ form: module.record_id""" % (xml_id,)
pass
if ids:
self.pool.get(d_model).unlink(cr, self.uid, ids)
self.pool.get('ir.model.data')._unlink(cr, self.uid, d_model, ids)
def _remove_ir_values(self, cr, name, value, model):
ir_values_obj = self.pool.get('ir.values')
ir_value_ids = ir_values_obj.search(cr, self.uid, [('name','=',name),('value','=',value),('model','=',model)])
if ir_value_ids:
ir_values_obj.unlink(cr, self.uid, ir_value_ids)
self.pool.get('ir.model.data')._unlink(cr, self.uid, 'ir.values', ir_value_ids)
return True
-1
View File
@@ -643,7 +643,6 @@ class YamlInterpreter(object):
ids = [self.get_id(node.id)]
if len(ids):
self.pool.get(node.model).unlink(self.cr, self.uid, ids)
self.pool.get('ir.model.data')._unlink(self.cr, 1, node.model, ids)
else:
self.logger.log(logging.TEST, "Record not deleted.")
+1 -1
View File
@@ -89,7 +89,7 @@ if os.name == 'nt':
"pydot", "asyncore","asynchat", "reportlab", "vobject",
"HTMLParser", "select", "mako", "poplib",
"imaplib", "smtplib", "email", "yaml", "DAV",
"uuid", "commands", "openerp", # TODO is it necessary to include cgitb?
"uuid", "commands", "openerp",
],
"excludes" : ["Tkconstants","Tkinter","tcl"],
}