| Page Status: | Complete |
|---|---|
| Last Reviewed: | 2015-12-03 |
There are many techniques to maintain a single source of truth for the version number of your project:
Read the file in
setup.pyand parse the version with a regex. Example ( from pip setup.py):def read(*names, **kwargs): with io.open( os.path.join(os.path.dirname(__file__), *names), encoding=kwargs.get("encoding", "utf8") ) as fp: return fp.read() def find_version(*file_paths): version_file = read(*file_paths) version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M) if version_match: return version_match.group(1) raise RuntimeError("Unable to find version string.") setup( ... version=find_version("package", "__init__.py") ... )Note
This technique has the disadvantage of having to deal with complexities of regular expressions.
Use an external build tool that either manages updating both locations, or offers an API that both locations can use.
Few tools you could use, in no particular order, and not necessarily complete: bumpversion, changes, zest.releaser.
Set the value to a
__version__global variable in a dedicated module in your project (e.g.version.py), then havesetup.pyread andexecthe value into a variable.Using
execfile:execfile('...sample/version.py') # now we have a `__version__` variable # later on we use: __version__Using
exec:version = {} with open("...sample/version.py") as fp: exec(fp.read(), version) # later on we use: version['__version__']Example using this technique: warehouse.
Place the value in a simple
VERSIONtext file and have bothsetup.pyand the project code read it.with open(os.path.join(mypackage_root_dir, 'VERSION')) as version_file: version = version_file.read().strip()An advantage with this technique is that it's not specific to Python. Any tool can read the version.
Warning
With this approach you must make sure that the
VERSIONfile is included in all your source and binary distributions (e.g. addinclude VERSIONto yourMANIFEST.in).Set the value in
setup.py, and have the project code use thepkg_resourcesAPI.import pkg_resources assert pkg_resources.get_distribution('pip').version == '1.2.0'Be aware that the
pkg_resourcesAPI only knows about what's in the installation metadata, which is not necessarily the code that's currently imported.Set the value to
__version__insample/__init__.pyand importsampleinsetup.py.import sample setup( ... version=sample.__version__ ... )Although this technique is common, beware that it will fail if
sample/__init__.pyimports packages frominstall_requiresdependencies, which will very likely not be installed yet whensetup.pyis run.Keep the version number in the tags of a version control system (Git, Mercurial, etc) instead of in the code, and automatically extract it from there using setuptools_scm.