-
Notifications
You must be signed in to change notification settings - Fork 16.4k
Allow and prefer non-prefixed extra fields for AsanaHook #27043
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9795a38
052316a
41e2867
20213c4
e367f41
4ed5a5d
ba5edb4
56a79a6
4b7c26a
fad673b
3540690
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ | |
| """Connect to Asana.""" | ||
| from __future__ import annotations | ||
|
|
||
| from functools import wraps | ||
| from typing import Any | ||
|
|
||
| from asana import Client # type: ignore[attr-defined] | ||
|
|
@@ -27,6 +28,34 @@ | |
| from airflow.hooks.base import BaseHook | ||
|
|
||
|
|
||
| def _ensure_prefixes(conn_type): | ||
| """ | ||
| Remove when provider min airflow version >= 2.5.0 since this is handled by | ||
| provider manager from that version. | ||
| """ | ||
|
|
||
| def dec(func): | ||
| @wraps(func) | ||
| def inner(): | ||
| field_behaviors = func() | ||
| conn_attrs = {'host', 'schema', 'login', 'password', 'port', 'extra'} | ||
|
|
||
| def _ensure_prefix(field): | ||
| if field not in conn_attrs and not field.startswith('extra__'): | ||
| return f"extra__{conn_type}__{field}" | ||
| else: | ||
| return field | ||
|
|
||
| if 'placeholders' in field_behaviors: | ||
| placeholders = field_behaviors['placeholders'] | ||
| field_behaviors['placeholders'] = {_ensure_prefix(k): v for k, v in placeholders.items()} | ||
| return field_behaviors | ||
|
|
||
| return inner | ||
|
|
||
| return dec | ||
|
|
||
|
|
||
| class AsanaHook(BaseHook): | ||
| """Wrapper around Asana Python client library.""" | ||
|
|
||
|
|
@@ -39,8 +68,21 @@ def __init__(self, conn_id: str = default_conn_name, *args, **kwargs) -> None: | |
| super().__init__(*args, **kwargs) | ||
| self.connection = self.get_connection(conn_id) | ||
| extras = self.connection.extra_dejson | ||
| self.workspace = extras.get("extra__asana__workspace") or None | ||
| self.project = extras.get("extra__asana__project") or None | ||
| self.workspace = self._get_field(extras, "workspace") or None | ||
| self.project = self._get_field(extras, "project") or None | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly here, maybe _get_field should live in BaseHook? It would make the future cleanup easier.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah i considered that, and it is appealing, but I reasoned that it's not practical because there are frequently subtleties to the way that these params are gotten, idiosyncrasies that require little differences from one provider to another. some of them are done in the same way, but some not. and, it's just backcompat so, do we really want to add a new method to base hook for deprecated backcompat? further, even if we did add this to base hook now, we would not be able to use it until provider min version has this method (which would be a while). alternatively, eventually we could either standardize with appropriate deprecation signaling and make the breaking change for the ones that handle it differently. another option is we could just get rid of the backcompat altogether, but this would force a lot of users to change their connections, and i don't think we should because of the negative experience for users.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nah, you're right. The big one to me is that basehook would mean waiting for airflow core to update so the providers can inherit it. If you do it this way, it's a little more work but it's "immediate" and self-contained. I think you made the right call even if it means some redundant code. |
||
| def _get_field(self, extras: dict, field_name: str): | ||
| """Get field from extra, first checking short name, then for backcompat we check for prefixed name.""" | ||
| backcompat_prefix = "extra__asana__" | ||
| if field_name.startswith('extra__'): | ||
| raise ValueError( | ||
| f"Got prefixed name {field_name}; please remove the '{backcompat_prefix}' prefix " | ||
| "when using this method." | ||
| ) | ||
| if field_name in extras: | ||
| return extras[field_name] or None | ||
| prefixed_name = f"{backcompat_prefix}{field_name}" | ||
| return extras.get(prefixed_name) or None | ||
|
|
||
| def get_conn(self) -> Client: | ||
| return self.client | ||
|
|
@@ -53,20 +95,21 @@ def get_connection_form_widgets() -> dict[str, Any]: | |
| from wtforms import StringField | ||
|
|
||
| return { | ||
| "extra__asana__workspace": StringField(lazy_gettext("Workspace"), widget=BS3TextFieldWidget()), | ||
| "extra__asana__project": StringField(lazy_gettext("Project"), widget=BS3TextFieldWidget()), | ||
| "workspace": StringField(lazy_gettext("Workspace"), widget=BS3TextFieldWidget()), | ||
| "project": StringField(lazy_gettext("Project"), widget=BS3TextFieldWidget()), | ||
| } | ||
|
|
||
| @staticmethod | ||
| @_ensure_prefixes(conn_type='asana') | ||
| def get_ui_field_behaviour() -> dict[str, Any]: | ||
| """Returns custom field behaviour""" | ||
| return { | ||
| "hidden_fields": ["port", "host", "login", "schema"], | ||
| "relabeling": {}, | ||
| "placeholders": { | ||
| "password": "Asana personal access token", | ||
| "extra__asana__workspace": "Asana workspace gid", | ||
| "extra__asana__project": "Asana project gid", | ||
| "workspace": "Asana workspace gid", | ||
| "project": "Asana project gid", | ||
| }, | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to say that this is the second time I see you using this and it should maybe live in airflow.hooks.base as a shared helper method. Is there a reason not to do it that way?