Migrate Python scripts
If your Python scripts use an earlier version of Syside, some imports, calls, and attributes may need updating for v1. Use the changes below to update your scripts.
Load a model
load_model and try_load_model now return a locked model that you can
read directly. load_model raises syside.ModelError when the model has errors, so
to read the diagnostics of a model that may have errors, use try_load_model, which
returns the model either way. Get its diagnostics from model.diagnostics:
# before
model, diagnostics = syside.load_model(["model.sysml"])
# after
model = syside.load_model(["model.sysml"])
diagnostics = model.diagnostics
The model of a syside.ModelError is an UnlockedModel. Call lock() on
it to read the model.
You can still unpack the return value into model, diagnostics, but a type checker
infers both as Model | Diagnostics. Use model.diagnostics to avoid that ambiguity.
Given a list of sources, syside.json.loads also returns a locked model, together
with a report for each document it deserialized.
The kerml_source and sysml_source arguments are deprecated. To load source text,
pass (name, source) tuples in the source list, and the file extension of each name
sets its language. You can mix these tuples with files:
# before
model, diagnostics = syside.load_model(sysml_source=sysml)
# after
model = syside.load_model([("model.sysml", sysml)])
load_model and try_load_model can now find project settings and dependencies the
same way the CLI does. Pass config=True to find syside.toml, or sysand_dir=True
to find .sysand/, relative to the current working directory. With
sysand_dir=True, you don’t need to list each Sysand dependency yourself. The
load workspace example shows both options.
If you need to control when the model is locked, use load_model_unlocked or
try_load_model_unlocked. Both return an UnlockedModel. Call lock() when
you’re ready to read it.
Read documents
UnlockedModel and LockedModel replace BaseModel, so a check such
as isinstance(model, syside.BaseModel) is now false. Locking a model locks all its
documents together, so documents have no lock() method: remove each per-document
lock.
For a model returned by load_model, update document access as follows:
model.documentsandmodel.user_docsbecomemodel.documents.model.stdlib_docsbecomesmodel.environment.documents.To replace
model.all_docs, lock the model with its environment. See Choose which documents to read.Replace
model.uris()withmodel.urisforUrlvalues, ormodel.pathsforpathlib.Pathvalues. Neither property is available on an unlocked model.
# before
for path_str in model.uris():
...
# after
for uri in model.uris:
path_str = syside.decode_path(uri)
for path in model.paths:
path_str = str(path)
Choose which documents to read
DocumentKind and the considered_document_kinds argument of uris, nodes, and
elements have been removed. Choose which documents to read when you lock the model:
unlocked = syside.load_model_unlocked(["model.sysml"])
# DocumentKind.MODEL
with unlocked.lock() as model:
for node in model.nodes(...):
...
# DocumentKind.ENVIRONMENT
with unlocked.environment.lock() as model:
for node in model.nodes(...):
...
# DocumentKind.ALL
with unlocked.lock(with_environment=True) as model:
for node in model.nodes(...):
...
When you include the environment, the model’s documents come first, followed by the
environment’s documents. lock only locks the environment documents when
with_environment=True. If you run without the global interpreter lock (GIL), make
sure nothing modifies the environment documents while the model is locked.
Read diagnostics
DiagnosticMessage has been removed. Each diagnostic is now a (Url, Diagnostic)
tuple. Unpack it to get the source URL and the diagnostic:
# before
for diagnostic in diagnostics.validation:
filename = diagnostic.filename or "<source>"
full_message = diagnostic.full_message
# after
for url, diagnostic in diagnostics.validation:
filename = syside.decode_path(url)
full_message = f"{filename}{str(diagnostic).removeprefix('<source>')}"
Diagnostic also provides line and col properties, both counted from 1. The
message no longer includes the source excerpt. To print the diagnostics with their
excerpts, use str(model.diagnostics).
Diagnostics.results holds one DiagnosticResults for each document, with
its parser, sema and validation diagnostics. To add diagnostics, use the
document’s DiagnosticResults rather than Diagnostics itself. The properties of
DiagnosticResults are now mutable buffers.
Evaluate with a context
The Compiler evaluation methods and the CompilerFilter constructor now require a
syside.vm.Context instead of an Stdlib. Create the context from the model’s
standard library, then pass it as the first argument to the Compiler evaluation
methods:
ctx = syside.vm.Context(model.lib)
value, report = compiler.evaluate_feature(ctx, feature, scope)
value, report = compiler.evaluate(ctx, expr, scope=scope)
A call in the old form raises TypeError. Scripts often wrap evaluation in an
except that treats a failure as a value that can’t be evaluated; make sure it
doesn’t catch the TypeError, or every value reads as unevaluable.
Read the target of a feature chain
The fixes for
feature reference expression access
rewrite references such as Battery::capacity as feature chains such as
battery.capacity. A chain is a FeatureChainExpression, which has no
referent. Read its target_feature instead.
# before
target = expression.referent
# after
target = expression.target_feature
Read solver results
The JSON that syside solver prints reports each result as attainable and unattainable
values. An assertion no longer has a status of satisfied, violated or
unanalyzable, and values listed under values or proven are now in the
attainable listing. Update scripts that read those fields, using the mapping in
Read the solver’s output.
Replace removed members
Iterating a
LazyIteratordirectly (for x in it): use.collect()or.for_each.LazyIterator.__getitem__: use.getto access an item, or.collector.for_eachto iterate.The deprecated
Sema.resolveoverload: use.resolvewith locked documents.Feature.is_read_only: use.is_constant..transition_step,.trigger_step,.trigger_steps,.effect_step,.effect_steps, and.guard_expressionon succession types: these have been removed from the SysML v2 specification and have no replacement.TransitionUsagekeeps.guard_expressionand.guard_expressions.The mutation methods of
Urlhave been removed.collect_files_recursively: usepathlib.Path.rglob.The
syside.previewmodule: load models with theload_modelfamily instead,load_model,try_load_modeland their_unlockedforms.CstNode.grammar_type,grammar_symbol,has_changes,parse_state,next_parse_state,field_name_for_child,child_countandnamed_child_count, andStateId: these have been removed to allow future improvements.
Renamed and moved
ContainerViewis nowBufferView. The old name still works in type annotations, but not inisinstancechecks.Import interpreter symbols from
syside.vm. Their aliases in the root module are temporary.
Run each updated script on a model with known results and check that the output matches what you expect.