Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support version ranges #16

Merged
merged 3 commits into from
Jun 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Install the package and include `pip_version` in your tox.ini

```tox
[testenv]
pip_version = 19.0.1
pip_version = pip==19.0.1
```

Or, set the `TOX_PIP_VERSION` environment variable,
Expand All @@ -44,7 +44,7 @@ export TOX_PIP_VERSION=18.1
tox
```

The plugin will install that specific pip into the tox-created virtualenv,
The plugin will install that version of pip into the tox-created virtualenv,
just after tox creates the virtualenv, but before dependencies are installed.

The `pip_version` within tox.ini, if present, is always used over the
Expand All @@ -53,6 +53,21 @@ environment variable.
If neither `pip_version` or `TOX_PIP_VERSION` is present, the plugin does
nothing.

### Version Sets

Version sets/ranges are supported, enabling installation of a version of pip
matching a set of specifiers. There are two basic formats: a plain version
number, or the package name with optional [PEP440-compatible](
https://www.python.org/dev/peps/pep-0440/#version-specifiers) version
specifiers.

| tox.ini | effective pip command |
| ---------------------------- | ---------------------------- |
| `pip_version = 19.0` | `pip install -U pip==19.0` |
| `pip_version = pip==19.0` | `pip install -U pip==19.0` |
| `pip_version = pip>=19.0` | `pip install -U pip>=19.0` |
| `pip_version = pip!=19,>18` | `pip install -U pip!=19,>18` |
| `pip_version = pip` | `pip install -U pip` |

### Tests

Expand Down
1 change: 1 addition & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
backports.tempfile
bumpversion
flake8
packaging
pytest
pytest-xdist
readme_renderer[md]
Expand Down
29 changes: 29 additions & 0 deletions tests/check-pip-version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import subprocess
import sys

from packaging.version import Version
from packaging.specifiers import SpecifierSet

VERSION_RANGE_OPERATORS = ('==', '!=', '<', '<=', '>', '>=', '~=', '===')


def to_specifer_set(raw_version):
if any(raw_version.startswith(op) for op in VERSION_RANGE_OPERATORS):
return SpecifierSet(raw_version)
return SpecifierSet('==%s' % raw_version)


def main():
expected_set = to_specifer_set(sys.argv[1])
raw_pip_version = subprocess.check_output(["pip", "--version"]).decode()
actual_version = Version(raw_pip_version.split(' ')[1])
if actual_version not in expected_set:
print("FAIL: version '%s' not in set '%s'"
% (actual_version, expected_set))
return 1
print("PASS: version '%s' is in set '%s'" % (actual_version, expected_set))
return 0


if __name__ == '__main__':
sys.exit(main())
11 changes: 0 additions & 11 deletions tests/check-pip-version.sh

This file was deleted.

8 changes: 4 additions & 4 deletions tests/test-env-inheritance/tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ skipsdist = True

[testenv]
pip_version = 10.0.1
whitelist_externals = bash
commands = bash -c '../check-pip-version.sh 10.0.1'
deps = packaging
commands = python ../check-pip-version.py 10.0.1

[testenv:env1]
commands = bash -c '../check-pip-version.sh 10.0.1'
commands = python ../check-pip-version.py 10.0.1

[testenv:env2]
pip_version = 18.1
commands = bash -c '../check-pip-version.sh 18.1'
commands = python ../check-pip-version.py 18.1
8 changes: 4 additions & 4 deletions tests/test-environment-variable/tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ skipsdist = True

[testenv]
# 18.1 comes from the TOX_PIP_VERSION env var
whitelist_externals = bash
commands = bash -c '../check-pip-version.sh 18.1'
deps = packaging
commands = python ../check-pip-version.py 18.1

[testenv:env1]
# Check that setenv overrides an externally set env var
setenv =
TOX_PIP_VERSION = 10.0.1
commands = bash -c '../check-pip-version.sh 10.0.1'
commands = python ../check-pip-version.py 10.0.1

[testenv:env2]
# Check that pip_version wins over env vars
pip_version = 19.0.1
commands = bash -c '../check-pip-version.sh 19.0.1'
commands = python ../check-pip-version.py 19.0.1
6 changes: 3 additions & 3 deletions tests/test-two-envs/tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ minversion = 2.0
skipsdist = True

[testenv]
whitelist_externals = bash
deps = packaging

[testenv:pip18_1]
pip_version = 18.1
commands = bash -c '../check-pip-version.sh 18.1'
commands = python ../check-pip-version.py 18.1

[testenv:pip19_0_1]
pip_version = 19.0.1
commands = bash -c '../check-pip-version.sh 19.0.1'
commands = python ../check-pip-version.py 19.0.1
44 changes: 44 additions & 0 deletions tests/test-version-specifiers/tox.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Verify we can use version ranges
[tox]
envlist = equal, not_equal, lesser, greater, lesser_eq, greater_eq, tilde_eq, combo, latest
minversion = 2.0
skipsdist = True

[testenv]
deps = packaging

[testenv:equal]
pip_version = pip==18.1
commands = python ../check-pip-version.py 18.1

[testenv:not_equal]
pip_version = pip!=19.0
commands = python ../check-pip-version.py '!=19.0'

[testenv:lesser]
pip_version = pip<19.0
commands = python ../check-pip-version.py '<19.0'

[testenv:greater]
pip_version = pip>19.0
commands = python ../check-pip-version.py '>19.0'

[testenv:lesser_eq]
pip_version = pip<=19.0
commands = python ../check-pip-version.py '<=19.0'

[testenv:greater_eq]
pip_version = pip>=19.0
commands = python ../check-pip-version.py '>=19.0'

[testenv:tilde_eq]
pip_version = pip~=19.0
commands = python ../check-pip-version.py '~=19.0'

[testenv:combo]
pip_version = pip!=19.0,<19.1,>10.0
commands = python ../check-pip-version.py '!=19.0,<19.1,>10.0'

[testenv:latest]
pip_version = pip
commands = python ../check-pip-version.py '>=19.1.1'
7 changes: 5 additions & 2 deletions tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import subprocess
import sys

import pytest

if sys.version_info.major == 2:
from backports import tempfile
else:
import tempfile

import pytest

HERE = os.path.realpath(os.path.dirname(__file__))
PACKAGE_DIR = os.path.realpath(os.path.join(HERE, '..'))

Expand All @@ -34,6 +34,9 @@
"test-environment-variable": {
"env": {"TOX_PIP_VERSION": "18.1"},
},
"test-version-specifiers": {
"env": {},
}
}

PYTEST_PARAMETERS = sorted(itertools.product(TOX_VERSIONS, CASES))
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ skipsdist = True

[testenv:flake8]
deps = flake8
commands = flake8 ./tox_pip_version
commands = flake8 ./tox_pip_version ./tests
14 changes: 12 additions & 2 deletions tox_pip_version/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ def _testenv_create(venv, action):
tox_testenv_create(venv, action)


def get_pip_package_version(pip_version):
pip_version = pip_version.lower().strip()
# tox.ini: pip_version = pip==19.0
if pip_version.startswith('pip'):
return pip_version
# tox.ini: pip_version = 19.0
return 'pip==%s' % pip_version


@tox.hookimpl
def tox_configure(config):
for env, envconfig in config.envconfigs.items():
Expand Down Expand Up @@ -53,10 +62,11 @@ def tox_testenv_create(venv, action):
# Use `pip_version` in tox.ini over the environment variable
pip_version = PER_ENV_PIP_VERSIONS.get(venvname, tox_pip_version_from_env)
if pip_version:
package = get_pip_package_version(pip_version)

# Is there a way to output this better? Genuine tox commands show up
# colorized (as bold white text)...
print("%s: pip_version = %s" % (venvname, pip_version))
package = "pip==%s" % pip_version
print("%s: pip_version is %s" % (venvname, package))

# "private" _install method - unstable interface?
venv._install([package], extraopts=["-U"], action=action)
Expand Down