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
dstf/cli/spec_cmds.py ADDED
@@ -0,0 +1,123 @@
1
+ """Commands that write or describe `test_spec.json`: add, spec-update,
2
+ export-schema."""
3
+
4
+ import argparse
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ from .common import _build_config
9
+
10
+
11
+ def cmd_add(args: argparse.Namespace) -> int:
12
+ """Add a test to test_spec.json."""
13
+ config = _build_config(args)
14
+ model_id = args.model_id
15
+ variables = args.variables or []
16
+
17
+ from ..discovery.spec_parser import add_to_test_spec
18
+
19
+ # Determine spec file location
20
+ spec_path = config.spec_path
21
+
22
+ added = add_to_test_spec(spec_path, model_id, variables)
23
+ if added:
24
+ var_desc = ", ".join(variables) if variables else "(simulate only)"
25
+ print(f"Added: {model_id}")
26
+ print(f" Variables: {var_desc}")
27
+ print(f" Spec file: {spec_path}")
28
+ return 0
29
+ else:
30
+ # Already exists — prompt to overwrite
31
+ try:
32
+ choice = (
33
+ input(f" {model_id} already exists in spec. Overwrite? [y/n] > ")
34
+ .strip()
35
+ .lower()
36
+ )
37
+ except (EOFError, KeyboardInterrupt):
38
+ print("\nAborted.")
39
+ return 1
40
+ if choice == "y":
41
+ add_to_test_spec(spec_path, model_id, variables, overwrite=True)
42
+ print(f"Updated: {model_id}")
43
+ return 0
44
+ else:
45
+ print("Skipped.")
46
+ return 0
47
+
48
+
49
+ def cmd_spec_update(args: argparse.Namespace) -> int:
50
+ """Update test_spec.json from an RFC 6902 patch envelope (6.4.3).
51
+
52
+ The envelope is the only accepted input shape: the multi-model form the
53
+ authoring tool exports, or the single-model form older files carry.
54
+ """
55
+ import json as json_mod
56
+
57
+ config = _build_config(args)
58
+ spec_path = config.spec_path
59
+
60
+ json_file = Path(args.json_file)
61
+ if not json_file.exists():
62
+ print(f"File not found: {json_file}")
63
+ return 1
64
+
65
+ try:
66
+ update_data = json_mod.loads(json_file.read_text(encoding="utf-8"))
67
+ except (json_mod.JSONDecodeError, OSError) as e:
68
+ print(f"Failed to read {json_file}: {e}")
69
+ return 1
70
+
71
+ from ..discovery.patch_apply import PatchError
72
+ from ..discovery.patch_envelope import parse_envelope
73
+ from ..discovery.spec_update import apply_validated_patches
74
+
75
+ groups = parse_envelope(update_data, label=str(json_file))
76
+ requested = [(g.model_id, g.ops) for g in groups]
77
+ if not requested:
78
+ print(f"Nothing to apply: {json_file} carries no patches")
79
+ return 0
80
+ try:
81
+ applied = apply_validated_patches(spec_path, requested, config)
82
+ except PatchError as e:
83
+ print(f"Patch failed: {e}")
84
+ return 1
85
+ _print_applied(applied, requested, spec_path)
86
+ return 0
87
+
88
+
89
+ def _print_applied(applied, requested, spec_path) -> None:
90
+ """One block per model: the materialization note when the applied ops
91
+ outgrew the requested ones, then the requested ops."""
92
+ for (model_id, full), (_, ops) in zip(applied, requested):
93
+ if len(full) > len(ops):
94
+ # The implicit tree is an `and` of one leaf per criterion the
95
+ # flat path scored: counted as what every other surface calls
96
+ # them, and in the number's own noun (it read `(1 leaves)`).
97
+ n = len(full[0]["value"]["children"])
98
+ print(
99
+ f"Note: materialized implicit metrics tree for {model_id} "
100
+ f"({n} {'criterion' if n == 1 else 'criteria'}) — entry had no "
101
+ "'metrics' block"
102
+ )
103
+ print(f"Applied {len(ops)} op(s) to {model_id} → {spec_path}")
104
+ for op in ops:
105
+ print(f" {op.get('op'):<8} {op.get('path'):<60} {op.get('value', '')}")
106
+
107
+
108
+ def cmd_export_schema(args: argparse.Namespace) -> int:
109
+ """Emit a JSON-Schema document describing ``test_spec.json`` (6.4.5)."""
110
+ import json as json_mod
111
+
112
+ from ..reporting.schema_export import build_schema
113
+
114
+ schema = build_schema()
115
+ text = json_mod.dumps(schema, indent=2) + "\n"
116
+ out = getattr(args, "output", None)
117
+ if out:
118
+ # LF on every platform — the schema gets committed.
119
+ Path(out).write_text(text, encoding="utf-8", newline="\n")
120
+ print(f"Wrote schema to {out}")
121
+ else:
122
+ sys.stdout.write(text)
123
+ return 0
@@ -0,0 +1,13 @@
1
+ """Comparison layer: metrics, MetricTrees, and the registries behind both.
2
+
3
+ Importing this package registers the built-in metrics and combinators, so
4
+ ``registry.metric(...)`` / ``registry.combinator(...)`` resolve before any
5
+ spec is parsed. Third-party metrics register the same way (see
6
+ docs/extensibility.md).
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from .builtins import register_builtins
12
+
13
+ register_builtins()