You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by ur...@apache.org on 2024/11/08 08:38:28 UTC
(airflow) branch main updated: Improve ExecutionCallableRunner (#43812)
This is an automated email from the ASF dual-hosted git repository.
uranusjr 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 50aabd2a4d3 Improve ExecutionCallableRunner (#43812)
50aabd2a4d3 is described below
commit 50aabd2a4d320eda5ac9114eecbd714930c790a9
Author: Tzu-ping Chung <ur...@gmail.com>
AuthorDate: Fri Nov 8 16:38:21 2024 +0800
Improve ExecutionCallableRunner (#43812)
---
airflow/utils/operator_helpers.py | 80 ++++++++++++++++++++++-----------------
1 file changed, 46 insertions(+), 34 deletions(-)
diff --git a/airflow/utils/operator_helpers.py b/airflow/utils/operator_helpers.py
index 6e5e03d8d16..a259b455776 100644
--- a/airflow/utils/operator_helpers.py
+++ b/airflow/utils/operator_helpers.py
@@ -17,16 +17,21 @@
# under the License.
from __future__ import annotations
+import inspect
import logging
from datetime import datetime
-from typing import TYPE_CHECKING, Any, Callable, Collection, Mapping, TypeVar
+from typing import TYPE_CHECKING, Any, Callable, Collection, Mapping, Protocol, TypeVar
from airflow import settings
+from airflow.assets.metadata import Metadata
+from airflow.typing_compat import ParamSpec
from airflow.utils.context import Context, lazy_mapping_from_context
+from airflow.utils.types import NOTSET
if TYPE_CHECKING:
from airflow.utils.context import OutletEventAccessors
+P = ParamSpec("P")
R = TypeVar("R")
DEFAULT_FORMAT_PREFIX = "airflow.ctx."
@@ -225,7 +230,17 @@ def make_kwargs_callable(func: Callable[..., R]) -> Callable[..., R]:
return kwargs_func
-class ExecutionCallableRunner:
+class _ExecutionCallableRunner(Protocol):
+ @staticmethod
+ def run(*args, **kwargs): ...
+
+
+def ExecutionCallableRunner(
+ func: Callable[P, R],
+ outlet_events: OutletEventAccessors,
+ *,
+ logger: logging.Logger,
+) -> _ExecutionCallableRunner:
"""
Run an execution callable against a task context and given arguments.
@@ -234,45 +249,42 @@ class ExecutionCallableRunner:
the generator is exhausted here, with the yielded values getting fed back
into the task context automatically for execution.
+ This convoluted implementation of inner class with closure is so *all*
+ arguments passed to ``run()`` can be forwarded to the wrapped function. This
+ is particularly important for the argument "self", which some use cases
+ need to receive. This is not possible if this is implemented as a normal
+ class, where "self" needs to point to the ExecutionCallableRunner object.
+
+ The function name violates PEP 8 due to backward compatibility. This was
+ implemented as a class previously.
+
:meta private:
"""
- def __init__(
- self,
- func: Callable,
- outlet_events: OutletEventAccessors,
- *,
- logger: logging.Logger | None,
- ) -> None:
- self.func = func
- self.outlet_events = outlet_events
- self.logger = logger or logging.getLogger(__name__)
-
- def run(self, *args, **kwargs) -> Any:
- import inspect
-
- from airflow.assets.metadata import Metadata
- from airflow.utils.types import NOTSET
+ class _ExecutionCallableRunnerImpl:
+ @staticmethod
+ def run(*args: P.args, **kwargs: P.kwargs) -> R:
+ if not inspect.isgeneratorfunction(func):
+ return func(*args, **kwargs)
- if not inspect.isgeneratorfunction(self.func):
- return self.func(*args, **kwargs)
+ result: Any = NOTSET
- result: Any = NOTSET
+ def _run():
+ nonlocal result
+ result = yield from func(*args, **kwargs)
- def _run():
- nonlocal result
- result = yield from self.func(*args, **kwargs)
+ for metadata in _run():
+ if isinstance(metadata, Metadata):
+ outlet_events[metadata.uri].extra.update(metadata.extra)
- for metadata in _run():
- if isinstance(metadata, Metadata):
- self.outlet_events[metadata.uri].extra.update(metadata.extra)
+ if metadata.alias_name:
+ outlet_events[metadata.alias_name].add(metadata.uri, extra=metadata.extra)
- if metadata.alias_name:
- self.outlet_events[metadata.alias_name].add(metadata.uri, extra=metadata.extra)
+ continue
+ logger.warning("Ignoring unknown data of %r received from task", type(metadata))
+ if logger.isEnabledFor(logging.DEBUG):
+ logger.debug("Full yielded value: %r", metadata)
- continue
- self.logger.warning("Ignoring unknown data of %r received from task", type(metadata))
- if self.logger.isEnabledFor(logging.DEBUG):
- self.logger.debug("Full yielded value: %r", metadata)
+ return result
- return result
+ return _ExecutionCallableRunnerImpl