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/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
- @attr.s(auto_attribs=True)
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
- @attr.s(auto_attribs=True)
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
- @attr.s(auto_attribs=True)
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
- @attr.s(auto_attribs=True)
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
- """Provides a Python API wrapper for application commands."""
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(command, py_bridge_call=True)
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 recognize"""
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
- # noinspection PyPep8Naming,PyUnresolvedReferences
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
- # noinspection PyProtectedMember,PyUnresolvedReferences
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 readline was loaded
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
- """Gets Readline's current prompt"""
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
- # noinspection PyUnresolvedReferences
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
- """Overcome bug in GNU Readline in relation to calculation of prompt length in presence of ANSI escape codes
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 (fname, transcript) in its:
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 preceeded by a backslash
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[bytes]
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 str_to_bool(val: str) -> bool:
95
- """Converts a string to a boolean based on its value.
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: string being converted
98
- :return: boolean value expressed in the string
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
- raise ValueError("must be True or False (case-insensitive)")
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 str_to_bool(). The val_type function should raise an exception if it fails.
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 == bool:
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 = str_to_bool
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-2022 Catherine Devlin and others
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.4.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.6
27
+ Requires-Python: >=3.8
27
28
  Description-Content-Type: text/markdown
28
29
  License-File: LICENSE
29
- Requires-Dist: attrs (>=16.3.0)
30
- Requires-Dist: pyperclip (>=1.6)
31
- Requires-Dist: wcwidth (>=0.1.7)
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 ; extra == 'dev'
37
- Requires-Dist: doc8 ; extra == 'dev'
38
- Requires-Dist: flake8 ; extra == 'dev'
39
- Requires-Dist: invoke ; extra == 'dev'
40
- Requires-Dist: mypy (==0.902) ; extra == 'dev'
41
- Requires-Dist: nox ; extra == 'dev'
42
- Requires-Dist: pytest (>=4.6) ; extra == 'dev'
43
- Requires-Dist: pytest-cov ; extra == 'dev'
44
- Requires-Dist: pytest-mock ; extra == 'dev'
45
- Requires-Dist: sphinx ; extra == 'dev'
46
- Requires-Dist: sphinx-rtd-theme ; extra == 'dev'
47
- Requires-Dist: sphinx-autobuild ; extra == 'dev'
48
- Requires-Dist: twine (>=1.11) ; extra == 'dev'
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 ; extra == 'test'
51
- Requires-Dist: coverage ; extra == 'test'
52
- Requires-Dist: pytest (>=4.6) ; extra == 'test'
53
- Requires-Dist: pytest-cov ; extra == 'test'
54
- Requires-Dist: pytest-mock ; extra == 'test'
55
- Requires-Dist: gnureadline ; (sys_platform == "darwin") and extra == 'test'
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: flake8 ; extra == 'validate'
58
- Requires-Dist: mypy (==0.902) ; extra == 'validate'
59
- Requires-Dist: types-pkg-resources ; extra == 'validate'
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
  [![Latest Version](https://img.shields.io/pypi/v/cmd2.svg?style=flat-square&label=latest%20stable%20version)](https://pypi.python.org/pypi/cmd2/)
64
68
  [![GitHub Actions](https://github.com/python-cmd2/cmd2/workflows/CI/badge.svg)](https://github.com/python-cmd2/cmd2/actions?query=workflow%3ACI)
65
- [![Azure Build status](https://python-cmd2.visualstudio.com/cmd2/_apis/build/status/python-cmd2.cmd2?branch=master)](https://python-cmd2.visualstudio.com/cmd2/_build/latest?definitionId=1&branch=master)
66
69
  [![codecov](https://codecov.io/gh/python-cmd2/cmd2/branch/master/graph/badge.svg)](https://codecov.io/gh/python-cmd2/cmd2)
67
70
  [![Documentation Status](https://readthedocs.org/projects/cmd2/badge/?version=latest)](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="#main-features">Main Features</a> •
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
  [![Screenshot](https://raw.githubusercontent.com/python-cmd2/cmd2/master/cmd2.png)](https://youtu.be/DDU_JH6cFsA)
@@ -91,14 +96,14 @@ The developers toolbox
91
96
  ![system schema](https://raw.githubusercontent.com/python-cmd2/cmd2/master/.github/images/graph.drawio.png)
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.6+ on Windows, macOS, and Linux. It is pure Python code with few 3rd-party dependencies.
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.37.1)
2
+ Generator: bdist_wheel (0.44.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5