Przeglądaj źródła

cleanups
implement TclCommand.TclCommandSignaled as proof of concept (not usefull)
bypass using threads within obj.generatecncjob(use_thread = False, **args)
reimplement some more shell commands to OOP style

Kamil Sopko 9 lat temu
rodzic
commit
980638630d

+ 51 - 51
FlatCAMApp.py

@@ -651,7 +651,7 @@ class App(QtCore.QObject):
 
 
         pass
         pass
 
 
-    def raiseTclUnknownError(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
         :param unknownException:
         :param unknownException:
@@ -659,11 +659,11 @@ class App(QtCore.QObject):
         """
         """
 
 
         if not isinstance(unknownException, self.TclErrorException):
         if not isinstance(unknownException, self.TclErrorException):
-            self.raiseTclError("Unknown error: %s" % str(unknownException))
+            self.raise_tcl_error("Unknown error: %s" % str(unknownException))
         else:
         else:
             raise unknownException
             raise unknownException
 
 
-    def raiseTclError(self, text):
+    def raise_tcl_error(self, text):
         """
         """
         this method  pass exception from python into TCL as error, so we get stacktrace and reason
         this method  pass exception from python into TCL as error, so we get stacktrace and reason
         :param text: text of error
         :param text: text of error
@@ -2274,20 +2274,20 @@ class App(QtCore.QObject):
                 # 8     - 2*left + 2*right +2*top + 2*bottom
                 # 8     - 2*left + 2*right +2*top + 2*bottom
 
 
                 if name is None:
                 if name is None:
-                    self.raiseTclError('Argument name is missing.')
+                    self.raise_tcl_error('Argument name is missing.')
 
 
                 for key in kwa:
                 for key in kwa:
                     if key not in types:
                     if key not in types:
-                        self.raiseTclError('Unknown parameter: %s' % key)
+                        self.raise_tcl_error('Unknown parameter: %s' % key)
                     try:
                     try:
                         kwa[key] = types[key](kwa[key])
                         kwa[key] = types[key](kwa[key])
                     except Exception, e:
                     except Exception, e:
-                        self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, str(types[key])))
+                        self.raise_tcl_error("Cannot cast argument '%s' to type %s." % (key, str(types[key])))
 
 
                 try:
                 try:
                     obj = self.collection.get_by_name(str(name))
                     obj = self.collection.get_by_name(str(name))
                 except:
                 except:
-                    self.raiseTclError("Could not retrieve object: %s" % name)
+                    self.raise_tcl_error("Could not retrieve object: %s" % name)
 
 
                 # Get min and max data for each object as we just cut rectangles across X or Y
                 # Get min and max data for each object as we just cut rectangles across X or Y
                 xmin, ymin, xmax, ymax = obj.bounds()
                 xmin, ymin, xmax, ymax = obj.bounds()
@@ -2337,7 +2337,7 @@ class App(QtCore.QObject):
                                        ymax + gapsize)
                                        ymax + gapsize)
 
 
             except Exception as unknown:
             except Exception as unknown:
-                self.raiseTclUnknownError(unknown)
+                self.raise_tcl_unknown_error(unknown)
 
 
         def mirror(name, *args):
         def mirror(name, *args):
             a, kwa = h(*args)
             a, kwa = h(*args)
@@ -2624,26 +2624,26 @@ class App(QtCore.QObject):
                          }
                          }
 
 
                 if name is None:
                 if name is None:
-                    self.raiseTclError('Argument name is missing.')
+                    self.raise_tcl_error('Argument name is missing.')
 
 
                 for key in kwa:
                 for key in kwa:
                     if key not in types:
                     if key not in types:
-                        self.raiseTclError('Unknown parameter: %s' % key)
+                        self.raise_tcl_error('Unknown parameter: %s' % key)
                     try:
                     try:
                         kwa[key] = types[key](kwa[key])
                         kwa[key] = types[key](kwa[key])
                     except Exception, e:
                     except Exception, e:
-                        self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, str(types[key])))
+                        self.raise_tcl_error("Cannot cast argument '%s' to type %s." % (key, str(types[key])))
 
 
                 try:
                 try:
                     obj = self.collection.get_by_name(str(name))
                     obj = self.collection.get_by_name(str(name))
                 except:
                 except:
-                    self.raiseTclError("Could not retrieve object: %s" % name)
+                    self.raise_tcl_error("Could not retrieve object: %s" % name)
 
 
                 if obj is None:
                 if obj is None:
-                    self.raiseTclError('Object not found: %s' % name)
+                    self.raise_tcl_error('Object not found: %s' % name)
 
 
                 if not isinstance(obj, FlatCAMExcellon):
                 if not isinstance(obj, FlatCAMExcellon):
-                    self.raiseTclError('Only Excellon objects can be drilled, got %s %s.' % (name,  type(obj)))
+                    self.raise_tcl_error('Only Excellon objects can be drilled, got %s %s.' % (name, type(obj)))
 
 
                 try:
                 try:
                     # Get the tools from the list
                     # Get the tools from the list
@@ -2663,10 +2663,10 @@ class App(QtCore.QObject):
                     obj.app.new_object("cncjob", job_name, job_init)
                     obj.app.new_object("cncjob", job_name, job_init)
 
 
                 except Exception, e:
                 except Exception, e:
-                    self.raiseTclError("Operation failed: %s" % str(e))
+                    self.raise_tcl_error("Operation failed: %s" % str(e))
 
 
             except Exception as unknown:
             except Exception as unknown:
-                self.raiseTclUnknownError(unknown)
+                self.raise_tcl_unknown_error(unknown)
 
 
 
 
         def millholes(name=None, *args):
         def millholes(name=None, *args):
@@ -2684,43 +2684,43 @@ class App(QtCore.QObject):
                          'outname': str}
                          'outname': str}
 
 
                 if name is None:
                 if name is None:
-                    self.raiseTclError('Argument name is missing.')
+                    self.raise_tcl_error('Argument name is missing.')
 
 
                 for key in kwa:
                 for key in kwa:
                     if key not in types:
                     if key not in types:
-                        self.raiseTclError('Unknown parameter: %s' % key)
+                        self.raise_tcl_error('Unknown parameter: %s' % key)
                     try:
                     try:
                         kwa[key] = types[key](kwa[key])
                         kwa[key] = types[key](kwa[key])
                     except Exception, e:
                     except Exception, e:
-                        self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, types[key]))
+                        self.raise_tcl_error("Cannot cast argument '%s' to type %s." % (key, types[key]))
 
 
                 try:
                 try:
                     if 'tools' in kwa:
                     if 'tools' in kwa:
                         kwa['tools'] = [x.strip() for x in kwa['tools'].split(",")]
                         kwa['tools'] = [x.strip() for x in kwa['tools'].split(",")]
                 except Exception as e:
                 except Exception as e:
-                    self.raiseTclError("Bad tools: %s" % str(e))
+                    self.raise_tcl_error("Bad tools: %s" % str(e))
 
 
                 try:
                 try:
                     obj = self.collection.get_by_name(str(name))
                     obj = self.collection.get_by_name(str(name))
                 except:
                 except:
-                    self.raiseTclError("Could not retrieve object: %s" % name)
+                    self.raise_tcl_error("Could not retrieve object: %s" % name)
 
 
                 if obj is None:
                 if obj is None:
-                    self.raiseTclError("Object not found: %s" % name)
+                    self.raise_tcl_error("Object not found: %s" % name)
 
 
                 if not isinstance(obj, FlatCAMExcellon):
                 if not isinstance(obj, FlatCAMExcellon):
-                    self.raiseTclError('Only Excellon objects can be mill drilled, got %s %s.' % (name,  type(obj)))
+                    self.raise_tcl_error('Only Excellon objects can be mill drilled, got %s %s.' % (name, type(obj)))
 
 
                 try:
                 try:
                     success, msg = obj.generate_milling(**kwa)
                     success, msg = obj.generate_milling(**kwa)
                 except Exception as e:
                 except Exception as e:
-                    self.raiseTclError("Operation failed: %s" % str(e))
+                    self.raise_tcl_error("Operation failed: %s" % str(e))
 
 
                 if not success:
                 if not success:
-                    self.raiseTclError(msg)
+                    self.raise_tcl_error(msg)
 
 
             except Exception as unknown:
             except Exception as unknown:
-                self.raiseTclUnknownError(unknown)
+                self.raise_tcl_unknown_error(unknown)
 
 
         def exteriors(name=None, *args):
         def exteriors(name=None, *args):
             '''
             '''
@@ -2735,26 +2735,26 @@ class App(QtCore.QObject):
                 types = {'outname': str}
                 types = {'outname': str}
 
 
                 if name is None:
                 if name is None:
-                    self.raiseTclError('Argument name is missing.')
+                    self.raise_tcl_error('Argument name is missing.')
 
 
                 for key in kwa:
                 for key in kwa:
                     if key not in types:
                     if key not in types:
-                        self.raiseTclError('Unknown parameter: %s' % key)
+                        self.raise_tcl_error('Unknown parameter: %s' % key)
                     try:
                     try:
                         kwa[key] = types[key](kwa[key])
                         kwa[key] = types[key](kwa[key])
                     except Exception, e:
                     except Exception, e:
-                        self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, types[key]))
+                        self.raise_tcl_error("Cannot cast argument '%s' to type %s." % (key, types[key]))
 
 
                 try:
                 try:
                     obj = self.collection.get_by_name(str(name))
                     obj = self.collection.get_by_name(str(name))
                 except:
                 except:
-                    self.raiseTclError("Could not retrieve object: %s" % name)
+                    self.raise_tcl_error("Could not retrieve object: %s" % name)
 
 
                 if obj is None:
                 if obj is None:
-                    self.raiseTclError("Object not found: %s" % name)
+                    self.raise_tcl_error("Object not found: %s" % name)
 
 
                 if not isinstance(obj, Geometry):
                 if not isinstance(obj, Geometry):
-                    self.raiseTclError('Expected Geometry, got %s %s.' % (name,  type(obj)))
+                    self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
 
 
                 def geo_init(geo_obj, app_obj):
                 def geo_init(geo_obj, app_obj):
                     geo_obj.solid_geometry = obj_exteriors
                     geo_obj.solid_geometry = obj_exteriors
@@ -2768,10 +2768,10 @@ class App(QtCore.QObject):
                     obj_exteriors = obj.get_exteriors()
                     obj_exteriors = obj.get_exteriors()
                     self.new_object('geometry', outname, geo_init)
                     self.new_object('geometry', outname, geo_init)
                 except Exception as e:
                 except Exception as e:
-                    self.raiseTclError("Failed: %s" % str(e))
+                    self.raise_tcl_error("Failed: %s" % str(e))
 
 
             except Exception as unknown:
             except Exception as unknown:
-                self.raiseTclUnknownError(unknown)
+                self.raise_tcl_unknown_error(unknown)
 
 
         def interiors(name=None, *args):
         def interiors(name=None, *args):
             '''
             '''
@@ -2787,25 +2787,25 @@ class App(QtCore.QObject):
 
 
                 for key in kwa:
                 for key in kwa:
                     if key not in types:
                     if key not in types:
-                        self.raiseTclError('Unknown parameter: %s' % key)
+                        self.raise_tcl_error('Unknown parameter: %s' % key)
                     try:
                     try:
                         kwa[key] = types[key](kwa[key])
                         kwa[key] = types[key](kwa[key])
                     except Exception, e:
                     except Exception, e:
-                        self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, types[key]))
+                        self.raise_tcl_error("Cannot cast argument '%s' to type %s." % (key, types[key]))
 
 
                 if name is None:
                 if name is None:
-                    self.raiseTclError('Argument name is missing.')
+                    self.raise_tcl_error('Argument name is missing.')
 
 
                 try:
                 try:
                     obj = self.collection.get_by_name(str(name))
                     obj = self.collection.get_by_name(str(name))
                 except:
                 except:
-                    self.raiseTclError("Could not retrieve object: %s" % name)
+                    self.raise_tcl_error("Could not retrieve object: %s" % name)
 
 
                 if obj is None:
                 if obj is None:
-                    self.raiseTclError("Object not found: %s" % name)
+                    self.raise_tcl_error("Object not found: %s" % name)
 
 
                 if not isinstance(obj, Geometry):
                 if not isinstance(obj, Geometry):
-                    self.raiseTclError('Expected Geometry, got %s %s.' % (name,  type(obj)))
+                    self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
 
 
                 def geo_init(geo_obj, app_obj):
                 def geo_init(geo_obj, app_obj):
                     geo_obj.solid_geometry = obj_interiors
                     geo_obj.solid_geometry = obj_interiors
@@ -2819,10 +2819,10 @@ class App(QtCore.QObject):
                     obj_interiors = obj.get_interiors()
                     obj_interiors = obj.get_interiors()
                     self.new_object('geometry', outname, geo_init)
                     self.new_object('geometry', outname, geo_init)
                 except Exception as e:
                 except Exception as e:
-                    self.raiseTclError("Failed: %s" % str(e))
+                    self.raise_tcl_error("Failed: %s" % str(e))
 
 
             except Exception as unknown:
             except Exception as unknown:
-                self.raiseTclUnknownError(unknown)
+                self.raise_tcl_unknown_error(unknown)
 
 
         def isolate(name=None, *args):
         def isolate(name=None, *args):
             '''
             '''
@@ -2840,29 +2840,29 @@ class App(QtCore.QObject):
 
 
             for key in kwa:
             for key in kwa:
                 if key not in types:
                 if key not in types:
-                    self.raiseTclError('Unknown parameter: %s' % key)
+                    self.raise_tcl_error('Unknown parameter: %s' % key)
                 try:
                 try:
                     kwa[key] = types[key](kwa[key])
                     kwa[key] = types[key](kwa[key])
                 except Exception, e:
                 except Exception, e:
-                    self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, types[key]))
+                    self.raise_tcl_error("Cannot cast argument '%s' to type %s." % (key, types[key]))
             try:
             try:
                 obj = self.collection.get_by_name(str(name))
                 obj = self.collection.get_by_name(str(name))
             except:
             except:
-                self.raiseTclError("Could not retrieve object: %s" % name)
+                self.raise_tcl_error("Could not retrieve object: %s" % name)
 
 
             if obj is None:
             if obj is None:
-                self.raiseTclError("Object not found: %s" % name)
+                self.raise_tcl_error("Object not found: %s" % name)
 
 
             assert isinstance(obj, FlatCAMGerber), \
             assert isinstance(obj, FlatCAMGerber), \
                 "Expected a FlatCAMGerber, got %s" % type(obj)
                 "Expected a FlatCAMGerber, got %s" % type(obj)
 
 
             if not isinstance(obj, FlatCAMGerber):
             if not isinstance(obj, FlatCAMGerber):
-                self.raiseTclError('Expected FlatCAMGerber, got %s %s.' % (name,  type(obj)))
+                self.raise_tcl_error('Expected FlatCAMGerber, got %s %s.' % (name, type(obj)))
 
 
             try:
             try:
                 obj.isolate(**kwa)
                 obj.isolate(**kwa)
             except Exception, e:
             except Exception, e:
-                self.raiseTclError("Operation failed: %s" % str(e))
+                self.raise_tcl_error("Operation failed: %s" % str(e))
 
 
             return 'Ok'
             return 'Ok'
 
 
@@ -3253,11 +3253,11 @@ class App(QtCore.QObject):
             Test it like this:
             Test it like this:
             if name is None:
             if name is None:
 
 
-                self.raiseTclError('Argument name is missing.')
+                self.raise_tcl_error('Argument name is missing.')
 
 
-            When error ocurre, always use raiseTclError, never return "sometext" on error,
+            When error ocurre, always use raise_tcl_error, never return "sometext" on error,
             otherwise we will miss it and processing will silently continue.
             otherwise we will miss it and processing will silently continue.
-            Method raiseTclError  pass error into TCL interpreter, then raise python exception,
+            Method raise_tcl_error  pass error into TCL interpreter, then raise python exception,
             which is catched in exec_command and displayed in TCL shell console with red background.
             which is catched in exec_command and displayed in TCL shell console with red background.
             Error in console is displayed  with TCL  trace.
             Error in console is displayed  with TCL  trace.
 
 

+ 20 - 11
FlatCAMObj.py

@@ -1040,6 +1040,10 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
 
 
         self.app.inform.emit("Saved to: " + filename)
         self.app.inform.emit("Saved to: " + filename)
 
 
+    def get_gcode(self, preamble='', postamble=''):
+        #we need this to beable get_gcode separatelly for shell command export_code
+        return preamble + '\n' + self.gcode + "\n" + postamble
+
     def on_plot_cb_click(self, *args):
     def on_plot_cb_click(self, *args):
         if self.muted_ui:
         if self.muted_ui:
             return
             return
@@ -1243,7 +1247,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
                        outname=None,
                        outname=None,
                        spindlespeed=None,
                        spindlespeed=None,
                        multidepth=None,
                        multidepth=None,
-                       depthperpass=None):
+                       depthperpass=None,
+                       use_thread=True):
         """
         """
         Creates a CNCJob out of this Geometry object. The actual
         Creates a CNCJob out of this Geometry object. The actual
         work is done by the target FlatCAMCNCjob object's
         work is done by the target FlatCAMCNCjob object's
@@ -1304,18 +1309,22 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
 
 
             app_obj.progress.emit(80)
             app_obj.progress.emit(80)
 
 
-        # To be run in separate thread
-        def job_thread(app_obj):
-            with self.app.proc_container.new("Generating CNC Job."):
-                app_obj.new_object("cncjob", outname, job_init)
-                app_obj.inform.emit("CNCjob created: %s" % outname)
-                app_obj.progress.emit(100)
 
 
-        # Create a promise with the name
-        self.app.collection.promise(outname)
+        if  use_thread:
+            # To be run in separate thread
+            def job_thread(app_obj):
+                with self.app.proc_container.new("Generating CNC Job."):
+                    app_obj.new_object("cncjob", outname, job_init)
+                    app_obj.inform.emit("CNCjob created: %s" % outname)
+                    app_obj.progress.emit(100)
 
 
-        # Send to worker
-        self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+            # Create a promise with the name
+            self.app.collection.promise(outname)
+
+            # Send to worker
+            self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+        else:
+            self.app.new_object("cncjob", outname, job_init)
 
 
     def on_plot_cb_click(self, *args):  # TODO: args not needed
     def on_plot_cb_click(self, *args):  # TODO: args not needed
         if self.muted_ui:
         if self.muted_ui:

+ 148 - 42
tclCommands/TclCommand.py

@@ -1,83 +1,108 @@
-import sys, inspect, pkgutil
 import re
 import re
 import FlatCAMApp
 import FlatCAMApp
+import abc
 import collections
 import collections
+from PyQt4 import QtCore
+from contextlib import contextmanager
+
 
 
 class TclCommand(object):
 class TclCommand(object):
 
 
-    app=None
+    # FlatCAMApp
+    app = None
+
+    # logger
+    log = None
 
 
     # array of all command aliases, to be able use  old names for backward compatibility (add_poly, add_polygon)
     # array of all command aliases, to be able use  old names for backward compatibility (add_poly, add_polygon)
     aliases = []
     aliases = []
 
 
     # dictionary of types from Tcl command, needs to be ordered
     # dictionary of types from Tcl command, needs to be ordered
+    # OrderedDict should be like collections.OrderedDict([(key,value),(key2,value2)])
     arg_names = collections.OrderedDict([
     arg_names = collections.OrderedDict([
         ('name', str)
         ('name', str)
     ])
     ])
 
 
     # dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
     # dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
-    option_types = collections.OrderedDict([])
+    # OrderedDict should be like collections.OrderedDict([(key,value),(key2,value2)])
+    option_types = collections.OrderedDict()
 
 
     # array of mandatory options for current Tcl command: required = {'name','outname'}
     # array of mandatory options for current Tcl command: required = {'name','outname'}
     required = ['name']
     required = ['name']
 
 
     # structured help for current command, args needs to be ordered
     # structured help for current command, args needs to be ordered
+    # OrderedDict should be like collections.OrderedDict([(key,value),(key2,value2)])
     help = {
     help = {
         'main': "undefined help.",
         'main': "undefined help.",
         'args': collections.OrderedDict([
         'args': collections.OrderedDict([
             ('argumentname', 'undefined help.'),
             ('argumentname', 'undefined help.'),
             ('optionname', 'undefined help.')
             ('optionname', 'undefined help.')
         ]),
         ]),
-        'examples' : []
+        'examples': []
     }
     }
 
 
     def __init__(self, app):
     def __init__(self, app):
-        self.app=app
+        self.app = app
+        if self.app is None:
+            raise TypeError('Expected app to be FlatCAMApp instance.')
+        if not isinstance(self.app, FlatCAMApp.App):
+            raise TypeError('Expected FlatCAMApp, got %s.' % type(app))
+        self.log = self.app.log
+
+    def raise_tcl_error(self, text):
+        """
+        this method  pass exception from python into TCL as error, so we get stacktrace and reason
+        this is  only redirect to self.app.raise_tcl_error
+        :param text: text of error
+        :return: none
+        """
+
+        self.app.raise_tcl_error(text)
 
 
     def get_decorated_help(self):
     def get_decorated_help(self):
         """
         """
         Decorate help for TCL console output.
         Decorate help for TCL console output.
 
 
-        :return: decorated help from structue
+        :return: decorated help from structure
         """
         """
 
 
-        def get_decorated_command(alias):
+        def get_decorated_command(alias_name):
             command_string = []
             command_string = []
-            for key, value in self.help['args'].items():
-                command_string.append(get_decorated_argument(key, value, True))
-            return "> " + alias + " " + " ".join(command_string)
+            for arg_key, arg_type in self.help['args'].items():
+                command_string.append(get_decorated_argument(arg_key, arg_type, True))
+            return "> " + alias_name + " " + " ".join(command_string)
 
 
-        def get_decorated_argument(key, value, in_command=False):
+        def get_decorated_argument(help_key, help_text, in_command=False):
             option_symbol = ''
             option_symbol = ''
-            if key in self.arg_names:
-                type=self.arg_names[key]
-                type_name=str(type.__name__)
+            if help_key in self.arg_names:
+                arg_type = self.arg_names[help_key]
+                type_name = str(arg_type.__name__)
                 in_command_name = "<" + type_name + ">"
                 in_command_name = "<" + type_name + ">"
-            elif key in self.option_types:
+            elif help_key in self.option_types:
                 option_symbol = '-'
                 option_symbol = '-'
-                type=self.option_types[key]
-                type_name=str(type.__name__)
-                in_command_name = option_symbol + key + " <" + type_name + ">"
+                arg_type = self.option_types[help_key]
+                type_name = str(arg_type.__name__)
+                in_command_name = option_symbol + help_key + " <" + type_name + ">"
             else:
             else:
                 option_symbol = ''
                 option_symbol = ''
-                type_name='?'
-                in_command_name = option_symbol + key + " <" + type_name + ">"
+                type_name = '?'
+                in_command_name = option_symbol + help_key + " <" + type_name + ">"
 
 
             if in_command:
             if in_command:
-                if key in self.required:
+                if help_key in self.required:
                     return in_command_name
                     return in_command_name
                 else:
                 else:
                     return '[' + in_command_name + "]"
                     return '[' + in_command_name + "]"
             else:
             else:
-                if key in self.required:
-                    return "\t" + option_symbol + key + " <" + type_name + ">: " + value
+                if help_key in self.required:
+                    return "\t" + option_symbol + help_key + " <" + type_name + ">: " + help_text
                 else:
                 else:
-                    return "\t[" + option_symbol + key + " <" + type_name + ">: " + value+"]"
+                    return "\t[" + option_symbol + help_key + " <" + type_name + ">: " + help_text + "]"
 
 
-        def get_decorated_example(example):
-            return "> "+example
+        def get_decorated_example(example_item):
+            return "> "+example_item
 
 
-        help_string=[self.help['main']]
+        help_string = [self.help['main']]
         for alias in self.aliases:
         for alias in self.aliases:
             help_string.append(get_decorated_command(alias))
             help_string.append(get_decorated_command(alias))
 
 
@@ -89,12 +114,17 @@ class TclCommand(object):
 
 
         return "\n".join(help_string)
         return "\n".join(help_string)
 
 
-    def parse_arguments(self, args):
+    @staticmethod
+    def parse_arguments(args):
             """
             """
             Pre-processes arguments to detect '-keyword value' pairs into dictionary
             Pre-processes arguments to detect '-keyword value' pairs into dictionary
             and standalone parameters into list.
             and standalone parameters into list.
 
 
-            This is copy from FlatCAMApp.setup_shell().h() just for accesibility,  original should  be removed  after all commands will be converted
+            This is copy from FlatCAMApp.setup_shell().h() just for accessibility,
+            original should  be removed  after all commands will be converted
+
+            :param args: arguments from tcl to parse
+            :return: arguments, options
             """
             """
 
 
             options = {}
             options = {}
@@ -121,41 +151,43 @@ class TclCommand(object):
         Check arguments and  options for right types
         Check arguments and  options for right types
 
 
         :param args: arguments from tcl to check
         :param args: arguments from tcl to check
-        :return:
+        :return: named_args, unnamed_args
         """
         """
 
 
         arguments, options = self.parse_arguments(args)
         arguments, options = self.parse_arguments(args)
 
 
-        named_args={}
-        unnamed_args=[]
+        named_args = {}
+        unnamed_args = []
 
 
         # check arguments
         # check arguments
-        idx=0
-        arg_names_items=self.arg_names.items()
+        idx = 0
+        arg_names_items = self.arg_names.items()
         for argument in arguments:
         for argument in arguments:
             if len(self.arg_names) > idx:
             if len(self.arg_names) > idx:
-                key, type = arg_names_items[idx]
+                key, arg_type = arg_names_items[idx]
                 try:
                 try:
-                    named_args[key] = type(argument)
+                    named_args[key] = arg_type(argument)
                 except Exception, e:
                 except Exception, e:
-                    self.app.raiseTclError("Cannot cast named argument '%s' to type %s." % (key, type))
+                    self.raise_tcl_error("Cannot cast named argument '%s' to type %s  with exception '%s'."
+                                         % (key, arg_type, str(e)))
             else:
             else:
                 unnamed_args.append(argument)
                 unnamed_args.append(argument)
             idx += 1
             idx += 1
 
 
-        # check otions
+        # check options
         for key in options:
         for key in options:
             if key not in self.option_types:
             if key not in self.option_types:
-                self.app.raiseTclError('Unknown parameter: %s' % key)
+                self.raise_tcl_error('Unknown parameter: %s' % key)
             try:
             try:
                 named_args[key] = self.option_types[key](options[key])
                 named_args[key] = self.option_types[key](options[key])
             except Exception, e:
             except Exception, e:
-                self.app.raiseTclError("Cannot cast argument '-%s' to type %s." % (key, self.option_types[key]))
+                self.raise_tcl_error("Cannot cast argument '-%s' to type '%s' with exception '%s'."
+                                     % (key, self.option_types[key], str(e)))
 
 
         # check required arguments
         # check required arguments
         for key in self.required:
         for key in self.required:
             if key not in named_args:
             if key not in named_args:
-                self.app.raiseTclError("Missing required argument '%s'." % (key))
+                self.raise_tcl_error("Missing required argument '%s'." % key)
 
 
         return named_args, unnamed_args
         return named_args, unnamed_args
 
 
@@ -168,12 +200,16 @@ class TclCommand(object):
         :param args: arguments passed from tcl command console
         :param args: arguments passed from tcl command console
         :return: None, output text or exception
         :return: None, output text or exception
         """
         """
+
         try:
         try:
+            self.log.debug("TCL command '%s' executed." % str(self.__class__))
             args, unnamed_args = self.check_args(args)
             args, unnamed_args = self.check_args(args)
             return self.execute(args, unnamed_args)
             return self.execute(args, unnamed_args)
         except Exception as unknown:
         except Exception as unknown:
-            self.app.raiseTclUnknownError(unknown)
+            self.log.error("TCL command '%s' failed." % str(self))
+            self.app.raise_tcl_unknown_error(unknown)
 
 
+    @abc.abstractmethod
     def execute(self, args, unnamed_args):
     def execute(self, args, unnamed_args):
         """
         """
         Direct execute of command, this method should be implemented in each descendant.
         Direct execute of command, this method should be implemented in each descendant.
@@ -186,3 +222,73 @@ class TclCommand(object):
         """
         """
 
 
         raise NotImplementedError("Please Implement this method")
         raise NotImplementedError("Please Implement this method")
+
+
+class TclCommandSignaled(TclCommand):
+    """
+        !!! I left it here only  for demonstration !!!
+        Go to TclCommandCncjob and  into class definition put
+            class TclCommandCncjob(TclCommand.TclCommandSignaled):
+        also change
+            obj.generatecncjob(use_thread = False, **args)
+        to
+            obj.generatecncjob(use_thread = True, **args)
+
+
+        This class is  child of  TclCommand and is used for commands  which create  new objects
+        it handles  all neccessary stuff about blocking and passing exeptions
+    """
+
+    # default  timeout for operation is  30 sec, but it can be much more
+    default_timeout = 30000
+
+
+    def execute_wrapper(self, *args):
+        """
+        Command which is called by tcl console when current commands aliases are hit.
+        Main catch(except) is implemented here.
+        This method should be reimplemented only when initial checking sequence differs
+
+        :param args: arguments passed from tcl command console
+        :return: None, output text or exception
+        """
+
+        @contextmanager
+        def wait_signal(signal, timeout=30000):
+            """Block loop until signal emitted, or timeout (ms) elapses."""
+            loop = QtCore.QEventLoop()
+            signal.connect(loop.quit)
+
+            status = {'timed_out': False}
+
+            def report_quit():
+                status['timed_out'] = True
+                loop.quit()
+
+            yield
+
+            if timeout is not None:
+                QtCore.QTimer.singleShot(timeout, report_quit)
+
+            loop.exec_()
+
+            if status['timed_out']:
+                self.app.raise_tcl_unknown_error('Operation timed out!')
+
+        try:
+            self.log.debug("TCL command '%s' executed." % str(self.__class__))
+            args, unnamed_args = self.check_args(args)
+            if 'timeout' in args:
+                passed_timeout=args['timeout']
+                del args['timeout']
+            else:
+                passed_timeout=self.default_timeout
+            with wait_signal(self.app.new_object_available, passed_timeout):
+                # every TclCommandNewObject ancestor  support  timeout as parameter,
+                # but it does not mean anything for child itself
+                # when operation  will be  really long is good  to set it higher then defqault 30s
+                return self.execute(args, unnamed_args)
+
+        except Exception as unknown:
+            self.log.error("TCL command '%s' failed." % str(self))
+            self.app.raise_tcl_unknown_error(unknown)

+ 8 - 12
tclCommands/TclCommandAddPolygon.py

@@ -8,7 +8,7 @@ class TclCommandAddPolygon(TclCommand.TclCommand):
     """
     """
 
 
     # array of all command aliases, to be able use  old names for backward compatibility (add_poly, add_polygon)
     # array of all command aliases, to be able use  old names for backward compatibility (add_poly, add_polygon)
-    aliases = ['add_polygon','add_poly']
+    aliases = ['add_polygon', 'add_poly']
 
 
     # dictionary of types from Tcl command, needs to be ordered
     # dictionary of types from Tcl command, needs to be ordered
     arg_names = collections.OrderedDict([
     arg_names = collections.OrderedDict([
@@ -16,7 +16,7 @@ class TclCommandAddPolygon(TclCommand.TclCommand):
     ])
     ])
 
 
     # dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
     # dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
-    option_types = collections.OrderedDict([])
+    option_types = collections.OrderedDict()
 
 
     # array of mandatory options for current Tcl command: required = {'name','outname'}
     # array of mandatory options for current Tcl command: required = {'name','outname'}
     required = ['name']
     required = ['name']
@@ -28,7 +28,7 @@ class TclCommandAddPolygon(TclCommand.TclCommand):
             ('name', 'Name of the Geometry object to which to append the polygon.'),
             ('name', 'Name of the Geometry object to which to append the polygon.'),
             ('xi, yi', 'Coordinates of points in the polygon.')
             ('xi, yi', 'Coordinates of points in the polygon.')
         ]),
         ]),
-        'examples':[
+        'examples': [
             'add_polygon <name> <x0> <y0> <x1> <y1> <x2> <y2> [x3 y3 [...]]'
             'add_polygon <name> <x0> <y0> <x1> <y1> <x2> <y2> [x3 y3 [...]]'
         ]
         ]
     }
     }
@@ -45,21 +45,17 @@ class TclCommandAddPolygon(TclCommand.TclCommand):
 
 
         name = args['name']
         name = args['name']
 
 
-        try:
-            obj = self.app.collection.get_by_name(name)
-        except:
-            self.app.raiseTclError("Could not retrieve object: %s" % name)
-
+        obj = self.app.collection.get_by_name(name)
         if obj is None:
         if obj is None:
-            self.app.raiseTclError("Object not found: %s" % name)
+            self.raise_tcl_error("Object not found: %s" % name)
 
 
         if not isinstance(obj, Geometry):
         if not isinstance(obj, Geometry):
-            self.app.raiseTclError('Expected Geometry, got %s %s.' % (name, type(obj)))
+            self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
 
 
         if len(unnamed_args) % 2 != 0:
         if len(unnamed_args) % 2 != 0:
-            self.app.raiseTclError("Incomplete coordinates.")
+            self.raise_tcl_error("Incomplete coordinates.")
 
 
         points = [[float(unnamed_args[2*i]), float(unnamed_args[2*i+1])] for i in range(len(unnamed_args)/2)]
         points = [[float(unnamed_args[2*i]), float(unnamed_args[2*i+1])] for i in range(len(unnamed_args)/2)]
 
 
         obj.add_polygon(points)
         obj.add_polygon(points)
-        obj.plot()
+        obj.plot()

+ 7 - 11
tclCommands/TclCommandAddPolyline.py

@@ -16,7 +16,7 @@ class TclCommandAddPolyline(TclCommand.TclCommand):
     ])
     ])
 
 
     # dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
     # dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
-    option_types = collections.OrderedDict([])
+    option_types = collections.OrderedDict()
 
 
     # array of mandatory options for current Tcl command: required = {'name','outname'}
     # array of mandatory options for current Tcl command: required = {'name','outname'}
     required = ['name']
     required = ['name']
@@ -28,7 +28,7 @@ class TclCommandAddPolyline(TclCommand.TclCommand):
             ('name', 'Name of the Geometry object to which to append the polyline.'),
             ('name', 'Name of the Geometry object to which to append the polyline.'),
             ('xi, yi', 'Coordinates of points in the polyline.')
             ('xi, yi', 'Coordinates of points in the polyline.')
         ]),
         ]),
-        'examples':[
+        'examples': [
             'add_polyline <name> <x0> <y0> <x1> <y1> <x2> <y2> [x3 y3 [...]]'
             'add_polyline <name> <x0> <y0> <x1> <y1> <x2> <y2> [x3 y3 [...]]'
         ]
         ]
     }
     }
@@ -45,21 +45,17 @@ class TclCommandAddPolyline(TclCommand.TclCommand):
 
 
         name = args['name']
         name = args['name']
 
 
-        try:
-            obj = self.app.collection.get_by_name(name)
-        except:
-            self.app.raiseTclError("Could not retrieve object: %s" % name)
-
+        obj = self.app.collection.get_by_name(name)
         if obj is None:
         if obj is None:
-            self.app.raiseTclError("Object not found: %s" % name)
+            self.raise_tcl_error("Object not found: %s" % name)
 
 
         if not isinstance(obj, Geometry):
         if not isinstance(obj, Geometry):
-            self.app.raiseTclError('Expected Geometry, got %s %s.' % (name, type(obj)))
+            self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
 
 
         if len(unnamed_args) % 2 != 0:
         if len(unnamed_args) % 2 != 0:
-            self.app.raiseTclError("Incomplete coordinates.")
+            self.raise_tcl_error("Incomplete coordinates.")
 
 
         points = [[float(unnamed_args[2*i]), float(unnamed_args[2*i+1])] for i in range(len(unnamed_args)/2)]
         points = [[float(unnamed_args[2*i]), float(unnamed_args[2*i+1])] for i in range(len(unnamed_args)/2)]
 
 
         obj.add_polyline(points)
         obj.add_polyline(points)
-        obj.plot()
+        obj.plot()

+ 86 - 0
tclCommands/TclCommandCncjob.py

@@ -0,0 +1,86 @@
+from ObjectCollection import *
+import TclCommand
+
+
+class TclCommandCncjob(TclCommand.TclCommand):
+    """
+    Tcl shell command to Generates a CNC Job from a Geometry Object.
+
+    example:
+        set_sys units MM
+        new
+        open_gerber tests/gerber_files/simple1.gbr -outname margin
+        isolate margin -dia 3
+        cncjob margin_iso
+    """
+
+    # array of all command aliases, to be able use  old names for backward compatibility (add_poly, add_polygon)
+    aliases = ['cncjob']
+
+    # dictionary of types from Tcl command, needs to be ordered
+    arg_names = collections.OrderedDict([
+        ('name', str)
+    ])
+
+    # dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
+    option_types = collections.OrderedDict([
+        ('z_cut',float),
+        ('z_move',float),
+        ('feedrate',float),
+        ('tooldia',float),
+        ('spindlespeed',int),
+        ('multidepth',bool),
+        ('depthperpass',float),
+        ('outname',str)
+    ])
+
+    # array of mandatory options for current Tcl command: required = {'name','outname'}
+    required = ['name']
+
+    # structured help for current command, args needs to be ordered
+    help = {
+        'main': "Generates a CNC Job from a Geometry Object.",
+        'args': collections.OrderedDict([
+            ('name', 'Name of the source object.'),
+            ('z_cut', 'Z-axis cutting position.'),
+            ('z_move', 'Z-axis moving position.'),
+            ('feedrate', 'Moving speed when cutting.'),
+            ('tooldia', 'Tool diameter to show on screen.'),
+            ('spindlespeed', 'Speed of the spindle in rpm (example: 4000).'),
+            ('multidepth', 'Use or not multidepth cnccut.'),
+            ('depthperpass', 'Height of one layer for multidepth.'),
+            ('outname', 'Name of the resulting Geometry object.'),
+            ('timeout', 'Max wait for job timeout before error.')
+        ]),
+        'examples': []
+    }
+
+    def execute(self, args, unnamed_args):
+        """
+        execute current TCL shell command
+
+        :param args: array of known named arguments and options
+        :param unnamed_args: array of other values which were passed into command
+            without -somename and  we do not have them in known arg_names
+        :return: None or exception
+        """
+
+        name = args['name']
+
+        if 'outname' not in args:
+            args['outname'] = name + "_cnc"
+
+        if 'timeout' in args:
+            timeout = args['timeout']
+        else:
+            timeout = 10000
+
+        obj = self.app.collection.get_by_name(name)
+        if obj is None:
+            self.raise_tcl_error("Object not found: %s" % name)
+
+        if not isinstance(obj, FlatCAMGeometry):
+            self.raise_tcl_error('Expected FlatCAMGeometry, got %s %s.' % (name, type(obj)))
+
+        del args['name']
+        obj.generatecncjob(use_thread = False, **args)

+ 79 - 0
tclCommands/TclCommandExportGcode.py

@@ -0,0 +1,79 @@
+from ObjectCollection import *
+import TclCommand
+
+
+class TclCommandExportGcode(TclCommand.TclCommand):
+    """
+    Tcl shell command to export gcode as  tcl output for "set X [export_gcode ...]"
+
+    Requires name to be available. It might still be in the
+    making at the time this function is called, so check for
+    promises and send to background if there are promises.
+
+
+    this  export   may be  catched   by tcl and past as preable  to another  export_gcode or write_gcode
+    this can be used to join GCODES
+
+    example:
+        set_sys units MM
+        new
+        open_gerber tests/gerber_files/simple1.gbr -outname margin
+        isolate margin -dia 3
+        cncjob margin_iso
+        cncjob margin_iso
+        set EXPORT [export_gcode margin_iso_cnc]
+        write_gcode margin_iso_cnc_1 /tmp/file.gcode ${EXPORT}
+
+    """
+
+    # array of all command aliases, to be able use  old names for backward compatibility (add_poly, add_polygon)
+    aliases = ['export_gcode']
+
+    # dictionary of types from Tcl command, needs to be ordered
+    arg_names = collections.OrderedDict([
+        ('name', str),
+        ('preamble', str),
+        ('postamble', str)
+    ])
+
+    # dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
+    option_types = collections.OrderedDict()
+
+    # array of mandatory options for current Tcl command: required = {'name','outname'}
+    required = ['name']
+
+    # structured help for current command, args needs to be ordered
+    help = {
+        'main': "Export gcode into console output.",
+        'args': collections.OrderedDict([
+            ('name', 'Name of the source Geometry object.'),
+            ('preamble', 'Prepend GCODE.'),
+            ('postamble', 'Append GCODE.')
+        ]),
+        'examples': []
+    }
+
+    def execute(self, args, unnamed_args):
+        """
+        execute current TCL shell command
+
+        :param args: array of known named arguments and options
+        :param unnamed_args: array of other values which were passed into command
+            without -somename and  we do not have them in known arg_names
+        :return: None or exception
+        """
+
+        name = args['name']
+
+        obj = self.app.collection.get_by_name(name)
+        if obj is None:
+            self.raise_tcl_error("Object not found: %s" % name)
+
+        if not isinstance(obj, CNCjob):
+            self.raise_tcl_error('Expected CNCjob, got %s %s.' % (name, type(obj)))
+
+        if self.app.collection.has_promises():
+            self.raise_tcl_error('!!!Promises exists, but should not here!!!')
+
+        del args['name']
+        return obj.get_gcode(**args)

+ 7 - 11
tclCommands/TclCommandExteriors.py

@@ -8,7 +8,7 @@ class TclCommandExteriors(TclCommand.TclCommand):
     """
     """
 
 
     # array of all command aliases, to be able use  old names for backward compatibility (add_poly, add_polygon)
     # array of all command aliases, to be able use  old names for backward compatibility (add_poly, add_polygon)
-    aliases = ['exteriors','ext']
+    aliases = ['exteriors', 'ext']
 
 
     # dictionary of types from Tcl command, needs to be ordered
     # dictionary of types from Tcl command, needs to be ordered
     arg_names = collections.OrderedDict([
     arg_names = collections.OrderedDict([
@@ -30,7 +30,7 @@ class TclCommandExteriors(TclCommand.TclCommand):
             ('name', 'Name of the source Geometry object.'),
             ('name', 'Name of the source Geometry object.'),
             ('outname', 'Name of the resulting Geometry object.')
             ('outname', 'Name of the resulting Geometry object.')
         ]),
         ]),
-        'examples':[]
+        'examples': []
     }
     }
 
 
     def execute(self, args, unnamed_args):
     def execute(self, args, unnamed_args):
@@ -50,19 +50,15 @@ class TclCommandExteriors(TclCommand.TclCommand):
         else:
         else:
             outname = name + "_exteriors"
             outname = name + "_exteriors"
 
 
-        try:
-            obj = self.app.collection.get_by_name(name)
-        except:
-            self.app.raiseTclError("Could not retrieve object: %s" % name)
-
+        obj = self.app.collection.get_by_name(name)
         if obj is None:
         if obj is None:
-            self.app.raiseTclError("Object not found: %s" % name)
+            self.raise_tcl_error("Object not found: %s" % name)
 
 
         if not isinstance(obj, Geometry):
         if not isinstance(obj, Geometry):
-            self.app.raiseTclError('Expected Geometry, got %s %s.' % (name, type(obj)))
+            self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
 
 
-        def geo_init(geo_obj, app_obj):
+        def geo_init(geo_obj):
             geo_obj.solid_geometry = obj_exteriors
             geo_obj.solid_geometry = obj_exteriors
 
 
         obj_exteriors = obj.get_exteriors()
         obj_exteriors = obj.get_exteriors()
-        self.app.new_object('geometry', outname, geo_init)
+        self.app.new_object('geometry', outname, geo_init)

+ 7 - 10
tclCommands/TclCommandInteriors.py

@@ -1,6 +1,7 @@
 from ObjectCollection import *
 from ObjectCollection import *
 import TclCommand
 import TclCommand
 
 
+
 class TclCommandInteriors(TclCommand.TclCommand):
 class TclCommandInteriors(TclCommand.TclCommand):
     """
     """
     Tcl shell command to get interiors of polygons
     Tcl shell command to get interiors of polygons
@@ -29,7 +30,7 @@ class TclCommandInteriors(TclCommand.TclCommand):
             ('name', 'Name of the source Geometry object.'),
             ('name', 'Name of the source Geometry object.'),
             ('outname', 'Name of the resulting Geometry object.')
             ('outname', 'Name of the resulting Geometry object.')
         ]),
         ]),
-        'examples':[]
+        'examples': []
     }
     }
 
 
     def execute(self, args, unnamed_args):
     def execute(self, args, unnamed_args):
@@ -49,19 +50,15 @@ class TclCommandInteriors(TclCommand.TclCommand):
         else:
         else:
             outname = name + "_interiors"
             outname = name + "_interiors"
 
 
-        try:
-            obj = self.app.collection.get_by_name(name)
-        except:
-            self.app.raiseTclError("Could not retrieve object: %s" % name)
-
+        obj = self.app.collection.get_by_name(name)
         if obj is None:
         if obj is None:
-            self.app.raiseTclError("Object not found: %s" % name)
+            self.raise_tcl_error("Object not found: %s" % name)
 
 
         if not isinstance(obj, Geometry):
         if not isinstance(obj, Geometry):
-            self.app.raiseTclError('Expected Geometry, got %s %s.' % (name, type(obj)))
+            self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
 
 
-        def geo_init(geo_obj, app_obj):
+        def geo_init(geo_obj):
             geo_obj.solid_geometry = obj_exteriors
             geo_obj.solid_geometry = obj_exteriors
 
 
         obj_exteriors = obj.get_interiors()
         obj_exteriors = obj.get_interiors()
-        self.app.new_object('geometry', outname, geo_init)
+        self.app.new_object('geometry', outname, geo_init)

+ 15 - 15
tclCommands/__init__.py

@@ -1,5 +1,4 @@
 import pkgutil
 import pkgutil
-import inspect
 import sys
 import sys
 
 
 # allowed command modules
 # allowed command modules
@@ -7,9 +6,10 @@ import tclCommands.TclCommandExteriors
 import tclCommands.TclCommandInteriors
 import tclCommands.TclCommandInteriors
 import tclCommands.TclCommandAddPolygon
 import tclCommands.TclCommandAddPolygon
 import tclCommands.TclCommandAddPolyline
 import tclCommands.TclCommandAddPolyline
+import tclCommands.TclCommandExportGcode
+import tclCommands.TclCommandCncjob
 
 
-
-__all__=[]
+__all__ = []
 
 
 for loader, name, is_pkg in pkgutil.walk_packages(__path__):
 for loader, name, is_pkg in pkgutil.walk_packages(__path__):
     module = loader.find_module(name).load_module(name)
     module = loader.find_module(name).load_module(name)
@@ -25,8 +25,8 @@ def register_all_commands(app, commands):
 
 
     we need import all  modules  in top section:
     we need import all  modules  in top section:
     import tclCommands.TclCommandExteriors
     import tclCommands.TclCommandExteriors
-    at this stage we can include only wanted  commands  with this, autoloading may be implemented in future
-    I have no enought knowledge about python's anatomy. Would be nice to include all classes which are descendant etc.
+    at this stage we can include only wanted  commands  with this, auto loading may be implemented in future
+    I have no enough knowledge about python's anatomy. Would be nice to include all classes which are descendant etc.
 
 
     :param app: FlatCAMApp
     :param app: FlatCAMApp
     :param commands: array of commands  which should be modified
     :param commands: array of commands  which should be modified
@@ -35,14 +35,14 @@ def register_all_commands(app, commands):
 
 
     tcl_modules = {k: v for k, v in sys.modules.items() if k.startswith('tclCommands.TclCommand')}
     tcl_modules = {k: v for k, v in sys.modules.items() if k.startswith('tclCommands.TclCommand')}
 
 
-    for key, module in tcl_modules.items():
+    for key, mod in tcl_modules.items():
         if key != 'tclCommands.TclCommand':
         if key != 'tclCommands.TclCommand':
-            classname = key.split('.')[1]
-            class_ = getattr(module, classname)
-            commandInstance=class_(app)
-
-            for alias in commandInstance.aliases:
-                commands[alias]={
-                    'fcn': commandInstance.execute_wrapper,
-                    'help': commandInstance.get_decorated_help()
-                }
+            class_name = key.split('.')[1]
+            class_type = getattr(mod, class_name)
+            command_instance = class_type(app)
+
+            for alias in command_instance.aliases:
+                commands[alias] = {
+                    'fcn': command_instance.execute_wrapper,
+                    'help': command_instance.get_decorated_help()
+                }