Runs#
A run names a span of time for one test or analysis, such as a flight or a test-stand firing. It references data rather than copying it.
Connect the client#
This guide assumes you have installed the client and setup your API keys.
from nominal.core import NominalClient
client = NominalClient.from_profile("default")
Create a run on an asset#
When the data already belongs to an asset, create the run from the asset with the test’s time window. The run sees the asset’s datasets through their data scopes, so you don’t attach them again.
from datetime import datetime, timezone
asset = client.get_asset("<ASSET_RID>")
run = asset.create_run(
"Flight acceptance test",
start=datetime(2026, 9, 10, 14, 38, tzinfo=timezone.utc),
end=datetime(2026, 9, 10, 14, 48, tzinfo=timezone.utc),
)
Start and end accept timezone-aware datetimes or epoch nanoseconds.
Pass end=None for a test that’s still running.
For a run across several assets, use create_run() with assets=[...].
Create a run from datasets#
Without an asset, attach each dataset to the run under a ref name with add_dataset().
This example sets the run’s bounds from an uploaded file.
The examples upload flight.csv. To run them as written, save this sample under that name:
time,altitude,temperature,tail_number
2026-09-10T14:38:19Z,100.0,20.0,N456QC
2026-09-10T14:38:20Z,101.5,20.2,N456QC
2026-09-10T14:38:21Z,103.0,20.4,N456QC
dataset = client.create_dataset("Frosty flight")
file = dataset.add_tabular_data("flight.csv", timestamp_column="time", timestamp_type="iso_8601")
file.poll_until_ingestion_completed()
assert file.bounds is not None # set once ingestion succeeds
run = client.create_run("High precipitation flight", start=file.bounds.start, end=file.bounds.end)
run.add_dataset("telemetry", dataset)
The ref name, here "telemetry", is the dataset’s name within the run.
Use the same ref name for the same kind of data on every run, so workbook templates and checklists work across runs.
add_dataset also takes series_tags, to select tagged data, and a time offset.
get_dataset() and list_datasets() return only datasets attached this way.
For data on an associated asset, use get_dataset().
remove_data_sources() detaches a dataset without deleting it:
run.remove_data_sources(ref_names=["telemetry"])
Find runs#
Retrieve one run by the RID on its page in Nominal, or search with search_runs():
run = client.get_run("<RUN_RID>")
review_runs = client.search_runs(labels=["needs-review"], asset=asset)
name_substring matches names, descriptions, labels and properties, so results may not contain the text in their name.
Update a run#
update() replaces each field you pass and leaves the others unchanged.
To add a property, merge it with the existing ones:
run.update(labels=["reviewed"], properties={**run.properties, "reviewer": "flight-test"})
To close a run that’s still going, set its end:
run.update(end=datetime.now(timezone.utc))
Changing bounds changes the window the run shows, not the stored data.
Attachments, workbooks and events#
Attach files about this test to the run, and files about the system to its asset:
run.add_attachments([client.create_attachment("flight_report.pdf")])
Create a workbook for the run from a template whose inputs match the run’s ref names or data scope names. See Workbooks.
Mark moments inside the run with events.
Archive a run#
archive() hides the run without deleting its data:
run.archive()