From df02627134cabd99d92d521b91125e0cdaf90f59 Mon Sep 17 00:00:00 2001 From: mixelpixx Date: Sat, 30 May 2026 09:47:25 -0400 Subject: [PATCH] fix(windows): derive PYTHONPATH from the detected KiCAD python (#84) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit findPythonExecutable already auto-detects KiCAD's bundled python across versions (10.0/9.0/…) and both Program Files and per-user %LOCALAPPDATA% installs, but the spawn still defaulted PYTHONPATH to a hardcoded "C:/Program Files/KiCad/9.0/..." path. So a KiCad 10 or per-user user whose python.exe was found correctly still got the wrong PYTHONPATH unless they set it by hand — the exact manual fixup people keep posting in #84. Add deriveKiCadSitePackages(pythonExe): for a detected KiCAD python at //bin/python.exe it returns the matching site-packages (<...>/bin/Lib/site-packages, or the older lib/python3/dist-packages layout), verified to exist. Use it as the PYTHONPATH default. Precedence is unchanged at the top: explicit PYTHONPATH env override still wins; the legacy 9.0 string remains only as a last-resort fallback, so this can't regress below current behavior. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/server.ts | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/server.ts b/src/server.ts index f6f5264..fd92766 100644 --- a/src/server.ts +++ b/src/server.ts @@ -71,6 +71,29 @@ function getWindowsKiCadPythonCandidates(): string[] { return [...new Set(candidates)]; } +/** + * Derive the KiCAD bundled-Python site-packages path for a detected python.exe, + * so PYTHONPATH follows the *same* install we picked (any version, Program Files + * or per-user %LOCALAPPDATA%) instead of a hardcoded KiCad 9.0 path. + * + * KiCAD on Windows installs python at `//bin/python.exe`, with + * pcbnew under `<...>/bin/Lib/site-packages` (older/alt layouts use + * `/lib/python3/dist-packages`). Returns the first existing candidate, + * or undefined if pythonExe isn't a KiCAD bundled python. + */ +function deriveKiCadSitePackages(pythonExe: string): string | undefined { + if (process.platform !== "win32") return undefined; + const lower = pythonExe.toLowerCase(); + if (!lower.endsWith("python.exe") || !lower.includes("kicad")) return undefined; + const binDir = dirname(pythonExe); // //bin + const versionDir = dirname(binDir); // / + const candidates = [ + join(binDir, "Lib", "site-packages"), + join(versionDir, "lib", "python3", "dist-packages"), + ]; + return candidates.find((p) => existsSync(p)); +} + /** * Find the Python executable to use. * Prioritizes project venvs, then explicit overrides, then KiCAD-bundled Python @@ -475,12 +498,21 @@ export class KiCADMcpServer { if (!isValid) { throw new Error("Prerequisites validation failed. See logs above for details."); } + // PYTHONPATH precedence: explicit env override → site-packages derived + // from the detected KiCAD python (any version / install location) → + // legacy 9.0 fallback as a last resort. + const derivedSitePackages = deriveKiCadSitePackages(pythonExe); + if (derivedSitePackages && !process.env.PYTHONPATH) { + logger.info(`Using KiCAD site-packages: ${derivedSitePackages}`); + } this.pythonProcess = spawn(pythonExe, [this.kicadScriptPath], { stdio: ["pipe", "pipe", "pipe"], env: { ...process.env, PYTHONPATH: - process.env.PYTHONPATH || "C:/Program Files/KiCad/9.0/lib/python3/dist-packages", + process.env.PYTHONPATH || + derivedSitePackages || + "C:/Program Files/KiCad/9.0/lib/python3/dist-packages", }, });