spacr.chaining

Default a module’s input paths to the outputs that upstream runs recorded.

Without chaining, every module screen starts from the "path" placeholder, and the plate folder that an upstream module such as Mask has just written must be entered again; a wrong entry runs the module against another plate.

spacr.ports now declares what each module consumes and produces, and spacr.artifacts records where every finished run put its outputs. This module joins the two:

  • chained_inputs() asks the registry — latest(kind, project=…) — where the upstream module’s output is, and turns that into the value a settings key should hold. The answer comes from the row the producer wrote, not from re-deriving <root>/merged;

  • resolve_settings() applies those values to a settings dict without ever overwriting a path the user edited. A user edit is remembered in a PinStore and takes precedence until it is cleared; when the upstream later moves, the new location is offered (HeldPin) rather than pushed;

  • staleness_notes() turns spacr.artifacts.Registry.is_stale() into sentences a user can act on, keyed by the cause codes so the reason is specific — “Mask ran again after this” is a different problem from “the settings changed”;

  • next_steps() lists the modules that can run on a finished run’s outputs, using spacr.ports.next_modules() for the candidates, chained_inputs() for their pre-filled settings and spacr.ports.check_ready() so a successor that cannot run is offered with its blocking reason.

Nothing here imports Qt, numpy or torch: the Qt layer (spacr.qt.chaining) is a thin wrapper over these functions, and the same answers are available to the CLI and to a batch runner.

Public API

PinStore, pin_store, state_path

The memory of which paths the user edited by hand.

Binding, BINDINGS, register_binding, binding_for

Which settings key an input port fills, and in what form.

ChainedInput, chained_inputs, resolve_settings, Resolution

Auto-chaining itself.

StaleNote, stale_inputs, stale_outputs, staleness_notes

Staleness checks and their messages.

NextStep, next_steps

“Continue to the next step.”

Classes

Binding

How one consumed port becomes one settings value.

ChainedInput

One input a module can take from a run that already happened.

DropChoice

A choice between candidates that a dropped path does not resolve on its own.

DropResolution

What a dropped path means to one screen.

DropTarget

One settings key a drop can fill, and what it resolved to.

HeldPin

A settings key auto-chaining did not touch, because the user owns it.

NextStep

A module that can run on what the finished run just produced.

PinStore

Persist explicitly selected setting paths across application sessions.

Resolution

What auto-chaining did to a settings dict.

StaleNote

One out-of-date artifact, with the reason and the fix.

Functions

binding_for(→ Binding)

Return the binding for one consumed port, declared or derived.

candidate_roots() → Tuple[str, ...])

Return the project roots to search for module's inputs, in order.

chained_inputs(, registry, check_staleness, ...])

Return where module's inputs actually are, one entry per port.

db_candidates(→ Tuple[str, ...])

Return every SQLite database in a project, the declared one first.

explain_causes(→ str)

Render staleness cause codes as one readable clause.

is_empty_path(→ bool)

True when a settings value holds no real path.

layout_directories(→ Tuple[str, ...])

Return the folder names spaCR's project layout uses, sorted.

looks_laid_out(→ bool)

True when folder holds any of spaCR's declared layout folders.

next_steps(, registry, include_blocked, ...])

Return what can run next, pre-filled with what this run just produced.

pin_store(→ PinStore)

Return the process-wide PinStore.

placeholder_paths(→ Tuple[str, ...])

Return the values that mean "nothing chosen yet".

ports_for_kinds(→ Tuple[spacr.ports.Port, ...])

Return the canonical declaration of where each kind lives.

project_root_of(→ str)

Return the project root a dropped path belongs to.

register_binding(→ Binding)

Declare that one port fills one settings key.

resolve_drop(, form, settings, Any]] = None, registry, ...)

Resolve a dropped path against module's inputs.

resolve_settings(, registry, pins, check_staleness)

Fill module's input paths from the registry, respecting user edits.

result_tables(→ Tuple[str, ...])

Return the result tables a project has written, sorted.

same_path(→ bool)

Compare two settings values as paths, list-insensitively.

satisfies(→ bool)

True when root holds everything ports requires.

source_key(→ str)

Return the settings key naming module's source folder.

stale_inputs(→ Tuple[StaleNote, ...])

Return the inputs module would read that are already out of date.

stale_outputs(→ Tuple[StaleNote, ...])

Return the results module already produced that are out of date.

staleness_notes(→ Tuple[StaleNote, ...])

Return every stale artifact around module: its inputs and its outputs.

state_path(→ str)

Return the file the user's pinned paths live in.

Module Contents

class spacr.chaining.Binding[source]

How one consumed port becomes one settings value.

Parameters:
  • module – the consuming module key.

  • role – the port’s role within that module, e.g. "merged".

  • setting – the settings key it fills, e.g. "src".

  • form – ROOT (the project the artifact belongs to) or PATH (the artifact itself).

class spacr.chaining.ChainedInput[source]

One input a module can take from a run that already happened.

Parameters:
  • module – the consuming module key.

  • setting – the settings key this fills.

  • role – the consumed port’s role.

  • kind – the spacr.ports kind, e.g. "merged-arrays".

  • value – what the settings key should become.

  • artifact – the registered upstream output it came from.

  • producer – the module that wrote it.

  • root – the project root the artifact belongs to.

  • staleness – the artifact’s own staleness, so a chained default can be reported as out of date when it is filled in.

  • required – whether the consuming module needs this port.

describe() → str[source]

Return one line naming the input’s kind, producer and path.

property path: str[source]

The artifact’s own path, as recorded by the producing module.

property stale: bool[source]

True when the registry reports this input as out of date.

class spacr.chaining.DropChoice[source]

A choice between candidates that a dropped path does not resolve on its own.

Two databases in a folder, two projects under the folder that was dropped, two tables in the database — none of these is resolved by taking the first candidate. options holds the candidates to offer.

Parameters:
  • question – the sentence to put above the list.

  • kind – the vocabulary term the options are candidates for.

  • options – the candidates, in the order to offer them.

  • setting – the settings key the answer fills, when there is one.

class spacr.chaining.DropResolution[source]

What a dropped path means to one screen.

Parameters:
  • module – the screen key.

  • dropped – the path the user dropped, absolute.

  • root – the project root it resolved to.

  • targets – the inputs that were found.

  • choices – the questions that have to be asked first.

  • problems – spacr.validate.Problem for every input that is missing — the same sentences spacr.ports.check_ready() writes, because they come from it.

__bool__() → bool[source]

True when the drop resolved to something usable.

target_for(kind: str) → DropTarget | None[source]

Return the resolved target of kind, or None.

Parameters:

kind – port or artifact vocabulary kind to find.

property ambiguous: bool[source]

True when the drop has to be asked about rather than applied.

property ok: bool[source]

True when every required input was found.

property reason: str[source]

what it resolved to, or why it did not.

Type:

One human-readable line

class spacr.chaining.DropTarget[source]

One settings key a drop can fill, and what it resolved to.

Parameters:
  • module – the screen the drop landed on.

  • setting – the settings key it fills.

  • role – the port’s role.

  • kind – the spacr.ports kind.

  • value – what the settings key should become — the project root for a ROOT binding, the artifact itself for a PATH one.

  • location – the artifact’s own path, always. An interface shows this path as the resolved location.

  • source – FROM_REGISTRY when the answer came from a recorded run — the same answer auto-chaining gives — or FROM_LAYOUT when it came from the declared folder layout.

  • required – whether the screen needs this input.

  • paths – the individual files the port’s pattern matched, for a screen that wants one file rather than the folder holding them.

describe() → str[source]

One line naming what was found and where.

class spacr.chaining.HeldPin[source]

A settings key auto-chaining did not touch, because the user owns it.

Parameters:
  • setting – the settings key.

  • value – the value the user chose, which is what the key holds.

  • offered – the value auto-chaining would have used, or None when the registry has nothing to offer.

  • chained – the ChainedInput behind offered.

describe() → str[source]

One line for an interface that wants to offer the alternative.

property differs: bool[source]

True when the upstream has moved away from the user’s choice.

In that case the pin still takes precedence, and the new location is offered beside it.

class spacr.chaining.NextStep[source]

A module that can run on what the finished run just produced.

Parameters:
  • module – the successor’s module key.

  • source – the module that just finished.

  • root – the project it would run in.

  • kinds – the kinds it picks up from the finished run.

  • seed – settings to pre-fill its screen with — the artifact that was just produced, resolved through the registry like any other chained default. Paths are scalars even for a successor whose key holds a list: the receiving end normalises (the chip editor’s set_value and spacr.utils.normalize_src_path() both wrap a bare path), and guessing the container here would mean keeping a second copy of every module’s default shape in step with the first.

  • readiness – spacr.ports.check_ready()’s verdict.

  • artifacts – the artifact ids the seed points at.

property blocked: str[source]

Why it cannot run, or "" when it can.

Shown beside the offer, not instead of it: a successor that lacks one input folder is still listed, with the reason it cannot run.

property fix: str[source]

What to do about the blockage, or "" when there is none.

property ok: bool[source]

True when spacr.ports.check_ready() reports the successor ready to run.

class spacr.chaining.PinStore(path: str | None = None)[source]

Persist explicitly selected setting paths across application sessions.

A pin distinguishes a manually selected value from one populated by automatic chaining. Pinned values survive screen reopening, application restart, and subsequent upstream runs until they are cleared. Pins are stored separately from settings because a settings dictionary does not retain the origin of a value.

Read lazily and written through a temporary file plus os.replace(), so a crash mid-write cannot leave a half-written JSON file that would lose every pin at once.

Parameters:

path – the JSON file. Defaults to state_path().

Initialize a lazily loaded store at an expanded absolute path.

clear(module: str = '') → None[source]

Forget one module’s pins, or all of them.

Parameters:

module – module key, or "" for every module.

pin(module: str, setting: str, value: Any) → None[source]

Store an explicitly selected value for a module setting.

An empty path removes the existing pin and re-enables automatic chaining for that setting. Empty values are not persisted.

Parameters:
  • module – module key.

  • setting – settings key, e.g. "src".

  • value – the path (or list of paths) the user entered.

pinned(module: str, setting: str) → Any[source]

Return the pinned value, or None when the user never set one.

Parameters:
  • module – module key.

  • setting – settings key.

pins(module: str) → Dict[str, Any][source]

Return every pin for one module, as a copy.

Parameters:

module – module key.

reload() → PinStore[source]

Drop the cached table so the next read hits the file.

Returns:

self, for chaining.

unpin(module: str, setting: str) → bool[source]

Forget the pin for one setting.

Parameters:
  • module – module key.

  • setting – settings key.

Returns:

True when there was one to forget.

class spacr.chaining.Resolution[source]

What auto-chaining did to a settings dict.

Parameters:
  • module – the module key.

  • settings – a new dict — the input is never mutated, because a caller that shows a diff needs both sides.

  • filled – settings key → the chained input that filled it.

  • held – settings key → the pin that stopped it being filled.

  • inputs – every chained input found, filling or not.

property moved: Tuple[HeldPin, ...][source]

Pins whose upstream has since moved somewhere else.

class spacr.chaining.StaleNote[source]

One out-of-date artifact, with the reason and the fix.

Parameters:
  • module – the module whose screen this is being shown on.

  • direction – "input" (something this module reads is stale) or "output" (a result this module already produced is stale).

  • kind – the spacr.ports kind.

  • role – the port role.

  • path – where the artifact is.

  • producer – the module that wrote it.

  • artifact_id – the registry id.

  • causes – the machine cause codes, verbatim from spacr.artifacts.Staleness.

  • reasons – the registry’s own sentences, kept because they name the specific upstream path that moved.

  • missing – the artifact’s file is gone, which is an availability problem rather than a provenance one.

to_problem()[source]

Return this note as a spacr.validate.Problem.

So a caller can print staleness through spacr.validate.format_report() beside the settings pre-flight and the port readiness check, rather than inventing a third format.

property detail: str[source]

The registry’s own sentences, which name the paths involved.

property fix: str[source]

What to do about it, in the user’s terms.

property headline: str[source]

One line naming what is stale and why.

spacr.chaining.binding_for(module: str, port: spacr.ports.Port) → Binding[source]

Return the binding for one consumed port, declared or derived.

Derived means: the port fills the module’s source folder, in ROOT form. This holds for every shipped pipeline module — Measure, Classify, UMAP and the rest all take a plate folder and find merged/ or measurements/ inside it — so the common case needs no declaration and a new module is chained as soon as it declares ports.

Parameters:
  • module – the consuming module key or alias.

  • port – one of that module’s consumed ports.

spacr.chaining.candidate_roots(module: str, settings: Mapping[str, Any] | None = None, *, root: str = '', roots: Sequence[str] = ()) → Tuple[str, ...][source]

Return the project roots to search for module’s inputs, in order.

The module’s own source folder first — a user who has already named a plate means that plate — then whatever the caller offers. The Qt layer supplies the folders the upstream modules last ran in, which is how opening Measure on a blank screen finds the plate Mask just finished.

Parameters:
  • module – module key or alias.

  • settings – the settings dict being edited.

  • root – an explicit root, tried first.

  • roots – further candidates, in preference order.

Returns:

absolute, de-duplicated paths; whether they exist is not checked here.

spacr.chaining.chained_inputs(module: str, settings: Mapping[str, Any] | None = None, *, root: str = '', roots: Sequence[str] = (), registry: spacr.artifacts.Registry | None = None, check_staleness: bool = True) → Tuple[ChainedInput, ...][source]

Return where module’s inputs actually are, one entry per port.

For every port module consumes, the registry is asked for the newest artifact of that kind in each candidate project, in order, and the first hit wins. The answer is the row the producer wrote — its path, its project, its settings hash — so a plate whose merged arrays ended up somewhere unusual chains correctly, which re-deriving <root>/merged would not.

Ports whose settings key the module does not have are skipped: inventing a key would put a value somewhere nothing reads.

Parameters:
  • module – module key or alias.

  • settings – the settings dict being edited. Used for the current values (list-or-string, and “is it already filled?”) and for the module’s own project root.

  • root – an explicit project root, searched first.

  • roots – further project roots to search, in preference order.

  • registry – an open registry to ask instead of each project’s own.

  • check_staleness – also report whether each input is out of date. Costs one recursive query per input; off for a caller that only wants the paths.

Returns:

one ChainedInput per resolved port, in declaration order.

Raises:

spacr.ports.UnknownModule – when module declares no ports.

spacr.chaining.db_candidates(root: str) → Tuple[str, ...][source]

Return every SQLite database in a project, the declared one first.

Parameters:

root – candidate project root to search.

The declared location comes from the spacr.ports.MEASUREMENTS_DB port; the rest is a shallow listing of the root and of the folder that port names. Two databases in one project are not an error; the list is returned so the caller can ask which one to use, and none is chosen here.

spacr.chaining.explain_causes(causes: Iterable[str]) → str[source]

Render staleness cause codes as one readable clause.

Parameters:

causes – cause codes from spacr.artifacts.Staleness.causes.

Returns:

the sentences joined with “; “, de-duplicated in first-seen order. Unknown codes are passed through as themselves rather than dropped, so a code missing from this table is still reported.

spacr.chaining.is_empty_path(value: Any) → bool[source]

True when a settings value holds no real path.

Parameters:

value – the current value of a path-ish settings key.

spacr.chaining.layout_directories() → Tuple[str, ...][source]

Return the folder names spaCR’s project layout uses, sorted.

Derived from spacr.ports.PORTS rather than listed here — merged, measurements, masks, data, model, results, settings, orig, consolidated all come from port declarations — so a plugin that declares a port makes its own folder part of the layout without editing a list here.

Cached against the size of the registry, so a late spacr.ports.register_module_ports() is picked up.

spacr.chaining.looks_laid_out(folder: str) → bool[source]

True when folder holds any of spaCR’s declared layout folders.

Parameters:

folder – candidate project directory to inspect.

A structural check for whether a folder is a project: at most one isdir call per name in layout_directories() (nine for the shipped ports). spacr.projects.looks_like_project() is the thorough check and reads the registry and every module’s outputs; this one is fast enough to run while a drag is still in progress.

spacr.chaining.next_steps(module: str, settings: Mapping[str, Any] | None = None, *, root: str = '', roots: Sequence[str] = (), registry: spacr.artifacts.Registry | None = None, include_blocked: bool = True) → Tuple[NextStep, ...][source]

Return what can run next, pre-filled with what this run just produced.

Candidates come from spacr.ports.next_modules() — the modules that require one of the kinds this one produces — so the list is derived from the declared graph rather than a hand-written “after Mask, offer Measure”. Each is resolved against the registry for its settings, then run through spacr.ports.check_ready(), so each offer is either ready or carries the reason it cannot run.

Parameters:
  • module – the module that just finished; key or alias.

  • settings – the settings it ran with, for the project root.

  • root – explicit project root.

  • roots – further project roots for the successor’s inputs.

  • registry – an open registry instead of the project’s own.

  • include_blocked – keep successors that cannot run, carrying their blocking reason. False drops them entirely.

Returns:

one NextStep per successor, ready ones first, then in module order.

Raises:

spacr.ports.UnknownModule – when module declares no ports.

spacr.chaining.pin_store(path: str | None = None, *, refresh: bool = False) → PinStore[source]

Return the process-wide PinStore.

Parameters:
  • path – use a specific file instead of state_path(). Passing one always builds a fresh store rather than handing back a cached one pointed at a different file.

  • refresh – rebuild the shared store, re-reading state_path(). Needed after $SPACR_CHAINING_PINS changes, for example in a test that isolates the state.

spacr.chaining.placeholder_paths() → Tuple[str, ...][source]

Return the values that mean “nothing chosen yet”.

spacr.chaining.ports_for_kinds(kinds: Sequence[str]) → Tuple[spacr.ports.Port, ...][source]

Return the canonical declaration of where each kind lives.

A screen that is not a pipeline module — the table explorers, the viewers — still says what it wants in the shared vocabulary, and this is what turns that word into a path. The declaration is looked up in spacr.ports.PORTS: a produced port first, because the module that writes a kind is the one that knows where it goes, and a consumed port only when nothing produces it.

Parameters:

kinds – vocabulary terms such as spacr.ports.MEASUREMENTS_DB.

Returns:

one spacr.ports.Port per kind that is declared anywhere, in the order asked for. An undeclared kind is skipped rather than guessed at.

spacr.chaining.project_root_of(path: Any, *, max_climb: int = MAX_CLIMB) → str[source]

Return the project root a dropped path belongs to.

The layout is walked upwards: <root>/measurements/measurements.db, <root>/merged, <root>/data/plate1/cell_png and <root> itself all answer <root>, because measurements, merged and data are declared folders (layout_directories()) and nothing else on the way up is.

The highest declared folder within max_climb wins, so a drop deep inside data/ still lands on the project rather than on a crop folder.

Parameters:
  • path – the dropped file or folder.

  • max_climb – how many levels above the drop to consider.

Returns:

an absolute path, or "" when path is None. A path outside any project does not raise: the result is the dropped folder itself, or the folder holding a dropped file.

spacr.chaining.register_binding(binding: Binding, *, overwrite: bool = False) → Binding[source]

Declare that one port fills one settings key.

Used by a module with an unusual input key, so that the binding table does not have to be edited by hand.

Parameters:
  • binding – the declaration.

  • overwrite – allow replacing an existing one. Off by default, so two contributors claiming one port is an error rather than last-one-wins.

Returns:

the stored binding.

Raises:

ValueError – on an empty field, an unknown form, or a duplicate.

spacr.chaining.resolve_drop(module: str, dropped: Any, *, kinds: Sequence[str] = (), form: str = PATH, settings: Mapping[str, Any] | None = None, registry: spacr.artifacts.Registry | None = None, max_climb: int = MAX_CLIMB) → DropResolution[source]

Resolve a dropped path against module’s inputs.

The resolution is the same one auto-chaining performs. For every input the module declares, the registry is asked first — spacr.artifacts.Registry.latest() for that kind in that project, as chained_inputs() asks it — so a drop and an auto-chain fill the field with the same string. Only when no run was ever registered does the declared layout in spacr.ports.PORTS answer instead, and then it answers with the folder the ports say it is in.

Ambiguity is returned, never guessed:

  • the dropped folder holds several projects → DropChoice;

  • the project holds several databases → DropChoice;

  • nothing satisfies the module → DropResolution.problems, which is spacr.ports.check_ready()’s own list of sentences.

Parameters:
  • module – the screen key. When it declares ports those are used; otherwise kinds says what it wants.

  • dropped – the path the user dropped.

  • kinds – vocabulary terms, for a screen with no port declaration.

  • form – ROOT or PATH — what a kinds-driven screen wants in its field. A declared module’s own bindings always win.

  • settings – the settings dict being edited, for its current values.

  • registry – an open registry to ask instead of each project’s own.

  • max_climb – how far above the drop the project root may sit.

Returns:

a DropResolution.

spacr.chaining.resolve_settings(module: str, settings: Mapping[str, Any], *, root: str = '', roots: Sequence[str] = (), registry: spacr.artifacts.Registry | None = None, pins: PinStore | None = None, check_staleness: bool = True) → Resolution[source]

Fill module’s input paths from the registry, respecting user edits.

Values are resolved in this order of precedence:

  1. a pinned value wins. If the user has typed a path for this key, it is restored and is not overwritten by a newer upstream run, a different plate or a restart. When the upstream has moved since, the move is reported in Resolution.held for an interface to offer;

  2. otherwise, a value already in settings that is not a placeholder wins. Loading a settings CSV, dropping a folder or seeding from another screen all land here, and none of them is overridden within the same session;

  3. otherwise the registry’s answer is used.

Parameters:
  • module – module key or alias.

  • settings – the settings dict to resolve. Not mutated.

  • root – explicit project root, searched first.

  • roots – further project roots, in preference order.

  • registry – an open registry to ask instead of each project’s own.

  • pins – the user’s pinned paths. Defaults to pin_store().

  • check_staleness – also report whether each input is out of date.

Returns:

a Resolution.

Raises:

spacr.ports.UnknownModule – when module declares no ports.

spacr.chaining.result_tables(root: str) → Tuple[str, ...][source]

Return the result tables a project has written, sorted.

Parameters:

root – candidate project root to search.

The folders searched are the ones the result-bearing ports declare — results/ and settings/ today — one level deep, so a drop on a screen that reads “a table or a CSV” can offer the CSVs beside the database tables instead of making the user go and find them.

spacr.chaining.same_path(left: Any, right: Any) → bool[source]

Compare two settings values as paths, list-insensitively.

Parameters:
  • left – first scalar or nested list or tuple of path values.

  • right – second path value or collection to compare.

["/plate"] and "/plate" name the same folder; Classify keeps its source in a list and every other module keeps it as a string, so a comparison that called those different would record a pin every time a Classify screen was seeded with its own auto-chained value.

spacr.chaining.satisfies(root: str, ports: Sequence[spacr.ports.Port]) → bool[source]

True when root holds everything ports requires.

Parameters:
  • root – candidate project root whose artifacts are checked.

  • ports – input port declarations whose required artifacts must resolve beneath root.

With no ports the question is “is this a project at all?”, which is what a screen that takes a whole project — the pipeline graph, the QC dashboard — is asking.

spacr.chaining.source_key(module: str) → str[source]

Return the settings key naming module’s source folder.

The same lookup spacr.ports and spacr.validate make: spacr.ports.ROOT_KEYS first (a module whose output names the project), then spacr.validate.ALT_SRC_KEYS, then src.

Parameters:

module – module key or alias.

spacr.chaining.stale_inputs(module: str, settings: Mapping[str, Any] | None = None, *, root: str = '', registry: spacr.artifacts.Registry | None = None) → Tuple[StaleNote, ...][source]

Return the inputs module would read that are already out of date.

Running on a stale input produces a stale result, so this check reports the problem before the run rather than after it. Settings are deliberately not compared here: this module’s settings say nothing about whether the previous module’s output is current.

Parameters:
  • module – module key or alias.

  • settings – the settings currently on screen, for the project root.

  • root – explicit project root; otherwise derived from settings.

  • registry – an open registry instead of the project’s own.

spacr.chaining.stale_outputs(module: str, settings: Mapping[str, Any] | None = None, *, root: str = '', registry: spacr.artifacts.Registry | None = None) → Tuple[StaleNote, ...][source]

Return the results module already produced that are out of date.

An output is reported when, for example, the measurements in this project were made from a Mask run that has since been redone, or with settings that are not the ones now on screen. settings is compared against the recorded settings hash, so editing a material knob marks the existing result stale immediately — before the run that would fix it.

Parameters:
  • module – module key or alias.

  • settings – the settings currently on screen. Supplying them adds the spacr.artifacts.CAUSE_SETTINGS_CHANGED cause.

  • root – explicit project root; otherwise derived from settings.

  • registry – an open registry instead of the project’s own.

Returns:

one note per stale output, in declaration order. Empty when there is no registry, which is the answer for a project that has never recorded a run.

spacr.chaining.staleness_notes(module: str, settings: Mapping[str, Any] | None = None, *, root: str = '', registry: spacr.artifacts.Registry | None = None) → Tuple[StaleNote, ...][source]

Return every stale artifact around module: its inputs and its outputs.

Inputs are listed first, because a stale input explains a stale output.

Parameters:
  • module – module key or alias.

  • settings – the settings currently on screen.

  • root – explicit project root.

  • registry – an open registry instead of the project’s own.

spacr.chaining.state_path() → str[source]

Return the file the user’s pinned paths live in.

$SPACR_CHAINING_PINS takes precedence; otherwise XDG state storage, following the same convention as spacr.remote_execution.state_directory().

Returns:

an absolute path. The file need not exist.

Nested helpers

same_path.flatten(value: Any) → List[str]

Flatten one path-like value into normalised path strings.

Parameters:

value – scalar path, nested list or tuple, None, or another value whose stripped string representation names a path.

Returns:

depth-first path strings with empty values omitted and each retained value normalised with os.path.normpath().

spacr/chaining.py:164