Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions airflow-core/src/airflow/providers_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
from airflow._shared.module_loading import entry_points_with_dist, import_string
from airflow.exceptions import AirflowOptionalProviderFeatureException
from airflow.utils.log.logging_mixin import LoggingMixin
from airflow.utils.singleton import Singleton

if TYPE_CHECKING:
from airflow.cli.cli_config import CLICommand
Expand Down Expand Up @@ -366,7 +365,7 @@ def wrapped_function(*args: PS.args, **kwargs: PS.kwargs) -> None:
return provider_info_cache_decorator


class ProvidersManager(LoggingMixin, metaclass=Singleton):
class ProvidersManager(LoggingMixin):
"""
Manages all provider distributions.

Expand All @@ -377,6 +376,12 @@ class ProvidersManager(LoggingMixin, metaclass=Singleton):
resource_version = "0"
_initialized: bool = False
_initialization_stack_trace = None
_instance: ProvidersManager | None = None

def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance

@staticmethod
def initialized() -> bool:
Expand All @@ -388,6 +393,10 @@ def initialization_stack_trace() -> str | None:

def __init__(self):
"""Initialize the manager."""
# skip initialization if already initialized
if self.initialized():
return

super().__init__()
ProvidersManager._initialized = True
ProvidersManager._initialization_stack_trace = "".join(traceback.format_stack(inspect.currentframe()))
Expand Down
33 changes: 0 additions & 33 deletions airflow-core/src/airflow/utils/singleton.py

This file was deleted.

15 changes: 15 additions & 0 deletions airflow-core/tests/unit/always/test_providers_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,21 @@ class TestProviderManager:
def inject_fixtures(self, caplog, cleanup_providers_manager):
self._caplog = caplog

def test_providers_manager_singleton(self):
"""Test that ProvidersManager returns the same instance and shares state."""
pm1 = ProvidersManager()
pm2 = ProvidersManager()

assert pm1 is pm2

# assert their states are same
assert pm1._provider_dict is pm2._provider_dict
assert pm1._hook_provider_dict is pm2._hook_provider_dict

# update property on one instance and check on another
pm1.resource_version = "updated_version"
assert pm2.resource_version == "updated_version"

def test_providers_are_loaded(self):
with self._caplog.at_level(logging.WARNING):
self._caplog.clear()
Expand Down
65 changes: 0 additions & 65 deletions airflow-core/tests/unit/utils/test_singleton.py

This file was deleted.

Loading