Skip to content

Commit

Permalink
Merge pull request #69 from wwkimball/development
Browse files Browse the repository at this point in the history
Prepare release 2.4.3
  • Loading branch information
wwkimball authored Oct 2, 2020
2 parents b4962fd + 96fc0c0 commit 07bea79
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 25 deletions.
9 changes: 9 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
2.4.3:
Bug Fixes:
* Array-of-Hashes were not being detected for the purpose of applying merge
rules defined via the INI-style configuration file.
* Array-of-Hashes identity key inference was looking first to the LHS document.
This was backwards for an RHS-to-LHS merge and has been corrected.

The yaml-merge command now reports version 0.0.4 to reflect these changes.

2.4.2:
Enhancements:
* In the INI file's [rules] section, different merge rules can now be applied
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ for other projects to readily employ YAML Paths.
2. [Get a YAML Value](#get-a-yaml-value)
3. [Search For YAML Paths](#search-for-yaml-paths)
4. [Change a YAML Value](#change-a-yaml-value)
5. [Merge YAML/Compatible Files](#merge-yaml-compatible-files)
5. [Merge YAML/Compatible Files](#merge-yamlcompatible-files)
2. [Basic Usage: Libraries](#basic-usage--libraries)
1. [Initialize ruamel.yaml and These Helpers](#initialize-ruamelyaml-and-these-helpers)
2. [Searching for YAML Nodes](#searching-for-yaml-nodes)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="yamlpath",
version="2.4.2",
version="2.4.3",
description="Read and change YAML/Compatible data using powerful, intuitive, command-line friendly syntax",
long_description=long_description,
long_description_content_type="text/markdown",
Expand Down
142 changes: 142 additions & 0 deletions tests/test_merger_merger.py
Original file line number Diff line number Diff line change
Expand Up @@ -2359,3 +2359,145 @@ def test_merge_with_complex_hash_rules(
(os.path.getsize(output_file) == os.path.getsize(merged_yaml))
and (open(output_file,'r').read() == open(merged_yaml,'r').read())
)


def test_merge_with_complex_aoh_rules(
self, quiet_logger, tmp_path, tmp_path_factory
):
config_file = create_temp_yaml_file(tmp_path_factory, """
[rules]
baubles = deep
/coordinates = unique
[keys]
/baubles[name = Whatchamacallit] = sku
""")
lhs_yaml_file = create_temp_yaml_file(tmp_path_factory, """---
baubles:
- name: Doohickey
sku: 0-000-1
price: 4.75
weight: 2.7g
- name: Doodad
sku: 0-000-2
price: 10.5
weight: 5g
- name: Oddball
sku: 0-000-3
price: 25.99
weight: 25kg
coordinates:
- x: 4
y: -2
- x: 1
y: -1
- x: 0
y: 0
lhs_exclusive:
- step: 1
action: echo Hello, lefties of the World!
- step: 2
action: exit 0
""")
rhs1_yaml_file = create_temp_yaml_file(tmp_path_factory, """---
baubles:
- name: Fob
sku: 0-000-4
price: 0.99
weight: 18mg
- name: Doohickey
price: 10.5
- name: Oddball
sku: 0-000-3
description: This ball is odd
coordinates:
- x: 0
y: 0
- x: 1
y: 1
- x: 4
y: 2
rhs_exclusive:
- step: 1
action: echo Hello, righties of the World!
- step: 2
action: exit 0
""")
rhs2_yaml_file = create_temp_yaml_file(tmp_path_factory, """---
baubles:
- name: Whatchamacallit
sku: 0-000-1
""")
merged_yaml = create_temp_yaml_file(tmp_path_factory, """---
baubles:
- name: Whatchamacallit
sku: 0-000-1
price: 10.5
weight: 2.7g
- name: Doodad
sku: 0-000-2
price: 10.5
weight: 5g
- name: Oddball
sku: 0-000-3
price: 25.99
weight: 25kg
description: This ball is odd
- name: Fob
sku: 0-000-4
price: 0.99
weight: 18mg
coordinates:
- x: 4
y: -2
- x: 1
y: -1
- x: 0
y: 0
- x: 1
y: 1
- x: 4
y: 2
lhs_exclusive:
- step: 1
action: echo Hello, lefties of the World!
- step: 2
action: exit 0
rhs_exclusive:
- step: 1
action: echo Hello, righties of the World!
- step: 2
action: exit 0
""")

output_dir = tmp_path / "test_merge_with_complex_aoh_rules"
output_dir.mkdir()
output_file = output_dir / "output.yaml"

lhs_yaml = get_yaml_editor()
rhs1_yaml = get_yaml_editor()
rhs2_yaml = get_yaml_editor()
lhs_data = get_yaml_data(lhs_yaml, quiet_logger, lhs_yaml_file)
rhs1_data = get_yaml_data(rhs1_yaml, quiet_logger, rhs1_yaml_file)
rhs2_data = get_yaml_data(rhs2_yaml, quiet_logger, rhs2_yaml_file)

args = SimpleNamespace(config=config_file)
mc = MergerConfig(quiet_logger, args)
merger = Merger(quiet_logger, lhs_data, mc)
merger.merge_with(rhs1_data)
merger.merge_with(rhs2_data)

with open(output_file, 'w') as yaml_dump:
lhs_yaml.dump(merger.data, yaml_dump)

# DEBUG:
# with open(output_file, 'r') as output_fnd, open(merged_yaml, 'r') as merged_fnd:
# print("Expected:")
# print(merged_fnd.read())
# print("Got:")
# print(output_fnd.read())

assert (
(os.path.getsize(output_file) == os.path.getsize(merged_yaml))
and (open(output_file,'r').read() == open(merged_yaml,'r').read())
)
2 changes: 1 addition & 1 deletion yamlpath/commands/yaml_merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from yamlpath.wrappers import ConsolePrinter

# Implied Constants
MY_VERSION = "0.0.3"
MY_VERSION = "0.0.4"

def processcli():
"""Process command-line arguments."""
Expand Down
39 changes: 17 additions & 22 deletions yamlpath/merger/merger.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,19 +84,26 @@ def _merge_dicts(

# Short-circuit the deep merge if a different merge rule
# applies to this node.
merge_mode = self.config.hash_merge_mode(
NodeCoords(val, rhs, key))
if merge_mode is HashMergeOpts.LEFT:
node_coord = NodeCoords(val, rhs, key)
merge_mode = (
self.config.hash_merge_mode(node_coord)
if isinstance(val, CommentedMap)
else self.config.aoh_merge_mode(node_coord)
)
self.logger.debug("Merger::_merge_dicts: Got merge mode, {}."
.format(merge_mode))
if merge_mode in (HashMergeOpts.LEFT, AoHMergeOpts.LEFT):
continue
if merge_mode is HashMergeOpts.RIGHT:
if merge_mode in (HashMergeOpts.RIGHT, AoHMergeOpts.RIGHT):
lhs[key] = val
continue

if isinstance(val, CommentedMap):
lhs[key] = self._merge_dicts(lhs[key], val, path_next)
Merger.combine_merge_anchors(lhs[key], val)
elif isinstance(val, CommentedSeq):
lhs[key] = self._merge_lists(lhs[key], val, path_next)
lhs[key] = self._merge_lists(
lhs[key], val, path_next, parent=rhs, parentref=key)
else:
lhs[key] = val
else:
Expand Down Expand Up @@ -193,34 +200,22 @@ def _merge_arrays_of_hashes(
"Merger::_merge_arrays_of_hashes: Merging {} Hash(es) at {}."
.format(len(rhs), path))

merge_mode = self.config.aoh_merge_mode(node_coord)
if merge_mode is AoHMergeOpts.LEFT:
return lhs
if merge_mode is AoHMergeOpts.RIGHT:
return rhs

id_key: str = ""
if len(lhs) > 0 and isinstance(lhs[0], CommentedMap):
if len(rhs) > 0 and isinstance(rhs[0], CommentedMap):
id_key = self.config.aoh_merge_key(
NodeCoords(lhs[0], lhs, 0), lhs[0])
NodeCoords(rhs[0], rhs, 0), rhs[0])
self.logger.debug(
"Merger::_merge_arrays_of_hashes: LHS AoH yielded id_key:"
"Merger::_merge_arrays_of_hashes: RHS AoH yielded id_key:"
" {}.".format(id_key))

merge_mode = self.config.aoh_merge_mode(node_coord)
for idx, ele in enumerate(rhs):
path_next = YAMLPath(path).append("[{}]".format(idx))
node_next = NodeCoords(ele, rhs, idx)
self.logger.debug(
"Merger::_merge_arrays_of_hashes: Processing element {} {}"
" at {}.".format(ele, type(ele), path_next))

if merge_mode is AoHMergeOpts.DEEP:
if not id_key:
id_key = self.config.aoh_merge_key(node_next, ele)
self.logger.debug(
"Merger::_merge_arrays_of_hashes: RHS AoH yielded"
" id_key: {}.".format(id_key))

if id_key in ele:
id_val = ele[id_key]
else:
Expand Down Expand Up @@ -264,7 +259,7 @@ def _merge_lists(
Parameters:
1. lhs (CommentedSeq) The list to merge into.
2. rhs (CommentedSeq) The list to merge from.
3. path (YAMLPath) Location of the `rsh` source list within its DOM.
3. path (YAMLPath) Location of the `rhs` source list within its DOM.
Keyword Parameters:
* parent (Any) Parent node of `rhs`
Expand Down

0 comments on commit 07bea79

Please sign in to comment.