Skip to content

pip tools 3.5.0 to 4.0.0

mickael e edited this page Aug 16, 2019 · 1 revision
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)
Clone this wiki locally