pydantic: Using custom metaclass raises metaclass conflict
Initial Checks
- I have searched GitHub for a duplicate issue and I’m sure this is something new
- I have searched Google & StackOverflow for a solution and couldn’t find anything
- I have read and followed the docs and still think this is a bug
- I am confident that the issue is with pydantic (not my code, or another library in the ecosystem like FastAPI or mypy)
Description
I am getting the following error:
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
Example Code
class MetaBase(type):
def __new__(mcs, name, bases, attrs):
cls = type.__new__(mcs, name, bases, attrs)
return cls
class User(BaseModel, metaclass= MetaBase):
id: int
Python, Pydantic & OS Version
pydantic version: 1.10.5
pydantic compiled: True
install path: /Users/renato/Library/Caches/pypoetry/virtualenvs/apispec-plugins-c17nWIz5-py3.9/lib/python3.9/site-packages/pydantic
python version: 3.9.12 (main, Apr 5 2022, 01:52:34) [Clang 12.0.0 ]
platform: macOS-13.0-arm64-arm-64bit
optional deps. installed: ['typing-extensions']
Affected Components
- Compatibility between releases
- Data validation/parsing
- Data serialization -
.model_dump()
and.model_dump_json()
- JSON Schema
- Dataclasses
- Model Config
- Field Types - adding or changing a particular data type
- Function validation decorator
- Generic Models
- Other Model behaviour -
model_construct()
, pickling, private attributes, ORM mode - Plugins and integration with other tools - mypy, FastAPI, python-devtools, Hypothesis, VS Code, PyCharm, etc.
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 15 (8 by maintainers)
@codectl one thing that may work for you for this instead of using a custom metaclass is to override
__init_subclass__
, which was specifically introduced for the purpose of reducing the need for metaclasses in certain common situations.So you could do something like:
(Note: it might be a good idea to use
cls.__qualname__
instead ofcls.__name__
, though__name__
may be good enough outside of pathological cases.)@codectl Also, if you are willing to inherit from
type(BaseModel)
, you might as well just importModelMetaclass
(which is exactly the same thing). It can be imported frompydantic.main
:To be clear, unless @samuelcolvin were to say otherwise (and given his message above I strongly suspect he would not), I would not treat
ModelMetaclass
as a stable/public API, and would strongly encourage you to avoid modifyingModelMetaclass
if you care about reducing the probability of your code breaking in future versions of pydantic. (@samuelcolvin I’m wondering if it might make sense to move theModelMetaclass
into an_internal
module for this reason. Maybe it’s already “too public” from v1…)The use case you’ve described of adding all subclasses to a registry is exactly the kind of thing
__init_subclass__
was created for, I do think that approach should work for you.@dmontagu’s solution looks great, I’d prefer not to make the metaclass public unless absolutely necessary.
ah, forgot to call
super().__new__
. Yes, you are right.Then let’s wait for @samuelcolvin.