pydantic: TypeError: issubclass() arg 1 must be a class

Bug

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:

  • OS: 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
  • Python version import sys; print(sys.version): ‘3.7.1 (default, Oct 22 2018, 11:21:55) \n[GCC 8.2.0]’
  • Pydantic version 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 = ...

...

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 7
  • Comments: 37 (15 by maintainers)

Commits related to this issue

Most upvoted comments

I had the same issue, Python 3.9, Pydantic 1.9.2 and tested with 1.10.7 also.

Strangely I had to reinstall Pydantic to trigger the same problem locally. I noticed the reinstall also installed the newly released typing-extensions 4.6.0. Forcing typing-extensions==4.5.0 fixed the issue for me.

To reproduce, tested with Pydantic 1.9.2 and 1.10.7:

from typing import Literal
from pydantic import BaseModel


class MyModel(BaseModel):
    a: Literal["b", "c"]  # Problem with any Literal field

I hope this isn’t as widespread as it seems at first glance.

To fix: Force typing-extensions==4.5.0.

EDIT: This was already pointed out in https://github.com/pydantic/pydantic/issues/5821 but I’ll leave this up here as it looks like people are finding this thread first when googling the error message. Notably this seems to not be an issue with Python >=3.10.1.

i have suddenly started facing the same problem.

pydantic==1.8.2 python 3.9.10

class RuleStackProfiles(BaseModel, extra=Extra.forbid): 10:58:20 pydantic/main.py:299: in pydantic.main.ModelMetaclass.new 10:58:20 ??? 10:58:20 pydantic/fields.py:411: in pydantic.fields.ModelField.infer 10:58:20 ??? 10:58:20 pydantic/fields.py:342: in pydantic.fields.ModelField.init 10:58:20 ??? 10:58:20 pydantic/fields.py:451: in pydantic.fields.ModelField.prepare 10:58:20 ??? 10:58:20 pydantic/fields.py:545: in pydantic.fields.ModelField._type_analysis 10:58:20 ??? 10:58:20 pydantic/fields.py:550: in pydantic.fields.ModelField._type_analysis 10:58:20 ??? 10:58:20 /usr/local/lib/python3.9/typing.py:851: in subclasscheck 10:58:20 return issubclass(cls, self.origin) 10:58:20 E TypeError: issubclass() arg 1 must be a class

If you’re stuck on typing_extensions==4.6.0, you can also avoid the bug by importing Literal from typing_extensions instead of from typing.

# Triggers bug whenever `typing.Literal is not typing_extensions.Literal`
from typing import Literal

# Avoids bug
from typing_extensions import Literal

Downgrading the typing-extension version to 4.5.0 working perfectly ! Thank’s

Ok, I can confirm the issue is the self-reference(children: List[CategoryModel]). Using just list or List[Any] avoids the error.

pydantic==1.4
fastapi==0.52.0
python 3.7.4

issue persist

Removing from __future__ import annotations fixed this issue for me. However, it would be cool if there would be support for this.

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.

Thanks @Karimai.

Yeah, as @freywaid mentioned, update_forward_refs should solve the problem.

@Karimai update Pydantic to 1.10.10

@Kilo59 please try pydantic 1.10.8 that contains the fix

FWIW, also started happening here, with exactly same symptoms, and without any modifications to the code. We have Pydantic version pinned. Happens also on classes which don’t self-reference themselves.

Versions: Python 3.8, pydantic 1.10.5 (also tried 1.10.7 with same result).

@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.

@Karimai @freywaid could you please provide a minimal example that reproduce the error?

@hramezani I’m at pydantic 1.10.10 and I see this error… Adding: I added an MyModel.update_forward_refs() and this resolved the error.

Happens similarly here, started randomly happening this morning, sadly i cannot force typing-extensions version for our project layout at the moment

Version: Python 3.8, pydantic 1.10.7

Can also confirm we randomly started seeing the same issue in the past hour for what seems like no apparent reason. Code has been working for months and hasn’t been touched, but our builds randomly started failing, pointing to this error as the reason

pydantic==1.9.0 python 3.8.16

Great! I’ll close this issue now then.

@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"}

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.

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.