[MERGE] Merged YAML branch.
bzr revid: jth@openerp.com-20100406130733-cqm8wa21vy7j4ak0
This commit is contained in:
+74
-31
@@ -589,8 +589,75 @@ class MigrationManager(object):
|
||||
if mod:
|
||||
del mod
|
||||
|
||||
log = logging.getLogger('init')
|
||||
|
||||
def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs):
|
||||
|
||||
def process_sql_file(cr, file):
|
||||
queries = fp.read().split(';')
|
||||
for query in queries:
|
||||
new_query = ' '.join(query.split())
|
||||
if new_query:
|
||||
cr.execute(new_query)
|
||||
|
||||
def load_init_update_xml(cr, m, idref, mode, kind):
|
||||
for filename in package.data.get('%s_xml' % kind, []):
|
||||
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading %s' % (m, filename))
|
||||
_, ext = os.path.splitext(filename)
|
||||
fp = tools.file_open(opj(m, filename))
|
||||
if ext == '.csv':
|
||||
noupdate = (kind == 'init')
|
||||
tools.convert_csv_import(cr, m, os.path.basename(filename), fp.read(), idref, mode=mode, noupdate=noupdate)
|
||||
elif ext == '.sql':
|
||||
process_sql_file(cr, fp)
|
||||
elif ext == '.yml':
|
||||
tools.convert_yaml_import(cr, m, fp, idref, mode=mode, **kwargs)
|
||||
else:
|
||||
tools.convert_xml_import(cr, m, fp, idref, mode=mode, **kwargs)
|
||||
fp.close()
|
||||
|
||||
def load_demo_xml(cr, m, idref, mode):
|
||||
for xml in package.data.get('demo_xml', []):
|
||||
name, ext = os.path.splitext(xml)
|
||||
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading %s' % (m, xml))
|
||||
fp = tools.file_open(opj(m, xml))
|
||||
if ext == '.csv':
|
||||
tools.convert_csv_import(cr, m, os.path.basename(xml), fp.read(), idref, mode=mode, noupdate=True)
|
||||
elif ext == '.yml':
|
||||
tools.convert_yaml_import(cr, m, fp, idref, mode=mode, noupdate=True, **kwargs)
|
||||
else:
|
||||
tools.convert_xml_import(cr, m, fp, idref, mode=mode, noupdate=True, **kwargs)
|
||||
fp.close()
|
||||
|
||||
def load_data(cr, module_name, id_map, mode):
|
||||
_load_data(cr, module_name, id_map, mode, 'data')
|
||||
|
||||
def load_demo(cr, module_name, id_map, mode):
|
||||
_load_data(cr, module_name, id_map, mode, 'demo')
|
||||
|
||||
def load_test(cr, module_name, id_map, mode):
|
||||
cr.commit()
|
||||
try:
|
||||
_load_data(cr, module_name, id_map, mode, 'test')
|
||||
finally:
|
||||
cr.rollback()
|
||||
|
||||
def _load_data(cr, module_name, id_map, mode, kind):
|
||||
noupdate = (kind == 'demo')
|
||||
for filename in package.data.get(kind, []):
|
||||
_, ext = os.path.splitext(filename)
|
||||
log.info("module %s: loading %s", module_name, filename)
|
||||
pathname = os.path.join(module_name, filename)
|
||||
file = tools.file_open(pathname)
|
||||
# TODO manage .csv file with noupdate == (kind == 'init')
|
||||
if ext == '.sql':
|
||||
process_sql_file(cr, fp)
|
||||
elif ext == '.yml':
|
||||
tools.convert_yaml_import(cr, module_name, file, id_map, mode, noupdate)
|
||||
else:
|
||||
tools.convert_xml_import(cr, module_name, file, id_map, mode, noupdate)
|
||||
file.close()
|
||||
|
||||
# **kwargs is passed directly to convert_xml_import
|
||||
if not status:
|
||||
status = {}
|
||||
@@ -647,40 +714,16 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs):
|
||||
'license': package.data.get('license', 'GPL-2'),
|
||||
'certificate': package.data.get('certificate') or None,
|
||||
})
|
||||
for filename in package.data.get('%s_xml' % kind, []):
|
||||
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading %s' % (m, filename))
|
||||
name, ext = os.path.splitext(filename)
|
||||
fp = tools.file_open(opj(m, filename))
|
||||
if ext == '.csv':
|
||||
noupdate=False
|
||||
if kind == 'init':
|
||||
noupdate=True
|
||||
tools.convert_csv_import(cr, m, os.path.basename(filename), fp.read(), idref, mode=mode, noupdate=noupdate)
|
||||
elif ext == '.sql':
|
||||
queries = fp.read().split(';')
|
||||
for query in queries:
|
||||
new_query = ' '.join(query.split())
|
||||
if new_query:
|
||||
cr.execute(new_query)
|
||||
elif ext == '.yml':
|
||||
tools.convert_yaml_import(cr, m, fp, idref, mode=mode, **kwargs)
|
||||
else:
|
||||
tools.convert_xml_import(cr, m, fp, idref, mode=mode, **kwargs)
|
||||
fp.close()
|
||||
load_init_update_xml(cr, m, idref, mode, kind)
|
||||
load_data(cr, m, idref, mode)
|
||||
if hasattr(package, 'demo') or (package.dbdemo and package.state != 'installed'):
|
||||
status['progress'] = (float(statusi)+0.75) / len(graph)
|
||||
for xml in package.data.get('demo_xml', []):
|
||||
name, ext = os.path.splitext(xml)
|
||||
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading %s' % (m, xml))
|
||||
fp = tools.file_open(opj(m, xml))
|
||||
if ext == '.csv':
|
||||
tools.convert_csv_import(cr, m, os.path.basename(xml), fp.read(), idref, mode=mode, noupdate=True)
|
||||
elif ext == '.yml':
|
||||
tools.convert_yaml_import(cr, m, fp, idref, mode=mode, **kwargs)
|
||||
else:
|
||||
tools.convert_xml_import(cr, m, fp, idref, mode=mode, noupdate=True, **kwargs)
|
||||
fp.close()
|
||||
load_demo_xml(cr, m, idref, mode)
|
||||
load_demo(cr, m, idref, mode)
|
||||
cr.execute('update ir_module_module set demo=%s where id=%s', (True, mid))
|
||||
|
||||
load_test(cr, m, idref, mode)
|
||||
|
||||
package_todo.append(package.name)
|
||||
|
||||
migrations.migrate_module(package, 'post')
|
||||
|
||||
@@ -548,10 +548,10 @@ class ir_model_data(osv.osv):
|
||||
table.replace('.', '_'))] = (table, inherit_id)
|
||||
return res_id
|
||||
|
||||
def _unlink(self, cr, uid, model, ids, direct=False):
|
||||
for id in ids:
|
||||
self.unlink_mark[(model, id)]=False
|
||||
cr.execute('delete from ir_model_data where res_id=%s and model=%s', (id, model))
|
||||
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):
|
||||
|
||||
@@ -73,18 +73,15 @@ class ir_sequence(osv.osv):
|
||||
}
|
||||
|
||||
def get_id(self, cr, uid, sequence_id, test='id', context=None):
|
||||
try:
|
||||
assert test in ('code','id')
|
||||
cr.execute('SELECT id, number_next, prefix, suffix, padding FROM ir_sequence WHERE '+test+'=%s AND active=%s FOR UPDATE', (sequence_id, True))
|
||||
res = cr.dictfetchone()
|
||||
if res:
|
||||
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'])
|
||||
else:
|
||||
return self._process(res['prefix']) + self._process(res['suffix'])
|
||||
finally:
|
||||
cr.commit()
|
||||
assert test in ('code','id')
|
||||
cr.execute('SELECT id, number_next, prefix, suffix, padding FROM ir_sequence WHERE '+test+'=%s AND active=%s FOR UPDATE NOWAIT', (sequence_id, True))
|
||||
res = cr.dictfetchone()
|
||||
if res:
|
||||
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'])
|
||||
else:
|
||||
return self._process(res['prefix']) + self._process(res['suffix'])
|
||||
return False
|
||||
|
||||
def get(self, cr, uid, code):
|
||||
|
||||
+4
-2
@@ -148,8 +148,10 @@
|
||||
<rng:define name="delete">
|
||||
<rng:element name="delete">
|
||||
<rng:attribute name="model" />
|
||||
<rng:optional><rng:attribute name="id" /> </rng:optional>
|
||||
<rng:optional><rng:attribute name="search" /></rng:optional>
|
||||
<rng:choice>
|
||||
<rng:attribute name="id" />
|
||||
<rng:attribute name="search" />
|
||||
</rng:choice>
|
||||
</rng:element>
|
||||
</rng:define>
|
||||
|
||||
|
||||
+4
-1
@@ -205,7 +205,10 @@ def init_logger():
|
||||
|
||||
for level, (fg, bg) in mapping.items():
|
||||
msg = "\x1b[%dm\x1b[%dm%s\x1b[0m" % (foreground(fg), background(bg), level)
|
||||
logging.addLevelName(getattr(logging, level), msg)
|
||||
# jth: we should not override default level name
|
||||
# jth: use this instead http://stackoverflow.com/questions/384076/how-can-i-make-the-python-logging-output-to-be-colored
|
||||
# jth: also, do not output ANSI if terminal doesn't support it (test it in Eclipse console and on windows)
|
||||
#logging.addLevelName(getattr(logging, level), msg)
|
||||
|
||||
|
||||
class Logger(object):
|
||||
|
||||
@@ -251,7 +251,7 @@ 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, direct=True)
|
||||
self.pool.get('ir.model.data')._unlink(cr, self.uid, d_model, ids)
|
||||
|
||||
def _tag_report(self, cr, rec, data_node=None):
|
||||
res = {}
|
||||
|
||||
+146
-215
@@ -7,6 +7,7 @@ import pooler
|
||||
import netsvc
|
||||
import misc
|
||||
from config import config
|
||||
import yaml_tag
|
||||
|
||||
import yaml
|
||||
|
||||
@@ -18,161 +19,6 @@ class YamlImportException(Exception):
|
||||
class YamlImportAbortion(Exception):
|
||||
pass
|
||||
|
||||
class YamlTag(object):
|
||||
"""
|
||||
Superclass for constructors of custom tags defined in yaml file.
|
||||
"""
|
||||
def __init__(self, **kwargs):
|
||||
self.__dict__.update(kwargs)
|
||||
def __getitem__(self, key):
|
||||
return getattr(self, key)
|
||||
def __getattr__(self, attr):
|
||||
return None
|
||||
def __repr__(self):
|
||||
return "<%s %s>" % (self.__class__.__name__, sorted(self.__dict__.items()))
|
||||
|
||||
class Assert(YamlTag):
|
||||
def __init__(self, model, id, severity=logging.ERROR, string="NONAME", **kwargs):
|
||||
self.model = model
|
||||
self.id = id
|
||||
self.severity = severity
|
||||
self.string = string
|
||||
super(Assert, self).__init__(**kwargs)
|
||||
|
||||
class Record(YamlTag):
|
||||
def __init__(self, model, id, **kwargs):
|
||||
self.model = model
|
||||
self.id = id
|
||||
super(Record, self).__init__(**kwargs)
|
||||
|
||||
class Python(YamlTag):
|
||||
def __init__(self, model, severity=logging.ERROR, name="", **kwargs):
|
||||
self.model= model
|
||||
self.severity = severity
|
||||
self.name = name
|
||||
super(Python, self).__init__(**kwargs)
|
||||
|
||||
class Menuitem(YamlTag):
|
||||
def __init__(self, id, name, **kwargs):
|
||||
self.id = id
|
||||
self.name = name
|
||||
super(Menuitem, self).__init__(**kwargs)
|
||||
|
||||
class Workflow(YamlTag):
|
||||
def __init__(self, model, action, **kwargs):
|
||||
self.model = model
|
||||
self.action = action
|
||||
super(Workflow, self).__init__(**kwargs)
|
||||
|
||||
class ActWindow(YamlTag):
|
||||
def __init__(self, model, action, **kwargs):
|
||||
self.model = model
|
||||
self.action = action
|
||||
super(ActWindow, self).__init__(**kwargs)
|
||||
|
||||
class Function(YamlTag):
|
||||
def __init__(self, model, name, **kwargs):
|
||||
self.model = model
|
||||
self.name = name
|
||||
super(Function, self).__init__(**kwargs)
|
||||
|
||||
class Report(YamlTag):
|
||||
def __init__(self, model, name, string, **kwargs):
|
||||
self.model = model
|
||||
self.name = name
|
||||
self.string = string
|
||||
super(Report, self).__init__(**kwargs)
|
||||
|
||||
class Delete(YamlTag):
|
||||
def __init__(self, model, id, search, **kwargs):
|
||||
self.model = model
|
||||
self.id = id
|
||||
self.search = search
|
||||
super(Delete, self).__init__(**kwargs)
|
||||
|
||||
class Context(YamlTag):
|
||||
def __init__(self, **kwargs):
|
||||
super(Context, self).__init__(**kwargs)
|
||||
|
||||
class Url(YamlTag):
|
||||
def __init__(self, **kwargs):
|
||||
super(Url, self).__init__(**kwargs)
|
||||
|
||||
class Eval(YamlTag):
|
||||
def __init__(self, expression):
|
||||
self.expression = expression
|
||||
super(Eval, self).__init__()
|
||||
|
||||
class IrSet(YamlTag):
|
||||
def __init__(self):
|
||||
super(IrSet, self).__init__()
|
||||
|
||||
def assert_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Assert(**kwargs)
|
||||
|
||||
def record_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Record(**kwargs)
|
||||
|
||||
def python_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Python(**kwargs)
|
||||
|
||||
def menuitem_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Menuitem(**kwargs)
|
||||
|
||||
def workflow_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Workflow(**kwargs)
|
||||
|
||||
def act_window_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return ActWindow(**kwargs)
|
||||
|
||||
def function_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Function(**kwargs)
|
||||
|
||||
def report_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Report(**kwargs)
|
||||
|
||||
def delete_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Delete(**kwargs)
|
||||
|
||||
def context_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Context(**kwargs)
|
||||
|
||||
def url_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Url(**kwargs)
|
||||
|
||||
def eval_constructor(loader, node):
|
||||
expression = loader.construct_scalar(node)
|
||||
return Eval(expression)
|
||||
|
||||
def ir_set_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return IrSet(**kwargs)
|
||||
|
||||
yaml.add_constructor(u"!assert", assert_constructor)
|
||||
yaml.add_constructor(u"!record", record_constructor)
|
||||
yaml.add_constructor(u"!python", python_constructor)
|
||||
yaml.add_constructor(u"!menuitem", menuitem_constructor)
|
||||
yaml.add_constructor(u"!workflow", workflow_constructor)
|
||||
yaml.add_constructor(u"!act_window", act_window_constructor)
|
||||
yaml.add_constructor(u"!function", function_constructor)
|
||||
yaml.add_constructor(u"!report", report_constructor)
|
||||
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"!ir_set", ir_set_constructor)
|
||||
|
||||
def _is_yaml_mapping(node, tag_constructor):
|
||||
value = isinstance(node, types.DictionaryType) \
|
||||
and len(node.keys()) == 1 \
|
||||
@@ -183,45 +29,49 @@ def is_comment(node):
|
||||
return isinstance(node, types.StringTypes)
|
||||
|
||||
def is_assert(node):
|
||||
return _is_yaml_mapping(node, Assert)
|
||||
return _is_yaml_mapping(node, yaml_tag.Assert)
|
||||
|
||||
def is_record(node):
|
||||
return _is_yaml_mapping(node, Record)
|
||||
return _is_yaml_mapping(node, yaml_tag.Record)
|
||||
|
||||
def is_python(node):
|
||||
return _is_yaml_mapping(node, Python)
|
||||
return _is_yaml_mapping(node, yaml_tag.Python)
|
||||
|
||||
def is_menuitem(node):
|
||||
return isinstance(node, Menuitem) \
|
||||
or _is_yaml_mapping(node, Menuitem)
|
||||
return isinstance(node, yaml_tag.Menuitem) \
|
||||
or _is_yaml_mapping(node, yaml_tag.Menuitem)
|
||||
|
||||
def is_function(node):
|
||||
return isinstance(node, Function) \
|
||||
or _is_yaml_mapping(node, Function)
|
||||
return isinstance(node, yaml_tag.Function) \
|
||||
or _is_yaml_mapping(node, yaml_tag.Function)
|
||||
|
||||
def is_report(node):
|
||||
return isinstance(node, Report)
|
||||
return isinstance(node, yaml_tag.Report)
|
||||
|
||||
def is_workflow(node):
|
||||
return isinstance(node, Workflow)
|
||||
return isinstance(node, yaml_tag.Workflow)
|
||||
|
||||
def is_act_window(node):
|
||||
return isinstance(node, ActWindow)
|
||||
return isinstance(node, yaml_tag.ActWindow)
|
||||
|
||||
def is_delete(node):
|
||||
return isinstance(node, Delete)
|
||||
return isinstance(node, yaml_tag.Delete)
|
||||
|
||||
def is_context(node):
|
||||
return isinstance(node, Context)
|
||||
return isinstance(node, yaml_tag.Context)
|
||||
|
||||
def is_url(node):
|
||||
return isinstance(node, Url)
|
||||
return isinstance(node, yaml_tag.Url)
|
||||
|
||||
def is_eval(node):
|
||||
return isinstance(node, Eval)
|
||||
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, IrSet)
|
||||
return _is_yaml_mapping(node, yaml_tag.IrSet)
|
||||
|
||||
|
||||
class TestReport(object):
|
||||
@@ -276,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)
|
||||
@@ -309,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
|
||||
@@ -327,14 +178,29 @@ class YamlInterpreter(object):
|
||||
def isnoupdate(self, node):
|
||||
return self.noupdate or node.noupdate or False
|
||||
|
||||
def _get_first_result(self, results, default=False):
|
||||
if len(results):
|
||||
value = results[0]
|
||||
if isinstance(value, types.TupleType):
|
||||
value = value[0]
|
||||
else:
|
||||
value = default
|
||||
return value
|
||||
|
||||
def process_comment(self, node):
|
||||
return node
|
||||
|
||||
def _log_assert_failure(self, severity, msg, *args):
|
||||
self.assert_report.record(False, severity)
|
||||
self.logger.log(severity, msg, *args)
|
||||
if severity >= config['assert_exit_level']:
|
||||
raise YamlImportAbortion('Severe assertion failure (%s), aborting.' % logging.getLevelName(severity))
|
||||
if isinstance(severity, types.StringTypes):
|
||||
levelname = severity.strip().upper()
|
||||
level = logging.getLevelName(levelname)
|
||||
else:
|
||||
level = severity
|
||||
levelname = logging.getLevelName(level)
|
||||
self.assert_report.record(False, levelname)
|
||||
self.logger.log(level, msg, *args)
|
||||
if level >= config['assert_exit_level']:
|
||||
raise YamlImportAbortion('Severe assertion failure (%s), aborting.' % levelname)
|
||||
return
|
||||
|
||||
def _get_assertion_id(self, assertion):
|
||||
@@ -351,6 +217,7 @@ class YamlInterpreter(object):
|
||||
assertion, expressions = node.items()[0]
|
||||
|
||||
if self.isnoupdate(assertion) and self.mode != 'init':
|
||||
self.logger.warn('This assertion was not evaluated ("%s").' % assertion.string)
|
||||
return
|
||||
model = self.get_model(assertion.model)
|
||||
ids = self._get_assertion_id(assertion)
|
||||
@@ -365,7 +232,7 @@ class YamlInterpreter(object):
|
||||
context = self.get_context(assertion, self.eval_context)
|
||||
for id in ids:
|
||||
record = model.browse(self.cr, self.uid, id, context)
|
||||
for test in expressions.get('test', ''):
|
||||
for test in expressions:
|
||||
try:
|
||||
success = eval(test, self.eval_context, RecordDictWrapper(record))
|
||||
except Exception, e:
|
||||
@@ -378,19 +245,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 = {}
|
||||
@@ -399,19 +286,50 @@ class YamlInterpreter(object):
|
||||
record_dict[field_name] = field_value
|
||||
return record_dict
|
||||
|
||||
def process_ref(self, node, column=None):
|
||||
if node.search:
|
||||
if node.model:
|
||||
model_name = node.model
|
||||
elif column:
|
||||
model_name = column._obj
|
||||
else:
|
||||
raise YamlImportException('You need to give a model for the search, or a column to infer it.')
|
||||
model = self.get_model(model_name)
|
||||
q = eval(node.search, self.eval_context)
|
||||
ids = model.search(self.cr, self.uid, q)
|
||||
if node.use:
|
||||
instances = model.browse(self.cr, self.uid, ids)
|
||||
value = [inst[node.use] for inst in instances]
|
||||
else:
|
||||
value = ids
|
||||
elif node.id:
|
||||
value = self.get_id(node.id)
|
||||
else:
|
||||
value = None
|
||||
return value
|
||||
|
||||
def process_eval(self, node):
|
||||
return eval(node.expression, self.eval_context)
|
||||
|
||||
def _eval_field(self, model, field_name, expression):
|
||||
column = model._columns[field_name]
|
||||
if column._type == "many2one":
|
||||
if is_ref(expression):
|
||||
elements = self.process_ref(expression)
|
||||
if column._type in ("many2many", "one2many"):
|
||||
value = [(6, 0, elements)]
|
||||
else: # many2one
|
||||
value = self._get_first_result(elements)
|
||||
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, Eval):
|
||||
value = eval(expression.expression)
|
||||
if is_eval(expression):
|
||||
value = self.process_eval(expression)
|
||||
else:
|
||||
value = expression
|
||||
# raise YamlImportException('Unsupported column "%s" or value %s:%s' % (field_name, type(expression), expression))
|
||||
@@ -446,7 +364,6 @@ class YamlInterpreter(object):
|
||||
workflow, values = node.items()[0]
|
||||
if self.isnoupdate(workflow) and self.mode != 'init':
|
||||
return
|
||||
model = self.get_model(workflow.model)
|
||||
if workflow.ref:
|
||||
id = self.get_id(workflow.ref)
|
||||
else:
|
||||
@@ -467,26 +384,44 @@ class YamlInterpreter(object):
|
||||
else:
|
||||
uid = self.uid
|
||||
wf_service = netsvc.LocalService("workflow")
|
||||
wf_service.trg_validate(uid, model, id, workflow.action, self.cr)
|
||||
wf_service.trg_validate(uid, workflow.model, id, workflow.action, self.cr)
|
||||
|
||||
def _eval_params(self, model, params):
|
||||
args = []
|
||||
for i, param in enumerate(params):
|
||||
if isinstance(param, types.ListType):
|
||||
value = self._eval_params(model, param)
|
||||
elif is_ref(param):
|
||||
value = self.process_ref(param)
|
||||
elif is_eval(param):
|
||||
value = self.process_eval(param)
|
||||
elif isinstance(param, types.DictionaryType): # supports XML syntax
|
||||
param_model = self.get_model(param.get('model', model))
|
||||
if 'search' in param:
|
||||
q = eval(param['search'], self.eval_context)
|
||||
ids = param_model.search(cr, uid, q)
|
||||
value = self._get_first_result(ids)
|
||||
elif 'eval' in param:
|
||||
local_context = {'obj': lambda x: param_model.browse(self.cr, self.uid, x, context)}
|
||||
local_context.update(self.id_map)
|
||||
value = eval(param['eval'], self.eval_context, local_context)
|
||||
else:
|
||||
raise YamlImportException('You must provide either a !ref or at least a "eval" or a "search" to function parameter #%d.' % i)
|
||||
else:
|
||||
value = param # scalar value
|
||||
args.append(value)
|
||||
return args
|
||||
|
||||
def process_function(self, node):
|
||||
function, values = node.items()[0]
|
||||
function, params = node.items()[0]
|
||||
if self.isnoupdate(function) and self.mode != 'init':
|
||||
return
|
||||
context = self.get_context(function, self.eval_context)
|
||||
args = []
|
||||
if function.eval:
|
||||
args = eval(function.eval, self.eval_context)
|
||||
for value in values:
|
||||
if not 'model' in value and (not 'eval' in value or not 'search' in value):
|
||||
raise YamlImportException('You must provide a "model" and an "eval" or "search" to evaluate.')
|
||||
value_model = self.get_model(value['model'])
|
||||
local_context = {'obj': lambda x: value_model.browse(self.cr, self.uid, x, context=context)}
|
||||
local_context.update(self.id_map)
|
||||
id = eval(value['eval'], self.eval_context, local_context)
|
||||
if id != None:
|
||||
args.append(id)
|
||||
model = self.get_model(function.model)
|
||||
context = self.get_context(function, self.eval_context)
|
||||
if function.eval:
|
||||
args = self.process_eval(function.eval)
|
||||
else:
|
||||
args = self._eval_params(function.model, params)
|
||||
method = function.name
|
||||
getattr(model, method)(self.cr, self.uid, *args)
|
||||
|
||||
@@ -624,17 +559,13 @@ class YamlInterpreter(object):
|
||||
# TODO add remove ir.model.data
|
||||
|
||||
def process_delete(self, node):
|
||||
ids = []
|
||||
if len(node.search):
|
||||
ids = self.pool.get(node.model).search(self.cr, self.uid, eval(node.search, self.eval_context))
|
||||
if len(node.id):
|
||||
try:
|
||||
ids.append(self.get_id(node.id))
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
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, self.uid, node.model, ids, direct=True)
|
||||
self.pool.get('ir.model.data')._unlink(self.cr, self.uid, node.model, ids)
|
||||
|
||||
def process_url(self, node):
|
||||
self.validate_xml_id(node.id)
|
||||
@@ -717,9 +648,9 @@ class YamlInterpreter(object):
|
||||
try:
|
||||
self._process_node(node)
|
||||
except YamlImportException, e:
|
||||
self.logger.log(logging.ERROR, e)
|
||||
self.logger.exception(e)
|
||||
except Exception, e:
|
||||
self.logger.log(logging.ERROR, e)
|
||||
self.logger.exception(e)
|
||||
raise e
|
||||
|
||||
def _process_node(self, node):
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
import yaml
|
||||
import logging
|
||||
|
||||
class YamlTag(object):
|
||||
"""
|
||||
Superclass for constructors of custom tags defined in yaml file.
|
||||
"""
|
||||
def __init__(self, **kwargs):
|
||||
self.__dict__.update(kwargs)
|
||||
def __getitem__(self, key):
|
||||
return getattr(self, key)
|
||||
def __getattr__(self, attr):
|
||||
return None
|
||||
def __repr__(self):
|
||||
return "<%s %s>" % (self.__class__.__name__, sorted(self.__dict__.items()))
|
||||
|
||||
class Assert(YamlTag):
|
||||
def __init__(self, model, id, severity=logging.ERROR, string="NONAME", **kwargs):
|
||||
self.model = model
|
||||
self.id = id
|
||||
self.severity = severity
|
||||
self.string = string
|
||||
super(Assert, self).__init__(**kwargs)
|
||||
|
||||
class Record(YamlTag):
|
||||
def __init__(self, model, id, use='id', **kwargs):
|
||||
self.model = model
|
||||
self.id = id
|
||||
super(Record, self).__init__(**kwargs)
|
||||
|
||||
class Python(YamlTag):
|
||||
def __init__(self, model, severity=logging.ERROR, name="", **kwargs):
|
||||
self.model= model
|
||||
self.severity = severity
|
||||
self.name = name
|
||||
super(Python, self).__init__(**kwargs)
|
||||
|
||||
class Menuitem(YamlTag):
|
||||
def __init__(self, id, name, **kwargs):
|
||||
self.id = id
|
||||
self.name = name
|
||||
super(Menuitem, self).__init__(**kwargs)
|
||||
|
||||
class Workflow(YamlTag):
|
||||
def __init__(self, model, action, **kwargs):
|
||||
self.model = model
|
||||
self.action = action
|
||||
super(Workflow, self).__init__(**kwargs)
|
||||
|
||||
class ActWindow(YamlTag):
|
||||
def __init__(self, model, action, **kwargs):
|
||||
self.model = model
|
||||
self.action = action
|
||||
super(ActWindow, self).__init__(**kwargs)
|
||||
|
||||
class Function(YamlTag):
|
||||
def __init__(self, model, name, **kwargs):
|
||||
self.model = model
|
||||
self.name = name
|
||||
super(Function, self).__init__(**kwargs)
|
||||
|
||||
class Report(YamlTag):
|
||||
def __init__(self, model, name, string, **kwargs):
|
||||
self.model = model
|
||||
self.name = name
|
||||
self.string = string
|
||||
super(Report, self).__init__(**kwargs)
|
||||
|
||||
class Delete(YamlTag):
|
||||
def __init__(self, model, id, search, **kwargs):
|
||||
self.model = model
|
||||
self.id = id
|
||||
self.search = search
|
||||
super(Delete, self).__init__(**kwargs)
|
||||
|
||||
class Context(YamlTag):
|
||||
def __init__(self, **kwargs):
|
||||
super(Context, self).__init__(**kwargs)
|
||||
|
||||
class Url(YamlTag):
|
||||
def __init__(self, **kwargs):
|
||||
super(Url, self).__init__(**kwargs)
|
||||
|
||||
class Eval(YamlTag):
|
||||
def __init__(self, expression):
|
||||
self.expression = expression
|
||||
super(Eval, self).__init__()
|
||||
|
||||
class Ref(YamlTag):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Ref, self).__init__(*args, **kwargs)
|
||||
|
||||
class IrSet(YamlTag):
|
||||
def __init__(self):
|
||||
super(IrSet, self).__init__()
|
||||
|
||||
def assert_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Assert(**kwargs)
|
||||
|
||||
def record_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Record(**kwargs)
|
||||
|
||||
def python_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Python(**kwargs)
|
||||
|
||||
def menuitem_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Menuitem(**kwargs)
|
||||
|
||||
def workflow_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Workflow(**kwargs)
|
||||
|
||||
def act_window_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return ActWindow(**kwargs)
|
||||
|
||||
def function_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Function(**kwargs)
|
||||
|
||||
def report_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Report(**kwargs)
|
||||
|
||||
def delete_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Delete(**kwargs)
|
||||
|
||||
def context_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Context(**kwargs)
|
||||
|
||||
def url_constructor(loader, node):
|
||||
kwargs = loader.construct_mapping(node)
|
||||
return Url(**kwargs)
|
||||
|
||||
def eval_constructor(loader, node):
|
||||
expression = loader.construct_scalar(node)
|
||||
return Eval(expression)
|
||||
|
||||
def ref_constructor(loader, tag_suffix, node):
|
||||
if tag_suffix == "id":
|
||||
kwargs = {"id": loader.construct_scalar(node)}
|
||||
else:
|
||||
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)
|
||||
yaml.add_constructor(u"!menuitem", menuitem_constructor)
|
||||
yaml.add_constructor(u"!workflow", workflow_constructor)
|
||||
yaml.add_constructor(u"!act_window", act_window_constructor)
|
||||
yaml.add_constructor(u"!function", function_constructor)
|
||||
yaml.add_constructor(u"!report", report_constructor)
|
||||
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_multi_constructor(u"!ref", ref_constructor)
|
||||
yaml.add_constructor(u"!ir_set", ir_set_constructor)
|
||||
Reference in New Issue
Block a user