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/rl_utils.py
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
"""
|
3
3
|
Imports the proper Readline for the platform and provides utility functions for it
|
4
4
|
"""
|
5
|
+
|
5
6
|
import sys
|
6
7
|
from enum import (
|
7
8
|
Enum,
|
@@ -28,19 +29,17 @@ from typing import (
|
|
28
29
|
|
29
30
|
# Prefer statically linked gnureadline if installed due to compatibility issues with libedit
|
30
31
|
try:
|
31
|
-
# noinspection PyPackageRequirements
|
32
32
|
import gnureadline as readline # type: ignore[import]
|
33
33
|
except ImportError:
|
34
34
|
# Note: If this actually fails, you should install gnureadline on Linux/Mac or pyreadline3 on Windows.
|
35
35
|
try:
|
36
|
-
# noinspection PyUnresolvedReferences
|
37
36
|
import readline # type: ignore[no-redef]
|
38
37
|
except ImportError: # pragma: no cover
|
39
38
|
pass
|
40
39
|
|
41
40
|
|
42
41
|
class RlType(Enum):
|
43
|
-
"""Readline library types we
|
42
|
+
"""Readline library types we support"""
|
44
43
|
|
45
44
|
GNU = 1
|
46
45
|
PYREADLINE = 2
|
@@ -70,8 +69,8 @@ if 'pyreadline3' in sys.modules:
|
|
70
69
|
)
|
71
70
|
|
72
71
|
# Check if we are running in a terminal
|
73
|
-
if sys.stdout.isatty(): # pragma: no cover
|
74
|
-
|
72
|
+
if sys.stdout is not None and sys.stdout.isatty(): # pragma: no cover
|
73
|
+
|
75
74
|
def enable_win_vt100(handle: HANDLE) -> bool:
|
76
75
|
"""
|
77
76
|
Enables VT100 character sequences in a Windows console
|
@@ -101,27 +100,18 @@ if 'pyreadline3' in sys.modules:
|
|
101
100
|
# Enable VT100 sequences for stdout and stderr
|
102
101
|
STD_OUT_HANDLE = -11
|
103
102
|
STD_ERROR_HANDLE = -12
|
104
|
-
# noinspection PyUnresolvedReferences
|
105
103
|
vt100_stdout_support = enable_win_vt100(readline.rl.console.GetStdHandle(STD_OUT_HANDLE))
|
106
|
-
# noinspection PyUnresolvedReferences
|
107
104
|
vt100_stderr_support = enable_win_vt100(readline.rl.console.GetStdHandle(STD_ERROR_HANDLE))
|
108
105
|
vt100_support = vt100_stdout_support and vt100_stderr_support
|
109
106
|
|
110
107
|
############################################################################################################
|
111
108
|
# pyreadline3 is incomplete in terms of the Python readline API. Add the missing functions we need.
|
112
109
|
############################################################################################################
|
113
|
-
# readline.redisplay()
|
114
|
-
try:
|
115
|
-
getattr(readline, 'redisplay')
|
116
|
-
except AttributeError:
|
117
|
-
# noinspection PyProtectedMember,PyUnresolvedReferences
|
118
|
-
readline.redisplay = readline.rl.mode._update_line
|
119
|
-
|
120
110
|
# readline.remove_history_item()
|
121
111
|
try:
|
122
112
|
getattr(readline, 'remove_history_item')
|
123
113
|
except AttributeError:
|
124
|
-
|
114
|
+
|
125
115
|
def pyreadline_remove_history_item(pos: int) -> None:
|
126
116
|
"""
|
127
117
|
An implementation of remove_history_item() for pyreadline3
|
@@ -141,7 +131,7 @@ if 'pyreadline3' in sys.modules:
|
|
141
131
|
|
142
132
|
elif 'gnureadline' in sys.modules or 'readline' in sys.modules:
|
143
133
|
# We don't support libedit. See top of this file for why.
|
144
|
-
if 'libedit' not in readline.__doc__:
|
134
|
+
if readline.__doc__ is not None and 'libedit' not in readline.__doc__:
|
145
135
|
try:
|
146
136
|
# Load the readline lib so we can access members of it
|
147
137
|
import ctypes
|
@@ -156,7 +146,7 @@ elif 'gnureadline' in sys.modules or 'readline' in sys.modules:
|
|
156
146
|
rl_type = RlType.GNU
|
157
147
|
vt100_support = sys.stdout.isatty()
|
158
148
|
|
159
|
-
# Check if
|
149
|
+
# Check if we loaded a supported version of readline
|
160
150
|
if rl_type == RlType.NONE: # pragma: no cover
|
161
151
|
if not _rl_warn_reason:
|
162
152
|
_rl_warn_reason = (
|
@@ -168,7 +158,6 @@ else:
|
|
168
158
|
rl_warning = ''
|
169
159
|
|
170
160
|
|
171
|
-
# noinspection PyProtectedMember,PyUnresolvedReferences
|
172
161
|
def rl_force_redisplay() -> None: # pragma: no cover
|
173
162
|
"""
|
174
163
|
Causes readline to display the prompt and input text wherever the cursor is and start
|
@@ -191,7 +180,6 @@ def rl_force_redisplay() -> None: # pragma: no cover
|
|
191
180
|
readline.rl.mode._update_line()
|
192
181
|
|
193
182
|
|
194
|
-
# noinspection PyProtectedMember, PyUnresolvedReferences
|
195
183
|
def rl_get_point() -> int: # pragma: no cover
|
196
184
|
"""
|
197
185
|
Returns the offset of the current cursor position in rl_line_buffer
|
@@ -206,9 +194,8 @@ def rl_get_point() -> int: # pragma: no cover
|
|
206
194
|
return 0
|
207
195
|
|
208
196
|
|
209
|
-
# noinspection PyUnresolvedReferences
|
210
197
|
def rl_get_prompt() -> str: # pragma: no cover
|
211
|
-
"""
|
198
|
+
"""Get Readline's prompt"""
|
212
199
|
if rl_type == RlType.GNU:
|
213
200
|
encoded_prompt = ctypes.c_char_p.in_dll(readline_lib, "rl_prompt").value
|
214
201
|
if encoded_prompt is None:
|
@@ -229,7 +216,24 @@ def rl_get_prompt() -> str: # pragma: no cover
|
|
229
216
|
return rl_unescape_prompt(prompt)
|
230
217
|
|
231
218
|
|
232
|
-
#
|
219
|
+
def rl_get_display_prompt() -> str: # pragma: no cover
|
220
|
+
"""
|
221
|
+
Get Readline's currently displayed prompt.
|
222
|
+
|
223
|
+
In GNU Readline, the displayed prompt sometimes differs from the prompt.
|
224
|
+
This occurs in functions that use the prompt string as a message area, such as incremental search.
|
225
|
+
"""
|
226
|
+
if rl_type == RlType.GNU:
|
227
|
+
encoded_prompt = ctypes.c_char_p.in_dll(readline_lib, "rl_display_prompt").value
|
228
|
+
if encoded_prompt is None:
|
229
|
+
prompt = ''
|
230
|
+
else:
|
231
|
+
prompt = encoded_prompt.decode(encoding='utf-8')
|
232
|
+
return rl_unescape_prompt(prompt)
|
233
|
+
else:
|
234
|
+
return rl_get_prompt()
|
235
|
+
|
236
|
+
|
233
237
|
def rl_set_prompt(prompt: str) -> None: # pragma: no cover
|
234
238
|
"""
|
235
239
|
Sets Readline's prompt
|
@@ -246,7 +250,8 @@ def rl_set_prompt(prompt: str) -> None: # pragma: no cover
|
|
246
250
|
|
247
251
|
|
248
252
|
def rl_escape_prompt(prompt: str) -> str:
|
249
|
-
"""
|
253
|
+
"""
|
254
|
+
Overcome bug in GNU Readline in relation to calculation of prompt length in presence of ANSI escape codes
|
250
255
|
|
251
256
|
:param prompt: original prompt
|
252
257
|
:return: prompt safe to pass to GNU Readline
|
@@ -285,3 +290,32 @@ def rl_unescape_prompt(prompt: str) -> str:
|
|
285
290
|
prompt = prompt.replace(escape_start, "").replace(escape_end, "")
|
286
291
|
|
287
292
|
return prompt
|
293
|
+
|
294
|
+
|
295
|
+
def rl_in_search_mode() -> bool: # pragma: no cover
|
296
|
+
"""Check if readline is doing either an incremental (e.g. Ctrl-r) or non-incremental (e.g. Esc-p) search"""
|
297
|
+
if rl_type == RlType.GNU:
|
298
|
+
# GNU Readline defines constants that we can use to determine if in search mode.
|
299
|
+
# RL_STATE_ISEARCH 0x0000080
|
300
|
+
# RL_STATE_NSEARCH 0x0000100
|
301
|
+
IN_SEARCH_MODE = 0x0000180
|
302
|
+
|
303
|
+
readline_state = ctypes.c_int.in_dll(readline_lib, "rl_readline_state").value
|
304
|
+
return bool(IN_SEARCH_MODE & readline_state)
|
305
|
+
elif rl_type == RlType.PYREADLINE:
|
306
|
+
from pyreadline3.modes.emacs import ( # type: ignore[import]
|
307
|
+
EmacsMode,
|
308
|
+
)
|
309
|
+
|
310
|
+
# These search modes only apply to Emacs mode, which is the default.
|
311
|
+
if not isinstance(readline.rl.mode, EmacsMode):
|
312
|
+
return False
|
313
|
+
|
314
|
+
# While in search mode, the current keyevent function is set one of the following.
|
315
|
+
search_funcs = (
|
316
|
+
readline.rl.mode._process_incremental_search_keyevent,
|
317
|
+
readline.rl.mode._process_non_incremental_search_keyevent,
|
318
|
+
)
|
319
|
+
return readline.rl.mode.process_keyevent_queue[-1] in search_funcs
|
320
|
+
else:
|
321
|
+
return False
|
cmd2/table_creator.py
CHANGED
@@ -5,6 +5,7 @@ This API is built upon two core classes: Column and TableCreator
|
|
5
5
|
The general use case is to inherit from TableCreator to create a table class with custom formatting options.
|
6
6
|
There are already implemented and ready-to-use examples of this below TableCreator's code.
|
7
7
|
"""
|
8
|
+
|
8
9
|
import copy
|
9
10
|
import io
|
10
11
|
from collections import (
|
cmd2/transcript.py
CHANGED
@@ -9,6 +9,7 @@ a unit test, comparing the expected output to the actual output.
|
|
9
9
|
This file contains the class necessary to make that work. This
|
10
10
|
class is used in cmd2.py::run_transcript_tests()
|
11
11
|
"""
|
12
|
+
|
12
13
|
import re
|
13
14
|
import unittest
|
14
15
|
from typing import (
|
@@ -60,7 +61,7 @@ class Cmd2TestCase(unittest.TestCase):
|
|
60
61
|
def runTest(self) -> None: # was testall
|
61
62
|
if self.cmdapp:
|
62
63
|
its = sorted(self.transcripts.items())
|
63
|
-
for
|
64
|
+
for fname, transcript in its:
|
64
65
|
self._test_transcript(fname, transcript)
|
65
66
|
|
66
67
|
def _fetchTranscripts(self) -> None:
|
@@ -204,7 +205,7 @@ class Cmd2TestCase(unittest.TestCase):
|
|
204
205
|
# escaped. We found it.
|
205
206
|
break
|
206
207
|
else:
|
207
|
-
# check if the slash is
|
208
|
+
# check if the slash is preceded by a backslash
|
208
209
|
if s[pos - 1 : pos] == '\\':
|
209
210
|
# it is.
|
210
211
|
if in_regex:
|
cmd2/utils.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# coding=utf-8
|
2
2
|
"""Shared utility functions"""
|
3
|
+
|
3
4
|
import argparse
|
4
5
|
import collections
|
5
6
|
import functools
|
@@ -12,6 +13,9 @@ import subprocess
|
|
12
13
|
import sys
|
13
14
|
import threading
|
14
15
|
import unicodedata
|
16
|
+
from difflib import (
|
17
|
+
SequenceMatcher,
|
18
|
+
)
|
15
19
|
from enum import (
|
16
20
|
Enum,
|
17
21
|
)
|
@@ -154,7 +158,7 @@ class Settable:
|
|
154
158
|
:param choices_provider: function that provides choices for this argument
|
155
159
|
:param completer: tab completion function that provides choices for this argument
|
156
160
|
"""
|
157
|
-
if val_type
|
161
|
+
if val_type is bool:
|
158
162
|
|
159
163
|
def get_bool_choices(_) -> List[str]: # type: ignore[no-untyped-def]
|
160
164
|
"""Used to tab complete lowercase boolean values"""
|
@@ -174,17 +178,14 @@ class Settable:
|
|
174
178
|
self.completer = completer
|
175
179
|
|
176
180
|
def get_value(self) -> Any:
|
177
|
-
"""
|
178
|
-
Get the value of the settable attribute
|
179
|
-
:return:
|
180
|
-
"""
|
181
|
+
"""Get the value of the settable attribute."""
|
181
182
|
return getattr(self.settable_obj, self.settable_attrib_name)
|
182
183
|
|
183
|
-
def set_value(self, value: Any) ->
|
184
|
+
def set_value(self, value: Any) -> None:
|
184
185
|
"""
|
185
|
-
Set the settable attribute on the specified destination object
|
186
|
-
|
187
|
-
:
|
186
|
+
Set the settable attribute on the specified destination object.
|
187
|
+
|
188
|
+
:param value: new value to set
|
188
189
|
"""
|
189
190
|
# Run the value through its type function to handle any conversion or validation
|
190
191
|
new_value = self.val_type(value)
|
@@ -201,7 +202,6 @@ class Settable:
|
|
201
202
|
# Check if we need to call an onchange callback
|
202
203
|
if orig_value != new_value and self.onchange_cb:
|
203
204
|
self.onchange_cb(self.name, orig_value, new_value)
|
204
|
-
return new_value
|
205
205
|
|
206
206
|
|
207
207
|
def is_text_file(file_path: str) -> bool:
|
@@ -668,7 +668,6 @@ class ProcReader:
|
|
668
668
|
|
669
669
|
# Run until process completes
|
670
670
|
while self._proc.poll() is None:
|
671
|
-
# noinspection PyUnresolvedReferences
|
672
671
|
available = read_stream.peek() # type: ignore[attr-defined]
|
673
672
|
if available:
|
674
673
|
read_stream.read(len(available))
|
@@ -871,7 +870,8 @@ def align_text(
|
|
871
870
|
)
|
872
871
|
|
873
872
|
if width is None:
|
874
|
-
|
873
|
+
# Prior to Python 3.11 this can return 0, so use a fallback if needed.
|
874
|
+
width = shutil.get_terminal_size().columns or constants.DEFAULT_TERMINAL_WIDTH
|
875
875
|
|
876
876
|
if width < 1:
|
877
877
|
raise ValueError("width must be at least 1")
|
@@ -1152,17 +1152,18 @@ def categorize(func: Union[Callable[..., Any], Iterable[Callable[..., Any]]], ca
|
|
1152
1152
|
:param func: function or list of functions to categorize
|
1153
1153
|
:param category: category to put it in
|
1154
1154
|
|
1155
|
-
|
1155
|
+
Example:
|
1156
|
+
|
1157
|
+
```py
|
1158
|
+
import cmd2
|
1159
|
+
class MyApp(cmd2.Cmd):
|
1160
|
+
def do_echo(self, arglist):
|
1161
|
+
self.poutput(' '.join(arglist)
|
1156
1162
|
|
1157
|
-
|
1158
|
-
|
1159
|
-
>>> def do_echo(self, arglist):
|
1160
|
-
>>> self.poutput(' '.join(arglist)
|
1161
|
-
>>>
|
1162
|
-
>>> cmd2.utils.categorize(do_echo, "Text Processing")
|
1163
|
+
cmd2.utils.categorize(do_echo, "Text Processing")
|
1164
|
+
```
|
1163
1165
|
|
1164
|
-
For an alternative approach to categorizing commands using a decorator, see
|
1165
|
-
:func:`~cmd2.decorators.with_category`
|
1166
|
+
For an alternative approach to categorizing commands using a decorator, see [cmd2.decorators.with_category][]
|
1166
1167
|
"""
|
1167
1168
|
if isinstance(func, Iterable):
|
1168
1169
|
for item in func:
|
@@ -1187,9 +1188,7 @@ def get_defining_class(meth: Callable[..., Any]) -> Optional[Type[Any]]:
|
|
1187
1188
|
if isinstance(meth, functools.partial):
|
1188
1189
|
return get_defining_class(meth.func)
|
1189
1190
|
if inspect.ismethod(meth) or (
|
1190
|
-
inspect.isbuiltin(meth)
|
1191
|
-
and getattr(meth, '__self__') is not None
|
1192
|
-
and getattr(meth.__self__, '__class__') # type: ignore[attr-defined]
|
1191
|
+
inspect.isbuiltin(meth) and getattr(meth, '__self__') is not None and getattr(meth.__self__, '__class__')
|
1193
1192
|
):
|
1194
1193
|
for cls in inspect.getmro(meth.__self__.__class__): # type: ignore[attr-defined]
|
1195
1194
|
if meth.__name__ in cls.__dict__:
|
@@ -1262,3 +1261,36 @@ def strip_doc_annotations(doc: str) -> str:
|
|
1262
1261
|
elif found_first:
|
1263
1262
|
break
|
1264
1263
|
return cmd_desc
|
1264
|
+
|
1265
|
+
|
1266
|
+
def similarity_function(s1: str, s2: str) -> float:
|
1267
|
+
# The ratio from s1,s2 may be different to s2,s1. We keep the max.
|
1268
|
+
# See https://docs.python.org/3/library/difflib.html#difflib.SequenceMatcher.ratio
|
1269
|
+
return max(SequenceMatcher(None, s1, s2).ratio(), SequenceMatcher(None, s2, s1).ratio())
|
1270
|
+
|
1271
|
+
|
1272
|
+
MIN_SIMIL_TO_CONSIDER = 0.7
|
1273
|
+
|
1274
|
+
|
1275
|
+
def suggest_similar(
|
1276
|
+
requested_command: str, options: Iterable[str], similarity_function_to_use: Optional[Callable[[str, str], float]] = None
|
1277
|
+
) -> Optional[str]:
|
1278
|
+
"""
|
1279
|
+
Given a requested command and an iterable of possible options returns the most similar (if any is similar)
|
1280
|
+
|
1281
|
+
:param requested_command: The command entered by the user
|
1282
|
+
:param options: The list of available commands to search for the most similar
|
1283
|
+
:param similarity_function_to_use: An optional callable to use to compare commands
|
1284
|
+
:return: The most similar command or None if no one is similar
|
1285
|
+
"""
|
1286
|
+
|
1287
|
+
proposed_command = None
|
1288
|
+
best_simil = MIN_SIMIL_TO_CONSIDER
|
1289
|
+
requested_command_to_compare = requested_command.lower()
|
1290
|
+
similarity_function_to_use = similarity_function_to_use or similarity_function
|
1291
|
+
for each in options:
|
1292
|
+
simil = similarity_function_to_use(each.lower(), requested_command_to_compare)
|
1293
|
+
if best_simil < simil:
|
1294
|
+
best_simil = simil
|
1295
|
+
proposed_command = each
|
1296
|
+
return proposed_command
|
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2008-
|
3
|
+
Copyright (c) 2008-2024 Catherine Devlin and others
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -0,0 +1,218 @@
|
|
1
|
+
Metadata-Version: 2.2
|
2
|
+
Name: cmd2
|
3
|
+
Version: 2.5.9
|
4
|
+
Summary: cmd2 - quickly build feature-rich and user-friendly interactive command line applications in Python
|
5
|
+
Author: cmd2 Contributors
|
6
|
+
License: The MIT License (MIT)
|
7
|
+
|
8
|
+
Copyright (c) 2008-2024 Catherine Devlin and others
|
9
|
+
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
12
|
+
in the Software without restriction, including without limitation the rights
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
15
|
+
furnished to do so, subject to the following conditions:
|
16
|
+
|
17
|
+
The above copyright notice and this permission notice shall be included in
|
18
|
+
all copies or substantial portions of the Software.
|
19
|
+
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
26
|
+
THE SOFTWARE.
|
27
|
+
|
28
|
+
Keywords: CLI,cmd,command,interactive,prompt,Python
|
29
|
+
Classifier: Development Status :: 5 - Production/Stable
|
30
|
+
Classifier: Environment :: Console
|
31
|
+
Classifier: Operating System :: OS Independent
|
32
|
+
Classifier: Intended Audience :: Developers
|
33
|
+
Classifier: Intended Audience :: System Administrators
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
35
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
36
|
+
Classifier: Programming Language :: Python :: 3.8
|
37
|
+
Classifier: Programming Language :: Python :: 3.9
|
38
|
+
Classifier: Programming Language :: Python :: 3.10
|
39
|
+
Classifier: Programming Language :: Python :: 3.11
|
40
|
+
Classifier: Programming Language :: Python :: 3.12
|
41
|
+
Classifier: Programming Language :: Python :: 3.13
|
42
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
43
|
+
Requires-Python: >=3.8
|
44
|
+
Description-Content-Type: text/markdown
|
45
|
+
License-File: LICENSE
|
46
|
+
Requires-Dist: gnureadline>=8; platform_system == "Darwin"
|
47
|
+
Requires-Dist: pyperclip>=1.8
|
48
|
+
Requires-Dist: pyreadline3>=3.4; platform_system == "Windows"
|
49
|
+
Requires-Dist: wcwidth>=0.2.10
|
50
|
+
|
51
|
+
<h1 align="center">cmd2 : immersive interactive command line applications</h1>
|
52
|
+
|
53
|
+
[](https://pypi.python.org/pypi/cmd2/)
|
54
|
+
[](https://github.com/python-cmd2/cmd2/actions?query=workflow%3ACI)
|
55
|
+
[](https://codecov.io/gh/python-cmd2/cmd2)
|
56
|
+
[](http://cmd2.readthedocs.io/en/latest/?badge=latest)
|
57
|
+
<a href="https://discord.gg/RpVG6tk"><img src="https://img.shields.io/badge/chat-on%20discord-7289da.svg" alt="Chat"></a>
|
58
|
+
|
59
|
+
<p align="center">
|
60
|
+
<a href="#the-developers-toolbox">Developer's Toolbox</a> •
|
61
|
+
<a href="#philosophy">Philosophy</a> •
|
62
|
+
<a href="#installation">Installation</a> •
|
63
|
+
<a href="#documentation">Documentation</a> •
|
64
|
+
<a href="#tutorials">Tutorials</a> •
|
65
|
+
<a href="#hello-world">Hello World</a> •
|
66
|
+
<a href="#projects-using-cmd2">Projects using cmd2</a> •
|
67
|
+
</p>
|
68
|
+
|
69
|
+
[](https://youtu.be/DDU_JH6cFsA)
|
70
|
+
|
71
|
+
cmd2 is a tool for building interactive command line applications in Python. Its goal is to make it
|
72
|
+
quick and easy for developers to build feature-rich and user-friendly interactive command line
|
73
|
+
applications. It provides a simple API which is an extension of Python's built-in
|
74
|
+
[cmd](https://docs.python.org/3/library/cmd.html) module. cmd2 provides a wealth of features on top
|
75
|
+
of cmd to make your life easier and eliminates much of the boilerplate code which would be necessary
|
76
|
+
when using cmd.
|
77
|
+
|
78
|
+
## The developers toolbox
|
79
|
+
|
80
|
+

|
81
|
+
|
82
|
+
When creating solutions developers have no shortage of tools to create rich and smart user interfaces.
|
83
|
+
System administrators have long been duct taping together brittle workflows based on a menagerie of simple command line tools created by strangers on github and the guy down the hall.
|
84
|
+
Unfortunately, when CLIs become significantly complex the ease of command discoverability tends to fade quickly.
|
85
|
+
On the other hand, Web and traditional desktop GUIs are first in class when it comes to easily discovering functionality.
|
86
|
+
The price we pay for beautifully colored displays is complexity required to aggregate disperate applications into larger systems.
|
87
|
+
`cmd2` fills the niche between high [ease of command discovery](https://clig.dev/#ease-of-discovery) applications and smart workflow automation systems.
|
88
|
+
|
89
|
+
The `cmd2` framework provides a great mixture of both worlds. Application designers can easily create complex applications and rely on the cmd2 library to offer effortless user facing help and extensive tab completion.
|
90
|
+
When users become comfortable with functionality, cmd2 turns into a feature rich library enabling a smooth transition to full automation. If designed with enough forethought, a well implemented cmd2 application can serve as a boutique workflow tool. `cmd2` pulls off this flexibility based on two pillars of philosophy:
|
91
|
+
|
92
|
+
- Tab Completion
|
93
|
+
- Automation Transition
|
94
|
+
|
95
|
+
## Philosophy
|
96
|
+
|
97
|
+
<a href="https://imgflip.com/i/63h03x"><img src="https://i.imgflip.com/63h03x.jpg" title="made at imgflip.com" width="70%" height="%70"/></a>
|
98
|
+
|
99
|
+
Deep extensive tab completion and help text generation based on the argparse library create the first pillar of 'ease of command discovery'. The following is a list of features in this category.
|
100
|
+
|
101
|
+
- Great tab completion of commands, subcommands, file system paths, and shell commands.
|
102
|
+
- Custom tab completion for user designed commands via simple function overloading.
|
103
|
+
- Tab completion from `persistent_history_file` sources added with very little friction.
|
104
|
+
- Automatic tab completion of `argparse` flags and optional arguments.
|
105
|
+
- Path completion easily enabled.
|
106
|
+
- When all else fails, custom tab completion based on `choices_provider` can fill any gaps.
|
107
|
+
|
108
|
+
<a href="https://imgflip.com/i/66t0y0"><img src="https://i.imgflip.com/66t0y0.jpg" title="made at imgflip.com" width="70%" height="70%"/></a>
|
109
|
+
|
110
|
+
cmd2 creates the second pillar of 'ease of transition to automation' through alias/macro creation, command line argument parsing and execution of cmd2 scripting.
|
111
|
+
|
112
|
+
- Flexible alias and macro creation for quick abstraction of commands.
|
113
|
+
- Text file scripting of your application with `run_script` (`@`) and `_relative_run_script` (`@@`)
|
114
|
+
- Powerful and flexible built-in Python scripting of your application using the `run_pyscript` command
|
115
|
+
- Transcripts for use with built-in regression can be automatically generated from `history -t` or `run_script -t`
|
116
|
+
|
117
|
+
## Installation
|
118
|
+
|
119
|
+
On all operating systems, the latest stable version of `cmd2` can be installed using pip:
|
120
|
+
|
121
|
+
```bash
|
122
|
+
pip install -U cmd2
|
123
|
+
```
|
124
|
+
|
125
|
+
cmd2 works with Python 3.8+ on Windows, macOS, and Linux. It is pure Python code with few 3rd-party dependencies.
|
126
|
+
|
127
|
+
For information on other installation options, see
|
128
|
+
[Installation Instructions](https://cmd2.readthedocs.io/en/latest/overview/installation.html) in the cmd2
|
129
|
+
documentation.
|
130
|
+
|
131
|
+
## Documentation
|
132
|
+
|
133
|
+
The latest documentation for cmd2 can be read online here: https://cmd2.readthedocs.io/en/latest/
|
134
|
+
|
135
|
+
It is available in HTML, PDF, and ePub formats.
|
136
|
+
|
137
|
+
The best way to learn the cmd2 api is to delve into the example applications located in source under examples.
|
138
|
+
|
139
|
+
## Tutorials
|
140
|
+
|
141
|
+
- PyOhio 2019 presentation:
|
142
|
+
- [video](https://www.youtube.com/watch?v=pebeWrTqIIw)
|
143
|
+
- [slides](https://github.com/python-cmd2/talks/blob/master/PyOhio_2019/cmd2-PyOhio_2019.pdf)
|
144
|
+
- [example code](https://github.com/python-cmd2/talks/tree/master/PyOhio_2019/examples)
|
145
|
+
- [Cookiecutter](https://github.com/cookiecutter/cookiecutter) Templates from community
|
146
|
+
- Basic cookiecutter template for cmd2 application : https://github.com/jayrod/cookiecutter-python-cmd2
|
147
|
+
- Advanced cookiecutter template with external plugin support : https://github.com/jayrod/cookiecutter-python-cmd2-ext-plug
|
148
|
+
- [cmd2 example applications](https://github.com/python-cmd2/cmd2/tree/master/examples)
|
149
|
+
- Basic cmd2 examples to demonstrate how to use various features
|
150
|
+
- [Advanced Examples](https://github.com/jayrod/cmd2-example-apps)
|
151
|
+
- More complex examples that demonstrate more featuers about how to put together a complete application
|
152
|
+
|
153
|
+
## Hello World
|
154
|
+
|
155
|
+
```python
|
156
|
+
#!/usr/bin/env python
|
157
|
+
"""A simple cmd2 application."""
|
158
|
+
import cmd2
|
159
|
+
|
160
|
+
|
161
|
+
class FirstApp(cmd2.Cmd):
|
162
|
+
"""A simple cmd2 application."""
|
163
|
+
|
164
|
+
def do_hello_world(self, _: cmd2.Statement):
|
165
|
+
self.poutput('Hello World')
|
166
|
+
|
167
|
+
if __name__ == '__main__':
|
168
|
+
import sys
|
169
|
+
c = FirstApp()
|
170
|
+
sys.exit(c.cmdloop())
|
171
|
+
|
172
|
+
```
|
173
|
+
|
174
|
+
## Found a bug?
|
175
|
+
|
176
|
+
If you think you've found a bug, please first read through the open [Issues](https://github.com/python-cmd2/cmd2/issues). If you're confident it's a new bug, go ahead and create a new GitHub issue. Be sure to include as much information as possible so we can reproduce the bug. At a minimum, please state the following:
|
177
|
+
|
178
|
+
- `cmd2` version
|
179
|
+
- Python version
|
180
|
+
- OS name and version
|
181
|
+
- What you did to cause the bug to occur
|
182
|
+
- Include any traceback or error message associated with the bug
|
183
|
+
|
184
|
+
## Projects using cmd2
|
185
|
+
|
186
|
+
| Application Name | Description | Organization or Author |
|
187
|
+
| --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
|
188
|
+
| [CephFS Shell](https://github.com/ceph/ceph) | The Ceph File System, or CephFS, is a POSIX-compliant file system built on top of Ceph’s distributed object store | [ceph](https://ceph.com/) |
|
189
|
+
| [garak](https://github.com/NVIDIA/garak) | LLM vulnerability scanner that checks if an LLM can be made to fail in a way we don't want | [NVIDIA](https://github.com/NVIDIA) |
|
190
|
+
| [medusa](https://github.com/Ch0pin/medusa) | Binary instrumentation framework that that automates processes for the dynamic analysis of Android and iOS Applications | [Ch0pin](https://github.com/Ch0pin) |
|
191
|
+
| [InternalBlue](https://github.com/seemoo-lab/internalblue) | Bluetooth experimentation framework for Broadcom and Cypress chips | [Secure Mobile Networking Lab](https://github.com/seemoo-lab) |
|
192
|
+
| [SCCMHunter](https://github.com/garrettfoster13/sccmhunter) | A post-ex tool built to streamline identifying, profiling, and attacking SCCM related assets in an Active Directory domain | [Garret Foster](https://github.com/garrettfoster13) |
|
193
|
+
| [Unipacker](https://github.com/unipacker/unipacker) | Automatic and platform-independent unpacker for Windows binaries based on emulation | [unipacker](https://github.com/unipacker) |
|
194
|
+
| [Frankenstein](https://github.com/seemoo-lab/frankenstein) | Broadcom and Cypress firmware emulation for fuzzing and further full-stack debugging | [Secure Mobile Networking Lab](https://github.com/seemoo-lab) |
|
195
|
+
| [Poseidon](https://github.com/faucetsdn/poseidon) | Leverages software-defined networks (SDNs) to acquire and then feed network traffic to a number of machine learning techniques. | [Faucet SDN](https://github.com/faucetsdn) |
|
196
|
+
| [DFTimewolf](https://github.com/log2timeline/dftimewolf) | A framework for orchestrating forensic collection, processing and data export | [log2timeline](https://github.com/log2timeline) |
|
197
|
+
| [GAP SDK](https://github.com/GreenWaves-Technologies/gap_sdk) | SDK for Greenwaves Technologies' GAP8 IoT Application Processor | [GreenWaves Technologies](https://github.com/GreenWaves-Technologies) |
|
198
|
+
| [REW Sploit](https://github.com/REW-sploit/REW-sploit) | Emulate and Dissect Metasploit Framework (MSF) and other attacks | [REW-sploit](https://github.com/REW-sploit) |
|
199
|
+
| [tomcatmanager](https://github.com/tomcatmanager/tomcatmanager) | A command line tool and python library for managing a tomcat server | [tomcatmanager](https://github.com/tomcatmanager) |
|
200
|
+
| [Falcon Toolkit](https://github.com/CrowdStrike/Falcon-Toolkit) | Unleash the power of the CrowdStrike Falcon Platform at the CLI | [CrowdStrike](https://github.com/CrowdStrike) |
|
201
|
+
| [EXPLIoT](https://gitlab.com/expliot_framework/expliot) | Internet of Things Security Testing and Exploitation framework | [expliot_framework](https://gitlab.com/expliot_framework/) |
|
202
|
+
|
203
|
+
Possibly defunct but still good examples
|
204
|
+
|
205
|
+
| Application Name | Description | Organization or Author |
|
206
|
+
| ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
|
207
|
+
| [Katana](https://github.com/JohnHammond/katana) | Automatic CTF Challenge Solver | [John Hammond](https://github.com/JohnHammond) |
|
208
|
+
| [SatanSword](https://github.com/Lucifer1993/SatanSword) (in Chinese) | Comprehensive Penetration Framework for Red Teaming | [Lucifer1993](https://github.com/Lucifer1993) |
|
209
|
+
| [Jok3r](http://www.jok3r-framework.com) | Network & Web Pentest Automation Framework | [Koutto](https://github.com/koutto) |
|
210
|
+
| [Counterfit](https://github.com/Azure/counterfit) | a CLI that provides a generic automation layer for assessing the security of ML models | [Microsoft Azure](https://github.com/Azure) |
|
211
|
+
| [Overlord](https://github.com/qsecure-labs/overlord) | Red Teaming Infrastructure Automation | [QSecure Labs](https://github.com/qsecure-labs) |
|
212
|
+
| [Automated Reconnaissance Pipeline](https://github.com/epi052/recon-pipeline) | An automated target reconnaissance pipeline | [epi052](https://github.com/epi052) |
|
213
|
+
| [JSShell](https://github.com/Den1al/JSShell) | An interactive multi-user web JavaScript (JS) shell | [Den1al](https://github.com/Den1al) |
|
214
|
+
| [RedShell](https://github.com/Verizon/redshell) | An interactive command prompt for red teaming and pentesting | [Verizon](https://github.com/Verizon) |
|
215
|
+
| [FLASHMINGO](https://github.com/mandiant/flashmingo) | Automatic analysis of SWF files based on some heuristics. Extensible via plugins. | [Mandiant](https://github.com/mandiant) |
|
216
|
+
| [psiTurk](https://github.com/NYUCCL/psiTurk) | An open platform for science on Amazon Mechanical Turk | [NYU Computation and Cognition Lab](https://github.com/NYUCCL) |
|
217
|
+
|
218
|
+
Note: If you have created an application based on `cmd2` that you would like us to mention here, please get in touch.
|
@@ -0,0 +1,24 @@
|
|
1
|
+
cmd2/__init__.py,sha256=C6IHJ_uHgkqejuRwA10IK0-OzPxHKyZbPn82nMUwn-A,2602
|
2
|
+
cmd2/ansi.py,sha256=_3gAbMgqh8ksg43N2xQLp2u8uoB81BUl3CFoBN0990I,32036
|
3
|
+
cmd2/argparse_completer.py,sha256=6z0zmODqM7vhQhI0c6JUvCmR2V4qfdWQEyTZeNIea8c,36505
|
4
|
+
cmd2/argparse_custom.py,sha256=eZS-PodcF-UqhclKr61Wy0KXLRHM382Tk4T7mzlaWko,57689
|
5
|
+
cmd2/clipboard.py,sha256=7EISono76d7djj17hbvR9cCTB7jVGSBkUjgVQiMyUjE,549
|
6
|
+
cmd2/cmd2.py,sha256=GRIBAdRtDs2fXcUkE-IMaKIRLHV2slNbKTyPFq8QMHw,261090
|
7
|
+
cmd2/command_definition.py,sha256=OscFEk-O2N20fb8_fhkczqclaCxOwYyxNTnXWXOlngg,7655
|
8
|
+
cmd2/constants.py,sha256=DioxETv-_HzcMUnjuPyz7Cqw4YEt_MTrzOMotiHj-Jo,1981
|
9
|
+
cmd2/decorators.py,sha256=QVRyGQmAM6YBUhlZHqEVAvt9Tn1NqKGeSjDrLoUHvJg,20261
|
10
|
+
cmd2/exceptions.py,sha256=DwX7rQmon4eRyX1ZK4yne4lObdPO1j5Agg3Bav6pXwU,3600
|
11
|
+
cmd2/history.py,sha256=4iFi0Bny1CTjMx0ByQplrElvlZcus3lUgj2IyBfvAf0,14988
|
12
|
+
cmd2/parsing.py,sha256=58gD8hSvSV3nCliyoEZXJbvbzbnJ_5mSnwhTQhMM0BI,28297
|
13
|
+
cmd2/plugin.py,sha256=CCzzuHeBQbxH7YuG3UCdQ0uArnKYbodjhj-sYCbXSa0,814
|
14
|
+
cmd2/py.typed,sha256=qrkHrYJvGoZpU2BpVLNxJB44LlhqVSKyYOwD_L_1m3s,10
|
15
|
+
cmd2/py_bridge.py,sha256=DJCa7ff-XLwcz7Ij47nrwxgDDVUIVS5bRReLmayok1Q,5016
|
16
|
+
cmd2/rl_utils.py,sha256=HVPdNjuYyU67-XerPUJArmzhohzI1ABrZhU9cLc-EIs,11538
|
17
|
+
cmd2/table_creator.py,sha256=qoxt9s3MxQkfSkp4cIPFMlVzC7kRjUU55p0ow7pFQus,47544
|
18
|
+
cmd2/transcript.py,sha256=I0sD38RbG79Qz9GXIlfh1pHSNmWBTY2SLZAKEdSLWI4,9182
|
19
|
+
cmd2/utils.py,sha256=TElD9YnN5yT7BNuUcKSLpqRLcxrVmx_etkKHETFxRWU,49366
|
20
|
+
cmd2-2.5.9.dist-info/LICENSE,sha256=QXrW0Z0merk9mncyUkn-sgRxhT8_o1dL5HEaBNH47Q4,1099
|
21
|
+
cmd2-2.5.9.dist-info/METADATA,sha256=l1ODgTmFJO7C1Lgro-FIdGMldbIOCHrvmilsRCSUml8,17103
|
22
|
+
cmd2-2.5.9.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
23
|
+
cmd2-2.5.9.dist-info/top_level.txt,sha256=gJbOJmyrARwLhm5diXAtzlNQdxbDZ8iRJ8HJi65_5hg,5
|
24
|
+
cmd2-2.5.9.dist-info/RECORD,,
|