pythoninterfacepython-3.6zope.interface

Verify that an unknown module/object is obliged to a specific interface (python)


I'd like to check at runtime, for example, that a given object has methods foo() and bar().

My research system, built in python 3.6, is highly parameterized and can/should accept any kind of object as a replacement of its build in modules. This functionality is very useful because many different students who use this system can easily research different behavior without changing the source code of my system.

The problem is that if they built the module wrong, they might discover this only after their entire experiment is ended (might be hours).

I am looking for a way to check at a very early stage of the runtime that their input module matches a specific interface. Verifying it even before it was instantiated is even better (when the input is only the type, not the instance). For example some_interface.verify(MyClass).

Solutions

I have seen many solutions on the internet (such as this), but none of them is suitable:

  1. The most common solution (try/catch) will only fail during runtime and is not applicable in a multi-daemon system because it is hard to shut down when only one of the daemons fail.

  2. Checking isinstance() doesn't verify anything. It might be even worse because the developer might forget to implement a function and use base class implementation, which might not fit its current implementation.

  3. Using ABC (Abstract Base Classes) requires the developer to inherit from the base class. If she/he fail to do so, no warning or error will be issued when instantiating the class. On the other hand, if the developer did implement the interface but did not inherit from base, then issubclass() will return False.

  4. Using zope interfaces was my goto, but it has a few shortcomings:

    • It requires the developer to explicitly mention that it is implementing the interface. Failing to specify this will result in an error, although the actual implementation is correct.
    • It cannot verify a module before it was instantiated. The implementedBy() method will only check if the module declared it is implementing the interface, but to actually verify it, you should call verifyObject() on the actual instance.
    • It does not support the new typing feature that was added since python 3.5

EDIT: Apparently, zope also supports implicit implementation by calling verifyObject(YourInterface, obj, tentative=True) which does not force the developer to explicitly defining the class as an implementer of the interface.


Solution

  • To my mind, the problem is not a problem of tools. The main problem is that even if some interface is supported, no one can be sure the module really works. What would I do is creating a test for modules and running it when initializing plugins. The test should verify not just types and interfaces (isinstance, hasattr and so on are just tools for the task), but (if possible) minimal correctness of the module's functioning. E.g. it would be fine to perform some basic task that does not require much time to complete and verify the results. If a plugin fails during such a test task, then the plugin is not valid.