This is an automated email from the ASF dual-hosted git repository.
potiuk 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 04a058ad80b fix: report duplicate plugin names as import errors
(#66649)
04a058ad80b is described below
commit 04a058ad80b748cc71a0c833dc3c95cb18181e29
Author: Jinwoo <[email protected]>
AuthorDate: Mon May 11 02:28:59 2026 +0900
fix: report duplicate plugin names as import errors (#66649)
---
airflow-core/src/airflow/plugins_manager.py | 5 +++-
.../tests/unit/plugins/test_plugins_manager.py | 29 +++++++++++++++++++++-
2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/airflow-core/src/airflow/plugins_manager.py
b/airflow-core/src/airflow/plugins_manager.py
index 1ac1c06a7c0..9b0487a8985 100644
--- a/airflow-core/src/airflow/plugins_manager.py
+++ b/airflow-core/src/airflow/plugins_manager.py
@@ -99,7 +99,10 @@ def _get_plugins() -> tuple[list[AirflowPlugin], dict[str,
str]]:
def __register_plugins(plugin_instances: list[AirflowPlugin], errors:
dict[str, str]) -> None:
for plugin_instance in plugin_instances:
if plugin_instance.name in loaded_plugins:
- log.warning("Plugin %r already registered, skipping",
plugin_instance.name)
+ message = f"Plugin {plugin_instance.name!r} already
registered, skipping"
+ log.warning(message)
+ name = str(plugin_instance.source) if plugin_instance.source
else plugin_instance.name or ""
+ import_errors[name] = message
continue
loaded_plugins.add(plugin_instance.name)
diff --git a/airflow-core/tests/unit/plugins/test_plugins_manager.py
b/airflow-core/tests/unit/plugins/test_plugins_manager.py
index 7ffa84060f9..1163ac63386 100644
--- a/airflow-core/tests/unit/plugins/test_plugins_manager.py
+++ b/airflow-core/tests/unit/plugins/test_plugins_manager.py
@@ -160,7 +160,34 @@ class TestPluginsManager:
assert "plugin_b" in plugin_names
assert "plugin_c" in plugin_names
assert len(plugins) == 3
- assert not import_errors
+
+ def test_duplicate_plugin_name_is_reported_as_import_error(self):
+ from airflow import plugins_manager
+
+ class PluginA(AirflowPlugin):
+ name = "plugin_a"
+
+ class PluginADuplicateName(AirflowPlugin):
+ name = "plugin_a"
+
+ plugin_a = PluginA()
+ plugin_a_dup = PluginADuplicateName()
+
+ with (
+ mock.patch(
+ "airflow.plugins_manager._load_plugins_from_plugin_directory",
+ return_value=([plugin_a], {}),
+ ),
+ mock.patch(
+ "airflow.plugins_manager._load_entrypoint_plugins",
+ return_value=([plugin_a_dup], {}),
+ ),
+ mock.patch("airflow.plugins_manager._load_providers_plugins",
return_value=([], {})),
+ ):
+ plugins, import_errors = plugins_manager._get_plugins()
+
+ assert [p.name for p in plugins] == ["plugin_a"]
+ assert len(import_errors) == 1
def test_should_warning_about_incompatible_plugins(self, caplog):
class AirflowAdminViewsPlugin(AirflowPlugin):