Skip to content

Commit 70bf9e1

Browse files
committed
Began work to minimize public API
1 parent c12ba0f commit 70bf9e1

File tree

12 files changed

+246
-255
lines changed

12 files changed

+246
-255
lines changed

cmd2/cmd2.py

Lines changed: 135 additions & 175 deletions
Large diffs are not rendered by default.

cmd2/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,5 @@
2424
COLORS_NEVER = 'Never'
2525
COLORS_TERMINAL = 'Terminal'
2626
COLORS_ALWAYS = 'Always'
27+
28+
DEFAULT_SHORTCUTS = {'?': 'help', '!': 'shell', '@': 'run_script', '@@': '_relative_run_script'}

cmd2/parsing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ def is_valid_command(self, word: str) -> Tuple[bool, str]:
324324
This string is suitable for inclusion in an error message of your
325325
choice:
326326
327-
valid, errmsg = statement_parser.is_valid_command('>')
327+
valid, errmsg = _statement_parser.is_valid_command('>')
328328
if not valid:
329329
errmsg = "Alias {}".format(errmsg)
330330
"""
@@ -494,7 +494,7 @@ def parse(self, line: str, expand: bool = True) -> Statement:
494494
output = constants.REDIRECTION_APPEND
495495
output_index = append_index
496496

497-
# Check if we are redirecting to a file
497+
# Check if we are _redirecting to a file
498498
if len(tokens) > output_index + 1:
499499
unquoted_path = utils.strip_quotes(tokens[output_index + 1])
500500
if unquoted_path:

cmd2/pyscript_bridge.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ def __call__(self, command: str, echo: Optional[bool] = None) -> CommandResult:
9797
with redirect_stderr(copy_stderr):
9898
stop = self._cmd2_app.onecmd_plus_hooks(command, pyscript_bridge_call=True)
9999
finally:
100-
with self._cmd2_app.sigint_protection:
100+
with self._cmd2_app._sigint_protection:
101101
self._cmd2_app.stdout = copy_cmd_stdout.inner_stream
102102
self.stop = stop or self.stop
103103

cmd2/utils.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,35 @@ def files_from_glob_patterns(patterns: List[str], access=os.F_OK) -> List[str]:
348348
return files
349349

350350

351+
def get_exes_in_path(starts_with: str) -> List[str]:
352+
"""Returns names of executables in a user's path
353+
354+
:param starts_with: what the exes should start with. leave blank for all exes in path.
355+
:return: a list of matching exe names
356+
"""
357+
# Purposely don't match any executable containing wildcards
358+
wildcards = ['*', '?']
359+
for wildcard in wildcards:
360+
if wildcard in starts_with:
361+
return []
362+
363+
# Get a list of every directory in the PATH environment variable and ignore symbolic links
364+
paths = [p for p in os.getenv('PATH').split(os.path.pathsep) if not os.path.islink(p)]
365+
366+
# Use a set to store exe names since there can be duplicates
367+
exes_set = set()
368+
369+
# Find every executable file in the user's path that matches the pattern
370+
for path in paths:
371+
full_path = os.path.join(path, starts_with)
372+
matches = files_from_glob_pattern(full_path + '*', access=os.X_OK)
373+
374+
for match in matches:
375+
exes_set.add(os.path.basename(match))
376+
377+
return list(exes_set)
378+
379+
351380
class StdSim(object):
352381
"""
353382
Class to simulate behavior of sys.stdout or sys.stderr.
@@ -586,7 +615,7 @@ def __init__(self, self_stdout: Union[StdSim, TextIO], sys_stdout: Union[StdSim,
586615
self.saved_sys_stdout = sys_stdout
587616
self.saved_pipe_proc_reader = pipe_proc_reader
588617

589-
# Tells if the command is redirecting
618+
# Tells if the command is _redirecting
590619
self.redirecting = False
591620

592621
# If the command created a process to pipe to, then then is its reader

examples/async_printing.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def __init__(self, *args, **kwargs) -> None:
4848

4949
def _preloop_hook(self) -> None:
5050
""" Start the alerter thread """
51-
# This runs after cmdloop() acquires self.terminal_lock, which will be locked until the prompt appears.
51+
# This runs after cmdloop() acquires self._terminal_lock, which will be locked until the prompt appears.
5252
# Therefore this is the best place to start the alerter thread since there is no risk of it alerting
5353
# before the prompt is displayed. You can also start it via a command if its not something that should
5454
# be running during the entire application. See do_start_alerts().
@@ -60,7 +60,7 @@ def _preloop_hook(self) -> None:
6060
def _postloop_hook(self) -> None:
6161
""" Stops the alerter thread """
6262

63-
# After this function returns, cmdloop() releases self.terminal_lock which could make the alerter
63+
# After this function returns, cmdloop() releases self._terminal_lock which could make the alerter
6464
# thread think the prompt is on screen. Therefore this is the best place to stop the alerter thread.
6565
# You can also stop it via a command. See do_stop_alerts().
6666
self._stop_thread = True
@@ -169,9 +169,9 @@ def _alerter_thread_func(self) -> None:
169169
self._next_alert_time = 0
170170

171171
while not self._stop_thread:
172-
# Always acquire terminal_lock before printing alerts or updating the prompt
172+
# Always acquire _terminal_lock before printing alerts or updating the prompt
173173
# To keep the app responsive, do not block on this call
174-
if self.terminal_lock.acquire(blocking=False):
174+
if self._terminal_lock.acquire(blocking=False):
175175

176176
# Get any alerts that need to be printed
177177
alert_str = self._generate_alert_str()
@@ -191,7 +191,7 @@ def _alerter_thread_func(self) -> None:
191191
self.async_update_prompt(new_prompt)
192192

193193
# Don't forget to release the lock
194-
self.terminal_lock.release()
194+
self._terminal_lock.release()
195195

196196
time.sleep(0.5)
197197

examples/hooks.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def add_whitespace_hook(self, data: cmd2.plugin.PostparsingData) -> cmd2.plugin.
6666
command_pattern = re.compile(r'^([^\s\d]+)(\d+)')
6767
match = command_pattern.search(command)
6868
if match:
69-
data.statement = self.statement_parser.parse("{} {} {}".format(
69+
data.statement = self._statement_parser.parse("{} {} {}".format(
7070
match.group(1),
7171
match.group(2),
7272
'' if data.statement.args is None else data.statement.args
@@ -76,7 +76,7 @@ def add_whitespace_hook(self, data: cmd2.plugin.PostparsingData) -> cmd2.plugin.
7676
def downcase_hook(self, data: cmd2.plugin.PostparsingData) -> cmd2.plugin.PostparsingData:
7777
"""A hook to make uppercase commands lowercase."""
7878
command = data.statement.command.lower()
79-
data.statement = self.statement_parser.parse("{} {}".format(
79+
data.statement = self._statement_parser.parse("{} {}".format(
8080
command,
8181
'' if data.statement.args is None else data.statement.args
8282
))
@@ -90,7 +90,7 @@ def abbrev_hook(self, data: cmd2.plugin.PostparsingData) -> cmd2.plugin.Postpars
9090
possible_cmds = [cmd for cmd in self.get_all_commands() if cmd.startswith(data.statement.command)]
9191
if len(possible_cmds) == 1:
9292
raw = data.statement.raw.replace(data.statement.command, possible_cmds[0], 1)
93-
data.statement = self.statement_parser.parse(raw)
93+
data.statement = self._statement_parser.parse(raw)
9494
return data
9595

9696
@cmd2.with_argument_list

examples/tab_autocompletion.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ def complete_media(self, text, line, begidx, endidx):
382382
self,
383383
arg_choices=choices)
384384

385-
tokens, _ = self.tokens_for_completion(line, begidx, endidx)
385+
tokens, _ = self._tokens_for_completion(line, begidx, endidx)
386386
results = completer.complete_command(tokens, text, line, begidx, endidx)
387387

388388
return results
@@ -443,7 +443,7 @@ def _filter_library(self, text, line, begidx, endidx, full, exclude=()):
443443
# Demonstrates a custom completion function that does more with the command line than is
444444
# allowed by the standard completion functions
445445
def _filter_episodes(self, text, line, begidx, endidx, show_db, user_lib):
446-
tokens, _ = self.tokens_for_completion(line, begidx, endidx)
446+
tokens, _ = self._tokens_for_completion(line, begidx, endidx)
447447
show_id = tokens[3]
448448
if show_id:
449449
if show_id in show_db:
@@ -530,7 +530,7 @@ def complete_library(self, text, line, begidx, endidx):
530530
self,
531531
subcmd_args_lookup=library_subcommand_groups)
532532

533-
tokens, _ = self.tokens_for_completion(line, begidx, endidx)
533+
tokens, _ = self._tokens_for_completion(line, begidx, endidx)
534534
results = completer.complete_command(tokens, text, line, begidx, endidx)
535535

536536
return results

tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ def complete_tester(text: str, line: str, begidx: int, endidx: int, app) -> Opti
176176
:param endidx: the ending index of the prefix text
177177
:param app: the cmd2 app that will run completions
178178
:return: The first matched string or None if there are no matches
179-
Matches are stored in app.completion_matches
179+
Matches are stored in app._completion_matches
180180
These matches also have been sorted by complete()
181181
"""
182182
def get_line():

tests/test_autocompletion.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def test_autocomp_flags(cmd2_app):
7777

7878
first_match = complete_tester(text, line, begidx, endidx, cmd2_app)
7979
assert first_match is not None and \
80-
cmd2_app.completion_matches == ['--duration', '--help', '--type', '-d', '-h', '-t']
80+
cmd2_app._completion_matches == ['--duration', '--help', '--type', '-d', '-h', '-t']
8181

8282
def test_autcomp_hint(cmd2_app, capsys):
8383
text = ''
@@ -106,7 +106,7 @@ def test_autcomp_flag_comp(cmd2_app, capsys):
106106
out, err = capsys.readouterr()
107107

108108
assert first_match is not None and \
109-
cmd2_app.completion_matches == ['--duration ']
109+
cmd2_app._completion_matches == ['--duration ']
110110

111111

112112
def test_autocomp_flags_choices(cmd2_app):
@@ -117,7 +117,7 @@ def test_autocomp_flags_choices(cmd2_app):
117117

118118
first_match = complete_tester(text, line, begidx, endidx, cmd2_app)
119119
assert first_match is not None and \
120-
cmd2_app.completion_matches == ['movie', 'show']
120+
cmd2_app._completion_matches == ['movie', 'show']
121121

122122

123123
def test_autcomp_hint_in_narg_range(cmd2_app, capsys):
@@ -160,7 +160,7 @@ def test_autocomp_subcmd_nested(cmd2_app):
160160

161161
first_match = complete_tester(text, line, begidx, endidx, cmd2_app)
162162
assert first_match is not None and \
163-
cmd2_app.completion_matches == ['add', 'delete', 'list', 'load']
163+
cmd2_app._completion_matches == ['add', 'delete', 'list', 'load']
164164

165165

166166
def test_autocomp_subcmd_flag_choices_append(cmd2_app):
@@ -171,7 +171,7 @@ def test_autocomp_subcmd_flag_choices_append(cmd2_app):
171171

172172
first_match = complete_tester(text, line, begidx, endidx, cmd2_app)
173173
assert first_match is not None and \
174-
cmd2_app.completion_matches == ['G', 'NC-17', 'PG', 'PG-13', 'R']
174+
cmd2_app._completion_matches == ['G', 'NC-17', 'PG', 'PG-13', 'R']
175175

176176
def test_autocomp_subcmd_flag_choices_append_exclude(cmd2_app):
177177
text = ''
@@ -181,7 +181,7 @@ def test_autocomp_subcmd_flag_choices_append_exclude(cmd2_app):
181181

182182
first_match = complete_tester(text, line, begidx, endidx, cmd2_app)
183183
assert first_match is not None and \
184-
cmd2_app.completion_matches == ['G', 'NC-17', 'R']
184+
cmd2_app._completion_matches == ['G', 'NC-17', 'R']
185185

186186

187187
def test_autocomp_subcmd_flag_comp_func(cmd2_app):
@@ -192,7 +192,7 @@ def test_autocomp_subcmd_flag_comp_func(cmd2_app):
192192

193193
first_match = complete_tester(text, line, begidx, endidx, cmd2_app)
194194
assert first_match is not None and \
195-
cmd2_app.completion_matches == ['Adam Driver', 'Alec Guinness', 'Andy Serkis', 'Anthony Daniels']
195+
cmd2_app._completion_matches == ['Adam Driver', 'Alec Guinness', 'Andy Serkis', 'Anthony Daniels']
196196

197197

198198
def test_autocomp_subcmd_flag_comp_list(cmd2_app):
@@ -213,7 +213,7 @@ def test_autocomp_subcmd_flag_comp_func_attr(cmd2_app):
213213

214214
first_match = complete_tester(text, line, begidx, endidx, cmd2_app)
215215
assert first_match is not None and \
216-
cmd2_app.completion_matches == ['Adam Driver', 'Alec Guinness', 'Andy Serkis', 'Anthony Daniels']
216+
cmd2_app._completion_matches == ['Adam Driver', 'Alec Guinness', 'Andy Serkis', 'Anthony Daniels']
217217

218218

219219
def test_autocomp_subcmd_flag_comp_list_attr(cmd2_app):
@@ -244,7 +244,7 @@ def test_autocomp_pos_after_flag(cmd2_app):
244244

245245
first_match = complete_tester(text, line, begidx, endidx, cmd2_app)
246246
assert first_match is not None and \
247-
cmd2_app.completion_matches == ['John Boyega" ']
247+
cmd2_app._completion_matches == ['John Boyega" ']
248248

249249

250250
def test_autocomp_custom_func_list_arg(cmd2_app):
@@ -255,7 +255,7 @@ def test_autocomp_custom_func_list_arg(cmd2_app):
255255

256256
first_match = complete_tester(text, line, begidx, endidx, cmd2_app)
257257
assert first_match is not None and \
258-
cmd2_app.completion_matches == ['SW_CW', 'SW_REB', 'SW_TCW']
258+
cmd2_app._completion_matches == ['SW_CW', 'SW_REB', 'SW_TCW']
259259

260260

261261
def test_autocomp_custom_func_list_and_dict_arg(cmd2_app):
@@ -266,7 +266,7 @@ def test_autocomp_custom_func_list_and_dict_arg(cmd2_app):
266266

267267
first_match = complete_tester(text, line, begidx, endidx, cmd2_app)
268268
assert first_match is not None and \
269-
cmd2_app.completion_matches == ['S01E02', 'S01E03', 'S02E01', 'S02E03']
269+
cmd2_app._completion_matches == ['S01E02', 'S01E03', 'S02E01', 'S02E03']
270270

271271

272272
def test_autocomp_custom_func_dict_arg(cmd2_app):
@@ -277,7 +277,7 @@ def test_autocomp_custom_func_dict_arg(cmd2_app):
277277

278278
first_match = complete_tester(text, line, begidx, endidx, cmd2_app)
279279
assert first_match is not None and \
280-
cmd2_app.completion_matches == ['/home/user/another.db', '/home/user/file space.db', '/home/user/file.db']
280+
cmd2_app._completion_matches == ['/home/user/another.db', '/home/user/file space.db', '/home/user/file.db']
281281

282282

283283
def test_argparse_remainder_flag_completion(cmd2_app):
@@ -333,7 +333,7 @@ def test_completion_after_double_dash(cmd2_app):
333333

334334
# Since -- is the last token, then it should show flag choices
335335
first_match = complete_tester(text, line, begidx, endidx, cmd2_app)
336-
assert first_match is not None and '--help' in cmd2_app.completion_matches
336+
assert first_match is not None and '--help' in cmd2_app._completion_matches
337337

338338
# Test -- to end all flag completion
339339
text = '--'

0 commit comments

Comments
 (0)