ursa.data_interface¶
Credential isolation¶
A fresh :class:DataInterface opens against the assets_ro
credential role only. Calling any register_* method before
- meth:
enable_writesraises :class:~ursa.catalog.WritesNotEnabled— production callers must explicitly request theassets_rwrole.- meth:
enable_writeslazily builds a second :class:Cataloghandle againstassets_rw. The public read surface (query,list_*,get_*, :attr:catalog) always uses the RO handle.register_*runs on the RW handle — including its internal idempotencyget_*lookup in :mod:ursa.register, so the check-and-write happen under a single credential and the read-modify-write race window stays tight.
Lazy construction¶
R2 profiles do not resolve 1Password credentials at construction; the
underlying :class:Catalog is built on first access to :attr:catalog
(reads) or :meth:enable_writes (writes). This keeps offline /
sandboxed environments (CI, doc builds) able to import and instantiate
- class:
DataInterfacewithout anopsession. Argument validation (profilevalue,pathconstraints) still runs eagerly so caller mistakes surface immediately.
Coexistence with the existing surface¶
The module-level :func:ursa.query / :func:ursa.get /
- func:
ursa.download/ :mod:ursa.registerfunctions remain wired up;- class:
DataInterfaceis purely additive in PR 1. Internal callers migrate in PR 3a; the module-level forms are deleted in PR 3b.
Profile threading caveat (PR 1)¶
- meth:
getand :meth:downloaddelegate to module-level- func:
ursa.get.getand :func:ursa.download.download, which resolve the segment store via the process-ambientURSA_PROFILEenv var rather than theDataInterface(profile=...)argument. Callers must ensureURSA_PROFILEagrees with the profile passed here. Threadingprofilethrough those module-level functions is tracked as a follow-up under ENG-1107.
User-facing class surface for Ursa (ENG-1108).
- class:
DataInterfacepackages the three M2 read verbs (:mod:ursa.query, :mod:ursa.get, :mod:ursa.download), the four- mod:
ursa.registerwrite verbs, and the typed per-tablelist_<table>/get_<table>lookups behind a single object that owns its :class:~ursa.catalog.Cataloghandles.
Module Contents¶
Classes¶
Class-based entry point for Ursa’s read + register API. |
Data¶
API¶
- ursa.data_interface.__all__¶
[‘DataInterface’]
- ursa.data_interface._Profile¶
None
- class ursa.data_interface.DataInterface(profile: ursa.data_interface._Profile = 'r2', *, path: str | pathlib.Path | None = None)[source]¶
Class-based entry point for Ursa’s read + register API.
Construction validates arguments but defers credential resolution (R2 profiles) until first use. Call :meth:
enable_writesonce before invoking anyregister_*method; that promotion is idempotent.Parameters
profile
"r2"(default) for the production catalog,"r2-test"for the testing bucket,"local"for an on-disk lance directory. path Required whenprofile="local". Forbidden for R2 profiles — their URI is resolved from the configured object store.Initialization
- property catalog: ursa.catalog.Catalog¶
The read-only catalog handle.
Constructed on first access; subsequent accesses return the cached handle. Always returns the RO catalog, even after
- Meth:
enable_writes— credential isolation is enforced.register_*methods use a separate write handle internally.
- property writes_enabled: bool¶
- enable_writes() None[source]¶
Open the
assets_rwwrite handle.Idempotent — a second call is a no-op. For
profile="local", local lance has no credential distinction, so the bool flip is the only observable effect;register_*methods fall back to the read handle.
- _write_catalog() ursa.catalog.Catalog[source]¶
The write-capable catalog handle.
Raises :class:
WritesNotEnabledif :meth:enable_writeshasn’t been called. Forprofile="local", falls back to the same underlying handle as :attr:catalog— there is no credential distinction to enforce locally.register_*callers route both the idempotencyget_*check and theadd_*write through this handle so the check-and-write run under one credential.
- query(spec: ursa.query.QuerySpec | None = None, **kwargs: Any) ursa.query.QueryResultList[source]¶
Delegate to :func:
ursa.query.querywith the RO catalog.
- get(target: ursa.query.QueryResult | collections.abc.Iterable[ursa.query.QueryResult], *, concat: bool = False) ursa.temporal.Data | list[ursa.temporal.Data][source]¶
Delegate to :func:
ursa.get.get.See the module docstring’s profile-threading caveat —
URSA_PROFILEmust matchDataInterface(profile=...).
- download(target: ursa.query.QueryResult | collections.abc.Iterable[ursa.query.QueryResult], dest: str | os.PathLike[str], *, layout: Literal[by_recording, by_modality, flat] = 'by_recording', overwrite: bool = False) list[pathlib.Path][source]¶
Delegate to :func:
ursa.download.download.See the module docstring’s profile-threading caveat —
URSA_PROFILEmust matchDataInterface(profile=...).
- register_participant(*, participant_id: str, enrolled_at: int | datetime.datetime, metadata: dict[str, Any] | None = None) ursa.catalog.ParticipantRow[source]¶
- register_recording(*, recording_hash: str, participant_ids: list[str], start_time: int | datetime.datetime, duration: datetime.timedelta, device_info: dict[str, Any] | None = None, metadata: dict[str, Any] | None = None) ursa.catalog.RecordingRow[source]¶
- register_modality(*, recording_hash: str, modality: str, raw_storage_uri: str, storage_uri: str | None = None, ingestion_status: ursa.catalog.IngestionStatus = IngestionStatus.RAW, format: ursa.catalog.StorageFormat | None = None, domain_intervals: list[tuple[float, float]] | None = None, sampling_rate: float | None = None, channel_spec: dict[str, Any] | None = None, metadata: dict[str, Any] | None = None) ursa.catalog.ModalityRow[source]¶
- register_event(*, event_id: str, recording_hash: str, event_time: float, event_type: str, prompt: str | None = None, response: str | None = None, metadata: dict[str, Any] | None = None) ursa.catalog.EventRow[source]¶