Skip to content

Commit 73d1c34

Browse files
authored
Merge pull request #737 from python-cmd2/renames
Changes made while preparing for PyOhio presentation
2 parents 578593f + 4b91f63 commit 73d1c34

File tree

10 files changed

+190
-97
lines changed

10 files changed

+190
-97
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Fixed bug where `history -v` was sometimes showing raw and expanded commands when they weren't different
55
* Fixed bug where multiline commands were having leading and ending spaces stripped. This would mess up quoted
66
strings that crossed multiple lines.
7+
* Fixed a bug when appending to the clipboard where contents were in reverse order
78
* Enhancements
89
* Greatly simplified using argparse-based tab completion. The new interface is a complete overhaul that breaks
910
the previous way of specifying completion and choices functions. See header of [argparse_custom.py](https://github.com/python-cmd2/cmd2/blob/master/cmd2/argparse_custom.py)
@@ -31,6 +32,9 @@
3132
sort, but it can be changed to a natural sort by setting the value to NATURAL_SORT_KEY.
3233
* `StatementParser` now expects shortcuts to be passed in as dictionary. This eliminates the step of converting the
3334
shortcuts dictionary into a tuple before creating `StatementParser`.
35+
* Renamed `Cmd.pyscript_name` to `Cmd.py_bridge_name`
36+
* Renamed `Cmd.pystate` to `Cmd.py_locals`
37+
* Renamed `PyscriptBridge` to `PyBridge`
3438

3539
## 0.9.14 (June 29, 2019)
3640
* Enhancements
@@ -122,7 +126,7 @@
122126
of a `cmd2` based app, you will need to update your code to use `.history.get(1).statement.raw` instead.
123127
* Removed internally used `eos` command that was used to keep track of when a text script's commands ended
124128
* Removed `cmd2` member called `_STOP_AND_EXIT` since it was just a boolean value that should always be True
125-
* Removed `cmd2` member called `_should_quit` since `PyscriptBridge` now handles this logic
129+
* Removed `cmd2` member called `_should_quit` since `PyBridge` now handles this logic
126130
* Removed support for `cmd.cmdqueue`
127131
* `allow_cli_args` is now an argument to __init__ instead of a `cmd2` class member
128132
* **Python 3.4 EOL notice**

cmd2/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
from .cmd2 import Cmd, Statement, EmptyStatement, categorize
1616
from .cmd2 import with_argument_list, with_argparser, with_argparser_and_unknown_args, with_category
1717
from .constants import DEFAULT_SHORTCUTS
18-
from .pyscript_bridge import CommandResult
18+
from .py_bridge import CommandResult

cmd2/argparse_completer.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"""
88

99
import argparse
10+
import numbers
1011
import shutil
1112
from typing import List, Union
1213

@@ -499,6 +500,11 @@ def _resolve_choices_for_arg(self, arg: argparse.Action, used_values=()) -> List
499500
# Since arg_choices can be any iterable type, convert to a list
500501
arg_choices = list(arg_choices)
501502

503+
# If these choices are numbers, and have not yet been sorted, then sort them now
504+
if not self._cmd2_app.matches_sorted and all(isinstance(x, numbers.Number) for x in arg_choices):
505+
arg_choices.sort()
506+
self._cmd2_app.matches_sorted = True
507+
502508
# Since choices can be various types like int, we must convert them to strings
503509
for index, choice in enumerate(arg_choices):
504510
if not isinstance(choice, str):

cmd2/argparse_custom.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,13 +154,13 @@ def my_completer_function(text, line, begidx, endidx):
154154

155155
from .ansi import ansi_aware_write, style_error
156156

157+
# Used in nargs ranges to signify there is no maximum
158+
INFINITY = float('inf')
159+
157160
############################################################################################################
158161
# The following are names of custom argparse argument attributes added by cmd2
159162
############################################################################################################
160163

161-
# Used in nargs ranges to signify there is no maximum
162-
INFINITY = float('inf')
163-
164164
# A tuple specifying nargs as a range (min, max)
165165
ATTR_NARGS_RANGE = 'nargs_range'
166166

cmd2/cmd2.py

Lines changed: 129 additions & 80 deletions
Large diffs are not rendered by default.
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# coding=utf-8
22
"""
3-
Bridges calls made inside of a pyscript with the Cmd2 host app while maintaining a reasonable
3+
Bridges calls made inside of a Python environment to the Cmd2 host app while maintaining a reasonable
44
degree of isolation between the two
55
"""
66

@@ -53,7 +53,7 @@ def __bool__(self) -> bool:
5353
return not self.stderr
5454

5555

56-
class PyscriptBridge(object):
56+
class PyBridge(object):
5757
"""Provides a Python API wrapper for application commands."""
5858
def __init__(self, cmd2_app):
5959
self._cmd2_app = cmd2_app
@@ -70,7 +70,7 @@ def __dir__(self):
7070

7171
def __call__(self, command: str, echo: Optional[bool] = None) -> CommandResult:
7272
"""
73-
Provide functionality to call application commands by calling PyscriptBridge
73+
Provide functionality to call application commands by calling PyBridge
7474
ex: app('help')
7575
:param command: command line being run
7676
:param echo: if True, output will be echoed to stdout/stderr while the command runs
@@ -95,7 +95,7 @@ def __call__(self, command: str, echo: Optional[bool] = None) -> CommandResult:
9595
self._cmd2_app.stdout = copy_cmd_stdout
9696
with redirect_stdout(copy_cmd_stdout):
9797
with redirect_stderr(copy_stderr):
98-
stop = self._cmd2_app.onecmd_plus_hooks(command, pyscript_bridge_call=True)
98+
stop = self._cmd2_app.onecmd_plus_hooks(command, py_bridge_call=True)
9999
finally:
100100
with self._cmd2_app.sigint_protection:
101101
self._cmd2_app.stdout = copy_cmd_stdout.inner_stream

tests/pyscript/stop.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
app.cmd_echo = True
33
app('help')
44

5-
# This will set stop to True in the PyscriptBridge
5+
# This will set stop to True in the PyBridge
66
app('quit')
77

88
# Exercise py_quit() in unit test

tests/test_argparse_completer.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
from cmd2.utils import StdSim, basic_complete
1414
from .conftest import run_cmd, complete_tester
1515

16-
# Lists used in our tests
17-
static_int_choices_list = [-12, -1, -2, 0, 1, 2]
16+
# Lists used in our tests (there is a mix of sorted and unsorted on purpose)
17+
static_int_choices_list = [-1, 1, -2, 2, 0, -12]
1818
static_choices_list = ['static', 'choices', 'stop', 'here']
1919
choices_from_function = ['choices', 'function', 'chatty', 'smith']
2020
choices_from_method = ['choices', 'method', 'most', 'improved']
@@ -353,12 +353,14 @@ def test_autcomp_flag_completion(ac_app, command_and_args, text, completions):
353353
('--function', 'ch', ['choices', 'chatty']),
354354
('-m', '', choices_from_method),
355355
('--method', 'm', ['method', 'most']),
356-
('-i', '', [str(i) for i in static_int_choices_list]),
356+
('-i', '', static_int_choices_list),
357357
('--int', '1', ['1 ']),
358-
('--int', '-', ['-12', '-1', '-2']),
359-
('--int', '-1', ['-12', '-1'])
358+
('--int', '-', [-1, -2, -12]),
359+
('--int', '-1', [-1, -12])
360360
])
361361
def test_autocomp_flag_choices_completion(ac_app, flag, text, completions):
362+
import numbers
363+
362364
line = 'choices {} {}'.format(flag, text)
363365
endidx = len(line)
364366
begidx = endidx - len(text)
@@ -369,7 +371,14 @@ def test_autocomp_flag_choices_completion(ac_app, flag, text, completions):
369371
else:
370372
assert first_match is None
371373

372-
assert ac_app.completion_matches == sorted(completions, key=ac_app.default_sort_key)
374+
# Numbers will be sorted in ascending order and then converted to strings by AutoCompleter
375+
if all(isinstance(x, numbers.Number) for x in completions):
376+
completions.sort()
377+
completions = [str(x) for x in completions]
378+
else:
379+
completions.sort(key=ac_app.default_sort_key)
380+
381+
assert ac_app.completion_matches == completions
373382

374383

375384
@pytest.mark.parametrize('pos, text, completions', [

tests/test_cmd2.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,15 @@ def test_run_script_with_binary_file(base_app, request):
331331
out, err = run_cmd(base_app, 'run_script {}'.format(filename))
332332
assert "is not an ASCII or UTF-8 encoded text file" in err[0]
333333

334+
def test_run_script_with_python_file(base_app, request):
335+
m = mock.MagicMock(name='input', return_value='2')
336+
builtins.input = m
337+
338+
test_dir = os.path.dirname(request.module.__file__)
339+
filename = os.path.join(test_dir, 'pyscript', 'stop.py')
340+
out, err = run_cmd(base_app, 'run_script {}'.format(filename))
341+
assert "appears to be a Python file" in err[0]
342+
334343
def test_run_script_with_utf8_file(base_app, request):
335344
test_dir = os.path.dirname(request.module.__file__)
336345
filename = os.path.join(test_dir, 'scripts', 'utf8.txt')

tests/test_run_pyscript.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,18 @@
33
"""
44
Unit/functional testing for run_pytest in cmd2
55
"""
6+
import builtins
67
import os
7-
from cmd2 import plugin
88

9+
from cmd2 import plugin
910
from .conftest import run_cmd
1011

12+
# Python 3.5 had some regressions in the unitest.mock module, so use 3rd party mock if available
13+
try:
14+
import mock
15+
except ImportError:
16+
from unittest import mock
17+
1118
HOOK_OUTPUT = "TEST_OUTPUT"
1219

1320
def cmdfinalization_hook(data: plugin.CommandFinalizationData) -> plugin.CommandFinalizationData:
@@ -36,6 +43,15 @@ def test_run_pyscript_with_nonexist_file(base_app):
3643
out, err = run_cmd(base_app, "run_pyscript {}".format(python_script))
3744
assert "Error opening script file" in err[0]
3845

46+
def test_run_pyscript_with_non_python_file(base_app, request):
47+
m = mock.MagicMock(name='input', return_value='2')
48+
builtins.input = m
49+
50+
test_dir = os.path.dirname(request.module.__file__)
51+
filename = os.path.join(test_dir, 'scripts', 'help.txt')
52+
out, err = run_cmd(base_app, 'run_pyscript {}'.format(filename))
53+
assert "does not have a .py extension" in err[0]
54+
3955
def test_run_pyscript_with_exception(base_app, request):
4056
test_dir = os.path.dirname(request.module.__file__)
4157
python_script = os.path.join(test_dir, 'scripts', 'raises_exception.py')

0 commit comments

Comments
 (0)