Explorar o código

- 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 %!s(int64=6) %!d(string=hai) anos
pai
achega
a6b89dbf3a

+ 5 - 5
FlatCAMApp.py

@@ -52,7 +52,7 @@ from flatcamEditors.FlatCAMTextEditor import TextEditor
 
 from FlatCAMProcess import *
 from FlatCAMWorkerStack import WorkerStack
-from flatcamGUI.VisPyVisuals import Color
+# from flatcamGUI.VisPyVisuals import Color
 from vispy.gloo.util import _screenshot
 from vispy.io import write_png
 
@@ -71,12 +71,12 @@ fcTranslate.apply_language('strings')
 if '_' not in builtins.__dict__:
     _ = gettext.gettext
 
-# ########################################
-# #                App                 ###
-# ########################################
-
 
 class App(QtCore.QObject):
+    # ########################################
+    # #                App                 ###
+    # ########################################
+
     """
     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 Excellon and Gerber classes from camlib into their own files in the flatcamParser folder
 - 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
 

+ 374 - 1
camlib.py

@@ -49,7 +49,7 @@ import ezdxf
 # TODO: Commented for FlatCAM packaging with cx_freeze
 # from scipy.spatial import KDTree, Delaunay
 # from scipy.spatial import Delaunay
-from flatcamParsers.ParseGerber import ApertureMacro
+
 from flatcamParsers.ParseSVG import *
 from flatcamParsers.ParseDXF import *
 
@@ -82,6 +82,379 @@ class ParseError(Exception):
     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):
     """
     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__:
     _ = 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):
     """
@@ -265,7 +289,7 @@ class Excellon(Geometry):
 
         line_units = ''
 
-        #### Parsing starts here ## ##
+        # ## Parsing starts here ## ##
         line_num = 0  # Line number
         eline = ""
         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__:
     _ = 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):
     """
@@ -1134,25 +1160,25 @@ class Gerber(Geometry):
                     try:
                         circular_x = parse_gerber_number(circular_x,
                                                          self.int_digits, self.frac_digits, self.gerber_zeros)
-                    except:
+                    except Exception as e:
                         circular_x = current_x
 
                     try:
                         circular_y = parse_gerber_number(circular_y,
                                                          self.int_digits, self.frac_digits, self.gerber_zeros)
-                    except:
+                    except Exception as e:
                         circular_y = current_y
 
                     # 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
                     try:
                         i = parse_gerber_number(i, self.int_digits, self.frac_digits, self.gerber_zeros)
-                    except:
+                    except Exception as e:
                         i = 0
 
                     try:
                         j = parse_gerber_number(j, self.int_digits, self.frac_digits, self.gerber_zeros)
-                    except:
+                    except Exception as e:
                         j = 0
 
                     if quadrant_mode is None:
@@ -1598,6 +1624,7 @@ class Gerber(Geometry):
         :type xfactor: float
         :param yfactor: Number by which to scale on Y axis.
         :type yfactor: float
+        :param point: reference point for scaling operation
         :rtype : None
         """
         log.debug("camlib.Gerber.scale()")
@@ -1628,7 +1655,7 @@ class Gerber(Geometry):
         # variables to display the percentage of work done
         self.geo_len = 0
         try:
-            for g in self.solid_geometry:
+            for __ in self.solid_geometry:
                 self.geo_len += 1
         except TypeError:
             self.geo_len = 1
@@ -1717,7 +1744,7 @@ class Gerber(Geometry):
         # variables to display the percentage of work done
         self.geo_len = 0
         try:
-            for g in self.solid_geometry:
+            for __ in self.solid_geometry:
                 self.geo_len += 1
         except TypeError:
             self.geo_len = 1
@@ -1796,7 +1823,7 @@ class Gerber(Geometry):
         # variables to display the percentage of work done
         self.geo_len = 0
         try:
-            for g in self.solid_geometry:
+            for __ in self.solid_geometry:
                 self.geo_len += 1
         except TypeError:
             self.geo_len = 1
@@ -1857,6 +1884,10 @@ class Gerber(Geometry):
 
         See shapely manual for more information:
         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()")
 
@@ -1865,7 +1896,7 @@ class Gerber(Geometry):
         # variables to display the percentage of work done
         self.geo_len = 0
         try:
-            for g in self.solid_geometry:
+            for __ in self.solid_geometry:
                 self.geo_len += 1
         except TypeError:
             self.geo_len = 1
@@ -1926,7 +1957,7 @@ class Gerber(Geometry):
         # variables to display the percentage of work done
         self.geo_len = 0
         try:
-            for g in self.solid_geometry:
+            for __ in self.solid_geometry:
                 self.geo_len += 1
         except TypeError:
             self.geo_len = 1
@@ -1972,376 +2003,3 @@ class Gerber(Geometry):
         self.app.inform.emit('[success] %s' %
                              _("Gerber Rotate done."))
         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.QtCore import Qt
 
+
 class TitleBar(QtWidgets.QDialog):
     def __init__(self, parent=None):
         QtWidgets.QWidget.__init__(self, parent)
-        self.setWindowFlags(Qt.FramelessWindowHint);
+        self.setWindowFlags(Qt.FramelessWindowHint)
         css = """
         QWidget{
             Background: #AA00AA;
@@ -60,19 +61,19 @@ class TitleBar(QtWidgets.QDialog):
         self.maximize.clicked.connect(self.showMaxRestore)
 
     def showSmall(self):
-        box.showMinimized();
+        box.showMinimized()
 
     def showMaxRestore(self):
         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)
         else:
-            box.showMaximized();
-            self.maxNormal=  True;
+            box.showMaximized()
+            self.maxNormal=  True
             print(2)
-            self.maximize.setIcon(QtGui.QIcon('img/max2.png'));
+            self.maximize.setIcon(QtGui.QIcon('img/max2.png'))
 
     def close(self):
         box.close()
@@ -88,7 +89,7 @@ class TitleBar(QtWidgets.QDialog):
 class Frame(QtWidgets.QFrame):
     def __init__(self, parent=None):
         QtWidgets.QFrame.__init__(self, parent)
-        self.m_mouse_down= False;
+        self.m_mouse_down= False
         self.setFrameShape(QtWidgets.QFrame.StyledPanel)
         css = """
         QFrame{
@@ -122,25 +123,26 @@ class Frame(QtWidgets.QFrame):
         return self.m_titleBar
 
     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):
         x=event.x()
         y=event.y()
 
     def mouseReleaseEvent(self,event):
-        m_mouse_down=False;
+        m_mouse_down=False
+
 
 if __name__ == '__main__':
-    app = QtWidgets.QApplication(sys.argv);
+    app = QtWidgets.QApplication(sys.argv)
     box = Frame()
     box.move(60,60)
-    l=QtWidgets.QVBoxLayout(box.contentWidget());
+    l = QtWidgets.QVBoxLayout(box.contentWidget())
     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
-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)
     box.show()
     app.exec_()

+ 1 - 1
tests/gerber_parsing_profiling/gerber_parsing_line_profile_1.py

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

+ 1 - 1
tests/gerber_parsing_profiling/gerber_parsing_profile_1.py

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

+ 5 - 0
tests/new_window_test.py

@@ -2,6 +2,7 @@ import sys
 from PyQt5.Qt import *
 from PyQt5 import QtGui, QtWidgets
 
+
 class MyPopup(QWidget):
     def __init__(self):
         QWidget.__init__(self)
@@ -30,6 +31,7 @@ class MyPopup(QWidget):
     #     dc.drawLine(0, 0, 100, 100)
     #     dc.drawLine(100, 0, 0, 100)
 
+
 class MainWindow(QMainWindow):
     def __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.show()
 
+
 class App(QApplication):
     def __init__(self, *args):
         QtWidgets.QApplication.__init__(self, *args)
@@ -56,10 +59,12 @@ class App(QApplication):
     def byebye(self):
         self.exit(0)
 
+
 def main(args):
     global app
     app = App(args)
     app.exec_()
 
+
 if __name__ == "__main__":
     main(sys.argv)

+ 4 - 4
tests/other/destructor_test.py

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

+ 1 - 1
tests/other/profile_gerber_parser.py

@@ -1,7 +1,7 @@
 import os
 os.chdir('../')
 
-from camlib import *
+from flatcamParsers.ParseGerber import *
 
 g = Gerber()
 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
 os.chdir('../')
 
-from camlib import *
-#from matplotlib.figure import Figure
+from flatcamParsers.ParseGerber import *
+from flatcamParsers.ParseExcellon import *
+
 from matplotlib import pyplot
 
 # 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"
 g = Gerber()
 g.parse_file(gerber_filename)
@@ -32,7 +33,7 @@ ax.set_aspect(1)
 # Plot gerber
 for geo in g.solid_geometry:
     x, y = geo.exterior.coords.xy
-    plot(x, y, 'k-')
+    pyplot.plot(x, y, 'k-')
     for ints in geo.interiors:
         x, y = ints.coords.xy
         ax.plot(x, y, 'k-')
@@ -40,7 +41,7 @@ for geo in g.solid_geometry:
 # Plot excellon
 for geo in ex.solid_geometry:
     x, y = geo.exterior.coords.xy
-    plot(x, y, 'r-')
+    pyplot.plot(x, y, 'r-')
     for ints in geo.interiors:
         x, y = ints.coords.xy
         ax.plot(x, y, 'g-')

+ 2 - 1
tests/other/test_plotg.py

@@ -1,6 +1,7 @@
 from shapely.geometry import LineString, Polygon
 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 *
 
 

+ 26 - 25
tests/test_excellon.py

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

+ 17 - 17
tests/test_excellon_flow.py

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

+ 4 - 3
tests/test_gerber_buffer.py

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

+ 33 - 33
tests/test_gerber_flow.py

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

+ 3 - 10
tests/test_polygon_paint.py

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

+ 23 - 25
tests/test_svg_flow.py

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

+ 51 - 28
tests/test_tcl_shell.py

@@ -1,13 +1,13 @@
 import sys
 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 os import listdir
 from os.path import isfile
 from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMCNCjob, FlatCAMExcellon
-from ObjectUI import GerberObjectUI, GeometryObjectUI
+from flatcamGUI.ObjectUI import GerberObjectUI, GeometryObjectUI
 from time import sleep
 import os
 import tempfile
@@ -36,13 +36,13 @@ class TclShellTest(unittest.TestCase):
     # reason for this is reuse one test window only,
 
     # CANNOT DO THIS HERE!!!
-    #from tests.test_tclCommands import *
+    # from tests.test_tclCommands import *
 
     @classmethod
     def setUpClass(cls):
 
         cls.setup = True
-        cls.app = QtGui.QApplication(sys.argv)
+        cls.app = QtWidgets.QApplication(sys.argv)
 
         # Create App, keep app defaults (do not load
         # 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('new')
 
-        #----------------------------------------
+        # ----------------------------------------
         # Units must be IN
-        #----------------------------------------
+        # ----------------------------------------
         units = self.fc.exec_command_test('get_sys units')
         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('new')
 
-        #----------------------------------------
+        # ----------------------------------------
         # Units must be MM
-        #----------------------------------------
+        # ----------------------------------------
         units = self.fc.exec_command_test('get_sys units')
         self.assertEqual(units, "MM")
 
@@ -103,9 +103,9 @@ class TclShellTest(unittest.TestCase):
 
         gbr_cmd = 'open_gerber {path}/{filename} -outname {outname}'
 
-        #-----------------------------------------
+        # -----------------------------------------
         # Open top layer and check for object type
-        #-----------------------------------------
+        # -----------------------------------------
         cmd = gbr_cmd.format(
             path=self.gerber_files,
             filename=self.copper_top_filename,
@@ -116,9 +116,9 @@ class TclShellTest(unittest.TestCase):
                         "Expected FlatCAMGerber, instead, %s is %s" %
                         (self.gerber_top_name, type(gerber_top_obj)))
 
-        #--------------------------------------------
+        # --------------------------------------------
         # Open bottom layer and check for object type
-        #--------------------------------------------
+        # --------------------------------------------
         cmd = gbr_cmd.format(
             path=self.gerber_files,
             filename=self.copper_bottom_filename,
@@ -129,9 +129,9 @@ class TclShellTest(unittest.TestCase):
                         "Expected FlatCAMGerber, instead, %s is %s" %
                         (self.gerber_bottom_name, type(gerber_bottom_obj)))
 
-        #--------------------------------------------
+        # --------------------------------------------
         # Open cutout layer and check for object type
-        #--------------------------------------------
+        # --------------------------------------------
         cmd = gbr_cmd.format(
             path=self.gerber_files,
             filename=self.cutout_filename,
@@ -160,9 +160,9 @@ class TclShellTest(unittest.TestCase):
 
         # TODO: Check deleteb object is gone.
 
-        #--------------------------------------------
+        # --------------------------------------------
         # Exteriors of cutout layer, check type
-        #--------------------------------------------
+        # --------------------------------------------
         obj = self.fc.collection.get_by_name(self.gerber_cutout_name + '_iso_exterior')
         self.assertTrue(isinstance(obj, FlatCAMGeometry),
                         "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))
 
         # 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'))
         obj = self.fc.collection.get_by_name(self.gerber_cutout_name + '_bottom_iso_exterior')
         self.assertTrue(isinstance(obj, FlatCAMGeometry),
@@ -187,12 +193,20 @@ class TclShellTest(unittest.TestCase):
                          "Expected 5 objects, found %d" % len(names))
 
         # 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
-        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
         names = self.fc.collection.get_names()
@@ -211,14 +225,21 @@ class TclShellTest(unittest.TestCase):
                          "Expected 5 objects, found %d" % len(names))
 
         # 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'))
         obj = self.fc.collection.get_by_name(self.gerber_cutout_name + '_bottom_iso_exterior')
         self.assertTrue(isinstance(obj, FlatCAMGeometry),
                         "Expected FlatCAMGeometry, instead, %s is %s" %
                         (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
         names = self.fc.collection.get_names()
@@ -229,7 +250,8 @@ class TclShellTest(unittest.TestCase):
 
     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)
         self.assertTrue(isinstance(gerber_top_obj, FlatCAMGerber),
                         "Expected FlatCAMGerber, instead, %s is %s" %
@@ -237,7 +259,8 @@ class TclShellTest(unittest.TestCase):
 
     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)
         self.assertTrue(isinstance(excellon_obj, FlatCAMExcellon),
                         "Expected FlatCAMExcellon, instead, %s is %s" %