Frequently Asked Questions
Is this magic?
No, it’s metaclasses.
How is method checking handled differently from abc
?
Pluginlib checks methods when classes are declared, not when they are initialized.
How can I check if a class is a plugin?
It’s usually best to check inheritance against a specific parent.
issubclass(ChildPlugin, ParentPlugin)
For a more general case, use the Plugin
class.
issubclass(ChildPlugin, pluginlib.Plugin)
Why does creating a parent by subclassing another parent raise a warning?
A warning is raised when subclassing a plugin parent if it does not meet the
conditions of being a child plugin. Generally, it’s best to avoid this
situation completely by having both plugin parent classes inherit
from a common, non-plugin, class. If it’s unavoidable, set the
_skipload_
class attribute to False
to
avoid evaluating the class as a child plugin.
Why does calling super()
with no arguments in a parent class raise a TypeError
?
This is a side-effect of metaclasses. Take the following example:
>>> import pluginlib
>>>
>>> class Plugin():
... def __init__(self):
... pass
...
>>> @pluginlib.Parent('collector')
... class Collector(Plugin):
... def __init__(self):
... super().__init__()
...
>>> class Child(Collector):
... def __init__(self):
... super().__init__()
...
>>> Child()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
File "<stdin>", line 4, in __init__
TypeError: super(type, obj): obj must be an instance or subtype of type
We get this error when super()
is called with no arguments in Collector
because the
type of Collector
is PluginType
, not Plugin
.
>>> type(Collector)
<class 'pluginlib._parent.PluginType'>
super()
will use this type for the first argument if one is not supplied.
To work around this, we simply have to supply arguments to super()
.
As you can see, this is only required in parent classes.
>>> import pluginlib
>>>
>>> class Plugin():
... def __init__(self):
... pass
...
>>> @pluginlib.Parent('collector')
... class Collector(Plugin):
... def __init__(self):
... super(Collector, self).__init__()
...
>>> class Child(Collector):
... def __init__(self):
... super().__init__()
...
>>> Child()
<__main__.Child object at 0x7f5786e8d490>
Why am I getting TypeError: metaclass conflict
?
This happens when a parent class inherits from a class derived from a metaclass. This is not supported. Here is an example that illustrates the behavior.
import pluginlib
class Meta(type):
pass
class ClassFromMeta(metaclass=Meta):
pass
@pluginlib.Parent('widget')
class Widget(ClassFromMeta):
pass
This will raise 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
An alternative is to make an instance of the class an attribute of the parent class.
@pluginlib.Parent('widget')
class Widget():
def __init__(self):
self._widget = ClassFromMeta()
If desired, __getattr__()
can be used to provide pass-through access.
@pluginlib.Parent('widget')
class Widget():
def __init__(self):
self._widget = ClassFromMeta()
def __getattr__(self, attr):
return getattr(self._widget, attr)