dmulyalin / ttp

Template Text Parser
MIT License
350 stars 34 forks source link

Inconsistent return if match variable macro is executed #31

Closed james-powis closed 4 years ago

james-powis commented 4 years ago

Running a match variable macro results in the result being a list of tuples of list of dictionaries, where as not running a macro results in the return being a list of dictionaries.

Per documentation located here the return should be a list of dictionaries.


Python 3.7.4 (default, Sep  7 2019, 18:27:02) 
[Clang 10.0.1 (clang-1001.0.46.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> 
>>> 
>>> from ttp import ttp
>>> 
>>> data = '''
...    remote         refid           st t when poll reach   delay   offset  jitter
... ===============================================================================
... *172.27.1.4       .GPS.            1 -  108 1024  377    0.977   -0.309   0.088
...  2600:6cec:1c0:2::8
...                   .INIT.          16 u    - 1024    0    0.000    0.000 4000.00
... '''
>>> 
>>> template_a = '''
... <group name="associations">
... {{ active | re("[ *]") | macro("check_active") }}{{ ip | IP | IPV6 }} {{ method }} {{ stratum | to_int }} {{ peer_type }} {{ when }} {{ poll }} {{ reach }} {{ delay }} {{ offset }} {{ jitter }} 
... </group>
... <group name="associations">
... {{ active | re("[ *]") | macro("check_active") }}{{ ip | IP | IPV6 }}
...                   {{ method }} {{ stratum | to_int}} {{ peer_type }} {{ when }} {{ poll }} {{ reach }} {{ delay }} {{ offset }} {{ jitter }} 
... </group>
... 
... <macro>
... def check_active(data):
...     if data == '*': 
...         return data, { 'type': 'our_master' }
...     else:
...         return data, { 'type': 'candidate' }
...     return data
... </macro>
... 
... <output macro="check_active"/>
... '''
>>> 
>>> template_b = '''
... <group name="associations">
... {{ active | re("[ *]") | macro("check_active") }}{{ ip | IP | IPV6 }} {{ method }} {{ stratum | to_int }} {{ peer_type }} {{ when }} {{ poll }} {{ reach }} {{ delay }} {{ offset }} {{ jitter }} 
... </group>
... <group name="associations">
... {{ active | re("[ *]") | macro("check_active") }}{{ ip | IP | IPV6 }}
...                   {{ method }} {{ stratum | to_int}} {{ peer_type }} {{ when }} {{ poll }} {{ reach }} {{ delay }} {{ offset }} {{ jitter }} 
... </group>
... 
... <macro>
... def check_active(data):
...     if data == '*': 
...         return data, { 'type': 'our_master' }
...     else:
...         return data, { 'type': 'candidate' }
...     return data
... </macro>
... '''
>>> 
>>> 
>>> parser_a = ttp(data=data, template=template_a)
>>> parser_b = ttp(data=data, template=template_b)
>>> parser_a.parse()
>>> parser_b.parse()
>>> 
>>> parser_a.result()
[([{'associations': [{'active': '*', 'type': 'our_master', 'ip': '172.27.1.4', 'method': '.GPS.', 'stratum': 1, 'peer_type': '-', 'when': '108', 'poll': '1024', 'reach': '377', 'delay': '0.977', 'offset': '-0.309', 'jitter': '0.088'}, {'method': '.INIT.', 'stratum': 16, 'peer_type': 'u', 'when': '-', 'poll': '1024', 'reach': '0', 'delay': '0.000', 'offset': '0.000', 'jitter': '4000.00', 'active': ' ', 'type': 'candidate', 'ip': '2600:6cec:1c0:2::8'}]}], {'type': 'candidate'})]
>>> 
>>> parser_b.result()
[[{'associations': [{'active': '*', 'type': 'our_master', 'ip': '172.27.1.4', 'method': '.GPS.', 'stratum': 1, 'peer_type': '-', 'when': '108', 'poll': '1024', 'reach': '377', 'delay': '0.977', 'offset': '-0.309', 'jitter': '0.088'}, {'method': '.INIT.', 'stratum': 16, 'peer_type': 'u', 'when': '-', 'poll': '1024', 'reach': '0', 'delay': '0.000', 'offset': '0.000', 'jitter': '4000.00', 'active': ' ', 'type': 'candidate', 'ip': '2600:6cec:1c0:2::8'}]}]]

Running the example in documentation works as expected except the documented return is a list of dictionaries where as the actual result is a list of list of dictionaries:

Python 3.7.4 (default, Sep  7 2019, 18:27:02) 
[Clang 10.0.1 (clang-1001.0.46.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> 
>>> from ttp import ttp
>>> 
>>> template = '''
... <input load="text">
... interface Vlan123
...  description Desks vlan
...  ip address 192.168.123.1 255.255.255.0
... !
... interface GigabitEthernet1/1
...  description to core-1
... !
... interface Vlan222
...  description Phones vlan
...  ip address 192.168.222.1 255.255.255.0
... !
... interface Loopback0
...  description Routing ID loopback
... !
... </input>
... 
... <macro>
... def check_if_svi(data):
...     if "Vlan" in data:
...         return data, {"is_svi": True}
...     else:
...        return data, {"is_svi": False}
... 
... def check_if_loop(data):
...     if "Loopback" in data:
...         return data, {"is_loop": True}
...     else:
...        return data, {"is_loop": False}
... </macro>
... 
... <macro>
... def description_mod(data):
...     # To revert words order in descripotion
...     words_list = data.split(" ")
...     words_list_reversed = list(reversed(words_list))
...     words_reversed = " ".join(words_list_reversed)
...     return words_reversed
... </macro>
... 
... <group name="interfaces_macro">
... interface {{ interface | macro("check_if_svi") | macro("check_if_loop") }}
...  description {{ description | ORPHRASE | macro("description_mod")}}
...  ip address {{ ip }} {{ mask }}
... </group>
... '''
>>> 
>>> parser = ttp(template=template)
>>> parser.parse()
>>> parser.result()
[[{'interfaces_macro': [{'ip': '192.168.123.1', 'mask': '255.255.255.0', 'description': 'vlan Desks', 'interface': 'Vlan123', 'is_svi': True, 'is_loop': False}, {'description': 'core-1 to', 'interface': 'GigabitEthernet1/1', 'is_svi': False, 'is_loop': False}, {'ip': '192.168.222.1', 'mask': '255.255.255.0', 'description': 'vlan Phones', 'interface': 'Vlan222', 'is_svi': True, 'is_loop': False}, {'description': 'loopback ID Routing', 'interface': 'Loopback0', 'is_svi': False, 'is_loop': True}]}]]
>>> 
james-powis commented 4 years ago

Sigh I found my issue, I was running check_active as a variable macro and output macro...

Closing.