Cast into custom type
Hi, I created a plugin mechanism for my application orientating at the mechanism described by Martin Alchy in http://martyalchin.com/2008/jan/10/simple-plugin-framework/ Now I'd like to call methods like `initialize(parent)' when the user chooses to use a plugin. As described in the blog mentioned above, I only have access to the general type called `PluginMount' (holding all the actual plugin instances). I tried to define "abstract" methods in PluginMount type raising a `NotImplementedError' but it seems, there is no late binding (similar to Java), so the right method would be called. Only the message TypeError: unbound method initialize() must be called with GeoCache instance as first argument (got PluginMount instance instead) `GeoCache' would be the plugin type. What is strange, is the fact, that when asking what instances are hold by PluginMount [] is listed. So it seems, that no late binding is applied when calling the `initialize(self, parent)' method. I'm quite new using Python, so this might be a quite basic question caused by some misunderstandings in general. Feel free to point me to appropriate site to solve my problem. Thanks in advance. Henning -- http://mail.python.org/mailman/listinfo/python-list
Re: Cast into custom type
Diez, Gabriel, Steven, thanks for your answers. I'll mainly give response in this posting, so I hope not repeating myself. On Tue, 03 Nov 2009 10:18:29 +, Steven D'Aprano wrote: > On Tue, 03 Nov 2009 09:41:37 +0000, Henning Bredel wrote: > >> Now I'd like to call methods like `initialize(parent)' when the user >> chooses to use a plugin. As described in the blog mentioned above, I >> only have access to the general type called `PluginMount' (holding all >> the actual plugin instances). >> >> I tried to define "abstract" methods in PluginMount type raising a >> `NotImplementedError' but it seems, there is no late binding (similar >> to Java), so the right method would be called. > > You need to give some actual examples of what you are trying to do, and > what you are expecting to happen. How is initialized() being called? Example: Assume a framework which offers common functionality for a plugin or a module a user can choose at the beginning. The framework does not know the concrete type of the plugin so it is possible to extend it by implementing a well known interface or abstract class. The framework reads the plugin directory, loads each module and creates buttons for each plugin with a callback method for initializing. To use common functionality of the framework, initialization method takes it as the parent parameter. I think this listing makes the most sense to you: # initialize all plugins self._plugin_modules = _load_plugins() # imp loading here LOGGER.debug(ActionProvider.plugins) # print what was loaded for plugin in ActionProvider.plugins: # create button for each app_button = gtk.Button(plugin.title) LOGGER.debug('Title of plugin: %s' % plugin.title) app_button.connect("clicked", plugin.initialize(plugin, self), None) self.set_canvas(app_button) app_button.show() >> TypeError: unbound method initialize() must be called with GeoCache >> instance as first argument (got PluginMount instance instead) > > Sounds like you are calling initialize on the class instead of on an > instance. I'm *guessing* that you are doing something like this: Oh, I didn't expext PluginMount to hold only classes :/. When calling `LOGGER.debug('Title of plugin: %s' % plugin.title)' the global (not class attribute) `title' attribute is printed out though. Probably some misinterpretation, too ..?! > (1) Change the for-loop to: > > for cls in plugin_manager.plugins: > cls().initialize(plugin_Manager) Good guess .. but calling it in that way another error says app_button.connect("clicked", plugin().initialize(self), None) TypeError: __init__() takes exactly 2 arguments (1 given) But also app_button.connect("clicked", plugin().initialize(plugin, self), None) TypeError: __init__() takes exactly 2 arguments (1 given) That is strange, because neither initialize() nor __init__ of the plugin is called .. only a logging statement shall print a msg. I hope it got a bit clearer what I am intended to do. Thanks for your help. Henning -- http://mail.python.org/mailman/listinfo/python-list
Re: Cast into custom type
Gabriel, thanks for your reply. See my comments below. On Tue, 03 Nov 2009 21:31:27 -0300, Gabriel Genellina wrote: > En Tue, 03 Nov 2009 09:07:01 -0300, Henning Bredel > escribió: >> On Tue, 03 Nov 2009 10:18:29 +, Steven D'Aprano wrote: > > Then forget about the code you read in that blog post, doesn't apply to > your use case. Well, but it shows how to mount plugins into the application without creating instances instantly. I only use one plugin/module at a time, so I'd like to avoid holding instances which aren't used. If the solution from the blogpost are meant completely different, I'd appreciate if you could point me on some concrete arguments why I shouldn't realize plugin mechanism in that way. BTW: I made it work now (was only a(nother) misinterpretation of how a callable should look like. > Try something like this: [...] > class PluginManager: > def __init__(self, plugin_directory): > self.plugin_directory = plugin_directory self.plugins = [] > > def load_all(self): > for fn in glob(os.path.join(self.plugin_directory, '*.py')): > namespace = {} > execfile(fn, namespace) > for name, obj in namespace.items(): > if (isinstance(obj, type) and > issubclass(obj, Plugin) and > obj is not Plugin): > # obj is a Plugin subclass > cls = obj > print cls.__name__, fn > print cls.__doc__ > print > plugin = cls(self) # call the constructor > self.plugins.append(plugin) [...] Yes, I get your point. But you instantiate all available plugins. I'd like to avoid that. Will a callable like `plugin().initialize' avoid that, or is an instance created immediately when passing this callable? > Plugin is the base class; all plugins must inherit from it. PluginMgr > scans the plugin directory, executes all modules it finds there (be > careful...), and looks for Plugin subclasses. Then creates an instance > of each Plugin subclass. Well, as far I understand it, I'd say that the ActionProvider class from the blogpost is the (nearly) the same as your Plugin base class. All new plugins has to implement the abstract ActionProvider class. The module loading/recognizing is done by my main application. So what would be the main difference here? Thanks for your advice Henning -- http://mail.python.org/mailman/listinfo/python-list