Skip to content

Registry

registry

Format registry for automatic format detection and handler selection.

The registry maintains a list of available format handlers and automatically selects the appropriate handler for reading/writing files based on file extension and content detection.

Classes

FormatRegistry

FormatRegistry()

Registry for file format handlers with automatic format detection.

The registry maintains a collection of format handlers and provides methods to automatically detect and handle different file formats.

Initialize empty registry.

Source code in optiscope/io/registry.py
def __init__(self) -> None:
    """Initialize empty registry."""
    self._handlers: list[type[BaseFormatHandler]] = []
    self._extension_map: dict[str, list[type[BaseFormatHandler]]] = {}
Functions
register
register(handler: type[BaseFormatHandler], extensions: list[str] | None = None) -> None

Register a format handler.

Parameters:

Name Type Description Default
handler type[BaseFormatHandler]

Handler class to register

required
extensions list[str] | None

Optional list of file extensions (overrides handler.file_extensions)

None
Source code in optiscope/io/registry.py
def register(
    self, handler: type[BaseFormatHandler], extensions: list[str] | None = None
) -> None:
    """
    Register a format handler.

    Args:
        handler: Handler class to register
        extensions: Optional list of file extensions (overrides handler.file_extensions)
    """
    if handler in self._handlers:
        logger.warning(f"Handler {handler.format_name} already registered")
        return

    self._handlers.append(handler)

    # Sort by priority (lower first)
    self._handlers.sort(key=lambda h: h.priority)

    # Update extension map
    exts = extensions or handler.file_extensions
    for ext in exts:
        ext = ext.lower()
        if not ext.startswith("."):
            ext = "." + ext

        if ext not in self._extension_map:
            self._extension_map[ext] = []
        self._extension_map[ext].append(handler)
        # Sort by priority
        self._extension_map[ext].sort(key=lambda h: h.priority)

    logger.info(f"Registered handler '{handler.format_name}' for extensions: {exts}")
unregister
unregister(handler: type[BaseFormatHandler]) -> None

Unregister a format handler.

Parameters:

Name Type Description Default
handler type[BaseFormatHandler]

Handler class to unregister

required
Source code in optiscope/io/registry.py
def unregister(self, handler: type[BaseFormatHandler]) -> None:
    """
    Unregister a format handler.

    Args:
        handler: Handler class to unregister
    """
    if handler not in self._handlers:
        logger.warning(f"Handler {handler.format_name} not registered")
        return

    self._handlers.remove(handler)

    # Remove from extension map
    for ext, handlers in self._extension_map.items():
        if handler in handlers:
            handlers.remove(handler)

    logger.info(f"Unregistered handler '{handler.format_name}'")
get_handler_for_file
get_handler_for_file(filepath: Path | str, format_hint: str | None = None) -> BaseFormatHandler

Get appropriate handler for a file.

Parameters:

Name Type Description Default
filepath Path | str

Path to file

required
format_hint str | None

Optional format name to prefer

None

Returns:

Type Description
BaseFormatHandler

Handler instance

Raises:

Type Description
FormatDetectionError

If no suitable handler found

Source code in optiscope/io/registry.py
def get_handler_for_file(
    self, filepath: Path | str, format_hint: str | None = None
) -> BaseFormatHandler:
    """
    Get appropriate handler for a file.

    Args:
        filepath: Path to file
        format_hint: Optional format name to prefer

    Returns:
        Handler instance

    Raises:
        FormatDetectionError: If no suitable handler found
    """
    filepath = Path(filepath)

    if not filepath.exists():
        raise FileNotFoundError(f"File not found: {filepath}")

    # If format hint provided, try that first
    if format_hint:
        for handler_cls in self._handlers:
            if handler_cls.format_name.lower() == format_hint.lower():
                handler = handler_cls()
                if handler.can_handle(filepath):
                    logger.info(f"Using handler '{handler.format_name}' (from hint)")
                    return handler

    # Try handlers by extension first
    ext = filepath.suffix.lower()
    if ext in self._extension_map:
        for handler_cls in self._extension_map[ext]:
            handler = handler_cls()
            if handler.can_handle(filepath):
                logger.info(f"Using handler '{handler.format_name}' (from extension)")
                return handler

    # Fall back to checking all handlers
    for handler_cls in self._handlers:
        handler = handler_cls()
        try:
            if handler.can_handle(filepath):
                logger.info(f"Using handler '{handler.format_name}' (from detection)")
                return handler
        except Exception as e:
            logger.debug(f"Handler '{handler_cls.format_name}' failed detection: {e}")
            continue

    raise FormatDetectionError(
        f"No suitable handler found for file: {filepath}\n"
        f"Registered handlers: {[h.format_name for h in self._handlers]}"
    )
load
load(filepath: Path | str, format_hint: str | None = None, **kwargs: Any) -> OptimizationResult

Load optimization results from file with automatic format detection.

Parameters:

Name Type Description Default
filepath Path | str

Path to file

required
format_hint str | None

Optional format name hint

None
**kwargs Any

Additional arguments passed to handler

{}

Returns:

Type Description
OptimizationResult

OptimizationResult object

Raises:

Type Description
FormatDetectionError

If format cannot be detected

FormatReadError

If file cannot be read

Source code in optiscope/io/registry.py
def load(
    self, filepath: Path | str, format_hint: str | None = None, **kwargs: Any
) -> OptimizationResult:
    """
    Load optimization results from file with automatic format detection.

    Args:
        filepath: Path to file
        format_hint: Optional format name hint
        **kwargs: Additional arguments passed to handler

    Returns:
        OptimizationResult object

    Raises:
        FormatDetectionError: If format cannot be detected
        FormatReadError: If file cannot be read
    """
    filepath = Path(filepath)
    logger.info(f"Loading optimization results from: {filepath}")

    try:
        handler = self.get_handler_for_file(filepath, format_hint)
        result = handler.read(filepath, **kwargs)
        logger.info(f"Successfully loaded {result.n_points} points from {filepath}")
        return result
    except FormatDetectionError:
        raise
    except Exception as e:
        raise FormatReadError(f"Failed to read file {filepath}: {str(e)}") from e
save
save(result: OptimizationResult, filepath: Path | str, format_hint: str | None = None, **kwargs: Any) -> None

Save optimization results to file with automatic format selection.

Parameters:

Name Type Description Default
result OptimizationResult

OptimizationResult to save

required
filepath Path | str

Output file path

required
format_hint str | None

Optional format name hint

None
**kwargs Any

Additional arguments passed to handler

{}

Raises:

Type Description
FormatDetectionError

If format cannot be determined

FormatWriteError

If file cannot be written

Source code in optiscope/io/registry.py
def save(
    self,
    result: OptimizationResult,
    filepath: Path | str,
    format_hint: str | None = None,
    **kwargs: Any,
) -> None:
    """
    Save optimization results to file with automatic format selection.

    Args:
        result: OptimizationResult to save
        filepath: Output file path
        format_hint: Optional format name hint
        **kwargs: Additional arguments passed to handler

    Raises:
        FormatDetectionError: If format cannot be determined
        FormatWriteError: If file cannot be written
    """
    filepath = Path(filepath)
    logger.info(f"Saving optimization results to: {filepath}")

    # For saving, we need to select handler based on extension or hint
    if format_hint:
        # Find handler by format name
        handler = None
        for handler_cls in self._handlers:
            if handler_cls.format_name.lower() == format_hint.lower():
                handler = handler_cls()
                break
        if handler is None:
            raise FormatDetectionError(f"No handler found for format: {format_hint}")
    else:
        # Select by extension
        ext = filepath.suffix.lower()
        if ext not in self._extension_map:
            raise FormatDetectionError(f"No handler registered for extension: {ext}")
        # Use first handler for this extension
        handler = self._extension_map[ext][0]()

    try:
        handler.validate_result(result)
        handler.write(result, filepath, **kwargs)
        logger.info(f"Successfully saved {result.n_points} points to {filepath}")
    except Exception as e:
        raise FormatWriteError(f"Failed to write file {filepath}: {str(e)}") from e
list_formats
list_formats() -> list[dict[str, Any]]

List all registered formats.

Returns:

Type Description
list[dict[str, Any]]

List of format information dictionaries

Source code in optiscope/io/registry.py
def list_formats(self) -> list[dict[str, Any]]:
    """
    List all registered formats.

    Returns:
        List of format information dictionaries
    """
    return [
        {
            "name": h.format_name,
            "extensions": h.file_extensions,
            "priority": h.priority,
            "supports_metadata": getattr(h, "supports_metadata", False),
            "supports_sets": getattr(h, "supports_sets", False),
        }
        for h in self._handlers
    ]
get_supported_extensions
get_supported_extensions() -> list[str]

Get list of all supported file extensions.

Source code in optiscope/io/registry.py
def get_supported_extensions(self) -> list[str]:
    """Get list of all supported file extensions."""
    return sorted(self._extension_map.keys())

Functions

discover_handlers

discover_handlers(registry: FormatRegistry, entry_point_group: str = 'optiscope.io.handlers')

Discover handlers from installed Python packages that declare them.

Source code in optiscope/io/registry.py
def discover_handlers(registry: FormatRegistry, entry_point_group: str = "optiscope.io.handlers"):
    """Discover handlers from installed Python packages that declare them."""
    for dist in importlib.metadata.distributions():
        for ep in dist.entry_points:
            if ep.group == entry_point_group:
                try:
                    handler_cls = ep.load()
                    if issubclass(handler_cls, BaseFormatHandler):
                        registry.register(handler_cls)
                        logger.info(
                            f"Discovered and registered handler '{handler_cls.format_name}' from entry point."
                        )
                except Exception as e:
                    logger.warning(f"Failed to load handler from entry point '{ep.name}': {e}")

get_global_registry

get_global_registry() -> FormatRegistry

Get the global format registry instance.

Returns:

Type Description
FormatRegistry

Global FormatRegistry

Source code in optiscope/io/registry.py
def get_global_registry() -> FormatRegistry:
    """
    Get the global format registry instance.

    Returns:
        Global FormatRegistry
    """
    global _global_registry
    if _global_registry is None:
        _global_registry = FormatRegistry()
        # Auto-register built-in handlers
        from optiscope.io import csv_handler, json_handler, midaco_handler

        _global_registry.register(csv_handler.CSVHandler)
        _global_registry.register(json_handler.JSONHandler)
        _global_registry.register(midaco_handler.MIDACoHandler)

        # Discover and register handlers from entry points
        discover_handlers(_global_registry)

    return _global_registry

load_results

load_results(filepath: Path | str, **kwargs: Any) -> OptimizationResult

Convenience function to load results using global registry.

Parameters:

Name Type Description Default
filepath Path | str

Path to file

required
**kwargs Any

Additional arguments

{}

Returns:

Type Description
OptimizationResult

OptimizationResult

Source code in optiscope/io/registry.py
def load_results(filepath: Path | str, **kwargs: Any) -> OptimizationResult:
    """
    Convenience function to load results using global registry.

    Args:
        filepath: Path to file
        **kwargs: Additional arguments

    Returns:
        OptimizationResult
    """
    return get_global_registry().load(filepath, **kwargs)

save_results

save_results(result: OptimizationResult, filepath: Path | str, **kwargs: Any) -> None

Convenience function to save results using global registry.

Parameters:

Name Type Description Default
result OptimizationResult

OptimizationResult to save

required
filepath Path | str

Output path

required
**kwargs Any

Additional arguments

{}
Source code in optiscope/io/registry.py
def save_results(result: OptimizationResult, filepath: Path | str, **kwargs: Any) -> None:
    """
    Convenience function to save results using global registry.

    Args:
        result: OptimizationResult to save
        filepath: Output path
        **kwargs: Additional arguments
    """
    get_global_registry().save(result, filepath, **kwargs)