def __init__(self) -> None:
"""Initialize factory with manifest built from class attributes."""
# Validate required class attributes
self._validate_class_attributes()
# Validate runtime class is a proper subclass
# Import locally to avoid circular import during module import
from .runtime import ProviderPluginRuntime
if not issubclass(self.runtime_class, ProviderPluginRuntime):
raise TypeError(
f"runtime_class {self.runtime_class.__name__} must be a subclass of ProviderPluginRuntime"
)
# Build routes from routers list
routes = []
for router_spec in self.routers:
# Handle both router instances and router factory functions
router_instance = router_spec.router
if callable(router_spec.router) and not isinstance(
router_spec.router, APIRouter
):
# Router is a factory function, call it to get the actual router
router_instance = router_spec.router()
routes.append(
RouteSpec(
router=cast(APIRouter, router_instance),
prefix=router_spec.prefix,
tags=router_spec.tags or [],
dependencies=router_spec.dependencies,
)
)
# Create manifest from class attributes
manifest = PluginManifest(
name=self.plugin_name,
version=self.plugin_version,
description=self.plugin_description,
is_provider=True,
config_class=self.config_class,
tool_accumulator_class=self.tool_accumulator_class,
dependencies=self.dependencies.copy(),
optional_requires=self.optional_requires.copy(),
routes=routes,
tasks=self.tasks.copy(),
format_adapters=self.format_adapters.copy(),
requires_format_adapters=self.requires_format_adapters.copy(),
cli_commands=self.cli_commands.copy(),
cli_arguments=self.cli_arguments.copy(),
)
# Format adapter specification validation is deferred to runtime
# when settings are available via dependency injection
# Store the manifest and runtime class directly
# We don't call parent __init__ because ProviderPluginFactory
# would override our runtime_class with ProviderPluginRuntime
self.manifest = manifest
self.runtime_class = self.__class__.runtime_class