Source code for unsprawl.loaders.universal

"""unsprawl.loaders.universal.

UniversalLoader is the public facade that dispatches to a country adapter.

Anti-circular protocol
----------------------
Loaders may import adapters, but `unsprawl.core` must never import loaders.
"""

from __future__ import annotations

import importlib
from dataclasses import dataclass

from unsprawl.core.regions import RegionNode
from unsprawl.core.schemas import Asset


[docs] @dataclass(frozen=True) class UniversalLoader: """Dynamic dispatcher that loads Assets for a given Region node."""
[docs] def load(self, region_node: RegionNode) -> list[Asset]: """Load assets for a region. Parameters ---------- region_node: A `Region.*` node from `unsprawl.core.regions`. Returns ------- list[Asset] The normalized assets for this region. """ code = region_node.CODE country = code.split("-")[0] module_name = f"unsprawl.adapters.{country.lower()}" module = importlib.import_module(module_name) # Convention: adapter class name is '<CC>Adapter' (e.g., SGAdapter) adapter_class_name = f"{country.upper()}Adapter" adapter_cls = getattr(module, adapter_class_name) adapter = adapter_cls() from typing import cast as _cast return _cast(list[Asset], adapter.fetch(code))