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.