On Tue, Feb 12, 2013 at 07:45:40PM +0000, Andrew Chadwick wrote:
> I've pushed a simple plugin framework to
> 
> https://gitorious.org/~achadwick/mypaint/achadwick-mypaint/commits/plugins
> 
> temporarily.

I pushed a "drip" test plugin on top of it:
https://gitorious.org/~maxy/mypaint/maxy-experimental/commits/plugin-drip

It's a big hack, and a lot of fun :-)
Video: http://maxy.homeip.net/misc/mypaint-drip-plugin.ogv

> Can I get some quick code review / opinions about whether this is the
> right approach?

I don't think there is anything wrong with the approach. We might have to
decide at some point whether we just want to make it easy to access
everything (and allow plugins to break or make mypaint-version-specific
workarounds), or whether we need a formal, well-defined distinction about
what's plugin API and what is considered internal API.

Since we're using Python, it would be very hard to enforce this distinction,
of course, but with some effort it could be done in a way that it's always
clear if the API being used was meant to be public.  Whether this effort is
worth it or not, I don't know.

Some detail comments:

* I don't like to force every plugin into its own directory.  The
  __init__.py convention is also one of the uglier Python quirks.  Maybe
  this could be optional?  A simple plugin could be just a single .py file
  in a special location.  Easier to install and handle for users, too.

* I don't see the point of making "get_plugin_description()" and
  "get_plugin_name()" functions.  It's not that any plugin will return
  something dynamic there.  I think module-global variables (like
  "plugin_name" and "plugin_description") would be the nicer solution.
  Xchat uses __module_name__, __module_version__, __module_description__
  for that. Blender parses the docstring of the module, it seems.

* As I've noticed with the "drip" plugin, there is some stuff that simply
  had no useful API yet.  Importing core MyPaint modules and hacking through
  the "app" instance hierarchy is the only way to do many interesting
  things at the moment.
 
> I figured based on what Maxy said that plugins would hook objects and
> callbacks into the running app via API calls, accessed via the app
> singleton,

But don't listen too much to a coder who doesn't commit much ;-)
The mantra is, "the one who does the work decides".

> Plugins should be fairly safe, and not bomb out the application due to
> ImportErrors during plugin activation and deactivation. This means
> that MyPaint itself doesn't need to depend on some random lib just to
> get extra functionality with an optional core plugin - the plugin
> activation will just be observed to fail to load.

ImportErrors should not irritate the user too much, I think. They should
realize that it's coming from the plug-in, and see the traceback, and send
it to the plugin developer.

But if I install a GTK timer that accesses members that don't exist any more
every 20ms, well.  The exception dialog can be moved away, but the menu may
not be accessible.  As long as user knows where to delete the offending
plugin, I think we should be fine.

> We could perhaps do with more feedback for the user, but the little dialog
> in the above branch seems to work for now.

I think the dialog does everything we need for now. I would only suggest to
add a link that opens a wiki page in a browser.  There we can link to
plugins and write instructions how to install them.  And a security warning,
if plugins can be uploaded to that page without review.

> One thing it might be nice to break out into our first set of core
> plugins would be a file format mini-API, for filehandling.py. Consider
> a layered .PSD loader done with PIL or something else:
> http://stackoverflow.com/questions/6759459/python-psd-layers has a
> quick HOWTO.

Hm... but I wouldn't display internal plugins in the plugin GUI. Nobody
wants to disable the JPEG loader.  But I like the idea of breaking this
functionality out with a clean, small and public API, so a new file-format
can be added without editing any of the list of filename extensions in
filehandling.py.

I don't know what the best approach is, how much direct access to python
objects is okay as an API.  What I fear a bit is that we need a lot of
do-nothing wrappers, methods that simply return one value.  I've heard many
praise about the new Blender plugin API (Python3), maybe that's a good place
to check for ideas.  But I have never looked at blender plugins, so far.

> Fancy extra tool subwindows, actions, overlays and modes would be nice
> to make pluggable eventually.

The ability to add a menu entry may be important too.

> Selection buffers and other things that look like layers might be
> tricky :) Still, we already have a couple of special layers; perhaps
> somebody who understands that bit of the code could make a selection
> tool for slicing and dicing.

IMO that's the core of MyPaint, a plugin that the user might install will
only need to access the pixel data of each layer.  It's okay if a completely
new layer type (like an infinite-tiling layer) requires modifying the core. 
I don't want to reinvent the GEGL API inside MyPaint.

> Is there anything else that's sort of optional that could be stripped
> out of the static code code and into a plugin module?

Some application developers are excited to claim that everything is a
plug-in in their application.  I think it's just a hip way of saying "yes,
we are doing software architecture".  Nothing wrong with consciously
designing the interface between software modules, of course.  There are
places in MyPaint where I just hacked through the hirarchy to make something
work (as in the test plugin).  But IMO not everything needs an external API,
sometimes internal refactoring is enough (you did some of that already :-)

-- 
Martin Renold

_______________________________________________
Mypaint-discuss mailing list
[email protected]
https://mail.gna.org/listinfo/mypaint-discuss

Reply via email to