Skip to content

Python package reference

Prepare H&E slides on your own machine, submit them to Aurora, and read the spatial gene expression it predicts.

These pages were built from version 0.1.0.dev7 of the package, which is unreleased. The last published version is 0.1.0.dev6, and a call on these pages may be missing from it. auroraomics --version prints the one you have.

The reference covers the public calls used in the guides. On your machine it opens a slide, checks and packs its tiles, embeds them and writes a result. Packing reads the service's quality standard without a key; embedding needs one. From Python, a shell or an agent it calls the hosted API with a key.

Install and prepare a slide walks through the basic workflow.

A plain install carries everything the documented path needs, and no deep-learning framework. Embedding tiles on your own machine takes the embed extra.

To send a slide without writing code, upload it on the website with Aurora Direct. From code, import auroraomics as ao gives you these names:

Name What it is
ao.AuroraomicsError Base for everything this package raises deliberately.
ao.Client A credential, a deployment, and the public API over both.
ao.Job One prediction job: its last known state, and the ways to move it forward.
ao.QcThresholds Quality settings supplied by Aurora for checking tiles.
ao.Tile One tile: an RGB uint8 image and its position on the slide.
ao.bulk_rna Prepare a bulk RNA profile as the table the bulk_rna covariate takes.
ao.embed_tiles Embed the tiles of one slide and write the embeddings container.
ao.login Sign in with an emailed code, accept the Terms, and store an API key on this machine.
ao.open_slide Open a slide at full resolution, ready to be cut into tiles.
ao.pack_tiles Write the tiles that pass quality control into one archive.
ao.qc_tile Check whether a tile is suitable for prediction and report the result.
ao.read_archive Validate an archive and return it, open for reading.
ao.resolve_encoder Select a compatible local image model from Aurora's catalogue.
ao.subsample_spatial_square Choose at most max_items of the given points, as a boolean mask.
ao.write_result Write one result file and return its path.

Opening a slide

The first step of both journeys: open the file, read its resolution, and hand back something the packers can cut, decoding only the squares they ask for.

auroraomics.slide

SlideError

Bases: AuroraomicsError, ValueError

Slide

path instance-attribute
path = path
mpp instance-attribute
mpp = mpp
recorded_mpp instance-attribute
recorded_mpp = recorded_mpp
shape instance-attribute
shape: tuple[int, int, int] = (int(page.shape[0]), int(page.shape[1]), 3)
close
close() -> None

open_slide

open_slide(path: str | Path, *, mpp: float | None = None, series: int = 0) -> Slide

Parameters:

Name Type Description Default
path str | Path

The slide file. Any pyramidal or plain TIFF this package's reader can open, which includes the .svs and .tif a scanner writes and the BigTIFF a converter produces from one.

required
mpp float | None

Micrometres per pixel, when the caller knows it. It OVERRIDES what the file records, because a converted file can carry a resolution its converter invented, and it is required when the file records none — this refuses rather than assuming a value.

What the file recorded is still read, and kept on the slide as recorded_mpp. An override that contradicts it is answered where the contradiction becomes geometry: pack_tiles and embed_tiles say so when the two numbers cut a different tile, and write which one was used into the archive.

None
series int

Which image in the file. 0 is the slide itself; a scanner also writes a label and a macro image, and those are not it.

0

Returns:

Type Description
Slide

Open. Use it as a context manager, or close it when the packing is done.

Raises:

Type Description
SlideError

If the reader is not installed, the file cannot be opened, the series is not a colour image, or no resolution was recorded and none was given.

Warns:

Type Description
UserWarning

If the file is stored as one compressed segment, or in segments so coarse that no two windows can share a decode. Those are the layouts where a window costs most of the image, and the ones this cannot make cheap. The module's own page lists the three layouts, what each costs, and the memory map that routes around this one.

Quality control

Whether a tile is worth predicting on. Every tile a model reads has passed this check, and a rejected tile reports why.

auroraomics.qc

QcThresholds dataclass

foreground_ratio instance-attribute
foreground_ratio: float
hsv_tissue_ratio instance-attribute
hsv_tissue_ratio: float
blur_laplacian_var instance-attribute
blur_laplacian_var: float
foreground_white_level class-attribute instance-attribute
foreground_white_level: int = 0
field_names classmethod
field_names() -> tuple[str, ...]
from_service classmethod
from_service(published: dict[str, Any]) -> QcThresholds
as_dict
as_dict() -> dict[str, float]

QcResult dataclass

foreground_ratio instance-attribute
foreground_ratio: float
hsv_ratio instance-attribute
hsv_ratio: float
laplacian_var instance-attribute
laplacian_var: float
rejected_by class-attribute instance-attribute
rejected_by: str | None = None
passes property
passes: bool
stat_names classmethod
stat_names() -> tuple[str, ...]
stats
stats() -> dict[str, float]

qc_tile

qc_tile(tile: ndarray, thresholds: QcThresholds) -> QcResult

Packing tiles

Build the patches archive a prediction takes, and check one you have received.

auroraomics.pack

PackError

Bases: AuroraomicsError, ValueError

ArchiveError

Bases: AuroraomicsError, ValueError

Tile dataclass

image instance-attribute
image: ndarray
x instance-attribute
x: int
y instance-attribute
y: int

PackReport dataclass

path instance-attribute
path: Path
written instance-attribute
written: int
rejected instance-attribute
rejected: int
rejected_by_reason instance-attribute
rejected_by_reason: dict[str, int]
rejections instance-attribute
rejections: tuple[Rejection, ...]
thresholds instance-attribute
thresholds: QcThresholds
mpp instance-attribute
mpp: float
out_of_bounds class-attribute instance-attribute
out_of_bounds: int = 0
kind class-attribute instance-attribute
kind: str = field(default=KIND, init=False)
considered property
considered: int

Rejection dataclass

x instance-attribute
x: int
y instance-attribute
y: int
reason instance-attribute
reason: str
stats instance-attribute
stats: dict[str, float]

PatchArchive

mpp property
mpp: float
close
close() -> None
read_tile
read_tile(name: str) -> np.ndarray
tiles
tiles() -> Iterator[Tile]
provenance
provenance() -> dict[str, Any] | None
thumbnail
thumbnail() -> np.ndarray | None

pack_tiles

pack_tiles(tiles: Any, out_zip: str | Path, *, mpp: float, thresholds: QcThresholds, patch_um: float | None = None, centers: Iterable[tuple[int, int]] | None = None, resize_px: int | None = None, thumbnail: ndarray | None = None, max_items: int | None = None) -> PackReport

Parameters:

Name Type Description Default
tiles Any

A slide: anything with a shape of (height, width, 3) that can be sliced image[y0:y1, x0:x1] into RGB uint8. It is cut here at patch_um, one crop at a time, so a slide larger than memory is packable as long as reading a region of it is.

Or the tiles themselves: any iterable of Tile, consumed lazily and one at a time, for a caller who cuts them from something this package cannot open.

required
out_zip str | Path

Where to write. An existing file is replaced.

required
mpp float

Micrometres per pixel of the tiles, at the resolution they were cut. Recorded for every tile: without it a tile is a picture of unknown physical size and no model can be matched to it.

required
patch_um float | None

The physical edge of one tile, in micrometres. Required when cutting from a slide and meaningless otherwise — tiles you hand in are already cut, and a size declared over them would be a second opinion about their own pixels — so passing it with tiles is refused rather than ignored. It is a property of the model you intend to submit to, not of your slide: it is what makes tiles cut from scans at two different resolutions the same measurement.

None
centers Iterable[tuple[int, int]] | None

Tile centres as (column, row) in full-resolution pixels, when cutting from a slide. Omitted, the slide is tiled regularly with no overlap. Refused alongside tiles, for the reason patch_um is.

None
resize_px int | None

The square, in pixels, the model reads each tile at, which the model's card states beside patch_um. Optional, and it changes nothing in the archive. Given, a slide coarse enough that each tile is enlarged three times or more to reach that square is said so in a warning naming the factor, because enlarging adds no detail the scan did not record. Refused alongside tiles, for the reason patch_um is.

None
thresholds QcThresholds

Quality-control floors, from the service that will run the submission (Client.qc_thresholds). Required, with no default: they are the service's, and the same for every model. They are recorded in the archive, so the file says which floors made it.

required
thumbnail ndarray | None

An optional RGB overview image, written as the container's thumbnail. Any metadata it carries is dropped, as for every tile.

None
max_items int | None

The most tiles to write. Omitted, the cap the shipped registry states for this input kind — the number the service refuses OVER rather than trimming to, so a slide that would produce an archive no submission can carry stops here rather than after the upload. Pass a number for a deployment whose cap differs.

The bound lives on this side and not in read_archive because this function has exactly one kind of caller: whoever is building a submission. Nothing on the serving side packs, so a cap here can never fire in front of a service's own refusal and take its wording with it.

None

Returns:

Type Description
PackReport

Counts, plus one Rejection per dropped tile naming the threshold that dropped it. A caller that gets an unexpectedly small archive can see immediately whether the slide was empty, a centre was off the edge, or a threshold was wrong.

Warns:

Type Description
UserWarning

When the slide file records a resolution that cuts a different tile from the one this run declares, and when the model's square is given and each tile will be enlarged three times or more to reach it.

Raises:

Type Description
PackError

If mpp is not a positive number, if the model's square is not a whole number of pixels of at least 1, if a slide is given without patch_um, if patch_um, centers or the model's square is given with tiles, or if the tiles that pass would exceed max_items. The refusal comes as the cap is reached rather than after the last tile, so a slide with ten times the budget costs a budget's worth of packing to find out and not ten. What is on disk then is an archive with no manifest, which read_archive refuses — a partial archive cannot be mistaken for a whole one.

read_archive

read_archive(zip_path: str | Path, *, max_items: int | None = None) -> PatchArchive

Parameters:

Name Type Description Default
max_items int | None

The most tiles this archive may hold, or None to not ask. Not read from the registry: a caller preparing a submission passes the registry's cap.

None

Raises:

Type Description
ArchiveError

On the first failure, naming what failed.

Embedding tiles locally

The embeddings observation: run DeepSpot-H over your tiles and send a short row of numbers per tile. Needs the embed extra and a key. The path is Your slides stay with you.

auroraomics.embed

EmbedError

Bases: AuroraomicsError, RuntimeError

EncoderRefused

Bases: EmbedError

EncoderUnavailable

Bases: EmbedError

NetworkRefused

Encoder dataclass

name instance-attribute
name: str
revision instance-attribute
revision: str
is_default instance-attribute
is_default: bool
refusal property
refusal: str | None
is_runnable property
is_runnable: bool

EmbedReport dataclass

path instance-attribute
path: Path
rows instance-attribute
rows: int
considered instance-attribute
considered: int
out_of_bounds instance-attribute
out_of_bounds: int
rejected instance-attribute
rejected: int
rejected_by_reason instance-attribute
rejected_by_reason: dict[str, int]
encoder instance-attribute
encoder: Encoder
patch_px instance-attribute
patch_px: int
dim instance-attribute
dim: int
kind class-attribute instance-attribute
kind: str = field(default=KIND, init=False)

resolve_encoder

resolve_encoder

embed_tiles

embed_tiles

Returns:

Type Description
EmbedReport

Counts, and the resolved encoder. A caller who gets an unexpectedly small file can see at once whether the slide was mostly glass, the centres were off the edge, or a threshold was wrong.

Warns:

Type Description
UserWarning

When the slide file records a resolution that cuts a different patch from the one this run declares, and when each patch will be enlarged three times or more to reach the square the encoder reads, naming the factor: enlarging adds no detail the scan did not record.

Raises:

Type Description
EncoderRefused

The encoder is known but this package will not run it, and the message says why.

EncoderUnavailable

The weights are not on this machine and could not be fetched.

available_encoders

available_encoders

default_encoder

default_encoder

describe_encoders

describe_encoders

Subsampling

When a slide yields more tiles than one submission takes, choose one dense region. A scatter of tiles leaves holes between them. Check tile quality says how.

auroraomics.subsample

MAX_GRID module-attribute

MAX_GRID = 500

SEED module-attribute

SEED = 42

subsample_spatial_square

subsample_spatial_square(x: ndarray, y: ndarray, max_items: int) -> np.ndarray

Parameters:

Name Type Description Default
x ndarray

Coordinates of each candidate spot, in the same units (pixels), one entry per spot.

required
y ndarray

Coordinates of each candidate spot, in the same units (pixels), one entry per spot.

required
max_items int

The budget. When there are no more points than this, every point is kept and no work is done.

required

Returns:

Type Description
ndarray

A boolean mask over the input order: True for the points to keep. Returning a mask rather than the selected coordinates lets the caller apply the same choice to everything it holds per spot.

Writing a result

The standard .h5ad, written with h5py alone and streamed batch by batch, so that a matrix larger than memory can still be written.

auroraomics.h5ad

ResultError

Bases: AuroraomicsError, ValueError

write_result

write_result(path: str | Path, *, obs: Mapping[str, Any] | None = None, var: Mapping[str, Any] | None = None, x: Any = None, obs_index: Sequence[Any] | None = None, var_index: Sequence[Any] | None = None, spatial: Any = None, uns: Mapping[str, Any] | None = None, layers: Mapping[str, Any] | None = None, obs_index_name: str = _DEFAULT_INDEX_NAME, var_index_name: str | None = None, dtype: Any = np.float32, compression: str | None = 'gzip') -> Path

Parameters:

Name Type Description Default
path str | Path

Where to write. An existing file is replaced.

required
obs Mapping[str, Any] | None

The per-spot and per-gene tables, as mappings of column name to a one-dimensional sequence. Text columns are stored as text; everything else keeps its numpy dtype.

None
var Mapping[str, Any] | None

The per-spot and per-gene tables, as mappings of column name to a one-dimensional sequence. Text columns are stored as text; everything else keeps its numpy dtype.

None
x Any

The expression matrix: either a two-dimensional array, or an iterable of row batches covering every observation in order. The iterable form is what makes a matrix larger than memory writable — see _write_matrix.

None
obs_index Sequence[Any] | None

Row and column names. Default to the positions as strings.

None
var_index Sequence[Any] | None

Row and column names. Default to the positions as strings.

None
var_index_name str | None

The name var's index carries in the file. Defaults to the gene identifier the shared result contract declares, so a reader knows what kind of identifier it is looking at without guessing.

None
spatial Any

An (n_obs, 2) array of spot coordinates, written to obsm["spatial"] — where every viewer looks for them.

None
uns Mapping[str, Any] | None

Free-form provenance, nested mappings allowed.

None
layers Mapping[str, Any] | None

Extra matrices of the same shape as x, each an array or an iterable of batches, written under layers/<name>.

None
dtype Any

The element type the matrix is stored as. Single precision by default, which is what the tools that read a result expect: half precision halves the file, is not enough precision for the statistics these matrices get fed to, and is refused outright by several of them.

float32
compression str | None

Passed to HDF5. "gzip" by default; None writes uncompressed.

'gzip'

Other formats

The same result as a SpatialData store or a folder Seurat loads. Result file reference shows both in use.

auroraomics.export

SPOTS module-attribute

SPOTS = 'spots'

TABLE module-attribute

TABLE = 'table'

REGION_KEY module-attribute

REGION_KEY = 'region'

INSTANCE_KEY module-attribute

INSTANCE_KEY = 'instance_id'

MATRIX_FILE module-attribute

MATRIX_FILE = 'matrix.mtx.gz'

FEATURES_FILE module-attribute

FEATURES_FILE = 'features.tsv.gz'

BARCODES_FILE module-attribute

BARCODES_FILE = 'barcodes.tsv.gz'

COORDINATES_FILE module-attribute

COORDINATES_FILE = 'coordinates.csv'

METADATA_FILE module-attribute

METADATA_FILE = 'metadata.csv'

FEATURE_TYPE module-attribute

FEATURE_TYPE = 'Gene Expression'

ExportError

Bases: AuroraomicsError, ValueError

ExportUnavailable

Bases: AuroraomicsError, RuntimeError

to_spatialdata

to_spatialdata(result: Any) -> Any

Parameters:

Name Type Description Default
result Any

The path of a result file, or the AnnData already read from one. An AnnData passed in is not changed.

required

Returns:

Type Description
SpatialData

Two elements. shapes["spots"] holds one circle per spot at the result's coordinates, its radius half the spacing between neighbouring spots. tables["table"] is the result itself (matrix, gene and spot tables, coordinates, layers and provenance), annotating those circles through its region and instance_id columns.

write_zarr

write_zarr(result: Any, path: str | Path) -> Path

Parameters:

Name Type Description Default
result Any

The path of a result file, or the AnnData already read from one.

required
path str | Path

The store to create, a directory conventionally named *.zarr. It must not exist yet: nothing already there is replaced.

required

write_seurat_dir

write_seurat_dir(result: Any, path: str | Path) -> Path

Parameters:

Name Type Description Default
result Any

The path of a result file, or the AnnData already read from one.

required
path str | Path

The folder to create. It must not exist yet: nothing already there is replaced.

required

After prediction

What a model's card asks to be applied to a result after prediction, applied the same way the service applies it. A result you finish locally and one the service returns therefore read alike.

auroraomics.postprocess

PostprocessError

Bases: AuroraomicsError, RuntimeError

EntryUnknown

InputUnavailable

implemented

implemented() -> tuple[str, ...]

resolve

resolve(card: Mapping[str, Any]) -> tuple[Entry, ...]

Parameters:

Name Type Description Default
card Mapping[str, Any]

The model card the result was produced under.

required

Returns:

Type Description
tuple

One entry per name the card listed, in that order; empty for a card that asks for nothing. Each carries the name the card used, which is what apply_card reports back.

Raises:

Type Description
EntryUnknown

The card names a step this release does not implement.

PostprocessError

The card's list is not a list of names, or names one thing twice.

apply_card

apply_card(path: str | Path, *, card: Mapping[str, Any], covariates: Mapping[str, Any] | None = None, model: Callable[[], Iterator[ndarray]] | None = None, compression: str | None = 'gzip') -> tuple[str, ...]

transform_into_output_space

transform_into_output_space(card: Mapping[str, Any], profile: Mapping[str, float]) -> dict[str, float]

Parameters:

Name Type Description Default
card Mapping[str, Any]

The model card the numbers are to be comparable with.

required
profile Mapping[str, float]

The sample's profile, by gene, in linear units.

required

Returns:

Type Description
dict[str, float]

The same genes, in the card's space.

Raises:

Type Description
PostprocessError

The card does not state its space, or states one this release cannot apply, or the profile sums to nothing. A refusal, not an approximation: a plausible number in the wrong space is wrong for every gene and looks exactly like a right one.

Spatial structure

Whether a gene's predicted expression varies with place, scored per gene from one result and its coordinates.

auroraomics.spatial

MIN_NEIGHBOURED module-attribute

MIN_NEIGHBOURED = 2

neighbours_within

neighbours_within(coords: ndarray, radius: float) -> tuple[np.ndarray, np.ndarray]

Parameters:

Name Type Description Default
coords ndarray

(N, 2) positions, one row per spot, in any consistent unit.

required
radius float

The neighbourhood, in that unit. A pair at exactly the radius is a pair.

required

Returns:

Type Description
tuple[ndarray, ndarray]

(i, j) with i < j, each pair once. Symmetric use — every spot's neighbours — is the concatenation of the two orders, which is what morans_i does.

Spots are hashed into square cells of side ``radius``; a pair within the
radius is then in the same cell or in adjacent ones, so only those are
compared. Linear in the number of spots for the grids and lattices tiles
come on; the worst case is every spot in one cell, which is the quadratic
comparison a caller would have written anyway.

morans_i

morans_i(values: ndarray, coords: ndarray, *, radius: float) -> np.ndarray

Parameters:

Name Type Description Default
values ndarray

(N, G) — one row per spot, one column per gene. A prediction, or one of its layers. nan marks a gene that carries no measurement, and a gene with a nan anywhere is reported as nan.

required
coords ndarray

(N, 2) positions of the same spots, in any consistent unit.

required
radius float

The neighbourhood: every other spot within this distance, in the coordinates' unit, weighs one. For tiles on a grid, the stride gives four neighbours and the stride times the square root of two gives eight.

required

Returns:

Type Description
ndarray

(G,) float64: near 1 for a gene that varies smoothly across the tissue, near 0 for one with no spatial pattern, negative for one that alternates between neighbours. nan for a gene that is constant over the spots (there is no pattern to have), for one carrying a nan, and for every gene when fewer than MIN_NEIGHBOURED spots have any neighbour at all.

The statistic is ``(N_w / S0) * sum_ij w_ij z_i z_j / sum_i z_i^2`` with
``z`` each gene centred over the spots that have a neighbour, ``w`` one for
each ordered pair within the radius, ``S0`` the number of those pairs and
``N_w`` the number of spots with a neighbour. Spots with no neighbour are
left out of both the centring and the sums, so an isolated tile neither
contributes a pattern nor dilutes one.

Bulk RNA

Revisit existing bulk RNA findings in their tissue context, using sample-matched profiles to inform predicted gene maps. Without a bulk profile, Aurora predicts from the slide alone.

This module prepares the one table the service accepts from a long or wide table or a GDC gene-counts file. Bulk RNA is the guide.

auroraomics.bulk

BulkRnaError

Bases: AuroraomicsError, ValueError

BulkRnaReport dataclass

path instance-attribute
path: Path
units instance-attribute
units: str
layout instance-attribute
layout: str
rows instance-attribute
rows: int
resolved_by_symbol instance-attribute
resolved_by_symbol: int
passed_through instance-attribute
passed_through: int
dropped_unknown instance-attribute
dropped_unknown: int
dropped_names instance-attribute
dropped_names: tuple[str, ...]
coverage instance-attribute
coverage: float
coverage_of instance-attribute
coverage_of: str
max_value instance-attribute
max_value: float

bulk_rna

bulk_rna(source: str | Path | Mapping[str, Any], out: str | Path, *, units: str, card: Mapping[str, Any], resolve: Resolver, sample: str | None = None) -> BulkRnaReport

Parameters:

Name Type Description Default
source str | Path | Mapping[str, Any]

A CSV or TSV file in any of three layouts — long (one row per gene), wide (genes across the header, one row per sample) or a GDC STAR gene-counts file — or a mapping of gene name to value.

required
out str | Path

Where to write the prepared table. A .tsv with the contract's gene column and one value column named by units; an existing file is replaced.

required
units str

"counts" or "tpm", as the contract spells them. A counts table must hold whole numbers. Neither may be log-transformed.

required
sample str | None

For a wide table with several sample rows, the first-column value of the row to take.

None
card Mapping[str, Any]

The model's card, as the service serves it (Client.model_card). Required: it decides whether the model takes bulk RNA at all, and its output.gene_mask is the measured gene set coverage is judged against — the same refusal the service would make.

required
resolve Resolver

How a symbol becomes the Ensembl id a result is keyed by: Client.resolve_keys, or any callable taking a list of names and answering {name: key or None}. Required for the same reason: the mapping is the model's own axis and it lives on the service.

required

Returns:

Type Description
BulkRnaReport

Counts of what was written, resolved, passed through and dropped, plus the coverage measured and against what.

Genes

The model's gene symbols mapped to Ensembl stable gene identifiers, which is what every result's var index is keyed by. One committed table, resolved in the same order as the service. The concept is on What you get back.

Fact Value
Genes on the served axis 19,336
Symbols in the model's vocabulary but not on the axis 2
Ensembl release 116
Built from sources fetched 2026-09-05

The symbols the axis leaves out, and why:

Symbol Why it is not on the axis
IQCA1 no HGNC record and no gene named IQCA1 in Ensembl 116; the model predicts it, and no source can identify it, so it is not on the served axis
IQCD no HGNC record and no gene named IQCD in Ensembl 116; the model predicts it, and no source can identify it, so it is not on the served axis

auroraomics.genes

ENSEMBL_GENE_ID_PATTERN module-attribute

ENSEMBL_GENE_ID_PATTERN = re.compile('^ENSG\\d{11}$')

GeneError

Bases: AuroraomicsError, ValueError

GeneUnknown

Bases: GeneError

Gene dataclass

symbol instance-attribute
symbol: str
ensembl_gene_id instance-attribute
ensembl_gene_id: str
hgnc_id instance-attribute
hgnc_id: str | None
biotype instance-attribute
biotype: str | None
in_ensembl instance-attribute
in_ensembl: bool
key property
key: str
from_service classmethod
from_service(row: 'Any') -> 'Gene'

unversioned

unversioned(gene_id: str) -> str

is_ensembl_gene_id

is_ensembl_gene_id(value: str) -> bool

listed

listed(items: Sequence[str], separator: str = ', ', cap: int = 10) -> str

Failures

Every refusal this package raises descends from one root, so a whole journey fits in a single except. Each root keeps its builtin base as well, so a clause already written against ValueError still catches.

auroraomics.errors

AuroraomicsError

Bases: Exception

ArgumentRefused

Bases: AuroraomicsError, ValueError

Contract values

The shared container layouts, caps and result layout, as data. Nothing in this package re-types a number the service also reads, and client code need not either.

auroraomics.contracts

PUBLIC_API module-attribute

PUBLIC_API = 'public-api.tokens.json'

INPUT_KINDS module-attribute

INPUT_KINDS = 'public-api-input-kinds.tokens.json'

COUNTERS module-attribute

COUNTERS = 'public-api-counters.tokens.json'

MEMOISED module-attribute

MEMOISED: tuple[str, ...] = (PUBLIC_API, INPUT_KINDS, COUNTERS)

OBSERVATION_SLOT module-attribute

OBSERVATION_SLOT = 'observations'

COVARIATE_SLOT module-attribute

COVARIATE_SLOT = 'covariates'

ContractError

Bases: AuroraomicsError, RuntimeError

VendoredDocuments

directory instance-attribute
directory = directory
memoised instance-attribute
memoised = memoised
repoint
repoint(directory: Path) -> None
clear
clear() -> None
names
names() -> tuple[str, ...]
path_of
path_of(name: str) -> Path
read
read(name: str) -> dict[str, Any]
verify
verify() -> None

manifest

manifest() -> dict[str, Any]

names

names() -> tuple[str, ...]

path_of

path_of(name: str) -> Path

read

read(name: str) -> dict[str, Any]

load

load(name: str) -> dict[str, Any]

verify

verify() -> None

patch_archive

patch_archive() -> dict[str, Any]

result_layout

result_layout() -> dict[str, Any]

resolution_checks

resolution_checks() -> dict[str, str]

embeddings_npz

embeddings_npz() -> dict[str, Any]

bulk_rna

bulk_rna() -> dict[str, Any]

table_delimiters

table_delimiters() -> tuple[str, ...]

container_extensions

container_extensions(container: str) -> tuple[str, ...]

poolings

poolings() -> tuple[str, ...]

input_kind

input_kind(kind: str) -> dict[str, Any]

kinds_in

kinds_in(slot: str) -> tuple[str, ...]

max_items

max_items(kind: str) -> int

max_bytes

max_bytes(kind: str) -> int

gene_resolve_batch

gene_resolve_batch() -> int

api_error_codes

api_error_codes() -> dict[str, dict[str, Any]]

upload_protocol

upload_protocol() -> dict[str, Any]

headers

headers() -> dict[str, Any]

id_prefixes

id_prefixes() -> dict[str, str]

api_key_format

api_key_format() -> dict[str, Any]

job_states

job_states() -> dict[str, tuple[str, ...]]

model_card_tokens

model_card_tokens() -> dict[str, Any]

What the service runs

The list of models from their cards, and a pre-flight check on an archive's tile size. Asking for a local prediction returns a refusal: the model runs on the service.

auroraomics.runtimes

auroraomics.runtimes.deepspotm

OBSERVATION module-attribute

OBSERVATION = 'patches'

EMBED_EXTRA module-attribute

EMBED_EXTRA = 'pip install "auroraomics[embed]"'

PredictError

Bases: AuroraomicsError, RuntimeError

ModelRefused

Bases: PredictError

InputMismatch

Bases: PredictError

LocalRuntimeUnavailable

Bases: PredictError

Model dataclass

id instance-attribute
id: str
name instance-attribute
name: str
family instance-attribute
family: str
package instance-attribute
package: str
revision instance-attribute
revision: str
patch_um instance-attribute
patch_um: float
observations instance-attribute
observations: tuple[str, ...]
covariates instance-attribute
covariates: tuple[str, ...]
gene_table instance-attribute
gene_table: str
n_genes instance-attribute
n_genes: int
sunset instance-attribute
sunset: str | None
has_local instance-attribute
has_local: bool
card instance-attribute
card: Mapping[str, Any]
refusal property
refusal: str | None
served_refusal property
served_refusal: str | None
is_runnable property
is_runnable: bool

describe_models

describe_models(cards: Iterable[Mapping[str, Any]]) -> dict[str, Model]

available_models

available_models(cards: Iterable[Mapping[str, Any]]) -> tuple[str, ...]

resolve_model

resolve_model(cards: Iterable[Mapping[str, Any]], model_id: str) -> Model

check_archive

check_archive(archive: str | Path | PatchArchive, *, model: str | Mapping[str, Any] | Model, cards: Iterable[Mapping[str, Any]] = ()) -> int

Parameters:

Name Type Description Default
archive str | Path | PatchArchive

A patches archive: a path, or one already opened with auroraomics.pack.read_archive. A path is closed again on the way out; an archive you opened stays yours to close.

required
model str | Mapping[str, Any] | Model

A card, an id, or a resolved model — the three things a caller actually has at this point, and all three answer.

  • One CARD, exactly as client.models() returns them: that call answers with a list of card mappings, and one row of it is the obvious thing to hand a pre-flight. It carries its own id and its own patch size, so cards is not needed beside it.
  • The ID of one, as a string — in which case cards says where to look it up.
  • A Model already resolved against a catalogue.

Anything else is an ArgumentRefused naming what it was and what the three forms are — including the whole catalogue, which is a list of cards rather than one and is the near miss worth saying out loud.

required
cards Iterable[Mapping[str, Any]]

The served catalogue, from client.models(). Needed only when model is an id. There is no default catalogue to fall back on: the cards are the service's, and a menu this package invented would name models nothing serves.

()

Returns:

Type Description
int

The tile edge, in pixels, that the card's physical size implies at this archive's resolution — which is what the archive's tiles measure, or the call would have raised.

Raises:

Type Description
ModelRefused

No public card carries that id, or its card is not one this release can say anything definite about — see served_refusal. NOT because the card has no local runtime: none of them has one, and this call is about an archive rather than about where a model runs.

ArgumentRefused

model was none of the three forms above.

InputMismatch

The archive is not the input the card describes.

predict_local

predict_local(*_args: Any, **_kwargs: Any) -> NoReturn

Raises:

Type Description
LocalRuntimeUnavailable

Always. There is no install that changes this and no flag that enables it: the model is not distributed, so there is nothing here to enable. The exception is a PredictError, so a caller with one except around a submission path catches it.

The API client

Submit a prediction, follow the job, download the result. A plain install has it. The whole flow is on From slide to result. Every route is in the API reference, which the client is generated from.

auroraomics.client.api

JOBS_PAGE module-attribute

JOBS_PAGE = 50

BAD_NAME_REFUSALS module-attribute

BAD_NAME_REFUSALS = frozenset({'gene_unknown', 'gene_ambiguous'})

RouteNotInSchema

Bases: ClientError

Client

key_prefix property
key_prefix: str | None
discovery
discovery() -> Discovery
me
me() -> Me
models
models() -> list[dict[str, Any]]
model_card
model_card(model: str) -> dict[str, Any]
encoders
encoders() -> dict[str, Any]
qc_thresholds
qc_thresholds() -> 'QcThresholds'
search_genes
search_genes(query: str = '', *, limit: int = 20) -> GeneSetOut
resolve_genes
resolve_genes(names) -> ResolveOut
resolve_keys
resolve_keys(names: Iterable[str]) -> dict[str, str | None]
request_code
request_code(email: str) -> None
verify_code
verify_code(email: str, code: str) -> tuple[str, bool]
terms
terms(token: str) -> TermsOut
mint_key
mint_key(token: str, *, accept_terms_version: str, name: str = '', scopes=None) -> MintedKey
list_keys
list_keys(token: str) -> list[KeyRow]
upload
upload(source: str | Path | Any, *, kind: str, filename: str | None = None, on_progress=None, timeout: float | None = None) -> UploadVerdict
start_upload
start_upload(source: str | Path | Any, *, kind: str, filename: str | None = None) -> uploads_module.StartedUpload
predict
predict(*, model: str, observation: PackReport | EmbedReport | str | Path | Any = None, kind: str | None = None, covariates: Mapping[str, Any] | None = None, land_in_workspace: bool = False, idempotency_key: str | None = None, observations: Mapping[str, Any] | None = None) -> Job
job
job(job_id: str) -> Job
jobs
jobs(*, limit: int = JOBS_PAGE, pages: int | None = 1) -> Iterator[Job]

login

login(email: str, *, accept_terms: Callable[[TermsOut], bool] | None = None, code: str | None = None, prompt=None, base_url: str | None = None, name: str = '', scopes=None, path: Path | None = None, client: Client | None = None) -> credentials.StoredCredential

auroraomics.client.jobs

MIN_POLL_SECONDS module-attribute

MIN_POLL_SECONDS = 2.0

MAX_POLL_SECONDS module-attribute

MAX_POLL_SECONDS = 30.0

DEFAULT_TIMEOUT_SECONDS module-attribute

DEFAULT_TIMEOUT_SECONDS = 6 * 60 * 60

SLEEP_SLICE_SECONDS module-attribute

SLEEP_SLICE_SECONDS = 0.5

UNREACHABLE_POLLS module-attribute

UNREACHABLE_POLLS = 5

TERMINAL_STATES module-attribute

TERMINAL_STATES: tuple[str, ...] = contracts.job_states()['terminal']

SUCCEEDED module-attribute

SUCCEEDED = 'succeeded'

Job

model property
model: str
eta_seconds property
eta_seconds: int | None
events property
events: list[dict[str, Any]]
as_dict
as_dict() -> dict[str, Any]
refresh
refresh() -> 'Job'
wait
wait(*, timeout: float | None = DEFAULT_TIMEOUT_SECONDS, on_poll: Callable[['Job'], None] | None = None, stop: Stop | None = None, raise_on_failure: bool = True) -> 'Job'
result
result() -> JobResult
save
save(path: str | Path) -> Path
download
download(path: str | Path | None = None) -> Any
delete
delete() -> None

next_delay

next_delay(*, retry_after: float | None, eta_seconds: int | None, backoff: float) -> tuple[float, float]

auroraomics.client.uploads

CHUNK_ATTEMPTS module-attribute

CHUNK_ATTEMPTS = 3

CHUNK_CHECKSUM_STATUS module-attribute

CHUNK_CHECKSUM_STATUS = int(contracts.api_error_codes()['checksum_mismatch']['status'])

UploadProtocol dataclass

chunk_size instance-attribute
chunk_size: int
minimum instance-attribute
minimum: int
maximum instance-attribute
maximum: int
digest_header instance-attribute
digest_header: str
offset_header instance-attribute
offset_header: str
complete_header instance-attribute
complete_header: str
algorithm instance-attribute
algorithm: str
check
check(chunk_size: int) -> int

Source dataclass

name instance-attribute
name: str
size instance-attribute
size: int
path class-attribute instance-attribute
path: Path | None = None
handle class-attribute instance-attribute
handle: Any = None
origin class-attribute instance-attribute
origin: int = 0
from_path classmethod
from_path(path: Path, *, filename: str | None = None) -> 'Source'
from_stream classmethod
from_stream(handle: Any, *, filename: str | None = None) -> 'Source'
opened
opened() -> Iterator[_Window]
checksum
checksum(chunk_size: int, *, algorithm: str | None = None) -> str

StartedUpload dataclass

source instance-attribute
source: Source
upload_id instance-attribute
upload_id: str
url instance-attribute
url: str
chunk_size instance-attribute
chunk_size: int
size instance-attribute
size: int
protocol instance-attribute
protocol: 'UploadProtocol'
send
send(http: Http, *, on_progress: Progress | None = None, timeout: float | None = None) -> UploadVerdict

source_for

source_for(value: Any, *, filename: str | None = None) -> Source

chunk_bounds

chunk_bounds(size: int, chunk_size: int) -> Iterator[tuple[int, int]]

tree_hash

tree_hash(chunks, *, algorithm: str | None = None) -> str

tree_hash_of_file

tree_hash_of_file(path: Path, chunk_size: int, *, algorithm: str | None = None) -> str

committed_offset

committed_offset(http: Http, url: str, protocol: UploadProtocol) -> tuple[int, bool]

start_upload

start_upload(http: Http, source: Any, *, kind: str, filename: str | None = None) -> StartedUpload

upload_file

upload_file(http: Http, source: Any, *, kind: str, filename: str | None = None, on_progress: Progress | None = None, timeout: float | None = None) -> UploadVerdict

auroraomics.client.credentials

ENV_API_KEY module-attribute

ENV_API_KEY = _ENV_HINT

ENV_API_URL module-attribute

ENV_API_URL = 'AURORAOMICS_API_URL'

STORE_VERSION module-attribute

STORE_VERSION = 1

StoredCredential dataclass

key instance-attribute
key: str
base_url class-attribute instance-attribute
base_url: str | None = None
prefix class-attribute instance-attribute
prefix: str = ''
expires_at class-attribute instance-attribute
expires_at: str | None = None
scopes class-attribute instance-attribute
scopes: tuple[str, ...] = ()
source class-attribute instance-attribute
source: str = ''
summary
summary() -> dict[str, Any]

config_dir

config_dir() -> Path

credentials_path

credentials_path() -> Path

redact

redact(key: str) -> str

prefix_of

prefix_of(key: str) -> str

load

load(path: Path | None = None, *, env: dict[str, str] | None = None) -> StoredCredential | None

store

store(key: str, *, path: Path | None = None, base_url: str | None = None, expires_at: str | None = None, scopes: tuple[str, ...] | list[str] = ()) -> StoredCredential

forget

forget(path: Path | None = None) -> bool

auroraomics.client.errors

MAX_ECHOED_DETAIL module-attribute

MAX_ECHOED_DETAIL = 200

PROBLEM_MEDIA_TYPE module-attribute

PROBLEM_MEDIA_TYPE = str(contracts.headers()['problemJson'])

RETRY_AFTER_HEADER module-attribute

RETRY_AFTER_HEADER = 'Retry-After'

REQUEST_ID_HEADER module-attribute

REQUEST_ID_HEADER = str(contracts.headers()['requestId'])

GROUP_BY_STATUS module-attribute

GROUP_BY_STATUS: dict[int, type[ApiError]] = {401: NotAuthorizedError, 403: NotAuthorizedError, 404: NotFoundError, 409: ConflictError, 410: ConflictError, 413: LimitExceededError, 422: InvalidRequestError, 429: LimitExceededError, 500: ServiceError, 503: ServiceError}

ERRORS module-attribute

ERRORS: dict[str, type[ApiError]] = _build()

AuroraomicsError

Bases: Exception

ClientError

CredentialsError

Bases: ClientError

ProtocolError

Bases: ClientError

WaitTimeout

Bases: ClientError

TermsDeclined

Bases: ClientError

TransportError

ApiError

Bases: AuroraomicsError

code class-attribute instance-attribute
code: str = code or type(self).code
status class-attribute instance-attribute
status: int = status if status is not None else type(self).status

NotAuthorizedError

Bases: ApiError

NotFoundError

Bases: ApiError

ConflictError

Bases: ApiError

LimitExceededError

Bases: ApiError

InvalidRequestError

Bases: ApiError

ServiceError

Bases: ApiError

JobFailedError

Bases: AuroraomicsError

code property
code: str | None

error_for

error_for(code: str, status: int) -> type[ApiError]

from_response

from_response(response: Any) -> ApiError

The command line

The same client from a shell: --json on every command, exit codes derived from the error catalogue, and no interactive prompt without a terminal.

Subcommand What it does
auroraomics login sign in, accept the Terms, and store an API key
auroraomics doctor check the install, the credential and the service
auroraomics models the models this deployment serves
auroraomics genes search or resolve gene identifiers
auroraomics submit submit a prediction
auroraomics jobs list your jobs, or show one
auroraomics download download a finished job's result
auroraomics export write a result for SpatialData or Seurat
auroraomics mcp serve the tools over stdio for an agent

auroraomics.cli

EXIT_OK module-attribute

EXIT_OK = 0

EXIT_ERROR module-attribute

EXIT_ERROR = 1

EXIT_USAGE module-attribute

EXIT_USAGE = 2

EXIT_AUTH module-attribute

EXIT_AUTH = 3

EXIT_NOT_FOUND module-attribute

EXIT_NOT_FOUND = 4

EXIT_CONFLICT module-attribute

EXIT_CONFLICT = 5

EXIT_LIMIT module-attribute

EXIT_LIMIT = 6

EXIT_INVALID module-attribute

EXIT_INVALID = 7

EXIT_UNAVAILABLE module-attribute

EXIT_UNAVAILABLE = 8

EXIT_JOB_FAILED module-attribute

EXIT_JOB_FAILED = 9

EXIT_TIMEOUT module-attribute

EXIT_TIMEOUT = 10

EXIT_PENDING module-attribute

EXIT_PENDING = 11

EXIT_MEANINGS module-attribute

EXIT_MEANINGS: dict[int, str] = {EXIT_OK: 'success', EXIT_ERROR: 'an unexpected failure', EXIT_USAGE: 'the command line was wrong, or a prompt was needed with no terminal', EXIT_AUTH: 'not authenticated, not approved, or missing a scope', EXIT_NOT_FOUND: 'no such resource for this credential', EXIT_CONFLICT: 'the resource is in the wrong state', EXIT_LIMIT: 'a size, quota or rate bound was hit', EXIT_INVALID: 'the input does not satisfy the contract', EXIT_UNAVAILABLE: 'the service or the runtime is unavailable', EXIT_JOB_FAILED: 'the job failed or was canceled', EXIT_TIMEOUT: 'a wait ran out of budget; the job is untouched', EXIT_PENDING: 'programmatic access is requested and pending; wait for the email'}

EXIT_BY_GROUP module-attribute

EXIT_BY_GROUP: dict[type[ApiError], int] = {errors.NotAuthorizedError: EXIT_AUTH, errors.NotFoundError: EXIT_NOT_FOUND, errors.ConflictError: EXIT_CONFLICT, errors.LimitExceededError: EXIT_LIMIT, errors.InvalidRequestError: EXIT_INVALID, errors.ServiceError: EXIT_UNAVAILABLE}

OBSERVATION_SHAPE module-attribute

OBSERVATION_SHAPE = 'KIND=PATH'

COVARIATE_SHAPE module-attribute

COVARIATE_SHAPE = 'KIND=VALUE'

WAITING_IS_WHAT_A_TIMEOUT_BOUNDS module-attribute

WAITING_IS_WHAT_A_TIMEOUT_BOUNDS = 'without it this command returns as soon as the job is queued, so there is no wait for a deadline to cut short'

NEEDS_WAIT module-attribute

NEEDS_WAIT: dict[str, dict[str, str]] = {'submit': {'output': 'without it this command returns while the job is still queued, and a queued job has no result to write', 'timeout': WAITING_IS_WHAT_A_TIMEOUT_BOUNDS}, 'jobs': {'timeout': WAITING_IS_WHAT_A_TIMEOUT_BOUNDS}, 'download': {'timeout': WAITING_IS_WHAT_A_TIMEOUT_BOUNDS}}

OUTPUT_NEEDS_WAIT module-attribute

OUTPUT_NEEDS_WAIT = f"needs --wait: {NEEDS_WAIT['submit']['output']}"

ACCESS_PENDING_CODE module-attribute

ACCESS_PENDING_CODE = 'access_pending'

NOT_APPROVED_CODE module-attribute

NOT_APPROVED_CODE = 'not_approved'

ACCESS_DECIDED_AT_MINT module-attribute

ACCESS_DECIDED_AT_MINT = "Programmatic access is granted per account, and the service applies the grant when the key is minted — the LAST of this command's round trips. So an account that does not hold it is emailed a sign-in code and asked for it like any other, and learns where it stands once that code has been verified. There is no cheaper check to make first: the flag the code exchange hands back is the web application's own approval, which is a different grant, and the route that reports this one needs the key this command exists to create."

TERMS_INCLUDE module-attribute

TERMS_INCLUDE = "The Terms include how uploaded data may be used to develop Aurora's models."

TERMS_QUESTION module-attribute

TERMS_QUESTION = 'Do you accept these Terms? [y/N] '

TERMS_YES module-attribute

TERMS_YES = frozenset({'y', 'yes'})

ACCEPT_TERMS_FLAG module-attribute

ACCEPT_TERMS_FLAG = '--accept-terms'

NEW_CODE module-attribute

NEW_CODE = 'a sign-in code works once, so it will send a new one'

STORED_KEY_BELONGS module-attribute

STORED_KEY_BELONGS = 'It belongs to the account it was minted for, which may not be this one, and `auroraomics doctor` and every other command go on using it.'

REMOVE_STORED_FILE module-attribute

REMOVE_STORED_FILE = 'To remove it from this machine, delete that file.'

UNSET_STORED_ENV module-attribute

UNSET_STORED_ENV = f'To stop using it, unset {credentials.ENV_API_KEY}.'

TERMS_NOT_ACCEPTED_CODE module-attribute

TERMS_NOT_ACCEPTED_CODE = 'terms_not_accepted'

LOGIN_FOR_A_NEW_KEY module-attribute

LOGIN_FOR_A_NEW_KEY = 'Run `auroraomics login` with the address of the account this key was minted for: it shows the current Terms and, once you accept them, stores a new key in place of this one.'

CALIBRATION_CHECK module-attribute

CALIBRATION_CHECK = 'calibration'

EXPORT_FORMATS module-attribute

EXPORT_FORMATS: dict[str, str] = {'zarr': '.zarr', 'seurat': '_seurat'}

TILE_COST_UNIT module-attribute

TILE_COST_UNIT = 'tiles'

ROW_COST_UNIT module-attribute

ROW_COST_UNIT = 'rows'

CATALOGUED_KIND module-attribute

CATALOGUED_KIND: dict[str, str] = {OBSERVATION_SLOT: 'patches', COVARIATE_SLOT: 'bulk_rna'}

HELP_WIDTH module-attribute

HELP_WIDTH = 76

Out

note
note(text: str) -> None

exit_code_for

exit_code_for(exc: BaseException) -> int

cmd_login

cmd_login(args: Namespace, out: Out) -> int

cmd_doctor

cmd_doctor(args: Namespace, out: Out) -> int

accepted_observations

accepted_observations(card: Any) -> tuple[str, ...]

cmd_submit

cmd_submit(args: Namespace, out: Out) -> int

cmd_export

cmd_export(args: Namespace, out: Out) -> int

cmd_mcp

cmd_mcp(args: Namespace, out: Out) -> int

kind_charged_in

kind_charged_in(unit: str) -> str

servable_kinds

servable_kinds(slot: str, cards: Iterable[Mapping[str, Any]] = ()) -> tuple[str, ...]

refuse_flags_that_need_wait

refuse_flags_that_need_wait(args: Namespace) -> None

For an agent

The same client as MCP tools over stdio, started with auroraomics mcp. Needs the mcp extra and a stored key: run auroraomics login once, or set AURORAOMICS_API_KEY. An agent can do exactly what a person can do with that key. From slide to result has the client configuration.

Tool What it does
list_models List the models this deployment serves, with what each one accepts.
submit Submit a prediction and return the job it created, without waiting.
get_job Read one job: its state, queue position, ETA and events.
download_result Write a finished job's result to path and report where it went.
resolve_genes Resolve symbols and aliases to the Ensembl ids every result is keyed by.

auroraomics.mcp.tools

MAX_WAIT_SECONDS module-attribute

MAX_WAIT_SECONDS = 120

TOOLS module-attribute

TOOLS: dict[str, Any] = {'list_models': _models, 'submit': _submit, 'get_job': _get_job, 'download_result': _download_result, 'resolve_genes': _resolve_genes}

auroraomics.mcp.server

SERVER_NAME module-attribute

SERVER_NAME = 'auroraomics'

INSTRUCTIONS module-attribute

INSTRUCTIONS = 'Predict spatial gene expression from H&E images. Submit a prediction with `submit`, follow it with `get_job` until it ends, and write the result to a file with `download_result`.'

bind

bind(name: str, client: Client)

build

build(client: Client | None = None, *, base_url: str | None = None) -> MCPServer

serve

serve(*, base_url: str | None = None) -> None

Installation options

Import as auroraomics
Version documented here 0.1.0.dev7
Python >=3.10
Licence PolyForm-Noncommercial-1.0.0
pip install "auroraomics[embed]"        # extracting patch embeddings on your own machine
pip install "auroraomics[mcp]"          # the same client as MCP tools, for an agent
pip install "auroraomics[spatialdata]"  # writing a result as a SpatialData Zarr store