testerkit 0.4.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.
Files changed (521) hide show
  1. testerkit/__init__.py +68 -0
  2. testerkit/_docs/_assets/operator-ui/channels/table.png +0 -0
  3. testerkit/_docs/_assets/operator-ui/dashboard/runs.png +0 -0
  4. testerkit/_docs/_assets/operator-ui/dashboard/stations.png +0 -0
  5. testerkit/_docs/_assets/operator-ui/events/filters.png +0 -0
  6. testerkit/_docs/_assets/operator-ui/events/table.png +0 -0
  7. testerkit/_docs/_assets/operator-ui/explore/chart.png +0 -0
  8. testerkit/_docs/_assets/operator-ui/explore/filters.png +0 -0
  9. testerkit/_docs/_assets/operator-ui/explore/plot-controls.png +0 -0
  10. testerkit/_docs/_assets/operator-ui/files/table.png +0 -0
  11. testerkit/_docs/_assets/operator-ui/launch/form.png +0 -0
  12. testerkit/_docs/_assets/operator-ui/metrics/filters.png +0 -0
  13. testerkit/_docs/_assets/operator-ui/metrics/pareto.png +0 -0
  14. testerkit/_docs/_assets/operator-ui/metrics/ppk.png +0 -0
  15. testerkit/_docs/_assets/operator-ui/metrics/yield.png +0 -0
  16. testerkit/_docs/_assets/operator-ui/results/detail-header.png +0 -0
  17. testerkit/_docs/_assets/operator-ui/results/detail-measurements.png +0 -0
  18. testerkit/_docs/_assets/operator-ui/results/detail-overview.png +0 -0
  19. testerkit/_docs/_assets/operator-ui/results/detail-steps.png +0 -0
  20. testerkit/_docs/_assets/operator-ui/results/stats.png +0 -0
  21. testerkit/_docs/_assets/operator-ui/results/table.png +0 -0
  22. testerkit/_docs/_assets/operator-ui/tour/designer.png +0 -0
  23. testerkit/_docs/_assets/operator-ui/tour/docs.png +0 -0
  24. testerkit/_docs/_assets/operator-ui/tour/fixtures.png +0 -0
  25. testerkit/_docs/_assets/operator-ui/tour/instruments.png +0 -0
  26. testerkit/_docs/_assets/operator-ui/tour/parts.png +0 -0
  27. testerkit/_docs/_assets/operator-ui/tour/profiles.png +0 -0
  28. testerkit/_docs/_assets/operator-ui/tour/stations.png +0 -0
  29. testerkit/_docs/_assets/operator-ui/tour/tests.png +0 -0
  30. testerkit/_docs/_assets/operator-ui/tour/uuts.png +0 -0
  31. testerkit/_docs/concepts/configuration/capabilities.md +447 -0
  32. testerkit/_docs/concepts/configuration/fixtures.md +335 -0
  33. testerkit/_docs/concepts/configuration/index.md +14 -0
  34. testerkit/_docs/concepts/configuration/parts.md +276 -0
  35. testerkit/_docs/concepts/configuration/stations.md +214 -0
  36. testerkit/_docs/concepts/data/data-stores.md +199 -0
  37. testerkit/_docs/concepts/data/event-log.md +185 -0
  38. testerkit/_docs/concepts/data/event-sourcing.md +76 -0
  39. testerkit/_docs/concepts/data/flight-streaming.md +58 -0
  40. testerkit/_docs/concepts/data/index.md +17 -0
  41. testerkit/_docs/concepts/data/sessions.md +78 -0
  42. testerkit/_docs/concepts/data/three-verbs.md +260 -0
  43. testerkit/_docs/concepts/execution/index.md +13 -0
  44. testerkit/_docs/concepts/execution/outcomes.md +199 -0
  45. testerkit/_docs/concepts/execution/step-hierarchy.md +170 -0
  46. testerkit/_docs/concepts/execution/step-manifest.md +115 -0
  47. testerkit/_docs/concepts/index.md +40 -0
  48. testerkit/_docs/concepts/overview/ai-integration.md +57 -0
  49. testerkit/_docs/concepts/overview/architecture.md +357 -0
  50. testerkit/_docs/concepts/overview/index.md +14 -0
  51. testerkit/_docs/concepts/overview/platform-vs-framework.md +147 -0
  52. testerkit/_docs/concepts/overview/pytest.md +53 -0
  53. testerkit/_docs/concepts/overview/tiers.md +46 -0
  54. testerkit/_docs/how-to/catalog/datasheet-to-test.md +169 -0
  55. testerkit/_docs/how-to/catalog/index.md +11 -0
  56. testerkit/_docs/how-to/configuration/configuring-stations.md +364 -0
  57. testerkit/_docs/how-to/configuration/custom-drivers.md +484 -0
  58. testerkit/_docs/how-to/configuration/index.md +13 -0
  59. testerkit/_docs/how-to/configuration/mock-mode.md +342 -0
  60. testerkit/_docs/how-to/data/benchmarking.md +120 -0
  61. testerkit/_docs/how-to/data/capture-an-artifact.md +84 -0
  62. testerkit/_docs/how-to/data/capture-waveform.md +110 -0
  63. testerkit/_docs/how-to/data/choosing-a-channel-verb.md +108 -0
  64. testerkit/_docs/how-to/data/compare-runs.md +120 -0
  65. testerkit/_docs/how-to/data/export-results.md +104 -0
  66. testerkit/_docs/how-to/data/find-flaky-tests.md +108 -0
  67. testerkit/_docs/how-to/data/grafana-dashboards.md +148 -0
  68. testerkit/_docs/how-to/data/index.md +23 -0
  69. testerkit/_docs/how-to/data/mcp-debug-failures.md +125 -0
  70. testerkit/_docs/how-to/data/mcp-query-runs.md +120 -0
  71. testerkit/_docs/how-to/data/querying-channels.md +117 -0
  72. testerkit/_docs/how-to/data/querying-events.md +85 -0
  73. testerkit/_docs/how-to/data/stream-live-channel.md +134 -0
  74. testerkit/_docs/how-to/execution/custom-operator-ui.md +136 -0
  75. testerkit/_docs/how-to/execution/index.md +21 -0
  76. testerkit/_docs/how-to/execution/limits.md +193 -0
  77. testerkit/_docs/how-to/execution/managing-sessions.md +100 -0
  78. testerkit/_docs/how-to/execution/multi-uut-testing.md +211 -0
  79. testerkit/_docs/how-to/execution/operator-prompts.md +151 -0
  80. testerkit/_docs/how-to/execution/profiles.md +304 -0
  81. testerkit/_docs/how-to/execution/spec-driven-testing.md +169 -0
  82. testerkit/_docs/how-to/execution/test-context.md +212 -0
  83. testerkit/_docs/how-to/execution/traceability.md +252 -0
  84. testerkit/_docs/how-to/execution/vector-expansion.md +394 -0
  85. testerkit/_docs/how-to/execution/writing-tests.md +363 -0
  86. testerkit/_docs/how-to/index.md +59 -0
  87. testerkit/_docs/how-to/overview/index.md +11 -0
  88. testerkit/_docs/how-to/overview/mcp-integration.md +168 -0
  89. testerkit/_docs/how-to/overview/operator-ui-tour.md +234 -0
  90. testerkit/_docs/integration/data/grafana.md +162 -0
  91. testerkit/_docs/integration/data/index.md +15 -0
  92. testerkit/_docs/integration/data/lakehouse-import.md +226 -0
  93. testerkit/_docs/integration/data/logging.md +131 -0
  94. testerkit/_docs/integration/data/results-api.md +51 -0
  95. testerkit/_docs/integration/index.md +20 -0
  96. testerkit/_docs/integration/runtime/harness.md +281 -0
  97. testerkit/_docs/integration/runtime/index.md +13 -0
  98. testerkit/_docs/integration/runtime/instruments.md +284 -0
  99. testerkit/_docs/integration/runtime/pytest-existing.md +315 -0
  100. testerkit/_docs/reference/catalog/cookbook.md +389 -0
  101. testerkit/_docs/reference/catalog/index.md +11 -0
  102. testerkit/_docs/reference/catalog/schema.md +375 -0
  103. testerkit/_docs/reference/cli.md +660 -0
  104. testerkit/_docs/reference/configuration.md +406 -0
  105. testerkit/_docs/reference/data/channels-schema.md +145 -0
  106. testerkit/_docs/reference/data/event-types.md +554 -0
  107. testerkit/_docs/reference/data/events-schema.md +120 -0
  108. testerkit/_docs/reference/data/files-schema.md +141 -0
  109. testerkit/_docs/reference/data/index.md +18 -0
  110. testerkit/_docs/reference/data/models.md +2229 -0
  111. testerkit/_docs/reference/data/outputs.md +82 -0
  112. testerkit/_docs/reference/data/parquet-schema.md +529 -0
  113. testerkit/_docs/reference/data/performance-limits.md +224 -0
  114. testerkit/_docs/reference/data/query-api.md +247 -0
  115. testerkit/_docs/reference/index.md +69 -0
  116. testerkit/_docs/reference/operator-ui/channels/detail.md +82 -0
  117. testerkit/_docs/reference/operator-ui/channels/list.md +70 -0
  118. testerkit/_docs/reference/operator-ui/dashboard.md +87 -0
  119. testerkit/_docs/reference/operator-ui/designer.md +167 -0
  120. testerkit/_docs/reference/operator-ui/events.md +89 -0
  121. testerkit/_docs/reference/operator-ui/files.md +74 -0
  122. testerkit/_docs/reference/operator-ui/fixtures.md +100 -0
  123. testerkit/_docs/reference/operator-ui/instruments.md +126 -0
  124. testerkit/_docs/reference/operator-ui/launch.md +79 -0
  125. testerkit/_docs/reference/operator-ui/live.md +102 -0
  126. testerkit/_docs/reference/operator-ui/measurements.md +159 -0
  127. testerkit/_docs/reference/operator-ui/metrics.md +217 -0
  128. testerkit/_docs/reference/operator-ui/parts.md +98 -0
  129. testerkit/_docs/reference/operator-ui/profiles.md +103 -0
  130. testerkit/_docs/reference/operator-ui/results/detail.md +214 -0
  131. testerkit/_docs/reference/operator-ui/results/list.md +106 -0
  132. testerkit/_docs/reference/operator-ui/stations.md +98 -0
  133. testerkit/_docs/reference/operator-ui/tests.md +173 -0
  134. testerkit/_docs/reference/operator-ui/uuts.md +67 -0
  135. testerkit/_docs/reference/overview/index.md +11 -0
  136. testerkit/_docs/reference/overview/pytest-native.md +142 -0
  137. testerkit/_docs/reference/overview/skills.md +177 -0
  138. testerkit/_docs/reference/pytest/fixtures.md +342 -0
  139. testerkit/_docs/reference/pytest/index.md +12 -0
  140. testerkit/_docs/reference/pytest/markers.md +257 -0
  141. testerkit/_docs/reference/runtime/api.md +246 -0
  142. testerkit/_docs/reference/runtime/client.md +280 -0
  143. testerkit/_docs/reference/runtime/connect.md +140 -0
  144. testerkit/_docs/reference/runtime/index.md +13 -0
  145. testerkit/_docs/tutorial/01-first-test.md +113 -0
  146. testerkit/_docs/tutorial/02-mock-instruments.md +88 -0
  147. testerkit/_docs/tutorial/03-fixtures.md +169 -0
  148. testerkit/_docs/tutorial/04-limits.md +139 -0
  149. testerkit/_docs/tutorial/05-configuration.md +194 -0
  150. testerkit/_docs/tutorial/06-specifications.md +273 -0
  151. testerkit/_docs/tutorial/07-real-instruments.md +245 -0
  152. testerkit/_docs/tutorial/08-capabilities.md +223 -0
  153. testerkit/_docs/tutorial/09-production.md +374 -0
  154. testerkit/_docs/tutorial/10-live-monitoring.md +156 -0
  155. testerkit/_docs/tutorial/11-waveforms-and-evidence.md +169 -0
  156. testerkit/_docs/tutorial/12-continuous-monitoring.md +145 -0
  157. testerkit/_docs/tutorial/13-parallel-testing.md +233 -0
  158. testerkit/_docs/tutorial/index.md +61 -0
  159. testerkit/_docs/tutorial/quickstart.md +282 -0
  160. testerkit/analysis/__init__.py +9 -0
  161. testerkit/analysis/_common.py +24 -0
  162. testerkit/analysis/measurement_facets.py +524 -0
  163. testerkit/analysis/measurements_query.py +1458 -0
  164. testerkit/analysis/metrics.py +389 -0
  165. testerkit/analysis/runs_query.py +434 -0
  166. testerkit/analysis/steps_query.py +413 -0
  167. testerkit/api/__init__.py +6 -0
  168. testerkit/api/_mime.py +71 -0
  169. testerkit/api/app.py +1171 -0
  170. testerkit/api/dialogs/__init__.py +36 -0
  171. testerkit/api/dialogs/manager.py +617 -0
  172. testerkit/api/dialogs/models.py +79 -0
  173. testerkit/api/models.py +80 -0
  174. testerkit/api/responses.py +205 -0
  175. testerkit/api/runner.py +222 -0
  176. testerkit/api/schemas.py +311 -0
  177. testerkit/benchmark/__init__.py +34 -0
  178. testerkit/benchmark/concurrency.py +248 -0
  179. testerkit/benchmark/core.py +232 -0
  180. testerkit/benchmark/runner.py +628 -0
  181. testerkit/benchmark/scenario.py +313 -0
  182. testerkit/benchmark/system.py +191 -0
  183. testerkit/benchmark/workloads.py +507 -0
  184. testerkit/catalog/__init__.py +6 -0
  185. testerkit/catalog/generic/generic_dmm.yaml +61 -0
  186. testerkit/catalog/generic/generic_eload.yaml +31 -0
  187. testerkit/catalog/generic/generic_fgen.yaml +56 -0
  188. testerkit/catalog/generic/generic_oscilloscope.yaml +45 -0
  189. testerkit/catalog/generic/generic_psu.yaml +77 -0
  190. testerkit/catalog/generic/generic_smu.yaml +73 -0
  191. testerkit/channels.py +538 -0
  192. testerkit/cli/__init__.py +32 -0
  193. testerkit/cli/_common.py +113 -0
  194. testerkit/cli/_time.py +179 -0
  195. testerkit/cli/benchmark_cmd.py +56 -0
  196. testerkit/cli/catalog_cmd.py +39 -0
  197. testerkit/cli/daemon.py +157 -0
  198. testerkit/cli/data_cmd.py +1040 -0
  199. testerkit/cli/discover_cmd.py +94 -0
  200. testerkit/cli/docs_cmd.py +100 -0
  201. testerkit/cli/instrument.py +172 -0
  202. testerkit/cli/mcp_cmd.py +37 -0
  203. testerkit/cli/metrics.py +366 -0
  204. testerkit/cli/project.py +312 -0
  205. testerkit/cli/root.py +14 -0
  206. testerkit/cli/runs.py +412 -0
  207. testerkit/cli/schema_cmd.py +87 -0
  208. testerkit/cli/serve_cmd.py +50 -0
  209. testerkit/cli/setup_cmd.py +604 -0
  210. testerkit/cli/station.py +294 -0
  211. testerkit/cli/validate.py +112 -0
  212. testerkit/client.py +463 -0
  213. testerkit/connect.py +635 -0
  214. testerkit/data/__init__.py +8 -0
  215. testerkit/data/_accumulator_pool.py +455 -0
  216. testerkit/data/_atomic.py +59 -0
  217. testerkit/data/_collection_indices.py +67 -0
  218. testerkit/data/_daemon_lifecycle.py +535 -0
  219. testerkit/data/_duckdb_daemon.py +695 -0
  220. testerkit/data/_duckdb_flight_server.py +813 -0
  221. testerkit/data/_event_filters.py +15 -0
  222. testerkit/data/_event_reader.py +101 -0
  223. testerkit/data/_flight_errors.py +199 -0
  224. testerkit/data/_flight_query.py +202 -0
  225. testerkit/data/_flight_retry.py +148 -0
  226. testerkit/data/_flight_subscribe.py +67 -0
  227. testerkit/data/_index_epoch.py +342 -0
  228. testerkit/data/_ipc_writer.py +185 -0
  229. testerkit/data/_json_safe.py +63 -0
  230. testerkit/data/_process.py +18 -0
  231. testerkit/data/_push_relay.py +124 -0
  232. testerkit/data/_runs_duckdb_daemon.py +2704 -0
  233. testerkit/data/_session_reaper.py +110 -0
  234. testerkit/data/_sql_helpers.py +30 -0
  235. testerkit/data/_store.py +24 -0
  236. testerkit/data/backends/__init__.py +7 -0
  237. testerkit/data/backends/_event_accumulator.py +957 -0
  238. testerkit/data/backends/_row_helpers.py +1172 -0
  239. testerkit/data/backends/parquet.py +1143 -0
  240. testerkit/data/backends/protocol.py +35 -0
  241. testerkit/data/channels/__init__.py +8 -0
  242. testerkit/data/channels/_flight_daemon.py +75 -0
  243. testerkit/data/channels/client.py +242 -0
  244. testerkit/data/channels/flight_manager.py +88 -0
  245. testerkit/data/channels/index.py +664 -0
  246. testerkit/data/channels/models.py +418 -0
  247. testerkit/data/channels/server.py +162 -0
  248. testerkit/data/channels/store.py +1481 -0
  249. testerkit/data/data_dir.py +61 -0
  250. testerkit/data/duckdb_manager.py +79 -0
  251. testerkit/data/event_log.py +384 -0
  252. testerkit/data/event_store.py +768 -0
  253. testerkit/data/events.py +1025 -0
  254. testerkit/data/exporters/__init__.py +6 -0
  255. testerkit/data/exporters/_helpers.py +40 -0
  256. testerkit/data/exporters/csv_exporter.py +168 -0
  257. testerkit/data/exporters/hdf5.py +234 -0
  258. testerkit/data/exporters/json_exporter.py +229 -0
  259. testerkit/data/exporters/mdf4.py +201 -0
  260. testerkit/data/exporters/stdf.py +255 -0
  261. testerkit/data/exporters/tdms.py +292 -0
  262. testerkit/data/files/__init__.py +71 -0
  263. testerkit/data/files/_backend.py +207 -0
  264. testerkit/data/files/_catalog_daemon.py +84 -0
  265. testerkit/data/files/catalog.py +218 -0
  266. testerkit/data/files/catalog_manager.py +325 -0
  267. testerkit/data/files/models.py +60 -0
  268. testerkit/data/files/serializers.py +414 -0
  269. testerkit/data/files/store.py +463 -0
  270. testerkit/data/files/streaming.py +783 -0
  271. testerkit/data/models.py +604 -0
  272. testerkit/data/ref.py +152 -0
  273. testerkit/data/retention.py +297 -0
  274. testerkit/data/run_store.py +367 -0
  275. testerkit/data/runs_duckdb_manager.py +103 -0
  276. testerkit/data/schema_dispatch.py +191 -0
  277. testerkit/data/schema_migrate.py +76 -0
  278. testerkit/data/schema_versions.py +85 -0
  279. testerkit/data/schemas.py +288 -0
  280. testerkit/data/subscribers/__init__.py +48 -0
  281. testerkit/data/subscribers/_base.py +20 -0
  282. testerkit/data/subscribers/_output_file.py +25 -0
  283. testerkit/data/subscribers/replay.py +55 -0
  284. testerkit/environment.py +84 -0
  285. testerkit/execution/__init__.py +11 -0
  286. testerkit/execution/_git.py +190 -0
  287. testerkit/execution/_state.py +740 -0
  288. testerkit/execution/accessors.py +54 -0
  289. testerkit/execution/audit.py +51 -0
  290. testerkit/execution/cascade.py +85 -0
  291. testerkit/execution/connections.py +491 -0
  292. testerkit/execution/harness.py +1931 -0
  293. testerkit/execution/instrument_events.py +42 -0
  294. testerkit/execution/limits.py +154 -0
  295. testerkit/execution/metadata.py +102 -0
  296. testerkit/execution/mocks.py +63 -0
  297. testerkit/execution/profiles.py +616 -0
  298. testerkit/execution/run_scope.py +1331 -0
  299. testerkit/execution/session_scope.py +196 -0
  300. testerkit/execution/sidecar.py +280 -0
  301. testerkit/execution/site_runner.py +705 -0
  302. testerkit/execution/sites.py +183 -0
  303. testerkit/execution/sync.py +294 -0
  304. testerkit/execution/uut_provider.py +231 -0
  305. testerkit/execution/vectors.py +205 -0
  306. testerkit/execution/verify.py +396 -0
  307. testerkit/expand.py +75 -0
  308. testerkit/files.py +235 -0
  309. testerkit/fixtures/__init__.py +6 -0
  310. testerkit/fixtures/manager.py +357 -0
  311. testerkit/grafana/__init__.py +1 -0
  312. testerkit/grafana/bootstrap.py +61 -0
  313. testerkit/grafana/cli.py +314 -0
  314. testerkit/grafana/dashboards/asset_utilization.json +92 -0
  315. testerkit/grafana/dashboards/channel_explorer.json +77 -0
  316. testerkit/grafana/dashboards/event_log.json +92 -0
  317. testerkit/grafana/dashboards/failure_pareto.json +104 -0
  318. testerkit/grafana/dashboards/measurement_distribution.json +97 -0
  319. testerkit/grafana/dashboards/measurement_trend.json +161 -0
  320. testerkit/grafana/dashboards/station_comparison.json +95 -0
  321. testerkit/grafana/dashboards/test_duration.json +104 -0
  322. testerkit/grafana/dashboards/unit_traceability.json +73 -0
  323. testerkit/grafana/dashboards/yield_overview.json +189 -0
  324. testerkit/grafana/provisioning/dashboards.yaml.j2 +12 -0
  325. testerkit/grafana/provisioning/datasources.yaml.j2 +17 -0
  326. testerkit/grafana/server.py +282 -0
  327. testerkit/init.py +724 -0
  328. testerkit/instruments/__init__.py +10 -0
  329. testerkit/instruments/base.py +82 -0
  330. testerkit/instruments/discovery/__init__.py +62 -0
  331. testerkit/instruments/discovery/_base.py +174 -0
  332. testerkit/instruments/discovery/lxi.py +152 -0
  333. testerkit/instruments/discovery/ni.py +95 -0
  334. testerkit/instruments/discovery/serial.py +73 -0
  335. testerkit/instruments/discovery/visa.py +98 -0
  336. testerkit/instruments/lifecycle.py +213 -0
  337. testerkit/instruments/loader.py +79 -0
  338. testerkit/instruments/locks.py +178 -0
  339. testerkit/instruments/mocks.py +230 -0
  340. testerkit/instruments/observer.py +270 -0
  341. testerkit/instruments/observers/__init__.py +36 -0
  342. testerkit/instruments/observers/_base.py +68 -0
  343. testerkit/instruments/observers/daqmx.py +70 -0
  344. testerkit/instruments/observers/descriptor.py +69 -0
  345. testerkit/instruments/observers/generic.py +92 -0
  346. testerkit/instruments/observers/lantz.py +31 -0
  347. testerkit/instruments/observers/modbus.py +96 -0
  348. testerkit/instruments/observers/motion.py +68 -0
  349. testerkit/instruments/observers/ni_modular.py +73 -0
  350. testerkit/instruments/observers/ophyd.py +80 -0
  351. testerkit/instruments/observers/pymeasure.py +120 -0
  352. testerkit/instruments/observers/qcodes.py +66 -0
  353. testerkit/instruments/observers/scpi.py +88 -0
  354. testerkit/instruments/observers/tektronix.py +57 -0
  355. testerkit/instruments/observers/visa.py +103 -0
  356. testerkit/instruments/pool.py +459 -0
  357. testerkit/instruments/proxy.py +59 -0
  358. testerkit/instruments/route_manager.py +329 -0
  359. testerkit/instruments/routed_proxy.py +88 -0
  360. testerkit/instruments/server.py +508 -0
  361. testerkit/instruments/switch.py +43 -0
  362. testerkit/instruments/visa.py +294 -0
  363. testerkit/matching/__init__.py +6 -0
  364. testerkit/matching/service.py +969 -0
  365. testerkit/mcp/__init__.py +6 -0
  366. testerkit/mcp/server.py +681 -0
  367. testerkit/mcp/tools.py +1868 -0
  368. testerkit/models/__init__.py +18 -0
  369. testerkit/models/capability.py +598 -0
  370. testerkit/models/catalog.py +76 -0
  371. testerkit/models/data_options.py +153 -0
  372. testerkit/models/enums.py +334 -0
  373. testerkit/models/instrument.py +152 -0
  374. testerkit/models/instrument_asset.py +25 -0
  375. testerkit/models/part.py +271 -0
  376. testerkit/models/part_manifest.py +96 -0
  377. testerkit/models/project.py +114 -0
  378. testerkit/models/station.py +140 -0
  379. testerkit/models/test_config.py +748 -0
  380. testerkit/ontology/__init__.py +39 -0
  381. testerkit/ontology/schema.py +188 -0
  382. testerkit/ontology/testerkit.yaml +1420 -0
  383. testerkit/parts/__init__.py +8 -0
  384. testerkit/parts/context.py +181 -0
  385. testerkit/parts/folder.py +251 -0
  386. testerkit/parts/loader.py +27 -0
  387. testerkit/prompts/__init__.py +17 -0
  388. testerkit/prompts/core.py +133 -0
  389. testerkit/pytest_plugin/__init__.py +1287 -0
  390. testerkit/pytest_plugin/autouse.py +369 -0
  391. testerkit/pytest_plugin/helpers.py +354 -0
  392. testerkit/pytest_plugin/hooks.py +1982 -0
  393. testerkit/pytest_plugin/markers.py +203 -0
  394. testerkit/pytest_plugin/retry.py +37 -0
  395. testerkit/pytest_plugin/sweeps.py +117 -0
  396. testerkit/queries.py +78 -0
  397. testerkit/reports/__init__.py +6 -0
  398. testerkit/reports/core.py +492 -0
  399. testerkit/reports/datasheet.py +831 -0
  400. testerkit/reports/templates/datasheet.html +383 -0
  401. testerkit/reports/templates/default.html +153 -0
  402. testerkit/sbom.py +142 -0
  403. testerkit/schema_export.py +101 -0
  404. testerkit/signals.py +63 -0
  405. testerkit/skills/README.md +58 -0
  406. testerkit/skills/templates/project-instructions.md +125 -0
  407. testerkit/skills/testerkit-analysis/SKILL.md +87 -0
  408. testerkit/skills/testerkit-capture/SKILL.md +114 -0
  409. testerkit/skills/testerkit-data/SKILL.md +138 -0
  410. testerkit/skills/testerkit-datasheets/SKILL.md +100 -0
  411. testerkit/skills/testerkit-datasheets/agents/scaffold-writer.md +115 -0
  412. testerkit/skills/testerkit-datasheets/agents/section-extractor.md +98 -0
  413. testerkit/skills/testerkit-datasheets/agents/section-reviewer.md +153 -0
  414. testerkit/skills/testerkit-datasheets/agents/section-splitter.md +89 -0
  415. testerkit/skills/testerkit-datasheets/agents/section-writer.md +226 -0
  416. testerkit/skills/testerkit-datasheets/references/catalog-pipeline.md +271 -0
  417. testerkit/skills/testerkit-datasheets/references/process-queue.md +42 -0
  418. testerkit/skills/testerkit-datasheets/references/scaffold.md +156 -0
  419. testerkit/skills/testerkit-datasheets/references/test-pipeline.md +312 -0
  420. testerkit/skills/testerkit-debug/SKILL.md +127 -0
  421. testerkit/skills/testerkit-interactive/SKILL.md +188 -0
  422. testerkit/skills/testerkit-interactive/references/live-ui-patterns.md +102 -0
  423. testerkit/skills/testerkit-mocks/SKILL.md +128 -0
  424. testerkit/skills/testerkit-parts/SKILL.md +126 -0
  425. testerkit/skills/testerkit-profiles/SKILL.md +139 -0
  426. testerkit/skills/testerkit-sites/SKILL.md +140 -0
  427. testerkit/skills/testerkit-stations/SKILL.md +146 -0
  428. testerkit/skills/testerkit-tests/SKILL.md +136 -0
  429. testerkit/store.py +1639 -0
  430. testerkit/ui/__init__.py +71 -0
  431. testerkit/ui/_asgi.py +162 -0
  432. testerkit/ui/app.py +32 -0
  433. testerkit/ui/components/__init__.py +13 -0
  434. testerkit/ui/components/artifact_viewer.py +250 -0
  435. testerkit/ui/components/channel_values.py +159 -0
  436. testerkit/ui/components/event_timeline.py +222 -0
  437. testerkit/ui/components/execution_gantt.py +210 -0
  438. testerkit/ui/components/file_streams.py +147 -0
  439. testerkit/ui/components/instrument_activity.py +146 -0
  440. testerkit/ui/components/session_table.py +118 -0
  441. testerkit/ui/pages/__init__.py +25 -0
  442. testerkit/ui/pages/channels/__init__.py +4 -0
  443. testerkit/ui/pages/channels/detail.py +932 -0
  444. testerkit/ui/pages/channels/list.py +515 -0
  445. testerkit/ui/pages/dashboard.py +236 -0
  446. testerkit/ui/pages/designer/__init__.py +5 -0
  447. testerkit/ui/pages/designer/graph.py +635 -0
  448. testerkit/ui/pages/designer/matching.py +663 -0
  449. testerkit/ui/pages/designer/page.py +593 -0
  450. testerkit/ui/pages/designer/properties.py +591 -0
  451. testerkit/ui/pages/designer/state.py +468 -0
  452. testerkit/ui/pages/docs/__init__.py +6 -0
  453. testerkit/ui/pages/docs/index.py +95 -0
  454. testerkit/ui/pages/docs/page.py +698 -0
  455. testerkit/ui/pages/events/__init__.py +3 -0
  456. testerkit/ui/pages/events/list.py +263 -0
  457. testerkit/ui/pages/explore.py +1108 -0
  458. testerkit/ui/pages/files/__init__.py +4 -0
  459. testerkit/ui/pages/files/detail.py +426 -0
  460. testerkit/ui/pages/files/list.py +447 -0
  461. testerkit/ui/pages/fixtures/__init__.py +8 -0
  462. testerkit/ui/pages/fixtures/detail.py +280 -0
  463. testerkit/ui/pages/fixtures/edit.py +370 -0
  464. testerkit/ui/pages/fixtures/list.py +180 -0
  465. testerkit/ui/pages/fixtures/new.py +195 -0
  466. testerkit/ui/pages/instruments/__init__.py +4 -0
  467. testerkit/ui/pages/instruments/detail.py +320 -0
  468. testerkit/ui/pages/instruments/edit.py +482 -0
  469. testerkit/ui/pages/instruments/list.py +249 -0
  470. testerkit/ui/pages/instruments/new.py +200 -0
  471. testerkit/ui/pages/launch.py +261 -0
  472. testerkit/ui/pages/live.py +124 -0
  473. testerkit/ui/pages/metrics_page.py +1229 -0
  474. testerkit/ui/pages/parts/__init__.py +11 -0
  475. testerkit/ui/pages/parts/detail.py +202 -0
  476. testerkit/ui/pages/parts/edit.py +310 -0
  477. testerkit/ui/pages/parts/list.py +160 -0
  478. testerkit/ui/pages/parts/new.py +170 -0
  479. testerkit/ui/pages/parts/requirements.py +153 -0
  480. testerkit/ui/pages/parts/stations.py +199 -0
  481. testerkit/ui/pages/profiles/__init__.py +4 -0
  482. testerkit/ui/pages/profiles/detail.py +113 -0
  483. testerkit/ui/pages/profiles/list.py +86 -0
  484. testerkit/ui/pages/results/__init__.py +4 -0
  485. testerkit/ui/pages/results/detail.py +631 -0
  486. testerkit/ui/pages/results/list.py +230 -0
  487. testerkit/ui/pages/stations/__init__.py +4 -0
  488. testerkit/ui/pages/stations/detail.py +256 -0
  489. testerkit/ui/pages/stations/edit.py +273 -0
  490. testerkit/ui/pages/stations/list.py +180 -0
  491. testerkit/ui/pages/stations/new.py +311 -0
  492. testerkit/ui/pages/tests/__init__.py +4 -0
  493. testerkit/ui/pages/tests/detail.py +152 -0
  494. testerkit/ui/pages/tests/list.py +194 -0
  495. testerkit/ui/pages/uuts/__init__.py +4 -0
  496. testerkit/ui/pages/uuts/list.py +97 -0
  497. testerkit/ui/shared/__init__.py +8 -0
  498. testerkit/ui/shared/components.py +1826 -0
  499. testerkit/ui/shared/dialogs.py +105 -0
  500. testerkit/ui/shared/event_binding.py +194 -0
  501. testerkit/ui/shared/layout.py +314 -0
  502. testerkit/ui/shared/services.py +1719 -0
  503. testerkit/ui/shared/timestamps.py +21 -0
  504. testerkit/ui/static/branding/favicon-16.png +0 -0
  505. testerkit/ui/static/branding/favicon-32.png +0 -0
  506. testerkit/ui/static/branding/favicon-48.png +0 -0
  507. testerkit/ui/static/branding/testerkit-icon-256.png +0 -0
  508. testerkit/ui/static/branding/testerkit-mark.svg +1 -0
  509. testerkit/ui/static/branding/testerkit-wordmark.svg +1 -0
  510. testerkit/ui/static/global.css +465 -0
  511. testerkit/utils/__init__.py +17 -0
  512. testerkit/utils/enum_meta.py +800 -0
  513. testerkit/utils/paths.py +75 -0
  514. testerkit/utils/ranges.py +257 -0
  515. testerkit/validation.py +82 -0
  516. testerkit/verbs.py +142 -0
  517. testerkit-0.4.0.dist-info/METADATA +250 -0
  518. testerkit-0.4.0.dist-info/RECORD +521 -0
  519. testerkit-0.4.0.dist-info/WHEEL +4 -0
  520. testerkit-0.4.0.dist-info/entry_points.txt +5 -0
  521. testerkit-0.4.0.dist-info/licenses/LICENSE +191 -0
@@ -0,0 +1,169 @@
1
+ # Datasheet → tests with Claude Code
2
+
3
+ Walks through the `datasheet-to-test` workflow end-to-end: from a part datasheet PDF to a runnable pytest suite, with operator approval at every step. This flow chains spec extraction, instrument selection, station config, and test scaffolding into one conversation, with an approval gate at each step.
4
+
5
+ For motivation see [why AI integration](../../concepts/overview/ai-integration.md). For the full inventory of what ships, see the [skills reference](../../reference/overview/skills.md).
6
+
7
+ ## Prerequisites
8
+
9
+ - TesterKit installed (`pip install testerkit`)
10
+ - A part datasheet PDF on disk
11
+ - Claude Code installed and authenticated, with access to a high-capability model on your plan (Opus, GPT-5 / o-series, Gemini 2.5 Pro, or equivalent — the workflow does heavy PDF extraction)
12
+ - A working catalog of instruments — either real catalog YAMLs in your project, or you can use TesterKit's bundled generics
13
+
14
+ If you don't have Claude Code, swap to any client that supports MCP — the steps work the same, only the invocation differs (slash command vs conversational). See the [skills reference](../../reference/overview/skills.md#slash-commands) for the matrix.
15
+
16
+ ## One-time setup
17
+
18
+ Register TesterKit's MCP server with Claude Code:
19
+
20
+ ```bash
21
+ testerkit setup claude-code
22
+ ```
23
+
24
+ This does three things ([full reference](../../reference/overview/skills.md#what-the-setup-commands-install)):
25
+
26
+ 1. Registers TesterKit as an MCP server (`claude mcp add testerkit -- <testerkit-bin> mcp serve`)
27
+ 2. Copies `/catalog-from-datasheet` and `/process-catalog` slash command stubs into `./.claude/commands/`
28
+ 3. Writes or merges `./CLAUDE.md` with the TesterKit project instructions
29
+
30
+ Restart Claude Code after `testerkit setup` so it picks up the new server.
31
+
32
+ Confirm MCP registration:
33
+
34
+ ```bash
35
+ claude mcp list
36
+ ```
37
+
38
+ TesterKit should appear in the list. If it doesn't, re-run `testerkit setup claude-code` and check the printed error.
39
+
40
+ ## Invoke the workflow
41
+
42
+ Open Claude Code in your project directory. Start a new conversation with this prompt:
43
+
44
+ ```
45
+ Run the datasheet-to-test workflow on this datasheet:
46
+ ./datasheets/my_part.pdf
47
+ ```
48
+
49
+ Claude fetches the workflow prompt via MCP (`prompts/get datasheet-to-test`) and begins **Phase 1**.
50
+
51
+ ## The phases
52
+
53
+ The workflow STOPS at every gate. You approve, edit, or reject before it moves on.
54
+
55
+ ### Phase 1 — Parse datasheet
56
+
57
+ Claude reads the PDF, extracts:
58
+
59
+ - Pin definitions (names, types, signal directions)
60
+ - Electrical characteristics (voltage ranges, current draws, accuracy specs)
61
+ - Test conditions (temperature, supply voltage points)
62
+
63
+ You see a structured summary. Approval gate: "Here's what I extracted, anything missing or wrong?"
64
+
65
+ Common edits at this gate:
66
+ - Renaming pins to match your team's convention
67
+ - Adding characteristics the datasheet implies but doesn't tabulate (e.g., quiescent current at no-load)
68
+ - Removing characteristics you don't intend to test
69
+
70
+ ### Phase 2 — Save part spec
71
+
72
+ Claude saves the spec to `parts/<id>.yaml`. The spec uses the same [Capability schema](../../reference/catalog/schema.md) as catalog entries. TesterKit validates the YAML against the catalog schema as it saves; you'll see Claude correct shape errors in-flight if it tries to save something invalid.
73
+
74
+ Approval gate: review the saved YAML. Edit directly if you want — the agent re-reads on the next step.
75
+
76
+ ### Phase 2b — Recommend instruments
77
+
78
+ Claude calls `testerkit_match(part_id=<id>)` and proposes instruments that cover the part's specs (see [how capability matching works](../../concepts/overview/ai-integration.md)). Three outcomes:
79
+
80
+ | Outcome | What Claude proposes |
81
+ |---|---|
82
+ | Catalog has matches | Shortlist of matched catalog entries with capability coverage |
83
+ | Catalog is empty / no matches | Asks what equipment you have available |
84
+ | Mixed | Catalog matches for some, asks about gaps |
85
+
86
+ If you have a specific model the catalog doesn't know yet, Claude offers three paths:
87
+
88
+ 1. **Fast, approximate:** ask Claude to scaffold a catalog entry from just the model number using its prior knowledge — good for a quick start, not production-accurate.
89
+ 2. `generic_dmm` / `generic_psu` / `generic_eload` / `generic_oscilloscope` — bundled with TesterKit, approximate capabilities, fine for mocked development.
90
+ 3. **Accurate, for production:** `/catalog-from-datasheet <pdf>` — correct to the datasheet, for catalog entries where spec correctness matters.
91
+
92
+ Pick whichever fits where you are: generics if you're sketching, Claude's prior knowledge for well-known instruments, full datasheet for the production catalog entry.
93
+
94
+ ### Phase 3 — Create station config
95
+
96
+ Claude generates `stations/<id>.yaml` wiring the selected instruments to roles (`psu`, `dmm`, `uut_load`, etc.) with realistic mock values. TesterKit validates the wiring when it saves.
97
+
98
+ Approval gate: review the wiring. Most edits here are around VISA resource strings (the agent has no way to discover your bench's actual `TCPIP::*::INSTR` addresses unless you've already populated them or it can call `testerkit_discover` against a live bench).
99
+
100
+ ### Phase 4 — Generate tests
101
+
102
+ Two files generated:
103
+
104
+ - `tests/test_<part>.py` — pytest-native test code using the TesterKit fixtures (`context`, `verify`, `measure`, plus instrument role fixtures like `psu`, `dmm`)
105
+ - `tests/test_<part>.yaml` — sidecar YAML with `sweeps:`, `limits:`, `mocks:` for operator-editable values
106
+
107
+ The generated tests use:
108
+ - `verify(name, value)` for judgment-bearing measurements — limits resolve from the active part spec / sidecar / profile, raises on out-of-band
109
+ - `measure(name, value)` for record-only setup readouts
110
+ - `context.changed("vin")` in parametrized sweeps to skip expensive reconfig
111
+ - Native `@pytest.mark.parametrize` for code-owned sweeps; sidecar `sweeps:` for operator-edited sweeps
112
+
113
+ Approval gate: review both files. Edit directly — pytest and the YAML are the source of truth, not Claude's memory of what it generated.
114
+
115
+ ### Phase 5 — Execute and analyze
116
+
117
+ Claude calls `testerkit_run(test="tests/test_<id>.py", station="<station_id>", serial="<UUT-SERIAL>", project=<root>)`. The test executes against the configured station (with `mocks:` from the sidecar if `--mock-instruments` is implied, otherwise against the real bench).
118
+
119
+ Claude shows you the results table — rows are measurements, columns are sweep axes, cells colored pass/fail/skip. From here you can ask follow-ups:
120
+
121
+ - "Why did the load=0.8 row fail at vin=4.5?" → Claude pulls the measurement detail via `testerkit_runs` + `testerkit_steps`
122
+ - "Open this run in the browser" → `testerkit_open(type="run", id=<run-id>)` returns a `testerkit serve` URL
123
+ - "Tighten the output_voltage tolerance to ±1%" → Claude edits the sidecar and re-runs
124
+
125
+ ## What's actually saved to your project
126
+
127
+ After the workflow completes, your project tree has:
128
+
129
+ ```
130
+ my_project/
131
+ ├── testerkit.yaml # set by testerkit_project init
132
+ ├── parts/
133
+ │ └── <id>.yaml # phase 2
134
+ ├── stations/
135
+ │ └── <station_id>.yaml # phase 3
136
+ ├── tests/
137
+ │ ├── test_<part>.py # phase 4
138
+ │ └── test_<part>.yaml # phase 4 sidecar
139
+ └── catalog/ # only if Phase 2b added an instrument entry
140
+ └── <instrument>.yaml
141
+ ```
142
+
143
+ Every file is plain YAML or Python. Git diffs work. Code review works. If you want to delete the AI from the loop, `pytest tests/` still runs the test.
144
+
145
+ ## When things go wrong
146
+
147
+ | Symptom | Cause | Fix |
148
+ |---|---|---|
149
+ | Claude can't find the workflow | MCP server not registered or Claude not restarted after `testerkit setup` | `claude mcp list` to verify; restart Claude Code |
150
+ | Agent loops trying to save an invalid YAML | The save was rejected because the YAML didn't match the catalog schema | Let it iterate — validation is the feedback signal; or stop it and edit the YAML by hand |
151
+ | Test runs but every row is `SKIP` / `MISSING_LIMIT` | Phase 4 generated `verify()` calls without limits, and no sidecar / part spec covers them | Either add limits to the sidecar `limits:` block or switch the calls to `measure()` for characterization-only |
152
+ | Instrument match returns nothing | Catalog is empty or capability requirements aren't covered | Use generics for development, or run `/catalog-from-datasheet` for the missing instruments |
153
+ | Agent picks the wrong instrument | The capability match is correct but the agent's preference doesn't match yours | Tell it directly: "I want the Keithley 2400 for the load instead of the eload" — it'll update the station and re-validate |
154
+
155
+ ## Variations
156
+
157
+ Three ways to use this flow short of the full pipeline:
158
+
159
+ 1. **Just part spec.** Stop after Phase 2. You get a part YAML; do station + tests by hand.
160
+ 2. **Part + tests, mock instruments.** Stop after Phase 4, use the bundled `generic_*` instruments through Phase 2b, run `pytest --mock-instruments`. No real hardware needed; useful for test-code review before the bench is ready.
161
+ 3. **Incremental update.** Re-invoke the workflow on a part that already has files. The agent reads the existing YAMLs and proposes diffs rather than from-scratch generation.
162
+
163
+ ## See also
164
+
165
+ - [Concepts: why AI integration](../../concepts/overview/ai-integration.md) — motivation
166
+ - [Reference: skills](../../reference/overview/skills.md) — full inventory of workflows, agents, MCP tools
167
+ - [How-to: MCP integration](../overview/mcp-integration.md) — per-client setup detail
168
+ - [Reference: catalog schema](../../reference/catalog/schema.md) — the shape part spec and catalog entries share
169
+ - [Tutorial step 3: pytest-native tests](../../tutorial/03-fixtures.md) — what the generated test code looks like in context
@@ -0,0 +1,11 @@
1
+ # How-To — Catalog
2
+
3
+ AI-assisted authoring against the capability catalog: produce instrument YAML and part YAML from a datasheet PDF with operator approval at every step.
4
+
5
+ - [Datasheet → tests with Claude Code](datasheet-to-test.md) — end-to-end walkthrough of the `datasheet-to-test` workflow
6
+
7
+ ## See also
8
+
9
+ - [Concepts → AI integration](../../concepts/overview/ai-integration.md) — what the MCP surface gives an AI client and where the boundary sits
10
+ - [Reference → Catalog schema](../../reference/catalog/schema.md) and [Catalog cookbook](../../reference/catalog/cookbook.md) — the YAML shape the workflow produces
11
+ - [Reference → Skills](../../reference/overview/skills.md) — full inventory of workflows, sub-agents, slash commands the platform ships
@@ -0,0 +1,364 @@
1
+ # Configuring Stations
2
+
3
+ This guide covers station configuration for different environments.
4
+
5
+ ## Basic Station Config
6
+
7
+ ```yaml
8
+ # stations/bench_1.yaml
9
+ id: bench_1
10
+ name: "Production Bench 1"
11
+ location: "Lab A"
12
+
13
+ instruments:
14
+ dmm:
15
+ type: dmm
16
+ driver: pymeasure.instruments.keysight.Keysight34461A
17
+ resource: "TCPIP::192.168.1.100::INSTR"
18
+ psu:
19
+ type: psu
20
+ driver: pymeasure.instruments.keysight.KeysightE36312A
21
+ resource: "GPIB0::5::INSTR"
22
+ ```
23
+
24
+ ## Station Fields
25
+
26
+ | Field | Required | Description |
27
+ |-------|----------|-------------|
28
+ | `id` | Defaults to filename stem | Unique identifier — must match the filename stem if declared explicitly |
29
+ | `name` | Yes | Display name |
30
+ | `location` | No | Physical location |
31
+ | `description` | No | Description |
32
+ | `supported_phases` | No | Documents which phases this bench is set up for — shown in the stations UI |
33
+
34
+ ## Instrument Fields
35
+
36
+ Per [`StationInstrumentConfig`](../../reference/data/models.md):
37
+
38
+ | Field | Required | Description |
39
+ |-------|----------|-------------|
40
+ | `type` | Yes | Instrument type (dmm, psu, etc.) |
41
+ | `driver` | At least one of driver/resource (unless `mock: true`) | The driver to load, written `package.module.DriverName` (e.g. `pymeasure.instruments.keysight.Keysight34461A`) |
42
+ | `resource` | At least one of driver/resource (unless `mock: true`) | VISA address or connection string |
43
+ | `catalog_ref` | No | ID of a catalog entry that declares this instrument's capabilities |
44
+ | `channels` | No | Named channel aliases (`dict[str, str]`) |
45
+ | `description` | No | Human-readable description |
46
+ | `mock` | No | Always mock this instrument (even without `--mock-instruments`). Default `false` |
47
+ | `mock_config` | No | Return values when running in mock mode |
48
+
49
+ ## Using a station's instruments in a test
50
+
51
+ Each role under `instruments:` becomes a pytest fixture of the same name. A `dmm:` role gives you a `dmm` fixture; `psu:` gives `psu`. Rename the role, rename the fixture.
52
+
53
+ ```python
54
+ def test_rail_voltage(dmm, psu):
55
+ psu.voltage = 5.0
56
+ reading = dmm.measure_dc_voltage()
57
+ assert 3.2 < reading < 3.4
58
+ ```
59
+
60
+ The fixtures are session-scoped — TesterKit connects each instrument once and shares the driver instance across all tests in the run.
61
+
62
+ ## VISA Addresses
63
+
64
+ ### TCP/IP (LAN)
65
+
66
+ ```yaml
67
+ resource: "TCPIP::192.168.1.100::INSTR"
68
+ resource: "TCPIP::192.168.1.100::5025::SOCKET" # With port
69
+ resource: "TCPIP::dmm.lab.local::INSTR" # DNS name
70
+ ```
71
+
72
+ ### GPIB
73
+
74
+ ```yaml
75
+ resource: "GPIB0::5::INSTR" # Board 0, address 5
76
+ resource: "GPIB1::12::INSTR" # Board 1, address 12
77
+ ```
78
+
79
+ ### USB
80
+
81
+ ```yaml
82
+ resource: "USB0::0x2A8D::0x0101::MY12345::INSTR"
83
+ # Format: USB{board}::{vendor}::{part}::{serial}::INSTR
84
+ ```
85
+
86
+ ### Serial
87
+
88
+ ```yaml
89
+ resource: "ASRL/dev/ttyUSB0::INSTR" # Linux
90
+ resource: "ASRLCOM3::INSTR" # Windows
91
+ ```
92
+
93
+ ## Mock Mode Configuration
94
+
95
+ Configure default values for `--mock-instruments` mode:
96
+
97
+ ```yaml
98
+ instruments:
99
+ dmm:
100
+ type: dmm
101
+ driver: pymeasure.instruments.keysight.Keysight34461A
102
+ resource: "TCPIP::192.168.1.100::INSTR"
103
+ mock_config:
104
+ measure_dc_voltage: 3.31
105
+ measure_current: 0.1
106
+ measure_resistance: 1000
107
+ ```
108
+
109
+ ### Running in Mock Mode
110
+
111
+ ```bash
112
+ pytest tests/ --station=stations/bench_1.yaml --mock-instruments --uut-serial=SIM001
113
+ ```
114
+
115
+ The `--mock-instruments` flag uses mock instruments instead of real hardware. Mock values come from `mock_config` in the station, or can be overridden per-test in the sidecar YAML next to your test file (`tests/test_*.yaml`).
116
+
117
+ ## Station Types
118
+
119
+ A station type is a template — one YAML file per type under `stations/types/<id>.yaml`. It declares the instrument roles (and their `type:` and `driver:`) every station of that type must provide, plus the catalog capability ids the type advertises:
120
+
121
+ ```yaml
122
+ # stations/types/voltage_tester.yaml
123
+ id: voltage_tester
124
+ description: "Basic voltage testing station"
125
+ instruments:
126
+ dmm:
127
+ type: dmm
128
+ driver: pymeasure.instruments.keysight.Keysight34461A
129
+ psu:
130
+ type: psu
131
+ driver: pymeasure.instruments.keysight.KeysightE36312A
132
+ capabilities:
133
+ - keysight.34461a.dc_voltage
134
+ - keysight.e36312a.dc_source
135
+ ```
136
+
137
+ ```yaml
138
+ # stations/types/full_test.yaml
139
+ id: full_test
140
+ description: "Complete test station"
141
+ instruments:
142
+ dmm:
143
+ type: dmm
144
+ driver: pymeasure.instruments.keysight.Keysight34461A
145
+ psu:
146
+ type: psu
147
+ driver: pymeasure.instruments.keysight.KeysightE36312A
148
+ scope:
149
+ type: scope
150
+ driver: drivers.scope.MyScope
151
+ ```
152
+
153
+ There is no `required:` field on an instrument entry — every role listed under `instruments:` is required, and any role not listed is omitted by definition. `capabilities:` is a list of catalog capability ids (strings), not inline capability dicts.
154
+
155
+ Reference in station instances:
156
+
157
+ ```yaml
158
+ # stations/bench_1.yaml
159
+ id: bench_1
160
+ name: "Production Bench 1"
161
+ station_type: voltage_tester
162
+ location: "Lab A"
163
+
164
+ instruments:
165
+ dmm:
166
+ type: dmm
167
+ driver: pymeasure.instruments.keysight.Keysight34461A
168
+ resource: "TCPIP::192.168.1.100::INSTR"
169
+ psu:
170
+ type: psu
171
+ driver: pymeasure.instruments.keysight.KeysightE36312A
172
+ resource: "GPIB0::5::INSTR"
173
+ ```
174
+
175
+ ## Multiple Stations
176
+
177
+ ### Production Lab
178
+
179
+ ```yaml
180
+ # stations/prod_bench_1.yaml
181
+ id: prod_bench_1
182
+ name: "Production Bench 1"
183
+ location: "Production Floor, Bay 1"
184
+
185
+ supported_phases:
186
+ - production
187
+
188
+ instruments:
189
+ dmm:
190
+ type: dmm
191
+ driver: pymeasure.instruments.keysight.Keysight34461A
192
+ resource: "TCPIP::192.168.10.101::INSTR"
193
+ psu:
194
+ type: psu
195
+ driver: pymeasure.instruments.keysight.KeysightE36312A
196
+ resource: "TCPIP::192.168.10.102::INSTR"
197
+ ```
198
+
199
+ ### Development Lab
200
+
201
+ ```yaml
202
+ # stations/dev_bench.yaml
203
+ id: dev_bench
204
+ name: "Development Bench"
205
+ location: "R&D Lab"
206
+
207
+ supported_phases:
208
+ - development
209
+ - debug
210
+
211
+ instruments:
212
+ dmm:
213
+ type: dmm
214
+ driver: pymeasure.instruments.keysight.Keysight34461A
215
+ resource: "USB0::0x2A8D::0x0101::MY12345::INSTR"
216
+ psu:
217
+ type: psu
218
+ driver: pymeasure.instruments.keysight.KeysightE36312A
219
+ resource: "GPIB0::5::INSTR"
220
+ scope:
221
+ type: scope
222
+ driver: drivers.scope.MyScope
223
+ resource: "TCPIP::192.168.1.200::INSTR"
224
+ ```
225
+
226
+ ### CI/CD
227
+
228
+ ```yaml
229
+ # stations/ci_station.yaml
230
+ id: ci_station
231
+ name: "CI Environment"
232
+ description: "For automated testing with --mock-instruments"
233
+
234
+ instruments:
235
+ dmm:
236
+ type: dmm
237
+ mock: true
238
+ catalog_ref: generic_dmm
239
+ mock_config:
240
+ measure_dc_voltage: 3.31
241
+ measure_current: 0.1
242
+ psu:
243
+ type: psu
244
+ mock: true
245
+ catalog_ref: generic_psu
246
+ mock_config:
247
+ measure_voltage: 5.0
248
+ ```
249
+
250
+ Run in CI:
251
+ ```bash
252
+ pytest tests/ --station=stations/ci_station.yaml --mock-instruments --uut-serial=CI-TEST
253
+ ```
254
+
255
+ ## Selecting a fixture at run time
256
+
257
+ Stations don't pin a fixture themselves. The active fixture is selected by `--fixture=...` on the pytest command line (or by a profile that sets it). The plugin validates that the fixture's `part_id` / `part_family` matches the active part spec before any test runs.
258
+
259
+ ```bash
260
+ pytest tests/ \
261
+ --station=bench_1 \
262
+ --fixture=fixtures/power_board_fixture.yaml \
263
+ --uut-serial=SN001
264
+ ```
265
+
266
+ See [Fixtures](../../concepts/configuration/fixtures.md) for the pin-to-instrument mapping model.
267
+
268
+ ## Capability Declarations
269
+
270
+ A station instance (`stations/<id>.yaml`) does not carry a `capabilities:` field — capabilities are derived from each instrument's catalog entry when the station loads. See [Capabilities](../../concepts/configuration/capabilities.md) for how capability matching works.
271
+
272
+ If you want to advertise a fixed capability set as part of a *type* (so concrete stations of that type are guaranteed to provide it), declare it on the **station type**, not on the instance, as a list of catalog capability ids:
273
+
274
+ ```yaml
275
+ # stations/types/voltage_bench.yaml
276
+ id: voltage_bench
277
+ description: "Generic DC + AC voltage bench"
278
+ instruments:
279
+ dmm:
280
+ type: dmm
281
+ driver: pymeasure.instruments.keysight.Keysight34461A
282
+ psu:
283
+ type: psu
284
+ driver: pymeasure.instruments.keysight.KeysightE36312A
285
+ capabilities:
286
+ - keysight.34461a.dc_voltage
287
+ - keysight.34461a.ac_voltage
288
+ - keysight.e36312a.dc_source
289
+ ```
290
+
291
+ To customize the capabilities a specific instrument provides, edit that instrument's catalog YAML (`catalog/<vendor>/<model>.yaml`) — not the station file.
292
+
293
+ ## Validation
294
+
295
+ To validate a station file before a run, point pytest at it — a bad config fails fast:
296
+
297
+ ```bash
298
+ pytest --collect-only --station=stations/bench_1.yaml
299
+ ```
300
+
301
+ A missing required field or a type mismatch raises a `pydantic.ValidationError` before any test is collected.
302
+
303
+ ## Shared Instruments (Multi-UUT)
304
+
305
+ When a multi-UUT fixture runs sites in parallel and more than one site uses the same instrument role, TesterKit connects that instrument once and shares it across sites — no extra config. See [Multi-UUT testing](../execution/multi-uut-testing.md).
306
+
307
+ ## Best Practices
308
+
309
+ 1. **Use descriptive station IDs** — `prod_bench_1` not `station1`
310
+ 2. **Include location** — Helps operators find equipment
311
+ 3. **Document supported phases** — `supported_phases:` records which phases this bench is set up for; it is shown in the stations UI
312
+ 4. **Create a CI station** — Fully mocked for automated tests; keep one `stations/ci_station.yaml` with `mock: true` on every instrument
313
+ 5. **Version control** — Track station YAML changes alongside test code
314
+
315
+ ## Common Configurations
316
+
317
+ ### Single DMM
318
+
319
+ ```yaml
320
+ id: simple_station
321
+ name: "Simple DMM Station"
322
+
323
+ instruments:
324
+ dmm:
325
+ type: dmm
326
+ driver: pymeasure.instruments.keysight.Keysight34461A
327
+ resource: "USB0::0x2A8D::0x0101::MY12345::INSTR"
328
+ ```
329
+
330
+ ### Full Production
331
+
332
+ ```yaml
333
+ id: production_station
334
+ name: "Production Station"
335
+ location: "Production Floor"
336
+
337
+ instruments:
338
+ dmm_1:
339
+ type: dmm
340
+ driver: pymeasure.instruments.keysight.Keysight34461A
341
+ resource: "TCPIP::192.168.1.101::INSTR"
342
+ dmm_2:
343
+ type: dmm
344
+ driver: pymeasure.instruments.keysight.Keysight34461A
345
+ resource: "TCPIP::192.168.1.102::INSTR"
346
+ psu:
347
+ type: psu
348
+ driver: pymeasure.instruments.keysight.KeysightE36312A
349
+ resource: "TCPIP::192.168.1.103::INSTR"
350
+ eload:
351
+ type: eload
352
+ driver: drivers.eload.MyELoad
353
+ resource: "TCPIP::192.168.1.104::INSTR"
354
+ scope:
355
+ type: scope
356
+ driver: drivers.scope.MyScope
357
+ resource: "TCPIP::192.168.1.105::INSTR"
358
+ ```
359
+
360
+ ## Next Steps
361
+
362
+ - [Stations Concept](../../concepts/configuration/stations.md) — Understanding stations
363
+ - [Capabilities](../../concepts/configuration/capabilities.md) — Capability matching
364
+ - [Custom drivers](custom-drivers.md) — Build a non-VISA driver