testing.ObjectBackend

The operations tether needs from one class of system.

Usage

Source

testing.ObjectBackend()

listing, diff, and history have default implementations (no listing; capability errors) so backends without DIFF / HISTORY need not define them.

Locators may carry an at field naming a specific native state (a snapshot id, version, commit, or tag). A backend that supports it treats the object as detached there: fingerprint(locator, None) returns that state instead of the base branch’s head, so commit pins it and new forks from it. Once a working ref exists it takes precedence.

Attributes

Name Description
KEY_SUFFIXES For a kind whose positional locator (uri) is a path or URI: the store
LOCAL_PATH_KEYS Locator keys whose value may be a local filesystem path. The engine
LOCAL_PATH_PREFIXES Prefixes a LOCAL_PATH_KEYS value may carry before its path
MATURITY How much the backend has been exercised: "stable" runs its full
PROMOTE_HINT What to tell a user when tether cannot move the base branch (no
SAFE_CONFIG_KEYS [backends.<kind>] keys the committed tether.toml may set. A clone
SAFE_OPTION_KEYS For each committed option table (storage_options, catalog), the
URI_KEYS Locator keys that name the object’s store, in order of preference; the
VOLATILE_KEYS State keys that address the data without identifying it – a Neon LSN

KEY_SUFFIXES

For a kind whose positional locator (uri) is a path or URI: the store

KEY_SUFFIXES: tuple[str, …] | None = None

suffixes default_key() drops from its last segment (.icechunk in greetings.icechunk); () drops none. None: the locator is not a path, and an object of this kind is always registered with a key.


LOCAL_PATH_KEYS

Locator keys whose value may be a local filesystem path. The engine

LOCAL_PATH_KEYS: tuple[str, …] = ()

turns a relative one into an absolute path when the object is registered (add, import), against the caller’s working directory, so a committed locator means the same path from every directory and every clone.


LOCAL_PATH_PREFIXES

Prefixes a LOCAL_PATH_KEYS value may carry before its path

LOCAL_PATH_PREFIXES: tuple[str, …] = ()

(DuckLake’s ducklake: or ducklake:sqlite:), which would otherwise read as a URL scheme. The path after the longest matching prefix is resolved like a bare one.


MATURITY

How much the backend has been exercised: "stable" runs its full

MATURITY: str = "stable"

lifecycle against the real system in CI (embedded stores and libraries); "experimental" is tested against a fake of a network service and has not been run against the service itself by the maintainers. tether backends prints it; add mentions it for experimental kinds.


PROMOTE_HINT

What to tell a user when tether cannot move the base branch (no

PROMOTE_HINT: str = ""

PROMOTE / MERGE, or the base diverged and there is no merge).


SAFE_CONFIG_KEYS

[backends.<kind>] keys the committed tether.toml may set. A clone

SAFE_CONFIG_KEYS: frozenset[str] = frozenset()

arrives with that file, so anything that chooses an executable, an endpoint credentials are sent to, SQL to run, or which environment variable holds a secret must come from the untracked .tether/secrets.toml or the environment instead. A key whose value is a table (such as storage_options) must also appear in SAFE_OPTION_KEYS; see check_committed_config().


SAFE_OPTION_KEYS

For each committed option table (storage_options, catalog), the

SAFE_OPTION_KEYS: Mapping[str, frozenset[str]] = {}

keys a clone may set inside it. An allowlist, not a pattern: a key the backend has not named is refused, so a new endpoint- or credential-shaped option cannot slip through by spelling. Everything else in that table comes from secrets.toml, where the same table may hold any key.


URI_KEYS

Locator keys that name the object’s store, in order of preference; the

URI_KEYS: tuple[str, …] = ("uri", "path")

per-URI entries of secrets.toml are matched against the first present.


VOLATILE_KEYS

State keys that address the data without identifying it – a Neon LSN

VOLATILE_KEYS: frozenset[str] = frozenset()

that advances on checkpoints, a change id derived from a sha. They stay in the state (pin and open need them) but are excluded from equality and from pin ids; see content_state().

Methods

Name Description
ancestor_of() Whether ancestor is in descendant’s history (None: unknown).
base_branch() The upstream branch a locator names: what the trunk bookmark stands
branch_scope() The native resource that owns branches, as a stable string.
configure_cache() Tell the backend where it may keep per-workspace scratch state.
configure_checkout() Tell the backend where the dataset’s VCS checkout is.
configure_secrets() Receive the untracked per-checkout settings for this kind.
create() Make an empty store at locator and write the owner marker for
default_key() The key add gives an object registered without one: the last
delete_store() Remove the store. Called only after is_ref_empty() returned
delete_working_ref() Delete a working ref created by fork(). Requires FORK.
diff() Describe what changed from state a to state b. Requires DIFF.
fingerprint() Read the current state at working_ref (or the locator’s base).
fork() Create a writable branch name off source. Requires FORK.
history() List native history, newest first, starting at ref (default: base).
identity() Locator subset that participates in the content-addressed pin id.
is_ref_empty() Whether nothing remains in the store but its base branch at the
list_pins() Return pin ids that currently exist natively. Requires PIN.
list_working_refs() Native branches created by fork() (tether.ws.*). Requires FORK.
listing() Optional detailed description of state to store alongside it.
merge() Three-way merge source into the base branch.
open() Return a native handle for a target.
owner() The dataset id in the store’s owner marker, or None when tether
pin() Create a durable native ref for state. Requires PIN.
promote() Fast-forward the locator’s base branch to source. Requires PROMOTE.
ref_namespace() The native resource whose pins list_pins returns, as a string.
rename_pin() Give the pin old (which names state) the id new_id.
rename_working_ref() Rename working branch old to new; return the resulting ref.
secret_rule_for() The one object’s own secrets.toml entry – the longest matching
secrets_for() Credential options for one object: the longest matching URI prefix
state_addressable() Whether this recorded state can be opened again later.
unpin() Release a pin. Requires PIN.
validate_locator() Refuse a locator this backend must never be handed.
verify() Check that state/pin still hold.
working_ref_blockers() Why ref cannot be deleted right now, or None if it can.

ancestor_of()

Whether ancestor is in descendant’s history (None: unknown).

Usage

Source

ancestor_of(locator, ancestor, descendant)

Used by promote when no fork point was recorded. Default: unknown.


base_branch()

The upstream branch a locator names: what the trunk bookmark stands

Usage

Source

base_branch(locator)

for, promote moves, and a trunk working copy writes to. Default locator["branch"] (main); git uses the checked-out branch when the locator has no ref.


branch_scope()

The native resource that owns branches, as a stable string.

Usage

Source

branch_scope(locator)

Two objects with the same scope share one branch namespace: a fork under a bookmark creates one branch for both, and the engine forks it once and lets every member write through it. Defaults to the canonical identity (one object per system). Override where several objects legitimately live in one branch space – a Neon project, an Iceberg table with several object keys – and where the identity carries fields the branch does not (a database, a source branch).


configure_cache()

Tell the backend where it may keep per-workspace scratch state.

Usage

Source

configure_cache(cache_dir)

Called by the engine after construction with .tether/cache/ (untracked). Backends that remember expensive results between runs – the file backend keeps a stat -> content-hash cache there – store them under this directory; everything else ignores the call.


configure_checkout()

Tell the backend where the dataset’s VCS checkout is.

Usage

Source

configure_checkout(root)

Called by the engine after construction. Every file under root arrived with the clone, so a backend that would run something a directory there configures – the git backend reads a repository’s config – refuses paths inside it; everything else ignores the call.


configure_secrets()

Receive the untracked per-checkout settings for this kind.

Usage

Source

configure_secrets(defaults, rules)

defaults is the merged [backends.<kind>] (committed allowlisted keys under the secrets file’s); rules maps a URI prefix to the credential options for objects under it (the engine folds [objects."<key>"] entries in as exact-URI rules). Backends read them through secrets_for().


create()

Make an empty store at locator and write the owner marker for

Usage

Source

create(locator, *, owner)

owner (a dataset id); return its initial state. Requires CREATE.

Raises
BackendError
Anything already exists there – create never adopts a store someone else made.

default_key()

The key add gives an object registered without one: the last

Usage

Source

default_key(locator)

segment of the locator’s uri (or path), less one of KEY_SUFFIXES. None when this kind names no path or no valid key comes out.


delete_store()

Remove the store. Called only after is_ref_empty() returned

Usage

Source

delete_store(locator)

True for it, and only for a store whose owner() is the caller’s dataset – and expected to check both again itself, right before the irreversible step. Requires CREATE.


delete_working_ref()

Delete a working ref created by fork(). Requires FORK.

Usage

Source

delete_working_ref(locator, ref)

diff()

Describe what changed from state a to state b. Requires DIFF.

Usage

Source

diff(locator, a, b, *, listings=(None, None))

fingerprint()

Read the current state at working_ref (or the locator’s base).

Usage

Source

fingerprint(locator, working_ref)

fork()

Create a writable branch name off source. Requires FORK.

Usage

Source

fork(locator, source, name, *, expected=None)

source is a ~tether.manifest.Pin (fork from the native ref) or a recorded State (fork directly from an addressable state, used by policy.pin == "record" objects that carry no native ref).

Reset contract: if name already exists it is moved back onto source (whatever was written on it is discarded); a branch already at source is left alone. The conformance suite checks this.

Conditional move: expected is the head name must hold for the move to happen – the state the caller reviewed, or ABSENT when the branch must not exist yet. When it holds something else, raise ~tether.errors.RefMovedError and move nothing (compare content states: VOLATILE_KEYS may differ). None moves unconditionally, as before 0.1.0b4; see accepts_expected() for how the engine treats a backend whose signature predates the keyword.


history()

List native history, newest first, starting at ref (default: base).

Usage

Source

history(locator, ref=None, limit=20)

Requires HISTORY. Metadata only; limit bounds the walk.


identity()

Locator subset that participates in the content-addressed pin id.

Usage

Source

identity(locator)

Defaults to the full locator; override to exclude non-identity fields (region, credential references, source branch, …).


is_ref_empty()

Whether nothing remains in the store but its base branch at the

Usage

Source

is_ref_empty(locator, *, ignoring=())

initial state, the owner marker, and the refs in ignoring (the ones a gc plan is about to delete). A store with a working area (a git checkout, a directory) must also hold no uncommitted content: files are data whether or not a ref names them. Requires CREATE.

None means the backend cannot tell – and None means keep: a store is only ever removed on a definite True.


list_pins()

Return pin ids that currently exist natively. Requires PIN.

Usage

Source

list_pins(locator)

list_working_refs()

Native branches created by fork() (tether.ws.*). Requires FORK.

Usage

Source

list_working_refs(locator)

Default: none. Used by gc --prune-bookmarks.


listing()

Optional detailed description of state to store alongside it.

Usage

Source

listing(locator, state)

The engine writes the text content-addressed under .tether/listings/ at commit time and hands both sides back to diff() later. Used by backends whose state is a digest (the file backend’s directory and prefix listings) so Observed states can still be diffed.


merge()

Three-way merge source into the base branch.

Usage

Source

merge(locator, source, message, *, expected=None)

source is a working ref, a Pin, or a State. The engine passes the state the plan reviewed, so what is merged is what was shown – a ref is a name someone can move between plan and apply. Requires MERGE. Raises ~tether.errors.MergeConflict (and leaves the base untouched) when the system reports conflicts, and ~tether.errors.RefMovedError when expected is given and the base head is not that state. Returns the base branch’s new state.


open()

Return a native handle for a target.

Usage

Source

open(locator, target, read_only)

target is one of: None (the base/working ref), a str working ref, a ~tether.manifest.Pin (read a pinned state), or a recorded State mapping (read an addressable state without a pin).


owner()

The dataset id in the store’s owner marker, or None when tether

Usage

Source

owner(locator)

never wrote one (or the store is gone). Requires CREATE.


pin()

Create a durable native ref for state. Requires PIN.

Usage

Source

pin(locator, state, pin_id)

promote()

Fast-forward the locator’s base branch to source. Requires PROMOTE.

Usage

Source

promote(locator, source, *, expected=None)

source is a working ref name, a ~tether.manifest.Pin, or a recorded State. Implementations must refuse (BackendError) when the base head is not an ancestor of source – a fast-forward never discards anything – and be a no-op when the base is already there. expected is the base head the caller reviewed: when the base holds another state, raise ~tether.errors.RefMovedError and move nothing (a compare-and-swap where the system has one – git’s update-ref with an old value, Icechunk’s from_snapshot_id on an object store; see Capability.CONDITIONAL_REF). Returns the base branch’s new state.


ref_namespace()

The native resource whose pins list_pins returns, as a string.

Usage

Source

ref_namespace(locator)

gc compares the pins it lists against the pins every object in that namespace references; listing a project-wide namespace against one object’s references would release the others’ pins. Defaults to the canonical identity.


rename_pin()

Give the pin old (which names state) the id new_id.

Usage

Source

rename_pin(locator, old, state, new_id)

Used by tether upgrade when the pin naming scheme changes. Default: pin() the state under the new id, then unpin() the old one – which works wherever pins are tags. Backends whose pins are branches with children (Neon) rename in place instead.


rename_working_ref()

Rename working branch old to new; return the resulting ref.

Usage

Source

rename_working_ref(locator, old, new)

Used by tether upgrade when the branch naming scheme changes. Default: fork new from old’s head state and delete old. Requires FORK and a backend that can fork from a state.


secret_rule_for()

The one object’s own secrets.toml entry – the longest matching

Usage

Source

secret_rule_for(locator)

URI-prefix rule, without the kind defaults secrets_for layers it on; empty when none matches.


secrets_for()

Credential options for one object: the longest matching URI prefix

Usage

Source

secrets_for(locator)

rule over the kind defaults; empty when nothing applies (the backend then falls back to the environment, as it always did).


state_addressable()

Whether this recorded state can be opened again later.

Usage

Source

state_addressable(locator, state)

The capability says the backend can address states in general; a particular fingerprint may still lack the coordinate (an object in a bucket without versioning has no version_id). commit records such a state as not recoverable instead of promising a read it cannot do.


unpin()

Release a pin. Requires PIN.

Usage

Source

unpin(locator, pin)

validate_locator()

Refuse a locator this backend must never be handed.

Usage

Source

validate_locator(locator)

Called when an object is registered (add, import) so the refusal comes with the manifest’s author present, not at the first read of a clone. Default: accept. Raise BackendError to refuse.


verify()

Check that state/pin still hold.

Usage

Source

verify(locator, state, pin, deep)

working_ref_blockers()

Why ref cannot be deleted right now, or None if it can.

Usage

Source

working_ref_blockers(locator, ref)

Consulted by gc --prune-bookmarks and forget-workspace before planning a delete-branch, so an undeletable branch is planned as kept with the reason instead of failing at apply time. Neon: a branch with children (pins taken on it) cannot be deleted until they are. Default: no blockers.