spacr.install_cleanup¶
Find spaCR installations and run the appropriate update or removal procedure.
The standard replacement procedure runs three steps in order:
find old spaCR files –
find_old_installs()delete old spaCR files –
remove_install()install new spaCR –
run_update_sequence()runs the install only after step 2 removed every installer-made copy.
In-app updates use a different procedure for supported macOS installations.
An online installation upgrades spaCR in its existing Python environment
using its bundled uv executable. It keeps the environment, bootstrap
files, application launcher, and installed packages that need no update.
It verifies the installed spaCR version before restarting the application.
A supported frozen macOS application uses a verified DMG replacement and retains its complete previous application bundle. These macOS update paths do not run the standard deletion procedure. Other frozen application families require a supported replacement adapter before an update can start.
Removal never runs an old version’s own uninstaller, so a copy whose
Uninstall.exe or uninstall-spacr.sh is missing or broken is removed
all the same. Preferences and user data are kept: ~/.spacr,
~/.cache/spacr, ~/.local/state/spacr, ~/spacr-demos,
~/spacr-tutorials, the Hugging Face cache, and the spacr/qt
settings (~/.config/spacr, the macOS preferences file, and the
Software\spacr registry key on Windows).
A pip or conda environment the user made is listed but never deleted; the spaCR package is uninstalled from it only when the caller says it was ticked. An editable source checkout is reported and left alone.
The module uses only the standard library and imports nothing from spaCR, so an installer can run it with its bootstrapped Python before any spaCR exists, and a helper process can run a copy of it after the running spaCR has closed:
python -I install_cleanup.py find [--json]
python -I install_cleanup.py remove [--keep PATH] [--sudo] [--purge [--yes]]
python -I install_cleanup.py purge [--yes] [--dry-run]
python -I install_cleanup.py run-plan PLAN.json
purge is the opt-in clean uninstall: it also deletes spaCR’s caches,
backend environments and user data, after listing them and asking. It never
runs on its own; remove --purge runs it after the removal succeeded.
Classes¶
One spaCR installation found on this computer. |
|
What |
Functions¶
|
Find every spaCR installation on this computer. |
|
Remove one installation, without running its own uninstaller. |
|
Find, then delete, then install -- and never install over an old copy. |
|
Run an installation update in a process that outlives spaCR. |
Module Contents¶
- class spacr.install_cleanup.InstallRecord[source]¶
One spaCR installation found on this computer.
- Parameters:
kind –
"installer"for a copy a spaCR installer made,"environment"for a pip or conda environment the user made, or"checkout"for an editable source checkout.layout – which layout it is, for example
"windows-online","linux-online","macos-app"or"conda".platform –
"windows","macos"or"linux".root – the directory the installation lives in.
version – the spaCR version, when it can be read.
launchers – command launchers that start this copy.
shortcuts – desktop and Start Menu shortcut files.
menu_entries – application-menu entries:
.desktopfiles and Start Menu folders.registrations – uninstall registrations:
registry:keys,deb:packages, and application bundles.python – the environment’s interpreter, used to uninstall spaCR.
running – whether the current process runs from this copy.
needs_admin – whether removal needs administrator rights.
notes – other facts worth showing, such as a missing uninstaller.
- class spacr.install_cleanup.RemovalReport[source]¶
What
remove_install()did with one installation.- Parameters:
record – the installation this report is about.
removed – every path, registry entry and package that was removed.
failed –
(item, reason)for everything that could not be removed.skipped –
(item, reason)for everything left in place on purpose.
- spacr.install_cleanup.find_old_installs(*, system=None) List[InstallRecord][source]¶
Find every spaCR installation on this computer.
Installer-made copies come first, then environments the user made, then editable source checkouts. Every layout any released installer used is looked for: the Windows online and offline installers, the Linux and macOS online installers, the macOS application bundle, and the Debian package.
- Parameters:
system – the computer to look at;
Nonemeans this one. Tests pass a stand-in over a temporary directory.- Returns:
one
InstallRecordper installation.
- spacr.install_cleanup.remove_install(record: InstallRecord, *, ticked: bool = False, keep: Sequence[str] = (), system=None) RemovalReport[source]¶
Remove one installation, without running its own uninstaller.
An installer-made copy is removed completely: its folder, launchers, shortcuts, menu entries and uninstall registrations. A Debian package is removed through the package manager, and reported as needing administrator rights when that is what stops it. From an environment the user made, only the spaCR package is uninstalled, and only when
ticked; the environment itself stays. A source checkout is skipped.The running copy is not removed here, because on Windows an installation cannot delete itself while it runs.
start_update_helper()runs the appropriate update procedure after spaCR has closed.- Parameters:
record – an installation from
find_old_installs().ticked – whether the user ticked this environment for removal.
keep – paths to leave in place, such as the log of the install that is about to start.
system – the computer;
Nonemeans this one.
- Returns:
what was removed, what could not be, and why.
- spacr.install_cleanup.run_update_sequence(install: Callable[[], object], *, records: Sequence[InstallRecord] | None = None, ticked: Iterable[str] = (), keep: Sequence[str] = (), find=None, remove=None, system=None)[source]¶
Find, then delete, then install – and never install over an old copy.
Every installer-made copy is removed, the spaCR package is uninstalled from each ticked environment, and only then is
installcalled. When an installer-made copy could not be removed,installis not called at all, and the reports say what stopped it.- Parameters:
install – zero-argument callable that installs the new version.
records – installations already found;
find_old_installs()is called whenNone.ticked – roots of the environments the user ticked.
keep – paths removal must leave in place.
find – replaces
find_old_installs().remove – replaces
remove_install().system – the computer;
Nonemeans this one.
- Returns:
(reports, install_result);install_resultisNonewhen the install was not run.
- spacr.install_cleanup.start_update_helper(records: Sequence[InstallRecord], version: str, *, ticked: Iterable[str] = (), pid: int | None = None, workdir: str | None = None, system=None, spawn=None) Dict[source]¶
Run an installation update in a process that outlives spaCR.
The running spaCR must be an installer-made copy. The helper waits for this process to exit before changing the installation.
For a supported macOS online installation, use the existing bundled
uvand private Python to upgrade spaCR in the same environment. Preserve the environment directory, bootstrap files, application launcher, and installed packages that need no update. Restart only after verifying that the installed version is at leastversionand newer than the previous version, when that previous version is known. A failed upgrade or version check does not trigger removal or a replacement installer.The standard replacement path downloads the new installer, removes older installer-made copies, installs the new version, and starts it. If any required removal fails, skip installation and write the reason to the log.
- Parameters:
records – installations from
find_old_installs().version – the version to install.
ticked – roots of the environments the user ticked.
pid – the process to wait for; this process when
None.workdir – the helper’s folder; a new temporary folder when
None.system – the computer;
Nonemeans this one.spawn – replaces the detached process launcher.
- Returns:
the plan as written to
plan.json.plan["command"]is the helper’s command, orNonewithplan["error"]saying why nothing was started.
A frozen macOS bundle in a user-writable location uses its verified DMG replacement adapter and retains its complete prior bundle. Other frozen application families return an error before removing anything; the helper does not enable an online-installer fallback for these applications.
Nested helpers¶
- _delete._writable_then_retry(func, failed_path, exc_info)¶
Clear a read-only flag and retry once, recording failures.
- Parameters:
func – the
osfunction that failed.failed_path – the path it failed on.
exc_info – the error, as
shutil.rmtree()passes it.
spacr/install_cleanup.py:1154
- _macos_recover_user_bundle.identity(path)¶
Bind recovery to actual directory inodes, not mutable app names alone.
- Parameters:
path – journaled bundle directory to identify.
- Returns:
JSON-compatible device/inode pair.
spacr/install_cleanup.py:2586
- _macos_replace_user_bundle.identity(path)¶
Record the actual directory identity before or after the exchange.
- Parameters:
path – bundle directory whose device and inode are recorded.
- Returns:
JSON-compatible device/inode pair.
spacr/install_cleanup.py:2246
- _macos_tree.refuse_unreadable(error)¶
Propagate a filesystem traversal failure instead of omitting its subtree.
- Parameters:
error – operating-system exception reported by os.walk.
spacr/install_cleanup.py:2044
- _run_plan._finish(code: int) int¶
Write the update log and return
code.- Parameters:
code – the exit code to return.
spacr/install_cleanup.py:3143
- _standalone_helper_command.contains(path, root)¶
Compare canonical paths using the host filesystem’s case semantics.
- Parameters:
path – candidate nested path.
root – containing directory to check.
- Returns:
whether the candidate resolves inside the directory.
spacr/install_cleanup.py:2666