5

I have this somewhat complicated command line function in Python (lets call it myFunction()), and I am working to integrate it in a graphical interface (using PySide/Qt).

The GUI is used to help select inputs, and display outputs. However, myFunction is designed to work as a stand-alone command line function, and it occasionnaly prints out the progress.

My question is: how can I intercept these print calls and display them in the GUI? I know it would be possible to modify myFunction() to send processEvents() to the GUI, but I would then lose the ability to execute myFunction() in a terminal.

Ideally, I would like something similar to Ubuntu's graphical software updater, which has a small embeded terminal-looking widget displaying what apt-get would display were it executed in a terminal.

4 Answers 4

9

you could redirect stdout and restore after. for example:

import StringIO import sys # somewhere to store output out = StringIO.StringIO() # set stdout to our StringIO instance sys.stdout = out # print something (nothing will print) print 'herp derp' # restore stdout so we can really print (__stdout__ stores the original stdout) sys.stdout = sys.__stdout__ # print the stored value from previous print print out.getvalue() 
Sign up to request clarification or add additional context in comments.

1 Comment

From preliminary testing, this seems to be what I'm looking for. I can intercept the output of print and store it in a variable. Now I just need to find a way to display it such that my GUI doesn't look like it freezes, but that's for another question!
4

Here is a Python 3 pattern using contextmanager that both encapsulates the monkey-patch technique and also ensures that sys.stdout is restored in case of an exception.

from io import StringIO import sys from contextlib import contextmanager @contextmanager def capture_stdout(): """ context manager encapsulating a pattern for capturing stdout writes and restoring sys.stdout even upon exceptions Examples: >>> with capture_stdout() as get_value: >>> print("here is a print") >>> captured = get_value() >>> print('Gotcha: ' + captured) >>> with capture_stdout() as get_value: >>> print("here is a print") >>> raise Exception('oh no!') >>> print('Does printing still work?') """ # Redirect sys.stdout out = StringIO() sys.stdout = out # Yield a method clients can use to obtain the value try: yield out.getvalue finally: # Restore the normal stdout sys.stdout = sys.__stdout__ 

Comments

2

Wrap it with a function that hijacks stdout:

def stdin2file(func, file): def innerfunc(*args, **kwargs): old = sys.stdout sys.stdout = file try: return func(*args, **kwargs) finally: sys.stdout = old return innerfunc 

Then simply provide a file like object that supports write():

class GUIWriter: def write(self, stuff): #send stuff to GUI MyFunction = stdin2file(MyFunction, GUIWriter()) 

The wrapper can be turned into a decorator too:

def redirect_stdin(file): def stdin2file(func, file): def innerfunc(*args, **kwargs): old = sys.stdout sys.stdout = file try: return func(*args, **kwargs) finally: sys.stdout = old return innerfunc return stdin2file 

The use it when declaring MyFunction():

@redirect_stdin(GUIWriter()) def MyFunction(a, b, c, d): # any calls to print will call the 'write' method of the GUIWriter # do stuff 

1 Comment

thanks, very helpful. just def stdin2file(func,file) has subtle error: file parameter causes error when trying to use redirect_stdin as a decorator, so it should be def stdin2file(func) instead.
1

All printing is done via sys.stdout, which is a ordinary file-like object: iirc, it requires a method write(str). As long as your replacement has that method, it's quite easy to drop in your hook:

import sys class CaptureOutput: def write(self, message): log_message_to_textbox(message) sys.stdout = CaptureOutput() 

The actual contents of log_message_to_textbox are up to you.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.