@@ -372,6 +372,30 @@ def infer_python_executable(options: Options, special_opts: argparse.Namespace)
372372def is_terminal_punctuation (char : str ) -> bool :
373373 return char in ("." , "?" , "!" )
374374
375+ class ArgumentGroup :
376+ """A wrapper for argparse's ArgumentGroup class that lets us enforce capitalization
377+ on the added arguments."""
378+ def __init__ (self , argument_group : argparse ._ArgumentGroup ) -> None :
379+ self .argument_group = argument_group
380+
381+ def add_argument (self , * name_or_flags , help = None , ** kwargs ) -> argparse .Action :
382+ if self .argument_group .title == "Report generation" :
383+ if help and help != argparse .SUPPRESS :
384+ raise ValueError (f"CLI documentation style error: help description for the Report generation flag { name_or_flags } was unexpectedly provided. (Currently, '{ help } '.)"
385+ + " This check is in the code because we assume there's nothing help to say about the report flags."
386+ + " If you're improving that situation, feel free to remove this check."
387+ )
388+ else :
389+ if not help :
390+ raise ValueError (f"CLI documentation style error: flag help description for { name_or_flags } must be provided. (Currently, '{ help } '.)" )
391+ if help [0 ] != help [0 ].upper ():
392+ raise ValueError (f"CLI documentation style error: flag help description for { name_or_flags } must start with a capital letter (or unicameral symbol). (Currently, '{ help } '.)" )
393+ if help [- 1 ] == '.' :
394+ raise ValueError (f"CLI documentation style error: flag help description for { name_or_flags } must NOT end with a period. (Currently, '{ help } '.)" )
395+ return self .argument_group .add_argument (* name_or_flags , help = help , ** kwargs )
396+
397+ def _add_action (self , action ) -> None :
398+ self .argument_group ._add_action (action )
375399class CapturableArgumentParser (argparse .ArgumentParser ):
376400 """Override ArgumentParser methods that use sys.stdout/sys.stderr directly.
377401
@@ -395,17 +419,17 @@ def add_argument_group(
395419 title : str ,
396420 description : str | None = None ,
397421 ** kwargs ,
398- ) -> argparse . _ArgumentGroup :
422+ ) -> ArgumentGroup :
399423 if title not in ["positional arguments" , "options" ]: # These are built-in names, ignore them.
400424 if not title [0 ].isupper ():
401425 raise ValueError (f"CLI documentation style error: Title of group { title } must start with a capital letter. (Currently, '{ title [0 ]} '.)" )
402426 if description and not description [0 ].isupper ():
403427 raise ValueError (f"CLI documentation style error: Description of group { title } must start with a capital letter. (Currently, '{ description [0 ]} '.)" )
404428 if is_terminal_punctuation (title [- 1 ]):
405429 raise ValueError (f"CLI documentation style error: Title of group { title } must NOT end with terminal punction. (Currently, '{ title [- 1 ]} '.)" )
406- if description and not is_terminal_punctuation (title [- 1 ]):
430+ if description and not is_terminal_punctuation (description [- 1 ]):
407431 raise ValueError (f"CLI documentation style error: Description of group { title } must end with terminal punction. (Currently, '{ description [- 1 ]} '.)" )
408- return super ().add_argument_group (title , description , ** kwargs )
432+ return ArgumentGroup ( super ().add_argument_group (title , description , ** kwargs ) )
409433
410434 # =====================
411435 # Help-printing methods
@@ -805,7 +829,7 @@ def add_invertible_flag(
805829 title = "None and Optional handling" ,
806830 description = "Adjust how values of type 'None' are handled. For more context on "
807831 "how mypy handles values of type 'None', see: "
808- "https://mypy.readthedocs.io/en/stable/kinds_of_types.html#no-strict-optional " ,
832+ ". " ,
809833 )
810834 add_invertible_flag (
811835 "--implicit-optional" ,
@@ -1052,7 +1076,7 @@ def add_invertible_flag(
10521076 "Mypy caches type information about modules into a cache to "
10531077 "let you speed up future invocations of mypy. Also see "
10541078 "mypy's daemon mode: "
1055- "mypy.readthedocs.io/en/stable/mypy_daemon.html#mypy-daemon" ,
1079+ "https:// mypy.readthedocs.io/en/stable/mypy_daemon.html#mypy-daemon. " ,
10561080 )
10571081 incremental_group .add_argument (
10581082 "-i" , "--incremental" , action = "store_true" , help = argparse .SUPPRESS
@@ -1157,7 +1181,7 @@ def add_invertible_flag(
11571181 dest = "shadow_file" ,
11581182 action = "append" ,
11591183 help = "When encountering SOURCE_FILE, read and type check "
1160- "the contents of SHADOW_FILE instead. " ,
1184+ "the contents of SHADOW_FILE instead" ,
11611185 )
11621186 internals_group .add_argument ("--fast-exit" , action = "store_true" , help = argparse .SUPPRESS )
11631187 internals_group .add_argument (
@@ -1178,7 +1202,7 @@ def add_invertible_flag(
11781202 if report_type not in {"memory-xml" }:
11791203 report_group .add_argument (
11801204 f"--{ report_type .replace ('_' , '-' )} -report" ,
1181- metavar = "DIR " ,
1205+ metavar = "OUTPUT_DIR " ,
11821206 dest = f"special-opts:{ report_type } _report" ,
11831207 )
11841208
@@ -1294,7 +1318,7 @@ def add_invertible_flag(
12941318 code_group = parser .add_argument_group (
12951319 title = "Running code" ,
12961320 description = "Specify the code you want to type check. For more details, see "
1297- "mypy.readthedocs.io/en/stable/running_mypy.html#running-mypy" ,
1321+ "https:// mypy.readthedocs.io/en/stable/running_mypy.html#running-mypy. " ,
12981322 )
12991323 add_invertible_flag (
13001324 "--explicit-package-bases" ,
0 commit comments