Python API Reference#

The Python API provides a ctypes-based interface to the ovstage runtime data plane.

ovstage#

Version and Constants#

__version__ = '0.3.0'#

str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.

get_build_info()#

Return build information from the native OVStage loader.

The loader library is opened on first use, but the OVStage runtime is not initialized and no Stage instance is created.

Return type:

BuildInfo

class BuildInfo#

Build information embedded in the loaded OVStage native library.

Future versions may append fields while preserving the meaning and order of existing fields. build_string has the form version+branch.build_number.git_hash.build_location and starts with the OVStage semantic version. Native string views are decoded and copied, so every string stored in this Python object is owned by Python.

Variables:
  • struct_size (int) – Size of the native build-information structure.

  • build_number (int) – Numeric CI or local build number.

  • build_string (str) – Full version, build number, and source revision.

  • git_branch (str) – Source branch used for the build.

  • git_hash (str) – Source revision used for the build.

  • build_location (str) – Build-system or location identifier.

__init__(
struct_size,
build_number,
build_string,
git_branch,
git_hash,
build_location,
)#
Parameters:
  • struct_size (int)

  • build_number (int)

  • build_string (str)

  • git_branch (str)

  • git_hash (str)

  • build_location (str)

Return type:

None

struct_size: int#
build_number: int#
build_string: str#
git_branch: str#
git_hash: str#
build_location: str#
library_version()#

Return the loaded library’s (major, minor, patch) version.

Forces the lazy load so a standalone ovstage.library_version() returns a real version (or raises if the library can’t load) instead of None before first use.

Return type:

tuple | None

TIMEOUT_INFINITE = 18446744073709551615#

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating-point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by ‘+’ or ‘-’ and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int(‘0b100’, base=0) 4

OVSTAGE_TIMEOUT_INFINITE = 18446744073709551615#

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating-point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by ‘+’ or ‘-’ and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int(‘0b100’, base=0) 4

OVX_API_SUCCESS = 0#

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating-point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by ‘+’ or ‘-’ and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int(‘0b100’, base=0) 4

OVX_API_ERROR = 1#

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating-point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by ‘+’ or ‘-’ and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int(‘0b100’, base=0) 4

Stage and Path Dictionary#

class Stage#

An ovstage instance: the unit of stage-data read/write/query.

Parameters:
  • name – Optional instance name used for diagnostics.

  • config – Optional process configuration. Its runtime-default hierarchy model controls automatic transform updates; its ordinal admission policy controls mutation ordering. Both are captured by this instance.

__init__(name=None, config=None)#
Parameters:
advance_write_floor(ordinal, scope=Scope.ALL, attributes=None)#

Advance the write floor; scope selects the affected attributes (see Scope).

Advances clamp to the current value, so a non-monotonic ordinal is a no-op rather than an error.

Attribute aliases advance one shared floor.

Parameters:
Return type:

Operation

clone(source_path, target_paths, ordinal)#

Clone the subtree under source_path to each path in target_paths (blocking).

Data-plane peer of ovrtx’s clone_usd (the _usd postfix is dropped). The ordinal must exceed the global write floor and the effective floors of the source subtree’s attributes. For nonempty targets, it must also exceed the effective floors of every reproduced destination attribute, including copied prim type, applied schema and ancestor type metadata. These floor checks run at execution time under every admission policy.

Independently of the source floor checks, the configured history policy checks retained destination-cell changes and every derived target prim’s lifecycle, including the effective usd-path floor. The STRICTLY_INCREASING policy requires a newer ordinal than intersecting retained changes; NONDECREASING allows equality but rejects older ordinals. FLOOR_ONLY skips retained-history and separate lifecycle admission. With no targets, only the source/global floor checks apply. Copied cells record changes at ordinal, so later customization needs a newer ordinal under the strict policy; NONDECREASING permits the same ordinal while it remains above applicable floors. Disjoint target cells may share an ordinal.

The source must exist; each target must not already exist, and a target path may appear only once, independently of the admission policy. Returns the clone’s CloneResult. Execution failure raises OvstageError; use fetch_clone_result() with the low-level async path to inspect the clone’s underlying error code.

Parameters:
Return type:

CloneResult

clone_async(source_path, target_paths, ordinal)#

Enqueue a subtree clone of source_path to target_paths at ordinal (asynchronous).

Returns a CloneOperation — an Operation whose result() yields the CloneResult once the clone has completed (op.wait().result()). The source, target and ordinal requirements are those of clone(). Enqueue success does not guarantee execution success: call wait() to observe completion errors.

Parameters:
Return type:

CloneOperation

compute_hierarchy(
input_ordinal,
output_ordinal,
model=HierarchyComputationModel.CPU_INCREMENTAL,
)#

Compute hierarchy-derived world transforms (blocking).

Computation uses the currently connected hierarchy. Children may compute as roots while their parents remain unavailable.

The computation uses the latest committed inputs. It records the rewritten omni:fabric:worldMatrix rows at output_ordinal, also when the column is already sealed there. Compute before you seal when consumers need a complete snapshot at that ordinal. The current implementation ignores input_ordinal.

Parameters:
  • input_ordinal (int)

  • output_ordinal (int)

  • model (int)

Return type:

None

compute_hierarchy_async(
input_ordinal,
output_ordinal,
model=HierarchyComputationModel.CPU_INCREMENTAL,
)#

Enqueue hierarchy-derived world transform computation.

The computation uses the latest committed inputs. It records the rewritten omni:fabric:worldMatrix rows at output_ordinal, also when the column is already sealed there. Compute before you seal when consumers need a complete snapshot at that ordinal. The current implementation ignores input_ordinal.

Parameters:
  • input_ordinal (int)

  • output_ordinal (int)

  • model (int)

Return type:

Operation

property config: StageConfig#

Get a detached copy of the original process configuration entries.

Omitted settings remain None and selectors remain selectors; this snapshot does not expand them into the resolved runtime defaults.

delete_attributes(query, attributes, ordinal)#

Enqueue a delete. Empty attributes deletes entire prims.

The ordinal must exceed applicable floors. The admission policy described by write_attribute() also checks retained changes to deleted cells and, for whole-prim deletion, the affected prim lifecycles. FLOOR_ONLY skips those history and separate lifecycle checks. Call wait() on the returned operation to observe failures discovered after enqueue.

Parameters:
Return type:

Operation

destroy()#
Return type:

None

fetch_clone_result(op_or_id, timeout=18446744073709551615)#

Fetch a clone’s completion report by op id (low-level ovstage_fetch_clone_result).

The report is per-op state that lives until the op is released, so this is the C-shaped path — Stage.wait_op / fetch_clone_result / Stage.release_op — and the way to observe a failed clone’s own error code (wait() reports every failure as OP_FAILED). After CloneOperation.wait(), which releases the op, it raises INVALID_HANDLE; use CloneOperation.result() there instead.

Parameters:
  • op_or_id – the CloneOperation or its integer op id.

  • timeout (int) – max nanoseconds to wait for completion; 0 polls.

Raises:

OvstageError – TIMEOUT while the clone is pending (it stays waitable), INVALID_HANDLE for an id that is not a live clone op, or the clone’s own failure code with its message.

Return type:

CloneResult

fetch_hierarchy_result(hierarchy)#

Fetch, copy, and release a completed hierarchy lookup result payload.

Return type:

HierarchyResult

fetch_map_next(mapping, timeout=18446744073709551615)#
Parameters:

timeout (int)

Return type:

MapGroup | None

fetch_ordinal(ordinal_query, timeout=18446744073709551615)#
Parameters:

timeout (int)

Return type:

int

fetch_query_result(query, timeout=18446744073709551615)#

Fetch (and release) a query result, copying out its scalar summary.

Parameters:

timeout (int)

Return type:

QueryResult

fetch_read_next(read, timeout=18446744073709551615)#

Fetch the next read group, or None at end of iteration.

Parameters:

timeout (int)

Return type:

ReadGroup | None

get_attribute_write_floor(attribute=None)#

Query a per-attribute write floor, or the global write floor if attribute is None.

Aliases of one stored column report the same floor.

Parameters:

attribute (str | int | None)

Return type:

OrdinalQuery

get_hierarchy(path_list, ordinal, relation)#

Return parent/children/siblings for an ordered path list (blocking).

This reads the current committed hierarchy when the operation executes. ordinal is echoed as a caller-supplied tag; it does not select a historical hierarchy snapshot.

Parameters:
  • path_list (int)

  • ordinal (int)

  • relation (int)

Return type:

HierarchyResult

get_hierarchy_async(path_list, ordinal, relation)#

Enqueue a parent/children/siblings lookup for an ordered path list.

Parameters:
  • path_list (int)

  • ordinal (int)

  • relation (int)

Return type:

Hierarchy

get_hierarchy_computation_models()#

Return the hierarchy computation models supported by this runtime.

Return type:

List[HierarchyComputationModelDesc]

get_oldest_preserved_ordinal()#
Return type:

OrdinalQuery

get_path_dictionary()#

Return the instance’s path-dictionary bundle ({vtable, context}).

The dictionary is owned by this instance and stays valid while it is alive; list references do not extend that lifetime. Callers must not tear the dictionary down. This is the raw bundle the binding dispatches through, not a ovstage.PathDictionary — to work with tokens, paths, and path lists from Python, construct PathDictionary(stage), which calls this for you.

Return type:

LP_path_dictionary_instance_t

static get_version()#
Return type:

tuple

map_attribute(
query,
attribute,
ordinal,
*,
prim_mode=PrimMode.UPSERT,
dtype=None,
semantic=0,
element_sizes=None,
attribute_mode=AttributeMode.REJECT,
placement=None,
)#

Reserve a map session for writing an attribute.

dtype specifies the element storage type, with the complete tuple width in dtype.lanes. It is required for a new attribute. If omitted, the existing schema must be unambiguous for the target prims. A requested dtype that conflicts with existing storage, or semantic that conflicts with an authored role on a target prim/name, is rejected; delete that attribute before mapping it with a new schema, or pass attribute_mode=AttributeMode.FORCE with dtype to replace that schema when each group commits, under the same rules as a forcing write, including when a commit fails after the previous schema has ended. Setup and each commit are rejected while a prim they would replace has an outstanding read. An omitted semantic adopts an unambiguous compatible existing identity. Specify dtype and semantic when the target prims have multiple same-name identities. Fixed-size map groups expose the same scalar-lane layout as reads: scalar lanes with shape (data_rows,) for scalars, (data_rows, C) for tuples, or (data_rows, S, S) for square matrices. Use the group’s data_row_index(local) to resolve a logical element through any data index map. Shapes follow the stored type and semantic rather than the original convenience write shape. semantic is the AttributeSemantic (or raw ovstage_attribute_semantic_t value) carried on the map. Geometric semantics and TIME_CODE record a role on the column when unmap succeeds; ID semantics select the corresponding ID storage type and require pre-interned ids in the map buffer (TOKEN_ID / RELATIONSHIP_PATH_ID use dtype = (kDLUInt, 64, 1), CONNECTION_PATH_ID uses dtype = (kDLUInt, 64, 2)). element_sizes gives per-prim element counts for ragged columns.

Setup and publication use the admission policy described by write_attribute(), against the affected cells and applicable prim lifecycles. Every policy retains the applicable write-floor checks. A successful enqueue can still fail ordinal admission during setup, before writable groups are made available. Observe setup failure through the returned map’s wait() or fetch_next(). Successful setup only makes writable staging buffers available. It does not change stage values, create prims or attributes, modify schemas or hierarchy, or record value or prim-lifecycle changes at the session’s ordinal. These effects commit only for groups whose unmap succeeds. Commit rechecks the current layout, type/semantic compatibility, prim creation policy, ordinal admission and read overlap, so a ready map can still fail to commit. See Map for failure and finalization rules.

Parameters:
Return type:

Map

query(filter=None, attrs=None)#

Enqueue a filter query. attrs scopes attribute discovery (tokens).

Parameters:
Return type:

Query

query_from_path_list(path_list)#

Create a query handle from an interned prim path list (synchronous).

The handle wraps a caller-owned list (see query_from_path_list in ovstage_api.h), so keep your list alive for as long as the query and release it when you are done:

with paths.create_path_list_from_strings(paths_) as plist:
    with stage.query_from_path_list(plist) as query:
        ...

When given a PathList, the returned Query holds a reference to it, so the list cannot be finalized while the query is live. That is a safety net, not a transfer of ownership: releasing the query does not release your list. Passing a freshly created list inline — stage.query_from_path_list(paths.create_path_list_from_strings(...)) — leaves no handle to release, so the list is eventually reclaimed by PathList.__del__() with a ResourceWarning. Bind it.

Parameters:

path_list (int)

Return type:

Query

read_attributes(query, attrs, ordinal_range, *, placement=None)#

Enqueue a multi-attribute read; iterate groups with Read.groups().

placement selects which of an attribute’s copies the returned groups point at, so the payload DLTensors report that device and a CUDA read yields pointers a kernel can consume without a host round-trip. None is the host, and is byte-for-byte the unplaced call.

Unlike a placed write or map, a placed read is permissive: a column that is not current on placement.device_type/device_id is made available there rather than the read failing. Zero-copy survives where it is available – a column already current on that device is pointed at directly and nothing is transferred. A column materialized onto the device lives in storage the group owns and is freed with Stage.release_group().

placement.availability_event is what makes a transferring read asynchronous, and it changes when the payload may be touched. Without one the transfer is drained before the operation completes, so the data is ready as soon as Read.fetch_next() hands the group over – the behaviour an unplaced read already has. With one, the pointers in the returned groups are not safe to dereference until the caller has waited on that event (or has enqueued their own work on placement.stream behind it). Wait once Read.fetch_next() has returned a group: the event is recorded before any group is handed back, and a wait issued earlier may observe an old or unrecorded event. The read operation completes before the event fires, by design: the event marks when the column is available to dereference, not when this op finished, and what it waits out can include device work the caller never issued – a write still in flight ahead of the read. A read served without a transfer records the event too, so a caller never has to know which case they got, and a wait on it never hangs.

Parameters:
Return type:

Read

release_group(group)#

Release a read group’s pinned storage.

A group released twice would free storage the instance has already reclaimed, so a ReadGroup raises instead — this is what keeps an explicit release plus a later finalizer from double-releasing.

Release state is tracked on every ReadGroup, including one a caller constructed themselves (no owning stage). Such a group has no finalizer, but it still needs the flag: without it a second release_group would reach the C API, and ReadGroup.tensor() / ReadGroup.prim_index() would keep reading storage that has been handed back.

Parameters:

group (ReadGroup)

Return type:

None

release_hierarchy(hierarchy)#
Return type:

Operation

release_op(op_id)#

Release op tracking state; returns the raw ovstage_api_status_t.

Parameters:

op_id (int)

Return type:

int

release_ordinal_query(ordinal_query)#
Return type:

Operation

release_query(query)#
Return type:

Operation

release_read(read)#
Return type:

Operation

unmap_attribute(mapping, cuda_event=None, cuda_stream=None)#

Enqueue remaining commits and release the map handle.

An accepted finalization consumes the handle even if execution fails. If all groups committed earlier, it only releases the session, without reapplying changes or repeating commit admission checks. If an accepted group commit failed, it releases the session and reports the retained failure without committing remaining data; a group commit that failed only because its availability_event could not be recorded is not such a failure (see unmap_group()). An otherwise successful finalization whose own event cannot be recorded fails with OP_FAILED after committing the remaining groups, whose changes stay recorded.

Unplaced maps use CPU storage: leave cuda_event / cuda_stream unset for those maps. A CPU commit with payload rejects a non-zero value as an accepted, terminal failure. For CUDA-placed maps, these arguments supply the source handoff before the commit reads mapped values. A cleanup-only final unmap – every group already committed – does not inspect the handoff.

Parameters:
  • cuda_event (int | None)

  • cuda_stream (int | None)

Return type:

Operation

unmap_group(mapping, group, cuda_event=None, cuda_stream=None)#

Enqueue a group commit; its changes take effect once on success.

An accepted commit that fails makes the session terminal. Finalize it with unmap_attribute(); retry requires a new session. Previously committed groups remain committed. See Map for failure rules. The exception is a session mapped with a Placement carrying an availability_event: an otherwise successful commit whose event CUDA refuses to record fails with OP_FAILED after committing, its changes stay recorded, and the session stays open, so later commits and final unmap proceed as usual.

Unplaced maps use CPU storage: leave cuda_event / cuda_stream unset for those maps. A CPU commit with payload rejects a non-zero value as an accepted, terminal failure. For CUDA-placed maps, these arguments supply the source handoff before the commit reads mapped values. A cleanup-only final unmap – every group already committed – does not inspect the handoff.

Parameters:
Return type:

Operation

wait_op(op_id, timeout=18446744073709551615)#

Low-level wait: returns (code, error_op_ids, lowest_pending_op_id).

Does not release the op. Lets callers inspect the wait result struct directly (e.g. timeout’s lowest_pending_op_id or a failed producer’s error_op_ids).

Parameters:
wait_op_raw(op_id, timeout=18446744073709551615)#

Wait without raising or releasing; returns the raw ovstage_api_status_t.

Parameters:
Return type:

int

write_attribute(
query,
attribute,
ordinal,
tensors,
*,
is_array,
prim_mode=PrimMode.UPSERT,
semantic=0,
attribute_mode=AttributeMode.REJECT,
index_map=None,
mask=None,
count=None,
cuda_event=None,
cuda_stream=None,
placement=None,
)#

Enqueue a copy-in write.

is_array explicitly declares the logical attribute kind and is never inferred from tensor count, tensor shape, payload width, attribute name, semantic, or existing storage. tensors is a numpy array / DLTensor, or a list thereof (one per source row for array attributes). Caller-owned tensors are kept alive on the returned Operation until wait() – which is long enough only while wait() implies the device work drained. A placement carrying an availability_event can leave that work running past it; see Placement for what the caller must then hold a reference to.

Writing a different schema to an existing prim/name fails unless attribute_mode is AttributeMode.FORCE. Then a target prim whose existing schema differs has it replaced. A NONE semantic keeps the existing role on a prim whose storage is unchanged; on a prim whose storage is replaced the written schema has no role. The replacement is admitted once at ordinal and recorded there as the end of the previous schema on the replaced prims together with the written value; it is rejected while a replaced prim has an outstanding read or the attribute an overlapping map, leaving the previous schema in place. A write that fails after the previous schema has ended on a prim leaves that end recorded at ordinal and the prim without a value; a corrected retry for that prim needs a later ordinal. Other prims keep their schema, and reserved metadata attributes accept only AttributeMode.REJECT. A change-range read that includes ordinal returns, for each replaced prim, a tombstone group for the previous schema and a value group in the written schema, in unspecified order; a latest read returns only the written schema.

Aliases of one stored column share ordinal admission, change tracking, and overlap checks on intersecting prim paths. The ordinal must exceed applicable write floors. With the OrdinalAdmissionPolicy.STRICTLY_INCREASING, it must also be newer than retained committed changes to each affected cell and applicable prim lifecycle. NONDECREASING allows equal unsealed ordinals but rejects older intersecting history; FLOOR_ONLY skips retained-history and separate prim-lifecycle admission. Disjoint cells may share an ordinal. These policy choices also apply to map commits, clone and delete, each with its own applicable floors and lifecycle targets. Execution checks ordinal admission before changing stage data. Call wait() on the returned operation to observe admission and completion errors; enqueue acceptance or dropping the operation does not establish success.

Fixed-size writes (is_array=False) are normalized internally. Raw reads return scalar-lane tensors with type-aware component axes (for example, (N, 3) for points and (N, 4, 4) for matrices); maps expose the same typed shapes. Logical prims select rows directly or through the group’s data index map. The exact input shape is not retained. Without an index map, the leading dimension must equal the logical element count; a flat (N * L,) array is not inferred as N rows of width L. This normalization does not describe array/ragged attributes.

Array element types are never inferred from tensor shape. If a non-NumPy DLPack producer exposes a vector element as a trailing component axis (for example Warp vec3f as (N, 3), lanes=1), first call make_dltensor() with the explicit lane dtype. That helper permits only a validated, compact trailing-axis fold, so point3f[] can remain zero-copy without ambiguously reinterpreting scalar arrays.

Reserved metadata uses the same contract: usd-prim-type requires is_array=False; usd-schemas and usd-ancestor-types require is_array=True. None is implicitly broadcast; use index_map when target rows intentionally share source data.

count is the number of logical elements the write addresses — the leading count prims of the query, in query order. With neither index_map nor mask it defaults to the query’s prim count. When given it must be positive: 0 is the C contract’s spelling of “the whole query”, so passing it — including as len() of an empty selection — raises ValueError rather than writing nothing. index_map and mask are mutually exclusive and both refine that logical element axis:

  • index_map[i] is the source row logical element i reads from, not the prim being written. Use it to gather, reorder, or broadcast rows (index_map=[0, 0] writes one source row to two prims). Every entry must be less than the transported row count, which for a fixed-size write is shape[0]. The map holds one entry per logical element, so count defaults to len(index_map) and may not exceed it — to address more of the query, lengthen the map rather than raising count.

  • mask is a bitmask over the same logical element axis selecting which prims are written; unselected prims are left untouched. It has no default count: supply one, along with enough 64-bit words to cover it (ceil(count / 64)).

To write a subset of a query’s prims, use mask; index_map selects source data, not targets.

All three carry the width of the C fields behind them: count and every index_map entry must fit in uint32 and each mask word in uint64. An out-of-range value raises ValueError rather than wrapping into the field — count=2**32 is rejected, not silently turned into the whole-query 0.

semantic is the AttributeSemantic (or raw ovstage_attribute_semantic_t value) carried on the write. Geometric semantics (POINT/VECTOR/NORMAL/COLOR/QUATERNION/MATRIX/FRAME/TEXTURE_COORDINATE) and TIME_CODE record a role on the column; ID semantics select the corresponding ID storage type and require pre-interned id payloads (TOKEN_ID / RELATIONSHIP_PATH_ID use dtype = (kDLUInt, 64, 1), CONNECTION_PATH_ID uses dtype = (kDLUInt, 64, 2)). 0 (NONE) writes the payload without stamping a role / base type on the column.

Like write_attributes(), this operation is not transactional. A successfully applied entry commits its values, any new prims or attributes, and their change records at the submitted ordinal. A failed entry is not recorded as a completed write, although changes made before the failure can remain visible to a HAS query. Because this operation has only one entry, a failed application leaves the submitted ordinal available; a corrected same-ordinal retry remains admissible subject to current stage state. The exception is a AttributeMode.FORCE write that ended a prim’s previous schema before failing: that end stays recorded, so a retry for that prim needs a later ordinal. INSERT treats a prim left by a failed write as an existing target and can reject it with ErrorCode.PRIM_NOT_FOUND; UPSERT can repair it. Recoverable allocation and size failures follow the normal OvstageError path. Only failure to record an already-applied entry’s prim, attribute and ordinal changes terminates the process; Python cannot catch that as an exception.

Parameters:
Return type:

Operation

write_attributes(
query,
writes,
ordinal,
*,
prim_mode=PrimMode.UPSERT,
placement=None,
)#

Enqueue one copy-in operation for multiple attribute columns.

Every write undergoes common preflight before the operation is queued. Native preflight failures, including known write-floor violations, are recorded in the returned operation’s status and raised by wait(). Python argument validation raises immediately. Successful enqueue can still be followed by ordinal-admission failure, also reported by wait(). Admission follows the policy described by write_attribute() and is checked for the complete batch before any entry changes stage data. The returned operation owns all ctypes/tensor keepalives until wait(). Each fixed-size entry follows the same read/map normalization as write_attribute().

Compatible aliases of one stored column may appear together only when their selected prim coverage is disjoint.

The operation is not transactional. If a later entry fails, wait() reports failure for the operation, while entries whose application completed successfully remain committed, including any new prims or attributes and their change records at the submitted ordinal. The failed entry is not recorded as a completed write, although changes made before the failure can remain visible to a HAS query. Preparing storage alone does not count as a completed write or record changes at the submitted ordinal. Reserved metadata may complete before ordinary attribute values; it remains committed if a later entry fails.

The API exposes no per-entry completion mask, so repair a whole batch that may have completed an entry with a newer ordinal: the STRICTLY_INCREASING policy rejects rewriting completed entries at their recorded ordinal. If no entry completed, including when the sole entry of a one-entry call did not complete, the ordinal remains available and a corrected same-ordinal retry remains admissible subject to current stage state, except for a prim whose previous schema an AttributeMode.FORCE entry ended before the failure: that end stays recorded, so its retry needs a later ordinal. Recoverable allocation or size failures follow the normal OvstageError path while the stage and its ordinal change records can remain consistent with completed entries.

A failed write can leave a prim visible to queries without recording its creation at the submitted ordinal. INSERT treats that prim as an existing target and rejects it with ErrorCode.PRIM_NOT_FOUND. A later successful UPSERT commits its attribute changes and their ordinal records but does not record a prim-creation event for that already-present prim.

Only failure to record an already-applied entry’s prim, attribute and ordinal changes terminates the process; Python cannot catch that as an exception.

Parameters:
Return type:

Operation

class StageConfig#

Process configuration applied when creating a Stage.

The configuration is process-scoped. Configured stages may coexist when their concrete settings match; creating a stage with a conflicting setting while another stage is live raises OvstageError.

__init__(
runtime_default_hierarchy_computation_model=None,
runtime_default_ordinal_admission_policy=None,
)#
Parameters:
Return type:

None

runtime_default_hierarchy_computation_model: HierarchyComputationModel | None = None#
runtime_default_ordinal_admission_policy: OrdinalAdmissionPolicy | None = None#
class PathDictionary#

Access a Stage’s interning dictionary for tokens, paths, and path lists.

stage is required. The wrapper borrows its dictionary; destroying this wrapper does not destroy the Stage. List references never extend Stage life.

__init__(stage)#
add_path_list_reference(path_list)#

Increment a path list’s refcount (pair with destroy_path_list()).

The added reference is yours alone: dropping the PathList never revokes it, because the finalizer reclaims only the reference create_path_list* minted. The path-dictionary contract sanctions holding a bare handle beyond the object you added it through — release it with a matching destroy_path_list().

The count is still recorded, so a later destroy_path_list through a plain int is attributed to one of these references rather than silently consuming the owner’s claim.

Parameters:

path_list (int)

Return type:

None

create_path_list(primpaths)#

Build a path list from interned prim paths, owning one reference.

The returned PathList is the handle (an int subclass) and releases that reference on with-exit, PathList.release(), or destroy_path_list().

Parameters:

primpaths (Sequence[int])

Return type:

PathList

create_path_list_from_strings(paths)#

Build a path list from path strings, owning one reference.

See create_path_list() for the returned handle’s lifetime.

Parameters:

paths (Sequence[str])

Return type:

PathList

destroy()#
Return type:

None

destroy_path_list(path_list)#

Release one reference on a path list (erases it at refcount zero).

Which reference this drops is attributed as follows, because the C API counts references without distinguishing them:

  • passing the PathList releases its reference, clearing the owner flag so the finalizer will not release it a second time;

  • passing a plain int releases one you added with add_path_list_reference() when any are outstanding, and only falls through to the owner’s reference when none are. Otherwise releasing an added reference through the handle would steal the owner’s claim and strand the create reference for good.

Ownership is keyed by handle on the Stage, so this holds whether the call goes through the PathList, a plain int copy of the handle, or a different PathDictionary wrapper over the same stage. A handle no wrapper minted — a borrowed list from a read result, or one already fully released — is untracked and passes straight through to the C API, exactly as before.

Parameters:

path_list (int)

Return type:

None

get_path_strings(path_list)#
Parameters:

path_list (int)

Return type:

List[str]

get_paths(path_list)#
Parameters:

path_list (int)

Return type:

List[int]

intern_path(path)#

Intern a prim-path string and return its dictionary-lifetime handle.

An absolute path yields the same handle as construction from its component tokens through the C API in the same dictionary. Use "/" for the root, which corresponds to zero component tokens in C.

Parameters:

path (str)

Return type:

int

intern_token(string)#
Parameters:

string (str)

Return type:

int

path_list_count(path_list)#
Parameters:

path_list (int)

Return type:

int

path_to_string(primpath)#

Resolve a prim-path handle to its path string.

Raises OvxError if the handle is invalid, unknown, or expired. The absolute root resolves to "/", matching SdfPath; a valid handle never resolves to the empty string, so "" is exclusively the shape no successful decode produces.

Parameters:

primpath (int)

Return type:

str

token_to_string(token)#
Parameters:

token (int)

Return type:

str

class PathList#

One owned reference to an interned path list (ovx_primpath_list_t).

This is the handle — it subclasses int, so it passes into Stage.query_from_path_list(), PathDictionary.path_list_count(), and every other slot that takes a path list unchanged, and isinstance(handle, int) still holds.

What it adds is lifetime management. Path lists are refcounted C-side, and dropping a bare int does not decrement that refcount — the reference leaks for the life of the dictionary. Use it as a context manager so the reference is released even when an error interrupts processing:

with paths.create_path_list_from_strings(["/World/A"]) as plist:
    stage.write_attribute(query, attr, ordinal=0, tensors=data).wait()
# the create reference is released on block exit

Explicit release() (or PathDictionary.destroy_path_list()) is equally fine. If that reference is still outstanding when the object is garbage-collected, __del__() releases it and emits a ResourceWarning; treat that as a bug report, not a strategy — in a per-frame loop, create the list once outside the loop and reuse it.

It owns exactly one reference: the one create_path_list* minted. Anything added later with PathDictionary.add_path_list_reference() is yours to release, and dropping this object never revokes it.

A query built by Stage.query_from_path_list() wraps a caller-owned list, so keep this object alive for as long as that query. The returned Query holds a reference so the list cannot be finalized under a live query, but releasing the query does not release your list — bind it and release it yourself rather than passing a freshly created list inline, which leaves nothing to release and ends in the warning above.

Only create_path_list* mints a PathList. Borrowed lists handed back by read groups and query results stay plain int, because the caller does not own a reference on them and must not release one.

Ownership is tracked by handle on the backing Stage — not by object identity, and not per wrapper — so releasing through a plain int copy of the handle (see __copy__()) or through a different PathDictionary over the same stage still clears this object’s claim.

That bookkeeping is unsynchronized, like the rest of the binding’s handle state: releasing one handle from two threads at once can desync it. The C dictionary’s interning is thread-safe, but these Python-side release decisions are not — own a given handle from one thread.

The finalizer stays silent only once the C dictionary itself is gone — that is, when the Stage backing it was destroyed. Closing a PathDictionary(stage) wrapper leaves the dictionary alive while the Stage lives, so an outstanding list is still reclaimed and reported.

static __new__(cls, path_list, dictionary, owner)#
Parameters:
Return type:

PathList

release()#

Release this object’s reference (see PathDictionary.destroy_path_list()).

Return type:

None

property released: bool#

Whether the reference this object owns has been released.

Queries, Reads, and Maps#

class Query#
__init__(stage, handle, op)#
Parameters:
release()#
Return type:

Operation

result(timeout=18446744073709551615)#

Fetch (and release) the query result.

Parameters:

timeout (int) – max nanoseconds to wait for the result; TIMEOUT_INFINITE (default) blocks, 0 polls.

Raises:
  • TypeError – if timeout is not an integer (e.g. None).

  • ValueError – if timeout is negative or does not fit in uint64.

Return type:

QueryResult

wait(timeout=18446744073709551615)#

Wait on the reserving op and return this handle.

Returning the handle lets the follow-on call chain — group = read.wait().fetch_next() — inside the handle’s with block (chaining on the temporary drops the handle unreleased). Waiting is also what releases the reserving op, so it is not redundant with the fetch’s own wait. A synchronously-created handle has no reserving op: the call is a no-op that still returns the handle. See Operation.wait() for the timeout and error contract.

Parameters:
  • self (_HandleT)

  • timeout (int)

Return type:

_HandleT

class OrdinalQuery#
__init__(stage, handle, op)#
Parameters:
fetch(timeout=18446744073709551615)#

Fetch the queried ordinal value.

Parameters:

timeout (int) – max nanoseconds to wait for the value; TIMEOUT_INFINITE (default) blocks, 0 polls.

Raises:
  • TypeError – if timeout is not an integer (e.g. None).

  • ValueError – if timeout is negative or does not fit in uint64.

Return type:

int

release()#
Return type:

Operation

wait(timeout=18446744073709551615)#

Wait on the reserving op and return this handle.

Returning the handle lets the follow-on call chain — group = read.wait().fetch_next() — inside the handle’s with block (chaining on the temporary drops the handle unreleased). Waiting is also what releases the reserving op, so it is not redundant with the fetch’s own wait. A synchronously-created handle has no reserving op: the call is a no-op that still returns the handle. See Operation.wait() for the timeout and error contract.

Parameters:
  • self (_HandleT)

  • timeout (int)

Return type:

_HandleT

class Read#
__init__(stage, handle, op)#
Parameters:
fetch_next(timeout=18446744073709551615)#

Fetch the next read group, or None at end of iteration.

Parameters:

timeout (int) – max nanoseconds to wait for the next group; TIMEOUT_INFINITE (default) blocks, 0 polls.

Raises:
  • TypeError – if timeout is not an integer (e.g. None).

  • ValueError – if timeout is negative or does not fit in uint64.

  • OvstageError – with ErrorCode.TIMEOUT if no group is ready in time.

Return type:

ReadGroup | None

groups(timeout=18446744073709551615)#

Generator over read groups. The caller must release each group.

Parameters:

timeout (int)

release()#
Return type:

Operation

wait(timeout=18446744073709551615)#

Wait on the reserving op and return this handle.

Returning the handle lets the follow-on call chain — group = read.wait().fetch_next() — inside the handle’s with block (chaining on the temporary drops the handle unreleased). Waiting is also what releases the reserving op, so it is not redundant with the fetch’s own wait. A synchronously-created handle has no reserving op: the call is a no-op that still returns the handle. See Operation.wait() for the timeout and error contract.

Parameters:
  • self (_HandleT)

  • timeout (int)

Return type:

_HandleT

class Map#

A reserved map session for writing an attribute.

Reserve via Stage.map_attribute(), iterate writable groups with groups() / fetch_next(), fill each group, and commit it with unmap_group(). Finalize with unmap(), which commits any remaining groups and releases the handle.

Setup only prepares writable staging buffers; Stage.map_attribute() describes the effects deferred until successful commit. An outstanding map blocks overlapping operations on the same canonical attribute and prims. Commit rechecks admission against current state, so successful setup does not guarantee a successful commit.

Fetched groups retain this session, preventing garbage collection from finalizing it while a group is still in use. Accepted group or final unmap submissions invalidate the affected groups immediately. Previously exported arrays and DLPack views must no longer be accessed after submission.

Each successful group commits its values, any prim or attribute creation, schema or hierarchy changes, and ordinal change records once. A failed group does not record these as completed changes and does not undo groups committed earlier. Map commits are not transactional: a failed commit may have changed some or all stored rows, and those changes can remain observable. No rollback or atomicity is guaranteed.

An accepted group commit that fails during execution makes the session terminal. Its groups cannot be retried. Final unmap() releases the session and reports the retained failure without committing remaining data. Recovery requires a new session or another write operation. The exception is a commit that fails only because a placement’s availability_event could not be recorded: it has committed, and the session stays open (see Stage.unmap_group()). If all groups committed successfully, final unmap only releases the session; it neither reapplies changes nor repeats commit admission checks. An accepted final unmap consumes the handle even when execution fails. To finalize on exit, use the session as a context manager:

with stage.map_attribute(query, attr, ordinal=o) as m:
    for mg in m.wait().groups():
        fill(mg)
        m.unmap_group(mg).wait()

Leaving the with block — normally or via an exception — calls unmap(). The C API has no cancel: for a session without a prior accepted commit failure, final unmap attempts to commit whatever the remaining buffers hold. An exception mid-fill can therefore commit partially filled buffers if finalization succeeds. If a session is dropped without unmapping, __del__() issues a best-effort unmap and a ResourceWarning; it does not wait for or report asynchronous commit failures. Normal context-manager exit waits and reports errors; explicit unmap().wait() also observes completion.

__init__(stage, handle, op)#
Parameters:
fetch_next(timeout=18446744073709551615)#

Fetch the next writable map group, or None at end of iteration.

Parameters:

timeout (int) – max nanoseconds to wait for the next group; TIMEOUT_INFINITE (default) blocks, 0 polls.

Raises:
  • TypeError – if timeout is not an integer (e.g. None).

  • ValueError – if timeout is negative or does not fit in uint64.

  • OvstageError – with ErrorCode.TIMEOUT if no group is ready in time.

Return type:

MapGroup | None

groups(timeout=18446744073709551615)#
Parameters:

timeout (int)

unmap(cuda_event=None, cuda_stream=None)#

Commit remaining groups and release the map handle (see class docstring).

Parameters:
  • cuda_event (int | None)

  • cuda_stream (int | None)

Return type:

Operation

unmap_group(group, cuda_event=None, cuda_stream=None)#
Parameters:
Return type:

Operation

wait(timeout=18446744073709551615)#

Wait on the reserving op and return this handle.

Returning the handle lets the follow-on call chain — group = read.wait().fetch_next() — inside the handle’s with block (chaining on the temporary drops the handle unreleased). Waiting is also what releases the reserving op, so it is not redundant with the fetch’s own wait. A synchronously-created handle has no reserving op: the call is a no-op that still returns the handle. See Operation.wait() for the timeout and error contract.

Parameters:
  • self (_HandleT)

  • timeout (int)

Return type:

_HandleT

class Operation#

A handle to an enqueued (asynchronous) ovstage operation.

status is the enqueue status (OVSTAGE_OK = accepted); op_id is the per-op identifier. Call wait() to block until the op (and its ordinal-keyed dependencies) completes; it returns the operation itself on success and raises OvstageError if it failed. This is the data-plane operation; ovstage.population.Operation is a separate class whose wait() returns the operation’s payload.

__init__(stage, status, op_id, keepalive=None)#
Parameters:
error_message()#
Return type:

str

property ok: bool#
wait(timeout=18446744073709551615)#

Wait for completion and release the op; returns self. Raises on failure.

Mirrors the C++ waitOk helper: if the enqueue was rejected, or the op or its dependencies failed, raises OvstageError.

On success the operation itself is returned so a wait can be chained into its follow-on call; the op is consumed, and a second wait() raises INVALID_HANDLE. A finite timeout that elapses raises OvstageError with ErrorCode.TIMEOUT and leaves the op waitable, keeping the references that pin its input buffers.

Parameters:

timeout (int) – max nanoseconds to wait; TIMEOUT_INFINITE (default) blocks, 0 polls.

Returns:

this operation (consumed).

Raises:
  • TypeError – if timeout is not an integer (e.g. None).

  • ValueError – if timeout is negative or does not fit in uint64.

  • OvstageError – if the enqueue was rejected, the op was already waited, the op (or a dependency) failed, or timeout elapsed.

Return type:

Operation

class CloneOperation#

The Operation returned by Stage.clone_async(), plus its completion report.

wait() behaves exactly like Operation.wait() (and returns this operation); it additionally captures the clone’s completion report before the op is released, so result() can return it afterwards:

report = stage.clone_async(src, targets, ordinal).wait().result()
print(report.prims_cloned)
__init__(stage, status, op_id, keepalive=None)#
Parameters:
result(timeout=18446744073709551615)#

Return the clone’s completion report, waiting for the clone if needed.

Parameters:

timeout (int) – max nanoseconds to wait when the clone is still pending; TIMEOUT_INFINITE (default) blocks, 0 polls. Ignored once the report is cached.

Raises:

OvstageError – with ErrorCode.TIMEOUT if the clone has not completed in time (it stays waitable), or with the failure the clone reported — the same error wait() raised, raised again.

Return type:

CloneResult

wait(timeout=18446744073709551615)#

Wait for completion and release the op; returns self. Raises on failure.

Mirrors the C++ waitOk helper: if the enqueue was rejected, or the op or its dependencies failed, raises OvstageError.

On success the operation itself is returned so a wait can be chained into its follow-on call; the op is consumed, and a second wait() raises INVALID_HANDLE. A finite timeout that elapses raises OvstageError with ErrorCode.TIMEOUT and leaves the op waitable, keeping the references that pin its input buffers.

Parameters:

timeout (int) – max nanoseconds to wait; TIMEOUT_INFINITE (default) blocks, 0 polls.

Returns:

this operation (consumed).

Raises:
  • TypeError – if timeout is not an integer (e.g. None).

  • ValueError – if timeout is negative or does not fit in uint64.

  • OvstageError – if the enqueue was rejected, the op was already waited, the op (or a dependency) failed, or timeout elapsed.

Return type:

CloneOperation

class Hierarchy#
__init__(stage, handle, op)#
Parameters:
release()#
Return type:

Operation

result()#
Return type:

HierarchyResult

wait(timeout=18446744073709551615)#

Wait on the reserving op and return this handle.

Returning the handle lets the follow-on call chain — group = read.wait().fetch_next() — inside the handle’s with block (chaining on the temporary drops the handle unreleased). Waiting is also what releases the reserving op, so it is not redundant with the fetch’s own wait. A synchronously-created handle has no reserving op: the call is a no-op that still returns the handle. See Operation.wait() for the timeout and error contract.

Parameters:
  • self (_HandleT)

  • timeout (int)

Return type:

_HandleT

Instancing Queries#

available()#

Return whether the loaded libovstage exports all instancing queries.

Return type:

bool

get_prototype_roots(stage)#

Return every scene-graph-instancing prototype-root path in stage.

Return type:

list[str]

get_prototype_root(stage, instance_root)#

Return the prototype-root path referenced by instance_root.

Raises:

OvstageError – If instance_root is not an instance root or the native query otherwise fails.

Parameters:

instance_root (str)

Return type:

str

get_instance_roots(stage, prototype_root)#

Return the instance-root paths that reference prototype_root.

Parameters:

prototype_root (str)

Return type:

list[str]

Data and Result Types#

class WriteDesc#

Python-facing form of one native ovstage_attribute_write_t.

Each instance supplies one named attribute write to Stage.write_attributes().

is_array is required and explicitly declares the logical attribute kind; it is never inferred from tensors. tensors accepts the same numpy/DLTensor forms as Stage.write_attribute(). Sparsity and CUDA synchronization are write-local, as are semantic and attribute_mode; the ordinal and prim mode are shared by the batch. Fixed-size convenience shapes are normalized to one source-data-row dimension with the tuple width in dtype.lanes; their trailing dimensions are not preserved.

count, index_map, and mask carry the same bounds as Stage.write_attribute().

__init__(
attribute,
tensors,
is_array,
index_map=None,
mask=None,
count=None,
cuda_event=None,
cuda_stream=None,
semantic=AttributeSemantic.NONE,
attribute_mode=AttributeMode.REJECT,
)#
Parameters:
Return type:

None

attribute_mode: AttributeMode = 0#
count: int | None = None#
cuda_event: int | None = None#
cuda_stream: int | None = None#
index_map: Sequence[int] | None = None#
mask: Sequence[int] | None = None#
semantic: AttributeSemantic = 0#
attribute: int | str#
tensors: Any#
is_array: bool#
class OrdinalRange#

Ordinal range for reads.

  • OrdinalRange.latest(N) requests a snapshot at N for all queried paths. The name is historical: N bounds the snapshot, so latest(N) does not return values written after N.

  • OrdinalRange.between(start, end) selects queried attribute/path pairs with recorded changes in [start, end], including both ends.

This build stores only the current values. For each attribute, an unsealed selected change at or before the end raises WRITE_FLOOR_VIOLATION. Otherwise, a recorded change after the end on a selected path raises OUT_OF_RANGE, whether that later change is sealed or not. Reads stop at the first attribute that fails either check.

Use (1 << 64) - 1 as the end to request current values. That skips the later-change check, but a selected unsealed change still raises WRITE_FLOOR_VIOLATION. These checks use recorded change history. Snapshot reads of values without such history, including derived attributes such as usd-path, return current state. Queries select current paths, not the paths present at an earlier ordinal.

While the end is above the attribute’s write floor (Stage.get_attribute_write_floor()), changes between the floor and the end can still be admitted and, once sealed, change what the same request returns. Once the end is at or below the floor, later writes, deletes and maps cannot change the recorded values that a successful read of the same request returns for paths the query still selects. This does not cover derived attributes or query membership, which reflect current state, changes that compute_hierarchy records at or below the floor, or history below the retention frontier. Because a later change after the end makes a bounded read raise OUT_OF_RANGE, a bounded read is not a replay point.

Under OrdinalAdmissionPolicy.FLOOR_ONLY, a write or delete above the applicable floors can be admitted even when the same attribute and path already has a change at a higher ordinal. STRICTLY_INCREASING and the default NONDECREASING policy reject such older changes against retained history. Under FLOOR_ONLY, reads return the most recently applied change, and a read whose end covers both changes can succeed with it.

Query the retention frontier with Stage.get_oldest_preserved_ordinal() before relying on an old snapshot or interval. Below that frontier, history may have been discarded, so success does not guarantee the earlier state. For example, a snapshot from before an attribute deletion may return no row for that attribute once its deletion history has been discarded.

__init__(end_ordinal, start_ordinal=None)#
Parameters:
  • end_ordinal (int)

  • start_ordinal (int | None)

Return type:

None

classmethod between(start_ordinal, end_ordinal)#
Parameters:
  • start_ordinal (int)

  • end_ordinal (int)

Return type:

OrdinalRange

classmethod latest(end_ordinal)#

Snapshot at end_ordinal for all queried paths.

Despite the name, this does not return values written after end_ordinal; pass (1 << 64) - 1 for current values. See OrdinalRange.

Parameters:

end_ordinal (int)

Return type:

OrdinalRange

start_ordinal: int | None = None#
to_c()#
Return type:

ovstage_ordinal_range_t

end_ordinal: int#
class Predicate#

A single filter predicate. attribute may be an int token or a string.

__init__(attribute, op, values=<factory>)#
Parameters:
Return type:

None

attribute: int | str#
op: FilterOp#
values: Sequence[str]#
class Filter#

Conjunction (AND) of predicates. None filter = match all prims.

__init__(predicates)#
Parameters:

predicates (Sequence[Predicate])

to_c()#

Return (ovstage_filter_t, keepalive).

The keepalive list owns every ctypes buffer the filter struct points into (predicate array, attribute string refs, value-string arrays); the caller must keep it alive for the duration of the query enqueue call.

Return type:

Tuple[ovstage_filter_t, list]

class ReadGroup#

A read result group (ovstage_read_group_t).

Valid until released via Stage.release_group(). Exposes the attribute token, semantic, ordinal, delete flag, prim grouping, and tensor data.

A group’s pinned storage is an independent resource: it is reclaimed only by release_group. Releasing the owning Read does not reclaim it, so a dropped group stays pinned for the life of the Stage — and, because the pin also holds the group’s outstanding-read coverage, later writes to the same attribute and prims keep failing with an “overlapping outstanding read” error reported at the write site, far from the group that caused it.

Use it as a context manager so the group is released even when an error interrupts processing. fetch_next() returns None at end of iteration, so bind it before entering the block:

group = read.fetch_next()
if group is not None:
    with group:
        values = np.array(group.array(0))  # copy out to outlive the group

or iterate, which only yields real groups:

for group in read.groups():
    with group:
        ...

If a group is dropped without release, __del__() issues a best-effort release and emits a ResourceWarning; rely on the context manager (or an explicit Stage.release_group()) rather than the finalizer. Note the zero-copy views handed out by array() / tensor() point into that pinned storage and must not outlive the release.

__init__(raw, stage=None)#
array(index)#

Zero-copy shaped, read-only numpy view of tensor index (CPU only).

The view borrows this group’s storage and does not keep the group alive: it is valid only while the group is, and the group is released by Stage.release_group(), by with exit, or by the finalizer once the group becomes unreachable. Keep the group bound for as long as you read through the view, and copy out (np.array(...)) anything that must outlive it.

Parameters:

index (int)

property attribute: int#
property data_count: int#
data_row_index(local)#

Resolve the data-tensor row index of the local-th element.

Index-guarded before the range check, for the reason in prim_index().

Parameters:

local (int)

Return type:

int

dlpack(index, *, readonly=True)#

DLPack-protocol view of tensor index for zero-copy exchange with numpy / warp / torch / cupy: np.from_dlpack(group.dlpack(i)).

Unlike array() (CPU-only numpy), this also works for CUDA-resident tensors. The data is borrowed from ovstage and valid only until the owning group/result is released — copy it if it must outlive the read. The returned ManagedDLTensor retains the group, but a consumer view does not. Keep the group or returned producer alive while using a consumer view. Do not access either the producer or its views after releasing the group or an accepted group or final unmap submission; retaining the producer does not extend storage validity beyond those operations. Custom producers whose manager context owns the backing allocation have the same keepalive requirement (see ManagedDLTensor). Read and map shapes are exported as returned by the native API, including (N, 4, 4) for matrix4d.

Parameters:
Return type:

ManagedDLTensor

property has_data_index_map: bool#
property has_prim_index_map: bool#
property is_array: bool#

Whether this result group carries array-valued attribute rows.

property is_delete: bool#
property meta: AttributeMeta#
property ordinal: int#

Informational ordinal of this group.

It may be above or below the requested end and does not, by itself, prove which state the payload represents. See OrdinalRange.

property prim_count: int#
prim_index(local)#

Resolve the list-relative prim index of the local-th prim.

local is index-guarded before the range check, because the range check does not reject a fraction: 0 <= 1.5 < count is true. Without this, int(local) truncated, and the shipped row-placement idiom buffer[g.data_row_index(i)] = value[g.prim_index(i)] then wrote the wrong row – on a map that is committed stage state, not just a misread.

Parameters:

local (int)

Return type:

int

property prim_list: int#
property prim_offset: int#
release()#

Release this group’s pinned storage (see Stage.release_group()).

Return type:

None

property released: bool#

Whether this group’s pinned storage has been released.

property semantic: AttributeSemantic | int#

Authored interpretation of this attribute column’s bytes.

Known values are returned as AttributeSemantic. A value added by a newer native library is returned as its raw integer so callers can preserve it even when the installed Python enum does not yet name it.

tensor(index)#

Raw DLTensor at index (for shape/dtype/device checks).

Read and map tensors have scalar lanes and type-aware trailing dimensions. Use data_row_index() to resolve a logical group element through any data index map. The descriptor and data are borrowed; do not access them after releasing the group or an accepted group or final unmap submission.

Parameters:

index (int)

Return type:

DLTensor

property tensor_count: int#
class MapGroup#

A writable map group (ovstage_map_group_t).

Fill array(i) then commit via Stage.unmap_group() (or finalize the whole session with Stage.unmap_attribute()). The buffers borrow storage owned by the map session. A group fetched through a Map retains that session. Array and DLPack consumer views borrow the group: keep the group or its ManagedDLTensor alive while using them. After an accepted group or final unmap submission, do not access any previously obtained producer, raw tensor, or view; they do not check whether the storage is still valid. A synchronously rejected submission leaves the group usable. Filling a group alone does not change the stage.

__init__(raw, mapping=None)#
array(index)#

Zero-copy shaped, writable numpy view of tensor index (CPU only).

Use view.reshape(-1) when scalar buffer indexing is needed. The view borrows map storage until accepted group or final unmap.

Parameters:

index (int)

property data_count: int#
data_row_index(local)#

Resolve the data-tensor row index of the local-th element.

Index-guarded before the range check, for the reason in prim_index().

Parameters:

local (int)

Return type:

int

dlpack(index, *, readonly=False)#

Writable DLPack view of tensor index (a map group is writable).

Fill it in place — np.from_dlpack(group.dlpack(i))[:] = ... (numpy >= 2.1 honors the writable flag) — then commit via Stage.unmap_group() / Stage.unmap_attribute(). Unplaced maps return CPU buffers; the experimental placement argument can select CUDA buffers. Inspect the tensor’s device and use a compatible DLPack consumer. Finish device writes and provide the source handoff before committing; stop using the buffer once unmap submission is accepted. See Placement for commit availability events and buffer lifetimes.

Parameters:
Return type:

ManagedDLTensor

property has_data_index_map: bool#
property has_prim_index_map: bool#
property meta: AttributeMeta#
property prim_count: int#
prim_index(local)#

Resolve the list-relative prim index of the local-th prim.

local is index-guarded before the range check, because the range check does not reject a fraction: 0 <= 1.5 < count is true. Without this, int(local) truncated, and the shipped row-placement idiom buffer[g.data_row_index(i)] = value[g.prim_index(i)] then wrote the wrong row – on a map that is committed stage state, not just a misread.

Parameters:

local (int)

Return type:

int

property prim_list: int#
property prim_offset: int#
tensor(index)#

Raw DLTensor at index (for shape/dtype/device checks).

Read and map tensors have scalar lanes and type-aware trailing dimensions. Use data_row_index() to resolve a logical group element through any data index map. The descriptor and data are borrowed; do not access them after releasing the group or an accepted group or final unmap submission.

Parameters:

index (int)

Return type:

DLTensor

property tensor_count: int#
class AttributeMeta#

Read-only view of ovstage_attribute_meta_t.

attribute_write_floor_ordinal#
layout_generation#
__init__(raw)#
Parameters:

raw (ovstage_attribute_meta_t)

class QueryResult#

Snapshot of a fetched query result (copied out before release).

Owns no C-side resources: Stage.fetch_query_result() copies the scalar summary and the attribute tokens out, then releases the payload before returning. Nothing here needs to be freed.

__init__(attributes, total_prim_count, all_handle)#
Parameters:
Return type:

None

attributes: List[int]#
total_prim_count: int#
all_handle: int#
class CloneResult#

Completion report of a clone (ovstage_clone_result_t), copied out by value.

prims_cloned sums the sizes of the targets’ scene hierarchy subtrees after cloning, including each target root. It counts prims created or merged into and any prims already attached beneath them. A prim whose path lies beneath a target but remains detached from its scene hierarchy is not counted. For disjoint targets that merge into no existing prims, it equals source_prim_count * target_count. A zero-target clone reports prims_cloned == 0. Failure is not a field: a failed clone raises OvstageError from CloneOperation.wait() / CloneOperation.result().

__init__(
prims_cloned,
target_count,
source_prim_count,
ordinal,
)#
Parameters:
  • prims_cloned (int)

  • target_count (int)

  • source_prim_count (int)

  • ordinal (int)

Return type:

None

prims_cloned: int#
target_count: int#
source_prim_count: int#
ordinal: int#
class HierarchyItem#

Per-input hierarchy lookup result.

__init__(status, paths)#
Parameters:
Return type:

None

property ok: bool#
status: int#
paths: Tuple[str, ...]#
class HierarchyResult#

Copied hierarchy lookup result.

items preserves the input path-list order. Each item carries its own status so a missing input prim can be reported without failing the whole batch.

__init__(ordinal, items)#
Parameters:
Return type:

None

property input_count: int#
item_paths(index)#
Parameters:

index (int)

Return type:

Tuple[str, …]

ordinal: int#
items: List[HierarchyItem]#
class HierarchyComputationModelDesc#

Runtime-supported hierarchy computation model descriptor.

__init__(model_id, name, description)#
Parameters:
  • model_id (int)

  • name (str)

  • description (str)

Return type:

None

model_id: int#
name: str#
description: str#

Enums#

class ErrorCode#
__new__(value)#
OK = 0#
INVALID_ARGUMENT = 1#
INVALID_HANDLE = 2#
NOT_FOUND = 3#
PRIM_NOT_FOUND = 4#
WRITE_FLOOR_VIOLATION = 5#
NOT_SUPPORTED = 6#
QUEUE_FULL = 7#
END_OF_ITERATION = 8#
OUT_OF_MEMORY = 9#
LAYOUT_CHANGED = 10#
TIMEOUT = 11#
OP_FAILED = 12#
OUT_OF_RANGE = 13#
INTERNAL = 99#
class FilterOp#
__new__(value)#
HAS = 0#
IN = 1#
CONTAINS = 2#
PREFIX = 3#
LT = 4#
LE = 5#
GT = 6#
GE = 7#
class PrimMode#
__new__(value)#
UPSERT = 0#
INSERT = 1#
class AttributeMode#

What a write or map does when a target prim already has the attribute with a different schema (storage or a different non-NONE semantic).

  • REJECT → the write or map fails (default).

  • FORCE → the target prim’s schema is replaced by the written one.

See Stage.write_attribute() and Stage.map_attribute() for how a replacement is applied.

__new__(value)#
REJECT = 0#
FORCE = 1#
class AttributeSemantic#

Authored USD interpretation of a column’s bytes (ovstage_attribute_semantic_t).

Geometric semantics (POINT/VECTOR/NORMAL/COLOR/QUATERNION/MATRIX/FRAME/ TEXTURE_COORDINATE) record a geometric role on the column; storage stays in the requested numeric dtype.

TIME_CODE marks a time code – a unitless time value – again with storage in the requested numeric dtype. Only the plain numeric value is carried: sentinel time codes have no portable numeric encoding, so they are not representable.

ID semantics select the corresponding ID storage type and require pre-interned id payloads (producers must intern via the path dictionary / token dictionary before writing – ovstage does not stringify or resolve):

  • TOKEN_ID → dtype = (kDLUInt, 64, 1) carrying one 64-bit token id per row; id 0 is the empty token.

  • RELATIONSHIP_PATH_ID → dtype = (kDLUInt, 64, 1) carrying one 64-bit path id per element. is_array = True is a relationship’s target list; is_array = False holds exactly one path per row.

  • CONNECTION_PATH_ID → dtype = (kDLUInt, 64, 2) carrying one (path_id, token_id) pair per row (one 16-byte element per row).

  • ASSET_PATH_ID → dtype = (kDLUInt, 64, 2) carrying one (authored_token, resolved_token) pair per row (one 16-byte element per row).

An asset has two paths: the path as authored, and the path after resolution. ASSET_PATH_ID carries both as token ids. A token id of 0 means no path, so an unresolved asset has a resolved token id of 0.

PATH_EXPRESSION_STRING carries the expression text as one interned token id, (kDLUInt, 64, 1). is_array = False is a scalar pathExpression; True is pathExpression[], one id per element. Writes reject other layouts. A token id of 0 means no expression. ovstage does not evaluate the expression; it stores the id of the authored text.

STRING carries a plain USD string as raw UTF-8 bytes in a ragged (kDLUInt, 8, 1) byte array (is_array = True), not a token id. It records the USD-string role so the column uses the canonical USD-string representation.

The semantic round-trips through the attribute column: writes record it at creation, reads recover it by decoding the column.

__new__(value)#
NONE = 0#
ASSET_PATH_ID = 1#
TOKEN_ID = 2#
PATH_EXPRESSION_STRING = 3#
RELATIONSHIP_PATH_ID = 4#
POINT = 5#
VECTOR = 6#
NORMAL = 7#
COLOR = 8#
QUATERNION = 9#
MATRIX = 10#
TEXTURE_COORDINATE = 11#
CONNECTION_PATH_ID = 12#
STRING = 13#
TIME_CODE = 14#
FRAME = 15#
class Scope#

Write-floor advance scope (see Stage.advance_write_floor()).

  • ALL → advance the global write floor and every known attribute.

  • INCLUDE → advance only the listed attributes.

  • EXCLUDE → advance every known attribute except the listed ones (an empty list behaves like ALL).

__new__(value)#
ALL = 0#
INCLUDE = 1#
EXCLUDE = 2#
class PopulationDomain#
__new__(value)#
NONE = 0#
RENDERING = 1#
PHYSICS = 2#
ALL = 3#
class HierarchyRelation#
__new__(value)#
PARENT = 0#
CHILDREN = 1#
SIBLINGS = 2#
class OrdinalAdmissionPolicy#

Admission of mutations relative to committed changes in affected cells.

Every policy enforces applicable explicit floors. NONDECREASING additionally rejects older ordinals; STRICTLY_INCREASING also rejects equal ordinals. History comparisons apply to affected cells and prim lifecycles; disjoint cells may share an ordinal. DEFAULT inherits an active process policy, or selects NONDECREASING when acquiring the first process reference.

NONDECREASING remains the default. STRICTLY_INCREASING is experimental and represents the intended direction for a future default; FLOOR_ONLY is retained for backward compatibility.

__new__(value)#
DEFAULT = 0#
FLOOR_ONLY = 1#
NONDECREASING = 2#
STRICTLY_INCREASING = 3#
class HierarchyComputationModel#
__new__(value)#
INVALID = 0#
CPU_INCREMENTAL = 1#
GPU_INCREMENTAL = 2#
GPU_GLOBAL = 3#
RUNTIME_DEFAULT = 4#
DEFAULT_CPU = 1#
DEFAULT_GPU = 3#

Errors#

class OvstageError#

Raised when an ovstage call or enqueued op fails.

code is the raw ovstage_api_status_t; message is the human-readable detail from ovstage_get_last_op_error / ovstage_get_last_error when available.

__init__(code, message='')#
Parameters:
class OvxError#

Raised on a non-success ovx_api_result_t from a path-dictionary call.

__init__(code, message='')#
Parameters:

Logging#

set_log_callback(callback, severity=None, channel_filter=None)#

Install (or clear) a process-global log callback.

Routes ovstage’s log messages — and messages from its USD support layer — to callback(severity, timestamp, message), where severity is a LogSeverity, timestamp is wall-clock seconds since the epoch, and message is an owned str (a decoded copy that remains valid after the call returns).

Delivery is asynchronous on a dedicated dispatcher thread (created lazily on the first callback), so the callback never runs on the logging hot path and invocations are serialized. Use flush_log() to force pending messages through before a checkpoint.

Requires the runtime to be bootstrapped — hold a live Stage when calling this.

Note

An exception raised by callback has its traceback printed to stderr (so it is visible for debugging) and is then suppressed — it never unwinds into the C dispatcher. Do not emit ovstage/USD log messages from inside callback: they re-enter the dispatcher and can feed back indefinitely.

Parameters:
  • callback – f(severity, timestamp, message) callable, or None to flush pending messages and disable delivery.

  • severity – default LogSeverity threshold for channels not matched by channel_filter; messages below it are dropped. Defaults to WARNING.

  • channel_filter (str | None) – optional comma-separated <channel>=<level> list (e.g. "omni.ovstage=verbose"); None applies severity uniformly. Levels: verbose|debug|info|warn|warning|error|fatal|none.

Raises:

OvstageError – INVALID_ARGUMENT if the filter fails to parse, or OP_FAILED if the runtime is not bootstrapped.

Return type:

None

flush_log(timeout=18446744073709551615)#

Block until log messages emitted before this call have been delivered.

Point-in-time barrier: messages produced concurrently with or after the call are not guaranteed to be included. Returns immediately if no callback is installed (nothing is buffered).

Warning

With the default OVSTAGE_TIMEOUT_INFINITE this blocks until the dispatcher drains; a stuck callback makes it hang. Pass a finite timeout if the callback might block.

Parameters:

timeout (int) – max nanoseconds to wait; OVSTAGE_TIMEOUT_INFINITE blocks, 0 polls.

Returns:

True if drained (or no callback installed); False if not drained within timeout.

Raises:
  • TypeError – if timeout is not an integer (e.g. None).

  • ValueError – if timeout is negative or does not fit in uint64.

  • OvstageError – on any error other than a timeout.

Return type:

bool

class LogSeverity#

Log severity levels (mirrors ovstage_log_severity_t).

Values follow the underlying log-level ordering. NONE is a threshold sentinel: as a filter level it disables all logging and is never delivered to a callback.

__new__(value)#
VERBOSE = -2#
INFO = -1#
WARNING = 0#
ERROR = 1#
NONE = 3#

USD Schemas#

register_usd_schemas(paths)#

Register USD schema definitions with the USD runtime population reads through.

Population registers only what its USD build provides (the core Usd* schemas). Register any additional family your stages use, so population resolves each prim’s full schema-declared property set rather than only its authored properties.

Registering does not load schema code, so a family that ships a C++ library or Python module is usable for its definitions alone.

Warning

Call this before the first ovstage call that reads USD schema definitions – populating a stage and exporting one both do. A family registered after that contributes nothing and raises OvstageError. One registered after some other USD consumer in the process has read schemas cannot be detected and fails silently.

Registration is irreversible. Re-registering an already-registered family is a no-op, not an error.

Parameters:

paths – one path, or an iterable of paths. Each is either a USD plugin descriptor (plugInfo.json) or a directory containing one. A descriptor’s Includes are followed, so a single entry can bring in a whole tree of schema families. Symbolic links (and directory junctions on Windows) are followed, but a linked descriptor’s relative Root, ResourcePath and Includes resolve beside the link, not beside its target. Link the directory holding a descriptor, or link the descriptor together with the files it refers to; otherwise the call returns normally but the definitions those paths lead to never resolve.

Raises:

OvstageError – if a path names no readable descriptor, or the call came too late to take effect.

Return type:

None

Note

Only the paths themselves are checked. What a descriptor contains is USD’s to validate: a malformed one, or an Includes pattern matching nothing, raises a USD diagnostic, contributes no plugins, and still returns normally — surfacing later as schema properties that never resolve.

DLPack Tensor Interchange#

class DLTensor#

Plain C tensor object; does not manage memory.

byte_offset#

Structure/Union member

data#

Structure/Union member

device#

Structure/Union member

dtype#

Structure/Union member

classmethod from_dlpack(obj, stream=None)#

Build a DLTensor viewing any object implementing the DLPack protocol.

Accepts numpy / warp / torch / cupy / jax tensors (anything exposing __dlpack__) resident on CPU or CUDA and aliases their memory zero-copy, so a GPU producer’s device buffer can be handed straight to ovstage without a host round-trip. Shape and strides are deep-copied, while the consumed producer descriptor/deleter and source object are retained on the returned tensor so the aliased buffer remains valid until the returned tensor is destroyed. The caller must keep the returned tensor alive until the consuming op completes (Stage.write_attribute does this via the Operation keepalive).

stream is forwarded to a CUDA producer so it can synchronize the exporting stream against the consumer; it is ignored for CPU tensors and for producers that do not advertise __dlpack_device__.

Parameters:
  • obj (Any)

  • stream (int | None)

Return type:

DLTensor

ndim#

Structure/Union member

shape#

Structure/Union member

property shape_tuple: tuple#
strides#

Structure/Union member

class DLDataType#

Descriptor of the element data type of a DLTensor.

bits#

Structure/Union member

code#

Structure/Union member

lanes#

Structure/Union member

class DLDevice#

Device where DLTensor memory is allocated.

device_id#

Structure/Union member

device_type#

Structure/Union member

class DLDeviceType#

The enum encoding the type of device where DLTensor memory lives.

kDLCPU = 1#
kDLCUDA = 2#
kDLCUDAHost = 3#
kDLCUDAManaged = 13#
kDLExtDev = 12#
kDLHexagon = 16#
kDLMAIA = 17#
kDLMetal = 8#
kDLOneAPI = 14#
kDLOpenCL = 4#
kDLROCM = 10#
kDLROCMHost = 11#
kDLTrn = 18#
kDLVPI = 9#
kDLVulkan = 7#
kDLWebGPU = 15#
class DLDataTypeCode#

An integer encoding the category of a DLTensor element’s data type.

kDLBfloat = 4#
kDLBool = 6#
kDLComplex = 5#
kDLFloat = 2#
kDLInt = 0#
kDLOpaqueHandle = 3#
kDLUInt = 1#
class ManagedDLTensor#

A DLPack-exportable view of an ovstage tensor.

Obtained from ovstage.ReadGroup.dlpack() / ovstage.MapGroup.dlpack(). Pass the instance to np.from_dlpack() / wp.from_dlpack() / torch.from_dlpack() for zero-copy access (CPU or CUDA), or call numpy() for a CPU numpy view.

The tensor data and descriptor are borrowed from ovstage. Do not access this producer or its consumer views after releasing the read group or after an accepted group or final unmap submission. Retaining this producer does not extend storage validity beyond those operations, and this producer does not check whether the storage is still valid. Copy data while it is valid if it must outlive the group. A read group is exported readonly=True; a (writable) map group readonly=False. Native read and map tensors have scalar lanes, so DLPack consumers and ManagedDLTensor.shape see the same typed shape. Caller-owned multi-lane tensors export one additional component axis; their shape property continues to report the raw descriptor shape.

manager_ctx is retained by this object and by any capsule it exports, but a capsule is destroyed as soon as a consumer takes ownership of it — which is before that consumer releases the tensor. The DLPack deleter runs no Python (see _C_FREE_DELETER), so it cannot release a Python reference at that later point. If manager_ctx is the sole owner of the backing memory, keep this ManagedDLTensor alive for as long as the consumer’s view is used:

managed = ManagedDLTensor(tensor, manager_ctx=owner)
view = np.from_dlpack(managed)  # `managed` must outlive `view`

For ovstage read/map groups, keep the group or this producer alive while using a consumer view, and observe the release/unmap limits above. A consumer view does not keep the group alive. For example:

group = read.fetch_next()
arr = np.from_dlpack(group.dlpack(0))  # `group` must outlive `arr`

np.from_dlpack(read.fetch_next().dlpack(0)) drops the group on the same line: its finalizer releases the pinned storage and arr is left reading memory that has been handed back.

__dlpack__(
*,
stream=None,
max_version=None,
dl_device=None,
copy=None,
)#

Return a DLPack capsule. stream is accepted but ignored — GPU synchronization is the caller’s responsibility (see the dlpack skill).

Parameters:
  • stream (int | None)

  • max_version (tuple | None)

  • dl_device (tuple | None)

  • copy (bool | None)

Return type:

Any

__init__(
dl_tensor,
manager_ctx,
deleter_callback=None,
readonly=True,
)#
Parameters:
property data: int#
property device: DLDevice#
property dtype: DLDataType#
property ndim: int#
numpy()#

Zero-copy numpy view (CPU tensors only).

property raw_dltensor: DLTensor#
property shape: tuple#
typed_tensor_to_write(source)#

Convert a known OVStage read/map descriptor to canonical write input.

This copies metadata only; payload, device and byte offset are preserved. It does not infer component types for arbitrary multidimensional arrays. Preserve the attribute semantic and array kind when submitting the write. The returned descriptor retains source, but cannot extend native group storage lifetime. Copy payload before releasing a pinned read when writing back to the same storage; wait for completion before releasing input data. Compact component axes and a nonnegative, whole-element row stride are required. Outer slices and broadcasts are preserved.

Parameters:

source (DLTensor)

Return type:

DLTensor

make_dltensor(
array,
*,
dtype=None,
shape=None,
ndim=None,
strides=None,
device_type=1,
device_id=0,
)#

Build a DLTensor viewing the memory of an array.

A numpy array (CPU) is wrapped directly; the array, the shape storage, and the tensor are linked by reference so the C-visible pointers stay valid for as long as the returned tensor is alive. shape/ndim/dtype/strides may be overridden to describe vector (multi-lane) layouts a plain numpy dtype cannot express, matching an explicitly authored multi-lane DLTensor descriptor. A fixed-size ovstage write may also accept the numpy shape directly as a convenience layout (for example, (N, 4, 4) with lanes=1); subsequent reads and maps expose shape=(N, 4, 4), lanes=1 when the stored attribute has MATRIX semantic.

Any non-numpy object exposing the DLPack protocol (warp / torch / cupy / jax, CPU or CUDA) is ingested zero-copy via DLTensor.from_dlpack() instead, so a GPU device buffer can be written without a host round-trip. Such a producer may be re-described with a vector dtype only through a validated fold of complete trailing dimensions into dtype.lanes. The source must be compact row-major with byte-aligned elements, its base type and positive bit width are unchanged, and any explicit shape/ndim/strides must match the folded compact view. For example, a Warp vec3f export shaped (N, 3) can be viewed as shape=(N,) with lanes=3 without copying its CPU or CUDA allocation. A lane fold that consumes every source axis is normalized to shape=(1,), ndim=1.

The caller owns the data: it must keep the returned tensor (and thus the backing array) alive until the consuming op completes.

Parameters:
Return type:

DLTensor

dltensor_to_numpy(tensor, *, readonly=False)#

Return a zero-copy numpy view of a CPU DLTensor.

The view is flat: its length is prod(shape) * dtype.lanes base elements, matching the raw-buffer indexing the C++ tests perform. Vector lanes are folded into the element count rather than the dtype. The data is owned by ovstage and only valid until the owning group/result is released.

When readonly is true, the view is backed by a read-only buffer so its WRITEABLE flag cannot be re-enabled. The default remains writable for caller-owned tensors and map buffers.

Every tensor’s lane count is checked against the transportable range [1, 255] and a dtype outside it is rejected with ValueError, whatever produced the descriptor. That bound needs no buffer size, so it also covers a raw DLTensor decoded straight out of the C read/map result, where the lanes field is a uint16 that a wrapped value (-1 -> 65535) would otherwise turn into a view far past the payload.

Where a real buffer size is known — a numpy array wrapped by make_dltensor(), or the extent a DLPack producer described at DLTensor.from_dlpack() time — the decoded view is additionally checked against it and can never extend past it. A raw descriptor carries no buffer length at all, so for those the lane bound is the guarantee.

Parameters:
numpy_to_dldatatype(np_dtype, lanes=1)#

Build a DLDataType from a numpy dtype (with optional vector lanes).

lanes must be an integer in [1, 255], the range ovstage can transport: anything outside it raises ValueError (TypeError for non-integers) rather than building a dtype no ovstage read or write accepts. The value lands in the DLPack uint16 lane field, which would otherwise also wrap a negative count silently (-1 becoming 65535).

Parameters:

lanes (int)

Return type:

DLDataType

Experimental Device Placement#

Pass placement= to stage read, write, or map methods. Availability depends on the runtime’s experimental extension; see Experimental Device Placement.

class Placement#

Which device’s copy of an attribute a write should produce.

Warning

Experimental, like the C "ovstage.placement" extension it maps to: its API and semantics may change between releases. A library without the extension rejects a placed call with ErrorCode.NOT_FOUND.

Destination residency, as opposed to cuda_stream/cuda_event, which describe the source handoff. A producer may hand over a tensor on one device while asking that the write land on another. availability_event is the one field pointing the other way: the source handoff is something ovstage waits on, that event is something ovstage signals. A write may use both – wait for the producer, signal the consumer.

Placement selects a mirror; it does not pin a column to one device for its lifetime. Stage storage keeps CPU and per-device copies and tracks which are current, so writing the same attribute later with a different placement is an ordinary mirror update, not a conflict.

What placement buys is on the read side: after a write placed on device D, a read of that attribute on D is served from the copy already current there and performs no migration.

One placement applies to a whole write call, not to individual attributes – the destination device and the stream carrying the op’s device work have to travel at the same granularity. Placing two attributes on two devices takes two calls.

Leaving device_type at 0 (or passing placement=None) is “unspecified”: the write follows the source tensor’s device.

Note

A payload whose placement differs from its source device is staged onto the target, so a column produced on the CPU becomes current on the GPU and a later device read of it needs no transfer. Host to CUDA, CUDA to another CUDA device, and CUDA back to the host are all handled. Staging costs a full device synchronization today, because the scatter runs on the default stream.

Ragged (is_array=True) payloads are staged too: each row is its own tensor, so staging moves every row into one allocation and preserves the row structure. A strided host row is packed by its strides, as an unplaced write reads it; a row with a negative or zero (broadcast) stride is rejected as not supported.

A staged write waits on the write’s cuda_event / cuda_stream handoff before it first reads the payload, on the source tensor’s device.

Note

stream carries the op’s device work for a fixed-size placed write: the scatter is launched on it. The write executes after the call returns, so work enqueued on stream is ordered behind it only once wait() has returned – a host-side handshake, not a wait for the GPU; see the sequences below. A write that has to stage – its placement names a device other than the source’s – drains that stream before releasing the staging buffer, so it is synchronous despite naming a stream; a placed write whose source already lives on the target stages nothing and runs fully asynchronously. stream is ignored for ragged writes.

Note

availability_event is how a caller learns the data an operation makes available is safe to touch without the host waiting for the device work. It does not replace wait() (or a read’s successful fetch), which is still the point after which the event has been recorded. It is a cudaEvent_t address the caller creates and owns; ovstage records into it and never creates, destroys or hands back a CUDA object, exactly as for stream and cuda_event. Pass the raw cudaEvent_t as an int, the same way cuda_event takes one.

It marks availability, not this operation’s completion. On a read the two deliberately differ: the read op completes first, and the event fires once the memory the groups point at may be dereferenced – which can mean waiting on device work the caller never issued, such as an earlier write still in flight. That is what makes one name fit all three placed operations: a write makes its data available on the target device, a map commit makes the values it committed available, a read makes the column available.

It is recorded exactly once for every accepted operation, on stream, after the device work is launched – and also when the operation turns out to need no device work at all (host payload, host placement, nothing to scatter) and when it fails while executing. So waiting on it is always safe – but because a failed operation records it too, the event firing means stop waiting, not the data is good: whether the operation succeeded is what wait() reports. An enqueue rejected outright owes no record and leaves the event untouched, unless it was rejected for lack of memory; the call reports the rejection. A placed map records it on each commit – every unmap_group and unmap_attribute – once that commit has run, and on setup only if the setup is cancelled before it runs: it covers committed values, not the staging buffers Map.fetch_next() hands back.

Wait on it only after the submission boundary. The record is issued when the operation executes, after the call has returned; a wait issued earlier, on the event or on stream, observes an old or never-recorded event and orders nothing against this operation. The safe sequences, neither of which waits on the host for the GPU:

  • write or map commit: enqueue; wait() returns (it raises on failure); then wait on the event, or enqueue downstream work on stream.

  • read: enqueue; Read.fetch_next() returns a group, which happens only after the record was issued; then make the consumer wait on the event, or enqueue it on stream.

The event firing does not replace that status check. A default stream is the default stream of the device the record ran on; stream=2 is the per-thread stream of the thread that ran the operation, not necessarily yours, so there only the event orders your work.

It must belong to the device the record runs on: stream’s device; for a default stream (0, 1 or 2), the CUDA device when one is named; for a write that leaves device_type at 0 and has CUDA sources, their device; otherwise, a host placement included, the device current on the calling thread at enqueue. A write that leaves device_type at 0 and has CUDA sources on more than one device is rejected with INVALID_ARGUMENT when the stream is a default one.

A record CUDA refuses leaves the event untouched and fails an otherwise successful operation with OP_FAILED after its effects – a write stays committed at its ordinal, a map commit stays recorded – and a read fails instead of returning its payload. An operation that completes during the enqueue, such as a read of a ready query, is then rejected outright after it ran. Nothing drains a write’s device work on that path, and the untouched event does not cover it (see the last note).

The event must outlive the call. The Placement itself does not – everything in it is copied out during the enqueue – but the event is recorded when the operation executes, which is after the enqueue returns, so destroying it before the record is issued is a use-after-free. The record has been issued, or refused, once wait() has returned or raised a failure (not a timeout) for the operation, or a read’s fetch_next has returned a group. A wait on the event or on stream before then establishes nothing.

Supplying one makes the operation genuinely asynchronous, which changes what wait() means: without an event ovstage drains the device work before reporting the op complete, so wait() implies the data landed; with one it no longer does for the cases ovstage can leave running – wait on the event instead. The exceptions are the ones above: a write that must stage drains its call-scoped buffer anyway, and a ragged write runs on the default stream, so for those the event is already signalled by the time the op completes. The event is correct in every case; it only buys asynchrony in some.

One Python-side consequence: Operation.wait() releases the references pinning the write’s source tensors, and with an availability event the device may still be reading them. Keep your own reference to those tensors until you have waited on the event. If the event could not be recorded, keep them until, after wait() raised, you have synchronized stream if it is a specific stream, or else the device the record was due to run on (for example cudaDeviceSynchronize with that device current).

__init__(
device_type=0,
device_id=0,
stream=0,
availability_event=0,
)#
Parameters:
  • device_type (int)

  • device_id (int)

  • stream (int)

  • availability_event (int)

Return type:

None

availability_event: int = 0#
device_id: int = 0#
device_type: int = 0#
classmethod from_dlpack_device(obj, *, stream=0, availability_event=0)#

Build a placement naming the device an existing tensor already lives on.

obj is anything exposing __dlpack_device__() – a torch or warp array, or the (device_type, device_id) tuple itself. This is the common case: put stage storage where the caller’s tensors already are.

stream and availability_event are forwarded unchanged: the device comes from the tensor, the synchronization is still the caller’s to name.

Parameters:
  • obj (Any)

  • stream (int)

  • availability_event (int)

Return type:

Placement

stream: int = 0#

ovstage.population#

USD population composes USD content into the runtime stage; population export authors selected runtime state back into a USD destination that ovstage opens and owns. See Population (USD → ovstage) and Exporting ovstage to USD.

ovstage population: populate an ovstage instance from USD.

Thin wrappers over the ovstage_population_* C entry points (the USD -> ovstage bridge in ovstage_population.h). The application owns the ordinal lifecycle and must pass an explicit ordinal to every call that carries one. Under the strict admission policy, overlapping writes need successively newer ordinals; the wrappers do not allocate or advance ordinals automatically.

The surface follows the ovrtx Python conventions: every mutating entry point comes as a blocking foo(...) that returns once the work has completed, plus an asynchronous foo_async(...) that returns an Operation to wait on explicitly. Per-stage population state is created lazily on first use and released automatically when the stage is destroyed (no manual detach).

class Operation#

A handle to an enqueued (asynchronous) population operation.

Mirrors the ovrtx Operation ergonomics: wait() blocks until the op (and the ordinal-keyed ops before it) completes, returning the op’s payload on success — a USD reference handle for an add-reference op, True for a void op — or None on timeout, and raising OvstageError on failure. status is the enqueue status (OVSTAGE_OK = accepted).

__init__(
stage,
status,
op_id,
*,
value=True,
keepalive=None,
name='',
)#
Parameters:
property ok: bool#
error_message()#
Return type:

str

wait(timeout=18446744073709551615)#

Wait for completion. Returns the payload, None on timeout; raises on failure.

Parameters:

timeout (int) – max nanoseconds to wait; OVSTAGE_TIMEOUT_INFINITE (default) blocks, 0 polls.

Raises:
  • TypeError – if timeout is not an integer (e.g. None).

  • ValueError – if timeout is negative or does not fit in uint64.

class ExportOperation#

Handle for an enqueued runtime-to-USD export operation.

Every accepted operation must eventually receive a terminal wait(). Timeout polling does not consume the native report or destination keepalive.

__init__(stage, lib, status, op_id, *, name)#
Parameters:
error_message()#
Return type:

str

property ok: bool#
wait(timeout=18446744073709551615)#

Return the export report, None on timeout, or raise on failure.

Parameters:

timeout (int)

class ExportProjection#

Automatic source-attribute projection policy.

__new__(value)#
EXPLICIT_RULES = 0#
SCHEMA_DECLARED = 1#
class SourceApiSchemaPolicy#

Policy for applied API schemas recorded on source prims.

__new__(value)#
EXPLICIT_ONLY = 0#
APPLY_RECORDED = 1#
class DestinationCreateOperation#

Async creation operation whose reserved destination is immediately available.

property destination#
class DestinationOperation#

Handle for an enqueued destination lifecycle operation.

__init__(
stage,
lib,
status,
op_id,
*,
value=True,
keepalive=None,
on_terminal=None,
)#
Parameters:
property ok: bool#
wait(timeout=18446744073709551615)#

Return the operation value, None on timeout, or raise on failure.

Parameters:

timeout (int)

class ExportDestination#

ABI-opaque, source-stage-bound USD export destination.

Export calls accumulate in memory. Call save() explicitly to persist; context-manager exit only closes and discards any unsaved changes. If an open destination is dropped while its source stage remains live, the finalizer best-effort queues release without saving and emits ResourceWarning.

__init__(stage, lib, handle, identifier)#
Parameters:
  • handle (int)

  • identifier (str)

close()#

Release the destination without implicitly saving.

Return type:

None

close_async()#

Enqueue ordered release without implicitly saving.

Return type:

DestinationOperation

property closed: bool#
classmethod create(
stage,
identifier,
mode=ExportDestinationMode.EMPTY,
)#

Create a destination and wait until it is ready.

Parameters:
classmethod create_async(
stage,
identifier,
mode=ExportDestinationMode.EMPTY,
)#

Enqueue creation and expose the reserved destination immediately.

Parameters:
Return type:

DestinationCreateOperation

export(ordinal, **options)#

Export one selected runtime slice into this destination.

Parameters:

ordinal (int)

Return type:

dict

export_async(ordinal, **options)#

Enqueue one selected runtime slice into this destination.

Parameters:

ordinal (int)

Return type:

ExportOperation

property handle: int#
save()#

Persist all currently accumulated opinions.

Return type:

None

save_async()#

Enqueue persistence after previously submitted destination work.

Return type:

DestinationOperation

class ExportDestinationMode#

Initial-content policy for a reusable USD export destination.

__new__(value)#
EMPTY = 0#
OPEN_EXISTING = 1#
open_usd(
stage,
path,
ordinal,
time=nan,
domains=<PopulationDomain.RENDERING: 1>,
)#

Open a USD file and populate the stage (blocking).

ordinal is required and chosen by the caller. Under the strict admission policy, use a newer ordinal when this writes attributes already written by an earlier operation.

time is in seconds (converted via the stage’s timeCodesPerSecond, like the C time parameter). The default, DEFAULT_TIME, evaluates at USD’s default time code. Wraps the C entry point ovstage_population_open_usd_from_file.

An open writes over what the stage already holds and removes nothing an earlier one left, so opening different content on a populated stage merges the two. To replace, clear first at a lower ordinal – reset_usd() followed by apply_usd_changes(), or a whole-prim delete over an unfiltered query. See Repopulating a Stage in the population guide.

Parameters:
Return type:

None

open_usd_async(
stage,
path,
ordinal,
time=nan,
domains=<PopulationDomain.RENDERING: 1>,
)#

Open a USD file and populate the stage (asynchronous). See open_usd().

Parameters:
Return type:

Operation

open_usd_from_string(
stage,
usda,
ordinal,
time=nan,
domains=<PopulationDomain.RENDERING: 1>,
)#

Open inline USDA content and populate the stage (blocking).

ordinal is required, with the same admission contract as open_usd().

time follows the same contract as open_usd(): seconds, with DEFAULT_TIME (the default) evaluating at USD’s default time code. Like open_usd(), it merges into whatever the stage already holds; clear first to replace.

Parameters:
Return type:

None

open_usd_from_string_async(
stage,
usda,
ordinal,
time=nan,
domains=<PopulationDomain.RENDERING: 1>,
)#

Open inline USDA content and populate the stage (asynchronous). See open_usd_from_string().

Parameters:
Return type:

Operation

open_usd_with_desc(stage, path, ordinal, time, descs)#

Open a USD file and populate the stage through a description (blocking).

descs is a Desc or a sequence of them, mirroring the C entry point: each contributor supplies one, their domains are OR-ed and their selectors and stage metadata paths combined. A description carrying only domains is exactly open_usd(). An empty sequence selects nothing. time follows the same contract as open_usd(), including DEFAULT_TIME; it is required here rather than defaulted, matching the C entry point.

Parameters:
Return type:

None

open_usd_with_desc_async(stage, path, ordinal, time, descs)#

Open a USD file through a description (asynchronous). See open_usd_with_desc().

Parameters:
Return type:

Operation

open_usd_from_string_with_desc(stage, usda, ordinal, time, descs)#

Open inline USDA and populate the stage through a description (blocking).

See open_usd_with_desc().

Parameters:
Return type:

None

open_usd_from_string_with_desc_async(
stage,
usda,
ordinal,
time,
descs,
)#

Open inline USDA through a description (asynchronous). See open_usd_with_desc().

Parameters:
Return type:

Operation

repopulate_usd_with_desc(stage, ordinal, time, descs)#

Populate the stage again from its current USD source (blocking).

Preserves the USD stage, authored root/session edits, composition and reference handles. Every attribute descs selects is rewritten from USD, replacing direct data-plane overrides; like an open, it removes nothing descs does not populate, including prims/columns absent from USD. descs replaces the population scope; time is in seconds or DEFAULT_TIME, as for open_usd_with_desc().

Raises OvstageError with NOT_SUPPORTED on an older runtime.

Parameters:
Return type:

None

repopulate_usd_with_desc_async(stage, ordinal, time, descs)#

Rebuild from the retained USD source asynchronously; see repopulate_usd_with_desc().

Parameters:
Return type:

Operation

add_usd_reference(stage, ref_file_path, target_path)#

Add a USD file as a reference at target_path (blocking). Returns the handle.

The merge is additive in every case; target_path selects its shape: the root "/" merges the layer’s top-level prims into the stage, an existing prim path adds the reference onto that prim (leaving its prior content), and a not-yet-existing prim path defines a new prim there. Call apply_usd_changes() afterwards to reflect it into the stage.

Parameters:
  • ref_file_path (str)

  • target_path (str)

Return type:

int

add_usd_reference_async(stage, ref_file_path, target_path)#

Add a USD file as a reference at target_path (asynchronous).

Parameters:
  • ref_file_path (str)

  • target_path (str)

Return type:

Operation

add_usd_reference_from_string(stage, ref_str, target_path)#

Add inline USDA content as a reference at target_path (blocking). Returns the handle.

Same additive target_path semantics as add_usd_reference() (root "/" merge, overlay onto an existing prim, or a new prim), but the layer is provided as inline USDA text instead of a file.

Parameters:
  • ref_str (str)

  • target_path (str)

Return type:

int

add_usd_reference_from_string_async(stage, ref_str, target_path)#

Add inline USDA content as a reference at target_path (asynchronous).

Parameters:
  • ref_str (str)

  • target_path (str)

Return type:

Operation

remove_usd(stage, handle)#

Remove a USD reference previously added by add_usd_reference* (blocking).

Parameters:

handle (int)

Return type:

None

remove_usd_async(stage, handle)#

Remove a USD reference previously added by add_usd_reference* (asynchronous).

Parameters:

handle (int)

Return type:

Operation

reset_usd(stage)#

Clear all USD source content from the stage (blocking).

This edits only the USD source. What was populated from it stays until apply_usd_changes() propagates the clear, and a later open merges into it rather than replacing it.

Return type:

None

reset_usd_async(stage)#

Clear all USD source content from the stage (asynchronous).

Edits only the USD source; see reset_usd().

Return type:

Operation

update_from_usd_time(stage, ordinal, time)#

Advance time and propagate time-sampled attribute changes (blocking).

time is in seconds (converted via the stage’s timeCodesPerSecond, like the C time parameter); DEFAULT_TIME advances to USD’s default time code. Wraps the C entry point ovstage_population_apply_usd_time.

Every in-scope time-sampled property is overwritten, whether or not time differs from the previous call — re-applying the same time is not a no-op. This holds for every domain, and equally when time is DEFAULT_TIME.

Under the strict admission policy, use a newer ordinal than earlier overlapping writes, including apply_usd_changes() on the same stage. Equal ordinals require the writes to be disjoint.

Parameters:
Return type:

None

update_from_usd_time_async(stage, ordinal, time)#

Advance time and propagate time-sampled changes (asynchronous). See update_from_usd_time().

Parameters:
Return type:

Operation

apply_usd_changes(stage, ordinal)#

Propagate USD edits accumulated since the last call into the stage (blocking).

ordinal is required and chosen by the caller. Under the strict admission policy, use a newer ordinal than earlier overlapping writes, including the initial open and update_from_usd_time() on the same stage. Equal ordinals require the writes to be disjoint.

Parameters:

ordinal (int)

Return type:

None

apply_usd_changes_async(stage, ordinal)#

Propagate accumulated USD edits asynchronously. See apply_usd_changes().

Parameters:

ordinal (int)

Return type:

Operation

DEFAULT_TIME = nan#

The time value selecting USD’s default time code rather than a numeric one, and the default for every time parameter that has one. The value is a NaN, the same as the C OVSTAGE_POPULATION_DEFAULT_TIME.

Never compare with == – a NaN is not equal to itself, so t == DEFAULT_TIME is false even for the default time. Use is_default_time().

is_default_time(time)#

True when time selects USD’s default time code.

Use this rather than time == DEFAULT_TIME, which is false even for the default time. Mirrors the C ovstage_population_is_default_time.

Parameters:

time (float)

Return type:

bool

last_error()#

Thread-local detail for the latest population call on this thread.

Return type:

str

available()#

True when the loaded libovstage exports the ovstage population bridge.

Return type:

bool

export_available()#

True when libovstage exports the ovstage population USD export bridge.

Return type:

bool

create_export_destination(
stage,
identifier,
mode=ExportDestinationMode.EMPTY,
)#

Create a reusable destination and wait until it is ready.

Parameters:
Return type:

ExportDestination

create_export_destination_async(
stage,
identifier,
mode=ExportDestinationMode.EMPTY,
)#

Enqueue destination creation and expose its reserved handle immediately.

Parameters:
Return type:

DestinationCreateOperation

export_to_destination(
stage,
destination,
ordinal,
*,
since_ordinal=0,
selection=0,
layer_mode=0,
transform_policy=0,
unknown_metadata_policy=0,
source_api_schema_policy=0,
projection=0,
prim_predicate=None,
property_predicate=None,
prim_rules=None,
api_schema_rules=None,
attribute_rules=None,
property_rules=None,
metadata_rules=None,
)#

Accumulate one selected runtime slice in a reusable destination.

Parameters:
Return type:

dict

export_to_destination_async(
stage,
destination,
ordinal,
*,
since_ordinal=0,
selection=0,
layer_mode=0,
transform_policy=0,
unknown_metadata_policy=0,
source_api_schema_policy=0,
projection=0,
prim_predicate=None,
property_predicate=None,
prim_rules=None,
api_schema_rules=None,
attribute_rules=None,
property_rules=None,
metadata_rules=None,
)#

Enqueue one selected runtime slice into a reusable destination.

Parameters:
Return type:

ExportOperation

export_to_usd_file(
stage,
identifier,
ordinal,
*,
since_ordinal=0,
selection=0,
layer_mode=0,
transform_policy=0,
unknown_metadata_policy=0,
source_api_schema_policy=0,
projection=0,
prim_predicate=None,
property_predicate=None,
prim_rules=None,
api_schema_rules=None,
attribute_rules=None,
property_rules=None,
metadata_rules=None,
)#

Export one selected snapshot and persist it as a replacement USD file.

Parameters:
Return type:

dict

export_to_usd_file_async(
stage,
identifier,
ordinal,
*,
since_ordinal=0,
selection=0,
layer_mode=0,
transform_policy=0,
unknown_metadata_policy=0,
source_api_schema_policy=0,
projection=0,
prim_predicate=None,
property_predicate=None,
prim_rules=None,
api_schema_rules=None,
attribute_rules=None,
property_rules=None,
metadata_rules=None,
)#

Enqueue one selected snapshot export and persistence operation.

Parameters:
Return type:

ExportOperation

export_to_usd_layer(
stage,
usd_layer,
ordinal,
*,
since_ordinal=0,
selection=0,
layer_mode=0,
transform_policy=0,
unknown_metadata_policy=0,
source_api_schema_policy=0,
projection=0,
prim_predicate=None,
property_predicate=None,
prim_rules=None,
api_schema_rules=None,
attribute_rules=None,
property_rules=None,
metadata_rules=None,
)#

Export selected ovstage runtime state into a USD layer.

The target layer is resolved by identifier. This works for file-backed layers and for already-open layers visible to USD’s layer registry.

Parameters:
Return type:

dict

export_to_usd_layer_async(
stage,
usd_layer,
ordinal,
*,
since_ordinal=0,
selection=0,
layer_mode=0,
transform_policy=0,
unknown_metadata_policy=0,
source_api_schema_policy=0,
projection=0,
prim_predicate=None,
property_predicate=None,
prim_rules=None,
api_schema_rules=None,
attribute_rules=None,
property_rules=None,
metadata_rules=None,
)#

Enqueue export into a USD layer and return an operation handle.

The native enqueue copies the complete descriptor before returning. The caller must still avoid concurrent USD reads or writes to the destination until the returned operation completes.

Parameters:
Return type:

ExportOperation

export_to_usd_stage(
stage,
usd_stage,
ordinal,
*,
since_ordinal=0,
selection=0,
layer_mode=0,
transform_policy=0,
unknown_metadata_policy=0,
source_api_schema_policy=0,
projection=0,
prim_predicate=None,
property_predicate=None,
prim_rules=None,
api_schema_rules=None,
attribute_rules=None,
property_rules=None,
metadata_rules=None,
)#

Export through a stage root-layer identifier and its default edit target.

A pxr.Usd.Stage-like object is reduced to its root-layer identifier. Its current edit target is not preserved.

Parameters:
Return type:

dict

export_to_usd_stage_async(
stage,
usd_stage,
ordinal,
*,
since_ordinal=0,
selection=0,
layer_mode=0,
transform_policy=0,
unknown_metadata_policy=0,
source_api_schema_policy=0,
projection=0,
prim_predicate=None,
property_predicate=None,
prim_rules=None,
api_schema_rules=None,
attribute_rules=None,
property_rules=None,
metadata_rules=None,
)#

Enqueue export through a stage root-layer identifier.

The caller must avoid concurrent USD reads or writes to the destination stage and its layers until the returned operation completes. A pxr.Usd.Stage-like object is reduced to its root-layer identifier; its current edit target is not preserved.

Parameters:
Return type:

ExportOperation

export_typed_hierarchy_to_usd_file(
stage,
identifier,
root_path,
ordinal,
*,
prim_predicate=None,
property_predicate=None,
include_custom_namespaces=None,
transform_policy=0,
unknown_metadata_policy=0,
)#

Export a typed runtime hierarchy and persist it as a replacement USD file.

Parameters:
Return type:

dict

export_typed_hierarchy_to_usd_file_async(
stage,
identifier,
root_path,
ordinal,
*,
prim_predicate=None,
property_predicate=None,
include_custom_namespaces=None,
transform_policy=0,
unknown_metadata_policy=0,
)#

Enqueue typed-hierarchy export and persistence as one export operation.

Parameters:
Return type:

ExportOperation

export_typed_hierarchy_to_usd_layer(
stage,
usd_layer,
root_path,
ordinal,
*,
prim_predicate=None,
property_predicate=None,
include_custom_namespaces=None,
transform_policy=0,
unknown_metadata_policy=0,
)#

Export a typed runtime hierarchy using recorded USD representation facts.

Supported concrete prim types and recognized effective applied API schemas are preserved. Unrecognized representation metadata follows unknown_metadata_policy. Supported schema-declared attributes are projected with their source names and USD types. Custom attributes are excluded unless their namespace is explicitly included.

Parameters:
Return type:

dict

export_typed_hierarchy_to_usd_layer_async(
stage,
usd_layer,
root_path,
ordinal,
*,
prim_predicate=None,
property_predicate=None,
include_custom_namespaces=None,
transform_policy=0,
unknown_metadata_policy=0,
)#

Enqueue typed-hierarchy export and return its normal export operation.

Parameters:
Return type:

ExportOperation

Descriptions and Selectors#

class Desc#

What one contributor asks to be populated.

Descs compose: domains is OR-ed across the array an entry point is given, and their selectors and stage metadata paths are combined.

domains#
selectors#
stage_metadata_paths#
__init__(
domains=<PopulationDomain.NONE: 0>,
selectors=(),
stage_metadata_paths=(),
)#
Parameters:

domains (int)

class Selector#

One (which prims, which of their properties, which metadata) rule.

Selectors compose: a prim is in scope if any selector matches it, and its properties are the union over the selectors that did.

prim_predicate#
property_predicate#
prim_metadata_paths#
property_metadata_paths#
__init__(
prim_predicate=None,
property_predicate=None,
prim_metadata_paths=(),
property_metadata_paths=(),
)#
class PrimPredicate#

Which prims a selector puts in scope.

Several values of one kind match if any one of them does, so a list of schema names is a single predicate; combine different kinds with and_(), or_() and not_().

kind#
strings#
subpredicates#
nested#
static all()#

Matches every prim.

Return type:

PrimPredicate

static and_(*subpredicates)#

Matches when every subpredicate matches.

Parameters:

subpredicates (PrimPredicate)

Return type:

PrimPredicate

static has_ancestor(subpredicate)#

Matches when any strict ancestor matches. A prim is not its own ancestor.

Parameters:

subpredicate (PrimPredicate)

Return type:

PrimPredicate

static has_applied_schema(*schema_names)#

Matches an applied API schema exactly, including any :instance suffix.

Parameters:

schema_names (str)

Return type:

PrimPredicate

static has_applied_schema_in_namespace(*family_names)#

Matches every instance of a multiple-apply schema family.

Parameters:

family_names (str)

Return type:

PrimPredicate

static has_kind(*kinds)#

Matches the prim’s model kind exactly; the kind hierarchy is not consulted.

Parameters:

kinds (str)

Return type:

PrimPredicate

static has_metadata(*paths)#

Matches a prim resolving one of the named metadata paths.

Paths take the form Desc metadata paths do: a field name, extended with a :-joined key path to reach inside a dictionary field. Presence, not value: a path resolving to False matches as much as one resolving to True.

Name a key, not a whole dictionary field: a field matches whenever anything resolves beneath it, including what a schema registers rather than the prim authoring it. has_metadata("customData:myTool:export") selects the prims carrying that key.

Parameters:

paths (str)

Return type:

PrimPredicate

static has_parent(subpredicate)#

Matches when the prim’s parent matches subpredicate.

A top-level prim has no parent to match: the pseudo-root is not offered to a predicate, so this is false for it.

Parameters:

subpredicate (PrimPredicate)

Return type:

PrimPredicate

static has_path(*paths)#

Matches the prim’s absolute path exactly.

Parameters:

paths (str)

Return type:

PrimPredicate

static has_property(subpredicate)#

Matches when any property of the prim matches subpredicate.

The properties considered are the union of what the prim authors and what its schemas declare, so an unauthored schema property counts; combine with PropertyPredicate.is_authored() for “carries an authored value”.

Parameters:

subpredicate (PropertyPredicate)

Return type:

PrimPredicate

static has_purpose(*purposes)#

Matches the prim’s purpose, as inherited down the tree.

Parameters:

purposes (str)

Return type:

PrimPredicate

static has_schema(*schema_names)#

Matches a schema the prim conforms to: its type or an applied API schema.

The form to use when a list of schema names mixes the two, which a schema family generally does.

Parameters:

schema_names (str)

Return type:

PrimPredicate

static has_type(*type_names)#

Matches the prim’s type name exactly.

Parameters:

type_names (str)

Return type:

PrimPredicate

static is_a_type(*type_names)#

Matches the prim’s type name or any type it derives from.

Parameters:

type_names (str)

Return type:

PrimPredicate

static is_under_path(*paths)#

Matches a prim at or beneath an absolute path, at path-component boundaries.

Parameters:

paths (str)

Return type:

PrimPredicate

static none()#

Matches no prim. A selector built on it contributes nothing.

Return type:

PrimPredicate

static not_(subpredicate)#

Matches when subpredicate does not.

Parameters:

subpredicate (PrimPredicate)

Return type:

PrimPredicate

static or_(*subpredicates)#

Matches when any subpredicate matches.

Parameters:

subpredicates (PrimPredicate)

Return type:

PrimPredicate

class PropertyPredicate#

Which of an in-scope prim’s properties a selector includes in population.

kind#
strings#
subpredicates#
nested#
static all()#

Matches every property of an in-scope prim.

Return type:

PropertyPredicate

static and_(*subpredicates)#

Matches when every subpredicate matches.

Parameters:

subpredicates (PropertyPredicate)

Return type:

PropertyPredicate

static declared_by_schema(*schema_names)#

Matches a property whose name one of the named schemas declares.

Whether the prim carrying the property has that schema applied is not considered. A name is tried as both a type and an applied API schema, so a mixed list needs no partitioning.

Parameters:

schema_names (str)

Return type:

PropertyPredicate

static has_metadata(*paths)#

Matches a property resolving one of the named metadata paths.

Same path form and presence semantics as PrimPredicate.has_metadata(), against the property’s own metadata.

Parameters:

paths (str)

Return type:

PropertyPredicate

static has_name(*names)#

Matches the property’s name exactly.

Parameters:

names (str)

Return type:

PropertyPredicate

static in_namespace(*namespaces)#

Matches a property in a namespace, at : boundaries.

material:binding matches material:binding:physics but not material:bindingStrength, and not a property named material:binding itself – a name is in a namespace rather than equal to it.

Parameters:

namespaces (str)

Return type:

PropertyPredicate

static is_attribute()#

Matches an attribute.

Return type:

PropertyPredicate

static is_authored()#

Matches a property carrying an authored opinion rather than a schema fallback.

Return type:

PropertyPredicate

static is_custom()#

Matches a property carrying USD’s custom modifier.

Return type:

PropertyPredicate

static is_relationship()#

Matches a relationship.

Return type:

PropertyPredicate

static none()#

Matches no property. The prim is still populated, with its reserved values.

Return type:

PropertyPredicate

static not_(subpredicate)#

Matches when subpredicate does not.

Parameters:

subpredicate (PropertyPredicate)

Return type:

PropertyPredicate

static or_(*subpredicates)#

Matches when any subpredicate matches.

Parameters:

subpredicates (PropertyPredicate)

Return type:

PropertyPredicate

class PrimPredicateKind#

How an ovstage_population_prim_predicate_t matches.

A kind that takes values matches when any one of them matches: the values of a single predicate are a disjunction, never a conjunction. Requiring more than one condition is what AND is for.

__new__(value)#
NONE = 0#
ALL = 1#
AND = 2#
OR = 3#
NOT = 4#
HAS_PARENT = 5#
HAS_ANCESTOR = 6#
HAS_PROPERTY = 7#
HAS_TYPE = 8#
IS_A_TYPE = 9#
HAS_SCHEMA = 10#
HAS_APPLIED_SCHEMA = 11#
HAS_APPLIED_SCHEMA_IN_NAMESPACE = 12#
HAS_PATH = 13#
IS_UNDER_PATH = 14#
HAS_KIND = 15#
HAS_PURPOSE = 16#
HAS_METADATA = 17#
class PropertyPredicateKind#

How an ovstage_population_property_predicate_t matches.

Values disjoin exactly as they do for PrimPredicateKind.

__new__(value)#
NONE = 0#
ALL = 1#
AND = 2#
OR = 3#
NOT = 4#
DECLARED_BY_SCHEMA = 5#
HAS_NAME = 6#
IN_NAMESPACE = 7#
HAS_METADATA = 8#
IS_ATTRIBUTE = 9#
IS_RELATIONSHIP = 10#
IS_CUSTOM = 11#
IS_AUTHORED = 12#