py-data-engine 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. data_engine/__init__.py +37 -0
  2. data_engine/application/__init__.py +39 -0
  3. data_engine/application/actions.py +42 -0
  4. data_engine/application/catalog.py +151 -0
  5. data_engine/application/control.py +213 -0
  6. data_engine/application/details.py +73 -0
  7. data_engine/application/runtime.py +449 -0
  8. data_engine/application/workspace.py +62 -0
  9. data_engine/authoring/__init__.py +14 -0
  10. data_engine/authoring/builder.py +31 -0
  11. data_engine/authoring/execution/__init__.py +6 -0
  12. data_engine/authoring/execution/app.py +6 -0
  13. data_engine/authoring/execution/context.py +82 -0
  14. data_engine/authoring/execution/continuous.py +176 -0
  15. data_engine/authoring/execution/grouped.py +106 -0
  16. data_engine/authoring/execution/logging.py +83 -0
  17. data_engine/authoring/execution/polling.py +135 -0
  18. data_engine/authoring/execution/runner.py +210 -0
  19. data_engine/authoring/execution/single.py +171 -0
  20. data_engine/authoring/flow.py +361 -0
  21. data_engine/authoring/helpers.py +160 -0
  22. data_engine/authoring/model.py +59 -0
  23. data_engine/authoring/primitives.py +430 -0
  24. data_engine/authoring/services.py +42 -0
  25. data_engine/devtools/__init__.py +3 -0
  26. data_engine/devtools/project_ast_map.py +503 -0
  27. data_engine/docs/__init__.py +1 -0
  28. data_engine/docs/sphinx_source/_static/custom.css +13 -0
  29. data_engine/docs/sphinx_source/api.rst +42 -0
  30. data_engine/docs/sphinx_source/conf.py +37 -0
  31. data_engine/docs/sphinx_source/guides/app-runtime-and-workspaces.md +397 -0
  32. data_engine/docs/sphinx_source/guides/authoring-flow-modules.md +215 -0
  33. data_engine/docs/sphinx_source/guides/configuring-flows.md +185 -0
  34. data_engine/docs/sphinx_source/guides/core-concepts.md +208 -0
  35. data_engine/docs/sphinx_source/guides/database-methods.md +107 -0
  36. data_engine/docs/sphinx_source/guides/duckdb-helpers.md +462 -0
  37. data_engine/docs/sphinx_source/guides/flow-context.md +538 -0
  38. data_engine/docs/sphinx_source/guides/flow-methods.md +206 -0
  39. data_engine/docs/sphinx_source/guides/getting-started.md +271 -0
  40. data_engine/docs/sphinx_source/guides/project-inventory.md +5683 -0
  41. data_engine/docs/sphinx_source/guides/project-map.md +118 -0
  42. data_engine/docs/sphinx_source/guides/recipes.md +268 -0
  43. data_engine/docs/sphinx_source/index.rst +22 -0
  44. data_engine/domain/__init__.py +92 -0
  45. data_engine/domain/actions.py +69 -0
  46. data_engine/domain/catalog.py +128 -0
  47. data_engine/domain/details.py +214 -0
  48. data_engine/domain/diagnostics.py +56 -0
  49. data_engine/domain/errors.py +104 -0
  50. data_engine/domain/inspection.py +99 -0
  51. data_engine/domain/logs.py +118 -0
  52. data_engine/domain/operations.py +172 -0
  53. data_engine/domain/operator.py +72 -0
  54. data_engine/domain/runs.py +155 -0
  55. data_engine/domain/runtime.py +279 -0
  56. data_engine/domain/source_state.py +17 -0
  57. data_engine/domain/support.py +54 -0
  58. data_engine/domain/time.py +23 -0
  59. data_engine/domain/workspace.py +159 -0
  60. data_engine/flow_modules/__init__.py +1 -0
  61. data_engine/flow_modules/flow_module_compiler.py +179 -0
  62. data_engine/flow_modules/flow_module_loader.py +201 -0
  63. data_engine/helpers/__init__.py +25 -0
  64. data_engine/helpers/duckdb.py +705 -0
  65. data_engine/hosts/__init__.py +1 -0
  66. data_engine/hosts/daemon/__init__.py +23 -0
  67. data_engine/hosts/daemon/app.py +221 -0
  68. data_engine/hosts/daemon/bootstrap.py +69 -0
  69. data_engine/hosts/daemon/client.py +465 -0
  70. data_engine/hosts/daemon/commands.py +64 -0
  71. data_engine/hosts/daemon/composition.py +310 -0
  72. data_engine/hosts/daemon/constants.py +15 -0
  73. data_engine/hosts/daemon/entrypoints.py +97 -0
  74. data_engine/hosts/daemon/lifecycle.py +191 -0
  75. data_engine/hosts/daemon/manager.py +272 -0
  76. data_engine/hosts/daemon/ownership.py +126 -0
  77. data_engine/hosts/daemon/runtime_commands.py +188 -0
  78. data_engine/hosts/daemon/runtime_control.py +31 -0
  79. data_engine/hosts/daemon/server.py +84 -0
  80. data_engine/hosts/daemon/shared_state.py +147 -0
  81. data_engine/hosts/daemon/state_sync.py +101 -0
  82. data_engine/platform/__init__.py +1 -0
  83. data_engine/platform/identity.py +35 -0
  84. data_engine/platform/local_settings.py +146 -0
  85. data_engine/platform/theme.py +259 -0
  86. data_engine/platform/workspace_models.py +190 -0
  87. data_engine/platform/workspace_policy.py +333 -0
  88. data_engine/runtime/__init__.py +1 -0
  89. data_engine/runtime/file_watch.py +185 -0
  90. data_engine/runtime/ledger_models.py +116 -0
  91. data_engine/runtime/runtime_db.py +938 -0
  92. data_engine/runtime/shared_state.py +523 -0
  93. data_engine/services/__init__.py +49 -0
  94. data_engine/services/daemon.py +64 -0
  95. data_engine/services/daemon_state.py +40 -0
  96. data_engine/services/flow_catalog.py +102 -0
  97. data_engine/services/flow_execution.py +48 -0
  98. data_engine/services/ledger.py +85 -0
  99. data_engine/services/logs.py +65 -0
  100. data_engine/services/runtime_binding.py +105 -0
  101. data_engine/services/runtime_execution.py +126 -0
  102. data_engine/services/runtime_history.py +62 -0
  103. data_engine/services/settings.py +58 -0
  104. data_engine/services/shared_state.py +28 -0
  105. data_engine/services/theme.py +59 -0
  106. data_engine/services/workspace_provisioning.py +224 -0
  107. data_engine/services/workspaces.py +74 -0
  108. data_engine/ui/__init__.py +3 -0
  109. data_engine/ui/cli/__init__.py +19 -0
  110. data_engine/ui/cli/app.py +161 -0
  111. data_engine/ui/cli/commands_doctor.py +178 -0
  112. data_engine/ui/cli/commands_run.py +80 -0
  113. data_engine/ui/cli/commands_start.py +100 -0
  114. data_engine/ui/cli/commands_workspace.py +97 -0
  115. data_engine/ui/cli/dependencies.py +44 -0
  116. data_engine/ui/cli/parser.py +56 -0
  117. data_engine/ui/gui/__init__.py +25 -0
  118. data_engine/ui/gui/app.py +116 -0
  119. data_engine/ui/gui/bootstrap.py +487 -0
  120. data_engine/ui/gui/bootstrapper.py +140 -0
  121. data_engine/ui/gui/cache_models.py +23 -0
  122. data_engine/ui/gui/control_support.py +185 -0
  123. data_engine/ui/gui/controllers/__init__.py +6 -0
  124. data_engine/ui/gui/controllers/flows.py +439 -0
  125. data_engine/ui/gui/controllers/runtime.py +245 -0
  126. data_engine/ui/gui/dialogs/__init__.py +12 -0
  127. data_engine/ui/gui/dialogs/messages.py +88 -0
  128. data_engine/ui/gui/dialogs/previews.py +222 -0
  129. data_engine/ui/gui/helpers/__init__.py +62 -0
  130. data_engine/ui/gui/helpers/inspection.py +81 -0
  131. data_engine/ui/gui/helpers/lifecycle.py +112 -0
  132. data_engine/ui/gui/helpers/scroll.py +28 -0
  133. data_engine/ui/gui/helpers/theming.py +87 -0
  134. data_engine/ui/gui/icons/dark_light.svg +12 -0
  135. data_engine/ui/gui/icons/documentation.svg +1 -0
  136. data_engine/ui/gui/icons/failed.svg +3 -0
  137. data_engine/ui/gui/icons/group.svg +4 -0
  138. data_engine/ui/gui/icons/home.svg +2 -0
  139. data_engine/ui/gui/icons/manual.svg +2 -0
  140. data_engine/ui/gui/icons/poll.svg +2 -0
  141. data_engine/ui/gui/icons/schedule.svg +4 -0
  142. data_engine/ui/gui/icons/settings.svg +2 -0
  143. data_engine/ui/gui/icons/started.svg +3 -0
  144. data_engine/ui/gui/icons/success.svg +3 -0
  145. data_engine/ui/gui/icons/view-log.svg +3 -0
  146. data_engine/ui/gui/icons.py +50 -0
  147. data_engine/ui/gui/launcher.py +48 -0
  148. data_engine/ui/gui/presenters/__init__.py +72 -0
  149. data_engine/ui/gui/presenters/docs.py +140 -0
  150. data_engine/ui/gui/presenters/logs.py +58 -0
  151. data_engine/ui/gui/presenters/runtime_projection.py +29 -0
  152. data_engine/ui/gui/presenters/sidebar.py +88 -0
  153. data_engine/ui/gui/presenters/steps.py +148 -0
  154. data_engine/ui/gui/presenters/workspace.py +39 -0
  155. data_engine/ui/gui/presenters/workspace_binding.py +75 -0
  156. data_engine/ui/gui/presenters/workspace_settings.py +182 -0
  157. data_engine/ui/gui/preview_models.py +37 -0
  158. data_engine/ui/gui/render_support.py +241 -0
  159. data_engine/ui/gui/rendering/__init__.py +12 -0
  160. data_engine/ui/gui/rendering/artifacts.py +95 -0
  161. data_engine/ui/gui/rendering/icons.py +50 -0
  162. data_engine/ui/gui/runtime.py +47 -0
  163. data_engine/ui/gui/state_support.py +193 -0
  164. data_engine/ui/gui/support.py +214 -0
  165. data_engine/ui/gui/surface.py +209 -0
  166. data_engine/ui/gui/theme.py +720 -0
  167. data_engine/ui/gui/widgets/__init__.py +34 -0
  168. data_engine/ui/gui/widgets/config.py +41 -0
  169. data_engine/ui/gui/widgets/logs.py +62 -0
  170. data_engine/ui/gui/widgets/panels.py +507 -0
  171. data_engine/ui/gui/widgets/sidebar.py +130 -0
  172. data_engine/ui/gui/widgets/steps.py +84 -0
  173. data_engine/ui/tui/__init__.py +5 -0
  174. data_engine/ui/tui/app.py +222 -0
  175. data_engine/ui/tui/bootstrap.py +475 -0
  176. data_engine/ui/tui/bootstrapper.py +117 -0
  177. data_engine/ui/tui/controllers/__init__.py +6 -0
  178. data_engine/ui/tui/controllers/flows.py +349 -0
  179. data_engine/ui/tui/controllers/runtime.py +167 -0
  180. data_engine/ui/tui/runtime.py +34 -0
  181. data_engine/ui/tui/state_support.py +141 -0
  182. data_engine/ui/tui/support.py +63 -0
  183. data_engine/ui/tui/theme.py +204 -0
  184. data_engine/ui/tui/widgets.py +123 -0
  185. data_engine/views/__init__.py +109 -0
  186. data_engine/views/actions.py +80 -0
  187. data_engine/views/artifacts.py +58 -0
  188. data_engine/views/flow_display.py +69 -0
  189. data_engine/views/logs.py +54 -0
  190. data_engine/views/models.py +96 -0
  191. data_engine/views/presentation.py +133 -0
  192. data_engine/views/runs.py +62 -0
  193. data_engine/views/state.py +39 -0
  194. data_engine/views/status.py +13 -0
  195. data_engine/views/text.py +109 -0
  196. py_data_engine-0.1.0.dist-info/METADATA +330 -0
  197. py_data_engine-0.1.0.dist-info/RECORD +200 -0
  198. py_data_engine-0.1.0.dist-info/WHEEL +5 -0
  199. py_data_engine-0.1.0.dist-info/entry_points.txt +2 -0
  200. py_data_engine-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,140 @@
1
+ """Bootstrap helpers for the desktop GUI application shell."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import os
7
+ import threading
8
+ from pathlib import Path
9
+ from queue import Queue
10
+ from uuid import uuid4
11
+ from typing import TYPE_CHECKING
12
+
13
+ from PySide6.QtCore import QTimer
14
+ from PySide6.QtGui import QGuiApplication
15
+
16
+ from data_engine.domain import DaemonStatusState, FlowLogEntry, OperationSessionState, OperatorSessionState, StepOutputIndex
17
+ from data_engine.platform.identity import APP_DISPLAY_NAME, APP_INTERNAL_ID
18
+ from data_engine.platform.workspace_models import DATA_ENGINE_WORKSPACE_COLLECTION_ROOT_ENV_VAR
19
+ from data_engine.ui.gui.bootstrap import GuiServices
20
+ from data_engine.ui.gui.controllers import GuiFlowController, GuiRuntimeController
21
+ from data_engine.ui.gui.helpers import register_client_session as helper_register_client_session
22
+ from data_engine.ui.gui.runtime import QueueLogHandler, UiSignals
23
+ from data_engine.ui.gui.surface import build_default_gui_services
24
+
25
+ if TYPE_CHECKING:
26
+ from data_engine.ui.gui.app import DataEngineWindow
27
+
28
+
29
+ def bootstrap_gui_window(window: "DataEngineWindow", *, theme_name: str, services: GuiServices | None = None) -> None:
30
+ """Bind one GUI window to its services, runtime state, and timers."""
31
+ window.setWindowTitle(APP_DISPLAY_NAME)
32
+ window.resize(1480, 920)
33
+ window.setMinimumSize(1180, 760)
34
+ window.services = services or build_default_gui_services(theme_name)
35
+ window.workspace_service = window.services.workspace_service
36
+ window.action_state_application = window.services.action_state_application
37
+ window.detail_application = window.services.detail_application
38
+ window.daemon_service = window.services.daemon_service
39
+ window.daemon_state_service = window.services.daemon_state_service
40
+ window.runtime_application = window.services.runtime_application
41
+ window.control_application = window.services.control_application
42
+ window.ledger_service = window.services.ledger_service
43
+ window.log_service = window.services.log_service
44
+ window.runtime_binding_service = window.services.runtime_binding_service
45
+ window.runtime_history_service = window.services.runtime_history_service
46
+ window.shared_state_service = window.services.shared_state_service
47
+ window.settings_service = window.services.settings_service
48
+ window.theme_service = window.services.theme_service
49
+ window.workspace_provisioning_service = window.services.workspace_provisioning_service
50
+ window.workspace_session_application = window.services.workspace_session_application
51
+ window.flow_catalog_application = window.services.flow_catalog_application
52
+ window.flow_controller = GuiFlowController(
53
+ workspace_session_application=window.workspace_session_application,
54
+ flow_catalog_application=window.flow_catalog_application,
55
+ log_service=window.log_service,
56
+ )
57
+ window.runtime_controller = GuiRuntimeController(
58
+ runtime_application=window.runtime_application,
59
+ daemon_service=window.daemon_service,
60
+ log_service=window.log_service,
61
+ )
62
+ window.theme_name = window.theme_service.resolve_name(theme_name)
63
+ env_collection_root = os.environ.get(DATA_ENGINE_WORKSPACE_COLLECTION_ROOT_ENV_VAR)
64
+ initial_override = None if env_collection_root and env_collection_root.strip() else window.settings_service.workspace_collection_root()
65
+ window.workspace_paths = window.workspace_service.resolve_paths(
66
+ workspace_collection_root=initial_override,
67
+ )
68
+ window._operator_session_state = OperatorSessionState.from_paths(window.workspace_paths, override_root=initial_override)
69
+ window.workspace_session_state = window.workspace_session_application.refresh_session(
70
+ workspace_paths=window.workspace_paths,
71
+ override_root=initial_override,
72
+ )
73
+ window.client_session_id = uuid4().hex
74
+
75
+ window.log_queue: Queue[FlowLogEntry] = Queue()
76
+ window.log_handler = QueueLogHandler(window.log_queue)
77
+ logger = logging.getLogger(APP_INTERNAL_ID)
78
+ logger.addHandler(window.log_handler)
79
+ logger.setLevel(logging.INFO)
80
+
81
+ window.signals = UiSignals()
82
+ window.signals.run_finished.connect(window._finish_run)
83
+ window.signals.runtime_finished.connect(window._finish_runtime)
84
+ window.signals.docs_build_finished.connect(window._finish_docs_build)
85
+ window.signals.daemon_startup_finished.connect(window._finish_daemon_startup)
86
+
87
+ window.engine_runtime_stop_event = threading.Event()
88
+ window.engine_flow_stop_event = threading.Event()
89
+ window.manual_flow_stop_events: dict[str, threading.Event] = {}
90
+ window.operation_row_widgets = []
91
+ window.operation_tracker = OperationSessionState.empty()
92
+ window.operation_flash_timers: list[QTimer] = []
93
+ window.sidebar_flow_widgets: dict[str, QFrame] = {}
94
+ window.sidebar_group_widgets: dict[str, QFrame] = {}
95
+ window.step_output_index = StepOutputIndex.empty()
96
+ window.runtime_binding = window.runtime_binding_service.open_binding(window.workspace_paths)
97
+ helper_register_client_session(window)
98
+ window.output_preview_dialog = None
99
+ window.config_preview_dialog = None
100
+ window.run_log_preview_dialog = None
101
+ window._docs_root_dir = None
102
+ window.docs_uses_webengine = False
103
+ window._docs_build_running = False
104
+ window.ui_closing = False
105
+ window._log_view_refresh_pending = False
106
+ window._action_buttons_refresh_pending = False
107
+ window._worker_threads: set[threading.Thread] = set()
108
+ window._worker_threads_lock = threading.RLock()
109
+ window._daemon_status = DaemonStatusState.empty()
110
+ window._last_daemon_spawn_attempt = 0.0
111
+ window._auto_daemon_enabled = False
112
+ window._daemon_startup_in_progress = False
113
+ window._pending_message_box: tuple[str, str, str] | None = None
114
+ window._message_box_scheduled = False
115
+ window._message_box_open = False
116
+ window._message_box_generation = 0
117
+ window._workspace_switch_generation = 0
118
+
119
+ window._build_window()
120
+ window._reload_workspace_options()
121
+ window._load_flows()
122
+ style_hints = QGuiApplication.styleHints()
123
+ if hasattr(style_hints, "colorSchemeChanged"):
124
+ style_hints.colorSchemeChanged.connect(window._sync_theme_to_system)
125
+
126
+ window.log_timer = QTimer(window)
127
+ window.log_timer.timeout.connect(window._poll_log_queue)
128
+ window.log_timer.start(50)
129
+ window.ui_refresh_timer = QTimer(window)
130
+ window.ui_refresh_timer.setSingleShot(True)
131
+ window.ui_refresh_timer.timeout.connect(window._flush_deferred_ui_updates)
132
+ window.operation_timer = QTimer(window)
133
+ window.operation_timer.timeout.connect(window._refresh_live_operation_durations)
134
+ window.operation_timer.start(100)
135
+ window.daemon_timer = QTimer(window)
136
+ window.daemon_timer.timeout.connect(window._sync_from_daemon)
137
+ window.daemon_timer.start(500)
138
+
139
+
140
+ __all__ = ["bootstrap_gui_window"]
@@ -0,0 +1,23 @@
1
+ """Explicit GUI-local cache models."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from PySide6.QtWidgets import QFrame, QLabel, QPushButton
10
+
11
+
12
+ @dataclass(frozen=True)
13
+ class OperationRowWidgets:
14
+ """Cached widget references for one operation row."""
15
+
16
+ row_card: "QFrame"
17
+ title_label: "QLabel"
18
+ duration_label: "QLabel"
19
+ inspect_button: "QPushButton | None"
20
+ operation_name: str
21
+
22
+
23
+ __all__ = ["OperationRowWidgets"]
@@ -0,0 +1,185 @@
1
+ """Flow, runtime, and log coordination helpers for the GUI shell."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from data_engine.domain import FlowLogEntry, FlowRunState, RuntimeStepEvent
8
+ from data_engine.ui.gui.dialogs import show_run_log_preview
9
+ from data_engine.ui.gui.preview_models import RunLogPreviewRequest
10
+ from data_engine.ui.gui.presenters import (
11
+ add_log_run_item as present_add_log_run_item,
12
+ apply_daemon_snapshot as present_apply_daemon_snapshot,
13
+ finish_daemon_startup as present_finish_daemon_startup,
14
+ refresh_log_view as present_refresh_log_view,
15
+ )
16
+
17
+ if TYPE_CHECKING:
18
+ from data_engine.ui.gui.app import DataEngineWindow
19
+
20
+
21
+ class GuiControlMixin:
22
+ """Shell coordination helpers for flows, runtime, daemon, and log refresh."""
23
+
24
+ def _load_flows(self: "DataEngineWindow") -> None:
25
+ self.flow_controller.load_flows(self)
26
+
27
+ def _populate_flow_tree(self: "DataEngineWindow") -> None:
28
+ self.flow_controller.populate_flow_tree(self)
29
+
30
+ def _select_flow(self: "DataEngineWindow", flow_name: str | None) -> None:
31
+ self.flow_controller.select_flow(self, flow_name)
32
+
33
+ def _refresh_selection(self: "DataEngineWindow", card) -> None:
34
+ self.flow_controller.refresh_selection(self, card)
35
+
36
+ def _refresh_summary(self: "DataEngineWindow") -> None:
37
+ self.flow_controller.refresh_summary(self)
38
+
39
+ def _refresh_action_buttons(self: "DataEngineWindow") -> None:
40
+ self.flow_controller.refresh_action_buttons(self)
41
+
42
+ def _reload_workspace_options(self: "DataEngineWindow") -> None:
43
+ self.flow_controller.reload_workspace_options(self)
44
+
45
+ def _workspace_selection_changed(self: "DataEngineWindow", index: int) -> None:
46
+ self.flow_controller.workspace_selection_changed(self, index)
47
+
48
+ def _switch_workspace(self: "DataEngineWindow", workspace_id: str) -> None:
49
+ self.flow_controller.switch_workspace(self, workspace_id)
50
+
51
+ def _refresh_lease_status(self: "DataEngineWindow") -> None:
52
+ self.flow_controller.refresh_lease_status(self)
53
+
54
+ def _request_control(self: "DataEngineWindow") -> None:
55
+ self.flow_controller.request_control(self)
56
+
57
+ def _update_engine_button(self: "DataEngineWindow") -> None:
58
+ self.flow_controller.update_engine_button(self)
59
+
60
+ def _set_flow_state(self: "DataEngineWindow", flow_name: str, state: str) -> None:
61
+ self.flow_controller.set_flow_state(self, flow_name, state)
62
+
63
+ def _set_flow_states(self: "DataEngineWindow", updates: dict[str, str]) -> None:
64
+ self.flow_controller.set_flow_states(self, updates)
65
+
66
+ def _sync_from_daemon(self: "DataEngineWindow") -> None:
67
+ self.runtime_controller.sync_from_daemon(self)
68
+
69
+ def _ensure_daemon_started(self: "DataEngineWindow") -> bool:
70
+ return self.runtime_controller.ensure_daemon_started(self)
71
+
72
+ def _start_daemon_worker(self: "DataEngineWindow") -> None:
73
+ self.runtime_controller.start_daemon_worker(self)
74
+
75
+ def _finish_daemon_startup(self: "DataEngineWindow", success: bool, error_text: str) -> None:
76
+ present_finish_daemon_startup(self, success, error_text)
77
+
78
+ def _apply_daemon_snapshot(self: "DataEngineWindow", snapshot) -> None:
79
+ present_apply_daemon_snapshot(self, snapshot)
80
+
81
+ def _rebuild_runtime_snapshot(self: "DataEngineWindow") -> None:
82
+ self.runtime_controller.rebuild_runtime_snapshot(self)
83
+
84
+ def _refresh_log_view(self: "DataEngineWindow", *, force_scroll_to_bottom: bool = False) -> None:
85
+ present_refresh_log_view(self, force_scroll_to_bottom=force_scroll_to_bottom)
86
+
87
+ def _add_log_run_item(self: "DataEngineWindow", run_group: FlowRunState) -> None:
88
+ present_add_log_run_item(self, run_group)
89
+
90
+ def _refresh_flows_requested(self: "DataEngineWindow") -> None:
91
+ self.flow_controller.refresh_flows_requested(self)
92
+
93
+ def _clear_logs(self: "DataEngineWindow") -> None:
94
+ self.flow_controller.clear_logs(self)
95
+
96
+ def _poll_log_queue(self: "DataEngineWindow") -> None:
97
+ from data_engine.ui.gui.surface import poll_log_queue as surface_poll_log_queue
98
+
99
+ surface_poll_log_queue(self)
100
+
101
+ def _show_run_log_preview(self: "DataEngineWindow", run_group: FlowRunState) -> None:
102
+ self.run_log_preview_dialog = show_run_log_preview(self, RunLogPreviewRequest.from_run(run_group))
103
+
104
+ def _show_run_error_details(self: "DataEngineWindow", run_group: FlowRunState, entry: FlowLogEntry) -> None:
105
+ """Show persisted failure detail for one failed run or step entry."""
106
+ event = entry.event
107
+ title, detail_text = self.runtime_history_service.error_text_for_entry(
108
+ self.runtime_binding.runtime_ledger,
109
+ run_group,
110
+ entry,
111
+ )
112
+ if event is not None and event.step_name is not None:
113
+ fallback_text = (
114
+ f'No persisted error detail was available for failed step "{event.step_name}" '
115
+ f'in run "{run_group.key[0]}".'
116
+ )
117
+ else:
118
+ fallback_text = f'No persisted error detail was available for failed run "{run_group.key[0]}".'
119
+ self._show_message_box(
120
+ title=title,
121
+ text=detail_text.strip() if isinstance(detail_text, str) and detail_text.strip() else fallback_text,
122
+ tone="error",
123
+ )
124
+
125
+ def _run_selected_flow(self: "DataEngineWindow") -> None:
126
+ if not self._has_authored_workspace():
127
+ self._sync_from_daemon()
128
+ return
129
+ card = self.flow_cards.get(self.selected_flow_name or "")
130
+ result = self.control_application.run_selected_flow(
131
+ paths=self.workspace_paths,
132
+ runtime_session=self.runtime_session,
133
+ selected_flow_name=card.name if card is not None else None,
134
+ selected_flow_valid=bool(card is not None and card.valid),
135
+ selected_flow_group=card.group if card is not None else None,
136
+ selected_flow_group_active=bool(card is not None and self._is_group_active(card.group)),
137
+ blocked_status_text=self.workspace_control_state.blocked_status_text,
138
+ timeout=2.0,
139
+ )
140
+ if result.error_text is not None:
141
+ self._show_message_box_later(
142
+ title="Data Engine",
143
+ text=result.error_text,
144
+ tone="error",
145
+ )
146
+ return
147
+ if not result.requested or card is None:
148
+ return
149
+ self._append_log_line(f"Starting one-time flow run: {card.name}", flow_name=card.name)
150
+ if result.sync_after:
151
+ self._sync_from_daemon()
152
+
153
+ def _start_runtime(self: "DataEngineWindow") -> None:
154
+ self.runtime_controller.start_runtime(self)
155
+
156
+ def _stop_runtime(self: "DataEngineWindow") -> None:
157
+ self.runtime_controller.stop_runtime(self)
158
+
159
+ def _toggle_runtime(self: "DataEngineWindow") -> None:
160
+ self.runtime_controller.toggle_runtime(self)
161
+
162
+ def _stop_pipeline(self: "DataEngineWindow") -> None:
163
+ self.runtime_controller.stop_pipeline(self)
164
+
165
+ def _safe_emit_run_finished(self: "DataEngineWindow", flow_name: str, results: object, error: object) -> None:
166
+ from data_engine.ui.gui.surface import safe_emit_run_finished as surface_safe_emit_run_finished
167
+
168
+ surface_safe_emit_run_finished(self, flow_name, results, error)
169
+
170
+ def _safe_emit_runtime_finished(self: "DataEngineWindow", flow_names: tuple[str, ...], results: object, error: object) -> None:
171
+ from data_engine.ui.gui.surface import safe_emit_runtime_finished as surface_safe_emit_runtime_finished
172
+
173
+ surface_safe_emit_runtime_finished(self, flow_names, results, error)
174
+
175
+ def _finish_run(self: "DataEngineWindow", flow_name: object, results: object, error: object) -> None:
176
+ self.runtime_controller.finish_run(self, flow_name, results, error)
177
+
178
+ def _finish_runtime(self: "DataEngineWindow", flow_names: object, results: object, error: object) -> None:
179
+ self.runtime_controller.finish_runtime(self, flow_names, results, error)
180
+
181
+ def _is_group_active(self: "DataEngineWindow", group_name: str) -> bool:
182
+ return self.runtime_controller.is_group_active(self, group_name)
183
+
184
+
185
+ __all__ = ["GuiControlMixin"]
@@ -0,0 +1,6 @@
1
+ """Controller objects for the desktop GUI surface."""
2
+
3
+ from data_engine.ui.gui.controllers.flows import GuiFlowController
4
+ from data_engine.ui.gui.controllers.runtime import GuiRuntimeController
5
+
6
+ __all__ = ["GuiFlowController", "GuiRuntimeController"]