From 513b4cd924492a7c92c1a9b7cf27572495ff200a Mon Sep 17 00:00:00 2001 From: zackees Date: Sun, 21 Jun 2026 23:30:48 -0700 Subject: [PATCH] fix(install): use src-layout package-dir so editable install ships a .pth (not a PEP 660 finder) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The per-package `package-dir = {fbuild = "python/fbuild", "fbuild.api" = "python/fbuild/api"}` map worked for the wheel build but made setuptools' editable install emit a PEP 660 meta-path finder (`__editable___fbuild_*_finder.py`) whose `MAPPING` only registered `fbuild`. `fbuild.api` resolved at runtime via `importlib.machinery.PathFinder` — fine for `import fbuild.api`, but invisible to static analyzers (ty, pyright, mypy) that walk `top_level.txt` and `.pth` files. Downstream consumers (FastLED hit this on `from fbuild.api import SerialMonitor`) saw `Cannot resolve imported module 'fbuild.api'` even though runtime imports worked. Replace the per-package map with the canonical src-layout pattern `package-dir = {"" = "python"}`. Setuptools now emits a plain `.pth` pointing at `python/`, which every static analyzer handles, and the wheel-build path is unaffected. Verified: - Wheel (`python -m build`): byte-for-byte identical to baseline (10,454,675 B). Same contents: `fbuild/__init__.py`, `fbuild/_native.pyd`, `fbuild/api/__init__.py`, `fbuild-2.2.31.data/scripts/fbuild.exe`, dist-info. - Sdist: +2,811 B / +0.12%, entirely from `fbuild.egg-info/` relocating to `python/fbuild.egg-info/`. Cosmetic. - `ci/publish.py::build_wheel` is independent of setuptools — it hand-rolls wheels from the hard-coded `PYTHON_SHIMS_DIR = ROOT / "python"`. Smoke-tested: still finds the same 2 shims (`fbuild/__init__.py`, `fbuild/api/__init__.py`). Release path unaffected. - Editable reinstall path: ~8s (FastLED → fbuild via uv sources), within noise of baseline. No regression to the perf work in #743 / #744. Co-Authored-By: Claude Opus 4.7 (1M context) --- pyproject.toml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a5515be7..94c99724 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,14 +60,19 @@ build-backend = "setuptools.build_meta" packages = ["fbuild", "fbuild.api"] include-package-data = true -# Map the `fbuild` and `fbuild.api` Python packages to their on-disk -# location under python/. Without this, `pip install .` would skip the -# python/ tree entirely, and downstream consumers like FastLED would hit -# `ModuleNotFoundError: No module named 'fbuild'` on -# `from fbuild.api import SerialMonitor`. +# Tell setuptools the package root is `python/` — `python/fbuild/`, +# `python/fbuild/api/`, and any future submodule are discovered relative +# to it. The previous per-package map (`fbuild = "python/fbuild"`, +# `"fbuild.api" = "python/fbuild/api"`) worked for the wheel build but +# confused setuptools' editable install: it emitted a PEP 660 meta-path +# finder whose MAPPING only registered the top-level `fbuild` package, +# so static analyzers (ty, pyright, mypy) saw `Cannot resolve imported +# module 'fbuild.api'` in downstream consumers even though runtime +# imports worked via the finder's PathFinder fallback. With this +# src-layout mapping, setuptools instead emits a plain `.pth` pointing +# at `python/`, which every static analyzer handles. [tool.setuptools.package-dir] -fbuild = "python/fbuild" -"fbuild.api" = "python/fbuild/api" +"" = "python" # Ship `_native.pyd`/.so that `python/fbuild/__init__.py` imports from. # The cargo-built `fbuild[.exe]` CLI binary is NOT package data — it is