diff --git a/.appveyor.yml b/.appveyor.yml index 58896ad84..3fa3f37c2 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -3,20 +3,30 @@ environment: PYTHON: "C:\\Python36" matrix: - # TODO: add "PIP: 20.0" after pip==20.1 being released + # TODO: change "20.1" to "20.0" after pip==20.1 being released + - TOXENV: py27-pip20.1-coverage + PIP: 20.1 - TOXENV: py27-piplatest-coverage PIP: latest + - TOXENV: py35-pip20.1 + PIP: 20.1 - TOXENV: py35-piplatest PIP: latest + - TOXENV: py36-pip20.1 + PIP: 20.1 - TOXENV: py36-piplatest PIP: latest + - TOXENV: py37-pip20.1 + PIP: 20.1 - TOXENV: py37-piplatest PIP: latest + - TOXENV: py38-pip20.1-coverage + PIP: 20.1 - TOXENV: py38-piplatest-coverage PIP: latest diff --git a/.travis.yml b/.travis.yml index c635a55ee..3c01ec74e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ python: env: # NOTE: keep this in sync with envlist in tox.ini for tox-travis. - # TODO: add PIP=20.0 after pip==20.1 being released + - PIP=20.1 # TODO: change to "20.0" after pip==20.1 being released - PIP=latest cache: false diff --git a/piptools/_compat/__init__.py b/piptools/_compat/__init__.py index 5950be430..fda80d571 100644 --- a/piptools/_compat/__init__.py +++ b/piptools/_compat/__init__.py @@ -4,7 +4,7 @@ import six -from .pip_compat import PIP_VERSION +from .pip_compat import PIP_VERSION, parse_requirements if six.PY2: from .tempfile import TemporaryDirectory diff --git a/piptools/_compat/pip_compat.py b/piptools/_compat/pip_compat.py index ccf0952b8..9508b7546 100644 --- a/piptools/_compat/pip_compat.py +++ b/piptools/_compat/pip_compat.py @@ -2,6 +2,26 @@ from __future__ import absolute_import import pip +from pip._internal.req import parse_requirements as _parse_requirements from pip._vendor.packaging.version import parse as parse_version PIP_VERSION = tuple(map(int, parse_version(pip.__version__).base_version.split("."))) + + +if PIP_VERSION[:2] <= (20, 0): + + def install_req_from_parsed_requirement(req, **kwargs): + return req + + +else: + from pip._internal.req.constructors import install_req_from_parsed_requirement + + +def parse_requirements( + filename, session, finder=None, options=None, constraint=False, isolated=False +): + for parsed_req in _parse_requirements( + filename, session, finder=finder, options=options, constraint=constraint + ): + yield install_req_from_parsed_requirement(parsed_req, isolated=isolated) diff --git a/piptools/repositories/local.py b/piptools/repositories/local.py index d85f5c541..7a0c920fc 100644 --- a/piptools/repositories/local.py +++ b/piptools/repositories/local.py @@ -5,6 +5,7 @@ from pip._internal.utils.hashes import FAVORITE_HASH +from .._compat import PIP_VERSION from .base import BaseRepository from piptools.utils import as_tuple, key_from_ireq, make_install_requirement @@ -74,7 +75,10 @@ def get_hashes(self, ireq): key = key_from_ireq(ireq) existing_pin = self.existing_pins.get(key) if existing_pin and ireq_satisfied_by_existing_pin(ireq, existing_pin): - hashes = existing_pin.options.get("hashes", {}) + if PIP_VERSION[:2] <= (20, 0): + hashes = existing_pin.options.get("hashes", {}) + else: + hashes = existing_pin.hash_options hexdigests = hashes.get(FAVORITE_HASH) if hexdigests: return { diff --git a/piptools/repositories/pypi.py b/piptools/repositories/pypi.py index f0b562cf8..9802cb6f1 100644 --- a/piptools/repositories/pypi.py +++ b/piptools/repositories/pypi.py @@ -19,7 +19,7 @@ from pip._internal.utils.temp_dir import TempDirectory, global_tempdir_manager from pip._internal.utils.urls import path_to_url, url_to_path -from .._compat import TemporaryDirectory, contextlib +from .._compat import PIP_VERSION, TemporaryDirectory, contextlib from ..click import progressbar from ..exceptions import NoCandidateFound from ..logging import log @@ -172,7 +172,8 @@ def resolve_reqs(self, download_dir, ireq, wheel_cache): ) results = resolver._resolve_one(reqset, ireq) - reqset.cleanup_files() + if PIP_VERSION[:2] <= (20, 0): + reqset.cleanup_files() return set(results) @@ -208,21 +209,23 @@ def get_dependencies(self, ireq): if not os.path.isdir(self._wheel_download_dir): os.makedirs(self._wheel_download_dir) - wheel_cache = WheelCache(self._cache_dir, self.options.format_control) - prev_tracker = os.environ.get("PIP_REQ_TRACKER") - try: - with global_tempdir_manager(): + with global_tempdir_manager(): + wheel_cache = WheelCache(self._cache_dir, self.options.format_control) + prev_tracker = os.environ.get("PIP_REQ_TRACKER") + try: self._dependencies_cache[ireq] = self.resolve_reqs( download_dir, ireq, wheel_cache ) - finally: - if "PIP_REQ_TRACKER" in os.environ: - if prev_tracker: - os.environ["PIP_REQ_TRACKER"] = prev_tracker - else: - del os.environ["PIP_REQ_TRACKER"] - - wheel_cache.cleanup() + finally: + if "PIP_REQ_TRACKER" in os.environ: + if prev_tracker: + os.environ["PIP_REQ_TRACKER"] = prev_tracker + else: + del os.environ["PIP_REQ_TRACKER"] + + if PIP_VERSION[:2] <= (20, 0): + wheel_cache.cleanup() + return self._dependencies_cache[ireq] def get_hashes(self, ireq): diff --git a/piptools/scripts/compile.py b/piptools/scripts/compile.py index 0572cd3fc..e379c183b 100755 --- a/piptools/scripts/compile.py +++ b/piptools/scripts/compile.py @@ -8,9 +8,9 @@ from click.utils import safecall from pip._internal.commands import create_command from pip._internal.req.constructors import install_req_from_line -from pip._internal.req.req_file import parse_requirements from .. import click +from .._compat import parse_requirements from ..cache import DependencyCache from ..exceptions import PipToolsError from ..locations import CACHE_DIR diff --git a/piptools/scripts/sync.py b/piptools/scripts/sync.py index 686eb7df8..94f738b59 100755 --- a/piptools/scripts/sync.py +++ b/piptools/scripts/sync.py @@ -6,10 +6,10 @@ import sys from pip._internal.commands import create_command -from pip._internal.req.req_file import parse_requirements from pip._internal.utils.misc import get_installed_distributions from .. import click, sync +from .._compat import parse_requirements from ..exceptions import PipToolsError from ..logging import log from ..repositories import PyPIRepository diff --git a/piptools/utils.py b/piptools/utils.py index c149a2478..a77e33cf5 100644 --- a/piptools/utils.py +++ b/piptools/utils.py @@ -10,6 +10,7 @@ from pip._internal.req.constructors import install_req_from_line from six.moves import shlex_quote +from ._compat import PIP_VERSION from .click import style UNSAFE_PACKAGES = {"setuptools", "distribute", "pip"} @@ -278,7 +279,10 @@ def get_hashes_from_ireq(ireq): in the requirement options. """ result = [] - ireq_hashes = ireq.options.get("hashes", {}) + if PIP_VERSION[:2] <= (20, 0): + ireq_hashes = ireq.options.get("hashes", {}) + else: + ireq_hashes = ireq.hash_options for algorithm, hexdigests in ireq_hashes.items(): for hash_ in hexdigests: result.append("{}:{}".format(algorithm, hash_)) diff --git a/tests/test_repository_pypi.py b/tests/test_repository_pypi.py index 51c180658..c04608f16 100644 --- a/tests/test_repository_pypi.py +++ b/tests/test_repository_pypi.py @@ -6,6 +6,7 @@ from pip._internal.utils.urls import path_to_url from pip._vendor.requests import Session +from piptools._compat import PIP_VERSION from piptools.repositories import PyPIRepository from piptools.repositories.pypi import open_local_or_remote_file @@ -127,6 +128,7 @@ def test_pypirepo_source_dir_is_str(pypi_repository): assert isinstance(pypi_repository.source_dir, str) +@pytest.mark.skipif(PIP_VERSION[:2] > (20, 0), reason="Refactored in pip==20.1") @mock.patch("piptools.repositories.pypi.PyPIRepository.resolve_reqs") # to run offline @mock.patch("piptools.repositories.pypi.WheelCache") def test_wheel_cache_cleanup_called( diff --git a/tox.ini b/tox.ini index 9738b182f..41268ee36 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] envlist = # NOTE: keep this in sync with the env list in .travis.yml for tox-travis. - py{27,35,36,37,38,py,py3}-pip{20.0,latest,master}-coverage + py{27,35,36,37,38,py,py3}-pip{20.0,20.1,latest,master}-coverage checkqa readme skip_missing_interpreters = True @@ -13,10 +13,13 @@ extras = deps = pipmaster: -e git+https://github.com/pypa/pip.git@master#egg=pip pip20.0: pip==20.0.* + # TODO: change to "pip==20.1.*" after 20.1 being released + pip20.1: -e git+https://github.com/pypa/pip.git@master#egg=pip setenv = piplatest: PIP=latest pipmaster: PIP=master pip20.0: PIP==20.0 + pip20.1: PIP==20.1 coverage: PYTEST_ADDOPTS=--strict --doctest-modules --cov --cov-report=term-missing {env:PYTEST_ADDOPTS:} commands_pre = @@ -40,5 +43,6 @@ commands = twine check {distdir}/* [travis:env] PIP = 20.0: pip20.0 + 20.1: pip20.1 latest: piplatest master: pipmaster