pip tools 3.5.0 to 4.0.0 - freedomofpress/securedrop-builder GitHub Wiki

0018485119986aebef136470c51bde85da736732079c687ab1d4c5eb5237e694  pip-tools-3.5.0.tar.gz
3b9fb8948340eff5869ac83dc85e3a7c62b837cec33609c45c48c2e5aa740ba5  pip-tools-4.0.0.tar.gz

--- pip-tools-3.5.0.tar.gz
+++ pip-tools-4.0.0.tar.gz
β”œβ”€β”€ metadata
β”‚ @@ -1 +1 @@
β”‚ -gzip compressed data, was "dist/pip-tools-3.5.0.tar", last modified: Wed Mar 13 06:14:00 2019, max compression
β”‚ +gzip compressed data, was "dist/pip-tools-4.0.0.tar", last modified: Thu Jul 25 02:48:28 2019, max compression
β”‚   --- pip-tools-3.5.0.tar
β”œβ”€β”€ +++ pip-tools-4.0.0.tar
β”œβ”€β”€ file list
β”‚ β”‚ @@ -1,93 +1,95 @@
β”‚ β”‚ -drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-03-13 06:14:00.000000 pip-tools-3.5.0/
β”‚ β”‚ -drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-03-13 06:14:00.000000 pip-tools-3.5.0/.github/
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      514 2019-03-13 06:13:38.000000 pip-tools-3.5.0/.github/PULL_REQUEST_TEMPLATE.md
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      291 2019-03-13 06:13:38.000000 pip-tools-3.5.0/.github/ISSUE_TEMPLATE.md
β”‚ β”‚ -drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-03-13 06:14:00.000000 pip-tools-3.5.0/examples/
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      132 2019-03-13 06:13:38.000000 pip-tools-3.5.0/examples/django.in
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)       49 2019-03-13 06:13:38.000000 pip-tools-3.5.0/examples/sentry.in
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)       19 2019-03-13 06:13:38.000000 pip-tools-3.5.0/examples/hypothesis.in
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      168 2019-03-13 06:13:38.000000 pip-tools-3.5.0/examples/protection.in
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)       49 2019-03-13 06:13:38.000000 pip-tools-3.5.0/examples/flask.in
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      121 2019-03-13 06:13:38.000000 pip-tools-3.5.0/.flake8
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)    11632 2019-03-13 06:14:00.000000 pip-tools-3.5.0/PKG-INFO
β”‚ β”‚ -drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-03-13 06:14:00.000000 pip-tools-3.5.0/img/
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)    23961 2019-03-13 06:13:38.000000 pip-tools-3.5.0/img/pip-tools-overview.png
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     1295 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tox.ini
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      253 2019-03-13 06:13:38.000000 pip-tools-3.5.0/.gitignore
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     2821 2019-03-13 06:13:38.000000 pip-tools-3.5.0/CONTRIBUTING.md
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      229 2019-03-13 06:14:00.000000 pip-tools-3.5.0/setup.cfg
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     2081 2019-03-13 06:13:38.000000 pip-tools-3.5.0/.travis.yml
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     1500 2019-03-13 06:13:38.000000 pip-tools-3.5.0/LICENSE
β”‚ β”‚ -drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-03-13 06:14:00.000000 pip-tools-3.5.0/pip_tools.egg-info/
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)    11632 2019-03-13 06:13:59.000000 pip-tools-3.5.0/pip_tools.egg-info/PKG-INFO
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)        1 2019-03-13 06:13:59.000000 pip-tools-3.5.0/pip_tools.egg-info/dependency_links.txt
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)        9 2019-03-13 06:13:59.000000 pip-tools-3.5.0/pip_tools.egg-info/top_level.txt
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)        1 2019-03-13 06:13:59.000000 pip-tools-3.5.0/pip_tools.egg-info/not-zip-safe
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     2099 2019-03-13 06:14:00.000000 pip-tools-3.5.0/pip_tools.egg-info/SOURCES.txt
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)       13 2019-03-13 06:13:59.000000 pip-tools-3.5.0/pip_tools.egg-info/requires.txt
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)       99 2019-03-13 06:13:59.000000 pip-tools-3.5.0/pip_tools.egg-info/entry_points.txt
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      126 2019-03-13 06:13:38.000000 pip-tools-3.5.0/.coveragerc
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     8572 2019-03-13 06:13:38.000000 pip-tools-3.5.0/README.rst
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     2736 2019-03-13 06:13:38.000000 pip-tools-3.5.0/.appveyor.yml
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)       23 2019-03-13 06:13:38.000000 pip-tools-3.5.0/dev-requirements.txt
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)    13361 2019-03-13 06:13:38.000000 pip-tools-3.5.0/CHANGELOG.md
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     1904 2019-03-13 06:13:38.000000 pip-tools-3.5.0/setup.py
β”‚ β”‚ -drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-03-13 06:14:00.000000 pip-tools-3.5.0/tests/
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)    12230 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_sync.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     1357 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_top_level_editable.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     3158 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_cache.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     4967 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_resolver.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     4664 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_repository_local.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     3952 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_cli_sync.py
β”‚ β”‚ -drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-03-13 06:14:00.000000 pip-tools-3.5.0/tests/test_data/
β”‚ β”‚ -drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-03-13 06:14:00.000000 pip-tools-3.5.0/tests/test_data/fake_package/
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      603 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_data/fake_package/setup.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     2753 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_data/fake-index.json
β”‚ β”‚ -drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-03-13 06:14:00.000000 pip-tools-3.5.0/tests/test_data/minimal_wheels/
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     1631 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_data/minimal_wheels/small_fake_b-0.2-py2.py3-none-any.whl
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     1632 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_data/minimal_wheels/small_fake_a-0.2-py2.py3-none-any.whl
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     1631 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_data/minimal_wheels/small_fake_a-0.1-py2.py3-none-any.whl
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     1124 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_data/minimal_wheels/small_fake_with_deps-0.1-py2.py3-none-any.whl
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     1635 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_data/minimal_wheels/small_fake_b-0.1-py2.py3-none-any.whl
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     1026 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_data/minimal_wheels/small_fake_b-0.3-py2.py3-none-any.whl
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)       56 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_data/fake-editables.json
β”‚ β”‚ -drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-03-13 06:14:00.000000 pip-tools-3.5.0/tests/test_data/small_fake_package/
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      142 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_data/small_fake_package/setup.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     2514 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_repositories.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      352 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/utils.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     7838 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_writer.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     4835 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_repository_pypi.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     1348 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_minimal_upgrade.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      110 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/__init__.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)    18158 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_cli_compile.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     3494 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/conftest.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     2528 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_fake_index.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     4382 2019-03-13 06:13:38.000000 pip-tools-3.5.0/tests/test_utils.py
β”‚ β”‚ -drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-03-13 06:14:00.000000 pip-tools-3.5.0/piptools/
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     5516 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/cache.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)    12856 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/resolver.py
β”‚ β”‚ -drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-03-13 06:14:00.000000 pip-tools-3.5.0/piptools/_compat/
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     4562 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/_compat/contextlib.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     2826 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/_compat/tempfile.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     2190 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/_compat/pip_compat.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      715 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/_compat/__init__.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      128 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/click.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)    21836 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/io.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      891 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/logging.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      266 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/__main__.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     5794 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/writer.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     2058 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/exceptions.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      711 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/locations.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     7440 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/utils.py
β”‚ β”‚ -drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-03-13 06:14:00.000000 pip-tools-3.5.0/piptools/scripts/
β”‚ β”‚ --rwxrwxr-x   0 travis    (2000) travis    (2000)    11732 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/scripts/compile.py
β”‚ β”‚ --rwxrwxr-x   0 travis    (2000) travis    (2000)     3260 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/scripts/sync.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)        0 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/scripts/__init__.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)      916 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/pip.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     5714 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/sync.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)        0 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/__init__.py
β”‚ β”‚ -drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-03-13 06:14:00.000000 pip-tools-3.5.0/piptools/repositories/
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)    12742 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/repositories/pypi.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     2878 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/repositories/local.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)     1498 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/repositories/base.py
β”‚ β”‚ --rw-rw-r--   0 travis    (2000) travis    (2000)       95 2019-03-13 06:13:38.000000 pip-tools-3.5.0/piptools/repositories/__init__.py
β”‚ β”‚ +drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:28.000000 pip-tools-4.0.0/
β”‚ β”‚ +drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:28.000000 pip-tools-4.0.0/.github/
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      514 2019-07-25 02:48:06.000000 pip-tools-4.0.0/.github/PULL_REQUEST_TEMPLATE.md
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      291 2019-07-25 02:48:06.000000 pip-tools-4.0.0/.github/ISSUE_TEMPLATE.md
β”‚ β”‚ +drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:28.000000 pip-tools-4.0.0/examples/
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      134 2019-07-25 02:48:06.000000 pip-tools-4.0.0/examples/django.in
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)       49 2019-07-25 02:48:06.000000 pip-tools-4.0.0/examples/sentry.in
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)       19 2019-07-25 02:48:06.000000 pip-tools-4.0.0/examples/hypothesis.in
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      168 2019-07-25 02:48:06.000000 pip-tools-4.0.0/examples/protection.in
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)       49 2019-07-25 02:48:06.000000 pip-tools-4.0.0/examples/flask.in
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)    13707 2019-07-25 02:48:28.000000 pip-tools-4.0.0/PKG-INFO
β”‚ β”‚ +drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:28.000000 pip-tools-4.0.0/img/
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)    23961 2019-07-25 02:48:06.000000 pip-tools-4.0.0/img/pip-tools-overview.png
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     1399 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tox.ini
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      253 2019-07-25 02:48:06.000000 pip-tools-4.0.0/.gitignore
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     2911 2019-07-25 02:48:06.000000 pip-tools-4.0.0/CONTRIBUTING.md
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)       46 2019-07-25 02:48:06.000000 pip-tools-4.0.0/.bandit
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      627 2019-07-25 02:48:28.000000 pip-tools-4.0.0/setup.cfg
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)       26 2019-07-25 02:48:06.000000 pip-tools-4.0.0/.fussyfox.yml
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     2304 2019-07-25 02:48:06.000000 pip-tools-4.0.0/.travis.yml
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     1500 2019-07-25 02:48:06.000000 pip-tools-4.0.0/LICENSE
β”‚ β”‚ +drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:28.000000 pip-tools-4.0.0/pip_tools.egg-info/
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)    13707 2019-07-25 02:48:28.000000 pip-tools-4.0.0/pip_tools.egg-info/PKG-INFO
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)        1 2019-07-25 02:48:28.000000 pip-tools-4.0.0/pip_tools.egg-info/dependency_links.txt
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)        9 2019-07-25 02:48:28.000000 pip-tools-4.0.0/pip_tools.egg-info/top_level.txt
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)        1 2019-07-25 02:48:28.000000 pip-tools-4.0.0/pip_tools.egg-info/not-zip-safe
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     2201 2019-07-25 02:48:28.000000 pip-tools-4.0.0/pip_tools.egg-info/SOURCES.txt
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)       13 2019-07-25 02:48:28.000000 pip-tools-4.0.0/pip_tools.egg-info/requires.txt
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)       99 2019-07-25 02:48:28.000000 pip-tools-4.0.0/pip_tools.egg-info/entry_points.txt
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      126 2019-07-25 02:48:06.000000 pip-tools-4.0.0/.coveragerc
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)    10323 2019-07-25 02:48:06.000000 pip-tools-4.0.0/README.rst
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     2513 2019-07-25 02:48:06.000000 pip-tools-4.0.0/.appveyor.yml
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)       23 2019-07-25 02:48:06.000000 pip-tools-4.0.0/dev-requirements.txt
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)    16152 2019-07-25 02:48:06.000000 pip-tools-4.0.0/CHANGELOG.md
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     1892 2019-07-25 02:48:06.000000 pip-tools-4.0.0/setup.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      546 2019-07-25 02:48:06.000000 pip-tools-4.0.0/.pre-commit-config.yaml
β”‚ β”‚ +drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:28.000000 pip-tools-4.0.0/tests/
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)    13607 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_sync.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     1324 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_top_level_editable.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     3334 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_cache.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)    11167 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_resolver.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      390 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_locations.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     4342 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_repository_local.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     4548 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_cli_sync.py
β”‚ β”‚ +drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:28.000000 pip-tools-4.0.0/tests/test_data/
β”‚ β”‚ +drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:28.000000 pip-tools-4.0.0/tests/test_data/fake_package/
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      599 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_data/fake_package/setup.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     2777 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_data/fake-index.json
β”‚ β”‚ +drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:28.000000 pip-tools-4.0.0/tests/test_data/minimal_wheels/
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     1631 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_data/minimal_wheels/small_fake_b-0.2-py2.py3-none-any.whl
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     1632 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_data/minimal_wheels/small_fake_a-0.2-py2.py3-none-any.whl
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     1631 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_data/minimal_wheels/small_fake_a-0.1-py2.py3-none-any.whl
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     1124 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_data/minimal_wheels/small_fake_with_deps-0.1-py2.py3-none-any.whl
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     1635 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_data/minimal_wheels/small_fake_b-0.1-py2.py3-none-any.whl
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     1206 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_data/minimal_wheels/small_fake_a-0.3b1-py2.py3-none-any.whl
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     1026 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_data/minimal_wheels/small_fake_b-0.3-py2.py3-none-any.whl
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)       56 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_data/fake-editables.json
β”‚ β”‚ +drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:28.000000 pip-tools-4.0.0/tests/test_data/small_fake_package/
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      149 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_data/small_fake_package/setup.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     2019 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_repositories.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      337 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/utils.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     9594 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_writer.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     6307 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_repository_pypi.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     1618 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_minimal_upgrade.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      110 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/__init__.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)    24680 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_cli_compile.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     4100 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/conftest.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     2643 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_fake_index.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)    10571 2019-07-25 02:48:06.000000 pip-tools-4.0.0/tests/test_utils.py
β”‚ β”‚ +drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:28.000000 pip-tools-4.0.0/piptools/
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     5300 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/cache.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)    14307 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/resolver.py
β”‚ β”‚ +drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:28.000000 pip-tools-4.0.0/piptools/_compat/
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      602 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/_compat/contextlib.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     2862 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/_compat/tempfile.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     2621 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/_compat/pip_compat.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      721 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/_compat/__init__.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      128 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/click.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      800 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/logging.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      267 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/__main__.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     7646 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/writer.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     1907 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/exceptions.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      756 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/locations.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)    10968 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/utils.py
β”‚ β”‚ +drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:28.000000 pip-tools-4.0.0/piptools/scripts/
β”‚ β”‚ +-rwxrwxr-x   0 travis    (2000) travis    (2000)    12606 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/scripts/compile.py
β”‚ β”‚ +-rwxrwxr-x   0 travis    (2000) travis    (2000)     4110 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/scripts/sync.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/scripts/__init__.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     6614 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/sync.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)      379 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/__init__.py
β”‚ β”‚ +drwxrwxr-x   0 travis    (2000) travis    (2000)        0 2019-07-25 02:48:28.000000 pip-tools-4.0.0/piptools/repositories/
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)    15077 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/repositories/pypi.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     2911 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/repositories/local.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)     1474 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/repositories/base.py
β”‚ β”‚ +-rw-rw-r--   0 travis    (2000) travis    (2000)       95 2019-07-25 02:48:06.000000 pip-tools-4.0.0/piptools/repositories/__init__.py
β”‚   --- pip-tools-3.5.0/tests/test_data/fake-index.json
β”œβ”€β”€ +++ pip-tools-4.0.0/tests/test_data/fake-index.json
β”‚β”„ Files similar despite different names (difference score: 4)
β”‚   --- /tmp/tmpdjr9hppa_diffoscope/0/44
β”œβ”€β”€ +++ /tmp/tmp9p46bj79_diffoscope/0/47
β”‚ β”‚ β”‚ @@ -219,14 +219,17 @@
β”‚ β”‚ β”‚      },
β”‚ β”‚ β”‚      "setuptools": {
β”‚ β”‚ β”‚          "34.0.0": {
β”‚ β”‚ β”‚              "": [
β”‚ β”‚ β”‚                  "packaging>=16.8",
β”‚ β”‚ β”‚                  "appdirs>=1.4.0"
β”‚ β”‚ β”‚              ]
β”‚ β”‚ β”‚ +        },
β”‚ β”‚ β”‚ +        "35.0.0": {
β”‚ β”‚ β”‚ +            "": []
β”‚ β”‚ β”‚          }
β”‚ β”‚ β”‚      },
β”‚ β”‚ β”‚      "six": {
β”‚ β”‚ β”‚          "1.6.1": {
β”‚ β”‚ β”‚              "": []
β”‚ β”‚ β”‚          },
β”‚ β”‚ β”‚          "1.9.0": {
β”‚   --- pip-tools-3.5.0/LICENSE
β”œβ”€β”€ +++ pip-tools-4.0.0/LICENSE
β”‚β”„ Files similar despite different names (difference score: 0)
β”‚   --- pip-tools-3.5.0/.github/PULL_REQUEST_TEMPLATE.md
β”œβ”€β”€ +++ pip-tools-4.0.0/.github/PULL_REQUEST_TEMPLATE.md
β”‚β”„ Files similar despite different names (difference score: 0)
β”‚   --- pip-tools-3.5.0/piptools/resolver.py
β”œβ”€β”€ +++ pip-tools-4.0.0/piptools/resolver.py
β”‚β”„ Files similar despite different names (difference score: 59)
β”‚ β”‚ @@ -1,33 +1,39 @@
β”‚ β”‚  # coding: utf-8
β”‚ β”‚ -from __future__ import (absolute_import, division, print_function,
β”‚ β”‚ -                        unicode_literals)
β”‚ β”‚ +from __future__ import absolute_import, division, print_function, unicode_literals
β”‚ β”‚  
β”‚ β”‚  import copy
β”‚ β”‚ +import os
β”‚ β”‚  from functools import partial
β”‚ β”‚  from itertools import chain, count
β”‚ β”‚ -import os
β”‚ β”‚ -
β”‚ β”‚ -from ._compat import install_req_from_line
β”‚ β”‚  
β”‚ β”‚  from . import click
β”‚ β”‚ +from ._compat import install_req_from_line
β”‚ β”‚  from .cache import DependencyCache
β”‚ β”‚ -from .exceptions import UnsupportedConstraint
β”‚ β”‚  from .logging import log
β”‚ β”‚ -from .utils import (format_requirement, format_specifier, full_groupby,
β”‚ β”‚ -                    is_pinned_requirement, key_from_ireq, key_from_req, UNSAFE_PACKAGES)
β”‚ β”‚ +from .utils import (
β”‚ β”‚ +    UNSAFE_PACKAGES,
β”‚ β”‚ +    format_requirement,
β”‚ β”‚ +    format_specifier,
β”‚ β”‚ +    full_groupby,
β”‚ β”‚ +    is_pinned_requirement,
β”‚ β”‚ +    is_url_requirement,
β”‚ β”‚ +    key_from_ireq,
β”‚ β”‚ +    key_from_req,
β”‚ β”‚ +)
β”‚ β”‚  
β”‚ β”‚ -green = partial(click.style, fg='green')
β”‚ β”‚ -magenta = partial(click.style, fg='magenta')
β”‚ β”‚ +green = partial(click.style, fg="green")
β”‚ β”‚ +magenta = partial(click.style, fg="magenta")
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  class RequirementSummary(object):
β”‚ β”‚      """
β”‚ β”‚      Summary of a requirement's properties for comparison purposes.
β”‚ β”‚      """
β”‚ β”‚ +
β”‚ β”‚      def __init__(self, ireq):
β”‚ β”‚          self.req = ireq.req
β”‚ β”‚          self.key = key_from_req(ireq.req)
β”‚ β”‚          self.extras = str(sorted(ireq.extras))
β”‚ β”‚          self.specifier = str(ireq.specifier)
β”‚ β”‚  
β”‚ β”‚      def __eq__(self, other):
β”‚ β”‚ @@ -36,16 +42,69 @@
β”‚ β”‚      def __hash__(self):
β”‚ β”‚          return hash(str(self))
β”‚ β”‚  
β”‚ β”‚      def __str__(self):
β”‚ β”‚          return repr([self.key, self.specifier, self.extras])
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚ +def combine_install_requirements(ireqs):
β”‚ β”‚ +    """
β”‚ β”‚ +    Return a single install requirement that reflects a combination of
β”‚ β”‚ +    all the inputs.
β”‚ β”‚ +    """
β”‚ β”‚ +    # We will store the source ireqs in a _source_ireqs attribute;
β”‚ β”‚ +    # if any of the inputs have this, then use those sources directly.
β”‚ β”‚ +    source_ireqs = []
β”‚ β”‚ +    for ireq in ireqs:
β”‚ β”‚ +        source_ireqs.extend(getattr(ireq, "_source_ireqs", [ireq]))
β”‚ β”‚ +    source_ireqs.sort(key=str)
β”‚ β”‚ +
β”‚ β”‚ +    # deepcopy the accumulator so as to not modify the inputs
β”‚ β”‚ +    combined_ireq = copy.deepcopy(source_ireqs[0])
β”‚ β”‚ +    for ireq in source_ireqs[1:]:
β”‚ β”‚ +        # NOTE we may be losing some info on dropped reqs here
β”‚ β”‚ +        combined_ireq.req.specifier &= ireq.req.specifier
β”‚ β”‚ +        combined_ireq.constraint &= ireq.constraint
β”‚ β”‚ +        # Return a sorted, de-duped tuple of extras
β”‚ β”‚ +        combined_ireq.extras = tuple(
β”‚ β”‚ +            sorted(set(tuple(combined_ireq.extras) + tuple(ireq.extras)))
β”‚ β”‚ +        )
β”‚ β”‚ +
β”‚ β”‚ +    # InstallRequirements objects are assumed to come from only one source, and
β”‚ β”‚ +    # so they support only a single comes_from entry. This function breaks this
β”‚ β”‚ +    # model. As a workaround, we deterministically choose a single source for
β”‚ β”‚ +    # the comes_from entry, and add an extra _source_ireqs attribute to keep
β”‚ β”‚ +    # track of multiple sources for use within pip-tools.
β”‚ β”‚ +    if len(source_ireqs) > 1:
β”‚ β”‚ +        if any(ireq.comes_from is None for ireq in source_ireqs):
β”‚ β”‚ +            # None indicates package was directly specified.
β”‚ β”‚ +            combined_ireq.comes_from = None
β”‚ β”‚ +        else:
β”‚ β”‚ +            # Populate the comes_from field from one of the sources.
β”‚ β”‚ +            # Requirement input order is not stable, so we need to sort:
β”‚ β”‚ +            # We choose the shortest entry in order to keep the printed
β”‚ β”‚ +            # representation as concise as possible.
β”‚ β”‚ +            combined_ireq.comes_from = min(
β”‚ β”‚ +                (ireq.comes_from for ireq in source_ireqs),
β”‚ β”‚ +                key=lambda x: (len(str(x)), str(x)),
β”‚ β”‚ +            )
β”‚ β”‚ +        combined_ireq._source_ireqs = source_ireqs
β”‚ β”‚ +    return combined_ireq
β”‚ β”‚ +
β”‚ β”‚ +
β”‚ β”‚  class Resolver(object):
β”‚ β”‚ -    def __init__(self, constraints, repository, cache=None, prereleases=False, clear_caches=False, allow_unsafe=False):
β”‚ β”‚ +    def __init__(
β”‚ β”‚ +        self,
β”‚ β”‚ +        constraints,
β”‚ β”‚ +        repository,
β”‚ β”‚ +        cache=None,
β”‚ β”‚ +        prereleases=False,
β”‚ β”‚ +        clear_caches=False,
β”‚ β”‚ +        allow_unsafe=False,
β”‚ β”‚ +    ):
β”‚ β”‚          """
β”‚ β”‚          This class resolves a given set of constraints (a collection of
β”‚ β”‚          InstallRequirement objects) by consulting the given Repository and the
β”‚ β”‚          DependencyCache.
β”‚ β”‚          """
β”‚ β”‚          self.our_constraints = set(constraints)
β”‚ β”‚          self.their_constraints = set()
β”‚ β”‚ @@ -56,21 +115,24 @@
β”‚ β”‚          self.prereleases = prereleases
β”‚ β”‚          self.clear_caches = clear_caches
β”‚ β”‚          self.allow_unsafe = allow_unsafe
β”‚ β”‚          self.unsafe_constraints = set()
β”‚ β”‚  
β”‚ β”‚      @property
β”‚ β”‚      def constraints(self):
β”‚ β”‚ -        return set(self._group_constraints(chain(self.our_constraints,
β”‚ β”‚ -                                                 self.their_constraints)))
β”‚ β”‚ +        return set(
β”‚ β”‚ +            self._group_constraints(chain(self.our_constraints, self.their_constraints))
β”‚ β”‚ +        )
β”‚ β”‚  
β”‚ β”‚      def resolve_hashes(self, ireqs):
β”‚ β”‚          """
β”‚ β”‚          Finds acceptable hashes for all of the given InstallRequirements.
β”‚ β”‚          """
β”‚ β”‚ +        log.debug("")
β”‚ β”‚ +        log.debug("Generating hashes:")
β”‚ β”‚          with self.repository.allow_all_wheels():
β”‚ β”‚              return {ireq: self.repository.get_hashes(ireq) for ireq in ireqs}
β”‚ β”‚  
β”‚ β”‚      def resolve(self, max_rounds=10):
β”‚ β”‚          """
β”‚ β”‚          Finds concrete package versions for all the given InstallRequirements
β”‚ β”‚          and their recursive dependencies.  The end result is a flat list of
β”‚ β”‚ @@ -80,53 +142,69 @@
β”‚ β”‚          anymore.  Protects against infinite loops by breaking out after a max
β”‚ β”‚          number rounds.
β”‚ β”‚          """
β”‚ β”‚          if self.clear_caches:
β”‚ β”‚              self.dependency_cache.clear()
β”‚ β”‚              self.repository.clear_caches()
β”‚ β”‚  
β”‚ β”‚ -        self.check_constraints(chain(self.our_constraints,
β”‚ β”‚ -                                     self.their_constraints))
β”‚ β”‚ -
β”‚ β”‚          # Ignore existing packages
β”‚ β”‚ -        os.environ[str('PIP_EXISTS_ACTION')] = str('i')  # NOTE: str() wrapping necessary for Python 2/3 compat
β”‚ β”‚ -        for current_round in count(start=1):
β”‚ β”‚ +        os.environ[str("PIP_EXISTS_ACTION")] = str(
β”‚ β”‚ +            "i"
β”‚ β”‚ +        )  # NOTE: str() wrapping necessary for Python 2/3 compat
β”‚ β”‚ +        for current_round in count(start=1):  # pragma: no branch
β”‚ β”‚              if current_round > max_rounds:
β”‚ β”‚ -                raise RuntimeError('No stable configuration of concrete packages '
β”‚ β”‚ -                                   'could be found for the given constraints after '
β”‚ β”‚ -                                   '%d rounds of resolving.\n'
β”‚ β”‚ -                                   'This is likely a bug.' % max_rounds)
β”‚ β”‚ +                raise RuntimeError(
β”‚ β”‚ +                    "No stable configuration of concrete packages "
β”‚ β”‚ +                    "could be found for the given constraints after "
β”‚ β”‚ +                    "%d rounds of resolving.\n"
β”‚ β”‚ +                    "This is likely a bug." % max_rounds
β”‚ β”‚ +                )
β”‚ β”‚  
β”‚ β”‚ -            log.debug('')
β”‚ β”‚ -            log.debug(magenta('{:^60}'.format('ROUND {}'.format(current_round))))
β”‚ β”‚ +            log.debug("")
β”‚ β”‚ +            log.debug(magenta("{:^60}".format("ROUND {}".format(current_round))))
β”‚ β”‚              has_changed, best_matches = self._resolve_one_round()
β”‚ β”‚ -            log.debug('-' * 60)
β”‚ β”‚ -            log.debug('Result of round {}: {}'.format(current_round,
β”‚ β”‚ -                                                      'not stable' if has_changed else 'stable, done'))
β”‚ β”‚ +            log.debug("-" * 60)
β”‚ β”‚ +            log.debug(
β”‚ β”‚ +                "Result of round {}: {}".format(
β”‚ β”‚ +                    current_round, "not stable" if has_changed else "stable, done"
β”‚ β”‚ +                )
β”‚ β”‚ +            )
β”‚ β”‚              if not has_changed:
β”‚ β”‚                  break
β”‚ β”‚  
β”‚ β”‚              # If a package version (foo==2.0) was built in a previous round,
β”‚ β”‚              # and in this round a different version of foo needs to be built
β”‚ β”‚              # (i.e. foo==1.0), the directory will exist already, which will
β”‚ β”‚              # cause a pip build failure.  The trick is to start with a new
β”‚ β”‚              # build cache dir for every round, so this can never happen.
β”‚ β”‚              self.repository.freshen_build_caches()
β”‚ β”‚  
β”‚ β”‚ -        del os.environ['PIP_EXISTS_ACTION']
β”‚ β”‚ +        del os.environ["PIP_EXISTS_ACTION"]
β”‚ β”‚ +
β”‚ β”‚          # Only include hard requirements and not pip constraints
β”‚ β”‚ -        return {req for req in best_matches if not req.constraint}
β”‚ β”‚ +        results = {req for req in best_matches if not req.constraint}
β”‚ β”‚  
β”‚ β”‚ -    @staticmethod
β”‚ β”‚ -    def check_constraints(constraints):
β”‚ β”‚ -        for constraint in constraints:
β”‚ β”‚ -            if constraint.link is not None and not constraint.editable:
β”‚ β”‚ -                msg = ('pip-compile does not support URLs as packages, unless they are editable. '
β”‚ β”‚ -                       'Perhaps add -e option?')
β”‚ β”‚ -                raise UnsupportedConstraint(msg, constraint)
β”‚ β”‚ +        # Filter out unsafe requirements.
β”‚ β”‚ +        self.unsafe_constraints = set()
β”‚ β”‚ +        if not self.allow_unsafe:
β”‚ β”‚ +            # reverse_dependencies is used to filter out packages that are only
β”‚ β”‚ +            # required by unsafe packages. This logic is incomplete, as it would
β”‚ β”‚ +            # fail to filter sub-sub-dependencies of unsafe packages. None of the
β”‚ β”‚ +            # UNSAFE_PACKAGES currently have any dependencies at all (which makes
β”‚ β”‚ +            # sense for installation tools) so this seems sufficient.
β”‚ β”‚ +            reverse_dependencies = self.reverse_dependencies(results)
β”‚ β”‚ +            for req in results.copy():
β”‚ β”‚ +                required_by = reverse_dependencies.get(req.name.lower(), [])
β”‚ β”‚ +                if req.name in UNSAFE_PACKAGES or (
β”‚ β”‚ +                    required_by and all(name in UNSAFE_PACKAGES for name in required_by)
β”‚ β”‚ +                ):
β”‚ β”‚ +                    self.unsafe_constraints.add(req)
β”‚ β”‚ +                    results.remove(req)
β”‚ β”‚ +
β”‚ β”‚ +        return results
β”‚ β”‚  
β”‚ β”‚      def _group_constraints(self, constraints):
β”‚ β”‚          """
β”‚ β”‚          Groups constraints (remember, InstallRequirements!) by their key name,
β”‚ β”‚          and combining their SpecifierSets into a single InstallRequirement per
β”‚ β”‚          package.  For example, given the following constraints:
β”‚ β”‚  
β”‚ β”‚ @@ -140,96 +218,75 @@
β”‚ β”‚              flask~=0.7
β”‚ β”‚  
β”‚ β”‚          """
β”‚ β”‚          for _, ireqs in full_groupby(constraints, key=key_from_ireq):
β”‚ β”‚              ireqs = list(ireqs)
β”‚ β”‚              editable_ireq = next((ireq for ireq in ireqs if ireq.editable), None)
β”‚ β”‚              if editable_ireq:
β”‚ β”‚ -                yield editable_ireq  # ignore all the other specs: the editable one is the one that counts
β”‚ β”‚ +                # ignore all the other specs: the editable one is the one that counts
β”‚ β”‚ +                yield editable_ireq
β”‚ β”‚                  continue
β”‚ β”‚  
β”‚ β”‚ -            ireqs = iter(ireqs)
β”‚ β”‚ -            # deepcopy the accumulator so as to not modify the self.our_constraints invariant
β”‚ β”‚ -            combined_ireq = copy.deepcopy(next(ireqs))
β”‚ β”‚ -            combined_ireq.comes_from = None
β”‚ β”‚ -            for ireq in ireqs:
β”‚ β”‚ -                # NOTE we may be losing some info on dropped reqs here
β”‚ β”‚ -                combined_ireq.req.specifier &= ireq.req.specifier
β”‚ β”‚ -                combined_ireq.constraint &= ireq.constraint
β”‚ β”‚ -                # Return a sorted, de-duped tuple of extras
β”‚ β”‚ -                combined_ireq.extras = tuple(sorted(set(tuple(combined_ireq.extras) + tuple(ireq.extras))))
β”‚ β”‚ -            yield combined_ireq
β”‚ β”‚ +            yield combine_install_requirements(ireqs)
β”‚ β”‚  
β”‚ β”‚      def _resolve_one_round(self):
β”‚ β”‚          """
β”‚ β”‚          Resolves one level of the current constraints, by finding the best
β”‚ β”‚          match for each package in the repository and adding all requirements
β”‚ β”‚          for those best package versions.  Some of these constraints may be new
β”‚ β”‚          or updated.
β”‚ β”‚  
β”‚ β”‚          Returns whether new constraints appeared in this round.  If no
β”‚ β”‚          constraints were added or changed, this indicates a stable
β”‚ β”‚          configuration.
β”‚ β”‚          """
β”‚ β”‚          # Sort this list for readability of terminal output
β”‚ β”‚          constraints = sorted(self.constraints, key=key_from_ireq)
β”‚ β”‚ -        unsafe_constraints = []
β”‚ β”‚ -        original_constraints = copy.copy(constraints)
β”‚ β”‚ -        if not self.allow_unsafe:
β”‚ β”‚ -            for constraint in original_constraints:
β”‚ β”‚ -                if constraint.name in UNSAFE_PACKAGES:
β”‚ β”‚ -                    constraints.remove(constraint)
β”‚ β”‚ -                    constraint.req.specifier = None
β”‚ β”‚ -                    unsafe_constraints.append(constraint)
β”‚ β”‚  
β”‚ β”‚ -        log.debug('Current constraints:')
β”‚ β”‚ +        log.debug("Current constraints:")
β”‚ β”‚          for constraint in constraints:
β”‚ β”‚ -            log.debug('  {}'.format(constraint))
β”‚ β”‚ +            log.debug("  {}".format(constraint))
β”‚ β”‚  
β”‚ β”‚ -        log.debug('')
β”‚ β”‚ -        log.debug('Finding the best candidates:')
β”‚ β”‚ +        log.debug("")
β”‚ β”‚ +        log.debug("Finding the best candidates:")
β”‚ β”‚          best_matches = {self.get_best_match(ireq) for ireq in constraints}
β”‚ β”‚  
β”‚ β”‚          # Find the new set of secondary dependencies
β”‚ β”‚ -        log.debug('')
β”‚ β”‚ -        log.debug('Finding secondary dependencies:')
β”‚ β”‚ +        log.debug("")
β”‚ β”‚ +        log.debug("Finding secondary dependencies:")
β”‚ β”‚  
β”‚ β”‚ -        safe_constraints = []
β”‚ β”‚ +        their_constraints = []
β”‚ β”‚          for best_match in best_matches:
β”‚ β”‚ -            for dep in self._iter_dependencies(best_match):
β”‚ β”‚ -                if self.allow_unsafe or dep.name not in UNSAFE_PACKAGES:
β”‚ β”‚ -                    safe_constraints.append(dep)
β”‚ β”‚ +            their_constraints.extend(self._iter_dependencies(best_match))
β”‚ β”‚          # Grouping constraints to make clean diff between rounds
β”‚ β”‚ -        theirs = set(self._group_constraints(safe_constraints))
β”‚ β”‚ +        theirs = set(self._group_constraints(their_constraints))
β”‚ β”‚  
β”‚ β”‚          # NOTE: We need to compare RequirementSummary objects, since
β”‚ β”‚          # InstallRequirement does not define equality
β”‚ β”‚ -        diff = {RequirementSummary(t) for t in theirs} - {RequirementSummary(t) for t in self.their_constraints}
β”‚ β”‚ -        removed = ({RequirementSummary(t) for t in self.their_constraints} -
β”‚ β”‚ -                   {RequirementSummary(t) for t in theirs})
β”‚ β”‚ -        unsafe = ({RequirementSummary(t) for t in unsafe_constraints} -
β”‚ β”‚ -                  {RequirementSummary(t) for t in self.unsafe_constraints})
β”‚ β”‚ +        diff = {RequirementSummary(t) for t in theirs} - {
β”‚ β”‚ +            RequirementSummary(t) for t in self.their_constraints
β”‚ β”‚ +        }
β”‚ β”‚ +        removed = {RequirementSummary(t) for t in self.their_constraints} - {
β”‚ β”‚ +            RequirementSummary(t) for t in theirs
β”‚ β”‚ +        }
β”‚ β”‚  
β”‚ β”‚ -        has_changed = len(diff) > 0 or len(removed) > 0 or len(unsafe) > 0
β”‚ β”‚ +        has_changed = len(diff) > 0 or len(removed) > 0
β”‚ β”‚          if has_changed:
β”‚ β”‚ -            log.debug('')
β”‚ β”‚ -            log.debug('New dependencies found in this round:')
β”‚ β”‚ +            log.debug("")
β”‚ β”‚ +            log.debug("New dependencies found in this round:")
β”‚ β”‚              for new_dependency in sorted(diff, key=lambda req: key_from_req(req.req)):
β”‚ β”‚ -                log.debug('  adding {}'.format(new_dependency))
β”‚ β”‚ -            log.debug('Removed dependencies in this round:')
β”‚ β”‚ -            for removed_dependency in sorted(removed, key=lambda req: key_from_req(req.req)):
β”‚ β”‚ -                log.debug('  removing {}'.format(removed_dependency))
β”‚ β”‚ -            log.debug('Unsafe dependencies in this round:')
β”‚ β”‚ -            for unsafe_dependency in sorted(unsafe, key=lambda req: key_from_req(req.req)):
β”‚ β”‚ -                log.debug('  remembering unsafe {}'.format(unsafe_dependency))
β”‚ β”‚ +                log.debug("  adding {}".format(new_dependency))
β”‚ β”‚ +            log.debug("Removed dependencies in this round:")
β”‚ β”‚ +            for removed_dependency in sorted(
β”‚ β”‚ +                removed, key=lambda req: key_from_req(req.req)
β”‚ β”‚ +            ):
β”‚ β”‚ +                log.debug("  removing {}".format(removed_dependency))
β”‚ β”‚  
β”‚ β”‚          # Store the last round's results in the their_constraints
β”‚ β”‚          self.their_constraints = theirs
β”‚ β”‚ -        # Store the last round's unsafe constraints
β”‚ β”‚ -        self.unsafe_constraints = unsafe_constraints
β”‚ β”‚          return has_changed, best_matches
β”‚ β”‚  
β”‚ β”‚      def get_best_match(self, ireq):
β”‚ β”‚          """
β”‚ β”‚          Returns a (pinned or editable) InstallRequirement, indicating the best
β”‚ β”‚          match to use for the given InstallRequirement (in the form of an
β”‚ β”‚          InstallRequirement).
β”‚ β”‚ @@ -239,58 +296,79 @@
β”‚ β”‚          a certain moment in time.
β”‚ β”‚  
β”‚ β”‚          Pinned requirements will always return themselves, i.e.
β”‚ β”‚  
β”‚ β”‚              Flask==0.10.1 => Flask==0.10.1
β”‚ β”‚  
β”‚ β”‚          """
β”‚ β”‚ -        if ireq.editable:
β”‚ β”‚ +        if ireq.editable or is_url_requirement(ireq):
β”‚ β”‚              # NOTE: it's much quicker to immediately return instead of
β”‚ β”‚              # hitting the index server
β”‚ β”‚              best_match = ireq
β”‚ β”‚          elif is_pinned_requirement(ireq):
β”‚ β”‚              # NOTE: it's much quicker to immediately return instead of
β”‚ β”‚              # hitting the index server
β”‚ β”‚              best_match = ireq
β”‚ β”‚          else:
β”‚ β”‚ -            best_match = self.repository.find_best_match(ireq, prereleases=self.prereleases)
β”‚ β”‚ +            best_match = self.repository.find_best_match(
β”‚ β”‚ +                ireq, prereleases=self.prereleases
β”‚ β”‚ +            )
β”‚ β”‚  
β”‚ β”‚          # Format the best match
β”‚ β”‚ -        log.debug('  found candidate {} (constraint was {})'.format(format_requirement(best_match),
β”‚ β”‚ -                                                                    format_specifier(ireq)))
β”‚ β”‚ +        log.debug(
β”‚ β”‚ +            "  found candidate {} (constraint was {})".format(
β”‚ β”‚ +                format_requirement(best_match), format_specifier(ireq)
β”‚ β”‚ +            )
β”‚ β”‚ +        )
β”‚ β”‚ +        best_match.comes_from = ireq.comes_from
β”‚ β”‚          return best_match
β”‚ β”‚  
β”‚ β”‚      def _iter_dependencies(self, ireq):
β”‚ β”‚          """
β”‚ β”‚ -        Given a pinned or editable InstallRequirement, collects all the
β”‚ β”‚ +        Given a pinned, url, or editable InstallRequirement, collects all the
β”‚ β”‚          secondary dependencies for them, either by looking them up in a local
β”‚ β”‚          cache, or by reaching out to the repository.
β”‚ β”‚  
β”‚ β”‚          Editable requirements will never be looked up, as they may have
β”‚ β”‚          changed at any time.
β”‚ β”‚          """
β”‚ β”‚ -        if ireq.editable:
β”‚ β”‚ +        if ireq.editable or is_url_requirement(ireq):
β”‚ β”‚              for dependency in self.repository.get_dependencies(ireq):
β”‚ β”‚                  yield dependency
β”‚ β”‚              return
β”‚ β”‚          elif not is_pinned_requirement(ireq):
β”‚ β”‚ -            raise TypeError('Expected pinned or editable requirement, got {}'.format(ireq))
β”‚ β”‚ +            raise TypeError(
β”‚ β”‚ +                "Expected pinned or editable requirement, got {}".format(ireq)
β”‚ β”‚ +            )
β”‚ β”‚  
β”‚ β”‚          # Now, either get the dependencies from the dependency cache (for
β”‚ β”‚          # speed), or reach out to the external repository to
β”‚ β”‚          # download and inspect the package version and get dependencies
β”‚ β”‚          # from there
β”‚ β”‚          if ireq not in self.dependency_cache:
β”‚ β”‚ -            log.debug('  {} not in cache, need to check index'.format(format_requirement(ireq)), fg='yellow')
β”‚ β”‚ +            log.debug(
β”‚ β”‚ +                "  {} not in cache, need to check index".format(
β”‚ β”‚ +                    format_requirement(ireq)
β”‚ β”‚ +                ),
β”‚ β”‚ +                fg="yellow",
β”‚ β”‚ +            )
β”‚ β”‚              dependencies = self.repository.get_dependencies(ireq)
β”‚ β”‚              self.dependency_cache[ireq] = sorted(str(ireq.req) for ireq in dependencies)
β”‚ β”‚  
β”‚ β”‚          # Example: ['Werkzeug>=0.9', 'Jinja2>=2.4']
β”‚ β”‚          dependency_strings = self.dependency_cache[ireq]
β”‚ β”‚ -        log.debug('  {:25} requires {}'.format(format_requirement(ireq),
β”‚ β”‚ -                                               ', '.join(sorted(dependency_strings, key=lambda s: s.lower())) or '-'))
β”‚ β”‚ +        log.debug(
β”‚ β”‚ +            "  {:25} requires {}".format(
β”‚ β”‚ +                format_requirement(ireq),
β”‚ β”‚ +                ", ".join(sorted(dependency_strings, key=lambda s: s.lower())) or "-",
β”‚ β”‚ +            )
β”‚ β”‚ +        )
β”‚ β”‚          for dependency_string in dependency_strings:
β”‚ β”‚ -            yield install_req_from_line(dependency_string, constraint=ireq.constraint)
β”‚ β”‚ +            yield install_req_from_line(
β”‚ β”‚ +                dependency_string, constraint=ireq.constraint, comes_from=ireq
β”‚ β”‚ +            )
β”‚ β”‚  
β”‚ β”‚      def reverse_dependencies(self, ireqs):
β”‚ β”‚ -        non_editable = [ireq for ireq in ireqs if not ireq.editable]
β”‚ β”‚ +        non_editable = [
β”‚ β”‚ +            ireq for ireq in ireqs if not (ireq.editable or is_url_requirement(ireq))
β”‚ β”‚ +        ]
β”‚ β”‚          return self.dependency_cache.reverse_dependencies(non_editable)
β”‚   --- pip-tools-3.5.0/piptools/cache.py
β”œβ”€β”€ +++ pip-tools-4.0.0/piptools/cache.py
β”‚β”„ Files similar despite different names (difference score: 44)
β”‚ β”‚ @@ -1,10 +1,9 @@
β”‚ β”‚  # coding: utf-8
β”‚ β”‚ -from __future__ import (absolute_import, division, print_function,
β”‚ β”‚ -                        unicode_literals)
β”‚ β”‚ +from __future__ import absolute_import, division, print_function, unicode_literals
β”‚ β”‚  
β”‚ β”‚  import json
β”‚ β”‚  import os
β”‚ β”‚  import sys
β”‚ β”‚  
β”‚ β”‚  from pip._vendor.packaging.requirements import Requirement
β”‚ β”‚  
β”‚ β”‚ @@ -15,50 +14,52 @@
β”‚ β”‚  
β”‚ β”‚  class CorruptCacheError(PipToolsError):
β”‚ β”‚      def __init__(self, path):
β”‚ β”‚          self.path = path
β”‚ β”‚  
β”‚ β”‚      def __str__(self):
β”‚ β”‚          lines = [
β”‚ β”‚ -            'The dependency cache seems to have been corrupted.',
β”‚ β”‚ -            'Inspect, or delete, the following file:',
β”‚ β”‚ -            '  {}'.format(self.path),
β”‚ β”‚ +            "The dependency cache seems to have been corrupted.",
β”‚ β”‚ +            "Inspect, or delete, the following file:",
β”‚ β”‚ +            "  {}".format(self.path),
β”‚ β”‚          ]
β”‚ β”‚          return os.linesep.join(lines)
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def read_cache_file(cache_file_path):
β”‚ β”‚ -    with open(cache_file_path, 'r') as cache_file:
β”‚ β”‚ +    with open(cache_file_path, "r") as cache_file:
β”‚ β”‚          try:
β”‚ β”‚              doc = json.load(cache_file)
β”‚ β”‚          except ValueError:
β”‚ β”‚              raise CorruptCacheError(cache_file_path)
β”‚ β”‚  
β”‚ β”‚          # Check version and load the contents
β”‚ β”‚ -        assert doc['__format__'] == 1, 'Unknown cache file format'
β”‚ β”‚ -        return doc['dependencies']
β”‚ β”‚ +        if doc["__format__"] != 1:
β”‚ β”‚ +            raise AssertionError("Unknown cache file format")
β”‚ β”‚ +        return doc["dependencies"]
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  class DependencyCache(object):
β”‚ β”‚      """
β”‚ β”‚      Creates a new persistent dependency cache for the current Python version.
β”‚ β”‚      The cache file is written to the appropriate user cache dir for the
β”‚ β”‚      current platform, i.e.
β”‚ β”‚  
β”‚ β”‚          ~/.cache/pip-tools/depcache-pyX.Y.json
β”‚ β”‚  
β”‚ β”‚      Where X.Y indicates the Python version.
β”‚ β”‚      """
β”‚ β”‚ +
β”‚ β”‚      def __init__(self, cache_dir=None):
β”‚ β”‚          if cache_dir is None:
β”‚ β”‚              cache_dir = CACHE_DIR
β”‚ β”‚          if not os.path.isdir(cache_dir):
β”‚ β”‚              os.makedirs(cache_dir)
β”‚ β”‚ -        py_version = '.'.join(str(digit) for digit in sys.version_info[:2])
β”‚ β”‚ -        cache_filename = 'depcache-py{}.json'.format(py_version)
β”‚ β”‚ +        py_version = ".".join(str(digit) for digit in sys.version_info[:2])
β”‚ β”‚ +        cache_filename = "depcache-py{}.json".format(py_version)
β”‚ β”‚  
β”‚ β”‚          self._cache_file = os.path.join(cache_dir, cache_filename)
β”‚ β”‚          self._cache = None
β”‚ β”‚  
β”‚ β”‚      @property
β”‚ β”‚      def cache(self):
β”‚ β”‚          """
β”‚ β”‚ @@ -67,21 +68,22 @@
β”‚ β”‚          """
β”‚ β”‚          if self._cache is None:
β”‚ β”‚              self.read_cache()
β”‚ β”‚          return self._cache
β”‚ β”‚  
β”‚ β”‚      def as_cache_key(self, ireq):
β”‚ β”‚          """
β”‚ β”‚ -        Given a requirement, return its cache key. This behavior is a little weird in order to allow backwards
β”‚ β”‚ -        compatibility with cache files. For a requirement without extras, this will return, for example:
β”‚ β”‚ +        Given a requirement, return its cache key. This behavior is a little weird
β”‚ β”‚ +        in order to allow backwards compatibility with cache files. For a requirement
β”‚ β”‚ +        without extras, this will return, for example:
β”‚ β”‚  
β”‚ β”‚          ("ipython", "2.1.0")
β”‚ β”‚  
β”‚ β”‚ -        For a requirement with extras, the extras will be comma-separated and appended to the version, inside brackets,
β”‚ β”‚ -        like so:
β”‚ β”‚ +        For a requirement with extras, the extras will be comma-separated and appended
β”‚ β”‚ +        to the version, inside brackets, like so:
β”‚ β”‚  
β”‚ β”‚          ("ipython", "2.1.0[nbconvert,notebook]")
β”‚ β”‚          """
β”‚ β”‚          name, version, extras = as_tuple(ireq)
β”‚ β”‚          if not extras:
β”‚ β”‚              extras_string = ""
β”‚ β”‚          else:
β”‚ β”‚ @@ -93,19 +95,16 @@
β”‚ β”‚          if os.path.exists(self._cache_file):
β”‚ β”‚              self._cache = read_cache_file(self._cache_file)
β”‚ β”‚          else:
β”‚ β”‚              self._cache = {}
β”‚ β”‚  
β”‚ β”‚      def write_cache(self):
β”‚ β”‚          """Writes the cache to disk as JSON."""
β”‚ β”‚ -        doc = {
β”‚ β”‚ -            '__format__': 1,
β”‚ β”‚ -            'dependencies': self._cache,
β”‚ β”‚ -        }
β”‚ β”‚ -        with open(self._cache_file, 'w') as f:
β”‚ β”‚ +        doc = {"__format__": 1, "dependencies": self._cache}
β”‚ β”‚ +        with open(self._cache_file, "w") as f:
β”‚ β”‚              json.dump(doc, f, sort_keys=True)
β”‚ β”‚  
β”‚ β”‚      def clear(self):
β”‚ β”‚          self._cache = {}
β”‚ β”‚          self.write_cache()
β”‚ β”‚  
β”‚ β”‚      def __contains__(self, ireq):
β”‚ β”‚ @@ -118,18 +117,14 @@
β”‚ β”‚  
β”‚ β”‚      def __setitem__(self, ireq, values):
β”‚ β”‚          pkgname, pkgversion_and_extras = self.as_cache_key(ireq)
β”‚ β”‚          self.cache.setdefault(pkgname, {})
β”‚ β”‚          self.cache[pkgname][pkgversion_and_extras] = values
β”‚ β”‚          self.write_cache()
β”‚ β”‚  
β”‚ β”‚ -    def get(self, ireq, default=None):
β”‚ β”‚ -        pkgname, pkgversion_and_extras = self.as_cache_key(ireq)
β”‚ β”‚ -        return self.cache.get(pkgname, {}).get(pkgversion_and_extras, default)
β”‚ β”‚ -
β”‚ β”‚      def reverse_dependencies(self, ireqs):
β”‚ β”‚          """
β”‚ β”‚          Returns a lookup table of reverse dependencies for all the given ireqs.
β”‚ β”‚  
β”‚ β”‚          Since this is all static, it only works if the dependency cache
β”‚ β”‚          contains the complete data, otherwise you end up with a partial view.
β”‚ β”‚          This is typically no problem if you use this function after the entire
β”‚ β”‚ @@ -153,12 +148,14 @@
β”‚ β”‚  
β”‚ β”‚              {'pep8': ['flake8'],
β”‚ β”‚               'flake8': [],
β”‚ β”‚               'mccabe': ['flake8'],
β”‚ β”‚               'pyflakes': ['flake8']}
β”‚ β”‚  
β”‚ β”‚          """
β”‚ β”‚ -        # First, collect all the dependencies into a sequence of (parent, child) tuples, like [('flake8', 'pep8'),
β”‚ β”‚ -        # ('flake8', 'mccabe'), ...]
β”‚ β”‚ -        return lookup_table((key_from_req(Requirement(dep_name)), name)
β”‚ β”‚ -                            for name, version_and_extras in cache_keys
β”‚ β”‚ -                            for dep_name in self.cache[name][version_and_extras])
β”‚ β”‚ +        # First, collect all the dependencies into a sequence of (parent, child)
β”‚ β”‚ +        # tuples, like [('flake8', 'pep8'), ('flake8', 'mccabe'), ...]
β”‚ β”‚ +        return lookup_table(
β”‚ β”‚ +            (key_from_req(Requirement(dep_name)), name)
β”‚ β”‚ +            for name, version_and_extras in cache_keys
β”‚ β”‚ +            for dep_name in self.cache[name][version_and_extras]
β”‚ β”‚ +        )
β”‚   --- pip-tools-3.5.0/tests/test_data/minimal_wheels/small_fake_a-0.1-py2.py3-none-any.whl
β”œβ”€β”€ +++ pip-tools-4.0.0/tests/test_data/minimal_wheels/small_fake_a-0.1-py2.py3-none-any.whl
β”‚β”„ Files similar despite different names (difference score: 0)
β”‚   --- pip-tools-3.5.0/tests/test_minimal_upgrade.py
β”œβ”€β”€ +++ pip-tools-4.0.0/tests/test_minimal_upgrade.py
β”‚β”„ Files similar despite different names (difference score: 50)
β”‚ β”‚ @@ -1,38 +1,46 @@
β”‚ β”‚  import pytest
β”‚ β”‚ +
β”‚ β”‚  from piptools.repositories import LocalRequirementsRepository
β”‚ β”‚  from piptools.utils import name_from_req
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  @pytest.mark.parametrize(
β”‚ β”‚ -    ('input', 'pins', 'expected'),
β”‚ β”‚ -
β”‚ β”‚ -    ((tup) for tup in [
β”‚ β”‚ -
β”‚ β”‚ -        # Add Flask to an existing requirements.in, using --no-upgrade
β”‚ β”‚ -        (['flask', 'jinja2', 'werkzeug'],
β”‚ β”‚ -         [
β”‚ β”‚ -            # The requirements.txt from a previous round
β”‚ β”‚ -            'jinja2==2.7.3',
β”‚ β”‚ -            'markupsafe==0.23',
β”‚ β”‚ -            'werkzeug==0.6'],
β”‚ β”‚ -         [
β”‚ β”‚ -            # Add flask and upgrade werkzeug from incompatible 0.6
β”‚ β”‚ -            'flask==0.10.1',
β”‚ β”‚ -            'itsdangerous==0.24',
β”‚ β”‚ -            'werkzeug==0.10.4',
β”‚ β”‚ -            # Other requirements are unchanged from the original requirements.txt
β”‚ β”‚ -            'jinja2==2.7.3',
β”‚ β”‚ -            'markupsafe==0.23']
β”‚ β”‚ -         ),
β”‚ β”‚ -    ])
β”‚ β”‚ +    ("input", "pins", "expected"),
β”‚ β”‚ +    (
β”‚ β”‚ +        (tup)
β”‚ β”‚ +        for tup in [
β”‚ β”‚ +            # Add Flask to an existing requirements.in, using --no-upgrade
β”‚ β”‚ +            (
β”‚ β”‚ +                ["flask", "jinja2", "werkzeug"],
β”‚ β”‚ +                [
β”‚ β”‚ +                    # The requirements.txt from a previous round
β”‚ β”‚ +                    "jinja2==2.7.3",
β”‚ β”‚ +                    "markupsafe==0.23",
β”‚ β”‚ +                    "werkzeug==0.6",
β”‚ β”‚ +                ],
β”‚ β”‚ +                [
β”‚ β”‚ +                    # Add flask and upgrade werkzeug from incompatible 0.6
β”‚ β”‚ +                    "flask==0.10.1",
β”‚ β”‚ +                    "itsdangerous==0.24 (from flask==0.10.1)",
β”‚ β”‚ +                    "werkzeug==0.10.4",
β”‚ β”‚ +                    # Other requirements are unchanged from
β”‚ β”‚ +                    # the original requirements.txt
β”‚ β”‚ +                    "jinja2==2.7.3",
β”‚ β”‚ +                    "markupsafe==0.23 (from jinja2==2.7.3)",
β”‚ β”‚ +                ],
β”‚ β”‚ +            )
β”‚ β”‚ +        ]
β”‚ β”‚ +    ),
β”‚ β”‚  )
β”‚ β”‚  def test_no_upgrades(base_resolver, repository, from_line, input, pins, expected):
β”‚ β”‚      input = [from_line(line) for line in input]
β”‚ β”‚      existing_pins = dict()
β”‚ β”‚      for line in pins:
β”‚ β”‚          ireq = from_line(line)
β”‚ β”‚          existing_pins[name_from_req(ireq.req)] = ireq
β”‚ β”‚      local_repository = LocalRequirementsRepository(existing_pins, repository)
β”‚ β”‚ -    output = base_resolver(input, prereleases=False, repository=local_repository).resolve()
β”‚ β”‚ +    output = base_resolver(
β”‚ β”‚ +        input, prereleases=False, repository=local_repository
β”‚ β”‚ +    ).resolve()
β”‚ β”‚      output = {str(line) for line in output}
β”‚ β”‚      assert output == {str(line) for line in expected}
β”‚   --- pip-tools-3.5.0/tests/test_data/minimal_wheels/small_fake_b-0.3-py2.py3-none-any.whl
β”œβ”€β”€ +++ pip-tools-4.0.0/tests/test_data/minimal_wheels/small_fake_b-0.3-py2.py3-none-any.whl
β”‚β”„ Files similar despite different names (difference score: 0)
β”‚   --- pip-tools-3.5.0/tests/test_cli_sync.py
β”œβ”€β”€ +++ pip-tools-4.0.0/tests/test_cli_sync.py
β”‚β”„ Files similar despite different names (difference score: 59)
β”‚ β”‚ @@ -1,136 +1,149 @@
β”‚ β”‚  import sys
β”‚ β”‚  
β”‚ β”‚  import mock
β”‚ β”‚  import pytest
β”‚ β”‚ -from click.testing import CliRunner
β”‚ β”‚  
β”‚ β”‚ -from piptools.scripts.sync import cli
β”‚ β”‚  from .utils import invoke
β”‚ β”‚  
β”‚ β”‚ +from piptools.scripts.sync import cli
β”‚ β”‚ +
β”‚ β”‚  
β”‚ β”‚  def test_run_as_module_sync():
β”‚ β”‚      """piptools can be run as ``python -m piptools ...``."""
β”‚ β”‚  
β”‚ β”‚ -    status, output = invoke([
β”‚ β”‚ -        sys.executable, '-m', 'piptools', 'sync', '--help',
β”‚ β”‚ -    ])
β”‚ β”‚ +    status, output = invoke([sys.executable, "-m", "piptools", "sync", "--help"])
β”‚ β”‚  
β”‚ β”‚      # Should have run pip-compile successfully.
β”‚ β”‚ -    output = output.decode('utf-8')
β”‚ β”‚ -    assert output.startswith('Usage:')
β”‚ β”‚ -    assert 'Synchronize virtual environment with' in output
β”‚ β”‚ +    output = output.decode("utf-8")
β”‚ β”‚ +    assert output.startswith("Usage:")
β”‚ β”‚ +    assert "Synchronize virtual environment with" in output
β”‚ β”‚      assert status == 0
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚ -def test_quiet_option(tmpdir):
β”‚ β”‚ [email protected]("piptools.sync.check_call")
β”‚ β”‚ +def test_quiet_option(check_call, runner):
β”‚ β”‚      """sync command can be run with `--quiet` or `-q` flag."""
β”‚ β”‚  
β”‚ β”‚ -    runner = CliRunner()
β”‚ β”‚ -    with runner.isolated_filesystem():
β”‚ β”‚ -        with open('requirements.txt', 'w') as req_in:
β”‚ β”‚ -            req_in.write('six==1.10.0')
β”‚ β”‚ -
β”‚ β”‚ -        with mock.patch('piptools.sync.check_call') as check_call:
β”‚ β”‚ -            out = runner.invoke(cli, ['-q'])
β”‚ β”‚ -            assert out.output == ''
β”‚ β”‚ -            assert out.exit_code == 0
β”‚ β”‚ -            # for every call to pip ensure the `-q` flag is set
β”‚ β”‚ -            for call in check_call.call_args_list:
β”‚ β”‚ -                assert '-q' in call[0][0]
β”‚ β”‚ +    with open("requirements.txt", "w") as req_in:
β”‚ β”‚ +        req_in.write("six==1.10.0")
β”‚ β”‚ +
β”‚ β”‚ +    out = runner.invoke(cli, ["-q"])
β”‚ β”‚ +    assert not out.stderr_bytes
β”‚ β”‚ +    assert out.exit_code == 0
β”‚ β”‚ +
β”‚ β”‚ +    # for every call to pip ensure the `-q` flag is set
β”‚ β”‚ +    assert check_call.call_count == 2
β”‚ β”‚ +    for call in check_call.call_args_list:
β”‚ β”‚ +        assert "-q" in call[0][0]
β”‚ β”‚ +
β”‚ β”‚ +
β”‚ β”‚ [email protected]("piptools.sync.check_call")
β”‚ β”‚ +def test_quiet_option_when_up_to_date(check_call, runner):
β”‚ β”‚ +    """
β”‚ β”‚ +    Sync should output nothing when everything is up to date and quiet option is set.
β”‚ β”‚ +    """
β”‚ β”‚ +    with open("requirements.txt", "w"):
β”‚ β”‚ +        pass
β”‚ β”‚ +
β”‚ β”‚ +    with mock.patch("piptools.sync.diff", return_value=(set(), set())):
β”‚ β”‚ +        out = runner.invoke(cli, ["-q"])
β”‚ β”‚ +
β”‚ β”‚ +    assert not out.stderr_bytes
β”‚ β”‚ +    assert out.exit_code == 0
β”‚ β”‚ +    check_call.assert_not_called()
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_no_requirements_file(runner):
β”‚ β”‚      """
β”‚ β”‚      It should raise an error if there are no input files
β”‚ β”‚      or a requirements.txt file does not exist.
β”‚ β”‚      """
β”‚ β”‚      out = runner.invoke(cli)
β”‚ β”‚  
β”‚ β”‚ -    assert 'No requirement files given' in out.output
β”‚ β”‚ +    assert "No requirement files given" in out.stderr
β”‚ β”‚      assert out.exit_code == 2
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_input_files_with_dot_in_extension(runner):
β”‚ β”‚      """
β”‚ β”‚      It should raise an error if some of the input files have .in extension.
β”‚ β”‚      """
β”‚ β”‚ -    with open('requirements.in', 'w') as req_in:
β”‚ β”‚ -        req_in.write('six==1.10.0')
β”‚ β”‚ +    with open("requirements.in", "w") as req_in:
β”‚ β”‚ +        req_in.write("six==1.10.0")
β”‚ β”‚  
β”‚ β”‚ -    out = runner.invoke(cli, ['requirements.in'])
β”‚ β”‚ +    out = runner.invoke(cli, ["requirements.in"])
β”‚ β”‚  
β”‚ β”‚ -    assert 'ERROR: Some input files have the .in extension' in out.output
β”‚ β”‚ +    assert "ERROR: Some input files have the .in extension" in out.stderr
β”‚ β”‚      assert out.exit_code == 2
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_force_files_with_dot_in_extension(runner):
β”‚ β”‚      """
β”‚ β”‚ -    It should print a warning and sync anyway if some of the input files have .in extension.
β”‚ β”‚ +    It should print a warning and sync anyway if some of the input files
β”‚ β”‚ +    have .in extension.
β”‚ β”‚      """
β”‚ β”‚  
β”‚ β”‚ -    with open('requirements.in', 'w') as req_in:
β”‚ β”‚ -        req_in.write('six==1.10.0')
β”‚ β”‚ +    with open("requirements.in", "w") as req_in:
β”‚ β”‚ +        req_in.write("six==1.10.0")
β”‚ β”‚  
β”‚ β”‚ -    with mock.patch('piptools.sync.check_call'):
β”‚ β”‚ -        out = runner.invoke(cli, ['requirements.in', '--force'])
β”‚ β”‚ +    with mock.patch("piptools.sync.check_call"):
β”‚ β”‚ +        out = runner.invoke(cli, ["requirements.in", "--force"])
β”‚ β”‚  
β”‚ β”‚ -    assert 'WARNING: Some input files have the .in extension' in out.output
β”‚ β”‚ +    assert "WARNING: Some input files have the .in extension" in out.stderr
β”‚ β”‚      assert out.exit_code == 0
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_merge_error(runner):
β”‚ β”‚      """
β”‚ β”‚      Sync command should raise an error if there are merge errors.
β”‚ β”‚      """
β”‚ β”‚ -    with open('requirements.txt', 'w') as req_in:
β”‚ β”‚ -        req_in.write('six>1.10.0\n')
β”‚ β”‚ +    with open("requirements.txt", "w") as req_in:
β”‚ β”‚ +        req_in.write("six>1.10.0\n")
β”‚ β”‚  
β”‚ β”‚          # Add incompatible package
β”‚ β”‚ -        req_in.write('six<1.10.0')
β”‚ β”‚ +        req_in.write("six<1.10.0")
β”‚ β”‚  
β”‚ β”‚ -    with mock.patch('piptools.sync.check_call'):
β”‚ β”‚ -        out = runner.invoke(cli, ['-n'])
β”‚ β”‚ +    with mock.patch("piptools.sync.check_call"):
β”‚ β”‚ +        out = runner.invoke(cli, ["-n"])
β”‚ β”‚  
β”‚ β”‚      assert out.exit_code == 2
β”‚ β”‚ -    assert 'Incompatible requirements found' in out.output
β”‚ β”‚ +    assert "Incompatible requirements found" in out.stderr
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  @pytest.mark.parametrize(
β”‚ β”‚ -    ('cli_flags', 'expected_install_flags'),
β”‚ β”‚ +    ("cli_flags", "expected_install_flags"),
β”‚ β”‚      [
β”‚ β”‚ -        (['--find-links', './libs'], ['-f', './libs']),
β”‚ β”‚ -        (['--no-index'], ['--no-index']),
β”‚ β”‚ -        (['--index-url', 'https://example.com'], ['-i', 'https://example.com']),
β”‚ β”‚ +        (["--find-links", "./libs"], ["-f", "./libs"]),
β”‚ β”‚ +        (["--no-index"], ["--no-index"]),
β”‚ β”‚ +        (["--index-url", "https://example.com"], ["-i", "https://example.com"]),
β”‚ β”‚          (
β”‚ β”‚ -            [
β”‚ β”‚ -                '--extra-index-url', 'https://foo',
β”‚ β”‚ -                '--extra-index-url', 'https://bar',
β”‚ β”‚ -            ],
β”‚ β”‚ -            [
β”‚ β”‚ -                '--extra-index-url', 'https://foo',
β”‚ β”‚ -                '--extra-index-url', 'https://bar',
β”‚ β”‚ -            ]
β”‚ β”‚ +            ["--extra-index-url", "https://foo", "--extra-index-url", "https://bar"],
β”‚ β”‚ +            ["--extra-index-url", "https://foo", "--extra-index-url", "https://bar"],
β”‚ β”‚          ),
β”‚ β”‚ -        (['--user'], ['--user']),
β”‚ β”‚ -    ]
β”‚ β”‚ +        (
β”‚ β”‚ +            ["--trusted-host", "https://foo", "--trusted-host", "https://bar"],
β”‚ β”‚ +            ["--trusted-host", "https://foo", "--trusted-host", "https://bar"],
β”‚ β”‚ +        ),
β”‚ β”‚ +        (
β”‚ β”‚ +            ["--extra-index-url", "https://foo", "--trusted-host", "https://bar"],
β”‚ β”‚ +            ["--extra-index-url", "https://foo", "--trusted-host", "https://bar"],
β”‚ β”‚ +        ),
β”‚ β”‚ +        (["--user"], ["--user"]),
β”‚ β”‚ +        (["--cert", "foo.crt"], ["--cert", "foo.crt"]),
β”‚ β”‚ +        (["--client-cert", "foo.pem"], ["--client-cert", "foo.pem"]),
β”‚ β”‚ +    ],
β”‚ β”‚  )
β”‚ β”‚ [email protected]('piptools.sync.check_call')
β”‚ β”‚ [email protected]("piptools.sync.check_call")
β”‚ β”‚  def test_pip_install_flags(check_call, cli_flags, expected_install_flags, runner):
β”‚ β”‚      """
β”‚ β”‚      Test the cli flags have to be passed to the pip install command.
β”‚ β”‚      """
β”‚ β”‚ -    with open('requirements.txt', 'w') as req_in:
β”‚ β”‚ -        req_in.write('six==1.10.0')
β”‚ β”‚ +    with open("requirements.txt", "w") as req_in:
β”‚ β”‚ +        req_in.write("six==1.10.0")
β”‚ β”‚  
β”‚ β”‚      runner.invoke(cli, cli_flags)
β”‚ β”‚  
β”‚ β”‚ -    for call in check_call.call_args_list:
β”‚ β”‚ -        check_call_args = call[0][0]
β”‚ β”‚ -        pip_command = check_call_args[3]
β”‚ β”‚ -
β”‚ β”‚ -        # Skip uninstall command
β”‚ β”‚ -        if pip_command != 'install':
β”‚ β”‚ -            continue
β”‚ β”‚ -
β”‚ β”‚ -        install_flags = check_call_args[6:]
β”‚ β”‚ -        assert install_flags == expected_install_flags
β”‚ β”‚ +    call_args = [call[0][0] for call in check_call.call_args_list]
β”‚ β”‚ +    assert [args[6:] for args in call_args if args[3] == "install"] == [
β”‚ β”‚ +        expected_install_flags
β”‚ β”‚ +    ]
β”‚   --- pip-tools-3.5.0/pip_tools.egg-info/SOURCES.txt
β”œβ”€β”€ +++ pip-tools-4.0.0/pip_tools.egg-info/SOURCES.txt
β”‚β”„ Files similar despite different names (difference score: 6)
β”‚ β”‚ @@ -1,11 +1,13 @@
β”‚ β”‚  .appveyor.yml
β”‚ β”‚ +.bandit
β”‚ β”‚  .coveragerc
β”‚ β”‚ -.flake8
β”‚ β”‚ +.fussyfox.yml
β”‚ β”‚  .gitignore
β”‚ β”‚ +.pre-commit-config.yaml
β”‚ β”‚  .travis.yml
β”‚ β”‚  CHANGELOG.md
β”‚ β”‚  CONTRIBUTING.md
β”‚ β”‚  LICENSE
β”‚ β”‚  README.rst
β”‚ β”‚  dev-requirements.txt
β”‚ β”‚  setup.cfg
β”‚ β”‚ @@ -27,18 +29,16 @@
β”‚ β”‚  pip_tools.egg-info/requires.txt
β”‚ β”‚  pip_tools.egg-info/top_level.txt
β”‚ β”‚  piptools/__init__.py
β”‚ β”‚  piptools/__main__.py
β”‚ β”‚  piptools/cache.py
β”‚ β”‚  piptools/click.py
β”‚ β”‚  piptools/exceptions.py
β”‚ β”‚ -piptools/io.py
β”‚ β”‚  piptools/locations.py
β”‚ β”‚  piptools/logging.py
β”‚ β”‚ -piptools/pip.py
β”‚ β”‚  piptools/resolver.py
β”‚ β”‚  piptools/sync.py
β”‚ β”‚  piptools/utils.py
β”‚ β”‚  piptools/writer.py
β”‚ β”‚  piptools/_compat/__init__.py
β”‚ β”‚  piptools/_compat/contextlib.py
β”‚ β”‚  piptools/_compat/pip_compat.py
β”‚ β”‚ @@ -52,14 +52,15 @@
β”‚ β”‚  piptools/scripts/sync.py
β”‚ β”‚  tests/__init__.py
β”‚ β”‚  tests/conftest.py
β”‚ β”‚  tests/test_cache.py
β”‚ β”‚  tests/test_cli_compile.py
β”‚ β”‚  tests/test_cli_sync.py
β”‚ β”‚  tests/test_fake_index.py
β”‚ β”‚ +tests/test_locations.py
β”‚ β”‚  tests/test_minimal_upgrade.py
β”‚ β”‚  tests/test_repositories.py
β”‚ β”‚  tests/test_repository_local.py
β”‚ β”‚  tests/test_repository_pypi.py
β”‚ β”‚  tests/test_resolver.py
β”‚ β”‚  tests/test_sync.py
β”‚ β”‚  tests/test_top_level_editable.py
β”‚ β”‚ @@ -67,12 +68,13 @@
β”‚ β”‚  tests/test_writer.py
β”‚ β”‚  tests/utils.py
β”‚ β”‚  tests/test_data/fake-editables.json
β”‚ β”‚  tests/test_data/fake-index.json
β”‚ β”‚  tests/test_data/fake_package/setup.py
β”‚ β”‚  tests/test_data/minimal_wheels/small_fake_a-0.1-py2.py3-none-any.whl
β”‚ β”‚  tests/test_data/minimal_wheels/small_fake_a-0.2-py2.py3-none-any.whl
β”‚ β”‚ +tests/test_data/minimal_wheels/small_fake_a-0.3b1-py2.py3-none-any.whl
β”‚ β”‚  tests/test_data/minimal_wheels/small_fake_b-0.1-py2.py3-none-any.whl
β”‚ β”‚  tests/test_data/minimal_wheels/small_fake_b-0.2-py2.py3-none-any.whl
β”‚ β”‚  tests/test_data/minimal_wheels/small_fake_b-0.3-py2.py3-none-any.whl
β”‚ β”‚  tests/test_data/minimal_wheels/small_fake_with_deps-0.1-py2.py3-none-any.whl
β”‚ β”‚  tests/test_data/small_fake_package/setup.py
β”‚   --- pip-tools-3.5.0/CONTRIBUTING.md
β”œβ”€β”€ +++ pip-tools-4.0.0/CONTRIBUTING.md
β”‚β”„ Files similar despite different names (difference score: 18)
β”‚ β”‚ @@ -3,14 +3,15 @@
β”‚ β”‚  This is a [Jazzband](https://jazzband.co/) project. By contributing you agree
β”‚ β”‚  to abide by the [Contributor Code of Conduct](https://jazzband.co/about/conduct)
β”‚ β”‚  and follow the [guidelines](https://jazzband.co/about/guidelines).
β”‚ β”‚  
β”‚ β”‚  ## Project Contribution Guidelines
β”‚ β”‚  
β”‚ β”‚  Here are a few additional or emphasized guidelines to follow when contributing to pip-tools:
β”‚ β”‚ +- Check with `tox -e checkqa` to see your changes are not breaking the style conventions.
β”‚ β”‚  - Always provide tests for your changes.
β”‚ β”‚  - Give a clear one-line description in the PR (that the maintainers can add to [CHANGELOG](CHANGELOG.md) afterwards).
β”‚ β”‚  - Wait for the review of at least one other contributor before merging (even if you're a Jazzband member).
β”‚ β”‚  - Before merging, assign the PR to a milestone for a version to help with the release process.
β”‚ β”‚  
β”‚ β”‚  The only exception to those guidelines is for trivial changes, such as
β”‚ β”‚  documentation corrections or contributions that do not change pip-tools itself.
β”‚   --- pip-tools-3.5.0/piptools/repositories/base.py
β”œβ”€β”€ +++ pip-tools-4.0.0/piptools/repositories/base.py
β”‚β”„ Files similar despite different names (difference score: 22)
β”‚ β”‚ @@ -1,20 +1,18 @@
β”‚ β”‚  # coding: utf-8
β”‚ β”‚ -from __future__ import (absolute_import, division, print_function,
β”‚ β”‚ -                        unicode_literals)
β”‚ β”‚ +from __future__ import absolute_import, division, print_function, unicode_literals
β”‚ β”‚  
β”‚ β”‚  from abc import ABCMeta, abstractmethod
β”‚ β”‚  from contextlib import contextmanager
β”‚ β”‚  
β”‚ β”‚  from six import add_metaclass
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  @add_metaclass(ABCMeta)
β”‚ β”‚  class BaseRepository(object):
β”‚ β”‚ -
β”‚ β”‚      def clear_caches(self):
β”‚ β”‚          """Should clear any caches used by the implementation."""
β”‚ β”‚  
β”‚ β”‚      def freshen_build_caches(self):
β”‚ β”‚          """Should start with fresh build/source caches."""
β”‚ β”‚  
β”‚ β”‚      @abstractmethod
β”‚ β”‚ @@ -23,15 +21,15 @@
β”‚ β”‚          Return a Version object that indicates the best match for the given
β”‚ β”‚          InstallRequirement according to the repository.
β”‚ β”‚          """
β”‚ β”‚  
β”‚ β”‚      @abstractmethod
β”‚ β”‚      def get_dependencies(self, ireq):
β”‚ β”‚          """
β”‚ β”‚ -        Given a pinned or an editable InstallRequirement, returns a set of
β”‚ β”‚ +        Given a pinned, URL, or editable InstallRequirement, returns a set of
β”‚ β”‚          dependencies (also InstallRequirements, but not necessarily pinned).
β”‚ β”‚          They indicate the secondary dependencies for the given requirement.
β”‚ β”‚          """
β”‚ β”‚  
β”‚ β”‚      @abstractmethod
β”‚ β”‚      def get_hashes(self, ireq):
β”‚ β”‚          """
β”‚   --- pip-tools-3.5.0/tests/test_data/minimal_wheels/small_fake_with_deps-0.1-py2.py3-none-any.whl
β”œβ”€β”€ +++ pip-tools-4.0.0/tests/test_data/minimal_wheels/small_fake_with_deps-0.1-py2.py3-none-any.whl
β”‚β”„ Files similar despite different names (difference score: 0)
β”‚   --- pip-tools-3.5.0/piptools/_compat/tempfile.py
β”œβ”€β”€ +++ pip-tools-4.0.0/piptools/_compat/tempfile.py
β”‚β”„ Files similar despite different names (difference score: 6)
β”‚ β”‚ @@ -36,16 +36,18 @@
β”‚ β”‚                  self._rmtree(self.name)
β”‚ β”‚              except (TypeError, AttributeError) as ex:
β”‚ β”‚                  # Issue #10188: Emit a warning on stderr
β”‚ β”‚                  # if the directory could not be cleaned
β”‚ β”‚                  # up due to missing globals
β”‚ β”‚                  if "None" not in str(ex):
β”‚ β”‚                      raise
β”‚ β”‚ -                print("ERROR: {!r} while cleaning up {!r}".format(ex, self,),
β”‚ β”‚ -                      file=_sys.stderr)
β”‚ β”‚ +                print(
β”‚ β”‚ +                    "ERROR: {!r} while cleaning up {!r}".format(ex, self),
β”‚ β”‚ +                    file=_sys.stderr,
β”‚ β”‚ +                )
β”‚ β”‚                  return
β”‚ β”‚              self._closed = True
β”‚ β”‚  
β”‚ β”‚      def __exit__(self, exc, value, tb):
β”‚ β”‚          self.cleanup()
β”‚ β”‚  
β”‚ β”‚      def __del__(self):
β”‚   --- pip-tools-3.5.0/.appveyor.yml
β”œβ”€β”€ +++ pip-tools-4.0.0/.appveyor.yml
β”‚β”„ Files similar despite different names (difference score: 33)
β”‚ β”‚ @@ -11,48 +11,35 @@
β”‚ β”‚            PIP: 9.0.3
β”‚ β”‚          - TOXENV: py27-pip10.0.1
β”‚ β”‚            PIP: 10.0.1
β”‚ β”‚          - TOXENV: py27-pip18.0
β”‚ β”‚            PIP: 18.0
β”‚ β”‚          - TOXENV: py27-pip19.0
β”‚ β”‚            PIP: 19.0
β”‚ β”‚ +        - TOXENV: py27-pip19.1
β”‚ β”‚ +          PIP: 19.1
β”‚ β”‚          - TOXENV: py27-pipmaster
β”‚ β”‚            PIP: master
β”‚ β”‚          - TOXENV: py27-piplatest-coverage
β”‚ β”‚            PIP: latest
β”‚ β”‚  
β”‚ β”‚ -        - TOXENV: py34-pip8.1.1
β”‚ β”‚ -          PIP: 8.1.1
β”‚ β”‚ -        - TOXENV: py34-pip9.0.1
β”‚ β”‚ -          PIP: 9.0.1
β”‚ β”‚ -        - TOXENV: py34-pip9.0.3-coverage
β”‚ β”‚ -          PIP: 9.0.3
β”‚ β”‚ -        - TOXENV: py34-pip10.0.1
β”‚ β”‚ -          PIP: 10.0.1
β”‚ β”‚ -        - TOXENV: py34-pip18.0
β”‚ β”‚ -          PIP: 18.0
β”‚ β”‚ -        - TOXENV: py34-pip19.0
β”‚ β”‚ -          PIP: 19.0
β”‚ β”‚ -        - TOXENV: py34-pipmaster
β”‚ β”‚ -          PIP: master
β”‚ β”‚ -        - TOXENV: py34-piplatest
β”‚ β”‚ -          PIP: latest
β”‚ β”‚ -
β”‚ β”‚          - TOXENV: py35-pip8.1.1
β”‚ β”‚            PIP: 8.1.1
β”‚ β”‚          - TOXENV: py35-pip9.0.1
β”‚ β”‚            PIP: 9.0.1
β”‚ β”‚          - TOXENV: py35-pip9.0.3
β”‚ β”‚            PIP: 9.0.3
β”‚ β”‚          - TOXENV: py35-pip10.0.1
β”‚ β”‚            PIP: 10.0.1
β”‚ β”‚          - TOXENV: py35-pip18.0-coverage
β”‚ β”‚            PIP: 18.0
β”‚ β”‚          - TOXENV: py35-pip19.0
β”‚ β”‚            PIP: 19.0
β”‚ β”‚ +        - TOXENV: py35-pip19.1
β”‚ β”‚ +          PIP: 19.1
β”‚ β”‚          - TOXENV: py35-pipmaster
β”‚ β”‚            PIP: master
β”‚ β”‚          - TOXENV: py35-piplatest
β”‚ β”‚            PIP: latest
β”‚ β”‚  
β”‚ β”‚          - TOXENV: py36-pip8.1.1
β”‚ β”‚            PIP: 8.1.1
β”‚ β”‚ @@ -62,14 +49,16 @@
β”‚ β”‚            PIP: 9.0.3
β”‚ β”‚          - TOXENV: py36-pip10.0.1
β”‚ β”‚            PIP: 10.0.1
β”‚ β”‚          - TOXENV: py36-pip18.0
β”‚ β”‚            PIP: 18.0
β”‚ β”‚          - TOXENV: py36-pip19.0-coverage
β”‚ β”‚            PIP: 19.0
β”‚ β”‚ +        - TOXENV: py36-pip19.1
β”‚ β”‚ +          PIP: 19.1
β”‚ β”‚          - TOXENV: py36-pipmaster
β”‚ β”‚            PIP: master
β”‚ β”‚          - TOXENV: py36-piplatest
β”‚ β”‚            PIP: latest
β”‚ β”‚  
β”‚ β”‚          - TOXENV: py37-pip8.1.1
β”‚ β”‚            PIP: 8.1.1
β”‚ β”‚ @@ -79,14 +68,16 @@
β”‚ β”‚            PIP: 9.0.3
β”‚ β”‚          - TOXENV: py37-pip10.0.1
β”‚ β”‚            PIP: 10.0.1
β”‚ β”‚          - TOXENV: py37-pip18.0
β”‚ β”‚            PIP: 18.0
β”‚ β”‚          - TOXENV: py37-pip19.0
β”‚ β”‚            PIP: 19.0
β”‚ β”‚ +        - TOXENV: py37-pip19.1-coverage
β”‚ β”‚ +          PIP: 19.1
β”‚ β”‚          - TOXENV: py37-pipmaster-coverage
β”‚ β”‚            PIP: master
β”‚ β”‚          - TOXENV: py37-piplatest-coverage
β”‚ β”‚            PIP: latest
β”‚ β”‚  
β”‚ β”‚  matrix:
β”‚ β”‚    fast_finish: true
β”‚   --- pip-tools-3.5.0/pip_tools.egg-info/PKG-INFO
β”œβ”€β”€ +++ pip-tools-4.0.0/pip_tools.egg-info/PKG-INFO
β”‚β”„ Files similar despite different names (difference score: 56)
β”‚ β”‚ @@ -1,44 +1,44 @@
β”‚ β”‚ -Metadata-Version: 1.2
β”‚ β”‚ +Metadata-Version: 2.1
β”‚ β”‚  Name: pip-tools
β”‚ β”‚ -Version: 3.5.0
β”‚ β”‚ +Version: 4.0.0
β”‚ β”‚  Summary: pip-tools keeps your pinned dependencies fresh.
β”‚ β”‚  Home-page: https://github.com/jazzband/pip-tools/
β”‚ β”‚  Author: Vincent Driessen
β”‚ β”‚  Author-email: [email protected]
β”‚ β”‚  License: BSD
β”‚ β”‚ -Description: |buildstatus-travis| |buildstatus-appveyor| |codecov| |coveralls| |jazzband| |pypi|
β”‚ β”‚ +Description: |jazzband| |pypi| |pyversions| |buildstatus-travis| |buildstatus-appveyor| |codecov|
β”‚ β”‚          
β”‚ β”‚          ==================================
β”‚ β”‚          pip-tools = pip-compile + pip-sync
β”‚ β”‚          ==================================
β”‚ β”‚          
β”‚ β”‚          A set of command line tools to help you keep your ``pip``-based packages fresh,
β”‚ β”‚          even when you've pinned them.  `You do pin them, right?`_
β”‚ β”‚          
β”‚ β”‚          .. image:: https://github.com/jazzband/pip-tools/raw/master/img/pip-tools-overview.png
β”‚ β”‚             :alt: pip-tools overview for phase II
β”‚ β”‚          
β”‚ β”‚ -        .. |buildstatus-travis| image:: https://img.shields.io/travis/jazzband/pip-tools/master.svg
β”‚ β”‚ -           :alt: Travis-CI build status
β”‚ β”‚ +        .. |buildstatus-travis| image:: https://img.shields.io/travis/jazzband/pip-tools/master.svg?logo=travis
β”‚ β”‚ +           :alt: Travis CI build status
β”‚ β”‚             :target: https://travis-ci.org/jazzband/pip-tools
β”‚ β”‚ -        .. |buildstatus-appveyor| image:: https://img.shields.io/appveyor/ci/jazzband/pip-tools/master.svg
β”‚ β”‚ -           :alt: Appveyor build status
β”‚ β”‚ +        .. |buildstatus-appveyor| image:: https://img.shields.io/appveyor/ci/jazzband/pip-tools/master.svg?logo=appveyor
β”‚ β”‚ +           :alt: AppVeyor build status
β”‚ β”‚             :target: https://ci.appveyor.com/project/jazzband/pip-tools
β”‚ β”‚          .. |codecov| image:: https://codecov.io/gh/jazzband/pip-tools/branch/master/graph/badge.svg
β”‚ β”‚ -           :alt: Codecov
β”‚ β”‚ +           :alt: Coverage
β”‚ β”‚             :target: https://codecov.io/gh/jazzband/pip-tools
β”‚ β”‚ -        .. |coveralls| image:: https://coveralls.io/repos/github/jazzband/pip-tools/badge.svg?branch=master
β”‚ β”‚ -           :alt: Coveralls
β”‚ β”‚ -           :target: https://coveralls.io/github/jazzband/pip-tools?branch=master
β”‚ β”‚          .. |jazzband| image:: https://jazzband.co/static/img/badge.svg
β”‚ β”‚             :alt: Jazzband
β”‚ β”‚             :target: https://jazzband.co/
β”‚ β”‚          .. |pypi| image:: https://img.shields.io/pypi/v/pip-tools.svg
β”‚ β”‚ -           :alt: PyPI
β”‚ β”‚ +           :alt: PyPI version
β”‚ β”‚ +           :target: https://pypi.org/project/pip-tools/
β”‚ β”‚ +        .. |pyversions| image:: https://img.shields.io/pypi/pyversions/pip-tools.svg
β”‚ β”‚ +           :alt: Supported Python versions
β”‚ β”‚             :target: https://pypi.org/project/pip-tools/
β”‚ β”‚          .. _You do pin them, right?: http://nvie.com/posts/pin-your-packages/
β”‚ β”‚          
β”‚ β”‚          
β”‚ β”‚          Installation
β”‚ β”‚          ============
β”‚ β”‚          
β”‚ β”‚ @@ -54,14 +54,21 @@
β”‚ β”‚          project's virtual environment.
β”‚ β”‚          
β”‚ β”‚          .. _virtual environment: https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments
β”‚ β”‚          
β”‚ β”‚          Example usage for ``pip-compile``
β”‚ β”‚          =================================
β”‚ β”‚          
β”‚ β”‚ +        The ``pip-compile`` command lets you compile a ``requirements.txt`` file from
β”‚ β”‚ +        your dependencies, specified in either ``setup.py`` or ``requirements.in``.
β”‚ β”‚ +        
β”‚ β”‚ +        Run it with ``pip-compile`` or  ``python -m piptools compile``. If you use
β”‚ β”‚ +        multiple Python versions, you can run ``pip-compile`` as ``py -X.Y -m piptools
β”‚ β”‚ +        compile`` on Windows and ``pythonX.Y -m piptools compile`` on other systems.
β”‚ β”‚ +        
β”‚ β”‚          Requirements from ``setup.py``
β”‚ β”‚          ------------------------------
β”‚ β”‚          
β”‚ β”‚          Suppose you have a Flask project, and want to pin it for production.
β”‚ β”‚          If you have a ``setup.py`` with ``install_requires=['Flask']``, then run
β”‚ β”‚          ``pip-compile`` without any arguments:
β”‚ β”‚          
β”‚ β”‚ @@ -114,15 +121,15 @@
β”‚ β”‚              markupsafe==1.0           # via jinja2
β”‚ β”‚              werkzeug==0.12.2          # via flask
β”‚ β”‚          
β”‚ β”‚          And it will produce your ``requirements.txt``, with all the Flask dependencies
β”‚ β”‚          (and all underlying dependencies) pinned.  You should put both
β”‚ β”‚          ``requirements.in`` and ``requirements.txt`` under version control.
β”‚ β”‚          
β”‚ β”‚ -        .. _it's easy to write one: https://packaging.python.org/distributing/#configuring-your-project
β”‚ β”‚ +        .. _it's easy to write one: https://packaging.python.org/guides/distributing-packages-using-setuptools/#configuring-your-project
β”‚ β”‚          
β”‚ β”‚          Using hashes
β”‚ β”‚          ------------
β”‚ β”‚          
β”‚ β”‚          If you would like to use *Hash-Checking Mode* available in ``pip`` since
β”‚ β”‚          version 8.0, ``pip-compile`` offers ``--generate-hashes`` flag:
β”‚ β”‚          
β”‚ β”‚ @@ -167,17 +174,41 @@
β”‚ β”‚          
β”‚ β”‚          .. code-block:: bash
β”‚ β”‚          
β”‚ β”‚              $ pip-compile --upgrade-package flask  # only update the flask package
β”‚ β”‚              $ pip-compile --upgrade-package flask --upgrade-package requests  # update both the flask and requests packages
β”‚ β”‚              $ pip-compile -P flask -P requests==2.0.0  # update the flask package to the latest, and requests to v2.0.0
β”‚ β”‚          
β”‚ β”‚ -        If you use multiple Python versions, you can run ``pip-compile`` as
β”‚ β”‚ -        ``py -X.Y -m piptools compile ...`` on Windows and
β”‚ β”‚ -        ``pythonX.Y -m piptools compile ...`` on other systems.
β”‚ β”‚ +        You can combine ``--upgrade`` and ``--upgrade-package`` in one command, to
β”‚ β”‚ +        provide constraints on the allowed upgrades. For example to upgrade all
β”‚ β”‚ +        packages whilst constraining requests to the latest version less than 3.0:
β”‚ β”‚ +        
β”‚ β”‚ +        .. code-block:: bash
β”‚ β”‚ +        
β”‚ β”‚ +            $ pip-compile --upgrade --upgrade-package 'requests<3.0'
β”‚ β”‚ +        
β”‚ β”‚ +        Output File
β”‚ β”‚ +        -----------
β”‚ β”‚ +        
β”‚ β”‚ +        To output the pinned requirements in a filename other than
β”‚ β”‚ +        ``requirements.txt``, use ``--output-file``. This might be useful for compiling
β”‚ β”‚ +        multiple files, for example with different constraints on flask to test a
β”‚ β”‚ +        library with both versions using `tox <https://tox.readthedocs.io/en/latest/>`__:
β”‚ β”‚ +        
β”‚ β”‚ +        .. code-block:: bash
β”‚ β”‚ +        
β”‚ β”‚ +            $ pip-compile --upgrade-package 'flask<1.0' --output-file requirements-flask0x.txt
β”‚ β”‚ +            $ pip-compile --upgrade-package 'flask<2.0' --output-file requirements-flask1x.txt
β”‚ β”‚ +        
β”‚ β”‚ +        Or to output to standard output, use ``--output-file=-``:
β”‚ β”‚ +        
β”‚ β”‚ +        .. code-block:: bash
β”‚ β”‚ +        
β”‚ β”‚ +            $ pip-compile --output-file=- > requirements.txt
β”‚ β”‚ +            $ pip-compile - --output-file=- < requirements.in > requirements.txt
β”‚ β”‚          
β”‚ β”‚          Configuration
β”‚ β”‚          -------------
β”‚ β”‚          
β”‚ β”‚          You might be wrapping the ``pip-compile`` command in another script. To avoid
β”‚ β”‚          confusing consumers of your custom script you can override the update command
β”‚ β”‚          generated at the top of requirements files by setting the
β”‚ β”‚ @@ -202,25 +233,29 @@
β”‚ β”‚          ==============================
β”‚ β”‚          
β”‚ β”‚          Now that you have a ``requirements.txt``, you can use ``pip-sync`` to update
β”‚ β”‚          your virtual environment to reflect exactly what's in there. This will
β”‚ β”‚          install/upgrade/uninstall everything necessary to match the
β”‚ β”‚          ``requirements.txt`` contents.
β”‚ β”‚          
β”‚ β”‚ +        Run it with ``pip-sync`` or ``python -m piptools sync``. If you use multiple
β”‚ β”‚ +        Python versions, you can also run ``py -X.Y -m piptools sync`` on Windows and
β”‚ β”‚ +        ``pythonX.Y -m piptools sync`` on other systems.
β”‚ β”‚ +        
β”‚ β”‚          **Be careful**: ``pip-sync`` is meant to be used only with a
β”‚ β”‚          ``requirements.txt`` generated by ``pip-compile``.
β”‚ β”‚          
β”‚ β”‚          .. code-block:: bash
β”‚ β”‚          
β”‚ β”‚              $ pip-sync
β”‚ β”‚              Uninstalling flake8-2.4.1:
β”‚ β”‚                Successfully uninstalled flake8-2.4.1
β”‚ β”‚              Collecting click==4.1
β”‚ β”‚                Downloading click-4.1-py2.py3-none-any.whl (62kB)
β”‚ β”‚ -                100% |β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 65kB 1.8MB/s
β”‚ β”‚ +                100% |................................| 65kB 1.8MB/s
β”‚ β”‚                Found existing installation: click 4.0
β”‚ β”‚                  Uninstalling click-4.0:
β”‚ β”‚                    Successfully uninstalled click-4.0
β”‚ β”‚              Successfully installed click-4.1
β”‚ β”‚          
β”‚ β”‚          To sync multiple ``*.txt`` dependency lists, just pass them in via command
β”‚ β”‚          line arguments, e.g.
β”‚ β”‚ @@ -239,28 +274,34 @@
β”‚ β”‚          ``setuptools``, ``pip``, or ``pip-tools`` itself. Use ``pip install --upgrade``
β”‚ β”‚          to upgrade those packages.
β”‚ β”‚          
β”‚ β”‚          Other useful tools
β”‚ β”‚          ==================
β”‚ β”‚          
β”‚ β”‚          - `pipdeptree`_ to print the dependency tree of the installed packages.
β”‚ β”‚ +        - ``requirements.in``/``requirements.txt`` syntax highlighting:
β”‚ β”‚ +        
β”‚ β”‚ +          * `requirements.txt.vim`_ for Vim.
β”‚ β”‚ +          * `Python extension for VS Code`_ for VS Code.
β”‚ β”‚          
β”‚ β”‚          .. _pipdeptree: https://github.com/naiquevin/pipdeptree
β”‚ β”‚ +        .. _requirements.txt.vim: https://github.com/raimon49/requirements.txt.vim
β”‚ β”‚ +        .. _Python extension for VS Code: https://marketplace.visualstudio.com/items?itemName=ms-python.python
β”‚ β”‚          
β”‚ β”‚  Platform: any
β”‚ β”‚  Classifier: Development Status :: 5 - Production/Stable
β”‚ β”‚  Classifier: Intended Audience :: Developers
β”‚ β”‚  Classifier: Intended Audience :: System Administrators
β”‚ β”‚  Classifier: License :: OSI Approved :: BSD License
β”‚ β”‚  Classifier: Operating System :: OS Independent
β”‚ β”‚  Classifier: Programming Language :: Python
β”‚ β”‚  Classifier: Programming Language :: Python :: 2
β”‚ β”‚  Classifier: Programming Language :: Python :: 2.7
β”‚ β”‚  Classifier: Programming Language :: Python :: 3
β”‚ β”‚ -Classifier: Programming Language :: Python :: 3.4
β”‚ β”‚  Classifier: Programming Language :: Python :: 3.5
β”‚ β”‚  Classifier: Programming Language :: Python :: 3.6
β”‚ β”‚  Classifier: Programming Language :: Python :: 3.7
β”‚ β”‚  Classifier: Programming Language :: Python :: Implementation :: CPython
β”‚ β”‚  Classifier: Programming Language :: Python :: Implementation :: PyPy
β”‚ β”‚  Classifier: Topic :: System :: Systems Administration
β”‚ β”‚ -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
β”‚ β”‚ +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
β”‚ β”‚ +Description-Content-Type: text/x-rst
β”œβ”€β”€ encoding
β”‚ β”‚ β”‚ @@ -1 +1 @@
β”‚ β”‚ β”‚ -utf-8
β”‚ β”‚ β”‚ +us-ascii
β”‚   --- pip-tools-3.5.0/tests/test_fake_index.py
β”œβ”€β”€ +++ pip-tools-4.0.0/tests/test_fake_index.py
β”‚β”„ Files similar despite different names (difference score: 46)
β”‚ β”‚ @@ -1,63 +1,80 @@
β”‚ β”‚  from pytest import raises
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_find_best_match(from_line, repository):
β”‚ β”‚ -    ireq = from_line('django>1.5')
β”‚ β”‚ -    assert str(repository.find_best_match(ireq)) == 'django==1.8'
β”‚ β”‚ +    ireq = from_line("django>1.5")
β”‚ β”‚ +    assert str(repository.find_best_match(ireq)) == "django==1.8"
β”‚ β”‚  
β”‚ β”‚ -    ireq = from_line('django<1.8,~=1.6')
β”‚ β”‚ -    assert str(repository.find_best_match(ireq)) == 'django==1.7.7'
β”‚ β”‚ +    ireq = from_line("django<1.8,~=1.6")
β”‚ β”‚ +    assert str(repository.find_best_match(ireq)) == "django==1.7.7"
β”‚ β”‚  
β”‚ β”‚      # Extras available, but no extras specified
β”‚ β”‚ -    ireq = from_line('ipython')
β”‚ β”‚ -    assert str(repository.find_best_match(ireq)) == 'ipython==2.1.0'
β”‚ β”‚ +    ireq = from_line("ipython")
β”‚ β”‚ +    assert str(repository.find_best_match(ireq)) == "ipython==2.1.0"
β”‚ β”‚  
β”‚ β”‚      # Make sure we include extras. They should be sorted in the output.
β”‚ β”‚ -    ireq = from_line('ipython[notebook,nbconvert]')
β”‚ β”‚ -    assert str(repository.find_best_match(ireq)) == 'ipython[nbconvert,notebook]==2.1.0'
β”‚ β”‚ +    ireq = from_line("ipython[notebook,nbconvert]")
β”‚ β”‚ +    assert str(repository.find_best_match(ireq)) == "ipython[nbconvert,notebook]==2.1.0"
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_find_best_match_incl_prereleases(from_line, repository):
β”‚ β”‚ -    ireq = from_line('SQLAlchemy')
β”‚ β”‚ -    assert str(repository.find_best_match(ireq, prereleases=False)) == 'sqlalchemy==0.9.9'
β”‚ β”‚ -    assert str(repository.find_best_match(ireq, prereleases=True)) == 'sqlalchemy==1.0.0b5'
β”‚ β”‚ +    ireq = from_line("SQLAlchemy")
β”‚ β”‚ +    assert (
β”‚ β”‚ +        str(repository.find_best_match(ireq, prereleases=False)) == "sqlalchemy==0.9.9"
β”‚ β”‚ +    )
β”‚ β”‚ +    assert (
β”‚ β”‚ +        str(repository.find_best_match(ireq, prereleases=True)) == "sqlalchemy==1.0.0b5"
β”‚ β”‚ +    )
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_find_best_match_for_editable(from_editable, repository):
β”‚ β”‚ -    ireq = from_editable('git+git://whatev.org/blah.git#egg=flask')
β”‚ β”‚ +    ireq = from_editable("git+git://whatev.org/blah.git#egg=flask")
β”‚ β”‚      assert repository.find_best_match(ireq) == ireq
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_get_dependencies(from_line, repository):
β”‚ β”‚ -    ireq = from_line('django==1.6.11')
β”‚ β”‚ +    ireq = from_line("django==1.6.11")
β”‚ β”‚      assert repository.get_dependencies(ireq) == []
β”‚ β”‚  
β”‚ β”‚ -    ireq = from_line('Flask==0.10.1')
β”‚ β”‚ +    ireq = from_line("Flask==0.10.1")
β”‚ β”‚      dependencies = repository.get_dependencies(ireq)
β”‚ β”‚ -    assert ({str(req) for req in dependencies} ==
β”‚ β”‚ -            {'Werkzeug>=0.7', 'Jinja2>=2.4', 'itsdangerous>=0.21'})
β”‚ β”‚ +    assert {str(req) for req in dependencies} == {
β”‚ β”‚ +        "Werkzeug>=0.7",
β”‚ β”‚ +        "Jinja2>=2.4",
β”‚ β”‚ +        "itsdangerous>=0.21",
β”‚ β”‚ +    }
β”‚ β”‚  
β”‚ β”‚ -    ireq = from_line('ipython==2.1.0')
β”‚ β”‚ +    ireq = from_line("ipython==2.1.0")
β”‚ β”‚      dependencies = repository.get_dependencies(ireq)
β”‚ β”‚ -    assert {str(req) for req in dependencies} == {'gnureadline'}
β”‚ β”‚ +    assert {str(req) for req in dependencies} == {"gnureadline"}
β”‚ β”‚  
β”‚ β”‚ -    ireq = from_line('ipython[notebook]==2.1.0')
β”‚ β”‚ +    ireq = from_line("ipython[notebook]==2.1.0")
β”‚ β”‚      dependencies = repository.get_dependencies(ireq)
β”‚ β”‚ -    assert ({str(req) for req in dependencies} ==
β”‚ β”‚ -            {'gnureadline', 'pyzmq>=2.1.11', 'tornado>=3.1', 'jinja2'})
β”‚ β”‚ +    assert {str(req) for req in dependencies} == {
β”‚ β”‚ +        "gnureadline",
β”‚ β”‚ +        "pyzmq>=2.1.11",
β”‚ β”‚ +        "tornado>=3.1",
β”‚ β”‚ +        "jinja2",
β”‚ β”‚ +    }
β”‚ β”‚  
β”‚ β”‚ -    ireq = from_line('ipython[notebook,nbconvert]==2.1.0')
β”‚ β”‚ +    ireq = from_line("ipython[notebook,nbconvert]==2.1.0")
β”‚ β”‚      dependencies = repository.get_dependencies(ireq)
β”‚ β”‚ -    assert ({str(req) for req in dependencies} ==
β”‚ β”‚ -            {'gnureadline', 'pyzmq>=2.1.11', 'tornado>=3.1', 'jinja2', 'pygments', 'Sphinx>=0.3'})
β”‚ β”‚ +    assert {str(req) for req in dependencies} == {
β”‚ β”‚ +        "gnureadline",
β”‚ β”‚ +        "pyzmq>=2.1.11",
β”‚ β”‚ +        "tornado>=3.1",
β”‚ β”‚ +        "jinja2",
β”‚ β”‚ +        "pygments",
β”‚ β”‚ +        "Sphinx>=0.3",
β”‚ β”‚ +    }
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_get_dependencies_for_editable(from_editable, repository):
β”‚ β”‚ -    ireq = from_editable('git+git://example.org/django.git#egg=django')
β”‚ β”‚ +    ireq = from_editable("git+git://example.org/django.git#egg=django")
β”‚ β”‚      assert repository.get_dependencies(ireq) == []
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_get_dependencies_rejects_non_pinned_requirements(from_line, repository):
β”‚ β”‚ -    not_a_pinned_req = from_line('django>1.6')
β”‚ β”‚ +    not_a_pinned_req = from_line("django>1.6")
β”‚ β”‚      with raises(TypeError):
β”‚ β”‚          repository.get_dependencies(not_a_pinned_req)
β”‚   --- pip-tools-3.5.0/tests/test_data/minimal_wheels/small_fake_a-0.2-py2.py3-none-any.whl
β”œβ”€β”€ +++ pip-tools-4.0.0/tests/test_data/minimal_wheels/small_fake_a-0.2-py2.py3-none-any.whl
β”‚β”„ Files similar despite different names (difference score: 0)
β”‚   --- pip-tools-3.5.0/tests/test_data/minimal_wheels/small_fake_b-0.1-py2.py3-none-any.whl
β”œβ”€β”€ +++ pip-tools-4.0.0/tests/test_data/minimal_wheels/small_fake_b-0.1-py2.py3-none-any.whl
β”‚β”„ Files similar despite different names (difference score: 0)
β”‚   --- pip-tools-3.5.0/img/pip-tools-overview.png
β”œβ”€β”€ +++ pip-tools-4.0.0/img/pip-tools-overview.png
β”‚β”„ Files similar despite different names (difference score: 0)
β”‚   --- pip-tools-3.5.0/piptools/exceptions.py
β”œβ”€β”€ +++ pip-tools-4.0.0/piptools/exceptions.py
β”‚β”„ Files similar despite different names (difference score: 54)
β”‚ β”‚ @@ -15,48 +15,43 @@
β”‚ β”‚          for candidate in sorted(self.candidates_tried):
β”‚ β”‚              version = str(candidate.version)
β”‚ β”‚              if candidate.version.is_prerelease:
β”‚ β”‚                  pre_versions.append(version)
β”‚ β”‚              else:
β”‚ β”‚                  versions.append(version)
β”‚ β”‚  
β”‚ β”‚ -        lines = [
β”‚ β”‚ -            'Could not find a version that matches {}'.format(self.ireq),
β”‚ β”‚ -        ]
β”‚ β”‚ +        lines = ["Could not find a version that matches {}".format(self.ireq)]
β”‚ β”‚  
β”‚ β”‚          if versions:
β”‚ β”‚ -            lines.append('Tried: {}'.format(', '.join(versions)))
β”‚ β”‚ +            lines.append("Tried: {}".format(", ".join(versions)))
β”‚ β”‚  
β”‚ β”‚          if pre_versions:
β”‚ β”‚              if self.finder.allow_all_prereleases:
β”‚ β”‚ -                line = 'Tried'
β”‚ β”‚ +                line = "Tried"
β”‚ β”‚              else:
β”‚ β”‚ -                line = 'Skipped'
β”‚ β”‚ +                line = "Skipped"
β”‚ β”‚  
β”‚ β”‚ -            line += ' pre-versions: {}'.format(', '.join(pre_versions))
β”‚ β”‚ +            line += " pre-versions: {}".format(", ".join(pre_versions))
β”‚ β”‚              lines.append(line)
β”‚ β”‚  
β”‚ β”‚          if versions or pre_versions:
β”‚ β”‚ -            lines.append('There are incompatible versions in the resolved dependencies.')
β”‚ β”‚ +            lines.append(
β”‚ β”‚ +                "There are incompatible versions in the resolved dependencies:"
β”‚ β”‚ +            )
β”‚ β”‚ +            source_ireqs = getattr(self.ireq, "_source_ireqs", [])
β”‚ β”‚ +            lines.extend("  {}".format(ireq) for ireq in source_ireqs)
β”‚ β”‚          else:
β”‚ β”‚ -            lines.append('No versions found')
β”‚ β”‚ -            lines.append('{} {} reachable?'.format(
β”‚ β”‚ -                'Were' if len(self.finder.index_urls) > 1 else 'Was', ' or '.join(self.finder.index_urls))
β”‚ β”‚ +            lines.append("No versions found")
β”‚ β”‚ +            lines.append(
β”‚ β”‚ +                "{} {} reachable?".format(
β”‚ β”‚ +                    "Were" if len(self.finder.index_urls) > 1 else "Was",
β”‚ β”‚ +                    " or ".join(self.finder.index_urls),
β”‚ β”‚ +                )
β”‚ β”‚              )
β”‚ β”‚ -        return '\n'.join(lines)
β”‚ β”‚ -
β”‚ β”‚ -
β”‚ β”‚ -class UnsupportedConstraint(PipToolsError):
β”‚ β”‚ -    def __init__(self, message, constraint):
β”‚ β”‚ -        super(UnsupportedConstraint, self).__init__(message)
β”‚ β”‚ -        self.constraint = constraint
β”‚ β”‚ -
β”‚ β”‚ -    def __str__(self):
β”‚ β”‚ -        message = super(UnsupportedConstraint, self).__str__()
β”‚ β”‚ -        return '{} (constraint was: {})'.format(message, str(self.constraint))
β”‚ β”‚ +        return "\n".join(lines)
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  class IncompatibleRequirements(PipToolsError):
β”‚ β”‚      def __init__(self, ireq_a, ireq_b):
β”‚ β”‚          self.ireq_a = ireq_a
β”‚ β”‚          self.ireq_b = ireq_b
β”‚   --- pip-tools-3.5.0/piptools/repositories/local.py
β”œβ”€β”€ +++ pip-tools-4.0.0/piptools/repositories/local.py
β”‚β”„ Files similar despite different names (difference score: 13)
β”‚ β”‚ @@ -1,16 +1,16 @@
β”‚ β”‚  # coding: utf-8
β”‚ β”‚ -from __future__ import (absolute_import, division, print_function,
β”‚ β”‚ -                        unicode_literals)
β”‚ β”‚ +from __future__ import absolute_import, division, print_function, unicode_literals
β”‚ β”‚  
β”‚ β”‚  from contextlib import contextmanager
β”‚ β”‚  
β”‚ β”‚ -from piptools.utils import as_tuple, key_from_req, make_install_requirement
β”‚ β”‚ -from .base import BaseRepository
β”‚ β”‚  from .._compat import FAVORITE_HASH
β”‚ β”‚ +from .base import BaseRepository
β”‚ β”‚ +
β”‚ β”‚ +from piptools.utils import as_tuple, key_from_req, make_install_requirement
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def ireq_satisfied_by_existing_pin(ireq, existing_pin):
β”‚ β”‚      """
β”‚ β”‚      Return True if the given InstallationRequirement is satisfied by the
β”‚ β”‚      previously encountered version pin.
β”‚ β”‚      """
β”‚ β”‚ @@ -24,19 +24,24 @@
β”‚ β”‚      checking if a requirement can be satisfied by existing pins (i.e. the
β”‚ β”‚      result of a previous compile step).
β”‚ β”‚  
β”‚ β”‚      In effect, if a requirement can be satisfied with a version pinned in the
β”‚ β”‚      requirements file, we prefer that version over the best match found in
β”‚ β”‚      PyPI.  This keeps updates to the requirements.txt down to a minimum.
β”‚ β”‚      """
β”‚ β”‚ +
β”‚ β”‚      def __init__(self, existing_pins, proxied_repository):
β”‚ β”‚          self.repository = proxied_repository
β”‚ β”‚          self.existing_pins = existing_pins
β”‚ β”‚  
β”‚ β”‚      @property
β”‚ β”‚ +    def options(self):
β”‚ β”‚ +        return self.repository.options
β”‚ β”‚ +
β”‚ β”‚ +    @property
β”‚ β”‚      def finder(self):
β”‚ β”‚          return self.repository.finder
β”‚ β”‚  
β”‚ β”‚      @property
β”‚ β”‚      def session(self):
β”‚ β”‚          return self.repository.session
β”‚ β”‚  
β”‚ β”‚ @@ -64,20 +69,19 @@
β”‚ β”‚      def get_dependencies(self, ireq):
β”‚ β”‚          return self.repository.get_dependencies(ireq)
β”‚ β”‚  
β”‚ β”‚      def get_hashes(self, ireq):
β”‚ β”‚          key = key_from_req(ireq.req)
β”‚ β”‚          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', {})
β”‚ β”‚ +            hashes = existing_pin.options.get("hashes", {})
β”‚ β”‚              hexdigests = hashes.get(FAVORITE_HASH)
β”‚ β”‚              if hexdigests:
β”‚ β”‚                  return {
β”‚ β”‚ -                    ':'.join([FAVORITE_HASH, hexdigest])
β”‚ β”‚ -                    for hexdigest in hexdigests
β”‚ β”‚ +                    ":".join([FAVORITE_HASH, hexdigest]) for hexdigest in hexdigests
β”‚ β”‚                  }
β”‚ β”‚          return self.repository.get_hashes(ireq)
β”‚ β”‚  
β”‚ β”‚      @contextmanager
β”‚ β”‚      def allow_all_wheels(self):
β”‚ β”‚          with self.repository.allow_all_wheels():
β”‚ β”‚              yield
β”‚   --- pip-tools-3.5.0/tests/test_sync.py
β”œβ”€β”€ +++ pip-tools-4.0.0/tests/test_sync.py
β”‚β”„ Files similar despite different names (difference score: 43)
β”‚ β”‚ @@ -1,393 +1,447 @@
β”‚ β”‚ -from collections import Counter
β”‚ β”‚  import os
β”‚ β”‚  import platform
β”‚ β”‚  import sys
β”‚ β”‚  import tempfile
β”‚ β”‚ +from collections import Counter
β”‚ β”‚  
β”‚ β”‚  import mock
β”‚ β”‚  import pytest
β”‚ β”‚  
β”‚ β”‚ -from piptools.exceptions import IncompatibleRequirements, UnsupportedConstraint
β”‚ β”‚ +from piptools.exceptions import IncompatibleRequirements
β”‚ β”‚  from piptools.sync import dependency_tree, diff, merge, sync
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  @pytest.fixture
β”‚ β”‚  def mocked_tmp_file():
β”‚ β”‚ -    with mock.patch.object(tempfile, 'NamedTemporaryFile') as m:
β”‚ β”‚ +    with mock.patch.object(tempfile, "NamedTemporaryFile") as m:
β”‚ β”‚          yield m.return_value
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  @pytest.fixture
β”‚ β”‚  def mocked_tmp_req_file(mocked_tmp_file):
β”‚ β”‚ -    with mock.patch('os.unlink'):
β”‚ β”‚ -        mocked_tmp_file.name = 'requirements.txt'
β”‚ β”‚ +    with mock.patch("os.unlink"):
β”‚ β”‚ +        mocked_tmp_file.name = "requirements.txt"
β”‚ β”‚          yield mocked_tmp_file
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  @pytest.mark.parametrize(
β”‚ β”‚ -    ('installed', 'root', 'expected'),
β”‚ β”‚ -
β”‚ β”‚ +    ("installed", "root", "expected"),
β”‚ β”‚      [
β”‚ β”‚ -        ([],
β”‚ β”‚ -            'pip-tools', []),
β”‚ β”‚ -
β”‚ β”‚ -        ([('pip-tools==1', [])],
β”‚ β”‚ -            'pip-tools', ['pip-tools']),
β”‚ β”‚ -
β”‚ β”‚ -        ([('pip-tools==1', []),
β”‚ β”‚ -          ('django==1.7', [])],
β”‚ β”‚ -            'pip-tools', ['pip-tools']),
β”‚ β”‚ -
β”‚ β”‚ -        ([('pip-tools==1', ['click>=2']),
β”‚ β”‚ -          ('django==1.7', []),
β”‚ β”‚ -          ('click==3', [])],
β”‚ β”‚ -            'pip-tools', ['pip-tools', 'click']),
β”‚ β”‚ -
β”‚ β”‚ -        ([('pip-tools==1', ['click>=2']),
β”‚ β”‚ -          ('django==1.7', []),
β”‚ β”‚ -          ('click==1', [])],
β”‚ β”‚ -            'pip-tools', ['pip-tools']),
β”‚ β”‚ -
β”‚ β”‚ -        ([('root==1', ['child==2']),
β”‚ β”‚ -          ('child==2', ['grandchild==3'])],
β”‚ β”‚ -            'root', ['root', 'child']),
β”‚ β”‚ -
β”‚ β”‚ -        ([('root==1', ['child==2']),
β”‚ β”‚ -          ('child==2', ['grandchild==3']),
β”‚ β”‚ -          ('grandchild==3', [])],
β”‚ β”‚ -            'root', ['root', 'child', 'grandchild']),
β”‚ β”‚ -
β”‚ β”‚ -        ([('root==1', ['child==2']),
β”‚ β”‚ -          ('child==2', ['root==1'])],
β”‚ β”‚ -            'root', ['root', 'child']),
β”‚ β”‚ -    ]
β”‚ β”‚ +        ([], "pip-tools", []),
β”‚ β”‚ +        ([("pip-tools==1", [])], "pip-tools", ["pip-tools"]),
β”‚ β”‚ +        ([("pip-tools==1", []), ("django==1.7", [])], "pip-tools", ["pip-tools"]),
β”‚ β”‚ +        (
β”‚ β”‚ +            [("pip-tools==1", ["click>=2"]), ("django==1.7", []), ("click==3", [])],
β”‚ β”‚ +            "pip-tools",
β”‚ β”‚ +            ["pip-tools", "click"],
β”‚ β”‚ +        ),
β”‚ β”‚ +        (
β”‚ β”‚ +            [("pip-tools==1", ["click>=2"]), ("django==1.7", []), ("click==1", [])],
β”‚ β”‚ +            "pip-tools",
β”‚ β”‚ +            ["pip-tools"],
β”‚ β”‚ +        ),
β”‚ β”‚ +        (
β”‚ β”‚ +            [("root==1", ["child==2"]), ("child==2", ["grandchild==3"])],
β”‚ β”‚ +            "root",
β”‚ β”‚ +            ["root", "child"],
β”‚ β”‚ +        ),
β”‚ β”‚ +        (
β”‚ β”‚ +            [
β”‚ β”‚ +                ("root==1", ["child==2"]),
β”‚ β”‚ +                ("child==2", ["grandchild==3"]),
β”‚ β”‚ +                ("grandchild==3", []),
β”‚ β”‚ +            ],
β”‚ β”‚ +            "root",
β”‚ β”‚ +            ["root", "child", "grandchild"],
β”‚ β”‚ +        ),
β”‚ β”‚ +        (
β”‚ β”‚ +            [("root==1", ["child==2"]), ("child==2", ["root==1"])],
β”‚ β”‚ +            "root",
β”‚ β”‚ +            ["root", "child"],
β”‚ β”‚ +        ),
β”‚ β”‚ +    ],
β”‚ β”‚  )
β”‚ β”‚  def test_dependency_tree(fake_dist, installed, root, expected):
β”‚ β”‚ -    installed = {distribution.key: distribution
β”‚ β”‚ -                 for distribution in
β”‚ β”‚ -                 (fake_dist(name, deps) for name, deps in installed)}
β”‚ β”‚ +    installed = {
β”‚ β”‚ +        distribution.key: distribution
β”‚ β”‚ +        for distribution in (fake_dist(name, deps) for name, deps in installed)
β”‚ β”‚ +    }
β”‚ β”‚  
β”‚ β”‚      actual = dependency_tree(installed, root)
β”‚ β”‚      assert actual == set(expected)
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_merge_detect_conflicts(from_line):
β”‚ β”‚ -    requirements = [from_line('flask==1'), from_line('flask==2')]
β”‚ β”‚ +    requirements = [from_line("flask==1"), from_line("flask==2")]
β”‚ β”‚  
β”‚ β”‚      with pytest.raises(IncompatibleRequirements):
β”‚ β”‚          merge(requirements, ignore_conflicts=False)
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_merge_ignore_conflicts(from_line):
β”‚ β”‚ -    requirements = [from_line('flask==1'), from_line('flask==2')]
β”‚ β”‚ +    requirements = [from_line("flask==1"), from_line("flask==2")]
β”‚ β”‚  
β”‚ β”‚ -    assert Counter(requirements[1:2]) == Counter(merge(requirements, ignore_conflicts=True))
β”‚ β”‚ +    assert Counter(requirements[1:2]) == Counter(
β”‚ β”‚ +        merge(requirements, ignore_conflicts=True)
β”‚ β”‚ +    )
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_merge(from_line):
β”‚ β”‚ -    requirements = [from_line('flask==1'),
β”‚ β”‚ -                    from_line('flask==1'),
β”‚ β”‚ -                    from_line('django==2')]
β”‚ β”‚ +    requirements = [
β”‚ β”‚ +        from_line("flask==1"),
β”‚ β”‚ +        from_line("flask==1"),
β”‚ β”‚ +        from_line("django==2"),
β”‚ β”‚ +    ]
β”‚ β”‚  
β”‚ β”‚ -    assert Counter(requirements[1:3]) == Counter(merge(requirements, ignore_conflicts=False))
β”‚ β”‚ +    assert Counter(requirements[1:3]) == Counter(
β”‚ β”‚ +        merge(requirements, ignore_conflicts=False)
β”‚ β”‚ +    )
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚ -def test_merge_non_editable_url(from_line):
β”‚ β”‚ -    """
β”‚ β”‚ -    Non-editable URLs are not supported.
β”‚ β”‚ -    """
β”‚ β”‚ -    requirements = [from_line('django==1.8'),
β”‚ β”‚ -                    from_line('https://example.com/#egg=example')]
β”‚ β”‚ +def test_merge_urls(from_line):
β”‚ β”‚ +    requirements = [
β”‚ β”‚ +        from_line("file:///example.zip#egg=example==1.0"),
β”‚ β”‚ +        from_line("example==1.0"),
β”‚ β”‚ +        from_line("file:///unrelated.zip"),
β”‚ β”‚ +    ]
β”‚ β”‚  
β”‚ β”‚ -    with pytest.raises(UnsupportedConstraint):
β”‚ β”‚ -        merge(requirements, ignore_conflicts=True)
β”‚ β”‚ +    assert Counter(requirements[1:]) == Counter(
β”‚ β”‚ +        merge(requirements, ignore_conflicts=False)
β”‚ β”‚ +    )
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_diff_should_do_nothing():
β”‚ β”‚      installed = []  # empty env
β”‚ β”‚      reqs = []  # no requirements
β”‚ β”‚  
β”‚ β”‚      to_install, to_uninstall = diff(reqs, installed)
β”‚ β”‚      assert to_install == set()
β”‚ β”‚      assert to_uninstall == set()
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_diff_should_install(from_line):
β”‚ β”‚      installed = []  # empty env
β”‚ β”‚ -    reqs = [from_line('django==1.8')]
β”‚ β”‚ +    reqs = [from_line("django==1.8")]
β”‚ β”‚  
β”‚ β”‚      to_install, to_uninstall = diff(reqs, installed)
β”‚ β”‚ -    assert {str(x.req) for x in to_install} == {'django==1.8'}
β”‚ β”‚ +    assert {str(x.req) for x in to_install} == {"django==1.8"}
β”‚ β”‚      assert to_uninstall == set()
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_diff_should_uninstall(fake_dist):
β”‚ β”‚ -    installed = [fake_dist('django==1.8')]
β”‚ β”‚ +    installed = [fake_dist("django==1.8")]
β”‚ β”‚      reqs = []
β”‚ β”‚  
β”‚ β”‚      to_install, to_uninstall = diff(reqs, installed)
β”‚ β”‚      assert to_install == set()
β”‚ β”‚ -    assert to_uninstall == {'django'}  # no version spec when uninstalling
β”‚ β”‚ +    assert to_uninstall == {"django"}  # no version spec when uninstalling
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_diff_should_not_uninstall(fake_dist):
β”‚ β”‚ -    ignored = ('pip==7.1.0', 'pip-tools==1.1.1', 'pip-review==1.1.1',
β”‚ β”‚ -               'pkg-resources==0.0.0', 'setuptools==34.0.0', 'wheel==0.29.0',
β”‚ β”‚ -               'python==3.0', 'distribute==0.1', 'wsgiref==0.1', 'argparse==0.1')
β”‚ β”‚ +    ignored = (
β”‚ β”‚ +        "pip==7.1.0",
β”‚ β”‚ +        "pip-tools==1.1.1",
β”‚ β”‚ +        "pip-review==1.1.1",
β”‚ β”‚ +        "pkg-resources==0.0.0",
β”‚ β”‚ +        "setuptools==34.0.0",
β”‚ β”‚ +        "wheel==0.29.0",
β”‚ β”‚ +        "python==3.0",
β”‚ β”‚ +        "distribute==0.1",
β”‚ β”‚ +        "wsgiref==0.1",
β”‚ β”‚ +        "argparse==0.1",
β”‚ β”‚ +    )
β”‚ β”‚      installed = [fake_dist(pkg) for pkg in ignored]
β”‚ β”‚      reqs = []
β”‚ β”‚  
β”‚ β”‚      to_uninstall = diff(reqs, installed)[1]
β”‚ β”‚      assert to_uninstall == set()
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_diff_should_update(fake_dist, from_line):
β”‚ β”‚ -    installed = [fake_dist('django==1.7')]
β”‚ β”‚ -    reqs = [from_line('django==1.8')]
β”‚ β”‚ +    installed = [fake_dist("django==1.7")]
β”‚ β”‚ +    reqs = [from_line("django==1.8")]
β”‚ β”‚  
β”‚ β”‚      to_install, to_uninstall = diff(reqs, installed)
β”‚ β”‚ -    assert {str(x.req) for x in to_install} == {'django==1.8'}
β”‚ β”‚ +    assert {str(x.req) for x in to_install} == {"django==1.8"}
β”‚ β”‚      assert to_uninstall == set()
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_diff_should_install_with_markers(from_line):
β”‚ β”‚      installed = []
β”‚ β”‚      reqs = [from_line("subprocess32==3.2.7 ; python_version=='2.7'")]
β”‚ β”‚  
β”‚ β”‚      to_install, to_uninstall = diff(reqs, installed)
β”‚ β”‚ -    assert {str(x.req) for x in to_install} == ({'subprocess32==3.2.7'} if sys.version.startswith('2.7') else set())
β”‚ β”‚ +    assert {str(x.req) for x in to_install} == (
β”‚ β”‚ +        {"subprocess32==3.2.7"} if sys.version.startswith("2.7") else set()
β”‚ β”‚ +    )
β”‚ β”‚      assert to_uninstall == set()
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_diff_should_uninstall_with_markers(fake_dist, from_line):
β”‚ β”‚ -    installed = [fake_dist('subprocess32==3.2.7')]
β”‚ β”‚ +    installed = [fake_dist("subprocess32==3.2.7")]
β”‚ β”‚      reqs = [from_line("subprocess32==3.2.7 ; python_version=='2.7'")]
β”‚ β”‚  
β”‚ β”‚      to_install, to_uninstall = diff(reqs, installed)
β”‚ β”‚      assert to_install == set()
β”‚ β”‚ -    assert to_uninstall == (set() if sys.version.startswith('2.7') else {'subprocess32'})
β”‚ β”‚ +    assert to_uninstall == (
β”‚ β”‚ +        set() if sys.version.startswith("2.7") else {"subprocess32"}
β”‚ β”‚ +    )
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_diff_leave_packaging_packages_alone(fake_dist, from_line):
β”‚ β”‚      # Suppose an env contains Django, and pip itself
β”‚ β”‚      installed = [
β”‚ β”‚ -        fake_dist('django==1.7'),
β”‚ β”‚ -        fake_dist('first==2.0.1'),
β”‚ β”‚ -        fake_dist('pip==7.1.0'),
β”‚ β”‚ +        fake_dist("django==1.7"),
β”‚ β”‚ +        fake_dist("first==2.0.1"),
β”‚ β”‚ +        fake_dist("pip==7.1.0"),
β”‚ β”‚      ]
β”‚ β”‚  
β”‚ β”‚      # Then this Django-only requirement should keep pip around (i.e. NOT
β”‚ β”‚      # uninstall it), but uninstall first
β”‚ β”‚ -    reqs = [
β”‚ β”‚ -        from_line('django==1.7'),
β”‚ β”‚ -    ]
β”‚ β”‚ +    reqs = [from_line("django==1.7")]
β”‚ β”‚  
β”‚ β”‚      to_install, to_uninstall = diff(reqs, installed)
β”‚ β”‚      assert to_install == set()
β”‚ β”‚ -    assert to_uninstall == {'first'}
β”‚ β”‚ +    assert to_uninstall == {"first"}
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_diff_leave_piptools_alone(fake_dist, from_line):
β”‚ β”‚      # Suppose an env contains Django, and pip-tools itself (including all of
β”‚ β”‚      # its dependencies)
β”‚ β”‚      installed = [
β”‚ β”‚ -        fake_dist('django==1.7'),
β”‚ β”‚ -        fake_dist('first==2.0.1'),
β”‚ β”‚ -        fake_dist('pip-tools==1.1.1', [
β”‚ β”‚ -            'click>=4',
β”‚ β”‚ -            'first',
β”‚ β”‚ -            'six',
β”‚ β”‚ -        ]),
β”‚ β”‚ -        fake_dist('six==1.9.0'),
β”‚ β”‚ -        fake_dist('click==4.1'),
β”‚ β”‚ -        fake_dist('foobar==0.3.6'),
β”‚ β”‚ +        fake_dist("django==1.7"),
β”‚ β”‚ +        fake_dist("first==2.0.1"),
β”‚ β”‚ +        fake_dist("pip-tools==1.1.1", ["click>=4", "first", "six"]),
β”‚ β”‚ +        fake_dist("six==1.9.0"),
β”‚ β”‚ +        fake_dist("click==4.1"),
β”‚ β”‚ +        fake_dist("foobar==0.3.6"),
β”‚ β”‚      ]
β”‚ β”‚  
β”‚ β”‚      # Then this Django-only requirement should keep pip around (i.e. NOT
β”‚ β”‚      # uninstall it), but uninstall first
β”‚ β”‚ -    reqs = [
β”‚ β”‚ -        from_line('django==1.7'),
β”‚ β”‚ -    ]
β”‚ β”‚ +    reqs = [from_line("django==1.7")]
β”‚ β”‚  
β”‚ β”‚      to_install, to_uninstall = diff(reqs, installed)
β”‚ β”‚      assert to_install == set()
β”‚ β”‚ -    assert to_uninstall == {'foobar'}
β”‚ β”‚ +    assert to_uninstall == {"foobar"}
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def _get_file_url(local_path):
β”‚ β”‚ -    if platform.system() == 'Windows':
β”‚ β”‚ -        local_path = '/%s' % local_path.replace('\\', '/')
β”‚ β”‚ -    return 'file://%s' % local_path
β”‚ β”‚ +    if platform.system() == "Windows":
β”‚ β”‚ +        local_path = "/%s" % local_path.replace("\\", "/")
β”‚ β”‚ +    return "file://%s" % local_path
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_diff_with_editable(fake_dist, from_editable):
β”‚ β”‚ -    installed = [
β”‚ β”‚ -        fake_dist('small-fake-with-deps==0.0.1'),
β”‚ β”‚ -        fake_dist('six==1.10.0'),
β”‚ β”‚ -    ]
β”‚ β”‚ -    path_to_package = os.path.join(os.path.dirname(__file__), 'test_data', 'small_fake_package')
β”‚ β”‚ -    reqs = [
β”‚ β”‚ -        from_editable(path_to_package),
β”‚ β”‚ -    ]
β”‚ β”‚ +    installed = [fake_dist("small-fake-with-deps==0.0.1"), fake_dist("six==1.10.0")]
β”‚ β”‚ +    path_to_package = os.path.join(
β”‚ β”‚ +        os.path.dirname(__file__), "test_data", "small_fake_package"
β”‚ β”‚ +    )
β”‚ β”‚ +    reqs = [from_editable(path_to_package)]
β”‚ β”‚      to_install, to_uninstall = diff(reqs, installed)
β”‚ β”‚  
β”‚ β”‚ -    # FIXME: The editable package is uninstalled and reinstalled, including all its dependencies,
β”‚ β”‚ -    # even if the version numbers match.
β”‚ β”‚ -    assert to_uninstall == {'six', 'small-fake-with-deps'}
β”‚ β”‚ +    # FIXME: The editable package is uninstalled and reinstalled, including
β”‚ β”‚ +    # all its dependencies, even if the version numbers match.
β”‚ β”‚ +    assert to_uninstall == {"six", "small-fake-with-deps"}
β”‚ β”‚  
β”‚ β”‚      assert len(to_install) == 1
β”‚ β”‚      package = list(to_install)[0]
β”‚ β”‚      assert package.editable
β”‚ β”‚      assert str(package.link) == _get_file_url(path_to_package)
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚ -def test_sync_install_temporary_requirement_file(from_line, from_editable, mocked_tmp_req_file):
β”‚ β”‚ -    with mock.patch('piptools.sync.check_call') as check_call:
β”‚ β”‚ -        to_install = {from_line('django==1.8')}
β”‚ β”‚ +def test_diff_with_matching_url_versions(fake_dist, from_line):
β”‚ β”‚ +    # if URL version is explicitly provided, use it to avoid reinstalling
β”‚ β”‚ +    installed = [fake_dist("example==1.0")]
β”‚ β”‚ +    reqs = [from_line("file:///example.zip#egg=example==1.0")]
β”‚ β”‚ +
β”‚ β”‚ +    to_install, to_uninstall = diff(reqs, installed)
β”‚ β”‚ +    assert to_install == set()
β”‚ β”‚ +    assert to_uninstall == set()
β”‚ β”‚ +
β”‚ β”‚ +
β”‚ β”‚ +def test_diff_with_no_url_versions(fake_dist, from_line):
β”‚ β”‚ +    # if URL version is not provided, assume the contents have
β”‚ β”‚ +    # changed and reinstall
β”‚ β”‚ +    installed = [fake_dist("example==1.0")]
β”‚ β”‚ +    reqs = [from_line("file:///example.zip#egg=example")]
β”‚ β”‚ +
β”‚ β”‚ +    to_install, to_uninstall = diff(reqs, installed)
β”‚ β”‚ +    assert to_install == set(reqs)
β”‚ β”‚ +    assert to_uninstall == {"example"}
β”‚ β”‚ +
β”‚ β”‚ +
β”‚ β”‚ +def test_sync_install_temporary_requirement_file(
β”‚ β”‚ +    from_line, from_editable, mocked_tmp_req_file
β”‚ β”‚ +):
β”‚ β”‚ +    with mock.patch("piptools.sync.check_call") as check_call:
β”‚ β”‚ +        to_install = {from_line("django==1.8")}
β”‚ β”‚          sync(to_install, set())
β”‚ β”‚          check_call.assert_called_once_with(
β”‚ β”‚ -            [sys.executable, '-m', 'pip', 'install', '-r', mocked_tmp_req_file.name, '-q']
β”‚ β”‚ +            [
β”‚ β”‚ +                sys.executable,
β”‚ β”‚ +                "-m",
β”‚ β”‚ +                "pip",
β”‚ β”‚ +                "install",
β”‚ β”‚ +                "-r",
β”‚ β”‚ +                mocked_tmp_req_file.name,
β”‚ β”‚ +                "-q",
β”‚ β”‚ +            ]
β”‚ β”‚          )
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_temporary_requirement_file_deleted(from_line, from_editable, mocked_tmp_file):
β”‚ β”‚ -    with mock.patch('piptools.sync.check_call'):
β”‚ β”‚ -        to_install = {from_line('django==1.8')}
β”‚ β”‚ +    with mock.patch("piptools.sync.check_call"):
β”‚ β”‚ +        to_install = {from_line("django==1.8")}
β”‚ β”‚  
β”‚ β”‚ -        with mock.patch('os.unlink') as unlink:
β”‚ β”‚ +        with mock.patch("os.unlink") as unlink:
β”‚ β”‚              sync(to_install, set())
β”‚ β”‚  
β”‚ β”‚              unlink.assert_called_once_with(mocked_tmp_file.name)
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_sync_requirement_file(from_line, from_editable, mocked_tmp_req_file):
β”‚ β”‚ -    with mock.patch('piptools.sync.check_call'):
β”‚ β”‚ +    with mock.patch("piptools.sync.check_call"):
β”‚ β”‚          to_install = {
β”‚ β”‚ -            from_line('django==1.8'),
β”‚ β”‚ -            from_editable('git+git://fake.org/x/y.git#egg=y'),
β”‚ β”‚ -            from_line('click==4.0'),
β”‚ β”‚ -            from_editable('git+git://fake.org/i/j.git#egg=j'),
β”‚ β”‚ -            from_line('pytz==2017.2'),
β”‚ β”‚ +            from_line("django==1.8"),
β”‚ β”‚ +            from_editable("git+git://fake.org/x/y.git#egg=y"),
β”‚ β”‚ +            from_line("click==4.0"),
β”‚ β”‚ +            from_editable("git+git://fake.org/i/j.git#egg=j"),
β”‚ β”‚ +            from_line("pytz==2017.2"),
β”‚ β”‚          }
β”‚ β”‚  
β”‚ β”‚          sync(to_install, set())
β”‚ β”‚  
β”‚ β”‚          expected = (
β”‚ β”‚ -            'click==4.0\n'
β”‚ β”‚ -            'django==1.8\n'
β”‚ β”‚ -            '-e git+git://fake.org/i/j.git#egg=j\n'
β”‚ β”‚ -            'pytz==2017.2\n'
β”‚ β”‚ -            '-e git+git://fake.org/x/y.git#egg=y'
β”‚ β”‚ +            "click==4.0\n"
β”‚ β”‚ +            "django==1.8\n"
β”‚ β”‚ +            "-e git+git://fake.org/i/j.git#egg=j\n"
β”‚ β”‚ +            "pytz==2017.2\n"
β”‚ β”‚ +            "-e git+git://fake.org/x/y.git#egg=y"
β”‚ β”‚          )
β”‚ β”‚          mocked_tmp_req_file.write.assert_called_once_with(expected)
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚ -def test_sync_requirement_file_with_hashes(from_line, from_editable, mocked_tmp_req_file):
β”‚ β”‚ -    with mock.patch('piptools.sync.check_call'):
β”‚ β”‚ +def test_sync_requirement_file_with_hashes(
β”‚ β”‚ +    from_line, from_editable, mocked_tmp_req_file
β”‚ β”‚ +):
β”‚ β”‚ +    with mock.patch("piptools.sync.check_call"):
β”‚ β”‚          to_install = {
β”‚ β”‚ -            from_line('django==1.8', options={
β”‚ β”‚ -                'hashes': {
β”‚ β”‚ -                    'sha256': [
β”‚ β”‚ -                        '6a03ce2feafdd193a0ba8a26dbd9773e757d2e5d5e7933a62eac129813bd381a',
β”‚ β”‚ -                    ]
β”‚ β”‚ -                }
β”‚ β”‚ -            }),
β”‚ β”‚ -            from_line('click==4.0', options={
β”‚ β”‚ -                'hashes': {
β”‚ β”‚ -                    'sha256': [
β”‚ β”‚ -                        '9ab1d313f99b209f8f71a629f36833030c8d7c72282cf7756834baf567dca662',
β”‚ β”‚ -                    ]
β”‚ β”‚ -                }
β”‚ β”‚ -            }),
β”‚ β”‚ -            from_line('pytz==2017.2', options={
β”‚ β”‚ -                'hashes': {
β”‚ β”‚ -                    'sha256': [
β”‚ β”‚ -                        'd1d6729c85acea5423671382868627129432fba9a89ecbb248d8d1c7a9f01c67',
β”‚ β”‚ -                        'f5c056e8f62d45ba8215e5cb8f50dfccb198b4b9fbea8500674f3443e4689589'
β”‚ β”‚ -                    ]
β”‚ β”‚ -                }
β”‚ β”‚ -            })
β”‚ β”‚ +            from_line(
β”‚ β”‚ +                "django==1.8",
β”‚ β”‚ +                options={
β”‚ β”‚ +                    "hashes": {
β”‚ β”‚ +                        "sha256": [
β”‚ β”‚ +                            "6a03ce2feafdd193a0ba8a26dbd9773e"
β”‚ β”‚ +                            "757d2e5d5e7933a62eac129813bd381a"
β”‚ β”‚ +                        ]
β”‚ β”‚ +                    }
β”‚ β”‚ +                },
β”‚ β”‚ +            ),
β”‚ β”‚ +            from_line(
β”‚ β”‚ +                "click==4.0",
β”‚ β”‚ +                options={
β”‚ β”‚ +                    "hashes": {
β”‚ β”‚ +                        "sha256": [
β”‚ β”‚ +                            "9ab1d313f99b209f8f71a629f3683303"
β”‚ β”‚ +                            "0c8d7c72282cf7756834baf567dca662"
β”‚ β”‚ +                        ]
β”‚ β”‚ +                    }
β”‚ β”‚ +                },
β”‚ β”‚ +            ),
β”‚ β”‚ +            from_line(
β”‚ β”‚ +                "pytz==2017.2",
β”‚ β”‚ +                options={
β”‚ β”‚ +                    "hashes": {
β”‚ β”‚ +                        "sha256": [
β”‚ β”‚ +                            "d1d6729c85acea542367138286862712"
β”‚ β”‚ +                            "9432fba9a89ecbb248d8d1c7a9f01c67",
β”‚ β”‚ +                            "f5c056e8f62d45ba8215e5cb8f50dfcc"
β”‚ β”‚ +                            "b198b4b9fbea8500674f3443e4689589",
β”‚ β”‚ +                        ]
β”‚ β”‚ +                    }
β”‚ β”‚ +                },
β”‚ β”‚ +            ),
β”‚ β”‚          }
β”‚ β”‚  
β”‚ β”‚          sync(to_install, set())
β”‚ β”‚  
β”‚ β”‚          expected = (
β”‚ β”‚ -            'click==4.0 \\\n'
β”‚ β”‚ -            '    --hash=sha256:9ab1d313f99b209f8f71a629f36833030c8d7c72282cf7756834baf567dca662\n'
β”‚ β”‚ -            'django==1.8 \\\n'
β”‚ β”‚ -            '    --hash=sha256:6a03ce2feafdd193a0ba8a26dbd9773e757d2e5d5e7933a62eac129813bd381a\n'
β”‚ β”‚ -            'pytz==2017.2 \\\n'
β”‚ β”‚ -            '    --hash=sha256:d1d6729c85acea5423671382868627129432fba9a89ecbb248d8d1c7a9f01c67 \\\n'
β”‚ β”‚ -            '    --hash=sha256:f5c056e8f62d45ba8215e5cb8f50dfccb198b4b9fbea8500674f3443e4689589'
β”‚ β”‚ +            "click==4.0 \\\n"
β”‚ β”‚ +            "    --hash=sha256:9ab1d313f99b209f8f71a629"
β”‚ β”‚ +            "f36833030c8d7c72282cf7756834baf567dca662\n"
β”‚ β”‚ +            "django==1.8 \\\n"
β”‚ β”‚ +            "    --hash=sha256:6a03ce2feafdd193a0ba8a26"
β”‚ β”‚ +            "dbd9773e757d2e5d5e7933a62eac129813bd381a\n"
β”‚ β”‚ +            "pytz==2017.2 \\\n"
β”‚ β”‚ +            "    --hash=sha256:d1d6729c85acea542367138286"
β”‚ β”‚ +            "8627129432fba9a89ecbb248d8d1c7a9f01c67 \\\n"
β”‚ β”‚ +            "    --hash=sha256:f5c056e8f62d45ba8215e5cb8f"
β”‚ β”‚ +            "50dfccb198b4b9fbea8500674f3443e4689589"
β”‚ β”‚          )
β”‚ β”‚          mocked_tmp_req_file.write.assert_called_once_with(expected)
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚ [email protected]('piptools.sync.click.echo')
β”‚ β”‚ [email protected]("piptools.sync.click.echo")
β”‚ β”‚  def test_sync_up_to_date(echo):
β”‚ β”‚      """
β”‚ β”‚      Everything up-to-date should be printed.
β”‚ β”‚      """
β”‚ β”‚ -    sync(set(), set())
β”‚ β”‚ -    echo.assert_called_once_with('Everything up-to-date')
β”‚ β”‚ +    sync(set(), set(), verbose=True)
β”‚ β”‚ +    echo.assert_called_once_with("Everything up-to-date")
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚ [email protected]('piptools.sync.check_call')
β”‚ β”‚ [email protected]("piptools.sync.check_call")
β”‚ β”‚  def test_sync_verbose(check_call, from_line):
β”‚ β”‚      """
β”‚ β”‚      The -q option has to be passed to every pip calls.
β”‚ β”‚      """
β”‚ β”‚ -    sync({from_line('django==1.8')}, set(), verbose=True)
β”‚ β”‚ +    sync({from_line("django==1.8")}, {from_line("click==4.0")}, verbose=True)
β”‚ β”‚ +    assert check_call.call_count == 2
β”‚ β”‚      for call in check_call.call_args_list:
β”‚ β”‚          check_call_args = call[0][0]
β”‚ β”‚ -        assert '-q' not in check_call_args
β”‚ β”‚ +        assert "-q" not in check_call_args
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚ [email protected]('piptools.sync.click.echo')
β”‚ β”‚ [email protected]("piptools.sync.click.echo")
β”‚ β”‚  def test_sync_dry_run_would_install(echo, from_line):
β”‚ β”‚      """
β”‚ β”‚      Sync with --dry-run option prints what's is going to be installed.
β”‚ β”‚      """
β”‚ β”‚ -    to_install = {
β”‚ β”‚ -        from_line('django==1.8'),
β”‚ β”‚ -        from_line('click==4.0'),
β”‚ β”‚ -    }
β”‚ β”‚ +    to_install = {from_line("django==1.8"), from_line("click==4.0")}
β”‚ β”‚  
β”‚ β”‚      sync(to_install, set(), dry_run=True)
β”‚ β”‚  
β”‚ β”‚      expected_calls = [
β”‚ β”‚ -        mock.call('Would install:'),
β”‚ β”‚ -        mock.call('  django==1.8'),
β”‚ β”‚ -        mock.call('  click==4.0'),
β”‚ β”‚ +        mock.call("Would install:"),
β”‚ β”‚ +        mock.call("  django==1.8"),
β”‚ β”‚ +        mock.call("  click==4.0"),
β”‚ β”‚      ]
β”‚ β”‚      echo.assert_has_calls(expected_calls, any_order=True)
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚ [email protected]('piptools.sync.click.echo')
β”‚ β”‚ [email protected]("piptools.sync.click.echo")
β”‚ β”‚  def test_sync_dry_run_would_uninstall(echo, from_line):
β”‚ β”‚      """
β”‚ β”‚      Sync with --dry-run option prints what is going to be uninstalled.
β”‚ β”‚      """
β”‚ β”‚ -    to_uninstall = {
β”‚ β”‚ -        from_line('django==1.8'),
β”‚ β”‚ -        from_line('click==4.0'),
β”‚ β”‚ -    }
β”‚ β”‚ +    to_uninstall = {from_line("django==1.8"), from_line("click==4.0")}
β”‚ β”‚  
β”‚ β”‚      sync(set(), to_uninstall, dry_run=True)
β”‚ β”‚  
β”‚ β”‚      expected_calls = [
β”‚ β”‚ -        mock.call('Would uninstall:'),
β”‚ β”‚ -        mock.call('  django==1.8'),
β”‚ β”‚ -        mock.call('  click==4.0'),
β”‚ β”‚ +        mock.call("Would uninstall:"),
β”‚ β”‚ +        mock.call("  django==1.8"),
β”‚ β”‚ +        mock.call("  click==4.0"),
β”‚ β”‚      ]
β”‚ β”‚      echo.assert_has_calls(expected_calls, any_order=True)
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚ [email protected]('piptools.sync.check_call')
β”‚ β”‚ [email protected]("piptools.sync.check_call")
β”‚ β”‚  def test_sync_uninstall_pip_command(check_call):
β”‚ β”‚ -    to_uninstall = ['six', 'django', 'pytz', 'click']
β”‚ β”‚ +    to_uninstall = ["six", "django", "pytz", "click"]
β”‚ β”‚  
β”‚ β”‚      sync(set(), to_uninstall)
β”‚ β”‚      check_call.assert_called_once_with(
β”‚ β”‚ -        [sys.executable, '-m', 'pip', 'uninstall', '-y', '-q'] + sorted(to_uninstall)
β”‚ β”‚ +        [sys.executable, "-m", "pip", "uninstall", "-y", "-q"] + sorted(to_uninstall)
β”‚ β”‚      )
β”‚   --- pip-tools-3.5.0/tests/conftest.py
β”œβ”€β”€ +++ pip-tools-4.0.0/tests/conftest.py
β”‚β”„ Files similar despite different names (difference score: 29)
β”‚ β”‚ @@ -1,59 +1,81 @@
β”‚ β”‚  import json
β”‚ β”‚  from contextlib import contextmanager
β”‚ β”‚  from functools import partial
β”‚ β”‚  
β”‚ β”‚  from click.testing import CliRunner
β”‚ β”‚  from pip._vendor.packaging.version import Version
β”‚ β”‚  from pip._vendor.pkg_resources import Requirement
β”‚ β”‚ -from piptools._compat import install_req_from_line, install_req_from_editable
β”‚ β”‚  from pytest import fixture
β”‚ β”‚  
β”‚ β”‚ +from piptools._compat import (
β”‚ β”‚ +    InstallationCandidate,
β”‚ β”‚ +    install_req_from_editable,
β”‚ β”‚ +    install_req_from_line,
β”‚ β”‚ +)
β”‚ β”‚  from piptools.cache import DependencyCache
β”‚ β”‚ +from piptools.exceptions import NoCandidateFound
β”‚ β”‚ +from piptools.repositories import PyPIRepository
β”‚ β”‚  from piptools.repositories.base import BaseRepository
β”‚ β”‚  from piptools.resolver import Resolver
β”‚ β”‚  from piptools.utils import as_tuple, key_from_req, make_install_requirement
β”‚ β”‚ -from piptools.exceptions import NoCandidateFound
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  class FakeRepository(BaseRepository):
β”‚ β”‚      def __init__(self):
β”‚ β”‚ -        with open('tests/test_data/fake-index.json', 'r') as f:
β”‚ β”‚ +        with open("tests/test_data/fake-index.json", "r") as f:
β”‚ β”‚              self.index = json.load(f)
β”‚ β”‚  
β”‚ β”‚ -        with open('tests/test_data/fake-editables.json', 'r') as f:
β”‚ β”‚ +        with open("tests/test_data/fake-editables.json", "r") as f:
β”‚ β”‚              self.editables = json.load(f)
β”‚ β”‚  
β”‚ β”‚      def get_hashes(self, ireq):
β”‚ β”‚          # Some fake hashes
β”‚ β”‚          return {
β”‚ β”‚ -            'test:123',
β”‚ β”‚ -            'sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
β”‚ β”‚ +            "test:123",
β”‚ β”‚ +            "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
β”‚ β”‚          }
β”‚ β”‚  
β”‚ β”‚      def find_best_match(self, ireq, prereleases=False):
β”‚ β”‚          if ireq.editable:
β”‚ β”‚              return ireq
β”‚ β”‚  
β”‚ β”‚ -        versions = list(ireq.specifier.filter(self.index[key_from_req(ireq.req)],
β”‚ β”‚ -                                              prereleases=prereleases))
β”‚ β”‚ +        versions = list(
β”‚ β”‚ +            ireq.specifier.filter(
β”‚ β”‚ +                self.index[key_from_req(ireq.req)], prereleases=prereleases
β”‚ β”‚ +            )
β”‚ β”‚ +        )
β”‚ β”‚          if not versions:
β”‚ β”‚ -            raise NoCandidateFound(ireq, self.index[key_from_req(ireq.req)], ['https://fake.url.foo'])
β”‚ β”‚ +            tried_versions = [
β”‚ β”‚ +                InstallationCandidate(ireq.name, version, "https://fake.url.foo")
β”‚ β”‚ +                for version in self.index[key_from_req(ireq.req)]
β”‚ β”‚ +            ]
β”‚ β”‚ +            raise NoCandidateFound(ireq, tried_versions, ["https://fake.url.foo"])
β”‚ β”‚          best_version = max(versions, key=Version)
β”‚ β”‚ -        return make_install_requirement(key_from_req(ireq.req), best_version, ireq.extras, constraint=ireq.constraint)
β”‚ β”‚ +        return make_install_requirement(
β”‚ β”‚ +            key_from_req(ireq.req),
β”‚ β”‚ +            best_version,
β”‚ β”‚ +            ireq.extras,
β”‚ β”‚ +            constraint=ireq.constraint,
β”‚ β”‚ +        )
β”‚ β”‚  
β”‚ β”‚      def get_dependencies(self, ireq):
β”‚ β”‚          if ireq.editable:
β”‚ β”‚              return self.editables[str(ireq.link)]
β”‚ β”‚  
β”‚ β”‚          name, version, extras = as_tuple(ireq)
β”‚ β”‚          # Store non-extra dependencies under the empty string
β”‚ β”‚          extras += ("",)
β”‚ β”‚ -        dependencies = [dep for extra in extras for dep in self.index[name][version][extra]]
β”‚ β”‚ -        return [install_req_from_line(dep, constraint=ireq.constraint) for dep in dependencies]
β”‚ β”‚ +        dependencies = [
β”‚ β”‚ +            dep for extra in extras for dep in self.index[name][version][extra]
β”‚ β”‚ +        ]
β”‚ β”‚ +        return [
β”‚ β”‚ +            install_req_from_line(dep, constraint=ireq.constraint)
β”‚ β”‚ +            for dep in dependencies
β”‚ β”‚ +        ]
β”‚ β”‚  
β”‚ β”‚      @contextmanager
β”‚ β”‚      def allow_all_wheels(self):
β”‚ β”‚          # No need to do an actual pip.Wheel mock here.
β”‚ β”‚          yield
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚ @@ -84,16 +106,21 @@
β”‚ β”‚  
β”‚ β”‚  @fixture
β”‚ β”‚  def repository():
β”‚ β”‚      return FakeRepository()
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  @fixture
β”‚ β”‚ +def pypi_repository():
β”‚ β”‚ +    return PyPIRepository(["--index-url", PyPIRepository.DEFAULT_INDEX_URL])
β”‚ β”‚ +
β”‚ β”‚ +
β”‚ β”‚ +@fixture
β”‚ β”‚  def depcache(tmpdir):
β”‚ β”‚ -    return DependencyCache(str(tmpdir))
β”‚ β”‚ +    return DependencyCache(str(tmpdir / "dep-cache"))
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  @fixture
β”‚ β”‚  def resolver(depcache, repository):
β”‚ β”‚      # TODO: It'd be nicer if Resolver instance could be set up and then
β”‚ β”‚      #       use .resolve(...) on the specset, instead of passing it to
β”‚ β”‚      #       the constructor like this (it's not reusable)
β”‚ β”‚ @@ -113,10 +140,16 @@
β”‚ β”‚  @fixture
β”‚ β”‚  def from_editable():
β”‚ β”‚      return install_req_from_editable
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  @fixture
β”‚ β”‚  def runner():
β”‚ β”‚ -    cli_runner = CliRunner()
β”‚ β”‚ +    cli_runner = CliRunner(mix_stderr=False)
β”‚ β”‚      with cli_runner.isolated_filesystem():
β”‚ β”‚          yield cli_runner
β”‚ β”‚ +
β”‚ β”‚ +
β”‚ β”‚ +@fixture
β”‚ β”‚ +def tmpdir_cwd(tmpdir):
β”‚ β”‚ +    with tmpdir.as_cwd():
β”‚ β”‚ +        yield tmpdir
β”‚   --- pip-tools-3.5.0/CHANGELOG.md
β”œβ”€β”€ +++ pip-tools-4.0.0/CHANGELOG.md
β”‚β”„ Files similar despite different names (difference score: 46)
β”‚ β”‚ @@ -1,7 +1,78 @@
β”‚ β”‚ +# 4.0.0 (2019-07-25)
β”‚ β”‚ +
β”‚ β”‚ +Backwards Incompatible Changes:
β”‚ β”‚ +- Drop support for EOL Python 3.4
β”‚ β”‚ +([#803](https://github.com/jazzband/pip-tools/pull/803)). Thanks @auvipy
β”‚ β”‚ +
β”‚ β”‚ +Bug Fixes:
β”‚ β”‚ +- Fix `pip>=19.2` compatibility
β”‚ β”‚ +([#857](https://github.com/jazzband/pip-tools/pull/857)). Thanks @atugushev
β”‚ β”‚ +
β”‚ β”‚ +# 3.9.0 (2019-07-17)
β”‚ β”‚ +
β”‚ β”‚ +Features:
β”‚ β”‚ +- Print provenance information when `pip-compile` fails
β”‚ β”‚ +([#837](https://github.com/jazzband/pip-tools/pull/837)). Thanks @jakevdp
β”‚ β”‚ +
β”‚ β”‚ +Bug Fixes:
β”‚ β”‚ +- Output all logging to stderr instead of stdout
β”‚ β”‚ +([#834](https://github.com/jazzband/pip-tools/pull/834)). Thanks @georgek
β”‚ β”‚ +- Fix output file update with `--dry-run` option in `pip-compile`
β”‚ β”‚ +([#842](https://github.com/jazzband/pip-tools/pull/842)). Thanks @shipmints and @atugushev
β”‚ β”‚ +
β”‚ β”‚ +# 3.8.0 (2019-06-06)
β”‚ β”‚ +
β”‚ β”‚ +Features:
β”‚ β”‚ +- Options `--upgrade` and `--upgrade-package` are no longer mutually exclusive
β”‚ β”‚ +([#831](https://github.com/jazzband/pip-tools/pull/831)). Thanks @adamchainz
β”‚ β”‚ +
β”‚ β”‚ +Bug Fixes:
β”‚ β”‚ +- Fix `--generate-hashes` with bare VCS URLs
β”‚ β”‚ +([#812](https://github.com/jazzband/pip-tools/pull/812)). Thanks @jcushman
β”‚ β”‚ +- Fix issues with `UnicodeError` when installing `pip-tools` from source in some systems
β”‚ β”‚ +([#816](https://github.com/jazzband/pip-tools/pull/816)). Thanks @AbdealiJK
β”‚ β”‚ +- Respect `--pre` option in the input file
β”‚ β”‚ +([#822](https://github.com/jazzband/pip-tools/pull/822)). Thanks @atugushev
β”‚ β”‚ +- Option `--upgrade-package` now works even if the output file does not exist
β”‚ β”‚ +([#831](https://github.com/jazzband/pip-tools/pull/831)). Thanks @adamchainz
β”‚ β”‚ +
β”‚ β”‚ +
β”‚ β”‚ +# 3.7.0 (2019-05-09)
β”‚ β”‚ +
β”‚ β”‚ +Features:
β”‚ β”‚ +- Show progressbar on generation hashes in `pip-compile` verbose mode
β”‚ β”‚ +([#743](https://github.com/jazzband/pip-tools/pull/743)). Thanks @atugushev
β”‚ β”‚ +- Add options `--cert` and `--client-cert` to `pip-sync`
β”‚ β”‚ +([#798](https://github.com/jazzband/pip-tools/pull/798)). Thanks @atugushev
β”‚ β”‚ +- Add support for `--find-links` in `pip-compile` output
β”‚ β”‚ +([#793](https://github.com/jazzband/pip-tools/pull/793)). Thanks @estan and @atugushev
β”‚ β”‚ +- Normalize Β«command to runΒ» in `pip-compile` headers
β”‚ β”‚ +([#800](https://github.com/jazzband/pip-tools/pull/800)). Thanks @atugushev
β”‚ β”‚ +- Support URLs as packages
β”‚ β”‚ +([#807](https://github.com/jazzband/pip-tools/pull/807)). Thanks @jcushman, @nim65s and @toejough
β”‚ β”‚ +
β”‚ β”‚ +Bug Fixes:
β”‚ β”‚ +- Fix replacing password to asterisks in `pip-compile`
β”‚ β”‚ +([#808](https://github.com/jazzband/pip-tools/pull/808)). Thanks @atugushev
β”‚ β”‚ +
β”‚ β”‚ +# 3.6.1 (2019-04-24)
β”‚ β”‚ +
β”‚ β”‚ +Bug Fixes:
β”‚ β”‚ +- Fix `pip>=19.1` compatibility
β”‚ β”‚ +([#795](https://github.com/jazzband/pip-tools/pull/795)). Thanks @atugushev
β”‚ β”‚ +
β”‚ β”‚ +# 3.6.0 (2019-04-03)
β”‚ β”‚ +
β”‚ β”‚ +Features:
β”‚ β”‚ +- Show less output on `pip-sync` with `--quiet` option
β”‚ β”‚ +([#765](https://github.com/jazzband/pip-tools/pull/765)). Thanks @atugushev
β”‚ β”‚ +- Support the flag `--trusted-host` in `pip-sync`
β”‚ β”‚ +([#777](https://github.com/jazzband/pip-tools/pull/777)). Thanks @firebirdberlin
β”‚ β”‚ +
β”‚ β”‚  # 3.5.0 (2019-03-13)
β”‚ β”‚  
β”‚ β”‚  Features:
β”‚ β”‚  - Show default index url provided by `pip`
β”‚ β”‚  ([#735](https://github.com/jazzband/pip-tools/pull/735)). Thanks @atugushev
β”‚ β”‚  - Add an option to allow enabling/disabling build isolation
β”‚ β”‚  ([#758](https://github.com/jazzband/pip-tools/pull/758)). Thanks @atugushev
β”œβ”€β”€ encoding
β”‚ β”‚ β”‚ @@ -1 +1 @@
β”‚ β”‚ β”‚ -us-ascii
β”‚ β”‚ β”‚ +utf-8
β”‚   --- pip-tools-3.5.0/PKG-INFO
β”œβ”€β”€ +++ pip-tools-4.0.0/PKG-INFO
β”‚β”„ Files similar despite different names (difference score: 56)
β”‚ β”‚ @@ -1,44 +1,44 @@
β”‚ β”‚ -Metadata-Version: 1.2
β”‚ β”‚ +Metadata-Version: 2.1
β”‚ β”‚  Name: pip-tools
β”‚ β”‚ -Version: 3.5.0
β”‚ β”‚ +Version: 4.0.0
β”‚ β”‚  Summary: pip-tools keeps your pinned dependencies fresh.
β”‚ β”‚  Home-page: https://github.com/jazzband/pip-tools/
β”‚ β”‚  Author: Vincent Driessen
β”‚ β”‚  Author-email: [email protected]
β”‚ β”‚  License: BSD
β”‚ β”‚ -Description: |buildstatus-travis| |buildstatus-appveyor| |codecov| |coveralls| |jazzband| |pypi|
β”‚ β”‚ +Description: |jazzband| |pypi| |pyversions| |buildstatus-travis| |buildstatus-appveyor| |codecov|
β”‚ β”‚          
β”‚ β”‚          ==================================
β”‚ β”‚          pip-tools = pip-compile + pip-sync
β”‚ β”‚          ==================================
β”‚ β”‚          
β”‚ β”‚          A set of command line tools to help you keep your ``pip``-based packages fresh,
β”‚ β”‚          even when you've pinned them.  `You do pin them, right?`_
β”‚ β”‚          
β”‚ β”‚          .. image:: https://github.com/jazzband/pip-tools/raw/master/img/pip-tools-overview.png
β”‚ β”‚             :alt: pip-tools overview for phase II
β”‚ β”‚          
β”‚ β”‚ -        .. |buildstatus-travis| image:: https://img.shields.io/travis/jazzband/pip-tools/master.svg
β”‚ β”‚ -           :alt: Travis-CI build status
β”‚ β”‚ +        .. |buildstatus-travis| image:: https://img.shields.io/travis/jazzband/pip-tools/master.svg?logo=travis
β”‚ β”‚ +           :alt: Travis CI build status
β”‚ β”‚             :target: https://travis-ci.org/jazzband/pip-tools
β”‚ β”‚ -        .. |buildstatus-appveyor| image:: https://img.shields.io/appveyor/ci/jazzband/pip-tools/master.svg
β”‚ β”‚ -           :alt: Appveyor build status
β”‚ β”‚ +        .. |buildstatus-appveyor| image:: https://img.shields.io/appveyor/ci/jazzband/pip-tools/master.svg?logo=appveyor
β”‚ β”‚ +           :alt: AppVeyor build status
β”‚ β”‚             :target: https://ci.appveyor.com/project/jazzband/pip-tools
β”‚ β”‚          .. |codecov| image:: https://codecov.io/gh/jazzband/pip-tools/branch/master/graph/badge.svg
β”‚ β”‚ -           :alt: Codecov
β”‚ β”‚ +           :alt: Coverage
β”‚ β”‚             :target: https://codecov.io/gh/jazzband/pip-tools
β”‚ β”‚ -        .. |coveralls| image:: https://coveralls.io/repos/github/jazzband/pip-tools/badge.svg?branch=master
β”‚ β”‚ -           :alt: Coveralls
β”‚ β”‚ -           :target: https://coveralls.io/github/jazzband/pip-tools?branch=master
β”‚ β”‚          .. |jazzband| image:: https://jazzband.co/static/img/badge.svg
β”‚ β”‚             :alt: Jazzband
β”‚ β”‚             :target: https://jazzband.co/
β”‚ β”‚          .. |pypi| image:: https://img.shields.io/pypi/v/pip-tools.svg
β”‚ β”‚ -           :alt: PyPI
β”‚ β”‚ +           :alt: PyPI version
β”‚ β”‚ +           :target: https://pypi.org/project/pip-tools/
β”‚ β”‚ +        .. |pyversions| image:: https://img.shields.io/pypi/pyversions/pip-tools.svg
β”‚ β”‚ +           :alt: Supported Python versions
β”‚ β”‚             :target: https://pypi.org/project/pip-tools/
β”‚ β”‚          .. _You do pin them, right?: http://nvie.com/posts/pin-your-packages/
β”‚ β”‚          
β”‚ β”‚          
β”‚ β”‚          Installation
β”‚ β”‚          ============
β”‚ β”‚          
β”‚ β”‚ @@ -54,14 +54,21 @@
β”‚ β”‚          project's virtual environment.
β”‚ β”‚          
β”‚ β”‚          .. _virtual environment: https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments
β”‚ β”‚          
β”‚ β”‚          Example usage for ``pip-compile``
β”‚ β”‚          =================================
β”‚ β”‚          
β”‚ β”‚ +        The ``pip-compile`` command lets you compile a ``requirements.txt`` file from
β”‚ β”‚ +        your dependencies, specified in either ``setup.py`` or ``requirements.in``.
β”‚ β”‚ +        
β”‚ β”‚ +        Run it with ``pip-compile`` or  ``python -m piptools compile``. If you use
β”‚ β”‚ +        multiple Python versions, you can run ``pip-compile`` as ``py -X.Y -m piptools
β”‚ β”‚ +        compile`` on Windows and ``pythonX.Y -m piptools compile`` on other systems.
β”‚ β”‚ +        
β”‚ β”‚          Requirements from ``setup.py``
β”‚ β”‚          ------------------------------
β”‚ β”‚          
β”‚ β”‚          Suppose you have a Flask project, and want to pin it for production.
β”‚ β”‚          If you have a ``setup.py`` with ``install_requires=['Flask']``, then run
β”‚ β”‚          ``pip-compile`` without any arguments:
β”‚ β”‚          
β”‚ β”‚ @@ -114,15 +121,15 @@
β”‚ β”‚              markupsafe==1.0           # via jinja2
β”‚ β”‚              werkzeug==0.12.2          # via flask
β”‚ β”‚          
β”‚ β”‚          And it will produce your ``requirements.txt``, with all the Flask dependencies
β”‚ β”‚          (and all underlying dependencies) pinned.  You should put both
β”‚ β”‚          ``requirements.in`` and ``requirements.txt`` under version control.
β”‚ β”‚          
β”‚ β”‚ -        .. _it's easy to write one: https://packaging.python.org/distributing/#configuring-your-project
β”‚ β”‚ +        .. _it's easy to write one: https://packaging.python.org/guides/distributing-packages-using-setuptools/#configuring-your-project
β”‚ β”‚          
β”‚ β”‚          Using hashes
β”‚ β”‚          ------------
β”‚ β”‚          
β”‚ β”‚          If you would like to use *Hash-Checking Mode* available in ``pip`` since
β”‚ β”‚          version 8.0, ``pip-compile`` offers ``--generate-hashes`` flag:
β”‚ β”‚          
β”‚ β”‚ @@ -167,17 +174,41 @@
β”‚ β”‚          
β”‚ β”‚          .. code-block:: bash
β”‚ β”‚          
β”‚ β”‚              $ pip-compile --upgrade-package flask  # only update the flask package
β”‚ β”‚              $ pip-compile --upgrade-package flask --upgrade-package requests  # update both the flask and requests packages
β”‚ β”‚              $ pip-compile -P flask -P requests==2.0.0  # update the flask package to the latest, and requests to v2.0.0
β”‚ β”‚          
β”‚ β”‚ -        If you use multiple Python versions, you can run ``pip-compile`` as
β”‚ β”‚ -        ``py -X.Y -m piptools compile ...`` on Windows and
β”‚ β”‚ -        ``pythonX.Y -m piptools compile ...`` on other systems.
β”‚ β”‚ +        You can combine ``--upgrade`` and ``--upgrade-package`` in one command, to
β”‚ β”‚ +        provide constraints on the allowed upgrades. For example to upgrade all
β”‚ β”‚ +        packages whilst constraining requests to the latest version less than 3.0:
β”‚ β”‚ +        
β”‚ β”‚ +        .. code-block:: bash
β”‚ β”‚ +        
β”‚ β”‚ +            $ pip-compile --upgrade --upgrade-package 'requests<3.0'
β”‚ β”‚ +        
β”‚ β”‚ +        Output File
β”‚ β”‚ +        -----------
β”‚ β”‚ +        
β”‚ β”‚ +        To output the pinned requirements in a filename other than
β”‚ β”‚ +        ``requirements.txt``, use ``--output-file``. This might be useful for compiling
β”‚ β”‚ +        multiple files, for example with different constraints on flask to test a
β”‚ β”‚ +        library with both versions using `tox <https://tox.readthedocs.io/en/latest/>`__:
β”‚ β”‚ +        
β”‚ β”‚ +        .. code-block:: bash
β”‚ β”‚ +        
β”‚ β”‚ +            $ pip-compile --upgrade-package 'flask<1.0' --output-file requirements-flask0x.txt
β”‚ β”‚ +            $ pip-compile --upgrade-package 'flask<2.0' --output-file requirements-flask1x.txt
β”‚ β”‚ +        
β”‚ β”‚ +        Or to output to standard output, use ``--output-file=-``:
β”‚ β”‚ +        
β”‚ β”‚ +        .. code-block:: bash
β”‚ β”‚ +        
β”‚ β”‚ +            $ pip-compile --output-file=- > requirements.txt
β”‚ β”‚ +            $ pip-compile - --output-file=- < requirements.in > requirements.txt
β”‚ β”‚          
β”‚ β”‚          Configuration
β”‚ β”‚          -------------
β”‚ β”‚          
β”‚ β”‚          You might be wrapping the ``pip-compile`` command in another script. To avoid
β”‚ β”‚          confusing consumers of your custom script you can override the update command
β”‚ β”‚          generated at the top of requirements files by setting the
β”‚ β”‚ @@ -202,25 +233,29 @@
β”‚ β”‚          ==============================
β”‚ β”‚          
β”‚ β”‚          Now that you have a ``requirements.txt``, you can use ``pip-sync`` to update
β”‚ β”‚          your virtual environment to reflect exactly what's in there. This will
β”‚ β”‚          install/upgrade/uninstall everything necessary to match the
β”‚ β”‚          ``requirements.txt`` contents.
β”‚ β”‚          
β”‚ β”‚ +        Run it with ``pip-sync`` or ``python -m piptools sync``. If you use multiple
β”‚ β”‚ +        Python versions, you can also run ``py -X.Y -m piptools sync`` on Windows and
β”‚ β”‚ +        ``pythonX.Y -m piptools sync`` on other systems.
β”‚ β”‚ +        
β”‚ β”‚          **Be careful**: ``pip-sync`` is meant to be used only with a
β”‚ β”‚          ``requirements.txt`` generated by ``pip-compile``.
β”‚ β”‚          
β”‚ β”‚          .. code-block:: bash
β”‚ β”‚          
β”‚ β”‚              $ pip-sync
β”‚ β”‚              Uninstalling flake8-2.4.1:
β”‚ β”‚                Successfully uninstalled flake8-2.4.1
β”‚ β”‚              Collecting click==4.1
β”‚ β”‚                Downloading click-4.1-py2.py3-none-any.whl (62kB)
β”‚ β”‚ -                100% |β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 65kB 1.8MB/s
β”‚ β”‚ +                100% |................................| 65kB 1.8MB/s
β”‚ β”‚                Found existing installation: click 4.0
β”‚ β”‚                  Uninstalling click-4.0:
β”‚ β”‚                    Successfully uninstalled click-4.0
β”‚ β”‚              Successfully installed click-4.1
β”‚ β”‚          
β”‚ β”‚          To sync multiple ``*.txt`` dependency lists, just pass them in via command
β”‚ β”‚          line arguments, e.g.
β”‚ β”‚ @@ -239,28 +274,34 @@
β”‚ β”‚          ``setuptools``, ``pip``, or ``pip-tools`` itself. Use ``pip install --upgrade``
β”‚ β”‚          to upgrade those packages.
β”‚ β”‚          
β”‚ β”‚          Other useful tools
β”‚ β”‚          ==================
β”‚ β”‚          
β”‚ β”‚          - `pipdeptree`_ to print the dependency tree of the installed packages.
β”‚ β”‚ +        - ``requirements.in``/``requirements.txt`` syntax highlighting:
β”‚ β”‚ +        
β”‚ β”‚ +          * `requirements.txt.vim`_ for Vim.
β”‚ β”‚ +          * `Python extension for VS Code`_ for VS Code.
β”‚ β”‚          
β”‚ β”‚          .. _pipdeptree: https://github.com/naiquevin/pipdeptree
β”‚ β”‚ +        .. _requirements.txt.vim: https://github.com/raimon49/requirements.txt.vim
β”‚ β”‚ +        .. _Python extension for VS Code: https://marketplace.visualstudio.com/items?itemName=ms-python.python
β”‚ β”‚          
β”‚ β”‚  Platform: any
β”‚ β”‚  Classifier: Development Status :: 5 - Production/Stable
β”‚ β”‚  Classifier: Intended Audience :: Developers
β”‚ β”‚  Classifier: Intended Audience :: System Administrators
β”‚ β”‚  Classifier: License :: OSI Approved :: BSD License
β”‚ β”‚  Classifier: Operating System :: OS Independent
β”‚ β”‚  Classifier: Programming Language :: Python
β”‚ β”‚  Classifier: Programming Language :: Python :: 2
β”‚ β”‚  Classifier: Programming Language :: Python :: 2.7
β”‚ β”‚  Classifier: Programming Language :: Python :: 3
β”‚ β”‚ -Classifier: Programming Language :: Python :: 3.4
β”‚ β”‚  Classifier: Programming Language :: Python :: 3.5
β”‚ β”‚  Classifier: Programming Language :: Python :: 3.6
β”‚ β”‚  Classifier: Programming Language :: Python :: 3.7
β”‚ β”‚  Classifier: Programming Language :: Python :: Implementation :: CPython
β”‚ β”‚  Classifier: Programming Language :: Python :: Implementation :: PyPy
β”‚ β”‚  Classifier: Topic :: System :: Systems Administration
β”‚ β”‚ -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
β”‚ β”‚ +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
β”‚ β”‚ +Description-Content-Type: text/x-rst
β”œβ”€β”€ encoding
β”‚ β”‚ β”‚ @@ -1 +1 @@
β”‚ β”‚ β”‚ -utf-8
β”‚ β”‚ β”‚ +us-ascii
β”‚   --- pip-tools-3.5.0/tests/test_cache.py
β”œβ”€β”€ +++ pip-tools-4.0.0/tests/test_cache.py
β”‚β”„ Files similar despite different names (difference score: 31)
β”‚ β”‚ @@ -1,15 +1,15 @@
β”‚ β”‚  from contextlib import contextmanager
β”‚ β”‚  from os import remove
β”‚ β”‚  from shutil import rmtree
β”‚ β”‚  from tempfile import NamedTemporaryFile
β”‚ β”‚  
β”‚ β”‚  from pytest import raises
β”‚ β”‚  
β”‚ β”‚ -from piptools.cache import read_cache_file, CorruptCacheError, DependencyCache
β”‚ β”‚ +from piptools.cache import CorruptCacheError, DependencyCache, read_cache_file
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  @contextmanager
β”‚ β”‚  def _read_cache_file_helper(to_write):
β”‚ β”‚      """
β”‚ β”‚      On enter, create the file with the given string, and then yield its path.
β”‚ β”‚      On exit, delete that file.
β”‚ β”‚ @@ -32,15 +32,18 @@
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_read_cache_file_not_json():
β”‚ β”‚      """
β”‚ β”‚      A cache file that's not JSON should throw a corrupt cache error.
β”‚ β”‚      """
β”‚ β”‚      with _read_cache_file_helper("not json") as cache_file_name:
β”‚ β”‚ -        with raises(CorruptCacheError):
β”‚ β”‚ +        with raises(
β”‚ β”‚ +            CorruptCacheError,
β”‚ β”‚ +            match="The dependency cache seems to have been corrupted.",
β”‚ β”‚ +        ):
β”‚ β”‚              read_cache_file(cache_file_name)
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_read_cache_file_wrong_format():
β”‚ β”‚      """
β”‚ β”‚      A cache file with a wrong "__format__" value should throw an assertion error.
β”‚ β”‚      """
β”‚ β”‚ @@ -49,50 +52,56 @@
β”‚ β”‚              read_cache_file(cache_file_name)
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_read_cache_file_successful():
β”‚ β”‚      """
β”‚ β”‚      A good cache file.
β”‚ β”‚      """
β”‚ β”‚ -    with _read_cache_file_helper('{"__format__": 1, "dependencies": "success"}') as cache_file_name:
β”‚ β”‚ +    with _read_cache_file_helper(
β”‚ β”‚ +        '{"__format__": 1, "dependencies": "success"}'
β”‚ β”‚ +    ) as cache_file_name:
β”‚ β”‚          assert "success" == read_cache_file(cache_file_name)
β”‚ β”‚  
β”‚ β”‚  
β”‚ β”‚  def test_reverse_dependencies(from_line, tmpdir):
β”‚ β”‚      # Since this is a test, make a temporary directory. Converting to str from py.path.
β”‚ β”‚      tmp_dir_path = str(tmpdir)
β”‚ β”‚  
β”‚ β”‚ -    # Create a cache object. The keys are packages, and the values are lists of packages on which the keys depend.
β”‚ β”‚ +    # Create a cache object. The keys are packages, and the values are lists
β”‚ β”‚ +    # of packages on which the keys depend.
β”‚ β”‚      cache = DependencyCache(cache_dir=tmp_dir_path)
β”‚ β”‚      cache[from_line("top==1.2")] = ["middle>=0.3", "bottom>=5.1.2"]
β”‚ β”‚      cache[from_line("top[xtra]==1.2")] = ["middle>=0.3", "bottom>=5.1.2", "bonus==0.4"]
β”‚ β”‚      cache[from_line("middle==0.4")] = ["bottom<6"]
β”‚ β”‚      cache[from_line("bottom==5.3.5")] = []
β”‚ β”‚      cache[from_line("bonus==0.4")] = []
β”‚ β”‚  
β”‚ β”‚ -    # In this case, we're using top 1.2 without an extra, so the "bonus" package is not depended upon.
β”‚ β”‚ -    reversed_no_extra = cache.reverse_dependencies([
β”‚ β”‚ -        from_line("top==1.2"),
β”‚ β”‚ -        from_line("middle==0.4"),
β”‚ β”‚ -        from_line("bottom==5.3.5"),
β”‚ β”‚ -        from_line("bonus==0.4")
β”‚ β”‚ -    ])
β”‚ β”‚ -    assert reversed_no_extra == {
β”‚ β”‚ -        'middle': {'top'},
β”‚ β”‚ -        'bottom': {'middle', 'top'}
β”‚ β”‚ -    }
β”‚ β”‚ -
β”‚ β”‚ -    # Now we're using top 1.2 with the "xtra" extra, so it depends on the "bonus" package.
β”‚ β”‚ -    reversed_extra = cache.reverse_dependencies([
β”‚ β”‚ -        from_line("top[xtra]==1.2"),
β”‚ β”‚ -        from_line("middle==0.4"),
β”‚ β”‚ -        from_line("bottom==5.3.5"),
β”‚ β”‚ -        from_line("bonus==0.4")
β”‚ β”‚ -    ])
β”‚ β”‚ +    # In this case, we're using top 1.2 without an extra, so the "bonus" package
β”‚ β”‚ +    # is not depended upon.
β”‚ β”‚ +    reversed_no_extra = cache.reverse_dependencies(
β”‚ β”‚ +        [
β”‚ β”‚ +            from_line("top==1.2"),
β”‚ β”‚ +            from_line("middle==0.4"),
β”‚ β”‚ +            from_line("bottom==5.3.5"),
β”‚ β”‚ +            from_line("bonus==0.4"),
β”‚ β”‚ +        ]
β”‚ β”‚ +    )
β”‚ β”‚ +    assert reversed_no_extra == {"middle": {"top"}, "bottom": {"middle", "top"}}
β”‚ β”‚ +
β”‚ β”‚ +    # Now we're using top 1.2 with the "xtra" extra, so it depends
β”‚ β”‚ +    # on the "bonus" package.
β”‚ β”‚ +    reversed_extra = cache.reverse_dependencies(
β”‚ β”‚ +        [
β”‚ β”‚ +            from_line("top[xtra]==1.2"),
β”‚ β”‚ +            from_line("middle==0.4"),
β”‚ β”‚ +            from_line("bottom==5.3.5"),
β”‚ β”‚ +            from_line("bonus==0.4"),
β”‚ β”‚ +        ]
β”‚ β”‚ +    )
β”‚ β”‚      assert reversed_extra == {
β”‚ β”‚ -        'middle': {'top'},
β”‚ β”‚ -        'bottom': {'middle', 'top'},
β”‚ β”‚ -        'bonus': {'top'}
β”‚ β”‚ +        "middle": {"top"},
β”‚ β”‚ +        "bottom": {"middle", "top"},
β”‚ β”‚ +        "bonus": {"top"},
β”‚ β”‚      }
β”‚ β”‚  
β”‚ β”‚      # Clean up our temp directory
β”‚ β”‚      rmtree(tmp_dir_path)
β”‚   --- pip-tools-3.5.0/tests/test_data/minimal_wheels/small_fake_b-0.2-py2.py3-none-any.whl
β”œβ”€β”€ +++ pip-tools-4.0.0/tests/test_data/minimal_wheels/small_fake_b-0.2-py2.py3-none-any.whl
β”‚β”„ Files similar despite different names (difference score: 0)