cmd2 2.5.11__py3-none-any.whl → 2.6.0__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 +11 -22
- cmd2/ansi.py +78 -91
- cmd2/argparse_completer.py +109 -132
- cmd2/argparse_custom.py +199 -217
- cmd2/clipboard.py +2 -6
- cmd2/cmd2.py +447 -521
- cmd2/command_definition.py +34 -44
- cmd2/constants.py +1 -3
- cmd2/decorators.py +47 -58
- cmd2/exceptions.py +23 -46
- cmd2/history.py +29 -43
- cmd2/parsing.py +59 -84
- cmd2/plugin.py +6 -10
- cmd2/py_bridge.py +20 -26
- cmd2/rl_utils.py +45 -69
- cmd2/table_creator.py +83 -106
- cmd2/transcript.py +55 -59
- cmd2/utils.py +143 -176
- {cmd2-2.5.11.dist-info → cmd2-2.6.0.dist-info}/METADATA +34 -17
- cmd2-2.6.0.dist-info/RECORD +24 -0
- {cmd2-2.5.11.dist-info → cmd2-2.6.0.dist-info}/WHEEL +1 -1
- cmd2-2.5.11.dist-info/RECORD +0 -24
- {cmd2-2.5.11.dist-info → cmd2-2.6.0.dist-info/licenses}/LICENSE +0 -0
- {cmd2-2.5.11.dist-info → cmd2-2.6.0.dist-info}/top_level.txt +0 -0
cmd2/command_definition.py
CHANGED
@@ -1,15 +1,9 @@
|
|
1
|
-
|
2
|
-
"""
|
3
|
-
Supports the definition of commands in separate classes to be composed into cmd2.Cmd
|
4
|
-
"""
|
1
|
+
"""Supports the definition of commands in separate classes to be composed into cmd2.Cmd."""
|
5
2
|
|
3
|
+
from collections.abc import Callable, Mapping
|
6
4
|
from typing import (
|
7
5
|
TYPE_CHECKING,
|
8
|
-
Callable,
|
9
|
-
Dict,
|
10
|
-
Mapping,
|
11
6
|
Optional,
|
12
|
-
Type,
|
13
7
|
TypeVar,
|
14
8
|
)
|
15
9
|
|
@@ -31,13 +25,11 @@ if TYPE_CHECKING: # pragma: no cover
|
|
31
25
|
#: Further refinements are needed to define the input parameters
|
32
26
|
CommandFunc = Callable[..., Optional[bool]]
|
33
27
|
|
34
|
-
CommandSetType = TypeVar('CommandSetType', bound=
|
28
|
+
CommandSetType = TypeVar('CommandSetType', bound=type['CommandSet'])
|
35
29
|
|
36
30
|
|
37
31
|
def with_default_category(category: str, *, heritable: bool = True) -> Callable[[CommandSetType], CommandSetType]:
|
38
|
-
"""
|
39
|
-
Decorator that applies a category to all ``do_*`` command methods in a class that do not already
|
40
|
-
have a category specified.
|
32
|
+
"""Apply a category to all ``do_*`` command methods in a class that do not already have a category specified (Decorator).
|
41
33
|
|
42
34
|
CommandSets that are decorated by this with `heritable` set to True (default) will set a class attribute that is
|
43
35
|
inherited by all subclasses unless overridden. All commands of this CommandSet and all subclasses of this CommandSet
|
@@ -85,9 +77,8 @@ def with_default_category(category: str, *, heritable: bool = True) -> Callable[
|
|
85
77
|
return decorate_class
|
86
78
|
|
87
79
|
|
88
|
-
class CommandSet
|
89
|
-
"""
|
90
|
-
Base class for defining sets of commands to load in cmd2.
|
80
|
+
class CommandSet:
|
81
|
+
"""Base class for defining sets of commands to load in cmd2.
|
91
82
|
|
92
83
|
``with_default_category`` can be used to apply a default category to all commands in the CommandSet.
|
93
84
|
|
@@ -95,18 +86,19 @@ class CommandSet(object):
|
|
95
86
|
"""
|
96
87
|
|
97
88
|
def __init__(self) -> None:
|
98
|
-
|
99
|
-
|
100
|
-
|
89
|
+
"""Private reference to the CLI instance in which this CommandSet running.
|
90
|
+
|
91
|
+
This will be set when the CommandSet is registered and it should be
|
92
|
+
accessed by child classes using the self._cmd property.
|
93
|
+
"""
|
101
94
|
self.__cmd_internal: Optional[cmd2.Cmd] = None
|
102
95
|
|
103
|
-
self._settables:
|
96
|
+
self._settables: dict[str, Settable] = {}
|
104
97
|
self._settable_prefix = self.__class__.__name__
|
105
98
|
|
106
99
|
@property
|
107
100
|
def _cmd(self) -> 'cmd2.Cmd':
|
108
|
-
"""
|
109
|
-
Property for child classes to access self.__cmd_internal.
|
101
|
+
"""Property for child classes to access self.__cmd_internal.
|
110
102
|
|
111
103
|
Using this property ensures that self.__cmd_internal has been set
|
112
104
|
and it tells type checkers that it's no longer a None type.
|
@@ -121,10 +113,11 @@ class CommandSet(object):
|
|
121
113
|
return self.__cmd_internal
|
122
114
|
|
123
115
|
def on_register(self, cmd: 'cmd2.Cmd') -> None:
|
124
|
-
"""
|
125
|
-
|
126
|
-
not been added to the CLI object at this point.
|
127
|
-
|
116
|
+
"""First step to registering a CommandSet, called by cmd2.Cmd.
|
117
|
+
|
118
|
+
The commands defined in this class have not been added to the CLI object at this point.
|
119
|
+
Subclasses can override this to perform any initialization requiring access to the Cmd object
|
120
|
+
(e.g. configure commands and their parsers based on CLI state data).
|
128
121
|
|
129
122
|
:param cmd: The cmd2 main application
|
130
123
|
:raises CommandSetRegistrationError: if CommandSet is already registered.
|
@@ -135,66 +128,63 @@ class CommandSet(object):
|
|
135
128
|
raise CommandSetRegistrationError('This CommandSet has already been registered')
|
136
129
|
|
137
130
|
def on_registered(self) -> None:
|
138
|
-
"""
|
139
|
-
|
131
|
+
"""2nd step to registering, called by cmd2.Cmd after a CommandSet is registered and all its commands have been added.
|
132
|
+
|
140
133
|
Subclasses can override this to perform custom steps related to the newly added commands (e.g. setting
|
141
134
|
them to a disabled state).
|
142
135
|
"""
|
143
|
-
pass
|
144
136
|
|
145
137
|
def on_unregister(self) -> None:
|
138
|
+
"""First step to unregistering a CommandSet, called by ``cmd2.Cmd``.
|
139
|
+
|
140
|
+
Subclasses can override this to perform any cleanup steps which require their commands being registered in the CLI.
|
146
141
|
"""
|
147
|
-
Called by ``cmd2.Cmd`` as the first step to unregistering a CommandSet. Subclasses can override this to
|
148
|
-
perform any cleanup steps which require their commands being registered in the CLI.
|
149
|
-
"""
|
150
|
-
pass
|
151
142
|
|
152
143
|
def on_unregistered(self) -> None:
|
153
|
-
"""
|
154
|
-
|
144
|
+
"""2nd step to unregistering, called by ``cmd2.Cmd`` after a CommandSet is unregistered and all its commands removed.
|
145
|
+
|
155
146
|
Subclasses can override this to perform remaining cleanup steps.
|
156
147
|
"""
|
157
148
|
self.__cmd_internal = None
|
158
149
|
|
159
150
|
@property
|
160
151
|
def settable_prefix(self) -> str:
|
152
|
+
"""Read-only accessor for the underlying private settable_prefix field."""
|
161
153
|
return self._settable_prefix
|
162
154
|
|
163
155
|
@property
|
164
156
|
def settables(self) -> Mapping[str, Settable]:
|
157
|
+
"""Read-only accessor for the underlying private settables field."""
|
165
158
|
return self._settables
|
166
159
|
|
167
160
|
def add_settable(self, settable: Settable) -> None:
|
168
|
-
"""
|
169
|
-
Convenience method to add a settable parameter to the CommandSet
|
161
|
+
"""Add a settable parameter to the CommandSet.
|
170
162
|
|
171
163
|
:param settable: Settable object being added
|
172
164
|
"""
|
173
165
|
if self.__cmd_internal is not None:
|
174
166
|
if not self._cmd.always_prefix_settables:
|
175
|
-
if settable.name in self._cmd.settables
|
167
|
+
if settable.name in self._cmd.settables and settable.name not in self._settables:
|
176
168
|
raise KeyError(f'Duplicate settable: {settable.name}')
|
177
169
|
else:
|
178
170
|
prefixed_name = f'{self._settable_prefix}.{settable.name}'
|
179
|
-
if prefixed_name in self._cmd.settables
|
171
|
+
if prefixed_name in self._cmd.settables and settable.name not in self._settables:
|
180
172
|
raise KeyError(f'Duplicate settable: {settable.name}')
|
181
173
|
self._settables[settable.name] = settable
|
182
174
|
|
183
175
|
def remove_settable(self, name: str) -> None:
|
184
|
-
"""
|
185
|
-
Convenience method for removing a settable parameter from the CommandSet
|
176
|
+
"""Remove a settable parameter from the CommandSet.
|
186
177
|
|
187
178
|
:param name: name of the settable being removed
|
188
179
|
:raises KeyError: if the Settable matches this name
|
189
180
|
"""
|
190
181
|
try:
|
191
182
|
del self._settables[name]
|
192
|
-
except KeyError:
|
193
|
-
raise KeyError(name + " is not a settable parameter")
|
183
|
+
except KeyError as exc:
|
184
|
+
raise KeyError(name + " is not a settable parameter") from exc
|
194
185
|
|
195
186
|
def sigint_handler(self) -> bool:
|
196
|
-
"""
|
197
|
-
Handle a SIGINT that occurred for a command in this CommandSet.
|
187
|
+
"""Handle a SIGINT that occurred for a command in this CommandSet.
|
198
188
|
|
199
189
|
:return: True if this completes the interrupt handling and no KeyboardInterrupt will be raised.
|
200
190
|
False to raise a KeyboardInterrupt.
|
cmd2/constants.py
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
# coding=utf-8
|
3
|
-
"""This module contains constants used throughout ``cmd2``."""
|
1
|
+
"""Constants used throughout ``cmd2``."""
|
4
2
|
|
5
3
|
# Unless documented in https://cmd2.readthedocs.io/en/latest/api/index.html
|
6
4
|
# nothing here should be considered part of the public API of this module
|
cmd2/decorators.py
CHANGED
@@ -1,17 +1,11 @@
|
|
1
|
-
|
2
|
-
"""Decorators for ``cmd2`` commands"""
|
1
|
+
"""Decorators for ``cmd2`` commands."""
|
3
2
|
|
4
3
|
import argparse
|
4
|
+
from collections.abc import Callable, Sequence
|
5
5
|
from typing import (
|
6
6
|
TYPE_CHECKING,
|
7
7
|
Any,
|
8
|
-
Callable,
|
9
|
-
Dict,
|
10
|
-
List,
|
11
8
|
Optional,
|
12
|
-
Sequence,
|
13
|
-
Tuple,
|
14
|
-
Type,
|
15
9
|
TypeVar,
|
16
10
|
Union,
|
17
11
|
)
|
@@ -38,13 +32,12 @@ if TYPE_CHECKING: # pragma: no cover
|
|
38
32
|
|
39
33
|
|
40
34
|
def with_category(category: str) -> Callable[[CommandFunc], CommandFunc]:
|
41
|
-
"""
|
35
|
+
"""Decorate a ``do_*`` command method to apply a category.
|
42
36
|
|
43
37
|
:param category: the name of the category in which this command should
|
44
38
|
be grouped when displaying the list of commands.
|
45
39
|
|
46
40
|
Example:
|
47
|
-
|
48
41
|
```py
|
49
42
|
class MyApp(cmd2.Cmd):
|
50
43
|
@cmd2.with_category('Text Functions')
|
@@ -54,6 +47,7 @@ def with_category(category: str) -> Callable[[CommandFunc], CommandFunc]:
|
|
54
47
|
|
55
48
|
For an alternative approach to categorizing commands using a function, see
|
56
49
|
[cmd2.utils.categorize][]
|
50
|
+
|
57
51
|
"""
|
58
52
|
|
59
53
|
def cat_decorator(func: CommandFunc) -> CommandFunc:
|
@@ -68,7 +62,7 @@ def with_category(category: str) -> Callable[[CommandFunc], CommandFunc]:
|
|
68
62
|
|
69
63
|
|
70
64
|
CommandParent = TypeVar('CommandParent', bound=Union['cmd2.Cmd', CommandSet])
|
71
|
-
CommandParentType = TypeVar('CommandParentType', bound=Union[
|
65
|
+
CommandParentType = TypeVar('CommandParentType', bound=Union[type['cmd2.Cmd'], type[CommandSet]])
|
72
66
|
|
73
67
|
|
74
68
|
RawCommandFuncOptionalBoolReturn = Callable[[CommandParent, Union[Statement, str]], Optional[bool]]
|
@@ -79,12 +73,13 @@ RawCommandFuncOptionalBoolReturn = Callable[[CommandParent, Union[Statement, str
|
|
79
73
|
# in cmd2 command functions/callables. As long as the 2-ple of arguments we expect to be there can be
|
80
74
|
# found we can swap out the statement with each decorator's specific parameters
|
81
75
|
##########################
|
82
|
-
def _parse_positionals(args:
|
83
|
-
"""
|
84
|
-
|
76
|
+
def _parse_positionals(args: tuple[Any, ...]) -> tuple['cmd2.Cmd', Union[Statement, str]]:
|
77
|
+
"""Inspect the positional arguments until the cmd2.Cmd argument is found.
|
78
|
+
|
85
79
|
Assumes that we will find cmd2.Cmd followed by the command statement object or string.
|
80
|
+
|
86
81
|
:arg args: The positional arguments to inspect
|
87
|
-
:return: The cmd2.Cmd reference and the command line statement
|
82
|
+
:return: The cmd2.Cmd reference and the command line statement.
|
88
83
|
"""
|
89
84
|
for pos, arg in enumerate(args):
|
90
85
|
from cmd2 import (
|
@@ -93,7 +88,7 @@ def _parse_positionals(args: Tuple[Any, ...]) -> Tuple['cmd2.Cmd', Union[Stateme
|
|
93
88
|
|
94
89
|
if isinstance(arg, (Cmd, CommandSet)) and len(args) > pos + 1:
|
95
90
|
if isinstance(arg, CommandSet):
|
96
|
-
arg = arg._cmd
|
91
|
+
arg = arg._cmd # noqa: PLW2901
|
97
92
|
next_arg = args[pos + 1]
|
98
93
|
if isinstance(next_arg, (Statement, str)):
|
99
94
|
return arg, args[pos + 1]
|
@@ -103,9 +98,8 @@ def _parse_positionals(args: Tuple[Any, ...]) -> Tuple['cmd2.Cmd', Union[Stateme
|
|
103
98
|
raise TypeError('Expected arguments: cmd: cmd2.Cmd, statement: Union[Statement, str] Not found')
|
104
99
|
|
105
100
|
|
106
|
-
def _arg_swap(args: Union[Sequence[Any]], search_arg: Any, *replace_arg: Any) ->
|
107
|
-
"""
|
108
|
-
Helper function for cmd2 decorators to swap the Statement parameter with one or more decorator-specific parameters
|
101
|
+
def _arg_swap(args: Union[Sequence[Any]], search_arg: Any, *replace_arg: Any) -> list[Any]:
|
102
|
+
"""Swap the Statement parameter with one or more decorator-specific parameters.
|
109
103
|
|
110
104
|
:param args: The original positional arguments
|
111
105
|
:param search_arg: The argument to search for (usually the Statement)
|
@@ -120,13 +114,13 @@ def _arg_swap(args: Union[Sequence[Any]], search_arg: Any, *replace_arg: Any) ->
|
|
120
114
|
|
121
115
|
#: Function signature for a command function that accepts a pre-processed argument list from user input
|
122
116
|
#: and optionally returns a boolean
|
123
|
-
ArgListCommandFuncOptionalBoolReturn = Callable[[CommandParent,
|
117
|
+
ArgListCommandFuncOptionalBoolReturn = Callable[[CommandParent, list[str]], Optional[bool]]
|
124
118
|
#: Function signature for a command function that accepts a pre-processed argument list from user input
|
125
119
|
#: and returns a boolean
|
126
|
-
ArgListCommandFuncBoolReturn = Callable[[CommandParent,
|
120
|
+
ArgListCommandFuncBoolReturn = Callable[[CommandParent, list[str]], bool]
|
127
121
|
#: Function signature for a command function that accepts a pre-processed argument list from user input
|
128
122
|
#: and returns Nothing
|
129
|
-
ArgListCommandFuncNoneReturn = Callable[[CommandParent,
|
123
|
+
ArgListCommandFuncNoneReturn = Callable[[CommandParent, list[str]], None]
|
130
124
|
|
131
125
|
#: Aggregate of all accepted function signatures for command functions that accept a pre-processed argument list
|
132
126
|
ArgListCommandFunc = Union[
|
@@ -144,9 +138,9 @@ def with_argument_list(
|
|
144
138
|
RawCommandFuncOptionalBoolReturn[CommandParent],
|
145
139
|
Callable[[ArgListCommandFunc[CommandParent]], RawCommandFuncOptionalBoolReturn[CommandParent]],
|
146
140
|
]:
|
147
|
-
"""
|
148
|
-
|
149
|
-
passes a string of whatever the user typed. With this decorator, the
|
141
|
+
"""Decorate a ``do_*`` method to alter the arguments passed to it so it is passed a list[str].
|
142
|
+
|
143
|
+
Default passes a string of whatever the user typed. With this decorator, the
|
150
144
|
decorated method will receive a list of arguments parsed from user input.
|
151
145
|
|
152
146
|
:param func_arg: Single-element positional argument list containing ``doi_*`` method
|
@@ -161,12 +155,13 @@ def with_argument_list(
|
|
161
155
|
def do_echo(self, arglist):
|
162
156
|
self.poutput(' '.join(arglist)
|
163
157
|
```
|
158
|
+
|
164
159
|
"""
|
165
160
|
import functools
|
166
161
|
|
167
162
|
def arg_decorator(func: ArgListCommandFunc[CommandParent]) -> RawCommandFuncOptionalBoolReturn[CommandParent]:
|
168
|
-
"""
|
169
|
-
|
163
|
+
"""Decorate function that ingests an Argument List function and returns a raw command function.
|
164
|
+
|
170
165
|
The returned function will process the raw input into an argument list to be passed to the wrapped function.
|
171
166
|
|
172
167
|
:param func: The defined argument list command function
|
@@ -175,8 +170,7 @@ def with_argument_list(
|
|
175
170
|
|
176
171
|
@functools.wraps(func)
|
177
172
|
def cmd_wrapper(*args: Any, **kwargs: Any) -> Optional[bool]:
|
178
|
-
"""
|
179
|
-
Command function wrapper which translates command line into an argument list and calls actual command function
|
173
|
+
"""Command function wrapper which translates command line into an argument list and calls actual command function.
|
180
174
|
|
181
175
|
:param args: All positional arguments to this function. We're expecting there to be:
|
182
176
|
cmd2_app, statement: Union[Statement, str]
|
@@ -195,21 +189,20 @@ def with_argument_list(
|
|
195
189
|
|
196
190
|
if callable(func_arg):
|
197
191
|
return arg_decorator(func_arg)
|
198
|
-
|
199
|
-
return arg_decorator
|
192
|
+
return arg_decorator
|
200
193
|
|
201
194
|
|
202
195
|
def _set_parser_prog(parser: argparse.ArgumentParser, prog: str) -> None:
|
203
|
-
"""
|
204
|
-
|
205
|
-
is a command name and not sys.argv[0].
|
196
|
+
"""Recursively set prog attribute of a parser and all of its subparsers.
|
197
|
+
|
198
|
+
Does so that the root command is a command name and not sys.argv[0].
|
206
199
|
|
207
200
|
:param parser: the parser being edited
|
208
201
|
:param prog: new value for the parser's prog attribute
|
209
202
|
"""
|
210
203
|
# Set the prog value for this parser
|
211
204
|
parser.prog = prog
|
212
|
-
req_args:
|
205
|
+
req_args: list[str] = []
|
213
206
|
|
214
207
|
# Set the prog value for the parser's subcommands
|
215
208
|
for action in parser._actions:
|
@@ -245,24 +238,24 @@ def _set_parser_prog(parser: argparse.ArgumentParser, prog: str) -> None:
|
|
245
238
|
break
|
246
239
|
|
247
240
|
# Need to save required args so they can be prepended to the subcommand usage
|
248
|
-
|
241
|
+
if action.required:
|
249
242
|
req_args.append(action.dest)
|
250
243
|
|
251
244
|
|
252
245
|
#: Function signatures for command functions that use an argparse.ArgumentParser to process user input
|
253
246
|
#: and optionally return a boolean
|
254
247
|
ArgparseCommandFuncOptionalBoolReturn = Callable[[CommandParent, argparse.Namespace], Optional[bool]]
|
255
|
-
ArgparseCommandFuncWithUnknownArgsOptionalBoolReturn = Callable[[CommandParent, argparse.Namespace,
|
248
|
+
ArgparseCommandFuncWithUnknownArgsOptionalBoolReturn = Callable[[CommandParent, argparse.Namespace, list[str]], Optional[bool]]
|
256
249
|
|
257
250
|
#: Function signatures for command functions that use an argparse.ArgumentParser to process user input
|
258
251
|
#: and return a boolean
|
259
252
|
ArgparseCommandFuncBoolReturn = Callable[[CommandParent, argparse.Namespace], bool]
|
260
|
-
ArgparseCommandFuncWithUnknownArgsBoolReturn = Callable[[CommandParent, argparse.Namespace,
|
253
|
+
ArgparseCommandFuncWithUnknownArgsBoolReturn = Callable[[CommandParent, argparse.Namespace, list[str]], bool]
|
261
254
|
|
262
255
|
#: Function signatures for command functions that use an argparse.ArgumentParser to process user input
|
263
256
|
#: and return nothing
|
264
257
|
ArgparseCommandFuncNoneReturn = Callable[[CommandParent, argparse.Namespace], None]
|
265
|
-
ArgparseCommandFuncWithUnknownArgsNoneReturn = Callable[[CommandParent, argparse.Namespace,
|
258
|
+
ArgparseCommandFuncWithUnknownArgsNoneReturn = Callable[[CommandParent, argparse.Namespace, list[str]], None]
|
266
259
|
|
267
260
|
#: Aggregate of all accepted function signatures for an argparse command function
|
268
261
|
ArgparseCommandFunc = Union[
|
@@ -286,8 +279,7 @@ def with_argparser(
|
|
286
279
|
preserve_quotes: bool = False,
|
287
280
|
with_unknown_args: bool = False,
|
288
281
|
) -> Callable[[ArgparseCommandFunc[CommandParent]], RawCommandFuncOptionalBoolReturn[CommandParent]]:
|
289
|
-
"""
|
290
|
-
with the given instance of argparse.ArgumentParser.
|
282
|
+
"""Decorate a ``do_*`` method to populate its ``args`` argument with the given instance of argparse.ArgumentParser.
|
291
283
|
|
292
284
|
:param parser: unique instance of ArgumentParser or a callable that returns an ArgumentParser
|
293
285
|
:param ns_provider: An optional function that accepts a cmd2.Cmd or cmd2.CommandSet object as an argument and returns an
|
@@ -301,7 +293,6 @@ def with_argparser(
|
|
301
293
|
parsing the command line. This can be useful if the command function needs to know the command line.
|
302
294
|
|
303
295
|
Example:
|
304
|
-
|
305
296
|
```py
|
306
297
|
parser = cmd2.Cmd2ArgumentParser()
|
307
298
|
parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay')
|
@@ -331,12 +322,13 @@ def with_argparser(
|
|
331
322
|
self.poutput(f'args: {args!r}')
|
332
323
|
self.poutput(f'unknowns: {unknown}')
|
333
324
|
```
|
325
|
+
|
334
326
|
"""
|
335
327
|
import functools
|
336
328
|
|
337
329
|
def arg_decorator(func: ArgparseCommandFunc[CommandParent]) -> RawCommandFuncOptionalBoolReturn[CommandParent]:
|
338
|
-
"""
|
339
|
-
|
330
|
+
"""Decorate function that ingests an Argparse Command Function and returns a raw command function.
|
331
|
+
|
340
332
|
The returned function will process the raw input into an argparse Namespace to be passed to the wrapped function.
|
341
333
|
|
342
334
|
:param func: The defined argparse command function
|
@@ -344,10 +336,8 @@ def with_argparser(
|
|
344
336
|
"""
|
345
337
|
|
346
338
|
@functools.wraps(func)
|
347
|
-
def cmd_wrapper(*args: Any, **kwargs:
|
348
|
-
"""
|
349
|
-
Command function wrapper which translates command line into argparse Namespace and calls actual
|
350
|
-
command function
|
339
|
+
def cmd_wrapper(*args: Any, **kwargs: dict[str, Any]) -> Optional[bool]:
|
340
|
+
"""Command function wrapper which translates command line into argparse Namespace and call actual command function.
|
351
341
|
|
352
342
|
:param args: All positional arguments to this function. We're expecting there to be:
|
353
343
|
cmd2_app, statement: Union[Statement, str]
|
@@ -377,21 +367,21 @@ def with_argparser(
|
|
377
367
|
namespace = ns_provider(provider_self if provider_self is not None else cmd2_app)
|
378
368
|
|
379
369
|
try:
|
380
|
-
new_args: Union[
|
370
|
+
new_args: Union[tuple[argparse.Namespace], tuple[argparse.Namespace, list[str]]]
|
381
371
|
if with_unknown_args:
|
382
372
|
new_args = arg_parser.parse_known_args(parsed_arglist, namespace)
|
383
373
|
else:
|
384
374
|
new_args = (arg_parser.parse_args(parsed_arglist, namespace),)
|
385
375
|
ns = new_args[0]
|
386
|
-
except SystemExit:
|
387
|
-
raise Cmd2ArgparseError
|
376
|
+
except SystemExit as exc:
|
377
|
+
raise Cmd2ArgparseError from exc
|
388
378
|
else:
|
389
379
|
# Add wrapped statement to Namespace as cmd2_statement
|
390
|
-
|
380
|
+
ns.cmd2_statement = Cmd2AttributeWrapper(statement)
|
391
381
|
|
392
382
|
# Add wrapped subcmd handler (which can be None) to Namespace as cmd2_handler
|
393
383
|
handler = getattr(ns, constants.NS_ATTR_SUBCMD_HANDLER, None)
|
394
|
-
|
384
|
+
ns.cmd2_handler = Cmd2AttributeWrapper(handler)
|
395
385
|
|
396
386
|
# Remove the subcmd handler attribute from the Namespace
|
397
387
|
# since cmd2_handler is how a developer accesses it.
|
@@ -421,11 +411,10 @@ def as_subcommand_to(
|
|
421
411
|
Callable[[CommandParentType], argparse.ArgumentParser], # Cmd or CommandSet classmethod
|
422
412
|
],
|
423
413
|
*,
|
424
|
-
help: Optional[str] = None,
|
425
|
-
aliases: Optional[
|
414
|
+
help: Optional[str] = None, # noqa: A002
|
415
|
+
aliases: Optional[list[str]] = None,
|
426
416
|
) -> Callable[[ArgparseCommandFunc[CommandParent]], ArgparseCommandFunc[CommandParent]]:
|
427
|
-
"""
|
428
|
-
Tag this method as a subcommand to an existing argparse decorated command.
|
417
|
+
"""Tag this method as a subcommand to an existing argparse decorated command.
|
429
418
|
|
430
419
|
:param command: Command Name. Space-delimited subcommands may optionally be specified
|
431
420
|
:param subcommand: Subcommand name
|
@@ -444,7 +433,7 @@ def as_subcommand_to(
|
|
444
433
|
setattr(func, constants.SUBCMD_ATTR_NAME, subcommand)
|
445
434
|
|
446
435
|
# Keyword arguments for subparsers.add_parser()
|
447
|
-
add_parser_kwargs:
|
436
|
+
add_parser_kwargs: dict[str, Any] = {}
|
448
437
|
if help is not None:
|
449
438
|
add_parser_kwargs['help'] = help
|
450
439
|
if aliases:
|
cmd2/exceptions.py
CHANGED
@@ -1,51 +1,36 @@
|
|
1
|
-
|
2
|
-
"""Custom exceptions for cmd2"""
|
1
|
+
"""Custom exceptions for cmd2."""
|
3
2
|
|
4
|
-
from typing import
|
5
|
-
Any,
|
6
|
-
)
|
3
|
+
from typing import Any
|
7
4
|
|
8
5
|
############################################################################################################
|
9
6
|
# The following exceptions are part of the public API
|
10
7
|
############################################################################################################
|
11
8
|
|
12
9
|
|
13
|
-
class SkipPostcommandHooks(Exception):
|
14
|
-
"""
|
15
|
-
Custom exception class for when a command has a failure bad enough to skip post command
|
16
|
-
hooks, but not bad enough to print the exception to the user.
|
17
|
-
"""
|
18
|
-
|
19
|
-
pass
|
10
|
+
class SkipPostcommandHooks(Exception): # noqa: N818
|
11
|
+
"""For when a command has a failed bad enough to skip post command hooks, but not bad enough to print to the user."""
|
20
12
|
|
21
13
|
|
22
14
|
class Cmd2ArgparseError(SkipPostcommandHooks):
|
23
|
-
"""
|
24
|
-
|
15
|
+
"""A ``SkipPostcommandHooks`` exception for when a command fails to parse its arguments.
|
16
|
+
|
25
17
|
Normally argparse raises a SystemExit exception in these cases. To avoid stopping the command
|
26
18
|
loop, catch the SystemExit and raise this instead. If you still need to run post command hooks
|
27
19
|
after parsing fails, just return instead of raising an exception.
|
28
20
|
"""
|
29
21
|
|
30
|
-
pass
|
31
|
-
|
32
22
|
|
33
23
|
class CommandSetRegistrationError(Exception):
|
34
|
-
"""
|
35
|
-
Exception that can be thrown when an error occurs while a CommandSet is being added or removed
|
36
|
-
from a cmd2 application.
|
37
|
-
"""
|
38
|
-
|
39
|
-
pass
|
24
|
+
"""For when an error occurs while a CommandSet is being added or removed from a cmd2 application."""
|
40
25
|
|
41
26
|
|
42
27
|
class CompletionError(Exception):
|
43
|
-
"""
|
44
|
-
|
45
|
-
just to display a message, even if it's not an error. For instance, ArgparseCompleter raises
|
46
|
-
to display tab completion hints and sets apply_style to False so hints aren't colored like error text.
|
28
|
+
"""Raised during tab completion operations to report any sort of error you want printed.
|
29
|
+
|
30
|
+
This can also be used just to display a message, even if it's not an error. For instance, ArgparseCompleter raises
|
31
|
+
CompletionErrors to display tab completion hints and sets apply_style to False so hints aren't colored like error text.
|
47
32
|
|
48
|
-
Example use cases
|
33
|
+
Example use cases:
|
49
34
|
|
50
35
|
- Reading a database to retrieve a tab completion data set failed
|
51
36
|
- A previous command line argument that determines the data set being completed is invalid
|
@@ -53,8 +38,8 @@ class CompletionError(Exception):
|
|
53
38
|
"""
|
54
39
|
|
55
40
|
def __init__(self, *args: Any, apply_style: bool = True) -> None:
|
56
|
-
"""
|
57
|
-
|
41
|
+
"""Initialize CompletionError instance.
|
42
|
+
|
58
43
|
:param apply_style: If True, then ansi.style_error will be applied to the message text when printed.
|
59
44
|
Set to False in cases where the message text already has the desired style.
|
60
45
|
Defaults to True.
|
@@ -64,16 +49,16 @@ class CompletionError(Exception):
|
|
64
49
|
super().__init__(*args)
|
65
50
|
|
66
51
|
|
67
|
-
class PassThroughException(Exception):
|
68
|
-
"""
|
69
|
-
|
52
|
+
class PassThroughException(Exception): # noqa: N818
|
53
|
+
"""Normally all unhandled exceptions raised during commands get printed to the user.
|
54
|
+
|
70
55
|
This class is used to wrap an exception that should be raised instead of printed.
|
71
56
|
"""
|
72
57
|
|
73
58
|
def __init__(self, *args: Any, wrapped_ex: BaseException) -> None:
|
74
|
-
"""
|
75
|
-
|
76
|
-
:param wrapped_ex: the exception that will be raised
|
59
|
+
"""Initialize PassThroughException instance.
|
60
|
+
|
61
|
+
:param wrapped_ex: the exception that will be raised.
|
77
62
|
"""
|
78
63
|
self.wrapped_ex = wrapped_ex
|
79
64
|
super().__init__(*args)
|
@@ -85,24 +70,16 @@ class PassThroughException(Exception):
|
|
85
70
|
|
86
71
|
|
87
72
|
class Cmd2ShlexError(Exception):
|
88
|
-
"""Raised when shlex fails to parse a command line string in StatementParser"""
|
89
|
-
|
90
|
-
pass
|
73
|
+
"""Raised when shlex fails to parse a command line string in StatementParser."""
|
91
74
|
|
92
75
|
|
93
76
|
class EmbeddedConsoleExit(SystemExit):
|
94
77
|
"""Custom exception class for use with the py command."""
|
95
78
|
|
96
|
-
pass
|
97
|
-
|
98
79
|
|
99
|
-
class EmptyStatement(Exception):
|
80
|
+
class EmptyStatement(Exception): # noqa: N818
|
100
81
|
"""Custom exception class for handling behavior when the user just presses <Enter>."""
|
101
82
|
|
102
|
-
pass
|
103
|
-
|
104
83
|
|
105
84
|
class RedirectionError(Exception):
|
106
|
-
"""Custom exception class for when redirecting or piping output fails"""
|
107
|
-
|
108
|
-
pass
|
85
|
+
"""Custom exception class for when redirecting or piping output fails."""
|