Skip to content

Commit

Permalink
Add / rename parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
mpenning committed Nov 3, 2023
1 parent 6f8dc31 commit d4ff1f7
Show file tree
Hide file tree
Showing 8 changed files with 357 additions and 163 deletions.
18 changes: 14 additions & 4 deletions ciscoconfparse/ccp_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,19 @@
class BaseCfgLine(metaclass=ABCMeta):
# deprecating py2.foo metaclass syntax in version 1.6.8...
# __metaclass__ = ABCMeta
def __init__(self, text=DEFAULT_TEXT, comment_delimiter="!"):
"""Accept an IOS line number and initialize family relationship
attributes"""
def __init__(self, all_lines=None, line=DEFAULT_TEXT, comment_delimiter="!"):
"""Accept an IOS line number and initialize family relationship attributes"""

if not isinstance(all_lines, list):
error = f"BaseCfgLine() expected `type(all_lines)` to be a list, but got {type(all_lines)}"
error.critical(error)
raise InvalidParameters(error)

if not isinstance(line, str):
error = f"BaseCfgLine() expected BaseCfgLine(line=`{line}`) to be a string, but got {type(line)}"
error.critical(error)
raise InvalidParameters(error)

self.comment_delimiter = comment_delimiter
self._uncfgtext_to_be_deprecated = ""
self._text = DEFAULT_TEXT
Expand All @@ -51,7 +61,7 @@ def __init__(self, text=DEFAULT_TEXT, comment_delimiter="!"):
self.blank_line_keep = False # CiscoConfParse() uses blank_line_keep

# Call set_comment_bool() in the self.text setter method...
self.text = text # Use self.text setter method to set this value
self.text = line # Use self.text setter method to set this value

self._line_id = None
self.diff_rendered = None
Expand Down
127 changes: 88 additions & 39 deletions ciscoconfparse/ciscoconfparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
from ciscoconfparse.models_cisco import IOSAaaLoginAuthenticationLine
from ciscoconfparse.models_cisco import IOSAaaEnableAuthenticationLine
from ciscoconfparse.models_cisco import IOSAaaCommandsAuthorizationLine
from ciscoconfparse.models_cisco import IOSAaaConsoleAuthorizationLine
from ciscoconfparse.models_cisco import IOSAaaCommandsAccountingLine
from ciscoconfparse.models_cisco import IOSAaaExecAccountingLine
from ciscoconfparse.models_cisco import IOSAaaGroupServerLine
Expand All @@ -57,6 +58,7 @@
from ciscoconfparse.models_nxos import NXOSAaaLoginAuthenticationLine
from ciscoconfparse.models_nxos import NXOSAaaEnableAuthenticationLine
from ciscoconfparse.models_nxos import NXOSAaaCommandsAuthorizationLine
from ciscoconfparse.models_nxos import NXOSAaaConsoleAuthorizationLine
from ciscoconfparse.models_nxos import NXOSAaaCommandsAccountingLine
from ciscoconfparse.models_nxos import NXOSAaaExecAccountingLine
from ciscoconfparse.models_nxos import NXOSCfgLine, NXOSIntfLine
Expand Down Expand Up @@ -100,6 +102,7 @@
IOSAaaLoginAuthenticationLine,
IOSAaaEnableAuthenticationLine,
IOSAaaCommandsAuthorizationLine,
IOSAaaConsoleAuthorizationLine,
IOSAaaCommandsAccountingLine,
IOSAaaExecAccountingLine,
IOSAaaGroupServerLine,
Expand All @@ -114,6 +117,7 @@
NXOSAaaLoginAuthenticationLine,
NXOSAaaEnableAuthenticationLine,
NXOSAaaCommandsAuthorizationLine,
NXOSAaaConsoleAuthorizationLine,
NXOSAaaCommandsAccountingLine,
NXOSAaaExecAccountingLine,
NXOSAaaGroupServerLine,
Expand Down Expand Up @@ -391,23 +395,47 @@ def _parse_line_braces(line_txt=None, comment_delimiter=None) -> tuple:
# This method was on ConfigList()
@logger.catch(reraise=True)
def _cfgobj_from_text(
txt, idx, syntax=None, comment_delimiter=None, factory=None
text_list, txt, idx, syntax=None, comment_delimiter=None, factory=None
):
"""Build cfgobj from configuration text syntax, and factory inputs."""

if not isinstance(txt, str):
error = f"_cfgobj_from_text(txt=`{txt}`) must be a string"
logger.error(error)
raise InvalidParameters(error)

if not isinstance(idx, int):
error = f"_cfgobj_from_text(idx=`{idx}`) must be an int"
logger.error(error)
raise InvalidParameters(error)

# if not factory is **faster** than factory is False
if not factory:
if syntax in ALL_VALID_SYNTAX and not factory:
obj = CFGLINE[syntax](
text=txt,
comment_delimiter=comment_delimiter,
)
if isinstance(obj, BaseCfgLine):
obj.linenum = idx
else:
error = f"{CFGLINE[syntax]}(txt=`{txt}`) must return an instance of BaseCfgLine(), but it returned {obj}"
logger.error(error)
raise ValueError(error)

# if factory is **faster** than if factory is True
elif syntax in ALL_VALID_SYNTAX and factory:
obj = ConfigLineFactory(
txt,
comment_delimiter,
obj = config_line_factory(
all_lines=text_list,
line=txt,
comment_delimiter=comment_delimiter,
syntax=syntax,
)
if isinstance(obj, BaseCfgLine):
obj.linenum = idx
else:
error = f"config_line_factory(line=`{txt}`) must return an instance of BaseCfgLine(), but it returned {obj}"
logger.error(error)
raise ValueError(error)

else:
err_txt = (
Expand All @@ -416,7 +444,6 @@ def _cfgobj_from_text(
logger.error(err_txt)
raise ValueError(err_txt)

obj.linenum = idx

return obj

Expand Down Expand Up @@ -702,15 +729,24 @@ def __init__(
# This method is on CiscoConfParse()
@logger.catch(reraise=True)
def _handle_ccp_syntax(self, tmp_lines=None, syntax=None):
"""Deal with syntax issues, such as conditionally discarding junos closing brace-lines."""
"""Deal with brace-delimited syntax issues, such as conditionally discarding junos closing brace-lines."""

assert tmp_lines is not None
if syntax == "junos":
err_msg = "junos parser factory is not yet enabled; use factory=False"
assert self.factory is False, err_msg
config_lines = convert_junos_to_ios(tmp_lines, comment_delimiter="#")
else:
if not syntax in ALL_VALID_SYNTAX:
error = f"{syntax} parser factory is not yet enabled; use factory=False"
logger.critical(error)
raise InvalidParameters(error)

if tmp_lines is None:
error = f"_handle_ccp_syntax(tmp_lines={tmp_lines}) must not be None"
logger.error(error)
raise InvalidParameters(error)

if syntax in ALL_VALID_SYNTAX:
config_lines = tmp_lines
else:
error = f"_handle_ccp_syntax(syntax=`{syntax}`) is not yet supported"
logger.error(error)
raise InvalidParameters(error)

return config_lines

Expand Down Expand Up @@ -4909,7 +4945,7 @@ def insert_before(self, exist_val=None, new_val=None, atomic=False):
)

elif self.factory is True:
new_obj = ConfigLineFactory(
new_obj = config_line_factory(
text=new_val,
comment_delimiter=self.comment_delimiter,
syntax=self.syntax,
Expand Down Expand Up @@ -5029,7 +5065,7 @@ def insert_after(self, exist_val=None, new_val=None, atomic=False, new_val_inden
)

elif self.factory is True:
new_obj = ConfigLineFactory(
new_obj = config_line_factory(
text=new_val,
comment_delimiter=self.comment_delimiter,
syntax=self.syntax,
Expand Down Expand Up @@ -5068,7 +5104,7 @@ def insert(self, ii, val):
# Coerce a string into the appropriate object
if getattr(val, "capitalize", False):
if self.factory:
obj = ConfigLineFactory(
obj = config_line_factory(
text=val,
comment_delimiter=self.comment_delimiter,
syntax=self.syntax,
Expand Down Expand Up @@ -5342,6 +5378,7 @@ def _bootstrap_obj_init_ng(self, text_list=None, debug=0):

# Assign a custom *CfgLine() based on factory...
obj = _cfgobj_from_text(
text_list,
txt=txt,
idx=idx,
syntax=syntax,
Expand Down Expand Up @@ -5662,40 +5699,52 @@ def decrypt(self, ep=""):


@logger.catch(reraise=True)
def ConfigLineFactory(text="", comment_delimiter="!", syntax="ios"):
"""A factory method to assign a custom *CfgLine() object based on the contents of the input text parameter and input syntax parameter."""
def config_line_factory(all_lines=None, line=None, comment_delimiter="!", syntax="ios"):
"""A factory method to assign a custom BaseCfgLine() subclass based on `all_lines`, `line`, `comment_delimiter`, and `syntax` parameters."""
# Complicted & Buggy
# classes = [j for (i,j) in globals().iteritems() if isinstance(j, TypeType) and issubclass(j, BaseCfgLine)]
if not isinstance(all_lines, list):
error = f"config_line_factory(all_lines=`{all_lines}`) must be a list, but we got {type(all_lines)}"
logger.error(error)
raise InvalidParameters(error)

## Manual and simple
if syntax == "ios":
classes = ALL_IOS_FACTORY_CLASSES
elif syntax == "nxos":
classes = ALL_NXOS_FACTORY_CLASSES
elif syntax == "asa":
classes = ALL_ASA_FACTORY_CLASSES
elif syntax == "junos":
classes = ALL_JUNOS_FACTORY_CLASSES
if not isinstance(line, str):
error = f"config_line_factory(text=`{line}`) must be a string, but we got {type(line)}"
logger.error(error)
raise InvalidParameters(error)

else:
err_txt = "'{}' is an unknown syntax".format(syntax)
logger.error(err_txt)
raise ValueError(err_txt)
if not isinstance(comment_delimiter, str):
error = f"config_line_factory(comment_delimiter=`{comment_delimiter}`) must be a string, but we got {type(comment_delimiter)}"
logger.error(error)
raise InvalidParameters(error)

if not isinstance(syntax, str):
error = f"config_line_factory(syntax=`{syntax}`) must be a string, but we got {type(syntax)}"
logger.error(error)
raise InvalidParameters(error)

if syntax not in ALL_VALID_SYNTAX:
error = f"`{syntax}` is an unknown syntax"
logger.error(error)
raise ValueError(error)

# Walk all the classes and return the first class that
# matches `.is_object_for(text)`.
try:
for cls in classes:
if cls.is_object_for(text):
inst = cls(
text=text,
for cls in ALL_IOS_FACTORY_CLASSES:
print(f" Consider config_line_factory() CLASS {cls}")
if cls.is_object_for(all_lines=all_lines, line=line):
basecfgline_subclass = cls(
all_lines=all_lines, line=line,
comment_delimiter=comment_delimiter,
) # instance of the proper subclass
return inst
return basecfgline_subclass
except ValueError:
err_txt = "Could not find an object for '%s'" % text
logger.error(err_txt)
raise ValueError(err_txt)
error = f"ciscoconfparse.py config_line_factory(all_lines={all_lines}, line=`{line}`, comment_delimiter=`{comment_delimiter}`, syntax=`{syntax}`) could not find a subclass of BaseCfgLine()"
logger.error(error)
raise ValueError(error)

return IOSCfgLine(all_lines=all_lines, line=line, comment_delimiter=comment_delimiter)

### TODO: Add unit tests below
if __name__ == "__main__":
Expand Down
16 changes: 8 additions & 8 deletions ciscoconfparse/models_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def __repr__(self):

@classmethod
@logger.catch(reraise=True)
def is_object_for(cls, line="", re=re):
def is_object_for(cls, all_lines, line, re=re):
## Default object, for now
raise NotImplementedError()

Expand Down Expand Up @@ -2144,7 +2144,7 @@ def __init__(self, *args, **kwargs):
# This method is on IOSIntfLine()
@classmethod
@logger.catch(reraise=True)
def is_object_for(cls, line="", re=re):
def is_object_for(cls, all_lines, line, re=re):
intf_regex = re.search(r"^interface\s+(?P<interface>\S+.+)", line.strip())
if isinstance(intf_regex, re.Match):
interface = intf_regex.groupdict()["interface"]
Expand Down Expand Up @@ -2469,7 +2469,7 @@ def __init__(self, *args, **kwargs):

@classmethod
@logger.catch(reraise=True)
def is_object_for(cls, line="", re=re):
def is_object_for(cls, all_lines, line, re=re):
if re.search(r"^aaa\sgroup\sserver", line):
return True
return False
Expand Down Expand Up @@ -2526,7 +2526,7 @@ def __init__(self, *args, **kwargs):

@classmethod
@logger.catch(reraise=True)
def is_object_for(cls, line="", re=re):
def is_object_for(cls, all_lines, line, re=re):
if re.search(r"^aaa\sauthentication\slogin", line):
return True
return False
Expand All @@ -2551,7 +2551,7 @@ def __init__(self, *args, **kwargs):

@classmethod
@logger.catch(reraise=True)
def is_object_for(cls, line="", re=re):
def is_object_for(cls, all_lines, line, re=re):
if re.search(r"^aaa\sauthentication\senable", line):
return True
return False
Expand All @@ -2577,7 +2577,7 @@ def __init__(self, *args, **kwargs):

@classmethod
@logger.catch(reraise=True)
def is_object_for(cls, line="", re=re):
def is_object_for(cls, all_lines, line, re=re):
if re.search(r"^aaa\sauthorization\scommands", line):
return True
return False
Expand All @@ -2604,7 +2604,7 @@ def __init__(self, *args, **kwargs):

@classmethod
@logger.catch(reraise=True)
def is_object_for(cls, line="", re=re):
def is_object_for(cls, all_lines, line, re=re):
if re.search(r"^aaa\saccounting\scommands", line):
return True
return False
Expand All @@ -2630,7 +2630,7 @@ def __init__(self, *args, **kwargs):

@classmethod
@logger.catch(reraise=True)
def is_object_for(cls, line="", re=re):
def is_object_for(cls, all_lines, line, re=re):
if re.search(r"^aaa\saccounting\sexec", line):
return True
return False
Loading

0 comments on commit d4ff1f7

Please sign in to comment.