Pārlūkot izejas kodu

Merge https://bitbucket.org/jpcgt/flatcam/src/master into Follow_TCL_command_add_to_new_architecture

# Conflicts:
#	FlatCAMApp.py
Marius Stanciu 7 gadi atpakaļ
vecāks
revīzija
5ff3f66b04
77 mainītis faili ar 431 papildinājumiem un 437 dzēšanām
  1. 66 40
      FlatCAMApp.py
  2. 31 31
      FlatCAMDraw.py
  3. 50 50
      FlatCAMGUI.py
  4. 19 12
      FlatCAMObj.py
  5. 9 9
      GUIElements.py
  6. 6 6
      ObjectCollection.py
  7. 4 4
      ObjectUI.py
  8. 8 8
      bugs/conf.py
  9. 9 5
      camlib.py
  10. 6 6
      descartes/tests.py
  11. 8 8
      doc/source/conf.py
  12. 2 2
      flatcam
  13. 3 3
      make_win32.py
  14. 10 10
      sandbox/diagnose.py
  15. 3 3
      sandbox/gerber_find.py
  16. 2 2
      svgparse.py
  17. 7 6
      tclCommands/TclCommand.py
  18. 2 3
      tclCommands/TclCommandAddCircle.py
  19. 2 3
      tclCommands/TclCommandAddPolygon.py
  20. 2 3
      tclCommands/TclCommandAddPolyline.py
  21. 2 3
      tclCommands/TclCommandAddRectangle.py
  22. 4 5
      tclCommands/TclCommandAlignDrill.py
  23. 2 3
      tclCommands/TclCommandAlignDrillGrid.py
  24. 2 3
      tclCommands/TclCommandCncjob.py
  25. 3 4
      tclCommands/TclCommandCutout.py
  26. 2 3
      tclCommands/TclCommandDelete.py
  27. 2 3
      tclCommands/TclCommandDrillcncjob.py
  28. 2 3
      tclCommands/TclCommandExportGcode.py
  29. 2 3
      tclCommands/TclCommandExportSVG.py
  30. 3 4
      tclCommands/TclCommandExteriors.py
  31. 2 3
      tclCommands/TclCommandGeoCutout.py
  32. 2 3
      tclCommands/TclCommandGeoUnion.py
  33. 2 3
      tclCommands/TclCommandGetNames.py
  34. 2 3
      tclCommands/TclCommandGetSys.py
  35. 2 3
      tclCommands/TclCommandImportSvg.py
  36. 2 3
      tclCommands/TclCommandInteriors.py
  37. 2 3
      tclCommands/TclCommandIsolate.py
  38. 2 3
      tclCommands/TclCommandJoinExcellon.py
  39. 2 3
      tclCommands/TclCommandJoinGeometry.py
  40. 2 3
      tclCommands/TclCommandMillHoles.py
  41. 4 5
      tclCommands/TclCommandMirror.py
  42. 2 3
      tclCommands/TclCommandNew.py
  43. 2 3
      tclCommands/TclCommandNewGeometry.py
  44. 2 3
      tclCommands/TclCommandOffset.py
  45. 2 3
      tclCommands/TclCommandOpenExcellon.py
  46. 2 3
      tclCommands/TclCommandOpenGCode.py
  47. 4 5
      tclCommands/TclCommandOpenGerber.py
  48. 2 3
      tclCommands/TclCommandOpenProject.py
  49. 2 3
      tclCommands/TclCommandOptions.py
  50. 2 3
      tclCommands/TclCommandPaint.py
  51. 2 4
      tclCommands/TclCommandPanelize.py
  52. 2 3
      tclCommands/TclCommandPlot.py
  53. 2 3
      tclCommands/TclCommandSaveProject.py
  54. 2 3
      tclCommands/TclCommandScale.py
  55. 2 3
      tclCommands/TclCommandSetActive.py
  56. 2 3
      tclCommands/TclCommandSetSys.py
  57. 2 3
      tclCommands/TclCommandSubtractPoly.py
  58. 2 3
      tclCommands/TclCommandSubtractRectangle.py
  59. 2 3
      tclCommands/TclCommandVersion.py
  60. 2 3
      tclCommands/TclCommandWriteGCode.py
  61. 2 2
      tclCommands/__init__.py
  62. 2 2
      termwidget.py
  63. 2 2
      tests/canvas/performance.py
  64. 1 1
      tests/other/destructor_test.py
  65. 3 3
      tests/other/test_fcrts.py
  66. 3 3
      tests/other/test_rt.py
  67. 9 9
      tests/test_excellon_flow.py
  68. 9 9
      tests/test_gerber_flow.py
  69. 21 21
      tests/test_paint.py
  70. 3 3
      tests/test_pathconnect.py
  71. 12 12
      tests/test_polygon_paint.py
  72. 7 7
      tests/test_svg_flow.py
  73. 14 14
      tests/test_tclCommands/__init__.py
  74. 1 1
      tests/test_tclCommands/test_TclCommandCncjob.py
  75. 1 1
      tests/test_tclCommands/test_TclCommandDrillcncjob.py
  76. 2 2
      tests/test_tclCommands/test_TclCommandExportGcode.py
  77. 2 2
      tests/test_tcl_shell.py

+ 66 - 40
FlatCAMApp.py

@@ -8,7 +8,7 @@
 
 import sys
 import traceback
-import urllib
+import urllib.request, urllib.parse, urllib.error
 import getopt
 import random
 import logging
@@ -16,8 +16,8 @@ import simplejson as json
 import re
 import webbrowser
 import os
-import Tkinter
-from PyQt4 import QtCore
+import tkinter
+from PyQt4 import Qt, QtCore, QtGui
 import time  # Just used for debugging. Double check before removing.
 from xml.dom.minidom import parseString as parse_xml_string
 from contextlib import contextmanager
@@ -27,10 +27,10 @@ from contextlib import contextmanager
 ########################################
 import FlatCAMVersion
 from FlatCAMWorker import Worker
-from ObjectCollection import *
-from FlatCAMObj import *
-from PlotCanvas import *
-from FlatCAMGUI import *
+import ObjectCollection
+from FlatCAMObj import FlatCAMCNCjob, FlatCAMExcellon, FlatCAMGerber, FlatCAMGeometry, FlatCAMObj
+from PlotCanvas import PlotCanvas
+from FlatCAMGUI import FlatCAMGUI, GlobalOptionsUI, FlatCAMActivityView, FlatCAMInfoBar
 from FlatCAMCommon import LoudDict
 from FlatCAMShell import FCShell
 from FlatCAMDraw import FlatCAMDraw
@@ -39,6 +39,8 @@ from MeasurementTool import Measurement
 from DblSidedTool import DblSidedTool
 import tclCommands
 
+from camlib import *
+
 
 ########################################
 ##                App                 ##
@@ -54,11 +56,11 @@ class App(QtCore.QObject):
     try:
         cmd_line_options, args = getopt.getopt(sys.argv[1:], "h:", "shellfile=")
     except getopt.GetoptError:
-        print cmd_line_help
+        print(cmd_line_help)
         sys.exit(2)
     for opt, arg in cmd_line_options:
         if opt == '-h':
-            print cmd_line_help
+            print(cmd_line_help)
             sys.exit()
         elif opt == '--shellfile':
             cmd_line_shellfile = arg
@@ -106,7 +108,7 @@ class App(QtCore.QObject):
     # Note: Setting the parameters to unicode does not seem
     #       to have an effect. Then are received as Qstring
     #       anyway.
-    file_opened = QtCore.pyqtSignal(unicode, unicode)  # File type and filename
+    file_opened = QtCore.pyqtSignal(str, str)  # File type and filename
 
     progress = QtCore.pyqtSignal(int)  # Percentage of progress
 
@@ -471,7 +473,7 @@ class App(QtCore.QObject):
         #self.options_write_form()
         self.on_options_combo_change(0)  # Will show the initial form
 
-        self.collection = ObjectCollection()
+        self.collection = ObjectCollection.ObjectCollection()
         self.ui.project_tab_layout.addWidget(self.collection.view)
         #### End of Data ####
 
@@ -612,7 +614,7 @@ class App(QtCore.QObject):
                     cmd_line_shellfile_text = myfile.read()
                     self.shell._sysShell.exec_command(cmd_line_shellfile_text)
             except Exception as ext:
-                print "ERROR: ", ext
+                print(("ERROR: ", ext))
                 sys.exit(2)
 
         # Post-GUI initialization: Experimental attempt
@@ -630,7 +632,7 @@ class App(QtCore.QObject):
             # because tcl  was execudted in old instance of TCL
             pass
         else:
-            self.tcl = Tkinter.Tcl()
+            self.tcl = tkinter.Tcl()
             self.setup_shell()
 
     def defaults_read_form(self):
@@ -849,7 +851,7 @@ class App(QtCore.QObject):
             if result != 'None':
                 self.shell.append_output(result + '\n')
 
-        except Tkinter.TclError, e:
+        except tkinter.TclError as e:
             # This will display more precise answer if something in TCL shell fails
             result = self.tcl.eval("set errorInfo")
             self.log.error("Exec command Exception: %s" % (result + '\n'))
@@ -895,7 +897,7 @@ class App(QtCore.QObject):
             if retval and retfcn(retval):
                 self.shell.append_output(retfcn(retval) + "\n")
 
-        except Exception, e:
+        except Exception as e:
             #self.shell.append_error(''.join(traceback.format_exc()))
             #self.shell.append_error("?\n")
             self.shell.append_error(str(e) + "\n")
@@ -915,14 +917,14 @@ class App(QtCore.QObject):
         if match:
             level = match.group(1)
             msg_ = match.group(2)
-            self.ui.fcinfo.set_status(QtCore.QString(msg_), level=level)
+            self.ui.fcinfo.set_status(str(msg_), level=level)
 
             if toshell:
                 error = level == "error" or level == "warning"
                 self.shell_message(msg, error=error, show=True)
 
         else:
-            self.ui.fcinfo.set_status(QtCore.QString(msg), level="info")
+            self.ui.fcinfo.set_status(str(msg), level="info")
 
             if toshell:
                 self.shell_message(msg)
@@ -973,7 +975,7 @@ class App(QtCore.QObject):
         self.log.debug("   %s" % kind)
         self.log.debug("   %s" % filename)
 
-        record = {'kind': unicode(kind), 'filename': unicode(filename)}
+        record = {'kind': str(kind), 'filename': str(filename)}
         if record in self.recent:
             return
 
@@ -1072,7 +1074,7 @@ class App(QtCore.QObject):
             t3 = time.time()
             self.log.debug("%f seconds converting units." % (t3 - t2))
 
-        FlatCAMApp.App.log.debug("Moving new object back to main thread.")
+        self.log.debug("Moving new object back to main thread.")
 
         # Move the object to the main thread and let the app know that it is available.
         obj.moveToThread(QtGui.QApplication.instance().thread())
@@ -1123,7 +1125,7 @@ class App(QtCore.QObject):
                 layout1.addLayout(layout2)
 
                 logo = QtGui.QLabel()
-                logo.setPixmap(QtGui.QPixmap('share:flatcam_icon256.png'))
+                logo.setPixmap(QtGui.QPixmap('share/flatcam_icon256.png'))
                 layout2.addWidget(logo, stretch=0)
 
                 title = QtGui.QLabel(
@@ -1643,7 +1645,7 @@ class App(QtCore.QObject):
             if modifiers == QtCore.Qt.ControlModifier:
                 self.clipboard.setText(self.defaults["point_clipboard_format"] % (event.xdata, event.ydata))
 
-        except Exception, e:
+        except Exception as e:
             App.log.debug("Outside plot?")
             App.log.debug(str(e))
 
@@ -1713,7 +1715,7 @@ class App(QtCore.QObject):
         # The Qt methods above will return a QString which can cause problems later.
         # So far json.dump() will fail to serialize it.
         # TODO: Improve the serialization methods and remove this fix.
-        filename = unicode(filename)
+        filename = str(filename)
 
         if filename == "":
             self.inform.emit("Open cancelled.")
@@ -1740,7 +1742,7 @@ class App(QtCore.QObject):
         # The Qt methods above will return a QString which can cause problems later.
         # So far json.dump() will fail to serialize it.
         # TODO: Improve the serialization methods and remove this fix.
-        filename = unicode(filename)
+        filename = str(filename)
 
         if filename == "":
             self.inform.emit("Open cancelled.")
@@ -1767,7 +1769,7 @@ class App(QtCore.QObject):
         # The Qt methods above will return a QString which can cause problems later.
         # So far json.dump() will fail to serialize it.
         # TODO: Improve the serialization methods and remove this fix.
-        filename = unicode(filename)
+        filename = str(filename)
 
         if filename == "":
             self.inform.emit("Open cancelled.")
@@ -1794,7 +1796,7 @@ class App(QtCore.QObject):
         # The Qt methods above will return a QString which can cause problems later.
         # So far json.dump() will fail to serialize it.
         # TODO: Improve the serialization methods and remove this fix.
-        filename = unicode(filename)
+        filename = str(filename)
 
         if filename == "":
             self.inform.emit("Open cancelled.")
@@ -1844,7 +1846,7 @@ class App(QtCore.QObject):
         except TypeError:
             filename = QtGui.QFileDialog.getSaveFileName(caption="Export SVG")
 
-        filename = unicode(filename)
+        filename = str(filename)
 
         if filename == "":
             self.inform.emit("Export SVG cancelled.")
@@ -1867,7 +1869,7 @@ class App(QtCore.QObject):
         except TypeError:
             filename = QtGui.QFileDialog.getOpenFileName(caption="Import SVG")
 
-        filename = unicode(filename)
+        filename = str(filename)
 
         if filename == "":
             self.inform.emit("Open cancelled.")
@@ -1910,7 +1912,7 @@ class App(QtCore.QObject):
         except TypeError:
             filename = QtGui.QFileDialog.getSaveFileName(caption="Save Project As ...")
 
-        filename = unicode(filename)
+        filename = str(filename)
 
         try:
             f = open(filename, 'r')
@@ -2044,7 +2046,7 @@ class App(QtCore.QObject):
                 app_obj.progress.emit(0)
                 raise IOError('Failed to open file: ' + filename)
 
-            except ParseError, e:
+            except ParseError as e:
                 app_obj.inform.emit("[error] Failed to parse file: " + filename + ". " + e[0])
                 app_obj.progress.emit(0)
                 self.log.error(str(e))
@@ -2345,7 +2347,7 @@ class App(QtCore.QObject):
         self.worker_task.emit({'fcn': worker_task, 'params': [self]})
 
     def register_folder(self, filename):
-        self.defaults["last_folder"] = os.path.split(unicode(filename))[0]
+        self.defaults["last_folder"] = os.path.split(str(filename))[0]
 
     def set_progress_bar(self, percentage, text=""):
         self.ui.progress_bar.setValue(int(percentage))
@@ -3597,7 +3599,7 @@ class App(QtCore.QObject):
             output = ''
             import collections
             od = collections.OrderedDict(sorted(commands.items()))
-            for cmd_, val in od.iteritems():
+            for cmd_, val in list(od.items()):
                 #print cmd, '\n', ''.join(['~']*len(cmd))
                 output += cmd_ + ' \n' + ''.join(['~'] * len(cmd_)) + '\n'
 
@@ -3632,6 +3634,7 @@ class App(QtCore.QObject):
 
             return output
 
+
         # def follow(obj_name, *args):
         #     a, kwa = h(*args)
         #
@@ -3654,6 +3657,29 @@ class App(QtCore.QObject):
         #     except Exception, e:
         #         return "ERROR: %s" % str(e)
 
+        # def follow(obj_name, *args):
+        #     a, kwa = h(*args)
+        #
+        #     types = {'outname': str}
+        #
+        #     for key in kwa:
+        #         if key not in types:
+        #             return 'Unknown parameter: %s' % key
+        #         kwa[key] = types[key](kwa[key])
+        #
+        #     try:
+        #         obj = self.collection.get_by_name(str(obj_name))
+        #     except:
+        #         return "Could not retrieve object: %s" % obj_name
+        #     if obj is None:
+        #         return "Object not found: %s" % obj_name
+        #
+        #     try:
+        #         obj.follow(**kwa)
+        #     except Exception as e:
+        #         return "ERROR: %s" % str(e)
+
+
         # def get_sys(param):
         #     if param in self.defaults:
         #         return self.defaults[param]
@@ -4145,11 +4171,11 @@ class App(QtCore.QObject):
 
         # TODO: Move this to constructor
         icons = {
-            "gerber": "share:flatcam_icon16.png",
-            "excellon": "share:drill16.png",
-            "cncjob": "share:cnc16.png",
-            "project": "share:project16.png",
-            "svg": "share:geometry16.png"
+            "gerber": "share/flatcam_icon16.png",
+            "excellon": "share/drill16.png",
+            "cncjob": "share/cnc16.png",
+            "project": "share/project16.png",
+            "svg": "share/geometry16.png"
         }
 
         openers = {
@@ -4238,12 +4264,12 @@ class App(QtCore.QObject):
             "?s=" + str(self.defaults['serial']) + \
             "&v=" + str(self.version) + \
             "&os=" + str(self.os) + \
-            "&" + urllib.urlencode(self.defaults["stats"])
+            "&" + urllib.parse.urlencode(self.defaults["stats"])
         App.log.debug("Checking for updates @ %s" % full_url)
 
         ### Get the data
         try:
-            f = urllib.urlopen(full_url)
+            f = urllib.request.urlopen(full_url)
         except:
             # App.log.warning("Failed checking for latest version. Could not connect.")
             self.log.warning("Failed checking for latest version. Could not connect.")
@@ -4252,7 +4278,7 @@ class App(QtCore.QObject):
 
         try:
             data = json.load(f)
-        except Exception, e:
+        except Exception as e:
             App.log.error("Could not parse information about latest version.")
             self.inform.emit("[error] Could not parse information about latest version.")
             App.log.debug("json.load(): %s" % str(e))
@@ -4270,7 +4296,7 @@ class App(QtCore.QObject):
         App.log.debug("Newer version available.")
         self.message.emit(
             "Newer Version Available",
-            QtCore.QString("There is a newer version of FlatCAM " +
+            str("There is a newer version of FlatCAM " +
                            "available for download:<br><br>" +
                            "<B>" + data["name"] + "</b><br>" +
                            data["message"].replace("\n", "<br>")),

+ 31 - 31
FlatCAMDraw.py

@@ -693,23 +693,23 @@ class FlatCAMDraw(QtCore.QObject):
         self.drawing_toolbar = QtGui.QToolBar()
         self.drawing_toolbar.setDisabled(disabled)
         self.app.ui.addToolBar(self.drawing_toolbar)
-        self.select_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share:pointer32.png'), "Select 'Esc'")
-        self.add_circle_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share:circle32.png'), 'Add Circle')
-        self.add_arc_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share:arc32.png'), 'Add Arc')
-        self.add_rectangle_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share:rectangle32.png'), 'Add Rectangle')
-        self.add_polygon_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share:polygon32.png'), 'Add Polygon')
-        self.add_path_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share:path32.png'), 'Add Path')
-        self.union_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share:union32.png'), 'Polygon Union')
-        self.intersection_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share:intersection32.png'), 'Polygon Intersection')
-        self.subtract_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share:subtract32.png'), 'Polygon Subtraction')
-        self.cutpath_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share:cutpath32.png'), 'Cut Path')
-        self.move_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share:move32.png'), "Move Objects 'm'")
-        self.copy_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share:copy32.png'), "Copy Objects 'c'")
-        self.delete_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share:deleteshape32.png'), "Delete Shape '-'")
+        self.select_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/pointer32.png'), "Select 'Esc'")
+        self.add_circle_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/circle32.png'), 'Add Circle')
+        self.add_arc_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/arc32.png'), 'Add Arc')
+        self.add_rectangle_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/rectangle32.png'), 'Add Rectangle')
+        self.add_polygon_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/polygon32.png'), 'Add Polygon')
+        self.add_path_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/path32.png'), 'Add Path')
+        self.union_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/union32.png'), 'Polygon Union')
+        self.intersection_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/intersection32.png'), 'Polygon Intersection')
+        self.subtract_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/subtract32.png'), 'Polygon Subtraction')
+        self.cutpath_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/cutpath32.png'), 'Cut Path')
+        self.move_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/move32.png'), "Move Objects 'm'")
+        self.copy_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/copy32.png'), "Copy Objects 'c'")
+        self.delete_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/deleteshape32.png'), "Delete Shape '-'")
 
         ### Snap Toolbar ###
         self.snap_toolbar = QtGui.QToolBar()
-        self.grid_snap_btn = self.snap_toolbar.addAction(QtGui.QIcon('share:grid32.png'), 'Snap to grid')
+        self.grid_snap_btn = self.snap_toolbar.addAction(QtGui.QIcon('share/grid32.png'), 'Snap to grid')
         self.grid_gap_x_entry = QtGui.QLineEdit()
         self.grid_gap_x_entry.setMaximumWidth(70)
         self.grid_gap_x_entry.setToolTip("Grid X distance")
@@ -719,7 +719,7 @@ class FlatCAMDraw(QtCore.QObject):
         self.grid_gap_y_entry.setToolTip("Grid Y distante")
         self.snap_toolbar.addWidget(self.grid_gap_y_entry)
 
-        self.corner_snap_btn = self.snap_toolbar.addAction(QtGui.QIcon('share:corner32.png'), 'Snap to corner')
+        self.corner_snap_btn = self.snap_toolbar.addAction(QtGui.QIcon('share/corner32.png'), 'Snap to corner')
         self.snap_max_dist_entry = QtGui.QLineEdit()
         self.snap_max_dist_entry.setMaximumWidth(70)
         self.snap_max_dist_entry.setToolTip("Max. magnet distance")
@@ -731,21 +731,21 @@ class FlatCAMDraw(QtCore.QObject):
         ### Application menu ###
         self.menu = QtGui.QMenu("Drawing")
         self.app.ui.menu.insertMenu(self.app.ui.menutoolaction, self.menu)
-        # self.select_menuitem = self.menu.addAction(QtGui.QIcon('share:pointer16.png'), "Select 'Esc'")
-        # self.add_circle_menuitem = self.menu.addAction(QtGui.QIcon('share:circle16.png'), 'Add Circle')
-        # self.add_arc_menuitem = self.menu.addAction(QtGui.QIcon('share:arc16.png'), 'Add Arc')
-        # self.add_rectangle_menuitem = self.menu.addAction(QtGui.QIcon('share:rectangle16.png'), 'Add Rectangle')
-        # self.add_polygon_menuitem = self.menu.addAction(QtGui.QIcon('share:polygon16.png'), 'Add Polygon')
-        # self.add_path_menuitem = self.menu.addAction(QtGui.QIcon('share:path16.png'), 'Add Path')
-        self.union_menuitem = self.menu.addAction(QtGui.QIcon('share:union16.png'), 'Polygon Union')
-        self.intersection_menuitem = self.menu.addAction(QtGui.QIcon('share:intersection16.png'), 'Polygon Intersection')
-        # self.subtract_menuitem = self.menu.addAction(QtGui.QIcon('share:subtract16.png'), 'Polygon Subtraction')
-        self.cutpath_menuitem = self.menu.addAction(QtGui.QIcon('share:cutpath16.png'), 'Cut Path')
-        # self.move_menuitem = self.menu.addAction(QtGui.QIcon('share:move16.png'), "Move Objects 'm'")
-        # self.copy_menuitem = self.menu.addAction(QtGui.QIcon('share:copy16.png'), "Copy Objects 'c'")
-        self.delete_menuitem = self.menu.addAction(QtGui.QIcon('share:deleteshape16.png'), "Delete Shape '-'")
-        self.buffer_menuitem = self.menu.addAction(QtGui.QIcon('share:buffer16.png'), "Buffer selection 'b'")
-        self.paint_menuitem = self.menu.addAction(QtGui.QIcon('share:paint16.png'), "Paint selection")
+        # self.select_menuitem = self.menu.addAction(QtGui.QIcon('share/pointer16.png'), "Select 'Esc'")
+        # self.add_circle_menuitem = self.menu.addAction(QtGui.QIcon('share/circle16.png'), 'Add Circle')
+        # self.add_arc_menuitem = self.menu.addAction(QtGui.QIcon('share/arc16.png'), 'Add Arc')
+        # self.add_rectangle_menuitem = self.menu.addAction(QtGui.QIcon('share/rectangle16.png'), 'Add Rectangle')
+        # self.add_polygon_menuitem = self.menu.addAction(QtGui.QIcon('share/polygon16.png'), 'Add Polygon')
+        # self.add_path_menuitem = self.menu.addAction(QtGui.QIcon('share/path16.png'), 'Add Path')
+        self.union_menuitem = self.menu.addAction(QtGui.QIcon('share/union16.png'), 'Polygon Union')
+        self.intersection_menuitem = self.menu.addAction(QtGui.QIcon('share/intersection16.png'), 'Polygon Intersection')
+        # self.subtract_menuitem = self.menu.addAction(QtGui.QIcon('share/subtract16.png'), 'Polygon Subtraction')
+        self.cutpath_menuitem = self.menu.addAction(QtGui.QIcon('share/cutpath16.png'), 'Cut Path')
+        # self.move_menuitem = self.menu.addAction(QtGui.QIcon('share/move16.png'), "Move Objects 'm'")
+        # self.copy_menuitem = self.menu.addAction(QtGui.QIcon('share/copy16.png'), "Copy Objects 'c'")
+        self.delete_menuitem = self.menu.addAction(QtGui.QIcon('share/deleteshape16.png'), "Delete Shape '-'")
+        self.buffer_menuitem = self.menu.addAction(QtGui.QIcon('share/buffer16.png'), "Buffer selection 'b'")
+        self.paint_menuitem = self.menu.addAction(QtGui.QIcon('share/paint16.png'), "Paint selection")
         self.menu.addSeparator()
 
         self.paint_menuitem.triggered.connect(self.on_paint_tool)
@@ -1473,7 +1473,7 @@ class FlatCAMDraw(QtCore.QObject):
 
         for param in [tooldia, overlap, margin]:
             if not isinstance(param, float):
-                param_name = [k for k, v in locals().iteritems() if v is param][0]
+                param_name = [k for k, v in list(locals().items()) if v is param][0]
                 self.app.inform.emit("[warning] Invalid value for {}".format())
 
         # Todo: Check for valid method.

+ 50 - 50
FlatCAMGUI.py

@@ -28,55 +28,55 @@ class FlatCAMGUI(QtGui.QMainWindow):
         self.menufile = self.menu.addMenu('&File')
 
         # New
-        self.menufilenew = QtGui.QAction(QtGui.QIcon('share:file16.png'), '&New', self)
+        self.menufilenew = QtGui.QAction(QtGui.QIcon('share/file16.png'), '&New', self)
         self.menufile.addAction(self.menufilenew)
         # Open recent
 
         # Recent
-        self.recent = self.menufile.addMenu(QtGui.QIcon('share:folder16.png'), "Open recent ...")
+        self.recent = self.menufile.addMenu(QtGui.QIcon('share/folder16.png'), "Open recent ...")
 
         # Open gerber ...
-        self.menufileopengerber = QtGui.QAction(QtGui.QIcon('share:folder16.png'), 'Open &Gerber ...', self)
+        self.menufileopengerber = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Open &Gerber ...', self)
         self.menufile.addAction(self.menufileopengerber)
 
         # Open Excellon ...
-        self.menufileopenexcellon = QtGui.QAction(QtGui.QIcon('share:folder16.png'), 'Open &Excellon ...', self)
+        self.menufileopenexcellon = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Open &Excellon ...', self)
         self.menufile.addAction(self.menufileopenexcellon)
 
         # Open G-Code ...
-        self.menufileopengcode = QtGui.QAction(QtGui.QIcon('share:folder16.png'), 'Open G-&Code ...', self)
+        self.menufileopengcode = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Open G-&Code ...', self)
         self.menufile.addAction(self.menufileopengcode)
 
         # Open Project ...
-        self.menufileopenproject = QtGui.QAction(QtGui.QIcon('share:folder16.png'), 'Open &Project ...', self)
+        self.menufileopenproject = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Open &Project ...', self)
         self.menufile.addAction(self.menufileopenproject)
 
         # Import SVG ...
-        self.menufileimportsvg = QtGui.QAction(QtGui.QIcon('share:folder16.png'), 'Import &SVG ...', self)
+        self.menufileimportsvg = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Import &SVG ...', self)
         self.menufile.addAction(self.menufileimportsvg)
 
         # Export SVG ...
-        self.menufileexportsvg = QtGui.QAction(QtGui.QIcon('share:folder16.png'), 'Export &SVG ...', self)
+        self.menufileexportsvg = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Export &SVG ...', self)
         self.menufile.addAction(self.menufileexportsvg)
 
         # Save Project
-        self.menufilesaveproject = QtGui.QAction(QtGui.QIcon('share:floppy16.png'), '&Save Project', self)
+        self.menufilesaveproject = QtGui.QAction(QtGui.QIcon('share/floppy16.png'), '&Save Project', self)
         self.menufile.addAction(self.menufilesaveproject)
 
         # Save Project As ...
-        self.menufilesaveprojectas = QtGui.QAction(QtGui.QIcon('share:floppy16.png'), 'Save Project &As ...', self)
+        self.menufilesaveprojectas = QtGui.QAction(QtGui.QIcon('share/floppy16.png'), 'Save Project &As ...', self)
         self.menufile.addAction(self.menufilesaveprojectas)
 
         # Save Project Copy ...
-        self.menufilesaveprojectcopy = QtGui.QAction(QtGui.QIcon('share:floppy16.png'), 'Save Project C&opy ...', self)
+        self.menufilesaveprojectcopy = QtGui.QAction(QtGui.QIcon('share/floppy16.png'), 'Save Project C&opy ...', self)
         self.menufile.addAction(self.menufilesaveprojectcopy)
 
         # Save Defaults
-        self.menufilesavedefaults = QtGui.QAction(QtGui.QIcon('share:floppy16.png'), 'Save &Defaults', self)
+        self.menufilesavedefaults = QtGui.QAction(QtGui.QIcon('share/floppy16.png'), 'Save &Defaults', self)
         self.menufile.addAction(self.menufilesavedefaults)
 
         # Quit
-        self.exit_action = QtGui.QAction(QtGui.QIcon('share:power16.png'), '&Exit', self)
+        self.exit_action = QtGui.QAction(QtGui.QIcon('share/power16.png'), '&Exit', self)
         # exitAction.setShortcut('Ctrl+Q')
         # exitAction.setStatusTip('Exit application')
         #self.exit_action.triggered.connect(QtGui.qApp.quit)
@@ -85,13 +85,13 @@ class FlatCAMGUI(QtGui.QMainWindow):
 
         ### Edit ###
         self.menuedit = self.menu.addMenu('&Edit')
-        self.menueditnew = self.menuedit.addAction(QtGui.QIcon('share:new_geo16.png'), 'New Geometry')
-        self.menueditedit = self.menuedit.addAction(QtGui.QIcon('share:edit16.png'), 'Edit Geometry')
-        self.menueditok = self.menuedit.addAction(QtGui.QIcon('share:edit_ok16.png'), 'Update Geometry')
+        self.menueditnew = self.menuedit.addAction(QtGui.QIcon('share/new_geo16.png'), 'New Geometry')
+        self.menueditedit = self.menuedit.addAction(QtGui.QIcon('share/edit16.png'), 'Edit Geometry')
+        self.menueditok = self.menuedit.addAction(QtGui.QIcon('share/edit_ok16.png'), 'Update Geometry')
         #self.menueditok.
-        #self.menueditcancel = self.menuedit.addAction(QtGui.QIcon('share:cancel_edit16.png'), "Cancel Edit")
-        self.menueditjoin = self.menuedit.addAction(QtGui.QIcon('share:join16.png'), 'Join Geometry')
-        self.menueditdelete = self.menuedit.addAction(QtGui.QIcon('share:trash16.png'), 'Delete')
+        #self.menueditcancel = self.menuedit.addAction(QtGui.QIcon('share/cancel_edit16.png'), "Cancel Edit")
+        self.menueditjoin = self.menuedit.addAction(QtGui.QIcon('share/join16.png'), 'Join Geometry')
+        self.menueditdelete = self.menuedit.addAction(QtGui.QIcon('share/trash16.png'), 'Delete')
 
         ### Options ###
         self.menuoptions = self.menu.addMenu('&Options')
@@ -105,22 +105,22 @@ class FlatCAMGUI(QtGui.QMainWindow):
 
         ### View ###
         self.menuview = self.menu.addMenu('&View')
-        self.menuviewdisableall = self.menuview.addAction(QtGui.QIcon('share:clear_plot16.png'), 'Disable all plots')
-        self.menuviewdisableother = self.menuview.addAction(QtGui.QIcon('share:clear_plot16.png'),
+        self.menuviewdisableall = self.menuview.addAction(QtGui.QIcon('share/clear_plot16.png'), 'Disable all plots')
+        self.menuviewdisableother = self.menuview.addAction(QtGui.QIcon('share/clear_plot16.png'),
                                                             'Disable all plots but this one')
-        self.menuviewenable = self.menuview.addAction(QtGui.QIcon('share:replot16.png'), 'Enable all plots')
+        self.menuviewenable = self.menuview.addAction(QtGui.QIcon('share/replot16.png'), 'Enable all plots')
 
         ### Tool ###
         #self.menutool = self.menu.addMenu('&Tool')
         self.menutool = QtGui.QMenu('&Tool')
         self.menutoolaction = self.menu.addMenu(self.menutool)
-        self.menutoolshell = self.menutool.addAction(QtGui.QIcon('share:shell16.png'), '&Command Line')
+        self.menutoolshell = self.menutool.addAction(QtGui.QIcon('share/shell16.png'), '&Command Line')
 
         ### Help ###
         self.menuhelp = self.menu.addMenu('&Help')
-        self.menuhelp_about = self.menuhelp.addAction(QtGui.QIcon('share:tv16.png'), 'About FlatCAM')
-        self.menuhelp_home = self.menuhelp.addAction(QtGui.QIcon('share:home16.png'), 'Home')
-        self.menuhelp_manual = self.menuhelp.addAction(QtGui.QIcon('share:globe16.png'), 'Manual')
+        self.menuhelp_about = self.menuhelp.addAction(QtGui.QIcon('share/tv16.png'), 'About FlatCAM')
+        self.menuhelp_home = self.menuhelp.addAction(QtGui.QIcon('share/home16.png'), 'Home')
+        self.menuhelp_manual = self.menuhelp.addAction(QtGui.QIcon('share/globe16.png'), 'Manual')
 
         ###############
         ### Toolbar ###
@@ -128,18 +128,18 @@ class FlatCAMGUI(QtGui.QMainWindow):
         self.toolbar = QtGui.QToolBar()
         self.addToolBar(self.toolbar)
 
-        self.zoom_fit_btn = self.toolbar.addAction(QtGui.QIcon('share:zoom_fit32.png'), "&Zoom Fit")
-        self.zoom_out_btn = self.toolbar.addAction(QtGui.QIcon('share:zoom_out32.png'), "&Zoom Out")
-        self.zoom_in_btn = self.toolbar.addAction(QtGui.QIcon('share:zoom_in32.png'), "&Zoom In")
-        self.clear_plot_btn = self.toolbar.addAction(QtGui.QIcon('share:clear_plot32.png'), "&Clear Plot")
-        self.replot_btn = self.toolbar.addAction(QtGui.QIcon('share:replot32.png'), "&Replot")
-        self.newgeo_btn = self.toolbar.addAction(QtGui.QIcon('share:new_geo32.png'), "New Blank Geometry")
-        self.editgeo_btn = self.toolbar.addAction(QtGui.QIcon('share:edit32.png'), "Edit Geometry")
-        self.updategeo_btn = self.toolbar.addAction(QtGui.QIcon('share:edit_ok32.png'), "Update Geometry")
+        self.zoom_fit_btn = self.toolbar.addAction(QtGui.QIcon('share/zoom_fit32.png'), "&Zoom Fit")
+        self.zoom_out_btn = self.toolbar.addAction(QtGui.QIcon('share/zoom_out32.png'), "&Zoom Out")
+        self.zoom_in_btn = self.toolbar.addAction(QtGui.QIcon('share/zoom_in32.png'), "&Zoom In")
+        self.clear_plot_btn = self.toolbar.addAction(QtGui.QIcon('share/clear_plot32.png'), "&Clear Plot")
+        self.replot_btn = self.toolbar.addAction(QtGui.QIcon('share/replot32.png'), "&Replot")
+        self.newgeo_btn = self.toolbar.addAction(QtGui.QIcon('share/new_geo32.png'), "New Blank Geometry")
+        self.editgeo_btn = self.toolbar.addAction(QtGui.QIcon('share/edit32.png'), "Edit Geometry")
+        self.updategeo_btn = self.toolbar.addAction(QtGui.QIcon('share/edit_ok32.png'), "Update Geometry")
         self.updategeo_btn.setEnabled(False)
-        #self.canceledit_btn = self.toolbar.addAction(QtGui.QIcon('share:cancel_edit32.png'), "Cancel Edit")
-        self.delete_btn = self.toolbar.addAction(QtGui.QIcon('share:delete32.png'), "&Delete")
-        self.shell_btn = self.toolbar.addAction(QtGui.QIcon('share:shell32.png'), "&Command Line")
+        #self.canceledit_btn = self.toolbar.addAction(QtGui.QIcon('share/cancel_edit32.png'), "Cancel Edit")
+        self.delete_btn = self.toolbar.addAction(QtGui.QIcon('share/delete32.png'), "&Delete")
+        self.shell_btn = self.toolbar.addAction(QtGui.QIcon('share/shell32.png'), "&Command Line")
 
         ################
         ### Splitter ###
@@ -179,7 +179,7 @@ class FlatCAMGUI(QtGui.QMainWindow):
         self.options_tab_layout.addLayout(hlay1)
 
         self.icon = QtGui.QLabel()
-        self.icon.setPixmap(QtGui.QPixmap('share:gear48.png'))
+        self.icon.setPixmap(QtGui.QPixmap('share/gear48.png'))
         hlay1.addWidget(self.icon)
 
         self.options_combo = QtGui.QComboBox()
@@ -247,12 +247,12 @@ class FlatCAMGUI(QtGui.QMainWindow):
         ### Icons ###
         #############
         self.app_icon = QtGui.QIcon()
-        self.app_icon.addFile('share:flatcam_icon16.png', QtCore.QSize(16, 16))
-        self.app_icon.addFile('share:flatcam_icon24.png', QtCore.QSize(24, 24))
-        self.app_icon.addFile('share:flatcam_icon32.png', QtCore.QSize(32, 32))
-        self.app_icon.addFile('share:flatcam_icon48.png', QtCore.QSize(48, 48))
-        self.app_icon.addFile('share:flatcam_icon128.png', QtCore.QSize(128, 128))
-        self.app_icon.addFile('share:flatcam_icon256.png', QtCore.QSize(256, 256))
+        self.app_icon.addFile('share/flatcam_icon16.png', QtCore.QSize(16, 16))
+        self.app_icon.addFile('share/flatcam_icon24.png', QtCore.QSize(24, 24))
+        self.app_icon.addFile('share/flatcam_icon32.png', QtCore.QSize(32, 32))
+        self.app_icon.addFile('share/flatcam_icon48.png', QtCore.QSize(48, 48))
+        self.app_icon.addFile('share/flatcam_icon128.png', QtCore.QSize(128, 128))
+        self.app_icon.addFile('share/flatcam_icon256.png', QtCore.QSize(256, 256))
         self.setWindowIcon(self.app_icon)
 
         self.setGeometry(100, 100, 1024, 650)
@@ -278,7 +278,7 @@ class FlatCAMActivityView(QtGui.QWidget):
 
         self.icon = QtGui.QLabel(self)
         self.icon.setGeometry(0, 0, 12, 12)
-        self.movie = QtGui.QMovie("share:active.gif")
+        self.movie = QtGui.QMovie("share/active.gif")
         self.icon.setMovie(self.movie)
         #self.movie.start()
 
@@ -309,7 +309,7 @@ class FlatCAMInfoBar(QtGui.QWidget):
 
         self.icon = QtGui.QLabel(self)
         self.icon.setGeometry(0, 0, 12, 12)
-        self.pmap = QtGui.QPixmap('share:graylight12.png')
+        self.pmap = QtGui.QPixmap('share/graylight12.png')
         self.icon.setPixmap(self.pmap)
 
         layout = QtGui.QHBoxLayout()
@@ -334,13 +334,13 @@ class FlatCAMInfoBar(QtGui.QWidget):
         level = str(level)
         self.pmap.fill()
         if level == "error":
-            self.pmap = QtGui.QPixmap('share:redlight12.png')
+            self.pmap = QtGui.QPixmap('share/redlight12.png')
         elif level == "success":
-            self.pmap = QtGui.QPixmap('share:greenlight12.png')
+            self.pmap = QtGui.QPixmap('share/greenlight12.png')
         elif level == "warning":
-            self.pmap = QtGui.QPixmap('share:yellowlight12.png')
+            self.pmap = QtGui.QPixmap('share/yellowlight12.png')
         else:
-            self.pmap = QtGui.QPixmap('share:graylight12.png')
+            self.pmap = QtGui.QPixmap('share/graylight12.png')
 
         self.icon.setPixmap(self.pmap)
         self.set_text_(text)

+ 19 - 12
FlatCAMObj.py

@@ -6,7 +6,7 @@
 # MIT Licence                                              #
 ############################################################
 
-from cStringIO import StringIO
+from io import StringIO
 from PyQt4 import QtCore
 from copy import copy
 from ObjectUI import *
@@ -221,7 +221,7 @@ class FlatCAMObj(QtCore.QObject):
         try:
             self.form_fields[option].set_value(self.options[option])
         except KeyError:
-            self.app.log.warn("Tried to set an option or field that does not exist: %s" % option)
+            self.app.log.warning("Tried to set an option or field that does not exist: %s" % option)
 
     def read_form_item(self, option):
         """
@@ -728,20 +728,20 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
                     exc_final.drills.append({"point": point, "tool": drill['tool']})
                 toolsrework=dict()
                 max_numeric_tool=0
-                for toolname in exc.tools.iterkeys():
+                for toolname in list(exc.tools.copy().keys()):
                     numeric_tool=int(toolname)
                     if numeric_tool>max_numeric_tool:
                         max_numeric_tool=numeric_tool
                     toolsrework[exc.tools[toolname]['C']]=toolname
 
                 #exc_final as last because names from final tools will be used
-                for toolname in exc_final.tools.iterkeys():
+                for toolname in list(exc_final.tools.copy().keys()):
                     numeric_tool=int(toolname)
                     if numeric_tool>max_numeric_tool:
                         max_numeric_tool=numeric_tool
                     toolsrework[exc_final.tools[toolname]['C']]=toolname
 
-                for toolvalues in toolsrework.iterkeys():
+                for toolvalues in list(toolsrework.copy().keys()):
                     if toolsrework[toolvalues] in exc_final.tools:
                         if exc_final.tools[toolsrework[toolvalues]]!={"C": toolvalues}:
                             exc_final.tools[str(max_numeric_tool+1)]={"C": toolvalues}
@@ -861,7 +861,14 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             tooldia = self.options["tooldia"]
 
         # Sort tools by diameter. items() -> [('name', diameter), ...]
-        sorted_tools = sorted(self.tools.items(), key=lambda tl: tl[1])
+        # sorted_tools = sorted(list(self.tools.items()), key=lambda tl: tl[1])
+
+        # Python3 no longer allows direct comparison between dicts so we need to sort tools differently
+        sort = []
+        for k, v in self.tools.items():
+            sort.append((k, v.get('C')))
+        sorted_tools = sorted(sort, key=lambda t1: t1[1])
+        log.debug("Tools are sorted: %s" % str(sorted_tools))
 
         if tools == "all":
             tools = [i[0] for i in sorted_tools]  # List if ordered tool names.
@@ -1082,10 +1089,10 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
         self.read_form()
 
         try:
-            filename = unicode(QtGui.QFileDialog.getSaveFileName(caption="Export G-Code ...",
+            filename = str(QtGui.QFileDialog.getSaveFileName(caption="Export G-Code ...",
                                                          directory=self.app.defaults["last_folder"]))
         except TypeError:
-            filename = unicode(QtGui.QFileDialog.getSaveFileName(caption="Export G-Code ..."))
+            filename = str(QtGui.QFileDialog.getSaveFileName(caption="Export G-Code ..."))
 
         preamble = str(self.ui.prepend_text.get_value())
         postamble = str(self.ui.append_text.get_value())
@@ -1368,9 +1375,9 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             geo_obj.options["cnctooldia"] = tooldia
 
             # Experimental...
-            print "Indexing...",
+            print("Indexing...")
             geo_obj.make_index()
-            print "Done"
+            print("Done")
 
             self.app.inform.emit("Done.")
 
@@ -1454,9 +1461,9 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             geo_obj.options["cnctooldia"] = tooldia
 
             # Experimental...
-            print "Indexing...",
+            print("Indexing...")
             geo_obj.make_index()
-            print "Done"
+            print("Done")
 
             self.app.inform.emit("Done.")
 

+ 9 - 9
GUIElements.py

@@ -81,7 +81,7 @@ class LengthEntry(QtGui.QLineEdit):
     def returnPressed(self, *args, **kwargs):
         val = self.get_value()
         if val is not None:
-            self.set_text(QtCore.QString(str(val)))
+            self.set_text(str(val))
         else:
             log.warning("Could not interpret entry: %s" % self.get_text())
 
@@ -105,7 +105,7 @@ class LengthEntry(QtGui.QLineEdit):
             return None
 
     def set_value(self, val):
-        self.setText(QtCore.QString(str(val)))
+        self.setText(str(val))
 
 
 class FloatEntry(QtGui.QLineEdit):
@@ -115,7 +115,7 @@ class FloatEntry(QtGui.QLineEdit):
     def returnPressed(self, *args, **kwargs):
         val = self.get_value()
         if val is not None:
-            self.set_text(QtCore.QString(str(val)))
+            self.set_text(str(val))
         else:
             log.warning("Could not interpret entry: %s" % self.text())
 
@@ -151,10 +151,10 @@ class IntEntry(QtGui.QLineEdit):
     def set_value(self, val):
 
         if val == self.empty_val and self.allow_empty:
-            self.setText(QtCore.QString(""))
+            self.setText("")
             return
 
-        self.setText(QtCore.QString(str(val)))
+        self.setText(str(val))
 
 
 class FCEntry(QtGui.QLineEdit):
@@ -165,7 +165,7 @@ class FCEntry(QtGui.QLineEdit):
         return str(self.text())
 
     def set_value(self, val):
-        self.setText(QtCore.QString(str(val)))
+        self.setText(str(val))
 
 
 class EvalEntry(QtGui.QLineEdit):
@@ -175,7 +175,7 @@ class EvalEntry(QtGui.QLineEdit):
     def returnPressed(self, *args, **kwargs):
         val = self.get_value()
         if val is not None:
-            self.setText(QtCore.QString(str(val)))
+            self.setText(str(val))
         else:
             log.warning("Could not interpret entry: %s" % self.get_text())
 
@@ -188,12 +188,12 @@ class EvalEntry(QtGui.QLineEdit):
             return None
 
     def set_value(self, val):
-        self.setText(QtCore.QString(str(val)))
+        self.setText(str(val))
 
 
 class FCCheckBox(QtGui.QCheckBox):
     def __init__(self, label='', parent=None):
-        super(FCCheckBox, self).__init__(QtCore.QString(label), parent)
+        super(FCCheckBox, self).__init__(str(label), parent)
 
     def get_value(self):
         return self.isChecked()

+ 6 - 6
ObjectCollection.py

@@ -6,7 +6,6 @@
 # MIT Licence                                              #
 ############################################################
 
-#from PyQt4.QtCore import QModelIndex
 from FlatCAMObj import *
 import inspect  # TODO: Remove
 import FlatCAMApp
@@ -47,6 +46,7 @@ class ObjectCollection():
 
     def __init__(self, parent=None):
         #QtCore.QAbstractListModel.__init__(self, parent=parent)
+
         ### Icons for the list view
         self.icons = {}
         for kind in ObjectCollection.icon_files:
@@ -101,7 +101,7 @@ class ObjectCollection():
 
     def print_list(self):
         for obj in self.object_list:
-            print obj
+            print(obj)
 
     def on_mouse_down(self, event):
         FlatCAMApp.App.log.debug("Mouse button pressed on list")
@@ -162,16 +162,16 @@ class ObjectCollection():
 
         # Create the model item to insert into the QListView
         icon = QtGui.QIcon(self.icons[obj.kind])#self.icons["gerber"])
-        item = QtGui.QStandardItem(icon, name)
+        item = QtGui.QStandardItem(icon, str(name))
         # Item is not editable, so that double click
         # does not allow cell value modification.
         item.setEditable(False)
         # The item is checkable, to add the checkbox.
         item.setCheckable(True)
-        if obj.options["plot"] == True:
-            item.setCheckState(2)#Qt.Checked)
+        if obj.options["plot"] is True:
+            item.setCheckState(2)   #Qt.Checked)
         else:
-            item.setCheckState(0) #Qt.Unchecked)
+            item.setCheckState(0)   #Qt.Unchecked)
 
         self.model.appendRow(item)
 

+ 4 - 4
ObjectUI.py

@@ -11,7 +11,7 @@ class ObjectUI(QtGui.QWidget):
     put UI elements in ObjectUI.custom_box (QtGui.QLayout).
     """
 
-    def __init__(self, icon_file='share:flatcam_icon32.png', title='FlatCAM Object', parent=None):
+    def __init__(self, icon_file='share/flatcam_icon32.png', title='FlatCAM Object', parent=None):
         QtGui.QWidget.__init__(self, parent=parent)
 
         layout = QtGui.QVBoxLayout()
@@ -117,7 +117,7 @@ class CNCObjectUI(ObjectUI):
         be placed in ``self.custom_box`` to preserve the layout.
         """
 
-        ObjectUI.__init__(self, title='CNC Job Object', icon_file='share:cnc32.png', parent=parent)
+        ObjectUI.__init__(self, title='CNC Job Object', icon_file='share/cnc32.png', parent=parent)
 
         # Scale and offset are not available for CNCJob objects.
         # Hiding from the GUI.
@@ -242,7 +242,7 @@ class GeometryObjectUI(ObjectUI):
     """
 
     def __init__(self, parent=None):
-        super(GeometryObjectUI, self).__init__(title='Geometry Object', icon_file='share:geometry32.png', parent=parent)
+        super(GeometryObjectUI, self).__init__(title='Geometry Object', icon_file='share/geometry32.png', parent=parent)
 
         ## Plot options
         self.plot_options_label = QtGui.QLabel("<b>Plot Options:</b>")
@@ -461,7 +461,7 @@ class ExcellonObjectUI(ObjectUI):
 
     def __init__(self, parent=None):
         ObjectUI.__init__(self, title='Excellon Object',
-                          icon_file='share:drill32.png',
+                          icon_file='share/drill32.png',
                           parent=parent)
 
         #### Plot options ####

+ 8 - 8
bugs/conf.py

@@ -43,8 +43,8 @@ source_suffix = '.rst'
 master_doc = 'index'
 
 # General information about the project.
-project = u'FlatCAM Bugs'
-copyright = u'2014, Juan Pablo Caram'
+project = 'FlatCAM Bugs'
+copyright = '2014, Juan Pablo Caram'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -196,8 +196,8 @@ latex_elements = {
 # (source start file, target name, title,
 #  author, documentclass [howto, manual, or own class]).
 latex_documents = [
-  ('index', 'FlatCAMBugs.tex', u'FlatCAM Bugs Documentation',
-   u'Juan Pablo Caram', 'manual'),
+  ('index', 'FlatCAMBugs.tex', 'FlatCAM Bugs Documentation',
+   'Juan Pablo Caram', 'manual'),
 ]
 
 # The name of an image file (relative to this directory) to place at the top of
@@ -226,8 +226,8 @@ latex_documents = [
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
 man_pages = [
-    ('index', 'flatcambugs', u'FlatCAM Bugs Documentation',
-     [u'Juan Pablo Caram'], 1)
+    ('index', 'flatcambugs', 'FlatCAM Bugs Documentation',
+     ['Juan Pablo Caram'], 1)
 ]
 
 # If true, show URL addresses after external links.
@@ -240,8 +240,8 @@ man_pages = [
 # (source start file, target name, title, author,
 #  dir menu entry, description, category)
 texinfo_documents = [
-  ('index', 'FlatCAMBugs', u'FlatCAM Bugs Documentation',
-   u'Juan Pablo Caram', 'FlatCAMBugs', 'One line description of project.',
+  ('index', 'FlatCAMBugs', 'FlatCAM Bugs Documentation',
+   'Juan Pablo Caram', 'FlatCAMBugs', 'One line description of project.',
    'Miscellaneous'),
 ]
 

+ 9 - 5
camlib.py

@@ -9,7 +9,7 @@
 #from scipy import optimize
 #import traceback
 
-from cStringIO import StringIO
+from io import StringIO
 from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos, dot, float32, \
     transpose
 from numpy.linalg import solve, norm
@@ -2360,7 +2360,7 @@ class Gerber (Geometry):
             else:
                 self.solid_geometry = self.solid_geometry.difference(new_poly)
 
-        except Exception, err:
+        except Exception as err:
             ex_type, ex, tb = sys.exc_info()
             traceback.print_tb(tb)
             #print traceback.format_exc()
@@ -2972,14 +2972,18 @@ class CNCjob(Geometry):
         # Tools
 
         # Sort tools by diameter. items() -> [('name', diameter), ...]
-        sorted_tools = sorted(exobj.tools.items(), key=lambda tl: tl[1])
+        #sorted_tools = sorted(list(exobj.tools.items()), key=lambda tl: tl[1])
+        sort = []
+        for k, v in exobj.tools.items():
+            sort.append((k, v.get('C')))
+        sorted_tools = sorted(sort, key=lambda t1: t1[1])
 
         if tools == "all":
             tools = [i[0] for i in sorted_tools]   # List if ordered tool names.
             log.debug("Tools 'all' and sorted are: %s" % str(tools))
         else:
             selected_tools = [x.strip() for x in tools.split(",")]
-            selected_tools = filter(lambda tl: tl in selected_tools, selected_tools)
+            selected_tools = [tl for tl in selected_tools if tl in selected_tools]
 
             # Create a sorted list of selected tools from the sorted_tools list
             tools = [i for i, j in sorted_tools for k in selected_tools if i == k]
@@ -4103,7 +4107,7 @@ class FlatCAMRTree(object):
         :param pt:
         :return:
         """
-        return self.rti.nearest(pt, objects=True).next()
+        return next(self.rti.nearest(pt, objects=True))
 
 
 class FlatCAMRTreeStorage(FlatCAMRTree):

+ 6 - 6
descartes/tests.py

@@ -8,10 +8,10 @@ class PolygonTestCase(unittest.TestCase):
                 MultiPoint([(-5, 0), (5, 0)]).buffer(3.0))
     def test_patch(self):
         patch = PolygonPatch(self.polygon)
-        self.failUnlessEqual(str(type(patch)), 
+        self.assertEqual(str(type(patch)), 
             "<class 'matplotlib.patches.PathPatch'>")
         path = patch.get_path()
-        self.failUnless(len(path.vertices) == len(path.codes) == 198)
+        self.assertTrue(len(path.vertices) == len(path.codes) == 198)
 
 class JSONPolygonTestCase(unittest.TestCase):
     polygon = Point(0, 0).buffer(10.0).difference(
@@ -19,10 +19,10 @@ class JSONPolygonTestCase(unittest.TestCase):
     def test_patch(self):
         geo = self.polygon.__geo_interface__
         patch = PolygonPatch(geo)
-        self.failUnlessEqual(str(type(patch)), 
+        self.assertEqual(str(type(patch)), 
             "<class 'matplotlib.patches.PathPatch'>")
         path = patch.get_path()
-        self.failUnless(len(path.vertices) == len(path.codes) == 198)
+        self.assertTrue(len(path.vertices) == len(path.codes) == 198)
 
 class GeoInterfacePolygonTestCase(unittest.TestCase):
     class GeoThing:
@@ -32,7 +32,7 @@ class GeoInterfacePolygonTestCase(unittest.TestCase):
                 MultiPoint([(-5, 0), (5, 0)]).buffer(3.0)).__geo_interface__
     def test_patch(self):
         patch = PolygonPatch(self.thing)
-        self.failUnlessEqual(str(type(patch)), 
+        self.assertEqual(str(type(patch)), 
             "<class 'matplotlib.patches.PathPatch'>")
         path = patch.get_path()
-        self.failUnless(len(path.vertices) == len(path.codes) == 198)
+        self.assertTrue(len(path.vertices) == len(path.codes) == 198)

+ 8 - 8
doc/source/conf.py

@@ -45,8 +45,8 @@ source_suffix = '.rst'
 master_doc = 'index'
 
 # General information about the project.
-project = u'Cirkuix'
-copyright = u'2014, Juan Pablo Caram'
+project = 'Cirkuix'
+copyright = '2014, Juan Pablo Caram'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -203,8 +203,8 @@ latex_elements = {
 # (source start file, target name, title,
 #  author, documentclass [howto, manual, or own class]).
 latex_documents = [
-  ('index', 'Cirkuix.tex', u'Cirkuix Documentation',
-   u'Juan Pablo Caram', 'manual'),
+  ('index', 'Cirkuix.tex', 'Cirkuix Documentation',
+   'Juan Pablo Caram', 'manual'),
 ]
 
 # The name of an image file (relative to this directory) to place at the top of
@@ -233,8 +233,8 @@ latex_documents = [
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
 man_pages = [
-    ('index', 'cirkuix', u'Cirkuix Documentation',
-     [u'Juan Pablo Caram'], 1)
+    ('index', 'cirkuix', 'Cirkuix Documentation',
+     ['Juan Pablo Caram'], 1)
 ]
 
 # If true, show URL addresses after external links.
@@ -247,8 +247,8 @@ man_pages = [
 # (source start file, target name, title, author,
 #  dir menu entry, description, category)
 texinfo_documents = [
-  ('index', 'Cirkuix', u'Cirkuix Documentation',
-   u'Juan Pablo Caram', 'Cirkuix', 'One line description of project.',
+  ('index', 'Cirkuix', 'Cirkuix Documentation',
+   'Juan Pablo Caram', 'Cirkuix', 'One line description of project.',
    'Miscellaneous'),
 ]
 

+ 2 - 2
flatcam

@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
 ############################################################
 # FlatCAM: 2D Post-processing for Manufacturing            #
 # http://flatcam.org                                       #
@@ -30,6 +30,6 @@ debug_trace()
 # NOTE: Never talk to the GUI from threads! This is why I commented the above.
 
 app = QtGui.QApplication(sys.argv)
-QtCore.QDir.setSearchPaths("share", QtCore.QStringList(("share", "share/flatcam", "/usr/share/flatcam")));
+QtCore.QDir.setSearchPaths("share", str(("share", "share/flatcam", "/usr/share/flatcam")));
 fc = App()
 sys.exit(app.exec_())

+ 3 - 3
make_win32.py

@@ -43,16 +43,16 @@ if sys.platform == "win32":
 buildOptions = dict(
     compressed=False,
     include_files=include_files,
-    icon='share:flatcam_icon48.ico',
+    icon='share/flatcam_icon48.ico',
     # excludes=['PyQt4', 'tk', 'tcl']
     excludes=['scipy.lib.lapack.flapack.pyd',
               'scipy.lib.blas.fblas.pyd',
               'QtOpenGL4.dll']
 )
 
-print "INCLUDE_FILES", include_files
+print(("INCLUDE_FILES", include_files))
 
-execfile('clean.py')
+exec(compile(open('clean.py').read(), 'clean.py', 'exec'))
 
 setup(
     name="FlatCAM",

+ 10 - 10
sandbox/diagnose.py

@@ -1,34 +1,34 @@
 #import sys
 import platform
 
-print "Platform", platform.system(), platform.release()
-print "Distro", platform.dist()
-print "Python", platform.python_version()
+print(("Platform", platform.system(), platform.release()))
+print(("Distro", platform.dist()))
+print(("Python", platform.python_version()))
 
 
 import rtree
 
-print "rtree", rtree.__version__
+print(("rtree", rtree.__version__))
 
 
 import shapely
 import shapely.geos
 
-print "shapely", shapely.__version__
-print "GEOS library", shapely.geos.geos_version
+print(("shapely", shapely.__version__))
+print(("GEOS library", shapely.geos.geos_version))
 
 
 from PyQt4 import Qt
 
-print "Qt", Qt.qVersion()
+print(("Qt", Qt.qVersion()))
 
 
 import numpy
 
-print "Numpy", numpy.__version__
+print(("Numpy", numpy.__version__))
 
 
 import matplotlib
 
-print "MatPlotLib", matplotlib.__version__
-print "MPL Numpy", matplotlib.__version__numpy__
+print(("MatPlotLib", matplotlib.__version__))
+print(("MPL Numpy", matplotlib.__version__numpy__))

+ 3 - 3
sandbox/gerber_find.py

@@ -19,10 +19,10 @@ def gerber_find(filename, coords, frac_digits=5, tol=0.1):
                     current_y = parse_gerber_number(match.group(3), frac_digits)
 
                 if distance(coords, (current_x, current_y)) <= tol:
-                    print line_num, ":", line.strip('\n\r')
+                    print((line_num, ":", line.strip('\n\r')))
         except Exception as e:
-            print str(e)
-            print line_num, ":", line.strip('\n\r')
+            print((str(e)))
+            print((line_num, ":", line.strip('\n\r')))
 
 
 if __name__ == "__main__":

+ 2 - 2
svgparse.py

@@ -521,6 +521,6 @@ if __name__ == "__main__":
     tree = ET.parse('tests/svg/drawing.svg')
     root = tree.getroot()
     ns = re.search(r'\{(.*)\}', root.tag).group(1)
-    print ns
+    print(ns)
     for geo in getsvggeo(root):
-        print geo
+        print(geo)

+ 7 - 6
tclCommands/TclCommand.py

@@ -5,6 +5,7 @@ import abc
 import collections
 from PyQt4 import QtCore
 from contextlib import contextmanager
+from FlatCAMObj import FlatCAMGerber, FlatCAMExcellon, FlatCAMGeometry, FlatCAMCNCjob, FlatCAMObj
 
 
 class TclCommand(object):
@@ -97,7 +98,7 @@ class TclCommand(object):
 
             command_string = []
 
-            for arg_key, arg_type in self.help['args'].items():
+            for arg_key, arg_type in list(self.help['args'].items()):
                 command_string.append(get_decorated_argument(arg_key, arg_type, True))
 
             return "> " + alias_name + " " + " ".join(command_string)
@@ -147,7 +148,7 @@ class TclCommand(object):
         for alias in self.aliases:
             help_string.append(get_decorated_command(alias))
 
-        for key, value in self.help['args'].items():
+        for key, value in list(self.help['args'].items()):
             help_string.append(get_decorated_argument(key, value))
 
         # timeout is unique for signaled commands (this is not best oop practice, but much easier for now)
@@ -206,13 +207,13 @@ class TclCommand(object):
 
         # check arguments
         idx = 0
-        arg_names_items = self.arg_names.items()
+        arg_names_items = list(self.arg_names.items())
         for argument in arguments:
             if len(self.arg_names) > idx:
                 key, arg_type = arg_names_items[idx]
                 try:
                     named_args[key] = arg_type(argument)
-                except Exception, e:
+                except Exception as e:
                     self.raise_tcl_error("Cannot cast named argument '%s' to type %s  with exception '%s'."
                                          % (key, arg_type, str(e)))
             else:
@@ -228,7 +229,7 @@ class TclCommand(object):
                     named_args[key] = self.option_types[key](options[key])
                 else:
                     named_args[key] = int(options[key])
-            except Exception, e:
+            except Exception as e:
                 self.raise_tcl_error("Cannot cast argument '-%s' to type '%s' with exception '%s'."
                                      % (key, self.option_types[key], str(e)))
 
@@ -292,7 +293,7 @@ class TclCommandSignaled(TclCommand):
     """
         !!! I left it here only  for demonstration !!!
         Go to TclCommandCncjob and  into class definition put
-            class TclCommandCncjob(TclCommand.TclCommandSignaled):
+            class TclCommandCncjob(TclCommandSignaled):
         also change
             obj.generatecncjob(use_thread = False, **args)
         to

+ 2 - 3
tclCommands/TclCommandAddCircle.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandAddCircle(TclCommand.TclCommand):
+class TclCommandAddCircle(TclCommand):
     """
     Tcl shell command to creates a circle in the given Geometry object.
 

+ 2 - 3
tclCommands/TclCommandAddPolygon.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandAddPolygon(TclCommand.TclCommandSignaled):
+class TclCommandAddPolygon(TclCommandSignaled):
     """
     Tcl shell command to create a polygon in the given Geometry object
     """

+ 2 - 3
tclCommands/TclCommandAddPolyline.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandAddPolyline(TclCommand.TclCommandSignaled):
+class TclCommandAddPolyline(TclCommandSignaled):
     """
     Tcl shell command to create a polyline in the given Geometry object
     """

+ 2 - 3
tclCommands/TclCommandAddRectangle.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandAddRectangle(TclCommand.TclCommandSignaled):
+class TclCommandAddRectangle(TclCommandSignaled):
     """
     Tcl shell command to add a rectange to the given Geometry object.
     """

+ 4 - 5
tclCommands/TclCommandAlignDrill.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandAlignDrill(TclCommand.TclCommandSignaled):
+class TclCommandAlignDrill(TclCommandSignaled):
     """
     Tcl shell command to create excellon with drills for aligment.
     """
@@ -180,7 +179,7 @@ class TclCommandAlignDrill(TclCommand.TclCommandSignaled):
                                    name + "_aligndrill",
                                    alligndrill_init_me)
 
-            except Exception, e:
+            except Exception as e:
                 return "Operation failed: %s" % str(e)
 
         else:
@@ -195,7 +194,7 @@ class TclCommandAlignDrill(TclCommand.TclCommandSignaled):
                 px = dist
                 py = dist
                 obj.app.new_object("excellon", name + "_alligndrill", alligndrill_init_me)
-            except Exception, e:
+            except Exception as e:
                 return "Operation failed: %s" % str(e)
 
         return 'Ok'

+ 2 - 3
tclCommands/TclCommandAlignDrillGrid.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandAlignDrillGrid(TclCommand.TclCommandSignaled):
+class TclCommandAlignDrillGrid(TclCommandSignaled):
     """
     Tcl shell command to create an Excellon object
     with drills for aligment grid.

+ 2 - 3
tclCommands/TclCommandCncjob.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandCncjob(TclCommand.TclCommandSignaled):
+class TclCommandCncjob(TclCommandSignaled):
     """
     Tcl shell command to Generates a CNC Job from a Geometry Object.
 

+ 3 - 4
tclCommands/TclCommandCutout.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandCutout(TclCommand.TclCommand):
+class TclCommandCutout(TclCommand):
     """
     Tcl shell command to create a board cutout geometry.
 
@@ -95,5 +94,5 @@ class TclCommandCutout(TclCommand.TclCommand):
 
         try:
             obj.app.new_object("geometry", name + "_cutout", geo_init_me)
-        except Exception, e:
+        except Exception as e:
             return "Operation failed: %s" % str(e)

+ 2 - 3
tclCommands/TclCommandDelete.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandDelete(TclCommand.TclCommand):
+class TclCommandDelete(TclCommand):
     """
     Tcl shell command to delete an object.
 

+ 2 - 3
tclCommands/TclCommandDrillcncjob.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandDrillcncjob(TclCommand.TclCommandSignaled):
+class TclCommandDrillcncjob(TclCommandSignaled):
     """
     Tcl shell command to Generates a Drill CNC Job from a Excellon Object.
     """

+ 2 - 3
tclCommands/TclCommandExportGcode.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandExportGcode(TclCommand.TclCommandSignaled):
+class TclCommandExportGcode(TclCommandSignaled):
     """
     Tcl shell command to export gcode as tcl output for "set X [export_gcode ...]"
 

+ 2 - 3
tclCommands/TclCommandExportSVG.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandExportSVG(TclCommand.TclCommand):
+class TclCommandExportSVG(TclCommand):
     """
     Tcl shell command to export a Geometry Object as an SVG File.
 

+ 3 - 4
tclCommands/TclCommandExteriors.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandExteriors(TclCommand.TclCommandSignaled):
+class TclCommandExteriors(TclCommandSignaled):
     """
     Tcl shell command to get exteriors of polygons
     """
@@ -54,7 +53,7 @@ class TclCommandExteriors(TclCommand.TclCommandSignaled):
         if obj is None:
             self.raise_tcl_error("Object not found: %s" % name)
 
-        if not isinstance(obj, Geometry):
+        if not isinstance(obj, FlatCAMGeometry):
             self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
 
         def geo_init(geo_obj, app_obj):

+ 2 - 3
tclCommands/TclCommandGeoCutout.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandGeoCutout(TclCommand.TclCommandSignaled):
+class TclCommandGeoCutout(TclCommandSignaled):
     """
     Tcl shell command to cut holding gaps from geometry.
     """

+ 2 - 3
tclCommands/TclCommandGeoUnion.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandGeoUnion(TclCommand.TclCommand):
+class TclCommandGeoUnion(TclCommand):
     """
     Tcl shell command to run a union (addition) operation on the
     components of a geometry object.

+ 2 - 3
tclCommands/TclCommandGetNames.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandGetNames(TclCommand.TclCommand):
+class TclCommandGetNames(TclCommand):
     """
     Tcl shell command to set an object as active in the GUI.
 

+ 2 - 3
tclCommands/TclCommandGetSys.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandGetSys(TclCommand.TclCommand):
+class TclCommandGetSys(TclCommand):
     """
     Tcl shell command to get the value of a system variable
 

+ 2 - 3
tclCommands/TclCommandImportSvg.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandImportSvg(TclCommand.TclCommandSignaled):
+class TclCommandImportSvg(TclCommandSignaled):
     """
     Tcl shell command to import an SVG file as a Geometry Object.
     """

+ 2 - 3
tclCommands/TclCommandInteriors.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandInteriors(TclCommand.TclCommandSignaled):
+class TclCommandInteriors(TclCommandSignaled):
     """
     Tcl shell command to get interiors of polygons
     """

+ 2 - 3
tclCommands/TclCommandIsolate.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandIsolate(TclCommand.TclCommandSignaled):
+class TclCommandIsolate(TclCommandSignaled):
     """
     Tcl shell command to Creates isolation routing geometry for the given Gerber.
 

+ 2 - 3
tclCommands/TclCommandJoinExcellon.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandJoinExcellon(TclCommand.TclCommand):
+class TclCommandJoinExcellon(TclCommand):
     """
     Tcl shell command to merge Excellon objects.
 

+ 2 - 3
tclCommands/TclCommandJoinGeometry.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandJoinGeometry(TclCommand.TclCommand):
+class TclCommandJoinGeometry(TclCommand):
     """
     Tcl shell command to merge Excellon objects.
 

+ 2 - 3
tclCommands/TclCommandMillHoles.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandMillHoles(TclCommand.TclCommandSignaled):
+class TclCommandMillHoles(TclCommandSignaled):
     """
     Tcl shell command to Create Geometry Object for milling holes from Excellon.
 

+ 4 - 5
tclCommands/TclCommandMirror.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandMirror(TclCommand.TclCommandSignaled):
+class TclCommandMirror(TclCommandSignaled):
     """
     Tcl shell command to mirror an object.
     """
@@ -90,7 +89,7 @@ class TclCommandMirror(TclCommand.TclCommandSignaled):
                 obj.mirror(axis, [px, py])
                 obj.plot()
 
-            except Exception, e:
+            except Exception as e:
                 return "Operation failed: %s" % str(e)
 
         else:
@@ -104,5 +103,5 @@ class TclCommandMirror(TclCommand.TclCommandSignaled):
             try:
                 obj.mirror(axis, [dist, dist])
                 obj.plot()
-            except Exception, e:
+            except Exception as e:
                 return "Operation failed: %s" % str(e)

+ 2 - 3
tclCommands/TclCommandNew.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandNew(TclCommand.TclCommand):
+class TclCommandNew(TclCommand):
     """
     Tcl shell command to starts a new project. Clears objects from memory
     """

+ 2 - 3
tclCommands/TclCommandNewGeometry.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandNewGeometry(TclCommand.TclCommandSignaled):
+class TclCommandNewGeometry(TclCommandSignaled):
     """
     Tcl shell command to subtract polygon from the given Geometry object.
     """

+ 2 - 3
tclCommands/TclCommandOffset.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandOffset(TclCommand.TclCommand):
+class TclCommandOffset(TclCommand):
     """
     Tcl shell command to change the position of the object.
 

+ 2 - 3
tclCommands/TclCommandOpenExcellon.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandOpenExcellon(TclCommand.TclCommandSignaled):
+class TclCommandOpenExcellon(TclCommandSignaled):
     """
     Tcl shell command to open an Excellon file.
     """

+ 2 - 3
tclCommands/TclCommandOpenGCode.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandOpenGCode(TclCommand.TclCommandSignaled):
+class TclCommandOpenGCode(TclCommandSignaled):
     """
     Tcl shell command to open a G-Code file.
     """

+ 4 - 5
tclCommands/TclCommandOpenGerber.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandOpenGerber(TclCommand.TclCommandSignaled):
+class TclCommandOpenGerber(TclCommandSignaled):
     """
     Tcl shell command to opens a Gerber file
     """
@@ -48,7 +47,7 @@ class TclCommandOpenGerber(TclCommand.TclCommandSignaled):
         # How the object should be initialized
         def obj_init(gerber_obj, app_obj):
 
-            if not isinstance(gerber_obj, Geometry):
+            if not isinstance(gerber_obj, FlatCAMGerber):
                 self.raise_tcl_error('Expected FlatCAMGerber, got %s %s.' % (outname, type(gerber_obj)))
 
             # Opening the file happens here
@@ -61,7 +60,7 @@ class TclCommandOpenGerber(TclCommand.TclCommandSignaled):
                 app_obj.progress.emit(0)
                 self.raise_tcl_error('Failed to open file: %s' % filename)
 
-            except ParseError, e:
+            except ParseError as e:
                 app_obj.inform.emit("[error] Failed to parse file: %s, %s " % (filename, str(e)))
                 app_obj.progress.emit(0)
                 self.log.error(str(e))

+ 2 - 3
tclCommands/TclCommandOpenProject.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandOpenProject(TclCommand.TclCommandSignaled):
+class TclCommandOpenProject(TclCommandSignaled):
     """
     Tcl shell command to open a FlatCAM project.
     """

+ 2 - 3
tclCommands/TclCommandOptions.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandOptions(TclCommand.TclCommandSignaled):
+class TclCommandOptions(TclCommandSignaled):
     """
     Tcl shell command to open an Excellon file.
     """

+ 2 - 3
tclCommands/TclCommandPaint.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandPaint(TclCommand.TclCommandSignaled):
+class TclCommandPaint(TclCommandSignaled):
     """
     Paint the interior of polygons
     """

+ 2 - 4
tclCommands/TclCommandPanelize.py

@@ -1,10 +1,8 @@
-from ObjectCollection import *
 from copy import copy,deepcopy
+from tclCommands.TclCommand import *
 
-import TclCommand
 
-
-class TclCommandPanelize(TclCommand.TclCommand):
+class TclCommandPanelize(TclCommand):
     """
     Tcl shell command to pannelize an object.
 

+ 2 - 3
tclCommands/TclCommandPlot.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandPlot(TclCommand.TclCommand):
+class TclCommandPlot(TclCommand):
     """
     Tcl shell command to update the plot on the user interface.
 

+ 2 - 3
tclCommands/TclCommandSaveProject.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandSaveProject(TclCommand.TclCommandSignaled):
+class TclCommandSaveProject(TclCommandSignaled):
     """
     Tcl shell command to save the FlatCAM project to file.
     """

+ 2 - 3
tclCommands/TclCommandScale.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandScale(TclCommand.TclCommand):
+class TclCommandScale(TclCommand):
     """
     Tcl shell command to resizes the object by a factor.
 

+ 2 - 3
tclCommands/TclCommandSetActive.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandSetActive(TclCommand.TclCommand):
+class TclCommandSetActive(TclCommand):
     """
     Tcl shell command to set an object as active in the GUI.
 

+ 2 - 3
tclCommands/TclCommandSetSys.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandSetSys(TclCommand.TclCommand):
+class TclCommandSetSys(TclCommand):
     """
     Tcl shell command to set the value of a system variable
 

+ 2 - 3
tclCommands/TclCommandSubtractPoly.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandSubtractPoly(TclCommand.TclCommandSignaled):
+class TclCommandSubtractPoly(TclCommandSignaled):
     """
     Tcl shell command to create a new empty Geometry object.
     """

+ 2 - 3
tclCommands/TclCommandSubtractRectangle.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandSubtractRectangle(TclCommand.TclCommandSignaled):
+class TclCommandSubtractRectangle(TclCommandSignaled):
     """
     Tcl shell command to subtract a rectange from the given Geometry object.
     """

+ 2 - 3
tclCommands/TclCommandVersion.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandVersion(TclCommand.TclCommand):
+class TclCommandVersion(TclCommand):
     """
     Tcl shell command to check the program version.
 

+ 2 - 3
tclCommands/TclCommandWriteGCode.py

@@ -1,8 +1,7 @@
-from ObjectCollection import *
-import TclCommand
+from tclCommands.TclCommand import *
 
 
-class TclCommandWriteGCode(TclCommand.TclCommandSignaled):
+class TclCommandWriteGCode(TclCommandSignaled):
     """
     Tcl shell command to save the G-code of a CNC Job object to file.
     """

+ 2 - 2
tclCommands/__init__.py

@@ -73,9 +73,9 @@ def register_all_commands(app, commands):
     :return: None
     """
 
-    tcl_modules = {k: v for k, v in sys.modules.items() if k.startswith('tclCommands.TclCommand')}
+    tcl_modules = {k: v for k, v in list(sys.modules.items()) if k.startswith('tclCommands.TclCommand')}
 
-    for key, mod in tcl_modules.items():
+    for key, mod in list(tcl_modules.items()):
         if key != 'tclCommands.TclCommand':
             class_name = key.split('.')[1]
             class_type = getattr(mod, class_name)

+ 2 - 2
termwidget.py

@@ -3,7 +3,7 @@ Terminal emulator widget.
 Shows intput and output text. Allows to enter commands. Supports history.
 """
 
-import cgi
+import html
 from PyQt4.QtCore import pyqtSignal, Qt
 from PyQt4.QtGui import QColor, QKeySequence, QLineEdit, QPalette, \
                         QSizePolicy, QTextCursor, QTextEdit, \
@@ -152,7 +152,7 @@ class TermWidget(QWidget):
         """
         assert style in ('in', 'out', 'err')
 
-        text = cgi.escape(text)
+        text = html.escape(text)
         text = text.replace('\n', '<br/>')
 
         if style == 'in':

+ 2 - 2
tests/canvas/performance.py

@@ -1,9 +1,9 @@
-from __future__ import division
+
 import matplotlib
 matplotlib.use('Agg')
 import matplotlib.pyplot as plt
 import numpy as np
-import cStringIO
+import io
 from matplotlib.backends.backend_agg import FigureCanvasAgg
 from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
 from matplotlib.figure import Figure

+ 1 - 1
tests/other/destructor_test.py

@@ -8,7 +8,7 @@ class MyObj():
         pass
 
     def __del__(self):
-        print "##### Destroyed ######"
+        print("##### Destroyed ######")
 
 
 def parse():

+ 3 - 3
tests/other/test_fcrts.py

@@ -26,12 +26,12 @@ for geo in geoms:
 current_pt = (0, 0)
 pt, geo = s.nearest(current_pt)
 while geo is not None:
-    print pt, geo
-    print "OBJECTS BEFORE:", s.objects
+    print((pt, geo))
+    print(("OBJECTS BEFORE:", s.objects))
 
     #geo.coords = list(geo.coords[::-1])
     s.remove(geo)
 
-    print "OBJECTS AFTER:", s.objects
+    print(("OBJECTS AFTER:", s.objects))
     current_pt = geo.coords[-1]
     pt, geo = s.nearest(current_pt)

+ 3 - 3
tests/other/test_rt.py

@@ -13,12 +13,12 @@ rt = rtindex.Index(properties=p)
 
 # If interleaved is True, the coordinates must be in
 # the form [xmin, ymin, ..., kmin, xmax, ymax, ..., kmax].
-print rt.interleaved
+print((rt.interleaved))
 
 [rt.add(0, pt2rect(pt)) for pt in pts]
-print [r.bbox for r in list(rt.nearest((0, 0), 10, True))]
+print([r.bbox for r in list(rt.nearest((0, 0), 10, True))])
 
 for pt in pts:
     rt.delete(0, pt2rect(pt))
-    print pt2rect(pt), [r.bbox for r in list(rt.nearest((0, 0), 10, True))]
+    print((pt2rect(pt), [r.bbox for r in list(rt.nearest((0, 0), 10, True))]))
 

+ 9 - 9
tests/test_excellon_flow.py

@@ -36,18 +36,18 @@ class ExcellonFlowTestCase(unittest.TestCase):
     def test_flow(self):
         # Names of available objects.
         names = self.fc.collection.get_names()
-        print names
+        print(names)
 
         #--------------------------------------
         # Total of 1 objects.
         #--------------------------------------
-        self.assertEquals(len(names), 1,
+        self.assertEqual(len(names), 1,
                           "Expected 1 object, found %d" % len(names))
 
         #--------------------------------------
         # Object's name matches the file name.
         #--------------------------------------
-        self.assertEquals(names[0], self.filename,
+        self.assertEqual(names[0], self.filename,
                           "Expected name == %s, got %s" % (self.filename, names[0]))
 
         #---------------------------------------
@@ -65,14 +65,14 @@ class ExcellonFlowTestCase(unittest.TestCase):
         # TODO: Open GUI with double-click on object.
         # Opens the Object's GUI, populates it.
         excellon_obj.build_ui()
-        for option, value in excellon_obj.options.iteritems():
+        for option, value in list(excellon_obj.options.items()):
             try:
                 form_field = excellon_obj.form_fields[option]
             except KeyError:
-                print ("**********************************************************\n"
+                print(("**********************************************************\n"
                        "* WARNING: Option '{}' has no form field\n"
                        "**********************************************************"
-                       "".format(option))
+                       "".format(option)))
                 continue
             self.assertEqual(value, form_field.get_value(),
                              "Option '{}' == {} but form has {}".format(
@@ -87,7 +87,7 @@ class ExcellonFlowTestCase(unittest.TestCase):
         form_field = excellon_obj.form_fields['feedrate']
         value = form_field.get_value()
         form_field.set_value(value * 1.1)  # Increase by 10%
-        print "'feedrate' == {}".format(value)
+        print(("'feedrate' == {}".format(value)))
 
         #--------------------------------------------------
         # Create GCode using all tools.
@@ -119,7 +119,7 @@ class ExcellonFlowTestCase(unittest.TestCase):
         self.assertEqual(value, form_value,
                          "Form value for '{}' == {} was not read into options"
                          "which has {}".format('feedrate', form_value, value))
-        print "'feedrate' == {}".format(value)
+        print(("'feedrate' == {}".format(value)))
 
         #---------------------------------------------
         # Check that only 1 object has been created.
@@ -160,4 +160,4 @@ class ExcellonFlowTestCase(unittest.TestCase):
         self.assertTrue(os.path.isfile(output_filename))
         os.remove(output_filename)
 
-        print names
+        print(names)

+ 9 - 9
tests/test_gerber_flow.py

@@ -36,18 +36,18 @@ class GerberFlowTestCase(unittest.TestCase):
     def test_flow(self):
         # Names of available objects.
         names = self.fc.collection.get_names()
-        print names
+        print(names)
 
         #--------------------------------------
         # Total of 1 objects.
         #--------------------------------------
-        self.assertEquals(len(names), 1,
+        self.assertEqual(len(names), 1,
                           "Expected 1 object, found %d" % len(names))
 
         #--------------------------------------
         # Object's name matches the file name.
         #--------------------------------------
-        self.assertEquals(names[0], self.filename,
+        self.assertEqual(names[0], self.filename,
                           "Expected name == %s, got %s" % (self.filename, names[0]))
 
         #---------------------------------------
@@ -65,14 +65,14 @@ class GerberFlowTestCase(unittest.TestCase):
         # TODO: Open GUI with double-click on object.
         # Opens the Object's GUI, populates it.
         gerber_obj.build_ui()
-        for option, value in gerber_obj.options.iteritems():
+        for option, value in list(gerber_obj.options.items()):
             try:
                 form_field = gerber_obj.form_fields[option]
             except KeyError:
-                print ("**********************************************************\n"
+                print(("**********************************************************\n"
                        "* WARNING: Option '{}' has no form field\n"
                        "**********************************************************"
-                       "".format(option))
+                       "".format(option)))
                 continue
             self.assertEqual(value, form_field.get_value(),
                              "Option '{}' == {} but form has {}".format(
@@ -87,7 +87,7 @@ class GerberFlowTestCase(unittest.TestCase):
         form_field = gerber_obj.form_fields['isotooldia']
         value = form_field.get_value()
         form_field.set_value(value * 1.1)  # Increase by 10%
-        print "'isotooldia' == {}".format(value)
+        print(("'isotooldia' == {}".format(value)))
 
         #--------------------------------------------------
         # Create isolation routing using default values
@@ -110,7 +110,7 @@ class GerberFlowTestCase(unittest.TestCase):
         self.assertEqual(value, form_value,
                          "Form value for '{}' == {} was not read into options"
                          "which has {}".format('isotooldia', form_value, value))
-        print "'isotooldia' == {}".format(value)
+        print(("'isotooldia' == {}".format(value)))
 
         #---------------------------------------------
         # Check that only 1 object has been created.
@@ -187,4 +187,4 @@ class GerberFlowTestCase(unittest.TestCase):
         self.assertTrue(os.path.isfile(output_filename))
         os.remove(output_filename)
 
-        print names
+        print(names)

+ 21 - 21
tests/test_paint.py

@@ -75,66 +75,66 @@ class PaintConnectTest(PaintTestCase):
         self.boundary = Polygon([[0, 0], [0, 5], [5, 5], [5, 0]])
 
     def test_jump(self):
-        print "Test: WALK Expected"
+        print("Test: WALK Expected")
         paths = [
             LineString([[0.5, 2], [2, 4.5]]),
             LineString([[2, 0.5], [4.5, 2]])
         ]
         for p in paths:
-            print p
+            print(p)
 
         tooldia = 1.0
 
-        print "--"
+        print("--")
         result = Geometry.paint_connect(mkstorage(deepcopy(paths)), self.boundary, tooldia)
 
         result = list(result.get_objects())
         for r in result:
-            print r
+            print(r)
 
         self.assertEqual(len(result), 1)
 
         # self.plot_summary_A(paths, tooldia, result, "WALK expected.")
 
     def test_no_jump1(self):
-        print "Test: FLY Expected"
+        print("Test: FLY Expected")
         paths = [
             LineString([[0, 2], [2, 5]]),
             LineString([[2, 0], [5, 2]])
         ]
         for p in paths:
-            print p
+            print(p)
 
         tooldia = 1.0
 
-        print "--"
+        print("--")
         result = Geometry.paint_connect(mkstorage(deepcopy(paths)), self.boundary, tooldia)
 
         result = list(result.get_objects())
         for r in result:
-            print r
+            print(r)
 
         self.assertEqual(len(result), len(paths))
 
         # self.plot_summary_A(paths, tooldia, result, "FLY Expected")
 
     def test_no_jump2(self):
-        print "Test: FLY Expected"
+        print("Test: FLY Expected")
         paths = [
             LineString([[0.5, 2], [2, 4.5]]),
             LineString([[2, 0.5], [4.5, 2]])
         ]
         for p in paths:
-            print p
+            print(p)
 
         tooldia = 1.1
 
-        print "--"
+        print("--")
         result = Geometry.paint_connect(mkstorage(deepcopy(paths)), self.boundary, tooldia)
 
         result = list(result.get_objects())
         for r in result:
-            print r
+            print(r)
 
         self.assertEqual(len(result), len(paths))
 
@@ -153,22 +153,22 @@ class PaintConnectTest2(PaintTestCase):
         )
 
     def test_no_jump3(self):
-        print "TEST: No jump expected"
+        print("TEST: No jump expected")
         paths = [
             LineString([[0.5, 1], [1.5, 3]]),
             LineString([[4, 1], [4, 4]])
         ]
         for p in paths:
-            print p
+            print(p)
 
         tooldia = 1.0
 
-        print "--"
+        print("--")
         result = Geometry.paint_connect(mkstorage(deepcopy(paths)), self.boundary, tooldia)
 
         result = list(result.get_objects())
         for r in result:
-            print r
+            print(r)
 
         self.assertEqual(len(result), len(paths))
 
@@ -182,26 +182,26 @@ class PaintConnectTest3(PaintTestCase):
 
     def setUp(self):
         self.boundary = Polygon([[0, 0], [0, 5], [5, 5], [5, 0]])
-        print "TEST w/ LinearRings"
+        print("TEST w/ LinearRings")
 
     def test_jump2(self):
-        print "Test: WALK Expected"
+        print("Test: WALK Expected")
         paths = [
             LineString([[0.5, 2], [2, 4.5]]),
             LineString([[2, 0.5], [4.5, 2]]),
             self.boundary.buffer(-0.5).exterior
         ]
         for p in paths:
-            print p
+            print(p)
 
         tooldia = 1.0
 
-        print "--"
+        print("--")
         result = Geometry.paint_connect(mkstorage(deepcopy(paths)), self.boundary, tooldia)
 
         result = list(result.get_objects())
         for r in result:
-            print r
+            print(r)
 
         self.assertEqual(len(result), 1)
 

+ 3 - 3
tests/test_pathconnect.py

@@ -20,7 +20,7 @@ def mkstorage(paths):
 class PathConnectTest1(unittest.TestCase):
 
     def setUp(self):
-        print "PathConnectTest1.setUp()"
+        print("PathConnectTest1.setUp()")
         pass
 
     def test_simple_connect(self):
@@ -68,8 +68,8 @@ class PathConnectTest1(unittest.TestCase):
                                                          [2 + offset_x, 1 + offset_y]])))
 
     def test_ring_interfere_connect(self):
-        print
-        print "TEST STARTING ..."
+        print()
+        print("TEST STARTING ...")
 
         paths = [
             LineString([[0, 0], [1, 1]]),

+ 12 - 12
tests/test_polygon_paint.py

@@ -30,9 +30,9 @@ class PolyPaintTestCase(unittest.TestCase):
 
     def test_poly_paint_svg_all(self):
 
-        print "*********************************"
-        print "*         svg_all               *"
-        print "*********************************"
+        print("*********************************")
+        print("*         svg_all               *")
+        print("*********************************")
 
         # Clear workspace
         self.fc.on_file_new()
@@ -69,9 +69,9 @@ class PolyPaintTestCase(unittest.TestCase):
 
     def test_poly_paint_svg_click(self):
 
-        print "*********************************"
-        print "*         svg_click             *"
-        print "*********************************"
+        print("*********************************")
+        print("*         svg_click             *")
+        print("*********************************")
 
         # Clear workspace
         self.fc.on_file_new()
@@ -109,9 +109,9 @@ class PolyPaintTestCase(unittest.TestCase):
 
     def test_poly_paint_noncopper_all(self):
 
-        print "*********************************"
-        print "*         noncopper_all         *"
-        print "*********************************"
+        print("*********************************")
+        print("*         noncopper_all         *")
+        print("*********************************")
 
         # Clear workspace
         self.fc.on_file_new()
@@ -165,9 +165,9 @@ class PolyPaintTestCase(unittest.TestCase):
 
     def test_poly_paint_noncopper_click(self):
 
-        print "*********************************"
-        print "*         noncopper_click       *"
-        print "*********************************"
+        print("*********************************")
+        print("*         noncopper_click       *")
+        print("*********************************")
 
         # Clear workspace
         self.fc.on_file_new()

+ 7 - 7
tests/test_svg_flow.py

@@ -29,18 +29,18 @@ class SVGFlowTestCase(unittest.TestCase):
         self.fc.import_svg('tests/svg/' + self.filename)
 
         names = self.fc.collection.get_names()
-        print names
+        print(names)
 
         #--------------------------------------
         # Total of 1 objects.
         #--------------------------------------
-        self.assertEquals(len(names), 1,
+        self.assertEqual(len(names), 1,
                           "Expected 1 object, found %d" % len(names))
 
         #--------------------------------------
         # Object's name matches the file name.
         #--------------------------------------
-        self.assertEquals(names[0], self.filename,
+        self.assertEqual(names[0], self.filename,
                           "Expected name == %s, got %s" % (self.filename, names[0]))
 
         #---------------------------------------
@@ -58,14 +58,14 @@ class SVGFlowTestCase(unittest.TestCase):
         # TODO: Open GUI with double-click on object.
         # Opens the Object's GUI, populates it.
         geo_obj.build_ui()
-        for option, value in geo_obj.options.iteritems():
+        for option, value in list(geo_obj.options.items()):
             try:
                 form_field = geo_obj.form_fields[option]
             except KeyError:
-                print ("**********************************************************\n"
+                print(("**********************************************************\n"
                        "* WARNING: Option '{}' has no form field\n"
                        "**********************************************************"
-                       "".format(option))
+                       "".format(option)))
                 continue
             self.assertEqual(value, form_field.get_value(),
                              "Option '{}' == {} but form has {}".format(
@@ -126,4 +126,4 @@ class SVGFlowTestCase(unittest.TestCase):
         self.assertTrue(os.path.isfile(output_filename))
         os.remove(output_filename)
 
-        print names
+        print(names)

+ 14 - 14
tests/test_tclCommands/__init__.py

@@ -2,17 +2,17 @@ import pkgutil
 import sys
 
 # allowed command tests (please append them alphabetically ordered)
-from test_TclCommandAddPolygon import *
-from test_TclCommandAddPolyline import *
-from test_TclCommandCncjob import *
-from test_TclCommandDrillcncjob import *
-from test_TclCommandExportGcode import *
-from test_TclCommandExteriors import *
-from test_TclCommandImportSvg import *
-from test_TclCommandInteriors import *
-from test_TclCommandIsolate import *
-from test_TclCommandNew import *
-from test_TclCommandNewGeometry  import *
-from test_TclCommandOpenExcellon import *
-from test_TclCommandOpenGerber import *
-from test_TclCommandPaintPolygon import *
+from .test_TclCommandAddPolygon import *
+from .test_TclCommandAddPolyline import *
+from .test_TclCommandCncjob import *
+from .test_TclCommandDrillcncjob import *
+from .test_TclCommandExportGcode import *
+from .test_TclCommandExteriors import *
+from .test_TclCommandImportSvg import *
+from .test_TclCommandInteriors import *
+from .test_TclCommandIsolate import *
+from .test_TclCommandNew import *
+from .test_TclCommandNewGeometry  import *
+from .test_TclCommandOpenExcellon import *
+from .test_TclCommandOpenGerber import *
+from .test_TclCommandPaintPolygon import *

+ 1 - 1
tests/test_tclCommands/test_TclCommandCncjob.py

@@ -1,5 +1,5 @@
 from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMObj
-from test_TclCommandIsolate import *
+from .test_TclCommandIsolate import *
 
 def test_cncjob(self):
     """

+ 1 - 1
tests/test_tclCommands/test_TclCommandDrillcncjob.py

@@ -1,5 +1,5 @@
 from FlatCAMObj import FlatCAMObj
-from test_TclCommandOpenExcellon import *
+from .test_TclCommandOpenExcellon import *
 
 
 def test_drillcncjob(self):

+ 2 - 2
tests/test_tclCommands/test_TclCommandExportGcode.py

@@ -1,8 +1,8 @@
 import os
 import tempfile
 
-from test_TclCommandCncjob import *
-from test_TclCommandDrillcncjob import *
+from .test_TclCommandCncjob import *
+from .test_TclCommandDrillcncjob import *
 
 
 def test_export_gcodecncjob(self):

+ 2 - 2
tests/test_tcl_shell.py

@@ -82,7 +82,7 @@ class TclShellTest(unittest.TestCase):
         # Units must be IN
         #----------------------------------------
         units = self.fc.exec_command_test('get_sys units')
-        self.assertEquals(units, "IN")
+        self.assertEqual(units, "IN")
 
         # MM
         self.fc.exec_command_test('set_sys units MM')
@@ -92,7 +92,7 @@ class TclShellTest(unittest.TestCase):
         # Units must be MM
         #----------------------------------------
         units = self.fc.exec_command_test('get_sys units')
-        self.assertEquals(units, "MM")
+        self.assertEqual(units, "MM")
 
     def test_gerber_flow(self):
         """