From 40a675543fb98eb6b9987bdd438b40c04c68ff68 Mon Sep 17 00:00:00 2001 From: Matt Davis <6775756+nitzmahone@users.noreply.github.com> Date: Thu, 29 May 2025 09:50:01 -0700 Subject: [PATCH] fix from_yaml_all filter inconsistent None handling (#85223) * fix from_yaml_all filter inconsistent None handling * always returns empty list for None or empty string input * deprecate non-string inputs for from_yaml and from_yaml_all (cherry picked from commit 356bf336bdd7741bd9044abe33d7e71ea13d276f) --- changelogs/fragments/from_yaml_all.yml | 2 ++ lib/ansible/plugins/filter/core.py | 10 ++++++++++ test/integration/targets/filter_core/tasks/main.yml | 2 ++ 3 files changed, 14 insertions(+) create mode 100644 changelogs/fragments/from_yaml_all.yml diff --git a/changelogs/fragments/from_yaml_all.yml b/changelogs/fragments/from_yaml_all.yml new file mode 100644 index 00000000000..2e65c15961b --- /dev/null +++ b/changelogs/fragments/from_yaml_all.yml @@ -0,0 +1,2 @@ +bugfixes: + - from_yaml_all filter - `None` and empty string inputs now always return an empty list. Previously, `None` was returned in Jinja native mode and empty list in classic mode. diff --git a/lib/ansible/plugins/filter/core.py b/lib/ansible/plugins/filter/core.py index e28fadadfab..6afd3045fd7 100644 --- a/lib/ansible/plugins/filter/core.py +++ b/lib/ansible/plugins/filter/core.py @@ -247,20 +247,30 @@ def regex_escape(string, re_type='python'): def from_yaml(data): + if data is None: + return None + if isinstance(data, string_types): # The ``text_type`` call here strips any custom # string wrapper class, so that CSafeLoader can # read the data return yaml_load(text_type(to_text(data, errors='surrogate_or_strict'))) + + display.deprecated(f"The from_yaml filter ignored non-string input of type {native_type_name(data)!r}.", version='2.23', obj=data) return data def from_yaml_all(data): + if data is None: + return [] # backward compatibility; ensure consistent result between classic/native Jinja for None/empty string input + if isinstance(data, string_types): # The ``text_type`` call here strips any custom # string wrapper class, so that CSafeLoader can # read the data return yaml_load_all(text_type(to_text(data, errors='surrogate_or_strict'))) + + display.deprecated(f"The from_yaml_all filter ignored non-string input of type {native_type_name(data)!r}.", version='2.23', obj=data) return data diff --git a/test/integration/targets/filter_core/tasks/main.yml b/test/integration/targets/filter_core/tasks/main.yml index 7e82ab4b4e9..7d7590ecea7 100644 --- a/test/integration/targets/filter_core/tasks/main.yml +++ b/test/integration/targets/filter_core/tasks/main.yml @@ -471,6 +471,8 @@ - "2|from_yaml_all == 2" - "unsafe_fruit|from_yaml == {'bananas': 'yellow', 'apples': 'red'}" - "unsafe_fruit_all|from_yaml_all|list == [{'bananas': 'yellow'}, {'apples': 'red'}]" + - None | from_yaml is none + - None | from_yaml_all == [] vars: unsafe_fruit: !unsafe | ---