cmd2 2.4.3__py3-none-any.whl → 2.5.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cmd2/__init__.py +2 -6
- cmd2/ansi.py +16 -16
- cmd2/argparse_completer.py +1 -10
- cmd2/argparse_custom.py +27 -81
- cmd2/clipboard.py +3 -22
- cmd2/cmd2.py +652 -358
- cmd2/command_definition.py +43 -8
- cmd2/constants.py +3 -0
- cmd2/decorators.py +135 -128
- cmd2/exceptions.py +0 -1
- cmd2/history.py +52 -23
- cmd2/parsing.py +54 -49
- cmd2/plugin.py +8 -6
- cmd2/py_bridge.py +15 -4
- cmd2/rl_utils.py +57 -23
- cmd2/table_creator.py +1 -0
- cmd2/transcript.py +3 -2
- cmd2/utils.py +56 -24
- {cmd2-2.4.3.dist-info → cmd2-2.5.9.dist-info}/LICENSE +1 -1
- cmd2-2.5.9.dist-info/METADATA +218 -0
- cmd2-2.5.9.dist-info/RECORD +24 -0
- {cmd2-2.4.3.dist-info → cmd2-2.5.9.dist-info}/WHEEL +1 -1
- cmd2-2.4.3.dist-info/METADATA +0 -226
- cmd2-2.4.3.dist-info/RECORD +0 -24
- {cmd2-2.4.3.dist-info → cmd2-2.5.9.dist-info}/top_level.txt +0 -0
cmd2/__init__.py
CHANGED
@@ -5,12 +5,8 @@
|
|
5
5
|
|
6
6
|
import sys
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
import importlib.metadata as importlib_metadata
|
11
|
-
else:
|
12
|
-
# For everyone else
|
13
|
-
import importlib_metadata
|
8
|
+
import importlib.metadata as importlib_metadata
|
9
|
+
|
14
10
|
try:
|
15
11
|
__version__ = importlib_metadata.version(__name__)
|
16
12
|
except importlib_metadata.PackageNotFoundError: # pragma: no cover
|
cmd2/ansi.py
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
"""
|
3
3
|
Support for ANSI escape sequences which are used for things like applying style to text,
|
4
4
|
setting the window title, and asynchronous alerts.
|
5
|
-
|
5
|
+
"""
|
6
|
+
|
6
7
|
import functools
|
7
8
|
import re
|
8
9
|
from enum import (
|
@@ -62,25 +63,25 @@ The default is ``AllowStyle.TERMINAL``.
|
|
62
63
|
"""
|
63
64
|
|
64
65
|
# Regular expression to match ANSI style sequence
|
65
|
-
ANSI_STYLE_RE = re.compile(
|
66
|
+
ANSI_STYLE_RE = re.compile(rf'{ESC}\[[^m]*m')
|
66
67
|
|
67
68
|
# Matches standard foreground colors: CSI(30-37|90-97|39)m
|
68
|
-
STD_FG_RE = re.compile(
|
69
|
+
STD_FG_RE = re.compile(rf'{ESC}\[(?:[39][0-7]|39)m')
|
69
70
|
|
70
71
|
# Matches standard background colors: CSI(40-47|100-107|49)m
|
71
|
-
STD_BG_RE = re.compile(
|
72
|
+
STD_BG_RE = re.compile(rf'{ESC}\[(?:(?:4|10)[0-7]|49)m')
|
72
73
|
|
73
74
|
# Matches eight-bit foreground colors: CSI38;5;(0-255)m
|
74
|
-
EIGHT_BIT_FG_RE = re.compile(
|
75
|
+
EIGHT_BIT_FG_RE = re.compile(rf'{ESC}\[38;5;(?:1?[0-9]?[0-9]?|2[0-4][0-9]|25[0-5])m')
|
75
76
|
|
76
77
|
# Matches eight-bit background colors: CSI48;5;(0-255)m
|
77
|
-
EIGHT_BIT_BG_RE = re.compile(
|
78
|
+
EIGHT_BIT_BG_RE = re.compile(rf'{ESC}\[48;5;(?:1?[0-9]?[0-9]?|2[0-4][0-9]|25[0-5])m')
|
78
79
|
|
79
80
|
# Matches RGB foreground colors: CSI38;2;(0-255);(0-255);(0-255)m
|
80
|
-
RGB_FG_RE = re.compile(
|
81
|
+
RGB_FG_RE = re.compile(rf'{ESC}\[38;2(?:;(?:1?[0-9]?[0-9]?|2[0-4][0-9]|25[0-5])){{3}}m')
|
81
82
|
|
82
83
|
# Matches RGB background colors: CSI48;2;(0-255);(0-255);(0-255)m
|
83
|
-
RGB_BG_RE = re.compile(
|
84
|
+
RGB_BG_RE = re.compile(rf'{ESC}\[48;2(?:;(?:1?[0-9]?[0-9]?|2[0-4][0-9]|25[0-5])){{3}}m')
|
84
85
|
|
85
86
|
|
86
87
|
def strip_style(text: str) -> str:
|
@@ -224,7 +225,6 @@ class BgColor(AnsiSequence):
|
|
224
225
|
####################################################################################
|
225
226
|
# Implementations intended for direct use
|
226
227
|
####################################################################################
|
227
|
-
# noinspection PyPep8Naming
|
228
228
|
class Cursor:
|
229
229
|
"""Create ANSI sequences to alter the cursor position"""
|
230
230
|
|
@@ -1043,20 +1043,20 @@ def style(
|
|
1043
1043
|
# These can be altered to suit an application's needs and only need to be a
|
1044
1044
|
# function with the following structure: func(str) -> str
|
1045
1045
|
style_success = functools.partial(style, fg=Fg.GREEN)
|
1046
|
-
"""Partial function supplying arguments to
|
1046
|
+
"""Partial function supplying arguments to [cmd2.ansi.style][] which colors text to signify success"""
|
1047
1047
|
|
1048
1048
|
style_warning = functools.partial(style, fg=Fg.LIGHT_YELLOW)
|
1049
|
-
"""Partial function supplying arguments to
|
1049
|
+
"""Partial function supplying arguments to [cmd2.ansi.style][] which colors text to signify a warning"""
|
1050
1050
|
|
1051
1051
|
style_error = functools.partial(style, fg=Fg.LIGHT_RED)
|
1052
|
-
"""Partial function supplying arguments to
|
1052
|
+
"""Partial function supplying arguments to [cmd2.ansi.style][] which colors text to signify an error"""
|
1053
1053
|
|
1054
1054
|
|
1055
1055
|
def async_alert_str(*, terminal_columns: int, prompt: str, line: str, cursor_offset: int, alert_msg: str) -> str:
|
1056
1056
|
"""Calculate the desired string, including ANSI escape codes, for displaying an asynchronous alert message.
|
1057
1057
|
|
1058
1058
|
:param terminal_columns: terminal width (number of columns)
|
1059
|
-
:param prompt:
|
1059
|
+
:param prompt: current onscreen prompt
|
1060
1060
|
:param line: current contents of the Readline line buffer
|
1061
1061
|
:param cursor_offset: the offset of the current cursor position within line
|
1062
1062
|
:param alert_msg: the message to display to the user
|
@@ -1069,9 +1069,9 @@ def async_alert_str(*, terminal_columns: int, prompt: str, line: str, cursor_off
|
|
1069
1069
|
# Calculate how many terminal lines are taken up by all prompt lines except for the last one.
|
1070
1070
|
# That will be included in the input lines calculations since that is where the cursor is.
|
1071
1071
|
num_prompt_terminal_lines = 0
|
1072
|
-
for
|
1073
|
-
|
1074
|
-
num_prompt_terminal_lines += int(
|
1072
|
+
for prompt_line in prompt_lines[:-1]:
|
1073
|
+
prompt_line_width = style_aware_wcswidth(prompt_line)
|
1074
|
+
num_prompt_terminal_lines += int(prompt_line_width / terminal_columns) + 1
|
1075
1075
|
|
1076
1076
|
# Now calculate how many terminal lines are take up by the input
|
1077
1077
|
last_prompt_line = prompt_lines[-1]
|
cmd2/argparse_completer.py
CHANGED
@@ -61,7 +61,6 @@ DEFAULT_DESCRIPTIVE_HEADER = 'Description'
|
|
61
61
|
ARG_TOKENS = 'arg_tokens'
|
62
62
|
|
63
63
|
|
64
|
-
# noinspection PyProtectedMember
|
65
64
|
def _build_hint(parser: argparse.ArgumentParser, arg_action: argparse.Action) -> str:
|
66
65
|
"""Build tab completion hint for a given argument"""
|
67
66
|
# Check if hinting is disabled for this argument
|
@@ -82,7 +81,6 @@ def _single_prefix_char(token: str, parser: argparse.ArgumentParser) -> bool:
|
|
82
81
|
return len(token) == 1 and token[0] in parser.prefix_chars
|
83
82
|
|
84
83
|
|
85
|
-
# noinspection PyProtectedMember
|
86
84
|
def _looks_like_flag(token: str, parser: argparse.ArgumentParser) -> bool:
|
87
85
|
"""
|
88
86
|
Determine if a token looks like a flag. Unless an argument has nargs set to argparse.REMAINDER,
|
@@ -94,7 +92,7 @@ def _looks_like_flag(token: str, parser: argparse.ArgumentParser) -> bool:
|
|
94
92
|
return False
|
95
93
|
|
96
94
|
# Flags have to start with a prefix character
|
97
|
-
if
|
95
|
+
if token[0] not in parser.prefix_chars:
|
98
96
|
return False
|
99
97
|
|
100
98
|
# If it looks like a negative number, it is not a flag unless there are negative-number-like flags
|
@@ -144,7 +142,6 @@ class _ArgumentState:
|
|
144
142
|
self.max = self.action.nargs
|
145
143
|
|
146
144
|
|
147
|
-
# noinspection PyProtectedMember
|
148
145
|
class _UnfinishedFlagError(CompletionError):
|
149
146
|
def __init__(self, flag_arg_state: _ArgumentState) -> None:
|
150
147
|
"""
|
@@ -171,7 +168,6 @@ class _NoResultsError(CompletionError):
|
|
171
168
|
super().__init__(_build_hint(parser, arg_action), apply_style=False)
|
172
169
|
|
173
170
|
|
174
|
-
# noinspection PyProtectedMember
|
175
171
|
class ArgparseCompleter:
|
176
172
|
"""Automatic command line tab completion based on argparse parameters"""
|
177
173
|
|
@@ -273,10 +269,8 @@ class ArgparseCompleter:
|
|
273
269
|
# Check if this action is in a mutually exclusive group
|
274
270
|
for group in self._parser._mutually_exclusive_groups:
|
275
271
|
if arg_action in group._group_actions:
|
276
|
-
|
277
272
|
# Check if the group this action belongs to has already been completed
|
278
273
|
if group in completed_mutex_groups:
|
279
|
-
|
280
274
|
# If this is the action that completed the group, then there is no error
|
281
275
|
# since it's allowed to appear on the command line more than once.
|
282
276
|
completer_action = completed_mutex_groups[group]
|
@@ -307,7 +301,6 @@ class ArgparseCompleter:
|
|
307
301
|
# Parse all but the last token
|
308
302
|
#############################################################################################
|
309
303
|
for token_index, token in enumerate(tokens[:-1]):
|
310
|
-
|
311
304
|
# If we're in a positional REMAINDER arg, force all future tokens to go to that
|
312
305
|
if pos_arg_state is not None and pos_arg_state.is_remainder:
|
313
306
|
consume_argument(pos_arg_state)
|
@@ -339,7 +332,6 @@ class ArgparseCompleter:
|
|
339
332
|
|
340
333
|
# Check the format of the current token to see if it can be an argument's value
|
341
334
|
if _looks_like_flag(token, self._parser) and not skip_remaining_flags:
|
342
|
-
|
343
335
|
# Check if there is an unfinished flag
|
344
336
|
if (
|
345
337
|
flag_arg_state is not None
|
@@ -484,7 +476,6 @@ class ArgparseCompleter:
|
|
484
476
|
|
485
477
|
# Otherwise check if we have a positional to complete
|
486
478
|
elif pos_arg_state is not None or remaining_positionals:
|
487
|
-
|
488
479
|
# If we aren't current tracking a positional, then get the next positional arg to handle this token
|
489
480
|
if pos_arg_state is None:
|
490
481
|
action = remaining_positionals.popleft()
|
cmd2/argparse_custom.py
CHANGED
@@ -101,7 +101,7 @@ dynamic. Therefore it is up to the developer to validate if the user has typed
|
|
101
101
|
an acceptable value for these arguments.
|
102
102
|
|
103
103
|
There are times when what's being tab completed is determined by a previous
|
104
|
-
argument on the command line. In
|
104
|
+
argument on the command line. In these cases, ArgparseCompleter can pass a
|
105
105
|
dictionary that maps the command line tokens up through the one being completed
|
106
106
|
to their argparse argument name. To receive this dictionary, your
|
107
107
|
choices/completer function should have an argument called arg_tokens.
|
@@ -198,31 +198,20 @@ more details.
|
|
198
198
|
cmd2 has patched ``argparse.Action`` to include the following accessor methods
|
199
199
|
for cases in which you need to manually access the cmd2-specific attributes.
|
200
200
|
|
201
|
-
- ``argparse.Action.get_choices_callable()`` - See
|
202
|
-
|
203
|
-
- ``argparse.Action.
|
204
|
-
|
205
|
-
- ``argparse.Action.
|
206
|
-
|
207
|
-
- ``argparse.Action.
|
208
|
-
|
209
|
-
- ``argparse.Action.
|
210
|
-
:func:`_action_set_descriptive_header` for more details.
|
211
|
-
- ``argparse.Action.get_nargs_range()`` - See
|
212
|
-
:func:`_action_get_nargs_range` for more details.
|
213
|
-
- ``argparse.Action.set_nargs_range()`` - See
|
214
|
-
:func:`_action_set_nargs_range` for more details.
|
215
|
-
- ``argparse.Action.get_suppress_tab_hint()`` - See
|
216
|
-
:func:`_action_get_suppress_tab_hint` for more details.
|
217
|
-
- ``argparse.Action.set_suppress_tab_hint()`` - See
|
218
|
-
:func:`_action_set_suppress_tab_hint` for more details.
|
201
|
+
- ``argparse.Action.get_choices_callable()`` - See `action_get_choices_callable` for more details.
|
202
|
+
- ``argparse.Action.set_choices_provider()`` - See `_action_set_choices_provider` for more details.
|
203
|
+
- ``argparse.Action.set_completer()`` - See `_action_set_completer` for more details.
|
204
|
+
- ``argparse.Action.get_descriptive_header()`` - See `_action_get_descriptive_header` for more details.
|
205
|
+
- ``argparse.Action.set_descriptive_header()`` - See `_action_set_descriptive_header` for more details.
|
206
|
+
- ``argparse.Action.get_nargs_range()`` - See `_action_get_nargs_range` for more details.
|
207
|
+
- ``argparse.Action.set_nargs_range()`` - See `_action_set_nargs_range` for more details.
|
208
|
+
- ``argparse.Action.get_suppress_tab_hint()`` - See `_action_get_suppress_tab_hint` for more details.
|
209
|
+
- ``argparse.Action.set_suppress_tab_hint()`` - See `_action_set_suppress_tab_hint` for more details.
|
219
210
|
|
220
211
|
cmd2 has patched ``argparse.ArgumentParser`` to include the following accessor methods
|
221
212
|
|
222
|
-
- ``argparse.ArgumentParser.get_ap_completer_type()`` - See
|
223
|
-
|
224
|
-
- ``argparse.Action.set_ap_completer_type()`` - See
|
225
|
-
:func:`_ArgumentParser_set_ap_completer_type` for more details.
|
213
|
+
- ``argparse.ArgumentParser.get_ap_completer_type()`` - See `_ArgumentParser_get_ap_completer_type` for more details.
|
214
|
+
- ``argparse.Action.set_ap_completer_type()`` - See `_ArgumentParser_set_ap_completer_type` for more details.
|
226
215
|
|
227
216
|
**Subcommand removal**
|
228
217
|
|
@@ -230,15 +219,12 @@ cmd2 has patched ``argparse._SubParsersAction`` to include a ``remove_parser()``
|
|
230
219
|
method which can be used to remove a subcommand.
|
231
220
|
|
232
221
|
``argparse._SubParsersAction.remove_parser`` - new function which removes a
|
233
|
-
sub-parser from a sub-parsers group. See
|
234
|
-
:func:`_SubParsersAction_remove_parser` for more details.
|
222
|
+
sub-parser from a sub-parsers group. See _SubParsersAction_remove_parser` for more details.
|
235
223
|
"""
|
236
224
|
|
237
225
|
import argparse
|
238
226
|
import re
|
239
227
|
import sys
|
240
|
-
|
241
|
-
# noinspection PyUnresolvedReferences,PyProtectedMember
|
242
228
|
from argparse import (
|
243
229
|
ONE_OR_MORE,
|
244
230
|
ZERO_OR_MORE,
|
@@ -257,12 +243,14 @@ from typing import (
|
|
257
243
|
List,
|
258
244
|
NoReturn,
|
259
245
|
Optional,
|
246
|
+
Protocol,
|
260
247
|
Sequence,
|
261
248
|
Set,
|
262
249
|
Tuple,
|
263
250
|
Type,
|
264
251
|
Union,
|
265
252
|
cast,
|
253
|
+
runtime_checkable,
|
266
254
|
)
|
267
255
|
|
268
256
|
from . import (
|
@@ -270,18 +258,6 @@ from . import (
|
|
270
258
|
constants,
|
271
259
|
)
|
272
260
|
|
273
|
-
try:
|
274
|
-
from typing import (
|
275
|
-
Protocol,
|
276
|
-
runtime_checkable,
|
277
|
-
)
|
278
|
-
except ImportError:
|
279
|
-
from typing_extensions import ( # type: ignore[assignment]
|
280
|
-
Protocol,
|
281
|
-
runtime_checkable,
|
282
|
-
)
|
283
|
-
|
284
|
-
|
285
261
|
if TYPE_CHECKING: # pragma: no cover
|
286
262
|
from .argparse_completer import (
|
287
263
|
ArgparseCompleter,
|
@@ -317,7 +293,6 @@ class CompletionItem(str):
|
|
317
293
|
def __new__(cls, value: object, *args: Any, **kwargs: Any) -> 'CompletionItem':
|
318
294
|
return super(CompletionItem, cls).__new__(cls, value)
|
319
295
|
|
320
|
-
# noinspection PyUnusedLocal
|
321
296
|
def __init__(self, value: object, description: str = '', *args: Any) -> None:
|
322
297
|
"""
|
323
298
|
CompletionItem Initializer
|
@@ -351,8 +326,7 @@ class ChoicesProviderFuncBase(Protocol):
|
|
351
326
|
Function that returns a list of choices in support of tab completion
|
352
327
|
"""
|
353
328
|
|
354
|
-
def __call__(self) -> List[str]:
|
355
|
-
... # pragma: no cover
|
329
|
+
def __call__(self) -> List[str]: ... # pragma: no cover
|
356
330
|
|
357
331
|
|
358
332
|
@runtime_checkable
|
@@ -361,8 +335,7 @@ class ChoicesProviderFuncWithTokens(Protocol):
|
|
361
335
|
Function that returns a list of choices in support of tab completion and accepts a dictionary of prior arguments.
|
362
336
|
"""
|
363
337
|
|
364
|
-
def __call__(self, *, arg_tokens: Dict[str, List[str]] = {}) -> List[str]:
|
365
|
-
... # pragma: no cover
|
338
|
+
def __call__(self, *, arg_tokens: Dict[str, List[str]] = {}) -> List[str]: ... # pragma: no cover
|
366
339
|
|
367
340
|
|
368
341
|
ChoicesProviderFunc = Union[ChoicesProviderFuncBase, ChoicesProviderFuncWithTokens]
|
@@ -380,8 +353,7 @@ class CompleterFuncBase(Protocol):
|
|
380
353
|
line: str,
|
381
354
|
begidx: int,
|
382
355
|
endidx: int,
|
383
|
-
) -> List[str]:
|
384
|
-
... # pragma: no cover
|
356
|
+
) -> List[str]: ... # pragma: no cover
|
385
357
|
|
386
358
|
|
387
359
|
@runtime_checkable
|
@@ -399,8 +371,7 @@ class CompleterFuncWithTokens(Protocol):
|
|
399
371
|
endidx: int,
|
400
372
|
*,
|
401
373
|
arg_tokens: Dict[str, List[str]] = {},
|
402
|
-
) -> List[str]:
|
403
|
-
... # pragma: no cover
|
374
|
+
) -> List[str]: ... # pragma: no cover
|
404
375
|
|
405
376
|
|
406
377
|
CompleterFunc = Union[CompleterFuncBase, CompleterFuncWithTokens]
|
@@ -506,12 +477,11 @@ def _action_set_choices_callable(self: argparse.Action, choices_callable: Choice
|
|
506
477
|
"""
|
507
478
|
# Verify consistent use of parameters
|
508
479
|
if self.choices is not None:
|
509
|
-
err_msg = "None of the following parameters can be used alongside a choices parameter:\
|
480
|
+
err_msg = "None of the following parameters can be used alongside a choices parameter:\nchoices_provider, completer"
|
510
481
|
raise (TypeError(err_msg))
|
511
482
|
elif self.nargs == 0:
|
512
483
|
err_msg = (
|
513
|
-
"None of the following parameters can be used on an action that takes no arguments:\
|
514
|
-
"choices_provider, completer"
|
484
|
+
"None of the following parameters can be used on an action that takes no arguments:\nchoices_provider, completer"
|
515
485
|
)
|
516
486
|
raise (TypeError(err_msg))
|
517
487
|
|
@@ -745,11 +715,9 @@ def register_argparse_argument_parameter(param_name: str, param_type: Optional[T
|
|
745
715
|
|
746
716
|
|
747
717
|
# Save original _ActionsContainer.add_argument so we can call it in our wrapper
|
748
|
-
# noinspection PyProtectedMember
|
749
718
|
orig_actions_container_add_argument = argparse._ActionsContainer.add_argument
|
750
719
|
|
751
720
|
|
752
|
-
# noinspection PyProtectedMember
|
753
721
|
def _add_argument_wrapper(
|
754
722
|
self: argparse._ActionsContainer,
|
755
723
|
*args: Any,
|
@@ -797,7 +765,7 @@ def _add_argument_wrapper(
|
|
797
765
|
num_params_set = len(choices_callables) - choices_callables.count(None)
|
798
766
|
|
799
767
|
if num_params_set > 1:
|
800
|
-
err_msg = "Only one of the following parameters may be used at a time:\
|
768
|
+
err_msg = "Only one of the following parameters may be used at a time:\nchoices_provider, completer"
|
801
769
|
raise (ValueError(err_msg))
|
802
770
|
|
803
771
|
# Pre-process special ranged nargs
|
@@ -807,7 +775,6 @@ def _add_argument_wrapper(
|
|
807
775
|
nargs_adjusted: Union[int, str, Tuple[int], Tuple[int, int], Tuple[int, float], None]
|
808
776
|
# Check if nargs was given as a range
|
809
777
|
if isinstance(nargs, tuple):
|
810
|
-
|
811
778
|
# Handle 1-item tuple by setting max to INFINITY
|
812
779
|
if len(nargs) == 1:
|
813
780
|
nargs = (nargs[0], constants.INFINITY)
|
@@ -885,7 +852,6 @@ def _add_argument_wrapper(
|
|
885
852
|
|
886
853
|
|
887
854
|
# Overwrite _ActionsContainer.add_argument with our wrapper
|
888
|
-
# noinspection PyProtectedMember
|
889
855
|
setattr(argparse._ActionsContainer, 'add_argument', _add_argument_wrapper)
|
890
856
|
|
891
857
|
############################################################################################################
|
@@ -893,11 +859,9 @@ setattr(argparse._ActionsContainer, 'add_argument', _add_argument_wrapper)
|
|
893
859
|
############################################################################################################
|
894
860
|
|
895
861
|
# Save original ArgumentParser._get_nargs_pattern so we can call it in our wrapper
|
896
|
-
# noinspection PyProtectedMember
|
897
862
|
orig_argument_parser_get_nargs_pattern = argparse.ArgumentParser._get_nargs_pattern
|
898
863
|
|
899
864
|
|
900
|
-
# noinspection PyProtectedMember
|
901
865
|
def _get_nargs_pattern_wrapper(self: argparse.ArgumentParser, action: argparse.Action) -> str:
|
902
866
|
# Wrapper around ArgumentParser._get_nargs_pattern behavior to support nargs ranges
|
903
867
|
nargs_range = action.get_nargs_range() # type: ignore[attr-defined]
|
@@ -919,18 +883,15 @@ def _get_nargs_pattern_wrapper(self: argparse.ArgumentParser, action: argparse.A
|
|
919
883
|
|
920
884
|
|
921
885
|
# Overwrite ArgumentParser._get_nargs_pattern with our wrapper
|
922
|
-
# noinspection PyProtectedMember
|
923
886
|
setattr(argparse.ArgumentParser, '_get_nargs_pattern', _get_nargs_pattern_wrapper)
|
924
887
|
|
925
888
|
|
926
889
|
############################################################################################################
|
927
890
|
# Patch ArgumentParser._match_argument with our wrapper to support nargs ranges
|
928
891
|
############################################################################################################
|
929
|
-
# noinspection PyProtectedMember
|
930
892
|
orig_argument_parser_match_argument = argparse.ArgumentParser._match_argument
|
931
893
|
|
932
894
|
|
933
|
-
# noinspection PyProtectedMember
|
934
895
|
def _match_argument_wrapper(self: argparse.ArgumentParser, action: argparse.Action, arg_strings_pattern: str) -> int:
|
935
896
|
# Wrapper around ArgumentParser._match_argument behavior to support nargs ranges
|
936
897
|
nargs_pattern = self._get_nargs_pattern(action)
|
@@ -946,7 +907,6 @@ def _match_argument_wrapper(self: argparse.ArgumentParser, action: argparse.Acti
|
|
946
907
|
|
947
908
|
|
948
909
|
# Overwrite ArgumentParser._match_argument with our wrapper
|
949
|
-
# noinspection PyProtectedMember
|
950
910
|
setattr(argparse.ArgumentParser, '_match_argument', _match_argument_wrapper)
|
951
911
|
|
952
912
|
|
@@ -960,7 +920,6 @@ setattr(argparse.ArgumentParser, '_match_argument', _match_argument_wrapper)
|
|
960
920
|
ATTR_AP_COMPLETER_TYPE = 'ap_completer_type'
|
961
921
|
|
962
922
|
|
963
|
-
# noinspection PyPep8Naming
|
964
923
|
def _ArgumentParser_get_ap_completer_type(self: argparse.ArgumentParser) -> Optional[Type['ArgparseCompleter']]:
|
965
924
|
"""
|
966
925
|
Get the ap_completer_type attribute of an argparse ArgumentParser.
|
@@ -978,7 +937,6 @@ def _ArgumentParser_get_ap_completer_type(self: argparse.ArgumentParser) -> Opti
|
|
978
937
|
setattr(argparse.ArgumentParser, 'get_ap_completer_type', _ArgumentParser_get_ap_completer_type)
|
979
938
|
|
980
939
|
|
981
|
-
# noinspection PyPep8Naming
|
982
940
|
def _ArgumentParser_set_ap_completer_type(self: argparse.ArgumentParser, ap_completer_type: Type['ArgparseCompleter']) -> None:
|
983
941
|
"""
|
984
942
|
Set the ap_completer_type attribute of an argparse ArgumentParser.
|
@@ -999,7 +957,6 @@ setattr(argparse.ArgumentParser, 'set_ap_completer_type', _ArgumentParser_set_ap
|
|
999
957
|
############################################################################################################
|
1000
958
|
# Patch ArgumentParser._check_value to support CompletionItems as choices
|
1001
959
|
############################################################################################################
|
1002
|
-
# noinspection PyPep8Naming
|
1003
960
|
def _ArgumentParser_check_value(self: argparse.ArgumentParser, action: argparse.Action, value: Any) -> None:
|
1004
961
|
"""
|
1005
962
|
Custom override of ArgumentParser._check_value that supports CompletionItems as choices.
|
@@ -1032,7 +989,7 @@ setattr(argparse.ArgumentParser, '_check_value', _ArgumentParser_check_value)
|
|
1032
989
|
# Patch argparse._SubParsersAction to add remove_parser function
|
1033
990
|
############################################################################################################
|
1034
991
|
|
1035
|
-
|
992
|
+
|
1036
993
|
def _SubParsersAction_remove_parser(self: argparse._SubParsersAction, name: str) -> None: # type: ignore
|
1037
994
|
"""
|
1038
995
|
Removes a sub-parser from a sub-parsers group. Used to remove subcommands from a parser.
|
@@ -1061,7 +1018,6 @@ def _SubParsersAction_remove_parser(self: argparse._SubParsersAction, name: str)
|
|
1061
1018
|
del self._name_parser_map[cur_name]
|
1062
1019
|
|
1063
1020
|
|
1064
|
-
# noinspection PyProtectedMember
|
1065
1021
|
setattr(argparse._SubParsersAction, 'remove_parser', _SubParsersAction_remove_parser)
|
1066
1022
|
|
1067
1023
|
|
@@ -1073,11 +1029,9 @@ setattr(argparse._SubParsersAction, 'remove_parser', _SubParsersAction_remove_pa
|
|
1073
1029
|
############################################################################################################
|
1074
1030
|
|
1075
1031
|
|
1076
|
-
# noinspection PyCompatibility,PyShadowingBuiltins
|
1077
1032
|
class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
|
1078
1033
|
"""Custom help formatter to configure ordering of help text"""
|
1079
1034
|
|
1080
|
-
# noinspection PyProtectedMember
|
1081
1035
|
def _format_usage(
|
1082
1036
|
self,
|
1083
1037
|
usage: Optional[str],
|
@@ -1117,20 +1071,19 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
|
|
1117
1071
|
|
1118
1072
|
# build full usage string
|
1119
1073
|
format = self._format_actions_usage
|
1120
|
-
action_usage = format(required_options + optionals + positionals, groups)
|
1074
|
+
action_usage = format(required_options + optionals + positionals, groups) # type: ignore[arg-type]
|
1121
1075
|
usage = ' '.join([s for s in [prog, action_usage] if s])
|
1122
1076
|
|
1123
1077
|
# wrap the usage parts if it's too long
|
1124
1078
|
text_width = self._width - self._current_indent
|
1125
1079
|
if len(prefix) + len(usage) > text_width:
|
1126
|
-
|
1127
1080
|
# Begin cmd2 customization
|
1128
1081
|
|
1129
1082
|
# break usage into wrappable parts
|
1130
1083
|
part_regexp = r'\(.*?\)+|\[.*?\]+|\S+'
|
1131
|
-
req_usage = format(required_options, groups)
|
1132
|
-
opt_usage = format(optionals, groups)
|
1133
|
-
pos_usage = format(positionals, groups)
|
1084
|
+
req_usage = format(required_options, groups) # type: ignore[arg-type]
|
1085
|
+
opt_usage = format(optionals, groups) # type: ignore[arg-type]
|
1086
|
+
pos_usage = format(positionals, groups) # type: ignore[arg-type]
|
1134
1087
|
req_parts = re.findall(part_regexp, req_usage)
|
1135
1088
|
opt_parts = re.findall(part_regexp, opt_usage)
|
1136
1089
|
pos_parts = re.findall(part_regexp, pos_usage)
|
@@ -1141,7 +1094,6 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
|
|
1141
1094
|
# End cmd2 customization
|
1142
1095
|
|
1143
1096
|
# helper for wrapping lines
|
1144
|
-
# noinspection PyMissingOrEmptyDocstring,PyShadowingNames
|
1145
1097
|
def get_lines(parts: List[str], indent: str, prefix: Optional[str] = None) -> List[str]:
|
1146
1098
|
lines: List[str] = []
|
1147
1099
|
line: List[str] = []
|
@@ -1224,7 +1176,6 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
|
|
1224
1176
|
return ', '.join(action.option_strings) + ' ' + args_string
|
1225
1177
|
# End cmd2 customization
|
1226
1178
|
|
1227
|
-
# noinspection PyMethodMayBeStatic
|
1228
1179
|
def _determine_metavar(
|
1229
1180
|
self,
|
1230
1181
|
action: argparse.Action,
|
@@ -1249,7 +1200,6 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
|
|
1249
1200
|
) -> Callable[[int], Tuple[str, ...]]:
|
1250
1201
|
metavar = self._determine_metavar(action, default_metavar)
|
1251
1202
|
|
1252
|
-
# noinspection PyMissingOrEmptyDocstring
|
1253
1203
|
def format(tuple_size: int) -> Tuple[str, ...]:
|
1254
1204
|
if isinstance(metavar, tuple):
|
1255
1205
|
return metavar
|
@@ -1258,7 +1208,6 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
|
|
1258
1208
|
|
1259
1209
|
return format
|
1260
1210
|
|
1261
|
-
# noinspection PyProtectedMember
|
1262
1211
|
def _format_args(self, action: argparse.Action, default_metavar: Union[str, Tuple[str, ...]]) -> str:
|
1263
1212
|
"""Customized to handle ranged nargs and make other output less verbose"""
|
1264
1213
|
metavar = self._determine_metavar(action, default_metavar)
|
@@ -1287,7 +1236,6 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
|
|
1287
1236
|
return super()._format_args(action, default_metavar) # type: ignore[arg-type]
|
1288
1237
|
|
1289
1238
|
|
1290
|
-
# noinspection PyCompatibility
|
1291
1239
|
class Cmd2ArgumentParser(argparse.ArgumentParser):
|
1292
1240
|
"""Custom ArgumentParser class that improves error and help output"""
|
1293
1241
|
|
@@ -1332,7 +1280,6 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
|
|
1332
1280
|
|
1333
1281
|
self.set_ap_completer_type(ap_completer_type) # type: ignore[attr-defined]
|
1334
1282
|
|
1335
|
-
# noinspection PyProtectedMember
|
1336
1283
|
def add_subparsers(self, **kwargs: Any) -> argparse._SubParsersAction: # type: ignore
|
1337
1284
|
"""
|
1338
1285
|
Custom override. Sets a default title if one was not given.
|
@@ -1361,7 +1308,6 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
|
|
1361
1308
|
formatted_message = ansi.style_error(formatted_message)
|
1362
1309
|
self.exit(2, f'{formatted_message}\n\n')
|
1363
1310
|
|
1364
|
-
# noinspection PyProtectedMember
|
1365
1311
|
def format_help(self) -> str:
|
1366
1312
|
"""Copy of format_help() from argparse.ArgumentParser with tweaks to separately display required parameters"""
|
1367
1313
|
formatter = self._get_formatter()
|
cmd2/clipboard.py
CHANGED
@@ -2,29 +2,10 @@
|
|
2
2
|
"""
|
3
3
|
This module provides basic ability to copy from and paste to the clipboard/pastebuffer.
|
4
4
|
"""
|
5
|
-
from typing import (
|
6
|
-
cast,
|
7
|
-
)
|
8
5
|
|
9
|
-
import
|
10
|
-
|
11
|
-
# noinspection PyProtectedMember
|
6
|
+
import typing
|
12
7
|
|
13
|
-
|
14
|
-
# noinspection PyBroadException
|
15
|
-
try:
|
16
|
-
# Try getting the contents of the clipboard
|
17
|
-
_ = pyperclip.paste()
|
18
|
-
|
19
|
-
# pyperclip raises at least the following types of exceptions. To be safe, just catch all Exceptions.
|
20
|
-
# FileNotFoundError on Windows Subsystem for Linux (WSL) when Windows paths are removed from $PATH
|
21
|
-
# ValueError for headless Linux systems without Gtk installed
|
22
|
-
# AssertionError can be raised by paste_klipper().
|
23
|
-
# PyperclipException for pyperclip-specific exceptions
|
24
|
-
except Exception:
|
25
|
-
can_clip = False
|
26
|
-
else:
|
27
|
-
can_clip = True
|
8
|
+
import pyperclip # type: ignore[import]
|
28
9
|
|
29
10
|
|
30
11
|
def get_paste_buffer() -> str:
|
@@ -32,7 +13,7 @@ def get_paste_buffer() -> str:
|
|
32
13
|
|
33
14
|
:return: contents of the clipboard
|
34
15
|
"""
|
35
|
-
pb_str = cast(str, pyperclip.paste())
|
16
|
+
pb_str = typing.cast(str, pyperclip.paste())
|
36
17
|
return pb_str
|
37
18
|
|
38
19
|
|