sanic-ext
sanic-ext copied to clipboard
[Bug] Can't use `pydantic>=2.0` model in OpenAPI definition
Minimal example:
from pydantic import BaseModel
from sanic import Sanic
from sanic.response import text
from sanic_ext import openapi
app = Sanic("MyHelloWorldApp")
class RequestSchema(BaseModel):
foo: str
@app.get("/")
@openapi.definition(
body=openapi.definitions.RequestBody({"application/json": RequestSchema}),
)
async def hello_world(request):
return text("Hello, world.")
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
This works as expected with pydantic==1.10.12
but after upgrading to pydantic==2.3.0
I get
/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py:333: PydanticDeprecatedSince20: The `schema` method is deprecated; use `model_json_schema` instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.3/migration/
extra = value.schema()["properties"]
Traceback (most recent call last):
File "/workspace/wsgi.py", line 17, in <module>
async def hello_world(request):
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/openapi.py", line 423, in inner
func = glbl["body"](**kwargs)(func)
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/openapi.py", line 238, in inner
OperationStore()[handler].body(body_content, **params)
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/builders.py", line 93, in body
self.requestBody = RequestBody.make(content, **kwargs)
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/definitions.py", line 175, in make
return RequestBody(MediaType.all(content), **kwargs)
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/definitions.py", line 111, in all
return {x: MediaType.make(v) for x, v in media_types.items()}
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/definitions.py", line 111, in <dictcomp>
return {x: MediaType.make(v) for x, v in media_types.items()}
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/definitions.py", line 103, in make
return MediaType(Schema.make(value))
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py", line 227, in make
return Object.make(value, **kwargs)
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py", line 367, in make
{
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py", line 368, in <dictcomp>
k: Schema.make(v, **extra.get(k, {}))
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py", line 205, in make
return Object.make(value, **kwargs)
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py", line 367, in make
{
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py", line 368, in <dictcomp>
k: Schema.make(v, **extra.get(k, {}))
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py", line 227, in make
return Object.make(value, **kwargs)
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py", line 367, in make
{
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py", line 368, in <dictcomp>
k: Schema.make(v, **extra.get(k, {}))
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py", line 142, in make
return Schema.make(filtered[0], **kwargs)
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py", line 227, in make
return Object.make(value, **kwargs)
File "/opt/python/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py", line 328, in make
if is_pydantic(value):
File "/opt/python/lib/python3.10/site-packages/sanic_ext/utils/typing.py", line 49, in is_pydantic
issubclass(model, BaseModel) or hasattr(model, "__pydantic_model__")
File "/opt/python/lib/python3.10/abc.py", line 123, in __subclasscheck__
return _abc_subclasscheck(cls, subclass)
TypeError: issubclass() arg 1 must be a class
Correct, they made some breaking changes in their api. 👎
If you're interested in helping out, would be happy for you to make a PR. 😎
@ahopkins Any instructions? I want to try it.
Sure thing. I want to get this in for release at the end of this month.