Skip to content

Conversation

@tleonhardt
Copy link
Member

@tleonhardt tleonhardt commented Aug 8, 2017

The previous implementation for piping command output to a shell command utilized a temporary file and only once the command was completely done did it "pipe" the command output to the shell command by using the temporary file as the commands input. This approach had many disadvantages, including:

  • No output would be seen from long running commands until the very end
  • Many shell commands behave entirely differently when piped to versus have input redirected to them from a file (for example, less and more didn't work with this previous approach)

Now a real pipe is created to a subprocess. This approach should "just work like intended" with all commands and has many advantages, including:

  • Output from long running commands will be seen immediately
  • Behavior in your cmd2 application should behave just like it would in a normal shell such as Bash

One downside is to work properly on Python 2.7, it requires the subprocess32 module which is the subprocess module from Python 3.2 backported to Python 2.7. Another downside, is that unit testing the feature is now more difficult.

A more subtle downside is that users now need to be careful when designing multi-threaded cmd2 applications that do command processing in other threads where those threads can make calls to self.stdout.write. If the end user does something to manually close the piped shell command before the cmd2 command is finished executing, then a BrokenPipe exception can occur. This is easily fixed by putting a try/except to catch Broken Pipe errors in one strategic location in your code. You just need to be aware of this.

This closes #197

…ommand

Now a real pipe is created to a subprocess.  This has many advantages and should "just work" like intended with all commands.

One downside is to work properly on Python 2.7, it requires the subprocess32 module which is the subprocess module from Python 3.2 backported to Python 2.7.  Another downside, is that unit testing the feature is now more difficult.

This still needs to be tested for compatibility across all OSes and supported versions of Python.

The user needs to be careful if designing multi-threaded cmd2 applications that do command processing in other threads and those threads can make calls to self.stdout.write to put in a try/except to catch Broken Pipe errors which can occur for long running commands if the user closes the shell subprocess before the command is finished.
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.
@tleonhardt tleonhardt added this to the 0.7.6 milestone Aug 8, 2017
@tleonhardt tleonhardt self-assigned this Aug 8, 2017
@codecov
Copy link

codecov bot commented Aug 8, 2017

Codecov Report

Merging #198 into master will decrease coverage by 0.3%.
The diff coverage is 92.59%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #198      +/-   ##
==========================================
- Coverage    97.1%   96.79%   -0.31%     
==========================================
  Files           1        1              
  Lines        1139     1155      +16     
==========================================
+ Hits         1106     1118      +12     
- Misses         33       37       +4
Impacted Files Coverage Δ
cmd2.py 96.79% <92.59%> (-0.31%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 11f14ed...8f32eea. Read the comment docs.

…ut().

Modified implementation of poutput() to accept an optional "end" argument which can change the ending to something other than a newline or simply suppress adding a newline.  Also added a try/except to catch BrokenPipeError exceptions which can occupoutputr if the subprocess output is being piped to closes before the command piping output to it is finished.

Updated install docs to note that when using Python 2.7, the subprocess32 module should also be installed.
@tleonhardt tleonhardt merged commit 3cba9c9 into master Aug 8, 2017
@tleonhardt tleonhardt deleted the pipe_improvement branch August 8, 2017 20:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve how command output gets piped to shell command

2 participants