This is an automated email from the ASF dual-hosted git repository.
shahar1 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 8a4984e30d7 Mark Snowflake connection form `Proxy Port` field optional
(#65444)
8a4984e30d7 is described below
commit 8a4984e30d71ea2fee099def7ed62749f58cfacc
Author: Nikhil Gupta <[email protected]>
AuthorDate: Wed Apr 22 20:40:43 2026 +0530
Mark Snowflake connection form `Proxy Port` field optional (#65444)
---
.../airflow/providers/snowflake/hooks/snowflake.py | 7 ++++-
.../tests/unit/snowflake/hooks/test_snowflake.py | 34 ++++++++++++++++++++++
2 files changed, 40 insertions(+), 1 deletion(-)
diff --git
a/providers/snowflake/src/airflow/providers/snowflake/hooks/snowflake.py
b/providers/snowflake/src/airflow/providers/snowflake/hooks/snowflake.py
index c69f2435581..1f9d1b0c5b9 100644
--- a/providers/snowflake/src/airflow/providers/snowflake/hooks/snowflake.py
+++ b/providers/snowflake/src/airflow/providers/snowflake/hooks/snowflake.py
@@ -138,6 +138,7 @@ class SnowflakeHook(DbApiHook):
)
from flask_babel import lazy_gettext
from wtforms import BooleanField, IntegerField, PasswordField,
StringField
+ from wtforms.validators import Optional
return {
"account": StringField(lazy_gettext("Account"),
widget=BS3TextFieldWidget()),
@@ -153,7 +154,11 @@ class SnowflakeHook(DbApiHook):
label=lazy_gettext("Insecure mode"), description="Turns off
OCSP certificate checks"
),
"proxy_host": StringField(lazy_gettext("Proxy Host"),
widget=BS3TextFieldWidget()),
- "proxy_port": IntegerField(lazy_gettext("Proxy Port")),
+ "proxy_port": IntegerField(
+ lazy_gettext("Proxy Port"),
+ widget=BS3TextFieldWidget(),
+ validators=[Optional()],
+ ),
"proxy_user": StringField(lazy_gettext("Proxy User"),
widget=BS3TextFieldWidget()),
"proxy_password": PasswordField(lazy_gettext("Proxy Password"),
widget=BS3PasswordFieldWidget()),
}
diff --git a/providers/snowflake/tests/unit/snowflake/hooks/test_snowflake.py
b/providers/snowflake/tests/unit/snowflake/hooks/test_snowflake.py
index 5e59a282b37..111a79d7021 100644
--- a/providers/snowflake/tests/unit/snowflake/hooks/test_snowflake.py
+++ b/providers/snowflake/tests/unit/snowflake/hooks/test_snowflake.py
@@ -1787,3 +1787,37 @@ class TestPytestSnowflakeHook:
# Check that the URI doesn't contain proxy params
called_uri = mock_create_engine.call_args[0][0]
assert "proxy_host" not in str(called_uri)
+
+ def test_get_connection_form_widgets_proxy_port_is_optional(self):
+ """Proxy Port is an IntegerField and must remain optional.
+
+ Regression test for the Snowflake connection form silently rejecting
+ save when `Proxy Port` is left blank. `IntegerField` fails WTForms
+ validation on empty input by default, so `Optional()` is required to
+ preserve the documented optional semantics.
+ """
+ pytest.importorskip("flask_appbuilder")
+ pytest.importorskip("flask_babel")
+ Form = pytest.importorskip("wtforms").Form
+ Optional = pytest.importorskip("wtforms.validators").Optional
+ MultiDict = pytest.importorskip("werkzeug.datastructures").MultiDict
+
+ widgets = SnowflakeHook.get_connection_form_widgets()
+ assert "proxy_port" in widgets
+
+ proxy_port_field = widgets["proxy_port"]
+ assert any(isinstance(v, Optional) for v in
proxy_port_field.kwargs.get("validators", []))
+
+ form_cls = type("_SnowflakeConnForm", (Form,), dict(widgets))
+
+ empty_form = form_cls(MultiDict([("proxy_port", "")]))
+ assert empty_form.validate() is True, empty_form.errors
+ assert empty_form.proxy_port.data is None
+
+ populated_form = form_cls(MultiDict([("proxy_port", "8080")]))
+ assert populated_form.validate() is True, populated_form.errors
+ assert populated_form.proxy_port.data == 8080
+
+ invalid_form = form_cls(MultiDict([("proxy_port", "not-an-int")]))
+ assert invalid_form.validate() is False
+ assert "proxy_port" in invalid_form.errors