From cfb99c113d135758f776dd44b781e89536bb133b Mon Sep 17 00:00:00 2001 From: Fabien BOURGEOIS Date: Thu, 30 Apr 2020 10:58:36 +0200 Subject: [PATCH] [REF][WIP]Yaltik DSL : new tests, refacoring of xml_base, ADTs --- yaltik_dsl/test_xml_base.coco | 34 +++++++----- yaltik_dsl/test_xml_base.py | 32 +++++++----- yaltik_dsl/xml_base.coco | 56 ++++++++++---------- yaltik_dsl/xml_base.py | 97 ++++++++++++++++------------------- 4 files changed, 114 insertions(+), 105 deletions(-) diff --git a/yaltik_dsl/test_xml_base.coco b/yaltik_dsl/test_xml_base.coco index d579fb5..4cd26cd 100644 --- a/yaltik_dsl/test_xml_base.coco +++ b/yaltik_dsl/test_xml_base.coco @@ -27,19 +27,19 @@ class TestXMLBase(unittest.TestCase): def test_xmln(self): # Tags - (xmln(), {'tag': '', 'attrs': {}, 'children': []}) |*> self.assertEquals - (xmln <| 'a tag' |> .get <| 'tag', 'a tag') |*> self.assertEquals + (xmln()._asdict(), {'tag': '', 'attrs': {}, 'children': []}) |*> self.assertEquals + (xmln <| 'a tag' |> getattr$(?, 'tag'), 'a tag') |*> self.assertEquals # Attrs - (xmln(attrs={'a good': 'one'}).get('attrs'), {'a good': 'one'}) |*> self.assertEquals - (xmln <**| {'attrs': {'a good': 'one'}} |> .get <| 'attrs', {'a good': 'one'}) |*> self.assertEquals + (xmln(attrs={'a good': 'one'}).attrs, {'a good': 'one'}) |*> self.assertEquals + (xmln <**| {'attrs': {'a good': 'one'}} |> getattr$(?, 'attrs'), {'a good': 'one'}) |*> self.assertEquals # Childrens attrs ={'children': [1, 2, 3]} - (xmln <**| attrs |> .get <| 'children' == [1, 2, 3]) |> self.assertTrue + (xmln <**| attrs |> getattr$(?, 'children') == [1, 2, 3]) |> self.assertTrue attrs = {'children': 'Some text'} - (xmln <**| attrs |> .get <| 'children' == ['Some text']) |> self.assertTrue + (xmln <**| attrs |> getattr$(?, 'children') == ['Some text']) |> self.assertTrue try: xmln <**| {'children': False} @@ -51,27 +51,35 @@ class TestXMLBase(unittest.TestCase): parent = {'tag': 'root', 'attrs': {}, 'children': []} |> xmlroot xmlc_par = xmlchild$ <| parent - (xmlc_par <| []) `self.assertEquals` None + # Bad arguments try: - xmlc_par <| False + xmlc_par <| False except TypeError as err: - 'is not iterable' `self.assertIn` err.message + 'Invalid arguments for xmlchild' `self.assertIn` err.message + try: + xmlc_par <| [] + except TypeError as err: + 'Invalid arguments for xmlchild' `self.assertIn` err.message + try: # Need XMLDictElement, not dict + xmlc_par <| [{'tag': 't', 'attrs': {'a': 'b'}, 'children': []}] + except TypeError as err: + 'Invalid arguments for xmlchild' `self.assertIn` err.message xmlc_par <| ['some text'] parent.text `self.assertEquals` 'some text' - xmlc_par <| [{'tag': 't', 'attrs': {'a': 'b'}, 'children': []}] + xmlc_par <| [xmln <**| {'tag': 't', 'attrs': {'a': 'b'}, 'children': []}] child = parent.iter <| 't' |> next child.tag `self.assertEquals` 't' child.attrib `self.assertEquals` {'a': 'b'} (child |> list) `self.assertEquals` [] - xmlc_par <| [{'tag': 't2', 'attrs': {1: 2}, 'children': []}] + xmlc_par <| [xmln <**| {'tag': 't2', 'attrs': {1: 2}, 'children': []}] child = parent.iter <| 't2' |> next child.attrib `self.assertEquals` {'1': '2'} - xmlc_par <| [{'tag': 'tchildren', 'attrs': {}, - 'children': [{'tag': 'subchild', 'attrs': {}, 'children': []}]}] + xmlc_par <| [xmln <**| {'tag': 'tchildren', 'attrs': {}, + 'children': [xmln <**| {'tag': 'subchild', 'attrs': {}, 'children': []}]}] child = parent.iter <| 'tchildren' |> next subchildren = (child |> list) (subchildren |> len) `self.assertEquals` 1 diff --git a/yaltik_dsl/test_xml_base.py b/yaltik_dsl/test_xml_base.py index 32d5746..043d85c 100644 --- a/yaltik_dsl/test_xml_base.py +++ b/yaltik_dsl/test_xml_base.py @@ -1,6 +1,6 @@ #!/usr/bin/env python2 # -*- coding: utf-8 -*- -# __coconut_hash__ = 0xf82711d8 +# __coconut_hash__ = 0x6e1a1e05 # Compiled with Coconut version 1.4.3 [Ernest Scribbler] @@ -52,19 +52,19 @@ class TestXMLBase(unittest.TestCase): def test_xmln(self): # Tags - (self.assertEquals)(*(xmln(), {'tag': '', 'attrs': {}, 'children': []})) - (self.assertEquals)(*((((xmln)('a tag')).get)('tag'), 'a tag')) + (self.assertEquals)(*(xmln()._asdict(), {'tag': '', 'attrs': {}, 'children': []})) + (self.assertEquals)(*((_coconut_partial(getattr, {1: 'tag'}, 2))((xmln)('a tag')), 'a tag')) # Attrs - (self.assertEquals)(*(xmln(attrs={'a good': 'one'}).get('attrs'), {'a good': 'one'})) - (self.assertEquals)(*((((xmln)(**{'attrs': {'a good': 'one'}})).get)('attrs'), {'a good': 'one'})) + (self.assertEquals)(*(xmln(attrs={'a good': 'one'}).attrs, {'a good': 'one'})) + (self.assertEquals)(*((_coconut_partial(getattr, {1: 'attrs'}, 2))((xmln)(**{'attrs': {'a good': 'one'}})), {'a good': 'one'})) # Childrens attrs = {'children': [1, 2, 3]} - (self.assertTrue)(((((xmln)(**attrs)).get)('children') == [1, 2, 3])) + (self.assertTrue)(((_coconut_partial(getattr, {1: 'children'}, 2))((xmln)(**attrs)) == [1, 2, 3])) attrs = {'children': 'Some text'} - (self.assertTrue)(((((xmln)(**attrs)).get)('children') == ['Some text'])) + (self.assertTrue)(((_coconut_partial(getattr, {1: 'children'}, 2))((xmln)(**attrs)) == ['Some text'])) try: (xmln)(**{'children': False}) @@ -76,26 +76,34 @@ class TestXMLBase(unittest.TestCase): parent = (xmlroot)({'tag': 'root', 'attrs': {}, 'children': []}) xmlc_par = (_coconut.functools.partial(_coconut.functools.partial, xmlchild))(parent) - (self.assertEquals)(((xmlc_par)([])), None) +# Bad arguments try: (xmlc_par)(False) except TypeError as err: - (self.assertIn)('is not iterable', err.message) + (self.assertIn)('Invalid arguments for xmlchild', err.message) + try: + (xmlc_par)([]) + except TypeError as err: + (self.assertIn)('Invalid arguments for xmlchild', err.message) + try: # Need XMLDictElement, not dict + (xmlc_par)([{'tag': 't', 'attrs': {'a': 'b'}, 'children': []}]) + except TypeError as err: + (self.assertIn)('Invalid arguments for xmlchild', err.message) (xmlc_par)(['some text']) (self.assertEquals)(parent.text, 'some text') - (xmlc_par)([{'tag': 't', 'attrs': {'a': 'b'}, 'children': []}]) + (xmlc_par)([(xmln)(**{'tag': 't', 'attrs': {'a': 'b'}, 'children': []})]) child = (next)((parent.iter)('t')) (self.assertEquals)(child.tag, 't') (self.assertEquals)(child.attrib, {'a': 'b'}) (self.assertEquals)(((list)(child)), []) - (xmlc_par)([{'tag': 't2', 'attrs': {1: 2}, 'children': []}]) + (xmlc_par)([(xmln)(**{'tag': 't2', 'attrs': {1: 2}, 'children': []})]) child = (next)((parent.iter)('t2')) (self.assertEquals)(child.attrib, {'1': '2'}) - (xmlc_par)([{'tag': 'tchildren', 'attrs': {}, 'children': [{'tag': 'subchild', 'attrs': {}, 'children': []}]}]) + (xmlc_par)([(xmln)(**{'tag': 'tchildren', 'attrs': {}, 'children': [(xmln)(**{'tag': 'subchild', 'attrs': {}, 'children': []})]})]) child = (next)((parent.iter)('tchildren')) subchildren = ((list)(child)) (self.assertEquals)(((len)(subchildren)), 1) diff --git a/yaltik_dsl/xml_base.coco b/yaltik_dsl/xml_base.coco index 12c8dad..0bf6b00 100644 --- a/yaltik_dsl/xml_base.coco +++ b/yaltik_dsl/xml_base.coco @@ -23,16 +23,15 @@ from xml.dom import minidom from typing import Dict, List, Union, Any -# TODO: ADT for XMLchild children**s** -# REF xml_write +# TODO: fix MyPy / typing +# REF and test xml_write -data XMLChildren(clist: List[Union[XMLDict, XMLText]]) +data XMLDictElement(tag: XMLText, attrs: XMLAttrs, children: List[Any]) -data XMLText(text: Union[str, unicode]) -data XMLDict(tag: str, attrs: Dict[str, str], children: XMLChildren) +XMLText = Union[str, unicode] +XMLAttrs = Dict[str, str] +XMLChild = Union[XMLDictElement, XMLText, List] -data XMLTag(tag: str) -data XMLAttrs(attrs: Dict[str, str]) def xmlroot(tree: Dict[str, Any]) -> ET.Element: """ Special process for root XML Node """ @@ -41,30 +40,35 @@ def xmlroot(tree: Dict[str, Any]) -> ET.Element: (rootel, tree['children']) |*> xmlchild return rootel -def xmlchild(parent: ET.Element, children: Any) -> None: +def xmlchild(parent: ET.Element, children: XMLDictElement) -> None: """ Handling of children (ie non root) XML Nodes with/o text and subchildren (recursive) """ - match _ is (str, unicode) in children: - parent.text = children - return - match _ is dict in children: - attrs = {unicode(k): unicode(v) for [k, v] in children['attrs'].items()} - new_parent = (parent, children['tag'], attrs) |*> ET.SubElement - subchildren = children['children'] - if subchildren: - (new_parent, subchildren) |*> xmlchild - match _ is list in children: - ((xmlchild$ <| parent), children) |*> map |> consume + case children: + match _ is XMLText: + parent.text = children + match _ is XMLDictElement: + attrs = {unicode(k): unicode(v) for [k, v] in children.attrs.items()} + new_parent = (parent, children.tag, attrs) |*> ET.SubElement + subchildren = children.children + if subchildren: + (new_parent, subchildren) |*> xmlchild + match _ is list: + ((xmlchild$ <| parent), children) |*> map |> consume + else: + raise TypeError('Invalid arguments for xmlchild') -def xmln(tag: str = '', - attrs: Dict[str, str] = {}, - children: Union[str, List] = []) -> Dict: +def xmln(tag: XMLText = '', + attrs: XMLAttrs = {}, + children: Union[str, List] = []) -> XMLDictElement: """ XMLNode with default children, not attributes """ - match c is str in children: - return {'tag': tag, 'attrs': attrs, 'children': [c]} - else: match c is list in children: - return {'tag': tag, 'attrs': attrs, 'children': c} + case children: + match c is str: + return XMLDictElement(tag=tag, attrs=attrs, children=[c]) + # return {'tag': tag, 'attrs': attrs, 'children': [c]} + match c is list: + return XMLDictElement(tag=tag, attrs=attrs, children=c) + # return {'tag': tag, 'attrs': attrs, 'children': c} else: raise TypeError('Invalid arguments for xmln') diff --git a/yaltik_dsl/xml_base.py b/yaltik_dsl/xml_base.py index d1f7142..641aded 100644 --- a/yaltik_dsl/xml_base.py +++ b/yaltik_dsl/xml_base.py @@ -1,6 +1,6 @@ #!/usr/bin/env python2 # -*- coding: utf-8 -*- -# __coconut_hash__ = 0xd881e1a +# __coconut_hash__ = 0x65805ba7 # Compiled with Coconut version 1.4.3 [Ernest Scribbler] @@ -49,9 +49,10 @@ from typing import Union from typing import Any -# TODO: ADT for XMLchild children**s** +# TODO: fix MyPy / typing +# REF and test xml_write -class XMLChildren(_coconut.typing.NamedTuple("XMLChildren", [("clist", 'List[Union[XMLChildDict, XMLChildText]]')]), _coconut.object): +class XMLDictElement(_coconut.typing.NamedTuple("XMLDictElement", [("tag", 'XMLText'), ("attrs", 'XMLAttrs'), ("children", 'List[Any]')]), _coconut.object): __slots__ = () __ne__ = _coconut.object.__ne__ def __eq__(self, other): @@ -59,21 +60,10 @@ class XMLChildren(_coconut.typing.NamedTuple("XMLChildren", [("clist", 'List[Uni def __hash__(self): return _coconut.tuple.__hash__(self) ^ hash(self.__class__) -class XMLChildText(_coconut.typing.NamedTuple("XMLChildText", [("text", 'Union[str, unicode]')]), _coconut.object): - __slots__ = () - __ne__ = _coconut.object.__ne__ - def __eq__(self, other): - return self.__class__ is other.__class__ and _coconut.tuple.__eq__(self, other) - def __hash__(self): - return _coconut.tuple.__hash__(self) ^ hash(self.__class__) -class XMLChildDict(_coconut.typing.NamedTuple("XMLChildDict", [("tag", 'str'), ("attrs", 'Dict[str, str]'), ("children", 'XMLChildren')]), _coconut.object): - __slots__ = () - __ne__ = _coconut.object.__ne__ - def __eq__(self, other): - return self.__class__ is other.__class__ and _coconut.tuple.__eq__(self, other) - def __hash__(self): - return _coconut.tuple.__hash__(self) ^ hash(self.__class__) +XMLText = Union[str, unicode] +XMLAttrs = Dict[str, str] +XMLChild = Union[XMLDictElement, XMLText, List] def xmlroot(tree # type: Dict[str, Any] @@ -86,59 +76,58 @@ def xmlroot(tree # type: Dict[str, Any] return rootel def xmlchild(parent, # type: ET.Element - children # type: Any + children # type: XMLDictElement ): # type: (...) -> None """ Handling of children (ie non root) XML Nodes with/o text and subchildren (recursive) """ _coconut_match_to = children - _coconut_match_check = False - if _coconut.isinstance(_coconut_match_to, (str, unicode)): - _coconut_match_check = True - if _coconut_match_check: + _coconut_case_check_0 = False + if _coconut.isinstance(_coconut_match_to, XMLText): + _coconut_case_check_0 = True + if _coconut_case_check_0: parent.text = children - return - _coconut_match_to = children - _coconut_match_check = False - if _coconut.isinstance(_coconut_match_to, dict): - _coconut_match_check = True - if _coconut_match_check: - attrs = dict(((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)) - _coconut_match_to = children - _coconut_match_check = False - if _coconut.isinstance(_coconut_match_to, list): - _coconut_match_check = True - if _coconut_match_check: - (consume)((map)(*(((_coconut.functools.partial(_coconut.functools.partial, xmlchild))(parent)), children))) + if not _coconut_case_check_0: + if _coconut.isinstance(_coconut_match_to, XMLDictElement): + _coconut_case_check_0 = True + if _coconut_case_check_0: + attrs = dict(((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)) + if not _coconut_case_check_0: + if _coconut.isinstance(_coconut_match_to, list): + _coconut_case_check_0 = True + if _coconut_case_check_0: + (consume)((map)(*(((_coconut.functools.partial(_coconut.functools.partial, xmlchild))(parent)), children))) + if not _coconut_case_check_0: + raise TypeError('Invalid arguments for xmlchild') -def xmln(tag='', # type: str - attrs={}, # type: Dict[str, str] +def xmln(tag='', # type: XMLText + attrs={}, # type: XMLAttrs children=[] # type: Union[str, List] ): -# type: (...) -> Dict +# type: (...) -> XMLDictElement """ XMLNode with default children, not attributes """ _coconut_match_to = children - _coconut_match_check = False + _coconut_case_check_1 = False if _coconut.isinstance(_coconut_match_to, str): c = _coconut_match_to - _coconut_match_check = True - if _coconut_match_check: - return {'tag': tag, 'attrs': attrs, 'children': [c]} - else: - _coconut_match_to = children - _coconut_match_check = False + _coconut_case_check_1 = True + if _coconut_case_check_1: + return XMLDictElement(tag=tag, attrs=attrs, children=[c]) +# return {'tag': tag, 'attrs': attrs, 'children': [c]} + if not _coconut_case_check_1: if _coconut.isinstance(_coconut_match_to, list): c = _coconut_match_to - _coconut_match_check = True - if _coconut_match_check: - return {'tag': tag, 'attrs': attrs, 'children': c} - else: - raise TypeError('Invalid arguments for xmln') + _coconut_case_check_1 = True + if _coconut_case_check_1: + return XMLDictElement(tag=tag, attrs=attrs, children=c) +# return {'tag': tag, 'attrs': attrs, 'children': c} + if not _coconut_case_check_1: + raise TypeError('Invalid arguments for xmln') def xml_write(filepath, tree): """ Write XML file according to filename and given tree """