-
-
Notifications
You must be signed in to change notification settings - Fork 34.2k
Expand file tree
/
Copy pathargparse.py
More file actions
2907 lines (2427 loc) · 109 KB
/
argparse.py
File metadata and controls
2907 lines (2427 loc) · 109 KB
Edit and raw actions
OlderNewer
1
# Author: Steven J. Bethard <steven.bethard@gmail.com>.
2
# New maintainer as of 29 August 2019: Raymond Hettinger <raymond.hettinger@gmail.com>
3
4
"""Command-line parsing library
5
6
This module is an optparse-inspired command-line parsing library that:
7
8
- handles both optional and positional arguments
9
- produces highly informative usage messages
10
- supports parsers that dispatch to sub-parsers
11
12
The following is a simple usage example that sums integers from the
13
command-line and writes the result to a file::
14
15
parser = argparse.ArgumentParser(
16
description='sum the integers at the command line')
17
parser.add_argument(
18
'integers', metavar='int', nargs='+', type=int,
19
help='an integer to be summed')
20
parser.add_argument(
21
'--log',
22
help='the file where the sum should be written')
23
args = parser.parse_args()
24
with (open(args.log, 'w') if args.log is not None
25
else contextlib.nullcontext(sys.stdout)) as log:
26
log.write('%s' % sum(args.integers))
27
28
The module contains the following public classes:
29
30
- ArgumentParser -- The main entry point for command-line parsing. As the
31
example above shows, the add_argument() method is used to populate
32
the parser with actions for optional and positional arguments. Then
33
the parse_args() method is invoked to convert the args at the
34
command-line into an object with attributes.
35
36
- ArgumentError -- The exception raised by ArgumentParser objects when
37
there are errors with the parser's actions. Errors raised while
38
parsing the command-line are caught by ArgumentParser and emitted
39
as command-line messages.
40
41
- FileType -- A factory for defining types of files to be created. As the
42
example above shows, instances of FileType are typically passed as
43
the type= argument of add_argument() calls. Deprecated since
44
Python 3.14.
45
46
- Action -- The base class for parser actions. Typically actions are
47
selected by passing strings like 'store_true' or 'append_const' to
48
the action= argument of add_argument(). However, for greater
49
customization of ArgumentParser actions, subclasses of Action may
50
be defined and passed as the action= argument.
51
52
- HelpFormatter, RawDescriptionHelpFormatter, RawTextHelpFormatter,
53
ArgumentDefaultsHelpFormatter -- Formatter classes which
54
may be passed as the formatter_class= argument to the
55
ArgumentParser constructor. HelpFormatter is the default,
56
RawDescriptionHelpFormatter and RawTextHelpFormatter tell the parser
57
not to change the formatting for help text, and
58
ArgumentDefaultsHelpFormatter adds information about argument defaults
59
to the help.
60
61
All other classes in this module are considered implementation details.
62
(Also note that HelpFormatter and RawDescriptionHelpFormatter are only
63
considered public as object names -- the API of the formatter objects is
64
still considered an implementation detail.)
65
"""
66
67
__all__ = [
68
'ArgumentParser',
69
'ArgumentError',
70
'ArgumentTypeError',
71
'BooleanOptionalAction',
72
'FileType',
73
'HelpFormatter',
74
'ArgumentDefaultsHelpFormatter',
75
'RawDescriptionHelpFormatter',
76
'RawTextHelpFormatter',
77
'MetavarTypeHelpFormatter',
78
'Namespace',
79
'Action',
80
'ONE_OR_MORE',
81
'OPTIONAL',
82
'PARSER',
83
'REMAINDER',
84
'SUPPRESS',
85
'ZERO_OR_MORE',
86
]
87
88
89
import os as _os
90
import re as _re
91
import sys as _sys
92
from gettext import gettext as _
93
from gettext import ngettext
94
95
SUPPRESS = '==SUPPRESS=='
96
97
OPTIONAL = '?'
98
ZERO_OR_MORE = '*'
99
ONE_OR_MORE = '+'
100
PARSER = 'A...'
101
REMAINDER = '...'
102
_UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args'
103
104
# =============================
105
# Utility functions and classes
106
# =============================
107
108
class _AttributeHolder(object):
109
"""Abstract base class that provides __repr__.
110
111
The __repr__ method returns a string in the format::
112
ClassName(attr=name, attr=name, ...)
113
The attributes are determined either by a class-level attribute,
114
'_kwarg_names', or by inspecting the instance __dict__.
115
"""
116
117
def __repr__(self):
118
type_name = type(self).__name__
119
arg_strings = []
120
star_args = {}
121
for arg in self._get_args():
122
arg_strings.append(repr(arg))
123
for name, value in self._get_kwargs():
124
if name.isidentifier():
125
arg_strings.append('%s=%r' % (name, value))
126
else:
127
star_args[name] = value
128
if star_args:
129
arg_strings.append('**%s' % repr(star_args))
130
return '%s(%s)' % (type_name, ', '.join(arg_strings))
131
132
def _get_kwargs(self):
133
return list(self.__dict__.items())
134
135
def _get_args(self):
136
return []
137
138
139
def _copy_items(items):
140
if items is None:
141
return []
142
# The copy module is used only in the 'append' and 'append_const'
143
# actions, and it is needed only when the default value isn't a list.
144
# Delay its import for speeding up the common case.
145
if type(items) is list:
146
return items[:]
147
import copy
148
return copy.copy(items)
149
150
151
def _identity(value):
152
return value
153
154
155
# ===============
156
# Formatting Help
157
# ===============
158
159
160
class HelpFormatter(object):
161
"""Formatter for generating usage messages and argument help strings.
162
163
Only the name of this class is considered a public API. All the methods
164
provided by the class are considered an implementation detail.
165
"""
166
167
def __init__(
168
self,
169
prog,
170
indent_increment=2,
171
max_help_position=24,
172
width=None,
173
):
174
# default setting for width
175
if width is None:
176
import shutil
177
width = shutil.get_terminal_size().columns
178
width -= 2
179
180
self._prog = prog
181
self._indent_increment = indent_increment
182
self._max_help_position = min(max_help_position,
183
max(width - 20, indent_increment * 2))
184
self._width = width
185
186
self._current_indent = 0
187
self._level = 0
188
self._action_max_length = 0
189
190
self._root_section = self._Section(self, None)
191
self._current_section = self._root_section
192
193
self._whitespace_matcher = _re.compile(r'\s+', _re.ASCII)
194
self._long_break_matcher = _re.compile(r'\n\n\n+')
195
196
self._set_color(False)
197
198
def _set_color(self, color, *, file=None):
199
from _colorize import can_colorize, decolor, get_theme
200
201
if color and can_colorize(file=file):
202
self._theme = get_theme(force_color=True).argparse
203
self._decolor = decolor
204
else:
205
self._theme = get_theme(force_no_color=True).argparse
206
self._decolor = _identity
207
208
# ===============================
209
# Section and indentation methods
210
# ===============================
211
212
def _indent(self):
213
self._current_indent += self._indent_increment
214
self._level += 1
215
216
def _dedent(self):
217
self._current_indent -= self._indent_increment
218
assert self._current_indent >= 0, 'Indent decreased below 0.'
219
self._level -= 1
220
221
class _Section(object):
222
223
def __init__(self, formatter, parent, heading=None):
224
self.formatter = formatter
225
self.parent = parent
226
self.heading = heading
227
self.items = []
228
229
def format_help(self):
230
# format the indented section
231
if self.parent is not None:
232
self.formatter._indent()
233
join = self.formatter._join_parts
234
item_help = join([func(*args) for func, args in self.items])
235
if self.parent is not None:
236
self.formatter._dedent()
237
238
# return nothing if the section was empty
239
if not item_help:
240
return ''
241
242
# add the heading if the section was non-empty
243
if self.heading is not SUPPRESS and self.heading is not None:
244
current_indent = self.formatter._current_indent
245
heading_text = _('%(heading)s:') % dict(heading=self.heading)
246
t = self.formatter._theme
247
heading = (
248
f'{" " * current_indent}'
249
f'{t.heading}{heading_text}{t.reset}\n'
250
)
251
else:
252
heading = ''
253
254
# join the section-initial newline, the heading and the help
255
return join(['\n', heading, item_help, '\n'])
256
257
def _add_item(self, func, args):
258
self._current_section.items.append((func, args))
259
260
# ========================
261
# Message building methods
262
# ========================
263
264
def start_section(self, heading):
265
self._indent()
266
section = self._Section(self, self._current_section, heading)
267
self._add_item(section.format_help, [])
268
self._current_section = section
269
270
def end_section(self):
271
self._current_section = self._current_section.parent
272
self._dedent()
273
274
def add_text(self, text):
275
if text is not SUPPRESS and text is not None:
276
self._add_item(self._format_text, [text])
277
278
def add_usage(self, usage, actions, groups, prefix=None):
279
if usage is not SUPPRESS:
280
args = usage, actions, groups, prefix
281
self._add_item(self._format_usage, args)
282
283
def add_argument(self, action):
284
if action.help is not SUPPRESS:
285
286
# find all invocations
287
get_invocation = lambda x: self._decolor(self._format_action_invocation(x))
288
invocation_lengths = [len(get_invocation(action)) + self._current_indent]
289
for subaction in self._iter_indented_subactions(action):
290
invocation_lengths.append(len(get_invocation(subaction)) + self._current_indent)
291
292
# update the maximum item length
293
action_length = max(invocation_lengths)
294
self._action_max_length = max(self._action_max_length,
295
action_length)
296
297
# add the item to the list
298
self._add_item(self._format_action, [action])
299
300
def add_arguments(self, actions):
301
for action in actions:
302
self.add_argument(action)
303
304
# =======================
305
# Help-formatting methods
306
# =======================
307
308
def format_help(self):
309
help = self._root_section.format_help()
310
if help:
311
help = self._long_break_matcher.sub('\n\n', help)
312
help = help.strip('\n') + '\n'
313
return help
314
315
def _join_parts(self, part_strings):
316
return ''.join([part
317
for part in part_strings
318
if part and part is not SUPPRESS])
319
320
def _format_usage(self, usage, actions, groups, prefix):
321
t = self._theme
322
323
if prefix is None:
324
prefix = _('usage: ')
325
326
# if usage is specified, use that
327
if usage is not None:
328
usage = (
329
t.prog_extra
330
+ usage
331
% {"prog": f"{t.prog}{self._prog}{t.reset}{t.prog_extra}"}
332
+ t.reset
333
)
334
335
# if no optionals or positionals are available, usage is just prog
336
elif usage is None and not actions:
337
usage = f"{t.prog}{self._prog}{t.reset}"
338
339
# if optionals and positionals are available, calculate usage
340
elif usage is None:
341
prog = '%(prog)s' % dict(prog=self._prog)
342
343
parts, pos_start = self._get_actions_usage_parts(actions, groups)
344
# build full usage string
345
usage = ' '.join(filter(None, [prog, *parts]))
346
347
# wrap the usage parts if it's too long
348
text_width = self._width - self._current_indent
349
if len(prefix) + len(self._decolor(usage)) > text_width:
350
351
# break usage into wrappable parts
352
opt_parts = parts[:pos_start]
353
pos_parts = parts[pos_start:]
354
355
# helper for wrapping lines
356
def get_lines(parts, indent, prefix=None):
357
lines = []
358
line = []
359
indent_length = len(indent)
360
if prefix is not None:
361
line_len = len(prefix) - 1
362
else:
363
line_len = indent_length - 1
364
for part in parts:
365
part_len = len(self._decolor(part))
366
if line_len + 1 + part_len > text_width and line:
367
lines.append(indent + ' '.join(line))
368
line = []
369
line_len = indent_length - 1
370
line.append(part)
371
line_len += part_len + 1
372
if line:
373
lines.append(indent + ' '.join(line))
374
if prefix is not None:
375
lines[0] = lines[0][indent_length:]
376
return lines
377
378
# if prog is short, follow it with optionals or positionals
379
prog_len = len(self._decolor(prog))
380
if len(prefix) + prog_len <= 0.75 * text_width:
381
indent = ' ' * (len(prefix) + prog_len + 1)
382
if opt_parts:
383
lines = get_lines([prog] + opt_parts, indent, prefix)
384
lines.extend(get_lines(pos_parts, indent))
385
elif pos_parts:
386
lines = get_lines([prog] + pos_parts, indent, prefix)
387
else:
388
lines = [prog]
389
390
# if prog is long, put it on its own line
391
else:
392
indent = ' ' * len(prefix)
393
parts = opt_parts + pos_parts
394
lines = get_lines(parts, indent)
395
if len(lines) > 1:
396
lines = []
397
lines.extend(get_lines(opt_parts, indent))
398
lines.extend(get_lines(pos_parts, indent))
399
lines = [prog] + lines
400
401
# join lines into usage
402
usage = '\n'.join(lines)
403
404
usage = usage.removeprefix(prog)
405
usage = f"{t.prog}{prog}{t.reset}{usage}"
406
407
# prefix with 'usage:'
408
return f'{t.usage}{prefix}{t.reset}{usage}\n\n'
409
410
def _is_long_option(self, string):
411
return len(string) > 2
412
413
def _get_actions_usage_parts(self, actions, groups):
414
"""Get usage parts with split index for optionals/positionals.
415
416
Returns (parts, pos_start) where pos_start is the index in parts
417
where positionals begin.
418
This preserves mutually exclusive group formatting across the
419
optionals/positionals boundary (gh-75949).
420
"""
421
actions = [action for action in actions if action.help is not SUPPRESS]
422
# group actions by mutually exclusive groups
423
action_groups = dict.fromkeys(actions)
424
for group in groups:
425
for action in group._group_actions:
426
if action in action_groups:
427
action_groups[action] = group
428
# positional arguments keep their position
429
positionals = []
430
for action in actions:
431
if not action.option_strings:
432
group = action_groups.pop(action)
433
if group:
434
group_actions = [
435
action2 for action2 in group._group_actions
436
if action2.option_strings and
437
action_groups.pop(action2, None)
438
] + [action]
439
positionals.append((group.required, group_actions))
440
else:
441
positionals.append((None, [action]))
442
# the remaining optional arguments are sorted by the position of
443
# the first option in the group
444
optionals = []
445
for action in actions:
446
if action.option_strings and action in action_groups:
447
group = action_groups.pop(action)
448
if group:
449
group_actions = [action] + [
450
action2 for action2 in group._group_actions
451
if action2.option_strings and
452
action_groups.pop(action2, None)
453
]
454
optionals.append((group.required, group_actions))
455
else:
456
optionals.append((None, [action]))
457
458
# collect all actions format strings
459
parts = []
460
t = self._theme
461
pos_start = None
462
for i, (required, group) in enumerate(optionals + positionals):
463
start = len(parts)
464
if i == len(optionals):
465
pos_start = start
466
in_group = len(group) > 1
467
for action in group:
468
# produce all arg strings
469
if not action.option_strings:
470
default = self._get_default_metavar_for_positional(action)
471
part = self._format_args(action, default)
472
# if it's in a group, strip the outer []
473
if in_group:
474
if part[0] == '[' and part[-1] == ']':
475
part = part[1:-1]
476
part = t.summary_action + part + t.reset
477
478
# produce the first way to invoke the option in brackets
479
else:
480
option_string = action.option_strings[0]
481
if self._is_long_option(option_string):
482
option_color = t.summary_long_option
483
else:
484
option_color = t.summary_short_option
485
486
# if the Optional doesn't take a value, format is:
487
# -s or --long
488
if action.nargs == 0:
489
part = action.format_usage()
490
part = f"{option_color}{part}{t.reset}"
491
492
# if the Optional takes a value, format is:
493
# -s ARGS or --long ARGS
494
else:
495
default = self._get_default_metavar_for_optional(action)
496
args_string = self._format_args(action, default)
497
part = (
498
f"{option_color}{option_string} "
499
f"{t.summary_label}{args_string}{t.reset}"
500
)
501
502
# make it look optional if it's not required or in a group
503
if not (action.required or required or in_group):
504
part = '[%s]' % part
505
506
# add the action string to the list
507
parts.append(part)
508
509
if in_group:
510
parts[start] = ('(' if required else '[') + parts[start]
511
for i in range(start, len(parts) - 1):
512
parts[i] += ' |'
513
parts[-1] += ')' if required else ']'
514
515
if pos_start is None:
516
pos_start = len(parts)
517
return parts, pos_start
518
519
def _format_text(self, text):
520
if '%(prog)' in text:
521
text = text % dict(prog=self._prog)
522
text_width = max(self._width - self._current_indent, 11)
523
indent = ' ' * self._current_indent
524
text = self._fill_text(text, text_width, indent)
525
text = self._apply_text_markup(text)
526
return text + '\n\n'
527
528
def _apply_text_markup(self, text):
529
"""Apply color markup to text.
530
531
Supported markup:
532
`...` - inline code (rendered with prog_extra color)
533
534
When colors are disabled, backticks are preserved as-is.
535
"""
536
t = self._theme
537
if not t.reset:
538
return text
539
text = _re.sub(
540
r'`([^`]+)`',
541
rf'{t.prog_extra}\1{t.reset}',
542
text,
543
)
544
return text
545
546
def _format_action(self, action):
547
# determine the required width and the entry label
548
help_position = min(self._action_max_length + 2,
549
self._max_help_position)
550
help_width = max(self._width - help_position, 11)
551
action_width = help_position - self._current_indent - 2
552
action_header = self._format_action_invocation(action)
553
action_header_no_color = self._decolor(action_header)
554
555
# no help; start on same line and add a final newline
556
if not action.help:
557
tup = self._current_indent, '', action_header
558
action_header = '%*s%s\n' % tup
559
560
# short action name; start on the same line and pad two spaces
561
elif len(action_header_no_color) <= action_width:
562
# calculate widths without color codes
563
action_header_color = action_header
564
tup = self._current_indent, '', action_width, action_header_no_color
565
action_header = '%*s%-*s ' % tup
566
# swap in the colored header
567
action_header = action_header.replace(
568
action_header_no_color, action_header_color
569
)
570
indent_first = 0
571
572
# long action name; start on the next line
573
else:
574
tup = self._current_indent, '', action_header
575
action_header = '%*s%s\n' % tup
576
indent_first = help_position
577
578
# collect the pieces of the action help
579
parts = [action_header]
580
581
# if there was help for the action, add lines of help text
582
if action.help and action.help.strip():
583
help_text = self._expand_help(action)
584
if help_text:
585
help_lines = self._split_lines(help_text, help_width)
586
parts.append('%*s%s\n' % (indent_first, '', help_lines[0]))
587
for line in help_lines[1:]:
588
parts.append('%*s%s\n' % (help_position, '', line))
589
590
# or add a newline if the description doesn't end with one
591
elif not action_header.endswith('\n'):
592
parts.append('\n')
593
594
# if there are any sub-actions, add their help as well
595
for subaction in self._iter_indented_subactions(action):
596
parts.append(self._format_action(subaction))
597
598
# return a single string
599
return self._join_parts(parts)
600
601
def _format_action_invocation(self, action):
602
t = self._theme
603
604
if not action.option_strings:
605
default = self._get_default_metavar_for_positional(action)
606
return (
607
t.action
608
+ ' '.join(self._metavar_formatter(action, default)(1))
609
+ t.reset
610
)
611
612
else:
613
614
def color_option_strings(strings):
615
parts = []
616
for s in strings:
617
if self._is_long_option(s):
618
parts.append(f"{t.long_option}{s}{t.reset}")
619
else:
620
parts.append(f"{t.short_option}{s}{t.reset}")
621
return parts
622
623
# if the Optional doesn't take a value, format is:
624
# -s, --long
625
if action.nargs == 0:
626
option_strings = color_option_strings(action.option_strings)
627
return ', '.join(option_strings)
628
629
# if the Optional takes a value, format is:
630
# -s, --long ARGS
631
else:
632
default = self._get_default_metavar_for_optional(action)
633
option_strings = color_option_strings(action.option_strings)
634
args_string = (
635
f"{t.label}{self._format_args(action, default)}{t.reset}"
636
)
637
return ', '.join(option_strings) + ' ' + args_string
638
639
def _metavar_formatter(self, action, default_metavar):
640
if action.metavar is not None:
641
result = action.metavar
642
elif action.choices is not None:
643
result = '{%s}' % ','.join(map(str, action.choices))
644
else:
645
result = default_metavar
646
647
def format(tuple_size):
648
if isinstance(result, tuple):
649
return result
650
else:
651
return (result, ) * tuple_size
652
return format
653
654
def _format_args(self, action, default_metavar):
655
get_metavar = self._metavar_formatter(action, default_metavar)
656
if action.nargs is None:
657
result = '%s' % get_metavar(1)
658
elif action.nargs == OPTIONAL:
659
result = '[%s]' % get_metavar(1)
660
elif action.nargs == ZERO_OR_MORE:
661
metavar = get_metavar(1)
662
if len(metavar) == 2:
663
result = '[%s [%s ...]]' % metavar
664
else:
665
result = '[%s ...]' % metavar
666
elif action.nargs == ONE_OR_MORE:
667
result = '%s [%s ...]' % get_metavar(2)
668
elif action.nargs == REMAINDER:
669
result = '...'
670
elif action.nargs == PARSER:
671
result = '%s ...' % get_metavar(1)
672
elif action.nargs == SUPPRESS:
673
result = ''
674
else:
675
try:
676
formats = ['%s' for _ in range(action.nargs)]
677
except TypeError:
678
raise ValueError("invalid nargs value") from None
679
result = ' '.join(formats) % get_metavar(action.nargs)
680
return result
681
682
def _expand_help(self, action):
683
help_string = self._get_help_string(action)
684
if '%' not in help_string:
685
return help_string
686
params = dict(vars(action), prog=self._prog)
687
for name in list(params):
688
value = params[name]
689
if value is SUPPRESS:
690
del params[name]
691
elif hasattr(value, '__name__'):
692
params[name] = value.__name__
693
if params.get('choices') is not None:
694
params['choices'] = ', '.join(map(str, params['choices']))
695
696
t = self._theme
697
698
result = help_string % params
699
700
if not t.reset:
701
return result
702
703
# Match format specifiers like: %s, %d, %(key)s, etc.
704
fmt_spec = r'''
705
%
706
(?:
707
% # %% escape
708
|
709
(?:\((?P<key>[^)]*)\))? # key
710
[-#0\ +]* # flags
711
(?:\*|\d+)? # width
712
(?:\.(?:\*|\d+))? # precision
713
[hlL]? # length modifier
714
[diouxXeEfFgGcrsa] # conversion type
715
)
716
'''
717
718
def colorize(match):
719
spec, key = match.group(0, 'key')
720
if spec == '%%':
721
return '%'
722
if key is not None:
723
# %(key)... - format and colorize
724
formatted = spec % {key: params[key]}
725
return f'{t.interpolated_value}{formatted}{t.reset}'
726
# bare %s etc. - format with full params dict, no colorization
727
return spec % params
728
729
return _re.sub(fmt_spec, colorize, help_string, flags=_re.VERBOSE)
730
731
def _iter_indented_subactions(self, action):
732
try:
733
get_subactions = action._get_subactions
734
except AttributeError:
735
pass
736
else:
737
self._indent()
738
yield from get_subactions()
739
self._dedent()
740
741
def _split_lines(self, text, width):
742
text = self._whitespace_matcher.sub(' ', text).strip()
743
# The textwrap module is used only for formatting help.
744
# Delay its import for speeding up the common usage of argparse.
745
import textwrap
746
return textwrap.wrap(text, width)
747
748
def _fill_text(self, text, width, indent):
749
text = self._whitespace_matcher.sub(' ', text).strip()
750
import textwrap
751
return textwrap.fill(text, width,
752
initial_indent=indent,
753
subsequent_indent=indent)
754
755
def _get_help_string(self, action):
756
return action.help
757
758
def _get_default_metavar_for_optional(self, action):
759
return action.dest.upper()
760
761
def _get_default_metavar_for_positional(self, action):
762
return action.dest
763
764
765
class RawDescriptionHelpFormatter(HelpFormatter):
766
"""Help message formatter which retains any formatting in descriptions.
767
768
Only the name of this class is considered a public API. All the methods
769
provided by the class are considered an implementation detail.
770
"""
771
772
def _fill_text(self, text, width, indent):
773
return ''.join(indent + line for line in text.splitlines(keepends=True))
774
775
776
class RawTextHelpFormatter(RawDescriptionHelpFormatter):
777
"""Help message formatter which retains formatting of all help text.
778
779
Only the name of this class is considered a public API. All the methods
780
provided by the class are considered an implementation detail.
781
"""
782
783
def _split_lines(self, text, width):
784
return text.splitlines()
785
786
787
class ArgumentDefaultsHelpFormatter(HelpFormatter):
788
"""Help message formatter which adds default values to argument help.
789
790
Only the name of this class is considered a public API. All the methods
791
provided by the class are considered an implementation detail.
792
"""
793
794
def _get_help_string(self, action):
795
help = action.help
796
if help is None:
797
help = ''
798
799
if (
800
'%(default)' not in help
801
and action.default is not SUPPRESS
802
and not action.required
803
):
804
defaulting_nargs = (OPTIONAL, ZERO_OR_MORE)
805
if action.option_strings or action.nargs in defaulting_nargs:
806
t = self._theme
807
default_str = _(" (default: %(default)s)")
808
prefix, suffix = default_str.split("%(default)s")
809
help += (
810
f" {t.default}{prefix.lstrip()}{t.reset}"
811
f"%(default)s"
812
f"{t.default}{suffix}{t.reset}"
813
)
814
return help
815
816
817
818
class MetavarTypeHelpFormatter(HelpFormatter):
819
"""Help message formatter which uses the argument 'type' as the default
820
metavar value (instead of the argument 'dest')
821
822
Only the name of this class is considered a public API. All the methods
823
provided by the class are considered an implementation detail.
824
"""
825
826
def _get_default_metavar_for_optional(self, action):
827
return action.type.__name__
828
829
def _get_default_metavar_for_positional(self, action):
830
return action.type.__name__
831
832
833
# =====================
834
# Options and Arguments
835
# =====================
836
837
def _get_action_name(argument):
838
if argument is None:
839
return None
840
elif argument.option_strings:
841
return '/'.join(argument.option_strings)
842
elif argument.metavar not in (None, SUPPRESS):
843
metavar = argument.metavar
844
if not isinstance(metavar, tuple):
845
return metavar
846
if argument.nargs == ZERO_OR_MORE and len(metavar) == 2:
847
return '%s[, %s]' % metavar
848
elif argument.nargs == ONE_OR_MORE:
849
return '%s[, %s]' % metavar
850
else:
851
return ', '.join(metavar)
852
elif argument.dest not in (None, SUPPRESS):
853
return argument.dest
854
elif argument.choices:
855
return '{%s}' % ','.join(map(str, argument.choices))
856
else:
857
return None
858
859
860
class ArgumentError(Exception):
861
"""An error from creating or using an argument (optional or positional).
862
863
The string value of this exception is the message, augmented with
864
information about the argument that caused it.
865
"""
866
867
def __init__(self, argument, message):
868
self.argument_name = _get_action_name(argument)
869
self.message = message
870
871
def __str__(self):
872
if self.argument_name is None:
873
format = '%(message)s'
874
else:
875
format = _('argument %(argument_name)s: %(message)s')
876
return format % dict(message=self.message,
877
argument_name=self.argument_name)
878
879
880
class ArgumentTypeError(Exception):
881
"""An error from trying to convert a command line string to a type."""
882
pass
883
884
885
# ==============
886
# Action classes
887
# ==============
888
889
class Action(_AttributeHolder):
890
"""Information about how to convert command line strings to Python objects.
891
892
Action objects are used by an ArgumentParser to represent the information
893
needed to parse a single argument from one or more strings from the
894
command line. The keyword arguments to the Action constructor are also
895
all attributes of Action instances.
896
897
Keyword Arguments:
898
899
- option_strings -- A list of command-line option strings which
900
should be associated with this action.
901
902
- dest -- The name of the attribute to hold the created object(s)
903
904
- nargs -- The number of command-line arguments that should be
905
consumed. By default, one argument will be consumed and a single
906
value will be produced. Other values include:
907
- N (an integer) consumes N arguments (and produces a list)
908
- '?' consumes zero or one arguments
909
- '*' consumes zero or more arguments (and produces a list)
910
- '+' consumes one or more arguments (and produces a list)
911
Note that the difference between the default and nargs=1 is that
912
with the default, a single value will be produced, while with
913
nargs=1, a list containing a single value will be produced.
914
915
- const -- The value to be produced if the option is specified and the
916
option uses an action that takes no values.
917
918
- default -- The value to be produced if the option is not specified.
919
920
- type -- A callable that accepts a single string argument, and
921
returns the converted value. The standard Python types str, int,
922
float, and complex are useful examples of such callables. If None,
923
str is used.
924
925
- choices -- A container of values that should be allowed. If not None,
926
after a command-line argument has been converted to the appropriate
927
type, an exception will be raised if it is not a member of this
928
collection.
929
930
- required -- True if the action must always be specified at the
931
command line. This is only meaningful for optional command-line
932
arguments.
933
934
- help -- The help string describing the argument.
935
936
- metavar -- The name to be used for the option's argument with the
937
help string. If None, the 'dest' value will be used as the name.
938
"""
939
940
def __init__(self,
941
option_strings,
942
dest,
943
nargs=None,
944
const=None,
945
default=None,
946
type=None,
947
choices=None,
948
required=False,
949
help=None,
950
metavar=None,
951
deprecated=False):
952
self.option_strings = option_strings
953
self.dest = dest
954
self.nargs = nargs
955
self.const = const
956
self.default = default
957
self.type = type
958
self.choices = choices
959
self.required = required
960
self.help = help
961
self.metavar = metavar
962
self.deprecated = deprecated
963
964
def _get_kwargs(self):
965
names = [
966
'option_strings',
967
'dest',
968
'nargs',
969
'const',
970
'default',
971
'type',
972
'choices',
973
'required',
974
'help',
975
'metavar',
976
'deprecated',
977
]
978
return [(name, getattr(self, name)) for name in names]
979
980
def format_usage(self):
981
return self.option_strings[0]
982
983
def __call__(self, parser, namespace, values, option_string=None):
984
raise NotImplementedError('.__call__() not defined')
985
986
987
class BooleanOptionalAction(Action):
988
def __init__(self,
989
option_strings,
990
dest,
991
default=None,
992
required=False,
993
help=None,
994
deprecated=False):
995
996
_option_strings = []
997
neg_option_strings = []
998
for option_string in option_strings:
999
_option_strings.append(option_string)
1000