How to intercept content of stdout in Python? - python

I make a custom command in Django where make some output to stdout.
How I can intercept stdout make some changes(for example add prefix) and write to stderr?
This is test task so do not pay attention on illogicality of question.

You can use StringIO like this:
from io import StringIO
import sys
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()
print("test")
sys.stdout = old_stdout
s = mystdout.getvalue()
s = "prefix" + s
sys.stderr.write(s)
The code is capturing stdout into the buffer, then reads the buffer, adds prefix and writes to stderr.
Also see:
Can I redirect the stdout in python into some sort of string buffer?

You can use sys.stdout and sys.stderr:
from sys import stdout, stderr
output_text = "Some text"
stdout.write('stdout: ' + output_text + '\n')
stderr.write('stderr: ' + output_text + '\n')
Demo:
monty#xonix:~/py$ python so.py &> foo.txt
monty#xonix:~/py$ cat foo.txt
stderr: Some text
stdout: Some text

Related

assign output of help to a variable instead of stdout in python

I want to do something like this in the python interpreter.
myhelp = help(myclass)
but the output goes to stdout. Is it possible to assign it to a variable?
Thanks!
You can capture stdout while help(myclass) runs:
from cStringIO import StringIO
import sys
stdout = sys.stdout
buffer = StringIO()
sys.stdout = buffer
help(myclass)
sys.stdout = stdout
myhelp = buffer.getvalue()

Get current console output in python

I want to get the current console output of my program in python. There are a lot of solutions to get the console output when running an external program, however, I couldn't find any solution for getting the console output of the current program. Am I missing something? I am looking for a solution which works under windows and linux.
For example:
print "Hello world"
output = get_console_output() # Returns "Hello World\n"
Edit:
The solution should preserve the console output, so just replacing stdout won't work, as the console will be empty then
If you want to access the output you need to redirect the standard output stdout somewhere. You can use StringIO for this for example:
from cStringIO import StringIO
import sys
sys.stdout = buffer = StringIO()
print "Hello World"
# get output via: buffer.getvalue()
If you rather want the output to a file you could instead redirect directly to a file:
import sys
sys.stdout = open('output.txt', 'w')
print 'Hello World'
Edit: If you want output to be appended to log (according to comment), I suggest a custom class:
import sys
class Log(object):
def __init__(self):
self.orgstdout = sys.stdout
self.log = open("log.txt", "a")
def write(self, msg):
self.orgstdout.write(msg)
self.log.write(msg)
sys.stdout = Log()
print('Hello World')
You can overwrite sys.stdout with any file-like object:
import sys
import StringIO
sys.stdout = StringIO.StringIO()
You should also think about using the logging module instead of print. Or simply write a function that stores and prints values.

Create and pipe a file-like object as input for a command

I'm looking for a better way to do this, if possible:
import subprocess
f = open('temp.file', 'w+')
f.write('hello world')
f.close()
out = subprocess.check_output(['cat', 'temp.file'])
print out
subprocess.check_output(['rm', 'temp.file'])
In this example I'm creating a file and passing it as input to cat (in reality it's not cat I'm running but some other program that parses an input pcap file).
What I'm wondering is, is there a way in Python I can create a 'file-like object' with some content, and pipe this file-like object as input to a command-line program. If it is possible, I reckon it would be more efficient than writing a file to the disk and then deleting that file.
check_output takes a stdin input argument to specify a file-like object to connect to the process's standard input.
with open('temp.file') as input:
out = subprocess.check_output(['cat'], stdin=input)
Also, there's no need to shell out to run rm; you can remove the file directly from Python:
os.remove('temp.file')
You can write to a TemporaryFile
import subprocess
from tempfile import TemporaryFile
f = TemporaryFile("w")
f.write("foo")
f.seek(0)
out = subprocess.check_output(['cat'],stdin=f)
print(out)
b'foo'
If you just want to write to a file like object and get the content:
from io import StringIO
f = StringIO()
f.write("foo")
print(f.getvalue())
If the program is configured to read from stdin, you can use Popen.communicate:
>>> from subprocess import Popen, PIPE
>>> p = Popen('cat', stdout=PIPE, stdin=PIPE, stderr=PIPE)
>>> out, err = p.communicate(input=b"Hello world!")
>>> out
'Hello world!'
If the command accepts only filenames, if it doesn't read input from its stdin i.e., if you can't use stdin=PIPE + .communicate() or stdin=real_file then you could try /dev/fd/# filenames:
#!/usr/bin/env python3
import os
import subprocess
import threading
def pump_input(pipe):
with pipe:
for i in range(3):
print(i, file=pipe)
r, w = os.pipe()
try:
threading.Thread(target=pump_input, args=[open(w, 'w')]).start()
out = subprocess.check_output(['cat', '/dev/fd/'+str(r)], pass_fds=[r])
finally:
os.close(r)
print('got:', out)
No content touches the disk. The input is passed to the subprocess via the pipe directly.
If you have a file-like object that is not a real file (otherwise, just pass its name as the command-line argument) then pump_input() could look like:
import shutil
def pump_input(pipe):
with pipe:
shutil.copyfileobj(file_like_object, pipe)

Redirect an output command to a variable or file?

I'm trying to write a python script that will allow me to take the output from a command and to put that into a file or variable (Preferability a variable).
In my code, I have redirected the output to a StringIO() object. From that, I want take the output a command and to put it into that StringIO() object.
Here is a sample of my code:
from StringIO import StringIO
import sys
old_stdout = sys.stdout
result = StringIO()
sys.stdout = result
# This will output to the screen, and not to the variable
# I want this to output to the 'result' variable
os.system('ls -l')
Also, how do I take result and put it into a string?
Thanks in advance!!
import subprocess
sp = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE)
output, _ = sp.communicate()
print "Status:", sp.wait()
print "Output:"
print output

How to redirect stderr of a program that is run using os.system by a third-party python library

I use external library, like this:
from some_lib import runThatProgram
infile = '/tmp/test'
outfile = '/tmp/testout'
runThatProgram(infile, outfile)
while runThatProgram is:
def runThatProgram(infile, outfile):
os.system("%s %s > %s" % ('thatProgram', infile, outfile))
The problem is that 'thatProgram' returns lots of stuff on STDERR, I want to redirect it to a file, but I cannot edit runThatProgram code because it is in third party lib!
To illustrate what Rosh Oxymoron said, you can hack the code like this :
from some_lib import runThatProgram
infile = '/tmp/test'
outfile = '/tmp/testout 2>&1'
runThatProgram(infile, outfile)
with this, it will call
thatProgram /tmp/test > /tmp/testout 2>&1
that will redirected stderr (2) to stdout (1), and everything will be logged in your outfile.
To elaborate on using subprocess, you can open it, give it a pipe and then work from there so
import subprocess
program = "runthatprogram.py".split()
process = subprocess.Popen(program, stdout = subprocess.PIPE, stderr = open('stderr','w')) #stderr to fileobj
process.communicate()[0] #display stdout

Categories

Resources