Hello community,

here is the log from the commit of package python-ciscoconfparse for 
openSUSE:Factory checked in at 2020-06-14 18:33:23
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-ciscoconfparse (Old)
 and      /work/SRC/openSUSE:Factory/.python-ciscoconfparse.new.3606 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-ciscoconfparse"

Sun Jun 14 18:33:23 2020 rev:15 rq:814535 version:1.5.5

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-ciscoconfparse/python-ciscoconfparse.changes  
    2020-04-23 18:38:26.817007091 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-ciscoconfparse.new.3606/python-ciscoconfparse.changes
    2020-06-14 18:35:38.902606812 +0200
@@ -1,0 +2,10 @@
+Sat Jun 13 18:24:01 UTC 2020 - Martin Hauke <[email protected]>
+
+- Update to version 1.5.5
+  * Beta-test new function: find_object_branches()
+- Update to version 1.5.4
+  * Modify IPv4Obj().__add__() and IPv6Obj().__add__() (and __sub__())
+    methods return IPv4Obj()/IPv6Obj() objects.
+  * Add support for int(), bin() and hex() on the IPv4Obj() and IPv6Obj() 
+
+-------------------------------------------------------------------

Old:
----
  ciscoconfparse-1.5.3.tar.gz

New:
----
  ciscoconfparse-1.5.5.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-ciscoconfparse.spec ++++++
--- /var/tmp/diff_new_pack.glEnZY/_old  2020-06-14 18:35:39.466608608 +0200
+++ /var/tmp/diff_new_pack.glEnZY/_new  2020-06-14 18:35:39.470608621 +0200
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %bcond_without python2
 Name:           python-ciscoconfparse
-Version:        1.5.3
+Version:        1.5.5
 Release:        0
 Summary:        Library for parsing, querying and modifying Cisco IOS-style 
configurations
 License:        GPL-3.0-or-later

++++++ ciscoconfparse-1.5.3.tar.gz -> ciscoconfparse-1.5.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ciscoconfparse-1.5.3/CHANGES 
new/ciscoconfparse-1.5.5/CHANGES
--- old/ciscoconfparse-1.5.3/CHANGES    2020-04-12 17:53:07.000000000 +0200
+++ new/ciscoconfparse-1.5.5/CHANGES    2020-06-12 09:17:50.000000000 +0200
@@ -1,3 +1,5 @@
+1.5.5   20200612 Beta-test new function: find_object_branches()
+1.5.4   20200412 Modify IPv4Obj().__add__() and IPv6Obj().__add__() (and 
__sub__()) methods return IPv4Obj()/IPv6Obj() objects.  Add support for int(), 
bin() and hex() on the IPv4Obj() and IPv6Obj() 
 1.5.3   20200412 Fix IPv6Obj().packed and IPv6Obj().exploded; add 
IPv4Obj().packed and IPv4Obj().exploded
 1.5.2   20200412 Add __add__() and __sub__() to IPv4Obj() and IPv6Obj(); 
remove use of IPv6Obj().broadcast in IPv6Obj().__contains__()
 1.5.1   20200223 Remove embedded junos debugging
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ciscoconfparse-1.5.3/PKG-INFO 
new/ciscoconfparse-1.5.5/PKG-INFO
--- old/ciscoconfparse-1.5.3/PKG-INFO   2020-04-12 17:56:08.000000000 +0200
+++ new/ciscoconfparse-1.5.5/PKG-INFO   2020-06-12 11:02:20.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: ciscoconfparse
-Version: 1.5.3
+Version: 1.5.5
 Summary: Parse, Audit, Query, Build, and Modify Cisco IOS-style configurations
 Home-page: http://www.pennington.net/py/ciscoconfparse/
 Author: David Michael Pennington
@@ -202,6 +202,8 @@
         - If you're having problems with general python issues, consider 
searching for a solution on `Stack Overflow`_.  If you can't find a solution 
for your problem or need more help, you can `ask a question`_.
         - If you're having problems with your Cisco devices, you can open a 
case with `Cisco TAC`_; if you prefer crowd-sourcing, you can ask on the Stack 
Exchange `Network Engineering`_ site.
         
+        If you like slack, we also have a `ciscoconfparse NetworkToCode slack 
channel`_, where new releases are announced.
+        
         .. _Unit-Tests:
         
         Unit-Tests
@@ -299,6 +301,8 @@
         
         .. _`ask a question`: http://stackoverflow.com/questions/ask
         
+        .. _`ciscoconfparse NetworkToCode slack channel`: 
https://app.slack.com/client/T09LQ7E9E/C015B4U8MMF/
+        
         .. _`Secure IOS Template`: 
https://www.cymru.com/Documents/secure-ios-template.html
         
         .. _`Center for Internet Security Benchmarks`: 
https://learn.cisecurity.org/benchmarks
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ciscoconfparse-1.5.3/README.rst 
new/ciscoconfparse-1.5.5/README.rst
--- old/ciscoconfparse-1.5.3/README.rst 2020-02-20 09:14:33.000000000 +0100
+++ new/ciscoconfparse-1.5.5/README.rst 2020-06-10 01:38:55.000000000 +0200
@@ -194,6 +194,8 @@
 - If you're having problems with general python issues, consider searching for 
a solution on `Stack Overflow`_.  If you can't find a solution for your problem 
or need more help, you can `ask a question`_.
 - If you're having problems with your Cisco devices, you can open a case with 
`Cisco TAC`_; if you prefer crowd-sourcing, you can ask on the Stack Exchange 
`Network Engineering`_ site.
 
+If you like slack, we also have a `ciscoconfparse NetworkToCode slack 
channel`_, where new releases are announced.
+
 .. _Unit-Tests:
 
 Unit-Tests
@@ -291,6 +293,8 @@
 
 .. _`ask a question`: http://stackoverflow.com/questions/ask
 
+.. _`ciscoconfparse NetworkToCode slack channel`: 
https://app.slack.com/client/T09LQ7E9E/C015B4U8MMF/
+
 .. _`Secure IOS Template`: 
https://www.cymru.com/Documents/secure-ios-template.html
 
 .. _`Center for Internet Security Benchmarks`: 
https://learn.cisecurity.org/benchmarks
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ciscoconfparse-1.5.3/ciscoconfparse/ccp_util.py 
new/ciscoconfparse-1.5.5/ciscoconfparse/ccp_util.py
--- old/ciscoconfparse-1.5.3/ciscoconfparse/ccp_util.py 2020-04-12 
17:51:45.000000000 +0200
+++ new/ciscoconfparse-1.5.5/ciscoconfparse/ccp_util.py 2020-05-05 
11:15:34.000000000 +0200
@@ -253,15 +253,35 @@
                 self.__repr__(), val)
             raise ValueError(errmsg)
 
+    def __int__(self):
+        """Return this object as an integer"""
+        return self.as_decimal
+
+    def __index__(self):
+        """Return this object as an integer (used for hex() and bin() 
operations)"""
+        return self.as_decimal
+
     def __add__(self, val):
-        """Add an integer to IPv4Obj() and return an integer"""
-        assert isinstance(val, int)
-        return self.as_decimal + val
+        """Add an integer to IPv4Obj() and return an IPv4Obj()"""
+        assert isinstance(val, int), "Cannot add type: '{}' to 
{}".format(type(val), self)
+        orig_prefixlen = self.prefixlen
+        total = self.as_decimal + val
+        assert total <= 4294967295, "Max IPv4 integer exceeded"
+        assert total >= 0, "Min IPv4 integer exceeded"
+        retval = IPv4Obj(total)
+        retval.prefixlen = orig_prefixlen
+        return retval
 
     def __sub__(self, val):
-        """Subtract an integer from IPv4Obj() and return an integer"""
-        assert isinstance(val, int)
-        return self.as_decimal - val
+        """Subtract an integer from IPv4Obj() and return an IPv4Obj()"""
+        assert isinstance(val, int), "Cannot subtract type: '{}' from 
{}".format(type(val), self)
+        orig_prefixlen = self.prefixlen
+        total = self.as_decimal - val
+        assert total <= 4294967295, "Max IPv4 integer exceeded"
+        assert total >= 0, "Min IPv4 integer exceeded"
+        retval = IPv4Obj(total)
+        retval.prefixlen = orig_prefixlen
+        return retval
 
     def __contains__(self, val):
         # Used for "foo in bar"... python calls bar.__contains__(foo)
@@ -312,6 +332,12 @@
         """Returns the length of the network mask as an integer."""
         return self.network_object.prefixlen
 
+    @prefixlen.setter
+    def prefixlen(self, arg):
+        """prefixlen setter method"""
+        self.network_object = IPv4Network('{0}/{1}'.format(str(self.ip_object),
+            arg), strict=False)
+
     @property
     def prefixlength(self):
         """Returns the length of the network mask as an integer."""
@@ -462,7 +488,7 @@
         except TypeError:
             if getattr(arg, 'dna', '')=="IPv6Obj":
                 ip_str = '{0}/{1}'.format(str(arg.ip_object), arg.prefixlen)
-                self.network_object = IPv6Network(ip_str, strict = False)
+                self.network_object = IPv6Network(ip_str, strict=False)
                 self.ip_object = IPv6Address(str(arg.ip_object))
                 return None
             elif isinstance(arg, IPv6Network):
@@ -542,15 +568,37 @@
                 self.__repr__(), val)
             raise ValueError(errmsg)
 
+    def __int__(self):
+        """Return this object as an integer"""
+        return self.as_decimal
+
+    def __index__(self):
+        """Return this object as an integer (used for hex() and bin() 
operations)"""
+        return self.as_decimal
+
     def __add__(self, val):
-        """Add an integer to IPv6Obj() and return an integer"""
-        assert isinstance(val, int)
-        return self.as_decimal + val
+        """Add an integer to IPv6Obj() and return an IPv6Obj()"""
+        assert isinstance(val, int), "Cannot add type: '{}' to 
{}".format(type(val), self)
+        orig_prefixlen = self.prefixlen
+        total = self.as_decimal + val
+        error = "Max IPv6 integer exceeded"
+        assert total <= 340282366920938463463374607431768211455, error
+        assert total >= 0, "Min IPv4 integer exceeded"
+        retval = IPv6Obj(total)
+        retval.prefixlen = orig_prefixlen
+        return retval
 
     def __sub__(self, val):
-        """Subtract an integer from IPv6Obj() and return an integer"""
-        assert isinstance(val, int)
-        return self.as_decimal - val
+        """Subtract an integer from IPv6Obj() and return an IPv6Obj()"""
+        assert isinstance(val, int), "Cannot subtract type: '{}' from 
{}".format(type(val), self)
+        orig_prefixlen = self.prefixlen
+        total = self.as_decimal - val
+        error = "Max IPv6 integer exceeded"
+        assert total <= 340282366920938463463374607431768211455, error
+        assert total >= 0, "Min IPv4 integer exceeded"
+        retval = IPv6Obj(total)
+        retval.prefixlen = orig_prefixlen
+        return retval
 
     def __contains__(self, val):
         # Used for "foo in bar"... python calls bar.__contains__(foo)
@@ -602,6 +650,12 @@
         """Returns the length of the network mask as an integer."""
         return self.network_object.prefixlen
 
+    @prefixlen.setter
+    def prefixlen(self, arg):
+        """prefixlen setter method"""
+        self.network_object = IPv6Network('{0}/{1}'.format(str(self.ip_object),
+            arg), strict=False)
+
     @property
     def prefixlength(self):
         """Returns the length of the network mask as an integer."""
@@ -660,7 +714,7 @@
         num_strings = str(self.ip.exploded).split(':')
         num_strings.reverse()  # reverse the order
         return sum(
-            [int(num, 16) * (256**idx) for idx, num in enumerate(num_strings)])
+            [int(num, 16) * (65536**idx) for idx, num in 
enumerate(num_strings)])
 
     @property
     def as_binary_tuple(self):
@@ -840,14 +894,17 @@
         - timeout (float): DNS lookup timeout duration (default: 2.0 seconds)
 
     Returns:
-        A set() of :class:`~ccp_util.DNSResponse` instances
+        A set([]) of :class:`~ccp_util.DNSResponse` instances.  Refer to the 
DNSResponse object in these docs for more information.
 
 >>> from ciscoconfparse.ccp_util import dns_query
->>> dns_query('www.pennington.net', "A", "4.2.2.2")
+>>> dns_query('www.pennington.net', "A", "4.2.2.2", timeout=0.5)
 set([<DNSResponse "A" result_str="65.19.187.2">])
->>> answer = dns_query('www.pennington.net', 'A', '4.2.2.2')
->>> str(answer.pop())
+>>> response_set = dns_query('www.pennington.net', 'A', '4.2.2.2')
+>>> aa = response_set.pop()
+>>> aa.result_str
 '65.19.187.2'
+>>> aa.error_str
+''
 >>>
     """
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ciscoconfparse-1.5.3/ciscoconfparse/ciscoconfparse.py 
new/ciscoconfparse-1.5.5/ciscoconfparse/ciscoconfparse.py
--- old/ciscoconfparse-1.5.3/ciscoconfparse/ciscoconfparse.py   2020-02-26 
10:40:59.000000000 +0100
+++ new/ciscoconfparse-1.5.5/ciscoconfparse/ciscoconfparse.py   2020-06-12 
10:55:01.000000000 +0200
@@ -4,6 +4,7 @@
 from difflib import SequenceMatcher
 import logging
 import time
+import copy
 import sys
 import re
 import os
@@ -51,7 +52,7 @@
 from ciscoconfparse.models_junos import JunosCfgLine
 
 r""" ciscoconfparse.py - Parse, Query, Build, and Modify IOS-style configs
-     Copyright (C) 2007-2019 David Michael Pennington
+     Copyright (C) 2007-2020 David Michael Pennington
 
      This program is free software: you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
@@ -492,6 +493,139 @@
             offset += indent_child
         return lines
 
+    def find_object_branches(self, branchspec=(), regex_flags=0):
+        """This method iterates over a tuple of regular expressions in 
`branchspec` and returns the matching objects in a list of lists. `branchspec` 
expects to start at some root ancestor and walk through the nested object 
hierarchy (with no limit on depth).
+
+        Previous CiscoConfParse() methods only handled a single parent regex 
and single child regex (such as 
:func:`~ciscoconfparse.CiscoConfParse.find_parents_w_child`).
+
+        This method dives beyond a simple parent-child relationship to include 
entire family 'branches' (i.e. parent, child, grand-children, 
great-grand-children, etc).  The net result of handling longer chains of 
objects is it flattens what would otherwise be nested loops in your scripts; 
this makes parsing heavily-nested configuratations like Palo-Alto and F5 much 
simpler.  Of course, there are plenty of applications for "flatter" config 
formats like IOS.
+        
+        This method returns a list of lists (of object 'branches') which are 
nested to the same depth required in `branchspec`.  However, unlike most other 
CiscoConfParse() methods, it returns an explicit `None` if there is no object 
match.  Returning `None` allows a single search over configs that may not be 
uniformly nested in every branch.
+
+        Args:
+            - branchspec (tuple): A tuple of python regular expressions to be 
matched.
+        Kwargs:
+            - regex_flags : Defaults to 0.
+
+        Returns:
+            - list.  A list of lists of matching 
:class:`~ciscoconfparse.IOSCfgLine` objects
+
+        .. code-block:: python
+           :emphasize-lines: 28, 29
+
+           >>> config = [
+           ...     'ltm pool FOO {',
+           ...     '  members {',
+           ...     '    k8s-05.localdomain:8443 {',
+           ...     '      address 192.0.2.5',
+           ...     '      session monitor-enabled',
+           ...     '      state up',
+           ...     '    }',
+           ...     '    k8s-06.localdomain:8443 {',
+           ...     '      address 192.0.2.6',
+           ...     '      session monitor-enabled',
+           ...     '      state down',
+           ...     '    }',
+           ...     '  }',
+           ...     '}',
+           ...     'ltm pool BAR {',
+           ...     '  members {',
+           ...     '    k8s-07.localdomain:8443 {',
+           ...     '      address 192.0.2.7',
+           ...     '      session monitor-enabled',
+           ...     '      state down',
+           ...     '    }',
+           ...     '  }',
+           ...     '}',
+           ...     ]
+           >>> parse = CiscoConfParse(config, syntax='junos', comment='#')
+           >>>
+           >>> branchspec = (r'ltm\spool', r'members', r'\S+?:\d+', 
r'state\sup')
+           >>> branches = parse.find_object_branches(branchspec=branchspec)
+           >>>
+           >>> # We found three branches which matched all regexes...
+           >>> len(branches)
+           3
+           >>> # Each branch will always match the length of branchspec
+           >>> len(branches[0])
+           4
+           >>> # Print out one object 'branch'
+           >>> branches[0]
+           [<IOSCfgLine # 0 'ltm pool FOO'>, <IOSCfgLine # 1 '    members' 
(parent is # 0)>, <IOSCfgLine # 2 '        k8s-05.localdomain:8443' (parent is 
# 1)>, <IOSCfgLine # 5 '            state up' (parent is # 2)>]
+           >>>
+           >>> # Note: `None` in branches[1][-1] because of no regex match
+           >>> branches[1]
+           [<IOSCfgLine # 0 'ltm pool FOO'>, <IOSCfgLine # 1 '    members' 
(parent is # 0)>, <IOSCfgLine # 6 '        k8s-06.localdomain:8443' (parent is 
# 1)>, None]
+           >>>
+           >>> branches[2]
+           [<IOSCfgLine # 10 'ltm pool BAR'>, <IOSCfgLine # 11 '    members' 
(parent is # 10)>, <IOSCfgLine # 12 '        k8s-07.localdomain:8443' (parent 
is # 11)>, None]
+        """
+        assert isinstance(branchspec, tuple), "Please enclose the regular 
expressions in a Python tuple"
+
+        def list_matching_children(parent_obj, childspec, regex_flags):
+            ## I'm not using parent_obj.re_search_children() because
+            ## re_search_children() doesn't return None for no match...
+
+            # FIXME: Insert debugging here...
+            #print("PARENT "+str(parent_obj))
+
+            # Get the child objects from parent objects
+            if parent_obj is None:
+                children =  self._find_line_OBJ(linespec=childspec,
+                    exactmatch=False)
+            else:
+                children = parent_obj.children
+
+            # Find all child objects which match childspec...
+            segment_list = [cobj for cobj in children if re.search(childspec, 
cobj.text, regex_flags)]
+            # Return [None] if no children matched...
+            if len(segment_list)==0:
+                segment_list = [None]
+
+            # FIXME: Insert debugging here...
+            #print("    SEGMENTS "+str(segment_list))
+            return segment_list
+
+        branches = list()
+        # iterate over the regular expressions in branchspec
+        for idx, childspec in enumerate(branchspec):
+            # FIXME: Insert debugging here...
+            #print("CHILDSPEC "+childspec)
+            if idx==0:
+                # Get matching 'root' objects from the config
+                next_kids = list_matching_children(parent_obj=None,
+                    childspec=childspec, regex_flags=regex_flags)
+                # Start growing branches from the segments we received...
+                branches = [[kid] for kid in next_kids]
+
+            else:
+                new_branches = list()
+                for branch in branches:
+                    # Extend existing branches into the new_branches
+                    if branch[-1] is not None:
+                        # Find children to extend the family branch...
+                        next_kids = list_matching_children(
+                            parent_obj=branch[-1], childspec=childspec,
+                            regex_flags=regex_flags)
+
+                        # branches 'grow' here with the matching kids above...
+                        branch.append('__INSERT_KID_HERE__')
+                        for kid in next_kids:
+                            # Fork off a new branch for each matching kid...
+                            # If there's a faster alternative to deepcopy(), I
+                            # haven't found it...
+                            tmp = copy.deepcopy(branch)
+                            tmp[-1] = kid
+                            new_branches.append(tmp)
+                    else:
+                        branch.append(None)
+                        new_branches.append(branch)
+
+                # Ensure we have the most recent branches...
+                branches = new_branches
+
+        return branches
+
     def find_interface_objects(self, intfspec, exactmatch=True):
         """Find all :class:`~models_cisco.IOSCfgLine` or 
         :class:`~models_cisco.NXOSCfgLine` objects whose text 
@@ -583,7 +717,6 @@
            >>> # The IOSHostnameLine object has a hostname attribute
            >>> obj_list[0].hostname
            'MyRouterHostname'
-           >>>
         """
         if not self.factory:
             raise ValueError(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ciscoconfparse-1.5.3/ciscoconfparse/version 
new/ciscoconfparse-1.5.5/ciscoconfparse/version
--- old/ciscoconfparse-1.5.3/ciscoconfparse/version     2020-04-12 
17:53:15.000000000 +0200
+++ new/ciscoconfparse-1.5.5/ciscoconfparse/version     2020-06-12 
09:16:56.000000000 +0200
@@ -1 +1 @@
-1.5.3
+1.5.5
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ciscoconfparse-1.5.3/ciscoconfparse.egg-info/PKG-INFO 
new/ciscoconfparse-1.5.5/ciscoconfparse.egg-info/PKG-INFO
--- old/ciscoconfparse-1.5.3/ciscoconfparse.egg-info/PKG-INFO   2020-04-12 
17:56:05.000000000 +0200
+++ new/ciscoconfparse-1.5.5/ciscoconfparse.egg-info/PKG-INFO   2020-06-12 
11:02:16.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: ciscoconfparse
-Version: 1.5.3
+Version: 1.5.5
 Summary: Parse, Audit, Query, Build, and Modify Cisco IOS-style configurations
 Home-page: http://www.pennington.net/py/ciscoconfparse/
 Author: David Michael Pennington
@@ -202,6 +202,8 @@
         - If you're having problems with general python issues, consider 
searching for a solution on `Stack Overflow`_.  If you can't find a solution 
for your problem or need more help, you can `ask a question`_.
         - If you're having problems with your Cisco devices, you can open a 
case with `Cisco TAC`_; if you prefer crowd-sourcing, you can ask on the Stack 
Exchange `Network Engineering`_ site.
         
+        If you like slack, we also have a `ciscoconfparse NetworkToCode slack 
channel`_, where new releases are announced.
+        
         .. _Unit-Tests:
         
         Unit-Tests
@@ -299,6 +301,8 @@
         
         .. _`ask a question`: http://stackoverflow.com/questions/ask
         
+        .. _`ciscoconfparse NetworkToCode slack channel`: 
https://app.slack.com/client/T09LQ7E9E/C015B4U8MMF/
+        
         .. _`Secure IOS Template`: 
https://www.cymru.com/Documents/secure-ios-template.html
         
         .. _`Center for Internet Security Benchmarks`: 
https://learn.cisecurity.org/benchmarks
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ciscoconfparse-1.5.3/tests/test_CiscoConfParse.py 
new/ciscoconfparse-1.5.5/tests/test_CiscoConfParse.py
--- old/ciscoconfparse-1.5.3/tests/test_CiscoConfParse.py       2019-06-05 
15:21:26.000000000 +0200
+++ new/ciscoconfparse-1.5.5/tests/test_CiscoConfParse.py       2020-06-12 
10:15:09.000000000 +0200
@@ -540,6 +540,186 @@
         test_result = parse_c01.find_children_w_parents(**args)
         assert result_correct==test_result
 
+def testValues_find_object_branches_01():
+    """Basic test: find_object_branches() - only look for object text matching 
(90% solution)"""
+    config = [
+       'ltm pool FOO {',
+       '  members {',
+       '    k8s-05.localdomain:8443 {',
+       '      address 192.0.2.5',
+       '      session monitor-enabled',
+       '      state up',
+       '    }',
+       '    k8s-06.localdomain:8443 {',
+       '      address 192.0.2.6',
+       '      session monitor-enabled',
+       '      state down',
+       '    }',
+       '  }',
+       '}',
+       'ltm pool BAR {',
+       '  members {',
+       '    k8s-07.localdomain:8443 {',
+       '      address 192.0.2.7',
+       '      session monitor-enabled',
+       '      state down',
+       '    }',
+       '  }',
+       '}',
+       ]
+    parse = CiscoConfParse(config, syntax='junos', comment='#')
+    branchspec = (r'ltm\spool', r'members', r'\S+?:\d+', r'state\sup')
+    test_result = parse.find_object_branches(branchspec=branchspec)
+
+    assert len(test_result)==3
+
+    # Test first family branch result...
+    assert test_result[0][0].text.strip()=='ltm pool FOO'
+    assert test_result[0][1].text.strip()=='members'
+    assert test_result[0][2].text.strip()=='k8s-05.localdomain:8443'
+    assert test_result[0][3].text.strip()=='state up'
+
+    # Test second family branch result...
+    assert test_result[1][0].text.strip()=='ltm pool FOO'
+    assert test_result[1][1].text.strip()=='members'
+    assert test_result[1][2].text.strip()=='k8s-06.localdomain:8443'
+    assert test_result[1][3] is None   # 'state down' != 'state up'
+    
+    # Test third family branch result...
+    assert test_result[2][0].text.strip()=='ltm pool BAR'
+    assert test_result[2][1].text.strip()=='members'
+    assert test_result[2][2].text.strip()=='k8s-07.localdomain:8443'
+    assert test_result[2][3] is None   # 'state down' != 'state up'
+
+def testValues_find_object_branches_02():
+    """Basic test: find_object_branches() - only look for object text matching 
(90% solution)"""
+    config = [
+       'ltm pool FOO {',
+       '  members {',
+       '    k8s-05.localdomain:8443 {',
+       '      address 192.0.2.5',
+       '      session monitor-enabled',
+       '      state up',
+       '    }',
+       '    k8s-06.localdomain:8443 {',
+       '      address 192.0.2.6',
+       '      session monitor-enabled',
+       '      state down',
+       '    }',
+       '  }',
+       '}',
+       'ltm pool BAR {',
+       '  members {',
+       '    k8s-07.localdomain:8443 {',
+       '      address 192.0.2.7',
+       '      session monitor-enabled',
+       '      state down',
+       '    }',
+       '  }',
+       '}',
+       ]
+
+    parse = CiscoConfParse(config, syntax='junos', comment='#')
+    # Test negative lookahead matching in the first regex term... Dont match
+    # 'ltm pool BAR'...
+    branchspec = (r'ltm\spool\s(?!BAR)', r'members', r'\S+?:\d+', r'state\sup')
+    test_result = parse.find_object_branches(branchspec=branchspec)
+
+    assert len(test_result)==2
+
+    # Test first family branch result...
+    assert test_result[0][0].text.strip()=='ltm pool FOO'
+    assert test_result[0][1].text.strip()=='members'
+    assert test_result[0][2].text.strip()=='k8s-05.localdomain:8443'
+    assert test_result[0][3].text.strip()=='state up'
+
+    # Test second family branch result...
+    assert test_result[1][0].text.strip()=='ltm pool FOO'
+    assert test_result[1][1].text.strip()=='members'
+    assert test_result[1][2].text.strip()=='k8s-06.localdomain:8443'
+    assert test_result[1][3] is None   # 'state down' != 'state up'
+
+    
+def testValues_find_object_branches_03(parse_c01):
+    """Basic test: find_object_branches() - Test for multiple matches to a 
vague branchspec term..."""
+
+    # NOTE This is NOT a good example of how to use find_object_branches... I'm
+    # testing to ensure we get the right matches for a vague regular 
expression...
+    # this winds up returning a lot of different match object types in the 
+    # last branch term
+    branchspec = (r'^interface', r'switchport',)
+    test_result = parse_c01.find_object_branches(branchspec=branchspec)
+
+    assert len(test_result)==19
+
+    assert test_result[0][0].text.strip()=='interface Serial 1/0'
+    assert test_result[0][1] is None # Serial is not a switchport :)
+
+    assert test_result[1][0].text.strip()=='interface GigabitEthernet4/1'
+    assert test_result[1][1].text.strip()=='switchport'
+
+    assert test_result[2][0].text.strip()=='interface GigabitEthernet4/1'
+    assert test_result[2][1].text.strip()=='switchport access vlan 100'
+
+    assert test_result[3][0].text.strip()=='interface GigabitEthernet4/1'
+    assert test_result[3][1].text.strip()=='switchport voice vlan 150'
+
+    assert test_result[4][0].text.strip()=='interface GigabitEthernet4/2'
+    assert test_result[4][1].text.strip()=='switchport'
+
+    assert test_result[5][0].text.strip()=='interface GigabitEthernet4/2'
+    assert test_result[5][1].text.strip()=='switchport access vlan 100'
+
+    assert test_result[6][0].text.strip()=='interface GigabitEthernet4/2'
+    assert test_result[6][1].text.strip()=='switchport voice vlan 150'
+
+    assert test_result[7][0].text.strip()=='interface GigabitEthernet4/3'
+    assert test_result[7][1].text.strip()=='switchport'
+
+    assert test_result[8][0].text.strip()=='interface GigabitEthernet4/3'
+    assert test_result[8][1].text.strip()=='switchport access vlan 100'
+
+    assert test_result[9][0].text.strip()=='interface GigabitEthernet4/3'
+    assert test_result[9][1].text.strip()=='switchport voice vlan 150'
+
+    assert test_result[10][0].text.strip()=='interface GigabitEthernet4/4'
+    assert test_result[10][1] is None #Gi4/4 isn't a switchport (ref regex 
term)
+
+    assert test_result[11][0].text.strip()=='interface GigabitEthernet4/5'
+    assert test_result[11][1].text.strip()=='switchport'
+
+    assert test_result[12][0].text.strip()=='interface GigabitEthernet4/5'
+    assert test_result[12][1].text.strip()=='switchport access vlan 110'
+
+    assert test_result[13][0].text.strip()=='interface GigabitEthernet4/6'
+    assert test_result[13][1].text.strip()=='switchport'
+
+    assert test_result[14][0].text.strip()=='interface GigabitEthernet4/6'
+    assert test_result[14][1].text.strip()=='switchport access vlan 110'
+
+    assert test_result[15][0].text.strip()=='interface GigabitEthernet4/7'
+    assert test_result[15][1].text.strip()=='switchport'
+
+    assert test_result[16][0].text.strip()=='interface GigabitEthernet4/7'
+    assert test_result[16][1].text.strip()=='switchport access vlan 110'
+
+    assert test_result[17][0].text.strip()=='interface GigabitEthernet4/8'
+    assert test_result[17][1].text.strip()=='switchport'
+
+    assert test_result[18][0].text.strip()=='interface GigabitEthernet4/8'
+    assert test_result[18][1].text.strip()=='switchport access vlan 110'
+
+def testValues_find_object_branches_04(parse_c01):
+    """Basic test: find_object_branches() - Test that non-existent regex child 
levels return `None`"""
+
+    # NOTE This is NOT a good example of using find_object_branches()... I'm
+    # negative testing to ensure we get the right matches for NO regex
+    # matches...
+    branchspec = (r'this', r'dont', 'match', 'at', 'all')
+    test_result = parse_c01.find_object_branches(branchspec=branchspec)
+    result_correct = [[None, None, None, None, None]]
+    assert test_result==result_correct
+
 def testValues_find_objects_w_parents(parse_c01):
     c01_children_w_parents_switchport = [
         ' switchport',


Reply via email to