dmulyalin / ttp

Template Text Parser
MIT License
351 stars 34 forks source link

Incorrect macro behavior in nested groups #95

Closed matrix273 closed 1 year ago

matrix273 commented 1 year ago

Data:

interface Port-Chanel11
  description Storage
!
interface Loopback0
  description RID
  ip address 10.0.0.3/24
!
interface Vlan777
  description Management
  ip address 192.168.0.1/24
  vrf MGMT
!

Template:

<macro>

def title(data):
    data['interface'] = data['interface'].upper()
</macro>

<group name='results*' macro='title' >
interface {{ interface }}
  description {{ description }}
<group name = "ips">
  ip address {{ ip }}/{{ mask }}
</group>
  vrf {{ vrf }}
!{{_end_}}
</group>

code below

# create parser object and parse data using template:
parser = ttp(data=data, template=template)
parser.parse()

# print result in JSON format
results = parser.result(format='json')[0]
print(results)

I got error like below

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
/tmp/ipykernel_5470/1778387175.py in <module>
      1 # create parser object and parse data using template:
      2 parser = ttp(data=data, template=template)
----> 3 parser.parse()
      4 
      5 # print result in JSON format

~/.conda/envs/fastapi/lib/python3.7/site-packages/ttp/ttp.py in parse(self, one, multi)
    447             self.__parse_in_multiprocess()
    448         else:
--> 449             self.__parse_in_one_process()
    450         # run outputters defined in templates:
    451         [template.run_outputs() for template in self._templates]

~/.conda/envs/fastapi/lib/python3.7/site-packages/ttp/ttp.py in __parse_in_one_process(self)
    516                             datum, main_results={}, input_functions=input_obj.functions
    517                         )
--> 518                         parserObj.parse(groups_indexes=input_obj.groups_indexes)
    519                         result = parserObj.main_results
    520                         template.form_results(result)

~/.conda/envs/fastapi/lib/python3.7/site-packages/ttp/ttp.py in parse(self, groups_indexes)
   2620         # form results for global groups:
   2621         RSLTSOBJ = _results_class(self._ttp_)
-> 2622         RSLTSOBJ.make_results(self.vars, raw_results, main_results=self.main_results)
   2623         self.main_results = RSLTSOBJ.results
   2624 

~/.conda/envs/fastapi/lib/python3.7/site-packages/ttp/ttp.py in make_results(self, variables, raw_results, main_results)
   2830                 )
   2831         # check the last group:
-> 2832         if self.processgrp() is not False:
   2833             self.save_curelements(
   2834                 result_data=self.record["result"], result_path=self.record["PATH"]

~/.conda/envs/fastapi/lib/python3.7/site-packages/ttp/ttp.py in processgrp(self)
   3216             # run group functions
   3217             self.record["result"], flags = self._ttp_["group"][func_name](
-> 3218                 self.record["result"], *args, **kwargs
   3219             )
   3220             # if conditions check been false, return False:

~/.conda/envs/fastapi/lib/python3.7/site-packages/ttp/group/macro.py in macro(data, *macro)
      6     for macro_item in macro_names_list:
      7         if macro_item in _ttp_["macro"]:
----> 8             res = _ttp_["macro"][macro_item](result)
      9             if res is False:
     10                 return result, False

<string> in title(data)

KeyError: 'interface'

if I remove the nested group, the results will correct

Template:

<macro>

def title(data):
    data['interface'] = data['interface'].upper()
</macro>

<group name='results*' macro='title' >
interface {{ interface }}
  description {{ description }}
  vrf {{ vrf }}
!{{_end_}}
</group>

the correct result like below:

[
    {
        "results": [
            {
                "description": "Storage",
                "interface": "PORT-CHANEL11"
            },
            {
                "description": "RID",
                "interface": "LOOPBACK0"
            },
            {
                "description": "Management",
                "interface": "VLAN777",
                "vrf": "MGMT"
            }
        ]
    }
]
dmulyalin commented 1 year ago

Thank you for reporting this issue, unfortunately there is a restriction/flaw in TTP results processing logic, this workaround should work for this case:

<macro>
def title(data):
    if data.get("interface"):
        data['interface'] = data['interface'].upper()
</macro>
matrix273 commented 1 year ago

Thank you,It's My fault.