I'm trying to pipe a io.BytesIO() bytetream to a separate program using subprocess.popen(), but I don't know how or if this is at all possible. Documentation and examples are all about text and newlines.
When I whip up something like this:
import io
from subprocess import *
stream = io.BytesIO()
someStreamCreatingProcess(stream)
command = ['somecommand', 'some', 'arguments']
process = Popen(command, stdin=PIPE)
process.communicate(input=stream)
I get
Traceback (most recent call last):
File "./test.py", line 9, in <module>
procOut = process.communicate(input=stream)
File "/usr/lib/python2.7/subprocess.py", line 754, in communicate
return self._communicate(input)
File "/usr/lib/python2.7/subprocess.py", line 1322, in _communicate
stdout, stderr = self._communicate_with_poll(input)
File "/usr/lib/python2.7/subprocess.py", line 1384, in _communicate_with_poll
chunk = input[input_offset : input_offset + _PIPE_BUF]
TypeError: '_io.BytesIO' object has no attribute '__getitem__'
I think popen() is only for text. Am I wrong?
Is there a different way to do this?
To use a pipe with the subprocess module, you have to pass shell=True . In your particular case, however, the simple solution is to call subprocess. check_output(('ps', '-A')) and then str. find on the output.
PIPE is passed as a constant so that either of the subprocess. Popen() or subprocess. PIPE the user specifies that they want the resultant. A child process named CallMyName.py is created in the program. Two names are passed to the CallMyName.py before sending the EOF signal to the input of the child.
The subprocess module defines one class, Popen and a few wrapper functions that use that class. The constructor for Popen takes arguments to set up the new process so the parent can communicate with it via pipes. It provides all of the functionality of the other modules and functions it replaces, and more.
It takes input POSIX based arguments and returns a file descriptor which represents the opened file. It does not return a file object; the returned value will not have read() or write() functions. Overall, io.
As @falsetru said you can't stream BytesIO()
object directly; you need to get a bytestring from it first. It implies that all content should be already written to stream
before you call stream.getvalue()
to pass to process.communicate()
.
If you want to stream instead of providing all input at once then you could drop BytesIO()
object and write to the pipe directly:
from subprocess import Popen, PIPE
process = Popen(['command', 'arg1'], stdin=PIPE, bufsize=-1)
someStreamCreatingProcess(stream=process.stdin) # many `stream.write()` inside
process.stdin.close() # done (no more input)
process.wait()
someStreamCreatingProcess()
should not return until it is done writing to the stream. If it returns immediately then it should call stream.close()
at some point in the future (remove process.stdin.close()
in your code):
from subprocess import Popen, PIPE
process = Popen(['command', 'arg1'], stdin=PIPE, bufsize=-1)
someStreamCreatingProcess(stream=process.stdin) # many `stream.write()` inside
process.wait() # stream.close() is called in `someStreamCreatingProcess`
According to subprocess.Popen.communicate
:
The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child.
To get (bytes) string value from BytesIO
object, use getvalue
:
process.communicate(input=stream.getvalue())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With