Skip to content

Cold-eyes review 2026Q3: twelve findings (S1 FAIL — the README's build recipe targets a src/ layout the repo no longer has) #25

Description

@bdbarnett

Quarterly cold-eyes review, 2026-09-03 (PyDevices/.github#25, standards S1/S4/S6). Read-only inspection by a repo-inspector agent from a fresh clone in a scratch directory; every claim below carries the command or URL that produced it. Filed by Arthur. Nothing here was changed by the review itself.

S1 (clean clone builds per its README): FAIL — the README's only build/authoring recipe cannot run from a fresh clone; the shipped library itself is clean.

S4 (README to working example, first try): PASS (CPython desktop), with one ordering stumble and one stale platform sentence.

Findings (13)

[HIGH] Maintainer build recipe is written against a src/ layout the repo no longer has — hard FileNotFoundError on the first non-optional step

README.md:118 .venv/bin/python scripts/assets_icons_to_py.py --delete-binaries. Run from a fresh clone with deps installed:
../venv-s1/bin/python scripts/assets_icons_to_py.py ->
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/.../coldeyes/pdwidgets/src/pdwidgets/icons'
The package lives in lib/pdwidgets/ (ls -d lib src -> ls: cannot access 'src': No such file or directory). Stale paths: scripts/assets_icons_to_py.py:30, scripts/assets_generate_pdwidgets_icons.py:137, scripts/assets_make_color_icons.py:118, scripts/add_api_docstrings.py:9. By contrast scripts/mkdocs_gen_ref_pages.py correctly walks lib/, so the rename was done half-way. Tagged: defect.

Suggested fix: Repoint the four scripts at lib/pdwidgets/... (or derive the package root once, in one place, from pyproject.toml's [tool.setuptools.packages.find] where = ["lib"]), and add a CI smoke step that at least imports/dry-runs each script in scripts/ so the next layout move fails loudly.

[HIGH] README states publication is TestPyPI-only; production PyPI has pydevices-pdwidgets 0.0.22 and pip install pydevices-pdwidgets works

README.md:91-92: "Publication to TestPyPI only (rather than PyPI) is deliberate."
curl -s https://pypi.org/pypi/pydevices-pdwidgets/json -> 200, info.version = 0.0.22.
pip install pydevices-pdwidgets (plain PyPI, fresh venv) -> Successfully installed pydevices-0.3.7 pydevices-palettes-0.0.12 pydevices-pdwidgets-0.0.22 pydevices-pygraphics-0.0.37; import pdwidgets succeeds.
The whole chain is mirror-parked one release behind (PyPI: pydevices 0.3.7, pygraphics 0.0.37, palettes 0.0.12, desktop 0.3.7 vs TestPyPI 0.3.8/0.0.38/0.0.13/0.3.8). The mirror-park itself is the approved ledger decision; the README sentence denying it is not. A stranger's reflex command therefore yields a different, older version than the README's own command, with no warning. Tagged: doc-stale.

Suggested fix: Rewrite README.md:91-92 to say what is true: the production PyPI names are mirror-parked and may trail; the TestPyPI index is the current release channel; give the exact command for each and say which version each yields today.

[MEDIUM] CircuitPython is claimed on the README's first line with no install route, no CI, no demo, and no recorded exclusion

README.md:5 "It runs seamlessly on MicroPython, CircuitPython, CPython desktop, and PyScript (Web)"; re-asserted README.md:87; badge at docs/index.md:10. But grep -rin "circup|CIRCUITPY|adafruit" README.md docs/ lib/ pdwidgets.toml manifest.py returns nothing — the Installation section (README.md:66-80) offers MIP and pip only. .github/workflows/tests.yml runs one ubuntu CPython 3.13 job; there is no CircuitPython build, freeze, or import check. grep -rin "not supported|unsupported|excluded|limitation|caveat" README.md docs/*.md returns nothing, so no exclusion is recorded either. Under design-principles.md §1 this is a claimed pairing that is neither delivered nor recorded — worse than claim-without-demo, since a CircuitPython reader has no route at all. Tagged: defect (completeness).

Suggested fix: Either add the CircuitPython install route (circup/bundle or a manifest-circuitpython path) plus one demo a stranger can watch, or record the exclusion with its honest cause in the README's "Support and platforms" section — and in either case publish the repo's pairing axes as an explicit support matrix (runtime x display backend x input device) so the mesh is inspectable.

[MEDIUM] No platform claim carries a proof tier, and the one recorded exclusion states a state rather than a cause

grep -rin "bench-proven|ci-proven|community-verified|proof tier" . across README.md, docs/, *.yml, *.toml returns nothing. README.md:5 and 87 make four unlabeled platform claims; docs/index.md:10 makes five (adds "Direct WebAssembly"), so the two surfaces do not even agree. dotgithub/docs/platform-support-tiers.md:8-9 requires every platform claim in a PyDevices README to carry one of the three labels. README.md:90-91 "there are no macOS or ARM-Linux wheels yet" is the repo's only exclusion and gives no cause (per the maiden-run ruling, a label is not a cause). Tagged: defect.

Suggested fix: Label each platform claim in README.md:87-92 with its tier — CPython desktop and PyScript are demonstrable today, MicroPython from the MIP publication, CircuitPython at whatever tier is honest — and give the macOS/ARM-Linux gap its cause (no bench Mac, no ARM runner) rather than only its state.

[MEDIUM] requires-python = ">=3.8" is unsatisfiable: no dependency wheel exists below cp310 and there is no sdist

pyproject.toml:10 requires-python = ">=3.8".
pip download -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ --python-version 39 --only-binary=:all: -d dl39 pydevices-pdwidgets ->
ERROR: ResolutionImpossible ... Additionally, some packages in these conflicts have no matching distributions available for your environment: pydevices-eventsys, pydevices-pygraphics.
TestPyPI pydevices-pygraphics 0.0.38 ships cp310-cp314 wheels only (manylinux x86_64, win_amd64, android, pyemscripten) and no sdist. So the declared floor is two minor versions below anything installable. Tagged: defect.

Suggested fix: Raise requires-python to the floor the wheel matrix actually supports (>=3.10), or publish an sdist/pure-Python fallback for pygraphics so the declared floor is honest. Seam note: the wheel matrix is pygraphics' to own; the false metadata claim is pdwidgets'.

[MEDIUM] README points at docs/index.md for "board_config requirements"; that document contains none

README.md:82-83: "Full dependency chain and board_config requirements: docs/index.md."
grep -rn "board_config" docs/ -> only docs/index.md:130,135,136 (three uses inside the "Practical App Skeleton" code block) and docs/app-recipes.md:14,16,17 / :49,51,52 / :83,85,86 — likewise bare uses. Nothing in docs/ explains where board_config comes from or how to get one. The only explanation in the repo is the README's own note at lines 16-21, which is what the pointer sends the reader away from. Tagged: defect.

Suggested fix: Either add a short "board_config" section to docs/index.md covering the desktop and on-board routes, or drop the forward reference and keep README.md:16-21 as the single source.

[MEDIUM] Documented focus API display.focus_manager.set_focus() does not exist

docs/input-and-events.md:73-74:

# Programmatically set focus
display.focus_manager.set_focus(button)

Live probe against the installed 0.0.23 wheel: display.focus_manager: True, set_focus: False. grep -rn "set_focus" lib/ returns nothing; lib/pdwidgets/_focus.py:44 defines def focus(self, widget). The repo's doc-example checker (tests/test_doc_examples.py) is static and, by its own docstring, only validates pdwidgets-rooted imports, pd.X attribute access and constructor kwargs — a method call on a local instance is outside its coverage, so this shipped with a green suite. Tagged: defect.

Suggested fix: Fix the snippet to display.focus_manager.focus(button), and extend test_doc_examples.py to resolve attribute chains on locals whose constructor it already resolved to a pdwidgets class (the checker already knows display came from pd.Display).

[MEDIUM] libSDL2 is an undocumented hard prerequisite for the desktop quickstart

grep -rin "sdl|apt install|system dependenc|prerequisit" README.md docs/*.md -> one hit only, README.md:122 (SDL_VIDEODRIVER=dummy, which sets a driver, not a dependency). The desktop board_config loads SDL2 by ctypes at import: usdl2.py:727-739 ctypes.CDLL("SDL2.dll") / names ("libSDL2-2.0.so.0", "libSDL2.so"), raising Could not load SDL2 library; tried: ... otherwise. find venv/lib/python3.12/site-packages -iname "*SDL2*" finds only Python shims — no bundled library; my run succeeded solely because ldconfig -p | grep -i sdl2 shows the host already has /lib/x86_64-linux-gnu/libSDL2-2.0.so.0. On a clean machine the README's very first snippet line (import board_config) fails. Tagged: defect.

Suggested fix: Add one line to the README Installation section naming the system package per OS (e.g. sudo apt install libsdl2-2.0-0), or state that it is inherited from pydevices-desktop and link that repo's prerequisite section.

[LOW] README's icon recipe claims TestPyPI pygraphics suffices; the published wheel lacks the API the script needs

README.md:117 comment: "uses sibling or TestPyPI pygraphics". scripts/assets_icons_to_py.py:35-60 requires hasattr(FrameBuffer, "export") and otherwise pip-installs pydevices-pygraphics from TestPyPI. Against the installed wheel: hasattr(pygraphics.FrameBuffer, 'export') -> False (dir() shows from_file/save but no export). scripts/assets_icons_to_py.py --no-install -> graphics is not importable with FrameBuffer.export; omit --no-install or use sibling pygraphics/lib; the default path pip-installs the same wheel and proceeds anyway. export exists only in the pure-Python sibling: /home/brad/gh/pydevices/pygraphics/lib/pygraphics/_framebuf_plus.py:620. So the TestPyPI half of that claim is false and the sibling is mandatory. Tagged: defect.

Suggested fix: Correct the README comment to say the sibling pygraphics checkout is required, or export FrameBuffer.export from the compiled pygraphics wheel so the auto-install path can actually work.

[LOW] Brad's private workspace layout is hard-coded as a fallback search path in two shipped tools

scripts/assets_convert_md_png_to_pbm.py:37 and tools/png_test.py:31 both list Path.home() / "gh" / "pydevices" / "pydevices-examples" among their candidates; the failure message printed it verbatim on my machine: Tried: /tmp/.../coldeyes/pydevices-examples, /home/brad/gh/pydevices/pydevices-examples. Per the modernization plan §1, "Anything that works only in Brad's workspace is a defect by definition." Mitigating: both honour PYDEVICES_EXAMPLES_ROOT, try the sibling first, and fail with a useful message — so this is a smell rather than a breakage. Tagged: defect (low).

Suggested fix: Drop the $HOME/gh/pydevices candidate and keep env var + sibling; the message already tells the user exactly what to set.

[LOW] README documents no way to run the tests or provision the .venv it then invokes

grep -in "test|pytest|contribut|develop" README.md matches only TestPyPI URLs and the icon-recipe lines — there is no Development/Contributing/Testing section. The working recipe exists only in AGENTS.md (PYTHONPATH="lib:tests/stubs:../pydevices/lib:../pygraphics/lib:../palettes/lib" .venv/bin/python -m unittest discover -s tests), which the README never links, and .github/workflows/tests.yml:52-56. Yet README.md:115-120 invokes .venv/bin/python four times as if that venv were a documented artifact. S1's "run its tests" therefore has no README-reachable path. Tagged: defect (low).

Suggested fix: Add a four-line Development section to the README: create the venv, install the three sibling deps (or the TestPyPI wheels), run python -m unittest discover -s tests and ruff check lib tests scripts — the same commands CI runs, so they cannot drift silently.

[LOW] Org platform-tiers doc claims macOS wheels PyDevices does not ship

dotgithub/docs/platform-support-tiers.md:44-47: "PyDevices ships everything for macOS that CI can prove — wheels, imports, unit and contract tests on macOS runners". Observed: TestPyPI pydevices-pygraphics 0.0.38 publishes cp310-cp314 wheels for manylinux x86_64, win_amd64, android_21_{arm64_v8a,x86_64} and pyemscripten only — no macosx tag, and no sdist. pdwidgets' own README.md:90-91 says so plainly ("there are no macOS or ARM-Linux wheels yet"), i.e. the repo is honest and the org doc is stale. Seam: the wheel matrix belongs to pygraphics; the stale sentence belongs to dotgithub. Tagged: doc-stale.

Suggested fix: Update platform-support-tiers.md's macOS posture to match what is published (no macOS wheels for the native pygraphics surface today; pure-Python surfaces only), or add macOS wheel builds to pygraphics' release matrix so the posture becomes true.

[LOW] Doc snippet prints a widget repr where it promises the button's text

docs/input-and-events.md:41-46 defines button = pd.Button(screen, label="Click Me", ...) then print(f"Button '{sender.label}' clicked at coordinates: {event.pos}"). Live: button.label -> ID 3 Label (a Label widget object, not the string). AGENTS.md's own widget contract says buttons take label= as a content kwarg, so the getter returning the child widget is by design; the doc example just reads wrong to a stranger copying it. Tagged: defect (low).

Suggested fix: Use sender.label.value in the snippet, or add a text accessor and use it.

Each finding is independent; tick them off here or split any that deserves its own thread.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions