On Fri, Apr 24, 2009 at 11:24 PM, Brian Matherly <brian@gramps-project.org> wrote:


> In Gramps we have two directories to load plugins from.
> This week
> I was playing with one of the standard plugins and I copied
> it
> from /usr/share/gramps to my ~/.gramps/plugins
> This does not work at all. It is because of how we load the
> plugins
> (see gen/plug/_manager.py), it is done by calling
> __import__. By
> giving the module name to __import__ we cannot explicitly
> force
> it to load from the specific directory. So, in my case, it
> loads
> the same module twice.

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.

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
> plugin?

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(".")[0]
    search = string.join(path, "/")
    oldpath = sys.path[:] # copy
    sys.path.insert(0, search)
    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:

    except AttributeError:
        raise ImportError, "your program needs an INIT() function"
    return userspace.INIT()

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.

> 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
> happen.)

I've never experienced this. How do you reproduce it?

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.



Crystal Reports &#45; New Free Runtime and 30 Day Trial
Check out the new simplified licensign option that enables unlimited
royalty&#45;free distribution of the report engine for externally facing
server and web deployment.
Gramps-devel mailing list