mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 19:27:45 +00:00
Use common helper function in resolve integration dependencies (#140989)
Extract to helper function in resolve integration dependencies
This commit is contained in:
parent
eee6e8a2c3
commit
efbb94a1b1
@ -1447,31 +1447,13 @@ async def resolve_integrations_dependencies(
|
|||||||
|
|
||||||
Detects circular dependencies and missing integrations.
|
Detects circular dependencies and missing integrations.
|
||||||
"""
|
"""
|
||||||
resolved = _ResolveDependenciesCache()
|
return await _resolve_integrations_dependencies(
|
||||||
|
hass,
|
||||||
async def _resolve_deps_catch_exceptions(itg: Integration) -> set[str] | None:
|
"resolve dependencies",
|
||||||
try:
|
integrations,
|
||||||
return await _do_resolve_dependencies(itg, cache=resolved)
|
cache=_ResolveDependenciesCache(),
|
||||||
except Exception as exc: # noqa: BLE001
|
ignore_exceptions=False,
|
||||||
_LOGGER.error("Unable to resolve dependencies for %s: %s", itg.domain, exc)
|
|
||||||
return None
|
|
||||||
|
|
||||||
resolve_dependencies_tasks = {
|
|
||||||
itg.domain: create_eager_task(
|
|
||||||
_resolve_deps_catch_exceptions(itg),
|
|
||||||
name=f"resolve dependencies {itg.domain}",
|
|
||||||
loop=hass.loop,
|
|
||||||
)
|
)
|
||||||
for itg in integrations
|
|
||||||
}
|
|
||||||
|
|
||||||
result = await asyncio.gather(*resolve_dependencies_tasks.values())
|
|
||||||
|
|
||||||
return {
|
|
||||||
domain: deps
|
|
||||||
for domain, deps in zip(resolve_dependencies_tasks, result, strict=True)
|
|
||||||
if deps is not None
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async def resolve_integrations_after_dependencies(
|
async def resolve_integrations_after_dependencies(
|
||||||
@ -1485,26 +1467,46 @@ async def resolve_integrations_after_dependencies(
|
|||||||
|
|
||||||
Detects circular dependencies and missing integrations.
|
Detects circular dependencies and missing integrations.
|
||||||
"""
|
"""
|
||||||
resolved: dict[Integration, set[str] | Exception] = {}
|
return await _resolve_integrations_dependencies(
|
||||||
|
hass,
|
||||||
|
"resolve (after) dependencies",
|
||||||
|
integrations,
|
||||||
|
cache={},
|
||||||
|
possible_after_dependencies=possible_after_dependencies,
|
||||||
|
ignore_exceptions=ignore_exceptions,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def _resolve_integrations_dependencies(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
name: str,
|
||||||
|
integrations: Iterable[Integration],
|
||||||
|
*,
|
||||||
|
cache: _ResolveDependenciesCacheProtocol,
|
||||||
|
possible_after_dependencies: set[str] | None | UndefinedType = UNDEFINED,
|
||||||
|
ignore_exceptions: bool,
|
||||||
|
) -> dict[str, set[str]]:
|
||||||
|
"""Resolve all dependencies, possibly including after_dependencies, for integrations.
|
||||||
|
|
||||||
|
Detects circular dependencies and missing integrations.
|
||||||
|
"""
|
||||||
|
|
||||||
async def _resolve_deps_catch_exceptions(itg: Integration) -> set[str] | None:
|
async def _resolve_deps_catch_exceptions(itg: Integration) -> set[str] | None:
|
||||||
try:
|
try:
|
||||||
return await _do_resolve_dependencies(
|
return await _resolve_integration_dependencies(
|
||||||
itg,
|
itg,
|
||||||
cache=resolved,
|
cache=cache,
|
||||||
possible_after_dependencies=possible_after_dependencies,
|
possible_after_dependencies=possible_after_dependencies,
|
||||||
ignore_exceptions=ignore_exceptions,
|
ignore_exceptions=ignore_exceptions,
|
||||||
)
|
)
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
_LOGGER.error(
|
_LOGGER.error("Unable to %s for %s: %s", name, itg.domain, exc)
|
||||||
"Unable to resolve (after) dependencies for %s: %s", itg.domain, exc
|
|
||||||
)
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
resolve_dependencies_tasks = {
|
resolve_dependencies_tasks = {
|
||||||
itg.domain: create_eager_task(
|
itg.domain: create_eager_task(
|
||||||
_resolve_deps_catch_exceptions(itg),
|
_resolve_deps_catch_exceptions(itg),
|
||||||
name=f"resolve after dependencies {itg.domain}",
|
name=f"{name} {itg.domain}",
|
||||||
loop=hass.loop,
|
loop=hass.loop,
|
||||||
)
|
)
|
||||||
for itg in integrations
|
for itg in integrations
|
||||||
@ -1519,7 +1521,7 @@ async def resolve_integrations_after_dependencies(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def _do_resolve_dependencies(
|
async def _resolve_integration_dependencies(
|
||||||
itg: Integration,
|
itg: Integration,
|
||||||
*,
|
*,
|
||||||
cache: _ResolveDependenciesCacheProtocol,
|
cache: _ResolveDependenciesCacheProtocol,
|
||||||
@ -1542,7 +1544,7 @@ async def _do_resolve_dependencies(
|
|||||||
resolved = cache
|
resolved = cache
|
||||||
resolving: set[str] = set()
|
resolving: set[str] = set()
|
||||||
|
|
||||||
async def do_resolve_dependencies_impl(itg: Integration) -> set[str]:
|
async def resolve_dependencies_impl(itg: Integration) -> set[str]:
|
||||||
domain = itg.domain
|
domain = itg.domain
|
||||||
|
|
||||||
# If it's already resolved, no point doing it again.
|
# If it's already resolved, no point doing it again.
|
||||||
@ -1584,7 +1586,7 @@ async def _do_resolve_dependencies(
|
|||||||
all_dependencies.add(dep_domain)
|
all_dependencies.add(dep_domain)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
dep_dependencies = await do_resolve_dependencies_impl(dep_integration)
|
dep_dependencies = await resolve_dependencies_impl(dep_integration)
|
||||||
except CircularDependency as exc:
|
except CircularDependency as exc:
|
||||||
exc.extend_cycle(domain)
|
exc.extend_cycle(domain)
|
||||||
resolved[itg] = exc
|
resolved[itg] = exc
|
||||||
@ -1600,7 +1602,7 @@ async def _do_resolve_dependencies(
|
|||||||
resolved[itg] = all_dependencies
|
resolved[itg] = all_dependencies
|
||||||
return all_dependencies
|
return all_dependencies
|
||||||
|
|
||||||
return await do_resolve_dependencies_impl(itg)
|
return await resolve_dependencies_impl(itg)
|
||||||
|
|
||||||
|
|
||||||
class LoaderError(Exception):
|
class LoaderError(Exception):
|
||||||
|
@ -29,25 +29,25 @@ async def test_circular_component_dependencies(hass: HomeAssistant) -> None:
|
|||||||
mod_4 = mock_integration(hass, MockModule("mod4", dependencies=["mod2", "mod3"]))
|
mod_4 = mock_integration(hass, MockModule("mod4", dependencies=["mod2", "mod3"]))
|
||||||
all_domains = {"mod1", "mod2", "mod3", "mod4"}
|
all_domains = {"mod1", "mod2", "mod3", "mod4"}
|
||||||
|
|
||||||
deps = await loader._do_resolve_dependencies(mod_4, cache={})
|
deps = await loader._resolve_integration_dependencies(mod_4, cache={})
|
||||||
assert deps == {"mod1", "mod2", "mod3"}
|
assert deps == {"mod1", "mod2", "mod3"}
|
||||||
|
|
||||||
# Create a circular dependency
|
# Create a circular dependency
|
||||||
mock_integration(hass, MockModule("mod1", dependencies=["mod4"]))
|
mock_integration(hass, MockModule("mod1", dependencies=["mod4"]))
|
||||||
with pytest.raises(loader.CircularDependency):
|
with pytest.raises(loader.CircularDependency):
|
||||||
await loader._do_resolve_dependencies(mod_4, cache={})
|
await loader._resolve_integration_dependencies(mod_4, cache={})
|
||||||
|
|
||||||
# Create a different circular dependency
|
# Create a different circular dependency
|
||||||
mock_integration(hass, MockModule("mod1", dependencies=["mod3"]))
|
mock_integration(hass, MockModule("mod1", dependencies=["mod3"]))
|
||||||
with pytest.raises(loader.CircularDependency):
|
with pytest.raises(loader.CircularDependency):
|
||||||
await loader._do_resolve_dependencies(mod_4, cache={})
|
await loader._resolve_integration_dependencies(mod_4, cache={})
|
||||||
|
|
||||||
# Create a circular after_dependency
|
# Create a circular after_dependency
|
||||||
mock_integration(
|
mock_integration(
|
||||||
hass, MockModule("mod1", partial_manifest={"after_dependencies": ["mod4"]})
|
hass, MockModule("mod1", partial_manifest={"after_dependencies": ["mod4"]})
|
||||||
)
|
)
|
||||||
with pytest.raises(loader.CircularDependency):
|
with pytest.raises(loader.CircularDependency):
|
||||||
await loader._do_resolve_dependencies(
|
await loader._resolve_integration_dependencies(
|
||||||
mod_4,
|
mod_4,
|
||||||
cache={},
|
cache={},
|
||||||
possible_after_dependencies=all_domains,
|
possible_after_dependencies=all_domains,
|
||||||
@ -58,7 +58,7 @@ async def test_circular_component_dependencies(hass: HomeAssistant) -> None:
|
|||||||
hass, MockModule("mod1", partial_manifest={"after_dependencies": ["mod3"]})
|
hass, MockModule("mod1", partial_manifest={"after_dependencies": ["mod3"]})
|
||||||
)
|
)
|
||||||
with pytest.raises(loader.CircularDependency):
|
with pytest.raises(loader.CircularDependency):
|
||||||
await loader._do_resolve_dependencies(
|
await loader._resolve_integration_dependencies(
|
||||||
mod_4,
|
mod_4,
|
||||||
cache={},
|
cache={},
|
||||||
possible_after_dependencies=all_domains,
|
possible_after_dependencies=all_domains,
|
||||||
@ -72,7 +72,7 @@ async def test_circular_component_dependencies(hass: HomeAssistant) -> None:
|
|||||||
hass, MockModule("mod4", partial_manifest={"after_dependencies": ["mod2"]})
|
hass, MockModule("mod4", partial_manifest={"after_dependencies": ["mod2"]})
|
||||||
)
|
)
|
||||||
with pytest.raises(loader.CircularDependency):
|
with pytest.raises(loader.CircularDependency):
|
||||||
await loader._do_resolve_dependencies(
|
await loader._resolve_integration_dependencies(
|
||||||
mod_4,
|
mod_4,
|
||||||
cache={},
|
cache={},
|
||||||
possible_after_dependencies=all_domains,
|
possible_after_dependencies=all_domains,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user