1

I have embedded python interpreter (2.7.6) in dll (Windows 7) that is loaded as plugin in a native host program that has its own ui. Python script file is executed by dll, in that script file stderr is redirected to a file and another script is imported. In this script (code below) is a class that creates Tkinter window and and has write() method that writes to Tkinter text widget. Stdout is redirected by that class to itself. The class is run in thread.

Code below works great when imported by non-embedded python. When importing to embedded python, window appears and displays output whenever anything is printed to stdout, but otherwise the window is unresponsive (not responding). Stderr is empty.

import time
import threading
from Tkinter import *
from ScrolledText import *

class OutputWindow(threading.Thread):
    '''Output window where stdout is re-directed. Inherits Thread'''
    def __init__(self):

        self.autoScroll = True

        #root
        self.root = Tk()
        self.root.title("My output window")

        Grid.rowconfigure(self.root, 0, weight = 0)
        Grid.rowconfigure(self.root, 1, weight = 1)
        Grid.columnconfigure(self.root, 0, weight = 1)

        #frame for buttons
        topframe = Frame(self.root, width = "250px", height = "10px")
        topframe.grid(row = 0, sticky = E+W+N)
        Grid.rowconfigure(topframe, 0, weight = 1)

        #frame for text widget
        botframe = Frame(self.root)
        botframe.grid(row = 1, sticky = N+S+E+W)
        Grid.rowconfigure(botframe, 0, weight = 1)
        Grid.columnconfigure(botframe, 0, weight = 1)

        #autoscroll bool button
        self.autoScrollBtn = Button(topframe, text="AutoScroll", command = self.onAutoScroll)
        self.autoScrollBtn.grid(row = 0, column = 0, sticky = W+E)
        self.autoScrollBtn["relief"] = SUNKEN

        #clear button
        self.clearBtn = Button(topframe, text = "Clear", command = self.onClear)
        self.clearBtn.grid(row = 0, column = 1, sticky = W+E)

        #text widget with scrollbar
        self.text = ScrolledText(botframe)
        self.text.grid(row = 0, sticky = W+E+N+S)
        self.text.config(state = DISABLED)

        threading.Thread.__init__(self)

    def onAutoScroll(self):
        self.autoScroll = not self.autoScroll
        if self.autoScroll:
            self.autoScrollBtn["relief"] = SUNKEN
        else:
            self.autoScrollBtn["relief"] = RAISED

    def onClear(self):
        self.text.config(state = NORMAL)
        self.text.delete(1.0, END)
        self.text.config(state = DISABLED)

    def write(self, txt):
        '''write method for redirecting stdout.'''
        #print txt

        self.text.config(state = NORMAL)
        self.text.insert(END,str(txt))
        self.text.config(state = DISABLED)
        if self.autoScroll:
            self.text.see(END)

    def run(self):
        '''Thread.run method.'''
        self.stdout_prev = sys.stdout
        sys.stdout = self
        self.root.mainloop()
        sys.stdout = self.stdout_prev
        self.windowOpen = False


out = OutputWindow()
out.start()
time.sleep(0.1) #wait for thread to start properly...
print "Start of output"
print "---------------"

I've also tried to launch this in subprocess and write to it's stdin. This time window remains responsive but output isn't appearing in output window until host application exits. Nothing in stderr. This is the code I added to end of script above:

for line in sys.stdin:        
    sys.stdout.write(line)

And this is the code I used to launch subprocess and redirect stdout:

class redirect():
    def __init__(self, proc):
        self.p = proc
    def write(self, txt):
        self.p.stdin.write(txt)
        self.p.stdin.flush()

import subprocess
proc = subprocess.Popen('C:\\python27\\python.exe stackoverflow_sub.py', stdin = subprocess.PIPE)
sys.stdout = redirect(proc)
print "test redir"

Main question being:

What would be the best approach? And how to do it?

Extra questions:

1) Why my tkinter output window goes to not responding state but still updating when output is printed when not launching as subprocess? What can be done to make it responsive?

2) How to utilize the subprocess stdin in this case?

I'd really like to get it working without subprocessing, for such simple output window it is ok, but I'd like to build ui's with a bit more elaborate interfaces and working via stdin and stdout is not preferred.

7
  • Your use of backslashes and path specifications is inconsistent in the code thar launches the subprocess -- the 'C:\python27\python.exe python27\\stackoverflow_sub.py'. Commented Feb 2, 2014 at 22:23
  • Thanks. Fixing that now. Though it doesn't resolve the issue. Commented Feb 2, 2014 at 22:28
  • @eryksun that sys.stdin.readline() actually worked when subprocessing, it is now working as intended. Thank you! Weird enough doing the move of Tk stuff to setup method and calling that from run() works as before when imported or subprocessed. When trying to run the file as is, I get: "TclError: out of stack space (infinite loop?)" when trying to print. It stalls on first Tkinter interaction: self.text.config(state = NORMAL) Commented Feb 3, 2014 at 8:06
  • I think path specification should be 'C:\\python27\\python.exe C:\\python27\\stackoverflow_sub.py'. Commented Feb 3, 2014 at 11:54
  • @martineau script is in subfolder python27 relative to script subprocessing it. It is a bit confusing so I've edited out that extra folder for clarity. Thanks for heads up. Commented Feb 3, 2014 at 13:10

1 Answer 1

1

Found solution in this:

Python Threads do not run in C++ Application Embedded Interpreter

Releasing the GIL in embedding dll made Tkinter window responsive without subprocessing. In my particular case I know that from certain point on all python code that is not put in it's own thread will only respond to callbacks called from dll, so it should be safe.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.