problem with hack using multiple inheritance for plugins

M

massimo s.

Before all, I'm not a professional programmer but just a biophysics
ph.d. student, so if something makes you scream of horror, please
forgive me...

Ok, this is not straightforward at all.
I am working on an application that uses plugins. Plugins are coded as
small classes that become inherited by a main class ( a cmd.Cmd
actually) in the following way:

(see also this thread:
http://groups.google.it/group/comp....read/thread/4d6da027bb9249bd/0f95c60add4ef5ad
)

---
.... def do_this(self, arg):
.... print "THIS", arg
....
.... def do_that(self, arg):
.... print "THAT", arg
....
plugins = [Foo, Bar]
def make_command_class(*bases):

.... return type(cmd.Cmd)("MyCli", bases + (cmd.Cmd,), {})
....
(Cmd) help

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

(Cmd) that one
THAT one
(Cmd)

-----------

And it works. Now I'm trying to do the same trick for another base
class, this time a WxPython frame.
Also in this case, "plugging" seem to work, but with an important
difference.

In the command line plugin API, I define a _plug_init() method that is
called in the main class __init__ . This for adding plugin-specific
initializiations.
That's what I do in the command line __init__:

for plugin_name in self.config['plugins']:
try:
plugin=__import__(plugin_name)
try:
print type(self)
eval('plugin.'+plugin_name
+'Commands._plug_init(self)')
except AttributeError:
pass
except ImportError:
pass

And it works flawlessly.
Problem is, the exact same code when done using the wxFrame as the
baseclass, doesn't work:

#make sure we execute _plug_init() for every command line
plugin we import
for plugin_name in config['plugins']:
try:
plugin=__import__(plugin_name)
try:
print type(self)
eval('plugin.'+plugin_name
+'Gui._plug_init(self)')
pass
except AttributeError:
pass
except ImportError:
pass

with the following error:

Traceback (most recent call last):
File "hooke.py", line 801, in <module>
main()
File "hooke.py", line 787, in main
main_frame = make_gui_class(*GUI_PLUGINS)(None, -1, ('Hooke
'+__version__))
File "hooke.py", line 308, in __init__
eval('plugin.'+plugin_name+'Gui._plug_init(self)')
File "<string>", line 1, in <module>
TypeError: unbound method _plug_init() must be called with
dummyguiplugGui instance as first argument (got MainWindowPlugged
instance instead)

The problem seems to be that if I call type(self) before doing the
eval('plugin... ) line:
- in the working case, I get type <type 'instance'>
- in the not working case, I get <class '__main__.MainWindowPlugged'>

At this point, it seems too much a deep object-oriented hell to be
able to dig it myself. Would you help me getting some cue on the
problem?

m.
 
M

massimo s.

At this point, it seems too much a deep object-oriented hell to be
able to dig it myself. Would you help me getting some cue on the
problem?

Update. Now I know that:
- every sane Python class should return <type 'instance'> after
type(self)
- when disabling the multiple-inheritance-hack, the situation comes
back to normal

What happens that makes the wxFrame class different from the cmd.Cmd
class?

m.
 
D

Duncan Booth

massimo s. said:
Now I know that:
- every sane Python class should return <type 'instance'> after
type(self)

Wrong. Only old style classes are 'instance' type, and you should never be
using an old style class unless you have a very good reason for it. Always
use 'object' (or another builtin type if appropriate) as a base class.
 
B

Bruno Desthuilliers

massimo s. a écrit :
Update. Now I know that:
- every sane Python class should return <type 'instance'> after
type(self)

Certainly not, unless you're using a pretty old Python version.
'instance' type means old-style classes - the legacy Python object
model, replaced some years ago with a *much* better one ('new-style'
classes). IIRC, this (now dying) legacy object model should disappear
with Py3K.
- when disabling the multiple-inheritance-hack, the situation comes
back to normal

I may be wrong here - I don't use old-style classes, and I avoid
multiple inheritance whenever I can - but I think this may has to do
with mixing old-style and new-style classes.
What happens that makes the wxFrame class different from the cmd.Cmd
class?

wxFrame is obviously a new-style class.

<side-note>
wrt/ this snippet:

for plugin_name in self.config['plugins']:
try:
plugin=__import__(plugin_name)
try:
print type(self)
eval('plugin.'+plugin_name+'Commands._plug_init(self)')
except AttributeError:
pass
except ImportError:
pass

You may want to try this instead:

for plugin_name in self.config['plugins']:
try:
plugin=__import__(plugin_name)
except ImportError:
# eventually do something like logging the error ?
continue
try:
cmdplug = getattr(plugin, plugin_name+'Commands')
cmdplug._plug_init(self)
except AttributeError:
# eventually do something like logging the error ?
continue

</side-note>
 
M

massimo s.

massimo s. a écrit :



Certainly not, unless you're using a pretty old Python version.
'instance' type means old-style classes - the legacy Python object
model, replaced some years ago with a *much* better one ('new-style'
classes). IIRC, this (now dying) legacy object model should disappear
with Py3K.

Oops. That's probably the problem.

I always followed the class syntax found in Section 9 of the tutorial,
and Python code I've seen uses the same syntax.

Where can I find the syntax of new-style classes?
I may be wrong here - I don't use old-style classes, and I avoid
multiple inheritance whenever I can - but I think this may has to do
with mixing old-style and new-style classes.

Probably it is.
<side-note>
wrt/ this snippet:

I'll try it ASAP. About logging the error, yes, I figured it out how
to do it some time ago but didn't have time (sigh).

Thanks,
m.
 
M

massimo s.

<side-note>
wrt/ this snippet:

for plugin_name in self.config['plugins']:
try:
plugin=__import__(plugin_name)
try:
print type(self)
eval('plugin.'+plugin_name+'Commands._plug_init(self)')
except AttributeError:
pass
except ImportError:
pass

You may want to try this instead:

for plugin_name in self.config['plugins']:
try:
plugin=__import__(plugin_name)
except ImportError:
# eventually do something like logging the error ?
continue
try:
cmdplug = getattr(plugin, plugin_name+'Commands')
cmdplug._plug_init(self)
except AttributeError:
# eventually do something like logging the error ?
continue

Tried, same error as before :(
 
M

massimo s.

wxFrame is obviously a new-style class.

I don't know if it's true, however. I tried that:
.... def __init__(self):
.... print type(self)
....<class '__main__.A'>

so in fact what I see has something to do with new style classes (if
subclassing 'object' is enough).

The new-style behaviour only appears when wxFrame is plugged with the
current hack.
That is:

- print type(self) in wxFrame alone returns <type 'instance'>
- print type(self) in the plugged (multiply inherited) wxFrame returns
< class '__main__.MainWindowPlugged'>

So the problem is that I acquire a new style behaviour somewhere!

I tried to let the plugin class be a new style class (subclassing
'object': again, I can't find a simple reference about it, I tried to
read www.python.org/doc/newstyle.html links but they are far too much
theoretical for my knowledge) and nothing seems to change at all.

m.
 
T

Thomas Jollans

massimo said:
Oops. That's probably the problem.

I always followed the class syntax found in Section 9 of the tutorial,
and Python code I've seen uses the same syntax.

Where can I find the syntax of new-style classes?

syntax is the same. A class is new-style if it inherits from at least
one new-style class and zero or more old-style classes. If you're not
really inheriting, inherit from object, which is a new-style class that
does nothing.

see
http://wiki.python.org/moin/NewClassVsClassicClass


Thomas



-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFGg7ANJpinDvQhQ0sRAvv6AJ9nPu33erLEigPjk9IX3UM0HzNxDgCfbkIe
20iYY1B72vpmGZres3RRDGY=
=8u/U
-----END PGP SIGNATURE-----
 
M

massimo s.

The new-style behaviour only appears when wxFrame is plugged with the
current hack.
That is:

- print type(self) in wxFrame alone returns <type 'instance'>
- print type(self) in the plugged (multiply inherited) wxFrame returns
< class '__main__.MainWindowPlugged'>

So the problem is that I acquire a new style behaviour somewhere!

Forget this one, it is wrong (Don't know how did I obtain it).
I rechecked and, yes, problem is that cmd.Cmd is old-style (and the
plugin hack works) while wxFrame is new style (and the plugin hack
works no more).

Again: using a new-style plugin class for multiple inheritance does
not work.
What can I do now?
 
P

Peter Otten

massimo said:
Again: using a new-style plugin class for multiple inheritance does
not work.

This statement is certainly too broad.

[earlier]
TypeError: unbound method _plug_init() must be called with
dummyguiplugGui instance as first argument (got MainWindowPlugged
instance instead)

So it looks like you failed to make dummyguiplugGui a base class of
MainWindowPlugged.
What can I do now?

Post a self-contained example.

Peter
 
M

massimo s.

massimo said:
Again: using a new-style plugin class for multiple inheritance does
not work.

This statement is certainly too broad.

[earlier]
TypeError: unbound method _plug_init() must be called with
dummyguiplugGui instance as first argument (got MainWindowPlugged
instance instead)

So it looks like you failed to make dummyguiplugGui a base class of
MainWindowPlugged.

Right (Checked with dir() -dummyguiplugGui methods do not appear ).
Post a self-contained example.

I'll try.

m.
 
B

Bruno Desthuilliers

massimo s. a écrit :
<side-note>
wrt/ this snippet:

for plugin_name in self.config['plugins']:
try:
plugin=__import__(plugin_name)
try:
print type(self)
eval('plugin.'+plugin_name+'Commands._plug_init(self)')
except AttributeError:
pass
except ImportError:
pass

You may want to try this instead:

for plugin_name in self.config['plugins']:
try:
plugin=__import__(plugin_name)
except ImportError:
# eventually do something like logging the error ?
continue
try:
cmdplug = getattr(plugin, plugin_name+'Commands')
cmdplug._plug_init(self)
except AttributeError:
# eventually do something like logging the error ?
continue

Tried, same error as before :(

Sorry, I failed to make clear that this was not suppoed to solve your
current problem - just to avoid using eval() when not necessary.
 
B

Bruno Desthuilliers

massimo s. a écrit :
Forget this one, it is wrong (Don't know how did I obtain it).
I rechecked and, yes, problem is that cmd.Cmd is old-style (and the
plugin hack works) while wxFrame is new style (and the plugin hack
works no more).

Again: using a new-style plugin class for multiple inheritance does
not work.

I doubt this is really the problem. Obviously Petter's brain works
better than mine.
 
M

massimo s.

Post a self-contained example.

Now I'm even more confused. The self-contained example is below... and
it works, using only old-style declarations.

#!/usr/bin/env python

import wx
import cmd

global CLI_PLUGINS
global GUI_PLUGINS

class MyCmd(cmd.Cmd):


def do_hello(self,args):
print 'hello'

class PlugCmd:

def _plug_init(self):
print 'init plugcmd'

def do_wow(self,args):
print 'wow'

#----------------------
class MyFrame(wx.Frame):

def __init__(self,parent,id,title):

ID_FRAME=-1

wx.Frame.__init__(self,parent,ID_FRAME,title,size=(800,600),style=wx.DEFAULT_FRAME_STYLE|
wx.NO_FULL_REPAINT_ON_RESIZE)

print dir(self)

for item in GUI_PLUGINS:
item._plug_init(self)

class PlugFrame:

def _plug_init(self):
print 'init plugframe'


CLI_PLUGINS=[PlugCmd]
GUI_PLUGINS=[PlugFrame]

def main():
app=wx.PySimpleApp()


def make_cli_class(*bases):
#return type(MainWindow)("MainWindowPlugged", bases +
(MainWindow,), {})
return type(MyCmd)("CliPlugged", bases + (MyCmd,), {})

def make_gui_class(*bases):
#return type(MainWindow)("MainWindowPlugged", bases +
(MainWindow,), {})
return type(MyFrame)("MainWindowPlugged", bases +
(MyFrame,), {})

my_cli=make_cli_class(*CLI_PLUGINS)()
main_frame = make_gui_class(*GUI_PLUGINS)(None, -1, ('Test'))
main_frame.Show()

#run one loop or the other when testing
#app.MainLoop()
my_cli.cmdloop()

main()
 
M

massimo s.

Uh, oh.

I think I found the bug, and it was a *really stupid bug*.
The list of GUI_PLUGINS was empty... so there was no plugin class that
was inherited.

I'm embarrassed to have wasted your time that way. However I learned a
lot about new-style classes and so on, so for me it was a learning
experience nonetheless.

Really sorry for wasting your time. I should use a debugger, I know. :
(

Thanks a lot for your patience,

M.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top