How to specify version ranges in install_requires (setuptools, distribute)

According to the documentation, your syntax should work correctly. The documentation states that:

setuptools and pkg_resources use a common syntax for specifying a project's required dependencies. This syntax consists of a project's PyPI name, optionally followed by a comma-separated list of "extras" in square brackets, optionally followed by a comma-separated list of version specifiers. A version specifier is one of the operators <, >, <=, >=, == or !=, followed by a version identifier.

The documentation gives a simple example like this:

docutils >= 0.3

# comment lines and \ continuations are allowed in requirement strings
BazSpam ==1.1, ==1.2, ==1.3, ==1.4, ==1.5, \
    ==1.6, ==1.7  # and so are line-end comments

To expand upon that, if you want your package to require a version of docutils greater than version 0.3 but less than version 0.5, code like this would work:

docutils >= 0.3, <=0.5

Two additional notes.

  1. The documentation also states that redundant/overlapping dependency specifications will be combined internally, so docutils >= 0.3, >=0.2 would be combined into docutils >= 0.3.
  2. Also, be careful about specifying conflicting version numbers, which "is meaningless and may therefore produce bizarre results." For example, I don't know why you would, but don't use this: docutils >= 0.3, <=0.2 since this is impossible.

Be wary of involuntary beta tests. Package maintainers sometimes release incompatible, incomplete, or broken a, b, and c releases to general audiences without warning. The next time you run setup.py in a fresh virtualenv, you might pull down one of these poisoned eggs, and suddenly your program will break.

To mitigate this risk, do not use the foo >=0.3, <0.4 style declaration, which has a purely numeric upper bound. <0.4 still admits versions 0.4a0, 0.4a1, 0.4b0, 0.4c3, etc. Instead, use an upper bound like <0.4a0, as in foo >=0.3, <0.4a0, when you write your install_requires.

When setuptools does something unexpected, trying using verlib to model your version comparisons. Verlib is a pretty good fit as long as your versions are normalized and non-contradictory. Here is an example that demonstrates the potentially counter-intuitive ordering of normalized versions:

#!/usr/bin/env python

from verlib import NormalizedVersion as V

assert (V("0.7.9") < V("0.8a0") < V("0.8a1") < V("0.8b0") < V("0.8b1")
    < V("0.8b2") < V("0.8.0") < V("0.8.1a0") < V("0.8.1") < V("0.9")
    < V("1.0a3") < V("1.0b2") < V("1.0b20") < V("1.0c0") < V("1.0")
    < V("1.0.1"))

assert (V("0.7.9") < V("0.8.0a0") < V("0.8.0a1") < V("0.8.0b0")
    < V("0.8.0b1") < V("0.8.0b2") < V("0.8.0") < V("0.8.1a0") < V("0.8.1")
    < V("0.9") < V("1.0a3") < V("1.0b2") < V("1.0b20") < V("1.0c0")
    < V("1.0") < V("1.0.1"))

print "Version comparisons are sane."

The notation mentioned in OP's question, >= 0.5.0, < 0.7.0, already works.

And, since many (if not most) of the libraries would already use semantic versioning, so by definition you can define your dependency as A>=1,<2, as explained here. And they even implemented an even simpler syntax for it, A~=X.Y, meaning it requires at least release X.Y, but also allows any later release with a matching MAJOR version.