Repository: jazzband/pip-tools

Issue:
pip-compile broken with pip 19.0
Describe the issue briefly here.

##### Environment Versions

1. OS Type
darwin
1. Python version: `$ python -V` 
Python 2.7.15
1. pip version:  `$ pip --version`
pip 19.0 from /Users/brandon/src/images/.venv/lib/python2.7/site-packages/pip (python 2.7)
1. pip-tools version: `$ pip-compile --version`
pip-compile, version 3.2.0

##### Steps to replicate

```sh
$ pip-compile --generate-hashes --upgrade --header --index --annotate --output-file $@ $<
Traceback (most recent call last):
  File "/Users/brandon/src/images/.venv/bin/pip-compile", line 10, in <module>
    sys.exit(cli())
  File "/Users/brandon/src/images/.venv/lib/python2.7/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/Users/brandon/src/images/.venv/lib/python2.7/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/Users/brandon/src/images/.venv/lib/python2.7/site-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/Users/brandon/src/images/.venv/lib/python2.7/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/Users/brandon/src/images/.venv/lib/python2.7/site-packages/piptools/scripts/compile.py", line 130, in cli
    repository = PyPIRepository(pip_options, session)
  File "/Users/brandon/src/images/.venv/lib/python2.7/site-packages/piptools/repositories/pypi.py", line 62, in __init__
    process_dependency_links=pip_options.process_dependency_links,
AttributeError: Values instance has no attribute 'process_dependency_links'



Discussion:
I'm having the same error when running `pip-compile` under Python 3.6.7, pip-tools==3.2.0, and pip==19.0. The problem doesn't happen with pip==18.1.

Resolving patch:
diff --git a/piptools/_compat/pip_compat.py b/piptools/_compat/pip_compat.py
--- a/piptools/_compat/pip_compat.py
+++ b/piptools/_compat/pip_compat.py
@@ -27,6 +27,7 @@ def do_import(module_path, subimport=None, old_path=None):
 user_cache_dir = do_import('utils.appdirs', 'user_cache_dir')
 FAVORITE_HASH = do_import('utils.hashes', 'FAVORITE_HASH')
 is_file_url = do_import('download', 'is_file_url')
+path_to_url = do_import('download', 'path_to_url')
 url_to_path = do_import('download', 'url_to_path')
 PackageFinder = do_import('index', 'PackageFinder')
 FormatControl = do_import('index', 'FormatControl')
diff --git a/piptools/repositories/pypi.py b/piptools/repositories/pypi.py
--- a/piptools/repositories/pypi.py
+++ b/piptools/repositories/pypi.py
@@ -7,6 +7,9 @@
 from contextlib import contextmanager
 from shutil import rmtree
 
+import pip
+import pkg_resources
+
 from .._compat import (
     is_file_url,
     url_to_path,
@@ -54,14 +57,19 @@ def __init__(self, pip_options, session):
         if pip_options.no_index:
             index_urls = []
 
-        self.finder = PackageFinder(
-            find_links=pip_options.find_links,
-            index_urls=index_urls,
-            trusted_hosts=pip_options.trusted_hosts,
-            allow_all_prereleases=pip_options.pre,
-            process_dependency_links=pip_options.process_dependency_links,
-            session=self.session,
-        )
+        finder_kwargs = {
+            "find_links": pip_options.find_links,
+            "index_urls": index_urls,
+            "trusted_hosts": pip_options.trusted_hosts,
+            "allow_all_prereleases": pip_options.pre,
+            "session": self.session,
+        }
+
+        # pip 19.0 has removed process_dependency_links from the PackageFinder constructor
+        if pkg_resources.parse_version(pip.__version__) < pkg_resources.parse_version('19.0'):
+            finder_kwargs["process_dependency_links"] = pip_options.process_dependency_links
+
+        self.finder = PackageFinder(**finder_kwargs)
 
         # Caches
         # stores project_name => InstallationCandidate mappings for all


Test patch:
diff --git a/tests/test_cli.py b/tests/test_cli.py
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -1,6 +1,5 @@
 import os
 from textwrap import dedent
-from six.moves.urllib.request import pathname2url
 import subprocess
 import sys
 import mock
@@ -9,6 +8,7 @@
 
 import pytest
 
+from piptools._compat.pip_compat import path_to_url
 from piptools.repositories import PyPIRepository
 from piptools.scripts.compile import cli
 from piptools.scripts.sync import cli as sync_cli
@@ -242,7 +242,7 @@ def test_sync_quiet(tmpdir):
 def test_editable_package(tmpdir):
     """ piptools can compile an editable """
     fake_package_dir = os.path.join(os.path.split(__file__)[0], 'test_data', 'small_fake_package')
-    fake_package_dir = 'file:' + pathname2url(fake_package_dir)
+    fake_package_dir = path_to_url(fake_package_dir)
     runner = CliRunner()
     with runner.isolated_filesystem():
         with open('requirements.in', 'w') as req_in:
@@ -278,7 +278,7 @@ def test_locally_available_editable_package_is_not_archived_in_cache_dir(tmpdir)
     cache_dir = tmpdir.mkdir('cache_dir')
 
     fake_package_dir = os.path.join(os.path.split(__file__)[0], 'test_data', 'small_fake_package')
-    fake_package_dir = 'file:' + pathname2url(fake_package_dir)
+    fake_package_dir = path_to_url(fake_package_dir)
 
     with mock.patch('piptools.repositories.pypi.CACHE_DIR', new=str(cache_dir)):
         runner = CliRunner()
@@ -360,7 +360,7 @@ def test_upgrade_packages_version_option(tmpdir):
 def test_generate_hashes_with_editable():
     small_fake_package_dir = os.path.join(
         os.path.split(__file__)[0], 'test_data', 'small_fake_package')
-    small_fake_package_url = 'file:' + pathname2url(small_fake_package_dir)
+    small_fake_package_url = path_to_url(small_fake_package_dir)
     runner = CliRunner()
     with runner.isolated_filesystem():
         with open('requirements.in', 'w') as fp: