[MIG][REF]Yaltik DSL backported from 16 with coconut

This commit is contained in:
Fabien BOURGEOIS 2022-11-17 16:05:36 +01:00
parent de341e5df6
commit 73ecdb19b5
14 changed files with 4065 additions and 70 deletions

View File

@ -1,3 +1,13 @@
.PHONY: setup
setup:
pip install --user -U coconut[watch,jobs,backports,mypy]
.PHONY: testdev
testdev: clean build test
.PHONY: testprod
testprod: clean prod test
.PHONY: clean .PHONY: clean
clean: clean:
find . -name '*.pyc' -delete find . -name '*.pyc' -delete
@ -7,3 +17,15 @@ clean:
test: test:
python2 tests/test_xml_base.py python2 tests/test_xml_base.py
python2 tests/test_odoo.py python2 tests/test_odoo.py
.PHONY: build
build:
coconut -t 2.7 -j sys .
.PHONY: prod
prod:
coconut --notco -t 2.7 -j sys -f .
.PHONY: watch
watch:
coconut --strict -t 2.7 -j sys -w .

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright 2019-2020 Fabien Bourgeois <fabien@yaltik.com> # Copyright 2019-2022 Fabien Bourgeois <fabien@yaltik.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as # it under the terms of the GNU Affero General Public License as
@ -19,7 +19,7 @@
'name': 'Yaltik Odoo DSL base module and fns', 'name': 'Yaltik Odoo DSL base module and fns',
'summary': 'Yaltik Odoo Domain Specific Language base module and functions', 'summary': 'Yaltik Odoo Domain Specific Language base module and functions',
'description': """ Yaltik Odoo Domain Specific Language base module and functions """, 'description': """ Yaltik Odoo Domain Specific Language base module and functions """,
'version': '10.0.0.4.1', 'version': '10.0.0.5.0',
'category': 'Yaltik', 'category': 'Yaltik',
'author': 'Fabien Bourgeois', 'author': 'Fabien Bourgeois',
'license': 'AGPL-3', 'license': 'AGPL-3',

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
# Copyright 2020 Fabien Bourgeois <fabien@yaltik.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from . import odoo_dsl

View File

@ -1,3 +1,38 @@
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# __coconut_hash__ = 0xd86e9c3c
# Compiled with Coconut version 2.1.1 [The Spanish Inquisition]
# Coconut Header: -------------------------------------------------------------
from __future__ import print_function, absolute_import, unicode_literals, division
import sys as _coconut_sys, os as _coconut_os
_coconut_file_dir = _coconut_os.path.dirname(_coconut_os.path.abspath(__file__))
_coconut_cached_module = _coconut_sys.modules.get(b"__coconut__")
if _coconut_cached_module is not None and _coconut_os.path.dirname(_coconut_cached_module.__file__) != _coconut_file_dir: # type: ignore
del _coconut_sys.modules[b"__coconut__"]
_coconut_sys.path.insert(0, _coconut_file_dir)
_coconut_module_name = _coconut_os.path.splitext(_coconut_os.path.basename(_coconut_file_dir))[0]
if _coconut_module_name and _coconut_module_name[0].isalpha() and all(c.isalpha() or c.isdigit() for c in _coconut_module_name) and "__init__.py" in _coconut_os.listdir(_coconut_file_dir):
_coconut_full_module_name = str(_coconut_module_name + ".__coconut__")
import __coconut__ as _coconut__coconut__
_coconut__coconut__.__name__ = _coconut_full_module_name
for _coconut_v in vars(_coconut__coconut__).values():
if getattr(_coconut_v, "__module__", None) == b"__coconut__":
try:
_coconut_v.__module__ = _coconut_full_module_name
except AttributeError:
_coconut_v_type = type(_coconut_v)
if getattr(_coconut_v_type, "__module__", None) == b"__coconut__":
_coconut_v_type.__module__ = _coconut_full_module_name
_coconut_sys.modules[_coconut_full_module_name] = _coconut__coconut__
from __coconut__ import *
from __coconut__ import _coconut_tail_call, _coconut_tco, _coconut_call_set_names, _coconut_handle_cls_kwargs, _coconut_handle_cls_stargs, _namedtuple_of, _coconut, _coconut_super, _coconut_MatchError, _coconut_iter_getitem, _coconut_base_compose, _coconut_forward_compose, _coconut_back_compose, _coconut_forward_star_compose, _coconut_back_star_compose, _coconut_forward_dubstar_compose, _coconut_back_dubstar_compose, _coconut_pipe, _coconut_star_pipe, _coconut_dubstar_pipe, _coconut_back_pipe, _coconut_back_star_pipe, _coconut_back_dubstar_pipe, _coconut_none_pipe, _coconut_none_star_pipe, _coconut_none_dubstar_pipe, _coconut_bool_and, _coconut_bool_or, _coconut_none_coalesce, _coconut_minus, _coconut_map, _coconut_partial, _coconut_get_function_match_error, _coconut_base_pattern_func, _coconut_addpattern, _coconut_sentinel, _coconut_assert, _coconut_raise, _coconut_mark_as_match, _coconut_reiterable, _coconut_self_match_types, _coconut_dict_merge, _coconut_exec, _coconut_comma_op, _coconut_multi_dim_arr, _coconut_mk_anon_namedtuple, _coconut_matmul
_coconut_sys.path.pop(0)
# Compiled Coconut: -----------------------------------------------------------
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright 2020 Fabien Bourgeois <fabien@yaltik.com> # Copyright 2020 Fabien Bourgeois <fabien@yaltik.com>

View File

@ -0,0 +1,126 @@
# -*- coding: utf-8 -*-
#
# Copyright 2019-2020 Fabien Bourgeois <fabien@yaltik.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
""" Odoo XML DSL """
from .xml_base import xmlroot, xmln
# XML helpers functions and macros
# Odoo root XML Node
odoo = lambda children: xmlroot({'tag': 'odoo', 'attrs': {}, 'children': children})
# Special data Node
def data(*args):
""" Allow optional args on data tag """
if len(args) == 1:
args = list(args)
args.insert(0, {})
return xmln('data', *args)
# Aliases
function = lambda *args: xmln('function', *args)
record = lambda *args: xmln('record', *args)
form = lambda *args: xmln('form', *args)
tree = lambda *args: xmln('tree', *args)
search = lambda *args: xmln('search', *args)
# Actions
act_window = lambda *args: xmln('act_window', *args)
def act_window_model(model, attrs):
""" Build new act_window from model and args """
xmlid = '%s_view_action' % (model.replace('.', '_'))
name = '%s Action' % ' '.join(map(lambda w: w.capitalize(), model.split('.')))
attrs_clone = attrs.copy() # Avoid side-effect
attrs_clone.update({'id': xmlid, 'name': name, 'res_model': model})
return act_window(attrs_clone)
def action_server_code(xmlid, name, modelref, code):
""" Server actions of type code """
children = [field_name(name),
field({'name': 'model_id', 'ref': modelref}, []),
field({'name': 'state'}, ['code']),
field({'name': 'code'}, [code])]
return record({'id': xmlid, 'model': 'ir.actions.server'}, children)
def client_action_multi(xmlid, name, model, action):
""" Client action multi (ir.values), with own xmlid, name, targeted model
and action """
action = "'ir.actions.server,%d'%{}".format(action)
children = [field_name(name),
field({'name': 'key2', 'eval': "'client_action_multi'"}),
field({'name': 'model', 'eval': "'%s'" % model}),
field({'name': 'value', 'eval': action})]
return record({'id': xmlid, 'model': 'ir.values'}, children)
# Menus
menuitem = lambda *args: xmln('menuitem', *args)
def menuitem_model(model, attrs):
""" Build new menuitem from model and attrs """
model_und = model.replace('.', '_')
xmlid = '%s_menu' % model_und
actionid = '%s_view_action' % model_und
attrs_clone = attrs.copy() # Avoid side-effect
attrs_clone.update({'id': xmlid, 'action': actionid})
return menuitem(attrs_clone)
# Form aliases
group = lambda *args: xmln('group', *args)
header = lambda *args: xmln('header', *args)
footer = lambda *args: xmln('footer', *args)
sheet = lambda *args: xmln('sheet', *args)
button = lambda *args: xmln('button', *args)
p = lambda *args: xmln('p', *args)
xpath = lambda *args: xmln('xpath', *args)
attribute = lambda name, value: xmln('attribute', {'name': name}, [value])
# Fields
field = lambda *args: xmln('field', *args)
field_name = lambda name: field({'name': 'name'}, [name])
field_nval = lambda name, value: field({'name': name}, [value])
field_model = lambda model: field({'name': 'model'}, [model])
field_inherit = lambda xmlid: field({'name': 'inherit_id', 'ref': xmlid}, [])
field_arch = lambda *args: field({'name': 'arch', 'type': 'xml'}, *args)
# Search
filter = lambda *args: xmln('filter', *args)
# Views
view = lambda xmlid, children: record({'id': xmlid, 'model': 'ir.ui.view'}, children)
def view_def(xmlid, name, model, arch):
""" Shortcut for new view """
return view(xmlid, [field_name(name), field_model(model), field_arch(arch)])
def view_new(view_type, model, arch):
""" View : new view definition, based on type (form, tree, ...) and model ID """
model_und = model.replace('.', '_')
model_cap = ' '.join(map(lambda w: w.capitalize(), model.split('.')))
xmlid = "%s_view_%s" % (model_und, view_type)
name = ' '.join([model_cap, view_type.capitalize()])
return view_def(xmlid, name, model, arch)
def view_inherit(filename, model, inherit, arch):
""" Inherited View simplification with name of the record, xmlid for model
and inherited view """
module = filename.split('.')[2]
inherited = inherit.split('.')[1]
xmlid = '%s_inherit_%s' % (inherited, module)
model_cap = ' '.join(map(lambda w: w.capitalize(), model.split('.')))
name = '%s Adaptations' % model_cap
return view(xmlid, [field_name(name), field_model(model),
field_inherit(inherit), field_arch(arch)])

View File

@ -1,3 +1,40 @@
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# __coconut_hash__ = 0xb1df5fa
# Compiled with Coconut version 2.1.1 [The Spanish Inquisition]
""" Odoo XML DSL """
# Coconut Header: -------------------------------------------------------------
from __future__ import print_function, absolute_import, unicode_literals, division
import sys as _coconut_sys, os as _coconut_os
_coconut_file_dir = _coconut_os.path.dirname(_coconut_os.path.abspath(__file__))
_coconut_cached_module = _coconut_sys.modules.get(b"__coconut__")
if _coconut_cached_module is not None and _coconut_os.path.dirname(_coconut_cached_module.__file__) != _coconut_file_dir: # type: ignore
del _coconut_sys.modules[b"__coconut__"]
_coconut_sys.path.insert(0, _coconut_file_dir)
_coconut_module_name = _coconut_os.path.splitext(_coconut_os.path.basename(_coconut_file_dir))[0]
if _coconut_module_name and _coconut_module_name[0].isalpha() and all(c.isalpha() or c.isdigit() for c in _coconut_module_name) and "__init__.py" in _coconut_os.listdir(_coconut_file_dir):
_coconut_full_module_name = str(_coconut_module_name + ".__coconut__")
import __coconut__ as _coconut__coconut__
_coconut__coconut__.__name__ = _coconut_full_module_name
for _coconut_v in vars(_coconut__coconut__).values():
if getattr(_coconut_v, "__module__", None) == b"__coconut__":
try:
_coconut_v.__module__ = _coconut_full_module_name
except AttributeError:
_coconut_v_type = type(_coconut_v)
if getattr(_coconut_v_type, "__module__", None) == b"__coconut__":
_coconut_v_type.__module__ = _coconut_full_module_name
_coconut_sys.modules[_coconut_full_module_name] = _coconut__coconut__
from __coconut__ import *
from __coconut__ import _coconut_tail_call, _coconut_tco, _coconut_call_set_names, _coconut_handle_cls_kwargs, _coconut_handle_cls_stargs, _namedtuple_of, _coconut, _coconut_super, _coconut_MatchError, _coconut_iter_getitem, _coconut_base_compose, _coconut_forward_compose, _coconut_back_compose, _coconut_forward_star_compose, _coconut_back_star_compose, _coconut_forward_dubstar_compose, _coconut_back_dubstar_compose, _coconut_pipe, _coconut_star_pipe, _coconut_dubstar_pipe, _coconut_back_pipe, _coconut_back_star_pipe, _coconut_back_dubstar_pipe, _coconut_none_pipe, _coconut_none_star_pipe, _coconut_none_dubstar_pipe, _coconut_bool_and, _coconut_bool_or, _coconut_none_coalesce, _coconut_minus, _coconut_map, _coconut_partial, _coconut_get_function_match_error, _coconut_base_pattern_func, _coconut_addpattern, _coconut_sentinel, _coconut_assert, _coconut_raise, _coconut_mark_as_match, _coconut_reiterable, _coconut_self_match_types, _coconut_dict_merge, _coconut_exec, _coconut_comma_op, _coconut_multi_dim_arr, _coconut_mk_anon_namedtuple, _coconut_matmul
_coconut_sys.path.pop(0)
# Compiled Coconut: -----------------------------------------------------------
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright 2019-2020 Fabien Bourgeois <fabien@yaltik.com> # Copyright 2019-2020 Fabien Bourgeois <fabien@yaltik.com>
@ -15,9 +52,10 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
""" Odoo XML DSL """
from .xml_base import xmlroot, xmln
from .xml_base import xmlroot
from .xml_base import xmln
# XML helpers functions and macros # XML helpers functions and macros
@ -25,14 +63,16 @@ from .xml_base import xmlroot, xmln
odoo = lambda children: xmlroot({'tag': 'odoo', 'attrs': {}, 'children': children}) odoo = lambda children: xmlroot({'tag': 'odoo', 'attrs': {}, 'children': children})
# Special data Node # Special data Node
@_coconut_tco
def data(*args): def data(*args):
""" Allow optional args on data tag """ """ Allow optional args on data tag """
if len(args) == 1: if len(args) == 1:
args = list(args) args = list(args)
args.insert(0, {}) args.insert(0, {})
return xmln('data', *args) return _coconut_tail_call(xmln, 'data', *args)
# Aliases # Aliases
function = lambda *args: xmln('function', *args) function = lambda *args: xmln('function', *args)
record = lambda *args: xmln('record', *args) record = lambda *args: xmln('record', *args)
form = lambda *args: xmln('form', *args) form = lambda *args: xmln('form', *args)
@ -41,34 +81,35 @@ search = lambda *args: xmln('search', *args)
# Actions # Actions
act_window = lambda *args: xmln('act_window', *args) act_window = lambda *args: xmln('act_window', *args)
@_coconut_tco
def act_window_model(model, attrs): def act_window_model(model, attrs):
""" Build new act_window from model and args """ """ Build new act_window from model and args """
xmlid = '%s_view_action' % (model.replace('.', '_')) xmlid = '%s_view_action' % (model.replace('.', '_'))
name = '%s Action' % ' '.join(map(lambda w: w.capitalize(), model.split('.'))) name = '%s Action' % ' '.join(map(lambda w: w.capitalize(), model.split('.')))
attrs_clone = attrs.copy() # Avoid side-effect attrs_clone = attrs.copy() # Avoid side-effect
attrs_clone.update({'id': xmlid, 'name': name, 'res_model': model}) attrs_clone.update({'id': xmlid, 'name': name, 'res_model': model})
return act_window(attrs_clone) return _coconut_tail_call(act_window, attrs_clone)
@_coconut_tco
def action_server_code(xmlid, name, modelref, code): def action_server_code(xmlid, name, modelref, code):
""" Server actions of type code """ """ Server actions of type code """
children = [field_name(name), children = [field_name(name), field({'name': 'model_id', 'ref': modelref}, []), field({'name': 'state'}, ['code',]), field({'name': 'code'}, [code,])]
field({'name': 'model_id', 'ref': modelref}, []), return _coconut_tail_call(record, {'id': xmlid, 'model': 'ir.actions.server'}, children)
field({'name': 'state'}, ['code']),
field({'name': 'code'}, [code])]
return record({'id': xmlid, 'model': 'ir.actions.server'}, children)
@_coconut_tco
def client_action_multi(xmlid, name, model, action): def client_action_multi(xmlid, name, model, action):
""" Client action multi (ir.values), with own xmlid, name, targeted model """ Client action multi (ir.values), with own xmlid, name, targeted model
and action """ and action """
action = "'ir.actions.server,%d'%{}".format(action) action = "'ir.actions.server,%d'%{}".format(action)
children = [field_name(name), children = [field_name(name), field({'name': 'key2', 'eval': "'client_action_multi'"}), field({'name': 'model', 'eval': "'%s'" % model}), field({'name': 'value', 'eval': action})]
field({'name': 'key2', 'eval': "'client_action_multi'"}), return _coconut_tail_call(record, {'id': xmlid, 'model': 'ir.values'}, children)
field({'name': 'model', 'eval': "'%s'" % model}),
field({'name': 'value', 'eval': action})]
return record({'id': xmlid, 'model': 'ir.values'}, children)
# Menus # Menus
menuitem = lambda *args: xmln('menuitem', *args) menuitem = lambda *args: xmln('menuitem', *args)
@_coconut_tco
def menuitem_model(model, attrs): def menuitem_model(model, attrs):
""" Build new menuitem from model and attrs """ """ Build new menuitem from model and attrs """
model_und = model.replace('.', '_') model_und = model.replace('.', '_')
@ -76,9 +117,10 @@ def menuitem_model(model, attrs):
actionid = '%s_view_action' % model_und actionid = '%s_view_action' % model_und
attrs_clone = attrs.copy() # Avoid side-effect attrs_clone = attrs.copy() # Avoid side-effect
attrs_clone.update({'id': xmlid, 'action': actionid}) attrs_clone.update({'id': xmlid, 'action': actionid})
return menuitem(attrs_clone) return _coconut_tail_call(menuitem, attrs_clone)
# Form aliases # Form aliases
group = lambda *args: xmln('group', *args) group = lambda *args: xmln('group', *args)
header = lambda *args: xmln('header', *args) header = lambda *args: xmln('header', *args)
footer = lambda *args: xmln('footer', *args) footer = lambda *args: xmln('footer', *args)
@ -86,12 +128,13 @@ sheet = lambda *args: xmln('sheet', *args)
button = lambda *args: xmln('button', *args) button = lambda *args: xmln('button', *args)
p = lambda *args: xmln('p', *args) p = lambda *args: xmln('p', *args)
xpath = lambda *args: xmln('xpath', *args) xpath = lambda *args: xmln('xpath', *args)
attribute = lambda name, value: xmln('attribute', {'name': name}, [value]) attribute = lambda name, value: xmln('attribute', {'name': name}, [value,])
# Fields # Fields
field = lambda *args: xmln('field', *args) field = lambda *args: xmln('field', *args)
field_name = lambda name: field({'name': 'name'}, [name]) field_name = lambda name: field({'name': 'name'}, [name,])
field_model = lambda model: field({'name': 'model'}, [model]) field_nval = lambda name, value: field({'name': name}, [value,])
field_model = lambda model: field({'name': 'model'}, [model,])
field_inherit = lambda xmlid: field({'name': 'inherit_id', 'ref': xmlid}, []) field_inherit = lambda xmlid: field({'name': 'inherit_id', 'ref': xmlid}, [])
field_arch = lambda *args: field({'name': 'arch', 'type': 'xml'}, *args) field_arch = lambda *args: field({'name': 'arch', 'type': 'xml'}, *args)
@ -101,18 +144,23 @@ filter = lambda *args: xmln('filter', *args)
# Views # Views
view = lambda xmlid, children: record({'id': xmlid, 'model': 'ir.ui.view'}, children) view = lambda xmlid, children: record({'id': xmlid, 'model': 'ir.ui.view'}, children)
@_coconut_tco
def view_def(xmlid, name, model, arch): def view_def(xmlid, name, model, arch):
""" Shortcut for new view """ """ Shortcut for new view """
return view(xmlid, [field_name(name), field_model(model), field_arch(arch)]) return _coconut_tail_call(view, xmlid, [field_name(name), field_model(model), field_arch(arch)])
@_coconut_tco
def view_new(view_type, model, arch): def view_new(view_type, model, arch):
""" View : new view definition, based on type (form, tree, ...) and model ID """ """ View : new view definition, based on type (form, tree, ...) and model ID """
model_und = model.replace('.', '_') model_und = model.replace('.', '_')
model_cap = ' '.join(map(lambda w: w.capitalize(), model.split('.'))) model_cap = ' '.join(map(lambda w: w.capitalize(), model.split('.')))
xmlid = "%s_view_%s" % (model_und, view_type) xmlid = "%s_view_%s" % (model_und, view_type)
name = ' '.join([model_cap, view_type.capitalize()]) name = ' '.join([model_cap, view_type.capitalize()])
return view_def(xmlid, name, model, arch) return _coconut_tail_call(view_def, xmlid, name, model, arch)
@_coconut_tco
def view_inherit(filename, model, inherit, arch): def view_inherit(filename, model, inherit, arch):
""" Inherited View simplification with name of the record, xmlid for model """ Inherited View simplification with name of the record, xmlid for model
and inherited view """ and inherited view """
@ -121,5 +169,4 @@ def view_inherit(filename, model, inherit, arch):
xmlid = '%s_inherit_%s' % (inherited, module) xmlid = '%s_inherit_%s' % (inherited, module)
model_cap = ' '.join(map(lambda w: w.capitalize(), model.split('.'))) model_cap = ' '.join(map(lambda w: w.capitalize(), model.split('.')))
name = '%s Adaptations' % model_cap name = '%s Adaptations' % model_cap
return view(xmlid, [field_name(name), field_model(model), return _coconut_tail_call(view, xmlid, [field_name(name), field_model(model), field_inherit(inherit), field_arch(arch)])
field_inherit(inherit), field_arch(arch)])

View File

@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
#
# Copyright 2019-2020 Fabien Bourgeois <fabien@yaltik.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
""" XML helpers and macros """
from os import path
import xml.etree.ElementTree as ET
from xml.dom import minidom
from collections import namedtuple
from functools import partial
XMLDictElement = namedtuple('XMLDictElement', ['tag', 'attrs', 'children'])
def xmlroot(tree):
""" Special process for root XML Node """
rootel = ET.Element(tree['tag'], tree['attrs'])
if 'children' in tree:
xmlchild(rootel, tree['children'])
return rootel
def xmlchild(parent, children):
""" Handling of children (ie non root) XML Nodes with/o text and
subchildren (recursive) """
if isinstance(children, str):
parent.text = children
elif isinstance(children, XMLDictElement):
attrs = {str(k): str(v) for [k, v] in children.attrs.items()}
new_parent = ET.SubElement(parent, children.tag, attrs)
subchildren = children.children
if subchildren:
xmlchild(new_parent, subchildren)
elif isinstance(children, list):
list(map(partial(xmlchild, parent), children))
else:
raise TypeError('Invalid arguments for xmlchild')
def xmln(tag='', attrs={}, children=[]):
""" XMLDictElement building from dict object, with defaults """
if isinstance(attrs, list):
children = attrs
attrs = {}
xmldictel = partial(XMLDictElement, tag, attrs)
if isinstance(children, str):
return xmldictel([children])
if isinstance(children, list):
return xmldictel(children)
raise TypeError('Invalid arguments for xmln')
def xml_write(filepath, tree, pretty=True, suffix='_views'):
""" Write XML file according to filename and given tree """
if filepath.endswith('.py'): # if .pyc, no need to generate XML
output_xml = ET.tostring(tree)
if pretty:
output_xml = minidom.parseString(output_xml).toprettyxml(indent=' ')
output_path = path.abspath(filepath).split('/')
output_path[-1] = output_path[-1].replace('.py', '%s.xml' % suffix)
output_path = '/'.join(output_path)
with open(output_path, 'w') as output_file:
output_file.write(output_xml)

View File

@ -1,3 +1,40 @@
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# __coconut_hash__ = 0xf86eeffc
# Compiled with Coconut version 2.1.1 [The Spanish Inquisition]
""" XML helpers and macros """
# Coconut Header: -------------------------------------------------------------
from __future__ import print_function, absolute_import, unicode_literals, division
import sys as _coconut_sys, os as _coconut_os
_coconut_file_dir = _coconut_os.path.dirname(_coconut_os.path.abspath(__file__))
_coconut_cached_module = _coconut_sys.modules.get(b"__coconut__")
if _coconut_cached_module is not None and _coconut_os.path.dirname(_coconut_cached_module.__file__) != _coconut_file_dir: # type: ignore
del _coconut_sys.modules[b"__coconut__"]
_coconut_sys.path.insert(0, _coconut_file_dir)
_coconut_module_name = _coconut_os.path.splitext(_coconut_os.path.basename(_coconut_file_dir))[0]
if _coconut_module_name and _coconut_module_name[0].isalpha() and all(c.isalpha() or c.isdigit() for c in _coconut_module_name) and "__init__.py" in _coconut_os.listdir(_coconut_file_dir):
_coconut_full_module_name = str(_coconut_module_name + ".__coconut__")
import __coconut__ as _coconut__coconut__
_coconut__coconut__.__name__ = _coconut_full_module_name
for _coconut_v in vars(_coconut__coconut__).values():
if getattr(_coconut_v, "__module__", None) == b"__coconut__":
try:
_coconut_v.__module__ = _coconut_full_module_name
except AttributeError:
_coconut_v_type = type(_coconut_v)
if getattr(_coconut_v_type, "__module__", None) == b"__coconut__":
_coconut_v_type.__module__ = _coconut_full_module_name
_coconut_sys.modules[_coconut_full_module_name] = _coconut__coconut__
from __coconut__ import *
from __coconut__ import _coconut_tail_call, _coconut_tco, _coconut_call_set_names, _coconut_handle_cls_kwargs, _coconut_handle_cls_stargs, _namedtuple_of, _coconut, _coconut_super, _coconut_MatchError, _coconut_iter_getitem, _coconut_base_compose, _coconut_forward_compose, _coconut_back_compose, _coconut_forward_star_compose, _coconut_back_star_compose, _coconut_forward_dubstar_compose, _coconut_back_dubstar_compose, _coconut_pipe, _coconut_star_pipe, _coconut_dubstar_pipe, _coconut_back_pipe, _coconut_back_star_pipe, _coconut_back_dubstar_pipe, _coconut_none_pipe, _coconut_none_star_pipe, _coconut_none_dubstar_pipe, _coconut_bool_and, _coconut_bool_or, _coconut_none_coalesce, _coconut_minus, _coconut_map, _coconut_partial, _coconut_get_function_match_error, _coconut_base_pattern_func, _coconut_addpattern, _coconut_sentinel, _coconut_assert, _coconut_raise, _coconut_mark_as_match, _coconut_reiterable, _coconut_self_match_types, _coconut_dict_merge, _coconut_exec, _coconut_comma_op, _coconut_multi_dim_arr, _coconut_mk_anon_namedtuple, _coconut_matmul
_coconut_sys.path.pop(0)
# Compiled Coconut: -----------------------------------------------------------
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright 2019-2020 Fabien Bourgeois <fabien@yaltik.com> # Copyright 2019-2020 Fabien Bourgeois <fabien@yaltik.com>
@ -15,7 +52,7 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
""" XML helpers and macros """
from os import path from os import path
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
@ -33,22 +70,25 @@ def xmlroot(tree):
xmlchild(rootel, tree['children']) xmlchild(rootel, tree['children'])
return rootel return rootel
def xmlchild(parent, children): def xmlchild(parent, children):
""" Handling of children (ie non root) XML Nodes with/o text and """ Handling of children (ie non root) XML Nodes with/o text and
subchildren (recursive) """ subchildren (recursive) """
if isinstance(children, str): if isinstance(children, str):
parent.text = children parent.text = children
elif isinstance(children, XMLDictElement): elif isinstance(children, XMLDictElement):
attrs = {unicode(k): unicode(v) for [k, v] in children.attrs.items()} attrs = dict(((str(k)), (str(v))) for [k, v] in children.attrs.items())
new_parent = ET.SubElement(parent, children.tag, attrs) new_parent = ET.SubElement(parent, children.tag, attrs)
subchildren = children.children subchildren = children.children
if subchildren: if subchildren:
xmlchild(new_parent, subchildren) xmlchild(new_parent, subchildren)
elif isinstance(children, list): elif isinstance(children, list):
map(partial(xmlchild, parent), children) list(map(partial(xmlchild, parent), children))
else: else:
raise TypeError('Invalid arguments for xmlchild') raise TypeError('Invalid arguments for xmlchild')
@_coconut_tco
def xmln(tag='', attrs={}, children=[]): def xmln(tag='', attrs={}, children=[]):
""" XMLDictElement building from dict object, with defaults """ """ XMLDictElement building from dict object, with defaults """
if isinstance(attrs, list): if isinstance(attrs, list):
@ -56,20 +96,21 @@ def xmln(tag='', attrs={}, children=[]):
attrs = {} attrs = {}
xmldictel = partial(XMLDictElement, tag, attrs) xmldictel = partial(XMLDictElement, tag, attrs)
if isinstance(children, str): if isinstance(children, str):
return xmldictel([children]) return _coconut_tail_call(xmldictel, [children,])
if isinstance(children, list): if isinstance(children, list):
return xmldictel(children) return _coconut_tail_call(xmldictel, children)
raise TypeError('Invalid arguments for xmln') raise TypeError('Invalid arguments for xmln')
def xml_write(filepath, tree, pretty=True):
def xml_write(filepath, tree, pretty=True, suffix='_views'):
""" Write XML file according to filename and given tree """ """ Write XML file according to filename and given tree """
if filepath.endswith('.py'): # if .pyc, no need to generate XML if filepath.endswith('.py'): # if .pyc, no need to generate XML
output_xml = ET.tostring(tree) output_xml = ET.tostring(tree)
if pretty: if pretty:
output_xml = minidom.parseString(output_xml).toprettyxml(indent=' ') output_xml = minidom.parseString(output_xml).toprettyxml(indent=' ')
output_path = path.abspath(filepath).split(u'/') output_path = path.abspath(filepath).split('/')
output_path[-1] = output_path[-1].replace(u'.py', u'_views.xml') output_path[-1] = output_path[-1].replace('.py', '%s.xml' % suffix)
output_path = u'/'.join(output_path) output_path = '/'.join(output_path)
with open(output_path, 'w') as output_file: with open(output_path, 'w') as output_file:
output_file.write(output_xml) output_file.write(output_xml)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,247 @@
# -*- coding: utf-8 -*-
#
# Copyright 2020 Fabien Bourgeois <fabien@yaltik.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
""" Odoo Helpers tests """
import unittest
import xml.etree.ElementTree as ET
from src.xml_base import XMLDictElement
import src.odoo_dsl as od
class TestOdooBase(unittest.TestCase):
""" Odoo Helpers tests """
def test_odoo(self):
""" Test odoo function """
element = od.odoo([])
self.assertIsInstance(element, ET.Element)
self.assertEqual(element.tag, 'odoo')
def test_data(self):
""" Test data function """
element = od.data([])
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'data')
self.assertEqual(element.attrs, {})
element = od.data({"one": "attribute"}, [])
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'data')
self.assertEqual(element.attrs, {"one": "attribute"})
def test_aliases(self):
""" Test simple aliases to xmln """
element = od.record({"one": "attribute"}, 'A child')
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'record')
self.assertEqual(element.attrs, {"one": "attribute"})
self.assertEqual(element.children, ['A child'])
element = od.tree()
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'tree')
def test_act_window_model(self):
""" Test act_window function """
element = od.act_window_model('sample.model', {'view_type': 'form'})
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'act_window')
self.assertEqual(element.attrs['view_type'], 'form')
self.assertEqual(element.attrs['id'], 'sample_model_view_action')
self.assertEqual(element.attrs['res_model'], 'sample.model')
self.assertEqual(element.attrs['name'], 'Sample Model Action')
def test_menunitem_model(self):
""" Test menuitem function """
element = od.menuitem_model('sample.model', {'groups': 'base.user_employee'})
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'menuitem')
self.assertEqual(element.attrs['groups'], 'base.user_employee')
self.assertEqual(element.attrs['id'], 'sample_model_menu')
self.assertEqual(element.attrs['action'], 'sample_model_view_action')
def test_attribute(self):
""" Test attribute function """
element = od.attribute('invisible', "1")
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'attribute')
self.assertEqual(element.attrs['name'], 'invisible')
self.assertEqual(element.children, ["1"])
def test_fields(self):
""" Test fields function """
element = od.field({"one": "attribute"}, 'A child')
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'field')
element = od.field_name('A name')
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'field')
self.assertEqual(element.attrs['name'], 'name')
self.assertEqual(element.children, ['A name'])
element = od.field_model('sample.model')
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'field')
self.assertEqual(element.attrs['name'], 'model')
self.assertEqual(element.children, ['sample.model'])
element = od.field_inherit('module.xml_view')
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'field')
self.assertEqual(element.attrs['name'], 'inherit_id')
self.assertEqual(element.attrs['ref'], 'module.xml_view')
self.assertFalse(element.children)
element = od.field_arch()
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'field')
self.assertEqual(element.attrs['name'], 'arch')
self.assertEqual(element.attrs['type'], 'xml')
self.assertFalse(element.children)
def test_view(self):
""" Test view function """
element = od.view('view_xmlid', [])
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'record')
self.assertEqual(element.attrs['id'], 'view_xmlid')
self.assertEqual(element.attrs['model'], 'ir.ui.view')
self.assertFalse(element.children)
def test_view_def(self):
""" Test view_def function """
element = od.view_def('view_xmlid', 'View', 'sample.model', [])
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'record')
self.assertEqual(element.attrs['id'], 'view_xmlid')
self.assertEqual(element.attrs['model'], 'ir.ui.view')
self.assertEqual((len(element.children)), 3)
self.assertIsInstance(element.children[0], XMLDictElement)
self.assertEqual(element.children[0].tag, 'field')
self.assertEqual(element.children[0].attrs['name'], 'name')
self.assertEqual(element.children[0].children, ['View'])
self.assertIsInstance(element.children[1], XMLDictElement)
self.assertEqual(element.children[1].tag, 'field')
self.assertEqual(element.children[1].attrs['name'], 'model')
self.assertEqual(element.children[1].children, ['sample.model'])
self.assertIsInstance(element.children[2], XMLDictElement)
self.assertEqual(element.children[2].tag, 'field')
self.assertEqual(element.children[2].attrs['name'], 'arch')
self.assertEqual(element.children[2].attrs['type'], 'xml')
self.assertFalse(element.children[2].children)
def test_view_new(self):
""" Test view_new function """
element = od.view_new('tree', 'sample.model', [])
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'record')
self.assertEqual(element.attrs['id'], 'sample_model_view_tree')
self.assertEqual(element.attrs['model'], 'ir.ui.view')
self.assertEqual((len(element.children)), 3)
self.assertIsInstance(element.children[0], XMLDictElement)
self.assertEqual(element.children[0].tag, 'field')
self.assertEqual(element.children[0].attrs['name'], 'name')
self.assertEqual(element.children[0].children, ['Sample Model Tree'])
self.assertIsInstance(element.children[1], XMLDictElement)
self.assertEqual(element.children[1].tag, 'field')
self.assertEqual(element.children[1].attrs['name'], 'model')
self.assertEqual(element.children[1].children, ['sample.model'])
self.assertIsInstance(element.children[2], XMLDictElement)
self.assertEqual(element.children[2].tag, 'field')
self.assertEqual(element.children[2].attrs['name'], 'arch')
self.assertEqual(element.children[2].attrs['type'], 'xml')
self.assertFalse(element.children[2].children)
def test_view_inherit(self):
""" Test view_inherit function """
element = od.view_inherit('odoo.addons.module', 'sample.model', 'parent.view', [])
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'record')
self.assertEqual(element.attrs['id'], 'view_inherit_module')
self.assertEqual(element.attrs['model'], 'ir.ui.view')
self.assertEqual((len(element.children)), 4)
self.assertIsInstance(element.children[0], XMLDictElement)
self.assertEqual(element.children[0].tag, 'field')
self.assertEqual(element.children[0].attrs['name'], 'name')
self.assertEqual(element.children[0].children, ['Sample Model Adaptations'])
self.assertIsInstance(element.children[1], XMLDictElement)
self.assertEqual(element.children[1].tag, 'field')
self.assertEqual(element.children[1].attrs['name'], 'model')
self.assertEqual(element.children[1].children, ['sample.model'])
self.assertIsInstance(element.children[2], XMLDictElement)
self.assertEqual(element.children[2].tag, 'field')
self.assertEqual(element.children[2].attrs['name'], 'inherit_id')
self.assertFalse(element.children[2].children)
self.assertIsInstance(element.children[3], XMLDictElement)
self.assertEqual(element.children[3].tag, 'field')
self.assertEqual(element.children[3].attrs['name'], 'arch')
self.assertEqual(element.children[3].attrs['type'], 'xml')
self.assertFalse(element.children[3].children)
def test_action_server_code(self):
""" Test action_server_code function """
element = od.action_server_code('sample.xmlid', 'Code', 'sample.model',
'''record.do_something()''')
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'record')
self.assertEqual(element.attrs['id'], 'sample.xmlid')
self.assertEqual(element.attrs['model'], 'ir.actions.server')
self.assertEqual((len(element.children)), 4)
self.assertIsInstance(element.children[0], XMLDictElement)
self.assertEqual(element.children[0].tag, 'field')
self.assertEqual(element.children[0].attrs['name'], 'name')
self.assertEqual(element.children[0].children, ['Code'])
self.assertIsInstance(element.children[1], XMLDictElement)
self.assertEqual(element.children[1].tag, 'field')
self.assertEqual(element.children[1].attrs['name'], 'model_id')
self.assertEqual(element.children[1].attrs['ref'], 'sample.model')
self.assertFalse(element.children[1].children)
self.assertEqual(element.children[2].tag, 'field')
self.assertEqual(element.children[2].attrs['name'], 'state')
self.assertEqual(element.children[2].children, ['code'])
self.assertEqual(element.children[3].tag, 'field')
self.assertEqual(element.children[3].attrs['name'], 'code')
self.assertEqual(element.children[3].children, ['record.do_something()'])
def test_client_action_multi(self):
""" Test client_action_multi function """
element = od.client_action_multi('sample.xmlid', 'Multi', 'sample.model', 'sample.action')
self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'record')
self.assertEqual(element.attrs['id'], 'sample.xmlid')
self.assertEqual(element.attrs['model'], 'ir.values')
self.assertEqual((len(element.children)), 4)
self.assertIsInstance(element.children[0], XMLDictElement)
self.assertEqual(element.children[0].tag, 'field')
self.assertEqual(element.children[0].attrs['name'], 'name')
self.assertEqual(element.children[0].children, ['Multi'])
self.assertIsInstance(element.children[1], XMLDictElement)
self.assertEqual(element.children[1].tag, 'field')
self.assertEqual(element.children[1].attrs['name'], 'key2')
self.assertEqual(element.children[1].attrs['eval'], "'client_action_multi'")
self.assertFalse(element.children[1].children)
self.assertEqual(element.children[2].tag, 'field')
self.assertEqual(element.children[2].attrs['name'], 'model')
self.assertEqual(element.children[2].attrs['eval'], "'sample.model'")
self.assertEqual(element.children[3].tag, 'field')
self.assertEqual(element.children[3].attrs['name'], 'value')
self.assertEqual(element.children[3].attrs['eval'], "'ir.actions.server,%d'%sample.action")
if __name__ == '__main__':
unittest.main()

View File

@ -1,3 +1,40 @@
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# __coconut_hash__ = 0x22cbaa1
# Compiled with Coconut version 2.1.1 [The Spanish Inquisition]
""" Odoo Helpers tests """
# Coconut Header: -------------------------------------------------------------
from __future__ import print_function, absolute_import, unicode_literals, division
import sys as _coconut_sys, os as _coconut_os
_coconut_file_dir = _coconut_os.path.dirname(_coconut_os.path.abspath(__file__))
_coconut_cached_module = _coconut_sys.modules.get(b"__coconut__")
if _coconut_cached_module is not None and _coconut_os.path.dirname(_coconut_cached_module.__file__) != _coconut_file_dir: # type: ignore
del _coconut_sys.modules[b"__coconut__"]
_coconut_sys.path.insert(0, _coconut_file_dir)
_coconut_module_name = _coconut_os.path.splitext(_coconut_os.path.basename(_coconut_file_dir))[0]
if _coconut_module_name and _coconut_module_name[0].isalpha() and all(c.isalpha() or c.isdigit() for c in _coconut_module_name) and "__init__.py" in _coconut_os.listdir(_coconut_file_dir):
_coconut_full_module_name = str(_coconut_module_name + ".__coconut__")
import __coconut__ as _coconut__coconut__
_coconut__coconut__.__name__ = _coconut_full_module_name
for _coconut_v in vars(_coconut__coconut__).values():
if getattr(_coconut_v, "__module__", None) == b"__coconut__":
try:
_coconut_v.__module__ = _coconut_full_module_name
except AttributeError:
_coconut_v_type = type(_coconut_v)
if getattr(_coconut_v_type, "__module__", None) == b"__coconut__":
_coconut_v_type.__module__ = _coconut_full_module_name
_coconut_sys.modules[_coconut_full_module_name] = _coconut__coconut__
from __coconut__ import *
from __coconut__ import _coconut_tail_call, _coconut_tco, _coconut_call_set_names, _coconut_handle_cls_kwargs, _coconut_handle_cls_stargs, _namedtuple_of, _coconut, _coconut_super, _coconut_MatchError, _coconut_iter_getitem, _coconut_base_compose, _coconut_forward_compose, _coconut_back_compose, _coconut_forward_star_compose, _coconut_back_star_compose, _coconut_forward_dubstar_compose, _coconut_back_dubstar_compose, _coconut_pipe, _coconut_star_pipe, _coconut_dubstar_pipe, _coconut_back_pipe, _coconut_back_star_pipe, _coconut_back_dubstar_pipe, _coconut_none_pipe, _coconut_none_star_pipe, _coconut_none_dubstar_pipe, _coconut_bool_and, _coconut_bool_or, _coconut_none_coalesce, _coconut_minus, _coconut_map, _coconut_partial, _coconut_get_function_match_error, _coconut_base_pattern_func, _coconut_addpattern, _coconut_sentinel, _coconut_assert, _coconut_raise, _coconut_mark_as_match, _coconut_reiterable, _coconut_self_match_types, _coconut_dict_merge, _coconut_exec, _coconut_comma_op, _coconut_multi_dim_arr, _coconut_mk_anon_namedtuple, _coconut_matmul
_coconut_sys.path.pop(0)
# Compiled Coconut: -----------------------------------------------------------
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright 2020 Fabien Bourgeois <fabien@yaltik.com> # Copyright 2020 Fabien Bourgeois <fabien@yaltik.com>
@ -15,7 +52,7 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
""" Odoo Helpers tests """
import unittest import unittest
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
@ -31,6 +68,7 @@ class TestOdooBase(unittest.TestCase):
self.assertIsInstance(element, ET.Element) self.assertIsInstance(element, ET.Element)
self.assertEqual(element.tag, 'odoo') self.assertEqual(element.tag, 'odoo')
def test_data(self): def test_data(self):
""" Test data function """ """ Test data function """
element = od.data([]) element = od.data([])
@ -43,18 +81,20 @@ class TestOdooBase(unittest.TestCase):
self.assertEqual(element.tag, 'data') self.assertEqual(element.tag, 'data')
self.assertEqual(element.attrs, {"one": "attribute"}) self.assertEqual(element.attrs, {"one": "attribute"})
def test_aliases(self): def test_aliases(self):
""" Test simple aliases to xmln """ """ Test simple aliases to xmln """
element = od.record({"one": "attribute"}, 'A child') element = od.record({"one": "attribute"}, 'A child')
self.assertIsInstance(element, XMLDictElement) self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'record') self.assertEqual(element.tag, 'record')
self.assertEqual(element.attrs, {"one": "attribute"}) self.assertEqual(element.attrs, {"one": "attribute"})
self.assertEqual(element.children, ['A child']) self.assertEqual(element.children, ['A child',])
element = od.tree() element = od.tree()
self.assertIsInstance(element, XMLDictElement) self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'tree') self.assertEqual(element.tag, 'tree')
def test_act_window_model(self): def test_act_window_model(self):
""" Test act_window function """ """ Test act_window function """
element = od.act_window_model('sample.model', {'view_type': 'form'}) element = od.act_window_model('sample.model', {'view_type': 'form'})
@ -65,6 +105,7 @@ class TestOdooBase(unittest.TestCase):
self.assertEqual(element.attrs['res_model'], 'sample.model') self.assertEqual(element.attrs['res_model'], 'sample.model')
self.assertEqual(element.attrs['name'], 'Sample Model Action') self.assertEqual(element.attrs['name'], 'Sample Model Action')
def test_menunitem_model(self): def test_menunitem_model(self):
""" Test menuitem function """ """ Test menuitem function """
element = od.menuitem_model('sample.model', {'groups': 'base.user_employee'}) element = od.menuitem_model('sample.model', {'groups': 'base.user_employee'})
@ -74,13 +115,15 @@ class TestOdooBase(unittest.TestCase):
self.assertEqual(element.attrs['id'], 'sample_model_menu') self.assertEqual(element.attrs['id'], 'sample_model_menu')
self.assertEqual(element.attrs['action'], 'sample_model_view_action') self.assertEqual(element.attrs['action'], 'sample_model_view_action')
def test_attribute(self): def test_attribute(self):
""" Test attribute function """ """ Test attribute function """
element = od.attribute('invisible', "1") element = od.attribute('invisible', "1")
self.assertIsInstance(element, XMLDictElement) self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'attribute') self.assertEqual(element.tag, 'attribute')
self.assertEqual(element.attrs['name'], 'invisible') self.assertEqual(element.attrs['name'], 'invisible')
self.assertEqual(element.children, ["1"]) self.assertEqual(element.children, ["1",])
def test_fields(self): def test_fields(self):
""" Test fields function """ """ Test fields function """
@ -92,13 +135,13 @@ class TestOdooBase(unittest.TestCase):
self.assertIsInstance(element, XMLDictElement) self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'field') self.assertEqual(element.tag, 'field')
self.assertEqual(element.attrs['name'], 'name') self.assertEqual(element.attrs['name'], 'name')
self.assertEqual(element.children, ['A name']) self.assertEqual(element.children, ['A name',])
element = od.field_model('sample.model') element = od.field_model('sample.model')
self.assertIsInstance(element, XMLDictElement) self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'field') self.assertEqual(element.tag, 'field')
self.assertEqual(element.attrs['name'], 'model') self.assertEqual(element.attrs['name'], 'model')
self.assertEqual(element.children, ['sample.model']) self.assertEqual(element.children, ['sample.model',])
element = od.field_inherit('module.xml_view') element = od.field_inherit('module.xml_view')
self.assertIsInstance(element, XMLDictElement) self.assertIsInstance(element, XMLDictElement)
@ -114,6 +157,7 @@ class TestOdooBase(unittest.TestCase):
self.assertEqual(element.attrs['type'], 'xml') self.assertEqual(element.attrs['type'], 'xml')
self.assertFalse(element.children) self.assertFalse(element.children)
def test_view(self): def test_view(self):
""" Test view function """ """ Test view function """
element = od.view('view_xmlid', []) element = od.view('view_xmlid', [])
@ -123,6 +167,7 @@ class TestOdooBase(unittest.TestCase):
self.assertEqual(element.attrs['model'], 'ir.ui.view') self.assertEqual(element.attrs['model'], 'ir.ui.view')
self.assertFalse(element.children) self.assertFalse(element.children)
def test_view_def(self): def test_view_def(self):
""" Test view_def function """ """ Test view_def function """
element = od.view_def('view_xmlid', 'View', 'sample.model', []) element = od.view_def('view_xmlid', 'View', 'sample.model', [])
@ -134,17 +179,18 @@ class TestOdooBase(unittest.TestCase):
self.assertIsInstance(element.children[0], XMLDictElement) self.assertIsInstance(element.children[0], XMLDictElement)
self.assertEqual(element.children[0].tag, 'field') self.assertEqual(element.children[0].tag, 'field')
self.assertEqual(element.children[0].attrs['name'], 'name') self.assertEqual(element.children[0].attrs['name'], 'name')
self.assertEqual(element.children[0].children, ['View']) self.assertEqual(element.children[0].children, ['View',])
self.assertIsInstance(element.children[1], XMLDictElement) self.assertIsInstance(element.children[1], XMLDictElement)
self.assertEqual(element.children[1].tag, 'field') self.assertEqual(element.children[1].tag, 'field')
self.assertEqual(element.children[1].attrs['name'], 'model') self.assertEqual(element.children[1].attrs['name'], 'model')
self.assertEqual(element.children[1].children, ['sample.model']) self.assertEqual(element.children[1].children, ['sample.model',])
self.assertIsInstance(element.children[2], XMLDictElement) self.assertIsInstance(element.children[2], XMLDictElement)
self.assertEqual(element.children[2].tag, 'field') self.assertEqual(element.children[2].tag, 'field')
self.assertEqual(element.children[2].attrs['name'], 'arch') self.assertEqual(element.children[2].attrs['name'], 'arch')
self.assertEqual(element.children[2].attrs['type'], 'xml') self.assertEqual(element.children[2].attrs['type'], 'xml')
self.assertFalse(element.children[2].children) self.assertFalse(element.children[2].children)
def test_view_new(self): def test_view_new(self):
""" Test view_new function """ """ Test view_new function """
element = od.view_new('tree', 'sample.model', []) element = od.view_new('tree', 'sample.model', [])
@ -156,17 +202,18 @@ class TestOdooBase(unittest.TestCase):
self.assertIsInstance(element.children[0], XMLDictElement) self.assertIsInstance(element.children[0], XMLDictElement)
self.assertEqual(element.children[0].tag, 'field') self.assertEqual(element.children[0].tag, 'field')
self.assertEqual(element.children[0].attrs['name'], 'name') self.assertEqual(element.children[0].attrs['name'], 'name')
self.assertEqual(element.children[0].children, ['Sample Model Tree']) self.assertEqual(element.children[0].children, ['Sample Model Tree',])
self.assertIsInstance(element.children[1], XMLDictElement) self.assertIsInstance(element.children[1], XMLDictElement)
self.assertEqual(element.children[1].tag, 'field') self.assertEqual(element.children[1].tag, 'field')
self.assertEqual(element.children[1].attrs['name'], 'model') self.assertEqual(element.children[1].attrs['name'], 'model')
self.assertEqual(element.children[1].children, ['sample.model']) self.assertEqual(element.children[1].children, ['sample.model',])
self.assertIsInstance(element.children[2], XMLDictElement) self.assertIsInstance(element.children[2], XMLDictElement)
self.assertEqual(element.children[2].tag, 'field') self.assertEqual(element.children[2].tag, 'field')
self.assertEqual(element.children[2].attrs['name'], 'arch') self.assertEqual(element.children[2].attrs['name'], 'arch')
self.assertEqual(element.children[2].attrs['type'], 'xml') self.assertEqual(element.children[2].attrs['type'], 'xml')
self.assertFalse(element.children[2].children) self.assertFalse(element.children[2].children)
def test_view_inherit(self): def test_view_inherit(self):
""" Test view_inherit function """ """ Test view_inherit function """
element = od.view_inherit('odoo.addons.module', 'sample.model', 'parent.view', []) element = od.view_inherit('odoo.addons.module', 'sample.model', 'parent.view', [])
@ -178,11 +225,11 @@ class TestOdooBase(unittest.TestCase):
self.assertIsInstance(element.children[0], XMLDictElement) self.assertIsInstance(element.children[0], XMLDictElement)
self.assertEqual(element.children[0].tag, 'field') self.assertEqual(element.children[0].tag, 'field')
self.assertEqual(element.children[0].attrs['name'], 'name') self.assertEqual(element.children[0].attrs['name'], 'name')
self.assertEqual(element.children[0].children, ['Sample Model Adaptations']) self.assertEqual(element.children[0].children, ['Sample Model Adaptations',])
self.assertIsInstance(element.children[1], XMLDictElement) self.assertIsInstance(element.children[1], XMLDictElement)
self.assertEqual(element.children[1].tag, 'field') self.assertEqual(element.children[1].tag, 'field')
self.assertEqual(element.children[1].attrs['name'], 'model') self.assertEqual(element.children[1].attrs['name'], 'model')
self.assertEqual(element.children[1].children, ['sample.model']) self.assertEqual(element.children[1].children, ['sample.model',])
self.assertIsInstance(element.children[2], XMLDictElement) self.assertIsInstance(element.children[2], XMLDictElement)
self.assertEqual(element.children[2].tag, 'field') self.assertEqual(element.children[2].tag, 'field')
self.assertEqual(element.children[2].attrs['name'], 'inherit_id') self.assertEqual(element.children[2].attrs['name'], 'inherit_id')
@ -193,10 +240,10 @@ class TestOdooBase(unittest.TestCase):
self.assertEqual(element.children[3].attrs['type'], 'xml') self.assertEqual(element.children[3].attrs['type'], 'xml')
self.assertFalse(element.children[3].children) self.assertFalse(element.children[3].children)
def test_action_server_code(self): def test_action_server_code(self):
""" Test action_server_code function """ """ Test action_server_code function """
element = od.action_server_code('sample.xmlid', 'Code', 'sample.model', element = od.action_server_code('sample.xmlid', 'Code', 'sample.model', '''record.do_something()''')
'''record.do_something()''')
self.assertIsInstance(element, XMLDictElement) self.assertIsInstance(element, XMLDictElement)
self.assertEqual(element.tag, 'record') self.assertEqual(element.tag, 'record')
self.assertEqual(element.attrs['id'], 'sample.xmlid') self.assertEqual(element.attrs['id'], 'sample.xmlid')
@ -205,7 +252,7 @@ class TestOdooBase(unittest.TestCase):
self.assertIsInstance(element.children[0], XMLDictElement) self.assertIsInstance(element.children[0], XMLDictElement)
self.assertEqual(element.children[0].tag, 'field') self.assertEqual(element.children[0].tag, 'field')
self.assertEqual(element.children[0].attrs['name'], 'name') self.assertEqual(element.children[0].attrs['name'], 'name')
self.assertEqual(element.children[0].children, ['Code']) self.assertEqual(element.children[0].children, ['Code',])
self.assertIsInstance(element.children[1], XMLDictElement) self.assertIsInstance(element.children[1], XMLDictElement)
self.assertEqual(element.children[1].tag, 'field') self.assertEqual(element.children[1].tag, 'field')
self.assertEqual(element.children[1].attrs['name'], 'model_id') self.assertEqual(element.children[1].attrs['name'], 'model_id')
@ -213,10 +260,11 @@ class TestOdooBase(unittest.TestCase):
self.assertFalse(element.children[1].children) self.assertFalse(element.children[1].children)
self.assertEqual(element.children[2].tag, 'field') self.assertEqual(element.children[2].tag, 'field')
self.assertEqual(element.children[2].attrs['name'], 'state') self.assertEqual(element.children[2].attrs['name'], 'state')
self.assertEqual(element.children[2].children, ['code']) self.assertEqual(element.children[2].children, ['code',])
self.assertEqual(element.children[3].tag, 'field') self.assertEqual(element.children[3].tag, 'field')
self.assertEqual(element.children[3].attrs['name'], 'code') self.assertEqual(element.children[3].attrs['name'], 'code')
self.assertEqual(element.children[3].children, ['record.do_something()']) self.assertEqual(element.children[3].children, ['record.do_something()',])
def test_client_action_multi(self): def test_client_action_multi(self):
""" Test client_action_multi function """ """ Test client_action_multi function """
@ -229,7 +277,7 @@ class TestOdooBase(unittest.TestCase):
self.assertIsInstance(element.children[0], XMLDictElement) self.assertIsInstance(element.children[0], XMLDictElement)
self.assertEqual(element.children[0].tag, 'field') self.assertEqual(element.children[0].tag, 'field')
self.assertEqual(element.children[0].attrs['name'], 'name') self.assertEqual(element.children[0].attrs['name'], 'name')
self.assertEqual(element.children[0].children, ['Multi']) self.assertEqual(element.children[0].children, ['Multi',])
self.assertIsInstance(element.children[1], XMLDictElement) self.assertIsInstance(element.children[1], XMLDictElement)
self.assertEqual(element.children[1].tag, 'field') self.assertEqual(element.children[1].tag, 'field')
self.assertEqual(element.children[1].attrs['name'], 'key2') self.assertEqual(element.children[1].attrs['name'], 'key2')
@ -243,5 +291,7 @@ class TestOdooBase(unittest.TestCase):
self.assertEqual(element.children[3].attrs['eval'], "'ir.actions.server,%d'%sample.action") self.assertEqual(element.children[3].attrs['eval'], "'ir.actions.server,%d'%sample.action")
_coconut_call_set_names(TestOdooBase)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -0,0 +1,129 @@
# -*- coding: utf-8 -*-
#
# Copyright 2020 Fabien Bourgeois <fabien@yaltik.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
""" XML Helpers tests """
from functools import partial
import unittest
import xml.etree.ElementTree as ET
from os import unlink
from src.xml_base import xmln, xmlroot, xmlchild, xml_write
class TestXMLBase(unittest.TestCase):
""" XML Helpers tests """
def test_xmln(self):
""" Text xmln """
# Tags
self.assertDictEqual(xmln()._asdict(), {'tag': '', 'attrs': {}, 'children': []})
self.assertEqual(xmln('a tag').tag, 'a tag')
# Attrs
self.assertDictEqual(xmln(attrs={'a good': 'one'}).attrs, {'a good': 'one'})
# Childrens
self.assertListEqual(xmln(children=[1, 2, 3]).children, [1, 2, 3])
self.assertListEqual(xmln(children='Some text').children, ['Some text'])
with self.assertRaisesRegexp(TypeError, 'Invalid arguments'):
xmln(children=False)
# Ensure that only children after tags is managed
element = xmln('tag', {'something': 'inside'})
self.assertIsInstance(element.attrs, dict)
self.assertIsInstance(element.children, list)
element = xmln('tag', ['something', 'inside'])
self.assertIsInstance(element.attrs, dict)
self.assertIsInstance(element.children, list)
def test_xmlchild(self):
""" Test xmlchild """
parent = xmlroot({'tag': 'root', 'attrs': {}, 'children': []})
xmlc_par = partial(xmlchild, parent)
# Bad arguments
with self.assertRaisesRegexp(TypeError, 'Invalid arguments for xmlchild'):
xmlc_par(False)
# Need XMLDictElement, not dict
with self.assertRaisesRegexp(TypeError, 'Invalid arguments for xmlchild'):
xmlc_par([{'tag': 't', 'attrs': {'a': 'b'}, 'children': []}])
xmlc_par(['some text'])
self.assertEqual(parent.text, 'some text')
xmlc_par([xmln('t', {'a': 'b'}, [])])
child = parent.iter('t').next()
self.assertEqual(child.tag, 't')
self.assertDictEqual(child.attrib, {'a': 'b'})
self.assertListEqual(list(child), [])
xmlc_par([xmln('t2', {1: 2}, [])])
child = parent.iter('t2').next()
self.assertDictEqual(child.attrib, {'1': '2'})
xmlc_par([xmln('tchildren', {}, [xmln('subchild', {}, [])])])
child = parent.iter('tchildren').next()
subchildren = list(child)
self.assertEqual(len(subchildren), 1)
self.assertEqual(subchildren[0].tag, 'subchild')
def test_xmlroot(self):
""" Test xmlroot """
root = xmlroot({'tag': 'root', 'attrs': {}, 'children': []})
self.assertIsInstance(root, ET.Element)
with self.assertRaisesRegexp(TypeError, 'no attribute'):
xmlroot(False)
with self.assertRaisesRegexp(KeyError, 'tag'):
xmlroot({})
with self.assertRaisesRegexp(KeyError, 'attrs'):
xmlroot({'tag': 'root'})
def test_xml_write(self):
""" test xml_write """
children = [xmln('child1', {'attr': 'value'}, []),
xmln('child2', {}, "Some text")]
tree = xmlroot({'tag': 'root', 'attrs': {}, 'children': children})
xmlw = lambda p: xml_write(p, tree)
self.assertIsNone(xmlw('/badpath'))
self.assertIsNone(xmlw('/bad.ext'))
xmlw(__file__)
filepath = __file__.replace('.py', '_views.xml')
with open(filepath, 'r') as output_file:
output_xml = output_file.read()
self.assertIn('<?xml version', output_xml)
self.assertIn('<root>', output_xml)
self.assertIn('<child1 attr="value"/>', output_xml)
self.assertIn('<child2>Some text</child2>', output_xml)
unlink(filepath)
xml_write(__file__, tree, suffix='_data')
filepath = __file__.replace('.py', '_data.xml')
with open(filepath, 'r') as output_file:
output_xml = output_file.read()
self.assertIn('<?xml version', output_xml)
self.assertIn('<root>', output_xml)
self.assertIn('<child1 attr="value"/>', output_xml)
self.assertIn('<child2>Some text</child2>', output_xml)
unlink(filepath)
if __name__ == '__main__':
unittest.main()

View File

@ -1,3 +1,40 @@
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# __coconut_hash__ = 0x45f68d1d
# Compiled with Coconut version 2.1.1 [The Spanish Inquisition]
""" XML Helpers tests """
# Coconut Header: -------------------------------------------------------------
from __future__ import print_function, absolute_import, unicode_literals, division
import sys as _coconut_sys, os as _coconut_os
_coconut_file_dir = _coconut_os.path.dirname(_coconut_os.path.abspath(__file__))
_coconut_cached_module = _coconut_sys.modules.get(b"__coconut__")
if _coconut_cached_module is not None and _coconut_os.path.dirname(_coconut_cached_module.__file__) != _coconut_file_dir: # type: ignore
del _coconut_sys.modules[b"__coconut__"]
_coconut_sys.path.insert(0, _coconut_file_dir)
_coconut_module_name = _coconut_os.path.splitext(_coconut_os.path.basename(_coconut_file_dir))[0]
if _coconut_module_name and _coconut_module_name[0].isalpha() and all(c.isalpha() or c.isdigit() for c in _coconut_module_name) and "__init__.py" in _coconut_os.listdir(_coconut_file_dir):
_coconut_full_module_name = str(_coconut_module_name + ".__coconut__")
import __coconut__ as _coconut__coconut__
_coconut__coconut__.__name__ = _coconut_full_module_name
for _coconut_v in vars(_coconut__coconut__).values():
if getattr(_coconut_v, "__module__", None) == b"__coconut__":
try:
_coconut_v.__module__ = _coconut_full_module_name
except AttributeError:
_coconut_v_type = type(_coconut_v)
if getattr(_coconut_v_type, "__module__", None) == b"__coconut__":
_coconut_v_type.__module__ = _coconut_full_module_name
_coconut_sys.modules[_coconut_full_module_name] = _coconut__coconut__
from __coconut__ import *
from __coconut__ import _coconut_tail_call, _coconut_tco, _coconut_call_set_names, _coconut_handle_cls_kwargs, _coconut_handle_cls_stargs, _namedtuple_of, _coconut, _coconut_super, _coconut_MatchError, _coconut_iter_getitem, _coconut_base_compose, _coconut_forward_compose, _coconut_back_compose, _coconut_forward_star_compose, _coconut_back_star_compose, _coconut_forward_dubstar_compose, _coconut_back_dubstar_compose, _coconut_pipe, _coconut_star_pipe, _coconut_dubstar_pipe, _coconut_back_pipe, _coconut_back_star_pipe, _coconut_back_dubstar_pipe, _coconut_none_pipe, _coconut_none_star_pipe, _coconut_none_dubstar_pipe, _coconut_bool_and, _coconut_bool_or, _coconut_none_coalesce, _coconut_minus, _coconut_map, _coconut_partial, _coconut_get_function_match_error, _coconut_base_pattern_func, _coconut_addpattern, _coconut_sentinel, _coconut_assert, _coconut_raise, _coconut_mark_as_match, _coconut_reiterable, _coconut_self_match_types, _coconut_dict_merge, _coconut_exec, _coconut_comma_op, _coconut_multi_dim_arr, _coconut_mk_anon_namedtuple, _coconut_matmul
_coconut_sys.path.pop(0)
# Compiled Coconut: -----------------------------------------------------------
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright 2020 Fabien Bourgeois <fabien@yaltik.com> # Copyright 2020 Fabien Bourgeois <fabien@yaltik.com>
@ -15,13 +52,16 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
""" XML Helpers tests """
from functools import partial from functools import partial
import unittest import unittest
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from os import unlink from os import unlink
from src.xml_base import xmln, xmlroot, xmlchild, xml_write from src.xml_base import xmln
from src.xml_base import xmlroot
from src.xml_base import xmlchild
from src.xml_base import xml_write
class TestXMLBase(unittest.TestCase): class TestXMLBase(unittest.TestCase):
@ -36,7 +76,7 @@ class TestXMLBase(unittest.TestCase):
self.assertDictEqual(xmln(attrs={'a good': 'one'}).attrs, {'a good': 'one'}) self.assertDictEqual(xmln(attrs={'a good': 'one'}).attrs, {'a good': 'one'})
# Childrens # Childrens
self.assertListEqual(xmln(children=[1, 2, 3]).children, [1, 2, 3]) self.assertListEqual(xmln(children=[1, 2, 3]).children, [1, 2, 3])
self.assertListEqual(xmln(children='Some text').children, ['Some text']) self.assertListEqual(xmln(children='Some text').children, ['Some text',])
with self.assertRaisesRegexp(TypeError, 'Invalid arguments'): with self.assertRaisesRegexp(TypeError, 'Invalid arguments'):
xmln(children=False) xmln(children=False)
@ -51,6 +91,7 @@ class TestXMLBase(unittest.TestCase):
self.assertIsInstance(element.children, list) self.assertIsInstance(element.children, list)
def test_xmlchild(self): def test_xmlchild(self):
""" Test xmlchild """ """ Test xmlchild """
parent = xmlroot({'tag': 'root', 'attrs': {}, 'children': []}) parent = xmlroot({'tag': 'root', 'attrs': {}, 'children': []})
@ -61,34 +102,35 @@ class TestXMLBase(unittest.TestCase):
xmlc_par(False) xmlc_par(False)
# Need XMLDictElement, not dict # Need XMLDictElement, not dict
with self.assertRaisesRegexp(TypeError, 'Invalid arguments for xmlchild'): with self.assertRaisesRegexp(TypeError, 'Invalid arguments for xmlchild'):
xmlc_par([{'tag': 't', 'attrs': {'a': 'b'}, 'children': []}]) xmlc_par([{'tag': 't', 'attrs': {'a': 'b'}, 'children': []},])
xmlc_par(['some text']) xmlc_par(['some text',])
self.assertEqual(parent.text, 'some text') self.assertEqual(parent.text, 'some text')
xmlc_par([xmln('t', {'a': 'b'}, [])]) xmlc_par([xmln('t', {'a': 'b'}, []),])
child = parent.iter('t').next() child = parent.iter('t').next()
self.assertEqual(child.tag, 't') self.assertEqual(child.tag, 't')
self.assertDictEqual(child.attrib, {'a': 'b'}) self.assertDictEqual(child.attrib, {'a': 'b'})
self.assertListEqual(list(child), []) self.assertListEqual(list(child), [])
xmlc_par([xmln('t2', {1: 2}, [])]) xmlc_par([xmln('t2', {1: 2}, []),])
child = parent.iter('t2').next() child = parent.iter('t2').next()
self.assertDictEqual(child.attrib, {'1': '2'}) self.assertDictEqual(child.attrib, {'1': '2'})
xmlc_par([xmln('tchildren', {}, [xmln('subchild', {}, [])])]) xmlc_par([xmln('tchildren', {}, [xmln('subchild', {}, []),]),])
child = parent.iter('tchildren').next() child = parent.iter('tchildren').next()
subchildren = list(child) subchildren = list(child)
self.assertEqual(len(subchildren), 1) self.assertEqual(len(subchildren), 1)
self.assertEqual(subchildren[0].tag, 'subchild') self.assertEqual(subchildren[0].tag, 'subchild')
def test_xmlroot(self): def test_xmlroot(self):
""" Test xmlroot """ """ Test xmlroot """
root = xmlroot({'tag': 'root', 'attrs': {}, 'children': []}) root = xmlroot({'tag': 'root', 'attrs': {}, 'children': []})
self.assertIsInstance(root, ET.Element) self.assertIsInstance(root, ET.Element)
with self.assertRaisesRegexp(TypeError, 'has no attribute'): with self.assertRaisesRegexp(TypeError, 'no attribute'):
xmlroot(False) xmlroot(False)
with self.assertRaisesRegexp(KeyError, 'tag'): with self.assertRaisesRegexp(KeyError, 'tag'):
xmlroot({}) xmlroot({})
@ -96,10 +138,10 @@ class TestXMLBase(unittest.TestCase):
xmlroot({'tag': 'root'}) xmlroot({'tag': 'root'})
def test_xml_write(self): def test_xml_write(self):
""" test xml_write """ """ test xml_write """
children = [xmln('child1', {'attr': 'value'}, []), children = [xmln('child1', {'attr': 'value'}, []), xmln('child2', {}, "Some text")]
xmln('child2', {}, "Some text")]
tree = xmlroot({'tag': 'root', 'attrs': {}, 'children': children}) tree = xmlroot({'tag': 'root', 'attrs': {}, 'children': children})
xmlw = lambda p: xml_write(p, tree) xmlw = lambda p: xml_write(p, tree)
@ -115,6 +157,17 @@ class TestXMLBase(unittest.TestCase):
self.assertIn('<child1 attr="value"/>', output_xml) self.assertIn('<child1 attr="value"/>', output_xml)
self.assertIn('<child2>Some text</child2>', output_xml) self.assertIn('<child2>Some text</child2>', output_xml)
unlink(filepath) unlink(filepath)
xml_write(__file__, tree, suffix='_data')
filepath = __file__.replace('.py', '_data.xml')
with open(filepath, 'r') as output_file:
output_xml = output_file.read()
self.assertIn('<?xml version', output_xml)
self.assertIn('<root>', output_xml)
self.assertIn('<child1 attr="value"/>', output_xml)
self.assertIn('<child2>Some text</child2>', output_xml)
unlink(filepath)
_coconut_call_set_names(TestXMLBase)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()