We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
--process-dependency-links not recognized in requirements.txt


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pip/req/req_file.py`
Content:
```
1 """
2 Requirements file parsing
3 """
4 
5 from __future__ import absolute_import
6 
7 import os
8 import re
9 import shlex
10 import optparse
11 import warnings
12 
13 from pip._vendor.six.moves.urllib import parse as urllib_parse
14 from pip._vendor.six.moves import filterfalse
15 
16 import pip
17 from pip.download import get_file_content
18 from pip.req.req_install import InstallRequirement
19 from pip.exceptions import (RequirementsFileParseError)
20 from pip.utils.deprecation import RemovedInPip10Warning
21 from pip import cmdoptions
22 
23 __all__ = ['parse_requirements']
24 
25 SCHEME_RE = re.compile(r'^(http|https|file):', re.I)
26 COMMENT_RE = re.compile(r'(^|\s)+#.*$')
27 
28 SUPPORTED_OPTIONS = [
29     cmdoptions.constraints,
30     cmdoptions.editable,
31     cmdoptions.requirements,
32     cmdoptions.no_index,
33     cmdoptions.index_url,
34     cmdoptions.find_links,
35     cmdoptions.extra_index_url,
36     cmdoptions.allow_external,
37     cmdoptions.allow_all_external,
38     cmdoptions.no_allow_external,
39     cmdoptions.allow_unsafe,
40     cmdoptions.no_allow_unsafe,
41     cmdoptions.use_wheel,
42     cmdoptions.no_use_wheel,
43     cmdoptions.always_unzip,
44     cmdoptions.no_binary,
45     cmdoptions.only_binary,
46     cmdoptions.trusted_host,
47 ]
48 
49 # options to be passed to requirements
50 SUPPORTED_OPTIONS_REQ = [
51     cmdoptions.install_options,
52     cmdoptions.global_options
53 ]
54 
55 # the 'dest' string values
56 SUPPORTED_OPTIONS_REQ_DEST = [o().dest for o in SUPPORTED_OPTIONS_REQ]
57 
58 
59 def parse_requirements(filename, finder=None, comes_from=None, options=None,
60                        session=None, constraint=False, wheel_cache=None):
61     """Parse a requirements file and yield InstallRequirement instances.
62 
63     :param filename:    Path or url of requirements file.
64     :param finder:      Instance of pip.index.PackageFinder.
65     :param comes_from:  Origin description of requirements.
66     :param options:     Global options.
67     :param session:     Instance of pip.download.PipSession.
68     :param constraint:  If true, parsing a constraint file rather than
69         requirements file.
70     :param wheel_cache: Instance of pip.wheel.WheelCache
71     """
72     if session is None:
73         raise TypeError(
74             "parse_requirements() missing 1 required keyword argument: "
75             "'session'"
76         )
77 
78     _, content = get_file_content(
79         filename, comes_from=comes_from, session=session
80     )
81 
82     lines = content.splitlines()
83     lines = ignore_comments(lines)
84     lines = join_lines(lines)
85     lines = skip_regex(lines, options)
86 
87     for line_number, line in enumerate(lines, 1):
88         req_iter = process_line(line, filename, line_number, finder,
89                                 comes_from, options, session, wheel_cache,
90                                 constraint=constraint)
91         for req in req_iter:
92             yield req
93 
94 
95 def process_line(line, filename, line_number, finder=None, comes_from=None,
96                  options=None, session=None, wheel_cache=None,
97                  constraint=False):
98     """Process a single requirements line; This can result in creating/yielding
99     requirements, or updating the finder.
100 
101     For lines that contain requirements, the only options that have an effect
102     are from SUPPORTED_OPTIONS_REQ, and they are scoped to the
103     requirement. Other options from SUPPORTED_OPTIONS may be present, but are
104     ignored.
105 
106     For lines that do not contain requirements, the only options that have an
107     effect are from SUPPORTED_OPTIONS. Options from SUPPORTED_OPTIONS_REQ may
108     be present, but are ignored. These lines may contain multiple options
109     (although our docs imply only one is supported), and all our parsed and
110     affect the finder.
111 
112     :param constraint: If True, parsing a constraints file.
113     """
114     parser = build_parser()
115     defaults = parser.get_default_values()
116     defaults.index_url = None
117     if finder:
118         # `finder.format_control` will be updated during parsing
119         defaults.format_control = finder.format_control
120     args_str, options_str = break_args_options(line)
121     opts, _ = parser.parse_args(shlex.split(options_str), defaults)
122 
123     # preserve for the nested code path
124     line_comes_from = '%s %s (line %s)' % (
125         '-c' if constraint else '-r', filename, line_number)
126 
127     # yield a line requirement
128     if args_str:
129         isolated = options.isolated_mode if options else False
130         if options:
131             cmdoptions.check_install_build_global(options, opts)
132         # get the options that apply to requirements
133         req_options = {}
134         for dest in SUPPORTED_OPTIONS_REQ_DEST:
135             if dest in opts.__dict__ and opts.__dict__[dest]:
136                 req_options[dest] = opts.__dict__[dest]
137         yield InstallRequirement.from_line(
138             args_str, line_comes_from, constraint=constraint,
139             isolated=isolated, options=req_options, wheel_cache=wheel_cache
140         )
141 
142     # yield an editable requirement
143     elif opts.editables:
144         isolated = options.isolated_mode if options else False
145         default_vcs = options.default_vcs if options else None
146         yield InstallRequirement.from_editable(
147             opts.editables[0], comes_from=line_comes_from,
148             constraint=constraint, default_vcs=default_vcs, isolated=isolated,
149             wheel_cache=wheel_cache
150         )
151 
152     # parse a nested requirements file
153     elif opts.requirements or opts.constraints:
154         if opts.requirements:
155             req_path = opts.requirements[0]
156             nested_constraint = False
157         else:
158             req_path = opts.constraints[0]
159             nested_constraint = True
160         # original file is over http
161         if SCHEME_RE.search(filename):
162             # do a url join so relative paths work
163             req_path = urllib_parse.urljoin(filename, req_path)
164         # original file and nested file are paths
165         elif not SCHEME_RE.search(req_path):
166             # do a join so relative paths work
167             req_dir = os.path.dirname(filename)
168             req_path = os.path.join(os.path.dirname(filename), req_path)
169         # TODO: Why not use `comes_from='-r {} (line {})'` here as well?
170         parser = parse_requirements(
171             req_path, finder, comes_from, options, session,
172             constraint=nested_constraint, wheel_cache=wheel_cache
173         )
174         for req in parser:
175             yield req
176 
177     # set finder options
178     elif finder:
179         if opts.allow_external:
180             warnings.warn(
181                 "--allow-external has been deprecated and will be removed in "
182                 "the future. Due to changes in the repository protocol, it no "
183                 "longer has any effect.",
184                 RemovedInPip10Warning,
185             )
186 
187         if opts.allow_all_external:
188             warnings.warn(
189                 "--allow-all-external has been deprecated and will be removed "
190                 "in the future. Due to changes in the repository protocol, it "
191                 "no longer has any effect.",
192                 RemovedInPip10Warning,
193             )
194 
195         if opts.allow_unverified:
196             warnings.warn(
197                 "--allow-unverified has been deprecated and will be removed "
198                 "in the future. Due to changes in the repository protocol, it "
199                 "no longer has any effect.",
200                 RemovedInPip10Warning,
201             )
202 
203         if opts.index_url:
204             finder.index_urls = [opts.index_url]
205         if opts.use_wheel is False:
206             finder.use_wheel = False
207             pip.index.fmt_ctl_no_use_wheel(finder.format_control)
208         if opts.no_index is True:
209             finder.index_urls = []
210         if opts.extra_index_urls:
211             finder.index_urls.extend(opts.extra_index_urls)
212         if opts.find_links:
213             # FIXME: it would be nice to keep track of the source
214             # of the find_links: support a find-links local path
215             # relative to a requirements file.
216             value = opts.find_links[0]
217             req_dir = os.path.dirname(os.path.abspath(filename))
218             relative_to_reqs_file = os.path.join(req_dir, value)
219             if os.path.exists(relative_to_reqs_file):
220                 value = relative_to_reqs_file
221             finder.find_links.append(value)
222         if opts.trusted_hosts:
223             finder.secure_origins.extend(
224                 ("*", host, "*") for host in opts.trusted_hosts)
225 
226 
227 def break_args_options(line):
228     """Break up the line into an args and options string.  We only want to shlex
229     (and then optparse) the options, not the args.  args can contain markers
230     which are corrupted by shlex.
231     """
232     tokens = line.split(' ')
233     args = []
234     options = tokens[:]
235     for token in tokens:
236         if token.startswith('-') or token.startswith('--'):
237             break
238         else:
239             args.append(token)
240             options.pop(0)
241     return ' '.join(args), ' '.join(options)
242 
243 
244 def build_parser():
245     """
246     Return a parser for parsing requirement lines
247     """
248     parser = optparse.OptionParser(add_help_option=False)
249 
250     option_factories = SUPPORTED_OPTIONS + SUPPORTED_OPTIONS_REQ
251     for option_factory in option_factories:
252         option = option_factory()
253         parser.add_option(option)
254 
255     # By default optparse sys.exits on parsing errors. We want to wrap
256     # that in our own exception.
257     def parser_exit(self, msg):
258         raise RequirementsFileParseError(msg)
259     parser.exit = parser_exit
260 
261     return parser
262 
263 
264 def join_lines(iterator):
265     """
266     Joins a line ending in '\' with the previous line.
267     """
268     lines = []
269     for line in iterator:
270         if not line.endswith('\\'):
271             if lines:
272                 lines.append(line)
273                 yield ''.join(lines)
274                 lines = []
275             else:
276                 yield line
277         else:
278             lines.append(line.strip('\\'))
279 
280     # TODO: handle space after '\'.
281     # TODO: handle '\' on last line.
282 
283 
284 def ignore_comments(iterator):
285     """
286     Strips and filters empty or commented lines.
287     """
288     for line in iterator:
289         line = COMMENT_RE.sub('', line)
290         line = line.strip()
291         if line:
292             yield line
293 
294 
295 def skip_regex(lines, options):
296     """
297     Optionally exclude lines that match '--skip-requirements-regex'
298     """
299     skip_regex = options.skip_requirements_regex if options else None
300     if skip_regex:
301         lines = filterfalse(re.compile(skip_regex).search, lines)
302     return lines
303
```
--- 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/pip/req/req_file.py b/pip/req/req_file.py
--- a/pip/req/req_file.py
+++ b/pip/req/req_file.py
@@ -43,6 +43,7 @@
     cmdoptions.always_unzip,
     cmdoptions.no_binary,
     cmdoptions.only_binary,
+    cmdoptions.process_dependency_links,
     cmdoptions.trusted_host,
 ]
 
@@ -219,6 +220,8 @@
             if os.path.exists(relative_to_reqs_file):
                 value = relative_to_reqs_file
             finder.find_links.append(value)
+        if opts.process_dependency_links:
+            finder.process_dependency_links = True
         if opts.trusted_hosts:
             finder.secure_origins.extend(
                 ("*", host, "*") for host in opts.trusted_hosts)

{"golden_diff": "diff --git a/pip/req/req_file.py b/pip/req/req_file.py\n--- a/pip/req/req_file.py\n+++ b/pip/req/req_file.py\n@@ -43,6 +43,7 @@\n     cmdoptions.always_unzip,\n     cmdoptions.no_binary,\n     cmdoptions.only_binary,\n+    cmdoptions.process_dependency_links,\n     cmdoptions.trusted_host,\n ]\n \n@@ -219,6 +220,8 @@\n             if os.path.exists(relative_to_reqs_file):\n                 value = relative_to_reqs_file\n             finder.find_links.append(value)\n+        if opts.process_dependency_links:\n+            finder.process_dependency_links = True\n         if opts.trusted_hosts:\n             finder.secure_origins.extend(\n                 (\"*\", host, \"*\") for host in opts.trusted_hosts)\n", "issue": "--process-dependency-links not recognized in requirements.txt\n\n", "before_files": [{"content": "\"\"\"\nRequirements file parsing\n\"\"\"\n\nfrom __future__ import absolute_import\n\nimport os\nimport re\nimport shlex\nimport optparse\nimport warnings\n\nfrom pip._vendor.six.moves.urllib import parse as urllib_parse\nfrom pip._vendor.six.moves import filterfalse\n\nimport pip\nfrom pip.download import get_file_content\nfrom pip.req.req_install import InstallRequirement\nfrom pip.exceptions import (RequirementsFileParseError)\nfrom pip.utils.deprecation import RemovedInPip10Warning\nfrom pip import cmdoptions\n\n__all__ = ['parse_requirements']\n\nSCHEME_RE = re.compile(r'^(http|https|file):', re.I)\nCOMMENT_RE = re.compile(r'(^|\\s)+#.*$')\n\nSUPPORTED_OPTIONS = [\n    cmdoptions.constraints,\n    cmdoptions.editable,\n    cmdoptions.requirements,\n    cmdoptions.no_index,\n    cmdoptions.index_url,\n    cmdoptions.find_links,\n    cmdoptions.extra_index_url,\n    cmdoptions.allow_external,\n    cmdoptions.allow_all_external,\n    cmdoptions.no_allow_external,\n    cmdoptions.allow_unsafe,\n    cmdoptions.no_allow_unsafe,\n    cmdoptions.use_wheel,\n    cmdoptions.no_use_wheel,\n    cmdoptions.always_unzip,\n    cmdoptions.no_binary,\n    cmdoptions.only_binary,\n    cmdoptions.trusted_host,\n]\n\n# options to be passed to requirements\nSUPPORTED_OPTIONS_REQ = [\n    cmdoptions.install_options,\n    cmdoptions.global_options\n]\n\n# the 'dest' string values\nSUPPORTED_OPTIONS_REQ_DEST = [o().dest for o in SUPPORTED_OPTIONS_REQ]\n\n\ndef parse_requirements(filename, finder=None, comes_from=None, options=None,\n                       session=None, constraint=False, wheel_cache=None):\n    \"\"\"Parse a requirements file and yield InstallRequirement instances.\n\n    :param filename:    Path or url of requirements file.\n    :param finder:      Instance of pip.index.PackageFinder.\n    :param comes_from:  Origin description of requirements.\n    :param options:     Global options.\n    :param session:     Instance of pip.download.PipSession.\n    :param constraint:  If true, parsing a constraint file rather than\n        requirements file.\n    :param wheel_cache: Instance of pip.wheel.WheelCache\n    \"\"\"\n    if session is None:\n        raise TypeError(\n            \"parse_requirements() missing 1 required keyword argument: \"\n            \"'session'\"\n        )\n\n    _, content = get_file_content(\n        filename, comes_from=comes_from, session=session\n    )\n\n    lines = content.splitlines()\n    lines = ignore_comments(lines)\n    lines = join_lines(lines)\n    lines = skip_regex(lines, options)\n\n    for line_number, line in enumerate(lines, 1):\n        req_iter = process_line(line, filename, line_number, finder,\n                                comes_from, options, session, wheel_cache,\n                                constraint=constraint)\n        for req in req_iter:\n            yield req\n\n\ndef process_line(line, filename, line_number, finder=None, comes_from=None,\n                 options=None, session=None, wheel_cache=None,\n                 constraint=False):\n    \"\"\"Process a single requirements line; This can result in creating/yielding\n    requirements, or updating the finder.\n\n    For lines that contain requirements, the only options that have an effect\n    are from SUPPORTED_OPTIONS_REQ, and they are scoped to the\n    requirement. Other options from SUPPORTED_OPTIONS may be present, but are\n    ignored.\n\n    For lines that do not contain requirements, the only options that have an\n    effect are from SUPPORTED_OPTIONS. Options from SUPPORTED_OPTIONS_REQ may\n    be present, but are ignored. These lines may contain multiple options\n    (although our docs imply only one is supported), and all our parsed and\n    affect the finder.\n\n    :param constraint: If True, parsing a constraints file.\n    \"\"\"\n    parser = build_parser()\n    defaults = parser.get_default_values()\n    defaults.index_url = None\n    if finder:\n        # `finder.format_control` will be updated during parsing\n        defaults.format_control = finder.format_control\n    args_str, options_str = break_args_options(line)\n    opts, _ = parser.parse_args(shlex.split(options_str), defaults)\n\n    # preserve for the nested code path\n    line_comes_from = '%s %s (line %s)' % (\n        '-c' if constraint else '-r', filename, line_number)\n\n    # yield a line requirement\n    if args_str:\n        isolated = options.isolated_mode if options else False\n        if options:\n            cmdoptions.check_install_build_global(options, opts)\n        # get the options that apply to requirements\n        req_options = {}\n        for dest in SUPPORTED_OPTIONS_REQ_DEST:\n            if dest in opts.__dict__ and opts.__dict__[dest]:\n                req_options[dest] = opts.__dict__[dest]\n        yield InstallRequirement.from_line(\n            args_str, line_comes_from, constraint=constraint,\n            isolated=isolated, options=req_options, wheel_cache=wheel_cache\n        )\n\n    # yield an editable requirement\n    elif opts.editables:\n        isolated = options.isolated_mode if options else False\n        default_vcs = options.default_vcs if options else None\n        yield InstallRequirement.from_editable(\n            opts.editables[0], comes_from=line_comes_from,\n            constraint=constraint, default_vcs=default_vcs, isolated=isolated,\n            wheel_cache=wheel_cache\n        )\n\n    # parse a nested requirements file\n    elif opts.requirements or opts.constraints:\n        if opts.requirements:\n            req_path = opts.requirements[0]\n            nested_constraint = False\n        else:\n            req_path = opts.constraints[0]\n            nested_constraint = True\n        # original file is over http\n        if SCHEME_RE.search(filename):\n            # do a url join so relative paths work\n            req_path = urllib_parse.urljoin(filename, req_path)\n        # original file and nested file are paths\n        elif not SCHEME_RE.search(req_path):\n            # do a join so relative paths work\n            req_dir = os.path.dirname(filename)\n            req_path = os.path.join(os.path.dirname(filename), req_path)\n        # TODO: Why not use `comes_from='-r {} (line {})'` here as well?\n        parser = parse_requirements(\n            req_path, finder, comes_from, options, session,\n            constraint=nested_constraint, wheel_cache=wheel_cache\n        )\n        for req in parser:\n            yield req\n\n    # set finder options\n    elif finder:\n        if opts.allow_external:\n            warnings.warn(\n                \"--allow-external has been deprecated and will be removed in \"\n                \"the future. Due to changes in the repository protocol, it no \"\n                \"longer has any effect.\",\n                RemovedInPip10Warning,\n            )\n\n        if opts.allow_all_external:\n            warnings.warn(\n                \"--allow-all-external has been deprecated and will be removed \"\n                \"in the future. Due to changes in the repository protocol, it \"\n                \"no longer has any effect.\",\n                RemovedInPip10Warning,\n            )\n\n        if opts.allow_unverified:\n            warnings.warn(\n                \"--allow-unverified has been deprecated and will be removed \"\n                \"in the future. Due to changes in the repository protocol, it \"\n                \"no longer has any effect.\",\n                RemovedInPip10Warning,\n            )\n\n        if opts.index_url:\n            finder.index_urls = [opts.index_url]\n        if opts.use_wheel is False:\n            finder.use_wheel = False\n            pip.index.fmt_ctl_no_use_wheel(finder.format_control)\n        if opts.no_index is True:\n            finder.index_urls = []\n        if opts.extra_index_urls:\n            finder.index_urls.extend(opts.extra_index_urls)\n        if opts.find_links:\n            # FIXME: it would be nice to keep track of the source\n            # of the find_links: support a find-links local path\n            # relative to a requirements file.\n            value = opts.find_links[0]\n            req_dir = os.path.dirname(os.path.abspath(filename))\n            relative_to_reqs_file = os.path.join(req_dir, value)\n            if os.path.exists(relative_to_reqs_file):\n                value = relative_to_reqs_file\n            finder.find_links.append(value)\n        if opts.trusted_hosts:\n            finder.secure_origins.extend(\n                (\"*\", host, \"*\") for host in opts.trusted_hosts)\n\n\ndef break_args_options(line):\n    \"\"\"Break up the line into an args and options string.  We only want to shlex\n    (and then optparse) the options, not the args.  args can contain markers\n    which are corrupted by shlex.\n    \"\"\"\n    tokens = line.split(' ')\n    args = []\n    options = tokens[:]\n    for token in tokens:\n        if token.startswith('-') or token.startswith('--'):\n            break\n        else:\n            args.append(token)\n            options.pop(0)\n    return ' '.join(args), ' '.join(options)\n\n\ndef build_parser():\n    \"\"\"\n    Return a parser for parsing requirement lines\n    \"\"\"\n    parser = optparse.OptionParser(add_help_option=False)\n\n    option_factories = SUPPORTED_OPTIONS + SUPPORTED_OPTIONS_REQ\n    for option_factory in option_factories:\n        option = option_factory()\n        parser.add_option(option)\n\n    # By default optparse sys.exits on parsing errors. We want to wrap\n    # that in our own exception.\n    def parser_exit(self, msg):\n        raise RequirementsFileParseError(msg)\n    parser.exit = parser_exit\n\n    return parser\n\n\ndef join_lines(iterator):\n    \"\"\"\n    Joins a line ending in '\\' with the previous line.\n    \"\"\"\n    lines = []\n    for line in iterator:\n        if not line.endswith('\\\\'):\n            if lines:\n                lines.append(line)\n                yield ''.join(lines)\n                lines = []\n            else:\n                yield line\n        else:\n            lines.append(line.strip('\\\\'))\n\n    # TODO: handle space after '\\'.\n    # TODO: handle '\\' on last line.\n\n\ndef ignore_comments(iterator):\n    \"\"\"\n    Strips and filters empty or commented lines.\n    \"\"\"\n    for line in iterator:\n        line = COMMENT_RE.sub('', line)\n        line = line.strip()\n        if line:\n            yield line\n\n\ndef skip_regex(lines, options):\n    \"\"\"\n    Optionally exclude lines that match '--skip-requirements-regex'\n    \"\"\"\n    skip_regex = options.skip_requirements_regex if options else None\n    if skip_regex:\n        lines = filterfalse(re.compile(skip_regex).search, lines)\n    return lines\n", "path": "pip/req/req_file.py"}], "after_files": [{"content": "\"\"\"\nRequirements file parsing\n\"\"\"\n\nfrom __future__ import absolute_import\n\nimport os\nimport re\nimport shlex\nimport optparse\nimport warnings\n\nfrom pip._vendor.six.moves.urllib import parse as urllib_parse\nfrom pip._vendor.six.moves import filterfalse\n\nimport pip\nfrom pip.download import get_file_content\nfrom pip.req.req_install import InstallRequirement\nfrom pip.exceptions import (RequirementsFileParseError)\nfrom pip.utils.deprecation import RemovedInPip10Warning\nfrom pip import cmdoptions\n\n__all__ = ['parse_requirements']\n\nSCHEME_RE = re.compile(r'^(http|https|file):', re.I)\nCOMMENT_RE = re.compile(r'(^|\\s)+#.*$')\n\nSUPPORTED_OPTIONS = [\n    cmdoptions.constraints,\n    cmdoptions.editable,\n    cmdoptions.requirements,\n    cmdoptions.no_index,\n    cmdoptions.index_url,\n    cmdoptions.find_links,\n    cmdoptions.extra_index_url,\n    cmdoptions.allow_external,\n    cmdoptions.allow_all_external,\n    cmdoptions.no_allow_external,\n    cmdoptions.allow_unsafe,\n    cmdoptions.no_allow_unsafe,\n    cmdoptions.use_wheel,\n    cmdoptions.no_use_wheel,\n    cmdoptions.always_unzip,\n    cmdoptions.no_binary,\n    cmdoptions.only_binary,\n    cmdoptions.process_dependency_links,\n    cmdoptions.trusted_host,\n]\n\n# options to be passed to requirements\nSUPPORTED_OPTIONS_REQ = [\n    cmdoptions.install_options,\n    cmdoptions.global_options\n]\n\n# the 'dest' string values\nSUPPORTED_OPTIONS_REQ_DEST = [o().dest for o in SUPPORTED_OPTIONS_REQ]\n\n\ndef parse_requirements(filename, finder=None, comes_from=None, options=None,\n                       session=None, constraint=False, wheel_cache=None):\n    \"\"\"Parse a requirements file and yield InstallRequirement instances.\n\n    :param filename:    Path or url of requirements file.\n    :param finder:      Instance of pip.index.PackageFinder.\n    :param comes_from:  Origin description of requirements.\n    :param options:     Global options.\n    :param session:     Instance of pip.download.PipSession.\n    :param constraint:  If true, parsing a constraint file rather than\n        requirements file.\n    :param wheel_cache: Instance of pip.wheel.WheelCache\n    \"\"\"\n    if session is None:\n        raise TypeError(\n            \"parse_requirements() missing 1 required keyword argument: \"\n            \"'session'\"\n        )\n\n    _, content = get_file_content(\n        filename, comes_from=comes_from, session=session\n    )\n\n    lines = content.splitlines()\n    lines = ignore_comments(lines)\n    lines = join_lines(lines)\n    lines = skip_regex(lines, options)\n\n    for line_number, line in enumerate(lines, 1):\n        req_iter = process_line(line, filename, line_number, finder,\n                                comes_from, options, session, wheel_cache,\n                                constraint=constraint)\n        for req in req_iter:\n            yield req\n\n\ndef process_line(line, filename, line_number, finder=None, comes_from=None,\n                 options=None, session=None, wheel_cache=None,\n                 constraint=False):\n    \"\"\"Process a single requirements line; This can result in creating/yielding\n    requirements, or updating the finder.\n\n    For lines that contain requirements, the only options that have an effect\n    are from SUPPORTED_OPTIONS_REQ, and they are scoped to the\n    requirement. Other options from SUPPORTED_OPTIONS may be present, but are\n    ignored.\n\n    For lines that do not contain requirements, the only options that have an\n    effect are from SUPPORTED_OPTIONS. Options from SUPPORTED_OPTIONS_REQ may\n    be present, but are ignored. These lines may contain multiple options\n    (although our docs imply only one is supported), and all our parsed and\n    affect the finder.\n\n    :param constraint: If True, parsing a constraints file.\n    \"\"\"\n    parser = build_parser()\n    defaults = parser.get_default_values()\n    defaults.index_url = None\n    if finder:\n        # `finder.format_control` will be updated during parsing\n        defaults.format_control = finder.format_control\n    args_str, options_str = break_args_options(line)\n    opts, _ = parser.parse_args(shlex.split(options_str), defaults)\n\n    # preserve for the nested code path\n    line_comes_from = '%s %s (line %s)' % (\n        '-c' if constraint else '-r', filename, line_number)\n\n    # yield a line requirement\n    if args_str:\n        isolated = options.isolated_mode if options else False\n        if options:\n            cmdoptions.check_install_build_global(options, opts)\n        # get the options that apply to requirements\n        req_options = {}\n        for dest in SUPPORTED_OPTIONS_REQ_DEST:\n            if dest in opts.__dict__ and opts.__dict__[dest]:\n                req_options[dest] = opts.__dict__[dest]\n        yield InstallRequirement.from_line(\n            args_str, line_comes_from, constraint=constraint,\n            isolated=isolated, options=req_options, wheel_cache=wheel_cache\n        )\n\n    # yield an editable requirement\n    elif opts.editables:\n        isolated = options.isolated_mode if options else False\n        default_vcs = options.default_vcs if options else None\n        yield InstallRequirement.from_editable(\n            opts.editables[0], comes_from=line_comes_from,\n            constraint=constraint, default_vcs=default_vcs, isolated=isolated,\n            wheel_cache=wheel_cache\n        )\n\n    # parse a nested requirements file\n    elif opts.requirements or opts.constraints:\n        if opts.requirements:\n            req_path = opts.requirements[0]\n            nested_constraint = False\n        else:\n            req_path = opts.constraints[0]\n            nested_constraint = True\n        # original file is over http\n        if SCHEME_RE.search(filename):\n            # do a url join so relative paths work\n            req_path = urllib_parse.urljoin(filename, req_path)\n        # original file and nested file are paths\n        elif not SCHEME_RE.search(req_path):\n            # do a join so relative paths work\n            req_dir = os.path.dirname(filename)\n            req_path = os.path.join(os.path.dirname(filename), req_path)\n        # TODO: Why not use `comes_from='-r {} (line {})'` here as well?\n        parser = parse_requirements(\n            req_path, finder, comes_from, options, session,\n            constraint=nested_constraint, wheel_cache=wheel_cache\n        )\n        for req in parser:\n            yield req\n\n    # set finder options\n    elif finder:\n        if opts.allow_external:\n            warnings.warn(\n                \"--allow-external has been deprecated and will be removed in \"\n                \"the future. Due to changes in the repository protocol, it no \"\n                \"longer has any effect.\",\n                RemovedInPip10Warning,\n            )\n\n        if opts.allow_all_external:\n            warnings.warn(\n                \"--allow-all-external has been deprecated and will be removed \"\n                \"in the future. Due to changes in the repository protocol, it \"\n                \"no longer has any effect.\",\n                RemovedInPip10Warning,\n            )\n\n        if opts.allow_unverified:\n            warnings.warn(\n                \"--allow-unverified has been deprecated and will be removed \"\n                \"in the future. Due to changes in the repository protocol, it \"\n                \"no longer has any effect.\",\n                RemovedInPip10Warning,\n            )\n\n        if opts.index_url:\n            finder.index_urls = [opts.index_url]\n        if opts.use_wheel is False:\n            finder.use_wheel = False\n            pip.index.fmt_ctl_no_use_wheel(finder.format_control)\n        if opts.no_index is True:\n            finder.index_urls = []\n        if opts.extra_index_urls:\n            finder.index_urls.extend(opts.extra_index_urls)\n        if opts.find_links:\n            # FIXME: it would be nice to keep track of the source\n            # of the find_links: support a find-links local path\n            # relative to a requirements file.\n            value = opts.find_links[0]\n            req_dir = os.path.dirname(os.path.abspath(filename))\n            relative_to_reqs_file = os.path.join(req_dir, value)\n            if os.path.exists(relative_to_reqs_file):\n                value = relative_to_reqs_file\n            finder.find_links.append(value)\n        if opts.process_dependency_links:\n            finder.process_dependency_links = True\n        if opts.trusted_hosts:\n            finder.secure_origins.extend(\n                (\"*\", host, \"*\") for host in opts.trusted_hosts)\n\n\ndef break_args_options(line):\n    \"\"\"Break up the line into an args and options string.  We only want to shlex\n    (and then optparse) the options, not the args.  args can contain markers\n    which are corrupted by shlex.\n    \"\"\"\n    tokens = line.split(' ')\n    args = []\n    options = tokens[:]\n    for token in tokens:\n        if token.startswith('-') or token.startswith('--'):\n            break\n        else:\n            args.append(token)\n            options.pop(0)\n    return ' '.join(args), ' '.join(options)\n\n\ndef build_parser():\n    \"\"\"\n    Return a parser for parsing requirement lines\n    \"\"\"\n    parser = optparse.OptionParser(add_help_option=False)\n\n    option_factories = SUPPORTED_OPTIONS + SUPPORTED_OPTIONS_REQ\n    for option_factory in option_factories:\n        option = option_factory()\n        parser.add_option(option)\n\n    # By default optparse sys.exits on parsing errors. We want to wrap\n    # that in our own exception.\n    def parser_exit(self, msg):\n        raise RequirementsFileParseError(msg)\n    parser.exit = parser_exit\n\n    return parser\n\n\ndef join_lines(iterator):\n    \"\"\"\n    Joins a line ending in '\\' with the previous line.\n    \"\"\"\n    lines = []\n    for line in iterator:\n        if not line.endswith('\\\\'):\n            if lines:\n                lines.append(line)\n                yield ''.join(lines)\n                lines = []\n            else:\n                yield line\n        else:\n            lines.append(line.strip('\\\\'))\n\n    # TODO: handle space after '\\'.\n    # TODO: handle '\\' on last line.\n\n\ndef ignore_comments(iterator):\n    \"\"\"\n    Strips and filters empty or commented lines.\n    \"\"\"\n    for line in iterator:\n        line = COMMENT_RE.sub('', line)\n        line = line.strip()\n        if line:\n            yield line\n\n\ndef skip_regex(lines, options):\n    \"\"\"\n    Optionally exclude lines that match '--skip-requirements-regex'\n    \"\"\"\n    skip_regex = options.skip_requirements_regex if options else None\n    if skip_regex:\n        lines = filterfalse(re.compile(skip_regex).search, lines)\n    return lines\n", "path": "pip/req/req_file.py"}]}