en
Aug 2010
Mo Tu We Th Fr Sa Su
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31

Last Played

» The Beatles – Hey Jude
» The Beatles – Lady Madonna
» The Beatles – Hello Goodbye
» The Beatles – All You Need Is Love
» The Beatles – Penny Lane
» The Beatles – Eleanor Rigby
» The Beatles – Yellow Submarine
» The Beatles – Paperback Writer
» The Beatles – We Can Work It Out
» The Beatles – Day Tripper

Python plugins continued : resources management

Plugin developers often want to supply data files (web templates, images, etc) with their package, let's see how to do this using setuptools resource management system.

If there are still some lazy people reading this, get an updated version of the code. So, on your plugin's setup.py, add a package_data argument to setup():

setup(
  # ...
  package_data = {
     'foo_plugin': ['data/*.tmpl'],
  },
  # ...
)

Create a data directory in foo's plugin directory, and create some files:

$ mkdir plugins/foo/data
$ echo "Hello this is foo\n" > plugins/foo/data/foobar.tmpl

Don't forget to re-run python setup.py develop in the foo plugin directory. The next step is to fetch those data files via our plugin_loader:

for entrypoint in pkg_resources.iter_entry_points("my.plugins"):
    plugin_class = entrypoint.load()
    print 'Plugin %s: %s' % (repr(entrypoint.name), repr(plugin_class))

    requirement = pkg_resources.Requirement.parse(plugin_class.__name__)
    tmpl = 'data/foobar.tmpl'
      
    data_contents = pkg_resources.resource_listdir(requirement, 'data')
    print 'data contents : %s' % repr(data_contents)

    # let's find and read a data file in our plugin
    if pkg_resources.resource_exists(requirement, tmpl):    
        foo_bar = pkg_resources.resource_string(requirement, tmpl)

        # contents of foobar.tmpl as a string
        print 'tmpl contents : %s' % repr(foo_bar)
    else:
        print '%s not found :-(' % repr(tmpl)

Given the plugin's name, we tell pkg_resources to find the plugin's resources given their relative location from the plugin point of view. That's fun, no ? You don't need to care about a global variable storing the full path of the data files, or whatever crappy monkey-code !

I promise, next time i'll start playing with plugin API management, probably with interfaces :-)

by Philippe Normand on Thu Feb 2 19:09:08 2006 (Viewed: 6151 / 2 comments )
  |   RSS  |   RSS2  |   Atom  |   Source  |   Edit

#.   Phillip J. Eby on Thu Feb 2 23:15:59 2006

Quick tip: if you use entrypoint.module_name as the first argument to the various resource_foo() APIs, your code won't be dependent on the plugin class' name being the same as the plugin egg's project name, and you won't have to mess around with Requirement.parse() for the use cases shown. Instead, it will always look for resources relative to the package containing the plugin:

for entrypoint in pkg_resources.iter_entry_points("my.plugins"):
   plugin_class = entrypoint.load()
   print 'Plugin %s: %s' % (repr(entrypoint.name), repr(plugin_class))

   tmpl = 'data/foobar.tmpl'
     
   data_contents = pkg_resources.resource_listdir(entrypoint.module_name, 'data')
   print 'data contents : %s' % repr(data_contents)

   # let's find and read a data file in our plugin
   if pkg_resources.resource_exists(entrypoint.module_name, tmpl):    
       foo_bar = pkg_resources.resource_string(entrypoint.module_name, tmpl)

       # contents of foobar.tmpl as a string
       print 'tmpl contents : %s' % repr(foo_bar)
   else:
       print '%s not found :-(' % repr(tmpl)

Also, instead of bundling data with packages, you can bundle it in the egg-info directories and get access to it with entrypoint.dist.get_metadata() and the like. But that might be out of scope for this tutorial.

Nice series, by the way, keep up the good work!

#.   Phil on Fri Feb 3 09:52:35 2006

Thanks for the tip Phillip ! The code looks better using this ;) I'll continue to play with setuptools, it's really helpful and a great step for Python packages distribution :)

Comments not allowed anymore on this post