simantic 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- simantic/__init__.py +85 -0
- simantic/__main__.py +10 -0
- simantic/_cli.py +139 -0
- simantic/_locate.py +76 -0
- simantic/agent.py +175 -0
- simantic/analog.py +94 -0
- simantic/auth.py +221 -0
- simantic/engine.py +91 -0
- simantic/fixtures.py +144 -0
- simantic/install.py +313 -0
- simantic/mcu.py +163 -0
- simantic/pyrite.py +72 -0
- simantic/pytest_plugin.py +232 -0
- simantic/report.py +194 -0
- simantic/session.py +409 -0
- simantic/telemetry.py +225 -0
- simantic-0.2.0.dist-info/METADATA +219 -0
- simantic-0.2.0.dist-info/RECORD +21 -0
- simantic-0.2.0.dist-info/WHEEL +4 -0
- simantic-0.2.0.dist-info/entry_points.txt +6 -0
- simantic-0.2.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: simantic
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Python SDK and pytest plugin for the Simantic circuit and firmware simulators
|
|
5
|
+
Project-URL: Homepage, https://simantic.dev
|
|
6
|
+
Project-URL: Source, https://github.com/simantic-dev/simantic-py
|
|
7
|
+
Project-URL: Issues, https://github.com/simantic-dev/simantic-py/issues
|
|
8
|
+
Author: Simantic
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: circuit,eda,firmware,kicad,pytest,simulation,spice
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Framework :: Pytest
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Requires-Dist: pythonnet>=3.0.5
|
|
20
|
+
Requires-Dist: pyyaml>=6
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# simantic
|
|
24
|
+
|
|
25
|
+
Python control of the [Simantic](https://simantic.dev) simulators — the
|
|
26
|
+
firmware engine hosted in your process, circuits via `analog-cli`. Everything
|
|
27
|
+
the CLIs can do, as objects and method calls: start a board or a multi-machine scenario, advance virtual
|
|
28
|
+
time by exact amounts, inject UART/GPIO/CAN/radio, read memory and RTOS state,
|
|
29
|
+
and run as many simulations in parallel as you have cores. pytest is one way
|
|
30
|
+
to use it, not a requirement.
|
|
31
|
+
|
|
32
|
+
> **Alpha — not stable.** Version 0.1.x. The API, the CLI surface, and the
|
|
33
|
+
> report schema may change without a deprecation period, and any release may
|
|
34
|
+
> break the previous one. Pin an exact version (`simantic==0.1.0`) if you
|
|
35
|
+
> depend on it. Not recommended for production pipelines yet.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install simantic
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
That is the whole setup for Python. The first `Sim(...)` fetches the
|
|
42
|
+
simulation engine (Simantic.Core plus a private .NET runtime — nothing else
|
|
43
|
+
to install) into `~/.simantic/engine/<version>/`, checksum-verified against
|
|
44
|
+
the public release manifest. `simantic install` fetches it up front, along
|
|
45
|
+
with the `sim` and `analog-cli` binaries if you also want the command-line
|
|
46
|
+
tools.
|
|
47
|
+
|
|
48
|
+
A Simantic account (`simantic auth`) is needed for one thing: resolving MCU
|
|
49
|
+
models by name (`mcu="STM32F401RE"`), which are fetched from your account
|
|
50
|
+
and cached in `~/.sim_cache`. A platform file you supply (`repl=`) needs no
|
|
51
|
+
account at all.
|
|
52
|
+
|
|
53
|
+
`simantic auth` opens a browser tab to sign in — like `gh auth login` — and
|
|
54
|
+
stores the resulting token in `~/.sim_id`, the same file the CLIs use, so one
|
|
55
|
+
login covers all of them. In a script or CI, pass `--token` or pipe one in
|
|
56
|
+
(`echo $TOKEN | simantic auth`) instead of opening a browser. Create a token
|
|
57
|
+
on the dashboard's `/account/api` page. `--no-browser` falls back to an
|
|
58
|
+
interactive prompt for a pasted token.
|
|
59
|
+
|
|
60
|
+
Every download — engine or binary — is verified against the checksum in the
|
|
61
|
+
release manifest. The package on PyPI contains only Python; the simulators
|
|
62
|
+
are never in the wheel.
|
|
63
|
+
|
|
64
|
+
Already have the binaries? Point `$SIMANTIC_ANALOG_CLI` and `$SIMANTIC_SIM`
|
|
65
|
+
at them, or put them on PATH — both take precedence over a managed install.
|
|
66
|
+
`simantic status` shows what is authenticated and which binary each name
|
|
67
|
+
resolves to.
|
|
68
|
+
|
|
69
|
+
## Drive a simulation
|
|
70
|
+
|
|
71
|
+
A `Sim` is a live simulation you control. Time advances only when you ask, so
|
|
72
|
+
a script is deterministic and your think-time is free:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from simantic import Sim
|
|
76
|
+
|
|
77
|
+
with Sim(elf="fw.elf", mcu="STM32F401RE", uart="usart2") as sim:
|
|
78
|
+
sim.expect("ready")
|
|
79
|
+
sim.inject_gpio("gpioc", 13, True) # press the user button
|
|
80
|
+
m = sim.expect("button pressed")
|
|
81
|
+
assert m.virtual_seconds < 0.010 # within 10 virtual ms
|
|
82
|
+
assert sim.read_u32("press_count") == 1
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The same class runs multi-machine scenarios with scripted peers
|
|
86
|
+
(`Sim(scenario={...})`). The engine lives in your process (one emulation per
|
|
87
|
+
process), so a parameter sweep is a `ProcessPoolExecutor` over plain
|
|
88
|
+
functions. See
|
|
89
|
+
[docs/session-api.md](docs/session-api.md) and `examples/`.
|
|
90
|
+
|
|
91
|
+
One-shot runs ("run 5 s, give me the transcript") are `run_firmware(...)`.
|
|
92
|
+
|
|
93
|
+
## Using it from pytest (optional)
|
|
94
|
+
|
|
95
|
+
`Sim` needs no plugin — construct it inside any test. If you also keep
|
|
96
|
+
manifests, installing the package registers two collectors that turn them
|
|
97
|
+
into individually addressable pytest items:
|
|
98
|
+
|
|
99
|
+
- `*.sim.toml` — one item per `[[test]]` table (analog)
|
|
100
|
+
- `test.yaml` — one item per fixture (firmware)
|
|
101
|
+
|
|
102
|
+
```console
|
|
103
|
+
$ pytest hardware/ firmware/
|
|
104
|
+
hardware/psu/psu.sim.toml::schematic-erc PASSED
|
|
105
|
+
hardware/psu/psu.sim.toml::rails-op PASSED
|
|
106
|
+
hardware/psu/psu.sim.toml::startup-settling FAILED
|
|
107
|
+
hardware/psu/psu.sim.toml::board-drc SKIPPED (no .kicad_pcb)
|
|
108
|
+
firmware/tests/gpio-loopback/test.yaml::gpio-loopback PASSED
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Because these are ordinary pytest items you get `-k` filtering, `--junitxml`
|
|
112
|
+
for CI, xdist parallelism, and per-test durations. Failures print the
|
|
113
|
+
runner's own explanation rather than a Python traceback:
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
startup-settling (tran): fail
|
|
117
|
+
FAIL settle-time: V(OUT) measured 0.0082 (expected max 0.006, margin -0.0022)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Tests that cannot run in the current environment skip rather than fail — a
|
|
121
|
+
missing binary, an unconfigured server, an analysis the installed CLI does
|
|
122
|
+
not support, a check inapplicable to the project. A red run means a
|
|
123
|
+
simulation ran and disagreed with its expectations.
|
|
124
|
+
|
|
125
|
+
## Library
|
|
126
|
+
|
|
127
|
+
### Circuits
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
import simantic
|
|
131
|
+
|
|
132
|
+
report = simantic.run_tests("hardware/psu")
|
|
133
|
+
print(f"{report.summary.passed}/{report.summary.total} passed")
|
|
134
|
+
|
|
135
|
+
for m in report.test("rails-op").measurements:
|
|
136
|
+
print(m.describe()) # out-dc: V(OUT) measured 1.597 (expected eq 1.597 +/- 0.02, margin 0.02)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
A failing test is data, not an exception: it arrives in the report with its
|
|
140
|
+
measured value, declared bounds, and margin. Only conditions that prevent a
|
|
141
|
+
run at all — bad project, missing `kicad-cli`, invalid testplan — raise
|
|
142
|
+
`AnalogCliError`.
|
|
143
|
+
|
|
144
|
+
### Firmware
|
|
145
|
+
|
|
146
|
+
The shortest path is a pytest fixture — no manifest, no flags:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
def test_firmware_boots(pyrite):
|
|
150
|
+
run = pyrite("build/zephyr.elf", board="stm32f401",
|
|
151
|
+
expect=["Hello World!"], expect_absent=["FAULT"])
|
|
152
|
+
assert run.passed, run.failure_report()
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`pyrite` runs the ELF offline on the pure-Rust backend and hands back the
|
|
156
|
+
UART transcript. The fixture skips when no binary is installed, so a suite
|
|
157
|
+
stays green on a machine that has not run `smtc install pyrite`.
|
|
158
|
+
|
|
159
|
+
The same runner is available as a plain function, and `sim` has its own:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
run = simantic.run_firmware(
|
|
163
|
+
"build/zephyr.elf",
|
|
164
|
+
mcu="STM32F401RE", # resolved by the backend through your account
|
|
165
|
+
expect=["RESULT: PASS"],
|
|
166
|
+
expect_absent=["RESULT: FAIL"],
|
|
167
|
+
)
|
|
168
|
+
assert run.passed, run.failure_report()
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`sim` emits no structured report — the only observable is UART text — so the
|
|
172
|
+
verdict is substring matching, the same contract `test.yaml` manifests use.
|
|
173
|
+
Pass `repl=` instead of `mcu=` for a platform file you author yourself.
|
|
174
|
+
|
|
175
|
+
MCU models are not distributed with this package: `mcu=` resolves them
|
|
176
|
+
through your account. If you have a local model library, set
|
|
177
|
+
`$SIMANTIC_MCU_LIB` to resolve from it instead — which is also what applying
|
|
178
|
+
a fixture's `overlay` fragment requires.
|
|
179
|
+
|
|
180
|
+
Some installations need a separate simulation server. When one does, the SDK
|
|
181
|
+
raises `ServerNotConfigured` and the pytest plugin skips, rather than
|
|
182
|
+
reporting a firmware failure.
|
|
183
|
+
|
|
184
|
+
## Telemetry
|
|
185
|
+
|
|
186
|
+
When you are authenticated, a completed pytest session reports its **shape**
|
|
187
|
+
to your account: how many simulator tests ran, how many passed, failed, or
|
|
188
|
+
skipped, plus this package's version, your Python version, OS, and CPU
|
|
189
|
+
architecture. One request per `pytest` invocation, never per test.
|
|
190
|
+
|
|
191
|
+
It also counts **which calls you make** — SDK functions, MCP tool names, and
|
|
192
|
+
`smtc` subcommands, by name only. These are buffered in
|
|
193
|
+
`~/.simantic/usage.jsonl` and uploaded as counts at most once an hour, so no
|
|
194
|
+
simulation ever waits on the network. You can read that file at any time; it
|
|
195
|
+
is one JSON object per line and contains nothing but call names.
|
|
196
|
+
|
|
197
|
+
It does **not** send file paths, project names, test names, firmware, or
|
|
198
|
+
simulation output. Those are yours.
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
export SIMANTIC_TELEMETRY=0 # or DO_NOT_TRACK=1
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
`smtc status` prints exactly what is sent and whether it is on. Reporting is
|
|
205
|
+
best-effort: if it fails, is blocked, or you are offline, your tests are
|
|
206
|
+
unaffected and nothing is printed.
|
|
207
|
+
|
|
208
|
+
## Compatibility
|
|
209
|
+
|
|
210
|
+
Speaks the `analog-cli.test-report/1` schema. Additive fields within that
|
|
211
|
+
revision are tolerated; a breaking revision raises `ReportError` rather than
|
|
212
|
+
silently misreading a report.
|
|
213
|
+
|
|
214
|
+
Multi-machine `test.yaml` fixtures — those with a `machines:` map — need the
|
|
215
|
+
`--scenario` runner and are not driven yet; they report as skips.
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
MIT. The simulators it drives are separate software under their own terms.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
simantic/__init__.py,sha256=nRcQNKGWNTcMBdGuVkwyTejxadfI-OyI80aRVGcBaaE,2305
|
|
2
|
+
simantic/__main__.py,sha256=RsPiml36e1H0q0vIoUA-S_Phwxn1Gls_j2goR7IRFJA,336
|
|
3
|
+
simantic/_cli.py,sha256=BpL1DOAX5WDz5BvSzaDnk5HH5Jmsz-JQO1J4YgeGOKI,4823
|
|
4
|
+
simantic/_locate.py,sha256=Czsu0x1mHSLuL2A3Srusbe3_SNiLcKcMkW_9LCsMKJ4,2258
|
|
5
|
+
simantic/agent.py,sha256=1gcvT0jEtnwgQ8WxTFUe33TCIrujJPYqh8kEM9NzJZo,6102
|
|
6
|
+
simantic/analog.py,sha256=kWeNV1-tM08lZqQM4WY3ASvZhTQSX6nXJZi9O7baswE,3249
|
|
7
|
+
simantic/auth.py,sha256=dxTgBk-QbhvlLd5y0mx-CYITHxXgQ0pup48DZt6MwE8,7777
|
|
8
|
+
simantic/engine.py,sha256=IxH_1pUlwbmDIfUu3sLWT-VUo62Qsvt1zURb8ycFnQ8,3383
|
|
9
|
+
simantic/fixtures.py,sha256=6z8SWrEqoET-Ze6cpcazlnCUqkg_-0J5OLWE4RNjwlQ,4679
|
|
10
|
+
simantic/install.py,sha256=ZzPJCGOGov8Klt-l4Frx7Czee3g5ZwXa46wlpsIvYgw,11143
|
|
11
|
+
simantic/mcu.py,sha256=IWfeqZQWrunuV10ClWdBVsNiYMylpcncs_UHzebfb1U,5932
|
|
12
|
+
simantic/pyrite.py,sha256=oe4h6Jm_y_BfQYPGESRzzJ9QpRJaG1cgO1yhXMCVPc4,2448
|
|
13
|
+
simantic/pytest_plugin.py,sha256=WlyGTw1iR7N49uKou7utD55QnJ4dRZVQSEKbbLaHrA8,7524
|
|
14
|
+
simantic/report.py,sha256=SBrZXaPMrN_nZWNnxoZ_yVgpnaJOyj62H0H5vUc6v4o,6185
|
|
15
|
+
simantic/session.py,sha256=wR05NWScWmzONcQCA0y_roa0REOeg0ITqN_fKPqey9g,17856
|
|
16
|
+
simantic/telemetry.py,sha256=MAhDtVqj87q0hH-QpJi-m11kw4QdeAllViI3uVW-9Sg,7473
|
|
17
|
+
simantic-0.2.0.dist-info/METADATA,sha256=3auIVM1epovDQvcDtPBKxq0zltEOPUVVqo80ZrKoWuk,8807
|
|
18
|
+
simantic-0.2.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
19
|
+
simantic-0.2.0.dist-info/entry_points.txt,sha256=uH213AdoDjOcclE5pHI5FLz0mRVWkxJu6cRbnvmOpRk,120
|
|
20
|
+
simantic-0.2.0.dist-info/licenses/LICENSE,sha256=VRIZiU3s-IRqoBOKW4KinZI6Y4Gf7H8xrXcM3WljfOk,1065
|
|
21
|
+
simantic-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Simantic
|
|
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.
|