From a3ff18cde3dd700e9f3974dbaf915402aff28816 Mon Sep 17 00:00:00 2001 From: Matt Shin Date: Tue, 1 Apr 2025 20:01:10 +0100 Subject: [PATCH 1/2] Fix include merge empty list process variable Iteration through a list with a merge include becomes incorrect if the number of elements the list changes due to the merge include. --- src/yamlprocessor/dataprocess.py | 18 ++++++++------- src/yamlprocessor/tests/test_dataprocess.py | 25 +++++++++++++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/yamlprocessor/dataprocess.py b/src/yamlprocessor/dataprocess.py index 15ff443..b60b4fd 100755 --- a/src/yamlprocessor/dataprocess.py +++ b/src/yamlprocessor/dataprocess.py @@ -409,17 +409,19 @@ def process_data( item, parent_filenames, variable_map)) if is_merge and type_of_data != type(include_data): raise TypeError() - if is_merge and type_of_data is list: - # For a list, the iterator seems to handle the new items - # perfectly fine. We insert the included list at and after - # the current position. The current item is logically - # replaced by the first item of the inserted list. + if is_merge and type_of_data is list and len(include_data) == 1: + # For a list, if the incoming is a single element list, then + # it can replace the original with no issue. + item = data[key] = include_data[0] + elif is_merge and type_of_data is list: + # For a list, if the incoming is not a single element list, + # the iterator will stop working, so we need to re-process + # the list for correctness. del data[key] - item = None for i, include_item in enumerate(include_data): data.insert(key + i, include_item) - if i == 0: - item = include_item + stack.append([data, parent_filenames, variable_map]) + break elif is_merge and type_of_data is dict: # For a dict, the iterator cannot handle size changes, so # we can only iterate over a copy of the original dict. We diff --git a/src/yamlprocessor/tests/test_dataprocess.py b/src/yamlprocessor/tests/test_dataprocess.py index be54142..d343f6c 100644 --- a/src/yamlprocessor/tests/test_dataprocess.py +++ b/src/yamlprocessor/tests/test_dataprocess.py @@ -460,6 +460,31 @@ def test_main_12(tmp_path, yaml): ] +def test_main_12_1(tmp_path, yaml): + """Test main, merge include file with empty list and variable process. + + Issue 35. + """ + root_data = [ + {'name': '${MATTER}'}, + {'INCLUDE': 'void.yaml', 'MERGE': True}, + {'name': '${MATTER}'}, + ] + void_data = [] + infilename = tmp_path / 'root.yaml' + with infilename.open('w') as infile: + yaml.dump(root_data, infile) + include_infilename = tmp_path / 'void.yaml' + with include_infilename.open('w') as infile: + yaml.dump(void_data, infile) + outfilename = tmp_path / 'b.yaml' + main(['--define=MATTER=stuff', str(infilename), str(outfilename)]) + assert yaml.load(outfilename.open()) == [ + {'name': 'stuff'}, + {'name': 'stuff'}, + ] + + def test_main_13(tmp_path, yaml): """Test main, merge include files into a map/object.""" root_data = { From 9a74831a94a3ae1799ad63b4358daca27f1b2bb5 Mon Sep 17 00:00:00 2001 From: Matt Shin Date: Tue, 1 Apr 2025 20:07:15 +0100 Subject: [PATCH 2/2] Flake8 happiness --- src/yamlprocessor/dataprocess.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/yamlprocessor/dataprocess.py b/src/yamlprocessor/dataprocess.py index b60b4fd..73e71e2 100755 --- a/src/yamlprocessor/dataprocess.py +++ b/src/yamlprocessor/dataprocess.py @@ -409,9 +409,13 @@ def process_data( item, parent_filenames, variable_map)) if is_merge and type_of_data != type(include_data): raise TypeError() - if is_merge and type_of_data is list and len(include_data) == 1: - # For a list, if the incoming is a single element list, then - # it can replace the original with no issue. + if ( + is_merge + and type_of_data is list + and len(include_data) == 1 + ): + # For a list, if the incoming is a single element list, + # then it can replace the original with no issue. item = data[key] = include_data[0] elif is_merge and type_of_data is list: # For a list, if the incoming is not a single element list,