diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | README.md | 15 | ||||
-rwxr-xr-x | gerber/excellon.py | 3 | ||||
-rw-r--r-- | gerber/primitives.py | 7 | ||||
-rw-r--r-- | gerber/tests/test_am_statements.py | 19 | ||||
-rw-r--r-- | gerber/tests/test_cam.py | 11 | ||||
-rw-r--r-- | gerber/tests/test_excellon.py | 5 | ||||
-rw-r--r-- | gerber/tests/test_primitives.py | 55 | ||||
-rw-r--r-- | test-requirements.txt | 1 |
9 files changed, 78 insertions, 40 deletions
@@ -46,3 +46,5 @@ nosetests.xml .DS_Store Thumbs.db +# Virtual environment +venv @@ -33,3 +33,18 @@ Source code for this example can be found [here](examples/cairo_example.py). Documentation:
--------------
[PCB Tools Documentation](http://pcb-tools.readthedocs.org/en/latest/)
+
+
+Development and Testing:
+------------------------
+
+Dependencies for developing and testing pcb-tools are listed in test-requirements.txt. Use of a virtual environment is strongly recommended.
+
+ $ virtualenv venv
+ $ source venv/bin/activate
+ (venv)$ pip install -r test-requirements.txt
+ (venv)$ pip install -e .
+
+We use nose to run pcb-tools's suite of unittests and doctests.
+
+ (venv)$ nosetests
diff --git a/gerber/excellon.py b/gerber/excellon.py index bcd136e..430ee7d 100755 --- a/gerber/excellon.py +++ b/gerber/excellon.py @@ -113,6 +113,9 @@ class DrillHit(object): def offset(self, x_offset, y_offset):
self.position = tuple(map(operator.add, self.position, (x_offset, y_offset)))
+
+ def __str__(self):
+ return 'Hit (%f, %f) {%s}' % (self.position[0], self.position[1], self.tool)
class DrillSlot(object):
"""
diff --git a/gerber/primitives.py b/gerber/primitives.py index 211acb8..90b6fb9 100644 --- a/gerber/primitives.py +++ b/gerber/primitives.py @@ -1112,7 +1112,7 @@ class Drill(Primitive): self.position = position
self.diameter = diameter
self.hit = hit
- self._to_convert = ['position', 'diameter']
+ self._to_convert = ['position', 'diameter', 'hit']
@property
def flashed(self):
@@ -1133,6 +1133,9 @@ class Drill(Primitive): def offset(self, x_offset=0, y_offset=0):
self.position = tuple(map(add, self.position, (x_offset, y_offset)))
+ def __str__(self):
+ return '<Drill %f (%f, %f) [%s]>' % (self.diameter, self.position[0], self.position[1], self.hit)
+
class Slot(Primitive):
""" A drilled slot
@@ -1145,7 +1148,7 @@ class Slot(Primitive): self.end = end
self.diameter = diameter
self.hit = hit
- self._to_convert = ['start', 'end', 'diameter']
+ self._to_convert = ['start', 'end', 'diameter', 'hit']
@property
def flashed(self):
diff --git a/gerber/tests/test_am_statements.py b/gerber/tests/test_am_statements.py index 0cee13d..39324e5 100644 --- a/gerber/tests/test_am_statements.py +++ b/gerber/tests/test_am_statements.py @@ -146,7 +146,9 @@ def test_AMOutlinePrimitive_factory(): def test_AMOUtlinePrimitive_dump(): o = AMOutlinePrimitive(4, 'on', (0, 0), [(3, 3), (3, 0), (0, 0)], 0) - assert_equal(o.to_gerber(), '4,1,3,0,0,3,3,3,0,0,0,0*') + # New lines don't matter for Gerber, but we insert them to make it easier to remove + # For test purposes we can ignore them + assert_equal(o.to_gerber().replace('\n', ''), '4,1,3,0,0,3,3,3,0,0,0,0*') def test_AMOutlinePrimitive_conversion(): o = AMOutlinePrimitive(4, 'on', (0, 0), [(25.4, 25.4), (25.4, 0), (0, 0)], 0) @@ -229,30 +231,31 @@ def test_AMMoirePrimitive_conversion(): assert_equal(m.crosshair_length, 25.4) def test_AMThermalPrimitive_validation(): - assert_raises(ValueError, AMThermalPrimitive, 8, (0.0, 0.0), 7, 5, 0.2) - assert_raises(TypeError, AMThermalPrimitive, 7, (0.0, '0'), 7, 5, 0.2) + assert_raises(ValueError, AMThermalPrimitive, 8, (0.0, 0.0), 7, 5, 0.2, 0.0) + assert_raises(TypeError, AMThermalPrimitive, 7, (0.0, '0'), 7, 5, 0.2, 0.0) def test_AMThermalPrimitive_factory(): - t = AMThermalPrimitive.from_gerber('7,0,0,7,6,0.2*') + t = AMThermalPrimitive.from_gerber('7,0,0,7,6,0.2,45*') assert_equal(t.code, 7) assert_equal(t.position, (0, 0)) assert_equal(t.outer_diameter, 7) assert_equal(t.inner_diameter, 6) assert_equal(t.gap, 0.2) + assert_equal(t.rotation, 45) def test_AMThermalPrimitive_dump(): - t = AMThermalPrimitive.from_gerber('7,0,0,7,6,0.2*') - assert_equal(t.to_gerber(), '7,0,0,7.0,6.0,0.2*') + t = AMThermalPrimitive.from_gerber('7,0,0,7,6,0.2,30*') + assert_equal(t.to_gerber(), '7,0,0,7.0,6.0,0.2,30.0*') def test_AMThermalPrimitive_conversion(): - t = AMThermalPrimitive(7, (25.4, 25.4), 25.4, 25.4, 25.4) + t = AMThermalPrimitive(7, (25.4, 25.4), 25.4, 25.4, 25.4, 0.0) t.to_inch() assert_equal(t.position, (1., 1.)) assert_equal(t.outer_diameter, 1.) assert_equal(t.inner_diameter, 1.) assert_equal(t.gap, 1.) - t = AMThermalPrimitive(7, (1, 1), 1, 1, 1) + t = AMThermalPrimitive(7, (1, 1), 1, 1, 1, 0) t.to_metric() assert_equal(t.position, (25.4, 25.4)) assert_equal(t.outer_diameter, 25.4) diff --git a/gerber/tests/test_cam.py b/gerber/tests/test_cam.py index 00a8285..3ae0a24 100644 --- a/gerber/tests/test_cam.py +++ b/gerber/tests/test_cam.py @@ -113,10 +113,19 @@ def test_zeros(): def test_filesettings_validation(): """ Test FileSettings constructor argument validation """ + + # absolute-ish is not a valid notation assert_raises(ValueError, FileSettings, 'absolute-ish', 'inch', None, (2, 5), None) + + # degrees kelvin isn't a valid unit for a CAM file assert_raises(ValueError, FileSettings, 'absolute', 'degrees kelvin', None, (2, 5), None) + assert_raises(ValueError, FileSettings, 'absolute', 'inch', 'leading', (2, 5), 'leading') - assert_raises(ValueError, FileSettings, 'absolute', 'inch', 'following', (2, 5), None) + + # Technnically this should be an error, but Eangle files often do this incorrectly so we + # allow it + # assert_raises(ValueError, FileSettings, 'absolute', 'inch', 'following', (2, 5), None) + assert_raises(ValueError, FileSettings, 'absolute', 'inch', None, (2, 5), 'following') assert_raises(ValueError, FileSettings, 'absolute', 'inch', None, (2, 5, 6), None) diff --git a/gerber/tests/test_excellon.py b/gerber/tests/test_excellon.py index 705adc3..afc2917 100644 --- a/gerber/tests/test_excellon.py +++ b/gerber/tests/test_excellon.py @@ -78,8 +78,9 @@ def test_conversion(): for m_tool, i_tool in zip(iter(ncdrill.tools.values()), iter(ncdrill_inch.tools.values())): assert_equal(i_tool, m_tool) - for m, i in zip(ncdrill.primitives,inch_primitives): - assert_equal(m, i) + for m, i in zip(ncdrill.primitives, inch_primitives): + assert_equal(m.position, i.position, '%s not equal to %s' % (m, i)) + assert_equal(m.diameter, i.diameter, '%s not equal to %s' % (m, i)) def test_parser_hole_count(): diff --git a/gerber/tests/test_primitives.py b/gerber/tests/test_primitives.py index f8a32da..0f13a80 100644 --- a/gerber/tests/test_primitives.py +++ b/gerber/tests/test_primitives.py @@ -150,7 +150,7 @@ def test_arc_radius(): ((0, 1), (1, 0), (0, 0), 1),] for start, end, center, radius in cases: - a = Arc(start, end, center, 'clockwise', 0) + a = Arc(start, end, center, 'clockwise', 0, 'single-quadrant') assert_equal(a.radius, radius) def test_arc_sweep_angle(): @@ -163,7 +163,7 @@ def test_arc_sweep_angle(): for start, end, center, direction, sweep in cases: c = Circle((0,0), 1) - a = Arc(start, end, center, direction, c) + a = Arc(start, end, center, direction, c, 'single-quadrant') assert_equal(a.sweep_angle, sweep) def test_arc_bounds(): @@ -175,12 +175,12 @@ def test_arc_bounds(): ] for start, end, center, direction, bounds in cases: c = Circle((0,0), 1) - a = Arc(start, end, center, direction, c) + a = Arc(start, end, center, direction, c, 'single-quadrant') assert_equal(a.bounding_box, bounds) def test_arc_conversion(): c = Circle((0, 0), 25.4, units='metric') - a = Arc((2.54, 25.4), (254.0, 2540.0), (25400.0, 254000.0),'clockwise', c, units='metric') + a = Arc((2.54, 25.4), (254.0, 2540.0), (25400.0, 254000.0),'clockwise', c, 'single-quadrant', units='metric') #No effect a.to_metric() @@ -203,7 +203,7 @@ def test_arc_conversion(): assert_equal(a.aperture.diameter, 1.0) c = Circle((0, 0), 1.0, units='inch') - a = Arc((0.1, 1.0), (10.0, 100.0), (1000.0, 10000.0),'clockwise', c, units='inch') + a = Arc((0.1, 1.0), (10.0, 100.0), (1000.0, 10000.0),'clockwise', c, 'single-quadrant', units='inch') a.to_metric() assert_equal(a.start, (2.54, 25.4)) assert_equal(a.end, (254.0, 2540.0)) @@ -212,7 +212,7 @@ def test_arc_conversion(): def test_arc_offset(): c = Circle((0, 0), 1) - a = Arc((0, 0), (1, 1), (2, 2), 'clockwise', c) + a = Arc((0, 0), (1, 1), (2, 2), 'clockwise', c, 'single-quadrant') a.offset(1, 0) assert_equal(a.start,(1., 0.)) assert_equal(a.end, (2., 1.)) @@ -703,29 +703,30 @@ def test_obround_offset(): def test_polygon_ctor(): """ Test polygon creation """ - test_cases = (((0,0), 3, 5), - ((0, 0), 5, 6), - ((1,1), 7, 7)) - for pos, sides, radius in test_cases: - p = Polygon(pos, sides, radius) + test_cases = (((0,0), 3, 5, 0), + ((0, 0), 5, 6, 0), + ((1,1), 7, 7, 45)) + for pos, sides, radius, hole_radius in test_cases: + p = Polygon(pos, sides, radius, hole_radius) assert_equal(p.position, pos) assert_equal(p.sides, sides) assert_equal(p.radius, radius) + assert_equal(p.hole_radius, hole_radius) def test_polygon_bounds(): """ Test polygon bounding box calculation """ - p = Polygon((2,2), 3, 2) + p = Polygon((2,2), 3, 2, 0) xbounds, ybounds = p.bounding_box assert_array_almost_equal(xbounds, (0, 4)) assert_array_almost_equal(ybounds, (0, 4)) - p = Polygon((2,2),3, 4) + p = Polygon((2,2), 3, 4, 0) xbounds, ybounds = p.bounding_box assert_array_almost_equal(xbounds, (-2, 6)) assert_array_almost_equal(ybounds, (-2, 6)) def test_polygon_conversion(): - p = Polygon((2.54, 25.4), 3, 254.0, units='metric') + p = Polygon((2.54, 25.4), 3, 254.0, 0, units='metric') #No effect p.to_metric() @@ -741,7 +742,7 @@ def test_polygon_conversion(): assert_equal(p.position, (0.1, 1.0)) assert_equal(p.radius, 10.0) - p = Polygon((0.1, 1.0), 3, 10.0, units='inch') + p = Polygon((0.1, 1.0), 3, 10.0, 0, units='inch') #No effect p.to_inch() @@ -758,7 +759,7 @@ def test_polygon_conversion(): assert_equal(p.radius, 254.0) def test_polygon_offset(): - p = Polygon((0, 0), 5, 10) + p = Polygon((0, 0), 5, 10, 0) p.offset(1, 0) assert_equal(p.position,(1., 0.)) p.offset(0, 1) @@ -997,7 +998,7 @@ def test_drill_ctor(): """ test_cases = (((0, 0), 2), ((1, 1), 3), ((2, 2), 5)) for position, diameter in test_cases: - d = Drill(position, diameter) + d = Drill(position, diameter, None) assert_equal(d.position, position) assert_equal(d.diameter, diameter) assert_equal(d.radius, diameter/2.) @@ -1005,21 +1006,21 @@ def test_drill_ctor(): def test_drill_ctor_validation(): """ Test drill argument validation """ - assert_raises(TypeError, Drill, 3, 5) - assert_raises(TypeError, Drill, (3,4,5), 5) + assert_raises(TypeError, Drill, 3, 5, None) + assert_raises(TypeError, Drill, (3,4,5), 5, None) def test_drill_bounds(): - d = Drill((0, 0), 2) + d = Drill((0, 0), 2, None) xbounds, ybounds = d.bounding_box assert_array_almost_equal(xbounds, (-1, 1)) assert_array_almost_equal(ybounds, (-1, 1)) - d = Drill((1, 2), 2) + d = Drill((1, 2), 2, None) xbounds, ybounds = d.bounding_box assert_array_almost_equal(xbounds, (0, 2)) assert_array_almost_equal(ybounds, (1, 3)) def test_drill_conversion(): - d = Drill((2.54, 25.4), 254., units='metric') + d = Drill((2.54, 25.4), 254., None, units='metric') #No effect d.to_metric() @@ -1036,7 +1037,7 @@ def test_drill_conversion(): assert_equal(d.diameter, 10.0) - d = Drill((0.1, 1.0), 10., units='inch') + d = Drill((0.1, 1.0), 10., None, units='inch') #No effect d.to_inch() @@ -1053,15 +1054,15 @@ def test_drill_conversion(): assert_equal(d.diameter, 254.0) def test_drill_offset(): - d = Drill((0, 0), 1.) + d = Drill((0, 0), 1., None) d.offset(1, 0) assert_equal(d.position,(1., 0.)) d.offset(0, 1) assert_equal(d.position,(1., 1.)) def test_drill_equality(): - d = Drill((2.54, 25.4), 254.) - d1 = Drill((2.54, 25.4), 254.) + d = Drill((2.54, 25.4), 254., None) + d1 = Drill((2.54, 25.4), 254., None) assert_equal(d, d1) - d1 = Drill((2.54, 25.4), 254.2) + d1 = Drill((2.54, 25.4), 254.2, None) assert_not_equal(d, d1) diff --git a/test-requirements.txt b/test-requirements.txt index c88a55a..826da33 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,3 +1,4 @@ # Test requirements +cairocffi==0.6 coverage==3.7.1 nose==1.3.4 |