We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
pip-sync on fresh conda environment with Python 2.7.15 tries to remove Python package
When running pip-sync in a conda environment with python 2.7.15 installed package, it always tries to uninstall non-pip packages like `python`, failing to execute.
It runs ok on conda environments with python 3.x.

##### Environment Versions

1. OS Type: `MacOSX 10.13.6`
1. Python version: `Python 2.7.15 :: Anaconda, Inc.`
1. pip version:  `pip 18.1 from /anaconda2/envs/my-env/lib/python2.7/site-packages/pip (python 2.7)`
1. pip-tools version: `pip-compile, version 3.1.0`

##### Steps to replicate

1. conda create -n my-env python=2.7
2. source activate my-env
3. pip install -U pip
4. pip install pip-tools
5. echo "django" > requirements.in
6. pip-compile requirements.in
7. pip-sync requirements.txt

##### Expected result

pip-sync execution successful. A clean environment with just Django installed to the latest possible version.

##### Actual result

pip-sync error:

````
Cannot uninstall 'Python'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.
Traceback (most recent call last):
  File "/anaconda2/envs/my-env/bin/pip-sync", line 11, in <module>
    sys.exit(cli())
  File "/anaconda2/envs/my-env/lib/python2.7/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/anaconda2/envs/my-env/lib/python2.7/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/anaconda2/envs/my-env/lib/python2.7/site-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/anaconda2/envs/my-env/lib/python2.7/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/anaconda2/envs/my-env/lib/python2.7/site-packages/piptools/scripts/sync.py", line 74, in cli
    install_flags=install_flags))
  File "/anaconda2/envs/my-env/lib/python2.7/site-packages/piptools/sync.py", line 149, in sync
    check_call([pip, 'uninstall', '-y'] + pip_flags + sorted(to_uninstall))
  File "/anaconda2/envs/my-env/lib/python2.7/subprocess.py", line 190, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['/anaconda2/envs/my-env/bin/pip', 'uninstall', '-y', u'certifi', u'python', u'wsgiref']' returned non-zero exit status 1
````

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `piptools/_compat/pip_compat.py`
Content:
```
1 # -*- coding=utf-8 -*-
2 import importlib
3 
4 import pip
5 import pkg_resources
6 
7 def do_import(module_path, subimport=None, old_path=None):
8     old_path = old_path or module_path
9     prefixes = ["pip._internal", "pip"]
10     paths = [module_path, old_path]
11     search_order = ["{0}.{1}".format(p, pth) for p in prefixes for pth in paths if pth is not None]
12     package = subimport if subimport else None
13     for to_import in search_order:
14         if not subimport:
15             to_import, _, package = to_import.rpartition(".")
16         try:
17             imported = importlib.import_module(to_import)
18         except ImportError:
19             continue
20         else:
21             return getattr(imported, package)
22 
23 
24 InstallRequirement = do_import('req.req_install', 'InstallRequirement')
25 parse_requirements = do_import('req.req_file', 'parse_requirements')
26 RequirementSet = do_import('req.req_set', 'RequirementSet')
27 user_cache_dir = do_import('utils.appdirs', 'user_cache_dir')
28 FAVORITE_HASH = do_import('utils.hashes', 'FAVORITE_HASH')
29 is_file_url = do_import('download', 'is_file_url')
30 path_to_url = do_import('download', 'path_to_url')
31 url_to_path = do_import('download', 'url_to_path')
32 PackageFinder = do_import('index', 'PackageFinder')
33 FormatControl = do_import('index', 'FormatControl')
34 Wheel = do_import('wheel', 'Wheel')
35 Command = do_import('cli.base_command', 'Command', old_path='basecommand')
36 cmdoptions = do_import('cli.cmdoptions', old_path='cmdoptions')
37 get_installed_distributions = do_import('utils.misc', 'get_installed_distributions', old_path='utils')
38 PyPI = do_import('models.index', 'PyPI')
39 
40 # pip 18.1 has refactored InstallRequirement constructors use by pip-tools.
41 if pkg_resources.parse_version(pip.__version__) < pkg_resources.parse_version('18.1'):
42     install_req_from_line = InstallRequirement.from_line
43     install_req_from_editable = InstallRequirement.from_editable
44 else:
45     install_req_from_line = do_import('req.constructors', 'install_req_from_line')
46     install_req_from_editable = do_import('req.constructors', 'install_req_from_editable')
47
```

Path: `piptools/sync.py`
Content:
```
1 import collections
2 import os
3 import sys
4 import tempfile
5 from subprocess import check_call
6 
7 from . import click
8 from .exceptions import IncompatibleRequirements, UnsupportedConstraint
9 from .utils import flat_map, format_requirement, key_from_ireq, key_from_req, get_hashes_from_ireq
10 
11 PACKAGES_TO_IGNORE = [
12     '-markerlib',
13     'pip',
14     'pip-tools',
15     'pip-review',
16     'pkg-resources',
17     'setuptools',
18     'wheel',
19 ]
20 
21 
22 def dependency_tree(installed_keys, root_key):
23     """
24     Calculate the dependency tree for the package `root_key` and return
25     a collection of all its dependencies.  Uses a DFS traversal algorithm.
26 
27     `installed_keys` should be a {key: requirement} mapping, e.g.
28         {'django': from_line('django==1.8')}
29     `root_key` should be the key to return the dependency tree for.
30     """
31     dependencies = set()
32     queue = collections.deque()
33 
34     if root_key in installed_keys:
35         dep = installed_keys[root_key]
36         queue.append(dep)
37 
38     while queue:
39         v = queue.popleft()
40         key = key_from_req(v)
41         if key in dependencies:
42             continue
43 
44         dependencies.add(key)
45 
46         for dep_specifier in v.requires():
47             dep_name = key_from_req(dep_specifier)
48             if dep_name in installed_keys:
49                 dep = installed_keys[dep_name]
50 
51                 if dep_specifier.specifier.contains(dep.version):
52                     queue.append(dep)
53 
54     return dependencies
55 
56 
57 def get_dists_to_ignore(installed):
58     """
59     Returns a collection of package names to ignore when performing pip-sync,
60     based on the currently installed environment.  For example, when pip-tools
61     is installed in the local environment, it should be ignored, including all
62     of its dependencies (e.g. click).  When pip-tools is not installed
63     locally, click should also be installed/uninstalled depending on the given
64     requirements.
65     """
66     installed_keys = {key_from_req(r): r for r in installed}
67     return list(flat_map(lambda req: dependency_tree(installed_keys, req), PACKAGES_TO_IGNORE))
68 
69 
70 def merge(requirements, ignore_conflicts):
71     by_key = {}
72 
73     for ireq in requirements:
74         if ireq.link is not None and not ireq.editable:
75             msg = ('pip-compile does not support URLs as packages, unless they are editable. '
76                    'Perhaps add -e option?')
77             raise UnsupportedConstraint(msg, ireq)
78 
79         key = ireq.link or key_from_req(ireq.req)
80 
81         if not ignore_conflicts:
82             existing_ireq = by_key.get(key)
83             if existing_ireq:
84                 # NOTE: We check equality here since we can assume that the
85                 # requirements are all pinned
86                 if ireq.specifier != existing_ireq.specifier:
87                     raise IncompatibleRequirements(ireq, existing_ireq)
88 
89         # TODO: Always pick the largest specifier in case of a conflict
90         by_key[key] = ireq
91 
92     return by_key.values()
93 
94 
95 def diff(compiled_requirements, installed_dists):
96     """
97     Calculate which packages should be installed or uninstalled, given a set
98     of compiled requirements and a list of currently installed modules.
99     """
100     requirements_lut = {r.link or key_from_req(r.req): r for r in compiled_requirements}
101 
102     satisfied = set()  # holds keys
103     to_install = set()  # holds InstallRequirement objects
104     to_uninstall = set()  # holds keys
105 
106     pkgs_to_ignore = get_dists_to_ignore(installed_dists)
107     for dist in installed_dists:
108         key = key_from_req(dist)
109         if key not in requirements_lut or not requirements_lut[key].match_markers():
110             to_uninstall.add(key)
111         elif requirements_lut[key].specifier.contains(dist.version):
112             satisfied.add(key)
113 
114     for key, requirement in requirements_lut.items():
115         if key not in satisfied and requirement.match_markers():
116             to_install.add(requirement)
117 
118     # Make sure to not uninstall any packages that should be ignored
119     to_uninstall -= set(pkgs_to_ignore)
120 
121     return (to_install, to_uninstall)
122 
123 
124 def sync(to_install, to_uninstall, verbose=False, dry_run=False, pip_flags=None, install_flags=None):
125     """
126     Install and uninstalls the given sets of modules.
127     """
128     if not to_uninstall and not to_install:
129         click.echo("Everything up-to-date")
130 
131     if pip_flags is None:
132         pip_flags = []
133 
134     if not verbose:
135         pip_flags += ['-q']
136 
137     if os.environ.get('VIRTUAL_ENV'):
138         # find pip via PATH
139         pip = 'pip'
140     else:
141         # find pip in same directory as pip-sync entry-point script
142         pip = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), 'pip')
143 
144     if to_uninstall:
145         if dry_run:
146             click.echo("Would uninstall:")
147             for pkg in to_uninstall:
148                 click.echo("  {}".format(pkg))
149         else:
150             check_call([pip, 'uninstall', '-y'] + pip_flags + sorted(to_uninstall))
151 
152     if to_install:
153         if install_flags is None:
154             install_flags = []
155         if dry_run:
156             click.echo("Would install:")
157             for ireq in to_install:
158                 click.echo("  {}".format(format_requirement(ireq)))
159         else:
160             # prepare requirement lines
161             req_lines = []
162             for ireq in sorted(to_install, key=key_from_ireq):
163                 ireq_hashes = get_hashes_from_ireq(ireq)
164                 req_lines.append(format_requirement(ireq, hashes=ireq_hashes))
165 
166             # save requirement lines to a temporary file
167             with tempfile.NamedTemporaryFile(mode='wt') as tmp_req_file:
168                 tmp_req_file.write('\n'.join(req_lines))
169                 tmp_req_file.flush()
170 
171                 check_call([pip, 'install', '-r', tmp_req_file.name] + pip_flags + install_flags)
172     return 0
173
```

Path: `piptools/_compat/__init__.py`
Content:
```
1 # coding: utf-8
2 # flake8: noqa
3 from __future__ import (absolute_import, division, print_function,
4                         unicode_literals)
5 
6 import six
7 
8 if six.PY2:
9     from .tempfile import TemporaryDirectory
10     from .contextlib import ExitStack
11 else:
12     from tempfile import TemporaryDirectory
13     from contextlib import ExitStack
14 
15 from .pip_compat import (
16     InstallRequirement,
17     parse_requirements,
18     RequirementSet,
19     user_cache_dir,
20     FAVORITE_HASH,
21     is_file_url,
22     url_to_path,
23     PackageFinder,
24     FormatControl,
25     Wheel,
26     Command,
27     cmdoptions,
28     get_installed_distributions,
29     PyPI,
30     install_req_from_line,
31     install_req_from_editable,
32 )
33
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/piptools/_compat/__init__.py b/piptools/_compat/__init__.py
--- a/piptools/_compat/__init__.py
+++ b/piptools/_compat/__init__.py
@@ -29,4 +29,6 @@
     PyPI,
     install_req_from_line,
     install_req_from_editable,
+    stdlib_pkgs,
+    DEV_PKGS,
 )
diff --git a/piptools/_compat/pip_compat.py b/piptools/_compat/pip_compat.py
--- a/piptools/_compat/pip_compat.py
+++ b/piptools/_compat/pip_compat.py
@@ -36,6 +36,8 @@
 cmdoptions = do_import('cli.cmdoptions', old_path='cmdoptions')
 get_installed_distributions = do_import('utils.misc', 'get_installed_distributions', old_path='utils')
 PyPI = do_import('models.index', 'PyPI')
+stdlib_pkgs = do_import('utils.compat', 'stdlib_pkgs', old_path='compat')
+DEV_PKGS = do_import('commands.freeze', 'DEV_PKGS')
 
 # pip 18.1 has refactored InstallRequirement constructors use by pip-tools.
 if pkg_resources.parse_version(pip.__version__) < pkg_resources.parse_version('18.1'):
diff --git a/piptools/sync.py b/piptools/sync.py
--- a/piptools/sync.py
+++ b/piptools/sync.py
@@ -4,6 +4,7 @@
 import tempfile
 from subprocess import check_call
 
+from piptools._compat import stdlib_pkgs, DEV_PKGS
 from . import click
 from .exceptions import IncompatibleRequirements, UnsupportedConstraint
 from .utils import flat_map, format_requirement, key_from_ireq, key_from_req, get_hashes_from_ireq
@@ -14,9 +15,7 @@
     'pip-tools',
     'pip-review',
     'pkg-resources',
-    'setuptools',
-    'wheel',
-]
+] + list(stdlib_pkgs) + list(DEV_PKGS)
 
 
 def dependency_tree(installed_keys, root_key):

{"golden_diff": "diff --git a/piptools/_compat/__init__.py b/piptools/_compat/__init__.py\n--- a/piptools/_compat/__init__.py\n+++ b/piptools/_compat/__init__.py\n@@ -29,4 +29,6 @@\n     PyPI,\n     install_req_from_line,\n     install_req_from_editable,\n+    stdlib_pkgs,\n+    DEV_PKGS,\n )\ndiff --git a/piptools/_compat/pip_compat.py b/piptools/_compat/pip_compat.py\n--- a/piptools/_compat/pip_compat.py\n+++ b/piptools/_compat/pip_compat.py\n@@ -36,6 +36,8 @@\n cmdoptions = do_import('cli.cmdoptions', old_path='cmdoptions')\n get_installed_distributions = do_import('utils.misc', 'get_installed_distributions', old_path='utils')\n PyPI = do_import('models.index', 'PyPI')\n+stdlib_pkgs = do_import('utils.compat', 'stdlib_pkgs', old_path='compat')\n+DEV_PKGS = do_import('commands.freeze', 'DEV_PKGS')\n \n # pip 18.1 has refactored InstallRequirement constructors use by pip-tools.\n if pkg_resources.parse_version(pip.__version__) < pkg_resources.parse_version('18.1'):\ndiff --git a/piptools/sync.py b/piptools/sync.py\n--- a/piptools/sync.py\n+++ b/piptools/sync.py\n@@ -4,6 +4,7 @@\n import tempfile\n from subprocess import check_call\n \n+from piptools._compat import stdlib_pkgs, DEV_PKGS\n from . import click\n from .exceptions import IncompatibleRequirements, UnsupportedConstraint\n from .utils import flat_map, format_requirement, key_from_ireq, key_from_req, get_hashes_from_ireq\n@@ -14,9 +15,7 @@\n     'pip-tools',\n     'pip-review',\n     'pkg-resources',\n-    'setuptools',\n-    'wheel',\n-]\n+] + list(stdlib_pkgs) + list(DEV_PKGS)\n \n \n def dependency_tree(installed_keys, root_key):\n", "issue": "pip-sync on fresh conda environment with Python 2.7.15 tries to remove Python package\nWhen running pip-sync in a conda environment with python 2.7.15 installed package, it always tries to uninstall non-pip packages like `python`, failing to execute.\r\nIt runs ok on conda environments with python 3.x.\r\n\r\n##### Environment Versions\r\n\r\n1. OS Type: `MacOSX 10.13.6`\r\n1. Python version: `Python 2.7.15 :: Anaconda, Inc.`\r\n1. pip version:  `pip 18.1 from /anaconda2/envs/my-env/lib/python2.7/site-packages/pip (python 2.7)`\r\n1. pip-tools version: `pip-compile, version 3.1.0`\r\n\r\n##### Steps to replicate\r\n\r\n1. conda create -n my-env python=2.7\r\n2. source activate my-env\r\n3. pip install -U pip\r\n4. pip install pip-tools\r\n5. echo \"django\" > requirements.in\r\n6. pip-compile requirements.in\r\n7. pip-sync requirements.txt\r\n\r\n##### Expected result\r\n\r\npip-sync execution successful. A clean environment with just Django installed to the latest possible version.\r\n\r\n##### Actual result\r\n\r\npip-sync error:\r\n\r\n````\r\nCannot uninstall 'Python'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.\r\nTraceback (most recent call last):\r\n  File \"/anaconda2/envs/my-env/bin/pip-sync\", line 11, in <module>\r\n    sys.exit(cli())\r\n  File \"/anaconda2/envs/my-env/lib/python2.7/site-packages/click/core.py\", line 764, in __call__\r\n    return self.main(*args, **kwargs)\r\n  File \"/anaconda2/envs/my-env/lib/python2.7/site-packages/click/core.py\", line 717, in main\r\n    rv = self.invoke(ctx)\r\n  File \"/anaconda2/envs/my-env/lib/python2.7/site-packages/click/core.py\", line 956, in invoke\r\n    return ctx.invoke(self.callback, **ctx.params)\r\n  File \"/anaconda2/envs/my-env/lib/python2.7/site-packages/click/core.py\", line 555, in invoke\r\n    return callback(*args, **kwargs)\r\n  File \"/anaconda2/envs/my-env/lib/python2.7/site-packages/piptools/scripts/sync.py\", line 74, in cli\r\n    install_flags=install_flags))\r\n  File \"/anaconda2/envs/my-env/lib/python2.7/site-packages/piptools/sync.py\", line 149, in sync\r\n    check_call([pip, 'uninstall', '-y'] + pip_flags + sorted(to_uninstall))\r\n  File \"/anaconda2/envs/my-env/lib/python2.7/subprocess.py\", line 190, in check_call\r\n    raise CalledProcessError(retcode, cmd)\r\nsubprocess.CalledProcessError: Command '['/anaconda2/envs/my-env/bin/pip', 'uninstall', '-y', u'certifi', u'python', u'wsgiref']' returned non-zero exit status 1\r\n````\n", "before_files": [{"content": "# -*- coding=utf-8 -*-\nimport importlib\n\nimport pip\nimport pkg_resources\n\ndef do_import(module_path, subimport=None, old_path=None):\n    old_path = old_path or module_path\n    prefixes = [\"pip._internal\", \"pip\"]\n    paths = [module_path, old_path]\n    search_order = [\"{0}.{1}\".format(p, pth) for p in prefixes for pth in paths if pth is not None]\n    package = subimport if subimport else None\n    for to_import in search_order:\n        if not subimport:\n            to_import, _, package = to_import.rpartition(\".\")\n        try:\n            imported = importlib.import_module(to_import)\n        except ImportError:\n            continue\n        else:\n            return getattr(imported, package)\n\n\nInstallRequirement = do_import('req.req_install', 'InstallRequirement')\nparse_requirements = do_import('req.req_file', 'parse_requirements')\nRequirementSet = do_import('req.req_set', 'RequirementSet')\nuser_cache_dir = do_import('utils.appdirs', 'user_cache_dir')\nFAVORITE_HASH = do_import('utils.hashes', 'FAVORITE_HASH')\nis_file_url = do_import('download', 'is_file_url')\npath_to_url = do_import('download', 'path_to_url')\nurl_to_path = do_import('download', 'url_to_path')\nPackageFinder = do_import('index', 'PackageFinder')\nFormatControl = do_import('index', 'FormatControl')\nWheel = do_import('wheel', 'Wheel')\nCommand = do_import('cli.base_command', 'Command', old_path='basecommand')\ncmdoptions = do_import('cli.cmdoptions', old_path='cmdoptions')\nget_installed_distributions = do_import('utils.misc', 'get_installed_distributions', old_path='utils')\nPyPI = do_import('models.index', 'PyPI')\n\n# pip 18.1 has refactored InstallRequirement constructors use by pip-tools.\nif pkg_resources.parse_version(pip.__version__) < pkg_resources.parse_version('18.1'):\n    install_req_from_line = InstallRequirement.from_line\n    install_req_from_editable = InstallRequirement.from_editable\nelse:\n    install_req_from_line = do_import('req.constructors', 'install_req_from_line')\n    install_req_from_editable = do_import('req.constructors', 'install_req_from_editable')\n", "path": "piptools/_compat/pip_compat.py"}, {"content": "import collections\nimport os\nimport sys\nimport tempfile\nfrom subprocess import check_call\n\nfrom . import click\nfrom .exceptions import IncompatibleRequirements, UnsupportedConstraint\nfrom .utils import flat_map, format_requirement, key_from_ireq, key_from_req, get_hashes_from_ireq\n\nPACKAGES_TO_IGNORE = [\n    '-markerlib',\n    'pip',\n    'pip-tools',\n    'pip-review',\n    'pkg-resources',\n    'setuptools',\n    'wheel',\n]\n\n\ndef dependency_tree(installed_keys, root_key):\n    \"\"\"\n    Calculate the dependency tree for the package `root_key` and return\n    a collection of all its dependencies.  Uses a DFS traversal algorithm.\n\n    `installed_keys` should be a {key: requirement} mapping, e.g.\n        {'django': from_line('django==1.8')}\n    `root_key` should be the key to return the dependency tree for.\n    \"\"\"\n    dependencies = set()\n    queue = collections.deque()\n\n    if root_key in installed_keys:\n        dep = installed_keys[root_key]\n        queue.append(dep)\n\n    while queue:\n        v = queue.popleft()\n        key = key_from_req(v)\n        if key in dependencies:\n            continue\n\n        dependencies.add(key)\n\n        for dep_specifier in v.requires():\n            dep_name = key_from_req(dep_specifier)\n            if dep_name in installed_keys:\n                dep = installed_keys[dep_name]\n\n                if dep_specifier.specifier.contains(dep.version):\n                    queue.append(dep)\n\n    return dependencies\n\n\ndef get_dists_to_ignore(installed):\n    \"\"\"\n    Returns a collection of package names to ignore when performing pip-sync,\n    based on the currently installed environment.  For example, when pip-tools\n    is installed in the local environment, it should be ignored, including all\n    of its dependencies (e.g. click).  When pip-tools is not installed\n    locally, click should also be installed/uninstalled depending on the given\n    requirements.\n    \"\"\"\n    installed_keys = {key_from_req(r): r for r in installed}\n    return list(flat_map(lambda req: dependency_tree(installed_keys, req), PACKAGES_TO_IGNORE))\n\n\ndef merge(requirements, ignore_conflicts):\n    by_key = {}\n\n    for ireq in requirements:\n        if ireq.link is not None and not ireq.editable:\n            msg = ('pip-compile does not support URLs as packages, unless they are editable. '\n                   'Perhaps add -e option?')\n            raise UnsupportedConstraint(msg, ireq)\n\n        key = ireq.link or key_from_req(ireq.req)\n\n        if not ignore_conflicts:\n            existing_ireq = by_key.get(key)\n            if existing_ireq:\n                # NOTE: We check equality here since we can assume that the\n                # requirements are all pinned\n                if ireq.specifier != existing_ireq.specifier:\n                    raise IncompatibleRequirements(ireq, existing_ireq)\n\n        # TODO: Always pick the largest specifier in case of a conflict\n        by_key[key] = ireq\n\n    return by_key.values()\n\n\ndef diff(compiled_requirements, installed_dists):\n    \"\"\"\n    Calculate which packages should be installed or uninstalled, given a set\n    of compiled requirements and a list of currently installed modules.\n    \"\"\"\n    requirements_lut = {r.link or key_from_req(r.req): r for r in compiled_requirements}\n\n    satisfied = set()  # holds keys\n    to_install = set()  # holds InstallRequirement objects\n    to_uninstall = set()  # holds keys\n\n    pkgs_to_ignore = get_dists_to_ignore(installed_dists)\n    for dist in installed_dists:\n        key = key_from_req(dist)\n        if key not in requirements_lut or not requirements_lut[key].match_markers():\n            to_uninstall.add(key)\n        elif requirements_lut[key].specifier.contains(dist.version):\n            satisfied.add(key)\n\n    for key, requirement in requirements_lut.items():\n        if key not in satisfied and requirement.match_markers():\n            to_install.add(requirement)\n\n    # Make sure to not uninstall any packages that should be ignored\n    to_uninstall -= set(pkgs_to_ignore)\n\n    return (to_install, to_uninstall)\n\n\ndef sync(to_install, to_uninstall, verbose=False, dry_run=False, pip_flags=None, install_flags=None):\n    \"\"\"\n    Install and uninstalls the given sets of modules.\n    \"\"\"\n    if not to_uninstall and not to_install:\n        click.echo(\"Everything up-to-date\")\n\n    if pip_flags is None:\n        pip_flags = []\n\n    if not verbose:\n        pip_flags += ['-q']\n\n    if os.environ.get('VIRTUAL_ENV'):\n        # find pip via PATH\n        pip = 'pip'\n    else:\n        # find pip in same directory as pip-sync entry-point script\n        pip = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), 'pip')\n\n    if to_uninstall:\n        if dry_run:\n            click.echo(\"Would uninstall:\")\n            for pkg in to_uninstall:\n                click.echo(\"  {}\".format(pkg))\n        else:\n            check_call([pip, 'uninstall', '-y'] + pip_flags + sorted(to_uninstall))\n\n    if to_install:\n        if install_flags is None:\n            install_flags = []\n        if dry_run:\n            click.echo(\"Would install:\")\n            for ireq in to_install:\n                click.echo(\"  {}\".format(format_requirement(ireq)))\n        else:\n            # prepare requirement lines\n            req_lines = []\n            for ireq in sorted(to_install, key=key_from_ireq):\n                ireq_hashes = get_hashes_from_ireq(ireq)\n                req_lines.append(format_requirement(ireq, hashes=ireq_hashes))\n\n            # save requirement lines to a temporary file\n            with tempfile.NamedTemporaryFile(mode='wt') as tmp_req_file:\n                tmp_req_file.write('\\n'.join(req_lines))\n                tmp_req_file.flush()\n\n                check_call([pip, 'install', '-r', tmp_req_file.name] + pip_flags + install_flags)\n    return 0\n", "path": "piptools/sync.py"}, {"content": "# coding: utf-8\n# flake8: noqa\nfrom __future__ import (absolute_import, division, print_function,\n                        unicode_literals)\n\nimport six\n\nif six.PY2:\n    from .tempfile import TemporaryDirectory\n    from .contextlib import ExitStack\nelse:\n    from tempfile import TemporaryDirectory\n    from contextlib import ExitStack\n\nfrom .pip_compat import (\n    InstallRequirement,\n    parse_requirements,\n    RequirementSet,\n    user_cache_dir,\n    FAVORITE_HASH,\n    is_file_url,\n    url_to_path,\n    PackageFinder,\n    FormatControl,\n    Wheel,\n    Command,\n    cmdoptions,\n    get_installed_distributions,\n    PyPI,\n    install_req_from_line,\n    install_req_from_editable,\n)\n", "path": "piptools/_compat/__init__.py"}], "after_files": [{"content": "# -*- coding=utf-8 -*-\nimport importlib\n\nimport pip\nimport pkg_resources\n\ndef do_import(module_path, subimport=None, old_path=None):\n    old_path = old_path or module_path\n    prefixes = [\"pip._internal\", \"pip\"]\n    paths = [module_path, old_path]\n    search_order = [\"{0}.{1}\".format(p, pth) for p in prefixes for pth in paths if pth is not None]\n    package = subimport if subimport else None\n    for to_import in search_order:\n        if not subimport:\n            to_import, _, package = to_import.rpartition(\".\")\n        try:\n            imported = importlib.import_module(to_import)\n        except ImportError:\n            continue\n        else:\n            return getattr(imported, package)\n\n\nInstallRequirement = do_import('req.req_install', 'InstallRequirement')\nparse_requirements = do_import('req.req_file', 'parse_requirements')\nRequirementSet = do_import('req.req_set', 'RequirementSet')\nuser_cache_dir = do_import('utils.appdirs', 'user_cache_dir')\nFAVORITE_HASH = do_import('utils.hashes', 'FAVORITE_HASH')\nis_file_url = do_import('download', 'is_file_url')\npath_to_url = do_import('download', 'path_to_url')\nurl_to_path = do_import('download', 'url_to_path')\nPackageFinder = do_import('index', 'PackageFinder')\nFormatControl = do_import('index', 'FormatControl')\nWheel = do_import('wheel', 'Wheel')\nCommand = do_import('cli.base_command', 'Command', old_path='basecommand')\ncmdoptions = do_import('cli.cmdoptions', old_path='cmdoptions')\nget_installed_distributions = do_import('utils.misc', 'get_installed_distributions', old_path='utils')\nPyPI = do_import('models.index', 'PyPI')\nstdlib_pkgs = do_import('utils.compat', 'stdlib_pkgs', old_path='compat')\nDEV_PKGS = do_import('commands.freeze', 'DEV_PKGS')\n\n# pip 18.1 has refactored InstallRequirement constructors use by pip-tools.\nif pkg_resources.parse_version(pip.__version__) < pkg_resources.parse_version('18.1'):\n    install_req_from_line = InstallRequirement.from_line\n    install_req_from_editable = InstallRequirement.from_editable\nelse:\n    install_req_from_line = do_import('req.constructors', 'install_req_from_line')\n    install_req_from_editable = do_import('req.constructors', 'install_req_from_editable')\n", "path": "piptools/_compat/pip_compat.py"}, {"content": "import collections\nimport os\nimport sys\nimport tempfile\nfrom subprocess import check_call\n\nfrom piptools._compat import stdlib_pkgs, DEV_PKGS\nfrom . import click\nfrom .exceptions import IncompatibleRequirements, UnsupportedConstraint\nfrom .utils import flat_map, format_requirement, key_from_ireq, key_from_req, get_hashes_from_ireq\n\nPACKAGES_TO_IGNORE = [\n    '-markerlib',\n    'pip',\n    'pip-tools',\n    'pip-review',\n    'pkg-resources',\n] + list(stdlib_pkgs) + list(DEV_PKGS)\n\n\ndef dependency_tree(installed_keys, root_key):\n    \"\"\"\n    Calculate the dependency tree for the package `root_key` and return\n    a collection of all its dependencies.  Uses a DFS traversal algorithm.\n\n    `installed_keys` should be a {key: requirement} mapping, e.g.\n        {'django': from_line('django==1.8')}\n    `root_key` should be the key to return the dependency tree for.\n    \"\"\"\n    dependencies = set()\n    queue = collections.deque()\n\n    if root_key in installed_keys:\n        dep = installed_keys[root_key]\n        queue.append(dep)\n\n    while queue:\n        v = queue.popleft()\n        key = key_from_req(v)\n        if key in dependencies:\n            continue\n\n        dependencies.add(key)\n\n        for dep_specifier in v.requires():\n            dep_name = key_from_req(dep_specifier)\n            if dep_name in installed_keys:\n                dep = installed_keys[dep_name]\n\n                if dep_specifier.specifier.contains(dep.version):\n                    queue.append(dep)\n\n    return dependencies\n\n\ndef get_dists_to_ignore(installed):\n    \"\"\"\n    Returns a collection of package names to ignore when performing pip-sync,\n    based on the currently installed environment.  For example, when pip-tools\n    is installed in the local environment, it should be ignored, including all\n    of its dependencies (e.g. click).  When pip-tools is not installed\n    locally, click should also be installed/uninstalled depending on the given\n    requirements.\n    \"\"\"\n    installed_keys = {key_from_req(r): r for r in installed}\n    return list(flat_map(lambda req: dependency_tree(installed_keys, req), PACKAGES_TO_IGNORE))\n\n\ndef merge(requirements, ignore_conflicts):\n    by_key = {}\n\n    for ireq in requirements:\n        if ireq.link is not None and not ireq.editable:\n            msg = ('pip-compile does not support URLs as packages, unless they are editable. '\n                   'Perhaps add -e option?')\n            raise UnsupportedConstraint(msg, ireq)\n\n        key = ireq.link or key_from_req(ireq.req)\n\n        if not ignore_conflicts:\n            existing_ireq = by_key.get(key)\n            if existing_ireq:\n                # NOTE: We check equality here since we can assume that the\n                # requirements are all pinned\n                if ireq.specifier != existing_ireq.specifier:\n                    raise IncompatibleRequirements(ireq, existing_ireq)\n\n        # TODO: Always pick the largest specifier in case of a conflict\n        by_key[key] = ireq\n\n    return by_key.values()\n\n\ndef diff(compiled_requirements, installed_dists):\n    \"\"\"\n    Calculate which packages should be installed or uninstalled, given a set\n    of compiled requirements and a list of currently installed modules.\n    \"\"\"\n    requirements_lut = {r.link or key_from_req(r.req): r for r in compiled_requirements}\n\n    satisfied = set()  # holds keys\n    to_install = set()  # holds InstallRequirement objects\n    to_uninstall = set()  # holds keys\n\n    pkgs_to_ignore = get_dists_to_ignore(installed_dists)\n    for dist in installed_dists:\n        key = key_from_req(dist)\n        if key not in requirements_lut or not requirements_lut[key].match_markers():\n            to_uninstall.add(key)\n        elif requirements_lut[key].specifier.contains(dist.version):\n            satisfied.add(key)\n\n    for key, requirement in requirements_lut.items():\n        if key not in satisfied and requirement.match_markers():\n            to_install.add(requirement)\n\n    # Make sure to not uninstall any packages that should be ignored\n    to_uninstall -= set(pkgs_to_ignore)\n\n    return (to_install, to_uninstall)\n\n\ndef sync(to_install, to_uninstall, verbose=False, dry_run=False, pip_flags=None, install_flags=None):\n    \"\"\"\n    Install and uninstalls the given sets of modules.\n    \"\"\"\n    if not to_uninstall and not to_install:\n        click.echo(\"Everything up-to-date\")\n\n    if pip_flags is None:\n        pip_flags = []\n\n    if not verbose:\n        pip_flags += ['-q']\n\n    if os.environ.get('VIRTUAL_ENV'):\n        # find pip via PATH\n        pip = 'pip'\n    else:\n        # find pip in same directory as pip-sync entry-point script\n        pip = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), 'pip')\n\n    if to_uninstall:\n        if dry_run:\n            click.echo(\"Would uninstall:\")\n            for pkg in to_uninstall:\n                click.echo(\"  {}\".format(pkg))\n        else:\n            check_call([pip, 'uninstall', '-y'] + pip_flags + sorted(to_uninstall))\n\n    if to_install:\n        if install_flags is None:\n            install_flags = []\n        if dry_run:\n            click.echo(\"Would install:\")\n            for ireq in to_install:\n                click.echo(\"  {}\".format(format_requirement(ireq)))\n        else:\n            # prepare requirement lines\n            req_lines = []\n            for ireq in sorted(to_install, key=key_from_ireq):\n                ireq_hashes = get_hashes_from_ireq(ireq)\n                req_lines.append(format_requirement(ireq, hashes=ireq_hashes))\n\n            # save requirement lines to a temporary file\n            with tempfile.NamedTemporaryFile(mode='wt') as tmp_req_file:\n                tmp_req_file.write('\\n'.join(req_lines))\n                tmp_req_file.flush()\n\n                check_call([pip, 'install', '-r', tmp_req_file.name] + pip_flags + install_flags)\n    return 0\n", "path": "piptools/sync.py"}, {"content": "# coding: utf-8\n# flake8: noqa\nfrom __future__ import (absolute_import, division, print_function,\n                        unicode_literals)\n\nimport six\n\nif six.PY2:\n    from .tempfile import TemporaryDirectory\n    from .contextlib import ExitStack\nelse:\n    from tempfile import TemporaryDirectory\n    from contextlib import ExitStack\n\nfrom .pip_compat import (\n    InstallRequirement,\n    parse_requirements,\n    RequirementSet,\n    user_cache_dir,\n    FAVORITE_HASH,\n    is_file_url,\n    url_to_path,\n    PackageFinder,\n    FormatControl,\n    Wheel,\n    Command,\n    cmdoptions,\n    get_installed_distributions,\n    PyPI,\n    install_req_from_line,\n    install_req_from_editable,\n    stdlib_pkgs,\n    DEV_PKGS,\n)\n", "path": "piptools/_compat/__init__.py"}]}