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 7b183071a3 Fix Slack Connections created in the UI (#26845)
7b183071a3 is described below
commit 7b183071a398cbe340853f357bc6c029d551b4d1
Author: Andrey Anshin <[email protected]>
AuthorDate: Mon Oct 3 20:26:41 2022 +0400
Fix Slack Connections created in the UI (#26845)
---
airflow/providers/slack/hooks/slack.py | 2 ++
airflow/providers/slack/hooks/slack_webhook.py | 2 ++
airflow/providers/slack/utils/__init__.py | 7 ++++++-
tests/providers/slack/utils/test_utils.py | 23 +++++++++++++++++++++++
4 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/airflow/providers/slack/hooks/slack.py
b/airflow/providers/slack/hooks/slack.py
index 60d6ce78a9..7b145cfcc5 100644
--- a/airflow/providers/slack/hooks/slack.py
+++ b/airflow/providers/slack/hooks/slack.py
@@ -293,11 +293,13 @@ class SlackHook(BaseHook):
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget
from flask_babel import lazy_gettext
from wtforms import IntegerField, StringField
+ from wtforms.validators import NumberRange, Optional
return {
prefixed_extra_field("timeout", cls.conn_type): IntegerField(
lazy_gettext("Timeout"),
widget=BS3TextFieldWidget(),
+ validators=[Optional(strip_whitespace=True),
NumberRange(min=1)],
description="Optional. The maximum number of seconds the
client will wait to connect "
"and receive a response from Slack API.",
),
diff --git a/airflow/providers/slack/hooks/slack_webhook.py
b/airflow/providers/slack/hooks/slack_webhook.py
index d6659da381..a929ef6c25 100644
--- a/airflow/providers/slack/hooks/slack_webhook.py
+++ b/airflow/providers/slack/hooks/slack_webhook.py
@@ -420,11 +420,13 @@ class SlackWebhookHook(BaseHook):
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget
from flask_babel import lazy_gettext
from wtforms import IntegerField, StringField
+ from wtforms.validators import NumberRange, Optional
return {
prefixed_extra_field("timeout", cls.conn_type): IntegerField(
lazy_gettext("Timeout"),
widget=BS3TextFieldWidget(),
+ validators=[Optional(), NumberRange(min=1)],
description="Optional. The maximum number of seconds the
client will wait to connect "
"and receive a response from Slack Incoming Webhook.",
),
diff --git a/airflow/providers/slack/utils/__init__.py
b/airflow/providers/slack/utils/__init__.py
index bfb9478ab3..6ae8143c87 100644
--- a/airflow/providers/slack/utils/__init__.py
+++ b/airflow/providers/slack/utils/__init__.py
@@ -54,7 +54,12 @@ class ConnectionExtraConfig:
:param default: If specified then use as default value if field not
present in Connection Extra.
"""
prefixed_field = prefixed_extra_field(field, self.conn_type)
- if prefixed_field in self.extra:
+ if prefixed_field in self.extra and self.extra[prefixed_field] not in
(None, ""):
+ # Addition validation with non-empty required for connection which
created in the UI
+ # in Airflow 2.2. In these connections always present key-value
pair for all prefixed extras
+ # even if user do not fill this fields.
+ # In additional fields from `wtforms.IntegerField` might contain
None value.
+ # E.g.: `{'extra__slackwebhook__proxy': '',
'extra__slackwebhook__timeout': None}`
return self.extra[prefixed_field]
elif field in self.extra:
return self.extra[field]
diff --git a/tests/providers/slack/utils/test_utils.py
b/tests/providers/slack/utils/test_utils.py
index eb45ac2f6e..33eebef0e4 100644
--- a/tests/providers/slack/utils/test_utils.py
+++ b/tests/providers/slack/utils/test_utils.py
@@ -59,6 +59,29 @@ class TestConnectionExtra:
)
assert extra_config.get("arg1") == "bar"
+ @pytest.mark.parametrize("conn_type", ["slack", "slack_incoming_webhook"])
+ @pytest.mark.parametrize("empty_value", [None, ""])
+ def test_prefixed_extra_created_in_ui_connections(self, conn_type,
empty_value):
+ """Test that empty strings or None values in UI ignored."""
+ extra_config = ConnectionExtraConfig(
+ conn_type=conn_type,
+ conn_id="test-conn-id",
+ extra={
+ f"extra__{conn_type}__arg_missing": empty_value,
+ "arg_extra": "bar",
+ f"extra__{conn_type}__arg_extra": empty_value,
+ },
+ )
+ error_message = (
+ r"Couldn't find '.*' or '.*' in Connection \('.*'\) Extra and no
default value specified\."
+ )
+ with pytest.raises(KeyError, match=error_message):
+ # No fallback should raise an error
+ extra_config.get("arg_missing")
+
+ assert extra_config.get("arg_missing", default="foo") == "foo"
+ assert extra_config.get("arg_extra") == "bar"
+
def test_get_parse_int(self):
extra_config = ConnectionExtraConfig(
conn_type="slack",