"""Registry of built-in ECLYPSE graph importers and exporters."""
from __future__ import annotations
from dataclasses import (
dataclass,
field,
replace,
)
from types import MappingProxyType
from typing import (
TYPE_CHECKING,
Any,
)
if TYPE_CHECKING:
from collections.abc import Mapping
from eclypse.io.base import (
GraphExporter,
GraphImporter,
)
from eclypse.utils.types import GraphKind
[docs]
@dataclass(slots=True, frozen=True)
class IORegistry:
"""Immutable registry of importer and exporter classes.
Args:
importers (Mapping[tuple[GraphKind, str], type[GraphImporter]]):
Importer classes
keyed by ``(kind, format)``.
exporters (Mapping[tuple[GraphKind, str], type[GraphExporter]]):
Exporter classes
keyed by ``(kind, format)``.
"""
importers: Mapping[tuple[GraphKind, str], type[GraphImporter]] = field(
default_factory=dict
)
exporters: Mapping[tuple[GraphKind, str], type[GraphExporter]] = field(
default_factory=dict
)
def __post_init__(self):
"""Freeze registry mappings after initialisation."""
object.__setattr__(self, "importers", MappingProxyType(dict(self.importers)))
object.__setattr__(self, "exporters", MappingProxyType(dict(self.exporters)))
[docs]
def get_importer(self, kind: GraphKind, format: str) -> type[GraphImporter]:
"""Return the importer class registered for a graph kind and format.
Args:
kind (GraphKind): The graph kind, such as ``"infrastructure"``.
format (str): The IO format, such as ``"gml"``.
Returns:
type[GraphImporter]: The registered importer class.
Raises:
ValueError: If no importer is registered for the pair.
"""
key = (kind, format)
try:
return self.importers[key]
except KeyError as exc:
raise ValueError(
f"No importer registered for kind {kind!r} and format {format!r}."
) from exc
[docs]
def get_exporter(self, kind: GraphKind, format: str) -> type[GraphExporter]:
"""Return the exporter class registered for a graph kind and format.
Args:
kind (GraphKind): The graph kind, such as ``"application"``.
format (str): The IO format, such as ``"graphml"``.
Returns:
type[GraphExporter]: The registered exporter class.
Raises:
ValueError: If no exporter is registered for the pair.
"""
key = (kind, format)
try:
return self.exporters[key]
except KeyError as exc:
raise ValueError(
f"No exporter registered for kind {kind!r} and format {format!r}."
) from exc
[docs]
def with_importer(
self,
kind: GraphKind,
format: str,
importer: type[GraphImporter],
) -> IORegistry:
"""Return a copy of the registry with an additional importer.
Args:
kind (GraphKind): The graph kind.
format (str): The IO format.
importer (type[GraphImporter]): The importer class to register.
Returns:
IORegistry: A new registry containing the additional importer.
"""
return replace(self, importers={**self.importers, (kind, format): importer})
[docs]
def with_exporter(
self,
kind: GraphKind,
format: str,
exporter: type[GraphExporter],
) -> IORegistry:
"""Return a copy of the registry with an additional exporter.
Args:
kind (GraphKind): The graph kind.
format (str): The IO format.
exporter (type[GraphExporter]): The exporter class to register.
Returns:
IORegistry: A new registry containing the additional exporter.
"""
return replace(self, exporters={**self.exporters, (kind, format): exporter})