[IMP] Added search for record relations.

[FIX] Record creation.
[FIX] Ref constructor.
[FIX] Safer Eval expression.

bzr revid: jth@openerp.com-20100331165526-5exmbhtx3jt161pm
This commit is contained in:
Julien Thewys 2010-03-31 18:55:26 +02:00
parent 0542a969ba
commit f66af28b30
2 changed files with 74 additions and 17 deletions

View File

@ -66,6 +66,10 @@ def is_url(node):
def is_eval(node):
return isinstance(node, yaml_tag.Eval)
def is_ref(node):
return isinstance(node, yaml_tag.Ref) \
or _is_yaml_mapping(node, yaml_tag.Ref)
def is_ir_set(node):
return _is_yaml_mapping(node, yaml_tag.IrSet)
@ -122,7 +126,7 @@ class YamlInterpreter(object):
self.pool = pooler.get_pool(cr.dbname)
self.uid = 1
self.context = {} # opererp context
self.eval_context = {'ref': self._ref, '_ref': self._ref} # added '_ref' so that record['ref'] is possible
self.eval_context = {'ref': self._ref, '_ref': self._ref, 'time': time} # added '_ref' so that record['ref'] is possible
def _ref(self):
return lambda xml_id: self.get_id(xml_id)
@ -155,10 +159,11 @@ class YamlInterpreter(object):
id = self.id_map[xml_id]
else:
if '.' in xml_id:
module, xml_id = xml_id.split('.', 1)
module, checked_xml_id = xml_id.split('.', 1)
else:
module = self.module
ir_id = self.pool.get('ir.model.data')._get_id(self.cr, self.uid, module, xml_id)
checked_xml_id = xml_id
ir_id = self.pool.get('ir.model.data')._get_id(self.cr, self.uid, module, checked_xml_id)
obj = self.pool.get('ir.model.data').read(self.cr, self.uid, ir_id, ['res_id'])
id = int(obj['res_id'])
self.id_map[xml_id] = id
@ -224,19 +229,39 @@ class YamlInterpreter(object):
else: # all tests were successful for this assertion tag (no break)
self.assert_report.record(True, assertion.severity)
def _coerce_bool(self, value, default=False):
if isinstance(value, types.BooleanType):
b = value
if isinstance(value, types.StringTypes):
b = value.strip().lower() not in ('0', 'false', 'off', 'no')
elif isinstance(value, types.IntType):
b = bool(value)
else:
b = default
return b
def process_record(self, node):
record, fields = node.items()[0]
self.validate_xml_id(record.id)
if self.isnoupdate(record) and self.mode != 'init':
model = self.get_model(record.model)
record_dict = self._create_record(model, fields)
self.logger.debug("RECORD_DICT %s" % record_dict)
id = self.pool.get('ir.model.data')._update(self.cr, self.uid, record.model, \
self.module, record_dict, record.id, noupdate=self.isnoupdate(record), mode=self.mode)
self.id_map[record.id] = int(id)
if config.get('import_partial', False):
self.cr.commit()
id = self.pool.get('ir.model.data')._update_dummy(self.cr, self.uid, record.model, self.module, record.id)
# check if the resource already existed at the last update
if id:
self.id_map[record] = int(id)
return None
else:
if not self._coerce_bool(record.forcecreate):
return None
model = self.get_model(record.model)
record_dict = self._create_record(model, fields)
self.logger.debug("RECORD_DICT %s" % record_dict)
id = self.pool.get('ir.model.data')._update(self.cr, self.uid, record.model, \
self.module, record_dict, record.id, noupdate=self.isnoupdate(record), mode=self.mode)
self.id_map[record.id] = int(id)
if config.get('import_partial', False):
self.cr.commit()
def _create_record(self, model, fields):
record_dict = {}
@ -247,17 +272,35 @@ class YamlInterpreter(object):
def _eval_field(self, model, field_name, expression):
column = model._columns[field_name]
if column._type == "many2one":
if is_ref(expression):
if expression.model:
other_model_name = expression.model
else:
other_model_name = column._obj
other_model = self.get_model(other_model_name)
if expression.search:
q = eval(expression.search, self.eval_context)
ids = other_model.search(self.cr, self.uid, q)
if expression.use:
instances = other_model.browse(self.cr, self.uid, ids)
elements = [inst[expression.use] for inst in instances]
else:
elements = ids
if column._type in ("many2many", "one2many"):
value = [(6, 0, elements)]
else: # many2one
value = elements[0]
elif column._type == "many2one":
value = self.get_id(expression)
elif column._type == "one2many":
other_model = self.get_model(column._obj)
value = [(0, 0, self._create_record(other_model, fields)) for fields in expression]
elif column._type == "many2many":
ids = [self.get_id(xml_id) for xml_id in expression]
value= [(6, 0, ids)]
value = [(6, 0, ids)]
else: # scalar field
if isinstance(expression, yaml_tag.Eval):
value = eval(expression.expression)
if is_eval(expression):
value = eval(expression.expression, self.eval_context)
else:
value = expression
# raise YamlImportException('Unsupported column "%s" or value %s:%s' % (field_name, type(expression), expression))

View File

@ -23,7 +23,7 @@ class Assert(YamlTag):
super(Assert, self).__init__(**kwargs)
class Record(YamlTag):
def __init__(self, model, id, **kwargs):
def __init__(self, model, id, use='id', **kwargs):
self.model = model
self.id = id
super(Record, self).__init__(**kwargs)
@ -86,6 +86,12 @@ class Eval(YamlTag):
self.expression = expression
super(Eval, self).__init__()
class Ref(YamlTag):
# 'model' parameter is optional since it defaults to the column type
def __init__(self, search):
self.search = search
super(Ref, self).__init__()
class IrSet(YamlTag):
def __init__(self):
super(IrSet, self).__init__()
@ -138,10 +144,17 @@ def eval_constructor(loader, node):
expression = loader.construct_scalar(node)
return Eval(expression)
def ref_constructor(loader, node):
kwargs = loader.construct_mapping(node)
return Ref(**kwargs)
def ir_set_constructor(loader, node):
kwargs = loader.construct_mapping(node)
return IrSet(**kwargs)
# Registers constructors for custom tags.
# Constructors are actually defined globally: do not redefined them in another
# class/file/package. This means that module recorder need import this file.
yaml.add_constructor(u"!assert", assert_constructor)
yaml.add_constructor(u"!record", record_constructor)
yaml.add_constructor(u"!python", python_constructor)
@ -154,4 +167,5 @@ yaml.add_constructor(u"!context", context_constructor)
yaml.add_constructor(u"!delete", delete_constructor)
yaml.add_constructor(u"!url", url_constructor)
yaml.add_constructor(u"!eval", eval_constructor)
yaml.add_constructor(u"!ref", ref_constructor)
yaml.add_constructor(u"!ir_set", ir_set_constructor)