On Fri, Apr 24, 2009 at 11:24 PM, Brian Matherly <firstname.lastname@example.org>
Personally, I don't think we should expect this to work. What if a user downloads a modified version of a supported report and places it in their "~/.gramps/plugins" directory? Which one should they expect to execute when they run the report? The behavior would be undefined. All plugins should have unique names.
> In Gramps we have two directories to load plugins from.
> This week
> I was playing with one of the standard plugins and I copied
> from /usr/share/gramps to my ~/.gramps/plugins
> This does not work at all. It is because of how we load the
> (see gen/plug/_manager.py), it is done by calling
> __import__. By
> giving the module name to __import__ we cannot explicitly
> it to load from the specific directory. So, in my case, it
> the same module twice.
Actually, this does work, but you are right that they have to have unique names. Currently, we provide a replacement for the system-installed plugin Check.py which the user can place in their .plugins directory, and it does load last, therefore overloading the system plugin. But, this doesn't work if it is just called "Check.py"... it has to be called something else.
We could probably handle this better by detecting that a module has the same name as one that has already been loaded and provide a useful error message to the user.
> To be honest, I don't know why we need to
> "import". Can't we
> just "exec" (or execfile) the contents of the
I think you could do something like that. I have worked on another system that has user-loadable files that does the following:
path = filename.split("/")
modulefile = path.pop() # module name
module = modulefile.split(".")
search = string.join(path, "/")
oldpath = sys.path[:] # copy
print "Attempting to import '%s'..." % module
exec("import " + module + " as userspace")
print "Loaded '%s'!" % userspace.__file__
sys.path = oldpath
That code will load it initially, or reload changed code. You can even call into that space to run an initializer:
raise ImportError, "your program needs an INIT() function"
If you use exec, the file will not be loaded as a module - it will only be executed. The contents in the plugin files are not just executable code - they are classes that need to be instantiated by the main program. This will only work if it is loaded as a module. Additionally, the "lib" plugins need to be imported by other plugins - which can only happen if they are modules.
I've never experienced this. How do you reproduce it?
> Then there is another problem, I think. Our plugin system
> has no way
> actually "reload" a plugin. It loads a plugin
> module again, but when
> you're developing you may change internals of a plugin.
> The already
> loaded plugin isn't unloaded, so the end result may be
> new and old
> features mixed. (Not sure about this, but I think it can
I think this can happen if you load a plugin, change the code to something else, and reload it. So, if you change everything (including the names) then the old one (I think) will still be around.