Show messages and errors in TCL shell. Better exception handling and reporting when opening files.

This commit is contained in:
Juan Pablo Caram 2016-06-11 21:33:38 -04:00
parent ba05f832c0
commit f9cbd78cd1
2 changed files with 85 additions and 31 deletions

View File

@ -691,16 +691,35 @@ class App(QtCore.QObject):
else: else:
self.defaults['stats'][resource] = 1 self.defaults['stats'][resource] = 1
# TODO: This shouldn't be here.
class TclErrorException(Exception): class TclErrorException(Exception):
""" """
this exception is deffined here, to be able catch it if we sucessfully handle all errors from shell command this exception is deffined here, to be able catch it if we sucessfully handle all errors from shell command
""" """
pass pass
def shell_message(self, msg, show=False, error=False):
"""
Shows a message on the FlatCAM Shell
:param msg: Message to display.
:param show: Opens the shell.
:param error: Shows the message as an error.
:return: None
"""
if show:
self.ui.shell_dock.show()
if error:
self.shell.append_error(msg + "\n")
else:
self.shell.append_output(msg + "\n")
def raise_tcl_unknown_error(self, unknownException): def raise_tcl_unknown_error(self, unknownException):
""" """
raise Exception if is different type than TclErrorException Raise exception if is different type than TclErrorException
this is here mainly to show unknown errors inside TCL shell console this is here mainly to show unknown errors inside TCL shell console.
:param unknownException: :param unknownException:
:return: :return:
""" """
@ -727,20 +746,20 @@ class App(QtCore.QObject):
show_trace = int(self.defaults['verbose_error_level']) show_trace = int(self.defaults['verbose_error_level'])
if show_trace > 0: if show_trace > 0:
trc=traceback.format_list(traceback.extract_tb(exc_traceback)) trc = traceback.format_list(traceback.extract_tb(exc_traceback))
trc_formated=[] trc_formated = []
for a in reversed(trc): for a in reversed(trc):
trc_formated.append(a.replace(" ", " > ").replace("\n","")) trc_formated.append(a.replace(" ", " > ").replace("\n", ""))
text="%s\nPython traceback: %s\n%s" % (exc_value, text = "%s\nPython traceback: %s\n%s" % (exc_value,
exc_type, exc_type,
"\n".join(trc_formated)) "\n".join(trc_formated))
else: else:
text="%s" % error text = "%s" % error
else: else:
text=error text = error
text = text.replace('[', '\\[').replace('"','\\"') text = text.replace('[', '\\[').replace('"', '\\"')
self.tcl.eval('return -code error "%s"' % text) self.tcl.eval('return -code error "%s"' % text)
@ -782,7 +801,7 @@ class App(QtCore.QObject):
try: try:
self.shell.open_proccessing() self.shell.open_proccessing()
result = self.tcl.eval(str(text)) result = self.tcl.eval(str(text))
if result!='None': if result != 'None':
self.shell.append_output(result + '\n') self.shell.append_output(result + '\n')
except Tkinter.TclError, e: except Tkinter.TclError, e:
#this will display more precise answer if something in TCL shell fail #this will display more precise answer if something in TCL shell fail
@ -836,16 +855,27 @@ class App(QtCore.QObject):
def info(self, msg): def info(self, msg):
""" """
Writes on the status bar. Informs the user. Normally on the status bar, optionally
also on the shell.
:param msg: Text to write. :param msg: Text to write.
:param toshell: Forward the
:return: None :return: None
""" """
# Type of message in brackets at the begining of the message.
match = re.search("\[([^\]]+)\](.*)", msg) match = re.search("\[([^\]]+)\](.*)", msg)
if match: if match:
self.ui.fcinfo.set_status(QtCore.QString(match.group(2)), level=match.group(1)) level = match.group(1)
msg_ = match.group(2)
self.ui.fcinfo.set_status(QtCore.QString(msg_), level=level)
error = level == "error" or level == "warning"
self.shell_message(msg, error=error, show=True)
else: else:
self.ui.fcinfo.set_status(QtCore.QString(msg), level="info") self.ui.fcinfo.set_status(QtCore.QString(msg), level="info")
self.shell_message(msg)
def load_defaults(self): def load_defaults(self):
""" """
@ -1953,6 +1983,17 @@ class App(QtCore.QObject):
self.log.error(str(e)) self.log.error(str(e))
raise raise
except:
msg = "[error] An internal error has ocurred. See shell.\n"
msg += traceback.format_exc()
app_obj.inform.emit(msg)
raise
if gerber_obj.is_empty():
app_obj.inform.emit("[error] No geometry found in file: " + filename)
self.collection.set_active(gerber_obj.options["name"])
self.collection.delete_active()
# Further parsing # Further parsing
self.progress.emit(70) # TODO: Note the mixture of self and app_obj used here self.progress.emit(70) # TODO: Note the mixture of self and app_obj used here
@ -1997,18 +2038,31 @@ class App(QtCore.QObject):
try: try:
excellon_obj.parse_file(filename) excellon_obj.parse_file(filename)
except IOError: except IOError:
app_obj.inform.emit("[error] Cannot open file: " + filename) app_obj.inform.emit("[error] Cannot open file: " + filename)
self.progress.emit(0) # TODO: self and app_bjj mixed self.progress.emit(0) # TODO: self and app_bjj mixed
raise IOError("Cannot open file: " + filename) raise IOError("Cannot open file: " + filename)
except:
msg = "[error] An internal error has ocurred. See shell.\n"
msg += traceback.format_exc()
app_obj.inform.emit(msg)
raise
try: try:
excellon_obj.create_geometry() excellon_obj.create_geometry()
except Exception as e:
app_obj.inform.emit("[error] Failed to create geometry after parsing: " + filename)
self.progress.emit(0)
raise e
except:
msg = "[error] An internal error has ocurred. See shell.\n"
msg += traceback.format_exc()
app_obj.inform.emit(msg)
raise
if excellon_obj.is_empty():
app_obj.inform.emit("[error] No geometry found in file: " + filename)
self.collection.set_active(excellon_obj.options["name"])
self.collection.delete_active()
#self.progress.emit(70) #self.progress.emit(70)
with self.proc_container.new("Opening Excellon."): with self.proc_container.new("Opening Excellon."):
@ -2479,8 +2533,8 @@ class App(QtCore.QObject):
return "Could not retrieve object: %s" % name return "Could not retrieve object: %s" % name
def geo_init_me(geo_obj, app_obj): def geo_init_me(geo_obj, app_obj):
margin = kwa['margin']+kwa['dia']/2 margin = kwa['margin'] + kwa['dia'] / 2
gap_size = kwa['dia']+kwa['gapsize'] gap_size = kwa['dia'] + kwa['gapsize']
minx, miny, maxx, maxy = obj.bounds() minx, miny, maxx, maxy = obj.bounds()
minx -= margin minx -= margin
maxx += margin maxx += margin
@ -2519,9 +2573,8 @@ class App(QtCore.QObject):
return 'Ok' return 'Ok'
def geocutout(name=None, *args): def geocutout(name=None, *args):
''' """
TCL shell command - see help section TCL shell command - see help section
Subtract gaps from geometry, this will not create new object Subtract gaps from geometry, this will not create new object
@ -2529,7 +2582,7 @@ class App(QtCore.QObject):
:param name: name of object :param name: name of object
:param args: array of arguments :param args: array of arguments
:return: "Ok" if completed without errors :return: "Ok" if completed without errors
''' """
try: try:
a, kwa = h(*args) a, kwa = h(*args)
@ -2569,7 +2622,7 @@ class App(QtCore.QObject):
lenghty = (ymax - ymin) lenghty = (ymax - ymin)
gapsize = kwa['gapsize'] + kwa['dia'] / 2 gapsize = kwa['gapsize'] + kwa['dia'] / 2
if kwa['gaps'] == '8' or kwa['gaps']=='2lr': if kwa['gaps'] == '8' or kwa['gaps'] == '2lr':
subtract_rectangle(name, subtract_rectangle(name,
xmin - gapsize, xmin - gapsize,

View File

@ -158,6 +158,16 @@ class Geometry(object):
log.error("Failed to run union on polylines.") log.error("Failed to run union on polylines.")
raise raise
def is_empty(self):
if isinstance(self.solid_geometry, BaseGeometry):
return self.solid_geometry.is_empty
if isinstance(self.solid_geometry, list):
return len(self.solid_geometry) == 0
raise Exception("self.solid_geometry is neither BaseGeometry or list.")
def subtract_polygon(self, points): def subtract_polygon(self, points):
""" """
Subtract polygon from the given object. This only operates on the paths in the original geometry, i.e. it converts polygons into paths. Subtract polygon from the given object. This only operates on the paths in the original geometry, i.e. it converts polygons into paths.
@ -390,15 +400,6 @@ class Geometry(object):
""" """
return self.solid_geometry.buffer(offset) return self.solid_geometry.buffer(offset)
def is_empty(self):
if self.solid_geometry is None:
return True
if type(self.solid_geometry) is list and len(self.solid_geometry) == 0:
return True
return False
def import_svg(self, filename, flip=True): def import_svg(self, filename, flip=True):
""" """
Imports shapes from an SVG file into the object's geometry. Imports shapes from an SVG file into the object's geometry.