Create SCADE models#

With the SCADE Python API, you can modify SCADE projects and models. However, creating consistent instances of classes and associations requires a deep knowledge of the underlying meta-model. Mistakes can lead to corrupted models, which are difficult to detect, and to tool crashes.

The create module provides higher-level functions to ensure the syntactically correctness of the created models. The overall design consists in having independent functions, meaning that you do not have to make several function calls to complete a single modification.

Important

You must only use the SCADE Python API in command-line scripts. Modifying a model from the IDE while it is loaded corrupts the internal state of the SCADE Editor and leads to unpredictable results.

Usage notes#

  • The current version only supports creating elements in an existing project or Scade model. The edition of a model, for example deleting elements, requires more functions that might be added later.

  • Annotations are not supported yet.

  • The SCADE Python API is derived from the existing SCADE Creation Library (SCL), available for TCL and Python.

    • Functions have been renamed accordingly to PEP8.

    • While most of the interfaces are identical, there are a few changes for providing more Pythonics way of accomplishing tasks.

    • You can migrate existing applications to use the SCADE Python API or continue to use SCL, which is to be re-implemented on top of the SCADE Python API.

    • The functions are all accessible from create, regardless of the submodule that they are defined in.

Script architecture#

A script that modifies a Scade model usually follows this architecture:

  • Load an existing project: This gives access to two separate sets of data:

    • Project: Content of the project (ETP) file.

    • SCADE model: Content of the model (XSCADE and SCADE) files.

  • Add new elements to the project and the model.

  • Save the project and the model.

This script adds a new package to a project:

"""
Example for creating a package.

scade.exe -script <project> create_package.py
"""

from pathlib import Path

from scade.model.suite import get_roots as get_sessions
from scade.model.project.stdproject import get_roots as get_projects

import ansys.scade.apitools.create as create

def main():
    project = get_projects()[0]
    session = get_sessions()[0]

    # create a package in the project's directory
    path = Path(project.pathname).parent / 'MyPackage.xscade'
    package = create.create_package(session.model, 'MyPackage', path)
    # save the Scade model
    create.save_all()

    # add the package to the project file
    create.add_element_to_project(project, package)
    # save the project file
    create.save_project(project)

if __name__ == '__main__':
    main()

When run on an empty project, the new Scade model is as follows:

../_images/create_package_s.png

The new file is added to the project at the default location:

../_images/create_package_fv.png

Debugging of a creation script#

To ease debugging of a creation script, you should embed the script in an environment that first makes a copy of the original model.

The following script, compatible with any Python IDE, makes a copy of the original model, declares the result project, and calls the original script’s main function:

"""
Wrapper of create_package.py for debugging.

Project: ./Model/Model.etp
"""

from pathlib import Path
from shutil import rmtree, copytree

from ansys.scade.apitools import declare_project

from create_package import main

# duplicate the model to a new directory
dir = Path(__file__).parent
source_dir = dir / 'Model'
target_dir = dir / 'Result'
if target_dir.exists():
    rmtree(target_dir)
copytree(source_dir, target_dir)

# declare the duplicated model
declare_project(str(target_dir / 'Model.etp'))

# regular script
main()

Trees#

The library does not support the creation of intermediate elements, which eliminates the risk of incorrect models because of partial or missing links. For example, it is not possible to create an ExprId instance linked to a constant but not contained by any model element.

Some parts, such as types or expressions, can be quite large. You can use functions for creating such trees in an incremental way, which are compiled when creating the related model element. These intermediate structures, or trees, are used for creating:

  • Types

  • Expressions

  • Transitions

  • Control block branches

Type tree (TT)#

A TypeTree instance represents any SCADE type. Extended type trees (EX) provide more flexibility by accepting any of the following types:

  • TypeTree instance

  • scade.model.suite.Type instance

  • Name of a predefined type, such as 'bool', 'int32', and 'float64'

There are functions to create complex expression trees, such as structures or arrays. For more information, see create.type.

This example adds a simple type to a model:

# add a new type to the model, in the default file for root declarations
speed = create.create_named_type(model, 'Speed', 'float32', path=None)

This next example creates an array of points:

# add an array of points
tree = create.create_structure(('x', 'float32'), ('y', 'float32'))
point = create.create_named_type(model, 'Point', tree)
tree = create.create_table(9, point)
polyline = create.create_named_type(model, 'polyline', tree)

Although not advised, combining type trees is possible:

# add an array of anonymous (x, y)
tree_struct = create.create_structure(('x', 'float32'), ('y', 'float32'))
tree_table = create.create_table(9, tree_struct)
polyline2 = create.create_named_type(model, 'polyline2', tree_table)

For comprehensive information on functions for creating any type of tree, see create.type.

Expression tree (ET)#

An ExpressionTree instance represents any SCADE expression made of operators and operands. To create an extended expression (EX) tree, you can use the create.expression.EX() method. It provide more flexibility by accepting any of these types:

  • ExpressionTree instance

  • scade.model.suite.ConstVar instance

  • Scade literal, such as 'true' and '3.14_f32'

  • Python literal, such as True, 42, 3.14, and 'c'

The following example adds two constants to a model. The first one, N, is an integer, and its expression is the literal 42. The second one, N2, requires an expression tree to specify its value.

# constant N: int32 = 42
cst_n = create.create_constant(model, 'N', 'int32', 42)
# constant N2: int32 = N * N
tree = create.create_nary('*', cst_n, cst_n)
cst_n2 = create.create_constant(model, 'N2', 'int32', tree)

For more information on functions for creating an expression tree, see create.expression.