| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960 |
- """Provider registry — maps ``source_type`` / URLs to model providers.
- The registry is the routing layer a future *shared* import API uses: a pasted
- URL goes through :meth:`ModelProviderRegistry.find_for_url`, which asks each
- registered provider ``supports_url`` and returns the one that owns it. Today
- the route layer still calls the MakerWorld provider directly (endpoints stay
- at ``/makerworld/*``), but registering providers here keeps the seam ready.
- """
- from __future__ import annotations
- from typing import TYPE_CHECKING
- if TYPE_CHECKING:
- from backend.app.services.model_providers.base import ModelProvider
- class ModelProviderRegistry:
- """Holds the registered :class:`ModelProvider` instances.
- Registering is idempotent per provider instance; registering a *different*
- provider under an already-taken ``source_type`` is an error.
- """
- def __init__(self) -> None:
- self._providers: dict[str, ModelProvider] = {}
- def register(self, provider: ModelProvider) -> None:
- existing = self._providers.get(provider.source_type)
- if existing is not None and existing is not provider:
- raise ValueError(f"A model provider for source_type {provider.source_type!r} is already registered")
- self._providers[provider.source_type] = provider
- def get(self, source_type: str) -> ModelProvider:
- try:
- return self._providers[source_type]
- except KeyError as exc:
- raise KeyError(f"No model provider registered for source_type {source_type!r}") from exc
- def all(self) -> tuple[ModelProvider, ...]:
- return tuple(self._providers.values())
- def find_for_url(self, url: str) -> ModelProvider | None:
- """Return the provider that claims ``url``, or ``None`` if none do.
- Iterates in registration (dict insertion) order; when more than one
- provider ``supports_url`` the *first registered* one wins. Providers
- overlap rarely (``host_patterns`` are usually disjoint), so this
- tie-break is documented rather than policed — a "generic" provider
- must register after the specific ones it might shadow.
- """
- for provider in self._providers.values():
- if provider.supports_url(url):
- return provider
- return None
- # App-wide registry. Providers register themselves on package import (see
- # ``backend/app/services/model_providers/__init__.py``).
- registry = ModelProviderRegistry()
|