We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
pip-compile bumps setuptools within commented-out spec
If you have a `requirements.in` which contains a package which depends on `setuptools`, for example:
```
$ cat requirements.in 
protobuf  # or google-api-core, ipython, pandas-gbq, pydata-google-auth
```
Then after running `pip-compile`, you get:
```
$ cat requirements.txt
#
# This file is autogenerated by pip-compile
# To update, run:
#
#    pip-compile
#
protobuf==3.10.0
six==1.12.0               # via protobuf

# The following packages are considered to be unsafe in a requirements file:
# setuptools==41.4.0        # via protobuf
```

As you can see, `pip-compile` refuses to include `setuptools` directly in a generated `requirements.txt`, instead adding a section with the comment "The following packages are considered to be unsafe in a requirements file:".
This behaviour is fine in the general (and I don't disagree with the comment or behaviour).

However because the commented out `setuptools` line includes a version number, when `setuptools` releases an update then the `requirements.txt` file ends up looking out of date.

Say you had committed a `requirements.txt` which looked like:
```
# requirements...

# The following packages are considered to be unsafe in a requirements file:
# setuptools==41.4.0        # via protobuf
```

Then `setuptools` releases `41.5.0` and now when you run `pip-compile` you get:
```
# requirements...

# The following packages are considered to be unsafe in a requirements file:
# setuptools==41.5.0        # via protobuf
```

This is inconvenient if you happen to regenerate your `requirements.txt` at some point after an upstream releases, however if you're also using `pip-compile` to check that your `requirements.txt` is in step with your `requirements.in` (see #882) in CI then it means that your build now fails for what is essentially a non-change.

I'm not sure what the right solution is here, though perhaps if there was a way for pip-compile to understand its own commented out dependency that might help?

--- 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/writer.py`
Content:
```
1 from __future__ import unicode_literals
2 
3 import os
4 from itertools import chain
5 
6 from .click import unstyle
7 from .logging import log
8 from .utils import (
9     UNSAFE_PACKAGES,
10     comment,
11     dedup,
12     format_requirement,
13     get_compile_command,
14     key_from_ireq,
15 )
16 
17 MESSAGE_UNHASHED_PACKAGE = comment(
18     "# WARNING: pip install will require the following package to be hashed."
19     "\n# Consider using a hashable URL like "
20     "https://github.com/jazzband/pip-tools/archive/SOMECOMMIT.zip"
21 )
22 
23 MESSAGE_UNSAFE_PACKAGES_UNPINNED = comment(
24     "# WARNING: The following packages were not pinned, but pip requires them to be"
25     "\n# pinned when the requirements file includes hashes. "
26     "Consider using the --allow-unsafe flag."
27 )
28 
29 MESSAGE_UNSAFE_PACKAGES = comment(
30     "# The following packages are considered to be unsafe in a requirements file:"
31 )
32 
33 MESSAGE_UNINSTALLABLE = (
34     "The generated requirements file may be rejected by pip install. "
35     "See # WARNING lines for details."
36 )
37 
38 
39 class OutputWriter(object):
40     def __init__(
41         self,
42         src_files,
43         dst_file,
44         click_ctx,
45         dry_run,
46         emit_header,
47         emit_index,
48         emit_trusted_host,
49         annotate,
50         generate_hashes,
51         default_index_url,
52         index_urls,
53         trusted_hosts,
54         format_control,
55         allow_unsafe,
56         find_links,
57         emit_find_links,
58     ):
59         self.src_files = src_files
60         self.dst_file = dst_file
61         self.click_ctx = click_ctx
62         self.dry_run = dry_run
63         self.emit_header = emit_header
64         self.emit_index = emit_index
65         self.emit_trusted_host = emit_trusted_host
66         self.annotate = annotate
67         self.generate_hashes = generate_hashes
68         self.default_index_url = default_index_url
69         self.index_urls = index_urls
70         self.trusted_hosts = trusted_hosts
71         self.format_control = format_control
72         self.allow_unsafe = allow_unsafe
73         self.find_links = find_links
74         self.emit_find_links = emit_find_links
75 
76     def _sort_key(self, ireq):
77         return (not ireq.editable, str(ireq.req).lower())
78 
79     def write_header(self):
80         if self.emit_header:
81             yield comment("#")
82             yield comment("# This file is autogenerated by pip-compile")
83             yield comment("# To update, run:")
84             yield comment("#")
85             compile_command = os.environ.get(
86                 "CUSTOM_COMPILE_COMMAND"
87             ) or get_compile_command(self.click_ctx)
88             yield comment("#    {}".format(compile_command))
89             yield comment("#")
90 
91     def write_index_options(self):
92         if self.emit_index:
93             for index, index_url in enumerate(dedup(self.index_urls)):
94                 if index_url.rstrip("/") == self.default_index_url:
95                     continue
96                 flag = "--index-url" if index == 0 else "--extra-index-url"
97                 yield "{} {}".format(flag, index_url)
98 
99     def write_trusted_hosts(self):
100         if self.emit_trusted_host:
101             for trusted_host in dedup(self.trusted_hosts):
102                 yield "--trusted-host {}".format(trusted_host)
103 
104     def write_format_controls(self):
105         for nb in dedup(self.format_control.no_binary):
106             yield "--no-binary {}".format(nb)
107         for ob in dedup(self.format_control.only_binary):
108             yield "--only-binary {}".format(ob)
109 
110     def write_find_links(self):
111         if self.emit_find_links:
112             for find_link in dedup(self.find_links):
113                 yield "--find-links {}".format(find_link)
114 
115     def write_flags(self):
116         emitted = False
117         for line in chain(
118             self.write_index_options(),
119             self.write_find_links(),
120             self.write_trusted_hosts(),
121             self.write_format_controls(),
122         ):
123             emitted = True
124             yield line
125         if emitted:
126             yield ""
127 
128     def _iter_lines(
129         self,
130         results,
131         unsafe_requirements=None,
132         reverse_dependencies=None,
133         primary_packages=None,
134         markers=None,
135         hashes=None,
136     ):
137         # default values
138         unsafe_requirements = unsafe_requirements or []
139         reverse_dependencies = reverse_dependencies or {}
140         primary_packages = primary_packages or []
141         markers = markers or {}
142         hashes = hashes or {}
143 
144         # Check for unhashed or unpinned packages if at least one package does have
145         # hashes, which will trigger pip install's --require-hashes mode.
146         warn_uninstallable = False
147         has_hashes = hashes and any(hash for hash in hashes.values())
148 
149         yielded = False
150 
151         for line in self.write_header():
152             yield line
153             yielded = True
154         for line in self.write_flags():
155             yield line
156             yielded = True
157 
158         unsafe_requirements = (
159             {r for r in results if r.name in UNSAFE_PACKAGES}
160             if not unsafe_requirements
161             else unsafe_requirements
162         )
163         packages = {r for r in results if r.name not in UNSAFE_PACKAGES}
164 
165         if packages:
166             packages = sorted(packages, key=self._sort_key)
167             for ireq in packages:
168                 if has_hashes and not hashes.get(ireq):
169                     yield MESSAGE_UNHASHED_PACKAGE
170                     warn_uninstallable = True
171                 line = self._format_requirement(
172                     ireq,
173                     reverse_dependencies,
174                     primary_packages,
175                     markers.get(key_from_ireq(ireq)),
176                     hashes=hashes,
177                 )
178                 yield line
179             yielded = True
180 
181         if unsafe_requirements:
182             unsafe_requirements = sorted(unsafe_requirements, key=self._sort_key)
183             yield ""
184             yielded = True
185             if has_hashes and not self.allow_unsafe:
186                 yield MESSAGE_UNSAFE_PACKAGES_UNPINNED
187                 warn_uninstallable = True
188             else:
189                 yield MESSAGE_UNSAFE_PACKAGES
190 
191             for ireq in unsafe_requirements:
192                 req = self._format_requirement(
193                     ireq,
194                     reverse_dependencies,
195                     primary_packages,
196                     marker=markers.get(key_from_ireq(ireq)),
197                     hashes=hashes,
198                 )
199                 if not self.allow_unsafe:
200                     yield comment("# {}".format(req))
201                 else:
202                     yield req
203 
204         # Yield even when there's no real content, so that blank files are written
205         if not yielded:
206             yield ""
207 
208         if warn_uninstallable:
209             log.warning(MESSAGE_UNINSTALLABLE)
210 
211     def write(
212         self,
213         results,
214         unsafe_requirements,
215         reverse_dependencies,
216         primary_packages,
217         markers,
218         hashes,
219     ):
220 
221         for line in self._iter_lines(
222             results,
223             unsafe_requirements,
224             reverse_dependencies,
225             primary_packages,
226             markers,
227             hashes,
228         ):
229             log.info(line)
230             if not self.dry_run:
231                 self.dst_file.write(unstyle(line).encode("utf-8"))
232                 self.dst_file.write(os.linesep.encode("utf-8"))
233 
234     def _format_requirement(
235         self, ireq, reverse_dependencies, primary_packages, marker=None, hashes=None
236     ):
237         ireq_hashes = (hashes if hashes is not None else {}).get(ireq)
238 
239         line = format_requirement(ireq, marker=marker, hashes=ireq_hashes)
240 
241         if not self.annotate or key_from_ireq(ireq) in primary_packages:
242             return line
243 
244         # Annotate what packages this package is required by
245         required_by = reverse_dependencies.get(ireq.name.lower(), [])
246         if required_by:
247             annotation = ", ".join(sorted(required_by))
248             line = "{:24}{}{}".format(
249                 line,
250                 " \\\n    " if ireq_hashes else "  ",
251                 comment("# via " + annotation),
252             )
253         return line
254
```
--- 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/writer.py b/piptools/writer.py
--- a/piptools/writer.py
+++ b/piptools/writer.py
@@ -189,17 +189,18 @@
                 yield MESSAGE_UNSAFE_PACKAGES
 
             for ireq in unsafe_requirements:
-                req = self._format_requirement(
-                    ireq,
-                    reverse_dependencies,
-                    primary_packages,
-                    marker=markers.get(key_from_ireq(ireq)),
-                    hashes=hashes,
-                )
+                ireq_key = key_from_ireq(ireq)
                 if not self.allow_unsafe:
-                    yield comment("# {}".format(req))
+                    yield comment("# {}".format(ireq_key))
                 else:
-                    yield req
+                    line = self._format_requirement(
+                        ireq,
+                        reverse_dependencies,
+                        primary_packages,
+                        marker=markers.get(ireq_key),
+                        hashes=hashes,
+                    )
+                    yield line
 
         # Yield even when there's no real content, so that blank files are written
         if not yielded:

{"golden_diff": "diff --git a/piptools/writer.py b/piptools/writer.py\n--- a/piptools/writer.py\n+++ b/piptools/writer.py\n@@ -189,17 +189,18 @@\n                 yield MESSAGE_UNSAFE_PACKAGES\n \n             for ireq in unsafe_requirements:\n-                req = self._format_requirement(\n-                    ireq,\n-                    reverse_dependencies,\n-                    primary_packages,\n-                    marker=markers.get(key_from_ireq(ireq)),\n-                    hashes=hashes,\n-                )\n+                ireq_key = key_from_ireq(ireq)\n                 if not self.allow_unsafe:\n-                    yield comment(\"# {}\".format(req))\n+                    yield comment(\"# {}\".format(ireq_key))\n                 else:\n-                    yield req\n+                    line = self._format_requirement(\n+                        ireq,\n+                        reverse_dependencies,\n+                        primary_packages,\n+                        marker=markers.get(ireq_key),\n+                        hashes=hashes,\n+                    )\n+                    yield line\n \n         # Yield even when there's no real content, so that blank files are written\n         if not yielded:\n", "issue": "pip-compile bumps setuptools within commented-out spec\nIf you have a `requirements.in` which contains a package which depends on `setuptools`, for example:\r\n```\r\n$ cat requirements.in \r\nprotobuf  # or google-api-core, ipython, pandas-gbq, pydata-google-auth\r\n```\r\nThen after running `pip-compile`, you get:\r\n```\r\n$ cat requirements.txt\r\n#\r\n# This file is autogenerated by pip-compile\r\n# To update, run:\r\n#\r\n#    pip-compile\r\n#\r\nprotobuf==3.10.0\r\nsix==1.12.0               # via protobuf\r\n\r\n# The following packages are considered to be unsafe in a requirements file:\r\n# setuptools==41.4.0        # via protobuf\r\n```\r\n\r\nAs you can see, `pip-compile` refuses to include `setuptools` directly in a generated `requirements.txt`, instead adding a section with the comment \"The following packages are considered to be unsafe in a requirements file:\".\r\nThis behaviour is fine in the general (and I don't disagree with the comment or behaviour).\r\n\r\nHowever because the commented out `setuptools` line includes a version number, when `setuptools` releases an update then the `requirements.txt` file ends up looking out of date.\r\n\r\nSay you had committed a `requirements.txt` which looked like:\r\n```\r\n# requirements...\r\n\r\n# The following packages are considered to be unsafe in a requirements file:\r\n# setuptools==41.4.0        # via protobuf\r\n```\r\n\r\nThen `setuptools` releases `41.5.0` and now when you run `pip-compile` you get:\r\n```\r\n# requirements...\r\n\r\n# The following packages are considered to be unsafe in a requirements file:\r\n# setuptools==41.5.0        # via protobuf\r\n```\r\n\r\nThis is inconvenient if you happen to regenerate your `requirements.txt` at some point after an upstream releases, however if you're also using `pip-compile` to check that your `requirements.txt` is in step with your `requirements.in` (see #882) in CI then it means that your build now fails for what is essentially a non-change.\r\n\r\nI'm not sure what the right solution is here, though perhaps if there was a way for pip-compile to understand its own commented out dependency that might help?\n", "before_files": [{"content": "from __future__ import unicode_literals\n\nimport os\nfrom itertools import chain\n\nfrom .click import unstyle\nfrom .logging import log\nfrom .utils import (\n    UNSAFE_PACKAGES,\n    comment,\n    dedup,\n    format_requirement,\n    get_compile_command,\n    key_from_ireq,\n)\n\nMESSAGE_UNHASHED_PACKAGE = comment(\n    \"# WARNING: pip install will require the following package to be hashed.\"\n    \"\\n# Consider using a hashable URL like \"\n    \"https://github.com/jazzband/pip-tools/archive/SOMECOMMIT.zip\"\n)\n\nMESSAGE_UNSAFE_PACKAGES_UNPINNED = comment(\n    \"# WARNING: The following packages were not pinned, but pip requires them to be\"\n    \"\\n# pinned when the requirements file includes hashes. \"\n    \"Consider using the --allow-unsafe flag.\"\n)\n\nMESSAGE_UNSAFE_PACKAGES = comment(\n    \"# The following packages are considered to be unsafe in a requirements file:\"\n)\n\nMESSAGE_UNINSTALLABLE = (\n    \"The generated requirements file may be rejected by pip install. \"\n    \"See # WARNING lines for details.\"\n)\n\n\nclass OutputWriter(object):\n    def __init__(\n        self,\n        src_files,\n        dst_file,\n        click_ctx,\n        dry_run,\n        emit_header,\n        emit_index,\n        emit_trusted_host,\n        annotate,\n        generate_hashes,\n        default_index_url,\n        index_urls,\n        trusted_hosts,\n        format_control,\n        allow_unsafe,\n        find_links,\n        emit_find_links,\n    ):\n        self.src_files = src_files\n        self.dst_file = dst_file\n        self.click_ctx = click_ctx\n        self.dry_run = dry_run\n        self.emit_header = emit_header\n        self.emit_index = emit_index\n        self.emit_trusted_host = emit_trusted_host\n        self.annotate = annotate\n        self.generate_hashes = generate_hashes\n        self.default_index_url = default_index_url\n        self.index_urls = index_urls\n        self.trusted_hosts = trusted_hosts\n        self.format_control = format_control\n        self.allow_unsafe = allow_unsafe\n        self.find_links = find_links\n        self.emit_find_links = emit_find_links\n\n    def _sort_key(self, ireq):\n        return (not ireq.editable, str(ireq.req).lower())\n\n    def write_header(self):\n        if self.emit_header:\n            yield comment(\"#\")\n            yield comment(\"# This file is autogenerated by pip-compile\")\n            yield comment(\"# To update, run:\")\n            yield comment(\"#\")\n            compile_command = os.environ.get(\n                \"CUSTOM_COMPILE_COMMAND\"\n            ) or get_compile_command(self.click_ctx)\n            yield comment(\"#    {}\".format(compile_command))\n            yield comment(\"#\")\n\n    def write_index_options(self):\n        if self.emit_index:\n            for index, index_url in enumerate(dedup(self.index_urls)):\n                if index_url.rstrip(\"/\") == self.default_index_url:\n                    continue\n                flag = \"--index-url\" if index == 0 else \"--extra-index-url\"\n                yield \"{} {}\".format(flag, index_url)\n\n    def write_trusted_hosts(self):\n        if self.emit_trusted_host:\n            for trusted_host in dedup(self.trusted_hosts):\n                yield \"--trusted-host {}\".format(trusted_host)\n\n    def write_format_controls(self):\n        for nb in dedup(self.format_control.no_binary):\n            yield \"--no-binary {}\".format(nb)\n        for ob in dedup(self.format_control.only_binary):\n            yield \"--only-binary {}\".format(ob)\n\n    def write_find_links(self):\n        if self.emit_find_links:\n            for find_link in dedup(self.find_links):\n                yield \"--find-links {}\".format(find_link)\n\n    def write_flags(self):\n        emitted = False\n        for line in chain(\n            self.write_index_options(),\n            self.write_find_links(),\n            self.write_trusted_hosts(),\n            self.write_format_controls(),\n        ):\n            emitted = True\n            yield line\n        if emitted:\n            yield \"\"\n\n    def _iter_lines(\n        self,\n        results,\n        unsafe_requirements=None,\n        reverse_dependencies=None,\n        primary_packages=None,\n        markers=None,\n        hashes=None,\n    ):\n        # default values\n        unsafe_requirements = unsafe_requirements or []\n        reverse_dependencies = reverse_dependencies or {}\n        primary_packages = primary_packages or []\n        markers = markers or {}\n        hashes = hashes or {}\n\n        # Check for unhashed or unpinned packages if at least one package does have\n        # hashes, which will trigger pip install's --require-hashes mode.\n        warn_uninstallable = False\n        has_hashes = hashes and any(hash for hash in hashes.values())\n\n        yielded = False\n\n        for line in self.write_header():\n            yield line\n            yielded = True\n        for line in self.write_flags():\n            yield line\n            yielded = True\n\n        unsafe_requirements = (\n            {r for r in results if r.name in UNSAFE_PACKAGES}\n            if not unsafe_requirements\n            else unsafe_requirements\n        )\n        packages = {r for r in results if r.name not in UNSAFE_PACKAGES}\n\n        if packages:\n            packages = sorted(packages, key=self._sort_key)\n            for ireq in packages:\n                if has_hashes and not hashes.get(ireq):\n                    yield MESSAGE_UNHASHED_PACKAGE\n                    warn_uninstallable = True\n                line = self._format_requirement(\n                    ireq,\n                    reverse_dependencies,\n                    primary_packages,\n                    markers.get(key_from_ireq(ireq)),\n                    hashes=hashes,\n                )\n                yield line\n            yielded = True\n\n        if unsafe_requirements:\n            unsafe_requirements = sorted(unsafe_requirements, key=self._sort_key)\n            yield \"\"\n            yielded = True\n            if has_hashes and not self.allow_unsafe:\n                yield MESSAGE_UNSAFE_PACKAGES_UNPINNED\n                warn_uninstallable = True\n            else:\n                yield MESSAGE_UNSAFE_PACKAGES\n\n            for ireq in unsafe_requirements:\n                req = self._format_requirement(\n                    ireq,\n                    reverse_dependencies,\n                    primary_packages,\n                    marker=markers.get(key_from_ireq(ireq)),\n                    hashes=hashes,\n                )\n                if not self.allow_unsafe:\n                    yield comment(\"# {}\".format(req))\n                else:\n                    yield req\n\n        # Yield even when there's no real content, so that blank files are written\n        if not yielded:\n            yield \"\"\n\n        if warn_uninstallable:\n            log.warning(MESSAGE_UNINSTALLABLE)\n\n    def write(\n        self,\n        results,\n        unsafe_requirements,\n        reverse_dependencies,\n        primary_packages,\n        markers,\n        hashes,\n    ):\n\n        for line in self._iter_lines(\n            results,\n            unsafe_requirements,\n            reverse_dependencies,\n            primary_packages,\n            markers,\n            hashes,\n        ):\n            log.info(line)\n            if not self.dry_run:\n                self.dst_file.write(unstyle(line).encode(\"utf-8\"))\n                self.dst_file.write(os.linesep.encode(\"utf-8\"))\n\n    def _format_requirement(\n        self, ireq, reverse_dependencies, primary_packages, marker=None, hashes=None\n    ):\n        ireq_hashes = (hashes if hashes is not None else {}).get(ireq)\n\n        line = format_requirement(ireq, marker=marker, hashes=ireq_hashes)\n\n        if not self.annotate or key_from_ireq(ireq) in primary_packages:\n            return line\n\n        # Annotate what packages this package is required by\n        required_by = reverse_dependencies.get(ireq.name.lower(), [])\n        if required_by:\n            annotation = \", \".join(sorted(required_by))\n            line = \"{:24}{}{}\".format(\n                line,\n                \" \\\\\\n    \" if ireq_hashes else \"  \",\n                comment(\"# via \" + annotation),\n            )\n        return line\n", "path": "piptools/writer.py"}], "after_files": [{"content": "from __future__ import unicode_literals\n\nimport os\nfrom itertools import chain\n\nfrom .click import unstyle\nfrom .logging import log\nfrom .utils import (\n    UNSAFE_PACKAGES,\n    comment,\n    dedup,\n    format_requirement,\n    get_compile_command,\n    key_from_ireq,\n)\n\nMESSAGE_UNHASHED_PACKAGE = comment(\n    \"# WARNING: pip install will require the following package to be hashed.\"\n    \"\\n# Consider using a hashable URL like \"\n    \"https://github.com/jazzband/pip-tools/archive/SOMECOMMIT.zip\"\n)\n\nMESSAGE_UNSAFE_PACKAGES_UNPINNED = comment(\n    \"# WARNING: The following packages were not pinned, but pip requires them to be\"\n    \"\\n# pinned when the requirements file includes hashes. \"\n    \"Consider using the --allow-unsafe flag.\"\n)\n\nMESSAGE_UNSAFE_PACKAGES = comment(\n    \"# The following packages are considered to be unsafe in a requirements file:\"\n)\n\nMESSAGE_UNINSTALLABLE = (\n    \"The generated requirements file may be rejected by pip install. \"\n    \"See # WARNING lines for details.\"\n)\n\n\nclass OutputWriter(object):\n    def __init__(\n        self,\n        src_files,\n        dst_file,\n        click_ctx,\n        dry_run,\n        emit_header,\n        emit_index,\n        emit_trusted_host,\n        annotate,\n        generate_hashes,\n        default_index_url,\n        index_urls,\n        trusted_hosts,\n        format_control,\n        allow_unsafe,\n        find_links,\n        emit_find_links,\n    ):\n        self.src_files = src_files\n        self.dst_file = dst_file\n        self.click_ctx = click_ctx\n        self.dry_run = dry_run\n        self.emit_header = emit_header\n        self.emit_index = emit_index\n        self.emit_trusted_host = emit_trusted_host\n        self.annotate = annotate\n        self.generate_hashes = generate_hashes\n        self.default_index_url = default_index_url\n        self.index_urls = index_urls\n        self.trusted_hosts = trusted_hosts\n        self.format_control = format_control\n        self.allow_unsafe = allow_unsafe\n        self.find_links = find_links\n        self.emit_find_links = emit_find_links\n\n    def _sort_key(self, ireq):\n        return (not ireq.editable, str(ireq.req).lower())\n\n    def write_header(self):\n        if self.emit_header:\n            yield comment(\"#\")\n            yield comment(\"# This file is autogenerated by pip-compile\")\n            yield comment(\"# To update, run:\")\n            yield comment(\"#\")\n            compile_command = os.environ.get(\n                \"CUSTOM_COMPILE_COMMAND\"\n            ) or get_compile_command(self.click_ctx)\n            yield comment(\"#    {}\".format(compile_command))\n            yield comment(\"#\")\n\n    def write_index_options(self):\n        if self.emit_index:\n            for index, index_url in enumerate(dedup(self.index_urls)):\n                if index_url.rstrip(\"/\") == self.default_index_url:\n                    continue\n                flag = \"--index-url\" if index == 0 else \"--extra-index-url\"\n                yield \"{} {}\".format(flag, index_url)\n\n    def write_trusted_hosts(self):\n        if self.emit_trusted_host:\n            for trusted_host in dedup(self.trusted_hosts):\n                yield \"--trusted-host {}\".format(trusted_host)\n\n    def write_format_controls(self):\n        for nb in dedup(self.format_control.no_binary):\n            yield \"--no-binary {}\".format(nb)\n        for ob in dedup(self.format_control.only_binary):\n            yield \"--only-binary {}\".format(ob)\n\n    def write_find_links(self):\n        if self.emit_find_links:\n            for find_link in dedup(self.find_links):\n                yield \"--find-links {}\".format(find_link)\n\n    def write_flags(self):\n        emitted = False\n        for line in chain(\n            self.write_index_options(),\n            self.write_find_links(),\n            self.write_trusted_hosts(),\n            self.write_format_controls(),\n        ):\n            emitted = True\n            yield line\n        if emitted:\n            yield \"\"\n\n    def _iter_lines(\n        self,\n        results,\n        unsafe_requirements=None,\n        reverse_dependencies=None,\n        primary_packages=None,\n        markers=None,\n        hashes=None,\n    ):\n        # default values\n        unsafe_requirements = unsafe_requirements or []\n        reverse_dependencies = reverse_dependencies or {}\n        primary_packages = primary_packages or []\n        markers = markers or {}\n        hashes = hashes or {}\n\n        # Check for unhashed or unpinned packages if at least one package does have\n        # hashes, which will trigger pip install's --require-hashes mode.\n        warn_uninstallable = False\n        has_hashes = hashes and any(hash for hash in hashes.values())\n\n        yielded = False\n\n        for line in self.write_header():\n            yield line\n            yielded = True\n        for line in self.write_flags():\n            yield line\n            yielded = True\n\n        unsafe_requirements = (\n            {r for r in results if r.name in UNSAFE_PACKAGES}\n            if not unsafe_requirements\n            else unsafe_requirements\n        )\n        packages = {r for r in results if r.name not in UNSAFE_PACKAGES}\n\n        if packages:\n            packages = sorted(packages, key=self._sort_key)\n            for ireq in packages:\n                if has_hashes and not hashes.get(ireq):\n                    yield MESSAGE_UNHASHED_PACKAGE\n                    warn_uninstallable = True\n                line = self._format_requirement(\n                    ireq,\n                    reverse_dependencies,\n                    primary_packages,\n                    markers.get(key_from_ireq(ireq)),\n                    hashes=hashes,\n                )\n                yield line\n            yielded = True\n\n        if unsafe_requirements:\n            unsafe_requirements = sorted(unsafe_requirements, key=self._sort_key)\n            yield \"\"\n            yielded = True\n            if has_hashes and not self.allow_unsafe:\n                yield MESSAGE_UNSAFE_PACKAGES_UNPINNED\n                warn_uninstallable = True\n            else:\n                yield MESSAGE_UNSAFE_PACKAGES\n\n            for ireq in unsafe_requirements:\n                ireq_key = key_from_ireq(ireq)\n                if not self.allow_unsafe:\n                    yield comment(\"# {}\".format(ireq_key))\n                else:\n                    line = self._format_requirement(\n                        ireq,\n                        reverse_dependencies,\n                        primary_packages,\n                        marker=markers.get(ireq_key),\n                        hashes=hashes,\n                    )\n                    yield line\n\n        # Yield even when there's no real content, so that blank files are written\n        if not yielded:\n            yield \"\"\n\n        if warn_uninstallable:\n            log.warning(MESSAGE_UNINSTALLABLE)\n\n    def write(\n        self,\n        results,\n        unsafe_requirements,\n        reverse_dependencies,\n        primary_packages,\n        markers,\n        hashes,\n    ):\n\n        for line in self._iter_lines(\n            results,\n            unsafe_requirements,\n            reverse_dependencies,\n            primary_packages,\n            markers,\n            hashes,\n        ):\n            log.info(line)\n            if not self.dry_run:\n                self.dst_file.write(unstyle(line).encode(\"utf-8\"))\n                self.dst_file.write(os.linesep.encode(\"utf-8\"))\n\n    def _format_requirement(\n        self, ireq, reverse_dependencies, primary_packages, marker=None, hashes=None\n    ):\n        ireq_hashes = (hashes if hashes is not None else {}).get(ireq)\n\n        line = format_requirement(ireq, marker=marker, hashes=ireq_hashes)\n\n        if not self.annotate or key_from_ireq(ireq) in primary_packages:\n            return line\n\n        # Annotate what packages this package is required by\n        required_by = reverse_dependencies.get(ireq.name.lower(), [])\n        if required_by:\n            annotation = \", \".join(sorted(required_by))\n            line = \"{:24}{}{}\".format(\n                line,\n                \" \\\\\\n    \" if ireq_hashes else \"  \",\n                comment(\"# via \" + annotation),\n            )\n        return line\n", "path": "piptools/writer.py"}]}