From 170aa6a86ea3d6099d88270465dd74eeddccef0d Mon Sep 17 00:00:00 2001 From: Fabien BOURGEOIS Date: Thu, 30 Apr 2020 23:41:39 +0200 Subject: [PATCH] [REF][IMP][WIP]Yaltik DSL : refactor to coco odoo And new tests, enhancements.... WIP ! --- yaltik_dsl/{odoo.coco => odoo_dsl.coco} | 93 +++++++++------- yaltik_dsl/test_odoo.coco | 142 ++++++++++++++++++++++++ yaltik_dsl/test_xml_base.coco | 2 +- 3 files changed, 193 insertions(+), 44 deletions(-) rename yaltik_dsl/{odoo.coco => odoo_dsl.coco} (52%) create mode 100644 yaltik_dsl/test_odoo.coco diff --git a/yaltik_dsl/odoo.coco b/yaltik_dsl/odoo_dsl.coco similarity index 52% rename from yaltik_dsl/odoo.coco rename to yaltik_dsl/odoo_dsl.coco index ac7fe14..40fc3a3 100644 --- a/yaltik_dsl/odoo.coco +++ b/yaltik_dsl/odoo_dsl.coco @@ -17,68 +17,75 @@ """ Odoo XML DSL """ -from .xml_base import xmlroot, xmln +from typing import Text, Dict +from xml_base import XMLAttrs, XMLDictElement, xmlroot, xmln # XML helpers functions and macros -odoo = lambda *args: xmlroot(xmln('odoo', {}, *args)) +# Odoo root XML Node +def odoo(children: Dict) -> ET.Element = {'tag': 'odoo', 'attrs': {}, 'children': children} |> xmlroot +# Special data Node def data(*args): """ Allow optional args on data tag """ - if len(args) == 1: - return xmln('data', {}, *args) + if args |> len == 1: + {} |> args.insert$(0) where: args = args |> list return xmln('data', *args) -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) +# Aliases +def function(*args) -> XMLDictElement = xmln('function', *args) +def record(*args) -> XMLDictElement = 'record' |> xmln$(?, *args) +def form(*args) -> XMLDictElement = 'form' |> xmln$ <*| args +def tree(*args) -> XMLDictElement = 'tree' |> xmln$ <*| args +def search(*args) -> XMLDictElement = 'search' |> xmln$ <*| args -act_window = lambda *args: xmln('act_window', *args) - -def act_window_model(model, attrs): +# Actions +def act_window(*args) -> XMLDictElement = 'act_window' |> xmln$ <*| args +def act_window_model(model: Text, attrs: XMLAttrs) -> XMLDictElement: """ Build new act_window from model and args """ - model_und = model.replace('.', '_') - model_cap = ' '.join([w.capitalize() for w in model.split('.')]) - xmlid = '{:{}}'.format(model_und, '') + '_view_action' - name = '{:{}}'.format(model_cap, '') + ' Action' - attrs.update({'id': xmlid, 'name': name, 'res_model': model}) + xmlid = '%s_view_action' % (('.', '_') |*> model.replace) + name = '%s Action' % ('.' |> model.split |> map$(-> _.capitalize()) |> list |> ' '.join) + {'id': xmlid, 'name': name, 'res_model': model} |> attrs.update return act_window(attrs) -menuitem = lambda *args: xmln('menuitem', *args) - -def menuitem_model(model, attrs): +# Menus +def menuitem(*args) -> XMLDictElement = 'menuitem' |> xmln$ <*| args +def menuitem_model(model: Text, attrs: XMLAttrs) -> XMLDictElement: """ Build new menuitem from model and attrs """ - model_und = model.replace('.', '_') - actionid = '{:{}}'.format(model_und, '') + '_view_action' - xmlid = '{:{}}'.format(model_und, '') + '_men' - attrs.update({'id': xmlid, 'action': actionid}) + model_und = ('.', '_') |*> model.replace + xmlid = '%s_menu' % model_und + actionid = '%s_view_action' % model_und + {'id': xmlid, 'action': actionid} |> attrs.update return menuitem(attrs) +# Form aliases +def group(*args) -> XMLDictElement = 'group' |> xmln$ <*| args +def header(*args) -> XMLDictElement = 'header' |> xmln$ <*| args +def footer(*args) -> XMLDictElement = 'footer' |> xmln$ <*| args +def sheet(*args) -> XMLDictElement = 'sheet' |> xmln$ <*| args +def button(*args) -> XMLDictElement = 'button' |> xmln$ <*| args +def p(*args) -> XMLDictElement = 'p' |> xmln$ <*| args +def xpath(*args) -> XMLDictElement = 'xpath' |> xmln$ <*| args +def attribute(name: Text, value: Text) -> XMLDictElement: + return ('attribute', {'name': name}, [value]) |*> xmln -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 +def field(*args) -> XMLDictElement = 'field' |> xmln$ <*| args +def field_name(name: Text) -> XMLDictElement = ({'name': 'name'}, [name]) |*> field +def field_model(model: Text) -> XMLDictElement = ({'name': 'model'}, [model]) |*> field +def field_inherit(xmlid: Text) -> XMLDictElement: + return ({'name': 'inherit_id', 'ref': xmlid}, []) |*> field +def field_arch(*args) -> XMLDictElement = {'name': 'arch', 'type': 'xml'} |> field$ <*| args -field = lambda *args: xmln('field', *args) -field_name = lambda name: field({'name': 'name'}, [name]) -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 +def filter(*args) -> XMLDictElement = 'filter' |> xmln$ <*| args -filter = lambda *args: xmln('filter', *args) +# Views +def view(xmlid: Text, children: List) -> XMLDictElement: + return ({'id': xmlid, 'model': 'ir.ui.view'}, children) |*> record -view = lambda xmlid, children: record({'id': xmlid, 'model': 'ir.ui.view'}, children) - -def view_def(xmlid, name, model, arch): - """ View and first fields simplification with record xmlid, name, targeted model """ - return view(xmlid, [field_name(name), field_model(model), field_arch(arch)]) +def view_def(xmlid: Text, name: Text, model: Text, arch: List) -> XMLDictElement: + return (xmlid, [field_name(name), field_model(model), field_arch(arch)]) |*> view def view_new(view_type, model, arch): """ View : new view definition, based on type (form, tree, ...) and model ID """ diff --git a/yaltik_dsl/test_odoo.coco b/yaltik_dsl/test_odoo.coco new file mode 100644 index 0000000..1cc59ad --- /dev/null +++ b/yaltik_dsl/test_odoo.coco @@ -0,0 +1,142 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2020 Fabien Bourgeois +# +# 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 . + +""" Odoo Helpers tests """ + +import unittest +import xml.etree.ElementTree as ET +from xml_base import XMLDictElement +import odoo_dsl as od + +class TestOdooBase(unittest.TestCase): + """ Odoo Helpers tests """ + + def test_odoo(self): + element = od.odoo([]) + element `self.assertIsInstance` ET.Element + element.tag `self.assertEquals` 'odoo' + + def test_data(self): + element = od.data([]) + element `self.assertIsInstance` XMLDictElement + element.tag `self.assertEquals` 'data' + element.attrs `self.assertEquals` {} + + element = od.data({"one": "attribute"}, []) + element `self.assertIsInstance` XMLDictElement + element.tag `self.assertEquals` 'data' + element.attrs `self.assertEquals` {"one": "attribute"} + + def test_aliases(self): + """ Test simple aliases to xmln """ + element = od.record({"one": "attribute"}, 'A child') + element `self.assertIsInstance` XMLDictElement + element.tag `self.assertEquals` 'record' + element.attrs `self.assertEquals` {"one": "attribute"} + element.children `self.assertEquals` ['A child'] + + element = od.tree() + element `self.assertIsInstance` XMLDictElement + element.tag `self.assertEquals` 'tree' + + def test_act_window_model(self): + element = ('sample.model', {'view_type': 'form'}) |*> od.act_window_model + element `self.assertIsInstance` XMLDictElement + element.tag `self.assertEquals` 'act_window' + element.attrs['view_type'] `self.assertEquals` 'form' + element.attrs['id'] `self.assertEquals` 'sample_model_view_action' + element.attrs['res_model'] `self.assertEquals` 'sample.model' + element.attrs['name'] `self.assertEquals` 'Sample Model Action' + + def test_menunitem_model(self): + element = ('sample.model', {'groups': 'base.user_employee'}) |*> od.menuitem_model + element `self.assertIsInstance` XMLDictElement + element.tag `self.assertEquals` 'menuitem' + element.attrs['groups'] `self.assertEquals` 'base.user_employee' + element.attrs['id'] `self.assertEquals` 'sample_model_menu' + element.attrs['action'] `self.assertEquals` 'sample_model_view_action' + + def test_attribute(self): + element = od.attribute('invisible', "1") + element `self.assertIsInstance` XMLDictElement + element.tag `self.assertEquals` 'attribute' + element.attrs['name'] `self.assertEquals` 'invisible' + element.children `self.assertEquals` ["1"] + + def test_fields(self): + element = od.field({"one": "attribute"}, 'A child') + element `self.assertIsInstance` XMLDictElement + element.tag `self.assertEquals` 'field' + + element = 'A name' |> od.field_name + element `self.assertIsInstance` XMLDictElement + element.tag `self.assertEquals` 'field' + element.attrs['name'] `self.assertEquals` 'name' + element.children `self.assertEquals` ['A name'] + + element = 'sample.model' |> od.field_model + element `self.assertIsInstance` XMLDictElement + element.tag `self.assertEquals` 'field' + element.attrs['name'] `self.assertEquals` 'model' + element.children `self.assertEquals` ['sample.model'] + + element = 'module.xml_view' |> od.field_inherit + element `self.assertIsInstance` XMLDictElement + element.tag `self.assertEquals` 'field' + element.attrs['name'] `self.assertEquals` 'inherit_id' + element.attrs['ref'] `self.assertEquals` 'module.xml_view' + element.children |> self.assertFalse + + element = od.field_arch() + element `self.assertIsInstance` XMLDictElement + element.tag `self.assertEquals` 'field' + element.attrs['name'] `self.assertEquals` 'arch' + element.attrs['type'] `self.assertEquals` 'xml' + element.children |> self.assertFalse + + def test_views(self): + element = od.view('view_xmlid', []) + element `self.assertIsInstance` XMLDictElement + element.tag `self.assertEquals` 'record' + element.attrs['id'] `self.assertEquals` 'view_xmlid' + element.attrs['model'] `self.assertEquals` 'ir.ui.view' + element.children |> self.assertFalse + + element = od.view_def('view_xmlid', 'View', 'sample.model', []) + element `self.assertIsInstance` XMLDictElement + element.tag `self.assertEquals` 'record' + element.attrs['id'] `self.assertEquals` 'view_xmlid' + element.attrs['model'] `self.assertEquals` 'ir.ui.view' + (element.children |> len) `self.assertEquals` 3 + element.children[0] `self.assertIsInstance` XMLDictElement + element.children[0].tag `self.assertEquals` 'field' + element.children[0].attrs['name'] `self.assertEquals` 'name' + element.children[0].children `self.assertEquals` ['View'] + element.children[1] `self.assertIsInstance` XMLDictElement + element.children[1].tag `self.assertEquals` 'field' + element.children[1].attrs['name'] `self.assertEquals` 'model' + element.children[1].children `self.assertEquals` ['sample.model'] + element.children[2] `self.assertIsInstance` XMLDictElement + element.children[2].tag `self.assertEquals` 'field' + element.children[2].attrs['name'] `self.assertEquals` 'arch' + element.children[2].attrs['type'] `self.assertEquals` 'xml' + element.children[2].children |> self.assertFalse + + def test_actions(self): pass + +if __name__ == '__main__': + unittest.main() diff --git a/yaltik_dsl/test_xml_base.coco b/yaltik_dsl/test_xml_base.coco index 337d241..814ffee 100644 --- a/yaltik_dsl/test_xml_base.coco +++ b/yaltik_dsl/test_xml_base.coco @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright 2019-2020 Fabien Bourgeois +# Copyright 2020 Fabien Bourgeois # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as