Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Promote after dependencies in bootstrap" #141584

Merged
merged 1 commit into from
Mar 27, 2025
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
28 changes: 17 additions & 11 deletions homeassistant/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -859,23 +859,15 @@ async def _async_set_up_integrations(
integrations, all_integrations = await _async_resolve_domains_and_preload(
hass, config
)
# Detect all cycles
integrations_after_dependencies = (
await loader.resolve_integrations_after_dependencies(
hass, all_integrations.values(), set(all_integrations)
)
)
all_domains = set(integrations_after_dependencies)
domains = set(integrations) & all_domains
all_domains = set(all_integrations)
domains = set(integrations)

_LOGGER.info(
"Domains to be set up: %s | %s",
domains,
all_domains - domains,
)

async_set_domains_to_be_loaded(hass, all_domains)

# Initialize recorder
if "recorder" in all_domains:
recorder.async_initialize_recorder(hass)
Expand Down Expand Up @@ -908,12 +900,24 @@ async def _async_set_up_integrations(
stage_dep_domains_unfiltered = {
dep
for domain in stage_domains
for dep in integrations_after_dependencies[domain]
for dep in all_integrations[domain].all_dependencies
if dep not in stage_domains
}
stage_dep_domains = stage_dep_domains_unfiltered - hass.config.components

stage_all_domains = stage_domains | stage_dep_domains
stage_all_integrations = {
domain: all_integrations[domain] for domain in stage_all_domains
}
# Detect all cycles
stage_integrations_after_dependencies = (
await loader.resolve_integrations_after_dependencies(
hass, stage_all_integrations.values(), stage_all_domains
)
)
stage_all_domains = set(stage_integrations_after_dependencies)
stage_domains &= stage_all_domains
stage_dep_domains &= stage_all_domains

_LOGGER.info(
"Setting up stage %s: %s | %s\nDependencies: %s | %s",
Expand All @@ -924,6 +928,8 @@ async def _async_set_up_integrations(
stage_dep_domains_unfiltered - stage_dep_domains,
)

async_set_domains_to_be_loaded(hass, stage_all_domains)

if timeout is None:
await _async_setup_multi_components(hass, stage_all_domains, config)
continue
Expand Down
18 changes: 8 additions & 10 deletions tests/test_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:


@pytest.mark.parametrize("load_registries", [False])
async def test_setup_after_deps_in_stage_1(hass: HomeAssistant) -> None:
"""Test after_dependencies are promoted in stage 1."""
async def test_setup_after_deps_in_stage_1_ignored(hass: HomeAssistant) -> None:
"""Test after_dependencies are ignored in stage 1."""
# This test relies on this
assert "cloud" in bootstrap.STAGE_1_INTEGRATIONS
order = []
Expand Down Expand Up @@ -295,7 +295,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:

assert "normal_integration" in hass.config.components
assert "cloud" in hass.config.components
assert order == ["an_after_dep", "normal_integration", "cloud"]
assert order == ["cloud", "an_after_dep", "normal_integration"]


@pytest.mark.parametrize("load_registries", [False])
Expand All @@ -304,7 +304,7 @@ async def test_setup_after_deps_manifests_are_loaded_even_if_not_setup(
) -> None:
"""Ensure we preload manifests for after deps even if they are not setup.

It's important that we preload the after dep manifests even if they are not setup
Its important that we preload the after dep manifests even if they are not setup
since we will always have to check their requirements since any integration
that lists an after dep may import it and we have to ensure requirements are
up to date before the after dep can be imported.
Expand Down Expand Up @@ -371,7 +371,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
assert "an_after_dep" not in hass.config.components
assert "an_after_dep_of_after_dep" not in hass.config.components
assert "an_after_dep_of_after_dep_of_after_dep" not in hass.config.components
assert order == ["normal_integration", "cloud"]
assert order == ["cloud", "normal_integration"]
assert loader.async_get_loaded_integration(hass, "an_after_dep") is not None
assert (
loader.async_get_loaded_integration(hass, "an_after_dep_of_after_dep")
Expand Down Expand Up @@ -456,9 +456,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:

assert order == [
"http",
"an_after_dep",
"frontend",
"recorder",
"an_after_dep",
"normal_integration",
]

Expand Down Expand Up @@ -1577,10 +1577,8 @@ async def test_no_base_platforms_loaded_before_recorder(hass: HomeAssistant) ->
assert not isinstance(integrations_or_excs, Exception)
integrations[domain] = integration

integrations_all_dependencies = (
await loader.resolve_integrations_after_dependencies(
hass, integrations.values(), ignore_exceptions=True
)
integrations_all_dependencies = await loader.resolve_integrations_dependencies(
hass, integrations.values()
)
all_integrations = integrations.copy()
all_integrations.update(
Expand Down