multiple inheritance of a dynamic list of classes?

Kent Johnson kent at kentsjohnson.com
Mon Feb 12 13:58:57 EST 2007


devicerandom at gmail.com wrote:
> Hi,
> 
> I am currently using the Cmd module for a mixed cli+gui application. I
> am starting to refactor my code and it would be highly desirable if
> many commands could be built as simple plugins.
> 
> My idea was:
> - Load a list of plugin names (i.e. from the config file, or from the
> plugins directory)
> - Import all plugins found dynamically:
> and this is easy, since I can do, for example:
> 
> PLUGIN_NAMES=['foo', 'bar']
> PLUGIN_MODULES = map(__import__, PLUGIN_NAMES)
> PLUGINS = [item.Commands for item in PLUGIN_MODULES]
> 
> Now, what I have to do is to define my command line class. This is
> usually done by subclassing cmd.Cmd:
> 
> class MyCli(cmd.Cmd):
>     ....
> 
> Now I want to add the commands defined in foo.Commands and
> bar.Commands. foo.Commands contains the functions corresponding to the
> new commands this way:
> #foo.py
> class Commands
> 
>      def do_this(self,args):
>           ...
>      def do_that(self,args):
>           ...
> 
> I've seen I can do it by explicitely import them and using multiple
> inheritance:
> 
> class MyCli(cmd.Cmd , foo.Commands, bar.Commands)
>       ....
> 
> so that do_this and do_that are now methods of a Cmd command line.
> 
> Now:
> - how can I instead have MyCli inherit from a dynamic list of modules?
> - is there a better way than using multiple inheritance to plug-in
> dynamically commands in a Cmd command line?

Your plugins could define plain functions with names starting with do_. 
Then you can create an empty subclass of cmd.Cmd and just plug in the 
imported commands:

In [1]: import cmd

In [3]: def do_this(self, arg): print 'This', arg
    ...:

In [4]: def do_that(self, arg): print 'That', arg
    ...:


In [8]: class MyCmd(cmd.Cmd): pass
    ...:

In [9]: MyCmd.do_this = do_this

In [10]: MyCmd.do_that = do_that

In [11]: c=MyCmd()

In [12]: c.cmdloop()
(Cmd) help

Undocumented commands:
======================
help  that  this

(Cmd) that
That

In your code you could use introspection to locate the plugin commands, 
something like
PLUGIN_MODULES = map(__import__, PLUGIN_NAMES)
for module in PLUGIN_MODULES:
   for name in dir(module):
     if name.startswith('do_'):
       setattr(MyCmd, name, getattr(module, name))

If the plugin module defines a list of commands then use that instead of 
dir(module).

Kent



More information about the Python-list mailing list