Hi. I'm getting a type error when trying to generate a schema, using fastapi:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/uvicorn/protocols/http/httptools_impl.py", line 368, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "/usr/local/lib/python3.7/site-packages/starlette/applications.py", line 133, in __call__
await self.error_middleware(scope, receive, send)
File "/usr/local/lib/python3.7/site-packages/starlette/middleware/errors.py", line 122, in __call__
raise exc from None
File "/usr/local/lib/python3.7/site-packages/starlette/middleware/errors.py", line 100, in __call__
await self.app(scope, receive, _send)
File "/usr/local/lib/python3.7/site-packages/starlette/middleware/cors.py", line 76, in __call__
await self.app(scope, receive, send)
File "/usr/local/lib/python3.7/site-packages/starlette/exceptions.py", line 73, in __call__
raise exc from None
File "/usr/local/lib/python3.7/site-packages/starlette/exceptions.py", line 62, in __call__
await self.app(scope, receive, sender)
File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 585, in __call__
await route(scope, receive, send)
File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 207, in __call__
await self.app(scope, receive, send)
File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 40, in app
response = await func(request)
File "/usr/local/lib/python3.7/site-packages/fastapi/applications.py", line 90, in openapi
return JSONResponse(self.openapi())
File "/usr/local/lib/python3.7/site-packages/fastapi/applications.py", line 82, in openapi
openapi_prefix=self.openapi_prefix,
File "/usr/local/lib/python3.7/site-packages/fastapi/openapi/utils.py", line 248, in get_openapi
flat_models=flat_models, model_name_map=model_name_map
File "/usr/local/lib/python3.7/site-packages/fastapi/utils.py", line 42, in get_model_definitions
model, model_name_map=model_name_map, ref_prefix=REF_PREFIX
File "/usr/local/lib/python3.7/site-packages/pydantic/schema.py", line 511, in model_process_schema
model, by_alias=by_alias, model_name_map=model_name_map, ref_prefix=ref_prefix
File "/usr/local/lib/python3.7/site-packages/pydantic/schema.py", line 537, in model_type_schema
f, by_alias=by_alias, model_name_map=model_name_map, ref_prefix=ref_prefix
File "/usr/local/lib/python3.7/site-packages/pydantic/schema.py", line 274, in field_schema
ref_prefix=ref_prefix,
File "/usr/local/lib/python3.7/site-packages/pydantic/schema.py", line 486, in field_type_schema
ref_prefix=ref_prefix,
File "/usr/local/lib/python3.7/site-packages/pydantic/schema.py", line 687, in field_singleton_schema
if issubclass(field.type_, Enum):
TypeError: issubclass() arg 1 must be a class
For bugs/questions:
uname -a
Linux char-lang-dev 4.18.0-20-generic #21~18.04.1-Ubuntu SMP Wed May 8 08:43:37 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
import sys; print(sys.version): '3.7.1 (default, Oct 22 2018, 11:21:55) \n[GCC 8.2.0]'import pydantic; print(pydantic.VERSION): '3.7.1 (default, Oct 22 2018, 11:21:55) \n[GCC 8.2.0]'Where possible please include a self contained code snippet describing your
bug, question, or where applicable feature request:
from __future__ import annotations
from typing import Optional, List
from pydantic import BaseModel, UUID4
class CategoryCreationValidator(BaseModel):
name: str = ...
labels: List[str] = None
description: str = ...
parent_id: int = None
class CategorySelectionValidator(BaseModel):
name: str = ...
organization_id: str = ...
labels: Optional[str] = None
description: str = ...
parent_id: Optional[int] = None
class CategoryUpdateValidator(BaseModel):
name: Optional[str] = None
organization_id: Optional[str] = None
labels: Optional[List[str]] = None
description: Optional[str] = None
parent_id: Optional[int] = None
class ClusterValidator(BaseModel):
name: str = ...
category_id: Optional[str] = None
class CategoryModel(BaseModel):
id: int = ...
name: str = ...
description: str = ...
parent_id: int = None
children: List[CategoryModel]
#CategoryModel.update_forward_refs()
class ClusterModel(BaseModel):
id: UUID4 = ...
name: str = ...
parent_category_id: str = ...
queries: List[str] = ...
urls: List[str] = ...
class SuggestionValidator(BaseModel):
queries: List[str] = ...
urls: List[str] = ...
class QueryCreationValidator(BaseModel):
query_text: str = ...
cluster_id: UUID4 = ...
class QuerySelectionValidator(BaseModel):
cluster_id: UUID4 = ...
class UrlCreationValidator(BaseModel):
url: str = ...
cluster_id: UUID4 = ...
class UrlSelectionValidator(BaseModel):
cluster_id: UUID4 = ...
class CreateClusterInput(BaseModel):
name: str = ...
category_id: int = ...
class ClusterSelectionValidator(BaseModel):
category_name: str = ...
...
Thanks for reporting.
@tiangolo, maybe this is as simple as using lenient_issubclass instead of issubclass?
Coincidentally, I just came here to report an issue about the same error. In my case, it happens when you create a subclass of BaseModel which specifies a field of type Dict which does not specify mapping types, i.e.:
from pydantic import BaseModel
from typing import Dict, Any
class SubclassThatWorks(BaseModel):
asdf: int
fdsa: Dict[Any, Any]
class SubclassThatFails(BaseModel):
asdf: int
fdsa: Dict
with the error message being:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/validators.py in find_validators(type_, arbitrary_types_allowed)
385 try:
--> 386 if issubclass(type_, val_type):
387 return validators
TypeError: issubclass() arg 1 must be a class
The above exception was the direct cause of the following exception:
RuntimeError Traceback (most recent call last)
<ipython-input-5-c7b931439a60> in <module>
----> 1 class Subclass(BaseModel):
2 asdf: int
3 fdsa: Dict
/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/main.py in __new__(mcs, name, bases, namespace)
180 annotation=ann_type,
181 class_validators=vg.get_validators(ann_name),
--> 182 config=config,
183 )
184
/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/fields.py in infer(cls, name, value, annotation, class_validators, config)
136 required=required,
137 model_config=config,
--> 138 schema=schema,
139 )
140
/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/fields.py in __init__(self, name, type_, class_validators, model_config, default, required, alias, schema)
105 self.parse_json: bool = False
106 self.shape: Shape = Shape.SINGLETON
--> 107 self.prepare()
108
109 @classmethod
/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/fields.py in prepare(self)
170 self.allow_none = True
171
--> 172 self._populate_sub_fields()
173 self._populate_validators()
174
/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/fields.py in _populate_sub_fields(self)
221 assert issubclass(origin, Mapping)
222 self.key_field = self._create_sub_type(
--> 223 self.type_.__args__[0], 'key_' + self.name, for_keys=True # type: ignore
224 )
225 self.type_ = self.type_.__args__[1] # type: ignore
/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/fields.py in _create_sub_type(self, type_, name, for_keys)
235 name=name,
236 class_validators=None if for_keys else {k: v for k, v in self.class_validators.items() if not v.whole},
--> 237 model_config=self.model_config,
238 )
239
/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/fields.py in __init__(self, name, type_, class_validators, model_config, default, required, alias, schema)
105 self.parse_json: bool = False
106 self.shape: Shape = Shape.SINGLETON
--> 107 self.prepare()
108
109 @classmethod
/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/fields.py in prepare(self)
171
172 self._populate_sub_fields()
--> 173 self._populate_validators()
174
175 def _populate_sub_fields(self) -> None: # noqa: C901 (ignore complexity)
/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/fields.py in _populate_validators(self)
253 get_validators()
254 if get_validators
--> 255 else find_validators(self.type_, self.model_config.arbitrary_types_allowed)
256 ),
257 self.schema is not None and self.schema.const and constant_validator,
/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/validators.py in find_validators(type_, arbitrary_types_allowed)
387 return validators
388 except TypeError as e:
--> 389 raise RuntimeError(f'error checking inheritance of {type_!r} (type: {display_as_type(type_)})') from e
390
391 if arbitrary_types_allowed:
RuntimeError: error checking inheritance of ~KT (type: KT)
Not sure if this is because of a design decision that Dict types should have the mapping types explicitly defined or not, but the error message wasn't very clear as to what the problem was.
sounds like a different problem, could you create a new issue and perhaps even a fix?
In the meantime you should be able to use just dict instead of Dict which will have the same effect but shouldn't fail.
@samuelcolvin Do you know a workaround for my situation? The doc uses List and Optional in its examples, so I'm confused on what is causing this?
Ok, I can confirm the issue is the self-reference(children: List[CategoryModel]). Using just list or List[Any] avoids the error.
Thanks for tagging me @samuelcolvin .
I think this is then a duplicate of https://github.com/samuelcolvin/pydantic/issues/531
I still have to check/fix the JSON Schema generation when using forward refs.
For @zbarry problem, you can use dict or Dict[Any, Any]. But that's has a separate issue now.
Hit this one, I think, with very simple reproduction:
from typing import NewType
from pydantic import BaseModel
Age = NewType("Age", int)
class Person(BaseModel):
age: Age
Similar issue when generating schema in FastAPI.
So far using class Age(int): pass as a workaround.
Removing from __future__ import annotations fixed this issue for me. However, it would be cool if there would be support for this.
I don't have from __future__ import annotations in my code btw.
@haizaar This is fixed in the current version of pydantic (v0.28), with or without the __future__ import. Or at least, I am able to run the code snippet you provided above (in python 3.7.3) without any errors.
@DrPyser I'm not sure what was the problem, maybe it was fixed recently in Pydantic or in FastAPI.
But here's a slightly modified (without from __future__ import annotations) self-contained working app:
from typing import List, Optional
from pydantic import UUID4, BaseModel
from fastapi import FastAPI
class CategoryCreationValidator(BaseModel):
name: str = ...
labels: List[str] = None
description: str = ...
parent_id: int = None
class CategorySelectionValidator(BaseModel):
name: str = ...
organization_id: str = ...
labels: Optional[str] = None
description: str = ...
parent_id: Optional[int] = None
class CategoryUpdateValidator(BaseModel):
name: Optional[str] = None
organization_id: Optional[str] = None
labels: Optional[List[str]] = None
description: Optional[str] = None
parent_id: Optional[int] = None
class ClusterValidator(BaseModel):
name: str = ...
category_id: Optional[str] = None
class CategoryModel(BaseModel):
id: int = ...
name: str = ...
description: str = ...
parent_id: int = None
children: List["CategoryModel"]
CategoryModel.update_forward_refs()
class ClusterModel(BaseModel):
id: UUID4 = ...
name: str = ...
parent_category_id: str = ...
queries: List[str] = ...
urls: List[str] = ...
class SuggestionValidator(BaseModel):
queries: List[str] = ...
urls: List[str] = ...
class QueryCreationValidator(BaseModel):
query_text: str = ...
cluster_id: UUID4 = ...
class QuerySelectionValidator(BaseModel):
cluster_id: UUID4 = ...
class UrlCreationValidator(BaseModel):
url: str = ...
cluster_id: UUID4 = ...
class UrlSelectionValidator(BaseModel):
cluster_id: UUID4 = ...
class CreateClusterInput(BaseModel):
name: str = ...
category_id: int = ...
class ClusterSelectionValidator(BaseModel):
category_name: str = ...
app = FastAPI()
@app.post("/")
def main(
a: CategoryCreationValidator,
b: CategorySelectionValidator,
c: CategoryUpdateValidator,
d: ClusterValidator,
e: CategoryModel,
f: ClusterModel,
g: SuggestionValidator,
h: QueryCreationValidator,
i: QuerySelectionValidator,
j: UrlCreationValidator,
k: UrlSelectionValidator,
l: CreateClusterInput,
m: ClusterSelectionValidator,
):
return {"message": "Hello World"}
@tiangolo Yup, I think I've tested that everything now works after updating. Thanks everyone!
Great! I'll close this issue now then.
Having the same issue:
class ModelName(str, Enum):
repeated_sale = "repeated_sale"
main = "main"
dummy = "dummy"
class Inference(BaseModel):
price: int
model: ModelName
model_version: float
date: date
@app.get("/infer", response_model=Inference)
def infer(
params: dict,
model: ModelName,
v: Optional[float] = None,
date: Optional["date"] = None,
) -> Inference:
"""attempts to pull predictions from snowflake"""
result = app.model_registry.pull(model=model, v=v, date=date).predict(params)
return {"model": model, "v": v, **result}
results in:
File "/Users/philippk/anaconda3/envs/py37/lib/python3.7/site-packages/pydantic/schema.py", line 657, in field_singleton_schema
if issubclass(field_type, Enum):
TypeError: issubclass() arg 1 must be a class
python 3.7
pydantic==1.4.0
fastapi==0.49.0
@Casyfill I can't reproduce that error with fastapi 0.52.0 and python 3.8.
Can you try updating your fastapi version and seeing if you still have issues? If so, could you share a full self-contained example (including import statements etc.)?
Also, I'd recommend creating a new issue if there is still a bug as it likely differs enough from this issue to be worth tracking separately (and having the issue be open makes it easier to prioritize).
pydantic==1.4
fastapi==0.52.0
python 3.7.4
issue persist
Could you put together a self-contained reproducible example? If you can do that I'm happy to debug/submit a PR to fix it.
Could you put together a self-contained reproducible example? If you can do that I'm happy to debug/submit a PR to fix it.
Here: https://github.com/samuelcolvin/pydantic/issues/1298#issuecomment-607842409
Submit same trouble as @half2me
Most helpful comment
issue persist