55import os
66import re
77import json
8+ import logging
89import sys
910
1011sys .path .append (os .path .dirname (__file__ ))
1112import units
1213
14+ logging .basicConfig (level = logging .INFO ,
15+ stream = sys .stdout ,
16+ format = "%(asctime)-15s %(levelname)s %(message)s" )
17+ is_cli = False
18+
1319
1420def generate_bom (pcb , filter_layer = None ):
1521 """
@@ -111,7 +117,7 @@ def parse_draw_segment(d):
111117 pcbnew .S_POLYGON : "polygon" ,
112118 }.get (d .GetShape (), "" )
113119 if shape == "" :
114- print "Unsupported shape" , d .GetShape (), "skipping."
120+ logging . info ( "Unsupported shape %s, skipping " , d .GetShape ())
115121 return None
116122 start = normalize (d .GetStart ())
117123 end = normalize (d .GetEnd ())
@@ -147,8 +153,8 @@ def parse_draw_segment(d):
147153 if hasattr (d , "GetPolyShape" ):
148154 polygons = parse_poly_set (d .GetPolyShape ())
149155 else :
150- print "Polygons not supported for KiCad 4"
151- polygons = []
156+ logging . info ( "Polygons not supported for KiCad 4, skipping" )
157+ return None
152158 angle = 0
153159 if d .GetParentModule () is not None :
154160 angle = d .GetParentModule ().GetOrientation () * 0.1 ,
@@ -165,8 +171,8 @@ def parse_poly_set(polygon_set):
165171 for polygon_index in xrange (polygon_set .OutlineCount ()):
166172 outline = polygon_set .Outline (polygon_index )
167173 if not hasattr (outline , "PointCount" ):
168- print "No PointCount method on outline object. " \
169- "Unpatched kicad version?"
174+ logging . warn ( "No PointCount method on outline object. " \
175+ "Unpatched kicad version?" )
170176 return result
171177 parsed_outline = []
172178 for point_index in xrange (outline .PointCount ()):
@@ -188,7 +194,6 @@ def parse_text(d):
188194 angle = d .GetTextAngle () * 0.1
189195 else :
190196 angle = d .GetOrientation () * 0.1
191- print d , angle
192197 if hasattr (d , "GetTextHeight" ):
193198 height = d .GetTextHeight () * 1e-6
194199 width = d .GetTextWidth () * 1e-6
@@ -215,7 +220,7 @@ def parse_drawing(d):
215220 elif d .GetClass () in ["PTEXT" , "MTEXT" ]:
216221 return parse_text (d )
217222 else :
218- print "Unsupported drawing class" , d .GetClass (), "skipping."
223+ logging . info ( "Unsupported drawing class %s, skipping " , d .GetClass ())
219224 return None
220225
221226
@@ -231,7 +236,8 @@ def parse_edges(pcb):
231236 bbox = d .GetBoundingBox ()
232237 else :
233238 bbox .Merge (d .GetBoundingBox ())
234- bbox .Normalize ()
239+ if bbox :
240+ bbox .Normalize ()
235241 return edges , bbox
236242
237243
@@ -315,7 +321,8 @@ def parse_modules(pcb):
315321 shape_lookup [pcbnew .PAD_SHAPE_CUSTOM ] = "custom"
316322 shape = shape_lookup .get (p .GetShape (), "" )
317323 if shape == "" :
318- print "Unsupported pad shape" , p .GetShape (), "skipping."
324+ logging .info ("Unsupported pad shape %s, skipping." ,
325+ p .GetShape ())
319326 continue
320327 pad_dict = {
321328 "layers" : layers ,
@@ -328,9 +335,10 @@ def parse_modules(pcb):
328335 if shape == "custom" :
329336 polygon_set = p .GetCustomShapeAsPolygon ()
330337 if polygon_set .HasHoles ():
331- print 'Detected holes in custom pad polygons'
338+ logging . warn ( 'Detected holes in custom pad polygons' )
332339 if polygon_set .IsSelfIntersecting ():
333- print 'Detected self intersecting polygons in custom pad'
340+ logging .warn (
341+ 'Detected self intersecting polygons in custom pad' )
334342 pad_dict ["polygons" ] = parse_poly_set (polygon_set )
335343 if shape == "roundrect" :
336344 pad_dict ["radius" ] = p .GetRoundRectCornerRadius () * 1e-6
@@ -377,7 +385,7 @@ def get_file_content(file_name):
377385 with open (os .path .join (os .path .dirname (__file__ ), file_name ), "r" ) as f :
378386 return f .read ()
379387
380- print "Dumping pcb json data"
388+ logging . info ( "Dumping pcb json data" )
381389 bom_file_name = os .path .join (dir , "ibom.html" )
382390 if not os .path .isdir (os .path .dirname (bom_file_name )):
383391 os .makedirs (os .path .dirname (bom_file_name ))
@@ -390,14 +398,18 @@ def get_file_content(file_name):
390398 html = html .replace ('///IBOMJS///' , get_file_content ('ibom.js' ))
391399 with open (bom_file_name , "wt" ) as bom :
392400 bom .write (html )
393- print "Created file" , bom_file_name
401+ logging . info ( "Created file %s " , bom_file_name )
394402 return bom_file_name
395403
396404
397405def main (pcb , launch_browser = True ):
398406 pcb_file_name = pcb .GetFileName ()
399407 if not pcb_file_name :
400- wx .MessageBox ('Please save the board file before generating BOM.' )
408+ msg = 'Please save the board file before generating BOM.'
409+ if is_cli :
410+ logging .error (msg )
411+ else :
412+ wx .MessageBox (msg )
401413 return
402414
403415 bom_file_dir = os .path .join (os .path .dirname (pcb_file_name ), "bom" )
@@ -414,6 +426,14 @@ def main(pcb, launch_browser=True):
414426 # remove .kicad_pcb extension
415427 title = os .path .splitext (title )[0 ]
416428 edges , bbox = parse_edges (pcb )
429+ if bbox is None :
430+ msg = 'Please draw pcb outline on the edges ' \
431+ 'layer before generating BOM.'
432+ if is_cli :
433+ logging .error (msg )
434+ else :
435+ wx .MessageBox (msg )
436+ return
417437 bbox = {
418438 "minx" : bbox .GetLeft () * 1e-6 ,
419439 "miny" : bbox .GetTop () * 1e-6 ,
@@ -433,10 +453,6 @@ def main(pcb, launch_browser=True):
433453 },
434454 "bom" : {},
435455 }
436- if len (pcbdata ["edges" ]) == 0 :
437- wx .MessageBox ('Please draw pcb outline on the edges '
438- 'layer before generating BOM.' )
439- return
440456 pcbdata ["bom" ]["both" ] = generate_bom (pcb )
441457
442458 # build BOM
@@ -447,7 +463,7 @@ def main(pcb, launch_browser=True):
447463 bom_file = generate_file (bom_file_dir , pcbdata )
448464
449465 if launch_browser :
450- print "Opening file in browser"
466+ logging . info ( "Opening file in browser" )
451467 open_file (bom_file )
452468
453469
@@ -471,6 +487,8 @@ def Run(self):
471487
472488
473489if __name__ == "__main__" :
490+ is_cli = True
491+
474492 import argparse
475493
476494 parser = argparse .ArgumentParser (
0 commit comments