plugins.registry

plugins.registry

Which component plays which cadjoint kind, and where it runs.

This is the part that is genuinely cadjoint’s: a name -> spec table, a kind -> name default, and three places a spec can come from, later ones winning:

  1. Built-ins — the Tesseract packages in this repository (:data:BUILTIN_PACKAGES), as local specs. Nothing shipped here fills the private tier’s five in-process kinds; the diff-brep distribution registers those through the entry-point group below, and :mod:cadjoint.tier says so in one sentence when it is absent.
  2. Entry points — the cadjoint.plugins group. A distribution registers a component by exposing a :class:~cadjoint.plugins.PluginSpec, a mapping in the plugins.toml table form, or a callable returning either.
  3. The config file — plugins.toml, found at $CADJOINT_PLUGINS (a file, or a directory holding one) or else $XDG_CONFIG_HOME/cadjoint/plugins.toml (default ~/.config/cadjoint/plugins.toml). A table whose name matches an existing plugin replaces its spec — that is how the thermal solver moves from this process to a cluster URL without a line of code changing.

The file has two tables::

[defaults]                       # which plugin fills each slot
elastic_solver = "elastic_calculix"

[plugins.thermal_jaxfem]         # where a plugin runs
kind = "thermal_solver"
transport = "remote"
url = "http://thermal.cadjoint.svc.cluster.local:8000"
schema_hash = "sha256:2a1f..."

Seeing the public tier. CADJOINT_PUBLIC_TIER=1 leaves the private tier’s kinds (:data:cadjoint.tier.KINDS) out of the process-wide registry wherever they come from — what a public install sees, on a machine that has diff-brep installed. Child processes inherit it, so a playground started with it answers every request as the public tier does.

Callers ask by name (:func:get_plugin) for one specific component, or by kind (:func:plugin_for_kind) for whatever currently fills a slot — which is what :mod:cadjoint.fem.tesseracts.chain and :mod:cadjoint.fem.backends do, so neither imports a tesseract_api module. Instances are cached, so a local plugin imports its API module once and a remote one holds a single warm session.

Classes

Name Description
PluginRegistry The plugins this process knows about, and the instances it has open.

PluginRegistry

plugins.registry.PluginRegistry(specs=None, defaults=None, *, source=None)

The plugins this process knows about, and the instances it has open.

Parameters

Name Type Description Default
specs Mapping[str, PluginSpec] | None Name -> spec. None
defaults Mapping[str, str] | None Kind -> plugin name. None
source Path | None Where the config came from, for error messages. None

Methods

Name Description
close Close every open instance (tearing down spawned containers).
default_for The plugin name filling kind.
for_kind The (cached) plugin instance currently filling kind.
kinds Registered plugin names grouped by kind.
names Registered plugin names, sorted.
plugin The (cached) plugin instance registered under name.
register Add or replace a spec, closing any open instance under that name.
spec The spec registered under name.
unregister Remove a spec (and its default, and any open instance).
without A copy of this registry with every plugin of kinds left out.
close
plugins.registry.PluginRegistry.close()

Close every open instance (tearing down spawned containers).

default_for
plugins.registry.PluginRegistry.default_for(kind)

The plugin name filling kind.

Raises
Name Type Description
KeyError If no plugin declares that kind, if several do with no default set, or if the default names something unregistered.
for_kind
plugins.registry.PluginRegistry.for_kind(kind)

The (cached) plugin instance currently filling kind.

kinds
plugins.registry.PluginRegistry.kinds()

Registered plugin names grouped by kind.

names
plugins.registry.PluginRegistry.names()

Registered plugin names, sorted.

plugin
plugins.registry.PluginRegistry.plugin(name)

The (cached) plugin instance registered under name.

register
plugins.registry.PluginRegistry.register(spec, *, default=None)

Add or replace a spec, closing any open instance under that name.

Parameters
Name Type Description Default
spec PluginSpec The spec to register. required
default bool | None Make it the default for its kind (None: only when nothing else fills that kind yet). None
spec
plugins.registry.PluginRegistry.spec(name)

The spec registered under name.

Raises
Name Type Description
KeyError If nothing is registered under that name.
unregister
plugins.registry.PluginRegistry.unregister(name)

Remove a spec (and its default, and any open instance).

Returns
Name Type Description
PluginSpec | None The removed spec, or None if nothing was registered under
PluginSpec | None name.
without
plugins.registry.PluginRegistry.without(kinds)

A copy of this registry with every plugin of kinds left out.

What :func:cadjoint.tier.absent installs so the public tier’s degraded behaviour can be exercised with the private providers still present in the process.

Functions

Name Description
available_plugins Names registered in the process-wide registry.
build_registry Assemble a registry from built-ins, entry points and the config file.
builtin_specs Specs for every component shipped in this checkout.
config_path The plugins.toml in effect, or None when there is none.
entry_point_specs Specs contributed by installed distributions.
get_plugin The plugin registered under name in the process-wide registry.
load_config Load the plugins config in effect.
parse_config Split a parsed config document into specs and per-kind defaults.
plugin_for_kind The plugin currently filling kind in the process-wide registry.
public_tier_forced Whether $CADJOINT_PUBLIC_TIER asks for the public tier only.
register_plugin Register spec in the process-wide registry.
registry The process-wide registry, assembled on first use.
set_registry Install new as the process-wide registry, returning the old one.

available_plugins

plugins.registry.available_plugins()

Names registered in the process-wide registry.

build_registry

plugins.registry.build_registry(config=None, use_entry_points=True)

Assemble a registry from built-ins, entry points and the config file.

Parameters

Name Type Description Default
config Path | None An explicit plugins.toml; None resolves it the usual way. None
use_entry_points bool Include installed cadjoint.plugins entry points (tests turn this off to stay hermetic). True

Returns

Name Type Description
PluginRegistry The assembled registry.

builtin_specs

plugins.registry.builtin_specs()

Specs for every component shipped in this checkout.

local specs for the Tesseract packages present, and nothing else. The private tier’s in-process kinds arrive through the entry-point group, never from here.

config_path

plugins.registry.config_path()

The plugins.toml in effect, or None when there is none.

Returns

Name Type Description
Path | None The resolved path.

Raises

Name Type Description
PluginConfigError If $CADJOINT_PLUGINS names something unreadable — silently falling back to the built-ins would hide a deployment bug.

entry_point_specs

plugins.registry.entry_point_specs()

Specs contributed by installed distributions.

A broken entry point raises a :class:PluginConfigError naming it rather than being skipped: a plugin that silently fails to register is the hardest kind of deployment bug to see.

get_plugin

plugins.registry.get_plugin(name)

The plugin registered under name in the process-wide registry.

load_config

plugins.registry.load_config(path=None)

Load the plugins config in effect.

Parameters

Name Type Description Default
path Path | None An explicit file to read; None resolves via :func:config_path. None

Returns

Name Type Description
dict (specs, defaults, path); the first two are empty and path is
dict None when no config file exists.

Raises

Name Type Description
PluginConfigError Before Python 3.11 without tomli installed.

parse_config

plugins.registry.parse_config(document, *, source)

Split a parsed config document into specs and per-kind defaults.

Parameters

Name Type Description Default
document Mapping[str, Any] The parsed TOML mapping. required
source str What to name in error messages (a path, usually). required

Returns

Name Type Description
dict (specs, defaults) — {name: PluginSpec} and
dict {kind: plugin name}.

Raises

Name Type Description
PluginConfigError On an unknown top-level table or a malformed plugin table.

plugin_for_kind

plugins.registry.plugin_for_kind(kind)

The plugin currently filling kind in the process-wide registry.

public_tier_forced

plugins.registry.public_tier_forced()

Whether $CADJOINT_PUBLIC_TIER asks for the public tier only.

register_plugin

plugins.registry.register_plugin(spec, *, default=None)

Register spec in the process-wide registry.

registry

plugins.registry.registry()

The process-wide registry, assembled on first use.

set_registry

plugins.registry.set_registry(new)

Install new as the process-wide registry, returning the old one.

None clears it, so the next :func:registry call rebuilds from the environment. Tests use this to point cadjoint at a served plugin without touching the user’s config.