Source code for scfile.convert.factory
"""
Decorator for registering named format converters.
"""
from collections import defaultdict
from copy import deepcopy
from functools import wraps
from typing import Callable, Optional, Type, TypeAlias
from scfile.core import ContentType, FileDecoder, FileEncoder, Options
from scfile.types import PathLike
from .convert import convert
ConverterMap: TypeAlias = dict[str, Callable]
ConverterRegistry: TypeAlias = dict[str, ConverterMap]
DecoderMap: TypeAlias = dict[str, type[FileDecoder]]
EncoderMap: TypeAlias = dict[str, type[FileEncoder]]
Decoder: TypeAlias = Type[FileDecoder[ContentType]]
Encoder: TypeAlias = Type[FileEncoder[ContentType]]
_REGISTRY: ConverterRegistry = defaultdict(dict)
_DECODERS: DecoderMap = {}
_ENCODERS: EncoderMap = {}
[docs]
def decoders() -> DecoderMap:
"""Copy of registered format decoders."""
return deepcopy(_DECODERS)
[docs]
def encoders() -> EncoderMap:
"""Copy of registered format encoders."""
return deepcopy(_ENCODERS)
[docs]
def registry() -> ConverterRegistry:
"""Copy of full converter registry."""
return deepcopy(dict(_REGISTRY))
[docs]
def converters(
src_format: str,
) -> ConverterMap:
"""Converters for source format."""
return deepcopy(_REGISTRY.get(src_format.lower().lstrip("."), {}))
def _register(decoder: Decoder, encoder: Encoder, func: Callable) -> None:
dec = decoder.format.lower()
enc = encoder.format.lower()
_DECODERS[dec] = decoder
_ENCODERS[enc] = encoder
_REGISTRY[dec][enc] = func
def _alias(source: str, target: str) -> None:
_DECODERS[source] = _DECODERS[target]
_REGISTRY[source] = _REGISTRY[target]
[docs]
def converter(
decoder: Decoder,
encoder: Encoder,
aliases: tuple[str, ...] = (),
) -> Callable:
"""Factory decorator for named conversion between two formats."""
def decorator(func: Callable):
@wraps(func)
def wrapper(
source: PathLike,
output: Optional[PathLike] = None,
options: Optional[Options] = None,
):
convert(
decoder=decoder,
encoder=encoder,
source=source,
output=output,
options=options,
)
_register(
decoder=decoder,
encoder=encoder,
func=wrapper,
)
for alias in aliases:
_alias(alias, decoder.format.lower())
return wrapper
return decorator