apache-airflow-providers-standard 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of apache-airflow-providers-standard might be problematic. Click here for more details.

Files changed (28) hide show
  1. airflow/providers/standard/LICENSE +253 -0
  2. airflow/providers/standard/__init__.py +39 -0
  3. airflow/providers/standard/get_provider_info.py +95 -0
  4. airflow/providers/standard/hooks/__init__.py +16 -0
  5. airflow/providers/standard/hooks/filesystem.py +89 -0
  6. airflow/providers/standard/hooks/package_index.py +95 -0
  7. airflow/providers/standard/hooks/subprocess.py +119 -0
  8. airflow/providers/standard/operators/__init__.py +16 -0
  9. airflow/providers/standard/operators/bash.py +304 -0
  10. airflow/providers/standard/operators/datetime.py +110 -0
  11. airflow/providers/standard/operators/generic_transfer.py +133 -0
  12. airflow/providers/standard/operators/python.py +1172 -0
  13. airflow/providers/standard/operators/weekday.py +120 -0
  14. airflow/providers/standard/sensors/__init__.py +16 -0
  15. airflow/providers/standard/sensors/bash.py +114 -0
  16. airflow/providers/standard/sensors/date_time.py +152 -0
  17. airflow/providers/standard/sensors/python.py +80 -0
  18. airflow/providers/standard/sensors/time.py +130 -0
  19. airflow/providers/standard/sensors/time_delta.py +134 -0
  20. airflow/providers/standard/sensors/weekday.py +104 -0
  21. airflow/providers/standard/utils/__init__.py +16 -0
  22. airflow/providers/standard/utils/python_virtualenv.py +209 -0
  23. airflow/providers/standard/utils/python_virtualenv_script.jinja2 +101 -0
  24. airflow/providers/standard/utils/version_references.py +26 -0
  25. apache_airflow_providers_standard-0.0.1.dist-info/METADATA +112 -0
  26. apache_airflow_providers_standard-0.0.1.dist-info/RECORD +28 -0
  27. apache_airflow_providers_standard-0.0.1.dist-info/WHEEL +4 -0
  28. apache_airflow_providers_standard-0.0.1.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,134 @@
1
+ #
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ from __future__ import annotations
19
+
20
+ from datetime import timedelta
21
+ from time import sleep
22
+ from typing import TYPE_CHECKING, Any, NoReturn
23
+
24
+ from airflow.configuration import conf
25
+ from airflow.exceptions import AirflowSkipException
26
+ from airflow.providers.standard.utils.version_references import AIRFLOW_V_3_0_PLUS
27
+ from airflow.sensors.base import BaseSensorOperator
28
+ from airflow.triggers.temporal import DateTimeTrigger, TimeDeltaTrigger
29
+ from airflow.utils import timezone
30
+
31
+ if TYPE_CHECKING:
32
+ from airflow.utils.context import Context
33
+
34
+
35
+ class TimeDeltaSensor(BaseSensorOperator):
36
+ """
37
+ Waits for a timedelta after the run's data interval.
38
+
39
+ :param delta: time length to wait after the data interval before succeeding.
40
+
41
+ .. seealso::
42
+ For more information on how to use this sensor, take a look at the guide:
43
+ :ref:`howto/operator:TimeDeltaSensor`
44
+
45
+
46
+ """
47
+
48
+ def __init__(self, *, delta, **kwargs):
49
+ super().__init__(**kwargs)
50
+ self.delta = delta
51
+
52
+ def poke(self, context: Context):
53
+ target_dttm = context["data_interval_end"]
54
+ target_dttm += self.delta
55
+ self.log.info("Checking if the time (%s) has come", target_dttm)
56
+ return timezone.utcnow() > target_dttm
57
+
58
+
59
+ class TimeDeltaSensorAsync(TimeDeltaSensor):
60
+ """
61
+ A deferrable drop-in replacement for TimeDeltaSensor.
62
+
63
+ Will defers itself to avoid taking up a worker slot while it is waiting.
64
+
65
+ :param delta: time length to wait after the data interval before succeeding.
66
+ :param end_from_trigger: End the task directly from the triggerer without going into the worker.
67
+
68
+ .. seealso::
69
+ For more information on how to use this sensor, take a look at the guide:
70
+ :ref:`howto/operator:TimeDeltaSensorAsync`
71
+
72
+ """
73
+
74
+ def __init__(self, *, end_from_trigger: bool = False, delta, **kwargs) -> None:
75
+ super().__init__(delta=delta, **kwargs)
76
+ self.end_from_trigger = end_from_trigger
77
+
78
+ def execute(self, context: Context) -> bool | NoReturn:
79
+ target_dttm = context["data_interval_end"]
80
+ target_dttm += self.delta
81
+ if timezone.utcnow() > target_dttm:
82
+ # If the target datetime is in the past, return immediately
83
+ return True
84
+ try:
85
+ if AIRFLOW_V_3_0_PLUS:
86
+ trigger = DateTimeTrigger(moment=target_dttm, end_from_trigger=self.end_from_trigger)
87
+ else:
88
+ trigger = DateTimeTrigger(moment=target_dttm)
89
+ except (TypeError, ValueError) as e:
90
+ if self.soft_fail:
91
+ raise AirflowSkipException("Skipping due to soft_fail is set to True.") from e
92
+ raise
93
+
94
+ self.defer(trigger=trigger, method_name="execute_complete")
95
+
96
+ def execute_complete(self, context: Context, event: Any = None) -> None:
97
+ """Handle the event when the trigger fires and return immediately."""
98
+ return None
99
+
100
+
101
+ class WaitSensor(BaseSensorOperator):
102
+ """
103
+ A sensor that waits a specified period of time before completing.
104
+
105
+ This differs from TimeDeltaSensor because the time to wait is measured from the start of the task, not
106
+ the data_interval_end of the DAG run.
107
+
108
+ :param time_to_wait: time length to wait after the task starts before succeeding.
109
+ :param deferrable: Run sensor in deferrable mode
110
+ """
111
+
112
+ def __init__(
113
+ self,
114
+ time_to_wait: timedelta | int,
115
+ deferrable: bool = conf.getboolean("operators", "default_deferrable", fallback=False),
116
+ **kwargs,
117
+ ) -> None:
118
+ super().__init__(**kwargs)
119
+ self.deferrable = deferrable
120
+ if isinstance(time_to_wait, int):
121
+ self.time_to_wait = timedelta(minutes=time_to_wait)
122
+ else:
123
+ self.time_to_wait = time_to_wait
124
+
125
+ def execute(self, context: Context) -> None:
126
+ if self.deferrable:
127
+ self.defer(
128
+ trigger=TimeDeltaTrigger(self.time_to_wait, end_from_trigger=True)
129
+ if AIRFLOW_V_3_0_PLUS
130
+ else TimeDeltaTrigger(self.time_to_wait),
131
+ method_name="execute_complete",
132
+ )
133
+ else:
134
+ sleep(int(self.time_to_wait.total_seconds()))
@@ -0,0 +1,104 @@
1
+ #
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ from __future__ import annotations
19
+
20
+ from typing import TYPE_CHECKING, Iterable
21
+
22
+ from airflow.sensors.base import BaseSensorOperator
23
+ from airflow.utils import timezone
24
+ from airflow.utils.weekday import WeekDay
25
+
26
+ if TYPE_CHECKING:
27
+ from airflow.utils.context import Context
28
+
29
+
30
+ class DayOfWeekSensor(BaseSensorOperator):
31
+ """
32
+ Waits until the first specified day of the week.
33
+
34
+ For example, if the execution day of the task is '2018-12-22' (Saturday)
35
+ and you pass 'FRIDAY', the task will wait until next Friday.
36
+
37
+ **Example** (with single day): ::
38
+
39
+ weekend_check = DayOfWeekSensor(
40
+ task_id="weekend_check", week_day="Saturday", use_task_logical_date=True, dag=dag
41
+ )
42
+
43
+ **Example** (with multiple day using set): ::
44
+
45
+ weekend_check = DayOfWeekSensor(
46
+ task_id="weekend_check", week_day={"Saturday", "Sunday"}, use_task_logical_date=True, dag=dag
47
+ )
48
+
49
+ **Example** (with :class:`~airflow.utils.weekday.WeekDay` enum): ::
50
+
51
+ # import WeekDay Enum
52
+ from airflow.utils.weekday import WeekDay
53
+
54
+ weekend_check = DayOfWeekSensor(
55
+ task_id="weekend_check",
56
+ week_day={WeekDay.SATURDAY, WeekDay.SUNDAY},
57
+ use_task_logical_date=True,
58
+ dag=dag,
59
+ )
60
+
61
+ :param week_day: Day of the week to check (full name). Optionally, a set
62
+ of days can also be provided using a set.
63
+ Example values:
64
+
65
+ * ``"MONDAY"``,
66
+ * ``{"Saturday", "Sunday"}``
67
+ * ``{WeekDay.TUESDAY}``
68
+ * ``{WeekDay.SATURDAY, WeekDay.SUNDAY}``
69
+
70
+ To use ``WeekDay`` enum, import it from ``airflow.utils.weekday``
71
+
72
+ :param use_task_logical_date: If ``True``, uses task's logical date to compare
73
+ with week_day. Execution Date is Useful for backfilling.
74
+ If ``False``, uses system's day of the week. Useful when you
75
+ don't want to run anything on weekdays on the system.
76
+
77
+ .. seealso::
78
+ For more information on how to use this sensor, take a look at the guide:
79
+ :ref:`howto/operator:DayOfWeekSensor`
80
+
81
+ """
82
+
83
+ def __init__(
84
+ self,
85
+ *,
86
+ week_day: str | Iterable[str] | WeekDay | Iterable[WeekDay],
87
+ use_task_logical_date: bool = False,
88
+ **kwargs,
89
+ ) -> None:
90
+ super().__init__(**kwargs)
91
+ self.week_day = week_day
92
+ self.use_task_logical_date = use_task_logical_date
93
+ self._week_day_num = WeekDay.validate_week_day(week_day)
94
+
95
+ def poke(self, context: Context) -> bool:
96
+ self.log.info(
97
+ "Poking until weekday is in %s, Today is %s",
98
+ self.week_day,
99
+ WeekDay(timezone.utcnow().isoweekday()).name,
100
+ )
101
+ if self.use_task_logical_date:
102
+ return context["logical_date"].isoweekday() in self._week_day_num
103
+ else:
104
+ return timezone.utcnow().isoweekday() in self._week_day_num
@@ -0,0 +1,16 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
@@ -0,0 +1,209 @@
1
+ #
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ """Utilities for creating a virtual environment."""
19
+
20
+ from __future__ import annotations
21
+
22
+ import os
23
+ import shutil
24
+ import sys
25
+ from pathlib import Path
26
+
27
+ import jinja2
28
+ from jinja2 import select_autoescape
29
+
30
+ from airflow.configuration import conf
31
+ from airflow.utils.process_utils import execute_in_subprocess
32
+
33
+
34
+ def _is_uv_installed() -> bool:
35
+ """
36
+ Verify whether the uv tool is installed by checking if it's included in the system PATH or installed as a package.
37
+
38
+ :return: True if it is. Whichever way of checking it works, is fine.
39
+ """
40
+ return bool(shutil.which("uv"))
41
+
42
+
43
+ def _use_uv() -> bool:
44
+ """
45
+ Check if the uv tool should be used.
46
+
47
+ :return: True if uv should be used.
48
+ """
49
+ venv_install_method = conf.get("standard", "venv_install_method", fallback="auto").lower()
50
+ if venv_install_method == "auto":
51
+ return _is_uv_installed()
52
+ elif venv_install_method == "uv":
53
+ return True
54
+ return False
55
+
56
+
57
+ def _generate_uv_cmd(tmp_dir: str, python_bin: str, system_site_packages: bool) -> list[str]:
58
+ """Build the command to install the venv via UV."""
59
+ cmd = ["uv", "venv", "--allow-existing", "--seed"]
60
+ if python_bin is not None:
61
+ cmd += ["--python", python_bin]
62
+ if system_site_packages:
63
+ cmd.append("--system-site-packages")
64
+ cmd.append(tmp_dir)
65
+ return cmd
66
+
67
+
68
+ def _generate_venv_cmd(tmp_dir: str, python_bin: str, system_site_packages: bool) -> list[str]:
69
+ """We are using venv command instead of venv module to allow creation of venv for different python versions."""
70
+ if python_bin is None:
71
+ python_bin = sys.executable
72
+ cmd = [python_bin, "-m", "venv", tmp_dir]
73
+ if system_site_packages:
74
+ cmd.append("--system-site-packages")
75
+ return cmd
76
+
77
+
78
+ def _generate_uv_install_cmd_from_file(
79
+ tmp_dir: str, requirements_file_path: str, pip_install_options: list[str]
80
+ ) -> list[str]:
81
+ return [
82
+ "uv",
83
+ "pip",
84
+ "install",
85
+ "--python",
86
+ f"{tmp_dir}/bin/python",
87
+ *pip_install_options,
88
+ "-r",
89
+ requirements_file_path,
90
+ ]
91
+
92
+
93
+ def _generate_pip_install_cmd_from_file(
94
+ tmp_dir: str, requirements_file_path: str, pip_install_options: list[str]
95
+ ) -> list[str]:
96
+ return [f"{tmp_dir}/bin/pip", "install", *pip_install_options, "-r", requirements_file_path]
97
+
98
+
99
+ def _generate_uv_install_cmd_from_list(
100
+ tmp_dir: str, requirements: list[str], pip_install_options: list[str]
101
+ ) -> list[str]:
102
+ return ["uv", "pip", "install", "--python", f"{tmp_dir}/bin/python", *pip_install_options, *requirements]
103
+
104
+
105
+ def _generate_pip_install_cmd_from_list(
106
+ tmp_dir: str, requirements: list[str], pip_install_options: list[str]
107
+ ) -> list[str]:
108
+ return [f"{tmp_dir}/bin/pip", "install", *pip_install_options, *requirements]
109
+
110
+
111
+ def _generate_pip_conf(conf_file: Path, index_urls: list[str]) -> None:
112
+ if index_urls:
113
+ pip_conf_options = f"index-url = {index_urls[0]}"
114
+ if len(index_urls) > 1:
115
+ pip_conf_options += f"\nextra-index-url = {' '.join(x for x in index_urls[1:])}"
116
+ else:
117
+ pip_conf_options = "no-index = true"
118
+ conf_file.write_text(f"[global]\n{pip_conf_options}")
119
+
120
+
121
+ def prepare_virtualenv(
122
+ venv_directory: str,
123
+ python_bin: str,
124
+ system_site_packages: bool,
125
+ requirements: list[str] | None = None,
126
+ requirements_file_path: str | None = None,
127
+ pip_install_options: list[str] | None = None,
128
+ index_urls: list[str] | None = None,
129
+ ) -> str:
130
+ """
131
+ Create a virtual environment and install the additional python packages.
132
+
133
+ :param venv_directory: The path for directory where the environment will be created.
134
+ :param python_bin: Path to the Python executable.
135
+ :param system_site_packages: Whether to include system_site_packages in your virtualenv.
136
+ See virtualenv documentation for more information.
137
+ :param requirements: List of additional python packages.
138
+ :param requirements_file_path: Path to the ``requirements.txt`` file.
139
+ :param pip_install_options: a list of pip install options when installing requirements
140
+ See 'pip install -h' for available options
141
+ :param index_urls: an optional list of index urls to load Python packages from.
142
+ If not provided the system pip conf will be used to source packages from.
143
+ :return: Path to a binary file with Python in a virtual environment.
144
+ """
145
+ if pip_install_options is None:
146
+ pip_install_options = []
147
+
148
+ if requirements is not None and requirements_file_path is not None:
149
+ raise ValueError("Either requirements OR requirements_file_path has to be passed, but not both")
150
+
151
+ if index_urls is not None:
152
+ _generate_pip_conf(Path(venv_directory) / "pip.conf", index_urls)
153
+
154
+ if _use_uv():
155
+ venv_cmd = _generate_uv_cmd(venv_directory, python_bin, system_site_packages)
156
+ else:
157
+ venv_cmd = _generate_venv_cmd(venv_directory, python_bin, system_site_packages)
158
+ execute_in_subprocess(venv_cmd)
159
+
160
+ pip_cmd = None
161
+ if requirements is not None and len(requirements) != 0:
162
+ if _use_uv():
163
+ pip_cmd = _generate_uv_install_cmd_from_list(venv_directory, requirements, pip_install_options)
164
+ else:
165
+ pip_cmd = _generate_pip_install_cmd_from_list(venv_directory, requirements, pip_install_options)
166
+ if requirements_file_path is not None and requirements_file_path:
167
+ if _use_uv():
168
+ pip_cmd = _generate_uv_install_cmd_from_file(
169
+ venv_directory, requirements_file_path, pip_install_options
170
+ )
171
+ else:
172
+ pip_cmd = _generate_pip_install_cmd_from_file(
173
+ venv_directory, requirements_file_path, pip_install_options
174
+ )
175
+
176
+ if pip_cmd:
177
+ execute_in_subprocess(pip_cmd)
178
+
179
+ return f"{venv_directory}/bin/python"
180
+
181
+
182
+ def write_python_script(
183
+ jinja_context: dict,
184
+ filename: str,
185
+ render_template_as_native_obj: bool = False,
186
+ ):
187
+ """
188
+ Render the python script to a file to execute in the virtual environment.
189
+
190
+ :param jinja_context: The jinja context variables to unpack and replace with its placeholders in the
191
+ template file.
192
+ :param filename: The name of the file to dump the rendered script to.
193
+ :param render_template_as_native_obj: If ``True``, rendered Jinja template would be converted
194
+ to a native Python object
195
+ """
196
+ template_loader = jinja2.FileSystemLoader(searchpath=os.path.dirname(__file__))
197
+ template_env: jinja2.Environment
198
+ if render_template_as_native_obj:
199
+ template_env = jinja2.nativetypes.NativeEnvironment(
200
+ loader=template_loader, undefined=jinja2.StrictUndefined
201
+ )
202
+ else:
203
+ template_env = jinja2.Environment(
204
+ loader=template_loader,
205
+ undefined=jinja2.StrictUndefined,
206
+ autoescape=select_autoescape(["html", "xml"]),
207
+ )
208
+ template = template_env.get_template("python_virtualenv_script.jinja2")
209
+ template.stream(**jinja_context).dump(filename)
@@ -0,0 +1,101 @@
1
+ {#
2
+ Licensed to the Apache Software Foundation (ASF) under one
3
+ or more contributor license agreements. See the NOTICE file
4
+ distributed with this work for additional information
5
+ regarding copyright ownership. The ASF licenses this file
6
+ to you under the Apache License, Version 2.0 (the
7
+ "License"); you may not use this file except in compliance
8
+ with the License. You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing,
13
+ software distributed under the License is distributed on an
14
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ KIND, either express or implied. See the License for the
16
+ specific language governing permissions and limitations
17
+ under the License.
18
+ -#}
19
+ from __future__ import annotations
20
+
21
+ import {{ pickling_library }}
22
+ import sys
23
+
24
+ {% if expect_airflow %}
25
+ {# Check whether Airflow is available in the environment.
26
+ # If it is, we'll want to ensure that we integrate any macros that are being provided
27
+ # by plugins prior to unpickling the task context. #}
28
+ if sys.version_info >= (3,6):
29
+ try:
30
+ from airflow.plugins_manager import integrate_macros_plugins
31
+ integrate_macros_plugins()
32
+ except ImportError:
33
+ {# Airflow is not available in this environment, therefore we won't
34
+ # be able to integrate any plugin macros. #}
35
+ pass
36
+ {% endif %}
37
+
38
+ # Script
39
+ {{ python_callable_source }}
40
+
41
+ # monkey patching for the cases when python_callable is part of the dag module.
42
+ {% if modified_dag_module_name is defined %}
43
+
44
+ import types
45
+
46
+ {{ modified_dag_module_name }} = types.ModuleType("{{ modified_dag_module_name }}")
47
+
48
+ {{ modified_dag_module_name }}.{{ python_callable }} = {{ python_callable }}
49
+
50
+ sys.modules["{{modified_dag_module_name}}"] = {{modified_dag_module_name}}
51
+
52
+ {% endif%}
53
+
54
+ {% if op_args or op_kwargs %}
55
+ with open(sys.argv[1], "rb") as file:
56
+ arg_dict = {{ pickling_library }}.load(file)
57
+ {% else %}
58
+ arg_dict = {"args": [], "kwargs": {}}
59
+ {% endif %}
60
+
61
+ {% if string_args_global | default(true) -%}
62
+ # Read string args
63
+ with open(sys.argv[3], "r") as file:
64
+ virtualenv_string_args = list(map(lambda x: x.strip(), list(file)))
65
+ {% endif %}
66
+
67
+ {% if use_airflow_context | default(false) -%}
68
+ if len(sys.argv) > 5:
69
+ import json
70
+ from types import ModuleType
71
+
72
+ from airflow.providers.standard.operators import python as airflow_python
73
+ from airflow.serialization.serialized_objects import BaseSerialization
74
+
75
+
76
+ class _MockPython(ModuleType):
77
+ @staticmethod
78
+ def get_current_context():
79
+ with open(sys.argv[5]) as file:
80
+ context = json.load(file)
81
+ return BaseSerialization.deserialize(context, use_pydantic_models=True)
82
+
83
+ def __getattr__(self, name: str):
84
+ return getattr(airflow_python, name)
85
+
86
+
87
+ MockPython = _MockPython("MockPython")
88
+ sys.modules["airflow.providers.standard.operators.python"] = MockPython
89
+ {% endif %}
90
+
91
+ try:
92
+ res = {{ python_callable }}(*arg_dict["args"], **arg_dict["kwargs"])
93
+ except Exception as e:
94
+ with open(sys.argv[4], "w") as file:
95
+ file.write(str(e))
96
+ raise
97
+
98
+ # Write output
99
+ with open(sys.argv[2], "wb") as file:
100
+ if res is not None:
101
+ {{ pickling_library }}.dump(res, file)
@@ -0,0 +1,26 @@
1
+ #
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ from __future__ import annotations
19
+
20
+ from packaging.version import Version
21
+
22
+ from airflow import __version__ as airflow_version
23
+
24
+ AIRFLOW_VERSION = Version(airflow_version)
25
+ AIRFLOW_V_2_10_PLUS = Version(AIRFLOW_VERSION.base_version) >= Version("2.10.0")
26
+ AIRFLOW_V_3_0_PLUS = Version(AIRFLOW_VERSION.base_version) >= Version("3.0.0")