Search code examples
pythonpipsetuptools

Exclude certain dependency version ranges in setuptools/pip


Currently the Django Project supports 1.4, 1.7 and 1.8. In my setup.py I want to reflect these versions as being supported.

install_requires=['Django>=1.4.2,<1.8.99,!=1.5,!=1.6']

However this still allows 1.5.x and 1.6.x releases. How can I exclude a complete range?

Setuptools lists the following valid requirements as an example:

PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1

However this doesn't work with pip (it should at least match 1.4.x / 1.5.x):

No matching distribution found for PickyThing!=1.9.6,<1.6,<2.0a0,==2.4c1,>1.9

Update with example
For example; I only want to include currently supported versions of Django. This would be 1.4.x, 1.7.x and 1.8.x. So I would write;

#setup.py
install_requires=['Django>=1.4.2,<1.4.99,>=1.7,<1.8.99']

However if I run pip install -e . on this project, it fails with;

Collecting Django<1.4.99,<1.8.99,>=1.4.2,>=1.7 (from ...)
Could not find a version that satisfies the requirement Django<1.4.99,<1.8.99,>=1.4.2,>=1.7 (from django-two-factor-auth==1.2.0) (from versions: 1.1.3, 1.1.4, 1.2, 1.2.1, 1.2.2, 1.2.3, 1.2.4, 1.2.5, 1.2.6, 1.2.7, 1.3, 1.3.1, 1.3.2, 1.3.3, 1.3.4, 1.3.5, 1.3.6, 1.3.7, 1.4, 1.4.1, 1.4.2, 1.4.3, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.4.8, 1.4.9, 1.4.10, 1.4.11, 1.4.12, 1.4.13, 1.4.14, 1.4.15, 1.4.16, 1.4.17, 1.4.18, 1.4.19, 1.4.20, 1.5, 1.5.1, 1.5.2, 1.5.3, 1.5.4, 1.5.5, 1.5.6, 1.5.7, 1.5.8, 1.5.9, 1.5.10, 1.5.11, 1.5.12, 1.6, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.6.5, 1.6.6, 1.6.7, 1.6.8, 1.6.9, 1.6.10, 1.6.11, 1.7, 1.7.1, 1.7.2, 1.7.3, 1.7.4, 1.7.5, 1.7.6, 1.7.7, 1.7.8, 1.8a1, 1.8b1, 1.8b2, 1.8rc1, 1.8, 1.8.1)
No matching distribution found for Django<1.4.99,<1.8.99,>=1.4.2,>=1.7 (from ...)

It is obvious that a version number 1.4.20 cannot satisfy >=1.7 and 1.8.1 cannot satisfy <1.4.99. However the documentation from Setuptools (see above) does suggest that something along these lines should be possible. However, this is non-obvious to me.


Solution

  • You can use

    Django>=1.4.2,<1.9,!=1.5.*,!=1.6.*
    

    This is defined inside PEP440.

    You can test this behavior with the packaging module that is vendored inside the last versions of setuptools and pip.

    In [1]: from packaging import specifiers
    
    In [2]: sp=specifiers.SpecifierSet(">=1.4.2,<1.9,!=1.5.*,!=1.6.*")
    
    In [3]: sp.contains("1.4.2")
    Out[3]: True
    
    In [4]: sp.contains("1.6.4")
    Out[4]: False
    
    In [5]: sp.contains("1.8.2")
    Out[5]: True