Documentation Index
Fetch the complete documentation index at: https://mintlify.com/KiCad/kicad-source-mirror/llms.txt
Use this file to discover all available pages before exploring further.
Overview
KiCad provides a powerful Python scripting interface that allows you to automate board design tasks, create custom workflows, and extend functionality. The Python API is built using SWIG (Simplified Wrapper and Interface Generator) and exposes core KiCad classes and functions.
Python Environment
Initialization
The Python scripting environment is initialized when KiCad starts. The system uses the SCRIPTING class defined in /scripting/python_scripting.h:
class SCRIPTING
{
public:
SCRIPTING();
~SCRIPTING();
static bool IsWxAvailable();
static bool IsModuleLoaded( std::string& aModule );
enum PATH_TYPE {
STOCK, // Bundled scripts
USER, // User scripts
THIRDPARTY // Third-party plugins
};
static wxString PyScriptingPath( PATH_TYPE aPathType = STOCK );
static wxString PyPluginsPath( PATH_TYPE aPathType = STOCK );
};
Thread Safety
When interacting with the Python API from C++, use the PyLOCK class to ensure thread safety:
PyLOCK lock;
// Perform Python operations here
Core API Functions
The main Python API is exposed through pcbnew_scripting_helpers.h. Here are the essential functions:
Board Management
import pcbnew
# Get the currently active board
board = pcbnew.GetBoard()
# Load a board from file
board = pcbnew.LoadBoard("/path/to/file.kicad_pcb")
# Load with specific format
board = pcbnew.LoadBoard("/path/to/file.kicad_pcb",
pcbnew.IO_MGR.KICAD_SEXP)
# Create a new empty board
board = pcbnew.CreateEmptyBoard()
# Create a new board with project
filename = "/path/to/new_board.kicad_pcb"
board = pcbnew.NewBoard(filename)
# Save a board
pcbnew.SaveBoard("/path/to/output.kicad_pcb", board)
Accessing Board Elements
# Get all footprints
for footprint in board.GetFootprints():
print(f"Reference: {footprint.GetReference()}")
print(f"Value: {footprint.GetValue()}")
print(f"Position: {footprint.GetPosition()}")
# Get all tracks
for track in board.GetTracks():
print(f"Start: {track.GetStart()}")
print(f"End: {track.GetEnd()}")
print(f"Width: {track.GetWidth()}")
print(f"Layer: {track.GetLayer()}")
# Get all zones (copper pours)
for i in range(board.GetAreaCount()):
zone = board.GetArea(i)
print(f"Net: {zone.GetNetname()}")
print(f"Layer: {zone.GetLayer()}")
# Get all drawings
for drawing in board.GetDrawings():
print(f"Class: {drawing.GetClass()}")
print(f"Layer: {drawing.GetLayer()}")
Unit Conversion
KiCad internally uses nanometers. Use these functions for conversion:
# Convert from millimeters to internal units
position_x = pcbnew.FromMM(10.5) # 10.5mm
# Convert from mils to internal units
width = pcbnew.FromMils(10) # 10 mils
# Convert to millimeters
mm_value = pcbnew.ToMM(position_x)
# Convert to mils
mils_value = pcbnew.ToMils(width)
# Using VECTOR2I for positions
position = pcbnew.VECTOR2I_MM(10, 20) # x=10mm, y=20mm
Modifying Board Elements
# Create a new track
track = pcbnew.PCB_TRACK(board)
track.SetStart(pcbnew.VECTOR2I_MM(10, 10))
track.SetEnd(pcbnew.VECTOR2I_MM(20, 20))
track.SetWidth(pcbnew.FromMM(0.25))
track.SetLayer(pcbnew.F_Cu)
board.Add(track)
# Create a via
via = pcbnew.PCB_VIA(board)
via.SetPosition(pcbnew.VECTOR2I_MM(15, 15))
via.SetDrill(pcbnew.FromMM(0.3))
via.SetWidth(pcbnew.FromMM(0.6))
via.SetViaType(pcbnew.VIATYPE_THROUGH)
board.Add(via)
# Create a zone
zone = pcbnew.ZONE(board)
zone.SetLayer(pcbnew.F_Cu)
zone.SetNetCode(net.GetNetCode())
board.Add(zone)
# Remove an item (proper undo/redo support)
board.RemoveNative(footprint)
Plot Generation
Generate various output files programmatically:
# Create plot controller
pctl = pcbnew.PLOT_CONTROLLER(board)
popt = pctl.GetPlotOptions()
# Configure plot options
popt.SetOutputDirectory("output/")
popt.SetPlotFrameRef(False)
popt.SetAutoScale(False)
popt.SetScale(1)
popt.SetMirror(False)
popt.SetUseGerberAttributes(True)
# Plot a single layer to PDF
pctl.SetLayer(pcbnew.F_SilkS)
pctl.OpenPlotfile("Silk", pcbnew.PLOT_FORMAT_PDF, "Assembly guide")
pctl.PlotLayer()
# Plot Gerber files
layers = [
("CuTop", pcbnew.F_Cu, "Top layer"),
("CuBottom", pcbnew.B_Cu, "Bottom layer"),
("PasteTop", pcbnew.F_Paste, "Paste top"),
("MaskTop", pcbnew.F_Mask, "Mask top"),
]
for name, layer_id, description in layers:
pctl.SetLayer(layer_id)
pctl.OpenPlotfile(name, pcbnew.PLOT_FORMAT_GERBER, description)
pctl.PlotLayer()
# Always close the plot controller
pctl.ClosePlot()
# Get all configured footprint libraries
libraries = pcbnew.GetFootprintLibraries()
for lib in libraries:
print(f"Library: {lib}")
# Get footprints from a specific library
footprints = pcbnew.GetFootprints("Capacitor_SMD")
for fp in footprints:
print(f"Footprint: {fp}")
DRC (Design Rule Check)
# Run DRC and save report
result = pcbnew.WriteDRCReport(
board,
"/path/to/drc_report.txt",
pcbnew.EDA_UNITS_MILLIMETRES,
True # Report all track errors
)
# Export to SPECCTRA DSN format
pcbnew.ExportSpecctraDSN(board, "/path/to/output.dsn")
# Import SPECCTRA SES
pcbnew.ImportSpecctraSES(board, "/path/to/input.ses")
# Export to VRML
pcbnew.ExportVRML(
"/path/to/output.wrl",
1.0, # MM to VRML unit scale
True, # Include unspecified components
False, # Include DNP components
True, # Export 3D files
True, # Use relative paths
"3d/", # 3D files subdirectory
0.0, # X reference
0.0 # Y reference
)
Interactive Features
When running in the PCBNew GUI:
# Get user units (inches or mm)
user_units = pcbnew.GetUserUnits()
# Returns: 0 = Inches, 1 = mm, -1 if frame not set
# Get current selection
selection = pcbnew.GetCurrentSelection()
for item in selection:
print(f"Selected: {item.GetClass()}")
# Focus view on an item
pcbnew.FocusOnItem(footprint, pcbnew.F_Cu)
# Refresh the display
pcbnew.Refresh()
# Update UI (layer manager, etc.)
pcbnew.UpdateUserInterface()
# Check if running in action plugin context
if pcbnew.IsActionRunning():
print("Running as action plugin")
Advanced Examples
def create_custom_resistor(value, ref_prefix="R"):
"""Create a custom SMD resistor footprint"""
footprint = pcbnew.FOOTPRINT(board)
footprint.SetReference(ref_prefix + "1")
footprint.SetValue(value)
# Create pads
pad_size = pcbnew.VECTOR2I_MM(1.0, 1.5)
pad_spacing = pcbnew.FromMM(2.0)
for i, name in enumerate(["1", "2"]):
pad = pcbnew.PAD(footprint)
pad.SetSize(pad_size)
pad.SetShape(pcbnew.PAD_SHAPE_RECT)
pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD)
pad.SetLayerSet(pad.SMDMask())
pad.SetPadName(name)
x_pos = -pad_spacing/2 if i == 0 else pad_spacing/2
pad.SetPosition(pcbnew.VECTOR2I(x_pos, 0))
footprint.Add(pad)
# Add silkscreen
silk = pcbnew.PCB_SHAPE(footprint)
silk.SetStart(pcbnew.VECTOR2I_MM(-2, -1))
silk.SetEnd(pcbnew.VECTOR2I_MM(2, -1))
silk.SetLayer(pcbnew.F_SilkS)
silk.SetWidth(pcbnew.FromMM(0.15))
footprint.Add(silk)
return footprint
Batch Processing
import os
import glob
def process_all_boards(directory):
"""Process all KiCad boards in a directory"""
for filepath in glob.glob(os.path.join(directory, "*.kicad_pcb")):
print(f"Processing: {filepath}")
board = pcbnew.LoadBoard(filepath)
# Perform operations
for footprint in board.GetFootprints():
# Example: Update all resistor values
if footprint.GetValue().startswith("10k"):
footprint.SetValue("10.0k")
# Save changes
pcbnew.SaveBoard(filepath, board)
Error Handling
try:
board = pcbnew.LoadBoard("/path/to/board.kicad_pcb")
if board is None:
print("Failed to load board")
except Exception as e:
print(f"Error: {e}")
import traceback
traceback.print_exc()
Best Practices
- Always close plot controllers: Call
pctl.ClosePlot() when finished
- Use proper units: Always convert to internal units using
FromMM() or FromMils()
- Validate board loading: Check if
LoadBoard() returns None
- Avoid print statements: Print statements can cause issues when running from GUI
- Use RemoveNative(): For proper undo/redo support when removing items
- Lock Python GIL: Use
PyLOCK when calling from C++
Common Pitfalls
- Unicode handling: Always encode/decode strings properly for cross-platform compatibility
- Layer IDs: Use layer constants like
F_Cu, B_Cu instead of numeric values
- Coordinate system: KiCad uses internal units (nanometers), not millimeters
- Memory management: Some objects are owned by the board, others must be explicitly added
See Also