I am asking these questions together because I feel like they go together. The way to do one effects how I have to do the other. I am a computer science/programming/python novice.
I have a very long, complicated script that doesn't contain any user-defined functions. It takes the inputs and manipulates them to form an output. I have built a GUI with Tkinter for the user to input data. I want to run my script within my GUI mainloop and have the script print status updates and errors to the GUI.
Printing errors to GUI: I have searched and searched for a possible solution but I have not managed to crack this.
Using a subprocess looked the most promising, but I believe the subprocess must be a .exe file in order for that to work. I have only a Python script and do not know how to convert something into an executable (but I will need to learn soon anyway). As for the second response on that page with the sys module, I just don't understand what's going on in the "run_script" function to apply it to my own GUI.
There's this "show error" solution but I am not sure I really understand this, either. Is this saying that I need to put Try...Except...
on all of the functions in my subscript and have it spit back a message box? Yick. I would really much prefer the exception get printed like it does in the command result/IDE and exit the command. Would the traceback solution on that page be a one-and-done sort of thing that I state once in my GUI and have it work for all functions in the GUI? Or would I have to call that show_error function every time I carry out a computation?
Incorporating the subscript: I realized that the manner in which I incorporate the subscript will impact how the messages are printed in the GUI. I have a bunch of print statements in my subscript (print "Loading modules..."
) to let the user know the program is running. Before moving on, here is an example of the code I am working with.
Here is a shortened version of my GUI code:
import Tkinter
###____________Widgets__________________###
class InputBox(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self, parent)
self.parent = parent
self.initialize()
def initialize(self):
# Frame
self.OK = Tkinter.Frame(self, padx=3, pady=3)
self.OK.grid(column=2, row=2, columnspan=3, sticky="EW")
self.printFrame = Tkinter.LabelFrame(self, borderwidth=3, relief="ridge", padx=3, pady=3, text="Results")
self.printFrame.grid(column=0, row=3, columnspan=4, sticky="EW")
# Approval
self.OKbutton = Tkinter.Button(self.OK, text=u"OK", command=self.OKgo, anchor="e")
self.OKbutton.pack(side="right")
self.view = Tkinter.Text(self.printFrame)
self.view.grid(column=0, row=0, columnspan=3, sticky="EW")
self.scroll = Tkinter.Scrollbar(self.printFrame, orient=Tkinter.VERTICAL)
self.scroll.config(command=self.view.yview)
self.view.config(yscrollcommand=self.scroll.set)
self.scroll.grid(column=4, row=0, sticky="SN")
def OKgo(self):
# Load Inputs
DEMin = self.demEntryVar.get()
WTin = self.wtEntryVar.get()
soil = self.soilEntryVar.get()
Here's a very small piece of my "subscript":
# Convert soils shapefile to raster and assign integer values to HSG.
# A=1, B=2, C=3, 4=D and dual groups A/D=14, B/D=24, C/D=34
# "---" is treated as a D soil
import arcpy
print("Converting dual group soils to single groups...")
SoilUnclass = arcpy.PolygonToRaster_conversion(soil, "HSG", ScratchPath + r"\SoilUnclass", "MAXIMUM_COMBINED_AREA")
SoilClass = arcpy.sa.Reclassify(SoilUnclass, "HSG", arcpy.sa.RemapValue([["A", 1],
["B", 2],
["C", 3],
["D", 4],
["A/D", 14],
["B/D", 24],
["C/D", 34],
["---", 4]]), "NODATA")
SoilClass.save(ScratchPath + r"\HSGras")
If I paste the subscript code directly into the OKgo
function, I can get it to print to the Text widget by changing all the print statements to self.view.insert("end", "Converting soils... \n")
. As I understand it, pasting my whole subscript into the OKgo
function is undesirable because it freezes the GUI and generally is very long. The subscript can take a substantial amount of time to run so this isn't preferred.
I can also break my subscript into numerous user-defined functions and call them individually within the OKgo
function with something like
import subscript as ss
ss.soilconvert(soil)
This would be much cleaner and easier for me to diagnose and do the Try...Except...
thing with even thought it freezes the GUI. The outputs from one function are needed as inputs for the next function, however, and I don't know how to call those back. I also do not know how I would turn the print
statements into something that could be read into the Text widget.
I saw some stuff about execfile
too, but I feel like that's even harder to get the output into the Text widget with. :/ I don't know any programming conventions or know what would be easier to debug/update. I need some direction, please. Thanks.
EDIT:
I created a single-thread version using import statments and a multiprocessing
version. I did something like this: Python multiprocessing redirect stdout of a child process to a Tkinter Text to trap stdout
and print it to the GUI. I am still trying to get the exceptions to work. Redirecting sys.stderr
in the same way I redirected sys.stdout
is not working but I have yet to try to sys.excepthook
thing.