We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Remove "(line X)" annotations from output
#### What's the problem this feature will solve?

I love the new source annotations in 4.5.0 from #1058. But the line number annotations cause unnecessary diff churn. For example on a project I'm working on, I added a couple requirements that are alphabetically early, and it means *every* requirement afterwards has a new line number:

<img width="395" alt="Screenshot 2020-02-25 at 15 22 19" src="https://user-images.githubusercontent.com/857609/75261303-b6d72580-57e2-11ea-99ef-dcef368bb755.png">

Adding a single requirement with no dependencies can become a 100 line diff 😢

Equally sorting one's `requirements.in` would make diff noise just from changing the line numbers.
 
#### Describe the solution you'd like

Remove the line numbers from the output.

#### Alternative Solutions

A flag? I prefer sensible defaults though.


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

{"golden_diff": "diff --git a/piptools/writer.py b/piptools/writer.py\n--- a/piptools/writer.py\n+++ b/piptools/writer.py\n@@ -1,6 +1,7 @@\n from __future__ import unicode_literals\n \n import os\n+import re\n from itertools import chain\n \n import six\n@@ -38,9 +39,12 @@\n )\n \n \n+strip_comes_from_line_re = re.compile(r\" \\(line \\d+\\)$\")\n+\n+\n def _comes_from_as_string(ireq):\n     if isinstance(ireq.comes_from, six.string_types):\n-        return ireq.comes_from\n+        return strip_comes_from_line_re.sub(\"\", ireq.comes_from)\n     return key_from_ireq(ireq.comes_from)\n", "issue": "Remove \"(line X)\" annotations from output\n#### What's the problem this feature will solve?\r\n\r\nI love the new source annotations in 4.5.0 from #1058. But the line number annotations cause unnecessary diff churn. For example on a project I'm working on, I added a couple requirements that are alphabetically early, and it means *every* requirement afterwards has a new line number:\r\n\r\n<img width=\"395\" alt=\"Screenshot 2020-02-25 at 15 22 19\" src=\"https://user-images.githubusercontent.com/857609/75261303-b6d72580-57e2-11ea-99ef-dcef368bb755.png\">\r\n\r\nAdding a single requirement with no dependencies can become a 100 line diff \ud83d\ude22\r\n\r\nEqually sorting one's `requirements.in` would make diff noise just from changing the line numbers.\r\n \r\n#### Describe the solution you'd like\r\n\r\nRemove the line numbers from the output.\r\n\r\n#### Alternative Solutions\r\n\r\nA flag? I prefer sensible defaults though.\r\n\n", "before_files": [{"content": "from __future__ import unicode_literals\n\nimport os\nfrom itertools import chain\n\nimport six\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\ndef _comes_from_as_string(ireq):\n    if isinstance(ireq.comes_from, six.string_types):\n        return ireq.comes_from\n    return key_from_ireq(ireq.comes_from)\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(self, results, unsafe_requirements=None, markers=None, hashes=None):\n        # default values\n        unsafe_requirements = unsafe_requirements 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, markers.get(key_from_ireq(ireq)), 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, marker=markers.get(ireq_key), 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(self, results, unsafe_requirements, markers, hashes):\n\n        for line in self._iter_lines(results, unsafe_requirements, markers, hashes):\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(self, ireq, marker=None, hashes=None):\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:\n            return line\n\n        # Annotate what packages or reqs-ins this package is required by\n        required_by = set()\n        if hasattr(ireq, \"_source_ireqs\"):\n            required_by |= {\n                _comes_from_as_string(src_ireq)\n                for src_ireq in ireq._source_ireqs\n                if src_ireq.comes_from\n            }\n        elif ireq.comes_from:\n            required_by.add(_comes_from_as_string(ireq))\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\nimport re\nfrom itertools import chain\n\nimport six\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\nstrip_comes_from_line_re = re.compile(r\" \\(line \\d+\\)$\")\n\n\ndef _comes_from_as_string(ireq):\n    if isinstance(ireq.comes_from, six.string_types):\n        return strip_comes_from_line_re.sub(\"\", ireq.comes_from)\n    return key_from_ireq(ireq.comes_from)\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(self, results, unsafe_requirements=None, markers=None, hashes=None):\n        # default values\n        unsafe_requirements = unsafe_requirements 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, markers.get(key_from_ireq(ireq)), 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, marker=markers.get(ireq_key), 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(self, results, unsafe_requirements, markers, hashes):\n\n        for line in self._iter_lines(results, unsafe_requirements, markers, hashes):\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(self, ireq, marker=None, hashes=None):\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:\n            return line\n\n        # Annotate what packages or reqs-ins this package is required by\n        required_by = set()\n        if hasattr(ireq, \"_source_ireqs\"):\n            required_by |= {\n                _comes_from_as_string(src_ireq)\n                for src_ireq in ireq._source_ireqs\n                if src_ireq.comes_from\n            }\n        elif ireq.comes_from:\n            required_by.add(_comes_from_as_string(ireq))\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"}]}