Skip to content

Commit 638fa9d

Browse files
committedJun 25, 2023
fix for #109, bump to 0.9.5
1 parent 9307f05 commit 638fa9d

File tree

7 files changed

+171
-21
lines changed

7 files changed

+171
-21
lines changed
 

‎pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "ttp"
3-
version = "0.9.4"
3+
version = "0.9.5"
44
description = "Template Text Parser"
55
authors = ["Denis Mulyalin <d.mulyalin@gmail.com>"]
66
maintainers = ["Denis Mulyalin <d.mulyalin@gmail.com>"]

‎test/pytest/test_group_functions.py

+124-1
Original file line numberDiff line numberDiff line change
@@ -864,4 +864,127 @@ def test_expand_issue_65():
864864
'switched-vlan': {'mode': 'access'},
865865
'vrf': 'XYZ'}]}}]]
866866

867-
# test_expand_issue_65()
867+
# test_expand_issue_65()
868+
869+
def test_group_to_int_for_non_integer():
870+
template = """
871+
<input load="text">
872+
interface GigabitEthernet1/1
873+
mtu ABC
874+
!
875+
interface GigabitEthernet1/2
876+
mtu 8000
877+
!
878+
interface GigabitEthernet1/2
879+
mtu 9200.0
880+
!
881+
</input>
882+
883+
<group to_int="">
884+
interface {{ name }}
885+
mtu {{ mtu }}
886+
</group>
887+
"""
888+
parser = ttp(template=template)
889+
parser.parse()
890+
res = parser.result()
891+
pprint.pprint(res)
892+
assert res == [[[{'mtu': 'ABC', 'name': 'GigabitEthernet1/1'},
893+
{'mtu': 8000, 'name': 'GigabitEthernet1/2'},
894+
{'mtu': 9200.0, 'name': 'GigabitEthernet1/2'}]]]
895+
896+
# test_group_to_int_for_non_integer()
897+
898+
def test_group_to_int_missing_key_issue_109():
899+
template = """
900+
<input load="text">
901+
interface GigabitEthernet1/1
902+
mtu ABC
903+
!
904+
interface GigabitEthernet1/2
905+
mtu 8000
906+
!
907+
interface GigabitEthernet1/2
908+
mtu 9200.0
909+
!
910+
</input>
911+
912+
<group to_int="mtu, foo, bar">
913+
interface {{ name }}
914+
mtu {{ mtu }}
915+
</group>
916+
"""
917+
parser = ttp(template=template)
918+
parser.parse()
919+
res = parser.result()
920+
pprint.pprint(res)
921+
assert res == [[[{'mtu': 'ABC', 'name': 'GigabitEthernet1/1'},
922+
{'mtu': 8000, 'name': 'GigabitEthernet1/2'},
923+
{'mtu': 9200.0, 'name': 'GigabitEthernet1/2'}]]]
924+
925+
# test_group_to_int_missing_key_issue_109()
926+
927+
def test_group_to_int_with_intlist_true_issue_109():
928+
template = """
929+
<input load="text">
930+
interface GigabitEthernet1/1
931+
switchport trunk allowed vlan 1,2,3,4
932+
!
933+
interface GigabitEthernet1/2
934+
switchport trunk allowed vlan 123
935+
!
936+
interface GigabitEthernet1/3
937+
switchport trunk allowed vlan foo,bar
938+
!
939+
interface GigabitEthernet1/4
940+
!
941+
</input>
942+
943+
<group to_int="trunk_vlan, intlist=True">
944+
interface {{ name }}
945+
switchport trunk allowed vlan {{ trunk_vlan | split(',') }}
946+
</group>
947+
"""
948+
parser = ttp(template=template)
949+
parser.parse()
950+
res = parser.result()
951+
pprint.pprint(res)
952+
assert res == [[[{'name': 'GigabitEthernet1/1', 'trunk_vlan': [1, 2, 3, 4]},
953+
{'name': 'GigabitEthernet1/2', 'trunk_vlan': [123]},
954+
{'name': 'GigabitEthernet1/3', 'trunk_vlan': ['foo', 'bar']},
955+
{'name': 'GigabitEthernet1/4'}]]]
956+
957+
# test_group_to_int_with_intlist_issue_109()
958+
959+
960+
def test_group_to_int_with_intlist_false_issue_109():
961+
template = """
962+
<input load="text">
963+
interface GigabitEthernet1/1
964+
switchport trunk allowed vlan 1,2,3,4
965+
!
966+
interface GigabitEthernet1/2
967+
switchport trunk allowed vlan 123
968+
!
969+
interface GigabitEthernet1/3
970+
switchport trunk allowed vlan foo,bar
971+
!
972+
interface GigabitEthernet1/4
973+
!
974+
</input>
975+
976+
<group to_int="trunk_vlan">
977+
interface {{ name }}
978+
switchport trunk allowed vlan {{ trunk_vlan | split(',') }}
979+
</group>
980+
"""
981+
parser = ttp(template=template)
982+
parser.parse()
983+
res = parser.result()
984+
pprint.pprint(res)
985+
assert res == [[[{'name': 'GigabitEthernet1/1', 'trunk_vlan': ['1', '2', '3', '4']},
986+
{'name': 'GigabitEthernet1/2', 'trunk_vlan': ['123']},
987+
{'name': 'GigabitEthernet1/3', 'trunk_vlan': ['foo', 'bar']},
988+
{'name': 'GigabitEthernet1/4'}]]]
989+
990+
# test_group_to_int_with_intlist_false_issue_109()

‎ttp/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
__all__ = ["ttp"]
44
__author__ = "Denis Mulyalin <d.mulyalin@gmail.com>"
5-
__version__ = "0.9.4"
5+
__version__ = "0.9.5"
66
from sys import version_info
77

88
# get python version:

‎ttp/group/sformat.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ def sformat(data, string, add_field):
99
"""
1010
try:
1111
data[add_field] = string.format(**data)
12-
except KeyError: # KeyError happens when not enough keys in **data supplied to format method
12+
except (
13+
KeyError
14+
): # KeyError happens when not enough keys in **data supplied to format method
1315
kwargs = _ttp_["global_vars"].copy()
1416
kwargs.update(_ttp_["vars"])
1517
kwargs.update(data)

‎ttp/group/to_converters.py

+25-4
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,37 @@ def str_to_unicode(data):
1212
return data, None
1313

1414

15-
def to_int(data, *keys):
15+
def to_int(data, *keys, intlist=False):
1616
if not keys:
1717
keys = list(data.keys())
1818
for k in keys:
19-
v = data[k]
19+
# check if given key exists
20+
try:
21+
v = data[k]
22+
except KeyError:
23+
continue
24+
25+
# do best effort string to int conversion
2026
try:
2127
data[k] = int(v)
22-
except ValueError:
28+
except:
2329
try:
2430
data[k] = float(v)
2531
except:
26-
continue
32+
pass
33+
34+
# convert list of integer strings to list of integers
35+
if intlist is True and isinstance(data[k], list):
36+
converted_list = []
37+
for i in data[k]:
38+
try:
39+
converted_list.append(int(i))
40+
except:
41+
try:
42+
converted_list.append(float(i))
43+
except:
44+
converted_list.append(i)
45+
46+
data[k] = converted_list
47+
2748
return data, None

‎ttp/output/validate_yangson.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,14 @@ def _make_library(ydir):
106106
) as yf:
107107
_module_entry(yf)
108108
marr = []
109-
for (yam, mrev) in modmap:
109+
for yam, mrev in modmap:
110110
men = {"name": yam, "revision": mrev}
111111
sarr = []
112112
mrec = modmap[(yam, mrev)]
113113
men["namespace"] = mrec["namespace"]
114114
fts = mrec["features"]
115115
imp_only = mrec["import-only"]
116-
for (subm, srev) in mrec["includes"]:
116+
for subm, srev in mrec["includes"]:
117117
sen = {"name": subm}
118118
try:
119119
srec = submodmap[subm]

‎ttp/ttp.py

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3-
__version__ = "0.9.4"
3+
__version__ = "0.9.5"
44

55
import re
66
import os
@@ -2333,7 +2333,7 @@ def debug(self):
23332333
from pprint import pformat
23342334

23352335
attributes = dict(vars(self))
2336-
_ = attributes.pop("_ttp_") # remove _ttp_ dictionary to not clutter the output
2336+
_ = attributes.pop("_ttp_") # remove _ttp_ dictionary to not clutter the output
23372337
text = "Variable object {}, Variable name '{}' content:\n{}".format(
23382338
self, self.var_name, pformat(attributes, indent=4)
23392339
)
@@ -3045,7 +3045,7 @@ def reconstruct_last_element(self, result_data, result_path):
30453045
copied = E.copy()
30463046
copied.update(result_data)
30473047
return copied
3048-
3048+
30493049
def start(self, result, PATH, DEFAULTS=None, FUNCTIONS=None, REDICT=""):
30503050
DEFAULTS = DEFAULTS or {}
30513051
FUNCTIONS = FUNCTIONS or []
@@ -3200,9 +3200,9 @@ def end(self, result, PATH, DEFAULTS=None, FUNCTIONS=None, REDICT=""):
32003200
def form_path(self, path):
32013201
"""
32023202
Method to form dynamic path transforming it into a list of tuples,
3203-
where each tuple first element is a path item value and second
3204-
element is a number of asterisks, need to keep asterisks count
3205-
separatefrom path item value becasue match result value can end
3203+
where each tuple first element is a path item value and second
3204+
element is a number of asterisks, need to keep asterisks count
3205+
separatefrom path item value becasue match result value can end
32063206
with asterisk - issue #97
32073207
"""
32083208
for index, path_item in enumerate(path):
@@ -3228,20 +3228,25 @@ def form_path(self, path):
32283228
path_item = re.sub(pattern, str(self.variables[m]), path_item)
32293229
else:
32303230
return False
3231-
path[index] = (path_item, asterisk_count * "*",)
3231+
path[index] = (
3232+
path_item,
3233+
asterisk_count * "*",
3234+
)
32323235
return path
32333236

32343237
def processgrp(self):
32353238
"""Method to process group results"""
32363239
# add default values to group results
32373240
for k, v in self.record["DEFAULTS"].items():
32383241
self.record["result"].setdefault(k, v)
3239-
# if merge_with_last - tail match, attempt to reconstruct group result
3240-
# this only will work if self.record["result"] contains enough info to form PATH
3242+
# if merge_with_last - tail match, attempt to reconstruct group result
3243+
# this only will work if self.record["result"] contains enough info to form PATH
32413244
if self.record.get("merge_with_last") is True:
32423245
processed_path = self.form_path(list(self.record["PATH"]))
32433246
if processed_path:
3244-
self.record["result"] = self.reconstruct_last_element(self.record["result"], processed_path)
3247+
self.record["result"] = self.reconstruct_last_element(
3248+
self.record["result"], processed_path
3249+
)
32453250
# process group functions
32463251
for item in self.record["FUNCTIONS"]:
32473252
func_name = item["name"]
@@ -3271,7 +3276,6 @@ class _outputter_class:
32713276
"""Class to serve run output functions, returners and formatters"""
32723277

32733278
def __init__(self, element=None, template_obj=None, _ttp_=None, **kwargs):
3274-
32753279
# set attributes default values
32763280
self._ttp_ = _ttp_
32773281
self.attributes = {"returner": "self", "format": "raw", "load": "python"}

0 commit comments

Comments
 (0)
Please sign in to comment.