Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3254626
Fixed issue where ipy wasn't using the correct name for the PyscriptB…
kmvanbrunt Jul 20, 2019
89523d4
Renamed PyscriptBridge to PyBridge
kmvanbrunt Jul 20, 2019
1fd4e0d
Fix code that appends to clipboard
tleonhardt Jul 20, 2019
e586136
Moved common code out of if/else
tleonhardt Jul 20, 2019
854afc6
Updated CHANGELOG
tleonhardt Jul 20, 2019
5f87e87
Removed unecessary line of code
tleonhardt Jul 20, 2019
01a6f9b
Fixed unit tests
tleonhardt Jul 20, 2019
30c740e
Much simpler solution for clipboard append
tleonhardt Jul 20, 2019
503814c
Removed something left in by accident
tleonhardt Jul 20, 2019
4ed15ba
Fix bogus flake8 warning due to exec()'ed code
tleonhardt Jul 20, 2019
c588079
Removed need to suppress flake8 warning
kmvanbrunt Jul 20, 2019
d020360
Added a self.default_category attribute which gets set to 'Uncategori…
tleonhardt Jul 20, 2019
108d3e5
Added constants for some hardcoded strings
kmvanbrunt Jul 20, 2019
b902a49
Added comments
kmvanbrunt Jul 20, 2019
c86f6c7
Sorting unsorted numbers list in ascending order in AutoCompleter
kmvanbrunt Jul 21, 2019
65a0c99
Fixed unit tests
kmvanbrunt Jul 21, 2019
ed44f15
Renamed bridge to py_bridge
kmvanbrunt Jul 21, 2019
882fa39
Fixed typo in comment
kmvanbrunt Jul 21, 2019
d874597
Print warning if a user tries to run a *.py file with run_script and …
tleonhardt Jul 21, 2019
1393665
Added pwarning()
tleonhardt Jul 21, 2019
a266446
Print warning if a user tries to run something other than a *.py file…
tleonhardt Jul 21, 2019
2bee50a
Added unit test for run_script
kmvanbrunt Jul 21, 2019
7f3c48e
Added mock to unit test
kmvanbrunt Jul 21, 2019
7991e51
Added unit test
kmvanbrunt Jul 21, 2019
4b91f63
Changed warning text
kmvanbrunt Jul 21, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Fixed bug where `history -v` was sometimes showing raw and expanded commands when they weren't different
* Fixed bug where multiline commands were having leading and ending spaces stripped. This would mess up quoted
strings that crossed multiple lines.
* Fixed a bug when appending to the clipboard where contents were in reverse order
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all looks good

* Enhancements
* Greatly simplified using argparse-based tab completion. The new interface is a complete overhaul that breaks
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)
Expand Down Expand Up @@ -31,6 +32,9 @@
sort, but it can be changed to a natural sort by setting the value to NATURAL_SORT_KEY.
* `StatementParser` now expects shortcuts to be passed in as dictionary. This eliminates the step of converting the
shortcuts dictionary into a tuple before creating `StatementParser`.
* Renamed `Cmd.pyscript_name` to `Cmd.py_bridge_name`
* Renamed `Cmd.pystate` to `Cmd.py_locals`
* Renamed `PyscriptBridge` to `PyBridge`

## 0.9.14 (June 29, 2019)
* Enhancements
Expand Down Expand Up @@ -122,7 +126,7 @@
of a `cmd2` based app, you will need to update your code to use `.history.get(1).statement.raw` instead.
* Removed internally used `eos` command that was used to keep track of when a text script's commands ended
* Removed `cmd2` member called `_STOP_AND_EXIT` since it was just a boolean value that should always be True
* Removed `cmd2` member called `_should_quit` since `PyscriptBridge` now handles this logic
* Removed `cmd2` member called `_should_quit` since `PyBridge` now handles this logic
* Removed support for `cmd.cmdqueue`
* `allow_cli_args` is now an argument to __init__ instead of a `cmd2` class member
* **Python 3.4 EOL notice**
Expand Down
2 changes: 1 addition & 1 deletion cmd2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
from .cmd2 import Cmd, Statement, EmptyStatement, categorize
from .cmd2 import with_argument_list, with_argparser, with_argparser_and_unknown_args, with_category
from .constants import DEFAULT_SHORTCUTS
from .pyscript_bridge import CommandResult
from .py_bridge import CommandResult
6 changes: 6 additions & 0 deletions cmd2/argparse_completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"""

import argparse
import numbers
import shutil
from typing import List, Union

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

# If these choices are numbers, and have not yet been sorted, then sort them now
if not self._cmd2_app.matches_sorted and all(isinstance(x, numbers.Number) for x in arg_choices):
arg_choices.sort()
self._cmd2_app.matches_sorted = True

# Since choices can be various types like int, we must convert them to strings
for index, choice in enumerate(arg_choices):
if not isinstance(choice, str):
Expand Down
6 changes: 3 additions & 3 deletions cmd2/argparse_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,13 +154,13 @@ def my_completer_function(text, line, begidx, endidx):

from .ansi import ansi_aware_write, style_error

# Used in nargs ranges to signify there is no maximum
INFINITY = float('inf')

############################################################################################################
# The following are names of custom argparse argument attributes added by cmd2
############################################################################################################

# Used in nargs ranges to signify there is no maximum
INFINITY = float('inf')

# A tuple specifying nargs as a range (min, max)
ATTR_NARGS_RANGE = 'nargs_range'

Expand Down
209 changes: 129 additions & 80 deletions cmd2/cmd2.py

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions cmd2/pyscript_bridge.py → cmd2/py_bridge.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# coding=utf-8
"""
Bridges calls made inside of a pyscript with the Cmd2 host app while maintaining a reasonable
Bridges calls made inside of a Python environment to the Cmd2 host app while maintaining a reasonable
degree of isolation between the two
"""

Expand Down Expand Up @@ -53,7 +53,7 @@ def __bool__(self) -> bool:
return not self.stderr


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

def __call__(self, command: str, echo: Optional[bool] = None) -> CommandResult:
"""
Provide functionality to call application commands by calling PyscriptBridge
Provide functionality to call application commands by calling PyBridge
ex: app('help')
:param command: command line being run
:param echo: if True, output will be echoed to stdout/stderr while the command runs
Expand All @@ -95,7 +95,7 @@ def __call__(self, command: str, echo: Optional[bool] = None) -> CommandResult:
self._cmd2_app.stdout = copy_cmd_stdout
with redirect_stdout(copy_cmd_stdout):
with redirect_stderr(copy_stderr):
stop = self._cmd2_app.onecmd_plus_hooks(command, pyscript_bridge_call=True)
stop = self._cmd2_app.onecmd_plus_hooks(command, py_bridge_call=True)
finally:
with self._cmd2_app.sigint_protection:
self._cmd2_app.stdout = copy_cmd_stdout.inner_stream
Expand Down
2 changes: 1 addition & 1 deletion tests/pyscript/stop.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
app.cmd_echo = True
app('help')

# This will set stop to True in the PyscriptBridge
# This will set stop to True in the PyBridge
app('quit')

# Exercise py_quit() in unit test
Expand Down
21 changes: 15 additions & 6 deletions tests/test_argparse_completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
from cmd2.utils import StdSim, basic_complete
from .conftest import run_cmd, complete_tester

# Lists used in our tests
static_int_choices_list = [-12, -1, -2, 0, 1, 2]
# Lists used in our tests (there is a mix of sorted and unsorted on purpose)
static_int_choices_list = [-1, 1, -2, 2, 0, -12]
static_choices_list = ['static', 'choices', 'stop', 'here']
choices_from_function = ['choices', 'function', 'chatty', 'smith']
choices_from_method = ['choices', 'method', 'most', 'improved']
Expand Down Expand Up @@ -353,12 +353,14 @@ def test_autcomp_flag_completion(ac_app, command_and_args, text, completions):
('--function', 'ch', ['choices', 'chatty']),
('-m', '', choices_from_method),
('--method', 'm', ['method', 'most']),
('-i', '', [str(i) for i in static_int_choices_list]),
('-i', '', static_int_choices_list),
('--int', '1', ['1 ']),
('--int', '-', ['-12', '-1', '-2']),
('--int', '-1', ['-12', '-1'])
('--int', '-', [-1, -2, -12]),
('--int', '-1', [-1, -12])
])
def test_autocomp_flag_choices_completion(ac_app, flag, text, completions):
import numbers

line = 'choices {} {}'.format(flag, text)
endidx = len(line)
begidx = endidx - len(text)
Expand All @@ -369,7 +371,14 @@ def test_autocomp_flag_choices_completion(ac_app, flag, text, completions):
else:
assert first_match is None

assert ac_app.completion_matches == sorted(completions, key=ac_app.default_sort_key)
# Numbers will be sorted in ascending order and then converted to strings by AutoCompleter
if all(isinstance(x, numbers.Number) for x in completions):
completions.sort()
completions = [str(x) for x in completions]
else:
completions.sort(key=ac_app.default_sort_key)

assert ac_app.completion_matches == completions


@pytest.mark.parametrize('pos, text, completions', [
Expand Down
9 changes: 9 additions & 0 deletions tests/test_cmd2.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,15 @@ def test_run_script_with_binary_file(base_app, request):
out, err = run_cmd(base_app, 'run_script {}'.format(filename))
assert "is not an ASCII or UTF-8 encoded text file" in err[0]

def test_run_script_with_python_file(base_app, request):
m = mock.MagicMock(name='input', return_value='2')
builtins.input = m

test_dir = os.path.dirname(request.module.__file__)
filename = os.path.join(test_dir, 'pyscript', 'stop.py')
out, err = run_cmd(base_app, 'run_script {}'.format(filename))
assert "appears to be a Python file" in err[0]

def test_run_script_with_utf8_file(base_app, request):
test_dir = os.path.dirname(request.module.__file__)
filename = os.path.join(test_dir, 'scripts', 'utf8.txt')
Expand Down
18 changes: 17 additions & 1 deletion tests/test_run_pyscript.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@
"""
Unit/functional testing for run_pytest in cmd2
"""
import builtins
import os
from cmd2 import plugin

from cmd2 import plugin
from .conftest import run_cmd

# Python 3.5 had some regressions in the unitest.mock module, so use 3rd party mock if available
try:
import mock
except ImportError:
from unittest import mock

HOOK_OUTPUT = "TEST_OUTPUT"

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

def test_run_pyscript_with_non_python_file(base_app, request):
m = mock.MagicMock(name='input', return_value='2')
builtins.input = m

test_dir = os.path.dirname(request.module.__file__)
filename = os.path.join(test_dir, 'scripts', 'help.txt')
out, err = run_cmd(base_app, 'run_pyscript {}'.format(filename))
assert "does not have a .py extension" in err[0]

def test_run_pyscript_with_exception(base_app, request):
test_dir = os.path.dirname(request.module.__file__)
python_script = os.path.join(test_dir, 'scripts', 'raises_exception.py')
Expand Down