Skip to content

Connecting and creating

Use connect to read a database that someone else runs. It takes the token you read with, which decides what you may see, though a server started with mosaica serve --open needs none. If the operator has not issued you a token, login makes one from your own password, API key or OIDC access token. A back end that signs in its own users calls authorise instead, which makes a token for any local principal, OIDC identity or set of access terms, or the operator's own token.

Use create or open when the database is your own. Each gives a Database kept in a directory, which starts its own server when a commit or a read first needs it.

connect

connect(url: str, token: Optional[TokenSource] = None) -> Viewer

Connect to a Mosaica database someone else runs, returning a Viewer that reads what the token's terms admit.

  • url: the address of the database's viewer plane.
  • token: the token the database's operator issued you, in any of the forms TokenSource describes. Leave it out for a server started with mosaica serve --open.
v = mosaica.connect("https://maps.example/viewer", token=my_token)
v.view("papers").count()
v = mosaica.connect(url, lambda: mosaica.login(url, api_key=my_key))

create

create(
    path: str | PathLike | None = None,
    replace: bool = False,
    port: int | None = None,
) -> Database

Make a new, empty database in a directory, and return it as a Database.

  • path: the directory, which must be empty or not yet exist. Without it the database goes in a temporary directory, in memory where the system offers one (/dev/shm on Linux), which is deleted as close() describes.
  • replace: True deletes a Mosaica database already at path first. A non-empty directory that is not a Mosaica database is refused either way.
  • port: the port its server listens on, on this machine only, and the database keeps it. A taken port is refused when the server starts, and 0 lets the system choose a free one. None, the default, serves on 9141, or on the next free port above it when 9141 is taken. The server prints the address it serves at when it starts.
db = mosaica.create()
db = mosaica.create("~/maps/papers", replace=True, port=9200)

open

open(path: str | PathLike, port: int | None = None) -> Database

Reopen a database kept in a directory, and return it as a Database.

A committed database reopens ready to read, and its next commit adds to it. A database saved before its first commit reopens with its declarations and inserts as they were left.

  • path: the database's directory, which holds its mosaica.toml, or before its first commit the package's own record of it.
  • port: the port its server listens on from now on, as create() describes. None, the default, keeps the one the database was served on.

A temporary directory that a crashed process left behind opens too, unless another live process has it open. The next create() removes it once you close it, so call save(path) on it to keep a copy.

db = mosaica.open("~/maps/papers")
db.view("papers").count()

Database

A Mosaica database kept in a directory, which you fill from data frames and then read.

Make one with create(), or reopen one with open(). You describe what the database holds with the declare_* methods before handing each declared thing a table with insert, which names the columns to read from it. Nothing reaches the database until commit, which builds it and starts its server the first time.

Reads go through that server with the operator's own token, which authorise describes under read_all. To read as someone who holds only some access terms, call viewer(terms).

db = mosaica.create()
db.declare_view("papers")
db.insert("papers", frame, x="x", y="y", access="labels")
db.commit()
db.view("papers").count()

Its attributes:

  • path: the directory the database is kept in.
  • temporary: True when create() made the database in a temporary directory, which close() deletes.
  • built: True once the first commit has built the database.
  • inserts: the Insert records made before the first commit, which that commit builds from.
  • pending: the Insert records made since the last commit, which the next commit sends.
  • listening: the addresses the server listens on, as serve() returns them, or None while the server is not running.
  • port: the port stated at create() or open(), or None when none was.

binary property

binary: str

The path of the mosaica program that checks, builds and serves this database.

The program is the one MOSAICA_BIN names, then the one the mosaica-native wheel installed, then a build in a Mosaica checkout, whichever is found first. A mosaica on PATH is used only when MOSAICA_BIN names it. Reading this raises Refusal when none is found.

save

save(path: str | PathLike) -> Path

Copy the database's directory to path, and return that path.

Because a temporary database is deleted when it is closed, saving it is how you keep one. The copy is an ordinary database, which open(path) reopens and mosaica serve --deployment <path>/mosaica.toml serves. A Parquet file inserted from outside the database's directory stays where it is, and the copy reads it from there.

  • path: the directory to copy into, outside the database's own, which must be empty or not yet exist.

close

close() -> None

Stop the database's server, and delete its directory if the database is temporary.

After close() a temporary database refuses every call, because its directory is gone, while any other database starts its server again when a call needs it.

The server also stops when nothing refers to the database any more, and when Python exits, however it exits. A temporary database's directory is deleted then too, except after a process that ended without running its exit handlers, such as a killed one, when a later create() removes it. A Map or a Selection refers to the database it reads, which keeps the server running while you hold one. Tokens the database made stay valid until they expire, within the hour, unless revoke ends them sooner.

token

token(terms: Sequence[str] | None = None) -> Token

Make a token that reads this database with the access terms given.

Pass the token to connect or Map to read as someone who holds it.

  • terms: the access terms the token holds, as a list or as one term in a string. Without them the token is the operator's own, which authorise describes under read_all.
token = db.token(["cs.LG"])

revoke

revoke(token) -> None

End a token this database made, so that it can no longer read.

  • token: the Token, or its token_id.

An id that names no live token is accepted. A reader holding the Token can still get another with its renew(), as mosaica.revoke describes.

viewer_url property

viewer_url: str | None

The address that readers read the database from, or None while the server is not running.

session_url property

session_url: str | None

The address that tokens for the database are made at, or None while the server is not running.

operator_credential property

operator_credential: str

The secret that gives full control of this database's server.

control, token and viewer use it. The secret is kept in the database's directory, and the package sends it only to the database's own server on this machine.

Token dataclass

A token that lets its holder read a Mosaica database until its session ends.

login and authorise return one, and connect, Map and logout take one or its token string. Printing a token shows its expiry, its principal and how many terms it holds, and leaves the token string out, so that the secret does not end up in a saved notebook or a log.

  • token: the secret string a reader sends with each request. Anyone who holds it reads as the token's principal.
  • expires_at: when the token's session ends, in seconds since 1970, or None when that is not known. A catalogue change, such as a grant to its principal, can end it sooner.
  • token_id: the id revoke takes to end the token without sending the token again. Only a token authorise made has one, and it is None otherwise.
  • renew: a function that makes a fresh token from the credential that made this one, which therefore stays in this process. It is set when login or authorise made the token and is None otherwise. A reader from connect and a Map call it when the token is about to expire, or when a 403 expired-token answer says that its session has ended.
  • principal: the local principal the token reads as, when authorise made it for one or login was given a password, and None otherwise.
  • terms: the access terms the token holds, when authorise made it for a set of terms, and None otherwise.

seconds_left property

seconds_left: Optional[float]

Seconds until the token expires, or None if its expiry is not known.

TokenSource module-attribute

TokenSource = Union[str, Token, Callable[[], Union[str, 'Token']]]

The forms in which connect, Viewer and Map take a token: the token string, a Token, or a function that returns either.

A reader gets a fresh token when the one it holds is about to expire, or when a 403 expired-token answer says that its session has ended. It renews a Token with the token's own renew and calls a function again, while it sends a plain string unchanged until the server refuses it. A function is therefore the way to hand a reader tokens that your own code makes.

login

login(
    viewer_url: str,
    *,
    principal: Optional[str] = None,
    password: Optional[str] = None,
    api_key: Optional[str] = None,
    access_token: Optional[str] = None,
    timeout: float = 10.0,
) -> Token

Log in to a Mosaica database and return a token that reads as the principal the credential belongs to.

  • viewer_url: the address of the database's viewer plane, where readers read.
  • principal, password: a local principal's name and password, given together.
  • api_key: an API key the database's operator issued.
  • access_token: an OIDC access token from a provider the database accepts.
  • timeout: how long to wait for the server, in seconds. The default is 10.

Any combination but exactly one of the three credentials raises ValueError, as a missing viewer_url does. The principal must hold the read permission. The server answers every credential it does not accept with the same refusal, which raises PermissionError, so the error does not reveal whether a principal exists.

token = mosaica.login(viewer_url, principal="ann", password=password)
mosaica.connect(viewer_url, token).view("papers").count()

logout

logout(
    viewer_url: str, token: Union[str, Token], *, timeout: float = 10.0
) -> None

End a token's session, so that the token can no longer read.

  • viewer_url: the address of the database's viewer plane.
  • token: the token to end, as a string or a Token.
  • timeout: how long to wait for the server, in seconds. The default is 10.

A token the server does not recognise, or whose session has already ended, raises PermissionError.

authorise

authorise(
    session_url: str,
    credential: str,
    *,
    principal: Optional[str] = None,
    access_token: Optional[str] = None,
    terms: Optional[Sequence[str]] = None,
    read_all: bool = False,
    timeout: float = 10.0,
) -> Token

Make a token on the session plane that reads as a local principal, an OIDC identity, a set of access terms or the operator.

An application that signs its own users in calls this from its back end, with an API key, to give each user a token that reads as them.

  • session_url: the address of the database's session plane, where tokens are made.
  • credential: an API key whose principal holds authorise-as, or the operator credential. Either one can make a token that reads as anyone.
  • principal: the name of a local principal to read as. The token carries the principal's terms and its read and write permissions, and none of its others, such as read-all. The principal must hold read.
  • access_token: the OIDC access token of an identity to read as, which the server checks as login does. The token carries the identity's terms and permissions as for principal.
  • terms: the access terms the token holds, as a list or one term as a string, for a reader the catalogue does not name. The token holds them and read. Only the operator credential may send terms.
  • read_all: True makes the operator's own token, which holds read-all and so reads every item that is not deleted or suppressed, including items committed after the token was made. Only the operator credential may send it.
  • timeout: how long to wait for the server, in seconds. The default is 10.

Name exactly one of principal, access_token, terms and read_all. Anything else, or an empty session_url or credential, raises ValueError, and a request the server refuses raises PermissionError, whose message holds the server's status and answer. A Database makes these tokens with its own operator credential through db.token(terms) and db.viewer(terms).

token = mosaica.authorise(session_url, api_key, principal="ann")
token = mosaica.authorise(session_url, operator_credential, terms=["cs.LG"])
mosaica.connect(viewer_url, token).view("papers").count()

revoke

revoke(
    session_url: str,
    credential: str,
    token_id: Union[int, Token],
    *,
    timeout: float = 10.0,
) -> None

End a token that authorise made, so that it can no longer read.

  • session_url: the address of the database's session plane.
  • credential: the operator credential, which ends any token, or an API key, which ends only the tokens made with a key of its own principal.
  • token_id: the Token, or its token_id. Only the id is sent.
  • timeout: how long to wait for the server, in seconds. The default is 10.

The server accepts an id that names no live token without saying so, because any other answer would tell a caller which tokens exist. An empty session_url or credential, or a Token without a token_id, raises ValueError, and a request the server refuses raises PermissionError. A reader holding the Token can make another with its renew(), because the credential that made it keeps working.

mosaica.revoke(session_url, credential, token)

Refusal

Bases: ValueError

The exception the package raises when it will not make a call, or when the server refuses a request, with a message that says what was wrong and what to write instead.

Catching Refusal handles every refusal from a Database or a reader in one place. Code that catches ValueError catches it too, because Refusal is a ValueError. The token functions login, logout, authorise and revoke raise PermissionError for a request the server refuses, and Control returns each refusal in its Answer without raising.

  • status: the HTTP status of a read the server refused, and None for every other refusal.
  • retry_after_s: how many seconds to wait before sending the request again, set when the server answers 429 or names a wait, and None otherwise.
  • report: the report of a commit, remove, suppress, unsuppress or leave that applied nothing, which says what was refused and why, the dictionary Database.compact(wait=True) would have returned where the compaction did not succeed, and None otherwise.
try:
    db.commit()
except mosaica.Refusal as refused:
    print(refused.report)