cmd2 2.4.2__py3-none-any.whl → 2.5.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 +2 -6
- cmd2/ansi.py +16 -13
- cmd2/argparse_completer.py +1 -10
- cmd2/argparse_custom.py +14 -55
- cmd2/clipboard.py +3 -22
- cmd2/cmd2.py +535 -236
- cmd2/command_definition.py +10 -0
- cmd2/decorators.py +90 -64
- cmd2/exceptions.py +0 -1
- cmd2/history.py +48 -19
- cmd2/parsing.py +36 -30
- cmd2/plugin.py +8 -6
- cmd2/py_bridge.py +14 -3
- cmd2/rl_utils.py +57 -23
- cmd2/table_creator.py +1 -0
- cmd2/transcript.py +3 -2
- cmd2/utils.py +58 -16
- {cmd2-2.4.2.dist-info → cmd2-2.5.0.dist-info}/LICENSE +1 -1
- {cmd2-2.4.2.dist-info → cmd2-2.5.0.dist-info}/METADATA +49 -46
- cmd2-2.5.0.dist-info/RECORD +24 -0
- {cmd2-2.4.2.dist-info → cmd2-2.5.0.dist-info}/WHEEL +1 -1
- cmd2-2.4.2.dist-info/RECORD +0 -24
- {cmd2-2.4.2.dist-info → cmd2-2.5.0.dist-info}/top_level.txt +0 -0
cmd2/plugin.py
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
#
|
2
2
|
# coding=utf-8
|
3
3
|
"""Classes for the cmd2 plugin system"""
|
4
|
+
|
5
|
+
from dataclasses import (
|
6
|
+
dataclass,
|
7
|
+
)
|
4
8
|
from typing import (
|
5
9
|
Optional,
|
6
10
|
)
|
7
11
|
|
8
|
-
import attr
|
9
|
-
|
10
12
|
from .parsing import (
|
11
13
|
Statement,
|
12
14
|
)
|
13
15
|
|
14
16
|
|
15
|
-
@
|
17
|
+
@dataclass
|
16
18
|
class PostparsingData:
|
17
19
|
"""Data class containing information passed to postparsing hook methods"""
|
18
20
|
|
@@ -20,14 +22,14 @@ class PostparsingData:
|
|
20
22
|
statement: Statement
|
21
23
|
|
22
24
|
|
23
|
-
@
|
25
|
+
@dataclass
|
24
26
|
class PrecommandData:
|
25
27
|
"""Data class containing information passed to precommand hook methods"""
|
26
28
|
|
27
29
|
statement: Statement
|
28
30
|
|
29
31
|
|
30
|
-
@
|
32
|
+
@dataclass
|
31
33
|
class PostcommandData:
|
32
34
|
"""Data class containing information passed to postcommand hook methods"""
|
33
35
|
|
@@ -35,7 +37,7 @@ class PostcommandData:
|
|
35
37
|
statement: Statement
|
36
38
|
|
37
39
|
|
38
|
-
@
|
40
|
+
@dataclass
|
39
41
|
class CommandFinalizationData:
|
40
42
|
"""Data class containing information passed to command finalization hook methods"""
|
41
43
|
|
cmd2/py_bridge.py
CHANGED
@@ -83,10 +83,17 @@ class CommandResult(NamedTuple):
|
|
83
83
|
|
84
84
|
|
85
85
|
class PyBridge:
|
86
|
-
"""
|
86
|
+
"""
|
87
|
+
Provides a Python API wrapper for application commands.
|
88
|
+
|
89
|
+
:param cmd2_app: app being controlled by this PyBridge.
|
90
|
+
:param add_to_history: If True, then add all commands run by this PyBridge to history.
|
91
|
+
Defaults to True.
|
92
|
+
"""
|
87
93
|
|
88
|
-
def __init__(self, cmd2_app: 'cmd2.Cmd') -> None:
|
94
|
+
def __init__(self, cmd2_app: 'cmd2.Cmd', *, add_to_history: bool = True) -> None:
|
89
95
|
self._cmd2_app = cmd2_app
|
96
|
+
self._add_to_history = add_to_history
|
90
97
|
self.cmd_echo = False
|
91
98
|
|
92
99
|
# Tells if any of the commands run via __call__ returned True for stop
|
@@ -126,7 +133,11 @@ class PyBridge:
|
|
126
133
|
self._cmd2_app.stdout = cast(TextIO, copy_cmd_stdout)
|
127
134
|
with redirect_stdout(cast(IO[str], copy_cmd_stdout)):
|
128
135
|
with redirect_stderr(cast(IO[str], copy_stderr)):
|
129
|
-
stop = self._cmd2_app.onecmd_plus_hooks(
|
136
|
+
stop = self._cmd2_app.onecmd_plus_hooks(
|
137
|
+
command,
|
138
|
+
add_to_history=self._add_to_history,
|
139
|
+
py_bridge_call=True,
|
140
|
+
)
|
130
141
|
finally:
|
131
142
|
with self._cmd2_app.sigint_protection:
|
132
143
|
self._cmd2_app.stdout = cast(IO[str], copy_cmd_stdout.inner_stream)
|
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
|
)
|
@@ -41,12 +45,10 @@ from .argparse_custom import (
|
|
41
45
|
if TYPE_CHECKING: # pragma: no cover
|
42
46
|
import cmd2 # noqa: F401
|
43
47
|
|
44
|
-
PopenTextIO = subprocess.Popen[
|
45
|
-
|
48
|
+
PopenTextIO = subprocess.Popen[str]
|
46
49
|
else:
|
47
50
|
PopenTextIO = subprocess.Popen
|
48
51
|
|
49
|
-
|
50
52
|
_T = TypeVar('_T')
|
51
53
|
|
52
54
|
|
@@ -91,11 +93,14 @@ def strip_quotes(arg: str) -> str:
|
|
91
93
|
return arg
|
92
94
|
|
93
95
|
|
94
|
-
def
|
95
|
-
"""Converts
|
96
|
+
def to_bool(val: Any) -> bool:
|
97
|
+
"""Converts anything to a boolean based on its value.
|
98
|
+
|
99
|
+
Strings like "True", "true", "False", and "false" return True, True, False, and False
|
100
|
+
respectively. All other values are converted using bool()
|
96
101
|
|
97
|
-
:param val:
|
98
|
-
:return: boolean value expressed in the
|
102
|
+
:param val: value being converted
|
103
|
+
:return: boolean value expressed in the passed in value
|
99
104
|
:raises: ValueError if the string does not contain a value corresponding to a boolean value
|
100
105
|
"""
|
101
106
|
if isinstance(val, str):
|
@@ -103,7 +108,11 @@ def str_to_bool(val: str) -> bool:
|
|
103
108
|
return True
|
104
109
|
elif val.capitalize() == str(False):
|
105
110
|
return False
|
106
|
-
|
111
|
+
raise ValueError("must be True or False (case-insensitive)")
|
112
|
+
elif isinstance(val, bool):
|
113
|
+
return val
|
114
|
+
else:
|
115
|
+
return bool(val)
|
107
116
|
|
108
117
|
|
109
118
|
class Settable:
|
@@ -128,7 +137,7 @@ class Settable:
|
|
128
137
|
:param name: name of the instance attribute being made settable
|
129
138
|
:param val_type: callable used to cast the string value from the command line into its proper type and
|
130
139
|
even validate its value. Setting this to bool provides tab completion for true/false and
|
131
|
-
validation using
|
140
|
+
validation using to_bool(). The val_type function should raise an exception if it fails.
|
132
141
|
This exception will be caught and printed by Cmd.do_set().
|
133
142
|
:param description: string describing this setting
|
134
143
|
:param settable_object: object to which the instance attribute belongs (e.g. self)
|
@@ -149,13 +158,13 @@ class Settable:
|
|
149
158
|
:param choices_provider: function that provides choices for this argument
|
150
159
|
:param completer: tab completion function that provides choices for this argument
|
151
160
|
"""
|
152
|
-
if val_type
|
161
|
+
if val_type is bool:
|
153
162
|
|
154
163
|
def get_bool_choices(_) -> List[str]: # type: ignore[no-untyped-def]
|
155
164
|
"""Used to tab complete lowercase boolean values"""
|
156
165
|
return ['true', 'false']
|
157
166
|
|
158
|
-
val_type =
|
167
|
+
val_type = to_bool
|
159
168
|
choices_provider = cast(ChoicesProviderFunc, get_bool_choices)
|
160
169
|
|
161
170
|
self.name = name
|
@@ -663,19 +672,21 @@ class ProcReader:
|
|
663
672
|
|
664
673
|
# Run until process completes
|
665
674
|
while self._proc.poll() is None:
|
666
|
-
# noinspection PyUnresolvedReferences
|
667
675
|
available = read_stream.peek() # type: ignore[attr-defined]
|
668
676
|
if available:
|
669
677
|
read_stream.read(len(available))
|
670
678
|
self._write_bytes(write_stream, available)
|
671
679
|
|
672
680
|
@staticmethod
|
673
|
-
def _write_bytes(stream: Union[StdSim, TextIO], to_write: bytes) -> None:
|
681
|
+
def _write_bytes(stream: Union[StdSim, TextIO], to_write: Union[bytes, str]) -> None:
|
674
682
|
"""
|
675
683
|
Write bytes to a stream
|
676
684
|
:param stream: the stream being written to
|
677
685
|
:param to_write: the bytes being written
|
678
686
|
"""
|
687
|
+
if isinstance(to_write, str):
|
688
|
+
to_write = to_write.encode()
|
689
|
+
|
679
690
|
try:
|
680
691
|
stream.buffer.write(to_write)
|
681
692
|
except BrokenPipeError:
|
@@ -1179,9 +1190,7 @@ def get_defining_class(meth: Callable[..., Any]) -> Optional[Type[Any]]:
|
|
1179
1190
|
if isinstance(meth, functools.partial):
|
1180
1191
|
return get_defining_class(meth.func)
|
1181
1192
|
if inspect.ismethod(meth) or (
|
1182
|
-
inspect.isbuiltin(meth)
|
1183
|
-
and getattr(meth, '__self__') is not None
|
1184
|
-
and getattr(meth.__self__, '__class__') # type: ignore[attr-defined]
|
1193
|
+
inspect.isbuiltin(meth) and getattr(meth, '__self__') is not None and getattr(meth.__self__, '__class__')
|
1185
1194
|
):
|
1186
1195
|
for cls in inspect.getmro(meth.__self__.__class__): # type: ignore[attr-defined]
|
1187
1196
|
if meth.__name__ in cls.__dict__:
|
@@ -1254,3 +1263,36 @@ def strip_doc_annotations(doc: str) -> str:
|
|
1254
1263
|
elif found_first:
|
1255
1264
|
break
|
1256
1265
|
return cmd_desc
|
1266
|
+
|
1267
|
+
|
1268
|
+
def similarity_function(s1: str, s2: str) -> float:
|
1269
|
+
# The ratio from s1,s2 may be different to s2,s1. We keep the max.
|
1270
|
+
# See https://docs.python.org/3/library/difflib.html#difflib.SequenceMatcher.ratio
|
1271
|
+
return max(SequenceMatcher(None, s1, s2).ratio(), SequenceMatcher(None, s2, s1).ratio())
|
1272
|
+
|
1273
|
+
|
1274
|
+
MIN_SIMIL_TO_CONSIDER = 0.7
|
1275
|
+
|
1276
|
+
|
1277
|
+
def suggest_similar(
|
1278
|
+
requested_command: str, options: Iterable[str], similarity_function_to_use: Optional[Callable[[str, str], float]] = None
|
1279
|
+
) -> Optional[str]:
|
1280
|
+
"""
|
1281
|
+
Given a requested command and an iterable of possible options returns the most similar (if any is similar)
|
1282
|
+
|
1283
|
+
:param requested_command: The command entered by the user
|
1284
|
+
:param options: The list of available commands to search for the most similar
|
1285
|
+
:param similarity_function_to_use: An optional callable to use to compare commands
|
1286
|
+
:return: The most similar command or None if no one is similar
|
1287
|
+
"""
|
1288
|
+
|
1289
|
+
proposed_command = None
|
1290
|
+
best_simil = MIN_SIMIL_TO_CONSIDER
|
1291
|
+
requested_command_to_compare = requested_command.lower()
|
1292
|
+
similarity_function_to_use = similarity_function_to_use or similarity_function
|
1293
|
+
for each in options:
|
1294
|
+
simil = similarity_function_to_use(each.lower(), requested_command_to_compare)
|
1295
|
+
if best_simil < simil:
|
1296
|
+
best_simil = simil
|
1297
|
+
proposed_command = each
|
1298
|
+
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
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: cmd2
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.5.0
|
4
4
|
Summary: cmd2 - quickly build feature-rich and user-friendly interactive command line applications in Python
|
5
5
|
Home-page: https://github.com/python-cmd2/cmd2
|
6
6
|
Author: Catherine Devlin
|
@@ -16,64 +16,69 @@ Classifier: Intended Audience :: System Administrators
|
|
16
16
|
Classifier: License :: OSI Approved :: MIT License
|
17
17
|
Classifier: Programming Language :: Python
|
18
18
|
Classifier: Programming Language :: Python :: 3
|
19
|
-
Classifier: Programming Language :: Python :: 3.6
|
20
|
-
Classifier: Programming Language :: Python :: 3.7
|
21
19
|
Classifier: Programming Language :: Python :: 3.8
|
22
20
|
Classifier: Programming Language :: Python :: 3.9
|
23
21
|
Classifier: Programming Language :: Python :: 3.10
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
24
25
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
25
26
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
26
|
-
Requires-Python: >=3.
|
27
|
+
Requires-Python: >=3.8
|
27
28
|
Description-Content-Type: text/markdown
|
28
29
|
License-File: LICENSE
|
29
|
-
Requires-Dist:
|
30
|
-
Requires-Dist:
|
31
|
-
Requires-Dist:
|
32
|
-
Requires-Dist: importlib-metadata (>=1.6.0) ; python_version < "3.8"
|
33
|
-
Requires-Dist: typing-extensions ; python_version < "3.8"
|
34
|
-
Requires-Dist: pyreadline3 ; sys_platform=='win32'
|
30
|
+
Requires-Dist: pyperclip
|
31
|
+
Requires-Dist: wcwidth
|
32
|
+
Requires-Dist: pyreadline3; sys_platform == "win32"
|
35
33
|
Provides-Extra: dev
|
36
|
-
Requires-Dist: codecov
|
37
|
-
Requires-Dist: doc8
|
38
|
-
Requires-Dist:
|
39
|
-
Requires-Dist:
|
40
|
-
Requires-Dist:
|
41
|
-
Requires-Dist:
|
42
|
-
Requires-Dist: pytest
|
43
|
-
Requires-Dist: pytest
|
44
|
-
Requires-Dist:
|
45
|
-
Requires-Dist: sphinx
|
46
|
-
Requires-Dist: sphinx-
|
47
|
-
Requires-Dist: sphinx-
|
48
|
-
Requires-Dist: twine
|
34
|
+
Requires-Dist: codecov; extra == "dev"
|
35
|
+
Requires-Dist: doc8; extra == "dev"
|
36
|
+
Requires-Dist: invoke; extra == "dev"
|
37
|
+
Requires-Dist: mypy; extra == "dev"
|
38
|
+
Requires-Dist: nox; extra == "dev"
|
39
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
40
|
+
Requires-Dist: pytest-mock; extra == "dev"
|
41
|
+
Requires-Dist: pytest>=4.6; extra == "dev"
|
42
|
+
Requires-Dist: ruff; extra == "dev"
|
43
|
+
Requires-Dist: sphinx; extra == "dev"
|
44
|
+
Requires-Dist: sphinx-autobuild; extra == "dev"
|
45
|
+
Requires-Dist: sphinx-rtd-theme; extra == "dev"
|
46
|
+
Requires-Dist: twine; extra == "dev"
|
47
|
+
Provides-Extra: docs
|
48
|
+
Requires-Dist: setuptools; extra == "docs"
|
49
|
+
Requires-Dist: setuptools-scm; extra == "docs"
|
50
|
+
Requires-Dist: sphinx; extra == "docs"
|
51
|
+
Requires-Dist: sphinx-autobuild; extra == "docs"
|
52
|
+
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
49
53
|
Provides-Extra: test
|
50
|
-
Requires-Dist: codecov
|
51
|
-
Requires-Dist: coverage
|
52
|
-
Requires-Dist: pytest
|
53
|
-
Requires-Dist: pytest-cov
|
54
|
-
Requires-Dist: pytest-mock
|
55
|
-
Requires-Dist: gnureadline
|
54
|
+
Requires-Dist: codecov; extra == "test"
|
55
|
+
Requires-Dist: coverage; extra == "test"
|
56
|
+
Requires-Dist: pytest; extra == "test"
|
57
|
+
Requires-Dist: pytest-cov; extra == "test"
|
58
|
+
Requires-Dist: pytest-mock; extra == "test"
|
59
|
+
Requires-Dist: gnureadline; sys_platform == "darwin" and extra == "test"
|
56
60
|
Provides-Extra: validate
|
57
|
-
Requires-Dist:
|
58
|
-
Requires-Dist:
|
59
|
-
Requires-Dist: types-
|
61
|
+
Requires-Dist: mypy; extra == "validate"
|
62
|
+
Requires-Dist: ruff; extra == "validate"
|
63
|
+
Requires-Dist: types-setuptools; extra == "validate"
|
60
64
|
|
61
65
|
<h1 align="center">cmd2 : immersive interactive command line applications</h1>
|
62
66
|
|
63
67
|
[](https://pypi.python.org/pypi/cmd2/)
|
64
68
|
[](https://github.com/python-cmd2/cmd2/actions?query=workflow%3ACI)
|
65
|
-
[](https://python-cmd2.visualstudio.com/cmd2/_build/latest?definitionId=1&branch=master)
|
66
69
|
[](https://codecov.io/gh/python-cmd2/cmd2)
|
67
70
|
[](http://cmd2.readthedocs.io/en/latest/?badge=latest)
|
68
71
|
<a href="https://discord.gg/RpVG6tk"><img src="https://img.shields.io/badge/chat-on%20discord-7289da.svg" alt="Chat"></a>
|
69
72
|
|
70
73
|
|
71
74
|
<p align="center">
|
72
|
-
<a href="#
|
75
|
+
<a href="#the-developers-toolbox">Developer's Toolbox</a> •
|
76
|
+
<a href="#philosophy">Philosophy</a> •
|
73
77
|
<a href="#installation">Installation</a> •
|
78
|
+
<a href="#documentation">Documentation</a> •
|
74
79
|
<a href="#tutorials">Tutorials</a> •
|
80
|
+
<a href="#hello-world">Hello World</a> •
|
75
81
|
<a href="#projects-using-cmd2">Projects using cmd2</a> •
|
76
|
-
<a href="#version-two-notes">Version 2.0 Notes</a>
|
77
82
|
</p>
|
78
83
|
|
79
84
|
[](https://youtu.be/DDU_JH6cFsA)
|
@@ -91,14 +96,14 @@ The developers toolbox
|
|
91
96
|

|
92
97
|
|
93
98
|
|
94
|
-
When creating solutions developers have no shortage of tools to create rich and smart user interfaces.
|
95
|
-
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.
|
96
|
-
Unfortunately, when CLIs become significantly complex the ease of command discoverability tends to fade quickly.
|
97
|
-
On the other hand, Web and traditional desktop GUIs are first in class when it comes to easily discovering functionality.
|
99
|
+
When creating solutions developers have no shortage of tools to create rich and smart user interfaces.
|
100
|
+
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.
|
101
|
+
Unfortunately, when CLIs become significantly complex the ease of command discoverability tends to fade quickly.
|
102
|
+
On the other hand, Web and traditional desktop GUIs are first in class when it comes to easily discovering functionality.
|
98
103
|
The price we pay for beautifully colored displays is complexity required to aggregate disperate applications into larger systems.
|
99
|
-
`cmd2` fills the niche between high [ease of command discovery](https://clig.dev/#ease-of-discovery) applications and smart workflow automation systems.
|
104
|
+
`cmd2` fills the niche between high [ease of command discovery](https://clig.dev/#ease-of-discovery) applications and smart workflow automation systems.
|
100
105
|
|
101
|
-
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.
|
106
|
+
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.
|
102
107
|
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:
|
103
108
|
|
104
109
|
* Tab Completion
|
@@ -137,7 +142,7 @@ On all operating systems, the latest stable version of `cmd2` can be installed u
|
|
137
142
|
pip install -U cmd2
|
138
143
|
```
|
139
144
|
|
140
|
-
cmd2 works with Python 3.
|
145
|
+
cmd2 works with Python 3.8+ on Windows, macOS, and Linux. It is pure Python code with few 3rd-party dependencies.
|
141
146
|
|
142
147
|
For information on other installation options, see
|
143
148
|
[Installation Instructions](https://cmd2.readthedocs.io/en/latest/overview/installation.html) in the cmd2
|
@@ -156,7 +161,7 @@ The best way to learn the cmd2 api is to delve into the example applications loc
|
|
156
161
|
Tutorials
|
157
162
|
---------
|
158
163
|
|
159
|
-
* PyOhio 2019 presentation:
|
164
|
+
* PyOhio 2019 presentation:
|
160
165
|
* [video](https://www.youtube.com/watch?v=pebeWrTqIIw)
|
161
166
|
* [slides](https://github.com/python-cmd2/talks/blob/master/PyOhio_2019/cmd2-PyOhio_2019.pdf)
|
162
167
|
* [example code](https://github.com/python-cmd2/talks/tree/master/PyOhio_2019/examples)
|
@@ -220,6 +225,4 @@ Projects using cmd2
|
|
220
225
|
Possibly defunct but still good examples
|
221
226
|
|
222
227
|
* [JSShell](https://github.com/Den1al/JSShell)
|
223
|
-
* [FLASHMINGO](https://github.com/fireeye/flashmingo)
|
224
|
-
|
225
|
-
|
228
|
+
* [FLASHMINGO](https://github.com/fireeye/flashmingo)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
cmd2/__init__.py,sha256=C6IHJ_uHgkqejuRwA10IK0-OzPxHKyZbPn82nMUwn-A,2602
|
2
|
+
cmd2/ansi.py,sha256=BasPj_Wla0cEyjpe_zu-cn24CgVdSXK3sfxknLM1WcY,32203
|
3
|
+
cmd2/argparse_completer.py,sha256=6z0zmODqM7vhQhI0c6JUvCmR2V4qfdWQEyTZeNIea8c,36505
|
4
|
+
cmd2/argparse_custom.py,sha256=bbAYRr79ZSJWGchd7trmRQDHWAsSJaW0dTQMp65Mrv4,57806
|
5
|
+
cmd2/clipboard.py,sha256=7EISono76d7djj17hbvR9cCTB7jVGSBkUjgVQiMyUjE,549
|
6
|
+
cmd2/cmd2.py,sha256=V5Wjr3PVhyAgxGaf93Qir76ojy2IZFFlDuNUH5istD4,261033
|
7
|
+
cmd2/command_definition.py,sha256=jm15jQoskQLn5vhvxJinvjHg0KYhzydDU67Dkl734z4,6592
|
8
|
+
cmd2/constants.py,sha256=O5SfjAZGgCl5-IxuHqBMmgbG3HhllxIcZBtkzzLYohA,1865
|
9
|
+
cmd2/decorators.py,sha256=wM0PtalUseDfJVVQV2LkbZbqkZad2XudRiCmARCBWWs,20658
|
10
|
+
cmd2/exceptions.py,sha256=DwX7rQmon4eRyX1ZK4yne4lObdPO1j5Agg3Bav6pXwU,3600
|
11
|
+
cmd2/history.py,sha256=GkJ3pZQNGNoXa9pYLul_iaqLeK132V5nLZZG6MsIEus,15000
|
12
|
+
cmd2/parsing.py,sha256=zWG_iDjUU6TWVNwMeY-yn6AIa2jx12Q9ey4DA9DGZFc,28272
|
13
|
+
cmd2/plugin.py,sha256=CCzzuHeBQbxH7YuG3UCdQ0uArnKYbodjhj-sYCbXSa0,814
|
14
|
+
cmd2/py.typed,sha256=qrkHrYJvGoZpU2BpVLNxJB44LlhqVSKyYOwD_L_1m3s,10
|
15
|
+
cmd2/py_bridge.py,sha256=YUkEnng_kAwnFbh1sPMyeMya_BF7G1kg6MT-6mW-IG4,5022
|
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=M6Ojtq3QQ7NbuvgIcxmhEaN2o-OcxkI_LAXZIxu7DF4,49383
|
20
|
+
cmd2-2.5.0.dist-info/LICENSE,sha256=QXrW0Z0merk9mncyUkn-sgRxhT8_o1dL5HEaBNH47Q4,1099
|
21
|
+
cmd2-2.5.0.dist-info/METADATA,sha256=Tzpgq5IrlMhVx2B8BzdzowdZu3VZQuDV59m5Sq0IOYM,12106
|
22
|
+
cmd2-2.5.0.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
|
23
|
+
cmd2-2.5.0.dist-info/top_level.txt,sha256=gJbOJmyrARwLhm5diXAtzlNQdxbDZ8iRJ8HJi65_5hg,5
|
24
|
+
cmd2-2.5.0.dist-info/RECORD,,
|