provcat.resolver

Resolvers turn a logical URI into a physical URI.

Resolver is the interface. TemplateResolver is the default implementation. It reads the schemes and stages sections of the configuration::

schemes:
  data+table:
    parts: [org, domain, env, family, name]   # names for authority + segments
    target: "lakefs://{org}-{domain}/{ref}/tables/{family}/{name}"
    ref: "{env}"                               # default for {ref}; may name parts
    match: {org: "[a-z0-9]+", domain: "[a-z0-9]+"}   # each part must match
  code:
    parts: [org, repo]
    rest: path              # extra segments are joined into {path}
    target: "github://{org}/{repo}/{path}"
    pass_selector: true     # hand ?at= on to the physical URI
  # tenant: org             # the part that names the tenant (see below)

stages:
  "data+table://acme/shared/prod/agreements/qa_outputs":
    production: "commit:b8a2f9c"

Selectors on a logical URI:

Template variables are the part names, the rest name, ref, version and at (the whole selector as kind:value). Each value is percent-encoded before it goes into the template, so a value can never add a path segment or a ?at= to the physical URI.

With pass_selector, the physical URI gets the selector that the resolver used: a stage becomes the selector it points at, and a scheme with a ref default passes branch:<ref> when the URI has no selector. With version:, only the version is passed.

tenant names the part that says whose a URI is, for example org. A resolver made for one tenant refuses a URI of another tenant of such a scheme. A scheme without tenant serves every tenant.

match gives a regular expression for a part. A URI whose part does not match the whole expression is refused, so that names such as lakeFS repository names stay valid and cannot run together.

Entries send one logical name, or every name under a prefix, somewhere other than the template of its scheme::

entries:
  "code://acme/tokenizer/prod":
    target: "github://acme/tokenizer/{path}?at=branch:prod"
  "code://acme/tokenizer/prod/weights":
    target: "hf://models/acme/tokenizer/{path}"
  "data+table://acme/shared/prod/corpora":
    target: "lakefs-acme://acme-corpora/{ref}/{path}"
    ref: main

class Resolution

source

Resolution(logical: Uri, physical: Uri, via: tuple[str, ...] = (), ts_branch: str | None = None)

The answer of a lookup: the URI asked for, the physical URI it names, and how.

Parameter Type Default Description
logical Uri required The URI asked for; for a physical URI, the URI itself
physical Uri required The physical URI, whose scheme names a store
via tuple[str, …] () The steps taken, for people to read
ts_branch str | None None The branch of a ts: that the physical URI has no place for

class Resolver

source

The interface of a resolver, which turns logical URIs into physical ones.

Resolver.handles

source

Resolver.handles(scheme: str) -> bool

Tell whether this resolver resolves the URIs of a scheme.

Parameter Type Default Description
scheme str required A URI scheme
returns bool Whether scheme is a logical scheme of this resolver

Resolver.resolve

source

Resolver.resolve(uri: Uri) -> Resolution

Turn a logical URI into a physical one.

Parameter Type Default Description
uri Uri required A logical URI of a scheme that this resolver handles
returns Resolution The physical URI and the steps taken; ResolveError when the URI does not fit

class TemplateResolver

source

TemplateResolver(schemes: dict | None = None, stages: dict | None = None, tenant: str | None = None, entries: dict | None = None, refs_in_path: Callable[[str], bool | None] | None = None)

The default resolver: fills the target template of a scheme, or of an entry, from the parts of the URI.

Parameter Type Default Description
schemes dict | None None The schemes section: each logical scheme’s parts, target and rules
stages dict | None None The stages section: for each logical URI, stage names and their selectors
tenant str | None None The tenant of the catalog; a scheme with tenant: refuses another tenant’s URIs. None serves every tenant
entries dict | None None The entries section: targets for one logical name or a prefix
refs_in_path Callable[[str], bool | None] | None None Given a store name: False for a bucket, which keeps only branches in its path, True for a store such as lakeFS, None for a name it does not know. None takes every store to keep refs in its path

TemplateResolver.handles

source

TemplateResolver.handles(scheme: str) -> bool

Tell whether scheme is one of the configured logical schemes.

Parameter Type Default Description
scheme str required A URI scheme
returns bool Whether the schemes section names it

TemplateResolver.serves

source

TemplateResolver.serves(uri: Uri) -> bool

Tell whether this resolver serves a URI; it refuses one of another tenant.

Parameter Type Default Description
uri Uri required A logical URI
returns bool False when it names another tenant than this resolver’s

TemplateResolver.resolve

source

TemplateResolver.resolve(uri: Uri) -> Resolution

Resolve a URI through the entry with the longest matching key, or else the template of its scheme. A stage: selector becomes the selector it points at.

Parameter Type Default Description
uri Uri required A logical URI of a configured scheme
returns Resolution The physical URI from the entry or the template, and the steps taken; ResolveError when the URI does not fit