sysml2kit 0.3.0__tar.gz → 0.3.1__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.
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/CHANGELOG.md +19 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/CLAUDE.md +1 -2
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/PKG-INFO +1 -1
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/docs/rf-library.md +7 -6
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/_version.py +2 -2
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/backends/sysmlpy.py +14 -1
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/cli.py +9 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/text/writer.py +10 -1
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/verify/runner.py +18 -1
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_cli_fmt.py +24 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_verify.py +23 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/.gitignore +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/.pre-commit-config.yaml +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/.python-version +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/CITATION.cff +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/CONTRIBUTING.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/LICENSE +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/NOTICE +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/README.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/SECURITY.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/SPEC.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/docker/compose.yaml +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/docs/api-client.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/docs/backends.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/docs/cli.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/docs/concepts.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/docs/index.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/docs/interchange.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/docs/mcp.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/docs/quickstart.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/docs/reference.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/docs/traceability.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/docs/verification.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/docs/views.md +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/mkdocs.yml +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/pyproject.toml +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/scripts/slopcheck.sh +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/scripts/wait_for_api.sh +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/__init__.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/api/__init__.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/api/client.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/api/errors.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/api/models.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/backends/__init__.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/backends/protocol.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/diff.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/graph.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/interchange/__init__.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/interchange/reader.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/interchange/typemap.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/interchange/writer.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/interop/__init__.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/interop/requirements.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/mcp/__init__.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/mcp/_common.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/mcp/server.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/mcp/tools_model.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/mcp/tools_requirements.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/model/__init__.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/model/analysis.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/model/base.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/model/builder.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/model/container.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/model/metadata.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/model/relations.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/model/requirements.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/model/structure.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/model/values.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/py.typed +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/query.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/text/__init__.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/text/keywords.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/units.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/validation.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/verify/__init__.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/verify/binding.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/verify/engines.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/views.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/src/sysml2kit/workspace.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/conftest.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/fixtures/RFParts.sysml +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/fixtures/RFRequirements.sysml +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/fixtures/SatcomTerminal28GHz.sysml +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/fixtures/vehicle.sysml +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_api_client.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_api_live.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_backend_fidelity.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_backend_sysmlpy.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_cli.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_cli_api.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_cli_verify.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_diff.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_interchange.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_interop.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_mcp.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_model.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_package.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_query.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_roundtrip_json.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_roundtrip_text.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_text_writer/test_vehicle_golden.sysml +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_text_writer.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_validation.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_values_units.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_views/test_trace_contains_all_edge_kinds.trace.mmd +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_views/test_tree_contains_hierarchy.tree.mmd +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_views.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_workspace.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/tools/conformance/run_oracle.py +0 -0
- {sysml2kit-0.3.0 → sysml2kit-0.3.1}/uv.lock +0 -0
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.1 — 2026-08-21
|
|
4
|
+
|
|
5
|
+
Hotfix release; upgrade recommended.
|
|
6
|
+
|
|
7
|
+
- **`fmt` could silently delete verification bindings and verify links.**
|
|
8
|
+
The loss gate's grammar signature missed MetadataFeature nodes, and
|
|
9
|
+
dependency statements leave no grammar node at all, so a format pass on a
|
|
10
|
+
binding-bearing file removed both without triggering the refusal. The
|
|
11
|
+
signature now covers metadata/annotation/dependency nodes and a textual
|
|
12
|
+
keyword guard catches statements the parser drops entirely; `fmt` on such
|
|
13
|
+
files now refuses unless `--lossy` is passed.
|
|
14
|
+
- Metadata values in textual output were rendered with Python repr
|
|
15
|
+
(single-quoted strings, `True`/`False`); they now render as SysML text
|
|
16
|
+
(double-quoted strings, `true`/`false`).
|
|
17
|
+
- With multiple verificationBinding annotations on one analysis, requirement
|
|
18
|
+
checking used the last binding while write-back provenance named the
|
|
19
|
+
first. Both now use the first binding, extra bindings execute with a
|
|
20
|
+
logged warning, and full multi-binding support is planned.
|
|
21
|
+
|
|
3
22
|
## 0.3.0 — 2026-08-21
|
|
4
23
|
|
|
5
24
|
- **Verification execution** (`sysml2kit.verify`): `verificationBinding`
|
|
@@ -50,8 +50,7 @@ never edit `_version.py` or add a version literal.
|
|
|
50
50
|
- `interop/` — `RequirementSpec` extraction; the `metricKey` attribute
|
|
51
51
|
convention bridges to phased-array-systems and aedl (adapters live in those
|
|
52
52
|
repos, not here).
|
|
53
|
-
- `cli.py` — typer app
|
|
54
|
-
`src/sysml2kit/mcp/` following apab's `docs/mcp-conventions.md`.
|
|
53
|
+
- `cli.py` — typer app; `mcp/` follows apab's `docs/mcp-conventions.md`.
|
|
55
54
|
|
|
56
55
|
## Constraints
|
|
57
56
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sysml2kit
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: API-first Python tooling for building, querying, validating, and automating SysML v2 models
|
|
5
5
|
Project-URL: Homepage, https://github.com/jman4162/sysml2kit
|
|
6
6
|
Project-URL: Source, https://github.com/jman4162/sysml2kit
|
|
@@ -21,12 +21,13 @@ for spec in extract_requirements(model):
|
|
|
21
21
|
It ships four library packages (RFVocabulary quantity kinds with units,
|
|
22
22
|
RFParts part/port definitions, RFRequirements requirement definitions using
|
|
23
23
|
the metricKey convention, RFAnalyses analysis case definitions) plus
|
|
24
|
-
**SatcomTerminal28GHz**
|
|
25
|
-
benchmark:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
two worked examples. **SatcomTerminal28GHz** mirrors the aedl `t3-001`
|
|
25
|
+
benchmark: eight machine-checkable requirements, each satisfied by a part
|
|
26
|
+
and verified by an analysis. **SatcomTerminalPAS** is executable: its
|
|
27
|
+
`pasStudy` analysis carries a `verificationBinding` for the
|
|
28
|
+
`phased-array-systems` engine, so `sysml2kit verify` runs a real study and
|
|
29
|
+
all five requirements pass with margin (see
|
|
30
|
+
[verification](verification.md)).
|
|
30
31
|
|
|
31
32
|
The library demonstrates the intended division of labor: domain vocabulary
|
|
32
33
|
as SysML v2 model content, generic mechanics in the kit, physics engines
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.3.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 3,
|
|
21
|
+
__version__ = version = '0.3.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 3, 1)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -257,7 +257,20 @@ def _import_texts(node: dict[str, Any]) -> list[str]:
|
|
|
257
257
|
|
|
258
258
|
#: Grammar node names counted by :func:`grammar_signature`; infrastructure
|
|
259
259
|
#: wrappers whose names merely end in Usage are excluded.
|
|
260
|
-
_SIGNATURE_EXTRA = frozenset(
|
|
260
|
+
_SIGNATURE_EXTRA = frozenset(
|
|
261
|
+
{
|
|
262
|
+
"Package",
|
|
263
|
+
"Documentation",
|
|
264
|
+
"NamespaceImport",
|
|
265
|
+
"MembershipImport",
|
|
266
|
+
# Metadata and annotation nodes carry verification bindings; missing
|
|
267
|
+
# them let fmt silently delete bindings before 0.3.1.
|
|
268
|
+
"MetadataFeature",
|
|
269
|
+
"MetadataDefinition",
|
|
270
|
+
"AnnotatingElement",
|
|
271
|
+
"Dependency",
|
|
272
|
+
}
|
|
273
|
+
)
|
|
261
274
|
_SIGNATURE_EXCLUDE = frozenset({"Usage", "SubjectUsage"})
|
|
262
275
|
|
|
263
276
|
|
|
@@ -326,6 +326,15 @@ def fmt(
|
|
|
326
326
|
for kind in sorted(set(before) | set(after)):
|
|
327
327
|
if before.get(kind, 0) != after.get(kind, 0):
|
|
328
328
|
losses.append(f"{kind}: {before.get(kind, 0)} -> {after.get(kind, 0)}")
|
|
329
|
+
# Dependency statements leave no node in the grammar signature at all, so
|
|
330
|
+
# a textual keyword count is the only guard that can see them.
|
|
331
|
+
import re as _re
|
|
332
|
+
|
|
333
|
+
for keyword in ("dependency", "metadata", "satisfy", "allocate"):
|
|
334
|
+
n_before = len(_re.findall(rf"\b{keyword}\b", source))
|
|
335
|
+
n_after = len(_re.findall(rf"\b{keyword}\b", formatted))
|
|
336
|
+
if n_before != n_after:
|
|
337
|
+
losses.append(f"'{keyword}' statements: {n_before} -> {n_after}")
|
|
329
338
|
entries = diff_models(model, backend.parse(formatted), by_name=True)
|
|
330
339
|
if entries:
|
|
331
340
|
losses.append(render_diff(entries))
|
|
@@ -175,5 +175,14 @@ def _render_metadata(model: Model, element: MetadataUsage, indent: str) -> str:
|
|
|
175
175
|
if not element.values:
|
|
176
176
|
return f"{indent}metadata{name}{about};"
|
|
177
177
|
inner = indent + _INDENT
|
|
178
|
-
lines = [f"{inner}{escape_name(k)} = {v
|
|
178
|
+
lines = [f"{inner}{escape_name(k)} = {_metadata_value(v)};" for k, v in element.values.items()]
|
|
179
179
|
return f"{indent}metadata{name}{about} {{\n" + "\n".join(lines) + f"\n{indent}}}"
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _metadata_value(value: str | float | bool) -> str:
|
|
183
|
+
"""Render a metadata value in SysML syntax, not Python repr."""
|
|
184
|
+
if isinstance(value, bool):
|
|
185
|
+
return "true" if value else "false"
|
|
186
|
+
if isinstance(value, str):
|
|
187
|
+
return '"' + value.replace('"', '\\"') + '"'
|
|
188
|
+
return str(value)
|
|
@@ -8,6 +8,7 @@ into the model with provenance, opt-in.
|
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
|
+
import logging
|
|
11
12
|
from collections.abc import Sequence
|
|
12
13
|
from pathlib import Path
|
|
13
14
|
from typing import Literal
|
|
@@ -22,6 +23,8 @@ from sysml2kit.model.metadata import MetadataUsage
|
|
|
22
23
|
from sysml2kit.verify.binding import VerificationBinding, build_payload, extract_bindings
|
|
23
24
|
from sysml2kit.verify.engines import EngineRegistry
|
|
24
25
|
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
25
28
|
VERDICT_NAME = "verificationVerdict"
|
|
26
29
|
_RESULT_SOURCE_PREFIX = "sysml2kit.verify"
|
|
27
30
|
|
|
@@ -141,7 +144,21 @@ def run_verification(
|
|
|
141
144
|
for binding in bindings:
|
|
142
145
|
results.append(_run_binding(binding, registry, base_dir, engine_versions))
|
|
143
146
|
|
|
144
|
-
|
|
147
|
+
# First binding per analysis wins for checking, matching apply_results'
|
|
148
|
+
# selection, so provenance always names the engine that produced the
|
|
149
|
+
# verdict. Full multi-binding (fidelity ladder) support is planned; until
|
|
150
|
+
# then extra bindings execute but are not checked, and we say so.
|
|
151
|
+
by_analysis: dict[str, AnalysisResult] = {}
|
|
152
|
+
for result in results:
|
|
153
|
+
if result.analysis in by_analysis:
|
|
154
|
+
logger.warning(
|
|
155
|
+
"analysis %s has multiple bindings; only the first (%s) is "
|
|
156
|
+
"checked against requirements",
|
|
157
|
+
result.analysis,
|
|
158
|
+
by_analysis[result.analysis].engine,
|
|
159
|
+
)
|
|
160
|
+
continue
|
|
161
|
+
by_analysis[result.analysis] = result
|
|
145
162
|
verdicts = [
|
|
146
163
|
_verdict(spec, by_analysis[qualified])
|
|
147
164
|
for spec in extract_requirements(model)
|
|
@@ -97,3 +97,27 @@ def test_fmt_rejects_json(tmp_path):
|
|
|
97
97
|
f.write_text("[]")
|
|
98
98
|
result = runner.invoke(app, ["fmt", str(f)])
|
|
99
99
|
assert result.exit_code != 0
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
BINDING_BEARING = """package P {
|
|
103
|
+
part b;
|
|
104
|
+
requirement <'R1'> A;
|
|
105
|
+
analysis ana;
|
|
106
|
+
dependency from ana to A; // verify
|
|
107
|
+
metadata verificationBinding about ana {
|
|
108
|
+
engine = "fake";
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def test_fmt_refuses_binding_bearing_file(tmp_path):
|
|
115
|
+
"""Regression: before 0.3.1 fmt silently deleted bindings and verify links."""
|
|
116
|
+
f = tmp_path / "m.sysml"
|
|
117
|
+
f.write_text(BINDING_BEARING)
|
|
118
|
+
result = runner.invoke(app, ["fmt", str(f)])
|
|
119
|
+
assert result.exit_code == 1
|
|
120
|
+
assert "refusing" in result.output
|
|
121
|
+
assert "dependency" in result.output
|
|
122
|
+
assert "metadata" in result.output
|
|
123
|
+
assert f.read_text() == BINDING_BEARING # untouched
|
|
@@ -214,3 +214,26 @@ def test_write_back_provenance_and_idempotency():
|
|
|
214
214
|
)
|
|
215
215
|
== 1
|
|
216
216
|
)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def test_multiple_bindings_first_wins_consistently(caplog):
|
|
220
|
+
"""Hotfix regression: checking and write-back provenance must agree."""
|
|
221
|
+
model = bound_model()
|
|
222
|
+
analysis = model.find(name="RangeAnalysis")[0]
|
|
223
|
+
builder.metadata(model, analysis, {"engine": "second"}, name="verificationBinding")
|
|
224
|
+
registry = EngineRegistry()
|
|
225
|
+
registry.register("fake", lambda p: {"range_km": 420.0})
|
|
226
|
+
registry.register("second", lambda p: {"range_km": 1.0}) # would fail the check
|
|
227
|
+
import logging
|
|
228
|
+
|
|
229
|
+
with caplog.at_level(logging.WARNING):
|
|
230
|
+
run = run_verification(model, registry=registry)
|
|
231
|
+
assert len(run.analyses) == 2 # both executed
|
|
232
|
+
(verdict,) = run.requirements
|
|
233
|
+
assert verdict.status == "pass" # checked against the FIRST binding (fake)
|
|
234
|
+
assert "multiple bindings" in caplog.text
|
|
235
|
+
apply_results(model, run)
|
|
236
|
+
written = next(
|
|
237
|
+
el for el in model.owned_by(analysis) if getattr(el, "declared_name", "") == "range_km"
|
|
238
|
+
)
|
|
239
|
+
assert "fake==" in written.value.source # provenance names the checked engine
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
{sysml2kit-0.3.0 → sysml2kit-0.3.1}/tests/test_views/test_trace_contains_all_edge_kinds.trace.mmd
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|