I am running the latest nightly build and trying to use Python to control the PCB editor.
My script is able to locate the footprint and print its current values. However, when I try to update the position by changing the position
property and calling update_items
, no change happens to the board.
Since documentation on the new API seems sparse I am not sure if I’m just doing it wrong, or if there is actually a bug in the API. I also don’t want to invest a ton of time in learning the SWIG API if it is to be deprecated in less than a year anyway.
EDIT: I’ve dug a bit into the kicad-python library and I don’t see any issues there. This code:
return [
unwrap(result.item)
for result in self._kicad.send(command, UpdateItemsResponse).updated_items
]
seems to be taking the response from the API and extracting the updated items list. When I modified this code and checked the items inside of updated_items
, the reference to J1 in there still has its original position.
I also tried printing out the proto
for the item before it goes into the API call, and it does have the position
section in that code. I did notice that if I set the position to 0,0
it doesn’t include it, so I tried changing it to 1,1
and the position
section is included in the proto. However the update still does not change the position and the position remains the original position after the board is re-queried. So I’m starting to think this may be a bug in KiCad.
EDIT 2: I tried tracing the API calls using the instructions here and I get this error (and only this error) on the console when my Python script runs:
Trace: (KICAD_API) Any message type type.googleapis.com/kiapi.board.types.Footprint3DModel is not known
Here is my Python script:
from typing import Dict, List
from kipy import KiCad
from kipy.board import Board, FootprintInstance
from kipy.geometry import Vector2
from kipy.board_types import TextBox
def get_duplicate_strings(strings: List[str]) -> List[str]:
seen = set()
duplicates = set()
for s in strings:
if s in seen:
duplicates.add(s)
else:
seen.add(s)
return list(duplicates)
def get_footprints(b: Board) -> Dict[str, FootprintInstance]:
all_footprints = b.get_footprints()
# verify that all footprint IDs are unique
footprint_id_dupes = get_duplicate_strings([i.reference_field.text.value for i in all_footprints])
# if "REF**" appears in the dupe list, remove it.
if 'REF**' in footprint_id_dupes:
footprint_id_dupes.remove('REF**')
assert len(footprint_id_dupes) == 0
footprints = {str(i.reference_field.text.value): i for i in all_footprints}
if 'REF**' in footprints:
del footprints['REF**']
return footprints
def main():
k = KiCad()
print(f"Connected to KiCad {k.get_version()}")
# look for the PCB
pcb = k.get_board()
if pcb is None:
print('No PCB is open.')
return
# TESTING CODE TO DEMONSTRATE CRASH:
# Find item J1 in the PCB.
items = get_footprints(pcb)
j1 = items.get('J1')
if j1 is None:
print('No footprint J1 found.')
return
# Print the position of J1
print("J1 is at: ",end='')
print(j1.position)
# Position J1
print("Moving J1 to 0,0")
j1.position = Vector2.from_xy(0, 0)
print("J1 is now at: ",end='')
print(j1.position)
print("Sending update to KiCad")
try:
pcb.update_items([j1])
# Save the PCB
pcb.save()
except Exception as e:
print("Could not update the PCB: " + str(e))
print("PCB update sent.")
items = get_footprints(pcb)
j1 = items.get('J1')
print("After update J1 is at: ",end='')
print(j1.position)
if __name__ == '__main__':
main()
A run of the code:
[fmillion@d178 script]$ poetry run python script.py
Connected to KiCad 9.99.0-701-g151cb01795-dirty
J1 is at: Vector2(23262500, 69862500)
Moving J1 to 0,0
J1 is now at: Vector2(0, 0)
Sending update to KiCad
PCB update sent.
After update J1 is at: Vector2(23262500, 69862500)
Version:
Application: KiCad PCB Editor x86_64 on x86_64
Version: 9.99.0-701-g151cb01795-dirty, release build
Libraries:
wxWidgets 3.2.6
FreeType 2.13.3
HarfBuzz 10.4.0
FontConfig 2.16.0
libcurl/8.12.1 OpenSSL/3.4.1 zlib/1.3.1 brotli/1.1.0 zstd/1.5.7 libidn2/2.3.7 libpsl/0.21.5 libssh2/1.11.1 nghttp2/1.65.0 nghttp3/1.8.0
Platform: Arch Linux, 64 bit, Little endian, wxGTK, X11, KDE, x11
OpenGL: Intel, Mesa Intel(R) UHD Graphics 630 (CFL GT2), 4.6 (Compatibility Profile) Mesa 24.3.4-arch1.1
Build Info:
Date: Mar 28 2025 04:12:43
wxWidgets: 3.2.6 (wchar_t,wx containers) GTK+ 3.24
Boost: 1.87.0
OCC: 7.8.1
Curl: 8.12.1
ngspice: 44.2
Compiler: GCC 14.2.1 with C++ ABI 1019
Build settings:
KICAD_USE_EGL=ON
KICAD_IPC_API=ON
Locale:
Lang: en_US
Enc: UTF-8
Num: 1234.5
Encoded кΩ丈: D0BACEA9E4B888 (sys), D0BACEA9E4B888 (utf8)
(I am on Nightly because Arch doesn’t seem to package RC or beta versions, and the packaged stable 9.0.0 crashes with a segfault whenever you call update_items
.)