summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/bench.py60
-rw-r--r--examples/load_directory.py11
-rwxr-xr-xgerbonara/excellon.py4
-rw-r--r--gerbonara/rs274x.py27
4 files changed, 94 insertions, 8 deletions
diff --git a/examples/bench.py b/examples/bench.py
new file mode 100644
index 0000000..b8d8c36
--- /dev/null
+++ b/examples/bench.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+
+import time
+from pathlib import Path
+
+import tqdm
+
+import gerbonara
+
+if __name__ == '__main__':
+ resources = Path(__file__).parent.parent / 'gerbonara' / 'tests' / 'resources'
+
+ TEST_FILES = [
+ 'easyeda/Gerber_TopSilkLayer.GTO',
+ 'allegro-2/MinnowMax_RevA1_GAF_Gerber/MinnowMax_lyr3.art',
+ 'allegro-2/MinnowMax_RevA1_GAF_Gerber/MinnowMax_fab.art',
+ 'eagle-newer/soldermask_bottom.gbr',
+ 'eagle-newer/copper_bottom.gbr',
+# FIXME remove redundant warnings in these files
+# 'siemens/80101_0125_F200_SilkscreenBottom.gdo',
+# 'siemens/80101_0125_F200_SoldermaskBottom.gdo',
+# 'siemens/80101_0125_F200_SolderPasteBottom.gdo',
+# 'siemens/80101_0125_F200_L03.gdo',
+# 'siemens/80101_0125_F200_L01_Top.gdo',
+# 'zuken-emulated/Gerber/Symbol-A.fph',
+ 'Target3001/IRNASIoTbank1.2.StopTop',
+ 'Target3001/IRNASIoTbank1.2.PasteTop',
+ 'Target3001/IRNASIoTbank1.2.PasteBot',
+ 'Target3001/IRNASIoTbank1.2.StopBot',
+ 'Target3001/IRNASIoTbank1.2.Top',
+ 'pcb-rnd/power-art.gtl',
+ 'pcb-rnd/power-art.gto',
+ 'pcb-rnd/power-art.gtp',
+ 'altium-composite-drill/Gerber/LimeSDR-QPCIe_1v2.G1',
+ 'altium-composite-drill/Gerber/LimeSDR-QPCIe_1v2.G2',
+ 'altium-composite-drill/Gerber/LimeSDR-QPCIe_1v2.G3',
+ 'altium-composite-drill/Gerber/LimeSDR-QPCIe_1v2.G4',
+ 'altium-composite-drill/Gerber/LimeSDR-QPCIe_1v2.G5',
+ 'altium-composite-drill/Gerber/LimeSDR-QPCIe_1v2.G6',
+ 'altium-composite-drill/Gerber/LimeSDR-QPCIe_1v2.G7',
+ 'altium-composite-drill/Gerber/LimeSDR-QPCIe_1v2.G8',
+ 'altium-composite-drill/Gerber/LimeSDR-QPCIe_1v2.G9',
+ 'altium-composite-drill/Gerber/LimeSDR-QPCIe_1v2.G10',
+ 'altium-composite-drill/Gerber/LimeSDR-QPCIe_1v2.G11',
+ 'altium-composite-drill/Gerber/LimeSDR-QPCIe_1v2.G12',
+ 'altium-composite-drill/Gerber/LimeSDR-QPCIe_1v2.GBS',
+ 'eagle_files/copper_top_l1.gbr',
+ 'eagle_files/soldermask_top.gbr',
+ 'diptrace/mainboard_Bottom.gbr',
+ 'upverter/design_export.gtp',
+ 'upverter/design_export.gbl',
+ ]
+
+ start = time.perf_counter()
+ for file in TEST_FILES: #tqdm.tqdm(TEST_FILES):
+ gerbonara.GerberFile.open(resources / file)
+ end = time.perf_counter()
+
+ print(f'Duration: {(end - start)*1000:.3f} ms')
+
diff --git a/examples/load_directory.py b/examples/load_directory.py
new file mode 100644
index 0000000..6e1f901
--- /dev/null
+++ b/examples/load_directory.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python3
+
+if __name__ == '__main__':
+ import argparse
+ parser = argparse.ArgumentParser()
+ parser.add_argument('input', help='Input Gerber directory')
+ args = parser.parse_args()
+
+ import gerbonara
+ print(gerbonara.LayerStack.from_directory(args.input))
+
diff --git a/gerbonara/excellon.py b/gerbonara/excellon.py
index 5f0db44..721fcca 100755
--- a/gerbonara/excellon.py
+++ b/gerbonara/excellon.py
@@ -535,6 +535,7 @@ class ExcellonParser(object):
self.lineno = None
self.filename = None
self.external_tools = external_tools or {}
+ self.found_kicad_format_comment = False
def warn(self, msg):
warnings.warn(f'{self.filename}:{self.lineno} "{self.line}": {msg}', SyntaxWarning)
@@ -844,7 +845,7 @@ class ExcellonParser(object):
integer, _, fractional = match[3][1:].partition('.')
self.settings.number_format = len(integer), len(fractional)
- elif self.settings.number_format == (None, None) and not metric:
+ elif self.settings.number_format == (None, None) and not metric and not self.found_kicad_format_comment:
self.warn('Using implicit number format from bare "INCH" statement. This is normal for Fritzing, Diptrace, Geda and pcb-rnd.')
self.settings.number_format = (2,4)
@@ -981,6 +982,7 @@ class ExcellonParser(object):
x = None if x == '-' else int(x)
y = None if y == '-' else int(y)
self.settings.number_format = x, y
+ self.found_kicad_format_comment = True
self.settings.notation = match[2]
self.settings.unit = Inch if match[3] == 'inch' else MM
diff --git a/gerbonara/rs274x.py b/gerbonara/rs274x.py
index 82ee047..e29ecd8 100644
--- a/gerbonara/rs274x.py
+++ b/gerbonara/rs274x.py
@@ -520,11 +520,11 @@ class GerberParser:
NAME = r"[a-zA-Z_$\.][a-zA-Z_$\.0-9+\-]+"
STATEMENT_REGEXES = {
- 'region_start': r'G36$',
- 'region_end': r'G37$',
'coord': fr"(?P<interpolation>G0?[123]|G74|G75|G54|G55)?(X(?P<x>{NUMBER}))?(Y(?P<y>{NUMBER}))?" \
fr"(I(?P<i>{NUMBER}))?(J(?P<j>{NUMBER}))?" \
fr"(?P<operation>D0?[123])?$",
+ 'region_start': r'G36$',
+ 'region_end': r'G37$',
'aperture': r"(G54|G55)?D(?P<number>\d+)",
# Allegro combines format spec and unit into one long illegal extended command.
'allegro_format_spec': r"FS(?P<zero>(L|T|D))?(?P<notation>(A|I))[NG0-9]*X(?P<x>[0-7][0-7])Y(?P<y>[0-7][0-7])[DM0-9]*\*MO(?P<unit>IN|MM)",
@@ -581,12 +581,25 @@ class GerberParser:
self.lineno = None
self.line = None
+ def _shorten_line(self):
+ line_joined = self.line.replace('\r', '').replace('\n', '\\n')
+ if len(line_joined) > 80:
+ return f'{line_joined[:20]}[...]{line_joined[-20:]}'
+ else:
+ return line_joined
+
def warn(self, msg, kls=SyntaxWarning):
- line_joined = self.line.replace('\n', '\\n')
- warnings.warn(f'{self.filename}:{self.lineno} "{line_joined}": {msg}', kls)
+ warnings.warn(f'{self.filename}:{self.lineno} "{self._shorten_line()}": {msg}', kls)
@classmethod
def _split_commands(kls, data):
+ for match in re.finditer(r'G04.*?\*|%.*?%|[^*%]*\*', data, re.DOTALL):
+ cmd = match[0].strip().strip('%').rstrip('*').replace('\r', '').replace('\n', '')
+ if cmd:
+ yield 1, cmd
+ return
+
+ #######
start = 0
extended_command = False
lineno = 1
@@ -637,13 +650,13 @@ class GerberParser:
try:
getattr(self, f'_parse_{name}')(match)
except Exception as e:
- raise SyntaxError(f'{filename}:{lineno} "{line}": {e}') from e
+ raise SyntaxError(f'{filename}:{lineno} "{self._shorten_line()}": {e}') from e
line = line[match.end(0):]
break
else:
- self.warn(f'Unknown statement found: "{line}", ignoring.', UnknownStatementWarning)
- self.target.comments.append(f'Unknown statement found: "{line}", ignoring.')
+ self.warn(f'Unknown statement found: "{self._shorten_line()}", ignoring.', UnknownStatementWarning)
+ self.target.comments.append(f'Unknown statement found: "{self._shorten_line()}", ignoring.')
self.target.apertures = list(self.aperture_map.values())
self.target.import_settings = self.file_settings