Yesterday I released an update on Pypi for a Django reusable app I wrote: django-geoportail. Actually, I released two updates because the first one wasn't fully operational and it makes me think all the previous releases weren't either. First lesson learned: check the packages you upload to pypi actually work.
So, I had to learn the hard way how to package a Django app. The biggest difference with a standard python package is that you may want to include non-python files, such as media files and templates. Let's have a look at a basic setup.py:
# -*- coding: utf-8 -*-
from distutils.core import setup
setup(
name='django-geoportail',
version='0.3.1',
author=u'Bruno ReniƩ',
author_email='bruno.renie.fr',
packages=['geoportal'],
url='http://bitbucket.org/bruno/django-geoportail',
license='BSD licence, see LICENCE.txt',
description='Add maps and photos from the French National Geographic' + \
' Institute to GeoDjango',
long_description=open('README.txt').read(),
zip_safe=False,
)
And here is the structure of what I want to package:
geoportal/ |-- admin.py |-- forms | |-- fields.py | |-- __init__.py | `-- widgets.py |-- __init__.py |-- models.py |-- templates | |-- geoportal | | |-- map.html | | `-- widget.html | `-- gis | `-- admin | |-- geoportal.html | `-- geoportal.js |-- templatetags | |-- geoportal_tags.py | `-- __init__.py |-- tests.py `-- utils.py
I was naively thinking that having packages=['geoportal'] in setup.py plus including the static files in a MANIFEST.in file would magically include everything. Well, the template files are included in the source distribution, but they are skipped at the time of the installation. Even worse, sub-packages are skipped as well, leaving me without the forms and the templatetags directories.
The solution for including sub-packages is to use find_packages:
from distutils.core import setup
from setuptools import find_packages
setup(
name='django-geoportail',
# ...
packages=find_packages(),
)
find_packages will look for every directory containing a __init__.py file and include it.
Next, the templates. Two things are needed to include them:
add include_package_data=True in the setup parameters
create a MANIFEST.in file to declare the files to include:
include AUTHORS CHANGES README INSTALL LICENCE recursive-include geoportal *.py *.html *.js include docs/Makefile recursive-include docs/source *
Here, I include all the HTML and javascript file under the geoportal directory, the standard authors / changes / readme files and the documentation. During installation, only the files in a python package will be copied to the site-packages. The docs and text files at the root level are just useful for people who manually download the tarball: one unzipped, it provides all the documentation and information about the package.
Finally, I like the zip_safe=False option. It prevents the package manager to install a python egg, instead you'll get a real directory with files in it. I find it very convenient for debugging, when some information can be found by looking at the code.
If you're a packaging expert and think I'm doing anything wrong, I'd like to read your thoughts!
UPDATE 2010-06-08: in the first version of this post, I explained that I didn't understood what the MANIFEST.in file was for. This is now clarified, include_package_data can only work if some data is included in the MANIFEST.in file.
Comments
#1 August 16, 2010 — Fabien
Thanks to you, it saved a lot of my time :)
#2 September 3, 2010 — Jens Hoffmann
Thanks a lot for this quick and good howto!
Add a comment
Comments are closed for this entry.