This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch v3-1-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v3-1-test by this push:
new 2ffe48384d5 [v3-1-test] Fix config list output for multi-line values
(#58115) (#58378)
2ffe48384d5 is described below
commit 2ffe48384d521caf1a9fba58aaf213e5f952fc64
Author: Jarek Potiuk <[email protected]>
AuthorDate: Sun Nov 16 23:43:01 2025 +0100
[v3-1-test] Fix config list output for multi-line values (#58115) (#58378)
Closes: #57355
When a user runs `airflow config list --include-descriptions
--include-examples`,
multi-line values (like `dag_bundle_config_list`) would cause a
`configparser.ParsingError` due to improper indentation.
This fix pretty-prints the JSON value using `json.dumps(indent=4)`
and then adds an additional four-space indent to each new line.
This ensures the INI parser treats the entire block as a
single, valid multi-line value.
(cherry picked from commit d009b6467544e657245f14543dcc6dd11046fcb1)
Co-authored-by: Aaron Chen <[email protected]>
---
airflow-core/src/airflow/configuration.py | 8 ++++
airflow-core/tests/unit/core/test_configuration.py | 46 ++++++++++++++++++++++
2 files changed, 54 insertions(+)
diff --git a/airflow-core/src/airflow/configuration.py
b/airflow-core/src/airflow/configuration.py
index 1bfbbcf62b4..361b5765fd4 100644
--- a/airflow-core/src/airflow/configuration.py
+++ b/airflow-core/src/airflow/configuration.py
@@ -589,6 +589,14 @@ class AirflowConfigParser(ConfigParser):
value = "\n# ".join(value_lines)
file.write(f"# {option} = {value}\n")
else:
+ if "\n" in value:
+ try:
+ value = json.dumps(json.loads(value), indent=4)
+ value = value.replace(
+ "\n", "\n "
+ ) # indent multi-line JSON to satisfy configparser
format
+ except JSONDecodeError:
+ pass
file.write(f"{option} = {value}\n")
if needs_separation:
file.write("\n")
diff --git a/airflow-core/tests/unit/core/test_configuration.py
b/airflow-core/tests/unit/core/test_configuration.py
index 0735245f509..bcce279d086 100644
--- a/airflow-core/tests/unit/core/test_configuration.py
+++ b/airflow-core/tests/unit/core/test_configuration.py
@@ -1028,6 +1028,52 @@ key7 =
for key, value in expected_backend_kwargs.items():
assert getattr(secrets_backend, key) == value
+ def test_write_pretty_prints_multiline_json(self):
+ """
+ Tests that the `write` method correctly pretty-prints
+ a config value that is a valid multi-line JSON string.
+ """
+ json_string = '[\n{\n"name": "dags-folder",\n"classpath":
"test.class"\n}\n]'
+
+ test_conf = AirflowConfigParser()
+ test_conf.add_section("test_json")
+ test_conf.set("test_json", "my_json_config", json_string)
+
+ with StringIO() as string_file:
+ test_conf.write(string_file, include_descriptions=False,
include_env_vars=False)
+ content = string_file.getvalue()
+
+ expected_formatted_string = (
+ "my_json_config = [\n"
+ " {\n"
+ ' "name": "dags-folder",\n'
+ ' "classpath": "test.class"\n'
+ " }\n"
+ " ]\n"
+ )
+
+ assert expected_formatted_string in content
+ assert json_string not in content
+
+ def test_write_handles_multiline_non_json_string(self):
+ """
+ Tests that `write` does not crash when encountering a multi-line string
+ that is NOT valid JSON.
+ """
+ multiline_string = "This is the first line.\nThis is the second line."
+
+ test_conf = AirflowConfigParser()
+ test_conf.add_section("test_multiline")
+ test_conf.set("test_multiline", "my_string_config", multiline_string)
+
+ with StringIO() as string_file:
+ test_conf.write(string_file, include_descriptions=False,
include_env_vars=False)
+ content = string_file.getvalue()
+
+ expected_raw_output = "my_string_config = This is the first
line.\nThis is the second line.\n"
+
+ assert expected_raw_output in content
+
@mock.patch.dict(
"os.environ",