I recently helped someone release their first project on PyPI and I was asked why I did version numbers the way I did, so I figured I would share where my current thinking on the topic sits (this doesn't mean all of my projects currently follow this as my thoughts on this have changed in the last couple of months).
First, keep your version number in a
__version__ attribute at the top of your package. I have two reasons for doing this. One is that it makes it easy to check what version you have installed by simply pulling up the REPL, importing the module, and printing out the
__version__ attribute. Two, flit requires it and it's currently my favourite packaging tool for any pure Python project.
The next thing I do is follow semantic versioning. Even if you do date-based releases, you should still follow semver so your users know if the latest release will be easy to upgrade to (i.e. a minor or patch release), or if there will be some work needed to be able to use the new release (i.e. a major release).
I personally like to keep a running changelog so that it's easy for users to know what's new or what may break in their code when they upgrade. It also helps me judge when I should cut a new release based on how much is currently in version control but not in an official release. Personally I just keep the changelog at the end of the README so it shows up on both PyPI and GitHub.
Once I do a release I immediately bump the version number by a patch level and append
.dev1 to it. This is so that anyone who installs the project from source won't accidentally have code that is different from a release with the same version number. It also clearly lets people know they are using an in-development version of the code and so they can't expect normal release guarantees like stability. I also try to bump the version number appropriately as pull requests get merged while keeping the
.dev1 suffix so that when it comes time to release I can just drop the
__version__ and the changelog, commit, and run