Skip to content

Commit

Permalink
Merge pull request #81 from wwkimball/bugfix/set-traversals
Browse files Browse the repository at this point in the history
Bugfix/set traversals
  • Loading branch information
wwkimball committed Oct 13, 2020
2 parents 12fc316 + 4c6ca7f commit 31e825e
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 62 deletions.
12 changes: 12 additions & 0 deletions tests/test_wrappers_consoleprinter.py
Expand Up @@ -5,6 +5,7 @@
from ruamel.yaml.comments import CommentedMap
from ruamel.yaml.scalarstring import PlainScalarString

from yamlpath.wrappers import NodeCoords
from yamlpath.wrappers import ConsolePrinter

class Test_wrappers_ConsolePrinter():
Expand Down Expand Up @@ -128,6 +129,17 @@ def test_debug_noisy(self, capsys):
"DEBUG: test_debug_noisy: === FOOTER ===",
]) + "\n" == console.out

nc = NodeCoords("value", dict(key="value"), "key")
logger.debug(
"A node coordinate:", prefix="test_debug_noisy: ", data=nc)
console = capsys.readouterr()
assert "\n".join([
"DEBUG: test_debug_noisy: A node coordinate:",
"DEBUG: test_debug_noisy: (node)value",
"DEBUG: test_debug_noisy: (parent)[key]value<class 'str'>",
"DEBUG: test_debug_noisy: (parentref)key",
]) + "\n" == console.out

def test_debug_quiet(self, capsys):
args = SimpleNamespace(verbose=False, quiet=True, debug=True)
logger = ConsolePrinter(args)
Expand Down
4 changes: 4 additions & 0 deletions tests/test_wrappers_nodecoords.py
Expand Up @@ -11,3 +11,7 @@ def test_generic(self):
def test_repr(self):
node_coord = NodeCoords([], None, None)
assert repr(node_coord) == "NodeCoords('[]', 'None', 'None')"

def test_str(self):
node_coord = NodeCoords([], None, None)
assert str(node_coord) == "[]"
4 changes: 3 additions & 1 deletion yamlpath/commands/yaml_get.py
Expand Up @@ -170,7 +170,9 @@ def main():
publickey=args.publickey, privatekey=args.privatekey)
try:
for node in processor.get_eyaml_values(yaml_path, mustexist=True):
log.debug("Got {} from {}.".format(repr(node), yaml_path))
log.debug(
"Got node from {}:".format(yaml_path), data=node,
prefix="yaml_get::main: ")
discovered_nodes.append(unwrap_node_coords(node))
except YAMLPathException as ex:
log.critical(ex, 1)
Expand Down
36 changes: 15 additions & 21 deletions yamlpath/commands/yaml_paths.py
Expand Up @@ -273,10 +273,9 @@ def yield_children(logger: ConsolePrinter, data: Any,
include_value_aliases: bool = kwargs.pop("include_value_aliases", False)
search_anchors: bool = kwargs.pop("search_anchors", False)
logger.debug(
("yaml_paths::yield_children: "
+ "dumping all children in data of type, {}:")
.format(type(data)))
logger.debug(data)
"Dumping all children in data of type, {}:"
.format(type(data)), data=data,
prefix="yaml_paths::yield_children: ")

exclude_alias_matchers = [AnchorMatches.UNSEARCHABLE_ALIAS,
AnchorMatches.ALIAS_EXCLUDED]
Expand Down Expand Up @@ -445,11 +444,9 @@ def search_for_paths(logger: ConsolePrinter, processor: EYAMLProcessor,

if isinstance(ele, (CommentedSeq, CommentedMap)):
logger.debug(
"yaml_paths::search_for_paths<list>:"
+ "recursing into complex data:"
)
logger.debug(ele)
logger.debug(">>>> >>>> >>>> >>>> >>>> >>>> >>>>")
"Recursing into complex data:", data=ele,
prefix="yaml_paths::search_for_paths<list>: ",
footer=">>>> >>>> >>>> >>>> >>>> >>>> >>>>")
for subpath in search_for_paths(
logger, processor, ele, terms, pathsep, tmp_path,
seen_anchors, search_values=search_values,
Expand All @@ -460,11 +457,10 @@ def search_for_paths(logger: ConsolePrinter, processor: EYAMLProcessor,
expand_children=expand_children
):
logger.debug(
("yaml_paths::search_for_paths<list>:"
+ "yielding RECURSED match, {}."
).format(subpath)
"Yielding RECURSED match, {}.".format(subpath),
prefix="yaml_paths::search_for_paths<list>: ",
footer="<<<< <<<< <<<< <<<< <<<< <<<< <<<<"
)
logger.debug("<<<< <<<< <<<< <<<< <<<< <<<< <<<<")
yield subpath
elif search_values:
if (anchor_matched is AnchorMatches.UNSEARCHABLE_ALIAS
Expand Down Expand Up @@ -588,11 +584,10 @@ def search_for_paths(logger: ConsolePrinter, processor: EYAMLProcessor,

if isinstance(val, (CommentedSeq, CommentedMap)):
logger.debug(
"yaml_paths::search_for_paths<dict>:"
+ "recursing into complex data:"
"Recursing into complex data:", data=val,
prefix="yaml_paths::search_for_paths<dict>: ",
footer=">>>> >>>> >>>> >>>> >>>> >>>> >>>>"
)
logger.debug(val)
logger.debug(">>>> >>>> >>>> >>>> >>>> >>>> >>>>")
for subpath in search_for_paths(
logger, processor, val, terms, pathsep, tmp_path,
seen_anchors, search_values=search_values,
Expand All @@ -603,11 +598,10 @@ def search_for_paths(logger: ConsolePrinter, processor: EYAMLProcessor,
expand_children=expand_children
):
logger.debug(
("yaml_paths::search_for_paths<dict>:"
+ "yielding RECURSED match, {}."
).format(subpath)
"Yielding RECURSED match, {}.".format(subpath),
prefix="yaml_paths::search_for_paths<dict>: ",
footer="<<<< <<<< <<<< <<<< <<<< <<<< <<<<"
)
logger.debug("<<<< <<<< <<<< <<<< <<<< <<<< <<<<")
yield subpath
elif search_values:
if (val_anchor_matched is AnchorMatches.UNSEARCHABLE_ALIAS
Expand Down
13 changes: 9 additions & 4 deletions yamlpath/commands/yaml_set.py
Expand Up @@ -262,7 +262,9 @@ def save_to_yaml_file(args, log, yaml_parser, yaml_data, backup_file):
if args.backup:
remove(backup_file)

log.debug("Assertion error: {}".format(ex))
log.debug(
"yaml_set::save_to_yaml_file: Assertion error: {}"
.format(ex))
log.critical((
"Indeterminate assertion error encountered while"
+ " attempting to write updated data to {}. The original"
Expand Down Expand Up @@ -379,7 +381,9 @@ def main():
for node_coordinate in processor.get_nodes(
change_path, mustexist=must_exist,
default_value=("" if new_value else " ")):
log.debug('Got "{}" from {}.'.format(node_coordinate, change_path))
log.debug(
"Got node from {}:".format(change_path),
data=node_coordinate, prefix="yaml_set::main: ")
change_node_coordinates.append(node_coordinate)
except YAMLPathException as ex:
log.critical(ex, 1)
Expand All @@ -392,8 +396,9 @@ def main():
old_format = YAMLValueFormats.from_node(
change_node_coordinates[0].node)

log.debug("Collected nodes:")
log.debug(change_node_coordinates)
log.debug(
"Collected nodes:", data=change_node_coordinates,
prefix="yaml_set::main: ")

# Check the value(s), if desired
if args.check:
Expand Down
18 changes: 3 additions & 15 deletions yamlpath/merger/mergerconfig.py
Expand Up @@ -253,14 +253,8 @@ def _prepare_user_rules(
"... RULE: {}".format(merge_rule),
prefix="MergerConfig::_prepare_user_rules: ")
self.log.debug(
"... NODE:", prefix="MergerConfig::_prepare_user_rules: ",
data=node_coord.node)
self.log.debug(
"... PARENT:", prefix="MergerConfig::_prepare_user_rules: ",
data=node_coord.parent)
self.log.debug(
"... REF:", prefix="MergerConfig::_prepare_user_rules: ",
data=node_coord.parentref)
"... NODE:", data=node_coord,
prefix="MergerConfig::_prepare_user_rules: ")

def _load_config(self) -> None:
"""Load the external configuration file."""
Expand Down Expand Up @@ -312,13 +306,7 @@ def _get_rule_for(self, node_coord: NodeCoords) -> str:
header=" ")
self.log.debug(
"... NODE:", prefix="MergerConfig::_get_rule_for: ",
data=node_coord.node)
self.log.debug(
"... PARENT:", prefix="MergerConfig::_get_rule_for: ",
data=node_coord.parent)
self.log.debug(
"... REF:", prefix="MergerConfig::_get_rule_for: ",
data=node_coord.parentref, footer=" ")
data=node_coord)
return self._get_config_for(node_coord, self.rules)

def _get_key_for(self, node_coord: NodeCoords) -> str:
Expand Down
66 changes: 45 additions & 21 deletions yamlpath/processor.py
Expand Up @@ -85,7 +85,7 @@ def get_nodes(self, yaml_path: Union[YAMLPath, str],
matched_nodes += 1
self.logger.debug(
"Relaying required node:",
prefix="Processor::get_nodes: ", data=node_coords.node)
prefix="Processor::get_nodes: ", data=node_coords)
yield node_coords

if matched_nodes < 1:
Expand All @@ -99,7 +99,7 @@ def get_nodes(self, yaml_path: Union[YAMLPath, str],
):
self.logger.debug(
"Relaying optional node:",
prefix="Processor::get_nodes: ", data=opt_node.node)
prefix="Processor::get_nodes: ", data=opt_node)
yield opt_node

def set_value(self, yaml_path: Union[YAMLPath, str],
Expand Down Expand Up @@ -174,10 +174,13 @@ def set_value(self, yaml_path: Union[YAMLPath, str],
self.data, yaml_path, value
):
self.logger.debug(
("Processor::set_value: Matched optional node coord, {};"
+ " setting its value to {}<{}>.")
.format(node_coord, value, value_format)
)
"Matched optional node coordinate:"
, data=node_coord
, prefix="Processor::set_value: ")
self.logger.debug(
"Setting its value with format {} to:".format(value_format)
, data=value
, prefix="Processor::set_value: ")
try:
self._update_node(
node_coord.parent, node_coord.parentref, value,
Expand Down Expand Up @@ -473,9 +476,9 @@ def _get_nodes_by_search(
Raises: N/A
"""
self.logger.debug(
("Processor::_get_nodes_by_search: Seeking SEARCH nodes matching"
+ " {}.")
.format(terms))
"Seeking SEARCH nodes matching {} in data:".format(terms),
data=data,
prefix="Processor::_get_nodes_by_search: ")

parent = kwargs.pop("parent", None)
parentref = kwargs.pop("parentref", None)
Expand All @@ -484,14 +487,21 @@ def _get_nodes_by_search(
method = terms.method
attr = terms.attribute
term = terms.term
if traverse_lists and isinstance(data, list):
if isinstance(data, list):
if not traverse_lists:
return

for lstidx, ele in enumerate(data):
if attr == '.':
matches = search_matches(method, term, ele)
elif isinstance(ele, dict) and attr in ele:
matches = search_matches(method, term, ele[attr])

if (matches and not invert) or (invert and not matches):
self.logger.debug(
"Yielding list match at index {}:".format(lstidx),
data=ele,
prefix="Processor::_get_nodes_by_search: ")
yield NodeCoords(ele, data, lstidx)

elif isinstance(data, dict):
Expand All @@ -500,18 +510,31 @@ def _get_nodes_by_search(
for key, val in data.items():
matches = search_matches(method, term, key)
if (matches and not invert) or (invert and not matches):
self.logger.debug(
"Yielding dictionary key name match against '{}':"
.format(key),
data=val,
prefix="Processor::_get_nodes_by_search: ")
yield NodeCoords(val, data, key)

elif attr in data:
value = data[attr]
matches = search_matches(method, term, value)
if (matches and not invert) or (invert and not matches):
self.logger.debug(
"Yielding dictionary attribute match against '{}':"
.format(attr),
data=value,
prefix="Processor::_get_nodes_by_search: ")
yield NodeCoords(value, data, attr)

else:
# Check the passed data itself for a match
matches = search_matches(method, term, data)
if (matches and not invert) or (invert and not matches):
self.logger.debug(
"Yielding the queried data itself because it matches.",
prefix="Processor::_get_nodes_by_search: ")
yield NodeCoords(data, parent, parentref)

# pylint: disable=locally-disabled
Expand Down Expand Up @@ -656,7 +679,7 @@ def _get_nodes_by_traversal(self, data: Any, yaml_path: YAMLPath,
parentref = kwargs.pop("parentref", None)

self.logger.debug(
"TRAVERSING the tree at:",
"TRAVERSING the tree at parentref:",
prefix="Processor::_get_nodes_by_traversal: ", data=parentref)

if data is None:
Expand All @@ -677,7 +700,7 @@ def _get_nodes_by_traversal(self, data: Any, yaml_path: YAMLPath,
self.logger.debug(
"Yielding unfiltered Hash value:",
prefix="Processor::_get_nodes_by_traversal: ",
data=node_coord.node)
data=node_coord)
yield node_coord
elif isinstance(data, list):
for idx, ele in enumerate(data):
Expand All @@ -688,7 +711,7 @@ def _get_nodes_by_traversal(self, data: Any, yaml_path: YAMLPath,
self.logger.debug(
"Yielding unfiltered Array value:",
prefix="Processor::_get_nodes_by_traversal: ",
data=node_coord.node)
data=node_coord)
yield node_coord
else:
self.logger.debug(
Expand All @@ -712,33 +735,34 @@ def _get_nodes_by_traversal(self, data: Any, yaml_path: YAMLPath,
parentref=parentref, traverse_lists=False
):
self.logger.debug(
"Yielding filtered DIRECT node at {}:".format(parentref),
"Yielding filtered DIRECT node at parentref {} of coord:"
.format(parentref),
prefix="Processor::_get_nodes_by_traversal: ",
data=node_coord.node)
data=node_coord)
yield NodeCoords(data, parent, parentref)

# Then, recurse into each child to perform the same test.
if isinstance(data, dict):
for key, val in data.items():
self.logger.debug(
"Processor::_get_nodes_by_traversal: Recursing into"
" KEY {} at {} for next-segment matches..."
" KEY '{}' at ref '{}' for next-segment matches..."
.format(key, parentref))
for node_coord in self._get_nodes_by_traversal(
val, yaml_path, segment_index,
parent=data, parentref=key
):
self.logger.debug(
"Yielding filtered indirect Hash value from KEY {}"
" at {}:".format(key, parentref),
"Yielding filtered indirect Hash value from KEY"
" '{}' at ref '{}':".format(key, parentref),
prefix="Processor::_get_nodes_by_traversal: ",
data=node_coord.node)
yield node_coord
elif isinstance(data, list):
for idx, ele in enumerate(data):
self.logger.debug(
"Processor::_get_nodes_by_traversal: Recursing into"
" INDEX {} at {} for next-segment matches..."
" INDEX '{}' at ref '{}' for next-segment matches..."
.format(idx, parentref))
for node_coord in self._get_nodes_by_traversal(
ele, yaml_path, segment_index,
Expand All @@ -748,7 +772,7 @@ def _get_nodes_by_traversal(self, data: Any, yaml_path: YAMLPath,
"Yielding filtered indirect Array value from INDEX"
" {} at {}:".format(idx, parentref),
prefix="Processor::_get_nodes_by_traversal: ",
data=node_coord.node)
data=node_coord)
yield node_coord

def _get_required_nodes(self, data: Any, yaml_path: YAMLPath,
Expand Down Expand Up @@ -820,7 +844,7 @@ def _get_required_nodes(self, data: Any, yaml_path: YAMLPath,
.format(type(subnode_coord.node),
subnode_coord.parentref),
prefix="Processor::_get_required_nodes: ",
data=subnode_coord.node, footer=" ")
data=subnode_coord, footer=" ")
yield subnode_coord
else:
self.logger.debug(
Expand Down

0 comments on commit 31e825e

Please sign in to comment.