---
title: "DataLab actions"
section: "Libraries: Python"
route: /pythondatalabactions
account: {accountId}
bruce_api: https://{accountId}.api.nextspace.host
guardian_api: https://guardian.nextspace.host
---
# DataLab actions

An action runs server side against everything a query matches, so nothing is transferred to change it. Build the selection as on the [DataLab queries](/pythondatalabqueries) page, then call one of the `run_action_*` methods on it.

Every action answers with a Pending Action rather than a result. `DataLabBuilder.action_id` reads its ID out of the response, and `PendingAction.on_completion` waits for it.

```python
import bruce_models as BM

query = BM.DataLabBuilder(bruce).entity_type(ENTITY_TYPE_ID).equals("status", "Draft")

response = query.run_action_set_attribute("status", "Active")
action_id = BM.DataLabBuilder.action_id(response)

result = BM.PendingAction.on_completion(
    bruce,
    action_id,
    on_progress=lambda a: print(f"{a.get('Status')} {a.get('Progress')}%")
)

action = result.get("action")

# A failed job returns rather than raising, so the messages are available.
if action.get("Status") != BM.EStatus.COMPLETE:
    for message in result.get("messages"):
        print(message.get("Message"))
```

## Action: Set attribute value

```python
query.run_action_set_attribute("status", "Active")

# The type the value is written as, when it is not a string.
query.run_action_set_attribute("height", 12.5, attribute_type="number")
```

## Action: Update Tags

```python
query.run_action_add_layers([405, 406])
query.run_action_remove_layers([405])

# Replaces whatever the Entities carried.
query.run_action_set_layers([405, 406])
```

## Action: Create Entity Attachments

Attaches one already uploaded Client File to every matching Entity.

```python
query.run_action_attach_file(
    client_file_id=CLIENT_FILE_ID,
    attachment_type_id=ATTACHMENT_TYPE_ID,
    group="Inspections"
)
```

## Action: Export JSON

The file lands in the account's temporary store. Its name and url arrive on the finished Pending Action.

```python
response = query.run_action_export(
    "export-json",
    expand="EntityType,LOD,Source,Relation,Attachment"
)

action = BM.PendingAction.on_completion(
    bruce, BM.DataLabBuilder.action_id(response)
).get("action")

print(BM.DataLabBuilder.export_url(action))
print(BM.DataLabBuilder.export_file_name(action))
```

## Action: Export CSV

The formats are `export-csv`, `export-xlsx`, `export-json` and `export-nsx`. Each takes a different subset of the settings, and one that would be ignored is refused rather than read as a filter that is quietly not applied.

```python
query.run_action_export("export-csv", expand="EntityType")

# export-nsx takes no expand, and says so rather than dropping it.
query.run_action_export("export-nsx")
```

## Action: Delete Entities

```python
# Deletes everything the selection matches, so check count() first.
print(f"about to delete {query.count():,} Entities")
query.run_action_delete()
```

## Action: Data Transformation

Moves Entities to another Entity Type, either wholesale or split by the value of an attribute.

```python
# Everything matched moves to one target Type.
query.run_action_transfer_to_type(
    source_entity_type_id=SOURCE_TYPE_ID,
    target_entity_type_id=TARGET_TYPE_ID,
    update_schema=True
)

# Or split by an attribute, one target Type per distinct value.
query.run_action_transfer_by_attribute(
    source_entity_type_id=SOURCE_TYPE_ID,
    attribute_path="category"
)
```

## Anything else

`run_action` sends an action body as given, for anything the named helpers do not cover yet.

```python
query.run_action({"ActionType": "some-new-action", "Setting": "value"})
```

## Things worth knowing

**An action runs against the whole selection.** There is no page size and no partial run, so a mistake in a criterion is a mistake applied to every match. `count` costs nothing and is worth calling first.

**A failed job does not raise.**`on_completion` returns on `FAILED` and `CANCELLED` as well as success, because the messages explaining why are what you usually want. Check `Status` to tell them apart.

**Changing what you are also reading.** An action that changes an attribute the query filters on changes what the query matches. Read every page first if you need both.

---

Urls on this page are resolved for account `{accountId}`.
Site index: https://docs.nextspace.host/llms.txt · whole site in one file: https://docs.nextspace.host/llms-full.txt
Human-readable version of this page: https://docs.nextspace.host/pythondatalabactions
