mirror of
https://github.com/certbot/certbot.git
synced 2026-06-05 14:54:24 -04:00
Add parsernode utils to check keyword arguments and document the defaults in pydoc
This commit is contained in:
parent
864f06100a
commit
11f977fa22
3 changed files with 152 additions and 47 deletions
|
|
@ -116,20 +116,21 @@ class ParserNode(object):
|
|||
ParserNode objects should have the following attributes:
|
||||
|
||||
# Reference to ancestor node, or None if the node is the root node of the
|
||||
# configuration tree.
|
||||
# configuration tree. Required.
|
||||
ancestor: Optional[ParserNode]
|
||||
|
||||
# True if this node has been modified since last save.
|
||||
# True if this node has been modified since last save. Default: False
|
||||
dirty: bool
|
||||
|
||||
# Filepath of the file where the configuration element for this ParserNode
|
||||
# object resides. This can be None if a configuration directive is defined in
|
||||
# for example the httpd command line.
|
||||
# object resides. For root node, the value for filepath is the httpd root
|
||||
# configuration file. Filepath can be None if a configuration directive is
|
||||
# defined in for example the httpd command line. Required.
|
||||
filepath: Optional[str]
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def __init__(self, ancestor=None, filepath="", dirty=False): # pragma: no cover
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
Initializes the ParserNode instance, and sets the ParserNode specific
|
||||
instance variables. This is not meant to be used directly, but through
|
||||
|
|
@ -153,6 +154,7 @@ class ParserNode(object):
|
|||
|
||||
"""
|
||||
|
||||
|
||||
# Linter rule exclusion done because of https://github.com/PyCQA/pylint/issues/179
|
||||
@six.add_metaclass(abc.ABCMeta) # pylint: disable=abstract-method
|
||||
class CommentNode(ParserNode):
|
||||
|
|
@ -164,17 +166,18 @@ class CommentNode(ParserNode):
|
|||
CommentNode stores its contents in class variable 'comment' and does not
|
||||
have a specific name.
|
||||
|
||||
CommentNode objects should have the following attributes:
|
||||
CommentNode objects should have the following attributes in addition to
|
||||
the ones described in ParserNode:
|
||||
|
||||
# Contains the contents of the comment without the directive notation
|
||||
# (typically # or /* ... */).
|
||||
# (typically # or /* ... */). Required.
|
||||
comment: str
|
||||
|
||||
"""
|
||||
|
||||
# pylint: disable=super-init-not-called
|
||||
@abc.abstractmethod
|
||||
def __init__(self, comment, ancestor, filepath, dirty=False): # pragma: no cover
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
Initializes the CommentNode instance and sets its instance variables.
|
||||
|
||||
|
|
@ -199,22 +202,23 @@ class DirectiveNode(ParserNode):
|
|||
variable for this DirectiveNode should be None, and it should be inserted to the
|
||||
beginning of root BlockNode children sequence.
|
||||
|
||||
DirectiveNode objects should have the following attributes:
|
||||
DirectiveNode objects should have the following attributes in addition to
|
||||
the ones described in ParserNode:
|
||||
|
||||
# True if this DirectiveNode is enabled and False if it is inside of an
|
||||
# inactive conditional block.
|
||||
# inactive conditional block. Default: True
|
||||
enabled: bool
|
||||
|
||||
# Name, or key of the configuration directive
|
||||
# Name, or key of the configuration directive. Required.
|
||||
name: str
|
||||
|
||||
# Tuple of parameters of this ParserNode object, excluding whitespaces.
|
||||
# Default: ()
|
||||
parameters: Tuple[str, ...]
|
||||
|
||||
"""
|
||||
# pylint: disable=too-many-arguments, super-init-not-called
|
||||
def __init__(self, name, parameters=(), ancestor=None, filepath="",
|
||||
dirty=False, enabled=True): # pragma: no cover
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
Initializes the DirectiveNode instance and sets its instance variables.
|
||||
|
||||
|
|
@ -277,37 +281,34 @@ class BlockNode(ParserNode):
|
|||
The applicable parameters are dependent on the underlying configuration language
|
||||
and its grammar.
|
||||
|
||||
BlockNode objects should have the following attributes:
|
||||
BlockNode objects should have the following attributes in addition to
|
||||
the ones described in ParserNode:
|
||||
|
||||
# True if this BlockNode is enabled and False if it is inside of an
|
||||
# inactive conditional block. If a BlockNode contains an unmatched
|
||||
# conditional statement, it should itself be flagged as enabled as it's
|
||||
# parsed, but its children should be flagged as disabled.
|
||||
# parsed, but its children should be flagged as disabled. Default: True
|
||||
enabled: bool
|
||||
|
||||
# Name, or key of the configuration directive. If the BlockNode is the root
|
||||
# configuration node, the name should be None.
|
||||
# configuration node, the name should be None. Required.
|
||||
name: Optional[str]
|
||||
|
||||
# Tuple of parameters of this ParserNode object, excluding whitespaces.
|
||||
# Default: ()
|
||||
parameters: Tuple[str, ...]
|
||||
|
||||
# Tuple of ParserNode objects that are the children for this node. The order
|
||||
# of the children is the same s that of the parsed configuration block.
|
||||
children: Tuple[ParserNode, ...]
|
||||
"""
|
||||
|
||||
# pylint: disable=too-many-arguments, super-init-not-called
|
||||
@abc.abstractmethod
|
||||
def __init__(self, name="", parameters=(), children=(), ancestor=None,
|
||||
filepath="", dirty=False, enabled=True): # pragma: no cover
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
Initializes the BlockNode instance and sets its instance variables.
|
||||
|
||||
:param name: Name or key of the BlockNode object, or None for root
|
||||
configuration node.
|
||||
:param tuple parameters: Tuple of str parameters for this BlockNode.
|
||||
:param tuple children: Tuple of ParserNode children for this BlockNode.
|
||||
:param ancestor: BlockNode ancestor for this BlockNode, or None for root
|
||||
configuration node.
|
||||
:param str filepath: Filesystem path for the file where this BlockNode does
|
||||
|
|
|
|||
74
certbot-apache/certbot_apache/parsernode_util.py
Normal file
74
certbot-apache/certbot_apache/parsernode_util.py
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
"""ParserNode utils"""
|
||||
|
||||
|
||||
def validate_kwargs(kwargs, required_names):
|
||||
"""
|
||||
Ensures that the kwargs dict has all the expected values.
|
||||
|
||||
:param dict kwargs: Dictionary of keyword arguments to validate.
|
||||
:param list required_names: List of required parameter names.
|
||||
"""
|
||||
|
||||
validated_kwargs = dict()
|
||||
for name in required_names:
|
||||
try:
|
||||
validated_kwargs[name] = kwargs.pop(name)
|
||||
except KeyError:
|
||||
raise TypeError("Required keyword argument: {} undefined.".format(name))
|
||||
|
||||
# Raise exception if unknown key word arguments are found.
|
||||
if kwargs:
|
||||
unknown = ", ".join(kwargs.keys())
|
||||
raise TypeError("Unknown keyword argument(s): {}".format(unknown))
|
||||
return validated_kwargs
|
||||
|
||||
|
||||
def parsernode_kwargs(kwargs):
|
||||
"""
|
||||
Validates keyword arguments for ParserNode.
|
||||
|
||||
:param dict kwargs: Keyword argument dictionary to validate.
|
||||
|
||||
:returns: Tuple of validated and prepared arguments.
|
||||
"""
|
||||
kwargs.setdefault("dirty", False)
|
||||
kwargs = validate_kwargs(kwargs, ["ancestor", "dirty", "filepath"])
|
||||
return kwargs["ancestor"], kwargs["dirty"], kwargs["filepath"]
|
||||
|
||||
|
||||
def commentnode_kwargs(kwargs):
|
||||
"""
|
||||
Validates keyword arguments for CommentNode and sets the default values for
|
||||
optional kwargs.
|
||||
|
||||
:param dict kwargs: Keyword argument dictionary to validate.
|
||||
|
||||
:returns: Tuple of validated and prepared arguments and the remaining kwargs.
|
||||
"""
|
||||
kwargs.setdefault("dirty", False)
|
||||
kwargs = validate_kwargs(kwargs, ["ancestor", "dirty", "filepath", "comment"])
|
||||
|
||||
comment = kwargs.pop("comment")
|
||||
return comment, kwargs
|
||||
|
||||
|
||||
def node_kwargs(kwargs):
|
||||
"""
|
||||
Validates keyword arguments for DirectiveNode and BlockNode and sets the
|
||||
default values for optional kwargs.
|
||||
|
||||
:param dict kwargs: Keyword argument dictionary to validate.
|
||||
|
||||
:returns: Tuple of validated and prepared arguments.
|
||||
"""
|
||||
kwargs.setdefault("dirty", False)
|
||||
kwargs.setdefault("enabled", True)
|
||||
kwargs.setdefault("parameters", ())
|
||||
|
||||
kwargs = validate_kwargs(kwargs, ["ancestor", "dirty", "filepath", "name",
|
||||
"parameters", "enabled"])
|
||||
|
||||
name = kwargs.pop("name")
|
||||
parameters = kwargs.pop("parameters")
|
||||
enabled = kwargs.pop("enabled")
|
||||
return name, parameters, enabled, kwargs
|
||||
|
|
@ -5,22 +5,21 @@ import unittest
|
|||
from acme.magic_typing import Optional, Tuple # pylint: disable=unused-import, no-name-in-module
|
||||
|
||||
from certbot_apache import interfaces
|
||||
from certbot_apache import parsernode_util as util
|
||||
|
||||
|
||||
class DummyParserNode(interfaces.ParserNode):
|
||||
""" A dummy class implementing ParserNode interface """
|
||||
ancestor = None
|
||||
dirty = False
|
||||
filepath = None
|
||||
|
||||
def __init__(self, ancestor=None, filepath=str(), dirty=False):
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
Initializes the ParserNode instance.
|
||||
"""
|
||||
super(DummyParserNode, self).__init__(ancestor, filepath, dirty)
|
||||
ancestor, dirty, filepath = util.parsernode_kwargs(kwargs)
|
||||
self.ancestor = ancestor
|
||||
self.dirty = dirty
|
||||
self.filepath = filepath
|
||||
super(DummyParserNode, self).__init__(**kwargs)
|
||||
|
||||
def save(self, msg): # pragma: no cover
|
||||
"""Save"""
|
||||
|
|
@ -30,31 +29,30 @@ class DummyParserNode(interfaces.ParserNode):
|
|||
class DummyCommentNode(DummyParserNode):
|
||||
""" A dummy class implementing CommentNode interface """
|
||||
|
||||
def __init__(self, comment, ancestor, filepath, dirty=False):
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
Initializes the CommentNode instance and sets its instance variables.
|
||||
"""
|
||||
super(DummyCommentNode, self).__init__(ancestor, filepath, dirty)
|
||||
comment, kwargs = util.commentnode_kwargs(kwargs)
|
||||
self.comment = comment
|
||||
super(DummyCommentNode, self).__init__(**kwargs)
|
||||
|
||||
|
||||
class DummyDirectiveNode(DummyParserNode):
|
||||
""" A dummy class implementing DirectiveNode interface """
|
||||
parameters = tuple() # type: Tuple[str, ...]
|
||||
enabled = True
|
||||
name = ""
|
||||
|
||||
# pylint: disable=too-many-arguments
|
||||
def __init__(self, name, parameters=(), ancestor=None, filepath="",
|
||||
dirty=False, enabled=True):
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
Initializes the DirectiveNode instance and sets its instance variables.
|
||||
"""
|
||||
super(DummyDirectiveNode, self).__init__(ancestor, filepath, dirty)
|
||||
name, parameters, enabled, kwargs = util.node_kwargs(kwargs)
|
||||
self.name = name
|
||||
self.parameters = parameters
|
||||
self.enabled = enabled
|
||||
|
||||
super(DummyDirectiveNode, self).__init__(**kwargs)
|
||||
|
||||
def set_parameters(self, parameters): # pragma: no cover
|
||||
"""Set parameters"""
|
||||
pass
|
||||
|
|
@ -62,23 +60,19 @@ class DummyDirectiveNode(DummyParserNode):
|
|||
|
||||
class DummyBlockNode(DummyParserNode):
|
||||
""" A dummy class implementing BlockNode interface """
|
||||
parameters = tuple() # type: Tuple[str, ...]
|
||||
children = tuple() # type: Tuple[interfaces.ParserNode, ...]
|
||||
enabled = True
|
||||
name = ""
|
||||
|
||||
# pylint: disable=too-many-arguments
|
||||
def __init__(self, name="", parameters=(), children=(), ancestor=None,
|
||||
filepath="", dirty=False, enabled=True):
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
Initializes the BlockNode instance and sets its instance variables.
|
||||
"""
|
||||
super(DummyBlockNode, self).__init__(ancestor, filepath, dirty)
|
||||
|
||||
name, parameters, enabled, kwargs = util.node_kwargs(kwargs)
|
||||
self.name = name
|
||||
self.parameters = parameters
|
||||
self.children = children
|
||||
self.enabled = enabled
|
||||
|
||||
super(DummyBlockNode, self).__init__(**kwargs)
|
||||
|
||||
def add_child_block(self, name, parameters=None, position=None): # pragma: no cover
|
||||
"""Add child block"""
|
||||
pass
|
||||
|
|
@ -124,9 +118,45 @@ class ParserNodeTest(unittest.TestCase):
|
|||
"""Dummy placeholder test case for ParserNode interfaces"""
|
||||
|
||||
def test_dummy(self):
|
||||
dummyblock = DummyBlockNode()
|
||||
dummydirective = DummyDirectiveNode("Name")
|
||||
dummycomment = DummyCommentNode("Comment", dummyblock, "/some/file")
|
||||
dummyblock = DummyBlockNode(
|
||||
name=None,
|
||||
parameters=(),
|
||||
ancestor=None,
|
||||
dirty=False,
|
||||
filepath="/some/random/path"
|
||||
)
|
||||
dummydirective = DummyDirectiveNode(
|
||||
name="Name",
|
||||
ancestor=None,
|
||||
filepath="/another/path"
|
||||
)
|
||||
dummycomment = DummyCommentNode(
|
||||
comment="Comment",
|
||||
ancestor=dummyblock,
|
||||
filepath="/some/file"
|
||||
)
|
||||
|
||||
def test_unknown_parameter(self):
|
||||
params = {
|
||||
"comment": "x",
|
||||
"ancestor": None,
|
||||
"dirty": False,
|
||||
"filepath": "/tmp",
|
||||
"unknown": "x"
|
||||
}
|
||||
self.assertRaises(TypeError, DummyCommentNode, **params)
|
||||
params["name"] = "unnamed"
|
||||
params.pop("comment")
|
||||
self.assertRaises(TypeError, DummyDirectiveNode, **params)
|
||||
self.assertRaises(TypeError, DummyBlockNode, **params)
|
||||
|
||||
def test_missing_required(self):
|
||||
params = {
|
||||
"ancestor": None,
|
||||
"dirty": False,
|
||||
"filepath": "/tmp",
|
||||
}
|
||||
self.assertRaises(TypeError, DummyCommentNode, **params)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
Loading…
Reference in a new issue