Compare commits
No commits in common. "10.0" and "10.0-purepy" have entirely different histories.
10.0
...
10.0-purep
@ -1,13 +1,3 @@
|
||||
.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
|
||||
clean:
|
||||
find . -name '*.pyc' -delete
|
||||
@ -17,15 +7,3 @@ clean:
|
||||
test:
|
||||
python2 tests/test_xml_base.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 .
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2019-2025 Fabien Bourgeois <fabien@yaltik.com>
|
||||
# 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
|
||||
@ -19,11 +19,12 @@
|
||||
'name': 'Yaltik Odoo DSL base module and fns',
|
||||
'summary': 'Yaltik Odoo Domain Specific Language base module and functions',
|
||||
'description': """ Yaltik Odoo Domain Specific Language base module and functions """,
|
||||
'version': '10.0.0.5.19',
|
||||
'version': '10.0.0.4.0',
|
||||
'category': 'Yaltik',
|
||||
'author': 'Fabien Bourgeois',
|
||||
'license': 'AGPL-3',
|
||||
'application': False,
|
||||
'installable': True,
|
||||
'depends': ['base']
|
||||
'depends': ['base'],
|
||||
"external_dependencies": {'python' : ['function-pattern-matching']}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2019-2025 Fabien Bourgeois <fabien@yaltik.com>
|
||||
# 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
|
||||
@ -35,26 +35,16 @@ def data(*args):
|
||||
# Aliases
|
||||
function = lambda *args: xmln('function', *args)
|
||||
record = lambda *args: xmln('record', *args)
|
||||
delete = lambda *args: xmln('delete', *args)
|
||||
form = lambda *args: xmln('form', *args)
|
||||
tree = lambda *args: xmln('tree', *args)
|
||||
search = lambda *args: xmln('search', *args)
|
||||
template = lambda *args: xmln('template', *args)
|
||||
templates = lambda *args: xmln('templates', *args)
|
||||
kanban = lambda *args: xmln('kanban', *args)
|
||||
calendar = lambda *args: xmln('calendar', *args)
|
||||
activity = lambda *args: xmln('activity', *args)
|
||||
widget = lambda *args: xmln('widget', *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('.', '_'))
|
||||
if 'name' in attrs:
|
||||
name = attrs['name']
|
||||
else:
|
||||
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.update({'id': xmlid, 'name': name, 'res_model': model})
|
||||
return act_window(attrs_clone)
|
||||
@ -95,54 +85,18 @@ footer = lambda *args: xmln('footer', *args)
|
||||
sheet = lambda *args: xmln('sheet', *args)
|
||||
button = lambda *args: xmln('button', *args)
|
||||
p = lambda *args: xmln('p', *args)
|
||||
i = lambda *args: xmln('i', *args)
|
||||
t = lambda *args: xmln('t', *args)
|
||||
div = lambda *args: xmln('div', *args)
|
||||
span = lambda *args: xmln('span', *args)
|
||||
br = lambda *args: xmln('br', *args)
|
||||
h1 = lambda *args: xmln('h1', *args)
|
||||
h2 = lambda *args: xmln('h2', *args)
|
||||
h3 = lambda *args: xmln('h3', *args)
|
||||
h4 = lambda *args: xmln('h4', *args)
|
||||
h5 = lambda *args: xmln('h5', *args)
|
||||
ul = lambda *args: xmln('ul', *args)
|
||||
li = lambda *args: xmln('li', *args)
|
||||
label = lambda *args: xmln('label', *args)
|
||||
strong = lambda *args: xmln('strong', *args)
|
||||
small = lambda *args: xmln('small', *args)
|
||||
table = lambda *args: xmln('table', *args)
|
||||
tr = lambda *args: xmln('tr', *args)
|
||||
th = lambda *args: xmln('th', *args)
|
||||
td = lambda *args: xmln('td', *args)
|
||||
style = lambda *args: xmln('style', *args)
|
||||
|
||||
notebook = lambda *args: xmln('notebook', *args)
|
||||
page = lambda *args: xmln('page', *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)
|
||||
separator = lambda *args: xmln('separator', *args)
|
||||
|
||||
def filter_yes_no(field, str_yes=False, str_no=False):
|
||||
""" Double filter for boolean : True and False """
|
||||
res = []
|
||||
if str_yes:
|
||||
res.append(filter({'name': '%s_yes' % field, 'string': str_yes,
|
||||
'domain': "[('%s', '=', True)]" % field}))
|
||||
if str_no:
|
||||
res.append(filter({'name': '%s_no' % field, 'string': str_no,
|
||||
'domain': "[('%s', '=', False)]" % field}))
|
||||
return res
|
||||
|
||||
# Views
|
||||
view = lambda xmlid, children: record({'id': xmlid, 'model': 'ir.ui.view'}, children)
|
||||
|
@ -36,16 +36,16 @@ def xmlroot(tree):
|
||||
def xmlchild(parent, children):
|
||||
""" Handling of children (ie non root) XML Nodes with/o text and
|
||||
subchildren (recursive) """
|
||||
if isinstance(children, basestring):
|
||||
if isinstance(children, str):
|
||||
parent.text = children
|
||||
elif isinstance(children, XMLDictElement):
|
||||
attrs = {str(k): str(v) for [k, v] in children.attrs.items()}
|
||||
attrs = {unicode(k): unicode(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))
|
||||
map(partial(xmlchild, parent), children)
|
||||
else:
|
||||
raise TypeError('Invalid arguments for xmlchild')
|
||||
|
||||
@ -55,21 +55,21 @@ def xmln(tag='', attrs={}, children=[]):
|
||||
children = attrs
|
||||
attrs = {}
|
||||
xmldictel = partial(XMLDictElement, tag, attrs)
|
||||
if isinstance(children, basestring):
|
||||
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'):
|
||||
def xml_write(filepath, tree, pretty=True):
|
||||
""" 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)
|
||||
output_path = path.abspath(filepath).split(u'/')
|
||||
output_path[-1] = output_path[-1].replace(u'.py', u'_views.xml')
|
||||
output_path = u'/'.join(output_path)
|
||||
with open(output_path, 'w') as output_file:
|
||||
output_file.write(output_xml)
|
||||
|
@ -114,33 +114,6 @@ class TestOdooBase(unittest.TestCase):
|
||||
self.assertEqual(element.attrs['type'], 'xml')
|
||||
self.assertFalse(element.children)
|
||||
|
||||
def test_filter_yes_no(self):
|
||||
""" Test Filter Yes No """
|
||||
elements = od.filter_yes_no('some_field')
|
||||
self.assertIsInstance(elements, list)
|
||||
self.assertFalse(elements)
|
||||
|
||||
elements = od.filter_yes_no('some_field', 'Some field')
|
||||
self.assertEqual(len(elements), 1)
|
||||
self.assertIsInstance(elements[0], XMLDictElement)
|
||||
self.assertEqual(elements[0].tag, 'filter')
|
||||
self.assertEqual(elements[0].attrs['name'], 'some_field_yes')
|
||||
self.assertEqual(elements[0].attrs['string'], 'Some field')
|
||||
self.assertEqual(elements[0].attrs['domain'], "[('some_field', '=', True)]")
|
||||
|
||||
elements = od.filter_yes_no('some_field', 'Some field', 'Not some field')
|
||||
self.assertEqual(len(elements), 2)
|
||||
self.assertIsInstance(elements[0], XMLDictElement)
|
||||
self.assertEqual(elements[0].tag, 'filter')
|
||||
self.assertEqual(elements[0].attrs['name'], 'some_field_yes')
|
||||
self.assertEqual(elements[0].attrs['string'], 'Some field')
|
||||
self.assertEqual(elements[0].attrs['domain'], "[('some_field', '=', True)]")
|
||||
self.assertIsInstance(elements[1], XMLDictElement)
|
||||
self.assertEqual(elements[1].tag, 'filter')
|
||||
self.assertEqual(elements[1].attrs['name'], 'some_field_no')
|
||||
self.assertEqual(elements[1].attrs['string'], 'Not some field')
|
||||
self.assertEqual(elements[1].attrs['domain'], "[('some_field', '=', False)]")
|
||||
|
||||
def test_view(self):
|
||||
""" Test view function """
|
||||
element = od.view('view_xmlid', [])
|
||||
|
@ -88,7 +88,7 @@ class TestXMLBase(unittest.TestCase):
|
||||
root = xmlroot({'tag': 'root', 'attrs': {}, 'children': []})
|
||||
self.assertIsInstance(root, ET.Element)
|
||||
|
||||
with self.assertRaisesRegexp(TypeError, 'no attribute'):
|
||||
with self.assertRaisesRegexp(TypeError, 'has no attribute'):
|
||||
xmlroot(False)
|
||||
with self.assertRaisesRegexp(KeyError, 'tag'):
|
||||
xmlroot({})
|
||||
@ -115,15 +115,6 @@ class TestXMLBase(unittest.TestCase):
|
||||
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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user