Closed bjorntheart closed 6 days ago
What implements(IFace)
actually does under the hood is construct a new instance of an ImplementsMeta
metaclass, which verifies the the implementation of your interface at type construction time.
One of the downsides of using a metaclass for this is that a given class can only have one metaclass. The error you're seeing there is telling you that both Django and Interface are trying to define a metaclass for your type, and python can't use both of them.
I can think of two ways that interface could potentially try to solve this problem.
check_implements
function that could be applied as a decorator to classes that can't use implements
because they need another metaclass. The API for this would look something like:
@check_implements(IContentSource)
class InstagramContentSource(ContentSource):
...
This would work by doing the same checks that implements(IContentSource)
does currently. The downside of this API is that we wouldn't automatically apply interface checks to subclasses of InstagramContentSource
; you'd have to remember to manually decorate your subclasses.
implements
named something like implements_with_metaclass
, that takes an existing metaclass (in this case, it would be the metaclass of models.Model
), and dynamically generates a new metaclass that multiply-inherits from both ImplementsMeta
and the additional metaclass. Internally, this would look more or less like this with_metaclasses
function. The API for this would look something like:meta = type(ContentSource)
class InstagramContentSource(ContentSource,
implements_with_meta(meta, IContentSource)):
class Meta:
proxy = True
That's a lot more verbose, and the implementation would be more complex, but the upside of this would be that implementation checks would continue to propagate through subclasses.
Here is another solution for this issue. Python 3.6 introduced a new method __init_subclass__
(the docs are here).
It is called automatically whenever a subclass is created and it gets in as a parameter the newly created subclass. So it has all the necessary data for performing the checks. Using this method, there is no need for a metaclass any more and thus the issue of metaclass conflicts will not arise.
I am using this approach in a similar project and are very happy with this new Python feature :)
I get the following error when using
implements()
with a Django model.Interface
Django Model
Interface Implementation