Serialize/deserialize of interface and flows fails

I’m serializing this sysml model to JSON:

package MyInterfaces {

item def BudgetRequest;

port def BuyerPort {
  out item request : BudgetRequest;
}

port def MarketPort {
  in item request : BudgetRequest;
}

interface def SearchFlow {

  flow of BudgetRequest
    from buyer.request
    to market.request;

  end buyer : BuyerPort;
  end market : MarketPort;
}

}

When deserializing it I get:
package MyInterfaces {
item def BudgetRequest;
port def BuyerPort { out item request : BudgetRequest; }
port def MarketPort { in item request : BudgetRequest; }
interface def all SearchFlow {
flow of BudgetRequest
buyer.BuyerPort::request to market.MarketPort::request;
end port buyer : BuyerPort;
end port market : MarketPort;
}
}

The keyword “all” has been added and “from” is missing.
This fails for all versions including 0.9.1

Thanks,

Robert

Here’s the code:



import syside

from pathlib import Path

from datetime import datetime, timezone




import json 

from pprint import pprint




from typing import List, Dict, Any

import pathlib

import os




import warnings




def _create_json_writer() -> syside.JsonStringWriter:

    json_options = syside.JsonStringOptions()

    json_options.include_cross_ref_uris = False

    json_options.indent = False

    writer = syside.JsonStringWriter(json_options)

    return writer




def _create_serialization_options() -> syside.SerializationOptions:

    options = syside.SerializationOptions().minimal().with_options(

        use_standard_names=True,

        include_derived=True,

        include_redefined=True,

        include_default=False,

        include_optional=False,

        include_implied=True,

    )

    options.fail_action = syside.FailAction.Ignore

    

    return options




def _model_to_json (model:syside.Model, minimal:bool=False):

    # Export the model to JSON

    assert len(model.user_docs) == 1




    writer = _create_json_writer()

    if minimal:

        options = syside.SerializationOptions.minimal()

    else:

        options =_create_serialization_options()




    with model.user_docs[0].lock() as locked:

        syside.serialize(locked.root_node, writer, options)

        json_string = writer.result




    now_str = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")




    obj = json.loads(json_string)

    for element in obj:

        if element.get("@type") == "Namespace" and "owningRelationship" not in element:

            element["qualifiedName"] = now_str   # set the value here

            #print(element)

            break

            

    return json.dumps(obj, indent=2)





def convert_sysml_file_textual_to_json2(sysml_file_path:str, json_out_path:str = None, minimal:bool=False) -> str:

    # load sysml textual notation and create json dump

    model, diagnostics = syside.try_load_model([sysml_file_path])




    # Only errors cause an exception. SysIDE may also report warnings and

    # informational messages

    assert not diagnostics.contains_errors(warnings_as_errors=True)




    json_string = _model_to_json(model, minimal)

    if json_out_path is not None:

        with open(json_out_path, "w", encoding="utf-8") as f:

            f.write(json_string)




    data = json.loads(json_string)

    return json_string





def convert_json_to_sysml_textual2(json_flexo:str, debug:bool=False):

    captured_warnings = []




    with warnings.catch_warnings(record=True) as wlist:

        warnings.simplefilter("always")  # capture all warnings




        # Normalize input to a JSON string (no double-encoding!)

        if isinstance(json_flexo, (dict, list)):

            json_in = json.dumps(json_flexo, ensure_ascii=False)

        elif isinstance(json_flexo, str):

            json_in = json_flexo

        else:

            raise TypeError(f"json_flexo must be dict/list/str, got {type(json_flexo).__name__}")




        # 1) Clean dangling refs & incomplete relationships → JSON string out

        #json_clean = clean_sysml_json_for_syside(json_in, preserve_refs_with_uri=True, debug=debug)




        # 3) Deserialize

        try:

            deserialized_model, _ = syside.json.loads(json_in, "memory:///import.sysml")

        except Exception as exc:

            # Try to catch the specific syside error type first

            try:

                from syside.json import DeserializationError  # sometimes exported here

            except Exception:

                try:

                    from syside.core import DeserializationError  # or here, depending on version

                except Exception:

                    DeserializationError = type(None)  # fallback so isinstance won't match




            if isinstance(exc, DeserializationError):

                # Many versions set these as attributes...

                report = getattr(exc, "report", None)

                model = getattr(exc, "model", None)




                # ...but they are always present in .args as a fallback

                if report is None and getattr(exc, "args", None):

                    if len(exc.args) >= 2:

                        model = exc.args[0]

                        report = exc.args[1]




                captured_warnings.append(f"Deserialization failed: {report}")

                return None, captured_warnings

            else:

                # Not a syside deserialization error; re-raise (or handle differently)

                raise





        # Collect warnings from this phase

        for w in wlist:

            captured_warnings.append(str(w.message))




    # Create an IdMap that will be used to link deserialized models together

    map = syside.IdMap()




    # Create an environment to have access to stdlib docs

    # If you have exported the stdlib to JSON as well, you do not need this

    # environment. However, currently we have a bug that prevents us from

    # loading the stdlib from JSON.

    for mutex in syside.Environment.get_default().documents:

        with mutex.lock() as dep:

            map.insert_or_assign(dep)




    try:

        report, success = deserialized_model.link(map)

    except Exception as exc:

        try:

            from syside.core import DeserializationError  # or here, depending on version

        except Exception:

            DeserializationError = type(None)  # fallback so isinstance won't match




        if isinstance(exc, DeserializationError):

            # Many versions set these as attributes...

            report = getattr(exc, "report", None)

            model = getattr(exc, "model", None)




            # ...but they are always present in .args as a fallback

            if report is None and getattr(exc, "args", None):

                if len(exc.args) >= 2:

                    model = exc.args[0]

                    report = exc.args[1]




            print("Deserialization failed. Diagnostic report:")

        else:

            # Not a syside deserialization error; re-raise (or handle differently)

            raise

        

    # Save the deserialized model to a file

    root_namespace = deserialized_model.document.root_node

    printer_cfg = syside.PrinterConfig(line_width=80, tab_width=2)

    printer = syside.ModelPrinter.sysml()

    sysml_text = syside.pprint(root_namespace, printer, printer_cfg)




    return (sysml_text, deserialized_model), captured_warnings




import json, pprint

EXAMPLE_DIR = pathlib.Path(os.getcwd())

MODEL_FILE_PATH = EXAMPLE_DIR / 't-v4.sysml'




# use minimal = True to get the compact version

raw_jsonf = convert_sysml_file_textual_to_json2(sysml_file_path=MODEL_FILE_PATH, minimal=False)

data = json.loads(raw_jsonf)  # parse JSON string into Python objects

(sysml_text, model), warnings = convert_json_to_sysml_textual2(data)

print(f"Created SysML model:\n{sysml_text}")

Thanks for the report.

  • all is erroneously printed on SysML connection definitions which are implicitly sufficient, however syntax does not allow it.
  • from is erroneously not printed even if payload exists. Is not an usually an issue with source formatting because from is preserved from the source instead.

Fixed for the next release.