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
31 changes: 7 additions & 24 deletions .github/workflows/sonarqube.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,22 @@ jobs:
with:
python-version: '3.12'

- name: Restore SysIDE license file
- name: Check SysIDE license key presence
run: |
if [ -n "$SYSIDE_LICENSE_CONTENT_B64" ]; then
echo "SysIDE license content found, restoring license file..."
echo "$SYSIDE_LICENSE_CONTENT_B64" | base64 -d > automator-license.lic
ls -l automator-license.lic
echo "SysIDE license key found, attempting to set up license..."
python -c "
try:
import syside
print(syside.__version__)
except ImportError:
print('syside_license not available, tests will use mocks')
except Exception as e:
print(f'Failed to activate SysIDE license: {e}, tests will use mocks')
" || echo "License setup failed, tests will use mocks"
if [ -n "$SYSIDE_LICENSE_KEY" ]; then
echo "SYSIDE_LICENSE_KEY present"
else
echo "No SysIDE license content found, tests will use mocks if supported"
echo "SYSIDE_LICENSE_KEY missing, tests will use mocks if supported"
fi
env:
SYSIDE_LICENSE_CONTENT_B64: ${{ secrets.SYSIDE_LICENSE_CONTENT_B64 }}
SYSIDE_LICENSE_KEY: ${{ secrets.SYSIDE_LICENSE_KEY }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install requests
pip install git+https://github.com/Open-MBEE/sysmlv2-python-client.git@main
pip install syside==0.8.5
pip install syside==0.10.0
pip install pytest pytest-cov pytest-check coverage
pip install -e .

Expand All @@ -79,13 +67,8 @@ jobs:

- name: Run tests with coverage
env:
SYSIDE_LICENSE_FILE: automator-license.lic
SYSIDE_LICENSE_KEY: ${{ secrets.SYSIDE_LICENSE_KEY }}
run: |
coverage run -m pytest
coverage xml -o coverage.xml

- name: Remove SysIDE license file
if: always()
run: |
rm -f automator-license.lic

35 changes: 7 additions & 28 deletions .github/workflows/test-flexo-syside.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@ name: Test flexo_syside
on:
push:
branches: [ main, develop ]
paths-ignore:
- '.github/**'
pull_request:
branches: [ main, develop ]
paths-ignore:
- '.github/**'

jobs:
test:
Expand Down Expand Up @@ -37,44 +33,27 @@ jobs:
python -m pip install --upgrade pip
pip install requests
pip install git+https://github.com/Open-MBEE/sysmlv2-python-client.git@main
pip install syside==0.8.5
pip install syside==0.10.0
pip install -e .
pip install pytest pytest-cov pytest-check

- name: Restore SysIDE license file
- name: Check SysIDE license key presence
run: |
if [ -n "$SYSIDE_LICENSE_CONTENT_B64" ]; then
echo "SysIDE license content found, restoring license file..."
echo "$SYSIDE_LICENSE_CONTENT_B64" | base64 -d > automator-license.lic
ls -l automator-license.lic
echo "SysIDE license key found, attempting to set up license..."
python -c "
try:
import syside
print(syside.__version__)
except ImportError:
print('syside_license not available, tests will use mocks')
except Exception as e:
print(f'Failed to activate SysIDE license: {e}, tests will use mocks')
" || echo "License setup failed, tests will use mocks"
if [ -n "$SYSIDE_LICENSE_KEY" ]; then
echo "SYSIDE_LICENSE_KEY present"
else
echo "No SysIDE license content found, tests will use mocks if supported"
echo "SYSIDE_LICENSE_KEY missing, tests will use mocks if supported"
fi
env:
SYSIDE_LICENSE_CONTENT_B64: ${{ secrets.SYSIDE_LICENSE_CONTENT_B64 }}
SYSIDE_LICENSE_KEY: ${{ secrets.SYSIDE_LICENSE_KEY }}

- name: Run tests with coverage
env:
SYSIDE_LICENSE_FILE: automator-license.lic
SYSIDE_LICENSE_KEY: ${{ secrets.SYSIDE_LICENSE_KEY }}
run: |
mkdir -p test-results
pytest -v --tb=short --junitxml=test-results/results.xml --cov=src/flexo_syside_lib --cov-report=xml:test-results/coverage.xml --cov-report=html:test-results/htmlcov

- name: Remove SysIDE license file
if: always()
run: |
rm -f automator-license.lic

- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ It also depends on sysIDE automator library: https://sensmetry.com/syside/
### Recommended install (development or production):

```bash
pip install syside==0.8.5
pip install syside==0.10.0
pip install -e .
161 changes: 161 additions & 0 deletions examples/lemontree_diff.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "ba9a5705",
"metadata": {},
"outputs": [],
"source": [
"\n",
"import syside\n",
"import pathlib\n",
"import sys\n",
"import os\n",
"import uuid # To generate unique IDs if needed by API for creation\n",
"\n",
"from sysmlv2_client import SysMLV2Client, SysMLV2Error, SysMLV2NotFoundError\n",
"import json \n",
"from pprint import pprint\n",
"\n",
"from flexo_syside_lib.core import convert_sysml_file_textual_to_json, convert_sysml_string_textual_to_json, convert_json_to_sysml_textual\n",
"from flexo_syside_lib.utils2 import diff_ignoring_uuids, compare_ignoring_uuids"
]
},
{
"cell_type": "markdown",
"id": "3adcf163",
"metadata": {},
"source": [
"# Parse SysML model from string and convert to SysML v2 API Flexo JSON"
]
},
{
"cell_type": "markdown",
"id": "46196f01",
"metadata": {},
"source": []
},
{
"cell_type": "code",
"execution_count": 2,
"id": "5b096ea1",
"metadata": {},
"outputs": [],
"source": [
"sysml_model_string_1 = '''\n",
"package pkg {\n",
" part p;\n",
"}\n",
"'''\n",
"\n",
"sysml_model_string_2 = '''\n",
"package pkg {\n",
" part p;\n",
" part p1;\n",
"}\n",
"'''\n",
"\n",
"\n",
"change_payload_str, raw_json_base = convert_sysml_string_textual_to_json(sysml_model_string_1, minimal=True)\n",
"change_payload_str, raw_json_branch = convert_sysml_string_textual_to_json(sysml_model_string_2, minimal=True)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "2878a085",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Created SysML model:\n",
"package pkg { part p; }\n",
"\n",
"Created SysML model:\n",
"package pkg { part p; part p1; }\n",
"\n"
]
}
],
"source": [
"(sysml_text, model), captured_warnings = convert_json_to_sysml_textual(raw_json_base)\n",
"print(f\"Created SysML model:\\n{sysml_text}\")\n",
"(sysml_text, model), captured_warnings = convert_json_to_sysml_textual(raw_json_branch)\n",
"print(f\"Created SysML model:\\n{sysml_text}\")"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "bb7f8215",
"metadata": {},
"outputs": [],
"source": [
"with open(\"lt_base.json\", \"w\", encoding=\"utf-8\") as f:\n",
" f.write(str(raw_json_base))\n",
"with open(\"lt_branch.json\", \"w\", encoding=\"utf-8\") as f:\n",
" f.write(str(raw_json_branch))"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "c9ab9b92",
"metadata": {},
"outputs": [
{
"ename": "ValueError",
"evalue": "No root namespace found",
"output_type": "error",
"traceback": [
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
"\u001b[31mValueError\u001b[39m Traceback (most recent call last)",
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[6]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mopen\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mlt_merged.json\u001b[39m\u001b[33m\"\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mr\u001b[39m\u001b[33m\"\u001b[39m, encoding=\u001b[33m\"\u001b[39m\u001b[33mutf-8\u001b[39m\u001b[33m\"\u001b[39m) \u001b[38;5;28;01mas\u001b[39;00m f:\n\u001b[32m 2\u001b[39m data = json.load(f)\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m (sysml_text, model), captured_warnings = \u001b[43mconvert_json_to_sysml_textual\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 4\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mCreated SysML model:\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;132;01m{\u001b[39;00msysml_text\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n",
"\u001b[36mFile \u001b[39m\u001b[32m~\\Documents\\GitHub\\starforge_jupyter_notebook\\flexo_syside\\src\\flexo_syside_lib\\core.py:204\u001b[39m, in \u001b[36mconvert_json_to_sysml_textual\u001b[39m\u001b[34m(json_flexo, debug)\u001b[39m\n\u001b[32m 198\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mjson_flexo must be dict/list/str, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(json_flexo).\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 200\u001b[39m \u001b[38;5;66;03m# 1) Clean dangling refs & incomplete relationships → JSON string out\u001b[39;00m\n\u001b[32m 201\u001b[39m \u001b[38;5;66;03m#json_clean = clean_sysml_json_for_syside(json_in, preserve_refs_with_uri=True, debug=debug)\u001b[39;00m\n\u001b[32m 202\u001b[39m \n\u001b[32m 203\u001b[39m \u001b[38;5;66;03m# 2) Ensure root namespace is first (this function expects a JSON string)\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m204\u001b[39m json_import = \u001b[43m_make_root_namespace_first\u001b[49m\u001b[43m(\u001b[49m\u001b[43mjson_in\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 205\u001b[39m \u001b[38;5;66;03m# with open(\"debug.json\", \"w\", encoding=\"utf-8\") as f:\u001b[39;00m\n\u001b[32m 206\u001b[39m \u001b[38;5;66;03m# f.write(json_import)\u001b[39;00m\n\u001b[32m 207\u001b[39m \n\u001b[32m 208\u001b[39m \u001b[38;5;66;03m# 3) Deserialize\u001b[39;00m\n\u001b[32m 209\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n",
"\u001b[36mFile \u001b[39m\u001b[32m~\\Documents\\GitHub\\starforge_jupyter_notebook\\flexo_syside\\src\\flexo_syside_lib\\core.py:102\u001b[39m, in \u001b[36m_make_root_namespace_first\u001b[39m\u001b[34m(json_str)\u001b[39m\n\u001b[32m 100\u001b[39m obj.insert(\u001b[32m0\u001b[39m, obj.pop(found_root_namespace))\n\u001b[32m 101\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m102\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33m\"\u001b[39m\u001b[33mNo root namespace found\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 104\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m json.dumps(obj)\n",
"\u001b[31mValueError\u001b[39m: No root namespace found"
]
}
],
"source": [
"with open(\"lt_merged.json\", \"r\", encoding=\"utf-8\") as f:\n",
" data = json.load(f)\n",
"(sysml_text, model), captured_warnings = convert_json_to_sysml_textual(data)\n",
"print(f\"Created SysML model:\\n{sysml_text}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ebfe59aa",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv (3.12.9)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
71 changes: 71 additions & 0 deletions examples/lt_base.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
[
{
"@type": "Namespace",
"@id": "b67757f7-b9b0-5d17-b669-1ddf9b874c49",
"elementId": "b67757f7-b9b0-5d17-b669-1ddf9b874c49",
"ownedRelationship": [
{
"@id": "12dcda40-d102-5822-8304-7bf6f9708e50"
}
],
"qualifiedName": "2026-06-12T16:26:42Z"
},
{
"@type": "OwningMembership",
"@id": "12dcda40-d102-5822-8304-7bf6f9708e50",
"elementId": "12dcda40-d102-5822-8304-7bf6f9708e50",
"owningRelatedElement": {
"@id": "b67757f7-b9b0-5d17-b669-1ddf9b874c49"
},
"memberElement": {
"@id": "5dc23f7c-bffd-5a67-88cc-b08d6fff6d76"
},
"memberName": "pkg",
"ownedRelatedElement": [
{
"@id": "5dc23f7c-bffd-5a67-88cc-b08d6fff6d76"
}
]
},
{
"@type": "Package",
"@id": "5dc23f7c-bffd-5a67-88cc-b08d6fff6d76",
"elementId": "5dc23f7c-bffd-5a67-88cc-b08d6fff6d76",
"declaredName": "pkg",
"owningRelationship": {
"@id": "12dcda40-d102-5822-8304-7bf6f9708e50"
},
"ownedRelationship": [
{
"@id": "5686336d-35dc-5177-8bdf-e917c5d97564"
}
]
},
{
"@type": "OwningMembership",
"@id": "5686336d-35dc-5177-8bdf-e917c5d97564",
"elementId": "5686336d-35dc-5177-8bdf-e917c5d97564",
"owningRelatedElement": {
"@id": "5dc23f7c-bffd-5a67-88cc-b08d6fff6d76"
},
"memberElement": {
"@id": "cfac584e-a870-5ad9-8ac3-7cb8c0ca98cc"
},
"memberName": "p",
"ownedRelatedElement": [
{
"@id": "cfac584e-a870-5ad9-8ac3-7cb8c0ca98cc"
}
]
},
{
"@type": "PartUsage",
"@id": "cfac584e-a870-5ad9-8ac3-7cb8c0ca98cc",
"elementId": "cfac584e-a870-5ad9-8ac3-7cb8c0ca98cc",
"declaredName": "p",
"owningRelationship": {
"@id": "5686336d-35dc-5177-8bdf-e917c5d97564"
},
"isVariation": false
}
]
Loading
Loading