codebook / potato /export /registry.py
davidjurgens's picture
Deploy: Potato — Codebook Annotation
aceb1b2 verified
Raw
History Blame Contribute Delete
5.31 kB
"""
Export Registry
Centralized registry for export format handlers, following the same
pattern as SchemaRegistry and DisplayRegistry.
Usage:
from potato.export.registry import export_registry
# List all exporters
exporters = export_registry.list_exporters()
# Export annotations
result = export_registry.export("coco", context, output_path)
"""
import logging
from typing import Dict, List, Optional, Any
from .base import BaseExporter, ExportContext, ExportResult
logger = logging.getLogger(__name__)
class ExportRegistry:
"""
Centralized registry for annotation export formats.
Provides methods to register, retrieve, and invoke exporters.
"""
def __init__(self):
self._exporters: Dict[str, BaseExporter] = {}
logger.debug("ExportRegistry initialized")
def register(self, exporter: BaseExporter) -> None:
"""
Register an exporter instance.
Args:
exporter: BaseExporter subclass instance
Raises:
ValueError: If an exporter with the same format_name is already registered
"""
name = exporter.format_name
if not name:
raise ValueError("Exporter must have a non-empty format_name")
if name in self._exporters:
raise ValueError(f"Exporter '{name}' is already registered")
self._exporters[name] = exporter
logger.debug(f"Registered exporter: {name}")
def get(self, name: str) -> Optional[BaseExporter]:
"""Get an exporter by format name."""
return self._exporters.get(name)
def export(self, format_name: str, context: ExportContext,
output_path: str, options: Optional[dict] = None) -> ExportResult:
"""
Export annotations using the named format.
Args:
format_name: Export format identifier (e.g., "coco", "yolo")
context: ExportContext with annotation data
output_path: Output directory or file path
options: Format-specific options
Returns:
ExportResult
Raises:
ValueError: If format is not registered or cannot handle the context
"""
exporter = self.get(format_name)
if not exporter:
supported = ", ".join(sorted(self._exporters.keys()))
raise ValueError(
f"Unknown export format: '{format_name}'. "
f"Supported formats: {supported}"
)
can, reason = exporter.can_export(context)
if not can:
return ExportResult(
success=False,
format_name=format_name,
errors=[f"Cannot export: {reason}"],
)
return exporter.export(context, output_path, options)
def list_exporters(self) -> List[Dict[str, Any]]:
"""List all registered exporters with metadata."""
return [
exporter.get_format_info()
for exporter in sorted(self._exporters.values(),
key=lambda e: e.format_name)
]
def get_supported_formats(self) -> List[str]:
"""Get sorted list of supported format names."""
return sorted(self._exporters.keys())
def is_registered(self, name: str) -> bool:
"""Check if a format is registered."""
return name in self._exporters
# Global registry instance
export_registry = ExportRegistry()
def _register_builtin_exporters():
"""Register all built-in exporters. Called on import."""
from .coco_exporter import COCOExporter
from .yolo_exporter import YOLOExporter
from .pascal_voc_exporter import PascalVOCExporter
from .conll_2003_exporter import CoNLL2003Exporter
from .conll_u_exporter import CoNLLUExporter
from .mask_exporter import MaskExporter
from .eaf_exporter import EAFExporter
from .textgrid_exporter import TextGridExporter
from .agent_eval_exporter import AgentEvalExporter
from .coding_eval_exporter import CodingEvalExporter
from .trajectory_correction_exporter import TrajectoryCorrectionExporter
from .parquet_exporter import ParquetExporter
from .tabular_exporter import CSVExporter, TSVExporter, JSONLExporter
from .codebook_exporter import CodebookExporter
from .quotation_report_exporter import QuotationReportExporter
exporters = [
COCOExporter(),
YOLOExporter(),
PascalVOCExporter(),
CoNLL2003Exporter(),
CoNLLUExporter(),
MaskExporter(),
EAFExporter(),
TextGridExporter(),
AgentEvalExporter(),
CodingEvalExporter(),
TrajectoryCorrectionExporter(),
ParquetExporter(),
CSVExporter(),
TSVExporter(),
JSONLExporter(),
CodebookExporter(),
QuotationReportExporter(),
]
# Optional exporters with external dependencies
try:
from .huggingface_exporter import HuggingFaceExporter
exporters.append(HuggingFaceExporter())
except ImportError:
logger.debug("HuggingFace exporter not available (missing dependencies)")
for exporter in exporters:
export_registry.register(exporter)
logger.debug(f"Registered {len(exporters)} built-in exporters")
_register_builtin_exporters()