Coverage for src / local_deep_research / exporters / registry.py: 95%
34 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-25 01:07 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-25 01:07 +0000
1"""Exporter registry for document format discovery.
3This module provides the ExporterRegistry class that manages exporter
4registration and lookup. Exporters can be registered using the @register
5decorator for automatic discovery.
6"""
8from typing import Dict, List, Optional, Type
10from loguru import logger
12from .base import BaseExporter
15class ExporterRegistry:
16 """Registry for document exporters.
18 This class manages the registration and lookup of exporter classes.
19 Exporters can be registered using the @register class method as a decorator.
21 Example:
22 @ExporterRegistry.register
23 class PDFExporter(BaseExporter):
24 ...
26 # Later, to get the exporter:
27 exporter = ExporterRegistry.get_exporter("pdf")
28 """
30 _exporters: Dict[str, Type[BaseExporter]] = {}
31 _instances: Dict[str, BaseExporter] = {}
33 @classmethod
34 def register(cls, exporter_class: Type[BaseExporter]) -> Type[BaseExporter]:
35 """Register an exporter class.
37 Can be used as a decorator:
38 @ExporterRegistry.register
39 class MyExporter(BaseExporter):
40 ...
42 Args:
43 exporter_class: The exporter class to register
45 Returns:
46 The exporter class (unchanged), allowing use as decorator
47 """
48 # Instantiate temporarily to get format_name
49 instance = exporter_class()
50 format_name = instance.format_name.lower()
51 cls._exporters[format_name] = exporter_class
52 logger.debug(f"Registered exporter for format: {format_name}")
53 return exporter_class
55 @classmethod
56 def get_exporter(cls, format_name: str) -> Optional[BaseExporter]:
57 """Get an exporter instance for the given format.
59 Uses singleton pattern - returns cached instance if available.
61 Args:
62 format_name: The format identifier (e.g., 'pdf', 'odt')
64 Returns:
65 An exporter instance, or None if format not supported
66 """
67 format_name = format_name.lower()
69 # Return cached instance if available
70 if format_name in cls._instances:
71 return cls._instances[format_name]
73 # Create new instance
74 exporter_class = cls._exporters.get(format_name)
75 if exporter_class:
76 instance = exporter_class()
77 cls._instances[format_name] = instance
78 return instance
80 return None
82 @classmethod
83 def get_available_formats(cls) -> List[str]:
84 """Get list of available export formats.
86 Returns:
87 List of format identifiers (e.g., ['pdf', 'odt', 'latex'])
88 """
89 return list(cls._exporters.keys())
91 @classmethod
92 def is_format_supported(cls, format_name: str) -> bool:
93 """Check if a format is supported.
95 Args:
96 format_name: The format identifier to check
98 Returns:
99 True if the format is supported, False otherwise
100 """
101 return format_name.lower() in cls._exporters
103 @classmethod
104 def clear(cls) -> None:
105 """Clear all registered exporters.
107 Primarily useful for testing.
108 """
109 cls._exporters.clear()
110 cls._instances.clear()