---
myst:
html_meta:
description: "Create, find, update and archive assets, and attach datasets to them with data scopes."
---
# Assets
{.lead}
An asset represents a system you test, such as a vehicle, satellite or test stand.
It collects that system's datasets, runs, events and attachments across every test.
```{include} /guides/_snippets/connect-the-client.md
```
## Create or find an asset
Properties identify the physical system, such as a serial number.
{py:meth}`~nominal.core.NominalClient.get_or_create_asset_by_properties` returns the asset with those properties, creating it if none exists, so a script can run more than once:
```python
asset = client.get_or_create_asset_by_properties(
{"serial": "QC-456"},
name="Quadcopter 456",
description="Airborne observation platform",
labels=["camera", "airborne"],
)
```
It raises `ValueError` if more than one asset has those properties.
To always create a new asset, use {py:meth}`~nominal.core.NominalClient.create_asset`.
## Add data with data scopes
An asset holds each dataset under a data scope name, such as `"telemetry"`.
Use the same data scope name for the same kind of data on every asset, so workbook templates and checklists work across them.
{py:meth}`~nominal.core.Asset.get_or_create_dataset` returns the dataset under a data scope name, creating it if needed.
```{include} /guides/_snippets/sample-flight-csv.md
```
```python
dataset = asset.get_or_create_dataset("telemetry", name="Quadcopter 456 telemetry")
dataset.add_tabular_data("flight.csv", timestamp_column="time", timestamp_type="iso_8601")
```
Running the upload again adds another file to the same dataset.
See [Datasets](/guides/datasets/overview.md) for file formats and waiting for ingestion.
To attach a dataset that already exists, use {py:meth}`~nominal.core.Asset.add_dataset`:
```python
asset.add_dataset("ground-station", client.get_dataset(""))
```
{py:meth}`~nominal.core.Asset.remove_data_scopes` detaches data by data scope name or by dataset. It doesn't delete the dataset.
```python
asset.remove_data_scopes(names=["ground-station"])
```
## Find assets
{py:meth}`~nominal.core.NominalClient.search_assets` combines its filters with AND:
```python
assets = client.search_assets(labels=["airborne"], properties={"serial": "QC-456"})
```
`search_text` is a fuzzy match, so results may not contain the text verbatim.
Use `exact_substring` when they must.
To retrieve one asset, use its RID from the asset's page in Nominal:
```python
asset = client.get_asset("")
```
## Update metadata and attachments
{py:meth}`~nominal.core.Asset.update` replaces each field you pass and leaves the others unchanged.
To add a label, merge it with the existing ones:
```python
asset.update(labels=[*asset.labels, "new-motor-vendor"])
```
Attach files that describe the system across tests, such as a specification:
```python
asset.add_attachments([client.create_attachment("spec.pdf")])
```
Attach files about a single test to its [run](/guides/runs.md) instead.
## Archive an asset
{py:meth}`~nominal.core.Asset.archive` hides the asset from views and searches without deleting its data.
{py:meth}`~nominal.core.Asset.unarchive` restores it.
```python
asset.archive()
```