45

We have a placeholder egg that contains no code and only exists for the sake of pulling down a list of dependent packages from our PyPi repository.

Most of these dependent packages are platform-agnostic, however some are only used on Win32 platforms.

Is it possible to somehow make the dependency platform-conditional, so that a given dependency in my install_requires list will only get pulled down when installing on Win32?

Alternatively: Is it possible to specify a list of optional dependencies, that will be installed if available, but will not cause easy_install to fail if they are not?

Wilfred Hughes
  • 29,846
  • 15
  • 139
  • 192
Daniel Fortunov
  • 43,309
  • 26
  • 81
  • 106

4 Answers4

55

For sdist, egg and wheel release from : https://setuptools.readthedocs.io/en/latest/userguide/dependency_management.html#platform-specific-dependencies

Sometimes a project might require a dependency to run on a specific platform. This could to a package that back ports a module so that it can be used in older python versions. Or it could be a package that is required to run on a specific operating system. This will allow a project to work on multiple different platforms without installing dependencies that are not required for a platform that is installing the project.

setup(
    name="Project",
    ...
    install_requires=[
        'enum34 ; python_version<"3.4"',
        'pywin32 >= 1.0 ; platform_system=="Windows"'
    ]
)
Carl Walsh
  • 6,100
  • 2
  • 46
  • 50
wtayyeb
  • 1,879
  • 2
  • 18
  • 38
  • 2
    Btw, the special variables `python_version` and `platform_system` need not be initialized before that. [PEP 508](https://www.python.org/dev/peps/pep-0508/#environment-markers) gives a list of available variables. – rvf Jul 08 '19 at 08:47
  • To specify both platform and python version for a dependency, you can use `and` per [this question](https://stackoverflow.com/a/57706151/777980) – Wisco crew Apr 17 '23 at 02:23
12

In setup.py:

from setuptools import setup
import sys

setup(
    name="...",
    install_requires=["This", "That"] + (
        ["WinOnly", "AnotherWinOnly"] if sys.platform.startswith("win") else []
        )
)

distutils.util.get_platform has more information than sys.platform if you need it:

>>> sys.platform
'linux2'
>>> distutils.util.get_platform()
'linux-i686'
jsphpl
  • 4,800
  • 3
  • 24
  • 27
codeape
  • 97,830
  • 24
  • 159
  • 188
  • 5
    Presumably the list of dependencies generated by this logic will be baked in to my egg metadata, meaning that if I *build* the egg on Windows then it will have the windows dependencies, and will then fail to install on Linux where those dependencies are not available? – Daniel Fortunov Jun 24 '11 at 15:27
  • I'm not sure how it works. I assumed that since ``setup.py`` is executed at install time, the dependencies will be generated at install time. But this should be easy enough to test. – codeape Jul 08 '11 at 20:13
  • 3
    Note that the platform check should be ``if sys.platform == 'win32'`` or it will pass on Mac OS X (*darwin*), see http://stackoverflow.com/questions/2144748/is-it-safe-to-use-sys-platform-win32-check-on-64-bit-python – kraymer Nov 01 '15 at 16:33
  • 3
    This won't work. `setup.py` is not executed at install time unless you're doing a source install. It's executed at package build time. – jpmc26 May 02 '19 at 22:26
11

Use the extras_require distribution option to make 'win32 support' an optional feature:

setup(
  ...
  extras_require={
    'win32': 'pywin32'
  },
  ...
)

Then specify the win32 feature when installing on Windows:

easy_install mypackage[win32]

This will pull down the pywin32 package, which is listed as a dependency for the 'win32' feature of mypackage.

See here for more information about optional features.

Daniel Fortunov
  • 43,309
  • 26
  • 81
  • 106
2

When the egg is built (using python setup.py bdist_egg), you can force setuptools/distribute to build a platform-specific egg.

from setuptools import setup
import os

# Monkey-patch Distribution so it always claims to be platform-specific.
from distutils.core import Distribution
Distribution.has_ext_modules = lambda *args, **kwargs: True

requirements = ['generic-foo', 'generic-bar']

if os.getenv('WINDOWS_BUILD'):
    requirements.extend(['a-windows-only-requirement'])

setup(
    name="...",
    install_requires=requirements
)

You can then run:

# Force a windows build
$ WINDOWS_BUILD=y python setup.py bdist_egg -p win32
# Do a linux build -- you may not need to specify -p if you're happy
# with your current linux architecture.
$ python setup.py bdist_egg -p linux-i686
Wilfred Hughes
  • 29,846
  • 15
  • 139
  • 192