Dropping support of a Python runtime can be a tricky task for any package maintainer.
Python 2.6 is out of maintenance, 3.3 is now out of maintenance and both have syntax gaps with the common subset found in 2.7 and 3.4. When you might want to later only offer Python 3 support on a package, you don’t want to completely leave your Python 2 users in the cold.
The Python Packaging Authority have been working on solving that issue, with a combination of updates to PyPi (the packaging service), the Packaging API, Pip (the command line installer), setuptools (the library used to create the metadata) and the metadata format. All of these changes have come together to allow package maintainers to publish “maintenance releases” to old Python runtimes and new releases to supported Python runtimes.
To publish a package to PyPi, you need to follow 3 steps:
setup(
with some information about the packagepython setup.py sdist
or python setup.py sdist bdist_wheel
if you want to include a wheel filetwine upload dist/*
.Within a Python source package (the zip or the tar-gz file you download) is a text file called PKG-INFO.
This file is generated by distutils or setuptools when it generates the source package. The file contains a set of keys and values, the list of keys is part of the PyPa standard metadata format. You can see the contents of the generated file like this:
tar xvfz dist/my-package-1.0.0.tar.gz -O | cat */PKG-INFO
At the top of the file should be the header Metadata-Version
, which depends upon the version of setuptools or distutils you have installed. So the first thing you should do is upgrade setuptools and stop using distutils.
pip install — upgrade setuptools
Setuptools is the package being maintained by PyPa now, so make sure at the top of setup.py you are importing the setup method from the setuptools module.
If you have upgraded correctly, the Metadata-Version value should be 1.2 or higher. Metadata 1.2 introduced a new field for the version of Python required for this package.
You can specify version ranges and exclusion rules, such as at least Python 3. Or, Python 2.7 and 3.4 beyond.
Requires-Python: >=3Requires-Python: >2.7,!=3.0.*,!=3.1.*, !=3.2.*,!=3.3.*
The way to set those values is within the call to setup
within your setup.py script.
Now, calling python setup.py sdist
and then twine upload dist/*
will publish version 1 of this package specifying that only Python 2.7+ is supported.
Since it’s almost impossible to edit a published package on PyPi, you really want to check first, so run this command to validate the metadata has been generated correctly.
tar xvfz dist/my-package-1.0.0.tar.gz -O | grep “Requires-Python”
Anyone used to using setup.py
to publish the package to PyPi, you can also stop doing that now. Twine has a number of advantages, apart from being faster is now the supported method for publishing packages.
Make sure you are using the newest version of twine (1.9 at the time of writing).
Once you have published a package with the metadata, you can then make a further update removing that Python runtime from support.
It must be done in this order for the automated fail-back to work.
This is a pretty typical timeline
python_requires
in setup.py for all versions 2.7+python_requires
field to >3.3 and publish version 2.0.0 of your packageNow, if the user has pip >9.0 and they install your package from Python 2 without specifying a version number, they get the last version of the package to support their Python distribution!
If a user has an in-support Python distribution as specified in your setup.py
then they get the latest version.
Try it out on a package I published to PyPi called friendly-deprecation-test
.
Someone raises a critical bug against v1.6.0 and you don’t want to leave your Python 2 users at risk. What do you do?
requires_python >= 2.7
attribute. Release it to PyPi.requires_python >= 3.4
attribute.Now the same process applies, all Python 2 users will get 1.6.1 and Python 3.4+ will get 2.0.1.