Hello,
I just started using yapsy and it is just as you describe it - exactly what you need and nothing more :)
What I have done in my application is creating a custom subclass Plugin, that inherits from IPlugin. It serves as a base class for all my plugins. I use PluginFileAnalyzerMathingRegex (it would be very nice to get the typo here fixed, too ;) ) to locate my plugins. The weird behaviour I was observing is that Plugins that have a class name that comes before Plugin in the alphabet, work just fine. Plugins that come after Plugin in the alphabet (like for example ZPlugin), don't work, they are simply not initialized correctly.
The error occurs in loadPlugins(), actually in line 531, where this loop is called:
for element, element_name in ((getattr(candidate_module,name),name) for name in dir(candidate_module)):
In case of a working Plugin whose name comes earlier than Plugin in the alphabet, the created tuple of tuples that is gone through starts like this:
(((<class 'yapsy_loaded_plugin_jplugin_0.JPlugin'>, 'JPlugin'), (<class 'plugin.Plugin'>, 'Plugin'), ...))
In case of a not working Plugin name (that comes after Plugin in the alphabet), the beginning of the same list of tuples looks like this:
(((<class 'plugin.Plugin'>, 'Plugin'), (<class 'yapsy_loaded_plugin_tplugin_0.TPlugin'>, 'TPlugin'), ...))
As I said earlier, Plugin inherits from IPlugin, so that is_correct_subclass gets true for Plugin already. This makes my code break though, as the plugin is only correctly loaded if the yapsy_loaded_plugin-class is called.
In my plugin-class, this for loop loops through a loong long list of possible members before the actual correct class-member starting with yapsy_loaded_plugin is called. I think this problem might occur in other implementations as well, where a self-defined superclass for the plugins comes into play.
In line 540 it is made sure that not only the plugin inherts from the same superclass, but also that the element is not IPlugin. In this case I would need another exclusion for Plugin. But of course that would be a solution that only fixes my case, which I don't want because it would be better to fix the problem itself.
Therefore my suggestion to fix this issue in general (and not only for me) is to replace line 531 with sth like the following:
elements = ((getattr(candidate_module,name),name) for name in dir(candidate_module))
elements = (x for x in elements if isinstance(x[0], type) and x[0].__module__.startswith("yapsy_loaded_plugin_"))
for element, element_name in elements:
This works for my code at least. What this does is that the original tuple of tuples is filtered, and only entries that are actually class-types and that are starting with the plugin-prefix yapsy_loaded_plugin actually are handled in the loop. I'm not sure but this could even be more efficient than the old code, because in my case the code checked the whole loop for a lot of members like dict, name etc. that no way would be a valid plugin anyway. It also removes the need for the check in line 540 that makes sure that IPlugin is not tried to be loaded as a valid plugin.
If you have a better idea on how to fix this that even better fits in this code, feel free to go ahead and do sth. else. I just made sure to understand enough of the code to fix the problem for me.
This has actually taken me a lot of time to discover - first why some of my plugins didn't work and some did. Then that only plugins with a name late in the alphabet didn't work, and then in the end where in the sourcecode this is happening.
Feel free to contact me if you'd like to discuss this further.
Greetings fjellvannet
Anonymous