10

Say I want to install pyodbc. It can't be build on some Windows machines but there's an alternative - pypyodbc which is pure python implementation of pyobdc.

Is there a way to specify install_requires=["pyobdc"] for setuptools.setup with falling back to pypyodbc if the former package wasn't installed?

UPD: My solution for this particular situation:

import sys
from setuptools import setup

if sys.platform.startswith("win"):
    pyodbc = "pypyodbc>=1.2.0"
else:
    pyodbc = "pyodbc>=3.0.7"

...

setup(
      ...
      install_requires=[pyobdc]
      )

But I still look for a more general solution.

Oleksandr Fedorov
  • 1,213
  • 10
  • 17
  • I see nothing wrong with your approach. This looks valid according to the docs. https://pythonhosted.org/setuptools/setuptools.html#declaring-dependencies – rh0dium Oct 22 '14 at 04:05

3 Answers3

10

Doing what you are already doing seems like a common recommendation, but since this question is the top google hit for this sort of question, I'll point out that install_requires supports a fairly intricate mini-language which is specified in PEP 508:

install_requires = [
    'pypyodbc>=1.2.0;platform_system=="Windows"',
    'pyodbc>=3.0.7;platform_system!="Windows"'
]

In a comment to a related question, user Marius Gedminas notes that having your install_requires computed in code could have some adverse effects, so the above should be preferred to avoid that problem.

(On the other hand, https://hynek.me/articles/conditional-python-dependencies/ laments some pretty serious portability problems if you have to support old versions of setuptools.)

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • 2
    So far I have not been able to find any specification or practical example of a syntax like the `foo || bar` syntax in Debian packages to say you want either `foo` or `bar` to be installed. – tripleee Sep 07 '17 at 13:39
0

Your solution is the correct one for this situation. It is the best and more flexible way at the moment to achieve this task.

Maksim
  • 215
  • 2
  • 12
-1

In setup there is no try A fallback B. The manual try is like this:

try:
   import pyodbc# i didn't test this
except ImportError:
   import subprocess
   import sys
   test=subprocess.run([sys.executable,'-m','pip','install','pypyodbc>=1.2.0'])
   if test.returncode:
        subprocess.run([sys.executable,'-m','pip','install','pyodbc>=3.0.7'])
Sam
  • 91
  • 1
  • 5