Repository: pypa/pip

Issue:
Extract supported requirement file options automatically
**What's the problem this feature will solve?**

Currently the documentation for what options are possible in requirements files are hand-maintained in the docs, but actually enforced in the code. Maintaining the list in both places is error-prone.

**Describe the solution you'd like**

Automatically extract the supported options from the lists of options in `pip._internal.req.req_file` [here](https://github.com/pypa/pip/blob/a1b0b9274f9a738b53d4ca530b4ec49c7d756815/src/pip/_internal/req/req_file.py#L60-L81).

The approach should be similar to what we do for command option help [here](https://github.com/pypa/pip/blob/9ae2e6440d9fc98e91acec0a324b410fabc5452a/docs/pip_sphinxext.py). We should also make sure to clearly separate the general options, which must be on their own line in a requirements file, from the requirement-specific options, which must be on the same line as a requirement.

**Alternative Solutions**

* Continue to manually maintain the lists in both places

**Additional context**

* From [#7386 (comment)](https://github.com/pypa/pip/pull/7386#pullrequestreview-319434477)


Discussion:

Resolving patch:
diff --git a/docs/pip_sphinxext.py b/docs/pip_sphinxext.py
--- a/docs/pip_sphinxext.py
+++ b/docs/pip_sphinxext.py
@@ -9,7 +9,8 @@
 from docutils.statemachine import ViewList
 
 from pip._internal.cli import cmdoptions
-from pip._internal.commands import create_command
+from pip._internal.commands import commands_dict, create_command
+from pip._internal.req.req_file import SUPPORTED_OPTIONS
 
 
 class PipCommandUsage(rst.Directive):
@@ -108,9 +109,50 @@ def process_options(self):
         )
 
 
+class PipReqFileOptionsReference(PipOptions):
+
+    def determine_opt_prefix(self, opt_name):
+        for command in commands_dict:
+            cmd = create_command(command)
+            if cmd.cmd_opts.has_option(opt_name):
+                return command
+
+        raise KeyError('Could not identify prefix of opt {}'.format(opt_name))
+
+    def process_options(self):
+        for option in SUPPORTED_OPTIONS:
+            if getattr(option, 'deprecated', False):
+                continue
+
+            opt = option()
+            opt_name = opt._long_opts[0]
+            if opt._short_opts:
+                short_opt_name = '{}, '.format(opt._short_opts[0])
+            else:
+                short_opt_name = ''
+
+            if option in cmdoptions.general_group['options']:
+                prefix = ''
+            else:
+                prefix = '{}_'.format(self.determine_opt_prefix(opt_name))
+
+            self.view_list.append(
+                '  *  :ref:`{short}{long}<{prefix}{opt_name}>`'.format(
+                    short=short_opt_name,
+                    long=opt_name,
+                    prefix=prefix,
+                    opt_name=opt_name
+                ),
+                "\n"
+            )
+
+
 def setup(app):
     app.add_directive('pip-command-usage', PipCommandUsage)
     app.add_directive('pip-command-description', PipCommandDescription)
     app.add_directive('pip-command-options', PipCommandOptions)
     app.add_directive('pip-general-options', PipGeneralOptions)
     app.add_directive('pip-index-options', PipIndexOptions)
+    app.add_directive(
+        'pip-requirements-file-options-ref-list', PipReqFileOptionsReference
+    )
diff --git a/src/pip/_internal/cli/cmdoptions.py b/src/pip/_internal/cli/cmdoptions.py
--- a/src/pip/_internal/cli/cmdoptions.py
+++ b/src/pip/_internal/cli/cmdoptions.py
@@ -832,6 +832,10 @@ def _handle_no_use_pep517(option, opt, value, parser):
     action='store_true',
     help=SUPPRESS_HELP,
 )  # type: Callable[..., Option]
+# TODO: Move into a class that inherits from partial, currently does not
+# work as mypy complains functools.partial is a generic class.
+# This way we know we can ignore this option in docs auto generation
+setattr(always_unzip, 'deprecated', True)
 
 
 def _handle_merge_hash(option, opt_str, value, parser):


Test patch: