Skip to content

Commit 2567306

Browse files
committed
effect review comments
1 parent ecebdb0 commit 2567306

File tree

9 files changed

+506
-365
lines changed

9 files changed

+506
-365
lines changed

aws_lambda_powertools/event_handler/api_gateway.py

Lines changed: 138 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,7 +1800,9 @@ def get_openapi_schema(
18001800

18011801
# Build final components and paths
18021802
components = self._build_openapi_components(definitions, config["security_schemes"])
1803-
output.update(self._finalize_openapi_output(components, config["tags"], paths, config["external_documentation"]))
1803+
output.update(
1804+
self._finalize_openapi_output(components, config["tags"], paths, config["external_documentation"]),
1805+
)
18041806

18051807
# Apply schema fixes and return result
18061808
return self._apply_schema_fixes(output)
@@ -1810,8 +1812,8 @@ def _resolve_openapi_config(self, **kwargs) -> dict[str, Any]:
18101812
# DEPRECATION: Will be removed in v4.0.0. Use configure_api() instead.
18111813
# Maintained for backwards compatibility.
18121814
# See: https://github.com/aws-powertools/powertools-lambda-python/issues/6122
1813-
resolved = {}
1814-
1815+
resolved: dict[str, Any] = {}
1816+
18151817
# Handle fields with specific default value checks
18161818
self._resolve_title_config(resolved, kwargs)
18171819
self._resolve_version_config(resolved, kwargs)
@@ -1823,41 +1825,112 @@ def _resolve_openapi_config(self, **kwargs) -> dict[str, Any]:
18231825
return resolved
18241826

18251827
def _resolve_title_config(self, resolved: dict[str, Any], kwargs: dict[str, Any]) -> None:
1826-
"""Resolve title configuration with fallback to openapi_config."""
1828+
"""
1829+
Resolve title configuration with fallback to openapi_config.
1830+
1831+
Checks if the provided title is the default value, and if so, uses the
1832+
title from openapi_config if available. This allows users to configure
1833+
a default title through the OpenAPI configuration object.
1834+
1835+
Parameters
1836+
----------
1837+
resolved : dict[str, Any]
1838+
Dictionary to store the resolved configuration (modified in place)
1839+
kwargs : dict[str, Any]
1840+
Keyword arguments passed to get_openapi_schema
1841+
"""
18271842
resolved["title"] = kwargs["title"]
18281843
if kwargs["title"] == DEFAULT_OPENAPI_TITLE and self.openapi_config.title:
18291844
resolved["title"] = self.openapi_config.title
18301845

18311846
def _resolve_version_config(self, resolved: dict[str, Any], kwargs: dict[str, Any]) -> None:
1832-
"""Resolve version configuration with fallback to openapi_config."""
1847+
"""
1848+
Resolve version configuration with fallback to openapi_config.
1849+
1850+
Checks if the provided version is the default value, and if so, uses the
1851+
version from openapi_config if available. This allows users to configure
1852+
a default API version through the OpenAPI configuration object.
1853+
1854+
Parameters
1855+
----------
1856+
resolved : dict[str, Any]
1857+
Dictionary to store the resolved configuration (modified in place)
1858+
kwargs : dict[str, Any]
1859+
Keyword arguments passed to get_openapi_schema
1860+
"""
18331861
resolved["version"] = kwargs["version"]
18341862
if kwargs["version"] == DEFAULT_API_VERSION and self.openapi_config.version:
18351863
resolved["version"] = self.openapi_config.version
18361864

18371865
def _resolve_openapi_version_config(self, resolved: dict[str, Any], kwargs: dict[str, Any]) -> None:
1838-
"""Resolve openapi_version configuration with fallback to openapi_config."""
1866+
"""
1867+
Resolve openapi_version configuration with fallback to openapi_config.
1868+
1869+
Checks if the provided OpenAPI version is the default value, and if so, uses
1870+
the version from openapi_config if available. This allows users to configure
1871+
a specific OpenAPI version through the OpenAPI configuration object.
1872+
1873+
Parameters
1874+
----------
1875+
resolved : dict[str, Any]
1876+
Dictionary to store the resolved configuration (modified in place)
1877+
kwargs : dict[str, Any]
1878+
Keyword arguments passed to get_openapi_schema
1879+
"""
18391880
resolved["openapi_version"] = kwargs["openapi_version"]
18401881
if kwargs["openapi_version"] == DEFAULT_OPENAPI_VERSION and self.openapi_config.openapi_version:
18411882
resolved["openapi_version"] = self.openapi_config.openapi_version
18421883

18431884
def _resolve_remaining_config_fields(self, resolved: dict[str, Any], kwargs: dict[str, Any]) -> None:
1844-
"""Resolve remaining configuration fields with simple fallbacks."""
1845-
resolved.update({
1846-
"summary": kwargs["summary"] or self.openapi_config.summary,
1847-
"description": kwargs["description"] or self.openapi_config.description,
1848-
"tags": kwargs["tags"] or self.openapi_config.tags,
1849-
"servers": kwargs["servers"] or self.openapi_config.servers,
1850-
"terms_of_service": kwargs["terms_of_service"] or self.openapi_config.terms_of_service,
1851-
"contact": kwargs["contact"] or self.openapi_config.contact,
1852-
"license_info": kwargs["license_info"] or self.openapi_config.license_info,
1853-
"security_schemes": kwargs["security_schemes"] or self.openapi_config.security_schemes,
1854-
"security": kwargs["security"] or self.openapi_config.security,
1855-
"external_documentation": kwargs["external_documentation"] or self.openapi_config.external_documentation,
1856-
"openapi_extensions": kwargs["openapi_extensions"] or self.openapi_config.openapi_extensions,
1857-
})
1885+
"""
1886+
Resolve remaining configuration fields with simple fallbacks.
1887+
1888+
For fields that use simple OR logic, use the provided value from kwargs
1889+
or fall back to the value from openapi_config. This includes fields like
1890+
summary, description, tags, servers, etc.
1891+
1892+
Parameters
1893+
----------
1894+
resolved : dict[str, Any]
1895+
Dictionary to store the resolved configuration (modified in place)
1896+
kwargs : dict[str, Any]
1897+
Keyword arguments passed to get_openapi_schema
1898+
"""
1899+
resolved.update(
1900+
{
1901+
"summary": kwargs["summary"] or self.openapi_config.summary,
1902+
"description": kwargs["description"] or self.openapi_config.description,
1903+
"tags": kwargs["tags"] or self.openapi_config.tags,
1904+
"servers": kwargs["servers"] or self.openapi_config.servers,
1905+
"terms_of_service": kwargs["terms_of_service"] or self.openapi_config.terms_of_service,
1906+
"contact": kwargs["contact"] or self.openapi_config.contact,
1907+
"license_info": kwargs["license_info"] or self.openapi_config.license_info,
1908+
"security_schemes": kwargs["security_schemes"] or self.openapi_config.security_schemes,
1909+
"security": kwargs["security"] or self.openapi_config.security,
1910+
"external_documentation": kwargs["external_documentation"]
1911+
or self.openapi_config.external_documentation,
1912+
"openapi_extensions": kwargs["openapi_extensions"] or self.openapi_config.openapi_extensions,
1913+
},
1914+
)
18581915

18591916
def _build_base_openapi_structure(self, config: dict[str, Any]) -> dict[str, Any]:
1860-
"""Build the base OpenAPI structure with info, servers, and security."""
1917+
"""
1918+
Build the base OpenAPI structure with info, servers, and security.
1919+
1920+
Creates the foundation of an OpenAPI schema including the required fields
1921+
(openapi version, info) and optional fields (servers, security) based on
1922+
the resolved configuration.
1923+
1924+
Parameters
1925+
----------
1926+
config : dict[str, Any]
1927+
Resolved OpenAPI configuration dictionary containing title, version, etc.
1928+
1929+
Returns
1930+
-------
1931+
dict[str, Any]
1932+
Base OpenAPI structure dictionary ready for paths and components
1933+
"""
18611934
openapi_version = self._determine_openapi_version(config["openapi_version"])
18621935

18631936
# Start with the bare minimum required for a valid OpenAPI schema
@@ -1885,9 +1958,13 @@ def _build_base_openapi_structure(self, config: dict[str, Any]) -> dict[str, Any
18851958
**openapi_extensions,
18861959
}
18871960

1888-
def _process_routes_for_openapi(self, security_schemes: dict[str, SecurityScheme] | None) -> tuple[dict[str, dict[str, Any]], dict[str, dict[str, Any]]]:
1961+
def _process_routes_for_openapi(
1962+
self,
1963+
security_schemes: dict[str, SecurityScheme] | None,
1964+
) -> tuple[dict[str, dict[str, Any]], dict[str, dict[str, Any]]]:
18891965
"""Process all routes and build paths and definitions."""
18901966
from pydantic.json_schema import GenerateJsonSchema
1967+
18911968
from aws_lambda_powertools.event_handler.openapi.compat import (
18921969
get_compat_model_name_map,
18931970
get_definitions,
@@ -1912,7 +1989,7 @@ def _process_routes_for_openapi(self, security_schemes: dict[str, SecurityScheme
19121989
# Add routes to the OpenAPI schema
19131990
for route in all_routes:
19141991
self._validate_route_security(route, security_schemes)
1915-
1992+
19161993
if not route.include_in_schema:
19171994
continue
19181995

@@ -1943,45 +2020,71 @@ def _validate_route_security(self, route, security_schemes: dict[str, SecuritySc
19432020
"See: https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/api_gateway/#security-schemes",
19442021
)
19452022

1946-
def _build_openapi_components(self, definitions: dict[str, dict[str, Any]], security_schemes: dict[str, SecurityScheme] | None) -> dict[str, dict[str, Any]]:
2023+
def _build_openapi_components(
2024+
self,
2025+
definitions: dict[str, dict[str, Any]],
2026+
security_schemes: dict[str, SecurityScheme] | None,
2027+
) -> dict[str, dict[str, Any]]:
19472028
"""Build the components section of the OpenAPI schema."""
19482029
components: dict[str, dict[str, Any]] = {}
1949-
2030+
19502031
if definitions:
19512032
components["schemas"] = self._generate_schemas(definitions)
19522033
if security_schemes:
19532034
components["securitySchemes"] = security_schemes
1954-
2035+
19552036
return components
19562037

1957-
def _finalize_openapi_output(self, components: dict[str, dict[str, Any]], tags, paths: dict[str, dict[str, Any]], external_documentation) -> dict[str, Any]:
2038+
def _finalize_openapi_output(
2039+
self,
2040+
components: dict[str, dict[str, Any]],
2041+
tags,
2042+
paths: dict[str, dict[str, Any]],
2043+
external_documentation,
2044+
) -> dict[str, Any]:
19582045
"""Finalize the OpenAPI output with components, tags, and paths."""
19592046
from aws_lambda_powertools.event_handler.openapi.models import PathItem, Tag
19602047

1961-
output = {}
1962-
2048+
output: dict[str, Any] = {}
2049+
19632050
if components:
19642051
output["components"] = components
19652052
if tags:
19662053
output["tags"] = [Tag(name=tag) if isinstance(tag, str) else tag for tag in tags]
19672054
if external_documentation:
19682055
output["externalDocs"] = external_documentation
19692056

1970-
output["paths"] = {k: PathItem(**v) for k, v in paths.items()}
1971-
2057+
output["paths"] = {k: PathItem(**v) if not isinstance(v, PathItem) else v for k, v in paths.items()}
2058+
19722059
return output
19732060

19742061
def _apply_schema_fixes(self, output: dict[str, Any]) -> OpenAPI:
1975-
"""Apply schema fixes and return the final OpenAPI model."""
2062+
"""
2063+
Apply schema fixes and return the final OpenAPI model.
2064+
2065+
This method handles various schema fixes, including resolving missing
2066+
component references for UploadFile parameters that can cause validation
2067+
errors in OpenAPI tools like Swagger Editor.
2068+
2069+
Parameters
2070+
----------
2071+
output : dict[str, Any]
2072+
The OpenAPI schema dictionary to process
2073+
2074+
Returns
2075+
-------
2076+
OpenAPI
2077+
The final OpenAPI model with all fixes applied
2078+
"""
19762079
from aws_lambda_powertools.event_handler.openapi.models import OpenAPI
1977-
from aws_lambda_powertools.event_handler.openapi.upload_file_fix import fix_upload_file_schema
2080+
from aws_lambda_powertools.event_handler.openapi.params import fix_upload_file_schema_references
19782081

19792082
# First create the OpenAPI model
19802083
result = OpenAPI(**output)
19812084

1982-
# Convert the model to a dict and apply the fix
2085+
# Convert the model to a dict and apply the upload file schema fix
19832086
result_dict = result.model_dump(by_alias=True)
1984-
fixed_dict = fix_upload_file_schema(result_dict)
2087+
fixed_dict = fix_upload_file_schema_references(result_dict)
19852088

19862089
# Reconstruct the model with the fixed dict
19872090
return OpenAPI(**fixed_dict)
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
# Expose the fix_upload_file_schema function
2-
from aws_lambda_powertools.event_handler.openapi.upload_file_fix import fix_upload_file_schema
1+
from __future__ import annotations
32

4-
__all__ = ["fix_upload_file_schema"]
3+
# OpenAPI module for event handler
4+
# The fix_upload_file_schema_references function is available in params module
5+
6+
__all__: list[str] = []

0 commit comments

Comments
 (0)