Skip to content

Commit 8a4984e

Browse files
authored
Mark Snowflake connection form Proxy Port field optional (#65444)
1 parent d59d32a commit 8a4984e

2 files changed

Lines changed: 40 additions & 1 deletion

File tree

providers/snowflake/src/airflow/providers/snowflake/hooks/snowflake.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ def get_connection_form_widgets(cls) -> dict[str, Any]:
138138
)
139139
from flask_babel import lazy_gettext
140140
from wtforms import BooleanField, IntegerField, PasswordField, StringField
141+
from wtforms.validators import Optional
141142

142143
return {
143144
"account": StringField(lazy_gettext("Account"), widget=BS3TextFieldWidget()),
@@ -153,7 +154,11 @@ def get_connection_form_widgets(cls) -> dict[str, Any]:
153154
label=lazy_gettext("Insecure mode"), description="Turns off OCSP certificate checks"
154155
),
155156
"proxy_host": StringField(lazy_gettext("Proxy Host"), widget=BS3TextFieldWidget()),
156-
"proxy_port": IntegerField(lazy_gettext("Proxy Port")),
157+
"proxy_port": IntegerField(
158+
lazy_gettext("Proxy Port"),
159+
widget=BS3TextFieldWidget(),
160+
validators=[Optional()],
161+
),
157162
"proxy_user": StringField(lazy_gettext("Proxy User"), widget=BS3TextFieldWidget()),
158163
"proxy_password": PasswordField(lazy_gettext("Proxy Password"), widget=BS3PasswordFieldWidget()),
159164
}

providers/snowflake/tests/unit/snowflake/hooks/test_snowflake.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1787,3 +1787,37 @@ def test_get_sqlalchemy_engine_with_proxy(self):
17871787
# Check that the URI doesn't contain proxy params
17881788
called_uri = mock_create_engine.call_args[0][0]
17891789
assert "proxy_host" not in str(called_uri)
1790+
1791+
def test_get_connection_form_widgets_proxy_port_is_optional(self):
1792+
"""Proxy Port is an IntegerField and must remain optional.
1793+
1794+
Regression test for the Snowflake connection form silently rejecting
1795+
save when `Proxy Port` is left blank. `IntegerField` fails WTForms
1796+
validation on empty input by default, so `Optional()` is required to
1797+
preserve the documented optional semantics.
1798+
"""
1799+
pytest.importorskip("flask_appbuilder")
1800+
pytest.importorskip("flask_babel")
1801+
Form = pytest.importorskip("wtforms").Form
1802+
Optional = pytest.importorskip("wtforms.validators").Optional
1803+
MultiDict = pytest.importorskip("werkzeug.datastructures").MultiDict
1804+
1805+
widgets = SnowflakeHook.get_connection_form_widgets()
1806+
assert "proxy_port" in widgets
1807+
1808+
proxy_port_field = widgets["proxy_port"]
1809+
assert any(isinstance(v, Optional) for v in proxy_port_field.kwargs.get("validators", []))
1810+
1811+
form_cls = type("_SnowflakeConnForm", (Form,), dict(widgets))
1812+
1813+
empty_form = form_cls(MultiDict([("proxy_port", "")]))
1814+
assert empty_form.validate() is True, empty_form.errors
1815+
assert empty_form.proxy_port.data is None
1816+
1817+
populated_form = form_cls(MultiDict([("proxy_port", "8080")]))
1818+
assert populated_form.validate() is True, populated_form.errors
1819+
assert populated_form.proxy_port.data == 8080
1820+
1821+
invalid_form = form_cls(MultiDict([("proxy_port", "not-an-int")]))
1822+
assert invalid_form.validate() is False
1823+
assert "proxy_port" in invalid_form.errors

0 commit comments

Comments
 (0)