multiple inheritance of a dynamic list of classes?
Michele Simionato
michele.simionato at gmail.com
Mon Feb 12 13:56:15 EST 2007
On Feb 12, 4:48 pm, deviceran... at gmail.com wrote:
> - is there a better way than using multiple inheritance to plug-in
> dynamically commands in a Cmd command line?
I had to solve the same problem recently, and I decided to avoid
multiple
inheritance by using delegation. My idea was to make the Cmd class a
wrapper
around an object with 'do_' methods. I give you the code as it is,
without
much explanations: just run it and give "help" on the command line.
You can cut the part about the 'do_input' method which I needed in
order
to pass lists of strings to the inner object.
Hope you can find some useful trick for solving your problem.
Michele Simionato
import sys, cmd, traceback, inspect
try: # Python 2.5
from functools import update_wrapper
except ImportError:
def update_wrapper(wrapper,
wrapped,
assigned=('__module__', '__name__', '__doc__'),
updated=('__dict__',)):
for attr in assigned:
setattr(wrapper, attr, getattr(wrapped, attr))
for attr in updated:
getattr(wrapper, attr).update(getattr(wrapped, attr))
return wrapper
def makewrapper(meth):
if inspect.ismethod(meth):
func = meth.im_func
elif inspect.isfunction(meth):
func = meth
else:
raise TypeError('%r must be a regular function or method' %
meth)
return update_wrapper(lambda self, arg: meth(arg), func)
# dispatch the input dictionary to self.innerobj
def do_input(self, arg):
if arg.split(): # passed some argument of type 'name <args>'
try:
name, args = arg.split(' ', 1)
except ValueError:
print 'Wrong format: use the format input <name> <values>'
else:
self.inputdict[name] = args.split(self.inputsep)
else:
self.innerobj.input(self.inputdict)
self.inputdict = {}
def copy_interface_methods(innerobj, _CLI):
for attr in dir(innerobj):
if attr.startswith('do_'):
setattr(_CLI, attr, makewrapper(getattr(innerobj, attr)))
elif attr == 'input':
do_input.__doc__ = innerobj.input.__doc__
_CLI.do_input = do_input
class CLI(cmd.Cmd, object):
"""
Wraps an object with 'do_' methods with a command line interface.
"""
def __new__(cls, innerobj, completekey='tab', stdin=None,
stdout=None,
nonblocking=False):
class _CLI(cls):
prompt = 'CLI> '
if stdin is not None:
use_rawinput = False
copy_interface_methods(innerobj, _CLI)
return super(CLI, cls).__new__(
_CLI, innerobj, completekey, stdin, stdout)
def __init__(self, innerobj, completekey='tab', stdin=None,
stdout=None):
self.innerobj = innerobj
if hasattr(self, 'do_input'):
self.inputdict = {}
self.inputsep = '|'
cmd.Cmd.__init__(self, completekey, stdin, stdout)
def onecmd(self, line): # enable comments
if not line.startswith('#'):
return super(CLI, self).onecmd(line)
def emptyline(self): # does not repeat the last command
pass
def do_EOF(self, arg):
"Called when you enter CTRL-D, it stops the command loop"
return 1
if __name__ == '__main__': # test
class PrintableObj(object):
def __init__(self, x, y):
self.x = x
self.y = y
def do_print(self, arg):
"example"
print self.x, self.y
def input(self, dict_of_lists):
'just print the entered value'
vars(self).update(dict_of_lists)
print dict_of_lists
cli = CLI(PrintableObj([], []))
cli.cmdloop()
More information about the Python-list
mailing list