Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Repeated option and port re to regex module. #38

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
aac2d61
changed re to regex module
gachteme Sep 24, 2018
d9aa5e5
fixed overly greedy replacements that were made in last commit
gachteme Sep 24, 2018
ff984db
finished porting over to regex from re. Runs.
gachteme Sep 28, 2018
1c5bdf7
First commit with basic functionality.
gachteme Oct 1, 2018
c5d17dd
Fix to bug where repeateddata without a match returned an empty strin…
gachteme Oct 15, 2018
2f92cfd
Added basic test case for Repeated option. Changed invalid regex test…
gachteme Oct 15, 2018
fd1d4dc
Update to requirements.
gachteme Oct 15, 2018
80ef2dd
Cleanup.
gachteme Oct 15, 2018
51b825a
merged in google/textfsm
gachteme Jul 13, 2019
81a043a
Allowed fallback to re if regex module cannot be imported. Tested for…
gachteme Jul 17, 2019
33149e9
removed regex module where unnecessary. Passes regression in python 3…
gachteme Jul 18, 2019
2f61b2a
Made repeated keyword tests not fail when falling back on re module. …
gachteme Jul 23, 2019
0707470
Allowed use of Repeated and List together. Added tests for correct be…
gachteme Jul 23, 2019
5aa7071
Allowed use of Repeated and Fillup or Filldown together. Added tests …
gachteme Jul 24, 2019
19a922e
Changes to ensure python 2.7 compatibility. Tests pass with and witho…
gachteme Jul 24, 2019
a34e64e
merge in google/textfsm. Breaks python 2.7 regression
gachteme Jul 25, 2019
1b5f21a
moved Repeated tests to assertListEqual. Bugfix for new dependencies.…
gachteme Jul 25, 2019
4745254
moved clitable_test back to re where regex is not needed.
gachteme Jul 27, 2019
46eae78
Merge branch 'master' into master
gachteme May 9, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions examples/repeated_basic_example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
This is an example to demonstrate the usage of the 'repeated' keyword, which enables one variable to have multiple captures on one line.


normaldata1.1 normaldata1.2 key1.1:data1.1, key1.2:data1.2, key1.3:data1.3, normaldata1.3 normaldata1.3
normaldata2.1 normaldata2.2 key2.1:data2.1, key2.2:data2.2, normaldata2.3 normaldata2.4
normaldata3.1 normaldata3.2 normaldata3.3 normaldata3.4
normaldata4.1 normaldata4.2 key4.1:data4.1, key4.2:data4.2, key4.3:data4.3, normaldata4.3 normaldata4.3
12 changes: 12 additions & 0 deletions examples/repeated_basic_template
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Value normaldata1 (\S+)
Value normaldata2 (\S+)
Value normaldata3 (\S+)
Value normaldata4 (\S+)
Value Repeated keything (\S+)
Value Repeated valuedata (\S+)
Value Repeated unusedRepeated (\S+)
Value List unused (\S+)


Start
^${normaldata1}\s+${normaldata2} (${keything}:${valuedata},? )*${normaldata3}\s+${normaldata4} -> Record
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,5 @@
},
include_package_data=True,
package_data={'textfsm': ['../testdata/*']},
install_requires=['six', 'future'],
install_requires=['six', 'future', 'regex'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm conflicted here ... we want to opportunistically install regex but not necessarily require it, as only newer templates would need it. Unfortunately I see no provision in setup.py for a install_desires=... stanza, so I guess this will have to do?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its the templates that drive the dependency. i.e. only if there are templates with the Repeated keyword, do we need the regexp module installed (plus the relevant unittests). It could be a declared as required as part of a template package install rather than here .. but that is perhaps asking to much of the template maintainers.

)
128 changes: 124 additions & 4 deletions tests/textfsm_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@
from builtins import str
import unittest
from io import StringIO



import textfsm
from textfsm.parser import TextFSMTemplateError
try:
import regex as regexModule
useRegex = True
except ImportError:
useRegex = False


class UnitTestFSM(unittest.TestCase):
Expand Down Expand Up @@ -802,7 +805,7 @@ def testEnd(self):

def testInvalidRegexp(self):

tplt = 'Value boo (.$*)\n\nStart\n ^$boo -> Next\n'
tplt = 'Value boo ([(\S+]))\n\nStart\n ^$boo -> Next\n'
self.assertRaises(textfsm.TextFSMTemplateError,
textfsm.TextFSM, StringIO(tplt))

Expand Down Expand Up @@ -910,6 +913,123 @@ def testTemplateValue(self):
t = textfsm.TextFSM(f)
self.assertEqual(str(t), buf_result)

def testRepeated(self):
"""Repeated option should work ok."""
tplt = """Value Repeated repeatedKey (\S+)
Value Repeated repeatedValue (\S+)
Value normalData (\S+)
Value normalData2 (\S+)
Value Repeated repeatedUnused (\S+)

Start
^${normalData} (${repeatedKey}:${repeatedValue} )*${normalData2} -> Record"""

data = """
normal1 key1:value1 key2:value2 key3:value3 normal2 \n
normal1 normal2 """

t = textfsm.TextFSM(StringIO(tplt))
if useRegex is True:
result = t.ParseText(data)
self.assertListEqual(
[[['key1', 'key2', 'key3'], ['value1', 'value2', 'value3'], 'normal1', 'normal2', []],
[[], [], 'normal1', 'normal2', []]],
result)
else:
# test proper failure when falling back on re module
with self.assertRaises(TextFSMTemplateError,
msg="Expected a ModuleNotFoundError when using keyword 'Repeated' without 'regex' module"):
result = t.ParseText(data)

def testRepeatedList(self):
"""Keywords Repeated and List should work together"""
tplt = """Value List,Repeated repeatedKey (\S+)
Value Repeated,List repeatedValue (\S+)
Value Repeated,List repeatedUnused (\S+)

Start
^(${repeatedKey}:${repeatedValue} )+
^record -> Record"""

data = """
key1:value1 key2:value2 key3:value3 \n
key4:value4 key5:value5 key6:value6 \n
record"""

t = textfsm.TextFSM(StringIO(tplt))
if useRegex is True:
result = t.ParseText(data)
else:
return

self.assertListEqual([[[['key1', 'key2', 'key3'], ['key4', 'key5', 'key6']], [['value1', 'value2', 'value3'],
['value4', 'value5', 'value6']], []]],
result
)

def testRepeatedFilldown(self):
"""Keywords Repeated and Filldown should work together"""
tplt = """Value Filldown,Repeated repeatedKey (\S+)
Value Repeated,Filldown repeatedValue (\S+)
Value Required otherMatch (\S+)

Start
^record -> Record
^(${repeatedKey}:${repeatedValue} )+
^${otherMatch}
"""

data = """
key1:value1 key2:value2 key3:value3 \n
key4:value4 key5:value5 key6:value6 \n
foo \n
bar \n
record \n
foobar \n
record"""

t = textfsm.TextFSM(StringIO(tplt))
if useRegex is True:
result = t.ParseText(data)
else:
return

self.assertListEqual([[['key4', 'key5', 'key6'], ['value4', 'value5', 'value6'], 'bar'], [['key4', 'key5', 'key6'],
['value4', 'value5', 'value6'], 'foobar']],
result
)

def testRepeatedFillup(self):
"""Keywords Repeated and Fillup should work together"""
tplt = """Value Fillup,Repeated repeatedKey (\S+)
Value Repeated,Fillup repeatedValue (\S+)
Value Required otherMatch (\S+)

Start
^record -> Record
^(${repeatedKey}:${repeatedValue} )+
^${otherMatch}
"""

data = """
foo \n
bar \n
record \n
foobar \n
key1:value1 key2:value2 key3:value3 \n
record"""

t = textfsm.TextFSM(StringIO(tplt))
if useRegex is True:
result = t.ParseText(data)
else:
return

self.assertListEqual([[['key1', 'key2', 'key3'], ['value1', 'value2', 'value3'], 'bar'],
[['key1', 'key2', 'key3'], ['value1', 'value2', 'value3'], 'foobar']],
result
)


if __name__ == '__main__':
unittest.main()
7 changes: 5 additions & 2 deletions textfsm/copyable_regex_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@

"""Work around a regression in Python 2.6 that makes RegexObjects uncopyable."""

try:
import regex as regexModule
except ImportError:
import re as regexModule

import re
from builtins import object # pylint: disable=redefined-builtin


Expand All @@ -26,7 +29,7 @@ class CopyableRegexObject(object):

def __init__(self, pattern):
self.pattern = pattern
self.regex = re.compile(pattern)
self.regex = regexModule.compile(pattern)

def match(self, *args, **kwargs):
return self.regex.match(*args, **kwargs)
Expand Down
Loading