First week at the new job, so I get do delve into currently-unkown code. And I get to reload my Django knowledge back into my head: it has been a year since I “did” my till-now-only-one django project.
And I got the job of introducing proper python packaging.
“Proper python packaging” for me means two things:
Every piece of software is a python package. So something with a
setup.py
that you can easy_install.
You manage your packages (in the projects/sites/whatever where you use them) with buildout. See for instance my managing dependencies article, especially the “isolation and version handling” part. That’s what buildout is good at: isolating your environment and grabbing just the right set of packages. (In the Django context, you’ll want to read Jacob Kaplan-Moss’s introduction).
In the Django context I’d add one more aspect to proper packaging:
Use packages a lot. Take your axe and chop up your code. Every django application should do just one thing and do it well, see James Bennett’s video on building reusable apps. So take your big monolithic project and chop it up in properly-sized packages.
Without packaging, you basically end up with one directory structure for your project. One main directory and the libraries (Django: applications) inside it. When you take those libraries and package them independently, you get several advantages:
If you use such a package in multiple projects, you can just do that. No need to copy-paste code. Reusability. Especially welcome when you keep your packages small, tight and focused.
A bit of formalization: the setup.py
contains the name of the package,
the version number, a short explanation.
One of the best things: specifying your dependencies! No more delving through a README to figure out what you need to install: it gets pulled in automatically.
A bit of documentation is easy. Perhaps a minor point, but a package has a
so-called long_description
. It is customary to take the readme,
changelog and possible other files and use those as long description.
Basically what you see on the pypi page of a project (but usable outside pypi of
course). For me, the “it is customary” is what helps.
Coming from a Zope and Plone background, I’m used to packages like zest.releaser, plone.app.something, z3c.anotherthing. Namespaces. Handy to keep zest.releaser out of collective.releaser’s hair. And to keep the generic openid package, plone’s openid package and your company’s openid package out of each others hair: you cannot call all of them “openid”.
We’ve got two main product lines at our company. And the first subdirectory
that I tackled was called “base”. So firstproductline.base
was born.
Raargh, Django doesn’t like namespaces. You get errors like “application firstproductline not found” when you expect it to load “firstproductline.base”. And from what I read, namespaces are actively discouraged in Django.
So what I settled with, after some googling for examples, was to name the
package firstproductline-base
(with a dash). The svn url is something
like https://.../firstproductline-base/trunk
. And inside that, the actual
code is in a firstproductline_base
directory (with an underscore).
firstproductline_base
is thus the module name that you import.
Well, I’ll have to see how well such a scheme holds up. Feedback welcome!
My name is Reinout van Rees and I program in Python, I live in the Netherlands, I cycle recumbent bikes and I have a model railway.
Most of my website content is in my weblog. You can keep up to date by subscribing to the automatic feeds (for instance with Google reader):