Remember I mentioned a Python library has version.py which essentially only contains one line like VERSION = 'x.y.z'?

After I posted it, I mailed the author and asked him about it. He told me it’s a common practice for packaging, you can see the get_version:


def get_version():
basedir = os.path.dirname(__file__)
with open(os.path.join(basedir, 'times/version.py')) as f:
VERSION = None
exec(f.read())
return VERSION
raise RuntimeError('No version info found.')

As you can see without thinking this is for package installation, you may improve it as:


def get_version():
from times import __version__
return __version__

I would do it, it’s clear and gets straight into the point.

However, the author received a bug report, which reminded him of why he made version information in separate file. The reason of doing so became apparent when this bug report came in.

The dependency is the issue. When you use pip or easy_install, they will handle the dependency for the user. Whatever dependency the library requires, as long as the packager list them all, they will be also be installed with the library.

If you don’t literally put the version number in setup script and you tries to extract the version information of the library by using direct import, it basically evaluates the library as if it’s being used and that becomes an issue if some depended libraries are not installed and are being used by the library.

In the case of bug report, pytz exposed the issue, you can also see the reporter tried to patch it by catching the ImportError exception. The handling wasn’t good, because the exception was bypass. It should end the program with error code, instead, because not everyone like using pip to install package. I don’t think it’s a good patch even as a workaround.

The library author reverted back to previous method of getting version information. They are actually some other ways to get the version or even others.

You can use regular expression to extract or to get variables like __foo_bar__ = 'blah blah blah'. If you have many libraries, your setup.py can be more generalized, some package metadata can be store in __init__.py. You can also use path trick and do a normal import or manual import.

I don’t think there is a strict rule to bridge between setup script and library for package metadata. I would like to think it’s safe to say, your library should not know about the setup script and act upon it.

I want to point out why focus on version, it’s because it’s probably the only one gets updated every time for a new release. You don’t change authors, website, etc. very often. Being given own place can be a good way for release. You can then update it and add a log entry to Changelog, update the README. All of these are without touching the library code. I personally like having two type of maintenances, one is for actual coding, another is for documenting. Generally, I don’t like them to be in same commit especially for a release. Although, you certainly need to mix them most of time.

Any thoughts on this?