seamm_manager package

Submodules

seamm_manager.apps module

Handle the apps for SEAMM.

seamm_manager.apps.create()[source]

Create the requested apps.

seamm_manager.apps.delete()[source]
seamm_manager.apps.refresh_apps()[source]

Bring the installed apps up to date after an update.

Sets each app’s version to its package’s and, on macOS, replaces the shell script launcher of bundles made by older versions with the compiled one (a script makes Apple Silicon Macs without Rosetta ask to install it). Apps that are not installed are left alone. Returns the names refreshed.

Recreate the installed apps so that they run from the environment’s real path (see versions). Returns the names recreated.

seamm_manager.apps.setup(parser)[source]

Define the command-line interface for handling the apps.

Parameters:

parser (argparse.ArgumentParser) – The main parser for the application.

seamm_manager.apps.show()[source]
seamm_manager.apps.update()[source]

seamm_manager.cache module

Handle the cache for SEAMM components.

seamm_manager.cache.refresh()[source]
seamm_manager.cache.setup(parser)[source]

Define the command-line interface for installing SEAMM components.

Parameters:

parser (argparse.ArgumentParser) – The main parser for the application.

seamm_manager.cli module

Define the command-line interface for the SEAMM installer.

seamm_manager.cli.setup(parser)[source]

Setup the command-line interface for the SEAMM manager.

Parameters:
  • parser (argparse.ArgumentParser) – The main parser for the application.

  • logger (logging.Logger) – The logger for output.

  • environment (str) – The Conda environment name

seamm_manager.compare module

The ‘compare’ command: run one flowchart in two environments and diff the results.

The comparison harness of the parallel-execution campaign (phase 0). Each side is an installation root, an environment directory, or a version of this installation’s environment (venvs/<stamp>); the flowchart runs with each side’s run_flowchart in its own working directory, with the same arguments, and the two trees are compared file by file:

  • .json: parsed, compared with a numeric tolerance; keys whose names say they are volatile (times, dates, versions, hosts, paths) are ignored;

  • .csv: cell by cell, numbers with tolerance;

  • structure and data files (.xyz, .extxyz, .sdf, .mmcif, .cif, .pdb, .dat): token by token, numbers with tolerance;

  • text (.out, .txt, .log, .inp, …): line by line after normalizing timestamps, durations, versions and the working directories;

  • anything else: size only.

Files present on one side only are reported. The exit status is 0 when every file agrees within tolerance.

seamm_manager.compare.compare()[source]
seamm_manager.compare.compare_csv(text_a, text_b, rtol, atol)[source]

Differences between two CSV texts.

seamm_manager.compare.compare_json(a, b, rtol, atol, path='')[source]

Differences between two parsed JSON values, as [‘where: what’, …].

seamm_manager.compare.compare_numeric_text(text_a, text_b, rtol, atol)[source]

Differences between two texts compared token by token, numbers with tolerance (structure files).

seamm_manager.compare.compare_text(text_a, text_b, replacements=())[source]

Differences between two texts after normalization, as a few diff lines.

seamm_manager.compare.compare_trees(dir_a, dir_b, rtol=1e-06, atol=1e-09, ignore=('harness_run.log',), replacements=())[source]

Compare two result trees.

replacements are further (old, new) text substitutions made before comparing text and JSON, e.g. the two installations’ roots.

Returns:

status is one of ‘identical’, ‘within tolerance’, ‘different’, ‘only in a’, ‘only in b’, ‘not compared’.

Return type:

[(relative path, status, details)]

seamm_manager.compare.normalize_text(text, replacements=())[source]

The lines of text that are not expected to vary between runs, with the given (old, new) replacements applied first (the working directories).

seamm_manager.compare.report(results, max_details=5)[source]

Print the comparison and return True if everything agrees.

seamm_manager.compare.resolve_environment(spec)[source]

The environment directory and installation root for a side’s spec.

Returns:

The environment (holding bin/run_flowchart) and the root it belongs to.

Return type:

(pathlib.Path, pathlib.Path)

seamm_manager.compare.run_flowchart(environment, root, flowchart, directory, args)[source]

Run flowchart with environment’s run_flowchart in directory.

seamm_manager.compare.setup(parser)[source]

Define the command-line interface for the comparison.

seamm_manager.conda module

class seamm_manager.conda.Conda(logger=<Logger seamm_manager.conda (WARNING)>)[source]

Bases: object

Class for handling conda

activate(environment)[source]

Activate the requested environment.

property active_environment

The currently active Conda environment.

create_environment(environment_file, name=None, force=False, conda_only=False)[source]

Create a Conda environment.

Parameters:
  • environment_file (str or pathlib.Path) – The name or path to the environment file.

  • name (str = None) – The name of the environment. Defaults to that given in the environment file.

  • force (bool = False) – Whether to overwrite an existing environment.

  • conda_only (bool = False) – Create from the file’s conda part alone, leaving its pip: section to the caller (which may need to install torch from a particular index before anything that depends on it).

delete_environment(name)[source]

Delete a Conda environment.

Parameters:

name (str) – The name of the environment.

property environments

The available conda environments.

exists(environment)[source]

Whether an environment exists.

Parameters:

environment (str) – The name of the environment.

Returns:

True if the environment exists, False otherwise.

Return type:

bool

export_environment(environment, path=None)[source]

Export the definition of an environment.

Parameters:
  • environment (str) – The name of the environment to export

  • path (str or pathlib.Path = None) – An optional filename to export to

install(package, environment=None, channels=None, override_channels=True, progress=True, newline=True, update=None)[source]

Install a package in an environment..

Parameters:
  • package (strip) – The package to install.

  • environment (str) – The name of the environment to list, defaults to the current.

  • channels ([str] = None) – A list of channels to search. defaults to the list in self.channels.

  • override_channels (bool = True) – Ignore channels configured in .condarc and the default channel.

  • progress (bool = True) – Whether to show progress dots.

  • newline (bool = True) – Whether to print a newline at the end if showing progress

  • update (None or method) – Method to call to e.g. update a progress bar

property is_installed

Whether we have access to conda.

list(environment=None, query=None, fullname=False, update=None, explicit=False)[source]

The contents of an environment.

Parameters:
  • environment (str) – The name of the environment to list, defaults to the current.

  • query (str) – Regexp for package names, default to all packages

  • fullname (bool = False) – For a query, match only the full name

  • update (None or method) – Method to call to e.g. update a progress bar

  • explicit (bool = False) – If true, get an explicit list, suitable for “conda create –file”

Returns:

A dictionary keyed by the package names.

Return type:

dict

path(environment)[source]

The path for an environment.

Parameters:

environment (str) – The name of the environment to remove.

Returns:

The path to the environment.

Return type:

pathlib.Path

pip_install(environment, requirements, upgrade=False, index_args=())[source]

pip install the requirements in an environment (name or path).

property prefix

The path for the conda root.

remove_environment(environment)[source]

Remove an existing environment.

Parameters:

environment (str) – The name of the environment to remove.

property root_prefix

The root prefix of the conda installation.

run_python(environment, script, timeout=600)[source]

Run a Python script (text) with an environment’s python and return its output, stdout then stderr; None if it could not be run.

search(query=None, channels=None, override_channels=True, progress=True, newline=True, update=None)[source]

Run conda search, returning a dictionary of packages.

Parameters:
  • query (str = None) – The pattern to search, Defaults to None, meaning all packages.

  • channels ([str] = None) – A list of channels to search. defaults to the list in self.channels.

  • override_channels (bool = True) – Ignore channels configured in .condarc and the default channel.

  • progress (bool = True) – Whether to show progress dots.

  • newline (bool = True) – Whether to print a newline at the end if showing progress

  • update (None or method) – Method to call to e.g. update a progress bar

Returns:

A dictionary of packages, with versions for each.

Return type:

dict

show(package)[source]

Show the information for a single package.

Parameters:

package (str) – The name of the package.

uninstall(package, environment=None, channels=None, override_channels=True, progress=True, newline=True, update=None)[source]

Uninstall a package from an environment..

Parameters:
  • package (str or [str]) – The package to uninstall install.

  • environment (str) – The name of the environment to list, defaults to the current.

  • channels ([str] = None) – A list of channels to search. defaults to the list in self.channels.

  • override_channels (bool = True) – Ignore channels configured in .condarc and the default channel.

  • progress (bool = True) – Whether to show progress dots.

  • newline (bool = True) – Whether to print a newline at the end if showing progress

  • update (None or method) – Method to call to e.g. update a progress bar

update(package=None, environment=None, channels=None, override_channels=True, progress=True, newline=True, all=False, update=None)[source]

Update a package in an environment..

Parameters:
  • package (strip) – The package to update.

  • environment (str) – The name of the environment to list, defaults to the current.

  • channels ([str] = None) – A list of channels to search. defaults to the list in self.channels.

  • override_channels (bool = True) – Ignore channels configured in .condarc and the default channel.

  • progress (bool = True) – Whether to show progress dots.

  • newline (bool = True) – Whether to print a newline at the end if showing progress

  • all (bool = False) – Fully update the environment.

  • update (None or method) – Method to call to e.g. update a progress bar

update_environment(environment_file, name=None, update=None, pip_policy='conservative', index_args=())[source]

Update a Conda environment from an environment file.

Parameters:
  • environment_file (str or pathlib.Path) – The name or path to the environment file.

  • name (str = None) – The name of the environment. Defaults to the current environment.

  • pip_policy (str = "conservative") – How the file’s pip: section is applied. "conda" lets conda do it, which runs pip install -U and so upgrades every pip package, including a bare torch that a machine may hold at a driver-matched build. "conservative" (the default) applies the conda part with conda, then bare pip names without upgrading (they must merely be present) and requirements with a version specifier with -U (kept current within their spec). index_args go to those pip steps (the torch index pair).

seamm_manager.conda.find_conda()[source]

The path to the conda executable, or None.

Tries, in order: $CONDA_EXE (set by an activated conda shell), the PATH, then the usual installation directories. When found somewhere other than the PATH, its directory is added to the PATH so that sub-processes (conda run, the plug-in installers) find it too.

seamm_manager.conda.split_environment_file(environment_file)[source]

Split a conda environment file into its conda part and its pip part.

Returns:

The YAML text of the file without its pip: entry; the pip requirements that are bare names (torch); and those carrying a version specifier or other qualification (xnns>=0.3.0, e3nn==0.4.4, a URL, pkg[extra]).

Return type:

(str, [str], [str])

seamm_manager.configuration module

A class for reading, updating and writing the configuration file.

This class handles the configuration (.ini) file as text, so that comments in the file are preserved.

class seamm_manager.configuration.Configuration(path=None)[source]

Bases: object

add_prolog(text='', force=False)[source]

Add the prolog to the configuration.

Parameters:
  • text (str = '') – The body of the prolog, which should be just comments.

  • force (bool = True) – Whether to overwrite an existing prolog.

add_section(name, text='', force=False)[source]

Add a new section to the configuration.

Parameters:
  • name (str) – The name of the section.

  • text (str = '') – The body of the section, which must be properly formatted.

  • force (bool = True) – Whether to overwrite an existing section of the same name.

file_exists()[source]

Whether the configuration file exists.

from_string(text)[source]

Replace the contents of the configuration with those from text.

Parameters:

text (str) – The configuration data as text.

get_prolog()[source]

Return the prolog of the file, if any.

Returns:

The prolog of the configuration.

Return type:

str

get_values(section)[source]

Return the values in a section as a dictionary.

Returns an empty dictionary if the section does not exist, or if it does not contain any keyword definitions. Use section_exists to differentiate.

Parameters:

section (str) – The name of the section to retrieve.

Returns:

A dictionary of keyword-value pairs, as strings.

Return type:

dict

property path

The path to the configuration file.

save()[source]

Save the current configuration to disk.

section_exists(section)[source]

Return whether a section exits in the configuration.

Parameters:

section (str) – The name of the section.

Returns:

True if the section exists; False otherwise.

Return type:

bool

sections()[source]

Return a list of sections in the configuration.

Returns:

The list of sections.

Return type:

[str]

set_value(section, key, value, strict=False)[source]

Set the key in a section.

Parameters:
  • section (str) – The section to work with.

  • key (str) – The key to set in the section.

  • value (str) – The value to set the key to.

  • strict (bool = False) – Raise an error is the key does not already exist.

to_string(section=None)[source]

Create the text of a section.

Parameters:

section (str) – The name of the section. Defaults to the entire file.

seamm_manager.datastore module

Handle the datastore for SEAMM.

seamm_manager.datastore.db_version()[source]

Return the version of the database.

seamm_manager.datastore.ensure(default_project='default')[source]

Create the datastore if it does not exist, using the environment’s own seamm_datastore, so that the JobServer and the web interface can start in any order. Returns True if it was created.

The first version of the manager left this to the web interface’s first start; a JobServer created before it crash-looped on the missing database.

seamm_manager.datastore.latest_version()[source]

Show information about the datastore.

seamm_manager.datastore.rebuild()[source]

Rebuild the datastore from the job directories.

The job directories hold each job’s flowchart and job_data.json, which is what the datastore records. A new datastore is built from them, keeping the accounts (users, groups, roles), the details of projects that still exist, and the owner of each job from the current datastore, which is kept as a dated backup. Jobs whose directories are gone are not in the new datastore.

seamm_manager.datastore.setup(parser)[source]

Define the command-line interface for handling services.

Parameters:

parser (argparse.ArgumentParser) – The main parser for the application.

seamm_manager.datastore.show()[source]

Show information about the datastore.

seamm_manager.datastore.stamp(revision)[source]

Record in the database that its tables are at revision, without changes.

seamm_manager.datastore.unversioned_revision(db_path)[source]

The revision an unversioned database’s tables already match, or None.

None when the database is versioned, has no jobs table, or predates the first migration (which alembic can then apply from scratch).

seamm_manager.datastore.update()[source]

Update the database to the latest version.

seamm_manager.datastore.update_db()[source]

Update the database to the latest version.

seamm_manager.environment module

The ‘environment’ command: create, show, recreate or remove the uv-managed Python environment that holds SEAMM.

seamm_manager.environment.create(python_version=None)[source]
seamm_manager.environment.ensure(python_version=None)[source]

Create the environment if it does not exist. Returns True if created.

seamm_manager.environment.migrate()[source]
seamm_manager.environment.pin()[source]
seamm_manager.environment.prune()[source]
seamm_manager.environment.recreate()[source]
seamm_manager.environment.remove()[source]
seamm_manager.environment.rollback()[source]
seamm_manager.environment.setup(parser)[source]

Define the command-line interface for the environment.

Parameters:

parser (argparse.ArgumentParser) – The main parser for the application.

seamm_manager.environment.show()[source]
seamm_manager.environment.switch()[source]
seamm_manager.environment.unpin()[source]
seamm_manager.environment.versions()[source]

seamm_manager.flowcharts module

Upgrade an installation’s flowcharts to format 3.0.

The flowchart of each job (flowchart.flow in its directory) and the datastore’s record of it are converted from format 2.0 to 3.0 by seamm-flowchart migrate, in the installation’s environment. This module wraps it in one step for users: a dry run and its summary, a confirmation, then – with the services stopped – the migration itself, which backs up the datastore and writes a manifest to undo the file changes.

seamm_manager.flowcharts.migrate()[source]

Convert the installation’s job flowcharts and datastore to format 3.0.

seamm_manager.flowcharts.migration_recorded(root=None)[source]

Whether <root>/installation.ini records that every job flowchart is in format 3.0, so the scan of the job directories can be skipped. The scan reads one line of every job’s flowchart, which on a cluster’s network file system with tens of thousands of jobs takes many minutes; once no old flowchart remains none can appear (seamm 3.0 writes only 3.0), so the result is recorded and the scan not repeated. flowcharts status always scans, and refreshes the record.

seamm_manager.flowcharts.notice()[source]

A one-line notice for ‘seamm-manager update’ and ‘install’ if old flowcharts remain.

Skipped once migration_recorded(); when a scan finds nothing old, that is recorded so the next update does not scan again.

seamm_manager.flowcharts.old_job_flowcharts(root=None, stop_at=None)[source]

The number of job directories whose flowchart is in format 2.0 (or 1.0).

Parameters:
  • root (pathlib.Path, optional) – The installation’s root; by default the current one.

  • stop_at (int, optional) – Stop counting once this many are found.

seamm_manager.flowcharts.record_migration(root=None, done=True)[source]

Record in <root>/installation.ini that the job flowcharts are all in format 3.0 (done), or remove the record.

seamm_manager.flowcharts.setup(parser)[source]

Define the command-line interface for the flowcharts.

Parameters:

parser (argparse.ArgumentParser) – The main parser for the application.

seamm_manager.flowcharts.status()[source]

Report whether any job flowcharts are still in format 2.0 (a full scan, which also refreshes the record update relies on).

seamm_manager.gui module

class seamm_manager.gui.GUI(logger=<Logger seamm_manager.gui (WARNING)>)[source]

Bases: MutableMapping

about()[source]
cancel()[source]
event_loop()[source]
property gui_only

Whether to install only the GUI.

handle_dbg_level(level)[source]
layout_apps()[source]

Redraw the apps table in the GUI.

layout_services()[source]

Redraw the services table in the GUI.

preferences()[source]
refresh()[source]

Update the table of packages.

refresh_apps()[source]
refresh_services()[source]
reset_table()[source]

Redraw the table in the GUI.

setup()[source]

seamm_manager.install module

Install requested components of SEAMM.

seamm_manager.install.install()[source]

Install the requested SEAMM components and plug-ins.

Parameters:

options (argparse.Namespace) – The options from the command-line parser.

seamm_manager.install.install_development_environment()[source]

Install packages needed for development, from the package list’s ‘development packages’ (falling back to a built-in list).

seamm_manager.install.install_packages(to_install, update=False, third_party=False, gui_only=False, progress=None, update_text=None)[source]

Install SEAMM components and plug-ins.

seamm_manager.install.install_seamm_webui(update=False)[source]

Create/update the dedicated venv-webui environment under the root and install (or upgrade) seamm_webui into it from PyPI.

seamm_webui is not in the package list and, being a daemon rather than a plug-in, lives in its own environment rather than the main one. Its own runtime dependencies (fastapi, uvicorn, …) are declared in its PyPI package and resolved by uv here, not duplicated.

seamm_manager.install.setup(parser)[source]

Define the command-line interface for installing SEAMM components.

Parameters:

parser (argparse.ArgumentParser) – The main parser for the application.

seamm_manager.install.write_queues_example(root)[source]

Write <root>/queues-example.ini, an annotated example of the JobServer’s queue file, if missing.

The JobServer reads <root>/<name>.ini (the hostname by default) for the queues a job may be sent to; nothing writes that file, since it describes the site. The example beside it shows a local queue, a machine’s own SLURM, a remote cluster over ssh and one that bundles a flowchart’s calculations, with every key explained, to copy and edit.

Returns:

The file, if it was written.

Return type:

pathlib.Path or None

seamm_manager.install.write_taskserver_ini(root)[source]

Write <root>/taskserver.ini, the TaskServer’s capacity, if missing.

The TaskServer (seamm_scheduler.taskserver) is the queue that a machine’s SEAMM jobs and their calculations can share, used by a queue section with scheduler = seamm. Its capacity is written out explicitly – this machine’s physical cores and half its memory – rather than left as a silent default, so it can be seen and changed.

Returns:

The file, if it was written.

Return type:

pathlib.Path or None

seamm_manager.installer_base module

class seamm_manager.installer_base.InstallerBase(ini_file='~/.seamm.d/seamm.ini', logger=<Logger seamm_manager.installer_base (WARNING)>)[source]

Bases: object

A base class for plug-in installers.

This base class provides much of the functionality needed by installers for plug-ins, but not the functionality specific to a given plug-in.

section

The section of the configuration file to use. Defaults to None.

Type:

str

REFRESH_DAYS = 7
ask_yes_no(text, default=None)[source]

Ask a simple yes/no question, returning True/False.

Parameters:

text (str) – The text of the question.

Returns:

True for yes; False, no

Return type:

bool

check()[source]

Check the installation and fix errors if requested.

If the option yes is present and True, this method will attempt to correct any errors in the configuration file. Use –yes on the command line to enable this.

The information in the configuration file is:

installation

How the executables are installed. One of user, modules or conda

conda-environment

The Conda environment if and only if installation = conda

modules

The environment modules if installation = modules

{self.path_name}

The path where the executables are. Automatically defined if installation is conda or modules, but given by the user is it is user.

Returns:

True if everything is OK, False otherwise. If yes is given as an option, the return value is after fixing the configuration.

Return type:

bool

check_configuration_file()[source]

Checks that the necessary section for the plug-in is in the configuration file.

check_exe_configuration_file()[source]

Checks that the init file for the executable for the plug-in exists.

If it does not, it is created from the plug-in’s template (data/<code>.ini), when the plug-in ships one.

Returns:

True if the file was created.

Return type:

bool

property code_environments

own, shared or prefixed.

See seamm_manager.policy. In a shared installation the plug-ins never create, update or remove a conda environment.

Type:

This installation’s code-environment policy

property conda

The Conda object to use for accessing Conda.

property configuration

The Configuration object for working with the ini file.

property exe_config
executables_in_path()[source]

Check whether the executables are found in the PATH.

Returns:

The path where the executables are, or None.

Return type:

pathlib.Path

have_executables(path)[source]

Check whether the executables are found at the given path.

Parameters:

path (pathlib.Path) – The directory to check.

Returns:

True if all of the executables are found.

Return type:

bool

property init_file_name

The initialization file for the executable.

install()[source]

Install using a Conda environment.

A plug-in whose code cannot be installed this way (ORCA, Gaussian, VASP, … are licensed manual installations) has no environment_file; say so instead of failing.

property manual_code

Whether the code is installed by hand rather than with Conda.

Licensed codes such as ORCA, Gaussian and VASP have no environment file.

property pip

The Pip object used for working with pip.

property root

The root of the SEAMM installation being worked on.

In order: SEAMM_ROOT, which seamm-manager sets for the installation it is working on; root in the [SEAMM] section of the per-user seamm.ini (deprecated, since every installation shares that file); the installation this Python belongs to (<root>/venv); ~/SEAMM. The codes’ .ini files are written here.

run()[source]

Do what the user asks via the commandline.

setup_parser()[source]

Parse the command line into the options.

property shared_codes

Whether this installation uses the default installation’s codes.

show()[source]

Show the current installation status.

torch_managed

torch is then installed from the index matching the machine’s NVIDIA driver, a working torch is left alone, and the environment is checked after install and update (seamm_manager.torch_support). torch_imports names the modules the check must import, e.g. (“torch”, “xnn”, “mdi”).

Type:

A plug-in whose code needs PyTorch sets this

torch_target()[source]

The torch build this machine needs: --torch-tag on the command line, else torch-build in the plug-in’s .ini file (auto detects), else detection. See seamm_manager.torch_support.torch_target().

uninstall()[source]

Uninstall the Conda environment.

update()[source]

Update the installation, if possible.

In a shared installation this only reports: the default installation keeps the codes up to date.

seamm_manager.installer_base.environment_created_by_seamm(prefix)[source]

Whether conda’s history says a SEAMM installer created the environment at prefix: its first command is conda env create ... --file seamm-<step>.yml. None when the history cannot be read.

seamm_manager.linux module

Linux OS specific routines handling unique operations.

  • Installing daemons to handle the Dashboard and JobServer

class seamm_manager.linux.ServiceManager(prefix='')[source]

Bases: object

create(name, exe_path, *args, user_agent=True, user_only=True, stderr_path=None, stdout_path=None, exist_ok=False)[source]

Create a service on Linux.

Linux supports three types of services. This function uses user_agent and user_only to control which is selected.

  1. A user service for a single user, which runs while that user is logged in. (True, True)

  2. A service installed by the admin that is available for all users, and runs when any user is logged in. (True, False)

  3. A system-wide service that runs when the machine is booted. (False, not used)

Parameters:
  • name (str) – The name of the agent

  • exe_path (pathlib.Path or str) – The path to the executable (required). Either a path-like object or string

  • args ([]) – List of arguments for the program.

  • user_agent (bool = True) – Whether to create a per-user agent (True) or system-wide daemon (False)

  • user_only (bool = True) – Whether to install for just the current user (True) or all users (False). Only affects user agents, not daemons which are always system-wide.

  • stderr_path (pathlib.Path or str = None) – The file to direct stderr. Defaults to “~/SEAMM/logs/<name>.out”

  • stdout_path (pathlib.Path or str = None) – The file to direct stdout. Defaults to “~/SEAMM/logs/<name>.out”

  • exist_ok (bool = False) – If True overwrite an existing file.

property data
delete(service, ignore_errors=False)[source]
file_path(service)[source]

Return the path to the unit file for the service.

is_installed(service)[source]
is_running(service)[source]
list()[source]
property paths
restart(service, ignore_errors=False)[source]
start(service, ignore_errors=False)[source]
status(service)[source]
stop(service, ignore_errors=False)[source]
property uid
seamm_manager.linux.create_app(exe_path, *args, name='SEAMM', comment='the Simulation Environment for Atomistic and Molecular Modeling', user_only=False, icons=None, **kwargs)[source]

Create an application bundle for a Linux app.

Parameters:
  • exe_path (pathlib.Path or str) – The path to the executable (required). Either a path-like object or string

  • name (str) – The name of the app

  • comment (str = "the Simulation Environment for Atomistic and Molecular Modeling") – A comment for use in tooltips, etc.

  • user_only (bool = False) – Whether to install for just the current user or all users (default).

  • icons (pathlib.Path or str) – Optional path to the icns files to use.

  • kwargs – Other keywords arguments for compatibility with other OS’s. Ignored

seamm_manager.linux.delete_app(name, missing_ok=False)[source]

Delete the app given.

Parameters:
  • name (str) – The name of the app.

  • missing_ok (bool = False) – Don’t throw an error if the app does not exist.

seamm_manager.linux.get_apps()[source]

Return a list of all user applications.

Returns:

{str – Dictionary of app names and paths to the desktop file.

Return type:

str}

seamm_manager.linux.list_to_dict(lst)[source]
seamm_manager.linux.update_app(name, version, missing_ok=False)[source]

Update the version for a Linux app.

Since the desktop file does not have the version, nothing to do.

Parameters:
  • name (str) – The name of the app

  • version (str) – The version of the app.

  • missing_ok (bool = False) – Don’t throw an error if the app does not exist.

seamm_manager.mac module

Mac OS specific routines handling unique operations.

  • Creating the ‘app’

  • Installing Launch Agents to handle the Dashboard and JobServer

class seamm_manager.mac.ServiceManager(prefix='')[source]

Bases: object

create(name, exe_path, *args, user_agent=True, user_only=True, stderr_path=None, stdout_path=None, exist_ok=False, environment=None)[source]

Create a service on MacOS.

The Mac supports three types of services. This function uses user_agent and user_only to control which is selected.

  1. A user Launch Agent for a single user, which runs while that user is logged in. (True, True)

  2. A Launch Agent installed by the admin that is available for all users, and runs when any user is logged in. (True, False)

  3. A system-wide service that runs when the machine is booted. (False, not used)

Parameters:
  • name (str) – The name of the agent

  • exe_path (pathlib.Path or str) – The path to the executable (required). Either a path-like object or string

  • args ([]) – List of arguments for the program.

  • user_agent (bool = True) – Whether to create a per-user agent (True) or system-wide daemon (False)

  • user_only (bool = True) – Whether to install for just the current user (True) or all users (False). Only affects user agents, not daemons which are always system-wide.

  • stderr_path (pathlib.Path or str = None) – The file to direct stderr. Defaults to “~/SEAMM/logs/<name>.out”

  • stdout_path (pathlib.Path or str = None) – The file to direct stdout. Defaults to “~/SEAMM/logs/<name>.out”

  • exist_ok (bool = False) – If True overwrite an existing file.

  • environment (dict(str, str) = None) – Environment variables to set for the service.

property data
delete(service, ignore_errors=False)[source]
file_path(service)[source]

Return the path to the plist file for the service.

is_installed(service)[source]
is_running(service)[source]
list()[source]
property paths
restart(service, ignore_errors=False)[source]
start(service, ignore_errors=False)[source]
status(service)[source]
stop(service, ignore_errors=False)[source]
property uid
seamm_manager.mac.create_app(exe_path, *args, identifier=None, name='SEAMM', version='0.1.0', user_only=False, icons=None, copyright=None)[source]

Create an application bundle for a Mac app.

Parameters:
  • exe_path (pathlib.Path or str) – The path to the executable (required). Either a path-like object or string

  • identifier (str) – The bundle identifier. If None, is set to ‘org.molssi.seamm.<name>’.

  • name (str) – The name of the app

  • version (str = "0.1.0") – The version of the app.

  • user_only (bool = False) – Whether to install for just the current user. Defaults to all users.

  • icons (pathlib.Path or string) – Optional path to the icns file to use.

  • copyright (str) – The human-readable copyright. Defaults to “Copyright 2017-xxxx MolSSI”

seamm_manager.mac.create_service_bundle(directory, name, python, icons)[source]

Make an app bundle whose executable is the Python interpreter itself.

A service run as <venv>/bin/seamm-jobserver shows up everywhere on macOS as python3.12, because the process is named after the program file that runs, the interpreter. With the interpreter inside <name>.app the process is called <name> and Activity Monitor shows the bundle’s icon. uv’s Python is a single statically linked file, so a hard link is enough.

The service must set __PYVENV_LAUNCHER__ to the venv’s bin/python so that the interpreter uses the venv (CPython reads it at startup on macOS, as the python.org launcher does, and removes it from the environment).

Parameters:
  • directory (pathlib.Path) – Where to put the bundle, e.g. <root>/services.

  • name (str) – The bundle’s name, which is also the process name, e.g. SEAMM-JobServer.

  • python (pathlib.Path or str) – The venv’s bin/python; the interpreter it resolves to is linked.

  • icons (pathlib.Path or str) – The icns file for the bundle.

Returns:

The bundle’s executable, to run in place of python.

Return type:

pathlib.Path

seamm_manager.mac.delete_app(name, missing_ok=False)[source]

Delete the app given.

Parameters:
  • name (str) – The name of the app.

  • missing_ok (bool = False) – Don’t throw an error if the app does not exist.

seamm_manager.mac.get_apps()[source]
seamm_manager.mac.install_launcher(contents_path, name, script)[source]

Put the compiled launcher and the script it runs into an app bundle.

macOS needs a bundle’s executable to be a compiled program. A shell script carries no architecture, so on Apple Silicon without Rosetta the system asks the user to install Rosetta before launching it. The universal launcher shipped in data/macos_launcher (source beside it) runs Contents/Resources/<name>.sh with bash instead.

Parameters:
  • contents_path (pathlib.Path) – The bundle’s Contents directory.

  • name (str) – The app’s name, which is also the executable’s (CFBundleExecutable).

  • script (str) – The text of the shell script to run.

seamm_manager.mac.is_macho(path)[source]

Whether the file is a compiled Mach-O program (not a script).

seamm_manager.mac.refresh_service_bundle(bundle_path)[source]

Re-link a service bundle’s interpreter if its environment’s has changed.

Returns True if the link was remade (the service picks it up when it next restarts), False if it was current or the bundle is not a service bundle.

seamm_manager.mac.update_app(name, version, missing_ok=False)[source]

Update the version for a Mac app.

Parameters:
  • name (str) – The name of the app

  • version (str) – The version of the app.

  • missing_ok (bool = False) – Don’t throw an error if the app does not exist.

seamm_manager.metadata module

Metadata about packages, etc.

seamm_manager.my module

Global module for passing around objects and constants.

seamm_manager.naming module

Names of an installation’s services, apps and service bundles.

Several SEAMM installations can live on one machine (~/SEAMM, ~/SEAMM_DEV, ~/SEAMM_NEW, …). Each is identified by a tag: empty for the default installation ~/SEAMM, otherwise the root’s directory name with its case kept (or the --name given to the manager). The default installation keeps the plain names (jobserver, SEAMM); any other gets the tag in its names (jobserver-SEAMM_DEV, SEAMM (SEAMM_DEV)), so installations never collide.

seamm_manager.naming.app_name(app)[source]

The desktop app’s name for this installation, e.g. SEAMM (SEAMM_DEV).

seamm_manager.naming.bundle_name(base)[source]

A service bundle’s name for this installation, e.g. SEAMM-JobServer-SEAMM_DEV.

seamm_manager.naming.compute_tag(root, name=None)[source]

The tag for the installation at root.

Parameters:
  • root (str or pathlib.Path) – The installation’s root.

  • name (str = None) – An explicit name for the installation, which wins.

Returns:

“” for the default installation ~/SEAMM.

Return type:

str

seamm_manager.naming.same_root(a, b)[source]

Whether two root paths name the same directory.

seamm_manager.naming.service_kind(name)[source]

The kind of a SEAMM service from its name: jobserver, webui or dashboard.

Handles the current names (jobserver, jobserver-SEAMM_NEW) and the older development names (dev_jobserver).

seamm_manager.naming.service_name(service)[source]

The service’s name for this installation, e.g. jobserver-SEAMM_DEV.

seamm_manager.naming.tag()[source]

The current installation’s tag.

seamm_manager.pip module

class seamm_manager.pip.Pip[source]

Bases: object

Class for handling pip

install(package)[source]

Install the requested package.

Parameters:

package (str) – The package of interest.

list(outdated=False, uptodate=False)[source]

List the installed packages.

Parameters:
  • outdated (bool) – If true, list only the outdated packages. Cannot be used with uptodate.

  • uptodate (bool) – If true, list only the up-to-date packages. Cannot be used with outdated.

search(query=None, framework=None, exact=False, progress=False, newline=True, update=None)[source]

Search PyPi for packages.

Parameters:
  • query (str) – The text of the query, if any.

  • framework (str) – The framework classifier, if any.

  • exact (bool = False) – Whether to only return the exact match, defaults to False.

  • progress (bool = False) – Whether to show progress dots.

  • newline (bool = True) – Whether to print a newline at the end if showing progress

  • update (None or method) – Method to call to e.g. update a progress bar

Returns:

A list of packages matching the query.

Return type:

[str]

show(package)[source]

Return the information for an installed package.

Parameters:

package (str) – The package of interest.

uninstall(package)[source]

Remove the requested packages.

Parameters:

package (str or [str]) – The package of interest.

update(package)[source]

Update the requested package.

Parameters:

package (str) – The package of interest.

seamm_manager.policy module

How an installation gets the external codes’ conda environments.

Every installation on a machine would otherwise share the codes’ conda environments by name (seamm-lammps, seamm-mopac, …), so installing or updating plug-ins in a trial installation could change production’s codes. Each installation therefore has a code-environment policy, kept in <root>/installation.ini:

own

The plug-ins create and update the codes’ environments, as always. The default, and the only choice, for the default installation ~/SEAMM.

shared

The plug-ins never create, update or remove a conda environment. Installing a plug-in copies the default installation’s <code>.ini into this root, so the code runs from the same environment, and reports a code the default installation does not have; updating only reports. The default for any other root.

prefixed

The installation has its own copies, named seamm-<tag>-<code> (e.g. seamm-SEAMM_NEW-lammps), for testing new versions of the codes themselves.

(The file is not <root>/seamm.ini: seamm_util still moves an old ~/SEAMM/seamm.ini into ~/.seamm.d.)

seamm_manager.policy.code_environment_policy(root)[source]

The installation’s code-environment policy: own, shared or prefixed.

seamm_manager.policy.is_default_root(root)[source]

Whether root is the default installation, ~/SEAMM.

seamm_manager.policy.prefixed_environment(name, tag)[source]

The installation’s own copy of a code environment: seamm-<tag>-<code>.

seamm_manager.policy.set_code_environment_policy(root, policy)[source]

Record the installation’s code-environment policy.

seamm_manager.services module

Handle the services (daemons) for SEAMM.

seamm_manager.services.create()[source]
seamm_manager.services.create_service(service, force=False, port=None, dashboard_name=None, webui_host='0.0.0.0', start=True)[source]

Create and start one of this installation’s services.

Parameters:
  • service (str) – “jobserver”, “webui” or “dashboard”.

  • force (bool = False) – Recreate the service if it exists.

  • port (int = None) – The web interface’s or dashboard’s port. Default: the service’s current port, else that of a same-root service it replaces, else the first free port from 55055.

  • dashboard_name (str = None) – The dashboard’s name. Default: the host name, plus the installation’s tag.

  • webui_host (str = "0.0.0.0") – The address the web interface listens on.

  • start (bool = True) – Start the service once created. False leaves it stopped, never started even briefly (a service deliberately stopped, recreated by an update).

Returns:

Whether the service was created.

Return type:

bool

seamm_manager.services.delete()[source]
seamm_manager.services.free_port(exclude=(), start=55055)[source]

The first port from start that no other SEAMM service uses and is free.

seamm_manager.services.is_running(name, manager=None)[source]

Whether the service name is installed and running.

seamm_manager.services.refresh_service_bundles()[source]

Keep the macOS service bundles in step with their environments.

Re-links a bundle’s interpreter when its environment’s Python has changed (effective at the service’s next restart), and points out services still run directly as python3.12. Returns the bundles re-linked.

Recreate this installation’s jobserver and dashboard services so that they run from the environment’s real path (see versions). The web interface has its own environment and is left alone.

A running service is restarted; a stopped one is recreated but left stopped. Returns the names of the services restarted.

seamm_manager.services.restart()[source]
seamm_manager.services.restart_if_running(name, manager=None)[source]

Restart the service name if it is running; leave a stopped one stopped.

Returns:

Whether it was restarted.

Return type:

bool

seamm_manager.services.same_root_services(service)[source]

Other SEAMM services of this kind started with this installation’s root.

Whatever their names – the older dev_jobserver, or one made by hand – two services of one kind on one root would share a datastore, so creating a service replaces them.

seamm_manager.services.setup(parser)[source]

Define the command-line interface for handling services.

Parameters:

parser (argparse.ArgumentParser) – The main parser for the application.

seamm_manager.services.show()[source]
seamm_manager.services.start()[source]
seamm_manager.services.status()[source]
seamm_manager.services.stop()[source]

seamm_manager.show module

Show the status of the SEAMM installation.

seamm_manager.show.setup(parser)[source]

Define the command-line interface for installing SEAMM components.

Parameters:

parser (argparse.ArgumentParser) – The main parser for the application.

seamm_manager.show.show()[source]

seamm_manager.torch_support module

PyTorch for a code environment: which build this machine needs, what an environment holds, and whether what it holds works.

PyTorch wheels bundle their CUDA runtime, so the build a machine needs is set by its NVIDIA driver, which nvidia-smi reports as a CUDA version ceiling, not by any CUDA toolkit installed on it. PyPI’s default wheel bundles the newest CUDA runtime, which an older driver cannot run: torch then imports and runs on the CPU, and nothing says so. A plug-in whose code needs torch (xnn-step, lammps-step’s MLFF engine) therefore installs torch from the PyTorch index that matches the driver, leaves a working torch alone, and checks the result.

The table of driver ceilings to wheel tags is the only part that goes stale: update it when PyTorch adds a CUDA build. A machine’s choice can be forced with torch-build = <tag> in the plug-in’s .ini file, or --torch-tag on its installer, for a cluster whose login node has no GPU.

The same reasoning, worked out by hand for the LAMMPS environment, is in lammps-mdi’s cuda_utils/ml_install; this module is the installer’s copy of it (lammps-mdi runs inside the code environment, where seamm-manager is not installed).

seamm_manager.torch_support.DRIVER_TO_TAG = (((13, 0), 'cu130'), ((12, 1), 'cu128'), ((11, 8), 'cu118'))

Minimum driver CUDA ceiling (major, minor) -> the newest PyTorch wheel tag that driver can run, newest first. A wheel’s bundled runtime may be newer than the driver’s ceiling within the same major version (CUDA’s minor-version compatibility), so cu128 runs on any 12.x driver from 12.1; a cu130 wheel needs a 13.x driver. Update when PyTorch adds a build.

seamm_manager.torch_support.PROBE_KEYS = ('torch', 'torch_version', 'cuda_build', 'cuda_available', 'mps_available', 'device_count', 'imports')

What a probe of an environment reports; see probe_script()

seamm_manager.torch_support.TORCH_INDEX_BASE = 'https://download.pytorch.org/whl'

The PyTorch wheel indexes

seamm_manager.torch_support.assess(probe, target)[source]

Judge an environment’s torch against the machine.

Returns:

A status and a sentence. Statuses: missing (no torch); ok (torch works for this machine); gpu-unusable (a CUDA build that cannot see the GPU this machine has: the driver is too old for it); cpu-on-gpu (a CPU build on a machine with an NVIDIA driver); unknown (the probe failed).

Return type:

(str, str)

seamm_manager.torch_support.detect_cuda_driver()[source]

The driver’s CUDA ceiling as (major, minor) from nvidia-smi, or None when there is no nvidia-smi, it fails, or it reports no GPU.

seamm_manager.torch_support.install_command(target, python='python', packages=('torch',))[source]

The pip command, as a list, that installs packages from the target’s index.

seamm_manager.torch_support.parse_probe(output)[source]

The probe’s dictionary from the python’s output, or None.

seamm_manager.torch_support.pip_index_args(target)[source]

The pip options that keep torch on the right index: the target’s index first and PyPI as the extra index, so anything that pulls torch in during the step still gets the right build. Empty for PyPI’s own wheel.

seamm_manager.torch_support.probe_script(imports=())[source]

Python that prints, as one JSON line, what an environment’s torch is and whether the named modules import. Run it with the environment’s python.

seamm_manager.torch_support.recommend_tag(driver)[source]

The wheel tag for a driver (major, minor): the newest it can run, or None if it is older than any build in DRIVER_TO_TAG.

seamm_manager.torch_support.torch_target(forced=None, system=None, driver='detect')[source]

Which torch build this machine should have.

Parameters:
  • forced (str, optional) – A tag to use regardless (cu128, cpu, default), from the .ini file or the command line. auto/""/None detect.

  • system (str, optional) – platform.system(); for tests.

  • driver (tuple or None or "detect") – The driver’s CUDA ceiling; "detect" runs nvidia-smi.

Returns:

tag: the wheel tag, "default" for PyPI’s own wheel (macOS, where it carries MPS), "cpu" for the CPU build, None when nothing can be decided (Linux, no nvidia-smi, nothing forced: the caller decides whether to assume a CPU machine); index_url: the index for that tag, None for PyPI; driver: what was detected; reason: one line saying why.

Return type:

dict

seamm_manager.uninstall module

Uninstall requested components of SEAMM.

seamm_manager.uninstall.setup(parser)[source]

Define the command-line interface for removing SEAMM components.

Parameters:

parser (argparse.ArgumentParser) – The main parser for the application.

seamm_manager.uninstall.uninstall()[source]

Uninstall the requested SEAMM components and plug-ins.

With –all the whole environment is removed after the plug-ins’ own uninstallers (for the external codes) have run.

seamm_manager.uninstall.uninstall_packages(to_uninstall, gui_only=False)[source]

Uninstall SEAMM components and plug-ins.

seamm_manager.update module

Update requested components of SEAMM.

seamm_manager.update.setup(parser)[source]

Define the command-line interface for updating SEAMM components.

Parameters:

parser (argparse.ArgumentParser) – The main parser for the application.

seamm_manager.update.update()[source]

Update the requested SEAMM components and plug-ins.

seamm_manager.update.update_development_environment()[source]

Update packages needed for development, in place (--in-place only; otherwise they are upgraded in the new environment with the packages).

seamm_manager.update.update_packages(to_update, gui_only=False, progress=None, update_text=None, latest=False, extra=None)[source]

Update SEAMM components and plug-ins.

extra names further packages (the development tools) to upgrade along with any SEAMM package that changes; they do not by themselves cause a rebuild.

The version to update to normally comes from the nightly package list, and the install is constrained to the matching lock file. With latest each package’s newest release on PyPI is used when it is newer than the list’s, pinned exactly, and the lock is not applied (it would pin the older version); PyPI being unreachable falls back to the list for that package.

seamm_manager.update.update_webui()[source]

Update the web interface’s own environment (venv-webui), if this installation has one, and restart its service if anything in it changed.

seamm-webui is not in the package list and lives in its own environment, so updating the main environment never touched it: an installation kept its old web interface, and the datastore inside it, until it was updated by hand.

seamm_manager.util module

Utility methods for the SEAMM installer.

class seamm_manager.util.JSONDecoder(**kwargs)[source]

Bases: JSONDecoder

Class for handling the package versions in JSON.

dict_to_object(d)[source]
class seamm_manager.util.JSONEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)[source]

Bases: JSONEncoder

Class for handling the package versions in JSON.

default(obj)[source]

Implement this method in a subclass such that it returns a serializable object for o, or calls the base implementation (to raise a TypeError).

For example, to support arbitrary iterators, you could implement default like this:

def default(self, o):
    try:
        iterable = iter(o)
    except TypeError:
        pass
    else:
        return list(iterable)
    # Let the base class default method raise the TypeError
    return super().default(o)
exception seamm_manager.util.PackageListUnavailable[source]

Bases: RuntimeError

The package list could not be fetched and there is no earlier copy.

seamm_manager.util.constraints()[source]

The lock file to pass to uv, or None if the user opted out or it is missing.

seamm_manager.util.find_packages(progress=True, update=None, update_cache=False, cache_valid=1)[source]

Fetch the package list and its lock file from Zenodo.

The package list (SEAMM_packages.json, format 2) gives every package the manager handles with its current version and type. The lock file (seamm.lock.txt) is the universal set of pinned versions that resolved together; it is saved under <root>/environments and passed to uv as constraints so installations are reproducible.

Returns:

name -> {“description”, “type”, “version”}

Return type:

dict(str, dict)

seamm_manager.util.get_metadata()[source]

Get the metadata for this installation.

Returns:

{str – A dictionary of the metadata.

Return type:

any}

seamm_manager.util.initialize()[source]

Set up the conda and pip wrappers. Conda is only needed for the external codes’ own environments, so its absence is not an error here; the plug-in installers report it when they need it.

seamm_manager.util.package_info(package, conda_only=False)[source]

Return info on a package in the SEAMM environment.

Parameters:

package – The name of the package.

Returns:

The installed version and “pypi”, or (None, None) if not installed.

Return type:

(str, str)

seamm_manager.util.pypi_latest(package, timeout=10)[source]

The newest release of package on PyPI, or None if it cannot be found.

Asks PyPI’s simple index (the JSON form of PEP 691) – the index uv installs from – so a release made after the nightly package list is visible at once and is certainly installable. (PyPI’s JSON API was used before, but its CDN served a stale copy to Python’s requests while the simple index already had the release.) Pre-releases and yanked files are ignored. Network problems, an unknown project or an odd response give None: the caller falls back to the package list.

seamm_manager.util.retire_installer(specs, installed)[source]

Remove seamm-installer from the environment before seamm-manager goes in.

Both provide the seamm_installer module (the manager ships it as a compatibility shim for the plug-ins’ installers), so they cannot coexist in one environment. Returns True if it was removed.

seamm_manager.util.run_plugin_installer(package, *args, verbose=True)[source]

Run the plug-in installer with given arguments.

Parameters:
  • package – The package name for the plug-in. Usually xxxx-step.

  • args – Command-line arguments for the plugin installer.

Returns:

The result structure from subprocess.run, or None if there is no installer.

Return type:

xxxx

seamm_manager.util.set_metadata(metadata)[source]

Set the metadata for this installation.

Parameters:

{str (any}) – A dictionary of the metadata.

seamm_manager.util.sync_manager()[source]

Put the running manager’s own release into the environment.

The package list (and lock) on Zenodo names the manager version current when the nightly job last ran, so for up to a day after a release the environment would get the previous manager – and the plug-ins’ installers run with that copy. If this manager is a clean release newer than what the environment holds, install exactly this version there, outside the lock’s constraints (only this package). Returns the version installed, or None if nothing was done.

seamm_manager.util.write_environment_snapshot(tag)[source]

Record uv pip freeze under <root>/environments as the audit trail.

seamm_manager.uv module

The uv-managed Python environment that holds SEAMM.

Uv wraps the uv executable for one virtual environment, by default <root>/venv. Every SEAMM package and every Python dependency is installed into it from PyPI with uv pip install; the interpreter itself comes from uv python install. Nothing here touches conda: the external codes’ own environments are handled by the plug-in installers.

Versioned environments

Once an installation is versioned, <root>/venv is a symlink to the current environment, which lives in <root>/venvs/<stamp>/. An update builds a new environment beside the current one and switches the link, so a running job – which imports lazily from the environment it started in – never sees a half-updated environment. Everything that launches a process (services, apps, the JobServer’s own jobs) must embed the real path, because CPython does not resolve the symlink when it locates a venv: a process started as <root>/venv/bin/python would follow the link to whatever is current. So bin_path, python, bin() and which() all return paths under real_path, and path stays the logical <root>/venv for messages.

class seamm_manager.uv.Uv(root, name='venv', python_version='3.12')[source]

Bases: object

A uv-managed virtual environment.

Parameters:
  • root (pathlib.Path or str) – The SEAMM root; the environment lives in <root>/venv.

  • name (str = "venv") – The environment directory name under the root.

  • python_version (str = "3.12") – The interpreter version to install when creating the environment.

bin(name)[source]

The path an executable name would have in this environment.

property bin_path
create(python_version=None, seed=True)[source]

Create the environment, installing the interpreter if needed.

seed adds pip to the environment, which some tools (and the docs builds) expect to find as python -m pip.

property current_version

The current version’s name, or None if not versioned.

property exists
freeze()[source]

The pip freeze text for the environment (the audit trail).

install(packages, constraints=None, upgrade=False, refresh=True)[source]

Install packages into the environment.

Parameters:
  • packages (str or [str]) – Requirement specifiers, e.g. "seamm" or "seamm==2026.9.25".

  • constraints (pathlib.Path or str = None) – A constraints file (the published lock) passed with -c.

  • upgrade (bool = False) – Upgrade to the newest allowed versions: the named packages and their dependencies. With constraints (the lock) the allowed versions are the tested set. Without them the declared requirements of every other installed package are part of the resolution too (see installed_requirements), so a dependency moves only as far as all installed packages allow – and uv reports an error, installing nothing, if no versions satisfy everything.

  • refresh (bool = True) – Ignore uv’s cached view of the index, so a release published minutes ago is seen. Without it uv can reuse stale index metadata and report nothing to do.

installed_requirements(exclude=())[source]

The declared requirements of the installed packages.

Parameters:

exclude ([str]) – Packages whose own requirements to leave out (those being installed; requirements on them from other packages are kept, since they may cap the upgrade).

Returns:

Requirement specifiers.

Return type:

[str]

Raises:

UvError – If they cannot be read; the upgrade must not go ahead blind.

property is_versioned

Whether path is a symlink into versions_dir.

list()[source]

The installed packages: {normalized name: {"version": str}}.

migrate_to_versioned(name=None)[source]

Turn a plain <root>/venv directory into a versioned environment.

The directory is renamed into versions_dir and path becomes a symlink to it. The rename keeps every inode, so processes running from it are unaffected. The scripts’ shebangs and the activate scripts, which name the old path, are rewritten to the new one so that anything started from them afterwards is tied to this version, not to the link.

Returns the version name, or None if there was nothing to migrate (already versioned, or no environment).

static new_version_name(now=None)[source]

A version name from the time: 2026-10-02T15-04-05.

property path

The environment’s logical path, <root>/venv (a symlink once the installation is versioned). Use for messages; see real_path.

property python

The environment’s interpreter.

python_version_installed()[source]

The ‘X.Y.Z’ version of the environment’s interpreter, or None.

property real_path

path with a symlink resolved, so that paths embedded in launchers survive a switch.

Type:

The directory the environment really lives in

remove()[source]

Delete the environment: the real directory, and the link if versioned.

report_conflicts(quiet=False)[source]

Print any installed package whose requirements are not met.

Returns the conflicts as text (”” if there are none); quiet only returns them.

run(*args, check=True, capture=True)[source]

Run uv <args> and return the CompletedProcess.

Raises UvError with uv’s output if the command fails and check.

switch_to(target)[source]

Atomically point path (the venv symlink) at target.

Parameters:

target (pathlib.Path or str) – The versioned environment directory, under versions_dir.

Raises:

UvError – If path is a real directory (migrate first) or target is not an environment.

tool_upgrade(tool='seamm-manager')[source]

Upgrade a uv tool (the manager’s own installation) to the newest release. Returns True if it succeeded.

Not uv tool upgrade: that reuses uv’s cached view of the index and can report “Nothing to upgrade” minutes after a release. A forced reinstall with --refresh always consults PyPI.

uninstall(packages)[source]
property uv

The uv executable.

version(name)[source]

A Uv for the versioned environment name (which need not exist).

versions()[source]

The versioned environments, oldest first, as (name, path) pairs.

property versions_dir

Where the versioned environments live, <root>/venvs.

which(name)[source]

The path of executable name in this environment, or None.

exception seamm_manager.uv.UvError[source]

Bases: RuntimeError

A uv command failed; the message carries uv’s own output.

seamm_manager.uv.find_uv()[source]

The path to the uv executable, or None.

Looks on PATH first, then where uv’s own installer puts it.

seamm_manager.uv.floored_constraints(lock_text, installed)[source]

The published lock, with no pin below what is installed.

The lock is a nightly snapshot, so it lags releases made since. Applied as uv constraints it governs every package uv resolves – including those already installed – so a pin older than the installed version would move that package backwards (seamm_manager#34). Such a pin becomes a floor, name>=installed; every other line is kept as it is.

Parameters:
  • lock_text (str) – The lock: name==version lines, optionally with ; markers.

  • installed ({str: str}) – Installed versions by distribution name.

Returns:

The constraints text, and the names whose pins became floors.

Return type:

(str, [str])

seamm_manager.uv.freeze_without(freeze_text, names)[source]

uv pip freeze output without the lines for names.

A new environment version starts as a copy of the current one; the packages being changed are left out of the copy so that their new versions replace the old pins. Otherwise an environment whose installed versions conflict (one package needing a newer version of another) cannot even be copied, and so cannot be repaired by an update (seamm_manager#34).

seamm_manager.uv.normalize(name)[source]

The canonical form of a distribution name: lower case, ‘-’ separators.

seamm_manager.versions module

Versioned environments: build a new one beside the current, switch, prune.

The rule this module enforces: a running job never sees a half-updated environment. SEAMM imports lazily in places, so updating <root>/venv in place while a job runs can mix two versions inside one process. Instead an update builds <root>/venvs/<stamp> from the current environment, applies the change there, and switches the venv link. Processes started from the old environment keep it until prune finds nothing using it.

Processes that were started through the link (<root>/venv/bin/...) are the exception: CPython does not resolve the link when locating a venv, so they would follow it to the new environment. unsafe_processes finds them and switch refuses while any exist, unless forced. After the first migration every launcher embeds the real path, so this only matters for jobs that were already running then.

seamm_manager.versions.PIN_FILE = '.seamm-pin'

prune never removes it while the file exists

Type:

The file that pins a version

seamm_manager.versions.apply_change(specs, constraints=None, upgrade=False, in_place=None)[source]

Install or update specs in the installation’s environment, safely.

With an existing environment (and not in_place), builds a new version from the current one, applies the change there and switches. Otherwise, or for a fresh install, installs into the environment directly.

Returns True if the change is now in the current environment (installed in place, or built and switched), False if it was built but the switch was refused (see switch). The caller records the snapshot afterwards.

seamm_manager.versions.build_version(specs, constraints=None, upgrade=False, from_freeze=True, name=None)[source]

Build a new versioned environment and return its Uv.

Parameters:
  • specs ([str]) – Requirement specifiers to install or upgrade, as Uv.install takes.

  • constraints (pathlib.Path = None) – The lock file, if any.

  • upgrade (bool = False) – Whether specs may move versions (an update) or only fill gaps.

  • from_freeze (bool = True) – Start from an exact copy of the current environment (uv pip freeze, which keeps editable and local installs), then apply specs; the result is what an in-place update would have produced. False builds from scratch with only specs – the clean rebuild recreate wants.

  • name (str = None) – The version’s name; default from the time.

seamm_manager.versions.ensure_versioned(relink=True)[source]

Make the installation versioned if it is not yet. Returns True if migrated.

Renaming the directory is safe while jobs run (the inodes do not change). The launchers are then rewritten to the real path and running services restarted, so that from here on nothing new is started through the link.

seamm_manager.versions.pin(path, reason='')[source]

Pin a version so that prune keeps it, e.g. for jobs that name it directly.

Parameters:
  • path (pathlib.Path) – The version’s directory.

  • reason (str) – Why it is pinned, shown by environment versions and prune.

seamm_manager.versions.pin_info(path)[source]

The pin of a version ({“reason”, “since”, “by”}), or None if it is not pinned.

seamm_manager.versions.processes_using(prefix)[source]

The processes whose executable or command line names a path under prefix.

Parameters:

prefix (str or pathlib.Path) – A directory; matched as str(prefix) + "/".

Returns:

The pid and a short description (name plus the matching argument).

Return type:

[(pid, str)]

seamm_manager.versions.prune(keep=2, min_age_days=1.0, dry_run=False)[source]

Remove old versions that nothing uses.

Keeps the current version and the newest keep versions in all (for rollback), anything younger than min_age_days, anything pinned (see pin()), and anything a running process on this machine uses. A job on another node of a cluster is not seen here, so a version that such jobs name directly must be pinned. Returns the paths removed (or that would be, with dry_run).

seamm_manager.versions.regressions(current, new, specs=(), removing=())[source]

What the new environment version would break, compared to the current one.

A package moved to an older version that was not asked for, a package removed that was not in removing, or an installed package’s requirements newly unmet (seamm_manager#34). An explicit pin in specs (name==version) to an older version is allowed.

Returns:

One line per problem; empty if the new version is safe to switch to.

Return type:

[str]

Point this installation’s services and apps at the environment’s real path.

Running services are restarted so they run from it; stopped ones stay stopped.

seamm_manager.versions.rollback(name=None, force=False)[source]

Switch back to the version name, by default the one before the current.

seamm_manager.versions.switch(new, force=False)[source]

Make new the current environment and relink the launchers.

Refuses if processes started through the link exist (see the module docstring), unless force. Returns True if switched.

seamm_manager.versions.unpin(path)[source]

Remove a version’s pin; returns whether it was pinned.

seamm_manager.versions.unsafe_processes()[source]

Processes started through the venv link rather than a real path.

Module contents

seamm_manager The installer/updater for SEAMM.