summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gerber/cam.py84
-rwxr-xr-xgerber/excellon.py31
-rw-r--r--gerber/excellon_statements.py10
-rw-r--r--gerber/tests/test_cam.py27
-rw-r--r--gerber/tests/test_excellon.py13
-rw-r--r--gerber/tests/test_excellon_statements.py14
6 files changed, 140 insertions, 39 deletions
diff --git a/gerber/cam.py b/gerber/cam.py
index 051c3b5..a4057bc 100644
--- a/gerber/cam.py
+++ b/gerber/cam.py
@@ -27,9 +27,34 @@ class FileSettings(object):
""" CAM File Settings
Provides a common representation of gerber/excellon file settings
+
+ Parameters
+ ----------
+ notation: string
+ notation format. either 'absolute' or 'incremental'
+
+ units : string
+ Measurement units. 'inch' or 'metric'
+
+ zero_suppression: string
+ 'leading' to suppress leading zeros, 'trailing' to suppress trailing zeros.
+ This is the convention used in Gerber files.
+
+ format : tuple (int, int)
+ Decimal format
+
+ zeros : string
+ 'leading' to include leading zeros, 'trailing to include trailing zeros.
+ This is the convention used in Excellon files
+
+ Notes
+ -----
+ Either `zeros` or `zero_suppression` should be specified, there is no need to
+ specify both. `zero_suppression` will take on the opposite value of `zeros`
+ and vice versa
"""
def __init__(self, notation='absolute', units='inch',
- zero_suppression='trailing', format=(2, 5)):
+ zero_suppression=None, format=(2, 5), zeros=None):
if notation not in ['absolute', 'incremental']:
raise ValueError('Notation must be either absolute or incremental')
self.notation = notation
@@ -38,15 +63,52 @@ class FileSettings(object):
raise ValueError('Units must be either inch or metric')
self.units = units
- if zero_suppression not in ['leading', 'trailing']:
- raise ValueError('Zero suppression must be either leading or \
- trailling')
- self.zero_suppression = zero_suppression
+
+ if zero_suppression is None and zeros is None:
+ self.zero_suppression = 'trailing'
+
+ elif zero_suppression == zeros:
+ raise ValueError('Zeros and Zero Suppression must be different. \
+ Best practice is to specify only one.')
+
+ elif zero_suppression is not None:
+ if zero_suppression not in ['leading', 'trailing']:
+ raise ValueError('Zero suppression must be either leading or \
+ trailling')
+ self.zero_suppression = zero_suppression
+
+
+ elif zeros is not None:
+ if zeros not in ['leading', 'trailing']:
+ raise ValueError('Zeros must be either leading or trailling')
+ self.zeros = zeros
+ else:
+ self.zeros = 'leading'
+
if len(format) != 2:
raise ValueError('Format must be a tuple(n=2) of integers')
self.format = format
+ @property
+ def zero_suppression(self):
+ return self._zero_suppression
+
+ @zero_suppression.setter
+ def zero_suppression(self, value):
+ self._zero_suppression = value
+ self._zeros = 'leading' if value == 'trailing' else 'trailing'
+
+ @property
+ def zeros(self):
+ return self._zeros
+
+ @zeros.setter
+ def zeros(self, value):
+
+ self._zeros = value
+ self._zero_suppression = 'leading' if value == 'trailing' else 'trailing'
+
def __getitem__(self, key):
if key == 'notation':
return self.notation
@@ -54,6 +116,8 @@ class FileSettings(object):
return self.units
elif key == 'zero_suppression':
return self.zero_suppression
+ elif key == 'zeros':
+ return self.zeros
elif key == 'format':
return self.format
else:
@@ -69,11 +133,18 @@ class FileSettings(object):
if value not in ['inch', 'metric']:
raise ValueError('Units must be either inch or metric')
self.units = value
+
elif key == 'zero_suppression':
if value not in ['leading', 'trailing']:
raise ValueError('Zero suppression must be either leading or \
trailling')
self.zero_suppression = value
+
+ elif key == 'zeros':
+ if value not in ['leading', 'trailing']:
+ raise ValueError('Zeros must be either leading or trailling')
+ self.zeros = value
+
elif key == 'format':
if len(value) != 2:
raise ValueError('Format must be a tuple(n=2) of integers')
@@ -86,7 +157,6 @@ class FileSettings(object):
self.format == other.format)
-
class CamFile(object):
""" Base class for Gerber/Excellon files.
@@ -131,11 +201,13 @@ class CamFile(object):
self.notation = settings['notation']
self.units = settings['units']
self.zero_suppression = settings['zero_suppression']
+ self.zeros = settings['zeros']
self.format = settings['format']
else:
self.notation = 'absolute'
self.units = 'inch'
self.zero_suppression = 'trailing'
+ self.zeros = 'leading'
self.format = (2, 5)
self.statements = statements if statements is not None else []
self.primitives = primitives
diff --git a/gerber/excellon.py b/gerber/excellon.py
index 17b870a..79a6e1f 100755
--- a/gerber/excellon.py
+++ b/gerber/excellon.py
@@ -43,7 +43,9 @@ def read(filename):
An ExcellonFile created from the specified file.
"""
- return ExcellonParser(None).parse(filename)
+ # File object should use settings from source file by default.
+ settings = FileSettings(**detect_excellon_format(filename))
+ return ExcellonParser(settings).parse(filename)
class ExcellonFile(CamFile):
@@ -116,7 +118,7 @@ class ExcellonParser(object):
def __init__(self, settings=None):
self.notation = 'absolute'
self.units = 'inch'
- self.zero_suppression = 'leading'
+ self.zeros = 'leading'
self.format = (2, 4)
self.state = 'INIT'
self.statements = []
@@ -126,7 +128,7 @@ class ExcellonParser(object):
self.pos = [0., 0.]
if settings is not None:
self.units = settings.units
- self.zero_suppression = settings.zero_suppression
+ self.zeros = settings.zeros
self.notation = settings.notation
self.format = settings.format
@@ -207,7 +209,7 @@ class ExcellonParser(object):
elif 'INCH' in line or 'METRIC' in line:
stmt = UnitStmt.from_excellon(line)
self.units = stmt.units
- self.zero_suppression = stmt.zero_suppression
+ self.zeros = stmt.zeros
self.statements.append(stmt)
elif line[:3] == 'M71' or line [:3] == 'M72':
@@ -270,8 +272,7 @@ class ExcellonParser(object):
def _settings(self):
return FileSettings(units=self.units, format=self.format,
- zero_suppression=self.zero_suppression,
- notation=self.notation)
+ zeros=self.zeros, notation=self.notation)
def detect_excellon_format(filename):
@@ -293,7 +294,7 @@ def detect_excellon_format(filename):
results = {}
detected_zeros = None
detected_format = None
- zs_options = ('leading', 'trailing', )
+ zeros_options = ('leading', 'trailing', )
format_options = ((2, 4), (2, 5), (3, 3),)
# Check for obvious clues:
@@ -301,7 +302,7 @@ def detect_excellon_format(filename):
p.parse(filename)
# Get zero_suppression from a unit statement
- zero_statements = [stmt.zero_suppression for stmt in p.statements
+ zero_statements = [stmt.zeros for stmt in p.statements
if isinstance(stmt, UnitStmt)]
# get format from altium comment
@@ -316,19 +317,19 @@ def detect_excellon_format(filename):
# Bail out here if possible
if detected_format is not None and detected_zeros is not None:
- return {'format': detected_format, 'zero_suppression': detected_zeros}
+ return {'format': detected_format, 'zeros': detected_zeros}
# Only look at remaining options
if detected_format is not None:
format_options = (detected_format,)
if detected_zeros is not None:
- zs_options = (detected_zeros,)
+ zeros_options = (detected_zeros,)
# Brute force all remaining options, and pick the best looking one...
- for zs in zs_options:
+ for zeros in zeros_options:
for fmt in format_options:
- key = (fmt, zs)
- settings = FileSettings(zero_suppression=zs, format=fmt)
+ key = (fmt, zeros)
+ settings = FileSettings(zeros=zeros, format=fmt)
try:
p = ExcellonParser(settings)
p.parse(filename)
@@ -351,7 +352,7 @@ def detect_excellon_format(filename):
# Bail out here if we got everything....
if detected_format is not None and detected_zeros is not None:
- return {'format': detected_format, 'zero_suppression': detected_zeros}
+ return {'format': detected_format, 'zeros': detected_zeros}
# Otherwise score each option and pick the best candidate
else:
@@ -362,7 +363,7 @@ def detect_excellon_format(filename):
minscore = min(scores.values())
for key in scores.iterkeys():
if scores[key] == minscore:
- return {'format': key[0], 'zero_suppression': key[1]}
+ return {'format': key[0], 'zeros': key[1]}
def _layer_size_score(size, hole_count, hole_area):
diff --git a/gerber/excellon_statements.py b/gerber/excellon_statements.py
index 02bb923..71009d8 100644
--- a/gerber/excellon_statements.py
+++ b/gerber/excellon_statements.py
@@ -360,16 +360,16 @@ class UnitStmt(ExcellonStatement):
@classmethod
def from_excellon(cls, line):
units = 'inch' if 'INCH' in line else 'metric'
- zero_suppression = 'trailing' if 'LZ' in line else 'leading'
- return cls(units, zero_suppression)
+ zeros = 'leading' if 'LZ' in line else 'trailing'
+ return cls(units, zeros)
- def __init__(self, units='inch', zero_suppression='trailing'):
+ def __init__(self, units='inch', zeros='leading'):
self.units = units.lower()
- self.zero_suppression = zero_suppression
+ self.zeros = zeros
def to_excellon(self, settings=None):
stmt = '%s,%s' % ('INCH' if self.units == 'inch' else 'METRIC',
- 'LZ' if self.zero_suppression == 'trailing'
+ 'LZ' if self.zeros == 'leading'
else 'TZ')
return stmt
diff --git a/gerber/tests/test_cam.py b/gerber/tests/test_cam.py
index ce4ec44..1aeb18c 100644
--- a/gerber/tests/test_cam.py
+++ b/gerber/tests/test_cam.py
@@ -64,5 +64,28 @@ def test_camfile_settings():
"""
cf = CamFile()
assert_equal(cf.settings, FileSettings())
-
- \ No newline at end of file
+
+def test_zeros():
+
+ fs = FileSettings()
+ assert_equal(fs.zero_suppression, 'trailing')
+ assert_equal(fs.zeros, 'leading')
+
+
+ fs['zero_suppression'] = 'leading'
+ assert_equal(fs.zero_suppression, 'leading')
+ assert_equal(fs.zeros, 'trailing')
+
+ fs.zero_suppression = 'trailing'
+ assert_equal(fs.zero_suppression, 'trailing')
+ assert_equal(fs.zeros, 'leading')
+
+ fs['zeros'] = 'trailing'
+ assert_equal(fs.zeros, 'trailing')
+ assert_equal(fs.zero_suppression, 'leading')
+
+
+ fs.zeros= 'leading'
+ assert_equal(fs.zeros, 'leading')
+ assert_equal(fs.zero_suppression, 'trailing')
+
diff --git a/gerber/tests/test_excellon.py b/gerber/tests/test_excellon.py
index 72e3d7d..70e4560 100644
--- a/gerber/tests/test_excellon.py
+++ b/gerber/tests/test_excellon.py
@@ -15,18 +15,13 @@ def test_format_detection():
"""
settings = detect_excellon_format(NCDRILL_FILE)
assert_equal(settings['format'], (2, 4))
- assert_equal(settings['zero_suppression'], 'leading')
+ assert_equal(settings['zeros'], 'trailing')
def test_read():
ncdrill = read(NCDRILL_FILE)
assert(isinstance(ncdrill, ExcellonFile))
-
+
def test_read_settings():
ncdrill = read(NCDRILL_FILE)
- assert_equal(ncdrill.settings.format, (2, 4))
- assert_equal(ncdrill.settings.zero_suppression, 'leading')
-
-
-
-
-
+ assert_equal(ncdrill.settings['format'], (2, 4))
+ assert_equal(ncdrill.settings['zeros'], 'trailing')
diff --git a/gerber/tests/test_excellon_statements.py b/gerber/tests/test_excellon_statements.py
index 4c3201b..2e508ff 100644
--- a/gerber/tests/test_excellon_statements.py
+++ b/gerber/tests/test_excellon_statements.py
@@ -141,12 +141,22 @@ def test_unitstmt_factory():
line = 'INCH,LZ'
stmt = UnitStmt.from_excellon(line)
assert_equal(stmt.units, 'inch')
- assert_equal(stmt.zero_suppression, 'trailing')
+ assert_equal(stmt.zeros, 'leading')
+
+ line = 'INCH,TZ'
+ stmt = UnitStmt.from_excellon(line)
+ assert_equal(stmt.units, 'inch')
+ assert_equal(stmt.zeros, 'trailing')
+
+ line = 'METRIC,LZ'
+ stmt = UnitStmt.from_excellon(line)
+ assert_equal(stmt.units, 'metric')
+ assert_equal(stmt.zeros, 'leading')
line = 'METRIC,TZ'
stmt = UnitStmt.from_excellon(line)
assert_equal(stmt.units, 'metric')
- assert_equal(stmt.zero_suppression, 'leading')
+ assert_equal(stmt.zeros, 'trailing')
def test_unitstmt_dump():