To continue my last post about reusable Django apps, I’d like to talk about setuptools, show you a way to install Django by using setuptools and propose the reintroduction into Django’s code, even if setuptools have been dumped by the developers not long ago due to manageability reasons. Features like entry points, egg-files, the develop command, automatic versioning and tight integration with the Python Package Index make it worth installing.
Reusable Django apps
I started django-reusableapps considering the widespread use of “setuptools” in highly dynamic Python web projects like Turbogears and Pylons and the still unresolved problem of a smart “Django apps” API. Being the responsible Google Summer of Code student for this topic, I now decided (some months after my GSoC) to go with “setuptools”, dump my GSoC code and rethink the whole reason why Django apps should be pluggable: DRY.
It’s very easy to develop a custom Django app nowadays, but quite hard to quickly create meshed up projects, manage production sites and share the involved app with a larger audience in a semi-automatic manner like the Python Package Index.
The entry points for example, enable Python applications (such as Django or any Django-based app) to provide hooks to other applications in an automatic but unobstrusive, hence powerful fashion – a perfect choice for an Application API, from my point of view.
django-reusableapps resembles the plugin loading mechanism of Trac and should be considered a very temporary solution, until Django supports app-loading from eggs natively.
Using setuptools with Django aps
To start with a “setuptools”-based Django installation you need a new setup.py file to replace the version provided by Django (note this currently only works with a current subversion checkout). Please delete the symbolic link or the django directory you might have created in the site-packages directory by following Django’s installation instructions.
Then, add the following text to the “setup.cfg” file in the django source directory:
[egg_info]
tag_build = dev
tag_svn_revision = 1
Please have a look at Phillip’s comment, update your setup.py and setup.cfg files and reinstall Django.
This tells “setuptools” to generate version numbers like 0.97dev-r6706 during the installation, marking it as a developer snapshot which would be superseded by a 0.97 release, once it’s released.
You can then use virtually any command of setup.py: install, develop, bdist_egg, bdist_mpkg, bdist_wininst, bdist_rpm etc.
One bonus of the new setup.py file is the instant availablitiy of a Django command, the same utility known as django-admin.py and manage.py - just by declaring a “console_scripts” entry point in the “setup()” function:
entry_points = {
'console_scripts': 'django = django.core.management:execute_from_command_line',
},
Django’s SVN release and setuptools
There is an easy way with “setuptools” to keep track of the changes in Django’s svn tree. Use the develop command to avoid installing Django over and over again after each subversion update:
$ cd django_src
$ sudo python setup.py develop
...
Creating /Library/Python/2.5/site-packages/Django.egg-link (link to .)
Adding Django 0.97dev-r6704 to easy-install.pth file
Installed /Users/Jannis/Code/django_src
...
This tells “setuptools” to create a link in the “site-packages” directory to the current directory with the Django checkout. Updating Django with subversion is also easy:
$ cd django_src
$ svn update
U django/contrib/admin/templatetags/admin_list.py
U django/template/defaultfilters.py
U tests/regressiontests/templates/filters.py
Updated to revision 6708.
$ sudo python setup.py develop
...
Creating /Library/Python/2.5/site-packages/Django.egg-link (link to .)
Removing Django 0.97dev-r6704 from easy-install.pth file
Adding Django 0.97dev-r6706 to easy-install.pth file
Installed /Users/Jannis/Code/django_src
...
You need to run “python setup.py develop” after every update in order to keep the version string of Django in sync with the checkout. The already existing link to the “old” version (0.97dev-r6704) is then replaces by a link to the “new” version (0.97dev-r6706).
Django can be a dependency of a Django-based app
While you build a Django app, you might consider to include information about dependencies which are required to be installed by using setuptools’ install_requires keyword. Fortunately this also applies to Django developer snapshots, if originally installed with “setuptools” like I described above. Just add a keyword to “setup()” of your app’s “setup.py”:
install_requires = ['Django >= 0.97dev-r6706,==dev',],
This tells “setuptools” to install Django (if necessary) either by using a current subversion checkout or the newest release if available.
Django can have dependencies and extras
Django tries hard to have as less dependencies as possible by bundling some essential packages (e.g. simplejson) and informing users to install packages if required (e.g. Flup, PIL, PyYaml and all database adapters). These dependencies could also be defined in a setup.py file in the extras_require keyword:
extras_require = {
'MySQL': ["MySQLdb>=1.2.1p2"],
'SQLite': ["pysqlite>=2.0.3"],
'PostgreSQL': ["psycopg>=1.1.21"],
'PostgreSQL2': ["psycopg2>=2.0.5"],
'Oracle': ["cx_Oracle>=4.3.1"],
'PyYaml': ["PyYaml"],
}
Later, while installing Django, extras could be specified in square brackets — for example one or more extras:
$ easy_install Django[PostgreSQL]
$ easy_install Django[SQLite, PyYaml]
$ easy_install http://code.djangoproject.com/svn/django/trunk/
Now imagine the same functionality with Django-based apps. Think of installing a weblog and all its recommended dependencies by running:
$ easy_install ColtraneBlog[DefaultThemes]
Reusable Django-based apps in the (near?) future
I hereby propose the reintroduction of “setuptools” because of the great advantages while designing a future “Django Applications” API.
Why not add the app-loading mechanism of django-reusableapps to Django’s core. Specifically add it to django.db.models.loading or another module which looks for qualified apps, either depending on INSTALLED_APPS or the “django.apps” entry point.