3535from typing import TYPE_CHECKING , Any , Callable , Collection , Iterable , Mapping , NamedTuple , Sequence , cast
3636
3737import lazy_object_proxy
38- from packaging .version import Version
3938
40- from airflow import __version__ as airflow_version
4139from airflow .exceptions import (
4240 AirflowConfigException ,
4341 AirflowException ,
5048from airflow .models .taskinstance import _CURRENT_CONTEXT
5149from airflow .models .variable import Variable
5250from airflow .operators .branch import BranchMixIn
51+ from airflow .providers .standard import AIRFLOW_V_2_10_PLUS , AIRFLOW_V_3_0_PLUS
5352from airflow .providers .standard .utils .python_virtualenv import prepare_virtualenv , write_python_script
5453from airflow .settings import _ENABLE_AIP_44
5554from airflow .typing_compat import Literal
5655from airflow .utils import hashlib_wrapper
57- from airflow .utils .context import context_copy_partial , context_get_outlet_events , context_merge
56+ from airflow .utils .context import context_copy_partial , context_merge
5857from airflow .utils .file import get_unique_dag_module_name
59- from airflow .utils .operator_helpers import ExecutionCallableRunner , KeywordParameters
60- from airflow .utils .process_utils import execute_in_subprocess
58+ from airflow .utils .operator_helpers import KeywordParameters
59+ from airflow .utils .process_utils import execute_in_subprocess , execute_in_subprocess_with_kwargs
6160from airflow .utils .session import create_session
6261
6362log = logging .getLogger (__name__ )
6463
65- AIRFLOW_VERSION = Version (airflow_version )
66- AIRFLOW_V_3_0_PLUS = Version (AIRFLOW_VERSION .base_version ) >= Version ("3.0.0" )
67-
6864if TYPE_CHECKING :
6965 from pendulum .datetime import DateTime
7066
@@ -187,7 +183,15 @@ def __init__(
187183 def execute (self , context : Context ) -> Any :
188184 context_merge (context , self .op_kwargs , templates_dict = self .templates_dict )
189185 self .op_kwargs = self .determine_kwargs (context )
190- self ._asset_events = context_get_outlet_events (context )
186+
187+ if AIRFLOW_V_3_0_PLUS :
188+ from airflow .utils .context import context_get_outlet_events
189+
190+ self ._asset_events = context_get_outlet_events (context )
191+ elif AIRFLOW_V_2_10_PLUS :
192+ from airflow .utils .context import context_get_outlet_events
193+
194+ self ._dataset_events = context_get_outlet_events (context )
191195
192196 return_value = self .execute_callable ()
193197 if self .show_return_value_in_logs :
@@ -206,7 +210,15 @@ def execute_callable(self) -> Any:
206210
207211 :return: the return value of the call.
208212 """
209- runner = ExecutionCallableRunner (self .python_callable , self ._asset_events , logger = self .log )
213+ try :
214+ from airflow .utils .operator_helpers import ExecutionCallableRunner
215+
216+ asset_events = self ._asset_events if AIRFLOW_V_3_0_PLUS else self ._dataset_events
217+
218+ runner = ExecutionCallableRunner (self .python_callable , asset_events , logger = self .log )
219+ except ImportError :
220+ # Handle Pre Airflow 3.10 case where ExecutionCallableRunner was not available
221+ return self .python_callable (* self .op_args , ** self .op_kwargs )
210222 return runner .run (* self .op_args , ** self .op_kwargs )
211223
212224
@@ -348,7 +360,6 @@ class _BasePythonVirtualenvOperator(PythonOperator, metaclass=ABCMeta):
348360 "ds_nodash" ,
349361 "expanded_ti_count" ,
350362 "inlets" ,
351- "map_index_template" ,
352363 "next_ds" ,
353364 "next_ds_nodash" ,
354365 "outlets" ,
@@ -551,18 +562,25 @@ def _execute_python_callable_in_subprocess(self, python_path: Path):
551562 env_vars .update (self .env_vars )
552563
553564 try :
554- execute_in_subprocess (
555- cmd = [
556- os .fspath (python_path ),
557- os .fspath (script_path ),
558- os .fspath (input_path ),
559- os .fspath (output_path ),
560- os .fspath (string_args_path ),
561- os .fspath (termination_log_path ),
562- os .fspath (airflow_context_path ),
563- ],
564- env = env_vars ,
565- )
565+ cmd : list [str ] = [
566+ os .fspath (python_path ),
567+ os .fspath (script_path ),
568+ os .fspath (input_path ),
569+ os .fspath (output_path ),
570+ os .fspath (string_args_path ),
571+ os .fspath (termination_log_path ),
572+ os .fspath (airflow_context_path ),
573+ ]
574+ if AIRFLOW_V_2_10_PLUS :
575+ execute_in_subprocess (
576+ cmd = cmd ,
577+ env = env_vars ,
578+ )
579+ else :
580+ execute_in_subprocess_with_kwargs (
581+ cmd = cmd ,
582+ env = env_vars ,
583+ )
566584 except subprocess .CalledProcessError as e :
567585 if e .returncode in self .skip_on_exit_code :
568586 raise AirflowSkipException (f"Process exited with code { e .returncode } . Skipping." )
@@ -697,10 +715,15 @@ def __init__(
697715 raise AirflowException (
698716 "Passing non-string types (e.g. int or float) as python_version not supported"
699717 )
700-
718+ if use_airflow_context and not AIRFLOW_V_3_0_PLUS :
719+ raise AirflowException (
720+ "The `use_airflow_context=True` is only supported in Airflow 3.0.0 and later."
721+ )
701722 if use_airflow_context and (not expect_airflow and not system_site_packages ):
702- error_msg = "use_airflow_context is set to True, but expect_airflow and system_site_packages are set to False."
703- raise AirflowException (error_msg )
723+ raise AirflowException (
724+ "The `use_airflow_context` parameter is set to True, but "
725+ "expect_airflow and system_site_packages are set to False."
726+ )
704727 if not requirements :
705728 self .requirements : list [str ] = []
706729 elif isinstance (requirements , str ):
@@ -976,9 +999,14 @@ def __init__(
976999 ):
9771000 if not python :
9781001 raise ValueError ("Python Path must be defined in ExternalPythonOperator" )
1002+ if use_airflow_context and not AIRFLOW_V_3_0_PLUS :
1003+ raise AirflowException (
1004+ "The `use_airflow_context=True` is only supported in Airflow 3.0.0 and later."
1005+ )
9791006 if use_airflow_context and not expect_airflow :
980- error_msg = "use_airflow_context is set to True, but expect_airflow is set to False."
981- raise AirflowException (error_msg )
1007+ raise AirflowException (
1008+ "The `use_airflow_context` parameter is set to True, but expect_airflow is set to False."
1009+ )
9821010 self .python = python
9831011 self .expect_pendulum = expect_pendulum
9841012 super ().__init__ (
0 commit comments