Extend py2exe to copy files to the zipfile where pkg_resources can load them
In creating a Windows PDF generation app for a client of mine, I ran into a limitation of py2exe which prevents resource loading with pkg_resources. The module attempts to load resources from py2exe’s library.zip. As the zipfile is reserved for compiled bytecode, there’s no option to copy files into it. You can copy files using py2exe’s data_files, but not into the zipfile, and package_data isn’t honoured. You can, however, extend the py2exe class, and that’s what I did.
The best entry point I could find was copy_extensions(). You can override that method to copy files into the build directory. You’ll want to create the necessary directories if they don’t already exist and then register the copied files for copying to dist. Here’s an example with images in a foo module’s media directory:
import os
import glob
from py2exe.build_exe import py2exe as build_exe
class MediaCollector(build_exe):
def copy_extensions(self, extensions):
super(MediaCollector, self).copy_extensions(extensions)
# Create the media subdir where the
# Python files are collected.
media = os.path.join('foo', 'media')
full = os.path.join(self.collect_dir, media)
if not os.path.exists(full):
self.mkpath(full)
# Copy the media files to the collection dir.
# Also add the copied file to the list of compiled
# files so it will be included in zipfile.
for f in glob.glob('foo/media/*'):
name = os.path.basename(f)
self.copy_file(f, os.path.join(full, name))
self.compiled_files.append(os.path.join(media, name))
Strictly speaking, resources are not compiled files but treating them as such was the only way I could find to force them to be included in the zipfile. To use this new collector, just specify it in your py2exe options:
py2exe_options = {
'cmdclass': {'py2exe': MediaCollector},
# [...] Other py2exe options here.
}
setup(
# [...] Other setup options here.
**py2exe_options
)
Posted on November 3rd, 2008 in python - 4 Comments »
Python bindings for ImageMagick’s MagickWand API
I’ve been spending some of my spare time recently putting together some Python bindings for ImageMagick’s MagickWand API. While most bindings I’ve seen just look like generated ctypes code from C header files, these bindings are more object-oriented, completely hiding the MagickWand methods. While this is still in the early stages, it’s workable in a way which I hope is expected and unsurprising:
from pythonmagick.image import Image
from pythonmagick.color import BLUE
i = Image('foo.jpg')
i.format = 'PNG'
i.rotate(45, BLUE)
i.save('flip.png')
The above reads in a JPEG image, reformats to PNG and rotates by 45 degrees with a background colour of blue. The image is then saved to a new file.
This may look a lot like PIL code, so why not use it instead of ImageMagick? ImageMagick covers a much wider range of image formats than PIL, and supports better algorithms for image resizing.
Check out the bindings by installing them with easy_install:
easy_install http://svn2.assembla.com/svn/pythonmagickwand/trunk/
On a side note, I’m quite impressed with Assembla, the site which I’m using for my SVN and Trac repo. It’s about as good as something I would deploy myself, but with much less hassle. Honestly, these days there’s less and less reason for me to spend hours setting up stuff myself, and that’s a great thing.
Posted on March 14th, 2008 in python - 10 Comments »