Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setuptools platform specific dependencies

Is there any way to tell setuptools or distribute to require a package on a specific platform?

In my specific case, I'm using readline, which comes as part of the standard library on Unix systems, but on Windows I need the pyreadline module to replace that functionality (cf. this question). If I just put it in the requirements It also installs on Unix systems where it's completely useless.

like image 556
Manuel Ebert Avatar asked Apr 17 '13 08:04

Manuel Ebert


People also ask

Does pip require setuptools?

A Python file that relies only on the standard library can be redistributed and reused without the need to use setuptools. But for projects that consist of multiple files, need additional libraries, or need a specific version of Python, setuptools will be required.

Is setuptools installed by default with Python?

Usually, Yes. the setuptools is not part of the python vanilla codebase, hence not a vanilla modules. python.org installers or mac homebrew will install it for you, but if someone compile the python by himself or install it on some linux distribution he may not get it and will need to install it by himself.

What does setuptools setup do?

setuptools allows you to install a package without copying any files to your interpreter directory (e.g. the site-packages directory). This allows you to modify your source code and have the changes take effect without you having to rebuild and reinstall.


2 Answers

While the answer given by Martijn Pieters was totally valid at the time, Python packaging has changed a lot since then.

The preferred format to distribute packages is using wheels*. Using wheels it is not possible to run Python code during installation.

Wheel use metadata version two as specified in PEP 0427. Environment markers can be used to specify platform specific dependencies.

Setuptools allows to specify these environment markers as extras_require keys. The following example script depends on pyreadline for Windows systems and on pyxdg for Linux distributions.

#!/usr/bin/env python
from setuptools import setup

setup(
    name='spam',
    version='0.0.1',
    extras_require={
        ':sys_platform == "win32"': [
            'pyreadline'
        ],
        ':"linux" in sys_platform': [
            'pyxdg'
        ]
    })

*Also release an sdist, so platforms which can't use wheel can still install your package.

like image 94
Remco Haszing Avatar answered Sep 22 '22 21:09

Remco Haszing


When I first wrote my answer here, in 2013, we didn't yet have PEP 496 – Environment Markers and PEP 508 – Dependency specification for Python Software Packages. Now that we do, the answer is: put environment markers in your setup_requires:

setup_requires = [
    'foo',
    'bar',
    'pyreadline; sys_platform == "win32"',
]

setup(
    # ...
    setup_requires=setup_requires,
)

This is supported as of setuptools 20.6.8, released in May 2016 (support was introduced in version 20.5 but was briefly disabled in intervening releases).

Note that setuptools will use easy_install to install those requirements when it is being executed, which is hard to configure for when using pip to install the project.

It may better to not use setuptools to handle build-time dependencies, and use a pyproject.toml file following the recommendations from PEP 518 – Specifying Minimum Build System Requirements for Python Projects. Using the PEP 518 build-system with built-time dependencies, means creating a pyproject.toml file that looks something like this:

[build-system]
requires = [
    "setuptools",
    "wheel",
    "foo",
    "bar",
    "pyreadline; sys_platform == "win32",
]

That's the same list as setup_requires but with setuptools and wheel added. This syntax is supported by pip as of version 10.0.0, released in March 2018.

My old answer, from 2013, follows.


setup.py is simply a python script. You can create dynamic dependencies in that script:

import sys

setup_requires = ['foo', 'bar']

if sys.platform() == 'win32':
    setup_requires.append('pyreadline')

setup(
    # ...
    setup_requires=setup_requires,
)
like image 42
Martijn Pieters Avatar answered Sep 24 '22 21:09

Martijn Pieters