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.
- testerkit/__init__.py +68 -0
- testerkit/_docs/_assets/operator-ui/channels/table.png +0 -0
- testerkit/_docs/_assets/operator-ui/dashboard/runs.png +0 -0
- testerkit/_docs/_assets/operator-ui/dashboard/stations.png +0 -0
- testerkit/_docs/_assets/operator-ui/events/filters.png +0 -0
- testerkit/_docs/_assets/operator-ui/events/table.png +0 -0
- testerkit/_docs/_assets/operator-ui/explore/chart.png +0 -0
- testerkit/_docs/_assets/operator-ui/explore/filters.png +0 -0
- testerkit/_docs/_assets/operator-ui/explore/plot-controls.png +0 -0
- testerkit/_docs/_assets/operator-ui/files/table.png +0 -0
- testerkit/_docs/_assets/operator-ui/launch/form.png +0 -0
- testerkit/_docs/_assets/operator-ui/metrics/filters.png +0 -0
- testerkit/_docs/_assets/operator-ui/metrics/pareto.png +0 -0
- testerkit/_docs/_assets/operator-ui/metrics/ppk.png +0 -0
- testerkit/_docs/_assets/operator-ui/metrics/yield.png +0 -0
- testerkit/_docs/_assets/operator-ui/results/detail-header.png +0 -0
- testerkit/_docs/_assets/operator-ui/results/detail-measurements.png +0 -0
- testerkit/_docs/_assets/operator-ui/results/detail-overview.png +0 -0
- testerkit/_docs/_assets/operator-ui/results/detail-steps.png +0 -0
- testerkit/_docs/_assets/operator-ui/results/stats.png +0 -0
- testerkit/_docs/_assets/operator-ui/results/table.png +0 -0
- testerkit/_docs/_assets/operator-ui/tour/designer.png +0 -0
- testerkit/_docs/_assets/operator-ui/tour/docs.png +0 -0
- testerkit/_docs/_assets/operator-ui/tour/fixtures.png +0 -0
- testerkit/_docs/_assets/operator-ui/tour/instruments.png +0 -0
- testerkit/_docs/_assets/operator-ui/tour/parts.png +0 -0
- testerkit/_docs/_assets/operator-ui/tour/profiles.png +0 -0
- testerkit/_docs/_assets/operator-ui/tour/stations.png +0 -0
- testerkit/_docs/_assets/operator-ui/tour/tests.png +0 -0
- testerkit/_docs/_assets/operator-ui/tour/uuts.png +0 -0
- testerkit/_docs/concepts/configuration/capabilities.md +447 -0
- testerkit/_docs/concepts/configuration/fixtures.md +335 -0
- testerkit/_docs/concepts/configuration/index.md +14 -0
- testerkit/_docs/concepts/configuration/parts.md +276 -0
- testerkit/_docs/concepts/configuration/stations.md +214 -0
- testerkit/_docs/concepts/data/data-stores.md +199 -0
- testerkit/_docs/concepts/data/event-log.md +185 -0
- testerkit/_docs/concepts/data/event-sourcing.md +76 -0
- testerkit/_docs/concepts/data/flight-streaming.md +58 -0
- testerkit/_docs/concepts/data/index.md +17 -0
- testerkit/_docs/concepts/data/sessions.md +78 -0
- testerkit/_docs/concepts/data/three-verbs.md +260 -0
- testerkit/_docs/concepts/execution/index.md +13 -0
- testerkit/_docs/concepts/execution/outcomes.md +199 -0
- testerkit/_docs/concepts/execution/step-hierarchy.md +170 -0
- testerkit/_docs/concepts/execution/step-manifest.md +115 -0
- testerkit/_docs/concepts/index.md +40 -0
- testerkit/_docs/concepts/overview/ai-integration.md +57 -0
- testerkit/_docs/concepts/overview/architecture.md +357 -0
- testerkit/_docs/concepts/overview/index.md +14 -0
- testerkit/_docs/concepts/overview/platform-vs-framework.md +147 -0
- testerkit/_docs/concepts/overview/pytest.md +53 -0
- testerkit/_docs/concepts/overview/tiers.md +46 -0
- testerkit/_docs/how-to/catalog/datasheet-to-test.md +169 -0
- testerkit/_docs/how-to/catalog/index.md +11 -0
- testerkit/_docs/how-to/configuration/configuring-stations.md +364 -0
- testerkit/_docs/how-to/configuration/custom-drivers.md +484 -0
- testerkit/_docs/how-to/configuration/index.md +13 -0
- testerkit/_docs/how-to/configuration/mock-mode.md +342 -0
- testerkit/_docs/how-to/data/benchmarking.md +120 -0
- testerkit/_docs/how-to/data/capture-an-artifact.md +84 -0
- testerkit/_docs/how-to/data/capture-waveform.md +110 -0
- testerkit/_docs/how-to/data/choosing-a-channel-verb.md +108 -0
- testerkit/_docs/how-to/data/compare-runs.md +120 -0
- testerkit/_docs/how-to/data/export-results.md +104 -0
- testerkit/_docs/how-to/data/find-flaky-tests.md +108 -0
- testerkit/_docs/how-to/data/grafana-dashboards.md +148 -0
- testerkit/_docs/how-to/data/index.md +23 -0
- testerkit/_docs/how-to/data/mcp-debug-failures.md +125 -0
- testerkit/_docs/how-to/data/mcp-query-runs.md +120 -0
- testerkit/_docs/how-to/data/querying-channels.md +117 -0
- testerkit/_docs/how-to/data/querying-events.md +85 -0
- testerkit/_docs/how-to/data/stream-live-channel.md +134 -0
- testerkit/_docs/how-to/execution/custom-operator-ui.md +136 -0
- testerkit/_docs/how-to/execution/index.md +21 -0
- testerkit/_docs/how-to/execution/limits.md +193 -0
- testerkit/_docs/how-to/execution/managing-sessions.md +100 -0
- testerkit/_docs/how-to/execution/multi-uut-testing.md +211 -0
- testerkit/_docs/how-to/execution/operator-prompts.md +151 -0
- testerkit/_docs/how-to/execution/profiles.md +304 -0
- testerkit/_docs/how-to/execution/spec-driven-testing.md +169 -0
- testerkit/_docs/how-to/execution/test-context.md +212 -0
- testerkit/_docs/how-to/execution/traceability.md +252 -0
- testerkit/_docs/how-to/execution/vector-expansion.md +394 -0
- testerkit/_docs/how-to/execution/writing-tests.md +363 -0
- testerkit/_docs/how-to/index.md +59 -0
- testerkit/_docs/how-to/overview/index.md +11 -0
- testerkit/_docs/how-to/overview/mcp-integration.md +168 -0
- testerkit/_docs/how-to/overview/operator-ui-tour.md +234 -0
- testerkit/_docs/integration/data/grafana.md +162 -0
- testerkit/_docs/integration/data/index.md +15 -0
- testerkit/_docs/integration/data/lakehouse-import.md +226 -0
- testerkit/_docs/integration/data/logging.md +131 -0
- testerkit/_docs/integration/data/results-api.md +51 -0
- testerkit/_docs/integration/index.md +20 -0
- testerkit/_docs/integration/runtime/harness.md +281 -0
- testerkit/_docs/integration/runtime/index.md +13 -0
- testerkit/_docs/integration/runtime/instruments.md +284 -0
- testerkit/_docs/integration/runtime/pytest-existing.md +315 -0
- testerkit/_docs/reference/catalog/cookbook.md +389 -0
- testerkit/_docs/reference/catalog/index.md +11 -0
- testerkit/_docs/reference/catalog/schema.md +375 -0
- testerkit/_docs/reference/cli.md +660 -0
- testerkit/_docs/reference/configuration.md +406 -0
- testerkit/_docs/reference/data/channels-schema.md +145 -0
- testerkit/_docs/reference/data/event-types.md +554 -0
- testerkit/_docs/reference/data/events-schema.md +120 -0
- testerkit/_docs/reference/data/files-schema.md +141 -0
- testerkit/_docs/reference/data/index.md +18 -0
- testerkit/_docs/reference/data/models.md +2229 -0
- testerkit/_docs/reference/data/outputs.md +82 -0
- testerkit/_docs/reference/data/parquet-schema.md +529 -0
- testerkit/_docs/reference/data/performance-limits.md +224 -0
- testerkit/_docs/reference/data/query-api.md +247 -0
- testerkit/_docs/reference/index.md +69 -0
- testerkit/_docs/reference/operator-ui/channels/detail.md +82 -0
- testerkit/_docs/reference/operator-ui/channels/list.md +70 -0
- testerkit/_docs/reference/operator-ui/dashboard.md +87 -0
- testerkit/_docs/reference/operator-ui/designer.md +167 -0
- testerkit/_docs/reference/operator-ui/events.md +89 -0
- testerkit/_docs/reference/operator-ui/files.md +74 -0
- testerkit/_docs/reference/operator-ui/fixtures.md +100 -0
- testerkit/_docs/reference/operator-ui/instruments.md +126 -0
- testerkit/_docs/reference/operator-ui/launch.md +79 -0
- testerkit/_docs/reference/operator-ui/live.md +102 -0
- testerkit/_docs/reference/operator-ui/measurements.md +159 -0
- testerkit/_docs/reference/operator-ui/metrics.md +217 -0
- testerkit/_docs/reference/operator-ui/parts.md +98 -0
- testerkit/_docs/reference/operator-ui/profiles.md +103 -0
- testerkit/_docs/reference/operator-ui/results/detail.md +214 -0
- testerkit/_docs/reference/operator-ui/results/list.md +106 -0
- testerkit/_docs/reference/operator-ui/stations.md +98 -0
- testerkit/_docs/reference/operator-ui/tests.md +173 -0
- testerkit/_docs/reference/operator-ui/uuts.md +67 -0
- testerkit/_docs/reference/overview/index.md +11 -0
- testerkit/_docs/reference/overview/pytest-native.md +142 -0
- testerkit/_docs/reference/overview/skills.md +177 -0
- testerkit/_docs/reference/pytest/fixtures.md +342 -0
- testerkit/_docs/reference/pytest/index.md +12 -0
- testerkit/_docs/reference/pytest/markers.md +257 -0
- testerkit/_docs/reference/runtime/api.md +246 -0
- testerkit/_docs/reference/runtime/client.md +280 -0
- testerkit/_docs/reference/runtime/connect.md +140 -0
- testerkit/_docs/reference/runtime/index.md +13 -0
- testerkit/_docs/tutorial/01-first-test.md +113 -0
- testerkit/_docs/tutorial/02-mock-instruments.md +88 -0
- testerkit/_docs/tutorial/03-fixtures.md +169 -0
- testerkit/_docs/tutorial/04-limits.md +139 -0
- testerkit/_docs/tutorial/05-configuration.md +194 -0
- testerkit/_docs/tutorial/06-specifications.md +273 -0
- testerkit/_docs/tutorial/07-real-instruments.md +245 -0
- testerkit/_docs/tutorial/08-capabilities.md +223 -0
- testerkit/_docs/tutorial/09-production.md +374 -0
- testerkit/_docs/tutorial/10-live-monitoring.md +156 -0
- testerkit/_docs/tutorial/11-waveforms-and-evidence.md +169 -0
- testerkit/_docs/tutorial/12-continuous-monitoring.md +145 -0
- testerkit/_docs/tutorial/13-parallel-testing.md +233 -0
- testerkit/_docs/tutorial/index.md +61 -0
- testerkit/_docs/tutorial/quickstart.md +282 -0
- testerkit/analysis/__init__.py +9 -0
- testerkit/analysis/_common.py +24 -0
- testerkit/analysis/measurement_facets.py +524 -0
- testerkit/analysis/measurements_query.py +1458 -0
- testerkit/analysis/metrics.py +389 -0
- testerkit/analysis/runs_query.py +434 -0
- testerkit/analysis/steps_query.py +413 -0
- testerkit/api/__init__.py +6 -0
- testerkit/api/_mime.py +71 -0
- testerkit/api/app.py +1171 -0
- testerkit/api/dialogs/__init__.py +36 -0
- testerkit/api/dialogs/manager.py +617 -0
- testerkit/api/dialogs/models.py +79 -0
- testerkit/api/models.py +80 -0
- testerkit/api/responses.py +205 -0
- testerkit/api/runner.py +222 -0
- testerkit/api/schemas.py +311 -0
- testerkit/benchmark/__init__.py +34 -0
- testerkit/benchmark/concurrency.py +248 -0
- testerkit/benchmark/core.py +232 -0
- testerkit/benchmark/runner.py +628 -0
- testerkit/benchmark/scenario.py +313 -0
- testerkit/benchmark/system.py +191 -0
- testerkit/benchmark/workloads.py +507 -0
- testerkit/catalog/__init__.py +6 -0
- testerkit/catalog/generic/generic_dmm.yaml +61 -0
- testerkit/catalog/generic/generic_eload.yaml +31 -0
- testerkit/catalog/generic/generic_fgen.yaml +56 -0
- testerkit/catalog/generic/generic_oscilloscope.yaml +45 -0
- testerkit/catalog/generic/generic_psu.yaml +77 -0
- testerkit/catalog/generic/generic_smu.yaml +73 -0
- testerkit/channels.py +538 -0
- testerkit/cli/__init__.py +32 -0
- testerkit/cli/_common.py +113 -0
- testerkit/cli/_time.py +179 -0
- testerkit/cli/benchmark_cmd.py +56 -0
- testerkit/cli/catalog_cmd.py +39 -0
- testerkit/cli/daemon.py +157 -0
- testerkit/cli/data_cmd.py +1040 -0
- testerkit/cli/discover_cmd.py +94 -0
- testerkit/cli/docs_cmd.py +100 -0
- testerkit/cli/instrument.py +172 -0
- testerkit/cli/mcp_cmd.py +37 -0
- testerkit/cli/metrics.py +366 -0
- testerkit/cli/project.py +312 -0
- testerkit/cli/root.py +14 -0
- testerkit/cli/runs.py +412 -0
- testerkit/cli/schema_cmd.py +87 -0
- testerkit/cli/serve_cmd.py +50 -0
- testerkit/cli/setup_cmd.py +604 -0
- testerkit/cli/station.py +294 -0
- testerkit/cli/validate.py +112 -0
- testerkit/client.py +463 -0
- testerkit/connect.py +635 -0
- testerkit/data/__init__.py +8 -0
- testerkit/data/_accumulator_pool.py +455 -0
- testerkit/data/_atomic.py +59 -0
- testerkit/data/_collection_indices.py +67 -0
- testerkit/data/_daemon_lifecycle.py +535 -0
- testerkit/data/_duckdb_daemon.py +695 -0
- testerkit/data/_duckdb_flight_server.py +813 -0
- testerkit/data/_event_filters.py +15 -0
- testerkit/data/_event_reader.py +101 -0
- testerkit/data/_flight_errors.py +199 -0
- testerkit/data/_flight_query.py +202 -0
- testerkit/data/_flight_retry.py +148 -0
- testerkit/data/_flight_subscribe.py +67 -0
- testerkit/data/_index_epoch.py +342 -0
- testerkit/data/_ipc_writer.py +185 -0
- testerkit/data/_json_safe.py +63 -0
- testerkit/data/_process.py +18 -0
- testerkit/data/_push_relay.py +124 -0
- testerkit/data/_runs_duckdb_daemon.py +2704 -0
- testerkit/data/_session_reaper.py +110 -0
- testerkit/data/_sql_helpers.py +30 -0
- testerkit/data/_store.py +24 -0
- testerkit/data/backends/__init__.py +7 -0
- testerkit/data/backends/_event_accumulator.py +957 -0
- testerkit/data/backends/_row_helpers.py +1172 -0
- testerkit/data/backends/parquet.py +1143 -0
- testerkit/data/backends/protocol.py +35 -0
- testerkit/data/channels/__init__.py +8 -0
- testerkit/data/channels/_flight_daemon.py +75 -0
- testerkit/data/channels/client.py +242 -0
- testerkit/data/channels/flight_manager.py +88 -0
- testerkit/data/channels/index.py +664 -0
- testerkit/data/channels/models.py +418 -0
- testerkit/data/channels/server.py +162 -0
- testerkit/data/channels/store.py +1481 -0
- testerkit/data/data_dir.py +61 -0
- testerkit/data/duckdb_manager.py +79 -0
- testerkit/data/event_log.py +384 -0
- testerkit/data/event_store.py +768 -0
- testerkit/data/events.py +1025 -0
- testerkit/data/exporters/__init__.py +6 -0
- testerkit/data/exporters/_helpers.py +40 -0
- testerkit/data/exporters/csv_exporter.py +168 -0
- testerkit/data/exporters/hdf5.py +234 -0
- testerkit/data/exporters/json_exporter.py +229 -0
- testerkit/data/exporters/mdf4.py +201 -0
- testerkit/data/exporters/stdf.py +255 -0
- testerkit/data/exporters/tdms.py +292 -0
- testerkit/data/files/__init__.py +71 -0
- testerkit/data/files/_backend.py +207 -0
- testerkit/data/files/_catalog_daemon.py +84 -0
- testerkit/data/files/catalog.py +218 -0
- testerkit/data/files/catalog_manager.py +325 -0
- testerkit/data/files/models.py +60 -0
- testerkit/data/files/serializers.py +414 -0
- testerkit/data/files/store.py +463 -0
- testerkit/data/files/streaming.py +783 -0
- testerkit/data/models.py +604 -0
- testerkit/data/ref.py +152 -0
- testerkit/data/retention.py +297 -0
- testerkit/data/run_store.py +367 -0
- testerkit/data/runs_duckdb_manager.py +103 -0
- testerkit/data/schema_dispatch.py +191 -0
- testerkit/data/schema_migrate.py +76 -0
- testerkit/data/schema_versions.py +85 -0
- testerkit/data/schemas.py +288 -0
- testerkit/data/subscribers/__init__.py +48 -0
- testerkit/data/subscribers/_base.py +20 -0
- testerkit/data/subscribers/_output_file.py +25 -0
- testerkit/data/subscribers/replay.py +55 -0
- testerkit/environment.py +84 -0
- testerkit/execution/__init__.py +11 -0
- testerkit/execution/_git.py +190 -0
- testerkit/execution/_state.py +740 -0
- testerkit/execution/accessors.py +54 -0
- testerkit/execution/audit.py +51 -0
- testerkit/execution/cascade.py +85 -0
- testerkit/execution/connections.py +491 -0
- testerkit/execution/harness.py +1931 -0
- testerkit/execution/instrument_events.py +42 -0
- testerkit/execution/limits.py +154 -0
- testerkit/execution/metadata.py +102 -0
- testerkit/execution/mocks.py +63 -0
- testerkit/execution/profiles.py +616 -0
- testerkit/execution/run_scope.py +1331 -0
- testerkit/execution/session_scope.py +196 -0
- testerkit/execution/sidecar.py +280 -0
- testerkit/execution/site_runner.py +705 -0
- testerkit/execution/sites.py +183 -0
- testerkit/execution/sync.py +294 -0
- testerkit/execution/uut_provider.py +231 -0
- testerkit/execution/vectors.py +205 -0
- testerkit/execution/verify.py +396 -0
- testerkit/expand.py +75 -0
- testerkit/files.py +235 -0
- testerkit/fixtures/__init__.py +6 -0
- testerkit/fixtures/manager.py +357 -0
- testerkit/grafana/__init__.py +1 -0
- testerkit/grafana/bootstrap.py +61 -0
- testerkit/grafana/cli.py +314 -0
- testerkit/grafana/dashboards/asset_utilization.json +92 -0
- testerkit/grafana/dashboards/channel_explorer.json +77 -0
- testerkit/grafana/dashboards/event_log.json +92 -0
- testerkit/grafana/dashboards/failure_pareto.json +104 -0
- testerkit/grafana/dashboards/measurement_distribution.json +97 -0
- testerkit/grafana/dashboards/measurement_trend.json +161 -0
- testerkit/grafana/dashboards/station_comparison.json +95 -0
- testerkit/grafana/dashboards/test_duration.json +104 -0
- testerkit/grafana/dashboards/unit_traceability.json +73 -0
- testerkit/grafana/dashboards/yield_overview.json +189 -0
- testerkit/grafana/provisioning/dashboards.yaml.j2 +12 -0
- testerkit/grafana/provisioning/datasources.yaml.j2 +17 -0
- testerkit/grafana/server.py +282 -0
- testerkit/init.py +724 -0
- testerkit/instruments/__init__.py +10 -0
- testerkit/instruments/base.py +82 -0
- testerkit/instruments/discovery/__init__.py +62 -0
- testerkit/instruments/discovery/_base.py +174 -0
- testerkit/instruments/discovery/lxi.py +152 -0
- testerkit/instruments/discovery/ni.py +95 -0
- testerkit/instruments/discovery/serial.py +73 -0
- testerkit/instruments/discovery/visa.py +98 -0
- testerkit/instruments/lifecycle.py +213 -0
- testerkit/instruments/loader.py +79 -0
- testerkit/instruments/locks.py +178 -0
- testerkit/instruments/mocks.py +230 -0
- testerkit/instruments/observer.py +270 -0
- testerkit/instruments/observers/__init__.py +36 -0
- testerkit/instruments/observers/_base.py +68 -0
- testerkit/instruments/observers/daqmx.py +70 -0
- testerkit/instruments/observers/descriptor.py +69 -0
- testerkit/instruments/observers/generic.py +92 -0
- testerkit/instruments/observers/lantz.py +31 -0
- testerkit/instruments/observers/modbus.py +96 -0
- testerkit/instruments/observers/motion.py +68 -0
- testerkit/instruments/observers/ni_modular.py +73 -0
- testerkit/instruments/observers/ophyd.py +80 -0
- testerkit/instruments/observers/pymeasure.py +120 -0
- testerkit/instruments/observers/qcodes.py +66 -0
- testerkit/instruments/observers/scpi.py +88 -0
- testerkit/instruments/observers/tektronix.py +57 -0
- testerkit/instruments/observers/visa.py +103 -0
- testerkit/instruments/pool.py +459 -0
- testerkit/instruments/proxy.py +59 -0
- testerkit/instruments/route_manager.py +329 -0
- testerkit/instruments/routed_proxy.py +88 -0
- testerkit/instruments/server.py +508 -0
- testerkit/instruments/switch.py +43 -0
- testerkit/instruments/visa.py +294 -0
- testerkit/matching/__init__.py +6 -0
- testerkit/matching/service.py +969 -0
- testerkit/mcp/__init__.py +6 -0
- testerkit/mcp/server.py +681 -0
- testerkit/mcp/tools.py +1868 -0
- testerkit/models/__init__.py +18 -0
- testerkit/models/capability.py +598 -0
- testerkit/models/catalog.py +76 -0
- testerkit/models/data_options.py +153 -0
- testerkit/models/enums.py +334 -0
- testerkit/models/instrument.py +152 -0
- testerkit/models/instrument_asset.py +25 -0
- testerkit/models/part.py +271 -0
- testerkit/models/part_manifest.py +96 -0
- testerkit/models/project.py +114 -0
- testerkit/models/station.py +140 -0
- testerkit/models/test_config.py +748 -0
- testerkit/ontology/__init__.py +39 -0
- testerkit/ontology/schema.py +188 -0
- testerkit/ontology/testerkit.yaml +1420 -0
- testerkit/parts/__init__.py +8 -0
- testerkit/parts/context.py +181 -0
- testerkit/parts/folder.py +251 -0
- testerkit/parts/loader.py +27 -0
- testerkit/prompts/__init__.py +17 -0
- testerkit/prompts/core.py +133 -0
- testerkit/pytest_plugin/__init__.py +1287 -0
- testerkit/pytest_plugin/autouse.py +369 -0
- testerkit/pytest_plugin/helpers.py +354 -0
- testerkit/pytest_plugin/hooks.py +1982 -0
- testerkit/pytest_plugin/markers.py +203 -0
- testerkit/pytest_plugin/retry.py +37 -0
- testerkit/pytest_plugin/sweeps.py +117 -0
- testerkit/queries.py +78 -0
- testerkit/reports/__init__.py +6 -0
- testerkit/reports/core.py +492 -0
- testerkit/reports/datasheet.py +831 -0
- testerkit/reports/templates/datasheet.html +383 -0
- testerkit/reports/templates/default.html +153 -0
- testerkit/sbom.py +142 -0
- testerkit/schema_export.py +101 -0
- testerkit/signals.py +63 -0
- testerkit/skills/README.md +58 -0
- testerkit/skills/templates/project-instructions.md +125 -0
- testerkit/skills/testerkit-analysis/SKILL.md +87 -0
- testerkit/skills/testerkit-capture/SKILL.md +114 -0
- testerkit/skills/testerkit-data/SKILL.md +138 -0
- testerkit/skills/testerkit-datasheets/SKILL.md +100 -0
- testerkit/skills/testerkit-datasheets/agents/scaffold-writer.md +115 -0
- testerkit/skills/testerkit-datasheets/agents/section-extractor.md +98 -0
- testerkit/skills/testerkit-datasheets/agents/section-reviewer.md +153 -0
- testerkit/skills/testerkit-datasheets/agents/section-splitter.md +89 -0
- testerkit/skills/testerkit-datasheets/agents/section-writer.md +226 -0
- testerkit/skills/testerkit-datasheets/references/catalog-pipeline.md +271 -0
- testerkit/skills/testerkit-datasheets/references/process-queue.md +42 -0
- testerkit/skills/testerkit-datasheets/references/scaffold.md +156 -0
- testerkit/skills/testerkit-datasheets/references/test-pipeline.md +312 -0
- testerkit/skills/testerkit-debug/SKILL.md +127 -0
- testerkit/skills/testerkit-interactive/SKILL.md +188 -0
- testerkit/skills/testerkit-interactive/references/live-ui-patterns.md +102 -0
- testerkit/skills/testerkit-mocks/SKILL.md +128 -0
- testerkit/skills/testerkit-parts/SKILL.md +126 -0
- testerkit/skills/testerkit-profiles/SKILL.md +139 -0
- testerkit/skills/testerkit-sites/SKILL.md +140 -0
- testerkit/skills/testerkit-stations/SKILL.md +146 -0
- testerkit/skills/testerkit-tests/SKILL.md +136 -0
- testerkit/store.py +1639 -0
- testerkit/ui/__init__.py +71 -0
- testerkit/ui/_asgi.py +162 -0
- testerkit/ui/app.py +32 -0
- testerkit/ui/components/__init__.py +13 -0
- testerkit/ui/components/artifact_viewer.py +250 -0
- testerkit/ui/components/channel_values.py +159 -0
- testerkit/ui/components/event_timeline.py +222 -0
- testerkit/ui/components/execution_gantt.py +210 -0
- testerkit/ui/components/file_streams.py +147 -0
- testerkit/ui/components/instrument_activity.py +146 -0
- testerkit/ui/components/session_table.py +118 -0
- testerkit/ui/pages/__init__.py +25 -0
- testerkit/ui/pages/channels/__init__.py +4 -0
- testerkit/ui/pages/channels/detail.py +932 -0
- testerkit/ui/pages/channels/list.py +515 -0
- testerkit/ui/pages/dashboard.py +236 -0
- testerkit/ui/pages/designer/__init__.py +5 -0
- testerkit/ui/pages/designer/graph.py +635 -0
- testerkit/ui/pages/designer/matching.py +663 -0
- testerkit/ui/pages/designer/page.py +593 -0
- testerkit/ui/pages/designer/properties.py +591 -0
- testerkit/ui/pages/designer/state.py +468 -0
- testerkit/ui/pages/docs/__init__.py +6 -0
- testerkit/ui/pages/docs/index.py +95 -0
- testerkit/ui/pages/docs/page.py +698 -0
- testerkit/ui/pages/events/__init__.py +3 -0
- testerkit/ui/pages/events/list.py +263 -0
- testerkit/ui/pages/explore.py +1108 -0
- testerkit/ui/pages/files/__init__.py +4 -0
- testerkit/ui/pages/files/detail.py +426 -0
- testerkit/ui/pages/files/list.py +447 -0
- testerkit/ui/pages/fixtures/__init__.py +8 -0
- testerkit/ui/pages/fixtures/detail.py +280 -0
- testerkit/ui/pages/fixtures/edit.py +370 -0
- testerkit/ui/pages/fixtures/list.py +180 -0
- testerkit/ui/pages/fixtures/new.py +195 -0
- testerkit/ui/pages/instruments/__init__.py +4 -0
- testerkit/ui/pages/instruments/detail.py +320 -0
- testerkit/ui/pages/instruments/edit.py +482 -0
- testerkit/ui/pages/instruments/list.py +249 -0
- testerkit/ui/pages/instruments/new.py +200 -0
- testerkit/ui/pages/launch.py +261 -0
- testerkit/ui/pages/live.py +124 -0
- testerkit/ui/pages/metrics_page.py +1229 -0
- testerkit/ui/pages/parts/__init__.py +11 -0
- testerkit/ui/pages/parts/detail.py +202 -0
- testerkit/ui/pages/parts/edit.py +310 -0
- testerkit/ui/pages/parts/list.py +160 -0
- testerkit/ui/pages/parts/new.py +170 -0
- testerkit/ui/pages/parts/requirements.py +153 -0
- testerkit/ui/pages/parts/stations.py +199 -0
- testerkit/ui/pages/profiles/__init__.py +4 -0
- testerkit/ui/pages/profiles/detail.py +113 -0
- testerkit/ui/pages/profiles/list.py +86 -0
- testerkit/ui/pages/results/__init__.py +4 -0
- testerkit/ui/pages/results/detail.py +631 -0
- testerkit/ui/pages/results/list.py +230 -0
- testerkit/ui/pages/stations/__init__.py +4 -0
- testerkit/ui/pages/stations/detail.py +256 -0
- testerkit/ui/pages/stations/edit.py +273 -0
- testerkit/ui/pages/stations/list.py +180 -0
- testerkit/ui/pages/stations/new.py +311 -0
- testerkit/ui/pages/tests/__init__.py +4 -0
- testerkit/ui/pages/tests/detail.py +152 -0
- testerkit/ui/pages/tests/list.py +194 -0
- testerkit/ui/pages/uuts/__init__.py +4 -0
- testerkit/ui/pages/uuts/list.py +97 -0
- testerkit/ui/shared/__init__.py +8 -0
- testerkit/ui/shared/components.py +1826 -0
- testerkit/ui/shared/dialogs.py +105 -0
- testerkit/ui/shared/event_binding.py +194 -0
- testerkit/ui/shared/layout.py +314 -0
- testerkit/ui/shared/services.py +1719 -0
- testerkit/ui/shared/timestamps.py +21 -0
- testerkit/ui/static/branding/favicon-16.png +0 -0
- testerkit/ui/static/branding/favicon-32.png +0 -0
- testerkit/ui/static/branding/favicon-48.png +0 -0
- testerkit/ui/static/branding/testerkit-icon-256.png +0 -0
- testerkit/ui/static/branding/testerkit-mark.svg +1 -0
- testerkit/ui/static/branding/testerkit-wordmark.svg +1 -0
- testerkit/ui/static/global.css +465 -0
- testerkit/utils/__init__.py +17 -0
- testerkit/utils/enum_meta.py +800 -0
- testerkit/utils/paths.py +75 -0
- testerkit/utils/ranges.py +257 -0
- testerkit/validation.py +82 -0
- testerkit/verbs.py +142 -0
- testerkit-0.4.0.dist-info/METADATA +250 -0
- testerkit-0.4.0.dist-info/RECORD +521 -0
- testerkit-0.4.0.dist-info/WHEEL +4 -0
- testerkit-0.4.0.dist-info/entry_points.txt +5 -0
- testerkit-0.4.0.dist-info/licenses/LICENSE +191 -0
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# TesterKit fixtures
|
|
2
|
+
|
|
3
|
+
The bundled pytest plugin registers a set of public fixtures. Take any of them in a test's signature; pytest resolves and injects them by name. Names beginning with `_` are internal and may change without notice.
|
|
4
|
+
|
|
5
|
+
This page is the comprehensive reference. For a guided introduction see the [tutorial](../../tutorial/); for the seven `@pytest.mark.testerkit_*` markers see [TesterKit markers](markers.md).
|
|
6
|
+
|
|
7
|
+
## At a glance
|
|
8
|
+
|
|
9
|
+
Grouped by what you reach for the fixture **for**:
|
|
10
|
+
|
|
11
|
+
| Group | What you'd reach for it for | Fixtures |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| Recording measurements | Write a measurement row, resolve a limit, raise on FAIL, prompt the operator | `verify`, `measure`, `limits`, `prompt` |
|
|
14
|
+
| Recording outputs & streams | Record a read-back value, or append samples to a channel | `observe`, `stream` |
|
|
15
|
+
| Talking to instruments | Get a driver instance, route a signal, hit a UUT pin | `instruments`, `instrument`, `instrument_records`, `uut`, `pins`, `routes`, `fixture_manager` |
|
|
16
|
+
| Reading per-test state | Active sweep params, observations, the connection currently being iterated | `context`, `connections` |
|
|
17
|
+
| Reading loaded configuration | The typed YAML / CLI that shaped this run | `part`, `station_config`, `fixture_config`, `run_context`, `mock_instruments` |
|
|
18
|
+
| Flow control | Drive the test body's iteration / synchronization | `vectors`, `sync` |
|
|
19
|
+
|
|
20
|
+
Plus **one role-named fixture per instrument the station YAML declares** (e.g. `dmm`, `psu`, `scope`). See [Per-role auto-fixtures](#per-role-auto-fixtures).
|
|
21
|
+
|
|
22
|
+
Every fixture above is available in every test — pytest will resolve any of them by name. The "what you'd reach for it for" column is intent, not availability. Several have meaningful "no project state" defaults (`part` returns `None`, `instruments` returns `{}`, `connections` returns `None`, etc.) so taking one in a vanilla project is safe.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Recording measurements
|
|
27
|
+
|
|
28
|
+
The verbs you write into test bodies. Most tests need `verify` and nothing else from this group.
|
|
29
|
+
|
|
30
|
+
### `verify` — function
|
|
31
|
+
|
|
32
|
+
Callable: `verify(name, value, limit=None, characteristic=None)`. Records the measurement row (value, units, limits, traceability), resolves a limit from the active chain (sidecar / inline marker / part spec), stamps `measurement_outcome`, and **raises `AssertionError`** when the value is out of range.
|
|
33
|
+
|
|
34
|
+
`limit=` accepts either a `Limit` model or a dict literal — `verify` coerces dicts via `Limit.model_validate(...)`.
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
def test_rail(dmm, verify):
|
|
38
|
+
verify("output_voltage", dmm.measure_dc_voltage()) # limit resolves from sidecar/marker
|
|
39
|
+
|
|
40
|
+
def test_rail_inline(dmm, verify):
|
|
41
|
+
verify("vout", dmm.measure_dc_voltage(),
|
|
42
|
+
limit={"low": 3.2, "high": 3.4, "unit": "V"}) # inline dict literal
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Same record-side effect as `measure`; the only difference is `verify` raises on FAIL. Use `verify` when a fail should stop the line. With no resolvable limit, `verify` raises `MissingLimitError` — unless the active profile sets `verify_requires_limit: false`, in which case it falls back to `measure` semantics (record-only, `Outcome.DONE`).
|
|
46
|
+
|
|
47
|
+
### `measure` — function
|
|
48
|
+
|
|
49
|
+
Callable: `measure(name, value, limit=None, characteristic=None)`. The record-only sibling of `verify` — records a measurement row with `outcome = DONE` and **never raises**, even when no limit resolves. Use it when a value should be captured but not pass/fail judged (characterization, diagnostics, sweeps you plot post-hoc).
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
def test_voltage(dmm, measure):
|
|
53
|
+
v = dmm.measure_dc_voltage()
|
|
54
|
+
measure("output_voltage", v, limit={"low": 3.2, "high": 3.4, "unit": "V"})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`limit=` accepts either a `Limit` model or a dict literal. Same recording path as `verify`, just no FAIL-side effect — use it when a failing measurement shouldn't abort the test.
|
|
58
|
+
|
|
59
|
+
### `limits` — function
|
|
60
|
+
|
|
61
|
+
Read-only `name → Limit` mapping for the current test, resolved from the same chain as `verify`. Use for ad-hoc pythonic assertions:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
def test_inline_check(dmm, limits):
|
|
65
|
+
v = dmm.measure_dc_voltage()
|
|
66
|
+
assert v in limits["output_voltage"]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`limits[name]` raises `KeyError` when no limit is configured — there is no silent default.
|
|
70
|
+
|
|
71
|
+
### `prompt` — function
|
|
72
|
+
|
|
73
|
+
Returns a callable that resolves operator prompts declared via `@pytest.mark.testerkit_prompts`:
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
@pytest.mark.testerkit_prompts(
|
|
77
|
+
inspect={"message": "Verify LED is GREEN", "prompt_type": "confirm"},
|
|
78
|
+
)
|
|
79
|
+
def test_visual(prompt, verify):
|
|
80
|
+
prompt("inspect") # blocks until operator responds
|
|
81
|
+
verify("led_state", read_led_color())
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
See [`testerkit_prompts`](markers.md#testerkit_prompts) for the marker shape.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Recording outputs & streams
|
|
89
|
+
|
|
90
|
+
The verbs for read-back values and continuous samples. Like `verify`/`measure`, these are callable fixtures — take the name in the test signature, then call it. Each wraps the matching `context` method.
|
|
91
|
+
|
|
92
|
+
### `observe` — function
|
|
93
|
+
|
|
94
|
+
Callable: `observe(name, value, *, namespace=None, unit=None)`. Records a read-back value (the response side — a measured output, not a pass/fail judgment) onto the active vector. The value's shape decides where it lands: scalars stay inline; arrays / `Waveform` go to the ChannelStore; blobs go to the FileStore — with a `channel://` / `file://` reference stamped on the vector.
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
def test_rail(dmm, observe, verify):
|
|
98
|
+
observe("v_rail", dmm.measure_dc_voltage()) # output, recorded not judged
|
|
99
|
+
observe("scope_cap", scope.capture()) # Waveform → ChannelStore
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
See [the three verbs](../../concepts/data/three-verbs.md) for how a value routes to the right store by shape.
|
|
103
|
+
|
|
104
|
+
### `stream` — function
|
|
105
|
+
|
|
106
|
+
Callable: `stream(name, sample, *, namespace=None, unit=None) -> str`. Appends one sample to a named channel timeline (continuous capture). Returns the `channel://` reference. Use it for a live sensor feed or free-running acquisition, where the channel — not the individual call — is the unit you query later.
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
def test_soak(dmm, stream):
|
|
110
|
+
for _ in range(n):
|
|
111
|
+
stream("supply_rail", dmm.measure_dc_voltage(), unit="V")
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Talking to instruments
|
|
117
|
+
|
|
118
|
+
These fixtures need a station YAML to produce useful results. Without one they return empty dicts / `None`.
|
|
119
|
+
|
|
120
|
+
### `instruments` — session
|
|
121
|
+
|
|
122
|
+
Yields `dict[role_name, driver_instance]`. Connects every instrument declared in the station YAML at session start, disconnects at session end. Auto-mocks when `--mock-instruments` is on. Identity and calibration are checked against config for real hardware.
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
def test_voltage(instruments):
|
|
126
|
+
dmm = instruments["dmm"]
|
|
127
|
+
assert dmm.measure_dc_voltage() > 3.0
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
In most tests you take **role names directly** as fixtures (`def test_x(dmm, psu)`) — see [Per-role auto-fixtures](#per-role-auto-fixtures) — and never need `instruments` itself.
|
|
131
|
+
|
|
132
|
+
### `instrument` — function
|
|
133
|
+
|
|
134
|
+
Returns an `InstrumentAccessor` for role-keyed access with grouping:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
def test_one(instrument):
|
|
138
|
+
dmm = instrument("dmm")
|
|
139
|
+
|
|
140
|
+
def test_all(instrument):
|
|
141
|
+
dmms = instrument.by_type("pymeasure.instruments.keithley.Keithley2000")
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### `instrument_records` — session
|
|
145
|
+
|
|
146
|
+
Returns `dict[role_name, InstrumentRecord]` — the resolved instrument metadata (driver class, resource string, calibration cert, mocked flag) before connection. Useful for tests that need identity or calibration info without taking the live driver.
|
|
147
|
+
|
|
148
|
+
### `uut` — session
|
|
149
|
+
|
|
150
|
+
Yields the connected UUT driver (resolved from `Part.driver` + `FixtureConfig.uut_resource`), or `None` when the part has no driver. Mocked when `--mock-instruments` is on.
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
def test_firmware(uut):
|
|
154
|
+
assert uut.get_version().startswith("2.")
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### `pins` — session
|
|
158
|
+
|
|
159
|
+
Returns a `PinAccessor` for UUT-centric pin access. Looks up the instrument that the fixture YAML maps to each UUT pin, transparently activates the route if any switch is in the path.
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
def test_output(pins):
|
|
163
|
+
pins["VIN"].set_voltage(5.0)
|
|
164
|
+
pins["VIN"].enable_output()
|
|
165
|
+
assert pins["VOUT"].measure_voltage() > 3.0
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Raises `pytest.UsageError` if no fixture config or instruments are loaded.
|
|
169
|
+
|
|
170
|
+
### `routes` — function
|
|
171
|
+
|
|
172
|
+
Yields a `RouteManager` for explicit switch routing, or `None` when no routes exist:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
def test_vout(dmm, routes):
|
|
176
|
+
with routes.for_pin("VOUT"):
|
|
177
|
+
v = dmm.measure_voltage()
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
`routes.deactivate_all()` runs automatically at test teardown.
|
|
181
|
+
|
|
182
|
+
### `fixture_manager` — session
|
|
183
|
+
|
|
184
|
+
Returns the `FixtureManager` directly, for the rare test that needs advanced lookup (e.g. net-name → connection) beyond what `pins` exposes:
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
def test_lookup(fixture_manager):
|
|
188
|
+
conn = fixture_manager.get_connection_for_net("VOUT_3V3")
|
|
189
|
+
inst = fixture_manager.get_instrument_for_connection(conn.name)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Reading per-test state
|
|
195
|
+
|
|
196
|
+
The active vector's params, observations, and the connection currently being iterated.
|
|
197
|
+
|
|
198
|
+
### `context` — function
|
|
199
|
+
|
|
200
|
+
Returns a `Context` exposing the run / UUT / station / vector state for the active test. Resolves on every test, with empty defaults when there's nothing to expose.
|
|
201
|
+
|
|
202
|
+
| Method | Returns | Purpose |
|
|
203
|
+
|---|---|---|
|
|
204
|
+
| `context.get_param(name, default=None)` | `Any` | Read a sweep / parametrize value. |
|
|
205
|
+
| `context.params` | `dict` | All active params for this row. |
|
|
206
|
+
| `context.changed(key)` | `bool` | True if `key` differs from prior iteration. |
|
|
207
|
+
| `context.last(key, default=None)` | `Any` | Prior iteration's value for `key`. |
|
|
208
|
+
| `context.observe(key, value)` | `None` | Record a free-form observation. |
|
|
209
|
+
| `context.observations` | `dict` | All recorded observations. |
|
|
210
|
+
| `context.part` | `Part \| None` | Active part definition (= `part` fixture). |
|
|
211
|
+
| `context.station` | `StationConfig \| None` | Active station config (= `station_config` fixture). |
|
|
212
|
+
| `context.run` | `TestRun \| None` | The current `TestRun`. |
|
|
213
|
+
| `context.limits` | `LimitsView` | Read-only view of the active limits. |
|
|
214
|
+
| `context.characteristics` | `tuple[str, ...]` | Active characteristic IDs from `testerkit_characteristics`. |
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
def test_rail(context, psu, dmm, verify):
|
|
218
|
+
psu.set_voltage(context.get_param("vin", 5.0))
|
|
219
|
+
verify("vout", dmm.measure_dc_voltage())
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### `connections` — function
|
|
223
|
+
|
|
224
|
+
Returns the `ConnectionIterator` resolved from `testerkit_characteristics` / `testerkit_connections` markers, or `None` when no markers are declared.
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
def test_per_pin(connections, dmm):
|
|
228
|
+
for conn in connections:
|
|
229
|
+
v = dmm.measure_voltage()
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Reading loaded configuration
|
|
235
|
+
|
|
236
|
+
Typed accessors over the YAML / CLI that shaped this run. Each one resolves to its model OR `None` (or an empty dict / bool) — taking one in a vanilla project is safe.
|
|
237
|
+
|
|
238
|
+
### `part` — session
|
|
239
|
+
|
|
240
|
+
Returns the active `Part` definition loaded from `parts/*.yaml` (identity, pins, characteristics), or `None` if no `parts/` directory or no match. For derived limits use the `limits` fixture or `context.get_limit(name)`.
|
|
241
|
+
|
|
242
|
+
Resolution chain (first match wins):
|
|
243
|
+
1. `--part <id-or-path>` — `<id>` looks up `parts/<id>.yaml`; `<path>` is used directly.
|
|
244
|
+
2. `--uut-part-number <pn>` — content match against `part.part_number:` across `parts/*.yaml`.
|
|
245
|
+
3. Single-file fallback when `parts/` holds exactly one part file.
|
|
246
|
+
4. `None`.
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
def test_spec(part, context, dmm, verify):
|
|
250
|
+
if part:
|
|
251
|
+
assert part.part_number == "DEMO-BUCK-3V3"
|
|
252
|
+
verify("output_voltage", dmm.measure_dc_voltage()) # limit resolves from the part spec
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### `station_config` — session
|
|
256
|
+
|
|
257
|
+
Returns the `StationConfig` resolved from `--station` / `stations/*.yaml`, or `None`. Also publishes the value to the active-station ContextVar so `context.station` works without taking the fixture.
|
|
258
|
+
|
|
259
|
+
### `fixture_config` — session
|
|
260
|
+
|
|
261
|
+
Returns the `FixtureConfig` resolved from `--fixture` / `fixtures/*.yaml`, or `None`. In worker mode (multi-site), extracts just this site's `connections` and `uut_resource`.
|
|
262
|
+
|
|
263
|
+
### `run_context` — session
|
|
264
|
+
|
|
265
|
+
Returns the `RunContext` for the active run. Use it to attach run-level metadata that persists across tests:
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
def test_setup(run_context):
|
|
269
|
+
run_context.set("operator_badge", "EMP-12345")
|
|
270
|
+
run_context.set("fixture_serial", "FIX-001")
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
For per-test or per-vector state, use `context` instead.
|
|
274
|
+
|
|
275
|
+
### `mock_instruments` — session
|
|
276
|
+
|
|
277
|
+
Returns `bool`. True when `--mock-instruments` was passed or `TESTERKIT_MOCK_INSTRUMENTS=1` is set. The same flag drives the `instruments` fixture's behavior; tests rarely take it directly except for diagnostic branches.
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Flow control
|
|
282
|
+
|
|
283
|
+
Two fixtures that drive the test body's iteration shape, not just expose data. `vectors` collapses pytest's per-row case multiplication into one in-body loop; `sync` blocks the body until peer workers reach the same named point.
|
|
284
|
+
|
|
285
|
+
### `vectors` — function
|
|
286
|
+
|
|
287
|
+
Taking `vectors` in the test signature switches collection to **self-loop mode**: the function-level vector sources (`@pytest.mark.parametrize`, function-level `testerkit_sweeps`, sidecar `sweeps:`, profile overrides) are consolidated into one matrix at collection time, and the test runs as a single pytest case. (Class- or module-level `testerkit_sweeps` still fan out as separate pytest cases — one per outer condition — each running the consolidated inner matrix.) The test body iterates the matrix itself:
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
def test_sweep(vectors, psu, dmm, measure):
|
|
291
|
+
for v in vectors:
|
|
292
|
+
psu.set_voltage(v["vin"])
|
|
293
|
+
measure("vout", dmm.measure_dc_voltage())
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Each `for` iteration pushes the row's params + index into active state so `measure`, `verify`, and `context` see the same row-scoped context they would in normal (one-case-per-row) mode. The fixture fails the test at teardown if the matrix is non-empty but the body iterated zero times.
|
|
297
|
+
|
|
298
|
+
Choose self-loop mode when an outer setup (thermal soak, supply ramp) shouldn't repeat per row; choose normal parametrize mode when you want pytest to report one case per row.
|
|
299
|
+
|
|
300
|
+
### `sync` — session
|
|
301
|
+
|
|
302
|
+
Yields a `SyncPoint` for multi-UUT coordination when running in worker mode (`_TESTERKIT_SITE_INDEX` is set), or `None` in single-site mode. `sync.wait(name, timeout=...)` blocks until every site reaches the same name:
|
|
303
|
+
|
|
304
|
+
```python
|
|
305
|
+
def test_measure_hot(dmm, sync):
|
|
306
|
+
if sync:
|
|
307
|
+
sync.wait("thermal_soak", timeout=300)
|
|
308
|
+
v = dmm.measure_voltage()
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Per-role auto-fixtures
|
|
314
|
+
|
|
315
|
+
When the plugin finds a station YAML at `pytest_configure`, it dynamically registers one session-scoped fixture per `instruments:` role. A station YAML like
|
|
316
|
+
|
|
317
|
+
```yaml
|
|
318
|
+
instruments:
|
|
319
|
+
dmm: keithley_dmm_001
|
|
320
|
+
psu: keysight_psu_002
|
|
321
|
+
scope: tek_dpo_003
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
exposes `dmm`, `psu`, and `scope` as fixtures, each returning the connected driver for that role:
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
def test_rail(dmm, psu, verify):
|
|
328
|
+
psu.set_voltage(5.0)
|
|
329
|
+
verify("vout", dmm.measure_dc_voltage())
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
These names are not hard-coded — they come from your station YAML at session start.
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## See also
|
|
337
|
+
|
|
338
|
+
- [TesterKit markers](markers.md) — the seven `@pytest.mark.testerkit_*` decorators and their sidecar equivalents
|
|
339
|
+
- [pytest-native reference](../overview/pytest-native.md) — how the bundled plugin uses pytest's own collection / fixtures / markers
|
|
340
|
+
- [Models](../data/models.md) — `Limit`, `MeasurementLimitConfig`, `PartContext`, `StationConfig`, `FixtureConfig` field shapes
|
|
341
|
+
- [Test vectors & sweeps](../../how-to/execution/vector-expansion.md) — `testerkit_sweeps`, `parametrize`, and the `vectors` self-loop fixture
|
|
342
|
+
- [Spec-driven testing](../../how-to/execution/spec-driven-testing.md) — `testerkit_characteristics` + `connections` workflow
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Reference — pytest plugin
|
|
2
|
+
|
|
3
|
+
The fixtures and markers the bundled pytest plugin contributes on top of stock pytest. For pytest-native mechanics (collection, parametrize, conftest, CLI flags), see [pytest-native](../overview/pytest-native.md).
|
|
4
|
+
|
|
5
|
+
- [Fixtures](fixtures.md) — all the fixtures the plugin contributes, with signatures, scopes, and per-fixture examples
|
|
6
|
+
- [Markers](markers.md) — the seven `@pytest.mark.testerkit_*` decorators and their 1:1 sidecar equivalents
|
|
7
|
+
|
|
8
|
+
## See also
|
|
9
|
+
|
|
10
|
+
- [Concepts → pytest](../../concepts/overview/pytest.md) — why the platform rides on pytest as the primary runner
|
|
11
|
+
- [How-to → Writing tests](../../how-to/execution/writing-tests.md) — task recipes for authoring tests that use these fixtures + markers
|
|
12
|
+
- [Reference → Configuration](../configuration.md) — sidecar YAML schemas (the YAML form of every marker)
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# TesterKit markers
|
|
2
|
+
|
|
3
|
+
The TesterKit pytest plugin registers **seven markers**. Each maps 1:1 to a field on `TestEntry` (the recursive node type in the sidecar YAML), so anything you can write inline as a marker, you can write in the sidecar — and vice versa.
|
|
4
|
+
|
|
5
|
+
Pytest's own markers (`@pytest.mark.parametrize`, `@pytest.mark.skip`, `@pytest.mark.flaky` from `pytest-rerunfailures`, etc.) work unchanged. TesterKit's markers slot in alongside them.
|
|
6
|
+
|
|
7
|
+
## No-stacking rule
|
|
8
|
+
|
|
9
|
+
At most one inline `@pytest.mark.testerkit_X` decorator of each kind per test. Multi-entry payloads (a list of dicts for sweeps/mocks, multiple kwargs for limits/prompts) consolidate onto one marker. `@pytest.mark.parametrize` is the explicit exception — pytest's native stacking convention stays. Stacking a TesterKit marker raises `StackedMarkersError` at collection.
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
# OK
|
|
13
|
+
@pytest.mark.testerkit_sweeps([{"temperature": [-40, 25, 85], "load": [0.1, 0.5]}])
|
|
14
|
+
def test_x(...): ...
|
|
15
|
+
|
|
16
|
+
# Not OK — raises StackedMarkersError
|
|
17
|
+
@pytest.mark.testerkit_sweeps([{"temperature": [-40, 25, 85]}])
|
|
18
|
+
@pytest.mark.testerkit_sweeps([{"load": [0.1, 0.5]}])
|
|
19
|
+
def test_x(...): ...
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## `testerkit_limits`
|
|
25
|
+
|
|
26
|
+
Pin a `Limit` per measurement name. Both `verify(name, value)` and `measure(name, value)` record the measurement row and resolve the limit against this marker (or the sidecar's `limits:` block, or the active part spec, in resolution order); the only difference is `verify` raises `AssertionError` on FAIL where `measure` doesn't.
|
|
27
|
+
|
|
28
|
+
**Signature:** `@pytest.mark.testerkit_limits(**by_name)` — one keyword per measurement name; each value is a dict matching `MeasurementLimitConfig`.
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
@pytest.mark.testerkit_limits(
|
|
32
|
+
output_voltage={"low": 3.135, "high": 3.465, "unit": "V"},
|
|
33
|
+
output_current={"high": 0.5, "unit": "A"},
|
|
34
|
+
)
|
|
35
|
+
def test_power_rail(dmm, psu, verify):
|
|
36
|
+
verify("output_voltage", dmm.measure_dc_voltage())
|
|
37
|
+
verify("output_current", psu.measure_current())
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Sidecar equivalent:**
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
limits:
|
|
44
|
+
output_voltage: {low: 3.135, high: 3.465, unit: V}
|
|
45
|
+
output_current: {high: 0.5, unit: A}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Full shape:** `low`, `high`, `nominal`, `unit`, `comparator`, plus the alternative `characteristic:` / `tolerance_pct:` / `tolerance_abs:` derivation, and the `bands:` list for condition-indexed limits. See [`MeasurementLimitConfig`](../data/models.md) for the full schema and [Test limits](../../how-to/execution/limits.md#condition-indexed-bands) for the band semantics.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## `testerkit_sweeps`
|
|
53
|
+
|
|
54
|
+
TesterKit-native parametrize. Each entry in the list is one **axis-group dict** — single-key dicts run as one independent loop; multi-key dicts inside one entry zip together; stacked entries cross-product (top entry = outermost / slowest loop).
|
|
55
|
+
|
|
56
|
+
**Signature (inline):** `@pytest.mark.testerkit_sweeps([entries])` — one positional list of axis-group dicts. Single-axis is `[{"name": [values]}]`; cross-product is multiple entries; zipped paired values are multiple keys in one entry.
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
# Single axis
|
|
60
|
+
@pytest.mark.testerkit_sweeps([{"vin": [3.3, 5.0, 12.0]}])
|
|
61
|
+
def test_rail(vin, psu, dmm, verify): ...
|
|
62
|
+
|
|
63
|
+
# Cross-product — outer first, inner last
|
|
64
|
+
@pytest.mark.testerkit_sweeps([
|
|
65
|
+
{"temperature": [-40, 25, 85]}, # outer
|
|
66
|
+
{"vin": [3.3, 5.0, 12.0]}, # inner
|
|
67
|
+
])
|
|
68
|
+
def test_rail_temp_sweep(temperature, vin, psu, dmm, verify): ...
|
|
69
|
+
|
|
70
|
+
# Zipped axis — same-length lists, paired
|
|
71
|
+
@pytest.mark.testerkit_sweeps([{"load_a": [0.1, 0.4], "load_b": [10, 20]}])
|
|
72
|
+
def test_zipped(load_a, load_b, ...): ...
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Sidecar equivalent:**
|
|
76
|
+
|
|
77
|
+
```yaml
|
|
78
|
+
sweeps:
|
|
79
|
+
- {temperature: [-40, 25, 85]}
|
|
80
|
+
- {vin: [3.3, 5.0, 12.0]}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**`testerkit_sweeps` vs `@pytest.mark.parametrize`:** both work; both feed the same `inputs` lane on the vector row (query with `FieldRef.input(name)`). Use `testerkit_sweeps` when you want range expanders (`linspace`, `arange`, `logspace`, etc.) or sidecar parity; use `@pytest.mark.parametrize` when you want pytest's `pytest.param(..., id="...")` / `marks=[...]` per-row metadata. See [Test vectors & sweeps](../../how-to/execution/vector-expansion.md) for full semantics including range expanders and the `vectors` self-loop fixture.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## `testerkit_mocks`
|
|
88
|
+
|
|
89
|
+
Install one or more mocks at test entry, unwound at teardown. Each entry has a `target:` and arbitrary `unittest.mock.patch.object` kwargs (`return_value`, `side_effect`, `wraps`, `spec`, etc.).
|
|
90
|
+
|
|
91
|
+
**Signature:** `@pytest.mark.testerkit_mocks([entries])` where each entry is a `MockEntry` dict.
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
@pytest.mark.testerkit_mocks([
|
|
95
|
+
{"target": "dmm.measure_dc_voltage", "return_value": 3.31},
|
|
96
|
+
{"target": "psu.measure_current", "side_effect": [0.1, 0.2, 0.3]},
|
|
97
|
+
])
|
|
98
|
+
def test_mocked(dmm, psu, verify): ...
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Sidecar equivalent:**
|
|
102
|
+
|
|
103
|
+
```yaml
|
|
104
|
+
mocks:
|
|
105
|
+
- {target: dmm.measure_dc_voltage, return_value: 3.31}
|
|
106
|
+
- {target: psu.measure_current, side_effect: [0.1, 0.2, 0.3]}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The target is `"<fixture>.<attr>"` — the pytest fixture name plus the attribute on the resolved fixture value. See [Mock mode](../../how-to/configuration/mock-mode.md) for the full priority resolution (per-test mocks > file-level mocks > station `mock_config` > zero).
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## `testerkit_characteristics`
|
|
114
|
+
|
|
115
|
+
Iterate the test body over a subset of the part spec's `characteristics`. Combined with `testerkit_connections` to select which signal-path connections to bind. Used by [spec-driven testing](../../how-to/execution/spec-driven-testing.md).
|
|
116
|
+
|
|
117
|
+
**Signature:** `@pytest.mark.testerkit_characteristics([ids])` — list of characteristic IDs.
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
@pytest.mark.testerkit_characteristics(["output_voltage", "output_current"])
|
|
121
|
+
def test_rail(context, verify):
|
|
122
|
+
for char_id in context.characteristics:
|
|
123
|
+
verify(char_id, ...)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Sidecar equivalent:**
|
|
127
|
+
|
|
128
|
+
```yaml
|
|
129
|
+
characteristics: [output_voltage, output_current]
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## `testerkit_connections`
|
|
135
|
+
|
|
136
|
+
Select which fixture connections the test iterates over. Pairs with `testerkit_characteristics`. Two payload shapes:
|
|
137
|
+
|
|
138
|
+
- **List of names** — bind by fixture-connection name: `@pytest.mark.testerkit_connections(["VOUT", "VIN"])`
|
|
139
|
+
- **Dict mapping instrument → channels** — bind by instrument and channel selector: `@pytest.mark.testerkit_connections(dmm=["CH1", "CH2"])`
|
|
140
|
+
|
|
141
|
+
**Sidecar equivalents:**
|
|
142
|
+
|
|
143
|
+
```yaml
|
|
144
|
+
connections: [VOUT, VIN] # list form
|
|
145
|
+
# OR
|
|
146
|
+
connections: {dmm: [CH1, CH2]} # dict form
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The pytest plugin's `connections` fixture exposes the resolved `FixtureConnection` iterator for the test body.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## `testerkit_retry`
|
|
154
|
+
|
|
155
|
+
Per-test retry policy. Translates to `pytest-rerunfailures`' `flaky` under the hood.
|
|
156
|
+
|
|
157
|
+
**Signature:** `@pytest.mark.testerkit_retry(max_retries=, delay=, on=)`
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
@pytest.mark.testerkit_retry(max_retries=2, delay=0.5, on=["AssertionError"])
|
|
161
|
+
def test_flaky_settling(dmm, verify): ...
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
| Field | Type | Default | Meaning |
|
|
165
|
+
|---|---|---|---|
|
|
166
|
+
| `max_retries` | `int >= 0` | `0` | 0 = single execution, 2 = up to 2 retries beyond original (3 total) |
|
|
167
|
+
| `delay` | `float >= 0` | `0.0` | Seconds between attempts |
|
|
168
|
+
| `on` | `list[str] \| None` | `None` (any) | Exception class names that trigger retry |
|
|
169
|
+
|
|
170
|
+
**Sidecar equivalent:**
|
|
171
|
+
|
|
172
|
+
```yaml
|
|
173
|
+
retry: {max_retries: 2, delay: 0.5, on: [AssertionError]}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Each retry produces measurement rows with the same `vector_index` and an incremented `vector_retry`. See [Parquet schema → Retries](../data/parquet-schema.md#retries).
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## `testerkit_prompts`
|
|
181
|
+
|
|
182
|
+
Declare operator prompts the test can invoke via the `prompt` fixture. Keyword per prompt name.
|
|
183
|
+
|
|
184
|
+
**Signature:** `@pytest.mark.testerkit_prompts(**by_name)` — each value matches `PromptConfig`.
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
@pytest.mark.testerkit_prompts(
|
|
188
|
+
inspect={"message": "Verify LED is GREEN", "prompt_type": "confirm"},
|
|
189
|
+
)
|
|
190
|
+
def test_visual(prompt, verify):
|
|
191
|
+
prompt("inspect") # blocks until operator responds
|
|
192
|
+
verify("led_state", read_led_color())
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
| Field | Type | Default | Meaning |
|
|
196
|
+
|---|---|---|---|
|
|
197
|
+
| `message` | `str` | (required) | Prompt text shown to the operator |
|
|
198
|
+
| `prompt_type` | `"confirm" \| "choice" \| "input"` | `"confirm"` | What the operator UI shows |
|
|
199
|
+
| `choices` | `list[str] \| None` | `None` | For `"choice"` type |
|
|
200
|
+
| `timeout_seconds` | `int \| None` | `None` | Stop waiting after N seconds (returns a timed-out response) |
|
|
201
|
+
|
|
202
|
+
**Sidecar equivalent:**
|
|
203
|
+
|
|
204
|
+
```yaml
|
|
205
|
+
prompts:
|
|
206
|
+
inspect: {message: "Verify LED is GREEN", prompt_type: confirm}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Composing `testerkit_characteristics` + `testerkit_connections`
|
|
212
|
+
|
|
213
|
+
These two markers are the two halves of selecting which connections a test iterates over `ctx.connections` (the `connections` fixture): `testerkit_characteristics` says *which characteristic* on the part, and `testerkit_connections` says *which fixture connections* to bind. They're independent, so every combination of present / absent / by-name / by-channel / fixture-loaded / fixture-absent has a defined behavior. Find the row that matches your test.
|
|
214
|
+
|
|
215
|
+
`testerkit_connections` takes one of two shapes (not both at once):
|
|
216
|
+
|
|
217
|
+
- **`[name, ...]`** — bind by fixture-connection name. Requires a fixture YAML.
|
|
218
|
+
- **`{instrument: [channels], ...}`** — bind by instrument → channel selector. Works without a fixture (synthesizes stubs) for early bringup.
|
|
219
|
+
|
|
220
|
+
| Case | `testerkit_characteristics` | `testerkit_connections` | Fixture loaded? | Result |
|
|
221
|
+
|------|---------------|----------------------|-----------------|--------|
|
|
222
|
+
| 1 | — | — | any | No markers → `ctx.connections` is `None`; the test runs once with no connection context. |
|
|
223
|
+
| 2 | `[X]` | — | yes | Iterate the fixture connections whose `uut_pin` (or `net`) matches a pin in `X`'s resolved pins. Order: characteristic order, then each characteristic's pin order (deduplicated). |
|
|
224
|
+
| 3 | `[X]` | — | no | Empty iterator — no fixture means no connections to bind. The test iterates `ctx.connections` zero times. |
|
|
225
|
+
| 4 | — | `[a, b]` (names) | yes | Iterate the named connections in the order listed. Unknown name → `pytest.UsageError`. |
|
|
226
|
+
| 5 | — | `[a, b]` (names) | no | `pytest.UsageError` — connection names are only meaningful against a fixture YAML. |
|
|
227
|
+
| 6 | — | `{inst: [ch]}` (channels) | yes | Match each `(instrument, channel)` against fixture connections, in listed order. No match → `pytest.UsageError`. `'all'` selects every connection on that instrument. |
|
|
228
|
+
| 7 | — | `{inst: [ch]}` (channels) | no | Synthesize connection stubs (`name="{inst}_ch{ch}"`, no `uut_pin`) for early bringup. `'all'` → `pytest.UsageError` (nothing to enumerate). |
|
|
229
|
+
| 8 | `[X]` | `[a, b]` (names) | yes | Resolve the names (case 4), then require every selected connection's `uut_pin` to fall in the union of the characteristics' pin sets. Out-of-set → `pytest.UsageError`. Listed order wins. |
|
|
230
|
+
| 9 | `[X]` | `[a, b]` (names) | no | `pytest.UsageError` (case 5 — a fixture is required for connection names). |
|
|
231
|
+
| 10 | `[X]` | `{inst: [ch]}` (channels) | yes | Resolve the channels (case 6), then require every match's `uut_pin` to fall in the union pin set. Out-of-set → `pytest.UsageError`. Listed order wins. |
|
|
232
|
+
| 11 | `[X]` | `{inst: [ch]}` (channels) | no | `pytest.UsageError` — fixtureless channel stubs have no `uut_pin` to cross-check against the characteristics. Drop `testerkit_characteristics` for pure bringup, or load a fixture. |
|
|
233
|
+
|
|
234
|
+
Invariants across the matrix:
|
|
235
|
+
|
|
236
|
+
- **No part loaded, or an unknown characteristic ID** → `pytest.UsageError`.
|
|
237
|
+
- **Iteration order** — when `testerkit_connections` is present it sets the order (user-listed); with characteristics alone, the order follows characteristic order then each characteristic's pin order.
|
|
238
|
+
- **Declared but un-iterated** — if connections resolve to a non-empty set and the test body never iterates `ctx.connections`, the test fails with `AssertionError`. An empty resolved set (case 3) is not an error; the body just runs zero rounds.
|
|
239
|
+
|
|
240
|
+
## Where markers live
|
|
241
|
+
|
|
242
|
+
Same vocabulary, three delivery channels:
|
|
243
|
+
|
|
244
|
+
| Channel | Example |
|
|
245
|
+
|---|---|
|
|
246
|
+
| Inline decorator | `@pytest.mark.testerkit_limits(output_voltage={"low": 3.135, "high": 3.465, "unit": "V"})` |
|
|
247
|
+
| Sidecar YAML (`tests/test_<module>.yaml`) | `limits: { output_voltage: { low: 3.135, high: 3.465, unit: V } }` |
|
|
248
|
+
| Profile YAML (`profiles/*.yaml`) | Same shape; applies session-wide via `--test-profile=<name>` |
|
|
249
|
+
|
|
250
|
+
Resolution order (least → most specific): inline marker (class then method) → sidecar file-level → sidecar class/method → profile chain. Sidecar overrides inline because sidecar markers are applied after inline decorators and the resolver is last-wins. CLI flags (`-k`, `-m`, `--mock-instruments`, etc.) compose with this chain rather than overriding it wholesale. See [Test configuration](../configuration.md#sidecar-yaml) for the full merge semantics.
|
|
251
|
+
|
|
252
|
+
## See also
|
|
253
|
+
|
|
254
|
+
- [pytest-native reference](../overview/pytest-native.md) — how TesterKit tests use pytest's own collection / fixtures / markers
|
|
255
|
+
- [TesterKit fixtures reference](fixtures.md) — all the fixtures the plugin exposes
|
|
256
|
+
- [Models](../data/models.md) — `MeasurementLimitConfig`, `MockEntry`, `SweepEntry`, `RetryConfig`, `PromptConfig` field shapes
|
|
257
|
+
- [Test vectors & sweeps](../../how-to/execution/vector-expansion.md) — `testerkit_sweeps` semantics + `vectors` self-loop fixture
|