5

I'm creating a package that has 'typing;python_version<"3.5"' in it's install_requires. Apparently, this kind of dependency specification has only been implemented in recent versions of setuptools. If the setuptools on the user's machine is old they'll get:

'install_requires' must be a string or list of strings containing valid project/version requirement specifiers; Expected version spec in typing;python_version<"3.5" at ;python_version<"3.5"

The easy solution is to tell the users to pip install 'setuptools>=36.2.1' before pip install my-package. (Note that 36.2.1 is just a version that I know works, not necessarily the the absolute minimum requirement)

But is there any way to specify this requirement in setup.py so that it gets done automatically? Adding setuptools>=36.2.1 to install_requires and setup_requires did not work. It says Installed /tmp/pip-si2fqg-build/.eggs/setuptools-38.2.5-py3.3.egg and then gives the same error above.

AXO
  • 8,198
  • 6
  • 62
  • 63

2 Answers2

6

You can't update setuptools and use its code in the setup script in one pass. I see two possible solutions: If you want to support old versions of setuptools, you can't use env markers. Implement the check yourself by using sys.version_info:

import sys
from setuptools import setup


setup(
    name='spam',
    version='0.1',
    packages=[],
    install_requires=['typing'] if sys.version_info < (3, 5) else []
)

If you don't want to support old versions of setuptools, check its version and abort early, informing the user:

import sys
from distutils.version import StrictVersion
from setuptools import setup, __version__


if StrictVersion(__version__) < StrictVersion('20.2'):
    print('your setuptools version does not support PEP 508. Upgrade setuptools and repeat the installation.')
    sys.exit(1)


setup(
    name='spam',
    version='0.1',
    packages=[],
    install_requires=['typing;python_version<"3.5"']
)
hoefling
  • 59,418
  • 12
  • 147
  • 194
  • The problem with the first approach is that if someone creates a wheel file using Python 3.5 or later, then the created wheel will not include the `typing` requirement and therefore that wheel won't install correctly on older python versions. – AXO Jan 02 '18 at 10:40
  • 1
    Usually, it's the project maintainer/developer who creates the wheels and uploads them to PyPI. He is responsible of building wheels that run on every platform/language implementation that are advertised to be supported (smth like `mypkg-0.1-cp35.cp36-abi3-any.whl` could be imaginable). If someone pulls your source code and builds a wheel that doesn't run, you can't be responsible for that ;-) – hoefling Jan 02 '18 at 18:38
4

I just learned about PEP 518 -- Specifying Minimum Build System Requirements for Python Projects that addresses this exact problem.

In short, this accepted PEP proposes to store dependencies in TOML format, in a file named pyproject.toml. For most Python projects the contents of this file will be:

[build-system]
# Minimum requirements for the build system to execute.
requires = ["setuptools", "wheel"]  # PEP 508 specifications.

In the case of this specific question, we just need to replace "setuptools" with "setuptools>=36.2.1".

The bad news is that pip does not support this yet. The good news is that it is implemented and will probably be shipped with pip 9.1.

AXO
  • 8,198
  • 6
  • 62
  • 63