This is an automated email from the ASF dual-hosted git repository.
shahar1 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 df9a3e73c8b Move AzureFileShareToGCSOperator directory_name alias out
of __init__ (#70740)
df9a3e73c8b is described below
commit df9a3e73c8b3ebb5cbca2134f4d35f6c9901ae0d
Author: Andrew Chang <[email protected]>
AuthorDate: Sat Sep 12 22:49:52 2026 +0800
Move AzureFileShareToGCSOperator directory_name alias out of __init__
(#70740)
---
.../cloud/transfers/azure_fileshare_to_gcs.py | 13 ++-
.../cloud/transfers/test_azure_fileshare_to_gcs.py | 102 +++++++++++++++++++++
.../ci/prek/validate_operators_init_exemptions.txt | 1 -
3 files changed, 111 insertions(+), 5 deletions(-)
diff --git
a/providers/google/src/airflow/providers/google/cloud/transfers/azure_fileshare_to_gcs.py
b/providers/google/src/airflow/providers/google/cloud/transfers/azure_fileshare_to_gcs.py
index 488738d1967..843876a7e4b 100644
---
a/providers/google/src/airflow/providers/google/cloud/transfers/azure_fileshare_to_gcs.py
+++
b/providers/google/src/airflow/providers/google/cloud/transfers/azure_fileshare_to_gcs.py
@@ -69,8 +69,8 @@ class AzureFileShareToGCSOperator(BaseOperator):
:param return_gcs_uris: If True, return a list of GCS URIs. If False
(default), return the legacy
list of Azure FileShare filenames and emit a deprecation warning.
- Note that ``share_name``, ``directory_path``, ``prefix``, and ``dest_gcs``
are
- templated, so you can use variables in them if you wish.
+ Note that ``share_name``, ``directory_name``, ``directory_path``,
``prefix``, and
+ ``dest_gcs`` are templated, so you can use variables in them if you wish.
"""
template_fields: Sequence[str] = (
@@ -102,8 +102,11 @@ class AzureFileShareToGCSOperator(BaseOperator):
self.share_name = share_name
self.directory_path = directory_path
self.directory_name = directory_name
- if self.directory_path is None and self.directory_name is not None:
- self.directory_path = self.directory_name
+ # The deprecated directory_name->directory_path alias is decided here
on the un-rendered
+ # values (native rendering can turn a supplied directory_path into
None) and applied in
+ # execute(), which runs for mapped tasks too — render_template_fields
overrides do not.
+ self._use_directory_name = directory_path is None and directory_name
is not None
+ if self._use_directory_name:
warnings.warn(
"Use 'directory_path' instead of 'directory_name'. Planned
removal date: October 5, 2026.",
AirflowProviderDeprecationWarning,
@@ -139,6 +142,8 @@ class AzureFileShareToGCSOperator(BaseOperator):
)
def execute(self, context: Context) -> list[str]:
+ if self._use_directory_name:
+ self.directory_path = self.directory_name
self._check_inputs()
azure_fileshare_hook = AzureFileShareHook(
share_name=self.share_name,
diff --git
a/providers/google/tests/unit/google/cloud/transfers/test_azure_fileshare_to_gcs.py
b/providers/google/tests/unit/google/cloud/transfers/test_azure_fileshare_to_gcs.py
index a70d7cc709b..c0392f6df87 100644
---
a/providers/google/tests/unit/google/cloud/transfers/test_azure_fileshare_to_gcs.py
+++
b/providers/google/tests/unit/google/cloud/transfers/test_azure_fileshare_to_gcs.py
@@ -16,14 +16,18 @@
# under the License.
from __future__ import annotations
+import datetime
from unittest import mock
import pytest
+from airflow import DAG
+from airflow.exceptions import AirflowProviderDeprecationWarning
from airflow.providers.google.cloud.transfers.azure_fileshare_to_gcs import
AzureFileShareToGCSOperator
pytestmark = pytest.mark.filterwarnings("ignore::FutureWarning")
+DEFAULT_DATE = datetime.datetime(2024, 1, 1)
TASK_ID = "test-azure-fileshare-to-gcs"
AZURE_FILESHARE_SHARE = "test-share"
AZURE_FILESHARE_DIRECTORY_PATH = "/path/to/dir"
@@ -56,6 +60,104 @@ class TestAzureFileShareToGCSOperator:
assert operator.dest_gcs == GCS_PATH_PREFIX
assert operator.google_impersonation_chain == IMPERSONATION_CHAIN
+
@mock.patch("airflow.providers.google.cloud.transfers.azure_fileshare_to_gcs.AzureFileShareHook")
+
@mock.patch("airflow.providers.google.cloud.transfers.azure_fileshare_to_gcs.GCSHook")
+ def test_directory_name_alias_uses_rendered_value(self, gcs_mock_hook,
azure_fileshare_mock_hook):
+ """A templated directory_name is aliased to directory_path using its
rendered value, not the Jinja expression."""
+ dag = DAG("test_azure_fileshare_alias", schedule=None,
start_date=DEFAULT_DATE)
+ with pytest.warns(AirflowProviderDeprecationWarning, match="Use
'directory_path' instead"):
+ operator = AzureFileShareToGCSOperator(
+ task_id=TASK_ID,
+ share_name=AZURE_FILESHARE_SHARE,
+ directory_name="{{ params.legacy_dir }}",
+ params={"legacy_dir": "rendered/dir"},
+ azure_fileshare_conn_id=AZURE_FILESHARE_CONN_ID,
+ gcp_conn_id=GCS_CONN_ID,
+ dest_gcs=GCS_PATH_PREFIX,
+ return_gcs_uris=True,
+ dag=dag,
+ )
+ assert operator.directory_path is None
+
+ operator.render_template_fields({"params": {"legacy_dir":
"rendered/dir"}})
+ assert operator.directory_path is None
+
+ azure_fileshare_mock_hook.return_value.list_files.return_value =
MOCK_FILES
+ operator.execute(None)
+ azure_fileshare_mock_hook.assert_any_call(
+ share_name=AZURE_FILESHARE_SHARE,
+ azure_fileshare_conn_id=AZURE_FILESHARE_CONN_ID,
+ directory_path="rendered/dir",
+ )
+
+
@mock.patch("airflow.providers.google.cloud.transfers.azure_fileshare_to_gcs.AzureFileShareHook")
+
@mock.patch("airflow.providers.google.cloud.transfers.azure_fileshare_to_gcs.GCSHook")
+ def test_native_directory_path_rendering_to_none_is_not_aliased(
+ self, gcs_mock_hook, azure_fileshare_mock_hook
+ ):
+ """
+ Behaviour-preservation guard: the alias decision must come from the
un-rendered values.
+
+ With render_template_as_native_obj an explicitly supplied
directory_path can render to None,
+ and re-deciding the alias after rendering would wrongly fall back to
the deprecated
+ directory_name. Deciding in __init__ (pre-render) keeps this case an
explicit error.
+ """
+ dag = DAG(
+ "test_azure_fileshare_native",
+ schedule=None,
+ start_date=DEFAULT_DATE,
+ render_template_as_native_obj=True,
+ )
+ operator = AzureFileShareToGCSOperator(
+ task_id=TASK_ID,
+ share_name=AZURE_FILESHARE_SHARE,
+ directory_path="{{ params.p }}",
+ directory_name="legacy",
+ params={"p": None},
+ azure_fileshare_conn_id=AZURE_FILESHARE_CONN_ID,
+ gcp_conn_id=GCS_CONN_ID,
+ dest_gcs=GCS_PATH_PREFIX,
+ return_gcs_uris=True,
+ dag=dag,
+ )
+
+ operator.render_template_fields({"params": {"p": None}})
+ assert operator.directory_path is None
+
+ # The deprecated alias must not silently substitute directory_name; a
genuinely unset
+ # directory surfaces as the operator's own error instead of listing
the wrong directory.
+ azure_fileshare_mock_hook.return_value.list_files.return_value =
MOCK_FILES
+ with pytest.raises(RuntimeError, match="directory_name must be set"):
+ operator.execute(None)
+
+
@mock.patch("airflow.providers.google.cloud.transfers.azure_fileshare_to_gcs.AzureFileShareHook")
+
@mock.patch("airflow.providers.google.cloud.transfers.azure_fileshare_to_gcs.GCSHook")
+ def test_mapped_task_aliases_directory_name(self, gcs_mock_hook,
azure_fileshare_mock_hook):
+ """
+ Mapped tasks reach execute() through MappedOperator.unmap(), never
through
+ render_template_fields overrides, so the alias must not depend on one.
+ """
+ mapped = AzureFileShareToGCSOperator.partial(
+ task_id=TASK_ID,
+ share_name=AZURE_FILESHARE_SHARE,
+ directory_name=AZURE_FILESHARE_DIRECTORY_PATH,
+ azure_fileshare_conn_id=AZURE_FILESHARE_CONN_ID,
+ gcp_conn_id=GCS_CONN_ID,
+ dest_gcs=GCS_PATH_PREFIX,
+ return_gcs_uris=True,
+ ).expand(prefix=["sub/a/", "sub/b/"])
+
+ with pytest.warns(AirflowProviderDeprecationWarning, match="Use
'directory_path' instead"):
+ operator = mapped.unmap({"prefix": "sub/a/"})
+
+ azure_fileshare_mock_hook.return_value.list_files.return_value =
MOCK_FILES
+ operator.execute(None)
+ azure_fileshare_mock_hook.assert_any_call(
+ share_name=AZURE_FILESHARE_SHARE,
+ azure_fileshare_conn_id=AZURE_FILESHARE_CONN_ID,
+ directory_path=AZURE_FILESHARE_DIRECTORY_PATH,
+ )
+
@pytest.mark.parametrize("return_gcs_uris", [True, False])
@mock.patch("airflow.providers.google.cloud.transfers.azure_fileshare_to_gcs.AzureFileShareHook")
@mock.patch("airflow.providers.google.cloud.transfers.azure_fileshare_to_gcs.GCSHook")
diff --git a/scripts/ci/prek/validate_operators_init_exemptions.txt
b/scripts/ci/prek/validate_operators_init_exemptions.txt
index 25cb0fe1a14..803a2ad7495 100644
--- a/scripts/ci/prek/validate_operators_init_exemptions.txt
+++ b/scripts/ci/prek/validate_operators_init_exemptions.txt
@@ -17,5 +17,4 @@
providers/google/src/airflow/providers/google/cloud/operators/functions.py::Clou
providers/google/src/airflow/providers/google/cloud/operators/gcs.py::GCSFileTransformOperator
providers/google/src/airflow/providers/google/cloud/sensors/bigquery_dts.py::BigQueryDataTransferServiceTransferRunSensor
providers/google/src/airflow/providers/google/cloud/sensors/cloud_composer.py::CloudComposerExternalTaskSensor
-providers/google/src/airflow/providers/google/cloud/transfers/azure_fileshare_to_gcs.py::AzureFileShareToGCSOperator
providers/microsoft/psrp/src/airflow/providers/microsoft/psrp/operators/psrp.py::PsrpOperator