spacr.qt.recipes¶
Settings templates: named, reusable and shareable bundles of settings.
The historical Recipe API, JSON format and storage paths remain compatible.
A lab often uses several sets of settings, each tied to a preparation, such as “Toxo PVM, 40×”. A settings CSV saved in a folder has no name, no record of its module and no record of the spaCR version that wrote it.
A recipe records all four:
it has a name the user chose;
it knows its module, so applying a Mask recipe to Measure is refused rather than writing keys that do not apply there;
it records the spaCR version it was captured with, and applying it under a different one says so and lists the recipe’s settings that the module no longer has;
it is one file, so sharing it is sending a file.
Storage is ~/.spacr/recipes/<module>/<slug>.json, honouring
RECIPE_DIR_ENV — the same shape spacr.macro.macros_dir() uses,
so a lab that redirects one redirects both.
The file format is plain JSON:
{
"spacr_recipe": 1,
"name": "Toxo PVM, 40x",
"app_key": "mask",
"spacr_version": "1.3.6",
"created": "2026-08-03T22:41:07",
"notes": "",
"settings": {"cell_channel": 1, ...}
}
spacr_recipe is a format version, not the spaCR version: the two change for
unrelated reasons, so a reader accepts any file whose format version it can
read.
Classes¶
One named settings bundle. |
|
List, apply, share and delete the recipes for one module. |
Functions¶
|
Write a recipe's settings into |
|
Build a recipe from a screen's current settings. |
|
Describe the recipe's settings that this module does not have. |
|
Remove a recipe's file. |
|
Add a Templates button to |
|
Add Settings templates… to the window's Help menu. |
|
Wire recipes into a live main window. |
|
Every readable recipe, newest first. |
|
Read one recipe file. |
|
Open the recipe dialog for |
|
The folder holding recipes, optionally for one module. |
|
Write |
|
The running spaCR version, or |
|
What to tell the user about the version gap, or |
Module Contents¶
- class spacr.qt.recipes.Recipe[source]¶
One named settings bundle.
- Parameters:
name – display name chosen by the user; its slug becomes the file stem when the recipe is saved.
app_key – key of the module the settings belong to; it picks the recipe’s subfolder and is checked against the screen on apply.
settings – setting key to value mapping written into the screen.
spacr_version – spaCR version the recipe was saved with; filled in on save when empty.
created – ISO-8601 timestamp of creation, to the second; filled in on save when empty and used to sort listings newest first.
notes – free-text notes stored with the recipe.
path – file the recipe was loaded from or saved to; not written into the file itself.
- classmethod from_json(data: Dict[str, Any], path: str = '') Recipe[source]¶
Build a recipe from a parsed file.
- Parameters:
data – the parsed JSON mapping; it must carry an integer
spacr_recipeformat version no newer than this build reads and asettingsdict. Missingnamefalls back to"Untitled".- Raises:
ValueError – when the mapping is not a recipe at all, or is a format version this build does not understand. Both raise an explicit error, so an arbitrary JSON file such as a
package.jsonis not applied as settings.
- class spacr.qt.recipes.RecipeDialog(screen, parent: PySide6.QtWidgets.QWidget | None = None)[source]¶
Bases:
PySide6.QtWidgets.QDialogList, apply, share and delete the recipes for one module.
- Parameters:
screen – the module screen whose recipes these are. Its
app_keyis what the list is filtered by, and it becomes the dialog’s parent when none is given.parent – parent widget. Defaults to
screen.
Build the recipe dialog for one module screen.
- Parameters:
screen – the module screen whose settings recipes are saved and applied; its
app_keyscopes which recipes are listed.parent – parent widget; defaults to
screen.
- set_confirmation_runner(runner: Callable[[PySide6.QtWidgets.QMessageBox], Any]) None[source]¶
Replace how the version/compatibility confirmation is run.
The default enters the real modal Apply/Cancel loop. Tests inject a runner that inspects the fully configured message box and returns an answer without blocking; a host can use the same seam for a custom presentation.
- Parameters:
runner – callable given the configured Apply/Cancel
QMessageBox; the recipe is applied only when it returnsQMessageBox.Apply.
- spacr.qt.recipes.apply_recipe(recipe: Recipe, screen) int[source]¶
Write a recipe’s settings into
screen. Returns how many landed.Delegates to
AppScreen.apply_settings_dict, which is the same path the settings-CSV import takes — so a recipe reaches the same widgets an imported CSV reaches.- Raises:
ValueError – when the recipe belongs to a different module. It is refused rather than partially applied: the keys that happen to overlap between two modules are exactly the generic ones (
src,verbose,n_jobs), so a cross-module apply would write only those and still report success.- Parameters:
recipe – the recipe to apply; its settings are copied, not mutated.
screen – the module screen to write into; its
app_keymust match the recipe’s (when both are set) and it must provideapply_settings_dict.
- spacr.qt.recipes.capture_recipe(screen, name: str, notes: str = '') Recipe[source]¶
Build a recipe from a screen’s current settings.
Uses
SettingsWidgets.collect, so what is captured is exactly what a Run would use — including the defaults the user never touched. Storing every value means the recipe reproduces the same settings after a default changes.- Parameters:
screen – the module screen to capture; it must have a settings model (
_settings_model) orValueErroris raised, and itsapp_keyis stored on the recipe.name – display name for the recipe; empty gives
"Untitled".
- spacr.qt.recipes.compatibility_note(recipe: Recipe, model) str[source]¶
Describe the recipe’s settings that this module does not have.
The version gap says that something may have moved; this says what. Reported as a count plus the first four names, so a recipe that differs in many keys gives a short note. The result is empty when there is nothing to report.
- Parameters:
recipe – the bundle.
model – the screen’s
SettingsWidgets.
- spacr.qt.recipes.delete_recipe(recipe: Recipe) bool[source]¶
Remove a recipe’s file.
Truewhen something was removed.- Parameters:
recipe – the recipe whose
pathis deleted; an empty or missing path removes nothing.
- spacr.qt.recipes.install(screen) PySide6.QtWidgets.QToolButton | None[source]¶
Add a Templates button to
screen’s settings search strip.The strip is where a settings bundle belongs — directly above the settings it bundles — and it already exists, so no new toolbar is added. Returns
Nonewhen the screen has no strip (a bespoke screen), or when one is already installed.- Parameters:
screen – the module screen; its
_settings_searchstrip must provideadd_trailing_widget. If the screen already has a_recipe_button, that button is returned unchanged.
- spacr.qt.recipes.install_help_action(window: PySide6.QtWidgets.QMainWindow) PySide6.QtGui.QAction | None[source]¶
Add Settings templates… to the window’s Help menu.
Returns the action, or
Nonewhen there is no Help menu or one is already installed. The command palette mirrors menu actions, so recipes are also reachable from Ctrl+K.- Parameters:
window – the main window; its menu-bar menu titled “Help” (
&ignored) receives the action, before the first separator.
- spacr.qt.recipes.install_window_hooks(window: PySide6.QtWidgets.QMainWindow) _StackWatcher | None[source]¶
Wire recipes into a live main window.
Called once from
spacr.qt.shortcuts.install(). Every failure is logged and swallowed, so a failure to add recipes does not stop the window.- Parameters:
window – the main window; the Help-menu action is added to it and its
_stackscreen stack is watched so each shown screen gets a Templates button. Without a_stackthe result isNone.
- spacr.qt.recipes.list_recipes(app_key: str | None = None) List[Recipe][source]¶
Every readable recipe, newest first.
Unreadable files are logged and skipped rather than raising: one corrupt file must not make the whole list unopenable.
- Parameters:
app_key – restrict to one module.
- spacr.qt.recipes.load_recipe(path: str) Recipe[source]¶
Read one recipe file.
- Parameters:
path – path to a recipe JSON file; it is recorded on the returned recipe.
- Raises:
ValueError – on anything that is not a readable recipe.
- spacr.qt.recipes.open_recipes(screen, parent: PySide6.QtWidgets.QWidget | None = None) RecipeDialog[source]¶
Open the recipe dialog for
screen.- Parameters:
screen – the module screen whose recipes are listed and applied, passed to
RecipeDialog.
- spacr.qt.recipes.recipes_dir(app_key: str | None = None) str[source]¶
The folder holding recipes, optionally for one module.
~/.spacr/recipes(orRECIPE_DIR_ENV), with one subfolder per module so a listing is already scoped and a user can hand over a whole module’s worth by copying one directory. Created on first use.- Parameters:
app_key – restrict to one module’s folder.
- spacr.qt.recipes.save_recipe(recipe: Recipe, directory: str | None = None) str[source]¶
Write
recipeand return its path.- Parameters:
recipe – the bundle. Its
spacr_versionandcreatedare filled in here when empty, so a caller does not have to set them.directory – override the destination (used by export).
- spacr.qt.recipes.spacr_version() str[source]¶
The running spaCR version, or
"unknown"if it cannot be read.
- spacr.qt.recipes.version_note(recipe: Recipe, current: str | None = None) str[source]¶
What to tell the user about the version gap, or
""if there is none.Returns a sentence that names both versions, not a boolean, so the user can judge the gap.
- Parameters:
recipe – the bundle about to be applied.
current – override the running version (tests).