diff options
-rw-r--r-- | CHANGES.md | 9 | ||||
-rwxr-xr-x | cmd2.py | 6 | ||||
-rw-r--r-- | tests/scripts/raises_exception.py | 6 | ||||
-rw-r--r-- | tests/scripts/recursive.py | 6 | ||||
-rw-r--r-- | tests/test_cmd2.py | 48 |
5 files changed, 67 insertions, 8 deletions
@@ -4,12 +4,13 @@ News 0.7.4 ----- -*Release date: TBD* +*Release date: 2017-07-TBD* * Bug fixes * Fixed a couple bugs in interacting with pastebuffer/clipboard on macOS and Linux * Fixed a couple bugs in edit and save commands if called when history is empty * Ability to pipe ``cmd2`` command output to a shell command is now more reliable, particularly on Windows + * Fixed a bug in ``pyscript`` command on Windows related to ``\`` being interpreted as an escape * Enhancements * Ensure that path and shell command tab-completion results are alphabetically sorted * Removed feature for load command to load scripts from URLS @@ -18,8 +19,10 @@ News * These also strongly felt out of place * ``load`` and ``_relative_load`` now require a file path * ``edit`` and ``save`` now use a temporary file if a file path isn't provided - * Load command has better error checking and reporting - * Clipboard copy and paste functionality is now handled by the ``pyperclip`` module + * ``load`` command has better error checking and reporting + * Clipboard copy and paste functionality is now handled by the **pyperclip** module + * NOTE: This adds an additional required 3rd-party dependency + * Added a lot of unit tests 0.7.3 ----- @@ -1421,7 +1421,7 @@ Paths or arguments that contain spaces must be enclosed in quotes arg = shlex.split(arg, posix=POSIX_SHLEX) # Get the absolute path of the script - script_path = os.path.abspath(os.path.expanduser(arg[0])) + script_path = os.path.expanduser(arg[0]) # Save current command line arguments orig_args = sys.argv @@ -1430,8 +1430,8 @@ Paths or arguments that contain spaces must be enclosed in quotes sys.argv = [script_path] sys.argv.extend(arg[1:]) - # Run the script - self.do_py("run('{}')".format(script_path)) + # Run the script - use repr formatting to escape things which need to be escaped to prevent issues on Windows + self.do_py("run({!r})".format(script_path)) # Restore command line arguments to original state sys.argv = orig_args diff --git a/tests/scripts/raises_exception.py b/tests/scripts/raises_exception.py new file mode 100644 index 00000000..738edaf2 --- /dev/null +++ b/tests/scripts/raises_exception.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python +# coding=utf-8 +""" +Example demonstrating what happens when a Python script raises an exception +""" +1 + 'blue' diff --git a/tests/scripts/recursive.py b/tests/scripts/recursive.py new file mode 100644 index 00000000..84f445bb --- /dev/null +++ b/tests/scripts/recursive.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python +# coding=utf-8 +""" +Example demonstrating that running a Python script recursively inside another Python script isn't allowed +""" +cmd('pyscript ../script.py') diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index 7e9769e3..592e6af2 100644 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -131,8 +131,6 @@ def test_base_run_python_script(base_app, capsys, request): assert out == expected -@pytest.mark.skipif(sys.platform == 'win32', - reason="Unit test doesn't work on win32, but feature does") def test_base_run_pyscript(base_app, capsys, request): test_dir = os.path.dirname(request.module.__file__) python_script = os.path.join(test_dir, 'script.py') @@ -142,6 +140,34 @@ def test_base_run_pyscript(base_app, capsys, request): out, err = capsys.readouterr() assert out == expected +def test_recursive_pyscript_not_allowed(base_app, capsys, request): + test_dir = os.path.dirname(request.module.__file__) + python_script = os.path.join(test_dir, 'scripts', 'recursive.py') + expected = 'ERROR: Recursively entering interactive Python consoles is not allowed.\n' + + run_cmd(base_app, "pyscript {}".format(python_script)) + out, err = capsys.readouterr() + assert err == expected + +def test_pyscript_with_nonexist_file(base_app, capsys): + python_script = 'does_not_exist.py' + run_cmd(base_app, "pyscript {}".format(python_script)) + out, err = capsys.readouterr() + assert err.startswith('ERROR: [Errno 2] No such file or directory:') + +def test_pyscript_with_exception(base_app, capsys, request): + test_dir = os.path.dirname(request.module.__file__) + python_script = os.path.join(test_dir, 'scripts', 'raises_exception.py') + run_cmd(base_app, "pyscript {}".format(python_script)) + out, err = capsys.readouterr() + assert err.startswith('Traceback') + assert err.endswith("TypeError: unsupported operand type(s) for +: 'int' and 'str'\n") + +def test_pyscript_requires_an_argument(base_app, capsys): + run_cmd(base_app, "pyscript") + out, err = capsys.readouterr() + assert err.startswith('ERROR: pyscript command requires at least 1 argument ...') + def test_base_error(base_app): out = run_cmd(base_app, 'meow') @@ -957,3 +983,21 @@ Charm us with the {}... # And verify the expected output to stdout assert out == expected + +@pytest.fixture +def noarglist_app(): + cmd2.set_use_arg_list(False) + app = cmd2.Cmd() + app.stdout = StdOut() + return app + +def test_pyscript_with_noarglist(noarglist_app, capsys, request): + test_dir = os.path.dirname(request.module.__file__) + python_script = os.path.join(test_dir, '..', 'examples', 'scripts', 'arg_printer.py') + expected = """Running Python script 'arg_printer.py' which was called with 2 arguments +arg 1: 'foo' +arg 2: 'bar' +""" + run_cmd(noarglist_app, 'pyscript {} foo bar'.format(python_script)) + out, err = capsys.readouterr() + assert out == expected |