Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pydantic V2 incompatibility: FieldInfo object does not have the attribute 'type_' #189

Open
cobycloud opened this issue Aug 6, 2023 · 4 comments

Comments

@cobycloud
Copy link

Issue Statement

Incompatible with pydantic v2. Unable to start containerized uvicorn due to AttributeError.
This occurs because pydantic's FieldInfo object does not have the attribute 'type_'
Please see: pydantic.fields.FieldInfo

This can be observed by adding the following line on startup:
print(Potato.__fields__)

The output follows:

{'thickness': FieldInfo(annotation=float, required=True), 'mass': FieldInfo(annotation=float, required=True), 'color': FieldInfo(annotation=str, required=True), 'type': FieldInfo(annotation=str, required=True), 'id': FieldInfo(annotation=int, required=True)}

Code

from sqlalchemy import Column, String, Float, Integer
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

from pydantic import BaseModel
from fastapi import FastAPI
from fastapi_crudrouter import SQLAlchemyCRUDRouter

app = FastAPI()
engine = create_engine(
    "sqlite:///./app.db",
    connect_args={"check_same_thread": False}
)

SessionLocal = sessionmaker(
    autocommit=False,
    autoflush=False,
    bind=engine
)

Base = declarative_base()


def get_db():
    session = SessionLocal()
    try:
        yield session
        session.commit()
    finally:
        session.close()


class PotatoCreate(BaseModel):
    thickness: float
    mass: float
    color: str
    type: str


class Potato(PotatoCreate):
    id: int

    class Config:
        orm_mode = True


class PotatoModel(Base):
    __tablename__ = 'potatoes'
    
    id = Column(Integer, primary_key=True, index=True)
    thickness = Column(Float)
    mass = Column(Float)
    color = Column(String)
    type = Column(String)


Base.metadata.create_all(bind=engine)

print(Potato.__fields__)

router = SQLAlchemyCRUDRouter(
    schema=Potato,
    create_schema=PotatoCreate,
    db_model=PotatoModel,
    db=get_db,
    prefix='potato'
)

app.include_router(router)

Error


>|  File "/app/src/main.py", line 63, in <module>
>|    router = SQLAlchemyCRUDRouter(
>| File "/usr/local/lib/python3.8/site-packages/fastapi_crudrouter/core/sqlalchemy.py", line 51, in __init__
>|     self._pk_type: type = _utils.get_pk_type(schema, self._pk)
>|   File "/usr/local/lib/python3.8/site-packages/fastapi_crudrouter/core/_utils.py", line 17, in get_pk_type
>|     return schema.__fields__[pk_field].type_
>| AttributeError: 'FieldInfo' object has no attribute 'type_'

@miko1ann
Copy link

miko1ann commented Oct 25, 2023

I got this issue. And my workaround is patch two methods:

patch_crudrouter

def get_pk_type_patch(schema: Type[PYDANTIC_SCHEMA], pk_field: str) -> Any:
	try:
		return schema.__fields__[pk_field].annotation
	except KeyError:
		return int

from pydantic import create_model
def schema_factory_patch(
	schema_cls: Type[T], pk_field_name: str = "id", name: str = "Create"
) -> Type[T]:
	"""
	Is used to create a CreateSchema which does not contain pk
	"""

	fields = {
		name: (f.annotation, ...)
		for name, f in schema_cls.__fields__.items()
		if name != pk_field_name
	}

	name = schema_cls.__name__ + name
	schema: Type[T] = create_model(__model_name=name, **fields)  # type: ignore
	return schema

Injection

import fastapi_crudrouter
fastapi_crudrouter.core._utils.get_pk_type = get_pk_type_patch
fastapi_crudrouter.core._utils.schema_factory = schema_factory_patch
fastapi_crudrouter.core._base.schema_factory = schema_factory_patch

@Laurel-rao
Copy link

it works

import fastapi_crudrouter
fastapi_crudrouter.core._utils.get_pk_type = get_pk_type_patch
fastapi_crudrouter.core._utils.schema_factory = schema_factory_patch
fastapi_crudrouter.core._base.schema_factory = schema_factory_patch

@Acutapugione
Copy link

It helps: #189 (comment)
Thanks a lot

@Acutapugione
Copy link

I took this part for my diploma)
from pydantic import create_model
def schema_factory_patch(
schema_cls: Type[T], pk_field_name: str = "id", name: str = "Create"
) -> Type[T]:
"""
Is used to create a CreateSchema which does not contain pk
"""

fields = {
	name: (f.annotation, ...)
	for name, f in schema_cls.__fields__.items()
	if name != pk_field_name
}

name = schema_cls.__name__ + name
schema: Type[T] = create_model(__model_name=name, **fields)  # type: ignore
return schema

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants