Creating a dynamic ABC class based on a custom class

I am writing a plugin framework, and I want to write an interface decorator that converts a user class to an ABC class and replaces all methods with abstract methods. I can't get it to work, and I believe the problem is with the wrong mro, but I could be wrong.

I basically need to write:

 @interface class X: def test(self): pass x = X() # should fail, because test will be abstract method. 

wildcard methods with their abstract versions are simple (you need to abc.abstractmethod(func) over func and replace them with abc.abstractmethod(func) ), but I have a problem creating a dynamic type that will be an ABCmeta ABCmeta .

Now I have something like:

 from abc import ABCMeta class Interface(metaclass=ABCMeta): pass def interface(cls): newcls = type(cls.__name__, (Interface, cls), {}) # substitute all methods with abstract ones for name, func in inspect.getmembers(newcls, predicate=inspect.isfunction): setattr(newcls, name, abstractmethod(func)) return newcls 

but it does not work - Ican initializes class X without errors.

With the standard use of ABC in Python, we can write:

 class X(metaclass=ABCMeta): @abstractmethod def test(self): pass x = X() # it will fail 

How to create a dynamic type in Python3 that will behave as if it will have the metaclass ABCmeta and replace all functions with abstract ones?

+4
source share
1 answer

The trick is not to use setattr to reset each of the attributes, but instead pass these changed attributes to the type function as a dictionary:

 import inspect from abc import ABCMeta, abstractmethod class Interface(metaclass=ABCMeta): pass def interface(cls): attrs = {n: abstractmethod(f) for n, f in inspect.getmembers(cls, predicate=inspect.isfunction)} return type(cls.__name__, (Interface, cls), attrs) @interface class X(metaclass=ABCMeta): def test(self): pass x = X() # does fail: # Traceback (most recent call last): # File "test.py", line 19, in <module> # x = X() # should fail, because test will be abstract method. # TypeError: Can't instantiate abstract class X with abstract methods test 
+3
source

All Articles