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 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.


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

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

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.

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.

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.

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

# 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.

# 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.

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.