Skip to content

Commit

Permalink
warning messages for when applying a priority will cause a circular d…
Browse files Browse the repository at this point in the history
…ependency
  • Loading branch information
jsl12 committed Feb 10, 2025
1 parent b870596 commit ef5aa3e
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 8 deletions.
8 changes: 3 additions & 5 deletions appdaemon/app_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ async def check_app_config_files(self, update_actions: UpdateActions):
self.app_config.root.update(freshly_read_cfg.root)

if update_actions.apps.init_set:
# If there are any new apps, the dependency graph needs to be updated
# If there are any new/modified apps, the dependency graph needs to be updated
self.dependency_manager.app_deps.refresh_dep_graph()

if self.AD.threading.pin_apps:
Expand Down Expand Up @@ -921,8 +921,7 @@ def _process_import_paths(self):
package_parents = set(p.parent for p in top_packages_dirs)

# Combine import directories. Having the list sorted will prioritize parent folders over children during import
import_dirs = sorted(
module_parents | package_parents, reverse=True)
import_dirs = sorted(module_parents | package_parents, reverse=True)

for path in import_dirs:
self.add_to_import_path(path)
Expand Down Expand Up @@ -1088,8 +1087,7 @@ async def safe_create(self: "AppManagement"):
await self.AD.threading.calculate_pin_threads()

# Need to recalculate start order in case creating the app object fails
start_order = update_actions.apps.start_sort(
self.dependency_manager)
start_order = update_actions.apps.start_sort(self.dependency_manager, self.logger)
for app_name in start_order:
if isinstance((cfg := self.app_config.root[app_name]), AppConfig):
rel_path = self.app_rel_path(app_name)
Expand Down
3 changes: 2 additions & 1 deletion appdaemon/dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ def visit(node: str):
if node not in visited:
visit(node)
if cycle_detected:
raise CircularDependency(f"Visited {visited} already and was going visit {node} again")
deps = graph[node]
raise CircularDependency(f"Visited {visited} already, but {node} depends on {deps}")

return stack
13 changes: 11 additions & 2 deletions appdaemon/models/internal/app_management.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from logging import Logger
import uuid
from copy import copy, deepcopy
from dataclasses import dataclass, field
Expand All @@ -9,6 +10,7 @@
from ...dependency_manager import DependencyManager



class UpdateMode(Enum):
"""Used as an argument for :meth:`AppManagement.check_app_updates` to set the mode of the check.
Expand Down Expand Up @@ -62,7 +64,7 @@ def import_sort(self, dm: DependencyManager) -> list[str]:
order = [n for n in topo_sort(dm.python_deps.dep_graph) if n in items]
return order

def start_sort(self, dm: DependencyManager) -> list[str]:
def start_sort(self, dm: DependencyManager, logger: Logger = None) -> list[str]:
"""Finds the apps that need to be started.
Uses a dependency graph to sort the internal ``init`` and ``reload`` sets together
Expand All @@ -83,7 +85,14 @@ def start_sort(self, dm: DependencyManager) -> list[str]:

dep_graph = deepcopy(dm.app_deps.dep_graph)
for app, deps in dep_graph.items():
deps |= priority_deps.get(app, set())
# need to make sure the app isn't in it's own dependencies
for dep in priority_deps.get(app, set()):
sub_deps = find_all_dependents({app}, dm.app_deps.rev_graph)
if dep in sub_deps:
if logger is not None:
logger.warning(f'Applying priority will cause a circular dependency: {app} -> {dep}')
else:
deps.add(dep)

order = [n for n in topo_sort(dep_graph) if n in items]
return order
Expand Down

0 comments on commit ef5aa3e

Please sign in to comment.