Create Project Dynamically by Using Polyspace Python API
If you structure your projects in a modular way, you can submit your Polyspace® Platform project file to version control along with its source files and components such as external configurations and test references, or you can submit everything except the project file. If you do not submit the project file to version control, you can use the Polyspace Python® API to create the project on demand from its component parts.
Prerequisites
This example demonstrates the dynamic project creation workflow using the Polyspace Test™ demo project. If you have not set up the Polyspace Python API, follow the steps in Set Up Python API for Polyspace before running these scripts.
In the Polyspace
Test demo project, all configurations and graphical tests are saved in the Demo_C_PS_Test.psprjx project file. To run this example, you first need to create the .pscfg configuration files and .pstestd graphical test files for the new, dynamically generated project to reference. Export these files individually from the Polyspace Platform user interface or run this Python script to export all configurations and graphical tests in the project to external files:
from polyspace.project import Project
import polyspace
import polyspace.test
import os
import shutil
import tempfile
from pathlib import Path
# Find the demo project
root_path_readonly = (
Path(polyspace.__install_path__)
/ "polyspace"
/ "examples"
/ "pstest"
/ "Getting_Started_Example"
)
project_name = "Demo_C_PS_Test"
project_path = root_path_readonly / f"{project_name}.psprjx"
# Copy the demo project folder to a writable temp directory
# To specify a different location, replace temp_dir_base with a custom folder
temp_dir_base = Path(tempfile.mkdtemp(prefix="polyspace_example_"))
writable_root_path = temp_dir_base / root_path_readonly.name
shutil.copytree(root_path_readonly, writable_root_path, dirs_exist_ok=True)
writable_project_path = writable_root_path / f"{project_name}.psprjx"
proj = Project(str(writable_project_path))
# Ensure subfolders exist in the writable location
configs_dir = writable_root_path / "configs"
test_refs_dir = writable_root_path / "test_refs"
configs_dir.mkdir(parents=True, exist_ok=True)
test_refs_dir.mkdir(parents=True, exist_ok=True)
# Export copies of the active configurations to files
build_config_path = configs_dir / f"{project_name}_buildConfig.pscfg"
proj.ActiveBuildConfiguration.export(str(build_config_path))
static_analysis_config_path = configs_dir / f"{project_name}_staticAnalysisConfig.pscfg"
proj.ActiveStaticAnalysisConfiguration.export(str(static_analysis_config_path))
test_config_path = configs_dir / f"{project_name}_testConfig.pscfg"
proj.ActiveTestConfiguration.export(str(test_config_path))
# Loop through all test suites and export a copy of each graphical test case
for test_suite in proj.TestSuites:
if test_suite.TestCases and len(test_suite.TestCases) > 0:
# Create a subfolder for the test suite
ref_suite_dir = test_refs_dir / test_suite.Name
ref_suite_dir.mkdir(parents=True, exist_ok=True)
for test_case in test_suite.TestCases:
# Use the test case name for the exported graphical test file
test_case_name = test_case.Name
ref_filename = ref_suite_dir / f"{test_case_name}.pstestd"
test_case.export(str(ref_filename))
# Print location of generated files
print("Writable project root:", writable_root_path)
print("External configurations folder:", configs_dir)
print("Graphical test files root folder:", test_refs_dir)New Folder Structure
After you run the script to export the configurations and graphical tests, your project folder has these subfolders and files:
Getting_Started_Example/ ├── Demo_C_PS_Test.psprjx ├── configs/ │ ├── Demo_C_PS_Test_buildConfig.pscfg │ ├── Demo_C_PS_Test_staticAnalysisConfig.pscfg │ ├── Demo_C_PS_Test_testConfig.pscfg ├── includes/ │ ├── types.h ├── sources/ │ ├── utils.c ├── test_refs/ │ ├── checkStateTests/ │ ├── checkAccelerations_test.pstestd │ ├── checkAgainstSpeedLimit_test.pstestd │ ├── integrationTests/ │ ├── update_test_1.pstestd │ ├── update_test_2.pstestd │ ├── updateStateTests/ │ ├── addLatestReading_test_1.pstestd │ ├── addLatestReading_test_1_fail.pstestd │ ├── addLatestReading_test_2.pstestd │ ├── initOrReset_test.pstestd ├── tests/ │ ├── Requirements.html │ ├── test.c │ ├── testdata.h
Dynamically Create Project from External Files Using Polyspace Python API
To recreate a modular version of the demo project using the exported files, run this Python script:
# Create new dynamically generated project in the writable location
project_name = "dynamic_demo_proj"
project_path = writable_root_path / f"{project_name}.psprjx"
# Remove file if it already exists
project_path.unlink(missing_ok=True)
# Create the new project
dynamic_proj = Project(str(project_path))
# Add sources, includes, and xUnit tests from the demo project example
dynamic_proj.Code.Files.add(str(writable_root_path / "sources" / "utils.c"))
dynamic_proj.IncludePaths.add(str(writable_root_path / "includes"), Recursive=True)
dynamic_proj.Tests.Files.add(str(writable_root_path / "tests" / "test.c"))
# Add references to the new external configuration files
# Set the references as the active configurations
build_config_name = "Demo_C_PS_Test_buildConfig"
build_config_ref = dynamic_proj.BuildConfigurationRefs.add(
str(configs_dir / f"{build_config_name}.pscfg"), build_config_name)
dynamic_proj.ActiveBuildConfiguration = build_config_ref
static_analysis_config_name = "Demo_C_PS_Test_staticAnalysisConfig"
static_config_ref = dynamic_proj.StaticAnalysisConfigurationRefs.add(
str(configs_dir / f"{static_analysis_config_name}.pscfg"), static_analysis_config_name)
dynamic_proj.ActiveStaticAnalysisConfiguration = static_config_ref
test_config_name = "Demo_C_PS_Test_testConfig"
test_config_ref = dynamic_proj.TestConfigurationRefs.add(
str(configs_dir / f"{test_config_name}.pscfg"), test_config_name)
dynamic_proj.ActiveTestConfiguration = test_config_ref
# Add references to the new graphical test files in the test_refs folder
if test_refs_dir.exists():
test_suite_subfolders = [item.name for item in test_refs_dir.iterdir() if item.is_dir()]
for test_suite_name in test_suite_subfolders:
suite = dynamic_proj.TestSuites.create(test_suite_name)
subfolder_path = test_refs_dir / test_suite_name
test_files = list(subfolder_path.glob("*.pstestd"))
for test_file in test_files:
suite.TestCaseRefs.add(str(test_file), test_file.stem)
else:
print("[WARN] No test_refs folder found at:", test_refs_dir)
# Build the new project and save if build succeeds
status = polyspace.test.build(dynamic_proj)
if status:
print("[SUCCESS] Creating project:", project_path)
dynamic_proj.save()
else:
print("[ERROR] Build failed. Could not create project.")
Edit Project in Polyspace Platform User Interface
After dynamically creating a project, you can open it in the Polyspace Platform user interface to make changes such as modifying existing graphical tests or adding new ones. Because the last step in the dynamic project creation script builds the project, you can begin test authoring in the user interface as soon as you open the project.
If your files are already in version control, check out any files you need to update before making changes in the user interface. After adding new configurations or graphical tests, convert them to files that the project references. Then, build the project, run your tests, and perform any pre-submission quality checks before submitting the new and updated source and component files to version control.
Clean Up Temporary Files
When you are done with this example, run this code to remove the temporary folder that contains the example files:
try:
shutil.rmtree(temp_dir_base)
print("[INFO] Removed temporary folder:", temp_dir_base)
except Exception as e:
print(f"[WARN] Could not remove temporary folder: {e}")See Also
polyspace.project.Project | polyspace.project.BuildConfigurationRef | polyspace.project.StaticAnalysisConfigurationRef | polyspace.project.TestConfigurationRef | polyspace.project.TestCaseRef | polyspace.test.build