Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-ciscoconfparse for 
openSUSE:Factory checked in at 2022-10-29 20:16:49
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-ciscoconfparse (Old)
 and      /work/SRC/openSUSE:Factory/.python-ciscoconfparse.new.2275 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-ciscoconfparse"

Sat Oct 29 20:16:49 2022 rev:25 rq:1032073 version:1.6.50

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-ciscoconfparse/python-ciscoconfparse.changes  
    2022-10-21 16:20:14.742251416 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-ciscoconfparse.new.2275/python-ciscoconfparse.changes
    2022-10-29 20:18:05.490525468 +0200
@@ -1,0 +2,22 @@
+Thu Oct 27 22:29:08 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com>
+
+- Update to version 1.6.50: 
+  Released: 2022-10-21
+  Summary:
+   * Modify .github/workflows/tests.yml with improved yml
+   * Enhance CiscoConfParse().repr() string output
+   * Minor package documentation tweaks
+
+- Update to version 1.6.49:
+  * Adjust string strip() conditions on config lines in 
assign_parent_to_closing_braces()
+
+- Update to version 1.6.48:
+  * Add code to catch misconfigurations such as parsing a string instead of a 
list in ciscoconfparse.ConfigList(``)
+  * Avoid problems with reading empty lines (see Github Issue #251)
+
+- Update to version 1.6.47:
+  * Add repo version management into the Makefile ('make bump-version-patch' / 
'make bump-version-minor')
+  * Add repo version management to 'dev_tools/git_helper.py'
+  * Revise README_git_workflow.md to include more rebase and merge details 
+
+-------------------------------------------------------------------

Old:
----
  ciscoconfparse-1.6.41.tar.gz

New:
----
  ciscoconfparse-1.6.50.tar.gz

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

Other differences:
------------------
++++++ python-ciscoconfparse.spec ++++++
--- /var/tmp/diff_new_pack.dKY79w/_old  2022-10-29 20:18:05.986528111 +0200
+++ /var/tmp/diff_new_pack.dKY79w/_new  2022-10-29 20:18:05.994528153 +0200
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %bcond_without python2
 Name:           python-ciscoconfparse
-Version:        1.6.41
+Version:        1.6.50
 Release:        0
 Summary:        Library for parsing, querying and modifying Cisco IOS-style 
configurations
 License:        GPL-3.0-or-later

++++++ ciscoconfparse-1.6.41.tar.gz -> ciscoconfparse-1.6.50.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ciscoconfparse-1.6.41/PKG-INFO 
new/ciscoconfparse-1.6.50/PKG-INFO
--- old/ciscoconfparse-1.6.41/PKG-INFO  2022-09-10 00:29:24.075619200 +0200
+++ new/ciscoconfparse-1.6.50/PKG-INFO  1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: ciscoconfparse
-Version: 1.6.41
+Version: 1.6.50
 Summary: Parse, Audit, Query, Build, and Modify Cisco IOS-style and 
JunOS-style configurations
 Home-page: https://github.com/mpenning/ciscoconfparse
 License: GPLv3
@@ -21,11 +21,12 @@
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.6
 Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
 Classifier: Topic :: Communications
 Classifier: Topic :: Internet
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
@@ -152,7 +153,7 @@
 Pre-requisites
 --------------
 
-[The ciscoconfparse python package][3] requires Python versions 3.6+ (note: 
Python version 3.7.0 has a bug - ref [Github issue \#117][18], but version 
3.7.1 works); the OS should not matter.
+[The ciscoconfparse python package][3] requires Python versions 3.7+ (note: 
Python version 3.7.0 has a bug - ref [Github issue \#117][18], but version 
3.7.1 works); the OS should not matter.
 
 Installation and Downloads
 --------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ciscoconfparse-1.6.41/README.md 
new/ciscoconfparse-1.6.50/README.md
--- old/ciscoconfparse-1.6.41/README.md 2022-05-26 11:47:08.097129000 +0200
+++ new/ciscoconfparse-1.6.50/README.md 2022-10-20 13:10:54.100284000 +0200
@@ -112,7 +112,7 @@
 Pre-requisites
 --------------
 
-[The ciscoconfparse python package][3] requires Python versions 3.6+ (note: 
Python version 3.7.0 has a bug - ref [Github issue \#117][18], but version 
3.7.1 works); the OS should not matter.
+[The ciscoconfparse python package][3] requires Python versions 3.7+ (note: 
Python version 3.7.0 has a bug - ref [Github issue \#117][18], but version 
3.7.1 works); the OS should not matter.
 
 Installation and Downloads
 --------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ciscoconfparse-1.6.41/ciscoconfparse/ccp_abc.py 
new/ciscoconfparse-1.6.50/ciscoconfparse/ccp_abc.py
--- old/ciscoconfparse-1.6.41/ciscoconfparse/ccp_abc.py 2022-07-20 
02:06:20.741461800 +0200
+++ new/ciscoconfparse-1.6.50/ciscoconfparse/ccp_abc.py 2022-10-20 
13:10:54.100284000 +0200
@@ -18,7 +18,6 @@
 """
 
 from difflib import get_close_matches
-from operator import methodcaller
 from abc import ABCMeta
 import warnings
 import inspect
@@ -538,10 +537,8 @@
            !
            >>>
         """
-        cobjs = filter(methodcaller("re_search", linespec), self.children)
-        retval = [ii.text for ii in cobjs]
-        # Delete the children
-        map(methodcaller("delete"), cobjs)
+        # if / else in a list comprehension... ref ---> 
https://stackoverflow.com/a/9442777/667301
+        retval = [(obj.delete() if obj.re_search(linespec) else obj) for obj 
in self.children]
         return retval
 
     # On BaseCfgLine()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ciscoconfparse-1.6.41/ciscoconfparse/ccp_util.py 
new/ciscoconfparse-1.6.50/ciscoconfparse/ccp_util.py
--- old/ciscoconfparse-1.6.41/ciscoconfparse/ccp_util.py        2022-09-10 
00:25:02.491401000 +0200
+++ new/ciscoconfparse-1.6.50/ciscoconfparse/ccp_util.py        2022-10-20 
13:10:54.100284000 +0200
@@ -143,7 +143,7 @@
 
 
     """
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def __init__(self):
 
         self.PYTHONOPTIMIZE_env_value = os.environ.get("PYTHONOPTIMIZE", None)
@@ -178,8 +178,136 @@
         if error != "__no_error__":
             raise PythonOptimizeException(error)
 
+@logger.catch(reraise=True)
+def ccp_logger_control(
+    sink=sys.stderr,
+    action="",
+    handler_id=None,
+    allow_enqueue=True,
+    # rotation="00:00",
+    # retention="1 month",
+    # compression="zip",
+    level="DEBUG",
+    colorize=True,
+    debug=0,
+):
+    """
+    A simple function to handle logging... Enable / Disable all
+    ciscoconfparse logging here... also see Github issue #211.
+
+    Example
+    -------
+    """
+
+    msg = "ccp_logger_control() was called with sink='{}', action='{}', 
handler_id='{}', allow_enqueue={}, level='{}', colorize={}, debug={}".format(
+        sink,
+        action,
+        handler_id,
+        allow_enqueue,
+        # rotation,
+        # retention,
+        # compression,
+        level,
+        colorize,
+        debug,
+    )
+    if debug > 0:
+        logger.info(msg)
+
+    assert isinstance(action, str)
+    assert action in ("remove", "add", "disable", "enable", "",)
+
+    package_name = "ciscoconfparse"
+
+    if action == "remove":
+        # Require an explicit loguru handler_id to remove...
+        assert isinstance(handler_id, int)
+
+        logger.remove(handler_id)
+        return True
+
+    elif action == "disable":
+        # Administratively disable this loguru logger
+        logger.disable(package_name)
+        return True
+
+    elif action == "enable":
+        # Administratively enable this loguru logger
+        logger.enable(package_name)
+        return True
+
+    elif action == "add":
+
+        logger.add(
+            sink=sink,
+            diagnose=True,
+            backtrace=True,
+            # https://github.com/mpenning/ciscoconfparse/issues/215
+            enqueue=allow_enqueue,
+            serialize=False,
+            catch=True,
+            # rotation="00:00",
+            # retention="1 day",
+            # compression="zip",
+            colorize=True,
+            level="DEBUG",
+        )
+        logger.enable(package_name)
+        return True
+
+    elif action == "":
+        raise ValueError(
+            "action='' is not supported.  Please use a valid action keyword"
+        )
+
+    else:
+        raise NotImplementedError(
+            "action='%s' is an unsupported logger action" % action
+        )
+
+
+@logger.catch(reraise=True)
+def configure_loguru(
+    sink=sys.stderr,
+    action="",
+    # rotation="midnight",
+    # retention="1 month",
+    # compression="zip",
+    level="DEBUG",
+    colorize=True,
+    debug=0,
+):
+    """
+    configure_loguru()
+    """
+    assert isinstance(action, str)
+    assert action in ('remove', 'add', 'enable', 'disable', '',)
+    # assert isinstance(rotation, str)
+    # assert isinstance(retention, str)
+    # assert isinstance(compression, str)
+    # assert compression == "zip"
+    assert isinstance(level, str)
+    assert isinstance(colorize, bool)
+    assert isinstance(debug, int) and (0 <= debug <= 5)
+
+    # logger_control() was imported above...
+    #    Remove the default loguru logger to stderr (handler_id==0)...
+    ccp_logger_control(action="remove", handler_id=0)
+
+    # Add log to STDOUT
+    ccp_logger_control(
+        sink=sys.stdout,
+        action="add",
+        level="DEBUG",
+        # rotation='midnight',   # ALE barks about the rotation keyword...
+        # retention="1 month",
+        # compression=compression,
+        colorize=colorize
+    )
+    ccp_logger_control(action="enable")
+
 
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
+@logger.catch(reraise=True)
 def as_text_list(object_list):
     """
     This is a helper-function to convert a list of configuration objects into
@@ -217,11 +345,11 @@
     return list(map(attrgetter("text"), object_list))
 
 
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
+@logger.catch(reraise=True)
 def junos_unsupported(func):
     """A function wrapper to warn junos users of unsupported features"""
 
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def wrapper(*args, **kwargs):
         warn = "syntax='junos' does not fully support config modifications 
such as .{}(); see Github Issue #185.  
https://github.com/mpenning/ciscoconfparse/issues/185".format(
             func.__name__
@@ -240,7 +368,7 @@
     return wrapper
 
 
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
+@logger.catch(reraise=True)
 def log_function_call(function=None, *args, **kwargs):
     """A wrapper; this decorator uses loguru to log function calls.
 
@@ -253,7 +381,7 @@
 
     """
 
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def logging_decorator(ff):
         @wraps(ff)
         def wrapped_logging(*args, **kwargs):
@@ -283,93 +411,6 @@
     return logging_decorator
 
 
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
-def ccp_logger_control(
-    sink=sys.stderr,
-    action="",
-    handler_id=None,
-    allow_enqueue=True,
-    # rotation="00:00",
-    # retention="1 month",
-    # compression="zip",
-    level="DEBUG",
-    colorize=True,
-    debug=0,
-):
-    """
-    A simple function to handle logging... Enable / Disable all
-    ciscoconfparse logging here... also see Github issue #211.
-
-    Example
-    -------
-    """
-
-    msg = "ccp_logger_control() was called with sink='{}', action='{}', 
handler_id='{}', allow_enqueue={}, level='{}', colorize={}, debug={}".format(
-        sink,
-        action,
-        handler_id,
-        allow_enqueue,
-        # rotation,
-        # retention,
-        # compression,
-        level,
-        colorize,
-        debug,
-    )
-    if debug > 0:
-        logger.info(msg)
-
-    assert isinstance(action, str)
-    assert action in ("remove", "add", "disable", "enable", "",)
-
-    package_name = "ciscoconfparse"
-
-    if action == "remove":
-        # Require an explicit loguru handler_id to remove...
-        assert isinstance(handler_id, int)
-
-        logger.remove(handler_id)
-        return True
-
-    elif action == "disable":
-        # Administratively disable this loguru logger
-        logger.disable(package_name)
-        return True
-
-    elif action == "enable":
-        # Administratively enable this loguru logger
-        logger.enable(package_name)
-        return True
-
-    elif action == "add":
-
-        logger.add(
-            sink=sink,
-            diagnose=True,
-            backtrace=True,
-            # https://github.com/mpenning/ciscoconfparse/issues/215
-            enqueue=allow_enqueue,
-            serialize=False,
-            catch=True,
-            # rotation="00:00",
-            # retention="1 day",
-            # compression="zip",
-            colorize=True,
-            level="DEBUG",
-        )
-        logger.enable(package_name)
-        return True
-
-    elif action == "":
-        raise ValueError(
-            "action='' is not supported.  Please use a valid action keyword"
-        )
-
-    else:
-        raise NotImplementedError(
-            "action='%s' is an unsupported logger action" % action
-        )
-
 
 class __ccp_re__(object):
     """
@@ -402,7 +443,7 @@
 
     """
 
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def __init__(self, regex_str=r"", target_str=None, groups=None, flags=0,
         debug=0):
         assert isinstance(regex_str, str)
@@ -628,7 +669,7 @@
         error_str = "Cannot parse '%s' as ipv4 or ipv6" % val
         raise AddressValueError(error_str)
 
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
+@logger.catch(reraise=True)
 def collapse_addresses(network_list):
     """
     This is a ciscoconfparse proxy for ipaddress.collapse_addresses()
@@ -642,7 +683,7 @@
     """
     assert isinstance(network_list, list) or isinstance(network_list, tuple)
 
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def ip_net(arg):
         if isinstance(arg, IPv4Obj):
             return arg.network
@@ -2242,7 +2283,7 @@
             )
 
 
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
+@logger.catch(reraise=True)
 def dns_query(input_str="", query_type="", server="", timeout=2.0):
     """A unified IPv4 & IPv6 DNS lookup interface; this is essentially just a 
wrapper around dnspython's API.  When you query a PTR record, you can use an 
IPv4 or IPv6 address (which will automatically be converted into an 
in-addr.arpa name.  This wrapper only supports a subset of DNS records: 'A', 
'AAAA', 'CNAME', 'MX', 'NS', 'PTR', and 'TXT'
 
@@ -2435,7 +2476,7 @@
     return retval
 
 
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
+@logger.catch(reraise=True)
 def dns_lookup(input_str, timeout=3, server="", record_type="A"):
     """Perform a simple DNS lookup, return results in a dictionary"""
     rr = Resolver()
@@ -2475,7 +2516,7 @@
         }
 
 
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
+@logger.catch(reraise=True)
 def dns6_lookup(input_str, timeout=3, server=""):
     """Perform a simple DNS lookup, return results in a dictionary"""
     rr = Resolver()
@@ -2500,7 +2541,7 @@
 
 _REVERSE_DNS_REGEX = re.compile(r"^\s*\d+\.\d+\.\d+\.\d+\s*$")
 
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
+@logger.catch(reraise=True)
 def check_valid_ipaddress(input_addr=None):
     """
     Accept an input string with an IPv4 or IPv6 address. If the address is
@@ -2529,13 +2570,14 @@
     assert (ipaddr_family == 4 or ipaddr_family == 6), error
     return (input_addr, ipaddr_family)
 
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
-def reverse_dns_lookup(input_str, timeout=3.0, server="", proto="udp"):
+@logger.catch(reraise=True)
+def reverse_dns_lookup(input_str, timeout=3.0, server="4.2.2.2", proto="udp"):
     """Perform a simple reverse DNS lookup on an IPv4 or IPv6 address; return 
results in a python dictionary"""
     assert isinstance(proto, str) and (proto=="udp" or proto=="tcp")
     assert isinstance(float(timeout), float) and float(timeout) > 0.0
 
-    input_str, ipaddr_family = check_valid_ipaddress(input_str)
+    addr, addr_family = check_valid_ipaddress(input_str)
+    assert addr_family==4 or addr_family==6
 
     tcp_flag = None
     if proto=="tcp":
@@ -2546,12 +2588,16 @@
         raise ValueError()
 
     rr = Resolver()
+    rr.nameservers = []
+
+    # Append valid addresses to rr.nameservers...
+    for candidate_server_addr in server.split(","):
+        addr, addr_family = 
check_valid_ipaddress(input_addr=candidate_server_addr)
+        rr.nameservers.append(addr)
+
     #rr = rr.resolve_address(ipaddr=input_str, tcp=tcp_flag, rdtype="PTR", 
lifetime=float(timeout))
     #rr = rr.resolve_address(ipaddr=input_str, tcp=tcp_flag, 
lifetime=float(timeout))
 
-    if server != "":
-        rr.nameservers = [server]
-
     records = []
     retval = {}
     try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ciscoconfparse-1.6.41/ciscoconfparse/ciscoconfparse.py 
new/ciscoconfparse-1.6.50/ciscoconfparse/ciscoconfparse.py
--- old/ciscoconfparse-1.6.41/ciscoconfparse/ciscoconfparse.py  2022-09-10 
00:25:02.491401000 +0200
+++ new/ciscoconfparse-1.6.50/ciscoconfparse/ciscoconfparse.py  2022-10-22 
04:32:00.204709500 +0200
@@ -38,9 +38,6 @@
 import re
 import os
 
-from loguru import logger
-import toml
-
 from ciscoconfparse.models_cisco import IOSHostnameLine, IOSRouteLine
 from ciscoconfparse.models_cisco import IOSIntfLine
 from ciscoconfparse.models_cisco import IOSAccessLine, IOSIntfGlobal
@@ -81,97 +78,110 @@
 from ciscoconfparse.ccp_abc import BaseCfgLine
 
 from ciscoconfparse.ccp_util import junos_unsupported
-from ciscoconfparse.ccp_util import ccp_logger_control
+from ciscoconfparse.ccp_util import configure_loguru
 # Not using ccp_re yet... still a work in progress
 # from ciscoconfparse.ccp_util import ccp_re
 
+from loguru import logger
+import toml
 
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
-def configure_loguru(
-    sink=sys.stderr,
-    action="",
-    # rotation="midnight",
-    # retention="1 month",
-    # compression="zip",
-    level="DEBUG",
-    colorize=True,
-    debug=0,
-):
+@logger.catch(reraise=True)
+def get_version_number():
     """
-    configure_loguru()
+    Read the version number from 'pyproject.toml', or use version 0.0.0 in odd
+    circumstances.
     """
-    assert isinstance(action, str)
-    assert action in ('remove', 'add', 'enable', 'disable', '',)
-    # assert isinstance(rotation, str)
-    # assert isinstance(retention, str)
-    # assert isinstance(compression, str)
-    # assert compression == "zip"
-    assert isinstance(level, str)
-    assert isinstance(colorize, bool)
-    assert isinstance(debug, int) and (0 <= debug <= 5)
-
-    # logger_control() was imported above...
-    #    Remove the default loguru logger to stderr (handler_id==0)...
-    ccp_logger_control(action="remove", handler_id=0)
-
-#    _logger_config = logger.configure(
-#        sys.stdout,
-#        level="DEBUG",
-#        rotation='midnight',
-#        retention="1 month",
-#        compression=compression,
-#        colorize=colorize,
-#    )
-#    logger.add(_logger_config)
-
-    ccp_logger_control(
-        sink=sys.stdout,
-        action="add",
-        level="DEBUG",
-        # rotation='midnight',   # ALE barks about the rotation keyword...
-        # retention="1 month",
-        # compression=compression,
-        colorize=colorize
+    # Docstring props: http://stackoverflow.com/a/1523456/667301
+    # version: if-else below fixes Github issue #123
+
+    version = "0.0.0"  # version read failed
+
+    pyproject_toml_path = os.path.join(
+        os.path.dirname(os.path.abspath(__file__)),
+        "../pyproject.toml",
     )
-    ccp_logger_control(action="enable")
+    if os.path.isfile(pyproject_toml_path):
+        # Retrieve the version number from pyproject.toml...
+        toml_values = dict()
+        with open(pyproject_toml_path, encoding=ENCODING) as fh:
+            toml_values = toml.loads(fh.read())
+            version = toml_values["tool"]["poetry"].get("version", -1.0)
 
+        assert isinstance(version, str)
 
-configure_loguru()
+    else:
+        # This is required for importing from a zipfile... Github issue #123
+        version = "0.0.0"  # __version__ read failed
 
-ENCODING = locale.getpreferredencoding()
-ALL_VALID_SYNTAX = (
-    'ios',
-    'nxos',
-    'asa',
-    'junos',
-    'terraform',
-)
-
-# Docstring props: http://stackoverflow.com/a/1523456/667301
-# __version__ if-else below fixes Github issue #123
-pyproject_path = os.path.join(
-    os.path.dirname(os.path.abspath(__file__)),
-    "../pyproject.toml",
-)
-if os.path.isfile(pyproject_path):
-    # Retrieve the version number from pyproject.toml...
-    toml_values = dict()
-    with open(pyproject_path, encoding=ENCODING) as fh:
-        toml_values = toml.loads(fh.read())
-    __version__ = toml_values.get("version")
-
-else:
-    # This case is required for importing from a zipfile... Github issue #123
-    __version__ = "0.0.0"  # __version__ read failed
-
-__author_email__ = r"mike /at\ pennington [dot] net"
-__author__ = "David Michael Pennington <{}>".format(__author_email__)
-__copyright__ = "2007-{}, {}".format(time.strftime("%Y"), __author__)
-__license__ = "GPLv3"
-__status__ = "Production"
+    return version
 
+@logger.catch(reraise=True)
+def initialize_globals():
+    """
+    Initialize ciscoconfparse global dunder variables and a couple others.
+    """
+    global ALL_VALID_SYNTAX
+    global ENCODING
+    global __author_email__
+    global __author__
+    global __copyright__
+    global __license__
+    global __status__
+    global __version__
+
+    ENCODING = locale.getpreferredencoding()
+    ALL_VALID_SYNTAX = (
+        'ios',
+        'nxos',
+        'asa',
+        'junos',
+        'terraform',
+    )
 
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    try:
+        __author_email__ = r"mike /at\ pennington [dot] net"
+        __author__ = "David Michael Pennington <{}>".format(__author_email__)
+        __copyright__ = "2007-{}, {}".format(time.strftime("%Y"), __author__)
+        __license__ = "GPLv3"
+        __status__ = "Production"
+        __version__ = get_version_number()
+
+    except:
+        raise ValueError()
+
+    finally:
+        # These are all the 'dunder variables' required...
+        globals_dict = {
+            '__author_email__': __author_email__,
+            '__author__': __author__,
+            '__copyright__': __copyright__,
+            '__license__': __license__,
+            '__status__': __status__,
+            '__version__': __version__,
+        }
+        return globals_dict
+
+@logger.catch(reraise=True)
+def initialize_ciscoconfparse():
+    """
+    Initialize ciscoconfparse global variables and configure logging
+    """
+    configure_loguru()
+
+    globals_dict = initialize_globals()
+    for key, value in globals_dict.items():
+        # Example, this will set __version__ to content of 'value'
+        #     from -> https://stackoverflow.com/a/3972978/667301
+        globals()[key] = value
+
+    return globals_dict
+
+
+# ALL ciscoconfparse global variables initizalization happens here...
+initialize_ciscoconfparse()
+
+
+@logger.catch(reraise=True)
 def _parse_line_braces(line_txt=None, comment_delimiter=None) -> tuple:
     """
     """
@@ -281,7 +291,7 @@
         raise ValueError('Cannot parse {}:"{}"'.format(syntax,
                     line_txt))
 
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
+@logger.catch(reraise=True)
 def build_space_tolerant_regex(linespec):
     r"""SEMI-PRIVATE: Accept a string, and return a string with all
     spaces replaced with '\s+'"""
@@ -302,7 +312,7 @@
 
     return linespec
 
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
+@logger.catch(reraise=True)
 def assign_parent_to_closing_braces(input_list=None):
     """
     Accept a list of brace-delimited BaseCfgLine() objects; these objects
@@ -335,16 +345,25 @@
         for obj in input_list:
             assert isinstance(obj, BaseCfgLine)
             assert isinstance(obj.text, str)
-            if len(obj.text)>=1 and obj.text.rstrip()[-1] == '{':
+
+            # These rstrip() are one of two fixes, intended to catch user 
error such as
+            # the problems that the submitter of Github issue #251 had.
+            # CiscoConfParse() could not read his configuration because he 
submitted
+            # a multi-line string...
+            #
+            # This check will explicitly catch some problems like that...
+            if len(obj.text.rstrip())>=1 and obj.text.rstrip()[-1] == '{':
                 opening_brace_objs.append(obj)
-            elif len(obj.text)>=1 and obj.text.lstrip()[0]=='}':
+
+            elif len(obj.text.strip())>=1 and obj.text.strip()[0]=='}':
                 assert len(opening_brace_objs) >= 1
                 obj.parent = opening_brace_objs.pop()
+
     return input_list
 
 # This method was copied from the same method in git commit below...
 # 
https://raw.githubusercontent.com/mpenning/ciscoconfparse/bb3f77436023873da344377d3c839387f5131e7f/ciscoconfparse/ciscoconfparse.py
-@logger.catch(default=True, onerror=lambda _: sys.exit(1))
+@logger.catch(reraise=True)
 def convert_junos_to_ios(input_list=None, stop_width=4, comment_delimiter="!",
         debug=0):
     """
@@ -383,7 +402,7 @@
     # IMPORTANT: do NOT decorate CiscoConfParse().__init__()
     #
     # Something breaks in CiscoConfParse() if using @logger.catch, below...
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def __init__(
         self,
         config="",
@@ -469,6 +488,7 @@
         self.factory = factory
         self.ConfigObjs = None
         self.syntax = syntax
+        self.ignore_blank_lines = ignore_blank_lines
         self.encoding = encoding or ENCODING
         self.debug = debug
 
@@ -550,22 +570,22 @@
             raise ValueError(error)
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def __repr__(self):
         if isinstance(self.ConfigObjs, (list, tuple, MutableSequence)):
             num_lines = str(len(self.ConfigObjs))
         elif self.ConfigObjs is None:
             num_lines = "None"
         return (
-            "<CiscoConfParse: %s lines / syntax: %s / comment delimiter: '%s' 
/ factory: %s / encoding: '%s'>"
+            "<CiscoConfParse: %s lines / syntax: %s / comment delimiter: '%s' 
/ factory: %s / ignore_blank_lines: %s / encoding: '%s'>"
             % (
                 num_lines, self.syntax, self.comment_delimiter,
-                self.factory, self.encoding,
+                self.factory, self.ignore_blank_lines, self.encoding,
             )
         )
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def get_config_lines(self, config=None, logger=None, 
linesplit_rgx=r"\r*\n+"):
         """
         Enforce rules - If config is a str, assume it's a filepath.  If config 
is a list, assume it's a router config.
@@ -601,8 +621,10 @@
         else:
             raise ValueError("config='%s' is an unexpected type()" % config)
 
+    #########################################################################
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    #      do NOT wrap this method in logger.catch() - github issue #249
+    #########################################################################
     @property
     def openargs(self):
         """Fix for Py3.5 deprecation of universal newlines - Ref Github #114
@@ -636,7 +658,7 @@
         return self.ConfigObjs
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def atomic(self):
         """Call :func:`~ciscoconfparse.CiscoConfParse.atomic` to manually fix
         up ``ConfigObjs`` relationships
@@ -665,7 +687,7 @@
         self.ConfigObjs._bootstrap_from_text()
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def commit(self):
         """
         Alias for calling the :func:`~ciscoconfparse.CiscoConfParse.atomic`
@@ -798,7 +820,7 @@
 
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def convert_terraform_to_ios(self, input_list, stop_width=4, quotes=False, 
comment_delimiter="#"):
         """
         This method accepts `input_list` (it should be a list of
@@ -829,7 +851,7 @@
         return lines
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_object_branches(
         self,
         branchspec=(),
@@ -1110,7 +1132,7 @@
         return branches
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_interface_objects(self, intfspec, exactmatch=True):
         """Find all :class:`~cisco.IOSCfgLine` or
         :class:`~models_cisco.NXOSCfgLine` objects whose text
@@ -1179,7 +1201,7 @@
         return retval
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_objects_dna(self, dnaspec, exactmatch=False):
         """Find all :class:`~models_cisco.IOSCfgLine` objects whose text
         matches ``dnaspec`` and return the :class:`~models_cisco.IOSCfgLine`
@@ -1253,7 +1275,7 @@
         )
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_objects(self, linespec, exactmatch=False, ignore_ws=False):
         """Find all :class:`~models_cisco.IOSCfgLine` objects whose text
         matches ``linespec`` and return the :class:`~models_cisco.IOSCfgLine`
@@ -1317,7 +1339,7 @@
         return self._find_line_OBJ(linespec, exactmatch)
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_lines(self, linespec, exactmatch=False, ignore_ws=False):
         """This method is the equivalent of a simple configuration grep
         (Case-sensitive).
@@ -1349,7 +1371,7 @@
             )
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_children(self, linespec, exactmatch=False, ignore_ws=False):
         """Returns the parents matching the linespec, and their immediate
         children.  This method is different than :meth:`find_all_children`,
@@ -1404,7 +1426,7 @@
         return [ii.text for ii in sorted(allobjs)]
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_all_children(self, linespec, exactmatch=False, ignore_ws=False):
         """Returns the parents matching the linespec, and all their children.
         This method is different than :meth:`find_children`, because
@@ -1482,7 +1504,7 @@
         return [ii.text for ii in sorted(allobjs)]
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_blocks(self, linespec, exactmatch=False, ignore_ws=False):
         """Find all siblings matching the linespec, then find all parents of
         those siblings. Return a list of config lines sorted by line number,
@@ -1605,7 +1627,7 @@
         return [ii.text for ii in sorted(tmp)]
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_objects_w_child(
         self,
         parentspec,
@@ -1710,7 +1732,7 @@
         )
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_objects_w_all_children(
         self,
         parentspec,
@@ -1828,7 +1850,7 @@
         return retval
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_objects_w_missing_children(
         self,
         parentspec,
@@ -1877,7 +1899,7 @@
         return retval
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_parents_w_child(self, parentspec, childspec, ignore_ws=False):
         """Parse through all children matching childspec, and return a list of
         parents that matched the parentspec.  Only the parent lines will be
@@ -1965,7 +1987,7 @@
         return [ii.text for ii in tmp]
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_objects_wo_child(self, parentspec, childspec, ignore_ws=False):
         r"""Return a list of parent :class:`~models_cisco.IOSCfgLine` objects, 
which matched the ``parentspec`` and whose children did not match 
``childspec``.  Only the parent :class:`~models_cisco.IOSCfgLine` objects will 
be returned.  For simplicity, this method only finds oldest_ancestors without 
immediate children that match.
 
@@ -2053,7 +2075,7 @@
         ]
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_parents_wo_child(self, parentspec, childspec, ignore_ws=False):
         r"""Parse through all parents matching parentspec, and return a list 
of parents that did NOT have children match the childspec.  For simplicity, 
this method only finds oldest_ancestors without immediate children that match.
 
@@ -2140,7 +2162,7 @@
         return [ii.text for ii in tmp]
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_children_w_parents(self, parentspec, childspec, ignore_ws=False):
         r"""Parse through the children of all parents matching parentspec,
         and return a list of children that matched the childspec.
@@ -2251,7 +2273,7 @@
         return [ii.text for ii in sorted(retval)]
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_objects_w_parents(self, parentspec, childspec, ignore_ws=False):
         r"""Parse through the children of all parents matching parentspec,
         and return a list of child objects, which matched the childspec.
@@ -2352,7 +2374,7 @@
         return sorted(retval)
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_lineage(self, linespec, exactmatch=False):
         """
         Iterate through to the oldest ancestor of this object, and return
@@ -2381,7 +2403,7 @@
         return [obj.text for obj in tmp[0].lineage]
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def has_line_with(self, linespec):
         # https://stackoverflow.com/a/16097112/667301
         matching_conftext = list(
@@ -2393,7 +2415,7 @@
         return bool(matching_conftext)
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def insert_before(
         self,
         exist_val="",
@@ -2495,7 +2517,7 @@
         return [ii.text for ii in sorted(objs)]
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def insert_after(
         self,
         exist_val="",
@@ -2602,7 +2624,7 @@
         return [ii.text for ii in sorted(objs)]
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def insert_after_child(
         self,
         parentspec,
@@ -2643,7 +2665,7 @@
         return retval
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def delete_lines(self, linespec, exactmatch=False, ignore_ws=False):
         """Find all :class:`~models_cisco.IOSCfgLine` objects whose text
         matches linespec, and delete the object"""
@@ -2655,7 +2677,7 @@
             obj.delete()
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def prepend_line(self, linespec):
         """Unconditionally insert an :class:`~models_cisco.IOSCfgLine` object
         for ``linespec`` (a text line) at the top of the configuration"""
@@ -2663,7 +2685,7 @@
         return self.ConfigObjs[0]
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def append_line(self, linespec):
         """Unconditionally insert ``linespec`` (a text line) at the end of the
         configuration
@@ -2682,7 +2704,7 @@
         return self.ConfigObjs[-1]
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def replace_lines(
         self,
         linespec,
@@ -2799,7 +2821,7 @@
         return retval
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def replace_children(
         self,
         parentspec,
@@ -2887,7 +2909,7 @@
         return retval
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def replace_all_children(
         self,
         parentspec,
@@ -2923,7 +2945,7 @@
         return retval
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def re_search_children(self, regex, recurse=False):
         """Use ``regex`` to search for root parents in the config with text 
matching regex.  If `recurse` is False, only root parent objects are returned.  
A list of matching objects is returned.
 
@@ -2953,7 +2975,7 @@
             return [obj for obj in self.find_objects(regex)]
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def re_match_iter_typed(
         self,
         regex,
@@ -3059,7 +3081,7 @@
             return result_type(default)
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def req_cfgspec_all_diff(self, cfgspec, ignore_ws=False):
         """
         req_cfgspec_all_diff takes a list of required configuration lines,
@@ -3127,7 +3149,7 @@
         return retval
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def req_cfgspec_excl_diff(self, linespec, uncfgspec, cfgspec):
         r"""
         req_cfgspec_excl_diff accepts a linespec, an unconfig spec, and
@@ -3205,7 +3227,7 @@
         return retval
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def _sequence_nonparent_lines(self, a_nonparent_objs, b_nonparent_objs):
         """Assume a_nonparent_objs is the existing config sequence, and
         b_nonparent_objs is the *desired* config sequence
@@ -3249,7 +3271,7 @@
         return a_parse, a_lines, a_linenums
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def _sequence_parent_lines(self, a_parent_objs, b_parent_objs):
         """Assume a_parent_objs is the existing config sequence, and
         b_parent_objs is the *desired* config sequence
@@ -3315,7 +3337,7 @@
         return a_parse, a_lines, a_linenums
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def sync_diff(
         self,
         cfgspec,
@@ -3695,7 +3717,7 @@
         return retval
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def save_as(self, filepath):
         """Save a text copy of the configuration at ``filepath``; this
         method uses the OperatingSystem's native line separators (such as
@@ -3713,7 +3735,7 @@
     ###  or iterable of objects instead of the configuration text itself.
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def _find_line_OBJ(self, linespec, exactmatch=False):
         """SEMI-PRIVATE: Find objects whose text matches the linespec"""
 
@@ -3741,7 +3763,7 @@
         )
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def _find_sibling_OBJ(self, lineobject):
         """SEMI-PRIVATE: Takes a singe object and returns a list of sibling
         objects"""
@@ -3749,7 +3771,7 @@
         return siblings
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def _find_all_child_OBJ(self, lineobject):
         """SEMI-PRIVATE: Takes a single object and returns a list of
         decendants in all 'children' / 'grandchildren' / etc... after it.
@@ -3764,7 +3786,7 @@
         return retval
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def _unique_OBJ(self, objectlist):
         """SEMI-PRIVATE: Returns a list of unique objects (i.e. with no
         duplicates).
@@ -3776,7 +3798,7 @@
         return sorted(retval)
 
     # This method is on CiscoConfParse()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def _objects_to_uncfg(self, objectlist, unconflist):
         # Used by req_cfgspec_excl_diff()
         retval = list()
@@ -3797,7 +3819,7 @@
     """
 
     # This method is on HDiff()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def __init__(
         self,
         before_config=None,
@@ -3891,12 +3913,12 @@
         self.sort_lines(parse_after, self.all_output_dicts)
 
     # This method is on HDiff()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def raw_diff_dicts(self):
         return self.all_output_dicts
 
     # This method is on HDiff()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def unified_diff_header(self):
         """
         Return a unified diff header similar to this...
@@ -3946,7 +3968,7 @@
         return unified_diff_header
 
     # This method is on HDiff()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def unified_diffs(self, header=True):
         """
         Return a python list of text which contains the unified diff of the
@@ -3974,7 +3996,7 @@
         return unified_diff_list
 
     # This method is on HDiff()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def sort_lines(self, after_lines, all_output_dicts):
         """
         Typical output line dict-format...
@@ -3989,7 +4011,7 @@
         pass
 
     # This method is on HDiff()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def dict_diffs(self, before_obj_list, after_obj_list):
         ############################################
         # Render diffs
@@ -4040,7 +4062,7 @@
         return all_dict_lines
 
     # This method is on HDiff()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def build_diff_obj_list(
         self, parse=None, default_diff_word=None, consider_whitespace=False
     ):
@@ -4068,7 +4090,7 @@
         return retval
 
     # This method is on HDiff()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def find_in_before_obj_list(
         self, before_obj_list, after_obj, consider_whitespace=False, debug=0
     ):
@@ -4161,7 +4183,7 @@
         return before_obj_list, after_obj
 
     # This method is on HDiff()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def render_after_obj_diffs(self, aobj=None):
         """
         Print after_obj (aobj) diffs to stdout.  before_obj should not be
@@ -4215,7 +4237,7 @@
         return output
 
     # This method is on HDiff()
-    @logger.catch(default=True, onerror=lambda _: sys.exit(1))
+    @logger.catch(reraise=True)
     def compress_dict_diffs(self, all_lines=None):
         """
         Summary
@@ -4403,6 +4425,15 @@
         #     FIXME the CiscoConfParse attribute / parameter should go away
         #     use self.ccp_ref instead of self.CiscoConfParse
         #######################################################################
+
+        # This assert is one of two fixes, intended to catch user error such as
+        # the problems that the submitter of Github issue #251 had.
+        # CiscoConfParse() could not read his configuration because he 
submitted
+        # a multi-line string...
+        #
+        # This check will explicitly catch some problems like that...
+        assert isinstance(initlist, (list, tuple, MutableSequence))
+
         ciscoconfparse_kwarg_val = kwargs.get("CiscoConfParse", None)
         ccp_ref_kwarg_val = kwargs.get("ccp_ref", None)
         if ciscoconfparse_kwarg_val is not None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ciscoconfparse-1.6.41/pyproject.toml 
new/ciscoconfparse-1.6.50/pyproject.toml
--- old/ciscoconfparse-1.6.41/pyproject.toml    2022-09-10 00:27:51.814184000 
+0200
+++ new/ciscoconfparse-1.6.50/pyproject.toml    2022-10-22 04:32:00.204709500 
+0200
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "ciscoconfparse"
-version = "1.6.41"
+version = "1.6.50"
 description = "Parse, Audit, Query, Build, and Modify Cisco IOS-style and 
JunOS-style configurations"
 authors = [
     "Mike Pennington <m...@pennington.net>",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ciscoconfparse-1.6.41/setup.py 
new/ciscoconfparse-1.6.50/setup.py
--- old/ciscoconfparse-1.6.41/setup.py  2022-09-10 00:29:24.075051000 +0200
+++ new/ciscoconfparse-1.6.50/setup.py  1970-01-01 01:00:00.000000000 +0100
@@ -15,13 +15,13 @@
 
 setup_kwargs = {
     'name': 'ciscoconfparse',
-    'version': '1.6.41',
+    'version': '1.6.50',
     'description': 'Parse, Audit, Query, Build, and Modify Cisco IOS-style and 
JunOS-style configurations',
-    'long_description': 'ciscoconfparse\n==============\n\n[![Github unittest 
workflow][4]][5] [![Code Health][37]][38] [![Version][2]][3] 
[![Downloads][6]][7] [![License][8]][9]\n\n\nIntroduction: What is 
ciscoconfparse?\n-------------------------------------\n\nShort answer: 
ciscoconfparse is a [Python][10] library\nthat helps you quickly answer 
questions like these about your\nconfigurations:\n\n- What interfaces are 
shutdown?\n- Which interfaces are in trunk mode?\n- What address and subnet 
mask is assigned to each interface?\n- Which interfaces are missing a critical 
command?\n- Is this configuration missing a standard config line?\n\nIt can 
help you:\n\n- Audit existing router / switch / firewall / wlc 
configurations\n- Modify existing configurations\n- Build new 
configurations\n\nSpeaking generally, the library examines an IOS-style config 
and breaks\nit into a set of linked parent / child relationships. You can 
perform\ncomplex queries about these relationships.\n\n[![Cisco 
 IOS config: Parent / child][11]][11]\n\nUsage\n-----\n\nThe following code 
will parse a configuration stored in\n\\\'exampleswitch.conf\\\' and select 
interfaces that are shutdown.\n\n```python\nfrom ciscoconfparse import 
CiscoConfParse\n\nparse = CiscoConfParse(\'exampleswitch.conf\', 
syntax=\'ios\')\n\nfor intf_obj in parse.find_objects_w_child(\'^interface\', 
\'^\\s+shutdown\'):\n    print("Shutdown: " + intf_obj.text)\n```\n\nThe next 
example will find the IP address assigned to interfaces.\n\n```python\nfrom 
ciscoconfparse import CiscoConfParse\n\nparse = 
CiscoConfParse(\'exampleswitch.conf\', syntax=\'ios\')\n\nfor intf_obj in 
parse.find_objects(\'^interface\'):\n\n    intf_name = 
intf_obj.re_match_typed(\'^interface\\s+(\\S.+?)$\')\n\n    # Search children 
of all interfaces for a regex match and return\n    # the value matched in 
regex match group 1.  If there is no match,\n    # return a default value: 
\'\'\n    intf_ip_addr = intf_obj.re_match_iter_typed(\n        r\'ip\\sa
 ddress\\s(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s\', result_type=str,\n        group=1, 
default=\'\')\n    print("{0}: {1}".format(intf_name, 
intf_ip_addr))\n```\n\nWhat if we don\\\'t use 
Cisco?\n----------------------------\n\nDon\\\'t let that stop you.\n\nAs of 
CiscoConfParse 1.2.4, you can parse [brace-delimited configurations][13] into a 
Cisco IOS style (see [Github Issue \\#17][14]), which means that CiscoConfParse 
can parse these configurations:\n\n- Juniper Networks Junos\n- Palo Alto 
Networks Firewall configurations\n- F5 Networks 
configurations\n\nCiscoConfParse also handles anything that has a Cisco IOS 
style of configuration, which includes:\n\n- Cisco IOS, Cisco Nexus, Cisco 
IOS-XR, Cisco IOS-XE, Aironet OS, Cisco ASA, Cisco CatOS\n- Arista EOS\n- 
Brocade\n- HP Switches\n- Force 10 Switches\n- Dell PowerConnect Switches\n- 
Extreme Networks\n- Enterasys\n- Screenos\n\nDocs\n----\n\n- The latest copy of 
the docs are [archived on the web][15]\n- There is also a [CiscoConfParse Tuto
 rial][16]\n\nEditing the Package\n-------------------\n\n-   `git clone 
https://github.com/mpenning/ciscoconfparse`\n-   `cd ciscoconfparse`\n-   `git 
checkout -b develop`\n-   Add / modify / delete on the `develop` branch\n-   
`make test`\n-   If tests run clean, `git commit` all the pending changes on 
the `develop` branch\n-   (as required) Edit the version number in 
[pyproject.toml][12]\n-   `git checkout main`\n-   `git merge develop`\n-   
`make test`\n-   `make repo-push`\n-   `make 
pypi`\n\nPre-requisites\n--------------\n\n[The ciscoconfparse python 
package][3] requires Python versions 3.6+ (note: Python version 3.7.0 has a bug 
- ref [Github issue \\#117][18], but version 3.7.1 works); the OS should not 
matter.\n\nInstallation and Downloads\n--------------------------\n\n-   Use 
`poetry` for Python3.x\\... :\n\n        python -m pip install 
ciscoconfparse\n\nIf you\\\'re interested in the source, you can always pull 
from the [github repo][17]:\n\n- Download from [the github r
 epo][17]: :\n\n        git clone git://github.com/mpenning/ciscoconfparse\n    
    cd ciscoconfparse/\n        python -m pip install .\n\nOther 
Resources\n---------------\n\n- [Dive into 
Python3](http://www.diveintopython3.net/) is a good way to learn Python\n- 
[Team CYMRU][30] has a [Secure IOS Template][29], which is especially useful 
for external-facing routers / switches\n- [Cisco\\\'s Guide to hardening IOS 
devices][31]\n- [Center for Internet Security Benchmarks][32] (An email 
address, cookies, and javascript are required)\n\nBug Tracker and 
Support\n-----------------------\n\n- Please report any suggestions, bug 
reports, or annoyances with a [github bug report][24].\n- If you\\\'re having 
problems with general python issues, consider searching for a solution on 
[Stack Overflow][33].  If you can\\\'t find a solution for your problem or need 
more help, you can [ask on Stack Overflow][34] or [reddit/r/Python][39].\n- If 
you\\\'re having problems with your Cisco devices, you can 
 contact:\n  - [Cisco TAC][28]\n  - [reddit/r/Cisco][35]\n  - 
[reddit/r/networking][36]\n  - 
[NetworkEngineering.se][23]\n\nUnit-Tests\n----------\n\nThe project\\\'s [test 
workflow][1] checks ciscoconfparse on Python versions 3.6 and higher, as well 
as a [pypy JIT][22] executable.\n\nClick the image below for details; the 
current build status is: [![Github unittest status][4]][5]\n\nLicense and 
Copyright\n---------------------\n\n[ciscoconfparse][3] is licensed 
[GPLv3][21]\n\n- Copyright (C) 2021-2022 David Michael Pennington\n- Copyright 
(C) 2020-2021 David Michael Pennington at Cisco Systems (post-acquisition: 
Cisco acquired ThousandEyes)\n- Copyright (C) 2019 David Michael Pennington at 
ThousandEyes\n- Copyright (C) 2012-2019 David Michael Pennington at Samsung 
Data Services\n- Copyright (C) 2011-2012 David Michael Pennington at Dell 
Computer Corp\n- Copyright (C) 2007-2011 David Michael Pennington\n\nThe word 
\\"Cisco\\" is a registered trademark of [Cisco Systems][27].\n\nAutho
 r\n------\n\n[ciscoconfparse][3] was written by [David Michael Pennington][25] 
(mike \\[\\~at\\~\\] pennington \\[.dot.\\] net).\n\n\n  [1]: 
https://github.com/mpenning/ciscoconfparse/tree/master/.github/workflows\n  
[2]: https://img.shields.io/pypi/v/ciscoconfparse.svg\n  [3]: 
https://pypi.python.org/pypi/ciscoconfparse/\n  [4]: 
https://github.com/mpenning/ciscoconfparse/actions/workflows/tests.yml/badge.svg\n
  [5]: https://github.com/mpenning/ciscoconfparse/actions/workflows/tests.yml\n 
 [6]: https://pepy.tech/badge/ciscoconfparse\n  [7]: 
https://pepy.tech/project/ciscoconfparse\n  [8]: 
http://img.shields.io/badge/license-GPLv3-blue.svg\n  [9]: 
https://www.gnu.org/copyleft/gpl.html\n  [10]: https://www.python.org\n  [11]: 
https://raw.githubusercontent.com/mpenning/ciscoconfparse/master/sphinx-doc/_static/ciscoconfparse_overview_75pct.png\n
  [12]: https://github.com/mpenning/ciscoconfparse/blob/main/pyproject.toml\n  
[13]: https://github.com/mpenning/ciscoconfparse/blob/master/conf
 igs/sample_01.junos\n  [14]: 
https://github.com/mpenning/ciscoconfparse/issues/17\n  [15]: 
http://www.pennington.net/py/ciscoconfparse/\n  [16]: 
http://pennington.net/tutorial/ciscoconfparse/ccp_tutorial.html\n  [17]: 
https://github.com/mpenning/ciscoconfparse\n  [18]: 
https://github.com/mpenning/ciscoconfparse/issues/117\n  [19]: 
https://github.com/mpenning/ciscoconfparse/issues/13\n  [20]: 
https://github.com/CrackerJackMack/\n  [21]: 
http://www.gnu.org/licenses/gpl-3.0.html\n  [22]: https://pypy.org\n  [23]: 
https://networkengineering.stackexchange.com/\n  [24]: 
https://github.com/mpenning/ciscoconfparse/issues/new/choose\n  [25]: 
https://github.com/mpenning\n  [26]: https://github.com/muir\n  [27]: 
https://www.cisco.com/\n  [28]: https://www.cisco.com/go/support\n  [29]: 
https://www.cymru.com/Documents/secure-ios-template.html\n  [30]: 
https://team-cymru.com/company/\n  [31]: 
http://www.cisco.com/c/en/us/support/docs/ip/access-lists/13608-21.html\n  
[32]: https://learn.cisecurity
 .org/benchmarks\n  [33]: https://stackoverflow.com\n  [34]: 
http://stackoverflow.com/questions/ask\n  [35]: 
https://www.reddit.com/r/Cisco/\n  [36]: https://www.reddit.com/r/networking\n  
[37]: https://snyk.io/advisor/python/ciscoconfparse/badge.svg\n  [38]: 
https://snyk.io/advisor/python/ciscoconfparse\n  [39]: 
https://www.reddit.com/r/Python/\n',
+    'long_description': 'ciscoconfparse\n==============\n\n[![Github unittest 
workflow][4]][5] [![Code Health][37]][38] [![Version][2]][3] 
[![Downloads][6]][7] [![License][8]][9]\n\n\nIntroduction: What is 
ciscoconfparse?\n-------------------------------------\n\nShort answer: 
ciscoconfparse is a [Python][10] library\nthat helps you quickly answer 
questions like these about your\nconfigurations:\n\n- What interfaces are 
shutdown?\n- Which interfaces are in trunk mode?\n- What address and subnet 
mask is assigned to each interface?\n- Which interfaces are missing a critical 
command?\n- Is this configuration missing a standard config line?\n\nIt can 
help you:\n\n- Audit existing router / switch / firewall / wlc 
configurations\n- Modify existing configurations\n- Build new 
configurations\n\nSpeaking generally, the library examines an IOS-style config 
and breaks\nit into a set of linked parent / child relationships. You can 
perform\ncomplex queries about these relationships.\n\n[![Cisco 
 IOS config: Parent / child][11]][11]\n\nUsage\n-----\n\nThe following code 
will parse a configuration stored in\n\\\'exampleswitch.conf\\\' and select 
interfaces that are shutdown.\n\n```python\nfrom ciscoconfparse import 
CiscoConfParse\n\nparse = CiscoConfParse(\'exampleswitch.conf\', 
syntax=\'ios\')\n\nfor intf_obj in parse.find_objects_w_child(\'^interface\', 
\'^\\s+shutdown\'):\n    print("Shutdown: " + intf_obj.text)\n```\n\nThe next 
example will find the IP address assigned to interfaces.\n\n```python\nfrom 
ciscoconfparse import CiscoConfParse\n\nparse = 
CiscoConfParse(\'exampleswitch.conf\', syntax=\'ios\')\n\nfor intf_obj in 
parse.find_objects(\'^interface\'):\n\n    intf_name = 
intf_obj.re_match_typed(\'^interface\\s+(\\S.+?)$\')\n\n    # Search children 
of all interfaces for a regex match and return\n    # the value matched in 
regex match group 1.  If there is no match,\n    # return a default value: 
\'\'\n    intf_ip_addr = intf_obj.re_match_iter_typed(\n        r\'ip\\sa
 ddress\\s(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s\', result_type=str,\n        group=1, 
default=\'\')\n    print("{0}: {1}".format(intf_name, 
intf_ip_addr))\n```\n\nWhat if we don\\\'t use 
Cisco?\n----------------------------\n\nDon\\\'t let that stop you.\n\nAs of 
CiscoConfParse 1.2.4, you can parse [brace-delimited configurations][13] into a 
Cisco IOS style (see [Github Issue \\#17][14]), which means that CiscoConfParse 
can parse these configurations:\n\n- Juniper Networks Junos\n- Palo Alto 
Networks Firewall configurations\n- F5 Networks 
configurations\n\nCiscoConfParse also handles anything that has a Cisco IOS 
style of configuration, which includes:\n\n- Cisco IOS, Cisco Nexus, Cisco 
IOS-XR, Cisco IOS-XE, Aironet OS, Cisco ASA, Cisco CatOS\n- Arista EOS\n- 
Brocade\n- HP Switches\n- Force 10 Switches\n- Dell PowerConnect Switches\n- 
Extreme Networks\n- Enterasys\n- Screenos\n\nDocs\n----\n\n- The latest copy of 
the docs are [archived on the web][15]\n- There is also a [CiscoConfParse Tuto
 rial][16]\n\nEditing the Package\n-------------------\n\n-   `git clone 
https://github.com/mpenning/ciscoconfparse`\n-   `cd ciscoconfparse`\n-   `git 
checkout -b develop`\n-   Add / modify / delete on the `develop` branch\n-   
`make test`\n-   If tests run clean, `git commit` all the pending changes on 
the `develop` branch\n-   (as required) Edit the version number in 
[pyproject.toml][12]\n-   `git checkout main`\n-   `git merge develop`\n-   
`make test`\n-   `make repo-push`\n-   `make 
pypi`\n\nPre-requisites\n--------------\n\n[The ciscoconfparse python 
package][3] requires Python versions 3.7+ (note: Python version 3.7.0 has a bug 
- ref [Github issue \\#117][18], but version 3.7.1 works); the OS should not 
matter.\n\nInstallation and Downloads\n--------------------------\n\n-   Use 
`poetry` for Python3.x\\... :\n\n        python -m pip install 
ciscoconfparse\n\nIf you\\\'re interested in the source, you can always pull 
from the [github repo][17]:\n\n- Download from [the github r
 epo][17]: :\n\n        git clone git://github.com/mpenning/ciscoconfparse\n    
    cd ciscoconfparse/\n        python -m pip install .\n\nOther 
Resources\n---------------\n\n- [Dive into 
Python3](http://www.diveintopython3.net/) is a good way to learn Python\n- 
[Team CYMRU][30] has a [Secure IOS Template][29], which is especially useful 
for external-facing routers / switches\n- [Cisco\\\'s Guide to hardening IOS 
devices][31]\n- [Center for Internet Security Benchmarks][32] (An email 
address, cookies, and javascript are required)\n\nBug Tracker and 
Support\n-----------------------\n\n- Please report any suggestions, bug 
reports, or annoyances with a [github bug report][24].\n- If you\\\'re having 
problems with general python issues, consider searching for a solution on 
[Stack Overflow][33].  If you can\\\'t find a solution for your problem or need 
more help, you can [ask on Stack Overflow][34] or [reddit/r/Python][39].\n- If 
you\\\'re having problems with your Cisco devices, you can 
 contact:\n  - [Cisco TAC][28]\n  - [reddit/r/Cisco][35]\n  - 
[reddit/r/networking][36]\n  - 
[NetworkEngineering.se][23]\n\nUnit-Tests\n----------\n\nThe project\\\'s [test 
workflow][1] checks ciscoconfparse on Python versions 3.6 and higher, as well 
as a [pypy JIT][22] executable.\n\nClick the image below for details; the 
current build status is: [![Github unittest status][4]][5]\n\nLicense and 
Copyright\n---------------------\n\n[ciscoconfparse][3] is licensed 
[GPLv3][21]\n\n- Copyright (C) 2021-2022 David Michael Pennington\n- Copyright 
(C) 2020-2021 David Michael Pennington at Cisco Systems (post-acquisition: 
Cisco acquired ThousandEyes)\n- Copyright (C) 2019 David Michael Pennington at 
ThousandEyes\n- Copyright (C) 2012-2019 David Michael Pennington at Samsung 
Data Services\n- Copyright (C) 2011-2012 David Michael Pennington at Dell 
Computer Corp\n- Copyright (C) 2007-2011 David Michael Pennington\n\nThe word 
\\"Cisco\\" is a registered trademark of [Cisco Systems][27].\n\nAutho
 r\n------\n\n[ciscoconfparse][3] was written by [David Michael Pennington][25] 
(mike \\[\\~at\\~\\] pennington \\[.dot.\\] net).\n\n\n  [1]: 
https://github.com/mpenning/ciscoconfparse/tree/master/.github/workflows\n  
[2]: https://img.shields.io/pypi/v/ciscoconfparse.svg\n  [3]: 
https://pypi.python.org/pypi/ciscoconfparse/\n  [4]: 
https://github.com/mpenning/ciscoconfparse/actions/workflows/tests.yml/badge.svg\n
  [5]: https://github.com/mpenning/ciscoconfparse/actions/workflows/tests.yml\n 
 [6]: https://pepy.tech/badge/ciscoconfparse\n  [7]: 
https://pepy.tech/project/ciscoconfparse\n  [8]: 
http://img.shields.io/badge/license-GPLv3-blue.svg\n  [9]: 
https://www.gnu.org/copyleft/gpl.html\n  [10]: https://www.python.org\n  [11]: 
https://raw.githubusercontent.com/mpenning/ciscoconfparse/master/sphinx-doc/_static/ciscoconfparse_overview_75pct.png\n
  [12]: https://github.com/mpenning/ciscoconfparse/blob/main/pyproject.toml\n  
[13]: https://github.com/mpenning/ciscoconfparse/blob/master/conf
 igs/sample_01.junos\n  [14]: 
https://github.com/mpenning/ciscoconfparse/issues/17\n  [15]: 
http://www.pennington.net/py/ciscoconfparse/\n  [16]: 
http://pennington.net/tutorial/ciscoconfparse/ccp_tutorial.html\n  [17]: 
https://github.com/mpenning/ciscoconfparse\n  [18]: 
https://github.com/mpenning/ciscoconfparse/issues/117\n  [19]: 
https://github.com/mpenning/ciscoconfparse/issues/13\n  [20]: 
https://github.com/CrackerJackMack/\n  [21]: 
http://www.gnu.org/licenses/gpl-3.0.html\n  [22]: https://pypy.org\n  [23]: 
https://networkengineering.stackexchange.com/\n  [24]: 
https://github.com/mpenning/ciscoconfparse/issues/new/choose\n  [25]: 
https://github.com/mpenning\n  [26]: https://github.com/muir\n  [27]: 
https://www.cisco.com/\n  [28]: https://www.cisco.com/go/support\n  [29]: 
https://www.cymru.com/Documents/secure-ios-template.html\n  [30]: 
https://team-cymru.com/company/\n  [31]: 
http://www.cisco.com/c/en/us/support/docs/ip/access-lists/13608-21.html\n  
[32]: https://learn.cisecurity
 .org/benchmarks\n  [33]: https://stackoverflow.com\n  [34]: 
http://stackoverflow.com/questions/ask\n  [35]: 
https://www.reddit.com/r/Cisco/\n  [36]: https://www.reddit.com/r/networking\n  
[37]: https://snyk.io/advisor/python/ciscoconfparse/badge.svg\n  [38]: 
https://snyk.io/advisor/python/ciscoconfparse\n  [39]: 
https://www.reddit.com/r/Python/\n',
     'author': 'Mike Pennington',
     'author_email': 'm...@pennington.net',
-    'maintainer': None,
-    'maintainer_email': None,
+    'maintainer': 'None',
+    'maintainer_email': 'None',
     'url': 'https://github.com/mpenning/ciscoconfparse',
     'packages': packages,
     'package_data': package_data,

Reply via email to