From bfe758f8c39e1d3ae703bb5af67b148c1416826a Mon Sep 17 00:00:00 2001 From: LuisHsu Date: Fri, 18 Oct 2024 13:56:25 -0700 Subject: [PATCH 01/10] Expose plain arguments --- fastapi_code_generator/parser.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index 5dfbe6b..db97454 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -1,5 +1,6 @@ from __future__ import annotations +from functools import reduce import pathlib import re from typing import ( @@ -118,6 +119,7 @@ class Operation(CachedPropertyModel): security: Optional[List[Dict[str, List[str]]]] = None tags: Optional[List[str]] = [] arguments: str = '' + plain_arguments: str = '' snake_case_arguments: str = '' request: Optional[Argument] = None response: str = '' @@ -473,6 +475,9 @@ def parse_operation( self._temporary_operation['snake_case_arguments'] = self.get_arguments( snake_case=True, path=path ) + self._temporary_operation['plain_arguments'] = ",".join(map(lambda a: a.name, self.get_argument_list( + snake_case=True, path=path + ))) main_operation = self._temporary_operation # Handle callbacks. This iterates over callbacks, shifting each one From a137f16760a5896128d1a73aaeb8acc952c2f336 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 18 Oct 2024 20:59:01 +0000 Subject: [PATCH 02/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- fastapi_code_generator/parser.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index db97454..190505f 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -1,8 +1,8 @@ from __future__ import annotations -from functools import reduce import pathlib import re +from functools import reduce from typing import ( Any, Callable, @@ -475,9 +475,9 @@ def parse_operation( self._temporary_operation['snake_case_arguments'] = self.get_arguments( snake_case=True, path=path ) - self._temporary_operation['plain_arguments'] = ",".join(map(lambda a: a.name, self.get_argument_list( - snake_case=True, path=path - ))) + self._temporary_operation['plain_arguments'] = ",".join( + map(lambda a: a.name, self.get_argument_list(snake_case=True, path=path)) + ) main_operation = self._temporary_operation # Handle callbacks. This iterates over callbacks, shifting each one From ac7a936f67b5d69d393ffc31ddf88611ab3b69c5 Mon Sep 17 00:00:00 2001 From: LuisHsu Date: Mon, 21 Oct 2024 15:28:16 -0700 Subject: [PATCH 03/10] Pass request always --- fastapi_code_generator/parser.py | 35 +++++++++++++++++++------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index 190505f..36d323a 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -336,9 +336,16 @@ def get_argument_list(self, snake_case: bool, path: List[str]) -> List[Argument] if parameter_type: arguments.append(parameter_type) - request = self._temporary_operation.get('_request') - if request: - arguments.append(request) + arguments.append( + Argument( + name='request', # type: ignore + type_hint='Request', # type: ignore + required=False + ) + ) + self.imports_for_fastapi.append( + Import.from_full_path("fastapi.Request") + ) positional_argument: bool = False for argument in arguments: @@ -397,17 +404,6 @@ def parse_request_body( self.imports_for_fastapi.append( Import.from_full_path('starlette.requests.Request') ) - elif media_type == 'application/octet-stream': - arguments.append( - Argument( - name='request', # type: ignore - type_hint='Request', # type: ignore - required=True, - ) - ) - self.imports_for_fastapi.append( - Import.from_full_path("fastapi.Request") - ) elif media_type == 'multipart/form-data': arguments.append( Argument( @@ -419,6 +415,17 @@ def parse_request_body( self.imports_for_fastapi.append( Import.from_full_path("fastapi.UploadFile") ) + if len(arguments) == 0: + arguments.append( + Argument( + name='request', # type: ignore + type_hint='Request', # type: ignore + required=True, + ) + ) + self.imports_for_fastapi.append( + Import.from_full_path("fastapi.Request") + ) self._temporary_operation['_request'] = arguments[0] if arguments else None def parse_responses( # type: ignore[override] From 2476018c3e6773ae4845dfdbbecb6d4152fbf879 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:29:00 +0000 Subject: [PATCH 04/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- fastapi_code_generator/parser.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index 36d323a..b8dbad6 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -340,12 +340,10 @@ def get_argument_list(self, snake_case: bool, path: List[str]) -> List[Argument] Argument( name='request', # type: ignore type_hint='Request', # type: ignore - required=False + required=False, ) ) - self.imports_for_fastapi.append( - Import.from_full_path("fastapi.Request") - ) + self.imports_for_fastapi.append(Import.from_full_path("fastapi.Request")) positional_argument: bool = False for argument in arguments: @@ -423,9 +421,7 @@ def parse_request_body( required=True, ) ) - self.imports_for_fastapi.append( - Import.from_full_path("fastapi.Request") - ) + self.imports_for_fastapi.append(Import.from_full_path("fastapi.Request")) self._temporary_operation['_request'] = arguments[0] if arguments else None def parse_responses( # type: ignore[override] From 7c0918327fe2f7f6bdbb425a19e87dfb4a732ebe Mon Sep 17 00:00:00 2001 From: LuisHsu Date: Mon, 27 Jan 2025 23:29:12 -0800 Subject: [PATCH 05/10] Pass UploadFile if format:'binary' presents --- fastapi_code_generator/__main__.py | 4 +- fastapi_code_generator/parser.py | 104 +++++++++-------------------- 2 files changed, 34 insertions(+), 74 deletions(-) diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py index f0055bf..3562a4a 100644 --- a/fastapi_code_generator/__main__.py +++ b/fastapi_code_generator/__main__.py @@ -13,8 +13,8 @@ from datamodel_code_generator.types import DataType from jinja2 import Environment, FileSystemLoader -from fastapi_code_generator.parser import OpenAPIParser -from fastapi_code_generator.visitor import Visitor +from parser import OpenAPIParser +from visitor import Visitor app = typer.Typer() diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index b8dbad6..dd45bb9 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -52,7 +52,7 @@ class CachedPropertyModel(BaseModel): class Config: arbitrary_types_allowed = True - keep_untouched = (cached_property,) + ignored_types = (cached_property,) class Response(BaseModel): @@ -118,9 +118,10 @@ class Operation(CachedPropertyModel): imports: List[Import] = [] security: Optional[List[Dict[str, List[str]]]] = None tags: Optional[List[str]] = [] - arguments: str = '' + arguments: List[Argument] = [] + plain_parameters: str = '' plain_arguments: str = '' - snake_case_arguments: str = '' + snake_case_arguments: List[Argument] = [] request: Optional[Argument] = None response: str = '' additional_responses: Dict[Union[str, int], Dict[str, str]] = {} @@ -319,11 +320,6 @@ def get_parameter_type( required=field.required, ) - def get_arguments(self, snake_case: bool, path: List[str]) -> str: - return ", ".join( - argument.argument for argument in self.get_argument_list(snake_case, path) - ) - def get_argument_list(self, snake_case: bool, path: List[str]) -> List[Argument]: arguments: List[Argument] = [] @@ -335,15 +331,21 @@ def get_argument_list(self, snake_case: bool, path: List[str]) -> List[Argument] ) if parameter_type: arguments.append(parameter_type) + - arguments.append( - Argument( + request = self._temporary_operation.get('_request') + if request: + arguments = arguments + request + else: + arguments.append(Argument( name='request', # type: ignore type_hint='Request', # type: ignore - required=False, - ) + required=True + )) + + self.imports_for_fastapi.append( + Import.from_full_path("fastapi.Request") ) - self.imports_for_fastapi.append(Import.from_full_path("fastapi.Request")) positional_argument: bool = False for argument in arguments: @@ -365,64 +367,19 @@ def parse_request_body( ) -> None: super().parse_request_body(name, request_body, path) arguments: List[Argument] = [] - for ( - media_type, - media_obj, - ) in request_body.content.items(): # type: str, MediaObject - if isinstance( - media_obj.schema_, (JsonSchemaObject, ReferenceObject) - ): # pragma: no cover - # TODO: support other content-types - if RE_APPLICATION_JSON_PATTERN.match(media_type): - if isinstance(media_obj.schema_, ReferenceObject): - data_type = self.get_ref_data_type(media_obj.schema_.ref) - else: - data_type = self.parse_schema( - name, media_obj.schema_, [*path, media_type] - ) - data_type = self._collapse_root_model(data_type) - arguments.append( - # TODO: support multiple body - Argument( - name='body', # type: ignore - type_hint=UsefulStr(data_type.type_hint), - required=request_body.required, - ) - ) - self.data_types.append(data_type) - elif media_type == 'application/x-www-form-urlencoded': - arguments.append( - # TODO: support form with `Form()` - Argument( - name='request', # type: ignore - type_hint='Request', # type: ignore - required=True, - ) - ) - self.imports_for_fastapi.append( - Import.from_full_path('starlette.requests.Request') - ) - elif media_type == 'multipart/form-data': - arguments.append( - Argument( - name='file', # type: ignore - type_hint='UploadFile', # type: ignore - required=True, - ) - ) - self.imports_for_fastapi.append( - Import.from_full_path("fastapi.UploadFile") + for media_obj in request_body.content.values(): + if isinstance(media_obj.schema_, JsonSchemaObject) and (media_obj.schema_.format == 'binary'): + arguments.append( + Argument( + name='file', # type: ignore + type_hint='UploadFile', # type: ignore + required=True, ) - if len(arguments) == 0: - arguments.append( - Argument( - name='request', # type: ignore - type_hint='Request', # type: ignore - required=True, ) - ) - self.imports_for_fastapi.append(Import.from_full_path("fastapi.Request")) - self._temporary_operation['_request'] = arguments[0] if arguments else None + self.imports_for_fastapi.append( + Import.from_full_path("fastapi.UploadFile") + ) + self._temporary_operation['_request'] = arguments def parse_responses( # type: ignore[override] self, @@ -472,14 +429,17 @@ def parse_operation( resolved_path = self.model_resolver.resolve_ref(path) path_name, method = path[-2:] - self._temporary_operation['arguments'] = self.get_arguments( + self._temporary_operation['arguments'] = self.get_argument_list( snake_case=False, path=path ) - self._temporary_operation['snake_case_arguments'] = self.get_arguments( + self._temporary_operation['snake_case_arguments'] = self.get_argument_list( snake_case=True, path=path ) self._temporary_operation['plain_arguments'] = ",".join( - map(lambda a: a.name, self.get_argument_list(snake_case=True, path=path)) + map(lambda a: a.name, self._temporary_operation['snake_case_arguments']) + ) + self._temporary_operation['plain_parameters'] = ",".join( + map(lambda a: f'{a.name}{": " + a.type_hint if a.type_hint is not None else ""}', self._temporary_operation['snake_case_arguments']) ) main_operation = self._temporary_operation From 348b935c2cef0b41b5c147e3c6b53ed21a517f80 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 28 Jan 2025 07:30:16 +0000 Subject: [PATCH 06/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- fastapi_code_generator/__main__.py | 3 +-- fastapi_code_generator/parser.py | 28 ++++++++++++++++------------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py index 3562a4a..fd1a358 100644 --- a/fastapi_code_generator/__main__.py +++ b/fastapi_code_generator/__main__.py @@ -1,6 +1,7 @@ import re from datetime import datetime, timezone from importlib.util import module_from_spec, spec_from_file_location +from parser import OpenAPIParser from pathlib import Path from typing import Any, Dict, List, Optional @@ -12,8 +13,6 @@ from datamodel_code_generator.reference import Reference from datamodel_code_generator.types import DataType from jinja2 import Environment, FileSystemLoader - -from parser import OpenAPIParser from visitor import Visitor app = typer.Typer() diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index dd45bb9..d1b0149 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -331,21 +331,20 @@ def get_argument_list(self, snake_case: bool, path: List[str]) -> List[Argument] ) if parameter_type: arguments.append(parameter_type) - request = self._temporary_operation.get('_request') if request: arguments = arguments + request else: - arguments.append(Argument( - name='request', # type: ignore - type_hint='Request', # type: ignore - required=True - )) - - self.imports_for_fastapi.append( - Import.from_full_path("fastapi.Request") - ) + arguments.append( + Argument( + name='request', # type: ignore + type_hint='Request', # type: ignore + required=True, + ) + ) + + self.imports_for_fastapi.append(Import.from_full_path("fastapi.Request")) positional_argument: bool = False for argument in arguments: @@ -368,7 +367,9 @@ def parse_request_body( super().parse_request_body(name, request_body, path) arguments: List[Argument] = [] for media_obj in request_body.content.values(): - if isinstance(media_obj.schema_, JsonSchemaObject) and (media_obj.schema_.format == 'binary'): + if isinstance(media_obj.schema_, JsonSchemaObject) and ( + media_obj.schema_.format == 'binary' + ): arguments.append( Argument( name='file', # type: ignore @@ -439,7 +440,10 @@ def parse_operation( map(lambda a: a.name, self._temporary_operation['snake_case_arguments']) ) self._temporary_operation['plain_parameters'] = ",".join( - map(lambda a: f'{a.name}{": " + a.type_hint if a.type_hint is not None else ""}', self._temporary_operation['snake_case_arguments']) + map( + lambda a: f'{a.name}{": " + a.type_hint if a.type_hint is not None else ""}', + self._temporary_operation['snake_case_arguments'], + ) ) main_operation = self._temporary_operation From f7b54d355ed8029570b67e28619a0330340a99fa Mon Sep 17 00:00:00 2001 From: LuisHsu Date: Mon, 27 Jan 2025 23:34:00 -0800 Subject: [PATCH 07/10] Fix imports --- fastapi_code_generator/__main__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py index fd1a358..e1cbc8b 100644 --- a/fastapi_code_generator/__main__.py +++ b/fastapi_code_generator/__main__.py @@ -13,7 +13,9 @@ from datamodel_code_generator.reference import Reference from datamodel_code_generator.types import DataType from jinja2 import Environment, FileSystemLoader -from visitor import Visitor + +from fastapi_code_generator.parser import OpenAPIParser +from fastapi_code_generator.visitor import Visitor app = typer.Typer() From cba8eed4e5806321a78c02eb20978e29ff98f7bb Mon Sep 17 00:00:00 2001 From: LuisHsu Date: Mon, 27 Jan 2025 23:36:25 -0800 Subject: [PATCH 08/10] Fix imports --- fastapi_code_generator/__main__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py index e1cbc8b..c8ad26a 100644 --- a/fastapi_code_generator/__main__.py +++ b/fastapi_code_generator/__main__.py @@ -1,7 +1,7 @@ import re from datetime import datetime, timezone from importlib.util import module_from_spec, spec_from_file_location -from parser import OpenAPIParser +from fastapi_code_generator.parser import OpenAPIParser from pathlib import Path from typing import Any, Dict, List, Optional @@ -14,7 +14,6 @@ from datamodel_code_generator.types import DataType from jinja2 import Environment, FileSystemLoader -from fastapi_code_generator.parser import OpenAPIParser from fastapi_code_generator.visitor import Visitor app = typer.Typer() From f02b98ac4ed5c700d41a86957e62369517e2de35 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 28 Jan 2025 07:38:18 +0000 Subject: [PATCH 09/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- fastapi_code_generator/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py index c8ad26a..f0055bf 100644 --- a/fastapi_code_generator/__main__.py +++ b/fastapi_code_generator/__main__.py @@ -1,7 +1,6 @@ import re from datetime import datetime, timezone from importlib.util import module_from_spec, spec_from_file_location -from fastapi_code_generator.parser import OpenAPIParser from pathlib import Path from typing import Any, Dict, List, Optional @@ -14,6 +13,7 @@ from datamodel_code_generator.types import DataType from jinja2 import Environment, FileSystemLoader +from fastapi_code_generator.parser import OpenAPIParser from fastapi_code_generator.visitor import Visitor app = typer.Typer() From dcb59b8a5d4632698fd4db0d06aee84d3ab97f86 Mon Sep 17 00:00:00 2001 From: LuisHsu Date: Tue, 28 Jan 2025 01:26:31 -0800 Subject: [PATCH 10/10] Append request only --- fastapi_code_generator/parser.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index d1b0149..35c47cd 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -332,17 +332,13 @@ def get_argument_list(self, snake_case: bool, path: List[str]) -> List[Argument] if parameter_type: arguments.append(parameter_type) - request = self._temporary_operation.get('_request') - if request: - arguments = arguments + request - else: - arguments.append( - Argument( - name='request', # type: ignore - type_hint='Request', # type: ignore - required=True, - ) + arguments.append( + Argument( + name='request', # type: ignore + type_hint='Request', # type: ignore + required=True, ) + ) self.imports_for_fastapi.append(Import.from_full_path("fastapi.Request"))