Skip to content

registry

registry

Registry of available remedies.

Provides a central place to register and look up remedies. The create_default_registry() factory returns a registry with all built-in remedies pre-registered.

Classes

RemedyRegistry

RemedyRegistry()

Registry of available remedies.

Maintains a list of remedy instances and provides methods to query them by name or find applicable remedies for a given error context.

Example

registry = RemedyRegistry() registry.register(CreateMissingWorkspaceRemedy())

Find by name

remedy = registry.get_by_name("create_missing_workspace")

Find all that apply to an error

applicable = registry.find_applicable(context)

Initialize an empty registry.

Source code in src/marianne/healing/registry.py
def __init__(self) -> None:
    """Initialize an empty registry."""
    self._remedies: list[Remedy] = []
Functions
register
register(remedy)

Register a remedy.

Parameters:

Name Type Description Default
remedy Remedy

Remedy instance to register.

required
Source code in src/marianne/healing/registry.py
def register(self, remedy: "Remedy") -> None:
    """Register a remedy.

    Args:
        remedy: Remedy instance to register.
    """
    self._remedies.append(remedy)
all_remedies
all_remedies()

Get all registered remedies.

Returns:

Type Description
list[Remedy]

List of all registered remedy instances.

Source code in src/marianne/healing/registry.py
def all_remedies(self) -> list["Remedy"]:
    """Get all registered remedies.

    Returns:
        List of all registered remedy instances.
    """
    return list(self._remedies)
get_by_name
get_by_name(name)

Get remedy by name.

Parameters:

Name Type Description Default
name str

Unique remedy identifier.

required

Returns:

Type Description
Remedy | None

Remedy if found, None otherwise.

Source code in src/marianne/healing/registry.py
def get_by_name(self, name: str) -> "Remedy | None":
    """Get remedy by name.

    Args:
        name: Unique remedy identifier.

    Returns:
        Remedy if found, None otherwise.
    """
    for remedy in self._remedies:
        if remedy.name == name:
            return remedy
    return None
find_applicable
find_applicable(context)

Find all remedies that apply to the error.

Queries each registered remedy and collects those that return a diagnosis. Results are sorted by diagnosis confidence (highest first).

Remedy diagnosis crashes are logged and recorded in self.diagnosis_errors so callers can report them instead of showing misleading "NO ACTION NEEDED" messages.

Parameters:

Name Type Description Default
context ErrorContext

Error context with diagnostic information.

required

Returns:

Type Description
list[tuple[Remedy, Diagnosis]]

List of (remedy, diagnosis) tuples sorted by confidence.

Source code in src/marianne/healing/registry.py
def find_applicable(
    self,
    context: "ErrorContext",
) -> list[tuple["Remedy", "Diagnosis"]]:
    """Find all remedies that apply to the error.

    Queries each registered remedy and collects those that
    return a diagnosis. Results are sorted by diagnosis
    confidence (highest first).

    Remedy diagnosis crashes are logged and recorded in
    ``self.diagnosis_errors`` so callers can report them
    instead of showing misleading "NO ACTION NEEDED" messages.

    Args:
        context: Error context with diagnostic information.

    Returns:
        List of (remedy, diagnosis) tuples sorted by confidence.
    """
    applicable: list[tuple[Remedy, Diagnosis]] = []
    self.diagnosis_errors: list[tuple[str, str]] = []

    for remedy in self._remedies:
        try:
            diagnosis = remedy.diagnose(context)
            if diagnosis is not None:
                applicable.append((remedy, diagnosis))
        except Exception as exc:
            # Individual remedy failures shouldn't block finding others,
            # but we must record them so the HealingReport doesn't show
            # "NO ACTION NEEDED" when a remedy actually crashed.
            _logger.warning(
                "Remedy %s.diagnose() raised exception",
                remedy.name,
                exc_info=True,
            )
            self.diagnosis_errors.append((remedy.name, str(exc)))

    # Sort by diagnosis confidence, highest first
    applicable.sort(key=lambda x: x[1].confidence, reverse=True)
    return applicable
count
count()

Get the number of registered remedies.

Returns:

Type Description
int

Number of remedies in the registry.

Source code in src/marianne/healing/registry.py
def count(self) -> int:
    """Get the number of registered remedies.

    Returns:
        Number of remedies in the registry.
    """
    return len(self._remedies)

Functions

create_default_registry

create_default_registry()

Create registry with all built-in remedies.

This is the primary factory for getting a fully-configured remedy registry. It registers:

Automatic remedies (safe, apply without confirmation): - CreateMissingWorkspaceRemedy - CreateMissingParentDirsRemedy - FixPathSeparatorsRemedy

Suggested remedies (require user confirmation): - SuggestJinjaFixRemedy

Diagnostic remedies (provide guidance only): - DiagnoseAuthErrorRemedy - DiagnoseMissingCLIRemedy

Returns:

Type Description
RemedyRegistry

RemedyRegistry with all built-in remedies registered.

Source code in src/marianne/healing/registry.py
def create_default_registry() -> RemedyRegistry:
    """Create registry with all built-in remedies.

    This is the primary factory for getting a fully-configured
    remedy registry. It registers:

    Automatic remedies (safe, apply without confirmation):
    - CreateMissingWorkspaceRemedy
    - CreateMissingParentDirsRemedy
    - FixPathSeparatorsRemedy

    Suggested remedies (require user confirmation):
    - SuggestJinjaFixRemedy

    Diagnostic remedies (provide guidance only):
    - DiagnoseAuthErrorRemedy
    - DiagnoseMissingCLIRemedy

    Returns:
        RemedyRegistry with all built-in remedies registered.
    """
    from marianne.healing.remedies.diagnostics import (
        DiagnoseAuthErrorRemedy,
        DiagnoseMissingCLIRemedy,
    )
    from marianne.healing.remedies.jinja import SuggestJinjaFixRemedy
    from marianne.healing.remedies.paths import (
        CreateMissingParentDirsRemedy,
        CreateMissingWorkspaceRemedy,
        FixPathSeparatorsRemedy,
    )

    registry = RemedyRegistry()

    # Automatic remedies (safe, apply without asking)
    registry.register(CreateMissingWorkspaceRemedy())
    registry.register(CreateMissingParentDirsRemedy())
    registry.register(FixPathSeparatorsRemedy())

    # Suggested remedies (ask user first)
    registry.register(SuggestJinjaFixRemedy())

    # Diagnostic-only (provide guidance)
    registry.register(DiagnoseAuthErrorRemedy())
    registry.register(DiagnoseMissingCLIRemedy())

    return registry