haybale-haystack 0.3.0__tar.gz → 0.3.2__tar.gz
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.
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/.gitignore +3 -1
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/PKG-INFO +4 -4
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/QUICKREF.md +1 -1
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/editors/haystack_editor.py +94 -1
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/graph_entry.py +14 -1
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/haybale.toml +1 -1
- haybale_haystack-0.3.2/haybale_haystack/settings/graph_run_settings.py +27 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/pyproject.toml +4 -4
- haybale_haystack-0.3.0/haybale_haystack/settings/graph_run_settings.py +0 -16
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/README.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/OVERVIEW.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/__init__.py +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.editor.HaystackEditor.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.farmhand.close_graph.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.farmhand.compile_graph.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.farmhand.create_graph.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.farmhand.list_graphs.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.farmhand.open_graph.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.farmhand.rename_graph.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.farmhand.save_graph.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.farmhand.start_graph.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.farmhand.stop_graph.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.panel.EditMacroMenuPanel.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.panel.GraphRunSettingsPanel.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.panel.OpenInHaystackMenuPanel.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.panel.UpdateMacroMenuPanel.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.setting.HaystackSettings.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/docs/haybale-haystack.state.HaystackState.md +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/editors/__init__.py +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/farmhands/__init__.py +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/farmhands/graph_tools.py +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/panels/__init__.py +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/panels/file_browser/menu/file.py +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/panels/graph/menu/macro.py +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/panels/properties/introspect/graph_run_settings_panel.py +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/persistence.py +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/settings/__init__.py +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/settings/haystack_settings.py +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/signals.py +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/state/__init__.py +0 -0
- {haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/state/haystack_state.py +0 -0
|
@@ -220,6 +220,8 @@ packages/haywire-core/src/haywire/_baked_docs/*
|
|
|
220
220
|
# Haywire project config (user-local, not repo state)
|
|
221
221
|
.haywire/
|
|
222
222
|
|
|
223
|
-
# Local
|
|
223
|
+
# Local symlinks to external dev projects (machine-specific paths)
|
|
224
224
|
barn/haybale-visiongraph
|
|
225
|
+
barn/haybale-spandrel
|
|
225
226
|
|
|
227
|
+
assets/*
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: haybale-haystack
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: File-centric multi-graph manager
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: graph-management
|
|
7
7
|
Requires-Python: >=3.12
|
|
8
|
-
Requires-Dist: haybale-graph-editor>=0.3.
|
|
9
|
-
Requires-Dist: haybale-studio>=0.3.
|
|
10
|
-
Requires-Dist: haywire-core>=0.3.
|
|
8
|
+
Requires-Dist: haybale-graph-editor>=0.3.2
|
|
9
|
+
Requires-Dist: haybale-studio>=0.3.2
|
|
10
|
+
Requires-Dist: haywire-core>=0.3.2
|
|
11
11
|
Requires-Dist: nicegui>=3.18.0
|
|
12
12
|
Requires-Dist: toml>=0.10.2
|
{haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/editors/haystack_editor.py
RENAMED
|
@@ -8,6 +8,7 @@ from nicegui import ui
|
|
|
8
8
|
|
|
9
9
|
from haywire.core.access import AccessTier, LevelMode
|
|
10
10
|
from haywire.ui import elements as hui
|
|
11
|
+
from haywire.ui.components.popup import Popup
|
|
11
12
|
from haywire.ui.editor import BaseEditor, SlotName, editor
|
|
12
13
|
from haywire.core.session import (
|
|
13
14
|
IAppState,
|
|
@@ -27,6 +28,7 @@ from haywire.core.signals import (
|
|
|
27
28
|
)
|
|
28
29
|
from haywire.ui.modals import confirm_modal, pick_modal, rename_modal
|
|
29
30
|
|
|
31
|
+
from haybale_graph_editor.notices import GraphNotice, GraphNoticesChanged
|
|
30
32
|
from haybale_graph_editor.state.edit_state import EditState
|
|
31
33
|
from haybale_graph_editor.state.graph_app_state import GraphAppState
|
|
32
34
|
from haybale_graph_editor.editors.graph_editor import GraphEditor, definition_path
|
|
@@ -75,12 +77,16 @@ class HaystackEditor(BaseEditor):
|
|
|
75
77
|
def __init__(self, wrapper):
|
|
76
78
|
super().__init__(wrapper)
|
|
77
79
|
self._list_container = None
|
|
80
|
+
self._dismissed_notices: set[tuple[str, str]] = set()
|
|
81
|
+
self._notice_popups: list[Popup] = []
|
|
78
82
|
|
|
79
83
|
# ------------------------------------------------------------------
|
|
80
84
|
# Signal-bus subscriptions / draw
|
|
81
85
|
# ------------------------------------------------------------------
|
|
82
86
|
|
|
83
|
-
@redraw_on(
|
|
87
|
+
@redraw_on(
|
|
88
|
+
ActiveGraphMoved, GraphDataMutated, GraphUnsavedChanged, HaystackReloaded, GraphNoticesChanged
|
|
89
|
+
)
|
|
84
90
|
def _refresh_on_state_move(self, context: "SessionContext", event) -> None:
|
|
85
91
|
"""Empty body — the decorator triggers ``wrapper.redraw()`` after
|
|
86
92
|
this returns, which re-runs ``draw`` and ``_render_list``."""
|
|
@@ -225,6 +231,7 @@ class HaystackEditor(BaseEditor):
|
|
|
225
231
|
if self._list_container is None:
|
|
226
232
|
return
|
|
227
233
|
self._list_container.clear()
|
|
234
|
+
self._delete_notice_popups()
|
|
228
235
|
|
|
229
236
|
app = context.app
|
|
230
237
|
if app is None:
|
|
@@ -309,6 +316,8 @@ class HaystackEditor(BaseEditor):
|
|
|
309
316
|
on_click=lambda eid=eid: self._on_start_execution(eid, context),
|
|
310
317
|
)
|
|
311
318
|
|
|
319
|
+
self._render_notices(eid, context)
|
|
320
|
+
|
|
312
321
|
# Dirty dot — amber when unsaved, hidden when clean
|
|
313
322
|
if is_unsaved:
|
|
314
323
|
ui.element("div").classes("w-2 h-2 rounded-full flex-shrink-0 bg-amber-400").style(
|
|
@@ -364,6 +373,89 @@ class HaystackEditor(BaseEditor):
|
|
|
364
373
|
on_click=lambda eid=eid: self._on_entry_delete(eid, context),
|
|
365
374
|
)
|
|
366
375
|
|
|
376
|
+
# ------------------------------------------------------------------
|
|
377
|
+
# graph notices
|
|
378
|
+
# ------------------------------------------------------------------
|
|
379
|
+
|
|
380
|
+
def _delete_notice_popups(self) -> None:
|
|
381
|
+
for popup in self._notice_popups:
|
|
382
|
+
popup.delete()
|
|
383
|
+
self._notice_popups.clear()
|
|
384
|
+
|
|
385
|
+
def _visible_notices(self, binding_id: str, context: "SessionContext") -> list[GraphNotice]:
|
|
386
|
+
"""Return the notices on a graph that this editor has not dismissed."""
|
|
387
|
+
posted = list(context.app_data[GraphAppState].notices(binding_id))
|
|
388
|
+
return [n for n in posted if (binding_id, n.key) not in self._dismissed_notices]
|
|
389
|
+
|
|
390
|
+
def _render_notices(self, binding_id: str, context: "SessionContext") -> None:
|
|
391
|
+
"""Draw the notice icon, tinted warning, and the popup listing each notice and its action."""
|
|
392
|
+
notices = self._visible_notices(binding_id, context)
|
|
393
|
+
if not notices:
|
|
394
|
+
return
|
|
395
|
+
popup = Popup(
|
|
396
|
+
title="Notices", width="26rem", closable=True, backdrop_click_close=True, escape_close=True
|
|
397
|
+
)
|
|
398
|
+
self._notice_popups.append(popup)
|
|
399
|
+
with popup:
|
|
400
|
+
for notice in notices:
|
|
401
|
+
self._render_notice_line(binding_id, notice, popup, context)
|
|
402
|
+
icons = {n.icon for n in notices}
|
|
403
|
+
shared = icons.pop() if len(icons) == 1 else None
|
|
404
|
+
btn = ui.button().props("flat round dense size=xs data-hw-mark=graph-notice")
|
|
405
|
+
with btn:
|
|
406
|
+
# The icon carries the opt-out: the .hw-panel dim rule beats an inline colour.
|
|
407
|
+
ui.icon(shared or hui.icon.notice).classes("hw-use-props-color hw-text-warning")
|
|
408
|
+
btn.tooltip("\n".join(n.text for n in notices))
|
|
409
|
+
btn.on("click.stop", popup.open)
|
|
410
|
+
|
|
411
|
+
def _render_notice_line(
|
|
412
|
+
self, binding_id: str, notice: GraphNotice, popup: Popup, context: "SessionContext"
|
|
413
|
+
) -> None:
|
|
414
|
+
with (
|
|
415
|
+
ui.column()
|
|
416
|
+
.classes("w-full gap-1 p-2 rounded")
|
|
417
|
+
.style(
|
|
418
|
+
"border-left: 3px solid var(--hw-warning);"
|
|
419
|
+
" background: color-mix(in srgb, var(--hw-warning) 12%, transparent)"
|
|
420
|
+
)
|
|
421
|
+
):
|
|
422
|
+
with ui.row().classes("w-full items-start gap-2 no-wrap"):
|
|
423
|
+
ui.icon(notice.icon or hui.icon.notice, size="sm").classes(
|
|
424
|
+
"hw-use-props-color hw-text-warning"
|
|
425
|
+
).props("data-hw-mark=graph-notice-line-icon")
|
|
426
|
+
ui.label(notice.text).classes("flex-1 min-w-0 text-sm")
|
|
427
|
+
if notice.dismissable:
|
|
428
|
+
hui.icon_action(
|
|
429
|
+
hui.icon.close,
|
|
430
|
+
tooltip="Dismiss",
|
|
431
|
+
on_click=lambda k=notice.key: self._dismiss_notice(binding_id, k, context),
|
|
432
|
+
)
|
|
433
|
+
if notice.action is not None and notice.action_label and context.can_access(notice.requires):
|
|
434
|
+
with ui.row().classes("w-full justify-end"):
|
|
435
|
+
hui.button(
|
|
436
|
+
notice.action_label,
|
|
437
|
+
on_click=lambda n=notice: self._run_notice_action(n, popup, context),
|
|
438
|
+
).props("data-hw-mark=graph-notice-action").classes("w-auto")
|
|
439
|
+
|
|
440
|
+
def _run_notice_action(self, notice: GraphNotice, popup: Popup, context: "SessionContext") -> None:
|
|
441
|
+
"""Run a notice's action with this session's context, then close the popup."""
|
|
442
|
+
client = ui.context.client
|
|
443
|
+
popup.close()
|
|
444
|
+
if notice.action is None:
|
|
445
|
+
return
|
|
446
|
+
try:
|
|
447
|
+
notice.action(context)
|
|
448
|
+
except Exception as exc:
|
|
449
|
+
logger.warning(f"HaystackEditor: notice action {notice.key} failed: {exc}")
|
|
450
|
+
with client:
|
|
451
|
+
ui.notify(f"{notice.action_label or 'Action'} failed: {exc}", type="negative")
|
|
452
|
+
|
|
453
|
+
def _dismiss_notice(self, binding_id: str, key: str, context: "SessionContext") -> None:
|
|
454
|
+
"""Hide a notice in this editor instance only."""
|
|
455
|
+
self._dismissed_notices.add((binding_id, key))
|
|
456
|
+
# The list redraw deletes the popup (and this button's slot) holding the handler.
|
|
457
|
+
self._render_list(context)
|
|
458
|
+
|
|
367
459
|
# ------------------------------------------------------------------
|
|
368
460
|
# per-entry file actions
|
|
369
461
|
# ------------------------------------------------------------------
|
|
@@ -899,4 +991,5 @@ class HaystackEditor(BaseEditor):
|
|
|
899
991
|
# ------------------------------------------------------------------
|
|
900
992
|
|
|
901
993
|
def cleanup(self) -> None:
|
|
994
|
+
self._delete_notice_popups()
|
|
902
995
|
self._list_container = None
|
|
@@ -152,7 +152,12 @@ class GraphEntry(GraphContainer):
|
|
|
152
152
|
)
|
|
153
153
|
|
|
154
154
|
library_state_container = get_library_state_container()
|
|
155
|
-
interpreter = Interpreter(
|
|
155
|
+
interpreter = Interpreter(
|
|
156
|
+
library_state_container=library_state_container,
|
|
157
|
+
exception_bail=lambda: self.run_settings.on_exception_bail,
|
|
158
|
+
# Stopping waits for the runner threads, so it cannot run on the runner that bailed.
|
|
159
|
+
on_bail_run=lambda: self.graph._validation.call_soon(self._stop_after_bail),
|
|
160
|
+
)
|
|
156
161
|
try:
|
|
157
162
|
interpreter.load_graph(self.graph)
|
|
158
163
|
except RuntimeError as exc:
|
|
@@ -179,6 +184,14 @@ class GraphEntry(GraphContainer):
|
|
|
179
184
|
self.start()
|
|
180
185
|
return result
|
|
181
186
|
|
|
187
|
+
def _stop_after_bail(self) -> None:
|
|
188
|
+
"""Stop the run after a worker exception bailed it, and tell every session's haystack UI."""
|
|
189
|
+
if self.haystack is None:
|
|
190
|
+
self.stop_execution()
|
|
191
|
+
return
|
|
192
|
+
self.haystack.stop_execution(self)
|
|
193
|
+
self.haystack._broadcast_data_mutated()
|
|
194
|
+
|
|
182
195
|
def stop_execution(self) -> None:
|
|
183
196
|
"""Stop execution and shut down the Interpreter."""
|
|
184
197
|
if not self.is_executing:
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from haywire.core.settings import setting
|
|
2
|
+
from haywire.core.settings.settings import Settings
|
|
3
|
+
from haywire.barn.builtin.types import BOOL, CHOICES
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class GraphRunSettings(Settings):
|
|
7
|
+
"""Per-entry run policy. Persisted in the haystack TOML ``[graphs.run]`` table."""
|
|
8
|
+
|
|
9
|
+
autorestart = setting[BOOL](
|
|
10
|
+
False,
|
|
11
|
+
label="Auto-restart",
|
|
12
|
+
description=(
|
|
13
|
+
"Restart this graph automatically after it is stopped by a "
|
|
14
|
+
"structural change that requires recompilation."
|
|
15
|
+
),
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
on_exception_bail = setting[CHOICES](
|
|
19
|
+
"branch",
|
|
20
|
+
label="On exception, bail",
|
|
21
|
+
description=(
|
|
22
|
+
"How far a run gives up when a node raises: 'branch' ends the current branch "
|
|
23
|
+
"(a loop goes on with its next item), 'frame' ends the current frame, 'run' stops "
|
|
24
|
+
"the graph. The failing node is retried at its next evaluation either way."
|
|
25
|
+
),
|
|
26
|
+
widget_config={"options": ["branch", "frame", "run"]},
|
|
27
|
+
)
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "haybale-haystack"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.2"
|
|
4
4
|
description = "File-centric multi-graph manager"
|
|
5
5
|
requires-python = ">=3.12"
|
|
6
6
|
license = {text = "MIT"}
|
|
7
7
|
|
|
8
8
|
dependencies = [
|
|
9
|
-
"haywire-core>=0.3.
|
|
10
|
-
"haybale-studio>=0.3.
|
|
11
|
-
"haybale-graph-editor>=0.3.
|
|
9
|
+
"haywire-core>=0.3.2",
|
|
10
|
+
"haybale-studio>=0.3.2",
|
|
11
|
+
"haybale-graph-editor>=0.3.2",
|
|
12
12
|
"nicegui>=3.18.0",
|
|
13
13
|
"toml>=0.10.2",
|
|
14
14
|
]
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
from haywire.core.settings import setting
|
|
2
|
-
from haywire.core.settings.settings import Settings
|
|
3
|
-
from haywire.barn.builtin.types import BOOL
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class GraphRunSettings(Settings):
|
|
7
|
-
"""Per-entry run policy. Persisted in the haystack TOML ``[graphs.run]`` table."""
|
|
8
|
-
|
|
9
|
-
autorestart = setting[BOOL](
|
|
10
|
-
False,
|
|
11
|
-
label="Auto-restart",
|
|
12
|
-
description=(
|
|
13
|
-
"Restart this graph automatically after it is stopped by a "
|
|
14
|
-
"structural change that requires recompilation."
|
|
15
|
-
),
|
|
16
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/panels/file_browser/menu/file.py
RENAMED
|
File without changes
|
{haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/panels/graph/menu/macro.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{haybale_haystack-0.3.0 → haybale_haystack-0.3.2}/haybale_haystack/settings/haystack_settings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|