0

The scenario is as follows:

I'm building a framework that will use external scripts as plugins. People will be able to create "adapters" to the scripts that conform to some interface. These adapters will be used either integrated into the framework (thus plugin registration is required) or "loosely" by a simple import.

In other words, the adapters are meant for script usage standardization.

I might be thinking too complex but the solution I'm currently on involves creating an abstract class defining the interface (and some utility methods). The module of the abstract class will be loaded only once and the framework will be loading a version with a self registering metaclass while the plugin itself will load a simpler version (The first one registering the abstract class wins).

This forces the plugin to have a file that defines the abstract class and therefore the "contract". I don't see a problem with that.

I'm not really going to have two different abstract classes but a single one in a module file that behaves differently depending from where it gets loaded (framework or plugin itself). But that shouldn't be relevant (I think).

So this is how the abstract class / metaclass looks like

#imp/plugin.py
import abc
class PluginAbstract(object):
    class __metaclass__(abc.ABCMeta):
        def __init__(self, name, bases, namespace):
            if name != 'PluginAbstract':
                pass #We can register the new "sub-class" if required
            return abc.ABCMeta.__init__(abc.ABCMeta, name, bases, namespace)

And the implementation would be something like:

#impl/MyPlugin.py
if 'plugin' not in locals():
    from impl import plugin

class MyPlugin(plugin.PluginAbstract):
    pass  #rest of the implementation....

So if the framework already registered PluginAbstract that one would be inherited, if not the one from the contract file impl/plugin.py will be used.

I don't want the adapters to require the framework to be installed, therefore the single file with the interface.

Does this strategy makes sense? Are there other options?

estani
  • 24,254
  • 2
  • 93
  • 76
  • Your approach sounds rather convoluted. What problem are you trying to solve? – Hans Then Nov 20 '12 at 15:48
  • @Hans indeed I'm afraid there might be a simpler solution. Basically as stated in the question: classes that can act as plug-in depending on the environment that creates them, but always assure some interface is fully implemented. – estani Nov 20 '12 at 16:10
  • That's not your problem, that is your solution ;-) – Hans Then Nov 21 '12 at 10:39
  • Even though it's obvious that the egg came before the chicken, we could get on this discussion forever :-) One step behind, I would say: "Building a framework system that's easy and self-describing so that implementation can be handled by non programmers" That's the task I have. – estani Dec 03 '12 at 17:46
  • How is it going with your task? To me it sounds like teaching non-programmers how to program, but you musn't teach them how to program. I think you have an unenviable task :-). – Hans Then Dec 05 '12 at 15:18
  • @Hans Worse than that, it's not about teaching it's about "enabling" since they don't want to _learn_, that's the task (we can't expect everyone to learn everything now, can we?). No, no one I know envy me :-) – estani Dec 05 '12 at 15:22

1 Answers1

1

In Python it is unusual to "enforce" an interface. We typically use duck-typing, which is the common-sense alternative to design by contract or other "bondage and discipline" approaches. Duck-typing means that if it walks like a duck, quacks like a duck, it must be duck.

In practice that means you simply do not enforce static typing. Instead you trust that with the right documentation the users of your code will simply do the right thing. This will typically simplify your code a lot. Also it will make you focus on the things that really matter, like checking for valid input data.

In people with a background in static typing, such as Java or C++, duck-typing usually causes some sort of existential angst, like looking in an abyss and finding that the abyss looks back. Let it go. There is no abyss, it is only in your mind.

Hans Then
  • 10,935
  • 3
  • 32
  • 51
  • I agree with most of it. The issue here is that I want to help developers with the interface so they know what should be done. Basically the abstract class is not defining any signature but how "quak" sounds like. But I accept that it's hard for me to accept duck-typing in a framework environment. I'll try. – estani Nov 21 '12 at 13:04
  • I am in a philosophical mood today, so I am reminded of Wittgenstein: "Tell us how high the Mont Blanc is. . . Tell us how a clarinet sounds", _Philosophical Investigations_, aphorism 78. (The point is that one can perfectly know how a clarinet sounds, but it is impossible to describe.) Joking aside, I think for your case the best way would not be to give a few examples of "quacks", so people can imitate. – Hans Then Nov 21 '12 at 14:26