exlab_wizard.lims.catalogue#

Offline LIMS project catalogue read/write. Backend Spec §7.2.9.

A catalogue is a single JSON document at a NAS-shared path that lets a disconnected workstation populate its LIMS-project picker without reaching the live LIMS API. The producer workstation writes the file on every successful LIMS refresh; the consumer workstation reads it when its local SQLite cache is empty AND the LIMS API is unreachable (see §7.2.9.3 for the consumer trigger).

This module provides only the file-format I/O. The producer-vs-consumer trigger logic, the warning-and-fall-through behavior on parse errors, and the picker-badge annotation are integrated by the caller (typically the LIMSClient or its supervising controller).

File format (§7.2.9.1):

```json {

“schema_version”: “1.0”, “produced_by”: “LAB_STATION_01”, “produced_at”: “2026-05-05T14:23:00Z”, “lims_endpoint”: “https://lims.lab.example/api/v1”, “projects”: [ {LIMSProject row}, … ]

}#

Atomic write (§7.2.9.2): write to <path>.tmp.<pid>, fsync, then os.replace to the final path. Concurrent producers are benign – each rename is atomic; the last writer wins.

Functions

read_catalogue(path, *, expected_endpoint)

Read and validate the catalogue file.

write_catalogue(path, catalogue)

Atomically write catalogue to path.

Classes

OfflineCatalogue(schema_version, ...)

Decoded offline catalogue.

class exlab_wizard.lims.catalogue.OfflineCatalogue(schema_version, produced_by, produced_at, lims_endpoint, projects)[source]#

Bases: object

Decoded offline catalogue. Backend Spec §7.2.9.1.

schema_version is pinned to the constant declared in exlab_wizard.constants.schema_versions; a mismatch is treated as catalogue-absent (WARN + None) per §7.2.9.3 – see read_catalogue().

lims_endpoint is verified by read_catalogue() against the consumer’s configured LIMS endpoint; mismatches are rejected per §7.2.9.3 to defend against accidentally pointing at a different lab’s LIMS.

Parameters:
lims_endpoint: str#
produced_at: str#
produced_by: str#
projects: list[LIMSProject]#
schema_version: str#
exlab_wizard.lims.catalogue.read_catalogue(path, *, expected_endpoint)[source]#

Read and validate the catalogue file.

Returns None (and logs a WARN) when the schema_version does not match exlab_wizard.constants.OFFLINE_CATALOGUE_VERSION: per Backend Spec §7.2.9.3 a version mismatch is treated as catalogue absent (the consumer falls through to its next picker source), rather than a hard error. (Policy decision, 2026-05-29: the catalogue follows the “treat as absent / WARN” rule of §7.2.9.3; it is deliberately not the §11.9.2 major-only cache-file gate.)

Raises exlab_wizard.errors.ConfigError on the genuine-error cases:

  • file missing / unreadable

  • JSON parse error

  • lims_endpoint differs from expected_endpoint (per §7.2.9.3 the producer’s LIMS must match the consumer’s configuration; cross-lab leakage is rejected, not warned).

Parameters:
  • path (Path)

  • expected_endpoint (str)

Return type:

OfflineCatalogue | None

exlab_wizard.lims.catalogue.write_catalogue(path, catalogue)[source]#

Atomically write catalogue to path. Backend Spec §7.2.9.2.

Protocol: serialize, write to <path>.tmp.<pid>, fsync, then os.replace to the final path. Concurrent producers do not corrupt the file – each rename is atomic; the last writer wins.

Parameters:
Return type:

None