Skip to content

Commit a1419a2

Browse files
committed
Initial commit
0 parents  commit a1419a2

File tree

12 files changed

+818
-0
lines changed

12 files changed

+818
-0
lines changed

.github/workflows/lint.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Ruff and Mypy Checks
2+
3+
on:
4+
push: # Triggers on all branches
5+
pull_request: # Triggers on all PRs
6+
7+
jobs:
8+
lint:
9+
name: Run Ruff and Mypy
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout code
14+
uses: actions/checkout@v3
15+
16+
- name: Set up Python
17+
uses: actions/setup-python@v4
18+
with:
19+
python-version: '3.11'
20+
21+
- name: Install dependencies
22+
run: |
23+
python -m pip install --upgrade pip
24+
pip install uv
25+
uv sync --group lint
26+
27+
- name: Run Ruff
28+
run: |
29+
uv run --frozen python -m ruff check
30+
31+
- name: Run Mypy
32+
run: |
33+
uv run --frozen python -m mypy

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.idea/
2+
venv/
3+
/dist/
4+
/output/result.csv
5+
/output/result_sampled.csv
6+
/output/generate_log.txt
7+
/output/simulate_log.txt

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 eXXcellent solutions
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
![easyssp-logo-light](https://raw.githubusercontent.com/exxcellent/easyssp-auth-client-python/refs/heads/master/images/logo-light.png#gh-light-mode-only)
2+
![easyssp-logo-dark](https://raw.githubusercontent.com/exxcellent/easyssp-auth-client-python/refs/heads/master/images/logo-dark.png#gh-dark-mode-only)
3+
4+
# 📘 easySSP – Simulation Client Examples
5+
6+
This repository provides real-world examples for using the
7+
official [easySSP Simulation Client](https://github.com/exxcellent/easyssp-simulation-client-python). Whether you're
8+
testing the
9+
API or building production workflows, these scripts will help you get started quickly.
10+
11+
---
12+
13+
## 🎯 What’s Inside
14+
15+
- 🔐 Authentication via the authentication module
16+
- 🧪 Run, stop, and delete simulations
17+
- 📈 Download results and sampled results
18+
- 📘 **Includes documentation for all Simulation API endpoints and models**
19+
20+
---
21+
22+
## 📁 Project Structure
23+
24+
```bash
25+
easyssp-simulation-examples-python/
26+
├── demo.py # Run a basic scenario
27+
├── simulation_operations.py # Helper functions for polling simulation status, downloading results, etc.
28+
├── start_simulation_config_json.py # JSON representation of a start simulation configuration
29+
├── input/
30+
│ └── exampleStimuli.csv # Stimuli file for starting a simulation
31+
│ └── simulation_example.ssp # SSP file for starting a simulation
32+
└── output # Directory for storing the simulation runs results and simulation steps logs.
33+
```
34+
35+
# 🚀 Getting Started with easySSP Simulation Examples
36+
37+
This guide walks you through setting up and running the example scripts provided in the easySSP Simulation Examples
38+
repository.
39+
40+
---
41+
42+
## 1. Clone the Repository
43+
44+
To begin, clone the repository and navigate into the project directory:
45+
46+
- Clone the repo:
47+
`git clone https://github.com/exxcellent/easyssp-simulation-examples-python.git`
48+
- Change into the directory:
49+
`cd easyssp-simulation-examples-python`
50+
51+
---
52+
53+
## 2. Install Dependencies
54+
55+
Ensure you have Python 3.11 or higher installed and a Pro Edition easySSP Account.
56+
Create the virtual environment by running
57+
58+
```bash
59+
python -m venv .venv
60+
.\.venv\Scripts\activate # or source .venv/bin/activate on macOS
61+
```
62+
63+
Then, install all required dependencies using uv:
64+
65+
```bash
66+
pip install uv
67+
uv sync
68+
```
69+
70+
---
71+
72+
## 3. Provide your login credentials
73+
74+
In the `demo.py` file, replace `your_easyssp_username` and `your_easyssp_password` with your real easySSP credentials
75+
to start the demo.
76+
77+
---
78+
79+
## 4. Run an Example Script
80+
81+
### 📂 Input & Output Directories
82+
83+
This repository uses structured folders to organize data and results:
84+
85+
#### 📥 `input/`
86+
87+
The `input/` directory contains files used to **start simulations**. These include:
88+
89+
- .ssp files
90+
- .csv stimuli files
91+
92+
Each script pulls its input data from this folder when submitting a request to the Simulation API.
93+
94+
---
95+
96+
#### 📤 `output/`
97+
98+
The `output/` directory is where **simulation results** are stored. This may include:
99+
100+
- Raw result files in CSV format
101+
- Simulation steps log files
102+
103+
This separation of input and output ensures clarity, reproducibility, and easy cleanup.
104+
105+
---
106+
107+
#### 🧪 `demo.py`
108+
109+
The `demo.py` script in the `demo` directory acts as a **central demo runner** and contains example requests that show
110+
how to use the client
111+
across different simulation scenarios. It's a great starting point if you're exploring the API for the first time or
112+
want to see full workflows in action.
113+
To start the demo, run
114+
115+
```bash
116+
cd demo
117+
python -m demo
118+
```
119+
120+
## 📚 Related Projects
121+
122+
### 🧠 [**Simulation Client**](https://github.com/exxcellent/easyssp-simulation-client-python)
123+
124+
The official Python client for interacting with the easySSP Simulation API.
125+
126+
### 🔐 [**Auth Client**](https://github.com/exxcellent/easyssp-auth-client-python)
127+
128+
Handles authentication by retrieving and storing JWT tokens.
129+
130+
### 🧰 [**Utils**](https://github.com/exxcellent/easyssp-python-clients-util)
131+
132+
A shared utility module used by all Python clients. Includes request handling, exceptions, and other reusable helpers.
133+
134+
---
135+
136+
## 🤝 Contributing
137+
138+
Spotted a bug or want to add your own scenario?
139+
Pull requests and issues are welcome!
140+
141+
## 📄 License
142+
143+
This project is licensed under the MIT License.

demo/demo.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from easyssp_auth import AuthError
2+
from easyssp_simulation.client import SimulationClient
3+
from easyssp_simulation.models import StartSimulationConfiguration
4+
from easyssp_utils.client import ApiException
5+
from pydantic import ValidationError
6+
from simulation_operations import (
7+
download_result,
8+
download_sampled_result,
9+
download_step_log,
10+
poll_status_until_finished,
11+
)
12+
from start_simulation_config_json import start_simulation_json_config
13+
14+
USER_AGENT = "easyssp-simulation-examples-python"
15+
16+
with (
17+
open("../input/simulation_example.ssp", "rb") as ssp_file,
18+
open("../input/exampleStimuli.csv", "rb") as stimuli_file
19+
):
20+
try:
21+
simulation_client = SimulationClient(username="your_easyssp_username", password="your_easyssp_password",
22+
user_agent=USER_AGENT)
23+
24+
# get simulation info and create start configuration
25+
simulation_info = simulation_client.get_simulation_info().data
26+
start_simulation_config = StartSimulationConfiguration.from_json(start_simulation_json_config)
27+
28+
# set the correct hardware identifier in the start configuration
29+
for run in start_simulation_config.runs: # type: ignore[union-attr]
30+
run.hardware_identifier = simulation_info.available_hardware[0].identifier
31+
32+
# start simulation
33+
simulation_started = simulation_client.start_simulation(
34+
configuration=start_simulation_config, # type: ignore[arg-type]
35+
ssp_file=ssp_file.read(),
36+
stimuli_file=[
37+
("exampleStimuli.csv",
38+
stimuli_file.read())
39+
]
40+
).data
41+
simulation_id = simulation_started.simulation.id
42+
print(f"Simulation Id: {simulation_id}")
43+
44+
# choose the first simulation run id
45+
run_id = simulation_started.simulation.runs[0].id
46+
print(f"Simulation Run Id: {run_id}")
47+
print(f"Simulation Cost: {simulation_started.total_credit_cost}")
48+
49+
poll_status_until_finished(simulation_id, simulation_client) # wait for the simulation to finish
50+
download_sampled_result(run_id, simulation_client) # download sampled results
51+
download_result(run_id, simulation_client) # download results
52+
53+
for step in simulation_started.simulation.runs[0].steps:
54+
download_step_log(step.id, step.step_key, simulation_client) # download step log
55+
# catch ValidationError for incorrect request parameters
56+
# catch ApiException for errors from the API client or the server
57+
except (AuthError, ApiException, ValidationError) as ex:
58+
print(ex)

demo/simulation_operations.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import time
2+
3+
from easyssp_simulation.client import SimulationClient
4+
from pydantic import StrictStr
5+
6+
7+
def poll_status_until_finished(simulation_id: StrictStr, simulation_client: SimulationClient) -> str:
8+
"""
9+
Method for polling the simulation status until it finishes
10+
:param simulation_id: The simulation id
11+
:param simulation_client: The simulation client
12+
:return: The simulation status
13+
"""
14+
status = ""
15+
16+
while status not in ["done", "stopped", "time_out", "error"]:
17+
try:
18+
time.sleep(5)
19+
except Exception as ex:
20+
print(f"An error occurred during sleep {ex}")
21+
22+
status = simulation_client.get_simulation(simulation_id=simulation_id).data.runs[0].run_status
23+
print(f"Current Simulation Status: {status}")
24+
25+
return status
26+
27+
28+
def download_sampled_result(run_id: StrictStr, simulation_client: SimulationClient) -> None:
29+
"""
30+
Method for downloading sampled results of a simulation run
31+
:param run_id: The run id
32+
:param simulation_client: The simulation client
33+
:return: None
34+
"""
35+
print("Will download sampled result file ...")
36+
with open("../output/result_sampled.csv", "wb") as file:
37+
try:
38+
intermediate_simulation_results = simulation_client.get_simulation_result_sample(
39+
run_id=run_id).data
40+
file.write(intermediate_simulation_results)
41+
except Exception as ex:
42+
print(ex)
43+
44+
45+
def download_result(run_id: StrictStr, simulation_client: SimulationClient) -> None:
46+
"""
47+
Method for downloading results of a simulation run
48+
:param run_id: The run id
49+
:param simulation_client: The simulation client
50+
:return: None
51+
"""
52+
print("Will download result file ...")
53+
with open("../output/result.csv", "wb") as file:
54+
try:
55+
simulation_results = simulation_client.get_simulation_result(run_id=run_id).data
56+
file.write(simulation_results)
57+
except Exception as ex:
58+
print(ex)
59+
60+
61+
def download_step_log(step_id: StrictStr, step_name: StrictStr, simulation_client: SimulationClient) -> None:
62+
"""
63+
Method for downloading step log
64+
:param step_id: The step id
65+
:param step_name: The step name
66+
:param simulation_client: The simulation client
67+
:return: None
68+
"""
69+
print(f"Will download log for {step_name} step ...")
70+
with open(f"../output/{step_name}_log.txt", "wb") as file:
71+
try:
72+
simulation_log = simulation_client.get_simulation_log(step_id=step_id).data
73+
file.write(simulation_log)
74+
except Exception as ex:
75+
print(ex)
76+
77+
78+
def delete_simulation(simulation_id: StrictStr, simulation_client: SimulationClient) -> None:
79+
"""
80+
Method for deleting a simulation
81+
:param simulation_id: The simulation id
82+
:param simulation_client: The simulation client
83+
:return: None
84+
"""
85+
try:
86+
simulation_client.delete_simulation(simulation_id=simulation_id)
87+
print(f"Deleted simulation {simulation_id}")
88+
except Exception as ex:
89+
print(f"Did not delete simulation {simulation_id}. Cause: {ex}")
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
start_simulation_json_config = """
2+
{
3+
"name": "Python Client Test Simulation",
4+
"runs": [
5+
{
6+
"name": "Python Client Run 1",
7+
"ssdFileName": "SystemStructure.ssd",
8+
"maxRunDurationInMinutes": 1,
9+
"stimuliFileName": "exampleStimuli.csv",
10+
"hardwareIdentifier": 123,
11+
"start": 0,
12+
"step": 0.01,
13+
"stop": 100,
14+
"targetType": "Linux64"
15+
},
16+
{
17+
"name": "Python Client Run 2",
18+
"ssdFileName": "SystemStructure.ssd",
19+
"maxRunDurationInMinutes": 2,
20+
"stimuliFileName": "exampleStimuli.csv",
21+
"hardwareIdentifier": 123,
22+
"start": 1,
23+
"step": 0.01,
24+
"stop": 102,
25+
"outputRate": 2,
26+
"targetType": "Linux64"
27+
}
28+
]
29+
}
30+
"""

0 commit comments

Comments
 (0)