Include version information in your Python packages

Do include version information somewhere in your package. When I say package here, I'm referring to the Python concept - the thing which can be imported and manipulated programmatically. Here is a random assortment of real-life examples of what I mean:

You can see several conventions represented here. Some of them are better than others (in case you need a hint, gtk is doing something pretty nice; win32api is towards the other end of the spectrum). However, even the worst of these is providing the desired information. Compare this to:

This is a simple piece of information, and after you've actually picked a version of something and installed it, it's hardly ever of much interest. However, when it is of interest, you really want to be able to get it. You don't want to rely on the memory of some user about which version they installed when you're tracking down some poor interaction.

So. Do you maintain a Python package? Does it expose its version somehow? If not, fixit!

Aha! I was pretty sure there was some way to do this with pkg_resources, but my five minutes of investigation weren't sufficient to discover the correct API.

This does help a lot, but I stand by everything in my post, since it's still not necessarily the case that pkg_resources will be available (particularly on end-user machines and the like). Perhaps someday in the future though this will change.

All installers record the version information somewhere when a library is installed. Well, Distutils used to toss this information out, but now records it in an .egg-info file. Setuptools expanded up this to create a .egg-info directory so that a richer set of metadata could be stored. Then Tarek created PEP 376 to standardize and unify the metadata format, so that different installation tools could understand each others package installs, which provides an API for reading version information with:

The tool doing the downloading and installing of a package knows the version information before the library is ever imported. Versioning is metadata - it happens *external* to the library. Which also makes it easy to consistently generate lists of libraries and their versions for any given working set of libraries. And tools make it trivial to re-install that same set elsewhere (pip, buildout).

> All installers record the version information somewhere when a library is installed. Well, Distutils used to toss this information out, but now records it in an .egg-info file.

So, all installers record it, except those that don't? :)

As I mentioned in my reply to the previous anonymous comment, it will be a while before everyone is using these new installers, so there's still value in exposing this information directly on the package, rather than relying on the installation tools to be able to provide the information.

That said, the installers can only provide the information given to them by the authors. So even once they're widespread, it will still be important for authors to provide useful version information. For example, subunit "0.0.3" doesn't even include a setup.py.

> Do you maintain a Python package? Does it expose its version somehow? If not, fix it!

I'd like to fix it for my packages, yes. But there's no one obvious way to do it. I have the following criteria:

* Don't Repeat Yourself. The version information should have one canonical location in the source code, and be dynamically retrieved from there as needed.

* Simple maintenance of version string. Ideally the version string should be stored in a plain text file, called 'version' at the top of the VCS working tree for the project, that has the sole purpose of being the canonical current version string of the package.

* Ability to get other metadata from importing the package. Fields like copyright years, short/long description, and author info are all useful to expose via the package; so I want 'setup.py' to do 'import foo' to get them from there. That, of course, means that the package needs to be importable during the build process.

* Ability to get the version information while the package code is running. This is to provide the exported version attribute as you describe above.

I haven't yet come up with a good solution for all this. My existing attempts have been convoluted and flawed. I'd love to see some examples of good practice that meet all the above criteria.

As far as I can tell, no one knows how to do this in way that satisfies all your criteria. I asked on distutils-sig about a year ago and received no satisfactory answers.

But don't let better be the enemy of good. In Twisted, we have a _version.py that just defines the version, and import it into setup.py. That basically works, except for obscure (sorry zooko) setuptools uses. Doing something with a plain text file also seems somewhat straightforward and workable, if mildly unpleasant.

I suggest trying one of those. When you run into something you don't like, complain about it to someone maintaining the software responsible for the issue. :)

@baijum81: Thanks! Someone pointed that out before, but the comment got lost. It's nice to have that answer back up here. My very first comment (starting "Aha! I was pretty sure ...") above is a response to that original comment.

About Me

I'm a software professional with over 15 years industry experience ranging from startups (with as few as four people) to multinational banks. I've built network software, database software, user-facing software, backends, distributed systems, games, business engines, application servers, and more. I've lead teams and followed leaders (great and otherwise).

I'm also deeply interested and involved in environmental protection, clean food, and how agricultural systems impact human health. I live and work on a small farm with my family building first-hand experience with as many of the related systems as I can. You can read more about that side of my life on my other blog.

Supporting Open Source

I'm a prolific contributor to free and open source software projects, both on a volunteer and paid basis. I greatly appreciate donations to support the volunteer efforts. Feel free to let me know which software you're interested: it's always great to hear from users and a downside of a lot of this work is not getting to hear from the people who use the result very much.