Skip to content

Commit a54038c

Browse files
committed
Fix recursion error, fix duplicate argument
1 parent d34ef16 commit a54038c

File tree

7 files changed

+187
-8
lines changed

7 files changed

+187
-8
lines changed

fastapi_code_generator/parser.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,22 @@ def get_argument_list(self, snake_case: bool, path: List[str]) -> List[Argument]
347347
or argument.type_hint.startswith('Optional[')
348348
)
349349

350-
return arguments
350+
# Group argument with same name into one argument.name argument.type_hint into Argument(name = argument.name, type_hint = "Union[argument.type_hint, argument.type_hint]")
351+
grouped_arguments: DefaultDict[str, List[Argument]] = DefaultDict(list)
352+
sorted_arguments = []
353+
for argument in arguments:
354+
grouped_arguments[argument.name].append(argument)
355+
for argument_list in grouped_arguments.values():
356+
if len(argument_list) == 1:
357+
sorted_arguments.append(argument_list[0])
358+
else:
359+
argument = argument_list[0]
360+
type_hints = [arg.type_hint for arg in argument_list]
361+
argument.type_hint = UsefulStr(f"Union[{', '.join(type_hints)}]")
362+
self.imports_for_fastapi.append(Import(from_='typing', import_="Union"))
363+
sorted_arguments.append(argument)
364+
365+
return sorted_arguments
351366

352367
def parse_request_body(
353368
self,
@@ -527,13 +542,16 @@ def _collapse_root_model(self, data_type: DataType) -> DataType:
527542
reference = data_type.reference
528543
import functools
529544

530-
if not (
531-
reference
532-
and (
533-
len(reference.children) == 1
534-
or functools.reduce(lambda a, b: a == b, reference.children)
535-
)
536-
):
545+
try:
546+
if not (
547+
reference
548+
and (
549+
len(reference.children) == 0
550+
or functools.reduce(lambda a, b: a == b, reference.children)
551+
)
552+
):
553+
return data_type
554+
except RecursionError:
537555
return data_type
538556
source = reference.source
539557
if not isinstance(source, CustomRootType):
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# generated by fastapi-codegen:
2+
# filename: duplicate_param.yaml
3+
# timestamp: 2020-06-19T00:00:00+00:00
4+
5+
from __future__ import annotations
6+
7+
from typing import Union
8+
9+
from fastapi import FastAPI
10+
from pydantic import constr
11+
12+
app = FastAPI(
13+
title='REST API',
14+
version='0.0.1',
15+
servers=[{'url': 'https://api.something.com/1'}],
16+
)
17+
18+
19+
@app.delete('/boards/{id}', response_model=None)
20+
def delete_boards_id(id: Union[str, constr(regex=r'^[0-9a-fA-F]{24}$')]) -> None:
21+
"""
22+
Delete a Board
23+
"""
24+
pass
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# generated by fastapi-codegen:
2+
# filename: duplicate_param.yaml
3+
# timestamp: 2020-06-19T00:00:00+00:00
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# generated by fastapi-codegen:
2+
# filename: recursion.yaml
3+
# timestamp: 2020-06-19T00:00:00+00:00
4+
5+
from __future__ import annotations
6+
7+
from fastapi import FastAPI
8+
9+
from .models import ID
10+
11+
app = FastAPI(
12+
title='REST API',
13+
version='0.0.1',
14+
servers=[{'url': 'https://api.something.com/1'}],
15+
)
16+
17+
18+
@app.get('/actions/{id}', response_model=None)
19+
def get_actions_id(id: ID) -> None:
20+
pass
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# generated by fastapi-codegen:
2+
# filename: recursion.yaml
3+
# timestamp: 2020-06-19T00:00:00+00:00
4+
5+
from __future__ import annotations
6+
7+
from typing import Optional
8+
9+
from pydantic import BaseModel, Field, constr
10+
11+
12+
class ID(BaseModel):
13+
__root__: constr(regex=r'^[0-9a-fA-F]{24}$') = Field(
14+
..., example='5abbe4b7ddc1b351ef961414'
15+
)
16+
17+
18+
class Card(BaseModel):
19+
id: Optional[ID] = None
20+
21+
22+
class Board(BaseModel):
23+
id: Optional[ID] = None
24+
25+
26+
class Data(BaseModel):
27+
card: Optional[Card] = None
28+
board: Optional[Board] = None
29+
30+
31+
class Action(BaseModel):
32+
data: Optional[Data] = None
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
openapi: 3.0.0
2+
info:
3+
title: REST API
4+
version: 0.0.1
5+
servers:
6+
- url: https://api.something.com/1
7+
components:
8+
securitySchemes: {}
9+
schemas:
10+
ID:
11+
type: string
12+
pattern: ^[0-9a-fA-F]{24}$
13+
example: 5abbe4b7ddc1b351ef961414
14+
responses: {}
15+
paths:
16+
/boards/{id}:
17+
parameters:
18+
- name: id
19+
in: path
20+
description: ''
21+
required: true
22+
schema:
23+
$ref: '#/components/schemas/ID'
24+
delete:
25+
tags: []
26+
summary: Delete a Board
27+
description: Delete a board.
28+
operationId: delete-boards-id
29+
parameters:
30+
- name: id
31+
in: path
32+
description: The id of the board to delete
33+
required: true
34+
schema:
35+
type: string
36+
deprecated: false
37+
responses:
38+
'200':
39+
description: Success
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
openapi: 3.0.0
2+
info:
3+
title: REST API
4+
version: 0.0.1
5+
servers:
6+
- url: https://api.something.com/1
7+
components:
8+
schemas:
9+
Action:
10+
type: object
11+
properties:
12+
data:
13+
type: object
14+
properties:
15+
card:
16+
type: object
17+
properties:
18+
id:
19+
type: string
20+
$ref: '#/components/schemas/ID'
21+
board:
22+
type: object
23+
properties:
24+
id:
25+
type: string
26+
$ref: '#/components/schemas/ID'
27+
ID:
28+
type: string
29+
pattern: ^[0-9a-fA-F]{24}$
30+
example: 5abbe4b7ddc1b351ef961414
31+
paths:
32+
/actions/{id}:
33+
parameters:
34+
- name: id
35+
in: path
36+
description: The ID of the Action
37+
required: true
38+
schema:
39+
$ref: '#/components/schemas/ID'
40+
get:
41+
responses:
42+
'200':
43+
description: Success

0 commit comments

Comments
 (0)