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

- moved back the ApertureMacro class to camlib for now and made some import changes in the new ParseGerber and ParseExcellon classes
- some changes to the tests - perhaps I will try adding a few tests in the future

Marius Stanciu 6 лет назад
Родитель
Сommit
a6b89dbf3a

+ 5 - 5
FlatCAMApp.py

@@ -52,7 +52,7 @@ from flatcamEditors.FlatCAMTextEditor import TextEditor
 
 
 from FlatCAMProcess import *
 from FlatCAMProcess import *
 from FlatCAMWorkerStack import WorkerStack
 from FlatCAMWorkerStack import WorkerStack
-from flatcamGUI.VisPyVisuals import Color
+# from flatcamGUI.VisPyVisuals import Color
 from vispy.gloo.util import _screenshot
 from vispy.gloo.util import _screenshot
 from vispy.io import write_png
 from vispy.io import write_png
 
 
@@ -71,12 +71,12 @@ fcTranslate.apply_language('strings')
 if '_' not in builtins.__dict__:
 if '_' not in builtins.__dict__:
     _ = gettext.gettext
     _ = gettext.gettext
 
 
-# ########################################
-# #                App                 ###
-# ########################################
-
 
 
 class App(QtCore.QObject):
 class App(QtCore.QObject):
+    # ########################################
+    # #                App                 ###
+    # ########################################
+
     """
     """
     The main application class. The constructor starts the GUI.
     The main application class. The constructor starts the GUI.
     """
     """

+ 2 - 0
README.md

@@ -17,6 +17,8 @@ CAD program, and create G-Code for Isolation routing.
 - made the Rules Check Tool document window Read Only
 - made the Rules Check Tool document window Read Only
 - made Excellon and Gerber classes from camlib into their own files in the flatcamParser folder
 - made Excellon and Gerber classes from camlib into their own files in the flatcamParser folder
 - moved the ApertureMacro class from camlib to ParseGerber file
 - moved the ApertureMacro class from camlib to ParseGerber file
+- moved back the ApertureMacro class to camlib for now and made some import changes in the new ParseGerber and ParseExcellon classes
+- some changes to the tests - perhaps I will try adding a few tests in the future
 
 
 5.10.2019
 5.10.2019
 
 

+ 374 - 1
camlib.py

@@ -49,7 +49,7 @@ import ezdxf
 # TODO: Commented for FlatCAM packaging with cx_freeze
 # TODO: Commented for FlatCAM packaging with cx_freeze
 # from scipy.spatial import KDTree, Delaunay
 # from scipy.spatial import KDTree, Delaunay
 # from scipy.spatial import Delaunay
 # from scipy.spatial import Delaunay
-from flatcamParsers.ParseGerber import ApertureMacro
+
 from flatcamParsers.ParseSVG import *
 from flatcamParsers.ParseSVG import *
 from flatcamParsers.ParseDXF import *
 from flatcamParsers.ParseDXF import *
 
 
@@ -82,6 +82,379 @@ class ParseError(Exception):
     pass
     pass
 
 
 
 
+class ApertureMacro:
+    """
+    Syntax of aperture macros.
+
+    <AM command>:           AM<Aperture macro name>*<Macro content>
+    <Macro content>:        {{<Variable definition>*}{<Primitive>*}}
+    <Variable definition>:  $K=<Arithmetic expression>
+    <Primitive>:            <Primitive code>,<Modifier>{,<Modifier>}|<Comment>
+    <Modifier>:             $M|< Arithmetic expression>
+    <Comment>:              0 <Text>
+    """
+
+    # ## Regular expressions
+    am1_re = re.compile(r'^%AM([^\*]+)\*(.+)?(%)?$')
+    am2_re = re.compile(r'(.*)%$')
+    amcomm_re = re.compile(r'^0(.*)')
+    amprim_re = re.compile(r'^[1-9].*')
+    amvar_re = re.compile(r'^\$([0-9a-zA-z]+)=(.*)')
+
+    def __init__(self, name=None):
+        self.name = name
+        self.raw = ""
+
+        # ## These below are recomputed for every aperture
+        # ## definition, in other words, are temporary variables.
+        self.primitives = []
+        self.locvars = {}
+        self.geometry = None
+
+    def to_dict(self):
+        """
+        Returns the object in a serializable form. Only the name and
+        raw are required.
+
+        :return: Dictionary representing the object. JSON ready.
+        :rtype: dict
+        """
+
+        return {
+            'name': self.name,
+            'raw': self.raw
+        }
+
+    def from_dict(self, d):
+        """
+        Populates the object from a serial representation created
+        with ``self.to_dict()``.
+
+        :param d: Serial representation of an ApertureMacro object.
+        :return: None
+        """
+        for attr in ['name', 'raw']:
+            setattr(self, attr, d[attr])
+
+    def parse_content(self):
+        """
+        Creates numerical lists for all primitives in the aperture
+        macro (in ``self.raw``) by replacing all variables by their
+        values iteratively and evaluating expressions. Results
+        are stored in ``self.primitives``.
+
+        :return: None
+        """
+        # Cleanup
+        self.raw = self.raw.replace('\n', '').replace('\r', '').strip(" *")
+        self.primitives = []
+
+        # Separate parts
+        parts = self.raw.split('*')
+
+        # ### Every part in the macro ####
+        for part in parts:
+            # ## Comments. Ignored.
+            match = ApertureMacro.amcomm_re.search(part)
+            if match:
+                continue
+
+            # ## Variables
+            # These are variables defined locally inside the macro. They can be
+            # numerical constant or defind in terms of previously define
+            # variables, which can be defined locally or in an aperture
+            # definition. All replacements ocurr here.
+            match = ApertureMacro.amvar_re.search(part)
+            if match:
+                var = match.group(1)
+                val = match.group(2)
+
+                # Replace variables in value
+                for v in self.locvars:
+                    # replaced the following line with the next to fix Mentor custom apertures not parsed OK
+                    # val = re.sub((r'\$'+str(v)+r'(?![0-9a-zA-Z])'), str(self.locvars[v]), val)
+                    val = val.replace('$' + str(v), str(self.locvars[v]))
+
+                # Make all others 0
+                val = re.sub(r'\$[0-9a-zA-Z](?![0-9a-zA-Z])', "0", val)
+                # Change x with *
+                val = re.sub(r'[xX]', "*", val)
+
+                # Eval() and store.
+                self.locvars[var] = eval(val)
+                continue
+
+            # ## Primitives
+            # Each is an array. The first identifies the primitive, while the
+            # rest depend on the primitive. All are strings representing a
+            # number and may contain variable definition. The values of these
+            # variables are defined in an aperture definition.
+            match = ApertureMacro.amprim_re.search(part)
+            if match:
+                # ## Replace all variables
+                for v in self.locvars:
+                    # replaced the following line with the next to fix Mentor custom apertures not parsed OK
+                    # part = re.sub(r'\$' + str(v) + r'(?![0-9a-zA-Z])', str(self.locvars[v]), part)
+                    part = part.replace('$' + str(v), str(self.locvars[v]))
+
+                # Make all others 0
+                part = re.sub(r'\$[0-9a-zA-Z](?![0-9a-zA-Z])', "0", part)
+
+                # Change x with *
+                part = re.sub(r'[xX]', "*", part)
+
+                # ## Store
+                elements = part.split(",")
+                self.primitives.append([eval(x) for x in elements])
+                continue
+
+            log.warning("Unknown syntax of aperture macro part: %s" % str(part))
+
+    def append(self, data):
+        """
+        Appends a string to the raw macro.
+
+        :param data: Part of the macro.
+        :type data: str
+        :return: None
+        """
+        self.raw += data
+
+    @staticmethod
+    def default2zero(n, mods):
+        """
+        Pads the ``mods`` list with zeros resulting in an
+        list of length n.
+
+        :param n: Length of the resulting list.
+        :type n: int
+        :param mods: List to be padded.
+        :type mods: list
+        :return: Zero-padded list.
+        :rtype: list
+        """
+        x = [0.0] * n
+        na = len(mods)
+        x[0:na] = mods
+        return x
+
+    @staticmethod
+    def make_circle(mods):
+        """
+
+        :param mods: (Exposure 0/1, Diameter >=0, X-coord, Y-coord)
+        :return:
+        """
+
+        pol, dia, x, y = ApertureMacro.default2zero(4, mods)
+
+        return {"pol": int(pol), "geometry": Point(x, y).buffer(dia/2)}
+
+    @staticmethod
+    def make_vectorline(mods):
+        """
+
+        :param mods: (Exposure 0/1, Line width >= 0, X-start, Y-start, X-end, Y-end,
+            rotation angle around origin in degrees)
+        :return:
+        """
+        pol, width, xs, ys, xe, ye, angle = ApertureMacro.default2zero(7, mods)
+
+        line = LineString([(xs, ys), (xe, ye)])
+        box = line.buffer(width/2, cap_style=2)
+        box_rotated = affinity.rotate(box, angle, origin=(0, 0))
+
+        return {"pol": int(pol), "geometry": box_rotated}
+
+    @staticmethod
+    def make_centerline(mods):
+        """
+
+        :param mods: (Exposure 0/1, width >=0, height >=0, x-center, y-center,
+            rotation angle around origin in degrees)
+        :return:
+        """
+
+        pol, width, height, x, y, angle = ApertureMacro.default2zero(6, mods)
+
+        box = shply_box(x-width/2, y-height/2, x+width/2, y+height/2)
+        box_rotated = affinity.rotate(box, angle, origin=(0, 0))
+
+        return {"pol": int(pol), "geometry": box_rotated}
+
+    @staticmethod
+    def make_lowerleftline(mods):
+        """
+
+        :param mods: (exposure 0/1, width >=0, height >=0, x-lowerleft, y-lowerleft,
+            rotation angle around origin in degrees)
+        :return:
+        """
+
+        pol, width, height, x, y, angle = ApertureMacro.default2zero(6, mods)
+
+        box = shply_box(x, y, x+width, y+height)
+        box_rotated = affinity.rotate(box, angle, origin=(0, 0))
+
+        return {"pol": int(pol), "geometry": box_rotated}
+
+    @staticmethod
+    def make_outline(mods):
+        """
+
+        :param mods:
+        :return:
+        """
+
+        pol = mods[0]
+        n = mods[1]
+        points = [(0, 0)]*(n+1)
+
+        for i in range(n+1):
+            points[i] = mods[2*i + 2:2*i + 4]
+
+        angle = mods[2*n + 4]
+
+        poly = Polygon(points)
+        poly_rotated = affinity.rotate(poly, angle, origin=(0, 0))
+
+        return {"pol": int(pol), "geometry": poly_rotated}
+
+    @staticmethod
+    def make_polygon(mods):
+        """
+        Note: Specs indicate that rotation is only allowed if the center
+        (x, y) == (0, 0). I will tolerate breaking this rule.
+
+        :param mods: (exposure 0/1, n_verts 3<=n<=12, x-center, y-center,
+            diameter of circumscribed circle >=0, rotation angle around origin)
+        :return:
+        """
+
+        pol, nverts, x, y, dia, angle = ApertureMacro.default2zero(6, mods)
+        points = [(0, 0)]*nverts
+
+        for i in range(nverts):
+            points[i] = (x + 0.5 * dia * cos(2*pi * i/nverts),
+                         y + 0.5 * dia * sin(2*pi * i/nverts))
+
+        poly = Polygon(points)
+        poly_rotated = affinity.rotate(poly, angle, origin=(0, 0))
+
+        return {"pol": int(pol), "geometry": poly_rotated}
+
+    @staticmethod
+    def make_moire(mods):
+        """
+        Note: Specs indicate that rotation is only allowed if the center
+        (x, y) == (0, 0). I will tolerate breaking this rule.
+
+        :param mods: (x-center, y-center, outer_dia_outer_ring, ring thickness,
+            gap, max_rings, crosshair_thickness, crosshair_len, rotation
+            angle around origin in degrees)
+        :return:
+        """
+
+        x, y, dia, thickness, gap, nrings, cross_th, cross_len, angle = ApertureMacro.default2zero(9, mods)
+
+        r = dia/2 - thickness/2
+        result = Point((x, y)).buffer(r).exterior.buffer(thickness/2.0)
+        ring = Point((x, y)).buffer(r).exterior.buffer(thickness/2.0)  # Need a copy!
+
+        i = 1  # Number of rings created so far
+
+        # ## If the ring does not have an interior it means that it is
+        # ## a disk. Then stop.
+        while len(ring.interiors) > 0 and i < nrings:
+            r -= thickness + gap
+            if r <= 0:
+                break
+            ring = Point((x, y)).buffer(r).exterior.buffer(thickness/2.0)
+            result = cascaded_union([result, ring])
+            i += 1
+
+        # ## Crosshair
+        hor = LineString([(x - cross_len, y), (x + cross_len, y)]).buffer(cross_th/2.0, cap_style=2)
+        ver = LineString([(x, y-cross_len), (x, y + cross_len)]).buffer(cross_th/2.0, cap_style=2)
+        result = cascaded_union([result, hor, ver])
+
+        return {"pol": 1, "geometry": result}
+
+    @staticmethod
+    def make_thermal(mods):
+        """
+        Note: Specs indicate that rotation is only allowed if the center
+        (x, y) == (0, 0). I will tolerate breaking this rule.
+
+        :param mods: [x-center, y-center, diameter-outside, diameter-inside,
+            gap-thickness, rotation angle around origin]
+        :return:
+        """
+
+        x, y, dout, din, t, angle = ApertureMacro.default2zero(6, mods)
+
+        ring = Point((x, y)).buffer(dout/2.0).difference(Point((x, y)).buffer(din/2.0))
+        hline = LineString([(x - dout/2.0, y), (x + dout/2.0, y)]).buffer(t/2.0, cap_style=3)
+        vline = LineString([(x, y - dout/2.0), (x, y + dout/2.0)]).buffer(t/2.0, cap_style=3)
+        thermal = ring.difference(hline.union(vline))
+
+        return {"pol": 1, "geometry": thermal}
+
+    def make_geometry(self, modifiers):
+        """
+        Runs the macro for the given modifiers and generates
+        the corresponding geometry.
+
+        :param modifiers: Modifiers (parameters) for this macro
+        :type modifiers: list
+        :return: Shapely geometry
+        :rtype: shapely.geometry.polygon
+        """
+
+        # ## Primitive makers
+        makers = {
+            "1": ApertureMacro.make_circle,
+            "2": ApertureMacro.make_vectorline,
+            "20": ApertureMacro.make_vectorline,
+            "21": ApertureMacro.make_centerline,
+            "22": ApertureMacro.make_lowerleftline,
+            "4": ApertureMacro.make_outline,
+            "5": ApertureMacro.make_polygon,
+            "6": ApertureMacro.make_moire,
+            "7": ApertureMacro.make_thermal
+        }
+
+        # ## Store modifiers as local variables
+        modifiers = modifiers or []
+        modifiers = [float(m) for m in modifiers]
+        self.locvars = {}
+        for i in range(0, len(modifiers)):
+            self.locvars[str(i + 1)] = modifiers[i]
+
+        # ## Parse
+        self.primitives = []  # Cleanup
+        self.geometry = Polygon()
+        self.parse_content()
+
+        # ## Make the geometry
+        for primitive in self.primitives:
+            # Make the primitive
+            prim_geo = makers[str(int(primitive[0]))](primitive[1:])
+
+            # Add it (according to polarity)
+            # if self.geometry is None and prim_geo['pol'] == 1:
+            #     self.geometry = prim_geo['geometry']
+            #     continue
+            if prim_geo['pol'] == 1:
+                self.geometry = self.geometry.union(prim_geo['geometry'])
+                continue
+            if prim_geo['pol'] == 0:
+                self.geometry = self.geometry.difference(prim_geo['geometry'])
+                continue
+
+        return self.geometry
+
+
 class Geometry(object):
 class Geometry(object):
     """
     """
     Base geometry class.
     Base geometry class.

+ 26 - 2
flatcamParsers/ParseExcellon.py

@@ -1,8 +1,32 @@
-from camlib import *
+from camlib import Geometry
+import FlatCAMApp
+
+import FlatCAMTranslation as fcTranslate
+
+from shapely.geometry import Polygon, Point, LineString, MultiPolygon
+from shapely.ops import cascaded_union
+import shapely.affinity as affinity
+
+import re
+import traceback
+import gettext
+import builtins
+import numpy as np
+from numpy import Inf
+
+import logging
 
 
 if '_' not in builtins.__dict__:
 if '_' not in builtins.__dict__:
     _ = gettext.gettext
     _ = gettext.gettext
 
 
+log = logging.getLogger('base2')
+log.setLevel(logging.DEBUG)
+
+formatter = logging.Formatter('[%(levelname)s] %(message)s')
+handler = logging.StreamHandler()
+handler.setFormatter(formatter)
+log.addHandler(handler)
+
 
 
 class Excellon(Geometry):
 class Excellon(Geometry):
     """
     """
@@ -265,7 +289,7 @@ class Excellon(Geometry):
 
 
         line_units = ''
         line_units = ''
 
 
-        #### Parsing starts here ## ##
+        # ## Parsing starts here ## ##
         line_num = 0  # Line number
         line_num = 0  # Line number
         eline = ""
         eline = ""
         try:
         try:

+ 41 - 383
flatcamParsers/ParseGerber.py

@@ -1,9 +1,35 @@
+from camlib import Geometry, ApertureMacro, parse_gerber_number, arc, arctan2, arc_angle
+import FlatCAMApp
+import FlatCAMTranslation as fcTranslate
 
 
-from camlib import *
+from shapely.geometry import Polygon, Point, LineString, MultiPolygon
+from shapely.ops import cascaded_union
+import shapely.affinity as affinity
+from shapely.geometry import box as shply_box
+import re
+import traceback
+from copy import deepcopy
+
+import gettext
+import builtins
+
+import numpy as np
+from numpy import Inf
+from math import sqrt, pi, sin, cos
+import sys
+
+import logging
 
 
 if '_' not in builtins.__dict__:
 if '_' not in builtins.__dict__:
     _ = gettext.gettext
     _ = gettext.gettext
 
 
+log = logging.getLogger('base2')
+log.setLevel(logging.DEBUG)
+
+formatter = logging.Formatter('[%(levelname)s] %(message)s')
+handler = logging.StreamHandler()
+handler.setFormatter(formatter)
+log.addHandler(handler)
 
 
 class Gerber(Geometry):
 class Gerber(Geometry):
     """
     """
@@ -1134,25 +1160,25 @@ class Gerber(Geometry):
                     try:
                     try:
                         circular_x = parse_gerber_number(circular_x,
                         circular_x = parse_gerber_number(circular_x,
                                                          self.int_digits, self.frac_digits, self.gerber_zeros)
                                                          self.int_digits, self.frac_digits, self.gerber_zeros)
-                    except:
+                    except Exception as e:
                         circular_x = current_x
                         circular_x = current_x
 
 
                     try:
                     try:
                         circular_y = parse_gerber_number(circular_y,
                         circular_y = parse_gerber_number(circular_y,
                                                          self.int_digits, self.frac_digits, self.gerber_zeros)
                                                          self.int_digits, self.frac_digits, self.gerber_zeros)
-                    except:
+                    except Exception as e:
                         circular_y = current_y
                         circular_y = current_y
 
 
                     # According to Gerber specification i and j are not modal, which means that when i or j are missing,
                     # According to Gerber specification i and j are not modal, which means that when i or j are missing,
                     # they are to be interpreted as being zero
                     # they are to be interpreted as being zero
                     try:
                     try:
                         i = parse_gerber_number(i, self.int_digits, self.frac_digits, self.gerber_zeros)
                         i = parse_gerber_number(i, self.int_digits, self.frac_digits, self.gerber_zeros)
-                    except:
+                    except Exception as e:
                         i = 0
                         i = 0
 
 
                     try:
                     try:
                         j = parse_gerber_number(j, self.int_digits, self.frac_digits, self.gerber_zeros)
                         j = parse_gerber_number(j, self.int_digits, self.frac_digits, self.gerber_zeros)
-                    except:
+                    except Exception as e:
                         j = 0
                         j = 0
 
 
                     if quadrant_mode is None:
                     if quadrant_mode is None:
@@ -1598,6 +1624,7 @@ class Gerber(Geometry):
         :type xfactor: float
         :type xfactor: float
         :param yfactor: Number by which to scale on Y axis.
         :param yfactor: Number by which to scale on Y axis.
         :type yfactor: float
         :type yfactor: float
+        :param point: reference point for scaling operation
         :rtype : None
         :rtype : None
         """
         """
         log.debug("camlib.Gerber.scale()")
         log.debug("camlib.Gerber.scale()")
@@ -1628,7 +1655,7 @@ class Gerber(Geometry):
         # variables to display the percentage of work done
         # variables to display the percentage of work done
         self.geo_len = 0
         self.geo_len = 0
         try:
         try:
-            for g in self.solid_geometry:
+            for __ in self.solid_geometry:
                 self.geo_len += 1
                 self.geo_len += 1
         except TypeError:
         except TypeError:
             self.geo_len = 1
             self.geo_len = 1
@@ -1717,7 +1744,7 @@ class Gerber(Geometry):
         # variables to display the percentage of work done
         # variables to display the percentage of work done
         self.geo_len = 0
         self.geo_len = 0
         try:
         try:
-            for g in self.solid_geometry:
+            for __ in self.solid_geometry:
                 self.geo_len += 1
                 self.geo_len += 1
         except TypeError:
         except TypeError:
             self.geo_len = 1
             self.geo_len = 1
@@ -1796,7 +1823,7 @@ class Gerber(Geometry):
         # variables to display the percentage of work done
         # variables to display the percentage of work done
         self.geo_len = 0
         self.geo_len = 0
         try:
         try:
-            for g in self.solid_geometry:
+            for __ in self.solid_geometry:
                 self.geo_len += 1
                 self.geo_len += 1
         except TypeError:
         except TypeError:
             self.geo_len = 1
             self.geo_len = 1
@@ -1857,6 +1884,10 @@ class Gerber(Geometry):
 
 
         See shapely manual for more information:
         See shapely manual for more information:
         http://toblerity.org/shapely/manual.html#affine-transformations
         http://toblerity.org/shapely/manual.html#affine-transformations
+        :param angle_x: the angle on X axis for skewing
+        :param angle_y: the angle on Y axis for skewing
+        :param point: reference point for skewing operation
+        :return None
         """
         """
         log.debug("camlib.Gerber.skew()")
         log.debug("camlib.Gerber.skew()")
 
 
@@ -1865,7 +1896,7 @@ class Gerber(Geometry):
         # variables to display the percentage of work done
         # variables to display the percentage of work done
         self.geo_len = 0
         self.geo_len = 0
         try:
         try:
-            for g in self.solid_geometry:
+            for __ in self.solid_geometry:
                 self.geo_len += 1
                 self.geo_len += 1
         except TypeError:
         except TypeError:
             self.geo_len = 1
             self.geo_len = 1
@@ -1926,7 +1957,7 @@ class Gerber(Geometry):
         # variables to display the percentage of work done
         # variables to display the percentage of work done
         self.geo_len = 0
         self.geo_len = 0
         try:
         try:
-            for g in self.solid_geometry:
+            for __ in self.solid_geometry:
                 self.geo_len += 1
                 self.geo_len += 1
         except TypeError:
         except TypeError:
             self.geo_len = 1
             self.geo_len = 1
@@ -1972,376 +2003,3 @@ class Gerber(Geometry):
         self.app.inform.emit('[success] %s' %
         self.app.inform.emit('[success] %s' %
                              _("Gerber Rotate done."))
                              _("Gerber Rotate done."))
         self.app.proc_container.new_text = ''
         self.app.proc_container.new_text = ''
-
-
-class ApertureMacro:
-    """
-    Syntax of aperture macros.
-
-    <AM command>:           AM<Aperture macro name>*<Macro content>
-    <Macro content>:        {{<Variable definition>*}{<Primitive>*}}
-    <Variable definition>:  $K=<Arithmetic expression>
-    <Primitive>:            <Primitive code>,<Modifier>{,<Modifier>}|<Comment>
-    <Modifier>:             $M|< Arithmetic expression>
-    <Comment>:              0 <Text>
-    """
-
-    # ## Regular expressions
-    am1_re = re.compile(r'^%AM([^\*]+)\*(.+)?(%)?$')
-    am2_re = re.compile(r'(.*)%$')
-    amcomm_re = re.compile(r'^0(.*)')
-    amprim_re = re.compile(r'^[1-9].*')
-    amvar_re = re.compile(r'^\$([0-9a-zA-z]+)=(.*)')
-
-    def __init__(self, name=None):
-        self.name = name
-        self.raw = ""
-
-        # ## These below are recomputed for every aperture
-        # ## definition, in other words, are temporary variables.
-        self.primitives = []
-        self.locvars = {}
-        self.geometry = None
-
-    def to_dict(self):
-        """
-        Returns the object in a serializable form. Only the name and
-        raw are required.
-
-        :return: Dictionary representing the object. JSON ready.
-        :rtype: dict
-        """
-
-        return {
-            'name': self.name,
-            'raw': self.raw
-        }
-
-    def from_dict(self, d):
-        """
-        Populates the object from a serial representation created
-        with ``self.to_dict()``.
-
-        :param d: Serial representation of an ApertureMacro object.
-        :return: None
-        """
-        for attr in ['name', 'raw']:
-            setattr(self, attr, d[attr])
-
-    def parse_content(self):
-        """
-        Creates numerical lists for all primitives in the aperture
-        macro (in ``self.raw``) by replacing all variables by their
-        values iteratively and evaluating expressions. Results
-        are stored in ``self.primitives``.
-
-        :return: None
-        """
-        # Cleanup
-        self.raw = self.raw.replace('\n', '').replace('\r', '').strip(" *")
-        self.primitives = []
-
-        # Separate parts
-        parts = self.raw.split('*')
-
-        # ### Every part in the macro ####
-        for part in parts:
-            # ## Comments. Ignored.
-            match = ApertureMacro.amcomm_re.search(part)
-            if match:
-                continue
-
-            # ## Variables
-            # These are variables defined locally inside the macro. They can be
-            # numerical constant or defind in terms of previously define
-            # variables, which can be defined locally or in an aperture
-            # definition. All replacements ocurr here.
-            match = ApertureMacro.amvar_re.search(part)
-            if match:
-                var = match.group(1)
-                val = match.group(2)
-
-                # Replace variables in value
-                for v in self.locvars:
-                    # replaced the following line with the next to fix Mentor custom apertures not parsed OK
-                    # val = re.sub((r'\$'+str(v)+r'(?![0-9a-zA-Z])'), str(self.locvars[v]), val)
-                    val = val.replace('$' + str(v), str(self.locvars[v]))
-
-                # Make all others 0
-                val = re.sub(r'\$[0-9a-zA-Z](?![0-9a-zA-Z])', "0", val)
-                # Change x with *
-                val = re.sub(r'[xX]', "*", val)
-
-                # Eval() and store.
-                self.locvars[var] = eval(val)
-                continue
-
-            # ## Primitives
-            # Each is an array. The first identifies the primitive, while the
-            # rest depend on the primitive. All are strings representing a
-            # number and may contain variable definition. The values of these
-            # variables are defined in an aperture definition.
-            match = ApertureMacro.amprim_re.search(part)
-            if match:
-                # ## Replace all variables
-                for v in self.locvars:
-                    # replaced the following line with the next to fix Mentor custom apertures not parsed OK
-                    # part = re.sub(r'\$' + str(v) + r'(?![0-9a-zA-Z])', str(self.locvars[v]), part)
-                    part = part.replace('$' + str(v), str(self.locvars[v]))
-
-                # Make all others 0
-                part = re.sub(r'\$[0-9a-zA-Z](?![0-9a-zA-Z])', "0", part)
-
-                # Change x with *
-                part = re.sub(r'[xX]', "*", part)
-
-                # ## Store
-                elements = part.split(",")
-                self.primitives.append([eval(x) for x in elements])
-                continue
-
-            log.warning("Unknown syntax of aperture macro part: %s" % str(part))
-
-    def append(self, data):
-        """
-        Appends a string to the raw macro.
-
-        :param data: Part of the macro.
-        :type data: str
-        :return: None
-        """
-        self.raw += data
-
-    @staticmethod
-    def default2zero(n, mods):
-        """
-        Pads the ``mods`` list with zeros resulting in an
-        list of length n.
-
-        :param n: Length of the resulting list.
-        :type n: int
-        :param mods: List to be padded.
-        :type mods: list
-        :return: Zero-padded list.
-        :rtype: list
-        """
-        x = [0.0] * n
-        na = len(mods)
-        x[0:na] = mods
-        return x
-
-    @staticmethod
-    def make_circle(mods):
-        """
-
-        :param mods: (Exposure 0/1, Diameter >=0, X-coord, Y-coord)
-        :return:
-        """
-
-        pol, dia, x, y = ApertureMacro.default2zero(4, mods)
-
-        return {"pol": int(pol), "geometry": Point(x, y).buffer(dia/2)}
-
-    @staticmethod
-    def make_vectorline(mods):
-        """
-
-        :param mods: (Exposure 0/1, Line width >= 0, X-start, Y-start, X-end, Y-end,
-            rotation angle around origin in degrees)
-        :return:
-        """
-        pol, width, xs, ys, xe, ye, angle = ApertureMacro.default2zero(7, mods)
-
-        line = LineString([(xs, ys), (xe, ye)])
-        box = line.buffer(width/2, cap_style=2)
-        box_rotated = affinity.rotate(box, angle, origin=(0, 0))
-
-        return {"pol": int(pol), "geometry": box_rotated}
-
-    @staticmethod
-    def make_centerline(mods):
-        """
-
-        :param mods: (Exposure 0/1, width >=0, height >=0, x-center, y-center,
-            rotation angle around origin in degrees)
-        :return:
-        """
-
-        pol, width, height, x, y, angle = ApertureMacro.default2zero(6, mods)
-
-        box = shply_box(x-width/2, y-height/2, x+width/2, y+height/2)
-        box_rotated = affinity.rotate(box, angle, origin=(0, 0))
-
-        return {"pol": int(pol), "geometry": box_rotated}
-
-    @staticmethod
-    def make_lowerleftline(mods):
-        """
-
-        :param mods: (exposure 0/1, width >=0, height >=0, x-lowerleft, y-lowerleft,
-            rotation angle around origin in degrees)
-        :return:
-        """
-
-        pol, width, height, x, y, angle = ApertureMacro.default2zero(6, mods)
-
-        box = shply_box(x, y, x+width, y+height)
-        box_rotated = affinity.rotate(box, angle, origin=(0, 0))
-
-        return {"pol": int(pol), "geometry": box_rotated}
-
-    @staticmethod
-    def make_outline(mods):
-        """
-
-        :param mods:
-        :return:
-        """
-
-        pol = mods[0]
-        n = mods[1]
-        points = [(0, 0)]*(n+1)
-
-        for i in range(n+1):
-            points[i] = mods[2*i + 2:2*i + 4]
-
-        angle = mods[2*n + 4]
-
-        poly = Polygon(points)
-        poly_rotated = affinity.rotate(poly, angle, origin=(0, 0))
-
-        return {"pol": int(pol), "geometry": poly_rotated}
-
-    @staticmethod
-    def make_polygon(mods):
-        """
-        Note: Specs indicate that rotation is only allowed if the center
-        (x, y) == (0, 0). I will tolerate breaking this rule.
-
-        :param mods: (exposure 0/1, n_verts 3<=n<=12, x-center, y-center,
-            diameter of circumscribed circle >=0, rotation angle around origin)
-        :return:
-        """
-
-        pol, nverts, x, y, dia, angle = ApertureMacro.default2zero(6, mods)
-        points = [(0, 0)]*nverts
-
-        for i in range(nverts):
-            points[i] = (x + 0.5 * dia * cos(2*pi * i/nverts),
-                         y + 0.5 * dia * sin(2*pi * i/nverts))
-
-        poly = Polygon(points)
-        poly_rotated = affinity.rotate(poly, angle, origin=(0, 0))
-
-        return {"pol": int(pol), "geometry": poly_rotated}
-
-    @staticmethod
-    def make_moire(mods):
-        """
-        Note: Specs indicate that rotation is only allowed if the center
-        (x, y) == (0, 0). I will tolerate breaking this rule.
-
-        :param mods: (x-center, y-center, outer_dia_outer_ring, ring thickness,
-            gap, max_rings, crosshair_thickness, crosshair_len, rotation
-            angle around origin in degrees)
-        :return:
-        """
-
-        x, y, dia, thickness, gap, nrings, cross_th, cross_len, angle = ApertureMacro.default2zero(9, mods)
-
-        r = dia/2 - thickness/2
-        result = Point((x, y)).buffer(r).exterior.buffer(thickness/2.0)
-        ring = Point((x, y)).buffer(r).exterior.buffer(thickness/2.0)  # Need a copy!
-
-        i = 1  # Number of rings created so far
-
-        # ## If the ring does not have an interior it means that it is
-        # ## a disk. Then stop.
-        while len(ring.interiors) > 0 and i < nrings:
-            r -= thickness + gap
-            if r <= 0:
-                break
-            ring = Point((x, y)).buffer(r).exterior.buffer(thickness/2.0)
-            result = cascaded_union([result, ring])
-            i += 1
-
-        # ## Crosshair
-        hor = LineString([(x - cross_len, y), (x + cross_len, y)]).buffer(cross_th/2.0, cap_style=2)
-        ver = LineString([(x, y-cross_len), (x, y + cross_len)]).buffer(cross_th/2.0, cap_style=2)
-        result = cascaded_union([result, hor, ver])
-
-        return {"pol": 1, "geometry": result}
-
-    @staticmethod
-    def make_thermal(mods):
-        """
-        Note: Specs indicate that rotation is only allowed if the center
-        (x, y) == (0, 0). I will tolerate breaking this rule.
-
-        :param mods: [x-center, y-center, diameter-outside, diameter-inside,
-            gap-thickness, rotation angle around origin]
-        :return:
-        """
-
-        x, y, dout, din, t, angle = ApertureMacro.default2zero(6, mods)
-
-        ring = Point((x, y)).buffer(dout/2.0).difference(Point((x, y)).buffer(din/2.0))
-        hline = LineString([(x - dout/2.0, y), (x + dout/2.0, y)]).buffer(t/2.0, cap_style=3)
-        vline = LineString([(x, y - dout/2.0), (x, y + dout/2.0)]).buffer(t/2.0, cap_style=3)
-        thermal = ring.difference(hline.union(vline))
-
-        return {"pol": 1, "geometry": thermal}
-
-    def make_geometry(self, modifiers):
-        """
-        Runs the macro for the given modifiers and generates
-        the corresponding geometry.
-
-        :param modifiers: Modifiers (parameters) for this macro
-        :type modifiers: list
-        :return: Shapely geometry
-        :rtype: shapely.geometry.polygon
-        """
-
-        # ## Primitive makers
-        makers = {
-            "1": ApertureMacro.make_circle,
-            "2": ApertureMacro.make_vectorline,
-            "20": ApertureMacro.make_vectorline,
-            "21": ApertureMacro.make_centerline,
-            "22": ApertureMacro.make_lowerleftline,
-            "4": ApertureMacro.make_outline,
-            "5": ApertureMacro.make_polygon,
-            "6": ApertureMacro.make_moire,
-            "7": ApertureMacro.make_thermal
-        }
-
-        # ## Store modifiers as local variables
-        modifiers = modifiers or []
-        modifiers = [float(m) for m in modifiers]
-        self.locvars = {}
-        for i in range(0, len(modifiers)):
-            self.locvars[str(i + 1)] = modifiers[i]
-
-        # ## Parse
-        self.primitives = []  # Cleanup
-        self.geometry = Polygon()
-        self.parse_content()
-
-        # ## Make the geometry
-        for primitive in self.primitives:
-            # Make the primitive
-            prim_geo = makers[str(int(primitive[0]))](primitive[1:])
-
-            # Add it (according to polarity)
-            # if self.geometry is None and prim_geo['pol'] == 1:
-            #     self.geometry = prim_geo['geometry']
-            #     continue
-            if prim_geo['pol'] == 1:
-                self.geometry = self.geometry.union(prim_geo['geometry'])
-                continue
-            if prim_geo['pol'] == 0:
-                self.geometry = self.geometry.difference(prim_geo['geometry'])
-                continue
-
-        return self.geometry

+ 18 - 16
tests/frameless_window.py

@@ -3,10 +3,11 @@ from PyQt5 import QtGui, QtWidgets
 from PyQt5 import QtCore
 from PyQt5 import QtCore
 from PyQt5.QtCore import Qt
 from PyQt5.QtCore import Qt
 
 
+
 class TitleBar(QtWidgets.QDialog):
 class TitleBar(QtWidgets.QDialog):
     def __init__(self, parent=None):
     def __init__(self, parent=None):
         QtWidgets.QWidget.__init__(self, parent)
         QtWidgets.QWidget.__init__(self, parent)
-        self.setWindowFlags(Qt.FramelessWindowHint);
+        self.setWindowFlags(Qt.FramelessWindowHint)
         css = """
         css = """
         QWidget{
         QWidget{
             Background: #AA00AA;
             Background: #AA00AA;
@@ -60,19 +61,19 @@ class TitleBar(QtWidgets.QDialog):
         self.maximize.clicked.connect(self.showMaxRestore)
         self.maximize.clicked.connect(self.showMaxRestore)
 
 
     def showSmall(self):
     def showSmall(self):
-        box.showMinimized();
+        box.showMinimized()
 
 
     def showMaxRestore(self):
     def showMaxRestore(self):
         if(self.maxNormal):
         if(self.maxNormal):
-            box.showNormal();
-            self.maxNormal= False;
-            self.maximize.setIcon(QtGui.QIcon('img/max.png'));
+            box.showNormal()
+            self.maxNormal= False
+            self.maximize.setIcon(QtGui.QIcon('img/max.png'))
             print(1)
             print(1)
         else:
         else:
-            box.showMaximized();
-            self.maxNormal=  True;
+            box.showMaximized()
+            self.maxNormal=  True
             print(2)
             print(2)
-            self.maximize.setIcon(QtGui.QIcon('img/max2.png'));
+            self.maximize.setIcon(QtGui.QIcon('img/max2.png'))
 
 
     def close(self):
     def close(self):
         box.close()
         box.close()
@@ -88,7 +89,7 @@ class TitleBar(QtWidgets.QDialog):
 class Frame(QtWidgets.QFrame):
 class Frame(QtWidgets.QFrame):
     def __init__(self, parent=None):
     def __init__(self, parent=None):
         QtWidgets.QFrame.__init__(self, parent)
         QtWidgets.QFrame.__init__(self, parent)
-        self.m_mouse_down= False;
+        self.m_mouse_down= False
         self.setFrameShape(QtWidgets.QFrame.StyledPanel)
         self.setFrameShape(QtWidgets.QFrame.StyledPanel)
         css = """
         css = """
         QFrame{
         QFrame{
@@ -122,25 +123,26 @@ class Frame(QtWidgets.QFrame):
         return self.m_titleBar
         return self.m_titleBar
 
 
     def mousePressEvent(self,event):
     def mousePressEvent(self,event):
-        self.m_old_pos = event.pos();
-        self.m_mouse_down = event.button()== Qt.LeftButton;
+        self.m_old_pos = event.pos()
+        self.m_mouse_down = event.button()== Qt.LeftButton
 
 
     def mouseMoveEvent(self,event):
     def mouseMoveEvent(self,event):
         x=event.x()
         x=event.x()
         y=event.y()
         y=event.y()
 
 
     def mouseReleaseEvent(self,event):
     def mouseReleaseEvent(self,event):
-        m_mouse_down=False;
+        m_mouse_down=False
+
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':
-    app = QtWidgets.QApplication(sys.argv);
+    app = QtWidgets.QApplication(sys.argv)
     box = Frame()
     box = Frame()
     box.move(60,60)
     box.move(60,60)
-    l=QtWidgets.QVBoxLayout(box.contentWidget());
+    l = QtWidgets.QVBoxLayout(box.contentWidget())
     l.setContentsMargins(0, 0,0 ,0)
     l.setContentsMargins(0, 0,0 ,0)
-    edit=QtWidgets.QLabel("""I would've did anything for you to show you how much I adored you
+    edit = QtWidgets.QLabel("""I would've did anything for you to show you how much I adored you
 But it's over now, it's too late to save our loveJust promise me you'll think of me
 But it's over now, it's too late to save our loveJust promise me you'll think of me
-Every time you look up in the sky and see a star 'cuz I'm  your star.""");
+Every time you look up in the sky and see a star 'cuz I'm  your star.""")
     l.addWidget(edit)
     l.addWidget(edit)
     box.show()
     box.show()
     app.exec_()
     app.exec_()

+ 1 - 1
tests/gerber_parsing_profiling/gerber_parsing_line_profile_1.py

@@ -4,7 +4,7 @@
 import sys
 import sys
 sys.path.append('../../')
 sys.path.append('../../')
 
 
-from camlib import *
+from flatcamParsers.ParseGerber import *
 
 
 log = logging.getLogger('base2')
 log = logging.getLogger('base2')
 log.setLevel(logging.WARNING)
 log.setLevel(logging.WARNING)

+ 1 - 1
tests/gerber_parsing_profiling/gerber_parsing_profile_1.py

@@ -3,7 +3,7 @@ import pstats
 import sys
 import sys
 sys.path.append('../../')
 sys.path.append('../../')
 
 
-from camlib import *
+from flatcamParsers.ParseGerber import *
 
 
 log = logging.getLogger('base2')
 log = logging.getLogger('base2')
 log.setLevel(logging.WARNING)
 log.setLevel(logging.WARNING)

+ 5 - 0
tests/new_window_test.py

@@ -2,6 +2,7 @@ import sys
 from PyQt5.Qt import *
 from PyQt5.Qt import *
 from PyQt5 import QtGui, QtWidgets
 from PyQt5 import QtGui, QtWidgets
 
 
+
 class MyPopup(QWidget):
 class MyPopup(QWidget):
     def __init__(self):
     def __init__(self):
         QWidget.__init__(self)
         QWidget.__init__(self)
@@ -30,6 +31,7 @@ class MyPopup(QWidget):
     #     dc.drawLine(0, 0, 100, 100)
     #     dc.drawLine(0, 0, 100, 100)
     #     dc.drawLine(100, 0, 0, 100)
     #     dc.drawLine(100, 0, 0, 100)
 
 
+
 class MainWindow(QMainWindow):
 class MainWindow(QMainWindow):
     def __init__(self, *args):
     def __init__(self, *args):
         QtWidgets.QMainWindow.__init__(self, *args)
         QtWidgets.QMainWindow.__init__(self, *args)
@@ -46,6 +48,7 @@ class MainWindow(QMainWindow):
         self.w.setGeometry(QRect(100, 100, 400, 200))
         self.w.setGeometry(QRect(100, 100, 400, 200))
         self.w.show()
         self.w.show()
 
 
+
 class App(QApplication):
 class App(QApplication):
     def __init__(self, *args):
     def __init__(self, *args):
         QtWidgets.QApplication.__init__(self, *args)
         QtWidgets.QApplication.__init__(self, *args)
@@ -56,10 +59,12 @@ class App(QApplication):
     def byebye(self):
     def byebye(self):
         self.exit(0)
         self.exit(0)
 
 
+
 def main(args):
 def main(args):
     global app
     global app
     app = App(args)
     app = App(args)
     app.exec_()
     app.exec_()
 
 
+
 if __name__ == "__main__":
 if __name__ == "__main__":
     main(sys.argv)
     main(sys.argv)

+ 4 - 4
tests/other/destructor_test.py

@@ -1,5 +1,5 @@
 import sys
 import sys
-from PyQt4 import QtCore, QtGui
+from PyQt5 import QtCore, QtGui, QtWidgets
 
 
 
 
 class MyObj():
 class MyObj():
@@ -16,12 +16,12 @@ def parse():
     raise Exception("Intentional Exception")
     raise Exception("Intentional Exception")
 
 
 
 
-class Example(QtGui.QWidget):
+class Example(QtWidgets.QWidget):
 
 
     def __init__(self):
     def __init__(self):
         super(Example, self).__init__()
         super(Example, self).__init__()
 
 
-        qbtn = QtGui.QPushButton('Raise', self)
+        qbtn = QtWidgets.QPushButton('Raise', self)
         qbtn.clicked.connect(parse)
         qbtn.clicked.connect(parse)
 
 
         self.setWindowTitle('Quit button')
         self.setWindowTitle('Quit button')
@@ -29,6 +29,6 @@ class Example(QtGui.QWidget):
 
 
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':
-    app = QtGui.QApplication(sys.argv)
+    app = QtWidgets.QApplication(sys.argv)
     ex = Example()
     ex = Example()
     sys.exit(app.exec_())
     sys.exit(app.exec_())

+ 1 - 1
tests/other/profile_gerber_parser.py

@@ -1,7 +1,7 @@
 import os
 import os
 os.chdir('../')
 os.chdir('../')
 
 
-from camlib import *
+from flatcamParsers.ParseGerber import *
 
 
 g = Gerber()
 g = Gerber()
 g.parse_file(r'C:\Users\jpcaram\Dropbox\CNC\pcbcam\test_files\PlacaReles-F_Cu.gtl')
 g.parse_file(r'C:\Users\jpcaram\Dropbox\CNC\pcbcam\test_files\PlacaReles-F_Cu.gtl')

+ 6 - 5
tests/other/test_excellon_1.py

@@ -8,12 +8,13 @@ Created on Sun Jan 05 13:30:47 2014
 import os
 import os
 os.chdir('../')
 os.chdir('../')
 
 
-from camlib import *
-#from matplotlib.figure import Figure
+from flatcamParsers.ParseGerber import *
+from flatcamParsers.ParseExcellon import *
+
 from matplotlib import pyplot
 from matplotlib import pyplot
 
 
 # Gerber. To see if the Excellon is correct
 # Gerber. To see if the Excellon is correct
-project_dir = "tests/"
+project_dir = "tests/gerber_files"
 gerber_filename = project_dir + "KiCad_Squarer-F_Cu.gtl"
 gerber_filename = project_dir + "KiCad_Squarer-F_Cu.gtl"
 g = Gerber()
 g = Gerber()
 g.parse_file(gerber_filename)
 g.parse_file(gerber_filename)
@@ -32,7 +33,7 @@ ax.set_aspect(1)
 # Plot gerber
 # Plot gerber
 for geo in g.solid_geometry:
 for geo in g.solid_geometry:
     x, y = geo.exterior.coords.xy
     x, y = geo.exterior.coords.xy
-    plot(x, y, 'k-')
+    pyplot.plot(x, y, 'k-')
     for ints in geo.interiors:
     for ints in geo.interiors:
         x, y = ints.coords.xy
         x, y = ints.coords.xy
         ax.plot(x, y, 'k-')
         ax.plot(x, y, 'k-')
@@ -40,7 +41,7 @@ for geo in g.solid_geometry:
 # Plot excellon
 # Plot excellon
 for geo in ex.solid_geometry:
 for geo in ex.solid_geometry:
     x, y = geo.exterior.coords.xy
     x, y = geo.exterior.coords.xy
-    plot(x, y, 'r-')
+    pyplot.plot(x, y, 'r-')
     for ints in geo.interiors:
     for ints in geo.interiors:
         x, y = ints.coords.xy
         x, y = ints.coords.xy
         ax.plot(x, y, 'g-')
         ax.plot(x, y, 'g-')

+ 2 - 1
tests/other/test_plotg.py

@@ -1,6 +1,7 @@
 from shapely.geometry import LineString, Polygon
 from shapely.geometry import LineString, Polygon
 from shapely.ops import cascaded_union, unary_union
 from shapely.ops import cascaded_union, unary_union
-from matplotlib.pyplot import plot, subplot, show
+from matplotlib.pyplot import plot, subplot, show, axes
+from matplotlib.axes import *
 from camlib import *
 from camlib import *
 
 
 
 

+ 26 - 25
tests/test_excellon.py

@@ -1,5 +1,6 @@
 import unittest
 import unittest
-import camlib
+from flatcamParsers.ParseExcellon import Excellon
+from flatcamParsers.ParseGerber import Gerber
 
 
 
 
 class ExcellonNumberParseTestInch(unittest.TestCase):
 class ExcellonNumberParseTestInch(unittest.TestCase):
@@ -16,39 +17,39 @@ class ExcellonNumberParseTestInch(unittest.TestCase):
     # of digits you typed and automatically fill in the missing zeros.
     # of digits you typed and automatically fill in the missing zeros.
 
 
     def test_inch_leading_6digit(self):
     def test_inch_leading_6digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         self.assertEqual(excellon.zeros, "L")
         self.assertEqual(excellon.zeros, "L")
         self.assertEqual(excellon.parse_number("123456"), 12.3456)
         self.assertEqual(excellon.parse_number("123456"), 12.3456)
 
 
     def test_inch_leading_5digit(self):
     def test_inch_leading_5digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         self.assertEqual(excellon.parse_number("12345"), 12.345)
         self.assertEqual(excellon.parse_number("12345"), 12.345)
 
 
     def test_inch_leading_15digit(self):
     def test_inch_leading_15digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         self.assertEqual(excellon.parse_number("012345"), 1.2345)
         self.assertEqual(excellon.parse_number("012345"), 1.2345)
 
 
     def test_inch_leading_51digit(self):
     def test_inch_leading_51digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         self.assertEqual(excellon.parse_number("123450"), 12.345)
         self.assertEqual(excellon.parse_number("123450"), 12.345)
 
 
     def test_inch_trailing_6digit(self):
     def test_inch_trailing_6digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         excellon.zeros = "T"
         excellon.zeros = "T"
         self.assertEqual(excellon.parse_number("123456"), 12.3456)
         self.assertEqual(excellon.parse_number("123456"), 12.3456)
 
 
     def test_inch_trailing_5digit(self):
     def test_inch_trailing_5digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         excellon.zeros = "T"
         excellon.zeros = "T"
         self.assertEqual(excellon.parse_number("12345"), 1.2345)
         self.assertEqual(excellon.parse_number("12345"), 1.2345)
 
 
     def test_inch_trailing_15digit(self):
     def test_inch_trailing_15digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         excellon.zeros = "T"
         excellon.zeros = "T"
         self.assertEqual(excellon.parse_number("012345"), 1.2345)
         self.assertEqual(excellon.parse_number("012345"), 1.2345)
 
 
     def test_inch_trailing_51digit(self):
     def test_inch_trailing_51digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         excellon.zeros = "T"
         excellon.zeros = "T"
         self.assertEqual(excellon.parse_number("123450"), 12.345)
         self.assertEqual(excellon.parse_number("123450"), 12.345)
 
 
@@ -67,45 +68,45 @@ class ExcellonNumberParseTestMetric(unittest.TestCase):
     # of digits you typed and automatically fill in the missing zeros.
     # of digits you typed and automatically fill in the missing zeros.
 
 
     def test_inch_leading_6digit(self):
     def test_inch_leading_6digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         excellon.units = "mm"
         excellon.units = "mm"
         self.assertEqual(excellon.parse_number("123456"), 123.456)
         self.assertEqual(excellon.parse_number("123456"), 123.456)
 
 
     def test_inch_leading_5digit(self):
     def test_inch_leading_5digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         excellon.units = "mm"
         excellon.units = "mm"
         self.assertEqual(excellon.parse_number("12345"), 123.45)
         self.assertEqual(excellon.parse_number("12345"), 123.45)
 
 
     def test_inch_leading_15digit(self):
     def test_inch_leading_15digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         excellon.units = "mm"
         excellon.units = "mm"
         self.assertEqual(excellon.parse_number("012345"), 12.345)
         self.assertEqual(excellon.parse_number("012345"), 12.345)
 
 
     def test_inch_leading_51digit(self):
     def test_inch_leading_51digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         excellon.units = "mm"
         excellon.units = "mm"
         self.assertEqual(excellon.parse_number("123450"), 123.45)
         self.assertEqual(excellon.parse_number("123450"), 123.45)
 
 
     def test_inch_trailing_6digit(self):
     def test_inch_trailing_6digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         excellon.units = "mm"
         excellon.units = "mm"
         excellon.zeros = "T"
         excellon.zeros = "T"
         self.assertEqual(excellon.parse_number("123456"), 123.456)
         self.assertEqual(excellon.parse_number("123456"), 123.456)
 
 
     def test_inch_trailing_5digit(self):
     def test_inch_trailing_5digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         excellon.units = "mm"
         excellon.units = "mm"
         excellon.zeros = "T"
         excellon.zeros = "T"
         self.assertEqual(excellon.parse_number("12345"), 12.345)
         self.assertEqual(excellon.parse_number("12345"), 12.345)
 
 
     def test_inch_trailing_15digit(self):
     def test_inch_trailing_15digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         excellon.units = "mm"
         excellon.units = "mm"
         excellon.zeros = "T"
         excellon.zeros = "T"
         self.assertEqual(excellon.parse_number("012345"), 12.345)
         self.assertEqual(excellon.parse_number("012345"), 12.345)
 
 
     def test_inch_trailing_51digit(self):
     def test_inch_trailing_51digit(self):
-        excellon = camlib.Excellon()
+        excellon = Excellon()
         excellon.units = "mm"
         excellon.units = "mm"
         excellon.zeros = "T"
         excellon.zeros = "T"
         self.assertEqual(excellon.parse_number("123450"), 123.45)
         self.assertEqual(excellon.parse_number("123450"), 123.45)
@@ -114,7 +115,7 @@ class ExcellonNumberParseTestMetric(unittest.TestCase):
 class ExcellonFormatM72Test(unittest.TestCase):
 class ExcellonFormatM72Test(unittest.TestCase):
 
 
     def setUp(self):
     def setUp(self):
-        self.excellon = camlib.Excellon()
+        self.excellon = Excellon()
         code = """
         code = """
         M48
         M48
         M72
         M72
@@ -141,7 +142,7 @@ class ExcellonFormatM72Test(unittest.TestCase):
 class ExcellonFormatM71Test(unittest.TestCase):
 class ExcellonFormatM71Test(unittest.TestCase):
 
 
     def setUp(self):
     def setUp(self):
-        self.excellon = camlib.Excellon()
+        self.excellon = Excellon()
         code = """
         code = """
         M48
         M48
         M71
         M71
@@ -168,7 +169,7 @@ class ExcellonFormatM71Test(unittest.TestCase):
 class ExcellonFormatINCHLZTest(unittest.TestCase):
 class ExcellonFormatINCHLZTest(unittest.TestCase):
 
 
     def setUp(self):
     def setUp(self):
-        self.excellon = camlib.Excellon()
+        self.excellon = Excellon()
         code = """
         code = """
         M48
         M48
         INCH,LZ
         INCH,LZ
@@ -195,7 +196,7 @@ class ExcellonFormatINCHLZTest(unittest.TestCase):
 class ExcellonFormatINCHTest(unittest.TestCase):
 class ExcellonFormatINCHTest(unittest.TestCase):
 
 
     def setUp(self):
     def setUp(self):
-        self.excellon = camlib.Excellon()
+        self.excellon = Excellon()
         code = """
         code = """
         M48
         M48
         INCH,LZ
         INCH,LZ
@@ -222,7 +223,7 @@ class ExcellonFormatINCHTest(unittest.TestCase):
 class ExcellonFormatINCHTZTest(unittest.TestCase):
 class ExcellonFormatINCHTZTest(unittest.TestCase):
 
 
     def setUp(self):
     def setUp(self):
-        self.excellon = camlib.Excellon()
+        self.excellon = Excellon()
         code = """
         code = """
         M48
         M48
         INCH,TZ
         INCH,TZ
@@ -249,7 +250,7 @@ class ExcellonFormatINCHTZTest(unittest.TestCase):
 class ExcellonFormatMETRICLZTest(unittest.TestCase):
 class ExcellonFormatMETRICLZTest(unittest.TestCase):
 
 
     def setUp(self):
     def setUp(self):
-        self.excellon = camlib.Excellon()
+        self.excellon = Excellon()
         code = """
         code = """
         M48
         M48
         METRIC,LZ
         METRIC,LZ
@@ -276,7 +277,7 @@ class ExcellonFormatMETRICLZTest(unittest.TestCase):
 class ExcellonFormatMETRICTest(unittest.TestCase):
 class ExcellonFormatMETRICTest(unittest.TestCase):
 
 
     def setUp(self):
     def setUp(self):
-        self.excellon = camlib.Excellon()
+        self.excellon = Excellon()
         code = """
         code = """
         M48
         M48
         METRIC,LZ
         METRIC,LZ
@@ -303,7 +304,7 @@ class ExcellonFormatMETRICTest(unittest.TestCase):
 class ExcellonFormatMETRICTZTest(unittest.TestCase):
 class ExcellonFormatMETRICTZTest(unittest.TestCase):
 
 
     def setUp(self):
     def setUp(self):
-        self.excellon = camlib.Excellon()
+        self.excellon = Excellon()
         code = """
         code = """
         M48
         M48
         METRIC,TZ
         METRIC,TZ

+ 17 - 17
tests/test_excellon_flow.py

@@ -1,9 +1,9 @@
 import unittest
 import unittest
-from PyQt4 import QtGui
+from PyQt5 import QtGui, QtWidgets
 import sys
 import sys
 from FlatCAMApp import App
 from FlatCAMApp import App
 from FlatCAMObj import FlatCAMExcellon, FlatCAMCNCjob
 from FlatCAMObj import FlatCAMExcellon, FlatCAMCNCjob
-from ObjectUI import ExcellonObjectUI
+from flatcamGUI.ObjectUI import ExcellonObjectUI
 import tempfile
 import tempfile
 import os
 import os
 from time import sleep
 from time import sleep
@@ -21,7 +21,7 @@ class ExcellonFlowTestCase(unittest.TestCase):
     filename = 'case1.drl'
     filename = 'case1.drl'
 
 
     def setUp(self):
     def setUp(self):
-        self.app = QtGui.QApplication(sys.argv)
+        self.app = QtWidgets.QApplication(sys.argv)
 
 
         # Create App, keep app defaults (do not load
         # Create App, keep app defaults (do not load
         # user-defined defaults).
         # user-defined defaults).
@@ -79,19 +79,19 @@ class ExcellonFlowTestCase(unittest.TestCase):
                                  option, value, form_field.get_value()
                                  option, value, form_field.get_value()
                              ))
                              ))
 
 
-        #--------------------------------------------------
+        # --------------------------------------------------
         # Changes in the GUI should be read in when
         # Changes in the GUI should be read in when
         # running any process. Changing something here.
         # running any process. Changing something here.
-        #--------------------------------------------------
+        # --------------------------------------------------
 
 
         form_field = excellon_obj.form_fields['feedrate']
         form_field = excellon_obj.form_fields['feedrate']
         value = form_field.get_value()
         value = form_field.get_value()
         form_field.set_value(value * 1.1)  # Increase by 10%
         form_field.set_value(value * 1.1)  # Increase by 10%
         print(("'feedrate' == {}".format(value)))
         print(("'feedrate' == {}".format(value)))
 
 
-        #--------------------------------------------------
+        # --------------------------------------------------
         # Create GCode using all tools.
         # Create GCode using all tools.
-        #--------------------------------------------------
+        # --------------------------------------------------
 
 
         assert isinstance(excellon_obj, FlatCAMExcellon)  # Just for the IDE
         assert isinstance(excellon_obj, FlatCAMExcellon)  # Just for the IDE
         ui = excellon_obj.ui
         ui = excellon_obj.ui
@@ -110,9 +110,9 @@ class ExcellonFlowTestCase(unittest.TestCase):
             sleep(0.1)
             sleep(0.1)
             self.app.processEvents()
             self.app.processEvents()
 
 
-        #---------------------------------------------
+        # ---------------------------------------------
         # Check that GUI has been read in.
         # Check that GUI has been read in.
-        #---------------------------------------------
+        # ---------------------------------------------
 
 
         value = excellon_obj.options['feedrate']
         value = excellon_obj.options['feedrate']
         form_value = form_field.get_value()
         form_value = form_field.get_value()
@@ -121,33 +121,33 @@ class ExcellonFlowTestCase(unittest.TestCase):
                          "which has {}".format('feedrate', form_value, value))
                          "which has {}".format('feedrate', form_value, value))
         print(("'feedrate' == {}".format(value)))
         print(("'feedrate' == {}".format(value)))
 
 
-        #---------------------------------------------
+        # ---------------------------------------------
         # Check that only 1 object has been created.
         # Check that only 1 object has been created.
-        #---------------------------------------------
+        # ---------------------------------------------
 
 
         names = self.fc.collection.get_names()
         names = self.fc.collection.get_names()
         self.assertEqual(len(names), 2,
         self.assertEqual(len(names), 2,
                          "Expected 2 objects, found %d" % len(names))
                          "Expected 2 objects, found %d" % len(names))
 
 
-        #-------------------------------------------------------
+        # -------------------------------------------------------
         # Make sure the CNCJob Object has the correct name
         # Make sure the CNCJob Object has the correct name
-        #-------------------------------------------------------
+        # -------------------------------------------------------
 
 
         cncjob_name = excellon_name + "_cnc"
         cncjob_name = excellon_name + "_cnc"
         self.assertTrue(cncjob_name in names,
         self.assertTrue(cncjob_name in names,
                         "Object named %s not found." % cncjob_name)
                         "Object named %s not found." % cncjob_name)
 
 
-        #-------------------------------------------------------
+        # -------------------------------------------------------
         # Get the object make sure it's a cncjob object
         # Get the object make sure it's a cncjob object
-        #-------------------------------------------------------
+        # -------------------------------------------------------
 
 
         cncjob_obj = self.fc.collection.get_by_name(cncjob_name)
         cncjob_obj = self.fc.collection.get_by_name(cncjob_name)
         self.assertTrue(isinstance(cncjob_obj, FlatCAMCNCjob),
         self.assertTrue(isinstance(cncjob_obj, FlatCAMCNCjob),
                         "Expected a FlatCAMCNCjob, got %s" % type(cncjob_obj))
                         "Expected a FlatCAMCNCjob, got %s" % type(cncjob_obj))
 
 
-        #-----------------------------------------
+        # -----------------------------------------
         # Export G-Code, check output
         # Export G-Code, check output
-        #-----------------------------------------
+        # -----------------------------------------
         assert isinstance(cncjob_obj, FlatCAMCNCjob)  # For IDE
         assert isinstance(cncjob_obj, FlatCAMCNCjob)  # For IDE
 
 
         # get system temporary file(try create it and delete)
         # get system temporary file(try create it and delete)

+ 4 - 3
tests/test_gerber_buffer.py

@@ -1,15 +1,16 @@
 import unittest
 import unittest
 import camlib
 import camlib
+from flatcamParsers.ParseGerber import Gerber
 
 
 
 
 class GerberBuffer(unittest.TestCase):
 class GerberBuffer(unittest.TestCase):
     def setUp(self):
     def setUp(self):
-        self.gerber1 = camlib.Gerber()
+        self.gerber1 = Gerber()
         self.gerber1.use_buffer_for_union = True
         self.gerber1.use_buffer_for_union = True
         self.gerber1.parse_file("tests/gerber_files/STM32F4-spindle.cmp")
         self.gerber1.parse_file("tests/gerber_files/STM32F4-spindle.cmp")
         geometry1 = self.gerber1.solid_geometry
         geometry1 = self.gerber1.solid_geometry
         self.geometry1_area = self.compute_area(geometry1)
         self.geometry1_area = self.compute_area(geometry1)
-        self.gerber2 = camlib.Gerber()
+        self.gerber2 = Gerber()
         self.gerber2.use_buffer_for_union = False
         self.gerber2.use_buffer_for_union = False
         self.gerber2.parse_file("tests/gerber_files/STM32F4-spindle.cmp")
         self.gerber2.parse_file("tests/gerber_files/STM32F4-spindle.cmp")
         geometry2 = self.gerber2.solid_geometry
         geometry2 = self.gerber2.solid_geometry
@@ -21,7 +22,7 @@ class GerberBuffer(unittest.TestCase):
             for geo in geometry:
             for geo in geometry:
                 area += geo.area
                 area += geo.area
 
 
-        ## Not iterable, do the actual indexing and add.
+        # Not iterable, do the actual indexing and add.
         except TypeError:
         except TypeError:
             area = geometry.area
             area = geometry.area
         return area
         return area

+ 33 - 33
tests/test_gerber_flow.py

@@ -1,9 +1,9 @@
 import sys
 import sys
 import unittest
 import unittest
-from PyQt4 import QtGui
+from PyQt5 import QtGui, QtWidgets
 from FlatCAMApp import App, tclCommands
 from FlatCAMApp import App, tclCommands
 from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMCNCjob
 from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMCNCjob
-from ObjectUI import GerberObjectUI, GeometryObjectUI
+from flatcamGUI.ObjectUI import GerberObjectUI, GeometryObjectUI
 from time import sleep
 from time import sleep
 import os
 import os
 import tempfile
 import tempfile
@@ -21,7 +21,7 @@ class GerberFlowTestCase(unittest.TestCase):
     filename = 'simple1.gbr'
     filename = 'simple1.gbr'
 
 
     def setUp(self):
     def setUp(self):
-        self.app = QtGui.QApplication(sys.argv)
+        self.app = QtWidgets.QApplication(sys.argv)
 
 
         # Create App, keep app defaults (do not load
         # Create App, keep app defaults (do not load
         # user-defined defaults).
         # user-defined defaults).
@@ -38,30 +38,30 @@ class GerberFlowTestCase(unittest.TestCase):
         names = self.fc.collection.get_names()
         names = self.fc.collection.get_names()
         print(names)
         print(names)
 
 
-        #--------------------------------------
+        # --------------------------------------
         # Total of 1 objects.
         # Total of 1 objects.
-        #--------------------------------------
+        # --------------------------------------
         self.assertEqual(len(names), 1,
         self.assertEqual(len(names), 1,
                           "Expected 1 object, found %d" % len(names))
                           "Expected 1 object, found %d" % len(names))
 
 
-        #--------------------------------------
+        # --------------------------------------
         # Object's name matches the file name.
         # Object's name matches the file name.
-        #--------------------------------------
+        # --------------------------------------
         self.assertEqual(names[0], self.filename,
         self.assertEqual(names[0], self.filename,
                           "Expected name == %s, got %s" % (self.filename, names[0]))
                           "Expected name == %s, got %s" % (self.filename, names[0]))
 
 
-        #---------------------------------------
+        # ---------------------------------------
         # Get object by that name, make sure it's a FlatCAMGerber.
         # Get object by that name, make sure it's a FlatCAMGerber.
-        #---------------------------------------
+        # ---------------------------------------
         gerber_name = names[0]
         gerber_name = names[0]
         gerber_obj = self.fc.collection.get_by_name(gerber_name)
         gerber_obj = self.fc.collection.get_by_name(gerber_name)
         self.assertTrue(isinstance(gerber_obj, FlatCAMGerber),
         self.assertTrue(isinstance(gerber_obj, FlatCAMGerber),
                         "Expected FlatCAMGerber, instead, %s is %s" %
                         "Expected FlatCAMGerber, instead, %s is %s" %
                         (gerber_name, type(gerber_obj)))
                         (gerber_name, type(gerber_obj)))
 
 
-        #----------------------------------------
+        # ----------------------------------------
         # Object's GUI matches Object's options
         # Object's GUI matches Object's options
-        #----------------------------------------
+        # ----------------------------------------
         # TODO: Open GUI with double-click on object.
         # TODO: Open GUI with double-click on object.
         # Opens the Object's GUI, populates it.
         # Opens the Object's GUI, populates it.
         gerber_obj.build_ui()
         gerber_obj.build_ui()
@@ -79,20 +79,20 @@ class GerberFlowTestCase(unittest.TestCase):
                                  option, value, form_field.get_value()
                                  option, value, form_field.get_value()
                              ))
                              ))
 
 
-        #--------------------------------------------------
+        # --------------------------------------------------
         # Changes in the GUI should be read in when
         # Changes in the GUI should be read in when
         # running any process. Changing something here.
         # running any process. Changing something here.
-        #--------------------------------------------------
+        # --------------------------------------------------
 
 
         form_field = gerber_obj.form_fields['isotooldia']
         form_field = gerber_obj.form_fields['isotooldia']
         value = form_field.get_value()
         value = form_field.get_value()
         form_field.set_value(value * 1.1)  # Increase by 10%
         form_field.set_value(value * 1.1)  # Increase by 10%
         print(("'isotooldia' == {}".format(value)))
         print(("'isotooldia' == {}".format(value)))
 
 
-        #--------------------------------------------------
+        # --------------------------------------------------
         # Create isolation routing using default values
         # Create isolation routing using default values
         # and by clicking on the button.
         # and by clicking on the button.
-        #--------------------------------------------------
+        # --------------------------------------------------
         # Get the object's GUI and click on "Generate Geometry" under
         # Get the object's GUI and click on "Generate Geometry" under
         # "Isolation Routing"
         # "Isolation Routing"
         assert isinstance(gerber_obj, FlatCAMGerber)  # Just for the IDE
         assert isinstance(gerber_obj, FlatCAMGerber)  # Just for the IDE
@@ -102,9 +102,9 @@ class GerberFlowTestCase(unittest.TestCase):
         assert isinstance(ui, GerberObjectUI)
         assert isinstance(ui, GerberObjectUI)
         ui.generate_iso_button.click()  # Click
         ui.generate_iso_button.click()  # Click
 
 
-        #---------------------------------------------
+        # ---------------------------------------------
         # Check that GUI has been read in.
         # Check that GUI has been read in.
-        #---------------------------------------------
+        # ---------------------------------------------
         value = gerber_obj.options['isotooldia']
         value = gerber_obj.options['isotooldia']
         form_value = form_field.get_value()
         form_value = form_field.get_value()
         self.assertEqual(value, form_value,
         self.assertEqual(value, form_value,
@@ -112,30 +112,30 @@ class GerberFlowTestCase(unittest.TestCase):
                          "which has {}".format('isotooldia', form_value, value))
                          "which has {}".format('isotooldia', form_value, value))
         print(("'isotooldia' == {}".format(value)))
         print(("'isotooldia' == {}".format(value)))
 
 
-        #---------------------------------------------
+        # ---------------------------------------------
         # Check that only 1 object has been created.
         # Check that only 1 object has been created.
-        #---------------------------------------------
+        # ---------------------------------------------
         names = self.fc.collection.get_names()
         names = self.fc.collection.get_names()
         self.assertEqual(len(names), 2,
         self.assertEqual(len(names), 2,
                          "Expected 2 objects, found %d" % len(names))
                          "Expected 2 objects, found %d" % len(names))
 
 
-        #-------------------------------------------------------
+        # -------------------------------------------------------
         # Make sure the Geometry Object has the correct name
         # Make sure the Geometry Object has the correct name
-        #-------------------------------------------------------
+        # -------------------------------------------------------
         geo_name = gerber_name + "_iso"
         geo_name = gerber_name + "_iso"
         self.assertTrue(geo_name in names,
         self.assertTrue(geo_name in names,
                         "Object named %s not found." % geo_name)
                         "Object named %s not found." % geo_name)
 
 
-        #-------------------------------------------------------
+        # -------------------------------------------------------
         # Get the object make sure it's a geometry object
         # Get the object make sure it's a geometry object
-        #-------------------------------------------------------
+        # -------------------------------------------------------
         geo_obj = self.fc.collection.get_by_name(geo_name)
         geo_obj = self.fc.collection.get_by_name(geo_name)
         self.assertTrue(isinstance(geo_obj, FlatCAMGeometry),
         self.assertTrue(isinstance(geo_obj, FlatCAMGeometry),
                         "Expected a FlatCAMGeometry, got %s" % type(geo_obj))
                         "Expected a FlatCAMGeometry, got %s" % type(geo_obj))
 
 
-        #------------------------------------
+        # ------------------------------------
         # Open the UI, make CNCObject
         # Open the UI, make CNCObject
-        #------------------------------------
+        # ------------------------------------
         geo_obj.build_ui()
         geo_obj.build_ui()
         ui = geo_obj.ui
         ui = geo_obj.ui
         assert isinstance(ui, GeometryObjectUI)  # Just for the IDE
         assert isinstance(ui, GeometryObjectUI)  # Just for the IDE
@@ -152,30 +152,30 @@ class GerberFlowTestCase(unittest.TestCase):
             sleep(0.1)
             sleep(0.1)
             self.app.processEvents()
             self.app.processEvents()
 
 
-        #---------------------------------------------
+        # ---------------------------------------------
         # Check that only 1 object has been created.
         # Check that only 1 object has been created.
-        #---------------------------------------------
+        # ---------------------------------------------
         names = self.fc.collection.get_names()
         names = self.fc.collection.get_names()
         self.assertEqual(len(names), 3,
         self.assertEqual(len(names), 3,
                          "Expected 3 objects, found %d" % len(names))
                          "Expected 3 objects, found %d" % len(names))
 
 
-        #-------------------------------------------------------
+        # -------------------------------------------------------
         # Make sure the CNC Job Object has the correct name
         # Make sure the CNC Job Object has the correct name
-        #-------------------------------------------------------
+        # -------------------------------------------------------
         cnc_name = geo_name + "_cnc"
         cnc_name = geo_name + "_cnc"
         self.assertTrue(cnc_name in names,
         self.assertTrue(cnc_name in names,
                         "Object named %s not found." % geo_name)
                         "Object named %s not found." % geo_name)
 
 
-        #-------------------------------------------------------
+        # -------------------------------------------------------
         # Get the object make sure it's a CNC Job object
         # Get the object make sure it's a CNC Job object
-        #-------------------------------------------------------
+        # -------------------------------------------------------
         cnc_obj = self.fc.collection.get_by_name(cnc_name)
         cnc_obj = self.fc.collection.get_by_name(cnc_name)
         self.assertTrue(isinstance(cnc_obj, FlatCAMCNCjob),
         self.assertTrue(isinstance(cnc_obj, FlatCAMCNCjob),
                         "Expected a FlatCAMCNCJob, got %s" % type(geo_obj))
                         "Expected a FlatCAMCNCJob, got %s" % type(geo_obj))
 
 
-        #-----------------------------------------
+        # -----------------------------------------
         # Export G-Code, check output
         # Export G-Code, check output
-        #-----------------------------------------
+        # -----------------------------------------
         assert isinstance(cnc_obj, FlatCAMCNCjob)
         assert isinstance(cnc_obj, FlatCAMCNCjob)
         output_filename = ""
         output_filename = ""
         # get system temporary file(try create it and  delete also)
         # get system temporary file(try create it and  delete also)

+ 1 - 0
tests/test_paint.py

@@ -3,6 +3,7 @@ import unittest
 from shapely.geometry import LineString, Polygon
 from shapely.geometry import LineString, Polygon
 from shapely.ops import cascaded_union, unary_union
 from shapely.ops import cascaded_union, unary_union
 from matplotlib.pyplot import plot, subplot, show, cla, clf, xlim, ylim, title
 from matplotlib.pyplot import plot, subplot, show, cla, clf, xlim, ylim, title
+from matplotlib.axes import *
 from camlib import *
 from camlib import *
 from copy import deepcopy
 from copy import deepcopy
 
 

+ 2 - 1
tests/test_pathconnect.py

@@ -84,5 +84,6 @@ class PathConnectTest1(unittest.TestCase):
         matches = [p for p in result if p.equals(LineString([[0, 0], [1, 1], [2, 1]]))]
         matches = [p for p in result if p.equals(LineString([[0, 0], [1, 1], [2, 1]]))]
         self.assertEqual(len(matches), 1)
         self.assertEqual(len(matches), 1)
 
 
+
 if __name__ == "__main__":
 if __name__ == "__main__":
-    unittest.main()
+    unittest.main()

+ 3 - 10
tests/test_polygon_paint.py

@@ -1,9 +1,9 @@
 import sys
 import sys
 import unittest
 import unittest
-from PyQt4 import QtGui
+from PyQt5 import QtGui, QtWidgets
 from FlatCAMApp import App
 from FlatCAMApp import App
 from FlatCAMObj import FlatCAMGeometry, FlatCAMCNCjob
 from FlatCAMObj import FlatCAMGeometry, FlatCAMCNCjob
-from ObjectUI import GerberObjectUI, GeometryObjectUI
+from flatcamGUI.ObjectUI import GerberObjectUI, GeometryObjectUI
 from time import sleep
 from time import sleep
 import os
 import os
 import tempfile
 import tempfile
@@ -13,7 +13,7 @@ from shapely.geometry import LineString, LinearRing, Polygon, MultiPolygon
 class PolyPaintTestCase(unittest.TestCase):
 class PolyPaintTestCase(unittest.TestCase):
 
 
     def setUp(self):
     def setUp(self):
-        self.app = QtGui.QApplication(sys.argv)
+        self.app = QtWidgets.QApplication(sys.argv)
 
 
         # Create App, keep app defaults (do not load
         # Create App, keep app defaults (do not load
         # user-defined defaults).
         # user-defined defaults).
@@ -218,10 +218,3 @@ class PolyPaintTestCase(unittest.TestCase):
             self.assertTrue(isinstance(geo, LineString))
             self.assertTrue(isinstance(geo, LineString))
             # Lots of points (Should be 1000s)
             # Lots of points (Should be 1000s)
             self.assertGreater(len(geo.coords), 2)
             self.assertGreater(len(geo.coords), 2)
-
-
-
-
-
-
-

+ 23 - 25
tests/test_svg_flow.py

@@ -1,9 +1,9 @@
 import sys
 import sys
 import unittest
 import unittest
-from PyQt4 import QtGui
+from PyQt5 import QtWidgets
 from FlatCAMApp import App
 from FlatCAMApp import App
 from FlatCAMObj import FlatCAMGeometry, FlatCAMCNCjob
 from FlatCAMObj import FlatCAMGeometry, FlatCAMCNCjob
-from ObjectUI import GerberObjectUI, GeometryObjectUI
+from flatcamGUI.ObjectUI import GerberObjectUI, GeometryObjectUI
 from time import sleep
 from time import sleep
 import os
 import os
 import tempfile
 import tempfile
@@ -12,7 +12,7 @@ import tempfile
 class SVGFlowTestCase(unittest.TestCase):
 class SVGFlowTestCase(unittest.TestCase):
 
 
     def setUp(self):
     def setUp(self):
-        self.app = QtGui.QApplication(sys.argv)
+        self.app = QtWidgets.QApplication(sys.argv)
 
 
         # Create App, keep app defaults (do not load
         # Create App, keep app defaults (do not load
         # user-defined defaults).
         # user-defined defaults).
@@ -31,30 +31,28 @@ class SVGFlowTestCase(unittest.TestCase):
         names = self.fc.collection.get_names()
         names = self.fc.collection.get_names()
         print(names)
         print(names)
 
 
-        #--------------------------------------
+        # --------------------------------------
         # Total of 1 objects.
         # Total of 1 objects.
-        #--------------------------------------
-        self.assertEqual(len(names), 1,
-                          "Expected 1 object, found %d" % len(names))
+        # --------------------------------------
+        self.assertEqual(len(names), 1, "Expected 1 object, found %d" % len(names))
 
 
-        #--------------------------------------
+        # --------------------------------------
         # Object's name matches the file name.
         # Object's name matches the file name.
-        #--------------------------------------
-        self.assertEqual(names[0], self.filename,
-                          "Expected name == %s, got %s" % (self.filename, names[0]))
+        # --------------------------------------
+        self.assertEqual(names[0], self.filename, "Expected name == %s, got %s" % (self.filename, names[0]))
 
 
-        #---------------------------------------
+        # ---------------------------------------
         # Get object by that name, make sure it's a FlatCAMGerber.
         # Get object by that name, make sure it's a FlatCAMGerber.
-        #---------------------------------------
+        # ---------------------------------------
         geo_name = names[0]
         geo_name = names[0]
         geo_obj = self.fc.collection.get_by_name(geo_name)
         geo_obj = self.fc.collection.get_by_name(geo_name)
         self.assertTrue(isinstance(geo_obj, FlatCAMGeometry),
         self.assertTrue(isinstance(geo_obj, FlatCAMGeometry),
                         "Expected FlatCAMGeometry, instead, %s is %s" %
                         "Expected FlatCAMGeometry, instead, %s is %s" %
                         (geo_name, type(geo_obj)))
                         (geo_name, type(geo_obj)))
 
 
-        #----------------------------------------
+        # ----------------------------------------
         # Object's GUI matches Object's options
         # Object's GUI matches Object's options
-        #----------------------------------------
+        # ----------------------------------------
         # TODO: Open GUI with double-click on object.
         # TODO: Open GUI with double-click on object.
         # Opens the Object's GUI, populates it.
         # Opens the Object's GUI, populates it.
         geo_obj.build_ui()
         geo_obj.build_ui()
@@ -72,9 +70,9 @@ class SVGFlowTestCase(unittest.TestCase):
                                  option, value, form_field.get_value()
                                  option, value, form_field.get_value()
                              ))
                              ))
 
 
-        #------------------------------------
+        # ------------------------------------
         # Open the UI, make CNCObject
         # Open the UI, make CNCObject
-        #------------------------------------
+        # ------------------------------------
         geo_obj.build_ui()
         geo_obj.build_ui()
         ui = geo_obj.ui
         ui = geo_obj.ui
         assert isinstance(ui, GeometryObjectUI)  # Just for the IDE
         assert isinstance(ui, GeometryObjectUI)  # Just for the IDE
@@ -91,30 +89,30 @@ class SVGFlowTestCase(unittest.TestCase):
             sleep(0.1)
             sleep(0.1)
             self.app.processEvents()
             self.app.processEvents()
 
 
-        #---------------------------------------------
+        # ---------------------------------------------
         # Check that only 1 object has been created.
         # Check that only 1 object has been created.
-        #---------------------------------------------
+        # ---------------------------------------------
         names = self.fc.collection.get_names()
         names = self.fc.collection.get_names()
         self.assertEqual(len(names), 2,
         self.assertEqual(len(names), 2,
                          "Expected 2 objects, found %d" % len(names))
                          "Expected 2 objects, found %d" % len(names))
 
 
-        #-------------------------------------------------------
+        # -------------------------------------------------------
         # Make sure the CNC Job Object has the correct name
         # Make sure the CNC Job Object has the correct name
-        #-------------------------------------------------------
+        # -------------------------------------------------------
         cnc_name = geo_name + "_cnc"
         cnc_name = geo_name + "_cnc"
         self.assertTrue(cnc_name in names,
         self.assertTrue(cnc_name in names,
                         "Object named %s not found." % geo_name)
                         "Object named %s not found." % geo_name)
 
 
-        #-------------------------------------------------------
+        # -------------------------------------------------------
         # Get the object make sure it's a CNC Job object
         # Get the object make sure it's a CNC Job object
-        #-------------------------------------------------------
+        # -------------------------------------------------------
         cnc_obj = self.fc.collection.get_by_name(cnc_name)
         cnc_obj = self.fc.collection.get_by_name(cnc_name)
         self.assertTrue(isinstance(cnc_obj, FlatCAMCNCjob),
         self.assertTrue(isinstance(cnc_obj, FlatCAMCNCjob),
                         "Expected a FlatCAMCNCJob, got %s" % type(geo_obj))
                         "Expected a FlatCAMCNCJob, got %s" % type(geo_obj))
 
 
-        #-----------------------------------------
+        # -----------------------------------------
         # Export G-Code, check output
         # Export G-Code, check output
-        #-----------------------------------------
+        # -----------------------------------------
         assert isinstance(cnc_obj, FlatCAMCNCjob)
         assert isinstance(cnc_obj, FlatCAMCNCjob)
         output_filename = ""
         output_filename = ""
         # get system temporary file(try create it and  delete also)
         # get system temporary file(try create it and  delete also)

+ 51 - 28
tests/test_tcl_shell.py

@@ -1,13 +1,13 @@
 import sys
 import sys
 import unittest
 import unittest
-from PyQt4 import QtGui
-from PyQt4.QtCore import QThread
+from PyQt5 import QtWidgets, QtGui
+from PyQt5.QtCore import QThread
 
 
 from FlatCAMApp import App
 from FlatCAMApp import App
 from os import listdir
 from os import listdir
 from os.path import isfile
 from os.path import isfile
 from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMCNCjob, FlatCAMExcellon
 from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMCNCjob, FlatCAMExcellon
-from ObjectUI import GerberObjectUI, GeometryObjectUI
+from flatcamGUI.ObjectUI import GerberObjectUI, GeometryObjectUI
 from time import sleep
 from time import sleep
 import os
 import os
 import tempfile
 import tempfile
@@ -36,13 +36,13 @@ class TclShellTest(unittest.TestCase):
     # reason for this is reuse one test window only,
     # reason for this is reuse one test window only,
 
 
     # CANNOT DO THIS HERE!!!
     # CANNOT DO THIS HERE!!!
-    #from tests.test_tclCommands import *
+    # from tests.test_tclCommands import *
 
 
     @classmethod
     @classmethod
     def setUpClass(cls):
     def setUpClass(cls):
 
 
         cls.setup = True
         cls.setup = True
-        cls.app = QtGui.QApplication(sys.argv)
+        cls.app = QtWidgets.QApplication(sys.argv)
 
 
         # Create App, keep app defaults (do not load
         # Create App, keep app defaults (do not load
         # user-defined defaults).
         # user-defined defaults).
@@ -78,9 +78,9 @@ class TclShellTest(unittest.TestCase):
         self.fc.exec_command_test('set_sys units IN')
         self.fc.exec_command_test('set_sys units IN')
         self.fc.exec_command_test('new')
         self.fc.exec_command_test('new')
 
 
-        #----------------------------------------
+        # ----------------------------------------
         # Units must be IN
         # Units must be IN
-        #----------------------------------------
+        # ----------------------------------------
         units = self.fc.exec_command_test('get_sys units')
         units = self.fc.exec_command_test('get_sys units')
         self.assertEqual(units, "IN")
         self.assertEqual(units, "IN")
 
 
@@ -88,9 +88,9 @@ class TclShellTest(unittest.TestCase):
         self.fc.exec_command_test('set_sys units MM')
         self.fc.exec_command_test('set_sys units MM')
         self.fc.exec_command_test('new')
         self.fc.exec_command_test('new')
 
 
-        #----------------------------------------
+        # ----------------------------------------
         # Units must be MM
         # Units must be MM
-        #----------------------------------------
+        # ----------------------------------------
         units = self.fc.exec_command_test('get_sys units')
         units = self.fc.exec_command_test('get_sys units')
         self.assertEqual(units, "MM")
         self.assertEqual(units, "MM")
 
 
@@ -103,9 +103,9 @@ class TclShellTest(unittest.TestCase):
 
 
         gbr_cmd = 'open_gerber {path}/{filename} -outname {outname}'
         gbr_cmd = 'open_gerber {path}/{filename} -outname {outname}'
 
 
-        #-----------------------------------------
+        # -----------------------------------------
         # Open top layer and check for object type
         # Open top layer and check for object type
-        #-----------------------------------------
+        # -----------------------------------------
         cmd = gbr_cmd.format(
         cmd = gbr_cmd.format(
             path=self.gerber_files,
             path=self.gerber_files,
             filename=self.copper_top_filename,
             filename=self.copper_top_filename,
@@ -116,9 +116,9 @@ class TclShellTest(unittest.TestCase):
                         "Expected FlatCAMGerber, instead, %s is %s" %
                         "Expected FlatCAMGerber, instead, %s is %s" %
                         (self.gerber_top_name, type(gerber_top_obj)))
                         (self.gerber_top_name, type(gerber_top_obj)))
 
 
-        #--------------------------------------------
+        # --------------------------------------------
         # Open bottom layer and check for object type
         # Open bottom layer and check for object type
-        #--------------------------------------------
+        # --------------------------------------------
         cmd = gbr_cmd.format(
         cmd = gbr_cmd.format(
             path=self.gerber_files,
             path=self.gerber_files,
             filename=self.copper_bottom_filename,
             filename=self.copper_bottom_filename,
@@ -129,9 +129,9 @@ class TclShellTest(unittest.TestCase):
                         "Expected FlatCAMGerber, instead, %s is %s" %
                         "Expected FlatCAMGerber, instead, %s is %s" %
                         (self.gerber_bottom_name, type(gerber_bottom_obj)))
                         (self.gerber_bottom_name, type(gerber_bottom_obj)))
 
 
-        #--------------------------------------------
+        # --------------------------------------------
         # Open cutout layer and check for object type
         # Open cutout layer and check for object type
-        #--------------------------------------------
+        # --------------------------------------------
         cmd = gbr_cmd.format(
         cmd = gbr_cmd.format(
             path=self.gerber_files,
             path=self.gerber_files,
             filename=self.cutout_filename,
             filename=self.cutout_filename,
@@ -160,9 +160,9 @@ class TclShellTest(unittest.TestCase):
 
 
         # TODO: Check deleteb object is gone.
         # TODO: Check deleteb object is gone.
 
 
-        #--------------------------------------------
+        # --------------------------------------------
         # Exteriors of cutout layer, check type
         # Exteriors of cutout layer, check type
-        #--------------------------------------------
+        # --------------------------------------------
         obj = self.fc.collection.get_by_name(self.gerber_cutout_name + '_iso_exterior')
         obj = self.fc.collection.get_by_name(self.gerber_cutout_name + '_iso_exterior')
         self.assertTrue(isinstance(obj, FlatCAMGeometry),
         self.assertTrue(isinstance(obj, FlatCAMGeometry),
                         "Expected FlatCAMGeometry, instead, %s is %s" %
                         "Expected FlatCAMGeometry, instead, %s is %s" %
@@ -173,8 +173,14 @@ class TclShellTest(unittest.TestCase):
         self.fc.exec_command_test('mirror %s -box %s -axis X' % (self.gerber_cutout_name, self.gerber_cutout_name))
         self.fc.exec_command_test('mirror %s -box %s -axis X' % (self.gerber_cutout_name, self.gerber_cutout_name))
 
 
         # exteriors delete and join geometries for bottom layer
         # exteriors delete and join geometries for bottom layer
-        self.fc.exec_command_test('isolate %s -dia %f -outname %s' % (self.gerber_cutout_name, self.engraver_diameter, self.gerber_cutout_name + '_bottom_iso'))
-        self.fc.exec_command_test('exteriors %s -outname %s' % (self.gerber_cutout_name + '_bottom_iso', self.gerber_cutout_name + '_bottom_iso_exterior'))
+        self.fc.exec_command_test(
+            'isolate %s -dia %f -outname %s' %
+            (self.gerber_cutout_name, self.engraver_diameter, self.gerber_cutout_name + '_bottom_iso')
+        )
+        self.fc.exec_command_test(
+            'exteriors %s -outname %s' %
+            (self.gerber_cutout_name + '_bottom_iso', self.gerber_cutout_name + '_bottom_iso_exterior')
+        )
         self.fc.exec_command_test('delete %s' % (self.gerber_cutout_name + '_bottom_iso'))
         self.fc.exec_command_test('delete %s' % (self.gerber_cutout_name + '_bottom_iso'))
         obj = self.fc.collection.get_by_name(self.gerber_cutout_name + '_bottom_iso_exterior')
         obj = self.fc.collection.get_by_name(self.gerber_cutout_name + '_bottom_iso_exterior')
         self.assertTrue(isinstance(obj, FlatCAMGeometry),
         self.assertTrue(isinstance(obj, FlatCAMGeometry),
@@ -187,12 +193,20 @@ class TclShellTest(unittest.TestCase):
                          "Expected 5 objects, found %d" % len(names))
                          "Expected 5 objects, found %d" % len(names))
 
 
         # isolate traces
         # isolate traces
-        self.fc.exec_command_test('isolate %s -dia %f' %  (self.gerber_top_name, self.engraver_diameter))
-        self.fc.exec_command_test('isolate %s -dia %f' %  (self.gerber_bottom_name, self.engraver_diameter))
+        self.fc.exec_command_test('isolate %s -dia %f' % (self.gerber_top_name, self.engraver_diameter))
+        self.fc.exec_command_test('isolate %s -dia %f' % (self.gerber_bottom_name, self.engraver_diameter))
 
 
         # join isolated geometries for top and  bottom
         # join isolated geometries for top and  bottom
-        self.fc.exec_command_test('join_geometries %s %s %s' %  (self.gerber_top_name + '_join_iso', self.gerber_top_name + '_iso', self.gerber_cutout_name + '_iso_exterior'))
-        self.fc.exec_command_test('join_geometries %s %s %s' %  (self.gerber_bottom_name + '_join_iso', self.gerber_bottom_name + '_iso', self.gerber_cutout_name + '_bottom_iso_exterior'))
+        self.fc.exec_command_test(
+            'join_geometries %s %s %s' %
+            (self.gerber_top_name + '_join_iso', self.gerber_top_name + '_iso',
+             self.gerber_cutout_name + '_iso_exterior')
+        )
+        self.fc.exec_command_test(
+            'join_geometries %s %s %s' %
+            (self.gerber_bottom_name + '_join_iso', self.gerber_bottom_name + '_iso',
+             self.gerber_cutout_name + '_bottom_iso_exterior')
+        )
 
 
         # at this stage we should have 9 objects
         # at this stage we should have 9 objects
         names = self.fc.collection.get_names()
         names = self.fc.collection.get_names()
@@ -211,14 +225,21 @@ class TclShellTest(unittest.TestCase):
                          "Expected 5 objects, found %d" % len(names))
                          "Expected 5 objects, found %d" % len(names))
 
 
         # geocutout bottom test (it cuts  to same object)
         # geocutout bottom test (it cuts  to same object)
-        self.fc.exec_command_test('isolate %s -dia %f -outname %s' % (self.gerber_cutout_name, self.cutout_diameter, self.gerber_cutout_name + '_bottom_iso'))
-        self.fc.exec_command_test('exteriors %s -outname %s' % (self.gerber_cutout_name + '_bottom_iso', self.gerber_cutout_name + '_bottom_iso_exterior'))
+        self.fc.exec_command_test(
+            'isolate %s -dia %f -outname %s' %
+            (self.gerber_cutout_name, self.cutout_diameter, self.gerber_cutout_name + '_bottom_iso')
+        )
+        self.fc.exec_command_test(
+            'exteriors %s -outname %s' %
+            (self.gerber_cutout_name + '_bottom_iso', self.gerber_cutout_name + '_bottom_iso_exterior')
+        )
         self.fc.exec_command_test('delete %s' % (self.gerber_cutout_name + '_bottom_iso'))
         self.fc.exec_command_test('delete %s' % (self.gerber_cutout_name + '_bottom_iso'))
         obj = self.fc.collection.get_by_name(self.gerber_cutout_name + '_bottom_iso_exterior')
         obj = self.fc.collection.get_by_name(self.gerber_cutout_name + '_bottom_iso_exterior')
         self.assertTrue(isinstance(obj, FlatCAMGeometry),
         self.assertTrue(isinstance(obj, FlatCAMGeometry),
                         "Expected FlatCAMGeometry, instead, %s is %s" %
                         "Expected FlatCAMGeometry, instead, %s is %s" %
                         (self.gerber_cutout_name + '_bottom_iso_exterior', type(obj)))
                         (self.gerber_cutout_name + '_bottom_iso_exterior', type(obj)))
-        self.fc.exec_command_test('geocutout %s -dia %f -gapsize 0.3 -gaps 4' % (self.gerber_cutout_name + '_bottom_iso_exterior', self.cutout_diameter))
+        self.fc.exec_command_test('geocutout %s -dia %f -gapsize 0.3 -gaps 4' %
+                                  (self.gerber_cutout_name + '_bottom_iso_exterior', self.cutout_diameter))
 
 
         # at this stage we should have 6 objects
         # at this stage we should have 6 objects
         names = self.fc.collection.get_names()
         names = self.fc.collection.get_names()
@@ -229,7 +250,8 @@ class TclShellTest(unittest.TestCase):
 
 
     def test_open_gerber(self):
     def test_open_gerber(self):
 
 
-        self.fc.exec_command_test('open_gerber %s/%s -outname %s' % (self.gerber_files, self.copper_top_filename, self.gerber_top_name))
+        self.fc.exec_command_test('open_gerber %s/%s -outname %s' %
+                                  (self.gerber_files, self.copper_top_filename, self.gerber_top_name))
         gerber_top_obj = self.fc.collection.get_by_name(self.gerber_top_name)
         gerber_top_obj = self.fc.collection.get_by_name(self.gerber_top_name)
         self.assertTrue(isinstance(gerber_top_obj, FlatCAMGerber),
         self.assertTrue(isinstance(gerber_top_obj, FlatCAMGerber),
                         "Expected FlatCAMGerber, instead, %s is %s" %
                         "Expected FlatCAMGerber, instead, %s is %s" %
@@ -237,7 +259,8 @@ class TclShellTest(unittest.TestCase):
 
 
     def test_excellon_flow(self):
     def test_excellon_flow(self):
 
 
-        self.fc.exec_command_test('open_excellon %s/%s -outname %s' % (self.gerber_files, self.excellon_filename, self.excellon_name))
+        self.fc.exec_command_test('open_excellon %s/%s -outname %s' %
+                                  (self.gerber_files, self.excellon_filename, self.excellon_name))
         excellon_obj = self.fc.collection.get_by_name(self.excellon_name)
         excellon_obj = self.fc.collection.get_by_name(self.excellon_name)
         self.assertTrue(isinstance(excellon_obj, FlatCAMExcellon),
         self.assertTrue(isinstance(excellon_obj, FlatCAMExcellon),
                         "Expected FlatCAMExcellon, instead, %s is %s" %
                         "Expected FlatCAMExcellon, instead, %s is %s" %