I have the following class definition that I would like to make dynamic:
class SQLModel_custom(SQLModel, registry=self.mapper_registry):
metadata = MetaData(schema=self.schema)
I've tried something like that:
type('SQLModel_custom', (SQLModel, self.mapper_registry), {'metadata': MetaData(schema=self.schema)})
But this give me 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
Maybe the issue comes from the fact I'm not using registry=
when defining parent classes in the dynamic version, but I don't see how I could acheive the same result.
Any advice? Thank you!
There are two problems here:
As the error message indicates, you are calling the wrong metaclass. SQLModel
itself is not constructed with type
, but some other subclass of type
. While the rules for determining the correct metaclass can be complicated, here it's simple: use the same one the (only) parent uses.
Only base classes are included in the 2nd argument to the metaclass; registry
is not a base class, but a keyword argument intended to be passed to the metaclass. (If you see self.mapper_registry
in the tuple, you should see a relevant error once you call the correct metaclass.)
The following should work:
mc = type(SQLModel)
SQLModel_custom = mc('SQLModel_custom',
(SQLModel,),
{'metadata': MetaData(schema=self.schema)},
registry=self.mapper_registry)
Point 1 is less of an issue than I previously thought; the error message comes from trying to use the types of SQLModel
and self.mapper_registry
to determine the correct metaclass. type
itself apparently can return an instance of the proper metaclass without you needing to call it explicitly. A simple example:
class MyMeta(type):
pass
class Foo(metaclass=MyMeta):
pass
Bar = type('Bar', (Foo,), {})
# The call to type figures out that the correct metaclass is
# type(Foo) == MyMeta, not type itself.
assert isinstance(Bar, MyMeta)