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 par
from setuptools import setup
setup(
install_requires=(['pymsgbox', 'PyTweening>=1.0.1', 'Pillow', 'pyscreeze']
+ ["python3-xlib; sys_platform == linux"]
+ ["python-xlib; sys_platform == linux2"]
+ ["pyobjc-core; sys_platform == darwin"]
+ ["pyobjc; sys_platform == darwing"]
),
)
This will install speicific versions of libraries depending on whether its linux2
(for a linux system using python2
), linux
(for a linux system using python3
), darwin
(for a MacOS system)
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,
)
Other answers are valid and probably more convenient if supporting old setuptools
versions is required, but there have been some advancements:
Recent versions of setuptools accept PEP 508 style dependency specification:
setup(
# ...
install_requires=[
'pyreadline; platform_system == "Windows"',
],
)
Choose the right parameter:
install_requires
: what other distributions are needed for the current distribution to work correctlyextras_require
: a dictionary mapping the names of optional features to a list of their requirementssetup_requires
: other distributions that need to be present for the setup script to run correctly
Note: projects listed in setup_requires
will NOT be automatically installed. They are simply downloaded to the ./.eggs directory if they’re not locally available already.There is also an alternative way for supplying these parameters through setup.cfg
file. See the documentation for more info.
PEP 518 introduces a new and more capable way of specifying setup_requires
in pyproject.toml
file:
[build-system]
# Minimum requirements for the build system to execute.
requires = ['setuptools>"38.3.0"', 'wheel'] # PEP 508 specifications.
The feature was implemented in pip 10.0.0b1. Using it one will be able to automatically install and update build system requirements.
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.