Skip to content

registry

lacuna.analysis.registry

Lacuna analysis auto-discovery registry module.

This module provides automatic discovery of BaseAnalysis subclasses using pkgutil.

Classes: AnalysisRegistry: Registry for discovered analysis classes.

Functions: list_analyses: List all available analysis classes. get_analysis: Get an analysis class by name.

AnalysisRegistry

Registry for discovered analysis classes.

This class manages auto-discovery and lookup of analysis classes using lazy initialization and caching.

Class Methods

discover() -> dict[str, type[BaseAnalysis]] Discover and cache all analysis classes. list_analyses() -> list[tuple[str, type[BaseAnalysis]]] List all available analyses as (name, class) tuples. get(name: str) -> type[BaseAnalysis] Get analysis class by name. clear_cache() -> None Clear the discovery cache (for testing).

Source code in src/lacuna/analysis/registry.py
class AnalysisRegistry:
    """
    Registry for discovered analysis classes.

    This class manages auto-discovery and lookup of analysis classes
    using lazy initialization and caching.

    Class Methods
    -------------
    discover() -> dict[str, type[BaseAnalysis]]
        Discover and cache all analysis classes.
    list_analyses() -> list[tuple[str, type[BaseAnalysis]]]
        List all available analyses as (name, class) tuples.
    get(name: str) -> type[BaseAnalysis]
        Get analysis class by name.
    clear_cache() -> None
        Clear the discovery cache (for testing).
    """

    _discovered: dict[str, type[BaseAnalysis]] | None = None

    @classmethod
    def discover(cls) -> dict[str, type[BaseAnalysis]]:
        """
        Discover and cache all analysis classes.

        Returns
        -------
        dict
            Dictionary mapping analysis names to their classes.
        """
        if cls._discovered is None:
            cls._discovered = {}
            for name, analysis_cls in _discover_analysis_classes():
                if name in cls._discovered:
                    logger.warning(f"Duplicate analysis name '{name}' - keeping first occurrence")
                    continue
                cls._discovered[name] = analysis_cls
        return cls._discovered

    @classmethod
    def list_analyses(cls) -> list[tuple[str, type[BaseAnalysis]]]:
        """
        List all available analyses as (name, class) tuples.

        Returns
        -------
        list of tuple
            List of (name, class) tuples, sorted alphabetically.
        """
        return sorted(cls.discover().items())

    @classmethod
    def get(cls, name: str) -> type[BaseAnalysis]:
        """
        Get analysis class by name.

        Parameters
        ----------
        name : str
            Name of the analysis class.

        Returns
        -------
        type[BaseAnalysis]
            The analysis class.

        Raises
        ------
        KeyError
            If the analysis name is not found.
        """
        analyses = cls.discover()
        if name not in analyses:
            available = ", ".join(sorted(analyses.keys()))
            raise KeyError(f"Unknown analysis '{name}'. Available: {available}")
        return analyses[name]

    @classmethod
    def clear_cache(cls) -> None:
        """Clear the discovery cache (useful for testing)."""
        cls._discovered = None

clear_cache() classmethod

Clear the discovery cache (useful for testing).

Source code in src/lacuna/analysis/registry.py
@classmethod
def clear_cache(cls) -> None:
    """Clear the discovery cache (useful for testing)."""
    cls._discovered = None

discover() classmethod

Discover and cache all analysis classes.

Returns:

Type Description
dict

Dictionary mapping analysis names to their classes.

Source code in src/lacuna/analysis/registry.py
@classmethod
def discover(cls) -> dict[str, type[BaseAnalysis]]:
    """
    Discover and cache all analysis classes.

    Returns
    -------
    dict
        Dictionary mapping analysis names to their classes.
    """
    if cls._discovered is None:
        cls._discovered = {}
        for name, analysis_cls in _discover_analysis_classes():
            if name in cls._discovered:
                logger.warning(f"Duplicate analysis name '{name}' - keeping first occurrence")
                continue
            cls._discovered[name] = analysis_cls
    return cls._discovered

get(name) classmethod

Get analysis class by name.

Parameters:

Name Type Description Default
name str

Name of the analysis class.

required

Returns:

Type Description
type[BaseAnalysis]

The analysis class.

Raises:

Type Description
KeyError

If the analysis name is not found.

Source code in src/lacuna/analysis/registry.py
@classmethod
def get(cls, name: str) -> type[BaseAnalysis]:
    """
    Get analysis class by name.

    Parameters
    ----------
    name : str
        Name of the analysis class.

    Returns
    -------
    type[BaseAnalysis]
        The analysis class.

    Raises
    ------
    KeyError
        If the analysis name is not found.
    """
    analyses = cls.discover()
    if name not in analyses:
        available = ", ".join(sorted(analyses.keys()))
        raise KeyError(f"Unknown analysis '{name}'. Available: {available}")
    return analyses[name]

list_analyses() classmethod

List all available analyses as (name, class) tuples.

Returns:

Type Description
list of tuple

List of (name, class) tuples, sorted alphabetically.

Source code in src/lacuna/analysis/registry.py
@classmethod
def list_analyses(cls) -> list[tuple[str, type[BaseAnalysis]]]:
    """
    List all available analyses as (name, class) tuples.

    Returns
    -------
    list of tuple
        List of (name, class) tuples, sorted alphabetically.
    """
    return sorted(cls.discover().items())

get_analysis(name)

Get an analysis class by name.

Parameters:

Name Type Description Default
name str

Name of the analysis class (e.g., "FunctionalNetworkMapping").

required

Returns:

Type Description
type[BaseAnalysis]

The analysis class.

Raises:

Type Description
KeyError

If the analysis name is not found.

Examples:

>>> from lacuna.analysis import get_analysis
>>> FNM = get_analysis("FunctionalNetworkMapping")
>>> analysis = FNM(connectome_name="GSP1000")
Source code in src/lacuna/analysis/registry.py
def get_analysis(name: str) -> type[BaseAnalysis]:
    """
    Get an analysis class by name.

    Parameters
    ----------
    name : str
        Name of the analysis class (e.g., "FunctionalNetworkMapping").

    Returns
    -------
    type[BaseAnalysis]
        The analysis class.

    Raises
    ------
    KeyError
        If the analysis name is not found.

    Examples
    --------
    >>> from lacuna.analysis import get_analysis
    >>> FNM = get_analysis("FunctionalNetworkMapping")
    >>> analysis = FNM(connectome_name="GSP1000")
    """
    return AnalysisRegistry.get(name)

list_analyses()

List all available analysis classes.

This function returns all discovered analyses that: - Are subclasses of BaseAnalysis - Are concrete (not abstract) - Are not private (name doesn't start with '_')

Returns:

Type Description
list of tuple

List of (name, class) tuples for all available analyses, sorted alphabetically by name.

Examples:

>>> from lacuna.analysis import list_analyses
>>> for name, cls in list_analyses():
...     print(f"{name}: {cls.batch_strategy}")
FunctionalNetworkMapping: vectorized
ParcelAggregation: parallel
RegionalDamage: parallel
StructuralNetworkMapping: parallel
Source code in src/lacuna/analysis/registry.py
def list_analyses() -> list[tuple[str, type[BaseAnalysis]]]:
    """
    List all available analysis classes.

    This function returns all discovered analyses that:
    - Are subclasses of BaseAnalysis
    - Are concrete (not abstract)
    - Are not private (name doesn't start with '_')

    Returns
    -------
    list of tuple
        List of (name, class) tuples for all available analyses,
        sorted alphabetically by name.

    Examples
    --------
    >>> from lacuna.analysis import list_analyses
    >>> for name, cls in list_analyses():
    ...     print(f"{name}: {cls.batch_strategy}")
    FunctionalNetworkMapping: vectorized
    ParcelAggregation: parallel
    RegionalDamage: parallel
    StructuralNetworkMapping: parallel
    """
    return AnalysisRegistry.list_analyses()