Merge pull request #97 from grillazz/96-migrate-to-pydantic-2

96 migrate to pydantic 2
This commit is contained in:
Jakub Miazek 2023-07-07 20:39:32 +02:00 committed by GitHub
commit d9e88d8ffc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 352 additions and 325 deletions

1
.env
View File

@ -6,6 +6,7 @@ SQL_TEST_DB=testdb
SQL_HOST=db
SQL_USER=user
SQL_PASS=secret
SQL_URL=postgresql+asyncpg://${SQL_USER}:${SQL_PASS}@${SQL_HOST}/${SQL_DB}
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30

View File

@ -13,7 +13,7 @@ jobs:
fail-fast: false
matrix:
python-version: [ "3.11" ]
poetry-version: [ "1.4.0" ]
poetry-version: [ "1.5.1" ]
env:
PYTHONDONTWRITEBYTECODE: 1
@ -23,6 +23,7 @@ jobs:
SQL_USER: app-user
POSTGRES_PASSWORD: secret
PGPASSWORD: secret
SQL_URL: postgresql+asyncpg://app-user:secret@localhost:5432/testdb
services:
sqldb:

View File

@ -7,7 +7,7 @@
![fastapi-sqlalchemy-asyncpg](/static/fsap_1.jpg)
Example of [FastAPI](https://fastapi.tiangolo.com/) integration supported by almighty [Pydantic](https://github.com/pydantic/pydantic)
Example of [FastAPI](https://fastapi.tiangolo.com/) integration supported by almighty [Pydantic 2.0](https://github.com/pydantic/pydantic)
with [SQLAlchemy ORM](https://www.sqlalchemy.org/) and PostgreSQL
connected via fastest Database Client Library for python/asyncio [asyncpg](https://github.com/MagicStack/asyncpg).
@ -81,6 +81,7 @@ Hope you enjoy it.
- 14 FEB 2023 bump project to Python 3.11
- 10 APR 2023 implement logging with rich
- 28 APR 2023 Rainbow logs with rich :rainbow:
- 7 JUL 2023 migrate to pydantic 2.0
### Local development with poetry

View File

@ -36,7 +36,7 @@ async def update_nonsense(
db_session: AsyncSession = Depends(get_db),
):
nonsense = await Nonsense.find(db_session, name)
await nonsense.update(db_session, **payload.dict())
await nonsense.update(db_session, **payload.model_dump())
return nonsense
@ -45,6 +45,6 @@ async def merge_nonsense(
payload: NonsenseSchema,
db_session: AsyncSession = Depends(get_db),
):
nonsense = Nonsense(**payload.dict())
nonsense = Nonsense(**payload.model_dump())
await nonsense.save_or_update(db_session)
return nonsense

View File

@ -1,7 +1,6 @@
from typing import Annotated
from fastapi import APIRouter, Depends, Query
from pydantic import Required
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
@ -14,7 +13,7 @@ router = APIRouter(prefix="/v1/shakespeare")
"/",
)
async def find_paragraph(
character: Annotated[str, Query(description="Character name")] = Required,
character: Annotated[str, Query(description="Character name")],
db_session: AsyncSession = Depends(get_db),
):
return await Paragraph.find(db_session=db_session, character=character)

View File

@ -54,5 +54,5 @@ async def update_stuff(
db_session: AsyncSession = Depends(get_db),
):
stuff = await Stuff.find(db_session, name)
await stuff.update(db_session, **payload.dict())
await stuff.update(db_session, **payload.model_dump())
return stuff

View File

@ -1,18 +1,12 @@
import os
from functools import lru_cache
from pydantic import BaseSettings, PostgresDsn
from pydantic import PostgresDsn
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
asyncpg_url: PostgresDsn = PostgresDsn.build(
scheme="postgresql+asyncpg",
user=os.getenv("SQL_USER"),
password=os.getenv("POSTGRES_PASSWORD"),
host=os.getenv("SQL_HOST"),
port="5432",
path=f"/{os.getenv('SQL_DB') or ''}",
)
asyncpg_url: PostgresDsn = os.getenv("SQL_URL")
@lru_cache

View File

@ -10,7 +10,7 @@ global_settings = config.get_settings()
logger = AppLogger.__call__().get_logger()
engine = create_async_engine(
global_settings.asyncpg_url,
global_settings.asyncpg_url.unicode_string(),
future=True,
echo=True,
)

View File

@ -14,8 +14,8 @@ class NonsenseSchema(BaseModel):
)
class Config:
orm_mode = True
schema_extra = {
from_attributes = True
json_schema_extra = {
"example": {
"name": "Name for Some Nonsense",
"description": "Some Nonsense Description",
@ -38,8 +38,8 @@ class NonsenseResponse(BaseModel):
)
class Config:
orm_mode = True
schema_extra = {
from_attributes = True
json_schema_extra = {
"example": {
"config_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "Name for Some Nonsense",

View File

@ -14,8 +14,8 @@ class StuffSchema(BaseModel):
)
class Config:
orm_mode = True
schema_extra = {
from_attributes = True
json_schema_extra = {
"example": {
"name": "Name for Some Stuff",
"description": "Some Stuff Description",
@ -38,8 +38,8 @@ class StuffResponse(BaseModel):
)
class Config:
orm_mode = True
schema_extra = {
from_attributes = True
json_schema_extra = {
"example": {
"config_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "Name for Some Stuff",

628
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[tool.poetry]
name = "fastapi-sqlalchemy-asyncpg"
version = "0.0.4"
version = "0.0.5"
description = ""
authors = ["Jakub Miazek <the@grillazz.com>"]
packages = []
@ -26,6 +26,7 @@ ipython = "*"
pytest-cov = "*"
pytest-asyncio = "*"
ruff = "*"
pydantic-settings = "^2.0.1"
[tool.poetry.group.dev.dependencies]
tryceratops = "^1.1.0"