Skip to content

Commit

Permalink
fix for #109, bump to 0.9.5
Browse files Browse the repository at this point in the history
  • Loading branch information
dmulyalin committed Jun 25, 2023
1 parent 9307f05 commit 638fa9d
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 21 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "ttp"
version = "0.9.4"
version = "0.9.5"
description = "Template Text Parser"
authors = ["Denis Mulyalin <d.mulyalin@gmail.com>"]
maintainers = ["Denis Mulyalin <d.mulyalin@gmail.com>"]
Expand Down
125 changes: 124 additions & 1 deletion test/pytest/test_group_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -864,4 +864,127 @@ def test_expand_issue_65():
'switched-vlan': {'mode': 'access'},
'vrf': 'XYZ'}]}}]]

# test_expand_issue_65()
# test_expand_issue_65()

def test_group_to_int_for_non_integer():
template = """
<input load="text">
interface GigabitEthernet1/1
mtu ABC
!
interface GigabitEthernet1/2
mtu 8000
!
interface GigabitEthernet1/2
mtu 9200.0
!
</input>
<group to_int="">
interface {{ name }}
mtu {{ mtu }}
</group>
"""
parser = ttp(template=template)
parser.parse()
res = parser.result()
pprint.pprint(res)
assert res == [[[{'mtu': 'ABC', 'name': 'GigabitEthernet1/1'},
{'mtu': 8000, 'name': 'GigabitEthernet1/2'},
{'mtu': 9200.0, 'name': 'GigabitEthernet1/2'}]]]

# test_group_to_int_for_non_integer()

def test_group_to_int_missing_key_issue_109():
template = """
<input load="text">
interface GigabitEthernet1/1
mtu ABC
!
interface GigabitEthernet1/2
mtu 8000
!
interface GigabitEthernet1/2
mtu 9200.0
!
</input>
<group to_int="mtu, foo, bar">
interface {{ name }}
mtu {{ mtu }}
</group>
"""
parser = ttp(template=template)
parser.parse()
res = parser.result()
pprint.pprint(res)
assert res == [[[{'mtu': 'ABC', 'name': 'GigabitEthernet1/1'},
{'mtu': 8000, 'name': 'GigabitEthernet1/2'},
{'mtu': 9200.0, 'name': 'GigabitEthernet1/2'}]]]

# test_group_to_int_missing_key_issue_109()

def test_group_to_int_with_intlist_true_issue_109():
template = """
<input load="text">
interface GigabitEthernet1/1
switchport trunk allowed vlan 1,2,3,4
!
interface GigabitEthernet1/2
switchport trunk allowed vlan 123
!
interface GigabitEthernet1/3
switchport trunk allowed vlan foo,bar
!
interface GigabitEthernet1/4
!
</input>
<group to_int="trunk_vlan, intlist=True">
interface {{ name }}
switchport trunk allowed vlan {{ trunk_vlan | split(',') }}
</group>
"""
parser = ttp(template=template)
parser.parse()
res = parser.result()
pprint.pprint(res)
assert res == [[[{'name': 'GigabitEthernet1/1', 'trunk_vlan': [1, 2, 3, 4]},
{'name': 'GigabitEthernet1/2', 'trunk_vlan': [123]},
{'name': 'GigabitEthernet1/3', 'trunk_vlan': ['foo', 'bar']},
{'name': 'GigabitEthernet1/4'}]]]

# test_group_to_int_with_intlist_issue_109()


def test_group_to_int_with_intlist_false_issue_109():
template = """
<input load="text">
interface GigabitEthernet1/1
switchport trunk allowed vlan 1,2,3,4
!
interface GigabitEthernet1/2
switchport trunk allowed vlan 123
!
interface GigabitEthernet1/3
switchport trunk allowed vlan foo,bar
!
interface GigabitEthernet1/4
!
</input>
<group to_int="trunk_vlan">
interface {{ name }}
switchport trunk allowed vlan {{ trunk_vlan | split(',') }}
</group>
"""
parser = ttp(template=template)
parser.parse()
res = parser.result()
pprint.pprint(res)
assert res == [[[{'name': 'GigabitEthernet1/1', 'trunk_vlan': ['1', '2', '3', '4']},
{'name': 'GigabitEthernet1/2', 'trunk_vlan': ['123']},
{'name': 'GigabitEthernet1/3', 'trunk_vlan': ['foo', 'bar']},
{'name': 'GigabitEthernet1/4'}]]]

# test_group_to_int_with_intlist_false_issue_109()
2 changes: 1 addition & 1 deletion ttp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

__all__ = ["ttp"]
__author__ = "Denis Mulyalin <d.mulyalin@gmail.com>"
__version__ = "0.9.4"
__version__ = "0.9.5"
from sys import version_info

# get python version:
Expand Down
4 changes: 3 additions & 1 deletion ttp/group/sformat.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ def sformat(data, string, add_field):
"""
try:
data[add_field] = string.format(**data)
except KeyError: # KeyError happens when not enough keys in **data supplied to format method
except (
KeyError
): # KeyError happens when not enough keys in **data supplied to format method
kwargs = _ttp_["global_vars"].copy()
kwargs.update(_ttp_["vars"])
kwargs.update(data)
Expand Down
29 changes: 25 additions & 4 deletions ttp/group/to_converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,37 @@ def str_to_unicode(data):
return data, None


def to_int(data, *keys):
def to_int(data, *keys, intlist=False):
if not keys:
keys = list(data.keys())
for k in keys:
v = data[k]
# check if given key exists
try:
v = data[k]
except KeyError:
continue

# do best effort string to int conversion
try:
data[k] = int(v)
except ValueError:
except:
try:
data[k] = float(v)
except:
continue
pass

# convert list of integer strings to list of integers
if intlist is True and isinstance(data[k], list):
converted_list = []
for i in data[k]:
try:
converted_list.append(int(i))
except:
try:
converted_list.append(float(i))
except:
converted_list.append(i)

data[k] = converted_list

return data, None
4 changes: 2 additions & 2 deletions ttp/output/validate_yangson.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ def _make_library(ydir):
) as yf:
_module_entry(yf)
marr = []
for (yam, mrev) in modmap:
for yam, mrev in modmap:
men = {"name": yam, "revision": mrev}
sarr = []
mrec = modmap[(yam, mrev)]
men["namespace"] = mrec["namespace"]
fts = mrec["features"]
imp_only = mrec["import-only"]
for (subm, srev) in mrec["includes"]:
for subm, srev in mrec["includes"]:
sen = {"name": subm}
try:
srec = submodmap[subm]
Expand Down
26 changes: 15 additions & 11 deletions ttp/ttp.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

__version__ = "0.9.4"
__version__ = "0.9.5"

import re
import os
Expand Down Expand Up @@ -2333,7 +2333,7 @@ def debug(self):
from pprint import pformat

attributes = dict(vars(self))
_ = attributes.pop("_ttp_") # remove _ttp_ dictionary to not clutter the output
_ = attributes.pop("_ttp_") # remove _ttp_ dictionary to not clutter the output
text = "Variable object {}, Variable name '{}' content:\n{}".format(
self, self.var_name, pformat(attributes, indent=4)
)
Expand Down Expand Up @@ -3045,7 +3045,7 @@ def reconstruct_last_element(self, result_data, result_path):
copied = E.copy()
copied.update(result_data)
return copied

def start(self, result, PATH, DEFAULTS=None, FUNCTIONS=None, REDICT=""):
DEFAULTS = DEFAULTS or {}
FUNCTIONS = FUNCTIONS or []
Expand Down Expand Up @@ -3200,9 +3200,9 @@ def end(self, result, PATH, DEFAULTS=None, FUNCTIONS=None, REDICT=""):
def form_path(self, path):
"""
Method to form dynamic path transforming it into a list of tuples,
where each tuple first element is a path item value and second
element is a number of asterisks, need to keep asterisks count
separatefrom path item value becasue match result value can end
where each tuple first element is a path item value and second
element is a number of asterisks, need to keep asterisks count
separatefrom path item value becasue match result value can end
with asterisk - issue #97
"""
for index, path_item in enumerate(path):
Expand All @@ -3228,20 +3228,25 @@ def form_path(self, path):
path_item = re.sub(pattern, str(self.variables[m]), path_item)
else:
return False
path[index] = (path_item, asterisk_count * "*",)
path[index] = (
path_item,
asterisk_count * "*",
)
return path

def processgrp(self):
"""Method to process group results"""
# add default values to group results
for k, v in self.record["DEFAULTS"].items():
self.record["result"].setdefault(k, v)
# if merge_with_last - tail match, attempt to reconstruct group result
# this only will work if self.record["result"] contains enough info to form PATH
# if merge_with_last - tail match, attempt to reconstruct group result
# this only will work if self.record["result"] contains enough info to form PATH
if self.record.get("merge_with_last") is True:
processed_path = self.form_path(list(self.record["PATH"]))
if processed_path:
self.record["result"] = self.reconstruct_last_element(self.record["result"], processed_path)
self.record["result"] = self.reconstruct_last_element(
self.record["result"], processed_path
)
# process group functions
for item in self.record["FUNCTIONS"]:
func_name = item["name"]
Expand Down Expand Up @@ -3271,7 +3276,6 @@ class _outputter_class:
"""Class to serve run output functions, returners and formatters"""

def __init__(self, element=None, template_obj=None, _ttp_=None, **kwargs):

# set attributes default values
self._ttp_ = _ttp_
self.attributes = {"returner": "self", "format": "raw", "load": "python"}
Expand Down

0 comments on commit 638fa9d

Please sign in to comment.