Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a028f37
starting point: separating PM roles for client and server, shared code
amoghrajesh Jan 6, 2026
5c18422
Merge branch 'main' into split-providers-manager
amoghrajesh Jan 7, 2026
7c53cf6
fixing selective checks
amoghrajesh Jan 8, 2026
47f07fc
Merge branch 'main' into split-providers-manager
amoghrajesh Jan 8, 2026
dfc13c9
fixing static checks
amoghrajesh Jan 9, 2026
0223540
moving tests to task sdk
amoghrajesh Jan 9, 2026
686b271
moving tests to shared
amoghrajesh Jan 9, 2026
fbde7d2
cleanup
amoghrajesh Jan 9, 2026
25b7708
adding missed export
amoghrajesh Jan 9, 2026
ef989ac
fixing shared tests
amoghrajesh Jan 9, 2026
fb07c4d
Merge branch 'main' into split-providers-manager
amoghrajesh Jan 12, 2026
0ba89ba
some fixes
amoghrajesh Jan 12, 2026
4681b98
adding importlib in pyproject
amoghrajesh Jan 12, 2026
926e789
Merge branch 'main' into split-providers-manager
amoghrajesh Jan 12, 2026
16ab40a
adding methodtools in pyproject
amoghrajesh Jan 12, 2026
a23d8a2
removinf dependencies
amoghrajesh Jan 12, 2026
3285845
making providers discovery standalone
amoghrajesh Jan 12, 2026
248659c
Merge branch 'main' into split-providers-manager
amoghrajesh Jan 12, 2026
704d42b
Merge branch 'main' into split-providers-manager
amoghrajesh Jan 12, 2026
6333f5d
making providers discovery standalone
amoghrajesh Jan 12, 2026
2e57306
fixing some issues
amoghrajesh Jan 12, 2026
7a47a89
remove pm ref in sdk
amoghrajesh Jan 13, 2026
eec3513
fixing broken tests
amoghrajesh Jan 13, 2026
8e684ba
fixing broken tests
amoghrajesh Jan 13, 2026
a9af140
fixing broken tests
amoghrajesh Jan 13, 2026
bd6caa8
remove dup
amoghrajesh Jan 15, 2026
5dcdccc
Merge branch 'main' into split-providers-manager
amoghrajesh Jan 15, 2026
b285dcd
comments from jason
amoghrajesh Jan 15, 2026
a2f22f1
Merge branch 'main' into split-providers-manager
amoghrajesh Jan 16, 2026
836f5dd
comments from jarek
amoghrajesh Jan 19, 2026
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
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ repos:
^airflow-core/src/airflow/utils/db\.py$|
^airflow-core/src/airflow/utils/trigger_rule\.py$|
^airflow-core/tests/|
^task-sdk/tests/|
^.*changelog\.(rst|txt)$|
^.*CHANGELOG\.(rst|txt)$|
^chart/values.schema\.json$|
Expand Down
2 changes: 2 additions & 0 deletions airflow-core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ exclude = [
"../shared/timezones/src/airflow_shared/timezones" = "src/airflow/_shared/timezones"
"../shared/listeners/src/airflow_shared/listeners" = "src/airflow/_shared/listeners"
"../shared/plugins_manager/src/airflow_shared/plugins_manager" = "src/airflow/_shared/plugins_manager"
"../shared/providers_discovery/src/airflow_shared/providers_discovery" = "src/airflow/_shared/providers_discovery"

[tool.hatch.build.targets.custom]
path = "./hatch_build.py"
Expand Down Expand Up @@ -317,4 +318,5 @@ shared_distributions = [
"apache-airflow-shared-secrets-masker",
"apache-airflow-shared-timezones",
"apache-airflow-shared-plugins-manager",
"apache-airflow-shared-providers-discovery",
]
1 change: 1 addition & 0 deletions airflow-core/src/airflow/_shared/providers_discovery
86 changes: 31 additions & 55 deletions airflow-core/src/airflow/providers_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@
from time import perf_counter
from typing import TYPE_CHECKING, Any, NamedTuple, ParamSpec, TypeVar, cast

from packaging.utils import canonicalize_name

from airflow._shared.module_loading import entry_points_with_dist, import_string
from airflow import DeprecatedImportWarning
from airflow._shared.module_loading import import_string
from airflow._shared.providers_discovery import discover_all_providers_from_packages
from airflow.exceptions import AirflowOptionalProviderFeatureException
from airflow.utils.log.logging_mixin import LoggingMixin

Expand Down Expand Up @@ -438,6 +438,33 @@ def __init__(self):
self._plugins_set: set[PluginInfo] = set()
self._init_airflow_core_hooks()

self._runtime_manager = None

def __getattribute__(self, name: str):
# Hacky but does the trick for now
runtime_properties = {
"hooks",
"taskflow_decorators",
"filesystem_module_names",
"asset_factories",
"asset_uri_handlers",
"asset_to_openlineage_converters",
}

if name in runtime_properties:
warnings.warn(
f"ProvidersManager.{name} is deprecated. Use ProvidersManagerTaskRuntime.{name} from task-sdk instead.",
DeprecatedImportWarning,
stacklevel=2,
)
if object.__getattribute__(self, "_runtime_manager") is None:
from airflow.sdk.providers_manager_runtime import ProvidersManagerTaskRuntime

object.__setattr__(self, "_runtime_manager", ProvidersManagerTaskRuntime())
return getattr(object.__getattribute__(self, "_runtime_manager"), name)

return object.__getattribute__(self, name)

def _init_airflow_core_hooks(self):
"""Initialize the hooks dict with default hooks from Airflow core."""
core_dummy_hooks = {
Expand Down Expand Up @@ -472,7 +499,7 @@ def initialize_providers_list(self):
# Development purpose. In production provider.yaml files are not present in the 'airflow" directory
# So there is no risk we are going to override package provider accidentally. This can only happen
# in case of local development
self._discover_all_providers_from_packages()
discover_all_providers_from_packages(self._provider_dict, self._provider_schema_validator)
self._verify_all_providers_all_compatible()
self._provider_dict = dict(sorted(self._provider_dict.items()))

Expand Down Expand Up @@ -607,57 +634,6 @@ def initialize_providers_cli_command(self):
self.initialize_providers_list()
self._discover_cli_command()

def _discover_all_providers_from_packages(self) -> None:
"""
Discover all providers by scanning packages installed.

The list of providers should be returned via the 'apache_airflow_provider'
entrypoint as a dictionary conforming to the 'airflow/provider_info.schema.json'
schema. Note that the schema is different at runtime than provider.yaml.schema.json.
The development version of provider schema is more strict and changes together with
the code. The runtime version is more relaxed (allows for additional properties)
and verifies only the subset of fields that are needed at runtime.
"""
for entry_point, dist in entry_points_with_dist("apache_airflow_provider"):
if not dist.metadata:
continue
package_name = canonicalize_name(dist.metadata["name"])
if package_name in self._provider_dict:
continue
log.debug("Loading %s from package %s", entry_point, package_name)
version = dist.version
provider_info = entry_point.load()()
self._provider_schema_validator.validate(provider_info)
provider_info_package_name = provider_info["package-name"]
if package_name != provider_info_package_name:
raise ValueError(
f"The package '{package_name}' from packaging information "
f"{provider_info_package_name} do not match. Please make sure they are aligned"
)

# issue-59576: Retrieve the project.urls.documentation from dist.metadata
project_urls = dist.metadata.get_all("Project-URL")
documentation_url: str | None = None

if project_urls:
for entry in project_urls:
if "," in entry:
name, url = entry.split(",")
if name.strip().lower() == "documentation":
documentation_url = url
break

provider_info["documentation-url"] = documentation_url

if package_name not in self._provider_dict:
self._provider_dict[package_name] = ProviderInfo(version, provider_info)
else:
log.warning(
"The provider for package '%s' could not be registered from because providers for that "
"package name have already been registered",
package_name,
)

def _discover_hooks_from_connection_types(
self,
hook_class_names_registered: set[str],
Expand Down
Loading
Loading