spacr.regression_backends

Report which regression backends are available in this environment.

spacr.regression_spec says what the backends ARE – pure data, no imports. This module is the only place that asks the environment about them: is the package installed, is there a CUDA device, and can this backend fit the selected regression_type? Each disabled entry includes its reason; an inapplicable control is never hidden or silently substituted.

The availability probe does not import torch while a settings panel is being built. It inspects driver device nodes unless torch is already loaded, then spacr.mixed_gpu.resolve_device() performs the definitive fit-time check.

Installing optional backends

Three optional backends cannot be enabled by pressing Install, so this section explains why and what to do instead. It is written here rather than only in INSTALL_RECIPES because docs/source/api is built by sphinx-autoapi from this source, and autoapi publishes a module DOCSTRING verbatim while it renders a dict as a truncated repr. The two copies cannot drift: test_the_module_docstring_carries_every_command_the_gui_shows asserts that every command in INSTALL_RECIPES appears below.

pymer4 / lme4 needs R. It is an interface to R’s lme4, not a reimplementation. The pymer4 0.9.2 wheel does not declare its runtime dependencies, although its modules import polars and rpy2. Install the Python dependencies and R packages explicitly:

conda install -c conda-forge r-base
R -e 'install.packages(c("lme4","lmerTest"), repos="https://cloud.r-project.org")'
pip install rpy2 polars
pip install pymer4

This is a heavier ask than the other backends – a second language runtime, its own package library and a compiled bridge between them – which is said plainly so a reader can decide before starting rather than halfway through.

cuML needs a different environment. cuml-cu12 26.8.0 declares requires_python >= 3.11 and its recent wheels are cp311 ONLY (25.10, 25.12 and 26.2 shipped cp310-cp313; 26.4, 26.6 and 26.8 ship cp311 alone – the window is narrowing):

conda create -n spacr-gpu python=3.11
conda activate spacr-gpu
pip install spacr
pip install cuml-cu12

Use a separate environment because cuML has narrower Python and CUDA wheel compatibility than spaCR’s core installation. Its coordinate-descent results may also differ from another implementation at the same alpha; treat it as a backend choice, not only a speed switch.

numpyro and gpytorch install cleanly and answer a different question. numpyro samples a posterior with NUTS and gpytorch fits a Gaussian process; neither produces the point estimates and standard errors statsmodels does, so a reader installing them to go faster has misunderstood what they are for:

pip install numpyro
pip install --upgrade 'jax[cuda12]'
pip install gpytorch

Functions

availability_entries(→ list)

Every backend as a panel entry, in panel order.

availability_entry(→ dict)

One backend as the shared hover panel wants it.

backend_choices(→ list)

The combo's option strings -- the labels, in panel order.

backend_install_offer(name[, regression_type])

What pressing Install on a greyed-out backend entry should do.

backend_label(→ str)

The combo entry for a backend -- always suffixed (CPU)/(GPU).

backend_menu(→ list)

Every backend in panel order, each with its status.

backend_status(→ dict)

Whether a backend is choosable right now, and the reason if not.

backend_supports(→ bool)

Can name fit regression_type?

cuda_present_without_importing_torch(→ bool)

Is there a CUDA device, decided without paying for import torch?

describe_backends(→ str)

The text the model box shows: every backend, briefly, with its link.

describe_install_recipes(→ str)

Every recipe in INSTALL_RECIPES, in panel order.

install_recipe(→ str)

The written recipe for making name available, or ''.

package_installed(→ bool)

Is a backend's package importable? Does NOT import it.

resolve_backend_name(→ str)

The canonical backend name for whatever a panel or a CSV posted.

Module Contents

spacr.regression_backends.availability_entries(regression_type=None) list[source]

Every backend as a panel entry, in panel order.

spacr.regression_backends.availability_entry(name, regression_type=None) dict[source]

One backend as the shared hover panel wants it.

The panel (spacr.qt.widgets.availability_panel) takes a mapping so that neither of its two callers has to import Qt to build one, and so that this module keeps its promise not to import torch or PySide6.

Parameters:

name – backend key, label, or alias represented by the entry.

Returns:

{key, title, reason, url, offer, enabled}.

spacr.regression_backends.backend_choices() list[source]

The combo’s option strings – the labels, in panel order.

spacr.regression_backends.backend_install_offer(name, regression_type=None)[source]

What pressing Install on a greyed-out backend entry should do.

THE ENVIRONMENT IS ASKED FIRST, before spaCR’s own wiring, because the answer a user can act on is about their machine. “cuML needs Python 3.11 and this is 3.10” is a thing they can go and do; “spaCR routes no fit through it yet” is a thing only spaCR can fix, and saying that instead would hide the part they could have acted on.

Parameters:
  • name – a backend name or label.

  • regression_type – what the panel currently asks to fit. Used only for the message, never to decide installability – a family mismatch is fixed by choosing another family, not by installing anything.

Returns:

a spacr.updater.InstallOffer.

spacr.regression_backends.backend_label(name) str[source]

The combo entry for a backend – always suffixed (CPU)/(GPU).

Parameters:

name – backend key, label, or alias to resolve.

spacr.regression_backends.backend_menu(regression_type=None) list[source]

Every backend in panel order, each with its status.

This is what a combo box is built from: the entries are all present, in one order, and the disabled ones carry their own reason.

spacr.regression_backends.backend_status(name, regression_type=None) dict[source]

Whether a backend is choosable right now, and the reason if not.

Parameters:
  • name – backend name or label.

  • regression_type – what the user is asking it to fit. None skips the compatibility half of the question.

Returns:

{name, label, device, enabled, reason, short_reason, url, summary, cost, differs, pip}. reason is '' when enabled – a disabled entry always carries the sentence that says why, and it is written to be shown ON the control, not logged.

short_reason IS THE SAME REFUSAL AT COMBO-ENTRY LENGTH, and it exists because a reason nobody can read is a reason nobody has. A greyed-out row in a dropdown says only “not this one”; Qt shows an item tooltip lazily and only while the popup is open, so the sentence was reachable but missable. The short form goes IN the entry’s own text and in the box under it, where it cannot be hovered past.

spacr.regression_backends.backend_supports(name, regression_type) bool[source]

Can name fit regression_type?

regression_type=None means “auto-selected from the response”, which only the default backend can answer, since the choice is made after the data is read.

Parameters:
  • name – backend key, label, or alias to inspect.

  • regression_type – requested model family, or None for automatic family selection.

spacr.regression_backends.cuda_present_without_importing_torch() bool[source]

Is there a CUDA device, decided without paying for import torch?

See the module docstring for why this is a driver probe rather than torch.cuda.is_available().

spacr.regression_backends.describe_backends(regression_type=None, html: bool = True, selected=None, compact: bool = False) str[source]

The text the model box shows: every backend, briefly, with its link.

The design: “the text box should describe all of the packages that are available and what they do, briefly, and link the API for each”, and 141 D: where a backend cannot agree with statsmodels by construction, the box says what differs.

Parameters:
  • regression_type – greys the entries that cannot fit it, and their reason is included.

  • html – emit <a href=...> links (the Qt backend box renders rich text). False gives plain text with the URL inline, for a log.

  • selected – the backend the panel currently holds. In compact mode it is the one written out in full.

  • compact

    ONE LINE PER BACKEND instead of one paragraph.

    THE SETTINGS PANEL IS ONE PAGE and the full text is 3,101 characters – about ninety wrapped lines in a settings field, which is not a description, it is a document that happens to be in a combo box’s neighbourhood. Compact keeps every backend and every API link and drops what a reader does not need about the seven they did NOT pick: the measured cost of each, and the second and later sentences of each summary. The one they DID pick is written out in full, cost and caveat included, because that is the run they are about to start.

Returns:

one paragraph per backend, or one line per backend under compact with the selected one expanded above them.

spacr.regression_backends.describe_install_recipes(html: bool = False) str[source]

Every recipe in INSTALL_RECIPES, in panel order.

Packages that cannot be installed directly need recipes on the API page. This renders them in one block so a caller – the documentation build, a log, or the box under the backend combo – can show all of them without knowing which backends have one.

spacr.regression_backends.install_recipe(name) str[source]

The written recipe for making name available, or ''.

Parameters:

name – a backend name or label.

Returns:

the entry in INSTALL_RECIPES, or an empty string for a backend that needs no recipe because pip install is the whole story.

spacr.regression_backends.package_installed(name) bool[source]

Is a backend’s package importable? Does NOT import it.

find_spec on a package that is not there raises ModuleNotFoundError for a missing PARENT, which is a different question from the one being asked, so it is caught.

Parameters:

name – import package name, or an empty value for a core backend.

spacr.regression_backends.resolve_backend_name(value) str[source]

The canonical backend name for whatever a panel or a CSV posted.

Accepts the canonical name ('torch'), the label the combo shows ('torch (GPU)'), any casing, and None/'' for “not chosen”.

THE LABEL IS AN ACCEPTED SPELLING ON PURPOSE. The design requires every entry to read (CPU) or (GPU), and both GUIs render a combo’s options verbatim – so the option strings ARE the labels and the value posted back is a label. Normalising here is what keeps the settings CSV written with the short canonical name.

Parameters:

value – what was posted.

Returns:

a key of REGRESSION_BACKENDS.

Raises:

ValueError – on a name no backend answers to. Naming the valid ones in the message, because a settings CSV with a typo in it is exactly when a bare “invalid” costs the most.