dynamic-systems-testing-framework 1.0.1__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.
- dstf/__init__.py +41 -0
- dstf/__main__.py +10 -0
- dstf/authoring/__init__.py +13 -0
- dstf/authoring/builtin/__init__.py +32 -0
- dstf/authoring/builtin/accept.py +205 -0
- dstf/authoring/builtin/edit_criteria.py +479 -0
- dstf/authoring/builtin/edit_family.py +228 -0
- dstf/authoring/builtin/edit_on_plot.py +1354 -0
- dstf/authoring/builtin/edit_tree.py +1399 -0
- dstf/authoring/builtin/enqueue.py +144 -0
- dstf/authoring/capabilities.py +463 -0
- dstf/authoring/errors.py +49 -0
- dstf/authoring/family_rows.py +526 -0
- dstf/authoring/forms.py +631 -0
- dstf/authoring/layout.py +104 -0
- dstf/authoring/live_rows.py +337 -0
- dstf/authoring/live_runs.py +385 -0
- dstf/authoring/needle.py +127 -0
- dstf/authoring/picker_rows.py +92 -0
- dstf/authoring/queue_rows.py +354 -0
- dstf/authoring/session.py +3016 -0
- dstf/authoring/shell/__init__.py +9 -0
- dstf/authoring/shell/actions.py +702 -0
- dstf/authoring/shell/app.py +53 -0
- dstf/authoring/shell/drawer_controls.py +190 -0
- dstf/authoring/shell/family_fold.py +468 -0
- dstf/authoring/shell/figure_hook.py +249 -0
- dstf/authoring/shell/grips.js +1000 -0
- dstf/authoring/shell/header.py +783 -0
- dstf/authoring/shell/live_view.py +93 -0
- dstf/authoring/shell/picker.py +267 -0
- dstf/authoring/shell/placing.py +122 -0
- dstf/authoring/shell/plot_card.py +1171 -0
- dstf/authoring/shell/queue_panel.py +433 -0
- dstf/authoring/shell/rail.py +593 -0
- dstf/authoring/shell/shell.py +528 -0
- dstf/authoring/shell/stats_card.py +501 -0
- dstf/authoring/shell/strip.py +204 -0
- dstf/authoring/shell/style.py +721 -0
- dstf/authoring/shell/suite.py +277 -0
- dstf/authoring/shell/suite_grid.js +414 -0
- dstf/authoring/shell/suite_grid.py +373 -0
- dstf/authoring/shell/tab_theme.py +110 -0
- dstf/authoring/shell/tabstate.py +146 -0
- dstf/authoring/shell/test_list.py +179 -0
- dstf/authoring/shell/test_page.py +1404 -0
- dstf/authoring/shell/tree_card.py +1171 -0
- dstf/authoring/shell/variables_drawer.py +589 -0
- dstf/authoring/shell/widgets.py +188 -0
- dstf/authoring/situation.py +287 -0
- dstf/authoring/spec_document.py +215 -0
- dstf/authoring/spec_preview.py +83 -0
- dstf/authoring/suite_rows.py +99 -0
- dstf/authoring/tree_move.py +516 -0
- dstf/authoring/tree_pointer.py +33 -0
- dstf/authoring/tree_text.py +61 -0
- dstf/authoring/typed_number.js +64 -0
- dstf/authoring/typed_number.py +76 -0
- dstf/authoring/unscorable.py +141 -0
- dstf/authoring/variable_rows.py +216 -0
- dstf/backends/__init__.py +283 -0
- dstf/backends/base.py +1117 -0
- dstf/backends/common/__init__.py +1 -0
- dstf/backends/common/json_driver.py +484 -0
- dstf/backends/common/live_mat.py +369 -0
- dstf/backends/common/mat_reader.py +632 -0
- dstf/backends/common/proc_kill.py +238 -0
- dstf/backends/common/proc_output.py +20 -0
- dstf/backends/common/result_files.py +109 -0
- dstf/backends/common/result_variables.py +329 -0
- dstf/backends/common/statistics.py +39 -0
- dstf/backends/cross_backend.py +193 -0
- dstf/backends/dymola/__init__.py +5 -0
- dstf/backends/dymola/backend.py +776 -0
- dstf/backends/dymola/interface_loader.py +241 -0
- dstf/backends/dymola/log_parser.py +396 -0
- dstf/backends/dymola/persistent_backend.py +949 -0
- dstf/backends/fmpy/__init__.py +11 -0
- dstf/backends/fmpy/backend.py +443 -0
- dstf/backends/julia/__init__.py +27 -0
- dstf/backends/julia/backend.py +156 -0
- dstf/backends/julia/persistent_backend.py +541 -0
- dstf/backends/julia/run_persistent.jl +167 -0
- dstf/backends/julia/run_test.jl +146 -0
- dstf/backends/openmodelica/__init__.py +21 -0
- dstf/backends/openmodelica/backend.py +368 -0
- dstf/backends/openmodelica/init_xml.py +76 -0
- dstf/backends/openmodelica/log_parser.py +119 -0
- dstf/backends/openmodelica/mos_generator.py +228 -0
- dstf/backends/openmodelica/persistent_backend.py +1045 -0
- dstf/backends/openmodelica/session_loader.py +63 -0
- dstf/backends/persistent.py +1811 -0
- dstf/backends/pool.py +602 -0
- dstf/backends/progress.py +395 -0
- dstf/backends/python/__init__.py +11 -0
- dstf/backends/python/backend.py +141 -0
- dstf/backends/python/run_test.py +141 -0
- dstf/backends/run_metadata.py +103 -0
- dstf/backends/types.py +310 -0
- dstf/cli/__init__.py +12 -0
- dstf/cli/author_cmd.py +61 -0
- dstf/cli/baseline_cmds.py +341 -0
- dstf/cli/common.py +231 -0
- dstf/cli/diag_cmds.py +350 -0
- dstf/cli/main.py +561 -0
- dstf/cli/review.py +398 -0
- dstf/cli/run_cmds.py +589 -0
- dstf/cli/spec_cmds.py +123 -0
- dstf/comparison/__init__.py +13 -0
- dstf/comparison/algorithms.py +2127 -0
- dstf/comparison/builtins.py +291 -0
- dstf/comparison/comparator.py +1189 -0
- dstf/comparison/geometry.py +164 -0
- dstf/comparison/handles.py +1194 -0
- dstf/comparison/metric_tree.py +332 -0
- dstf/comparison/mode_schema.py +176 -0
- dstf/comparison/modes.py +788 -0
- dstf/comparison/registry.py +230 -0
- dstf/comparison/seeds.py +281 -0
- dstf/comparison/sides.py +158 -0
- dstf/comparison/snap.py +62 -0
- dstf/comparison/strict_keys.py +246 -0
- dstf/comparison/summaries.py +354 -0
- dstf/comparison/tree_eval.py +868 -0
- dstf/comparison/tree_spec.py +678 -0
- dstf/comparison/types.py +194 -0
- dstf/comparison/validator.py +232 -0
- dstf/config.py +815 -0
- dstf/discovery/__init__.py +0 -0
- dstf/discovery/json_recognizer.py +702 -0
- dstf/discovery/library_state.py +248 -0
- dstf/discovery/mo_parser.py +794 -0
- dstf/discovery/patch_apply.py +308 -0
- dstf/discovery/patch_envelope.py +63 -0
- dstf/discovery/plots.py +318 -0
- dstf/discovery/recognizer.py +103 -0
- dstf/discovery/scan_cache.py +154 -0
- dstf/discovery/spec_parser.py +538 -0
- dstf/discovery/spec_shape.py +122 -0
- dstf/discovery/spec_update.py +493 -0
- dstf/discovery/test_registry.py +488 -0
- dstf/discovery/unit_tests.py +95 -0
- dstf/figures/__init__.py +14 -0
- dstf/figures/assemble.py +48 -0
- dstf/figures/decimate.py +150 -0
- dstf/figures/families.py +289 -0
- dstf/figures/palette.py +170 -0
- dstf/figures/plotly.py +1413 -0
- dstf/figures/view.py +233 -0
- dstf/pipeline.py +435 -0
- dstf/plugins.py +104 -0
- dstf/reporting/__init__.py +0 -0
- dstf/reporting/console_report.py +187 -0
- dstf/reporting/context_builder.py +979 -0
- dstf/reporting/dashboard_render.py +534 -0
- dstf/reporting/junit_report.py +192 -0
- dstf/reporting/overlay_loader.py +708 -0
- dstf/reporting/report_suite.py +1059 -0
- dstf/reporting/rows.py +458 -0
- dstf/reporting/schema_export.py +413 -0
- dstf/reporting/stats_rows.py +321 -0
- dstf/reporting/status.py +388 -0
- dstf/reporting/templates/axes.js +61 -0
- dstf/reporting/templates/dashboard.html +284 -0
- dstf/reporting/templates/dashboard.js +604 -0
- dstf/reporting/templates/filters.js +100 -0
- dstf/reporting/templates/interactive.html +420 -0
- dstf/reporting/templates/report.js +116 -0
- dstf/reporting/templates/vendor/plotly.min.js +8 -0
- dstf/reporting/theme.py +324 -0
- dstf/reporting/tree_rows.py +73 -0
- dstf/reporting/verdicts.py +124 -0
- dstf/storage/__init__.py +0 -0
- dstf/storage/accept.py +216 -0
- dstf/storage/baseline.py +43 -0
- dstf/storage/batch_manifest.py +204 -0
- dstf/storage/ref_index.py +295 -0
- dstf/storage/reference_store.py +661 -0
- dstf/storage/roles.py +576 -0
- dstf/storage/run_stats.py +85 -0
- dynamic_systems_testing_framework-1.0.1.dist-info/METADATA +266 -0
- dynamic_systems_testing_framework-1.0.1.dist-info/RECORD +185 -0
- dynamic_systems_testing_framework-1.0.1.dist-info/WHEEL +4 -0
- dynamic_systems_testing_framework-1.0.1.dist-info/entry_points.txt +2 -0
- dynamic_systems_testing_framework-1.0.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""The tests as rows, grouped by package or flat (brief §3.2; DESIGN.md
|
|
2
|
+
"Tables"): the Tests drawer's list (the Suite page's is a table,
|
|
3
|
+
`suite_grid.py`). A row's verdict and its unsaved edits repaint in place;
|
|
4
|
+
the list is rebuilt only when the test set, the order or the layout
|
|
5
|
+
moves."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from collections.abc import Callable, Sequence
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
from nicegui import ui
|
|
14
|
+
from nicegui.elements.mixins.text_element import TextElement
|
|
15
|
+
|
|
16
|
+
from ...reporting.rows import unsaved_text
|
|
17
|
+
from ...reporting.status import SCORING_CLASS, SCORING_FAILED, classify_with_class
|
|
18
|
+
from ...reporting.theme import STATUS
|
|
19
|
+
from ..spec_document import edit_counts
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from .shell import Shell
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class Row:
|
|
27
|
+
"""One test's row: the elements a click or a rescore updates in place —
|
|
28
|
+
the whole list is never resent (roadmap §2 "the row model")."""
|
|
29
|
+
|
|
30
|
+
model_id: str
|
|
31
|
+
group: str
|
|
32
|
+
container: ui.row
|
|
33
|
+
name: ui.button
|
|
34
|
+
badge: ui.badge
|
|
35
|
+
#: ``N unsaved`` while the test has staged edits, hidden otherwise
|
|
36
|
+
edits: ui.label
|
|
37
|
+
verdict: str = "" # the classifier's word, "" while unscored
|
|
38
|
+
pending: int = 0 # the test's staged edits
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _package(model_id: str) -> str:
|
|
42
|
+
return model_id.rpartition(".")[0]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _name(model_id: str, short: bool) -> str:
|
|
46
|
+
return model_id.rsplit(".", 1)[-1] if short else model_id
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _full_name(button: ui.button, model_id: str) -> None:
|
|
50
|
+
"""A Full name, cut at its START (the stylesheet's `.dstf-cut-start`):
|
|
51
|
+
TRANSFORM's ids share long package prefixes, and cut at the end two of
|
|
52
|
+
them read alike. Drawn in place of Quasar's label, in the `.block` span
|
|
53
|
+
Quasar draws one in, the id in a `<bdi>`: the span is right-to-left,
|
|
54
|
+
and a bare `direction: rtl` moved a leading or trailing `_` or `.` to
|
|
55
|
+
the other end (Chromium); inside the isolate the id keeps its order.
|
|
56
|
+
Not isolates from `::before` / `::after`: those entered the button's
|
|
57
|
+
accessible name."""
|
|
58
|
+
with button, ui.element("span").classes("block dstf-cut-start"):
|
|
59
|
+
TextElement(tag="bdi", text=model_id)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class TestList:
|
|
63
|
+
"""The list's rows and group labels. ``current`` gets
|
|
64
|
+
``dstf-row-current`` on its row; ``marker`` prefixes every marker the
|
|
65
|
+
list sets: ``tests``, ``group:<g>``, ``<id>``."""
|
|
66
|
+
|
|
67
|
+
def __init__(
|
|
68
|
+
self,
|
|
69
|
+
shell: Shell,
|
|
70
|
+
*,
|
|
71
|
+
on_open: Callable[[str], None],
|
|
72
|
+
current: str | None = None,
|
|
73
|
+
marker: str,
|
|
74
|
+
) -> None:
|
|
75
|
+
self.shell = shell
|
|
76
|
+
self.on_open = on_open
|
|
77
|
+
self.current = current
|
|
78
|
+
self.marker = marker
|
|
79
|
+
self.rows: dict[str, Row] = {}
|
|
80
|
+
self.groups: dict[str, ui.label] = {}
|
|
81
|
+
self.column = (
|
|
82
|
+
ui.column().classes("dstf-tests w-full gap-0").mark(f"{marker}tests")
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def rebuild(self, ids: Sequence[str], *, grouped: bool, short: bool) -> None:
|
|
86
|
+
"""The rows from scratch, in ``ids`` order — by package first when
|
|
87
|
+
``grouped``, each group under its label."""
|
|
88
|
+
self.column.clear()
|
|
89
|
+
self.rows, self.groups = {}, {}
|
|
90
|
+
position = {m: i for i, m in enumerate(ids)}
|
|
91
|
+
order = (
|
|
92
|
+
sorted(ids, key=lambda m: (_package(m), position[m])) if grouped else ids
|
|
93
|
+
)
|
|
94
|
+
with self.column:
|
|
95
|
+
current: str | None = None
|
|
96
|
+
for model_id in order:
|
|
97
|
+
group = _package(model_id)
|
|
98
|
+
if grouped and group != current:
|
|
99
|
+
current = group
|
|
100
|
+
self.groups[group] = (
|
|
101
|
+
ui.label(group or "(top level)")
|
|
102
|
+
.classes("dstf-group")
|
|
103
|
+
.mark(f"{self.marker}group:{group}")
|
|
104
|
+
)
|
|
105
|
+
with ui.row().classes(
|
|
106
|
+
"dstf-row items-center no-wrap gap-2 w-full"
|
|
107
|
+
) as container:
|
|
108
|
+
name = (
|
|
109
|
+
ui.button(
|
|
110
|
+
_name(model_id, short) if short else "",
|
|
111
|
+
on_click=lambda m=model_id: self.on_open(m),
|
|
112
|
+
)
|
|
113
|
+
.props("flat dense no-caps align=left")
|
|
114
|
+
.classes("dstf-name")
|
|
115
|
+
.mark(f"{self.marker}{model_id}")
|
|
116
|
+
)
|
|
117
|
+
# Cut with an ellipsis in a narrow drawer: the whole id
|
|
118
|
+
# is its title (on the props dict: a props string
|
|
119
|
+
# breaks on a quote).
|
|
120
|
+
name.props["title"] = model_id
|
|
121
|
+
if not short:
|
|
122
|
+
_full_name(name, model_id)
|
|
123
|
+
# `color=None`: a Quasar badge otherwise carries
|
|
124
|
+
# `bg-primary`, whose `!important` beats the inline
|
|
125
|
+
# status fill and paints every verdict blue (the review
|
|
126
|
+
# of Task 4 of the 2026-09-20 Test page plan, in
|
|
127
|
+
# Chromium).
|
|
128
|
+
edits = (
|
|
129
|
+
ui.label()
|
|
130
|
+
.classes("dstf-pill dstf-pill-warn dstf-pill-named")
|
|
131
|
+
.mark(f"{self.marker}edits:{model_id}")
|
|
132
|
+
)
|
|
133
|
+
badge = ui.badge("", color=None).classes("dstf-badge")
|
|
134
|
+
if model_id == self.current:
|
|
135
|
+
container.classes(add="dstf-row-current")
|
|
136
|
+
self.rows[model_id] = Row(
|
|
137
|
+
model_id, group, container, name, badge, edits
|
|
138
|
+
)
|
|
139
|
+
self.paint(model_id)
|
|
140
|
+
|
|
141
|
+
def paint(self, model_id: str) -> None:
|
|
142
|
+
"""One row's verdict: the badge's word and fill, the row's tint.
|
|
143
|
+
`…` while unscored; `scoring failed` for a model the open announced
|
|
144
|
+
with `error=True` (Task 1 of the 2026-09-16 Suite page plan). And
|
|
145
|
+
its staged edits: ``N unsaved``, as the Suite's Edits column."""
|
|
146
|
+
row = self.rows.get(model_id)
|
|
147
|
+
if row is None:
|
|
148
|
+
return
|
|
149
|
+
comp = self.shell.session.comparisons.get(model_id)
|
|
150
|
+
if comp is not None:
|
|
151
|
+
verdict, css = classify_with_class(comp)
|
|
152
|
+
elif model_id in self.shell.load.failed_models:
|
|
153
|
+
verdict, css = SCORING_FAILED, "sim-fail"
|
|
154
|
+
else:
|
|
155
|
+
verdict, css = "", SCORING_CLASS
|
|
156
|
+
row.verdict = verdict
|
|
157
|
+
row.pending = edit_counts(self.shell.session.spec.pending)[model_id]
|
|
158
|
+
row.edits.set_text(unsaved_text(row.pending))
|
|
159
|
+
row.edits.set_visibility(row.pending > 0)
|
|
160
|
+
row.badge.set_text(verdict or "…")
|
|
161
|
+
row.badge.style(f"background-color: var(--dstf-{css}-fill)")
|
|
162
|
+
# Add and remove, never replace: NiceGUI hides an element by appending
|
|
163
|
+
# a `hidden` class, and a replaced list dropped it — every filtered-out
|
|
164
|
+
# row came back on a rescore (the review's probe of Task 6 of the
|
|
165
|
+
# 2026-09-16 Suite page plan).
|
|
166
|
+
row.container.classes(
|
|
167
|
+
remove=" ".join(f"dstf-tint-{s}" for s in STATUS), add=f"dstf-tint-{css}"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
def filter(self, keep: Callable[[Row], bool]) -> None:
|
|
171
|
+
"""Visibility only — the rows stay. A group's label shows while any
|
|
172
|
+
of its rows does."""
|
|
173
|
+
shown_by_group: dict[str, bool] = {}
|
|
174
|
+
for row in self.rows.values():
|
|
175
|
+
shown = keep(row)
|
|
176
|
+
row.container.set_visibility(shown)
|
|
177
|
+
shown_by_group[row.group] = shown_by_group.get(row.group, False) or shown
|
|
178
|
+
for group, label in self.groups.items():
|
|
179
|
+
label.set_visibility(shown_by_group.get(group, False))
|