dataeval-flow 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 (94) hide show
  1. dataeval_flow/__init__.py +93 -0
  2. dataeval_flow/__main__.py +149 -0
  3. dataeval_flow/_app/__init__.py +5 -0
  4. dataeval_flow/_app/_model/__init__.py +5 -0
  5. dataeval_flow/_app/_model/_coerce.py +126 -0
  6. dataeval_flow/_app/_model/_discover.py +171 -0
  7. dataeval_flow/_app/_model/_execution.py +108 -0
  8. dataeval_flow/_app/_model/_introspect.py +280 -0
  9. dataeval_flow/_app/_model/_item.py +213 -0
  10. dataeval_flow/_app/_model/_registry.py +255 -0
  11. dataeval_flow/_app/_model/_state.py +322 -0
  12. dataeval_flow/_app/_model/_undo.py +61 -0
  13. dataeval_flow/_app/_panes/__init__.py +35 -0
  14. dataeval_flow/_app/_panes/_config_pane.py +173 -0
  15. dataeval_flow/_app/_panes/_result_pane.py +125 -0
  16. dataeval_flow/_app/_panes/_task_pane.py +91 -0
  17. dataeval_flow/_app/_panes/_widgets.py +111 -0
  18. dataeval_flow/_app/_screens/__init__.py +25 -0
  19. dataeval_flow/_app/_screens/_base.py +242 -0
  20. dataeval_flow/_app/_screens/_detail.py +333 -0
  21. dataeval_flow/_app/_screens/_model.py +102 -0
  22. dataeval_flow/_app/_screens/_params.py +80 -0
  23. dataeval_flow/_app/_screens/_pathpicker.py +68 -0
  24. dataeval_flow/_app/_screens/_section.py +621 -0
  25. dataeval_flow/_app/_screens/_settings.py +183 -0
  26. dataeval_flow/_app/_viewmodel/__init__.py +15 -0
  27. dataeval_flow/_app/_viewmodel/_builder_vm.py +272 -0
  28. dataeval_flow/_app/_viewmodel/_model_vm.py +70 -0
  29. dataeval_flow/_app/_viewmodel/_rendering.py +189 -0
  30. dataeval_flow/_app/_viewmodel/_result_vm.py +210 -0
  31. dataeval_flow/_app/_viewmodel/_section_vm.py +224 -0
  32. dataeval_flow/_app/app.py +742 -0
  33. dataeval_flow/_app/cli.py +592 -0
  34. dataeval_flow/_logging.py +102 -0
  35. dataeval_flow/cache.py +1355 -0
  36. dataeval_flow/config/__init__.py +80 -0
  37. dataeval_flow/config/_loader.py +79 -0
  38. dataeval_flow/config/_merge.py +92 -0
  39. dataeval_flow/config/_models.py +115 -0
  40. dataeval_flow/config/_paths.py +85 -0
  41. dataeval_flow/config/schemas/__init__.py +112 -0
  42. dataeval_flow/config/schemas/_dataset.py +111 -0
  43. dataeval_flow/config/schemas/_extractor.py +119 -0
  44. dataeval_flow/config/schemas/_metadata.py +28 -0
  45. dataeval_flow/config/schemas/_preprocessor.py +18 -0
  46. dataeval_flow/config/schemas/_selection.py +100 -0
  47. dataeval_flow/config/schemas/_task.py +89 -0
  48. dataeval_flow/config/schemas/_workflow.py +135 -0
  49. dataeval_flow/dataset.py +635 -0
  50. dataeval_flow/embeddings.py +135 -0
  51. dataeval_flow/metadata.py +48 -0
  52. dataeval_flow/preprocessing.py +141 -0
  53. dataeval_flow/py.typed +0 -0
  54. dataeval_flow/runner.py +118 -0
  55. dataeval_flow/selection.py +50 -0
  56. dataeval_flow/workflow/__init__.py +328 -0
  57. dataeval_flow/workflow/_text_report.py +511 -0
  58. dataeval_flow/workflow/base.py +69 -0
  59. dataeval_flow/workflow/orchestrator.py +454 -0
  60. dataeval_flow/workflows/__init__.py +1 -0
  61. dataeval_flow/workflows/analysis/__init__.py +38 -0
  62. dataeval_flow/workflows/analysis/outputs.py +202 -0
  63. dataeval_flow/workflows/analysis/params.py +114 -0
  64. dataeval_flow/workflows/analysis/workflow.py +1313 -0
  65. dataeval_flow/workflows/cleaning/__init__.py +23 -0
  66. dataeval_flow/workflows/cleaning/outputs.py +200 -0
  67. dataeval_flow/workflows/cleaning/params.py +160 -0
  68. dataeval_flow/workflows/cleaning/report.py +304 -0
  69. dataeval_flow/workflows/cleaning/workflow.py +794 -0
  70. dataeval_flow/workflows/drift/__init__.py +1 -0
  71. dataeval_flow/workflows/drift/outputs.py +144 -0
  72. dataeval_flow/workflows/drift/params.py +332 -0
  73. dataeval_flow/workflows/drift/report.py +201 -0
  74. dataeval_flow/workflows/drift/workflow.py +647 -0
  75. dataeval_flow/workflows/ood/__init__.py +1 -0
  76. dataeval_flow/workflows/ood/outputs.py +134 -0
  77. dataeval_flow/workflows/ood/params.py +161 -0
  78. dataeval_flow/workflows/ood/report.py +311 -0
  79. dataeval_flow/workflows/ood/workflow.py +728 -0
  80. dataeval_flow/workflows/prioritization/__init__.py +1 -0
  81. dataeval_flow/workflows/prioritization/outputs.py +122 -0
  82. dataeval_flow/workflows/prioritization/params.py +124 -0
  83. dataeval_flow/workflows/prioritization/report.py +117 -0
  84. dataeval_flow/workflows/prioritization/workflow.py +587 -0
  85. dataeval_flow/workflows/splitting/__init__.py +25 -0
  86. dataeval_flow/workflows/splitting/outputs.py +101 -0
  87. dataeval_flow/workflows/splitting/params.py +61 -0
  88. dataeval_flow/workflows/splitting/report.py +485 -0
  89. dataeval_flow/workflows/splitting/workflow.py +371 -0
  90. dataeval_flow-0.1.0.dist-info/METADATA +305 -0
  91. dataeval_flow-0.1.0.dist-info/RECORD +94 -0
  92. dataeval_flow-0.1.0.dist-info/WHEEL +4 -0
  93. dataeval_flow-0.1.0.dist-info/entry_points.txt +2 -0
  94. dataeval_flow-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,80 @@
1
+ """Param form helpers for step-builder modals (transforms/selections)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from typing import Any
7
+
8
+ from textual.containers import Vertical
9
+ from textual.css.query import NoMatches
10
+ from textual.widgets import Checkbox, Input, Label, Select
11
+
12
+ from dataeval_flow._app._model._item import coerce_step_params, validate_step_params
13
+ from dataeval_flow._app._screens._base import _select_value
14
+
15
+ _log = logging.getLogger(__name__)
16
+
17
+
18
+ def build_param_form(container: Vertical, params: list[Any], prefix: str) -> None:
19
+ """Populate *container* with widgets for each parameter."""
20
+
21
+ container.remove_children()
22
+ if not params:
23
+ return
24
+ for p in params:
25
+ suffix = "" if p.required else " (optional)"
26
+ label_text = f"{p.name} [{p.type_hint}]{suffix}:"
27
+ widget_id = f"{prefix}-{p.name}"
28
+
29
+ if p.choices:
30
+ container.mount(Label(label_text))
31
+ options = [(c, c) for c in p.choices]
32
+ has_default = p.default is not None and str(p.default) in p.choices
33
+ container.mount(
34
+ Select(
35
+ options,
36
+ id=widget_id,
37
+ allow_blank=not p.required,
38
+ **({"value": str(p.default)} if has_default else {}), # type: ignore
39
+ **({"prompt": "(default)"} if not p.required and not has_default else {}),
40
+ )
41
+ )
42
+ elif p.type_hint == "bool":
43
+ default_val = p.default if isinstance(p.default, bool) else False
44
+ container.mount(Checkbox(label_text, value=default_val, id=widget_id))
45
+ else:
46
+ container.mount(Label(label_text))
47
+ placeholder = str(p.default) if p.default is not None else ""
48
+ container.mount(Input(placeholder=placeholder, id=widget_id))
49
+
50
+
51
+ def _read_param_values(container: Vertical, params: list[Any], prefix: str) -> dict[str, str | bool | None]:
52
+ """Read raw values from param form widgets into a plain dict."""
53
+ values: dict[str, str | bool | None] = {}
54
+ for p in params:
55
+ widget_id = f"{prefix}-{p.name}"
56
+ try:
57
+ if p.choices:
58
+ sel = container.query_one(f"#{widget_id}", Select)
59
+ values[p.name] = _select_value(sel) or None
60
+ elif p.type_hint == "bool":
61
+ cb = container.query_one(f"#{widget_id}", Checkbox)
62
+ values[p.name] = cb.value
63
+ else:
64
+ inp = container.query_one(f"#{widget_id}", Input)
65
+ values[p.name] = inp.value.strip() or None
66
+ except NoMatches:
67
+ _log.warning("Widget %s not found — skipping param '%s'", widget_id, p.name)
68
+ return values
69
+
70
+
71
+ def validate_param_form(container: Vertical, params: list[Any], prefix: str) -> list[str]:
72
+ """Validate the param form. Returns list of error messages."""
73
+ values = _read_param_values(container, params, prefix)
74
+ return validate_step_params(params, values)
75
+
76
+
77
+ def collect_param_form(container: Vertical, params: list[Any], prefix: str) -> dict[str, Any]:
78
+ """Read values from a dynamic param form."""
79
+ values = _read_param_values(container, params, prefix)
80
+ return coerce_step_params(params, values)
@@ -0,0 +1,68 @@
1
+ # ---------------------------------------------------------------------------
2
+ # Path picker (file/folder selection modal)
3
+ # ---------------------------------------------------------------------------
4
+
5
+
6
+ import contextlib
7
+ from typing import Any
8
+
9
+ from textual.app import ComposeResult, ScreenStackError
10
+ from textual.containers import Horizontal, Vertical
11
+ from textual.css.query import NoMatches
12
+ from textual.screen import ModalScreen
13
+ from textual.widgets import Button, DirectoryTree, Static
14
+
15
+
16
+ class PathPickerScreen(ModalScreen[str | None]):
17
+ """Unified file/folder picker.
18
+
19
+ - ``"file"``: selects files and directories (for loading configs).
20
+ - ``"folder"``: selects directories only (for browse buttons / save).
21
+ """
22
+
23
+ CSS = """
24
+ PathPickerScreen { align: center middle; }
25
+ #pp-dialog { width: 70; height: 30; border: round $accent 40%; background: $surface; padding: 1 2; }
26
+ #pp-tree { height: 1fr; margin: 1 0; }
27
+ #pp-selected { height: auto; margin: 0 0 1 0; }
28
+ #pp-buttons { height: auto; align: right middle; }
29
+ """
30
+ BINDINGS = [("escape", "cancel", "Cancel")]
31
+
32
+ def __init__(self, start_path: str = ".", mode: str = "folder", **kwargs: Any) -> None:
33
+ super().__init__(**kwargs)
34
+ self._start_path = start_path
35
+ self._selected_path = start_path
36
+ self._mode = mode
37
+
38
+ def compose(self) -> ComposeResult:
39
+ title = "Select File" if self._mode == "file" else "Select Directory"
40
+ with Vertical(id="pp-dialog"):
41
+ yield Static(f"[bold]{title}[/bold]")
42
+ yield DirectoryTree(self._start_path, id="pp-tree")
43
+ yield Static(f"Selected: {self._start_path}", id="pp-selected")
44
+ with Horizontal(id="pp-buttons"):
45
+ yield Button("Select", id="btn-pp-select", variant="primary")
46
+ yield Button("Cancel", id="btn-pp-cancel")
47
+
48
+ def _update_selected(self, path: str) -> None:
49
+ self._selected_path = path
50
+ with contextlib.suppress(NoMatches):
51
+ self.query_one("#pp-selected", Static).update(f"Selected: {self._selected_path}")
52
+
53
+ def on_directory_tree_file_selected(self, event: DirectoryTree.FileSelected) -> None:
54
+ if self._mode == "file":
55
+ self._update_selected(str(event.path))
56
+
57
+ def on_directory_tree_directory_selected(self, event: DirectoryTree.DirectorySelected) -> None:
58
+ self._update_selected(str(event.path))
59
+
60
+ def on_button_pressed(self, event: Button.Pressed) -> None:
61
+ if event.button.id == "btn-pp-select":
62
+ self.dismiss(self._selected_path)
63
+ elif event.button.id == "btn-pp-cancel":
64
+ self.dismiss(None)
65
+
66
+ def action_cancel(self) -> None:
67
+ with contextlib.suppress(ScreenStackError):
68
+ self.dismiss(None)