This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new dda8d278671 Fix `airflowctl connections import` failure when JSON
omits `extra` field (#62662)
dda8d278671 is described below
commit dda8d2786710c72791b821f70c8b6f43c19e0b1e
Author: Leondon9 <[email protected]>
AuthorDate: Sun Mar 1 21:02:33 2026 +0000
Fix `airflowctl connections import` failure when JSON omits `extra` field
(#62662)
* Fix `airflowctl connections import` failure when JSON omits `extra` field
When the `extra` key is absent from a connection JSON entry, the default
value `{}` (dict) is incompatible with the `ConnectionBody.extra` field
which expects `str | None`. Removing the default lets `v.get("extra")`
return `None`, matching the model's type annotation.
closes: #62653
Co-Authored-By: claude-flow <[email protected]>
* Add regression test for connection import without extra field
Covers the case where `extra` is omitted from the JSON input,
which caused a Pydantic ValidationError before the fix.
Co-Authored-By: claude-flow <[email protected]>
---------
Co-authored-by: claude-flow <[email protected]>
---
.../airflowctl/ctl/commands/connection_command.py | 2 +-
.../ctl/commands/test_connections_command.py | 51 ++++++++++++++++++++++
2 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/airflow-ctl/src/airflowctl/ctl/commands/connection_command.py
b/airflow-ctl/src/airflowctl/ctl/commands/connection_command.py
index 8a894202206..b689083faa2 100644
--- a/airflow-ctl/src/airflowctl/ctl/commands/connection_command.py
+++ b/airflow-ctl/src/airflowctl/ctl/commands/connection_command.py
@@ -54,7 +54,7 @@ def import_(args, api_client=NEW_API_CLIENT) -> None:
login=v.get("login"),
password=v.get("password"),
port=v.get("port"),
- extra=v.get("extra", {}),
+ extra=v.get("extra"),
description=v.get("description", ""),
)
for k, v in connections_json.items()
diff --git
a/airflow-ctl/tests/airflow_ctl/ctl/commands/test_connections_command.py
b/airflow-ctl/tests/airflow_ctl/ctl/commands/test_connections_command.py
index a63a4b4fa6a..02b56eda99b 100644
--- a/airflow-ctl/tests/airflow_ctl/ctl/commands/test_connections_command.py
+++ b/airflow-ctl/tests/airflow_ctl/ctl/commands/test_connections_command.py
@@ -17,6 +17,7 @@
from __future__ import annotations
import json
+from unittest.mock import patch
import pytest
@@ -24,6 +25,7 @@ from airflowctl.api.client import ClientKind
from airflowctl.api.datamodels.generated import (
BulkActionResponse,
BulkResponse,
+ ConnectionBody,
ConnectionCollectionResponse,
ConnectionResponse,
)
@@ -125,3 +127,52 @@ class TestCliConnectionCommands:
self.parser.parse_args(["connections", "import",
expected_json_path.as_posix()]),
api_client=api_client,
)
+
+ def test_import_without_extra_field(self, api_client_maker, tmp_path,
monkeypatch):
+ """Import succeeds when JSON omits the ``extra`` field (#62653).
+
+ Before the fix, ``v.get("extra", {})`` returned ``{}`` (a dict) when
+ the key was absent, but ``ConnectionBody.extra`` expects ``str |
None``,
+ causing a Pydantic ``ValidationError``.
+ """
+ api_client = api_client_maker(
+ path="/api/v2/connections",
+ response_json=self.bulk_response_success.model_dump(),
+ expected_http_status_code=200,
+ kind=ClientKind.CLI,
+ )
+
+ monkeypatch.chdir(tmp_path)
+ json_path = tmp_path / self.export_file_name
+ # Intentionally omit "extra" (and several other optional keys) to
+ # mirror a minimal real-world connection JSON export.
+ connection_file = {
+ self.connection_id: {
+ "conn_type": "test_type",
+ "host": "test_host",
+ }
+ }
+
+ json_path.write_text(json.dumps(connection_file))
+
+ with patch(
+ "airflowctl.ctl.commands.connection_command.ConnectionBody",
+ wraps=ConnectionBody,
+ ) as mock_body:
+ connection_command.import_(
+ self.parser.parse_args(["connections", "import",
json_path.as_posix()]),
+ api_client=api_client,
+ )
+
+ # Verify that ``extra`` was passed as None (not {} which would fail
+ # Pydantic validation) and all other absent keys default correctly.
+ mock_body.assert_called_once_with(
+ connection_id=self.connection_id,
+ conn_type="test_type",
+ host="test_host",
+ login=None,
+ password=None,
+ port=None,
+ extra=None,
+ description="",
+ )