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 *
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.