Skip to content

docs: document the public Graphik API and drawText's center anchoring - #35

Merged
dmccoystephenson merged 2 commits into
mainfrom
feature/document-public-api-contract
Aug 10, 2026
Merged

docs: document the public Graphik API and drawText's center anchoring#35
dmccoystephenson merged 2 commits into
mainfrom
feature/document-public-api-contract

Conversation

@dmccoystephenson

Copy link
Copy Markdown
Member

Summary

  • A docstring has been added to the Graphik class and to all six public methods plus the constructor. The parameter contract a caller needs is now recorded in the source: coordinate anchoring, units, drawButton's repeat-fire callback semantics, and drawImage's path-keyed caching and raise behavior. Before this change inspect.getdoc returned None for the class and every public method, so help(Graphik) and IDE tooltips were empty.
  • The README bullet for drawText now states that xpos/ypos are the center of the rendered text, contrasted against the top-left convention used by drawRectangle, drawButton and drawImage. The drawRectangle bullet has been given the matching top-left note so the contrast is explicit on both sides.
  • A test has been added that pins the center anchoring, so the newly documented claim is enforced by the suite rather than merely asserted in prose.

The existing implementation comments have been left untouched — those answer a maintainer's question ("why is the font cache invalidated this way"), whereas the docstrings answer a caller's ("where does my text land"). The two are complementary.

Why the docstrings matter here specifically

graphik is consumed as a vendored copy of graphik.py in Roam, Apex, Ophidian, Patchwork and Tic-Tak-Toe. The README does not travel with that file, so the source itself is the only documentation a consumer developer has in front of them.

Consumer impact

None. No public member has been renamed, removed, or had its signature changed; no behavior has been altered; no version string has been touched. The change is additive documentation plus one new test, so the consumer-impact gate does not apply.

Test plan

  • python3 -m py_compile src/main/python/preponderous/graphik/graphik.py — succeeds.
  • Import smoke test under SDL_VIDEODRIVER=dummypreponderous.graphik imports and reports 0.3.0.dev20260808.
  • python3 -m pytest — 26 passed (25 before, 1 added).
  • Docstring reachability confirmed through inspect.getdoc for the class and all seven documented members; each returns text where None was returned previously.
  • The new anchoring test was mutation-checked: with textRectangle.center temporarily changed to textRectangle.topleft, the test fails; with the original line restored, it passes. The assertion therefore discriminates between the two anchoring conventions rather than passing vacuously.

Validation was run on Python 3.8.10 with pygame 2.1.2 and pytest 7.1.3. Note that pyproject.toml declares requires-python = ">=3.9", so the sandbox interpreter sits one minor version below the supported floor; the CI matrix in .github/workflows/test.yml covers 3.9 through 3.13 on this PR.

Deferred this cycle

Issue #34 (release tags are pushed without the v prefix that publish.yml requires, so the publish workflow has never run) was filed during triage and deliberately left unimplemented. It touches .github/workflows/ and the release process, and the choice between correcting the tagging practice and broadening the workflow trigger is a maintainer decision rather than an autonomous one.

Closes #32
Closes #33

This PR description was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).


drafted by Claude on behalf of Daniel Stephenson

dmccoystephenson and others added 2 commits August 9, 2026 19:40
Adds a docstring to the Graphik class and to every public method, covering
the parameter contract a caller needs: coordinate anchoring, units, the
repeat-fire semantics of drawButton's callback, and drawImage's path-keyed
caching and raise behavior. help(Graphik) and IDE tooltips previously showed
nothing, which matters most for the vendored copies of graphik.py that
consumers read without the README alongside.

Records in the README that drawText anchors on the center of the rendered
text while drawRectangle, drawButton and drawImage anchor on their top-left
corner, and pins that behavior with a test so the documented claim is
enforced rather than asserted.

The existing implementation comments are left untouched; they answer a
maintainer's question, not a caller's. No behavior, signature or version
change, so no consumer impact.

Closes #32
Closes #33

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Drops the doctest prompts from the class example -- the snippet is
illustrative, and `>>> pygame.init()` would fail if doctest collection were
ever switched on, since init() returns a tuple the example does not show.

Lists drawButton alongside drawRectangle and drawImage in drawText's
anchoring note, matching the class docstring and the README rather than
naming only two of the three top-left-anchored siblings.

Renames a loop variable in the new anchoring test for symmetry with the
line above it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dmccoystephenson

Copy link
Copy Markdown
Member Author

Review

The diff was reviewed against this repository's own conventions and validated on the PR head. Findings are folded into this comment as path:line — finding notes, since a formal Review object with anchored inline comments is not available to this session.

External anchor

  • Compile and testpass on all five supported interpreters (3.9, 3.10, 3.11, 3.12, 3.13), run 31347827265, covering py_compile, the import smoke test, and the headless pytest run. Locally the suite reports 26 passed on Python 3.8.10 / pygame 2.1.2.

Rubric

  • Scope: PASS — three files are touched (README.md, graphik.py, test_graphik.py), each traceable to docs: drawText's center anchoring is undocumented and inconsistent with its siblings #32 or docs: the public Graphik API carries no docstrings, so help() and IDE tooltips are empty #33. The one addition not literally named by either issue is the top-left note on the drawRectangle README bullet; it is retained because docs: drawText's center anchoring is undocumented and inconsistent with its siblings #32's complaint is about an undocumented contrast, which cannot be stated from one side alone. No formatting churn, no renames, no unrelated files.
  • Tests-new: PASS — no new public method was added, so the rule is satisfied vacuously; separately, the one behavioral claim newly written into the docs (center anchoring) is covered by test_draw_text_centers_the_text_on_the_given_position.
  • Tests-fix: PASS (empirical) — no production behavior was changed, so there is no fix to revert. The equivalent check was run as a mutation instead: with textRectangle.center temporarily replaced by textRectangle.topleft, the new test fails at the midpoint assertion; with the original line restored it passes. The assertion therefore discriminates between the two anchoring conventions rather than passing vacuously.
  • Sibling structure: PASS — no new file was created. The added test sits with the other drawText tests, reuses the file's existing _make_graphik and _rgb helpers, and follows the established comment-then-arrange-act-assert shape.
  • Sibling renames: PASS — nothing was renamed.
  • Docs: PASS — a full pass over the documentation sources was run against the implementation. README.md's dependency list still matches the single pygame import; the documented method set matches the class; the anchoring claims were confirmed against textRectangle.center, drawRectangle's rect call, drawButton's delegation to drawRectangle, and drawImage's blit((xpos, ypos)). pyproject.toml and _version.py are untouched, so no version reference can have drifted.
  • Issue resolution: PASSdocs: the public Graphik API carries no docstrings, so help() and IDE tooltips are empty #33's named surface (empty inspect.getdoc for the class and every public method) is fully addressed: all eight now return text. docs: drawText's center anchoring is undocumented and inconsistent with its siblings #32's named surface (the README drawText bullet) is addressed, with the docstring and a test added beyond the minimum.
  • camelCase: PASS — no method was added or renamed; every documented name is the existing camelCase one.
  • Backward-compat: PASS — no public member was renamed, removed, or had its signature changed. The diff adds only docstrings, one README line pair, and one test, so the vendored copies in Roam, Apex, Ophidian, Patchwork and Tic-Tak-Toe are unaffected whenever they next re-vendor.
  • Headless: PASS — the new test creates its surface through _make_graphik, which is governed by the conftest.py dummy SDL drivers; it passed in CI on runners with no display.
  • Version sync: PASS (not applicable) — no version string was changed.
  • No new deps: PASS — no import was added in either the source or the test file.

Findings raised and resolved during review

The first-pass diff was not accepted as-is. Three findings were raised and fixed in 1c58751:

  • src/main/python/preponderous/graphik/graphik.py:20 — the class example was written with >>> doctest prompts while showing no output. It is not collected today (testpaths points at src/test/python), but it would fail immediately if doctest collection were ever enabled, because pygame.init() returns a tuple the example does not display. The prompts were dropped in favor of a plain Example:: block, which is what the snippet actually is.
  • src/main/python/preponderous/graphik/graphik.py:121drawText's anchoring note named only drawRectangle and drawImage as top-left-anchored, omitting drawButton, while the class docstring and the README both name all three. The omission was the kind of partial-series inconsistency this repo's conventions call out; drawButton was added.
  • src/test/python/preponderous/graphik/test_graphik.py:266 — the y-coordinate comprehension bound _y, an underscore-prefixed name for a value that is used, directly beneath a sibling line binding a plain x. Renamed for symmetry.

Observations not blocking merge

  • The new test scans all 20,000 pixels of its 200x100 surface through Surface.get_at. It is the same brute-force shape the neighbouring test_draw_text_blits_non_background_pixels already uses, and the whole suite still completes in roughly 0.2 s, so no optimization was pursued.
  • The vertical assertion is deliberately looser than the horizontal one. Glyph ink is not vertically symmetric within the rendered rect (capitals sit above the baseline, and the rect reserves descender space), so the ink midpoint is offset from the rect center that drawText actually centers — measured at y-midpoint 48 for a requested 50. Only straddling is asserted vertically; the tight midpoint assertion is horizontal, where ink is symmetric.
  • Local validation ran on Python 3.8.10, one minor version below the requires-python = ">=3.9" floor. This is a property of the sandbox, not of the change, and the CI matrix covers the entire supported range on this PR.

Verdict

Approved for merge. The change is additive documentation plus one characterization test, the external anchor is green across every supported interpreter, and no path on the do-not-auto-merge list is touched.

This review comment was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).


drafted by Claude on behalf of Daniel Stephenson

@dmccoystephenson
dmccoystephenson merged commit 6ba2dad into main Aug 10, 2026
5 checks passed
@dmccoystephenson
dmccoystephenson deleted the feature/document-public-api-contract branch August 10, 2026 01:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant