Repository: python/mypy

Issue:
Command line documentation differs from --help
`mypy 0.740`

The order in which the command line options are described is different in `--help` output and in the documentation at https://mypy.readthedocs.io/en/latest/command_line.html, and section names also differ. This inconsistency could be confusing.

Particularly:

- In `Import discovery` section, `--named-packages` option goes first in the documentation, but last in `--help`.
(FIXED)

- `Disallow dynamic typing` section in the documentation is named `Dynamic typing` in `--help`.
(FIXED)

- In `Disallow dynamic typing` section, `--disallow-subclassing-any` option goes last in the documentation, but second in `--help`.
(FIXED)

- `--strict-optional-whitelist` option is not mentioned in the documentation.
(FIXED)

- `Configuring warnings` section in the documentation is named `Warnings` in `--help`.
(FIXED)

- `Miscellaneous strictness flags` section in the documentation is named `Other strictness checks` in `--help`.
(FIXED)

- In `Miscellaneous strictness flags` section, `--strict-equality` option goes after `--no-implicit-reexport` option in the documentation, but before it in `--help`.
(FIXED)

- `Configuring error messages` goes after `Miscellaneous strictness flags` section in the documentation, but after `Mypy internals` in `--help`.
(FIXED)

- `Configuring error messages` in the documentation is named `Error reporting` in `--help`.
(FIXED)

- `--pretty` option is not mentioned in the documentation.
(FIXED)

- `--sqlite-cache`, `--cache-fine-grained`, `--skip-cache-mtime-checks` are not mentioned in the documentation.
(FIXED)

- `Advanced flags` section in the documentation is named `Mypy internals` in `--help`.
(FIXED)

- `--raise-exceptions` option is not mentioned in the documentation.
(FIXED)

- In `Report generation` section the order of options is different in the documentation and in `--help`.
(FIXED)

- `--junit-xml` belongs to section `Report generation` in the documentation, but to section `Miscellaneous` in `--help`.
(FIXED)

- `--lineprecision-report`, `--memory-xml-report`, `--xml-report` options are not mentioned in the documentation.
(FIXED, requires followup after #7775 is resolved)

- In `Miscellaneous` section, `--scripts-are-modules` option goes before `--find-occurrences` in the documentation, but after it in `--help`.
(FIXED)

- `--verbose`, `--version` options are not mentioned in the documentation.
(FIXED)

--custom-typing command line option is named custom_typing_module in config file
mypy v0.740

It seems these two options do the same thing so they probably should be named similarly.

Probably `--custom-typing` should be renamed `--custom-typing-module`.


Discussion:
Although this doesn't look urgent, it would make sense to keep these more in sync.
A PR would be welcome.

It's unclear, which source of information (Command line doc, Config file doc, `--help`) is primary, meaning, is best supported and has the best structure according to the authors.

If one source is updated to reflect the most complete and well structured information, reflecting this information and structure in two other sources would be rather easy.
I would start by making command line docs and config file docs match up better, and then make --help follow the command line docs.

Note there are some necessary differences between command line and config file that need to remain separate, since only the config file supports per-module options; only the command line has --strict (and maybe there are other differences).

@Michael0x2a 
By the way I would suggest removing the separation of options to "Per-module and global" and "Global only" options in the config file doc. Per my opinion this separation makes the document worse:

- It makes options that are similar in their function, to be documented in different places.

- It makes harder updating and synchronizing information on config file and command line options, and harder to find answers on questions like "I know how to do it via command line option, can I do it via a config file?".

- It's hard for me to imagine a person who first thinks about "Do I need it globally or per-module?" and THEN thinks "What exactly do I need"? I think in most cases the person thinks the other way around.

So it seems better to group the config file options in a way similar to the structure of Command line doc, and add notes to the particular options, like "This option can only be configured globally".
Yes. I proposed that in the past but we never acted on it.


Resolving patch:
diff --git a/mypy/main.py b/mypy/main.py
--- a/mypy/main.py
+++ b/mypy/main.py
@@ -348,6 +348,10 @@ def add_invertible_flag(flag: str,
     imports_group = parser.add_argument_group(
         title='Import discovery',
         description="Configure how imports are discovered and followed.")
+    add_invertible_flag(
+        '--namespace-packages', default=False,
+        help="Support namespace packages (PEP 420, __init__.py-less)",
+        group=imports_group)
     imports_group.add_argument(
         '--ignore-missing-imports', action='store_true',
         help="Silently ignore imports of missing modules")
@@ -366,10 +370,6 @@ def add_invertible_flag(flag: str,
     imports_group.add_argument(
         '--no-silence-site-packages', action='store_true',
         help="Do not silence errors in PEP 561 compliant installed packages")
-    add_invertible_flag(
-        '--namespace-packages', default=False,
-        help="Support namespace packages (PEP 420, __init__.py-less)",
-        group=imports_group)
 
     platform_group = parser.add_argument_group(
         title='Platform configuration',
@@ -397,14 +397,11 @@ def add_invertible_flag(flag: str,
         help="Additional variable to be considered False (may be repeated)")
 
     disallow_any_group = parser.add_argument_group(
-        title='Dynamic typing',
+        title='Disallow dynamic typing',
         description="Disallow the use of the dynamic 'Any' type under certain conditions.")
     disallow_any_group.add_argument(
         '--disallow-any-unimported', default=False, action='store_true',
         help="Disallow Any types resulting from unfollowed imports")
-    add_invertible_flag('--disallow-subclassing-any', default=False, strict_flag=True,
-                        help="Disallow subclassing values of type 'Any' when defining classes",
-                        group=disallow_any_group)
     disallow_any_group.add_argument(
         '--disallow-any-expr', default=False, action='store_true',
         help='Disallow all expressions that have type Any')
@@ -418,6 +415,9 @@ def add_invertible_flag(flag: str,
     add_invertible_flag('--disallow-any-generics', default=False, strict_flag=True,
                         help='Disallow usage of generic types that do not specify explicit type '
                         'parameters', group=disallow_any_group)
+    add_invertible_flag('--disallow-subclassing-any', default=False, strict_flag=True,
+                        help="Disallow subclassing values of type 'Any' when defining classes",
+                        group=disallow_any_group)
 
     untyped_group = parser.add_argument_group(
         title='Untyped definitions and calls',
@@ -459,12 +459,10 @@ def add_invertible_flag(flag: str,
         help="Disable strict Optional checks (inverse: --strict-optional)")
     none_group.add_argument(
         '--strict-optional-whitelist', metavar='GLOB', nargs='*',
-        help="Suppress strict Optional errors in all but the provided files; "
-             "implies --strict-optional (may suppress certain other errors "
-             "in non-whitelisted files)")
+        help=argparse.SUPPRESS)
 
     lint_group = parser.add_argument_group(
-        title='Warnings',
+        title='Configuring warnings',
         description="Detect code that is sound but redundant or problematic.")
     add_invertible_flag('--warn-redundant-casts', default=False, strict_flag=True,
                         help="Warn about casting an expression to its inferred type",
@@ -492,7 +490,7 @@ def add_invertible_flag(flag: str,
     # We add `--strict` near the end so we don't accidentally miss any strictness
     # flags that are added after this group.
     strictness_group = parser.add_argument_group(
-        title='Other strictness checks')
+        title='Miscellaneous strictness flags')
 
     add_invertible_flag('--allow-untyped-globals', default=False, strict_flag=False,
                         help="Suppress toplevel errors caused by missing annotations",
@@ -502,15 +500,49 @@ def add_invertible_flag(flag: str,
                         help="Allow unconditional variable redefinition with a new type",
                         group=strictness_group)
 
+    add_invertible_flag('--no-implicit-reexport', default=True, strict_flag=True,
+                        dest='implicit_reexport',
+                        help="Treat imports as private unless aliased",
+                        group=strictness_group)
+
     add_invertible_flag('--strict-equality', default=False, strict_flag=False,
                         help="Prohibit equality, identity, and container checks for"
                              " non-overlapping types",
                         group=strictness_group)
 
-    add_invertible_flag('--no-implicit-reexport', default=True, strict_flag=True,
-                        dest='implicit_reexport',
-                        help="Treat imports as private unless aliased",
-                        group=strictness_group)
+    strict_help = "Strict mode; enables the following flags: {}".format(
+        ", ".join(strict_flag_names))
+    strictness_group.add_argument(
+        '--strict', action='store_true', dest='special-opts:strict',
+        help=strict_help)
+
+    error_group = parser.add_argument_group(
+        title='Configuring error messages',
+        description="Adjust the amount of detail shown in error messages.")
+    add_invertible_flag('--show-error-context', default=False,
+                        dest='show_error_context',
+                        help='Precede errors with "note:" messages explaining context',
+                        group=error_group)
+    add_invertible_flag('--show-column-numbers', default=False,
+                        help="Show column numbers in error messages",
+                        group=error_group)
+    add_invertible_flag('--show-error-codes', default=False,
+                        help="Show error codes in error messages",
+                        group=error_group)
+    add_invertible_flag('--pretty', default=False,
+                        help="Use visually nicer output in error messages:"
+                             " Use soft word wrap, show source code snippets,"
+                             " and show error location markers",
+                        group=error_group)
+    add_invertible_flag('--no-color-output', dest='color_output', default=True,
+                        help="Do not colorize error messages",
+                        group=error_group)
+    add_invertible_flag('--no-error-summary', dest='error_summary', default=True,
+                        help="Do not show error stats summary",
+                        group=error_group)
+    add_invertible_flag('--show-absolute-path', default=False,
+                        help="Show absolute paths to files",
+                        group=error_group)
 
     incremental_group = parser.add_argument_group(
         title='Incremental mode',
@@ -543,7 +575,7 @@ def add_invertible_flag(flag: str,
         help="Skip cache internal consistency checks based on mtime")
 
     internals_group = parser.add_argument_group(
-        title='Mypy internals',
+        title='Advanced options',
         description="Debug and customize mypy internals.")
     internals_group.add_argument(
         '--pdb', action='store_true', help="Invoke pdb on fatal error")
@@ -554,7 +586,7 @@ def add_invertible_flag(flag: str,
         '--raise-exceptions', action='store_true', help="Raise exception on fatal error"
     )
     internals_group.add_argument(
-        '--custom-typing', metavar='MODULE', dest='custom_typing_module',
+        '--custom-typing-module', metavar='MODULE', dest='custom_typing_module',
         help="Use a custom typing module")
     internals_group.add_argument(
         '--custom-typeshed-dir', metavar='DIR',
@@ -571,47 +603,14 @@ def add_invertible_flag(flag: str,
     add_invertible_flag('--fast-exit', default=False, help=argparse.SUPPRESS,
                         group=internals_group)
 
-    error_group = parser.add_argument_group(
-        title='Error reporting',
-        description="Adjust the amount of detail shown in error messages.")
-    add_invertible_flag('--show-error-context', default=False,
-                        dest='show_error_context',
-                        help='Precede errors with "note:" messages explaining context',
-                        group=error_group)
-    add_invertible_flag('--show-column-numbers', default=False,
-                        help="Show column numbers in error messages",
-                        group=error_group)
-    add_invertible_flag('--show-error-codes', default=False,
-                        help="Show error codes in error messages",
-                        group=error_group)
-    add_invertible_flag('--pretty', default=False,
-                        help="Use visually nicer output in error messages:"
-                             " Use soft word wrap, show source code snippets,"
-                             " and error location markers",
-                        group=error_group)
-    add_invertible_flag('--no-color-output', dest='color_output', default=True,
-                        help="Do not colorize error messages",
-                        group=error_group)
-    add_invertible_flag('--no-error-summary', dest='error_summary', default=True,
-                        help="Do not show error stats summary",
-                        group=error_group)
-    add_invertible_flag('--show-absolute-path', default=False,
-                        help="Show absolute paths to files",
-                        group=error_group)
-
-    strict_help = "Strict mode; enables the following flags: {}".format(
-        ", ".join(strict_flag_names))
-    strictness_group.add_argument(
-        '--strict', action='store_true', dest='special-opts:strict',
-        help=strict_help)
-
     report_group = parser.add_argument_group(
         title='Report generation',
         description='Generate a report in the specified format.')
     for report_type in sorted(defaults.REPORTER_NAMES):
-        report_group.add_argument('--%s-report' % report_type.replace('_', '-'),
-                                  metavar='DIR',
-                                  dest='special-opts:%s_report' % report_type)
+        if report_type not in {'memory-xml'}:
+            report_group.add_argument('--%s-report' % report_type.replace('_', '-'),
+                                      metavar='DIR',
+                                      dest='special-opts:%s_report' % report_type)
 
     other_group = parser.add_argument_group(
         title='Miscellaneous')
@@ -619,13 +618,13 @@ def add_invertible_flag(flag: str,
         '--quickstart-file', help=argparse.SUPPRESS)
     other_group.add_argument(
         '--junit-xml', help="Write junit.xml to the given file")
-    other_group.add_argument(
-        '--scripts-are-modules', action='store_true',
-        help="Script x becomes module x instead of __main__")
     other_group.add_argument(
         '--find-occurrences', metavar='CLASS.MEMBER',
         dest='special-opts:find_occurrences',
         help="Print out all usages of a class member (experimental)")
+    other_group.add_argument(
+        '--scripts-are-modules', action='store_true',
+        help="Script x becomes module x instead of __main__")
 
     if server_options:
         # TODO: This flag is superfluous; remove after a short transition (2018-03-16)


Test patch: