9

Some Python packages require one of two packages as a dependency. For example, Ghost.py requires either PySide or PyQt4.

Is it possible to include such a dependency in a requirements.txt file? Is there any 'or' operator that works with these files?

If not, what can I do to add these requirements to the file so only one of them will be installed?

Or B
  • 1,675
  • 5
  • 20
  • 41

3 Answers3

4

Currently neither pip's requirement.txt nor setuptools directly allow such a construction. Both require you to specify a list of requirements. You can restrict the version of a requirement, but that's all.

Inside Python, you can handle this situation as follows:

try:
    import dependency1

    def do_it(x):
        return dependency1.some_function(x)
except ImportError:
    try:
        import dependency2

        def do_it(x)
            return dependency2.another_function(x)
    except ImportError:
        raise ImportError('You must install either dependency1 or '
                          + 'dependecy2!')

Now do_it uses either dependency1.some_function or dependency2.another_function, depending on which is available.

That will still leave you with the problem of how to specify your requirements. I see two options:

  1. Don't formally specify the requirement in requirements.txt or setup.py but document that the user needs to install one of the dependencies. This approach might be OK if the setup of your software requires additional manual steps anyway (i.e. more than just pip install my_tool).
  2. Hard-code your preferred requirement in requirements.txt or setup.py.

In the end, you have to ask yourself why people might want to use one dependency over the other: I usually couldn't care less about the dependencies of the libraries that I use, because (disk) space is cheap and (due to virtualenv) there is little risk of incompatibilities. I'd therefore even suggest you think about not supporting two different dependencies for the same functionality.

Florian Brucker
  • 9,621
  • 3
  • 48
  • 81
2

I would use a small Python script to accomplish this

#!/usr/bin/env python
packages = 'p1 p2 p3'.split()

try:
    import optional1
except ImportError: # opt1 not installed 
    try:
        import optional2
    except ImportError: # opt2 not installed
        packages.append('optional2')

print(' '.join(packages))

Have this script executable with

chmod +x requirements.py

And finally run pip with it like this:

pip install $(requirements.py)

The '$(requirements.py)' will execute the requirements.py script and put its output (in this case, a list of packages) into pip install ...

licorna
  • 5,670
  • 6
  • 28
  • 39
0

For setuptools, you can change the setup code to look similar to here: https://github.com/albumentations-team/albumentations/blob/master/setup.py#L11

Where dependency1 would be installed if none of dependency1 and dependency2 is installed yet, but nothing is installed if any of them is already part of the system.

The caveat is that it doesn't work with wheels, and you need to install with --no-binary to make it work: https://albumentations.ai/docs/getting_started/installation/#note-on-opencv-dependencies

Jan Rüegg
  • 9,587
  • 8
  • 63
  • 105