Action Flow Type Compatibility
This example checks whether the item type flowing out of each source port is compatible with the type expected by the destination port. A flow is compatible when the source type is the same as, or a specialization of, the destination type.
This example uses the same DataPipeline model as Action Flow Port Connectivity and
Action Flow Latency Analysis Labs. In this model, the flow from Analyze to Publish
passes an AnalysisResult where a Report is expected — a type mismatch, since
AnalysisResult does not specialize Report.
Concepts Used
API |
Purpose |
|---|---|
Port features at each end of a flow ( |
|
Type chain for a feature; filter by |
|
Returns whether one type is the same as, or a specialization of, another |
|
Source tier of an element ( |
Example Model
package DataPipeline {
private import ISQBase::DurationValue;
private import SI::min;
item def RawData;
item def CleanData;
item def AnalysisResult;
item def Report;
item def Tag;
action def Ingest {
doc /* Read raw data from a source. */
out item raw : RawData;
attribute latency : DurationValue = 2 [min];
}
action def Clean {
doc /* Remove noise and normalize the raw data. */
in item raw : RawData;
out item clean : CleanData;
attribute latency : DurationValue = 5 [min];
}
action def Analyze {
doc /* Run statistical analysis on clean data. */
in item clean : CleanData;
out item result : AnalysisResult;
attribute latency : DurationValue = 10 [min];
}
action def Publish {
doc /* Format and publish the result.
Expects a Report but receives an AnalysisResult — a type mismatch. */
in item report : Report;
in item tag : Tag; // intentionally left unconnected
attribute latency : DurationValue = 1 [min];
}
action def Pipeline {
first start;
then action ingest : Ingest;
then action clean : Clean;
then action analyze : Analyze;
then action publish : Publish;
flow from ingest.raw to clean.raw;
flow from clean.clean to analyze.clean;
// Type mismatch: AnalysisResult is not a subtype of Report
flow from analyze.result to publish.report;
// publish.tag is intentionally left without a flow
}
}
Example Script
import pathlib
import syside
EXAMPLE_DIR = pathlib.Path(__file__).parent
MODEL_FILE_PATH = EXAMPLE_DIR / "example_model.sysml"
def get_project_type(port: syside.Feature) -> syside.Type | None:
"""Return the most-specific project-defined type of a port, or None if
the port carries only standard-library types."""
return next(
(
t
for t in port.types.collect()
if t.document.document_tier == syside.DocumentTier.Project
),
None,
)
def check_flow_types(model: syside.Model, action_def_name: str) -> None:
"""Check whether the item type at each flow source conforms to the
type expected at the destination. Report any type mismatch."""
incompatible_found = False
for flow in model.nodes(syside.FlowUsage):
owning_def = flow.owning_definition
if owning_def is None or owning_def.name != action_def_name:
continue
src_port = flow.source_output_feature
tgt_port = flow.target_input_feature
if src_port is None or tgt_port is None:
continue
src_type = get_project_type(src_port)
tgt_type = get_project_type(tgt_port)
if src_type is None or tgt_type is None:
continue
# Identify the owning actions for labeling
src_action = flow.source_feature
tgt_actions = flow.target_features.collect()
tgt_action = tgt_actions[0] if tgt_actions else None
src_label = (
f"{src_action.name}.{src_port.name}"
if src_action
else src_port.name
)
tgt_label = (
f"{tgt_action.name}.{tgt_port.name}"
if tgt_action
else tgt_port.name
)
# The source type must be the same as, or a specialization of,
# the destination type.
compatible = src_type.specializes(tgt_type)
status = "OK" if compatible else "TYPE MISMATCH"
print(
f" [{status}] {src_label} ({src_type.name})"
f" -> {tgt_label} ({tgt_type.name})"
)
if not compatible:
incompatible_found = True
if not incompatible_found:
print(" All flows are type-compatible.")
def main() -> None:
(model, diagnostics) = syside.load_model([MODEL_FILE_PATH])
assert not diagnostics.contains_errors(warnings_as_errors=True)
action_def = "Pipeline"
print(f"Flow type-compatibility report for {action_def}:")
check_flow_types(model, action_def)
if __name__ == "__main__":
main()
Output
Flow type-compatibility report for Pipeline:
[OK] ingest.raw (RawData) -> clean.raw (RawData)
[OK] clean.clean (CleanData) -> analyze.clean (CleanData)
[TYPE MISMATCH] analyze.result (AnalysisResult) -> publish.report (Report)
Download
Download this example here.