Versioneer is a tool for managing version numbers in Python projects. In this article I’ll explore how it can be set up and used.

Quoted from the Versioneer documentation

This is a tool for managing a recorded version number in setuptools-based python projects. The goal is to remove the tedious and error-prone “update the embedded version string” step from your release process. Making a new release should be as easy as recording a new tag in your version-control system, and maybe making new tarballs. This sounds great. Manually managing package versions is clunky and error prone, so a tool that can automate this process is very welcome. Let’s explore how to set it up.

Setting up Versioneer

To set up Versioneer, we need to install. This can be done using pip:

pip install versioneer

Now we must register the versioneer command with setuptools. This can be done by adding the following to your setup.cfg file:

[versioneer]
    VCS = git
    style = pep440
    versionfile_source = PACKAGENAME/_version.py
    versionfile_build = PACKAGENAME/_version.py
    tag_prefix = ''

replacing PACKAGENAME with the name of your package. The VCS field specifies the version control system you are using. The style field specifies the versioning style you want to use. The versionfile_source and versionfile_build fields specify the location of the version file - don’t worry that there’s no _version.py file - we’re about to create that. The tag_prefix field specifies the prefix of the version tag. For example, if you are using git and your version tags are of the form v1.0.0, then you would set tag_prefix = 'v'.

Finally, run the following command to let Versioneer run its setup:

versioneer install --vendor

and add the following lines to the setup command within your setup.py file:

    version=versioneer.get_version(),
    cmdclass=versioneer.get_cmdclass(),

As a bonus step, we can use versioneer within our CircleCI workflow to push a nightly build of the package. To read more about CircleCI, read https://tpin.uk/writing/ga-to-circleci-transition/ . To provide the necessary logic to Versioneer that enables a nightly build to be constructed, add the following to your setup.py file:

NAME = "PACKAGENAME"


# Handle builds of nightly release - adapted from BlackJax.
if "BUILD_PACKAGENAME_NIGHTLY" in os.environ:
    if os.environ["BUILD_PACKAGENAME_NIGHTLY"] == "nightly":
        NAME += "-nightly"

        from versioneer import get_versions as original_get_versions

        def get_versions():
            from datetime import datetime, timezone

            suffix = datetime.now(timezone.utc).strftime(r".dev%Y%m%d")
            versions = original_get_versions()
            versions["version"] = versions["version"].split("+")[0] + suffix
            return versions

        versioneer.get_versions = get_versions

Again, replacing PACKAGENAME with the name of your package. This code will look for an environment variable called BUILD_PACKAGENAME_NIGHTLY and if it is set to nightly, it will append -nightly to the package name. It will also append the current date to the version number. This will allow us to push a nightly build of the package to PyPI.

To connect this to your CircleCi workflow, add the following to your .circleci/config.yml job that creates a nightly build:

- run:
    name: Build package
    command: |
        pip install -U twine
        python setup.py sdist bdist_wheel
        environment:
            BUILD_JAXKERN_NIGHTLY: 'nightly'        

This job will create an environmental variable called BUILD_PACKAGENAME_NIGHTLY and set its value as 'nightly'. When we then build our package through python setup.py sdist bdist_wheel, the setup.py file will see this environmental variable and append -nightly to the package name and append the current date to the version number.