tags:

views:

138

answers:

3

What I'm trying to do is simply have the output of some terminal commands print out to a wx.TextCtrl widget. I figured the easiest way to accomplish this is to create a custom stdout class and overload the write function to that of the widget.

stdout class:

class StdOut(sys.stdout):
    def __init__(self,txtctrl):
        sys.stdout.__init__(self)
        self.txtctrl = txtctrl

    def write(self,string):
        self.txtctrl.write(string)

And then I would do something such as:

sys.stdout = StdOut(createdTxtCtrl)    
subprocess.Popen('echo "Hello World!"',stdout=sys.stdout,shell=True)

What results is the following error:

Traceback (most recent call last):
File "mainwindow.py", line 12, in <module>
from systemconsole import SystemConsole
File "systemconsole.py", line 4, in <module>
class StdOut(sys.stdout):
TypeError: Error when calling the metaclass bases
file() argument 2 must be string, not tuple

Any ideas to fix this would be appreciated.

A: 

Wouldn't sys.stdout = StdOut(createdTxtCtrl) create cyclical dependency? Try not reassigning sys.stdout to the class derived from sys.stdout.

Aleksa
+3  A: 

sys.stdout is not a class, it's an instance (of type file).

So, just do:

class StdOut(object):
    def __init__(self,txtctrl):
        self.txtctrl = txtctrl
    def write(self,string):
        self.txtctrl.write(string)

sys.stdout = StdOut()

No need to inherit from file, just make a simple file-like object like this! Duck typing is your friend...

(Note that in Python, like most other OO languages but differently from Javascript, you only ever inherit from classes AKA types, never from instances of classes/types;-).

Alex Martelli
I tried this, and it resulted in:Traceback (most recent call last): File "blade_gui.py", line 179, in OnNew subprocess.Popen('echo "Hello World!"',stdout=sys.stdout,shell=True) File "C:\Python26\lib\subprocess.py", line 614, in __init__ errread, errwrite) = self._get_handles(stdin, stdout, stderr) File "C:\Python26\lib\subprocess.py", line 734, in _get_handles c2pwrite = msvcrt.get_osfhandle(stdout.fileno())AttributeError: 'StdOut' object has no attribute 'fileno'
Duck
`subprocess` can execute programs written in any language (not just Python!) and so needs a "real OS-level file" (i.e., one with a FD, also known as fileno) -- no way to pass anything as the `stdout=` of `subprocess.Popen` except a real OS-level file (including, fortunately, `subprocess.PIPE`, which lets your parent process receive the child process's output -- however, buffering in the child process typically means this isn't what you want, so I always suggest using `pexpect` or `wexpect` instead).
Alex Martelli
A: 

If all you need to implement is writing, there is no need to define a new class at all. Simply use createdTxtCtrl instead of StdOut(createdTxtCtrl), because the former already supports the operation you need.

If all you need to do with stdout is direct some programs' output there, not direct all kinds of stuff there, don't change sys.stdout, just instantiate the subprocess.Popen with your own file-like object (createdTxtCtrl) instead of sys.stdout.

Mike Graham