Просмотр исходного кода

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

Juan Pablo Caram 9 лет назад
Родитель
Сommit
f9cbd78cd1
2 измененных файлов с 85 добавлено и 31 удалено
  1. 75 22
      FlatCAMApp.py
  2. 10 9
      camlib.py

+ 75 - 22
FlatCAMApp.py

@@ -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
-        this is here mainly to show unknown errors inside TCL shell console
+        Raise exception if is different type than TclErrorException
+        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_formated=[]
+                trc = traceback.format_list(traceback.extract_tb(exc_traceback))
+                trc_formated = []
                 for a in reversed(trc):
                 for a in reversed(trc):
-                    trc_formated.append(a.replace("    ", " > ").replace("\n",""))
-                text="%s\nPython traceback: %s\n%s" % (exc_value,
+                    trc_formated.append(a.replace("    ", " > ").replace("\n", ""))
+                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
-                gap_size = kwa['dia']+kwa['gapsize']
+                margin = kwa['margin'] + kwa['dia'] / 2
+                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,

+ 10 - 9
camlib.py

@@ -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.