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.
Files changed (185) hide show
  1. dstf/__init__.py +41 -0
  2. dstf/__main__.py +10 -0
  3. dstf/authoring/__init__.py +13 -0
  4. dstf/authoring/builtin/__init__.py +32 -0
  5. dstf/authoring/builtin/accept.py +205 -0
  6. dstf/authoring/builtin/edit_criteria.py +479 -0
  7. dstf/authoring/builtin/edit_family.py +228 -0
  8. dstf/authoring/builtin/edit_on_plot.py +1354 -0
  9. dstf/authoring/builtin/edit_tree.py +1399 -0
  10. dstf/authoring/builtin/enqueue.py +144 -0
  11. dstf/authoring/capabilities.py +463 -0
  12. dstf/authoring/errors.py +49 -0
  13. dstf/authoring/family_rows.py +526 -0
  14. dstf/authoring/forms.py +631 -0
  15. dstf/authoring/layout.py +104 -0
  16. dstf/authoring/live_rows.py +337 -0
  17. dstf/authoring/live_runs.py +385 -0
  18. dstf/authoring/needle.py +127 -0
  19. dstf/authoring/picker_rows.py +92 -0
  20. dstf/authoring/queue_rows.py +354 -0
  21. dstf/authoring/session.py +3016 -0
  22. dstf/authoring/shell/__init__.py +9 -0
  23. dstf/authoring/shell/actions.py +702 -0
  24. dstf/authoring/shell/app.py +53 -0
  25. dstf/authoring/shell/drawer_controls.py +190 -0
  26. dstf/authoring/shell/family_fold.py +468 -0
  27. dstf/authoring/shell/figure_hook.py +249 -0
  28. dstf/authoring/shell/grips.js +1000 -0
  29. dstf/authoring/shell/header.py +783 -0
  30. dstf/authoring/shell/live_view.py +93 -0
  31. dstf/authoring/shell/picker.py +267 -0
  32. dstf/authoring/shell/placing.py +122 -0
  33. dstf/authoring/shell/plot_card.py +1171 -0
  34. dstf/authoring/shell/queue_panel.py +433 -0
  35. dstf/authoring/shell/rail.py +593 -0
  36. dstf/authoring/shell/shell.py +528 -0
  37. dstf/authoring/shell/stats_card.py +501 -0
  38. dstf/authoring/shell/strip.py +204 -0
  39. dstf/authoring/shell/style.py +721 -0
  40. dstf/authoring/shell/suite.py +277 -0
  41. dstf/authoring/shell/suite_grid.js +414 -0
  42. dstf/authoring/shell/suite_grid.py +373 -0
  43. dstf/authoring/shell/tab_theme.py +110 -0
  44. dstf/authoring/shell/tabstate.py +146 -0
  45. dstf/authoring/shell/test_list.py +179 -0
  46. dstf/authoring/shell/test_page.py +1404 -0
  47. dstf/authoring/shell/tree_card.py +1171 -0
  48. dstf/authoring/shell/variables_drawer.py +589 -0
  49. dstf/authoring/shell/widgets.py +188 -0
  50. dstf/authoring/situation.py +287 -0
  51. dstf/authoring/spec_document.py +215 -0
  52. dstf/authoring/spec_preview.py +83 -0
  53. dstf/authoring/suite_rows.py +99 -0
  54. dstf/authoring/tree_move.py +516 -0
  55. dstf/authoring/tree_pointer.py +33 -0
  56. dstf/authoring/tree_text.py +61 -0
  57. dstf/authoring/typed_number.js +64 -0
  58. dstf/authoring/typed_number.py +76 -0
  59. dstf/authoring/unscorable.py +141 -0
  60. dstf/authoring/variable_rows.py +216 -0
  61. dstf/backends/__init__.py +283 -0
  62. dstf/backends/base.py +1117 -0
  63. dstf/backends/common/__init__.py +1 -0
  64. dstf/backends/common/json_driver.py +484 -0
  65. dstf/backends/common/live_mat.py +369 -0
  66. dstf/backends/common/mat_reader.py +632 -0
  67. dstf/backends/common/proc_kill.py +238 -0
  68. dstf/backends/common/proc_output.py +20 -0
  69. dstf/backends/common/result_files.py +109 -0
  70. dstf/backends/common/result_variables.py +329 -0
  71. dstf/backends/common/statistics.py +39 -0
  72. dstf/backends/cross_backend.py +193 -0
  73. dstf/backends/dymola/__init__.py +5 -0
  74. dstf/backends/dymola/backend.py +776 -0
  75. dstf/backends/dymola/interface_loader.py +241 -0
  76. dstf/backends/dymola/log_parser.py +396 -0
  77. dstf/backends/dymola/persistent_backend.py +949 -0
  78. dstf/backends/fmpy/__init__.py +11 -0
  79. dstf/backends/fmpy/backend.py +443 -0
  80. dstf/backends/julia/__init__.py +27 -0
  81. dstf/backends/julia/backend.py +156 -0
  82. dstf/backends/julia/persistent_backend.py +541 -0
  83. dstf/backends/julia/run_persistent.jl +167 -0
  84. dstf/backends/julia/run_test.jl +146 -0
  85. dstf/backends/openmodelica/__init__.py +21 -0
  86. dstf/backends/openmodelica/backend.py +368 -0
  87. dstf/backends/openmodelica/init_xml.py +76 -0
  88. dstf/backends/openmodelica/log_parser.py +119 -0
  89. dstf/backends/openmodelica/mos_generator.py +228 -0
  90. dstf/backends/openmodelica/persistent_backend.py +1045 -0
  91. dstf/backends/openmodelica/session_loader.py +63 -0
  92. dstf/backends/persistent.py +1811 -0
  93. dstf/backends/pool.py +602 -0
  94. dstf/backends/progress.py +395 -0
  95. dstf/backends/python/__init__.py +11 -0
  96. dstf/backends/python/backend.py +141 -0
  97. dstf/backends/python/run_test.py +141 -0
  98. dstf/backends/run_metadata.py +103 -0
  99. dstf/backends/types.py +310 -0
  100. dstf/cli/__init__.py +12 -0
  101. dstf/cli/author_cmd.py +61 -0
  102. dstf/cli/baseline_cmds.py +341 -0
  103. dstf/cli/common.py +231 -0
  104. dstf/cli/diag_cmds.py +350 -0
  105. dstf/cli/main.py +561 -0
  106. dstf/cli/review.py +398 -0
  107. dstf/cli/run_cmds.py +589 -0
  108. dstf/cli/spec_cmds.py +123 -0
  109. dstf/comparison/__init__.py +13 -0
  110. dstf/comparison/algorithms.py +2127 -0
  111. dstf/comparison/builtins.py +291 -0
  112. dstf/comparison/comparator.py +1189 -0
  113. dstf/comparison/geometry.py +164 -0
  114. dstf/comparison/handles.py +1194 -0
  115. dstf/comparison/metric_tree.py +332 -0
  116. dstf/comparison/mode_schema.py +176 -0
  117. dstf/comparison/modes.py +788 -0
  118. dstf/comparison/registry.py +230 -0
  119. dstf/comparison/seeds.py +281 -0
  120. dstf/comparison/sides.py +158 -0
  121. dstf/comparison/snap.py +62 -0
  122. dstf/comparison/strict_keys.py +246 -0
  123. dstf/comparison/summaries.py +354 -0
  124. dstf/comparison/tree_eval.py +868 -0
  125. dstf/comparison/tree_spec.py +678 -0
  126. dstf/comparison/types.py +194 -0
  127. dstf/comparison/validator.py +232 -0
  128. dstf/config.py +815 -0
  129. dstf/discovery/__init__.py +0 -0
  130. dstf/discovery/json_recognizer.py +702 -0
  131. dstf/discovery/library_state.py +248 -0
  132. dstf/discovery/mo_parser.py +794 -0
  133. dstf/discovery/patch_apply.py +308 -0
  134. dstf/discovery/patch_envelope.py +63 -0
  135. dstf/discovery/plots.py +318 -0
  136. dstf/discovery/recognizer.py +103 -0
  137. dstf/discovery/scan_cache.py +154 -0
  138. dstf/discovery/spec_parser.py +538 -0
  139. dstf/discovery/spec_shape.py +122 -0
  140. dstf/discovery/spec_update.py +493 -0
  141. dstf/discovery/test_registry.py +488 -0
  142. dstf/discovery/unit_tests.py +95 -0
  143. dstf/figures/__init__.py +14 -0
  144. dstf/figures/assemble.py +48 -0
  145. dstf/figures/decimate.py +150 -0
  146. dstf/figures/families.py +289 -0
  147. dstf/figures/palette.py +170 -0
  148. dstf/figures/plotly.py +1413 -0
  149. dstf/figures/view.py +233 -0
  150. dstf/pipeline.py +435 -0
  151. dstf/plugins.py +104 -0
  152. dstf/reporting/__init__.py +0 -0
  153. dstf/reporting/console_report.py +187 -0
  154. dstf/reporting/context_builder.py +979 -0
  155. dstf/reporting/dashboard_render.py +534 -0
  156. dstf/reporting/junit_report.py +192 -0
  157. dstf/reporting/overlay_loader.py +708 -0
  158. dstf/reporting/report_suite.py +1059 -0
  159. dstf/reporting/rows.py +458 -0
  160. dstf/reporting/schema_export.py +413 -0
  161. dstf/reporting/stats_rows.py +321 -0
  162. dstf/reporting/status.py +388 -0
  163. dstf/reporting/templates/axes.js +61 -0
  164. dstf/reporting/templates/dashboard.html +284 -0
  165. dstf/reporting/templates/dashboard.js +604 -0
  166. dstf/reporting/templates/filters.js +100 -0
  167. dstf/reporting/templates/interactive.html +420 -0
  168. dstf/reporting/templates/report.js +116 -0
  169. dstf/reporting/templates/vendor/plotly.min.js +8 -0
  170. dstf/reporting/theme.py +324 -0
  171. dstf/reporting/tree_rows.py +73 -0
  172. dstf/reporting/verdicts.py +124 -0
  173. dstf/storage/__init__.py +0 -0
  174. dstf/storage/accept.py +216 -0
  175. dstf/storage/baseline.py +43 -0
  176. dstf/storage/batch_manifest.py +204 -0
  177. dstf/storage/ref_index.py +295 -0
  178. dstf/storage/reference_store.py +661 -0
  179. dstf/storage/roles.py +576 -0
  180. dstf/storage/run_stats.py +85 -0
  181. dynamic_systems_testing_framework-1.0.1.dist-info/METADATA +266 -0
  182. dynamic_systems_testing_framework-1.0.1.dist-info/RECORD +185 -0
  183. dynamic_systems_testing_framework-1.0.1.dist-info/WHEEL +4 -0
  184. dynamic_systems_testing_framework-1.0.1.dist-info/entry_points.txt +2 -0
  185. dynamic_systems_testing_framework-1.0.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,266 @@
1
+ Metadata-Version: 2.5
2
+ Name: dynamic-systems-testing-framework
3
+ Version: 1.0.1
4
+ Summary: Dynamic Systems Testing Framework — regression & unit testing for time-dependent system behavior across Modelica (Dymola, OpenModelica), FMU (FMPy), Julia (ModelingToolkit), and Python backends
5
+ Project-URL: Homepage, https://github.com/ORNL-Modelica/DynamicSystemsTestingFramework
6
+ Project-URL: Repository, https://github.com/ORNL-Modelica/DynamicSystemsTestingFramework
7
+ Project-URL: Documentation, https://github.com/ORNL-Modelica/DynamicSystemsTestingFramework/blob/main/docs/usage.md
8
+ Project-URL: Issues, https://github.com/ORNL-Modelica/DynamicSystemsTestingFramework/issues
9
+ Author: Scott Greenwood
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: dymola,fmi,fmu,julia,modelica,modelingtoolkit,openmodelica,regression-testing,simulation,testing
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Topic :: Scientific/Engineering
19
+ Classifier: Topic :: Software Development :: Testing
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: jinja2>=3.1
22
+ Requires-Dist: numpy>=1.20
23
+ Requires-Dist: psutil>=5.9
24
+ Provides-Extra: author
25
+ Requires-Dist: nicegui>=3.16; extra == 'author'
26
+ Requires-Dist: regex>=2026.9.10; extra == 'author'
27
+ Provides-Extra: dev
28
+ Requires-Dist: mypy>=1.10; extra == 'dev'
29
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
30
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
31
+ Requires-Dist: pytest>=7.0; extra == 'dev'
32
+ Requires-Dist: ruff>=0.16; extra == 'dev'
33
+ Requires-Dist: scipy>=1.10; extra == 'dev'
34
+ Requires-Dist: types-regex>=2026.9.10; extra == 'dev'
35
+ Provides-Extra: fmpy
36
+ Requires-Dist: fmpy>=0.3; extra == 'fmpy'
37
+ Provides-Extra: om
38
+ Requires-Dist: ompython>=3.5; extra == 'om'
39
+ Description-Content-Type: text/markdown
40
+
41
+ # Dynamic Systems Testing Framework (DSTF)
42
+
43
+ [![quality](https://github.com/ORNL-Modelica/DynamicSystemsTestingFramework/actions/workflows/quality.yml/badge.svg)](https://github.com/ORNL-Modelica/DynamicSystemsTestingFramework/actions/workflows/quality.yml)
44
+
45
+ Regression and unit testing for time-dependent system behavior. Discovers tests, runs simulations, compares against versioned baselines, and reports — across **Modelica (Dymola, OpenModelica), FMU (FMPy), Julia/ModelingToolkit, and arbitrary Python**.
46
+
47
+ Library-agnostic: tests can be discovered from in-model annotations (`UnitTests` components), declarative `test_spec.json`, or both. Reference results are partitioned per backend / OS so the same library can be regression-tested across backends without ref drift.
48
+
49
+ Criteria are written in **`dstf author`**, a local browser tool over the same figures the report draws: edit a criterion beside the plot it scores — drag a handle, or Ctrl+click to add a row that settles on the data — give a tolerance a lower and an upper side, put one criterion on many elements of an array, queue tests on simulator workers that stay alive, and watch a running test's trace as Dymola or OpenModelica writes it. A default and a dark theme cover the tool, the dashboard and the report pages.
50
+
51
+ ![DSTF dashboard](https://raw.githubusercontent.com/ORNL-Modelica/DynamicSystemsTestingFramework/main/docs/img/dashboard.png)
52
+
53
+ *The unified dashboard — live progress during a run, a static report after. Each report is stamped with the backend, tool + MSL version, and OS that produced it; the table gives per-test verdicts, worst-NRMSE, and phase timing.*
54
+
55
+ ## What's in the box
56
+
57
+ - **5 backends**, each with persistent-worker support where it pays off:
58
+
59
+ | Backend | Source kind | Persistent | Notes |
60
+ |---|---|---|---|
61
+ | Dymola | Modelica `.mo` | ✓ default | Python interface; `--batch` selects the `.mos` path. Records translation statistics, so a change in a model's state count is a structural warning |
62
+ | OpenModelica | Modelica `.mo` | ✓ default | OMPython ZMQ; `--batch` selects the `omc -s` path. Records timing statistics and the model's state count (from the init file omc generates), so a change in it is the structural warning it is on Dymola — against a baseline that records the count, which one accepted before this does at its next accept; system sizes and Jacobian counts are Dymola's alone |
63
+ | FMPy | Pre-built FMU | per-test thread | `fmpy.simulate_fmu` in-process |
64
+ | Julia / MTK | `.jl` ModelingToolkit | ✓ default | stdin-JSON pipe; Dyad untested |
65
+ | Python | Any `simulate(stop_time, tol) -> dict` | subprocess-per-test | scipy, pandas, CSV loader, HTTP — anything |
66
+
67
+ - **7 comparison modes**, composable via a `MetricTree`:
68
+
69
+ | Mode | What it scores |
70
+ |---|---|
71
+ | `nrmse` | RMSE over signal range — the default |
72
+ | `tube` | Pass if signal stays inside a (constant or time-varying) envelope around ref |
73
+ | `points` | Per-point checks at declared times with `time_tolerance` x-box and abs/rel y-tolerance |
74
+ | `range` | Scalar `min_value` / `max_value` bounds — baseline-free |
75
+ | `event-timing` | Match Modelica solver events against a declared list within per-event tolerance |
76
+ | `dominant-frequency` | FFT peak matching against a declared peaks table — windowable |
77
+ | `scalar` | One number — a reduction of the signal (`max`/`min`/`mean`/`sample_mean`/`final`/`integral`) or a stored statistic by dotted path — vs a baseline scalar or declared bounds |
78
+
79
+ Combinators: `and`, `or`, `k-of-n`, `warn` (relax to advisory), `weighted`. Leaves can scope to a time window and target named baselines (`primary`, soft-checks, companions).
80
+
81
+ - **Read-only reports** — per-test Plotly HTML drawn from figures Python built: the trajectory with its criterion geometry (tube band, range bounds, point boxes, event windows, FFT spectrum), overlay picker, error overlays, and the metric tree with the CLI's verdict and score text per leaf. Plus a live dashboard during runs and JUnit XML for CI. The report shows, the CLI decides.
82
+
83
+ - **An authoring tool** — `dstf author` (the `[author]` extra) serves a Suite page and a Test page on `127.0.0.1`. Criteria are edited inline under the plot they score, staged, and written to `test_spec.json` on Save:
84
+
85
+ | Feature | What it does |
86
+ |---|---|
87
+ | Two-sided tolerance | A tolerance is one number or `{"lower": a, "upper": b}`; on the plot, an arrow outside each side sets it |
88
+ | On-plot editing | Drag a ring, an arrow or a bound line; Ctrl+click adds a row that settles on the data; a field's ⌖ arms it for the next click; a placed value is snapped to a readable step |
89
+ | Simulation queue | Queue the selected tests: first in, first out, on workers that stay alive between runs; Remove a waiting test, Cancel a running one |
90
+ | Live results | A running test's trace is drawn as Dymola or OpenModelica writes its result file; a cancelled or timed-out run is shown, never scored or accepted |
91
+ | Criteria over an array | One criterion on the elements `1:5:20` of an array; identical criteria fold into one row, edited as one |
92
+ | Themes | `"theme": "dark"` in `testing.json` for the dashboard, the report pages and the tool; the tool's ⋮ menu switches a browser tab live |
93
+
94
+ - **Three baseline roles** per test, partitioned on disk: **primary** (regression anchor, hard-fail), **soft_checks** (warn-wrapped cross-regression imports), **companions** (plot-only overlays, including cross-library).
95
+
96
+ ## Install
97
+
98
+ End users:
99
+
100
+ ```bash
101
+ # Not on PyPI yet — these work from the first published release.
102
+ uv tool install dynamic-systems-testing-framework # then run plain: dstf ...
103
+ # or: pipx install dynamic-systems-testing-framework
104
+ ```
105
+
106
+ Developers:
107
+
108
+ ```bash
109
+ uv sync --extra dev --locked # core + pytest, from uv.lock
110
+ uv sync --extra dev --extra author --extra fmpy --extra om --locked # plus the authoring tool, FMPy + OpenModelica extras
111
+ uv run dstf --help
112
+ ```
113
+
114
+ `uv sync` installs the project editable and pins every dependency to `uv.lock`,
115
+ the same lock CI uses; `--locked` fails instead of silently re-locking when the
116
+ lock has drifted from `pyproject.toml`. It prunes anything you did not ask for
117
+ on that command line — being in the lock does not save it — so name every extra
118
+ at once.
119
+
120
+ For the Julia backend, install Julia 1.11+ and instantiate the demo project once:
121
+
122
+ ```bash
123
+ curl -fsSL https://install.julialang.org | sh -s -- -y --default-channel 1.11
124
+ cd examples/julia/JuliaMtkTestingLib && julia --project=. -e 'using Pkg; Pkg.instantiate()'
125
+ ```
126
+
127
+ The Python examples (`SimpleRamp`, `PointsCheck`) need scipy, which the `dev`
128
+ extra installs. Reach them through `uv run dstf ...`: the Python backend takes
129
+ the interpreter from `testing.json`'s `backends: {"Python": [...]}` entry and
130
+ falls back to `PATH` — and the shipped example names `python`, so either route
131
+ ends at the first `python` on `PATH`, which `uv run` points at `.venv`. Run the
132
+ same examples from a tool-installed `dstf` and that is whatever comes first on
133
+ your PATH — a conda env, often — which needs its own scipy.
134
+
135
+ ## First 5 minutes
136
+
137
+ The repo ships demo libraries for every backend. Easiest first run is the Modelica demo:
138
+
139
+ ```bash
140
+ # From the repo root:
141
+ uv run dstf --config examples/modelica/ModelicaTestingLib/Resources/ReferenceResults/testing.json run
142
+ ```
143
+
144
+ What this does:
145
+
146
+ 1. Reads `testing.json` to find the demo library, the backend (Dymola or OpenModelica — first one whose binary exists wins), the reference root, and any per-test recognizers.
147
+ 2. Discovers the demo tests via the bundled `UnitTests` recognizer plus declarative recognizers in the JSON.
148
+ 3. Runs each in a persistent simulator worker, partitioning output under `testing_output/` by backend + OS.
149
+ 4. Compares against `Resources/ReferenceResults/<Backend>/<os>/ref_NNNN.json` baselines.
150
+ 5. Prints a console report with pass/fail per test.
151
+
152
+ To see the interactive HTML reporter:
153
+
154
+ ```bash
155
+ uv run dstf --config examples/modelica/ModelicaTestingLib/Resources/ReferenceResults/testing.json run --report
156
+ ```
157
+
158
+ The dashboard URL is printed as a run starts (`Live progress: file://…`) and the page is opened in a browser tab; it reloads itself every 5s during the run. `--report` writes the per-test pages under `<work_dir>/reports/` and opens the dashboard again when they are written. `--no-browser` (on `run` and `compare`) opens no tab and still prints the link.
159
+
160
+ The examples ship baselines for these `<Backend>/<os>` partitions: Modelica — `Dymola/linux`, `Dymola/windows` and `OpenModelica/linux` (its array model, `HeatRodTest`, on the two Linux ones); FMU — `FMPy/linux` and `FMPy/windows`; Julia — `Julia/linux`; Python — `Python/linux`. A first run on an OS a backend has no partition for (OpenModelica, Julia or Python on Windows, say) reports every test `NO_REF` until `run --accept` stores its baselines there. A companion in the examples is another source's curve of the SAME model, drawn over the test's plot when its box is ticked on the report page, and each ships in the partitions named here and no other: in `OpenModelica/linux`, the Modelica `FrequencyTest`, `RangeCheckTest` and `MultiFrequencyTest` carry the Julia example's baseline of that model; in `Julia/linux`, the Julia `Frequency`, `RangeCheck` and `MultiFrequency` carry the OpenModelica one; and `MetricTreeTest` carries its closed-form solution in `Dymola/linux` and `OpenModelica/linux`. A Dymola run of the example therefore shows no Julia companion, and `Dymola/windows` ships no companion at all.
161
+
162
+ To repeat with another backend's demo library, swap the config path:
163
+
164
+ ```bash
165
+ # Julia/MTK, Python, and prebuilt FMUs through FMPy
166
+ uv run dstf --config examples/julia/JuliaMtkTestingLib/Resources/ReferenceResults/testing.json run
167
+ uv run dstf --config examples/python/PythonTestingLib/Resources/ReferenceResults/testing.json run
168
+ uv run dstf --config examples/fmu/testing.json run # needs reference-fmus-binaries/
169
+ ```
170
+
171
+ ## Configuration cheat-sheet
172
+
173
+ `testing.json` is the single entry point. The full field reference lives in `docs/usage.md`; the headline shape:
174
+
175
+ ```json
176
+ {
177
+ "source_path": "../../MyLib",
178
+ "backends": {
179
+ "Dymola": ["C:\\Program Files\\Dymola 2026x\\bin64\\Dymola.exe"],
180
+ "OpenModelica": ["/usr/bin/omc"]
181
+ },
182
+ "test_spec": "test_spec.json",
183
+ "dependencies": ["/path/to/SomeDep"],
184
+ "tolerance": 1e-4,
185
+ "diagnostic_variables": ["CPUtime", "EventCounter"]
186
+ }
187
+ ```
188
+
189
+ The first `backends` entry whose binary exists wins (no need for per-OS config files). `backend: "Dymola"` (or any named entry) forces a specific one.
190
+
191
+ ## Common commands
192
+
193
+ ```bash
194
+ # Discover tests without running
195
+ uv run dstf --config testing.json discover
196
+
197
+ # Run, compare, accept all current results as new baselines
198
+ uv run dstf --config testing.json run --accept
199
+
200
+ # Interactive review by category
201
+ uv run dstf --config testing.json run -i failed
202
+
203
+ # Filter (glob, comma list, or @file)
204
+ uv run dstf --config testing.json run --filter "Foo.A,Foo.B"
205
+ uv run dstf --config testing.json run --filter @rerun.txt
206
+
207
+ # Parallel + interactive HTML report (--batch-size N splits a Dymola --batch run into small batches)
208
+ uv run dstf --config testing.json run --parallel 4 --report
209
+
210
+ # Rerun only previously-failed tests, merge with last full run, regen report
211
+ uv run dstf --config testing.json run --rerun failed,sim-failed --merge --report
212
+
213
+ # Compare without re-simulating (uses last results)
214
+ uv run dstf --config testing.json compare
215
+
216
+ # Open the authoring tool in a browser (needs the [author] extra)
217
+ uv run dstf --config testing.json author
218
+
219
+ # Apply an RFC 6902 JSON-Patch envelope against test_spec.json — single- or
220
+ # multi-model form, from any source
221
+ uv run dstf --config testing.json spec-update spec_patch.json
222
+
223
+ # Manage the other baseline roles
224
+ uv run dstf --config testing.json companion add <model> <name> <path>
225
+ uv run dstf --config testing.json soft-check list <model>
226
+ uv run dstf --config testing.json import-baseline <model> <name> <source> # soft_checks only
227
+
228
+ # Manifest / schema
229
+ uv run dstf --config testing.json manifest dump
230
+ uv run dstf --config testing.json manifest cleanup [--orphans] [--apply] # dry-run by default
231
+ uv run dstf --config testing.json export-schema --output schema.json
232
+
233
+ # Diagnose Dymola Python interface discovery
234
+ uv run dstf check-dymola
235
+ ```
236
+
237
+ `uv run dstf <command> --help` for each subcommand's full flag set.
238
+
239
+ ## Where things live
240
+
241
+ | Doc | What's in it |
242
+ |---|---|
243
+ | `docs/usage.md` | The deep user guide — every command, every config field, every comparison mode |
244
+ | `docs/architecture.md` | Six-layer plug-in pipeline + current-state map to code |
245
+ | `docs/extensibility.md` | Plug-in contracts for Source / Discovery / Backend / Dataset / Metric / Combinator |
246
+ | `docs/vision.md` | Where the framework is going (target user base, non-Modelica futures) |
247
+ | `docs/decisions.md` | Authoritative decision log |
248
+ | `docs/ideas.md` | Backlog (unimplemented features, with explicit deferred-by-design entries) |
249
+ | `examples/{modelica,fmu,julia,python}/` | Working demo libraries — one per backend |
250
+
251
+ ## CI integration
252
+
253
+ ```yaml
254
+ - run: |
255
+ uv run dstf --config ./testing.json run --report-format junit --output test-results.xml
256
+ - uses: actions/upload-artifact@v4
257
+ with:
258
+ name: test-results
259
+ path: test-results.xml
260
+ ```
261
+
262
+ For HTML reports as build artifacts, also pass `--report` and upload `dashboard.html` and the `reports/` directory from the work dir (`--work-dir` sets it).
263
+
264
+ ## Status
265
+
266
+ v1.0. 5 backends in production, 4 demo libraries, and a comprehensive pytest suite (a Playwright subset drives the report pages and the authoring tool in a real browser). The report is read-only and mutates nothing: every number it draws comes from a figure Python built or a string the server rendered. Criteria are authored in `dstf author`, driven by the same figures and the same scorer as the CLI. Nothing is published to PyPI yet.
@@ -0,0 +1,185 @@
1
+ dstf/__init__.py,sha256=iHzANiMOc-qyCmsCYgL7qG0zG-bRD_8kheWTD6qB6Bk,1686
2
+ dstf/__main__.py,sha256=US_uduAmh1DTCbdYeia9j7iiSCPVHr5dSIeOlkj02vE,231
3
+ dstf/config.py,sha256=xSgtdWz3UZuwYvJbfx047XbTHc4IzYvTixN0uyDwh34,35910
4
+ dstf/pipeline.py,sha256=rfnFgX7EDfz3A9pnNogV3pwGUKHFuOzB0DGck9YNnLw,17971
5
+ dstf/plugins.py,sha256=eeWUe8uxH4__bhbRadNvpfucYWtRr6iqnqsy1Kwd_T4,4279
6
+ dstf/authoring/__init__.py,sha256=QjO4WWCLwJ9UcqwnHJOOGr4XV7xIgY4ZZbZr92-15us,496
7
+ dstf/authoring/capabilities.py,sha256=DtpqHKRglOh_gw8l9Asz1GZCNnZ_3HcLj5uRUUgLh_Q,22181
8
+ dstf/authoring/errors.py,sha256=owZf1RZjB0EObQJZPN2-FXIEbIi_8nOJX8Ip3uao5fQ,2125
9
+ dstf/authoring/family_rows.py,sha256=kPknQkC-HmrpvyP-KfqXQE6bTZr-blsdga6aMNcmyAI,20592
10
+ dstf/authoring/forms.py,sha256=GZ6sXdOak-39XhOI6DPVsQcoIB11opFMuJe1ukmJPFQ,27990
11
+ dstf/authoring/layout.py,sha256=LdbiqUcXKujDl80oSsiIkOpt9FVLWejgNbSU-WvYJNU,4236
12
+ dstf/authoring/live_rows.py,sha256=F72EjGMPU0dP_CZSpxJaPnkxN83WzypxDlVpDl-4MpM,13301
13
+ dstf/authoring/live_runs.py,sha256=xCNOci2qxuwfWjHtS4QShn3qkHxtWyEGiolTEDd_3yE,16384
14
+ dstf/authoring/needle.py,sha256=ggeV76FWrAPlKhjGeqQYvJcMoZz4l2bK5QKJUK2BRyc,6650
15
+ dstf/authoring/picker_rows.py,sha256=m9mRddPys1WmogRQ0LM2hrIN3T0kCg2hsgz68pn8KUA,3411
16
+ dstf/authoring/queue_rows.py,sha256=nhXfJjGt7JQClcAiika4aGgtRmr3dUd9spTpSKb4MRQ,14589
17
+ dstf/authoring/session.py,sha256=q8CmxNShS6JqNUcVSC2agMdpUV9n1G2vXJUdC3AIZiE,139659
18
+ dstf/authoring/situation.py,sha256=FmZVKnYwluvtodWYVg2VPEXJ1bWDL7oe7y1tgyKlwHk,12577
19
+ dstf/authoring/spec_document.py,sha256=3waUoV0Nq47AKZs9-Z7ou1r7WtWVr21pxahP6ch4WSQ,9874
20
+ dstf/authoring/spec_preview.py,sha256=l9aablo7O7OlIXkVKCA-ErqLcrU1LPePfuljGwCvY_w,2937
21
+ dstf/authoring/suite_rows.py,sha256=wVI0eesdmuxxe94KnyFV94VOPz8eeuUv4DwOcWQWW6M,3834
22
+ dstf/authoring/tree_move.py,sha256=zBd7O7z6U_mlvmKu1TIHFH4UFc1fT-UkrDiS17Lex2c,20435
23
+ dstf/authoring/tree_pointer.py,sha256=J2wlGviciNJhHmeMynlcYQrtfCbEfYlEIEksO0caI78,1376
24
+ dstf/authoring/tree_text.py,sha256=k2a8Dioh8kKfZhSu2Ss8NMbUz74AIvGvnFapt_ahrBs,2616
25
+ dstf/authoring/typed_number.js,sha256=GbfEQNeXS1o1pGNU9jvLKTLzQYl7ZoQ_aU-Cc2tINes,2631
26
+ dstf/authoring/typed_number.py,sha256=O1mVPogRoxGwliheRKr4zpy4NG06A2DPwJhr-L6t17o,3843
27
+ dstf/authoring/unscorable.py,sha256=wPtWs70mDCS-Qezy1oFqWmALyEtKb5bYDKLAV5xyhoo,6488
28
+ dstf/authoring/variable_rows.py,sha256=YZhXCrTCbEIpgvDWrg5y65F5Mdr3C2JXuQSUCTGAKf4,9565
29
+ dstf/authoring/builtin/__init__.py,sha256=yhx7wtB-Xq9pODiVCQ4mCJ1wNIKDZdvVER0zo8I0-h8,1258
30
+ dstf/authoring/builtin/accept.py,sha256=1Inis7bLwkyKhqVwUZ2DChaA7mQPR6HbPcQjyeGgk2Y,8698
31
+ dstf/authoring/builtin/edit_criteria.py,sha256=0NBNqvUp38rXJR2tI-eLsDsjvbwLP7XaWhUF9AgTwwE,21802
32
+ dstf/authoring/builtin/edit_family.py,sha256=HR9za9WdJrWuiRkPyeGwdyKg_FALwUXDjmXCuF0B2CI,9464
33
+ dstf/authoring/builtin/edit_on_plot.py,sha256=SZSoDqnTmHMnwOpcxzcDPkWGs7NFPLZZDE8F-qSyxsc,60332
34
+ dstf/authoring/builtin/edit_tree.py,sha256=S2T6TZ3idYWGzH9HPf7S3gIMuZihzGfaCmqAfoOSDrA,59043
35
+ dstf/authoring/builtin/enqueue.py,sha256=eLNd8qaGBjUHv0V1MGE23G-Dn99zTb5HwDute5gOuds,5789
36
+ dstf/authoring/shell/__init__.py,sha256=DBVp4Trak1pTsoxu97c2qkM1rhbOMR1jBjFzkV6H9Gg,421
37
+ dstf/authoring/shell/actions.py,sha256=euLWAPEsX2dhIL97UNSTdwpcfS7qw1BBgrTTZFQuRXo,32414
38
+ dstf/authoring/shell/app.py,sha256=CyCHsc-IbH0R1P5z3GsJ_ATvigdt66G_6viqXiZR-ko,1460
39
+ dstf/authoring/shell/drawer_controls.py,sha256=jzdEqjbSF3JZlJKXTter3fPboRHNIex_ZtwBqI6wvLQ,6946
40
+ dstf/authoring/shell/family_fold.py,sha256=fHq4EmLq_8MJNXtzypxhsKY71CoPuUfZMTTibAb0Nz0,20989
41
+ dstf/authoring/shell/figure_hook.py,sha256=gFYscHoc28aBGDztP1-TipREW3XeyOIdZUbhKTttnL4,12242
42
+ dstf/authoring/shell/grips.js,sha256=uqnobyGsmu9SROVdsSgXdlGL_LlXndRdnSkmn6ojjVQ,46620
43
+ dstf/authoring/shell/header.py,sha256=kP7aUy6LPari1FbPn3oVYS9XWXvDEFsuV0u2xF10lUE,34385
44
+ dstf/authoring/shell/live_view.py,sha256=7NiFjv9X4tooIMdh3C8qW3ooQjHWy0o7kHz3pIowO6s,3586
45
+ dstf/authoring/shell/picker.py,sha256=-NjZP_KzhwYFzEjckfjuRPxDUXq4zSdGHlWnknVaL-8,11151
46
+ dstf/authoring/shell/placing.py,sha256=_Ry9podjMqKCKumNmIa0sr70f9nKvpt4sDB1FtvoC1E,5161
47
+ dstf/authoring/shell/plot_card.py,sha256=CMVoefIcpkCUN-fbxiWXnFlLMZFv6IduqNy9bLQsmKM,56063
48
+ dstf/authoring/shell/queue_panel.py,sha256=hsbp4Sceei7t7BWGQK1rC61z-QIf2FSFjd-BdUp7Zto,18547
49
+ dstf/authoring/shell/rail.py,sha256=tq4koCQ4eFCNTY9QJHGQUcNGRmYz2Nb2LgKtgI_JOv4,25088
50
+ dstf/authoring/shell/shell.py,sha256=4LECfh3zG7miK2Q_gJ9BPyWjSPD1cBa7aE-EGQvt9pY,22406
51
+ dstf/authoring/shell/stats_card.py,sha256=qG88MGoYKwmAT_jdzrJyfYOW0nz4pnb4g41g6UJjHOM,21626
52
+ dstf/authoring/shell/strip.py,sha256=K5OPPdjK_CYIV34VLdlh8kqgk_9Frl57MQt6vKEvi2k,8964
53
+ dstf/authoring/shell/style.py,sha256=A9AYp8yqfg2I1dQHWfu-mV2sSVJwJTjx8bG0Bs_aoyc,40564
54
+ dstf/authoring/shell/suite.py,sha256=j-CPsvV-r_wMw553Nl91ZsO1s0ShQRKpQw-yw2smQiw,12931
55
+ dstf/authoring/shell/suite_grid.js,sha256=atBnVQ18fsciD3Ho3dKehiq6wisaNmcfnsE-AfoV0_k,18248
56
+ dstf/authoring/shell/suite_grid.py,sha256=_rjBMrh8CISOBZdjkSPPbugUdCgKPNUdNzktCYrbN3Y,16385
57
+ dstf/authoring/shell/tab_theme.py,sha256=-hB4Ugm2vS5uqNQiR9owJ29c2igtWQhRTI8KT3l4QcU,4586
58
+ dstf/authoring/shell/tabstate.py,sha256=54JIM_JtByYzWafKqiORy2bQheZs39OFTvhSNQVhm48,7056
59
+ dstf/authoring/shell/test_list.py,sha256=0RwGsbkIYLXN4BpG_9l4hs78gWLkeUrxyVabgn5f3Rg,7530
60
+ dstf/authoring/shell/test_page.py,sha256=a10ca-_HE2EE2ZEpauOjgUSOHeqrYvctnwkjbQOjmoY,65434
61
+ dstf/authoring/shell/tree_card.py,sha256=YvotYYtVRCgbizdEByKMnpfrREOaoMJJM_VfVc4CI08,52681
62
+ dstf/authoring/shell/variables_drawer.py,sha256=Oupt-PzkQBo9P-G391U0n5anEkD0X3XqOC4604ePDjU,25963
63
+ dstf/authoring/shell/widgets.py,sha256=y9Oxdm-WbYu2hJfG1aWAhrQ9vq0KOz_CtfFVEUu0_Wc,7360
64
+ dstf/backends/__init__.py,sha256=VMB3BSZTQXpqNCiDcTnElzw_rbug5PpwJoKzo2zspZQ,11361
65
+ dstf/backends/base.py,sha256=Zd45TZTrTup1RyloJkw28MsduBIzG56TkD-WHGuyc5k,46190
66
+ dstf/backends/cross_backend.py,sha256=huU0uMik8uiPzLH7o8KHmz1c8-Xn4YRZw_znSVosdJg,7394
67
+ dstf/backends/persistent.py,sha256=sve37kfuv9k5lk-DNarlMzjHD5L6OmsX1U5WayF9O3s,81656
68
+ dstf/backends/pool.py,sha256=THEt8xOmODy7KdNk7NVE7FJKUtlRC8791Gsdtv3ytm0,25553
69
+ dstf/backends/progress.py,sha256=STxXpMZj3aSDNVQEzT7p_KN9fyTcRWs6oS0-DkGSJ5g,16500
70
+ dstf/backends/run_metadata.py,sha256=detq95wlTskJScrxyO-0wrHgVBhLC_QtdC9_EFOZpSg,3963
71
+ dstf/backends/types.py,sha256=u09obBTF_MrbtxmRgtqUqhUH5HNPNbP0NGquzeUk1LU,12322
72
+ dstf/backends/common/__init__.py,sha256=8e9NQmTCWscX9KYBwEUOE6nQxMbGPp4fN-X3p6pPJ3E,55
73
+ dstf/backends/common/json_driver.py,sha256=2CaW3L3Z0Iz39O-waWNBZk1jcr_jVhY6vZGmm46tOZs,17980
74
+ dstf/backends/common/live_mat.py,sha256=2VGmwtSGWprvIunEQL4Xn_ew2TBwo1JLNJMxTr6SKP8,15726
75
+ dstf/backends/common/mat_reader.py,sha256=sjOvmWS0G-rOsjd6BnJ6bP1r3ZDqAD9Nu1-OcbxVDFA,25570
76
+ dstf/backends/common/proc_kill.py,sha256=Lzv-LsWWakCmjBEel8WEd0aDZmGRKwF7w5EBckBYsHk,9547
77
+ dstf/backends/common/proc_output.py,sha256=jXhFSNZdt78Lgp0Mh7ZHiQCROOokMWkNLRnVXR6xJQk,795
78
+ dstf/backends/common/result_files.py,sha256=0_ZmigvmCVuZfxI8kgl_ttcVDFaonEKG3yZo_-Dv8Rw,3745
79
+ dstf/backends/common/result_variables.py,sha256=IBVALv0Wh3OjYzTnE60r7WCpfxqYwABQra4OB26hPgk,12529
80
+ dstf/backends/common/statistics.py,sha256=5_Q8BVghvqLJZONIHk3HMncccKXWQMDcOgIJfFjgvec,1577
81
+ dstf/backends/dymola/__init__.py,sha256=hFlDl2Xw2JAXbd_jqWp1lrs-8KOpjCxh4sC6LohLpc8,117
82
+ dstf/backends/dymola/backend.py,sha256=SedhQ0fmRwN18v5WCeNYHhZ2r-dqk73ENK3VzduSJfU,29809
83
+ dstf/backends/dymola/interface_loader.py,sha256=7A6WTxPptv0oCT3mNW49-2MGuORenOwRF7_KWy0NLMg,8497
84
+ dstf/backends/dymola/log_parser.py,sha256=OKA1-hgm6oZRj_fiBx13ATIgHvaSQTFtymM8uEjS6xw,13737
85
+ dstf/backends/dymola/persistent_backend.py,sha256=f03lBpfOU5Mln_BgSg_7Lzys05v4QA5dSz6sbEKI8Hg,40979
86
+ dstf/backends/fmpy/__init__.py,sha256=0swnXaf5yh-VzHav3VajYcgR_9iArXwORAqzXzhXi7M,325
87
+ dstf/backends/fmpy/backend.py,sha256=l1S1ZSbkXme55Hlv4XXjWHgxFYaBQ65TDLFzpk_eux0,17890
88
+ dstf/backends/julia/__init__.py,sha256=9uUqFargGyQ4Vk12b96dYxHqlIWrNNLJKJUZ2zykzUk,1259
89
+ dstf/backends/julia/backend.py,sha256=DuOqgXJYhlFk-SG71NelxtGI3G9P5L81HgpKZhEIb6M,5621
90
+ dstf/backends/julia/persistent_backend.py,sha256=18gKi6duwh51HvyJ6ginJvPap3LNrJu3ItmHsboXxZs,22070
91
+ dstf/backends/julia/run_persistent.jl,sha256=DmYuIdFJT7VrAS1MS8hYnd2BRXjB6GnpazkRqewAgLc,5945
92
+ dstf/backends/julia/run_test.jl,sha256=dHRy_ypKme3qlpTmGih-6guUG75xIo5pQZFzi5H0b-k,5159
93
+ dstf/backends/openmodelica/__init__.py,sha256=zB784sIpYLmXQ6MeAMCVQsuklEtr8kDz3CkcK0hlxEw,782
94
+ dstf/backends/openmodelica/backend.py,sha256=nWm_TUMrjI5DStX6VN0Ssp7MMhyLuSzi9taaeUiGOUc,13803
95
+ dstf/backends/openmodelica/init_xml.py,sha256=0dHfW1LME0vNATCQ6TkTipHffksVg265GgOooMimxxE,3344
96
+ dstf/backends/openmodelica/log_parser.py,sha256=lpwthZYBVD5AJVj1ovHTLUjP3nFyqCZDuEws4yxk4aI,3730
97
+ dstf/backends/openmodelica/mos_generator.py,sha256=SXLrnYuyZl5oMWLnv1f59c1ChCSaZde1xbjDysP1El4,9350
98
+ dstf/backends/openmodelica/persistent_backend.py,sha256=IMi2tg_W2k05UZqs_EhLQwtjQNhuwAywxpPFEhSK8Co,44164
99
+ dstf/backends/openmodelica/session_loader.py,sha256=Vr1RrNq2d9jx2Qdh0haO2goyWN012jRl5-3-CaWUeLI,2097
100
+ dstf/backends/python/__init__.py,sha256=b2w11ImPdOp9bDDDTr14uNbF8vRwOpuCTnzT5d1siPU,487
101
+ dstf/backends/python/backend.py,sha256=xIrc-RoLYpdLRZUxnjqHAhZcAGb9cySjnpl56OKpOVk,4825
102
+ dstf/backends/python/run_test.py,sha256=XDJxkNZDtgig1vo9odBeaU9pRyLm0JlJ0d561nUejBU,4602
103
+ dstf/cli/__init__.py,sha256=YsG2d979kCLlkBgUSCVIaUmgVGy0hVVHOyDj2cNw9nA,496
104
+ dstf/cli/author_cmd.py,sha256=UYvnzL_RsTs41RFCk5xQznX8eJJymSZLaZ3bEHmJ-Kg,2462
105
+ dstf/cli/baseline_cmds.py,sha256=1V92Pvz22D-8TnS1elkt9daOfM9ZbdrF8QOD6tgsRFs,12680
106
+ dstf/cli/common.py,sha256=862ZgEEEvKph2nMbbJ_FPllILfOBOVV0Z2AMX5X8QXY,8993
107
+ dstf/cli/diag_cmds.py,sha256=SMP1CvkO5z0EO_2_70c8lbsAeuoKMGp4hCOUljD91Es,12242
108
+ dstf/cli/main.py,sha256=mzNzYFDTFj9p9Ml0uxxNs2UIo8HvC_i0wpOVek8PdT4,20875
109
+ dstf/cli/review.py,sha256=tCjq2-E9UBgf8c0istCxs9jBoEFRzeWTUto-hHt-FEU,16016
110
+ dstf/cli/run_cmds.py,sha256=vo3ndGHCzmzTzLLcP0WLwlpdP3m-UjCaOPaN4_8iOlI,24639
111
+ dstf/cli/spec_cmds.py,sha256=dLp5zI0Y6BDxF8zo3Wsxke9r1cejz9xe4d1SeOIhx3A,4234
112
+ dstf/comparison/__init__.py,sha256=buwCPTUziwlhxfrqB_BT5Skxrl8UwF1z5GwHXB-6AMM,414
113
+ dstf/comparison/algorithms.py,sha256=mib6yJ35mvZTivmAcEuEADBy6qiTLkyMObyVOwo_WL0,84230
114
+ dstf/comparison/builtins.py,sha256=OroyQ9KNoB15U1FWJSjMl2bCODbBmnD_8HQ_XXbgGrE,9280
115
+ dstf/comparison/comparator.py,sha256=KuyEN25glgYw0hlYOf8AWJ4cV45ZRNG4jUbDCzLYx8s,50532
116
+ dstf/comparison/geometry.py,sha256=BY6VXXjxGeOaRqwvEGPZmzi3k6MCyqYzPWhdc6oM0n4,5609
117
+ dstf/comparison/handles.py,sha256=Guqeijm67FCH0SUMgZXKazLyBbiWulm2db6KXkiq83o,53168
118
+ dstf/comparison/metric_tree.py,sha256=YZgLNitbBEKN8ARGgFwLWcnzbYo6gJB4w49tYBzodG8,12795
119
+ dstf/comparison/mode_schema.py,sha256=w9cO1ofIGVIk7qLRR9tT2T8wm1OhUbG9IYB_fSwSpY8,6548
120
+ dstf/comparison/modes.py,sha256=AGcGx0gphOlyGAuYweevxcVxm29YWXtaY4Fc7oDckZ8,28951
121
+ dstf/comparison/registry.py,sha256=iG27jcHVeF9gKIuqPjsQOrpx7opaavB7bQ3t7MNZ5fw,9634
122
+ dstf/comparison/seeds.py,sha256=JevT2fXfZYLq7G51FKw8W0CaSFhheIPY7Auu0GcE9Ag,11176
123
+ dstf/comparison/sides.py,sha256=7mmPxCzyRZZjUQLy37ylq2C4ZBx5yobSZvMqAbmiK5I,6449
124
+ dstf/comparison/snap.py,sha256=RqPKQ4bU2i4bq6DTo_db1o0SJG2YxbWl2gEfngK7cY8,2832
125
+ dstf/comparison/strict_keys.py,sha256=P3dvrAhePS06V8vkFQlX4dL7-O3_40Rk7mvxJC7vOJ8,11461
126
+ dstf/comparison/summaries.py,sha256=1gwQsrupm6Xx9JvOJyraYE7jgwH_oIRLYQe00dtisX4,14786
127
+ dstf/comparison/tree_eval.py,sha256=JEfufB2QgfihScfRWwMpIhS1fOXg6ms9cBp9LugCdFQ,33989
128
+ dstf/comparison/tree_spec.py,sha256=fnkhe9Pzvm7nYnfi3DuHC743NGu9cE0Kn7cymupY0-k,26262
129
+ dstf/comparison/types.py,sha256=l0Cs2JrCB_wbU_B_cSm8V8yk6_i59MNTQkf64x5SiGU,8481
130
+ dstf/comparison/validator.py,sha256=V4Y6TL7ObMv7BtBZod0H8y02_ckpVxCMBZmk5QKTlrM,7575
131
+ dstf/discovery/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
+ dstf/discovery/json_recognizer.py,sha256=w9QlJBvK_Aer-Ap-ol0eVJWAgKmfBozTFThngv0tYTg,26476
133
+ dstf/discovery/library_state.py,sha256=lJqkNuGROF7DtlD7ZfgKraXVlbp7cfu4g3EFiTD6N6g,9472
134
+ dstf/discovery/mo_parser.py,sha256=HvkIdxrM9leJhpEIcMtt7XItg6kPX1Hq2KzHxow2sKE,30880
135
+ dstf/discovery/patch_apply.py,sha256=cd11kjcMuVuxeo8TSqNzSaIYiodqZnwOTMyrfgJe0Pg,11379
136
+ dstf/discovery/patch_envelope.py,sha256=pCF2sZer8aGVCnt0t2rr4vq7FwM26BQrk4uhuvYPAL4,2315
137
+ dstf/discovery/plots.py,sha256=t4tqLTPzs2P7eHBFNqcu11xZEWI0pfbthD1aDNlSURM,12947
138
+ dstf/discovery/recognizer.py,sha256=hlThvwXrkjgQCxkARtmu4DAjhjVZGlJQuPhSxayXHHc,4224
139
+ dstf/discovery/scan_cache.py,sha256=X3MHYli4xBkzXp3e6lBvSLVQBtgbpRpc21EYBGVY5Qo,5781
140
+ dstf/discovery/spec_parser.py,sha256=zSqUA3G_BApmnipuwLuND7i0a565TvYp96d7-lKredw,21701
141
+ dstf/discovery/spec_shape.py,sha256=Hq-Z8Ug-PlsKG2nfsCPOF2Ek-A_f9FPMzjIa2rapUAc,4410
142
+ dstf/discovery/spec_update.py,sha256=H2Hk3hm4v0iSIT5ZnIMP0WMWBhn3TZSCJT9ZGJG4NaI,21599
143
+ dstf/discovery/test_registry.py,sha256=heqZDjEWEFs2-t9AZpj8yBUjb7g0GcCVYSqAISaYuA0,21298
144
+ dstf/discovery/unit_tests.py,sha256=DeUYcfRgTkMOx_eWQNM3Q519Z290iDZft3jHoOiAiAU,3305
145
+ dstf/figures/__init__.py,sha256=6OPKDMpH8j9z6T3_y0kkmgo0I9ga3wqq_6SCoED_2E8,800
146
+ dstf/figures/assemble.py,sha256=BBaMmm8yRAAnRLXPgEy2_ROi7TKbBK1k6nHWtgiB75A,1801
147
+ dstf/figures/decimate.py,sha256=tVPrnga15kYOS-snc_330vQ1rA6EjZtQ5rX0L6jeSg4,6323
148
+ dstf/figures/families.py,sha256=gl56cLyVuZ77YtzybXKbSRngu2zmtXlB2obumE0NZX0,13169
149
+ dstf/figures/palette.py,sha256=U0VirGepzkGThfVbaCCql5QKYgdQIPS7vE3oBTy5-ik,6545
150
+ dstf/figures/plotly.py,sha256=GiC7tB0lP40S5MWW6rH7UdOe8cJfkLihCxR7h8PCVOg,55283
151
+ dstf/figures/view.py,sha256=_2k5L5H-7M6wxwVFqHBBJtTMfySs5EIZptZpKGH9ZHw,7982
152
+ dstf/reporting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
153
+ dstf/reporting/console_report.py,sha256=FXvKVwWoUDus-HXDf_nwDpU-U0bkxBaBe_X88QCp79U,6356
154
+ dstf/reporting/context_builder.py,sha256=azbv06hyV8KOsmo2wAzoINcA_JgN5p8x9-f9xvegMRw,40824
155
+ dstf/reporting/dashboard_render.py,sha256=UaF8rweGynB_pOrvB8kI7K3txfy1W4q7Nro7VxuauO4,21805
156
+ dstf/reporting/junit_report.py,sha256=KHeFd7rpzOkwMgbFs8ESpw7Ilfmn4236DXKBZ8a4IgU,7519
157
+ dstf/reporting/overlay_loader.py,sha256=r8X-OyM_fBWHRyYtwc2ImSubke0TBellH9dGGiI_GP4,28014
158
+ dstf/reporting/report_suite.py,sha256=sj2ZW-N9pKi5QwvwxW5wIU__910lTt6X9JypvcK5k8w,43577
159
+ dstf/reporting/rows.py,sha256=Ca4-YeN7ZsiZYc9mMn9GZBfwDpzLRmJ1AjM7hBrmx7Y,17604
160
+ dstf/reporting/schema_export.py,sha256=2dPB0CICtVjZUx5HjU08y_vo5VN88VEsC4QSJQG89ns,15394
161
+ dstf/reporting/stats_rows.py,sha256=9EW_V4NeWaHstvFYMh5dM1vURvb9ypMV3S1Lt0NBUcY,11463
162
+ dstf/reporting/status.py,sha256=5Pw7KPq-jRGnCxkMAWNAFQCgwr6lZDy_ia4Z4kBhkgI,15915
163
+ dstf/reporting/theme.py,sha256=5WkrErrsaUQZO6g67e0ernbGrXayYrCCGfMWUthpHG0,11414
164
+ dstf/reporting/tree_rows.py,sha256=U3tdmxdFAi2PNeK7I2DfR_mKTdTArMWzFY1jZFtxdQ4,3051
165
+ dstf/reporting/verdicts.py,sha256=s-kfnZuI5lPCOAROYVJvTr9OyO9W35y0W5lGfIZ52Cs,4987
166
+ dstf/reporting/templates/axes.js,sha256=y-AU38YVaXrqdplsWU190L0SaGIdhxYW0RW2raLNPhA,2767
167
+ dstf/reporting/templates/dashboard.html,sha256=oTAbfOVsSi9AFzAw_e_sby1ehroAJcZEGpoaUZ0UIAw,19103
168
+ dstf/reporting/templates/dashboard.js,sha256=83XkfDczCbLZU6shN3Fdo3erxf_-8XryIS-1gVv5UeM,25613
169
+ dstf/reporting/templates/filters.js,sha256=ulCsVxizIGg8HikSNMeKBrj4EC1vH3hG2X-JmZiza00,4137
170
+ dstf/reporting/templates/interactive.html,sha256=ve6lrqH-9omvYaf09Qw4niPulwOt6xAU-RN8XYJTrW4,26727
171
+ dstf/reporting/templates/report.js,sha256=OFsrJ3jKvb_6SsoZo6IL6DVIPoEdV4D6STK7wf6PF_c,4373
172
+ dstf/reporting/templates/vendor/plotly.min.js,sha256=Nz3xCRtdm_8XqkIPemlx8kBS9tkB41hcWB5k6Z8H--4,1313565
173
+ dstf/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
174
+ dstf/storage/accept.py,sha256=gm8ODZo29XBytxNZuzVqfmQfDf-VmsZ-0wCvrrJ3VBs,9209
175
+ dstf/storage/baseline.py,sha256=t5k2GftRf10mQaGziP9Ut5dkNnTJ2Otq2wsolU2vFZQ,1959
176
+ dstf/storage/batch_manifest.py,sha256=uKIy_rbVx_sbhhxsbauvYzzKuYtgAc2IAAFNXNUWRWY,9286
177
+ dstf/storage/ref_index.py,sha256=-DRqs0q6vm662W2pMFBoz7D-Wg609WZX_qQ3Icgu1s8,12767
178
+ dstf/storage/reference_store.py,sha256=r03Yh42bf-QXeVMo6N4NjHteG0IdNoluJi43ekinZN4,28859
179
+ dstf/storage/roles.py,sha256=M0ffguW46HVsrTi6jHurPOAcSxYGCdz6O4XjBPudWuk,24204
180
+ dstf/storage/run_stats.py,sha256=ElLTr1OLXKUfm0lW5oTADxzkrWIn9iNch2XUoAxKeVk,3349
181
+ dynamic_systems_testing_framework-1.0.1.dist-info/METADATA,sha256=9J5YyTMWmDaXdlh9sKmc59KOoKBd0BMOH8sWB5R2LJU,15865
182
+ dynamic_systems_testing_framework-1.0.1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
183
+ dynamic_systems_testing_framework-1.0.1.dist-info/entry_points.txt,sha256=5TXaZeaJIiUfAhKS5-JOfnm2He725cWucWllXvj_jcc,45
184
+ dynamic_systems_testing_framework-1.0.1.dist-info/licenses/LICENSE,sha256=JRptzz516i475RKERElnIJ9wslddOrv7QonM233-W1I,1070
185
+ dynamic_systems_testing_framework-1.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ dstf = dstf.cli:main_entry
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ORNL-Modelica
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.