import dataclasses
from typing import TYPE_CHECKING, Any
from dmr.openapi.objects import (
Parameter,
ParameterLocation,
ParameterMetadata,
Reference,
Schema,
)
if TYPE_CHECKING:
from dmr.openapi.core.context import OpenAPIContext
from dmr.serializer import BaseSerializer
[docs]
@dataclasses.dataclass(frozen=True, slots=True)
class ParameterGenerator:
"""Generator for OpenAPI ``Parameter`` objects."""
_context: 'OpenAPIContext'
[docs]
def __call__(
self,
model: Any,
model_meta: tuple[Any, ...],
serializer: type['BaseSerializer'],
context: 'OpenAPIContext',
*,
param_in: ParameterLocation,
) -> list[Parameter | Reference]:
"""Generate parameter spec for the OpenAPI."""
# Import cycle:
from dmr.metadata import get_annotated_metadata # noqa: PLC0415
schema = self._context.registries.schema.maybe_resolve_reference(
self._context.generators.schema(
model,
serializer,
skip_registration=True,
register_referenced_components=True,
),
)
metadata = get_annotated_metadata(
model,
ParameterMetadata,
model_meta=model_meta,
)
return [ # pyright: ignore[reportReturnType]
Parameter(
name=property_name,
param_in=param_in,
schema=property_schema,
required=(property_name in schema.required) or None,
**self._compute_metadata(
metadata,
property_name,
property_schema,
schema,
self._context,
),
)
for property_name, property_schema in (
schema.properties or {}
).items()
]
def _compute_metadata(
self,
metadata: ParameterMetadata | None,
property_name: str,
property_schema: Reference | Schema,
schema: Schema,
context: 'OpenAPIContext',
) -> dict[str, Any]:
metadata_params = (
{}
if metadata is None
else {
field.name: getattr(metadata, field.name)
for field in dataclasses.fields(metadata)
}
)
property_schema = context.registries.schema.maybe_resolve_reference(
property_schema,
)
return {
**metadata_params,
'description': (
property_schema.description
or metadata_params.get('description')
or schema.description
),
'deprecated': (
property_schema.deprecated
or metadata_params.get('deprecated')
or schema.deprecated
or None
),
}