Skip to content

Commit 145af73

Browse files
NatalyaGrigorevaNatalia Grigoreva
authored andcommitted
update fastapi package
1 parent f408368 commit 145af73

File tree

9 files changed

+119
-113
lines changed

9 files changed

+119
-113
lines changed

README.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pip install FastAPI-JSONAPI
3030
Create a test.py file and copy the following code into it
3131

3232
```python
33+
from contextlib import asynccontextmanager
3334
from pathlib import Path
3435
from typing import Any, ClassVar, Optional
3536

@@ -171,26 +172,26 @@ def add_routes(app: FastAPI):
171172
return tags
172173

173174

174-
def create_app() -> FastAPI:
175-
"""
176-
Create app factory.
177-
178-
:return: app
179-
"""
180-
app = FastAPI(
181-
title="FastAPI and SQLAlchemy",
182-
debug=True,
183-
openapi_url="/openapi.json",
184-
docs_url="/docs",
185-
)
175+
# noinspection PyUnusedLocal
176+
@asynccontextmanager
177+
async def lifespan(app: FastAPI):
186178
add_routes(app)
187-
app.on_event("startup")(Connector.init)
188-
app.on_event("shutdown")(Connector.dispose)
189179
init(app)
190-
return app
180+
181+
await Connector.init()
182+
183+
yield
184+
185+
await Connector.dispose()
191186

192187

193-
app = create_app()
188+
app = FastAPI(
189+
lifespan=lifespan,
190+
title="FastAPI and SQLAlchemy",
191+
debug=True,
192+
openapi_url="/openapi.json",
193+
docs_url="/docs",
194+
)
194195

195196

196197
if __name__ == "__main__":

docs/python_snippets/client_generated_id/schematic_example.py

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import sys
2+
from contextlib import asynccontextmanager
23
from pathlib import Path
34
from typing import ClassVar, Annotated, Optional
45

56
import uvicorn
67
from fastapi import APIRouter, Depends, FastAPI
8+
from fastapi.responses import ORJSONResponse as JSONResponse
79
from pydantic import ConfigDict
810
from sqlalchemy.engine import make_url
911
from sqlalchemy.ext.asyncio import AsyncSession
@@ -58,11 +60,6 @@ class UserInSchema(UserAttributesBaseSchema):
5860
id: Annotated[int, ClientCanSetId()]
5961

6062

61-
async def sqlalchemy_init() -> None:
62-
async with db.engine.begin() as conn:
63-
await conn.run_sync(Base.metadata.create_all)
64-
65-
6663
class SessionDependency(BaseModel):
6764
model_config = ConfigDict(
6865
arbitrary_types_allowed=True,
@@ -95,7 +92,7 @@ class UserListView(ListViewBaseGeneric):
9592
}
9693

9794

98-
def add_routes(app: FastAPI):
95+
def add_routes(app: FastAPI) -> list[dict]:
9996
tags = [
10097
{
10198
"name": "User",
@@ -121,26 +118,28 @@ def add_routes(app: FastAPI):
121118
return tags
122119

123120

124-
def create_app() -> FastAPI:
125-
"""
126-
Create app factory.
127-
128-
:return: app
129-
"""
130-
app = FastAPI(
131-
title="FastAPI and SQLAlchemy",
132-
debug=True,
133-
openapi_url="/openapi.json",
134-
docs_url="/docs",
135-
)
121+
# noinspection PyUnusedLocal
122+
@asynccontextmanager
123+
async def lifespan(app: FastAPI):
136124
add_routes(app)
137-
app.on_event("startup")(sqlalchemy_init)
138-
app.on_event("shutdown")(db.dispose)
139125
init(app)
140-
return app
141126

127+
async with db.engine.begin() as conn:
128+
await conn.run_sync(Base.metadata.create_all)
129+
130+
yield
142131

143-
app = create_app()
132+
await db.dispose()
133+
134+
135+
app = FastAPI(
136+
title="FastAPI and SQLAlchemy",
137+
lifespan=lifespan,
138+
debug=True,
139+
default_response_class=JSONResponse,
140+
docs_url="/docs",
141+
openapi_url="/openapi.json",
142+
)
144143

145144

146145
if __name__ == "__main__":

docs/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
fastapi>0.100.0
1+
fastapi>=0.112.3
22
orjson>=3.2.1
33
pydantic>=2.6.0
44
sphinx

examples/api_for_sqlalchemy/asgi.py

Lines changed: 0 additions & 5 deletions
This file was deleted.

examples/api_for_sqlalchemy/main.py

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
"""
66

77
import sys
8+
from contextlib import asynccontextmanager
89
from pathlib import Path
910

1011
import uvicorn
1112
from fastapi import FastAPI
13+
from fastapi.responses import ORJSONResponse as JSONResponse
1214

1315
from examples.api_for_sqlalchemy.api.views_base import db
1416
from examples.api_for_sqlalchemy.models.base import Base
@@ -19,34 +21,34 @@
1921
sys.path.append(f"{CURRENT_DIR.parent.parent}")
2022

2123

22-
async def sqlalchemy_init() -> None:
24+
# noinspection PyUnusedLocal
25+
@asynccontextmanager
26+
async def lifespan(app: FastAPI):
27+
app.config = {"MAX_INCLUDE_DEPTH": 5}
28+
add_routes(app)
29+
init(app)
30+
2331
async with db.engine.begin() as conn:
2432
await conn.run_sync(Base.metadata.create_all)
2533

34+
yield
2635

27-
def create_app() -> FastAPI:
28-
"""
29-
Create app factory.
36+
await db.engine.dispose()
3037

31-
:return: app
32-
"""
33-
app = FastAPI(
34-
title="FastAPI and SQLAlchemy",
35-
debug=True,
36-
openapi_url="/openapi.json",
37-
docs_url="/docs",
38-
)
39-
app.config = {"MAX_INCLUDE_DEPTH": 5}
40-
add_routes(app)
41-
app.on_event("startup")(sqlalchemy_init)
42-
app.on_event("shutdown")(db.dispose)
43-
init(app)
44-
return app
38+
39+
app = FastAPI(
40+
title="FastAPI and SQLAlchemy",
41+
lifespan=lifespan,
42+
debug=True,
43+
default_response_class=JSONResponse,
44+
docs_url="/docs",
45+
openapi_url="/openapi.json",
46+
)
4547

4648

4749
if __name__ == "__main__":
4850
uvicorn.run(
49-
"asgi:app",
51+
"main:app",
5052
host="0.0.0.0",
5153
port=8082,
5254
reload=True,

examples/api_minimal.py

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import sys
2+
from contextlib import asynccontextmanager
23
from pathlib import Path
34
from typing import Any, ClassVar, Optional
45

56
import uvicorn
67
from fastapi import APIRouter, Depends, FastAPI
8+
from fastapi.responses import ORJSONResponse as JSONResponse
79
from pydantic import ConfigDict
810
from sqlalchemy.engine import make_url
911
from sqlalchemy.ext.asyncio import AsyncSession
@@ -44,11 +46,6 @@ class UserSchema(BaseModel):
4446
name: str
4547

4648

47-
async def sqlalchemy_init() -> None:
48-
async with db.engine.begin() as conn:
49-
await conn.run_sync(Base.metadata.create_all)
50-
51-
5249
class SessionDependency(BaseModel):
5350
model_config = ConfigDict(
5451
arbitrary_types_allowed=True,
@@ -105,26 +102,28 @@ def add_routes(app: FastAPI):
105102
return tags
106103

107104

108-
def create_app() -> FastAPI:
109-
"""
110-
Create app factory.
111-
112-
:return: app
113-
"""
114-
app = FastAPI(
115-
title="FastAPI and SQLAlchemy",
116-
debug=True,
117-
openapi_url="/openapi.json",
118-
docs_url="/docs",
119-
)
105+
# noinspection PyUnusedLocal
106+
@asynccontextmanager
107+
async def lifespan(app: FastAPI):
120108
add_routes(app)
121-
app.on_event("startup")(sqlalchemy_init)
122-
app.on_event("shutdown")(db.dispose)
123109
init(app)
124-
return app
125110

111+
async with db.engine.begin() as conn:
112+
await conn.run_sync(Base.metadata.create_all)
113+
114+
yield
126115

127-
app = create_app()
116+
await db.dispose()
117+
118+
119+
app = FastAPI(
120+
title="FastAPI and SQLAlchemy",
121+
lifespan=lifespan,
122+
debug=True,
123+
default_response_class=JSONResponse,
124+
docs_url="/docs",
125+
openapi_url="/openapi.json",
126+
)
128127

129128

130129
if __name__ == "__main__":

fastapi_jsonapi/utils/dependency_helper.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import inspect
2+
from contextlib import AsyncExitStack
23
from typing import Any, Awaitable, Callable, TypeVar, Union
34

45
from fastapi import Request
@@ -23,20 +24,23 @@ def __init__(self, request: Request):
2324
async def solve_dependencies_and_run(self, dependant: Dependant) -> ReturnType:
2425
body_data = await self.request.body() or None
2526
body = body_data and (await self.request.json())
26-
values, errors, *_ = await solve_dependencies(
27-
request=self.request,
28-
dependant=dependant,
29-
body=body,
30-
)
31-
32-
if errors:
33-
raise RequestValidationError(errors, body=body)
27+
async with AsyncExitStack() as async_exit_stack:
28+
solved_dependencies = await solve_dependencies(
29+
request=self.request,
30+
dependant=dependant,
31+
body=body,
32+
async_exit_stack=async_exit_stack,
33+
embed_body_fields=True,
34+
)
35+
36+
if solved_dependencies.errors:
37+
raise RequestValidationError(solved_dependencies.errors, body=body)
3438

3539
orig_func: Callable[..., FuncReturnType[Any]] = dependant.call # type: ignore
3640
if inspect.iscoroutinefunction(orig_func):
37-
function_call_result = await orig_func(**values)
41+
function_call_result = await orig_func(**solved_dependencies.values)
3842
else:
39-
function_call_result = orig_func(**values)
43+
function_call_result = orig_func(**solved_dependencies.values)
4044

4145
return function_call_result
4246

poetry.lock

Lines changed: 17 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)