Skip to content

Commit 3a3c867

Browse files
committed
Changed how the pipe file descriptors get opened on Python 3 vs 2
Open them in text mode in Python 3 so self.stdout.write() expects normal Python 3 (unicode) strings. Open them in binary mode in Python 2 so self.stdout.write() expects normal Python 2 (byte) strings. Also fixed a unit test mocking issue on Python 2 to account for the fact that Python 2.7 requires the subprocess32 module instead of subprocess.
1 parent de9cda2 commit 3a3c867

File tree

2 files changed

+18
-7
lines changed

2 files changed

+18
-7
lines changed

cmd2.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -776,11 +776,18 @@ def _redirect_output(self, statement):
776776
# Create a pipe with read and write sides
777777
read_fd, write_fd = os.pipe()
778778

779+
# Make sure that self.stdout.write() expects unicode strings in Python 3 and byte strings in Python 2
780+
write_mode = 'w'
781+
read_mode = 'r'
782+
if six.PY2:
783+
write_mode = 'wb'
784+
read_mode = 'rb'
785+
779786
# Open each side of the pipe and set stdout accordingly
780787
# noinspection PyTypeChecker
781-
self.stdout = io.open(write_fd, 'w')
788+
self.stdout = io.open(write_fd, write_mode)
782789
# noinspection PyTypeChecker
783-
subproc_stdin = io.open(read_fd, 'r')
790+
subproc_stdin = io.open(read_fd, read_mode)
784791

785792
# If you don't set shell=True, subprocess failure will throw an exception
786793
try:

tests/test_cmd2.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ def test_set_quiet(base_app):
113113

114114
def test_base_shell(base_app, monkeypatch):
115115
m = mock.Mock()
116-
monkeypatch.setattr("subprocess.Popen", m)
116+
subprocess = 'subprocess'
117+
if six.PY2:
118+
subprocess = 'subprocess32'
119+
monkeypatch.setattr("{}.Popen".format(subprocess), m)
117120
out = run_cmd(base_app, 'shell echo a')
118121
assert out == []
119122
assert m.called
@@ -554,7 +557,6 @@ def test_pipe_to_shell(base_app, capsys):
554557
# Windows
555558
command = 'help | sort'
556559
# Get help menu and pipe it's output to the sort shell command
557-
run_cmd(base_app, 'help | sort')
558560
# expected = ['', '', '_relative_load edit history py quit save shell show',
559561
# '========================================',
560562
# 'cmdenvironment help load pyscript run set shortcuts',
@@ -578,15 +580,17 @@ def test_pipe_to_shell(base_app, capsys):
578580
# access to the output produced by that subprocess within a unit test, but we can verify that no error occured
579581
assert not err
580582

581-
582-
583583
def test_pipe_to_shell_error(base_app, capsys):
584584
# Try to pipe command output to a shell command that doesn't exist in order to produce an error
585585
run_cmd(base_app, 'help | foobarbaz.this_does_not_exist')
586586
out, err = capsys.readouterr()
587587

588588
assert not out
589-
assert err.startswith("EXCEPTION of type 'FileNotFoundError' occurred with message:")
589+
590+
expected_error = 'FileNotFoundError'
591+
if six.PY2:
592+
expected_error = 'OSError'
593+
assert err.startswith("EXCEPTION of type '{}' occurred with message:".format(expected_error))
590594

591595

592596
@pytest.mark.skipif(not cmd2.can_clip,

0 commit comments

Comments
 (0)