3030 supports_optionals_as_positionals ,
3131)
3232from ._completions import ShtabAction
33+ from ._deprecated import HelpFormatterDeprecations
3334from ._link_arguments import ActionLink
3435from ._namespace import Namespace , NSKeyError
3536from ._optionals import import_ruyaml
@@ -54,7 +55,116 @@ class PercentTemplate(Template):
5455 """ # type: ignore[assignment]
5556
5657
57- class DefaultHelpFormatter (HelpFormatter ):
58+ class YAMLCommentFormatter :
59+ """Formatter class for adding YAML comments to configuration files."""
60+
61+ def __init__ (self , help_formatter : HelpFormatter ):
62+ self .help_formatter = help_formatter
63+
64+ def add_yaml_comments (self , cfg : str ) -> str :
65+ """Adds help text as yaml comments."""
66+ ruyaml = import_ruyaml ("add_yaml_comments" )
67+ yaml = ruyaml .YAML ()
68+ cfg = yaml .load (cfg )
69+
70+ def get_subparsers (parser , prefix = "" ):
71+ subparsers = {}
72+ if parser ._subparsers is not None :
73+ for key , subparser in parser ._subparsers ._group_actions [0 ].choices .items ():
74+ full_key = (prefix + "." if prefix else "" ) + key
75+ subparsers [full_key ] = subparser
76+ subparsers .update (get_subparsers (subparser , prefix = full_key ))
77+ return subparsers
78+
79+ parser = parent_parser .get ()
80+ parsers = get_subparsers (parser )
81+ parsers [None ] = parser
82+
83+ group_titles = {}
84+ for parser_key , parser in parsers .items ():
85+ group_titles [parser_key ] = parser .description
86+ prefix = "" if parser_key is None else parser_key + "."
87+ for group in parser ._action_groups :
88+ actions = filter_default_actions (group ._group_actions )
89+ actions = [
90+ a for a in actions if not isinstance (a , (_ActionConfigLoad , ActionConfigFile , _ActionSubCommands ))
91+ ]
92+ keys = {re .sub (r"\.?[^.]+$" , "" , a .dest ) for a in actions if "." in a .dest }
93+ for key in keys :
94+ group_titles [prefix + key ] = group .title
95+
96+ def set_comments (cfg , prefix = "" , depth = 0 ):
97+ for key in cfg .keys ():
98+ full_key = (prefix + "." if prefix else "" ) + key
99+ action = _find_action (parser , full_key )
100+ text = None
101+ if full_key in group_titles and isinstance (cfg [key ], dict ):
102+ text = group_titles [full_key ]
103+ elif action is not None and action .help not in {None , SUPPRESS }:
104+ text = self .help_formatter ._expand_help (action )
105+ if isinstance (cfg [key ], dict ):
106+ if text :
107+ self .set_yaml_group_comment (text , cfg , key , depth )
108+ set_comments (cfg [key ], full_key , depth + 1 )
109+ elif text :
110+ self .set_yaml_argument_comment (text , cfg , key , depth )
111+
112+ if parser .description is not None :
113+ self .set_yaml_start_comment (parser .description , cfg )
114+ set_comments (cfg )
115+ out = StringIO ()
116+ yaml .dump (cfg , out )
117+ return out .getvalue ()
118+
119+ def set_yaml_start_comment (
120+ self ,
121+ text : str ,
122+ cfg : ruyamlCommentedMap ,
123+ ):
124+ """Sets the start comment to a ruyaml object.
125+
126+ Args:
127+ text: The content to use for the comment.
128+ cfg: The ruyaml object.
129+ """
130+ cfg .yaml_set_start_comment (text )
131+
132+ def set_yaml_group_comment (
133+ self ,
134+ text : str ,
135+ cfg : ruyamlCommentedMap ,
136+ key : str ,
137+ depth : int ,
138+ ):
139+ """Sets the comment for a group to a ruyaml object.
140+
141+ Args:
142+ text: The content to use for the comment.
143+ cfg: The parent ruyaml object.
144+ key: The key of the group.
145+ depth: The nested level of the group.
146+ """
147+ cfg .yaml_set_comment_before_after_key (key , before = "\n " + text , indent = 2 * depth )
148+
149+ def set_yaml_argument_comment (
150+ self ,
151+ text : str ,
152+ cfg : ruyamlCommentedMap ,
153+ key : str ,
154+ depth : int ,
155+ ):
156+ """Sets the comment for an argument to a ruyaml object.
157+
158+ Args:
159+ text: The content to use for the comment.
160+ cfg: The parent ruyaml object.
161+ key: The key of the argument.
162+ depth: The nested level of the argument.
163+ """
164+ cfg .yaml_set_comment_before_after_key (key , before = "\n " + text , indent = 2 * depth )
165+
166+
167+ class DefaultHelpFormatter (HelpFormatterDeprecations , HelpFormatter ):
58168 """Help message formatter that includes types, default values and env var names.
59169
60170 This class is an extension of `argparse.HelpFormatter
@@ -184,108 +294,6 @@ def add_usage(self, usage: Optional[str], actions: Iterable[Action], *args, **kw
184294 actions = [a for a in actions if not isinstance (a , ActionLink )]
185295 super ().add_usage (usage , actions , * args , ** kwargs )
186296
187- def add_yaml_comments (self , cfg : str ) -> str :
188- """Adds help text as yaml comments."""
189- ruyaml = import_ruyaml ("add_yaml_comments" )
190- yaml = ruyaml .YAML ()
191- cfg = yaml .load (cfg )
192-
193- def get_subparsers (parser , prefix = "" ):
194- subparsers = {}
195- if parser ._subparsers is not None :
196- for key , subparser in parser ._subparsers ._group_actions [0 ].choices .items ():
197- full_key = (prefix + "." if prefix else "" ) + key
198- subparsers [full_key ] = subparser
199- subparsers .update (get_subparsers (subparser , prefix = full_key ))
200- return subparsers
201-
202- parser = parent_parser .get ()
203- parsers = get_subparsers (parser )
204- parsers [None ] = parser
205-
206- group_titles = {}
207- for parser_key , parser in parsers .items ():
208- group_titles [parser_key ] = parser .description
209- prefix = "" if parser_key is None else parser_key + "."
210- for group in parser ._action_groups :
211- actions = filter_default_actions (group ._group_actions )
212- actions = [
213- a for a in actions if not isinstance (a , (_ActionConfigLoad , ActionConfigFile , _ActionSubCommands ))
214- ]
215- keys = {re .sub (r"\.?[^.]+$" , "" , a .dest ) for a in actions if "." in a .dest }
216- for key in keys :
217- group_titles [prefix + key ] = group .title
218-
219- def set_comments (cfg , prefix = "" , depth = 0 ):
220- for key in cfg .keys ():
221- full_key = (prefix + "." if prefix else "" ) + key
222- action = _find_action (parser , full_key )
223- text = None
224- if full_key in group_titles and isinstance (cfg [key ], dict ):
225- text = group_titles [full_key ]
226- elif action is not None and action .help not in {None , SUPPRESS }:
227- text = self ._expand_help (action )
228- if isinstance (cfg [key ], dict ):
229- if text :
230- self .set_yaml_group_comment (text , cfg , key , depth )
231- set_comments (cfg [key ], full_key , depth + 1 )
232- elif text :
233- self .set_yaml_argument_comment (text , cfg , key , depth )
234-
235- if parser .description is not None :
236- self .set_yaml_start_comment (parser .description , cfg )
237- set_comments (cfg )
238- out = StringIO ()
239- yaml .dump (cfg , out )
240- return out .getvalue ()
241-
242- def set_yaml_start_comment (
243- self ,
244- text : str ,
245- cfg : ruyamlCommentedMap ,
246- ):
247- """Sets the start comment to a ruyaml object.
248-
249- Args:
250- text: The content to use for the comment.
251- cfg: The ruyaml object.
252- """
253- cfg .yaml_set_start_comment (text )
254-
255- def set_yaml_group_comment (
256- self ,
257- text : str ,
258- cfg : ruyamlCommentedMap ,
259- key : str ,
260- depth : int ,
261- ):
262- """Sets the comment for a group to a ruyaml object.
263-
264- Args:
265- text: The content to use for the comment.
266- cfg: The parent ruyaml object.
267- key: The key of the group.
268- depth: The nested level of the group.
269- """
270- cfg .yaml_set_comment_before_after_key (key , before = "\n " + text , indent = 2 * depth )
271-
272- def set_yaml_argument_comment (
273- self ,
274- text : str ,
275- cfg : ruyamlCommentedMap ,
276- key : str ,
277- depth : int ,
278- ):
279- """Sets the comment for an argument to a ruyaml object.
280-
281- Args:
282- text: The content to use for the comment.
283- cfg: The parent ruyaml object.
284- key: The key of the argument.
285- depth: The nested level of the argument.
286- """
287- cfg .yaml_set_comment_before_after_key (key , before = "\n " + text , indent = 2 * depth )
288-
289297
290298def get_env_var (
291299 parser_or_formatter : Union [ArgumentParser , DefaultHelpFormatter ],
0 commit comments