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.
To use a specific version of setuptools it is necessary to have it in both locations - in pyproject. toml and at the beginning of install_requires of setup.py. The tool like pip will use the version from pyproject. toml to build the project.
In Fedora, our pip package Recommends setuptools. Practically that means: Majority of users who install pip will get setuptools by default. Users can explicitly uninstall setuptools after installing pip or exclude setuptools when installing pip.
The items listed in setup_requires get implicitly installed whenever you execute the setup.py but one of the common ways that the setup.py is executed is via another tool, such as pip , who is already managing dependencies.
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
I've read some related code of pkg_resources
. I think the document here is not accurate. Not only pip
fails to find the right package version, python setup.py install
, which actually uses setuptools
, also fails.
Some of the related code:
pip/_vendor/packaging/specifiers.py
# If we have any specifiers, then we want to wrap our iterable in the
# filter method for each one, this will act as a logical AND amongst
# each specifier.
if self._specs:
for spec in self._specs:
iterable = spec.filter(iterable, prereleases=prereleases)
return iterable
You can see that in the comment, the author emphasized that this will cause an AND
amongst each specifier, not OR
. So if you do this:
PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1
You will get nothing!
I tried with this code below:
import pkg_resources
a = ['1.4', '1.8', '1.9.2']
d = pkg_resources.Requirement.parse('PickyThing<1.6,>1.9,!=1.9.6')
r = d.specifier.filter(a)
print(list(r)) # Nothing, just an empty list []
You may want to file a bug to pip so they can fix it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With