I'm running in circles, trying to find an elegant way to devise run-time
pluggable classes. It all goes around method resolution order, I guess.
(We already use various solutions, but the maintenance burden is high.)
We have a common module containing many basic classes, but for the sake
of simplicity here, I'll use only Element and Connection. Next to this
common module, we have many "plugin" modules importing it, and each
plugin also defines an Element class having common.Element among its
bases, and a Connection class having common.Connection among its bases.
Or nearly, as some plugins just do not override common classes that just
"fit" like they are. Plugins are really meant to enrich common classes.
The common module and all plugins are part of a single package, but
there are many other packages meant to provide work schemas, installed
separately and maintained by different programmers. Each work schema
package contains a core schema module which, after having imported the
already installed common module above, defines tons of classes having
either common.Element or common.Connection in their bases, relating
them, and a schema class reaching everything, for applications to use.
And finally, we have a flurry of applications. These applications
import at least one and typically a few work schemas, and for each,
specify _at run time_ which plugin to use (we use an URL-like syntax for
specifying plugins, work schemas, and other various parameters, these
URLs being read from configuration files while applications progress).
So, while all work schemas are programmed to use classes from the common
module, I would need at run time that all base classes be automatically
"promoted" into plugin classes, depending on plugin as selected at run
time, for being able to benefit from enriched methods. More or less,
it might mean something like the virtual substitution of common classes
by corresponding plugin classes whenever they appear in the class bases
of work schemas, and consequently virtually altering the MRO of such
classes so plugin methods override common methods, yet common methods
staying available for fall back, that is, if not overridden by plugins.
I feel ready to allow some complexity to the common module, but would
like the overall approach to be as clean and unobtrusive as possible
everywhere else, (that is, for plugins, work schemas, and applications).
It ought to be overall simple. So, zealots: no Zope nor Twisted! :-).
Another constraint is that the same work schema may be used at run-time
with two different plugins, and this means that ideally, a work schema
may not be altered (in a non-reentrant way) for a particular plugin.
This is a lesser constraint, because it occurs only occasionally, and I
presume that we could afford unusual stunts whenever necessary.
Fran?ois Pinard http://pinard.progiciels-bpi.ca