This is an automated email from the ASF dual-hosted git repository.
amoghdesai 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 7c4520ba62e Update usages of entry_points helpers and deprecate it
from utils (#60061)
7c4520ba62e is described below
commit 7c4520ba62ec4bb5a35e07fb451dcda276a2a841
Author: Amogh Desai <[email protected]>
AuthorDate: Sat Jan 3 14:43:07 2026 +0530
Update usages of entry_points helpers and deprecate it from utils (#60061)
---
airflow-core/src/airflow/plugins_manager.py | 3 +-
airflow-core/src/airflow/providers_manager.py | 3 +-
airflow-core/src/airflow/utils/__init__.py | 10 ++++++
.../src/airflow/utils/deprecation_tools.py | 17 ++++++++--
airflow-core/src/airflow/utils/entry_points.py | 26 ---------------
.../tests/unit/utils/test_deprecation_tools.py | 38 ++++++++++++++++++++++
devel-common/src/tests_common/pytest_plugin.py | 6 +++-
7 files changed, 69 insertions(+), 34 deletions(-)
diff --git a/airflow-core/src/airflow/plugins_manager.py
b/airflow-core/src/airflow/plugins_manager.py
index 8fdb3f06356..40cfe9bd25d 100644
--- a/airflow-core/src/airflow/plugins_manager.py
+++ b/airflow-core/src/airflow/plugins_manager.py
@@ -32,13 +32,12 @@ from pathlib import Path
from typing import TYPE_CHECKING, Any
from airflow import settings
-from airflow._shared.module_loading import import_string, qualname
+from airflow._shared.module_loading import entry_points_with_dist,
import_string, qualname
from airflow.configuration import conf
from airflow.task.priority_strategy import (
PriorityWeightStrategy,
airflow_priority_weight_strategies,
)
-from airflow.utils.entry_points import entry_points_with_dist
from airflow.utils.file import find_path_from_directory
if TYPE_CHECKING:
diff --git a/airflow-core/src/airflow/providers_manager.py
b/airflow-core/src/airflow/providers_manager.py
index 0ddf7188021..227e063d5df 100644
--- a/airflow-core/src/airflow/providers_manager.py
+++ b/airflow-core/src/airflow/providers_manager.py
@@ -35,9 +35,8 @@ from typing import TYPE_CHECKING, Any, NamedTuple, ParamSpec,
TypeVar
from packaging.utils import canonicalize_name
-from airflow._shared.module_loading import import_string
+from airflow._shared.module_loading import entry_points_with_dist,
import_string
from airflow.exceptions import AirflowOptionalProviderFeatureException
-from airflow.utils.entry_points import entry_points_with_dist
from airflow.utils.log.logging_mixin import LoggingMixin
from airflow.utils.singleton import Singleton
diff --git a/airflow-core/src/airflow/utils/__init__.py
b/airflow-core/src/airflow/utils/__init__.py
index 4b0ad3419a1..9aa833f9e6c 100644
--- a/airflow-core/src/airflow/utils/__init__.py
+++ b/airflow-core/src/airflow/utils/__init__.py
@@ -56,3 +56,13 @@ __deprecated_classes = {
}
add_deprecated_classes(__deprecated_classes, __name__)
+
+add_deprecated_classes(
+ {
+ "entry_points": {
+ "*": "airflow._shared.module_loading",
+ },
+ },
+ __name__,
+ message="The `{module}.{name}` is deprecated and will be removed in a
future version.",
+)
diff --git a/airflow-core/src/airflow/utils/deprecation_tools.py
b/airflow-core/src/airflow/utils/deprecation_tools.py
index dcb2d6f72d6..2253b6b86c9 100644
--- a/airflow-core/src/airflow/utils/deprecation_tools.py
+++ b/airflow-core/src/airflow/utils/deprecation_tools.py
@@ -40,6 +40,7 @@ def getattr_with_deprecation(
override_deprecated_classes: dict[str, str],
extra_message: str,
name: str,
+ message_override: str = "",
):
"""
Retrieve the imported attribute from the redirected module and raises a
deprecation warning.
@@ -49,6 +50,8 @@ def getattr_with_deprecation(
:param override_deprecated_classes: override target attributes with
deprecated ones. If target attribute is
found in the dictionary, it will be displayed in the warning message.
:param extra_message: extra message to display in the warning or import
error message
+ :param message_override: if provided, overrides the default deprecation
message. Supports placeholders:
+ {module}, {name}, {target} which are substituted with the actual values.
:param name: attribute name
:return:
"""
@@ -67,9 +70,12 @@ def getattr_with_deprecation(
if override_deprecated_classes and name in override_deprecated_classes:
warning_class_name = override_deprecated_classes[name]
- message = f"The `{module}.{name}` attribute is deprecated. Please use
`{warning_class_name!r}`."
- if extra_message:
- message += f" {extra_message}."
+ if message_override:
+ message = message_override.format(module=module, name=name,
target=warning_class_name)
+ else:
+ message = f"The `{module}.{name}` attribute is deprecated. Please use
`{warning_class_name!r}`."
+ if extra_message:
+ message += f" {extra_message}."
warnings.warn(message, DeprecatedImportWarning, stacklevel=2)
# Import and return the target attribute
@@ -90,6 +96,7 @@ def add_deprecated_classes(
package: str,
override_deprecated_classes: dict[str, dict[str, str]] | None = None,
extra_message: str | None = None,
+ message: str | None = None,
):
"""
Add deprecated attribute PEP-563 imports and warnings modules to the
package.
@@ -105,6 +112,8 @@ def add_deprecated_classes(
:param override_deprecated_classes: override target attributes with
deprecated ones.
Format: dict[str, dict[str, str]] matching the structure of
module_imports
:param extra_message: extra message to display in the warning or import
error message
+ :param message: if provided, overrides the default deprecation message.
Supports placeholders:
+ {module}, {name}, {target} which are substituted with the actual
values.
Examples:
# Create virtual modules (e.g., for removed .py files)
@@ -175,6 +184,7 @@ def add_deprecated_classes(
package,
current_override,
extra_message or "",
+ message_override=message or "",
)
# Set the __getattr__ function on the current module
@@ -195,5 +205,6 @@ def add_deprecated_classes(
full_module_name,
override_deprecated_classes_for_module,
extra_message or "",
+ message_override=message or "",
)
sys.modules.setdefault(full_module_name, module_type)
diff --git a/airflow-core/src/airflow/utils/entry_points.py
b/airflow-core/src/airflow/utils/entry_points.py
deleted file mode 100644
index dac8e3b868b..00000000000
--- a/airflow-core/src/airflow/utils/entry_points.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-"""Re-export entry_points utilities from shared library for backward
compatibility."""
-
-from __future__ import annotations
-
-from airflow._shared.module_loading import (
- EPnD as EPnD,
- _get_grouped_entry_points as _get_grouped_entry_points,
- entry_points_with_dist as entry_points_with_dist,
- metadata as metadata,
-)
diff --git a/airflow-core/tests/unit/utils/test_deprecation_tools.py
b/airflow-core/tests/unit/utils/test_deprecation_tools.py
index 2a6ca7ce74c..c48a59ecac7 100644
--- a/airflow-core/tests/unit/utils/test_deprecation_tools.py
+++ b/airflow-core/tests/unit/utils/test_deprecation_tools.py
@@ -472,6 +472,44 @@ class TestAddDeprecatedClasses:
package=nonexistent_module,
)
+ def test_add_deprecated_classes_with_custom_message(self):
+ """Test add_deprecated_classes with custom message parameter."""
+ module_name = get_unique_module_name("custom_msg_module")
+ full_module_name = f"airflow.test.{module_name}"
+
+ # Create a module to modify
+ test_module = ModuleType(full_module_name)
+ sys.modules[full_module_name] = test_module
+
+ with temporary_module(full_module_name):
+ # Mock the target module and attribute
+ mock_target_module = mock.MagicMock()
+ mock_attribute = mock.MagicMock()
+ mock_target_module.deprecated_attr = mock_attribute
+
+ with mock.patch(
+ "airflow.utils.deprecation_tools.importlib.import_module",
return_value=mock_target_module
+ ):
+ custom_message = "We are just going to remove {module}.{name}.
Prepare yourselves!"
+ add_deprecated_classes(
+ {full_module_name: {"deprecated_attr":
"target.module.deprecated_attr"}},
+ package=full_module_name,
+ message=custom_message,
+ )
+
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter("always")
+ result = getattr(test_module, "deprecated_attr")
+
+ assert result == mock_attribute
+ assert len(w) == 1
+ assert issubclass(w[0].category, DeprecatedImportWarning)
+ expected = (
+ f"We are just going to remove
{full_module_name}.deprecated_attr. Prepare yourselves!"
+ )
+ assert str(w[0].message) == expected
+ assert "Please use" not in str(w[0].message)
+
def test_add_deprecated_classes_preserves_existing_module_attributes(self):
"""Test that add_deprecated_classes preserves existing module
attributes."""
module_name = get_unique_module_name("preserve_module")
diff --git a/devel-common/src/tests_common/pytest_plugin.py
b/devel-common/src/tests_common/pytest_plugin.py
index 5d60aa66d1c..3dc2cec736e 100644
--- a/devel-common/src/tests_common/pytest_plugin.py
+++ b/devel-common/src/tests_common/pytest_plugin.py
@@ -1785,7 +1785,11 @@ def clear_lru_cache():
yield
return
- from airflow.utils.entry_points import _get_grouped_entry_points
+ try:
+ from airflow._shared.module_loading import _get_grouped_entry_points
+ except ImportError:
+ # compat for airflow < 3.2
+ from airflow.utils.entry_points import _get_grouped_entry_points
_get_grouped_entry_points.cache_clear()
try: