spacr.cli_make_masks

spacr-make-masks — open the mask editor on a folder, as a queue.

A curation session has to be startable from a terminal, pointed at a folder, bounded, and resumable. Curation is done over SSH and on more than one machine, and the answer until now was spacr/cli.py’s flat refusal — “Make Masks is a manual mask editor; run it in the GUI”. That sentence is still true about the brush and false about the session. This module is the session:

spacr-make-masks --folder <dir>
spacr-make-masks --folder <dir> --order value --limit 25
spacr-make-masks --folder <dir> --dry-run      # no display needed
spacr-make-masks --folder <dir> --compute-uncertainty --save-uncertainty-maps

spacr.curation_queue does the thinking — which fields are waiting, in what order, and what was already decided about each one. This module is the thin part: parse four arguments, build the queue, say what the session is, and only then start Qt.

The optional uncertainty computation uses pure image I/O without starting Qt. The graphical interface is imported only after the folder is accepted. That order is the point of the module rather than a detail of it: a folder that does not exist, or that holds no layout spaCR recognises, is answered with a sentence on a login node with no display, not with a Qt crash after a ten-second import.

What is printed before the editor opens

The session summary, in the ledger’s own terms:

nested layout at /data/pv: 500 bundles, 366 done, 29 skip, 105 remaining;
25 this session, sorted by easy

so a curator sees what they are resuming into, and sees it in the shell they started from rather than only in a window.

All three layouts open the editor

spacr.curation_queue.detect_layout() reads three layouts, and the editor edits each where it lies: a nested folder’s masks in <folder>/masks, a sibling set’s in the masks/ beside its images/ – never images/masks, which would orphan every draft the set already has – and a seg folder’s _seg.npy bundles written back into themselves. spacr.qt.mask_engine says why in place is sound and no convert step is needed.

Exit codes:

0   the editor ran, or --dry-run printed the queue, or there was
    nothing left to curate
1   the Qt interface could not start, or uncertainty computation failed
2   bad arguments, a folder that is not there, or a folder holding no
    recognisable layout

Functions

build_parser(→ argparse.ArgumentParser)

Build the spacr-make-masks argument parser.

hand_over(→ None)

Leave queue for the next Make Masks screen that is built.

has_display(→ bool)

Whether there is a windowing system for the editor to open on.

main(→ int)

Open a folder as a curation session, or say why it cannot be opened.

open_editor(→ int)

Start the GUI on queue and return the process exit code.

take_handover(...)

Take the queue the terminal handed over, if there is one.

Module Contents

spacr.cli_make_masks.build_parser() → argparse.ArgumentParser[source]

Build the spacr-make-masks argument parser.

Returns:

the parser, with --folder, --order, --limit and --dry-run on it.

spacr.cli_make_masks.hand_over(queue: spacr.curation_queue.CurationQueue | None) → None[source]

Leave queue for the next Make Masks screen that is built.

Parameters:

queue – the session to hand over, or None to clear the slot.

spacr.cli_make_masks.has_display() → bool[source]

Whether there is a windowing system for the editor to open on.

This is the three-line question spacr.cli.use_agg_if_headless() asks of matplotlib, asked here of Qt instead. It runs BEFORE Qt is imported.

Without it an SSH session with no X forwarding gets “could not load the Qt platform plugin xcb” and aborts. That message says nothing about the queue, which was perfectly readable a moment earlier.

An explicit QT_QPA_PLATFORM counts as a display. It is how offscreen rendering, VNC and the embedded platforms are asked for, and somebody who set it has already said which surface Qt is to use.

Returns:

whether the editor can be opened here.

spacr.cli_make_masks.main(argv: Sequence[str] | None = None) → int[source]

Open a folder as a curation session, or say why it cannot be opened.

Parameters:

argv – command-line arguments without the program name. None reads sys.argv.

Returns:

a process exit code; see the module docstring for what each one means.

Raises:

SystemExit – with status 2 when the arguments themselves are invalid, which is argparse’s own refusal.

spacr.cli_make_masks.open_editor(queue: spacr.curation_queue.CurationQueue) → int[source]

Start the GUI on queue and return the process exit code.

Qt is imported HERE and nowhere above: everything that can be refused has been refused by the time this is called.

Parameters:

queue – the session the editor opens on.

Returns:

the exit code spacr.qt.run() returns, or EXIT_NO_GUI when there is no display to open on, or when the Qt interface is not installed.

spacr.cli_make_masks.take_handover() → spacr.curation_queue.CurationQueue | None[source]

Take the queue the terminal handed over, if there is one.

Emptying the slot is half of what this call is for: a screen rebuilt later in the same process — the user navigating back to Make Masks — must open on nothing rather than on a session that has already been worked through.

Returns:

the handed-over CurationQueue, or None when the screen was opened the ordinary way.