Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "flexo_syside_lib"
version = "0.4.0"
version = "0.4.1"
description = "Using syside sysmlv2 with Flexo"
authors = [{name="Robert Karban", email="robert.karban@planetaryutilities.com"}]
readme = "README.md"
Expand Down
2 changes: 1 addition & 1 deletion src/flexo_syside_lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
)


__version__ = "0.4.0"
__version__ = "0.4.1"

__all__ = [
"build_sysand_command",
Expand Down
91 changes: 86 additions & 5 deletions src/flexo_syside_lib/serde.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import tempfile
import warnings
from datetime import datetime, timezone
from importlib.metadata import PackageNotFoundError, version as package_version
from pathlib import Path
from typing import Any

Expand All @@ -13,6 +14,11 @@
from .payload import ELEMENT_TYPE_KEY, wrap_elements_as_payload
from .utils2 import print_serde_report

try:
_PACKAGE_VERSION = package_version("flexo_syside_lib")
except PackageNotFoundError:
_PACKAGE_VERSION = "unknown"


def make_root_namespace_first_legacy(json_str: str) -> str:
obj = json.loads(json_str)
Expand Down Expand Up @@ -121,10 +127,65 @@ def _build_environment_from_models(
with tempfile.TemporaryDirectory(prefix="flexo_syside_env_") as env_dir:
_basenames, env_paths = _write_models_to_temp_paths(env_dir, environment_models)
model, diagnostics = syside.try_load_model(env_paths)
assert not diagnostics.contains_errors(warnings_as_errors=True)
_assert_no_diagnostic_errors(
diagnostics,
context="environment model load",
input_names=[name for name, _text in environment_models],
staged_paths=env_paths,
)
return model.to_environment() if model is not None and hasattr(model, "to_environment") else None


def _format_diagnostic_entry(diag: Any) -> str:
message = str(getattr(diag, "message", None) or getattr(diag, "text", None) or diag).strip()
severity = getattr(diag, "severity", None) or getattr(diag, "level", None)
severity_name = str(getattr(severity, "name", severity) or "unknown").lower()

file_path = str(
getattr(diag, "file", None)
or getattr(getattr(diag, "location", None), "file", None)
or getattr(getattr(diag, "location", None), "resource", None)
or ""
).strip()
line = getattr(diag, "line", None)
col = getattr(diag, "col", None)

location = file_path
if line is not None:
location = f"{location}:{line}" if location else str(line)
if col is not None:
location = f"{location}:{col}"
if location:
return f"[{severity_name}] {location} {message}".strip()
return f"[{severity_name}] {message}".strip()


def _assert_no_diagnostic_errors(
diagnostics: Any,
*,
context: str,
input_names: list[str],
staged_paths: list[str],
) -> None:
if not diagnostics.contains_errors(warnings_as_errors=True):
return

all_diagnostics = list(getattr(diagnostics, "all", []) or [])
lines = [
f"flexo_syside_lib { _PACKAGE_VERSION } {context} failed with {len(all_diagnostics)} diagnostic(s)",
f"input_names={input_names}",
f"staged_paths={staged_paths}",
]
if not all_diagnostics:
lines.append("diagnostics=[]")
else:
lines.append("diagnostics:")
lines.extend(f"- {_format_diagnostic_entry(diag)}" for diag in all_diagnostics[:20])
if len(all_diagnostics) > 20:
lines.append(f"- ... {len(all_diagnostics) - 20} more diagnostic(s)")
raise AssertionError("\n".join(lines))


def model_to_json(
model: syside.Model,
minimal: bool = False,
Expand Down Expand Up @@ -171,7 +232,12 @@ def convert_sysml_file_textual_to_json(
minimal: bool = False,
) -> tuple[list[dict[str, Any]], str]:
model, diagnostics = syside.try_load_model([sysml_file_path])
assert not diagnostics.contains_errors(warnings_as_errors=True)
_assert_no_diagnostic_errors(
diagnostics,
context="single-file model load",
input_names=[Path(sysml_file_path).name],
staged_paths=[sysml_file_path],
)

json_string = model_to_json(
model,
Expand All @@ -192,7 +258,12 @@ def convert_sysml_files_textual_to_json(
minimal: bool = False,
) -> tuple[list[dict[str, Any]], str]:
model, diagnostics = syside.try_load_model(sysml_file_paths)
assert not diagnostics.contains_errors(warnings_as_errors=True)
_assert_no_diagnostic_errors(
diagnostics,
context="multi-file model load",
input_names=[Path(sysml_file_path).name for sysml_file_path in sysml_file_paths],
staged_paths=sysml_file_paths,
)

json_string = model_to_json(
model,
Expand Down Expand Up @@ -220,7 +291,12 @@ def convert_sysml_models_textual_to_json(
basenames, temp_paths = _write_models_to_temp_paths(tmp_dir, sysml_models)
environment = _build_environment_from_models(environment_models)
model, diagnostics = syside.try_load_model(temp_paths, environment=environment)
assert not diagnostics.contains_errors(warnings_as_errors=True)
_assert_no_diagnostic_errors(
diagnostics,
context="textual models load",
input_names=[name for name, _text in sysml_models],
staged_paths=temp_paths,
)

json_string = model_to_json(
model,
Expand All @@ -241,7 +317,12 @@ def convert_sysml_string_textual_to_json(
minimal: bool = False,
) -> tuple[list[dict[str, Any]], str]:
model, diagnostics = syside.load_model(sysml_source=sysml_model_string)
assert not diagnostics.contains_errors(warnings_as_errors=True)
_assert_no_diagnostic_errors(
diagnostics,
context="string model load",
input_names=["<string>"],
staged_paths=["<memory>"],
)

json_string = model_to_json(model, minimal)
if json_out_path is not None:
Expand Down
39 changes: 39 additions & 0 deletions tests/test_mocked_syside.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import tempfile
from unittest.mock import Mock, patch

import pytest

from flexo_syside_lib.core import (
_create_json_writer,
_create_serialization_options,
Expand Down Expand Up @@ -254,6 +256,43 @@ def test_convert_sysml_models_to_json_allows_duplicate_basenames_in_environment(
assert env_call_paths[1].endswith("LibB\\root\\package.sysml") or env_call_paths[1].endswith("LibB/root/package.sysml")


@patch("flexo_syside_lib.serde.syside")
def test_convert_sysml_models_to_json_surfaces_diagnostics_in_assertion(mock_syside):
env_model = Mock()
env_model.to_environment.return_value = "ENV"
env_diags = Mock()
env_diags.contains_errors.return_value = False

failure_diag = Mock()
failure_diag.message = "Couldn't resolve import Demo::Library"
failure_diag.severity = "error"
failure_diag.file = "/tmp/0000_workspace/test.sysml"
failure_diag.line = 7
failure_diag.col = 3

main_diags = Mock()
main_diags.contains_errors.return_value = True
main_diags.all = [failure_diag]

mock_syside.try_load_model.side_effect = [
(env_model, env_diags),
(Mock(), main_diags),
]

with pytest.raises(AssertionError) as excinfo:
convert_sysml_models_textual_to_json(
[("workspace/test.sysml", "package Test;")],
environment_models=[("Demo/root/library.sysml", "library package Demo; end;")],
)

message = str(excinfo.value)
assert "textual models load failed" in message
assert "Couldn't resolve import Demo::Library" in message
assert "workspace/test.sysml" in message
assert "0000_workspace" in message
assert "flexo_syside_lib" in message


@patch("flexo_syside_lib.serde.syside")
def test_create_json_writer(mock_syside):
mock_writer_class = Mock()
Expand Down
2 changes: 1 addition & 1 deletion tests/test_payload_and_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def test_package_root_exports_conversion_helpers():
assert callable(flexo_syside_lib.convert_sysml_string_textual_to_json)
assert callable(flexo_syside_lib.convert_json_to_sysml_textual)
assert callable(flexo_syside_lib.expand_minimal_json_to_full_json)
assert flexo_syside_lib.__version__ == "0.4.0"
assert flexo_syside_lib.__version__ == "0.4.1"


def test_convert_json_to_sysml_textual_invalid_input():
Expand Down
Loading