Reputation: 53
I am expecting multiple data types as input to a function & want to take a specific action if its a pydantic model (pydantic model here means class StartReturnModel(BaseModel)
).
In case of model instance I can check it, using isinstance(model, StartReturnModel)
or isinstance(model, BaseModel)
to identify its a pydantic model instance.
Based on the below test program I can see that type(StartReturnModel)
returns as ModelMetaclass
. Can I use this to identify a pydantic model? or is there any better way to do it?
from pydantic.main import ModelMetaclass
from typing import Optional
class StartReturnModel(BaseModel):
result: bool
pid: Optional[int]
print(type(StartReturnModel))
print(f"is base model: {bool(isinstance(StartReturnModel, BaseModel))}")
print(f"is meta model: {bool(isinstance(StartReturnModel, ModelMetaclass))}")
res = StartReturnModel(result=True, pid=500045)
print(f"\n{type(res)}")
print(f"is start model(res): {bool(isinstance(res, StartReturnModel))}")
print(f"is base model(res): {bool(isinstance(res, BaseModel))}")
print(f"is meta model(res): {bool(isinstance(res, ModelMetaclass))}")
*****Output****
<class 'pydantic.main.ModelMetaclass'>
is base model: False
is meta model: True
<class '__main__.StartReturnModel'>
is start model(res): True
is base model(res): True
is meta model(res): False
Upvotes: 2
Views: 6770
Reputation: 18683
After you expanded a bit in the comment thread, it is clear that you have a fundamental gap in understanding of Python classes and metaclasses. The topics have been discussed at length on SO, so I'll just refer you to the search function for details, but the short answer to your particular question is this:
from pydantic import BaseModel
from pydantic.main import ModelMetaclass
class MyModel(BaseModel):
x: int
y: str
obj = MyModel(x=1, y="a")
cls = MyModel
print(f"{isinstance(obj, BaseModel)=}")
print(f"{isinstance(obj, MyModel)=}")
print(f"{issubclass(cls, BaseModel)=}")
print(f"{issubclass(cls, MyModel)=}")
print(f"{cls is MyModel=}")
print(f"{isinstance(cls, ModelMetaclass)=}") # just to illustrate
print(f"{isinstance(cls, type)=}") # just to illustrate
Output:
isinstance(obj, BaseModel)=True
isinstance(obj, MyModel)=True
issubclass(cls, BaseModel)=True
issubclass(cls, MyModel)=True
cls is MyModel=True
isinstance(cls, ModelMetaclass)=True
isinstance(cls, type)=True
You should avoid using pydantic.main.ModelMetaclass
because it is currently not (fully) exposed publicly as you correctly noted. And as you can see from the code above, there is simply no need to deal with it for you.
If you have a function that is supposed to handle both instances of a model class and specific classes that inherit from BaseModel
, that could look like this:
from typing import Union
from pydantic import BaseModel
def do_stuff(obj_or_cls: Union[BaseModel, type[BaseModel]]) -> None:
if isinstance(obj_or_cls, BaseModel):
print(f"Got an instance of the model `{obj_or_cls.__class__.__name__}`")
elif isinstance(obj_or_cls, type) and issubclass(obj_or_cls, BaseModel):
print(f"Got a model subclass called `{obj_or_cls.__name__}`")
else:
raise TypeError
class MyModel(BaseModel):
x: int
y: str
obj = MyModel(x=1, y="a")
cls = MyModel
do_stuff(obj)
do_stuff(cls)
Output:
Got an instance of the model `MyModel`
Got a model subclass called `MyModel`
Upvotes: 3
Reputation: 13349
Yes you can use it, but why not use isinstance
or issubclass
.
Upvotes: 2