Standard way to embed version into python package?
Question: Is there a standard way to associate version string with a python package in
such way that I could do the following?

    
    
    import foo
    print foo.version
    

I would imagine there's some way to retrieve that data without any extra
hardcoding, since minor/major strings are specified in `setup.py` already.
Alternative solution that I found was to have `import __version__` in my
`foo/__init__.py` and then have `__version__.py` generated by `setup.py`.


Answer: Here is how I do this. Advantages of the following method:

  1. It provides a `__version__` attribute.

  2. It provides the standard metadata version. Therefore it will be detected by `pkg_resources` or other tools that parse the package metadata (EGG-INFO and/or PKG-INFO, PEP 0345).

  3. It doesn't import your package (or anything else) when building your package, which can cause problems in some situations. (See the comments below about what problems this can cause.)

  4. There is only one place that the version number is written down, so there is only one place to change it when the version number changes, and there is less chance of inconsistent versions.

Here is how it works: the "one canonical place" to store the version number is
a .py file, named "_version.py" which is in your Python package, for example
in `myniftyapp/_version.py`. This file is a Python module, but your setup.py
doesn't import it! (That would defeat feature 3.) Instead your setup.py knows
that the contents of this file is very simple, something like:

    
    
    __version__ = "3.6.5"
    

And so your setup.py opens the file and parses it, with code like:

    
    
    import re
    VERSIONFILE="myniftyapp/_version.py"
    verstrline = open(VERSIONFILE, "rt").read()
    VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]"
    mo = re.search(VSRE, verstrline, re.M)
    if mo:
        verstr = mo.group(1)
    else:
        raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,))
    

Then your setup.py passes that string as the value of the "version" argument
to `setup()`, thus satisfying feature 2.

To satisfy feature 1, you can have your package (at run-time, not at setup
time!) import the _version file from `myniftyapp/__init__.py` like this:

    
    
    from _version import __version__
    

Here is [an example of this technique](https://tahoe-
lafs.org/trac/zfec/browser/trunk/zfec/setup.py?rev=390#L84) that I've been
using for years.

The code in that example is a bit more complicated, but the simplified example
that I wrote into this comment should be a complete implementation.

Here is [example code of importing the version](https://tahoe-
lafs.org/trac/zfec/browser/trunk/zfec/zfec/__init__.py?rev=363).

If you see anything wrong with this approach, please let me know: zooko at
zooko dot com. If you don't see anything wrong with this approach then use it!
Because the more packages come with their version numbers in the expected
places the better!

