The parser KicadPCB are written using a python S-Expression parser, the
sexp_parser. To get this submodule, after checkout this repository, do
git submodule init git submodule update
The KicadPCB parser shall be able to handle both kicad_pcb and
kicad_mod file. The parser does not perform semantic check, though. For
that you'll need to write a large collection of sub-parsers that handle every
possible keyword. It'll be very tedious, but still easy with the help of
SexpParser. Check out the sample code here.
To get the python object model of a kicad_pcb or kicad_mod file
from kicad_parser import KicadPCB pcb = KicadPCB.load(filename)
Check for error
for e in pcb.getError():
print('Error: {}'.format(e))
You can modify, add, or delete any expressions inside. You can use . to
access any non numerical keys such as
pcb.general.zone
For numerical keys, and in fact, all type of keys, you can use []
pcb['layers']['0']
Or
pcb.layers['0']
But not
pcb.layers[0]
Because for (layers ( 0 F.cu single) ...) expression here, the 0 is
treated as a string key instead of an integer index.
For multiple instances with the same key at the same level, you should access the value by integer index, such as
pcb.module[0]
For un-named values (i.e. any atom behind the key), use their appearance index
for accessing, skipping any named values. For example, to access an expression
like (drill oval 1.0 2.0)
drill.oval drill[0] == 1.0 drill[1] == 2.0
The 'oval' above would normally be treated as an un-named value, too. However,
KicadPCB treats several special un-named values as named boolean type
value. Their appearance in the S-Expression source means True, otherwise
means False. These expressions are always accessible through the object
model regardless of their appearance in the source. When doing export(),
those False values will be ignored. These special values are
gr_text.hide pad.drill.oval module.locked
This list is obviously not complete. But, it's easy to add your own mappings. Check out the source code here
KicadPCB also treats specal keyword as un-named boolean type, they are
'yes', 'Yes', 'true', 'True', 'no', 'No', 'false', 'False'
To list the sub keys of a composite expression
for subkey in pcb:
print(subkey)
It will also list integer keys for un-named values if there is any.
To delete an expression
del pcb.layers['0']
To create expressions, you'll need to import the general S-Expression Parser
from kicad_parser import *
For multiple expressions with the same key, they will be stored into an object
of type sexp_parser.SexpList the parser will automatically create this list
object to hold the multiple instances. To check if it is a list
isinstance(pcb.module,SexpList)
To add a simple expression (0 new.layer signal),
pcb.layers['0'] = Sexp('0',[ 'new.layer', 'signal' ])
Note that if there is already an expression with the same key, = will not
overwrite the existing one. Instead, it will use SexpList to hold multiple
instances
To add a composite expression
pcb.module[0].model = SexpParser(parseSexp(
"""(model new/model3
(at (xyz 1 2 3))
(scale (xyz 3 5 6))
(rotate (xyz 7.0 8.0 9.0)))
""")
If you are not sure whether a key in the object model holds a single expression
or multiple instances, you can use SexpList to make sure it is a list
if 'module' in pcb:
for m in SexpList(pcb.module):
print(m)
KicadPCB will ensure several common keys to be presented even if there is
none, in which case an empty SexpList will be inserted. And if there is
only one instance, it will still be inside a SexpList. This is to spare
the pain of the boilerplate code above. The default keys are
net
net_class
add_net
dimension
gr_text
gr_line
gr_circle
gr_arc
gr_curve
segment
via
module
fp_text
fp_line
fp_circle
fp_arc
pad
model
To export the modified object model back to kicad_pcb file
pcb.export(filename)
Or to output stream
pcb.export(sys.stdout)
To export any Sexp
exportSexp(pcb.general,sys.stdout)
See sample code here for more details.