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 1089cef51b6 [v3-1-test] Fix/RE:Invalid uri created when extras 
contains non string elements (#59339) (#60219)
1089cef51b6 is described below

commit 1089cef51b65a98b16f9831d968a46bc3f896680
Author: Jarek Potiuk <[email protected]>
AuthorDate: Wed Jan 7 20:03:56 2026 +0100

    [v3-1-test] Fix/RE:Invalid uri created when extras contains non string 
elements (#59339) (#60219)
    
    (cherry picked from commit a377033)
    
    Co-authored-by: Piyush Mudgal <[email protected]>
    Co-authored-by: Pyasma <[email protected]>
---
 airflow-core/src/airflow/models/connection.py     | 18 +++++++++++---
 airflow-core/tests/unit/models/test_connection.py | 30 +++++++++++++++++++++++
 2 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/airflow-core/src/airflow/models/connection.py 
b/airflow-core/src/airflow/models/connection.py
index 1567cab1dd2..167df13c80c 100644
--- a/airflow-core/src/airflow/models/connection.py
+++ b/airflow-core/src/airflow/models/connection.py
@@ -241,6 +241,11 @@ class Connection(Base, LoggingMixin):
             if self.EXTRA_KEY in query:
                 self.extra = query[self.EXTRA_KEY]
             else:
+                for key, value in query.items():
+                    try:
+                        query[key] = json.loads(value)
+                    except (JSONDecodeError, TypeError):
+                        self.log.info("Failed parsing the json for key %s", 
key)
                 self.extra = json.dumps(query)
 
     @staticmethod
@@ -316,15 +321,22 @@ class Connection(Base, LoggingMixin):
         uri += host_block
 
         if self.extra:
+            extra_dict = self.extra_dejson
+            can_flatten = True
+            for value in extra_dict.values():
+                if not isinstance(value, str):
+                    can_flatten = False
+                    break
+
             try:
-                query: str | None = urlencode(self.extra_dejson)
+                query: str | None = urlencode(extra_dict)
             except TypeError:
                 query = None
-            if query and self.extra_dejson == dict(parse_qsl(query, 
keep_blank_values=True)):
+
+            if can_flatten and query and extra_dict == dict(parse_qsl(query, 
keep_blank_values=True)):
                 uri += ("?" if self.schema else "/?") + query
             else:
                 uri += ("?" if self.schema else "/?") + 
urlencode({self.EXTRA_KEY: self.extra})
-
         return uri
 
     def get_password(self) -> str | None:
diff --git a/airflow-core/tests/unit/models/test_connection.py 
b/airflow-core/tests/unit/models/test_connection.py
index 6fdea1b2d05..ba875ad38d4 100644
--- a/airflow-core/tests/unit/models/test_connection.py
+++ b/airflow-core/tests/unit/models/test_connection.py
@@ -129,6 +129,28 @@ class TestConnection:
                 None,
                 r"Invalid connection string: 
type://user:pass@protocol://host:port?param=value.",
             ),
+            (
+                
"type://host?int_param=123&bool_param=true&float_param=1.5&str_param=some_str",
+                "type",
+                "host",
+                None,
+                None,
+                None,
+                "",
+                {"int_param": 123, "bool_param": True, "float_param": 1.5, 
"str_param": "some_str"},
+                None,
+            ),
+            (
+                "type://host?__extra__=%7B%22foo%22%3A+%22bar%22%7D",
+                "type",
+                "host",
+                None,
+                None,
+                None,
+                "",
+                {"foo": "bar"},
+                None,
+            ),
         ],
     )
     def test_parse_from_uri(
@@ -193,6 +215,14 @@ class TestConnection:
                 ),
                 
"type://protocol://user:pass@host:100/schema?param1=val1&param2=val2",
             ),
+            (
+                Connection(
+                    conn_type="type",
+                    host="host",
+                    extra={"bool_param": True, "int_param": 123, 
"float_param": 1.5, "list_param": [1, 2]},
+                ),
+                
"type://host/?__extra__=%7B%22bool_param%22%3A+true%2C+%22int_param%22%3A+123%2C+%22float_param%22%3A+1.5%2C+%22list_param%22%3A+%5B1%2C+2%5D%7D",
+            ),
         ],
     )
     def test_get_uri(self, connection, expected_uri):

Reply via email to