Skip to content

Fix graphviz_draw return type annotation and docstring (PIL.Image -> PIL.Image.Image) - #1637

Merged
IvanIsCoding merged 4 commits into
Qiskit:mainfrom
juan52878911:fix/graphviz-draw-return-type-1357
Jul 20, 2026
Merged

Fix graphviz_draw return type annotation and docstring (PIL.Image -> PIL.Image.Image)#1637
IvanIsCoding merged 4 commits into
Qiskit:mainfrom
juan52878911:fix/graphviz-draw-return-type-1357

Conversation

@juan52878911

Copy link
Copy Markdown
Contributor

Summary

graphviz_draw was annotated and documented as returning the PIL.Image module instead of the PIL.Image.Image class. This fixes the runtime annotation and the docstring, and adds regression tests.

Fixes #1357.

Root cause

rustworkx/visualization/graphviz.py does from PIL import Image, so within that module Image is the module PIL.Image, not the image class. The return annotation was therefore:

def graphviz_draw(...) -> Image | None:   # Image is the *module* here

which annotates the return value with a module. The docstring had the matching mistake (:rtype: PIL.Image). This PR changes them to Image.Image | None and :rtype: PIL.Image.Image.

Why the stub (graphviz.pyi) is intentionally left untouched

This is the non-obvious part, and the reason the fix touches graphviz.py and not the stub:

  • The stub already does from PIL.Image import Image (the class) and returns Image, so it was already correct — git log shows it has imported the class since before enhance visualization func type hint #1443.
  • When a .pyi stub exists, static type checkers use the stub and ignore the .py implementation. So the wrong annotation in graphviz.py is invisible to mypy/pyright at call sites, and pyright --verifytypes (the tool cited in graphviz typing error #1357) reads the already-correct stub.

In other words, the specific --verifytypes symptom from the original report (filed against 0.15.1) is no longer reproducible on main at the stub level — but the implementation annotation and the rendered docstring were still wrong, which is what this PR fixes.

How this was found

While adding a regression test, a negative control (reverting the fix and re-running the checks) surfaced the stub-vs-implementation split above: a typing.assert_type test kept passing even with the bug reintroduced, because it validates the stub. The bug only manifests when something reads the implementation's own annotation:

>>> import typing
>>> from rustworkx.visualization.graphviz import graphviz_draw
>>> typing.get_type_hints(graphviz_draw)
TypeError: unsupported operand type(s) for |: 'module' and 'NoneType'   # before the fix

After the fix, get_type_hints(graphviz_draw)["return"] correctly resolves to PIL.Image.Image | None.

Tests

tests/visualization/test_graphviz_typing.py guards both fronts so neither can regress:

  1. Runtime guard (get_type_hints + docstring) over the implementation — this is what actually catches graphviz typing error #1357. Verified it fails without the fix (TypeError on the annotation; AssertionError on the :rtype: docstring) and passes with it.
  2. Static guard (assert_type under TYPE_CHECKING) over every stub overload — filename=None → Image, filename=str → None, with image_type as both a Literal and an arbitrary str. Wired into the existing stubs nox session via mypy so CI enforces it.

Verified locally against a fresh build (rustworkx main, Pillow 12.3, mypy 1.17.1, pyright 1.1.411): runtime tests pass, mypy/pyright clean on the typing test, and stubtest still passes.

How this helps the project

  • Correct rendered docs: Sphinx autodoc reads the .py docstring, so the API reference for graphviz_draw showed PIL.Image (a module) as the return type. Users now see the correct PIL.Image.Image.
  • Correct runtime introspection: any tooling calling typing.get_type_hints/inspect.signature on graphviz_draw no longer crashes with TypeError and gets the right type.
  • Regression safety on two axes: the new tests lock in both the implementation annotation and the public stub overloads, so a future edit to either can't silently reintroduce the module-vs-class confusion. The stub coverage is a small but real strengthening of the typing test surface.

🤖 Generated with Claude Code

graphviz_draw was annotated and documented as returning the PIL.Image
module instead of the PIL.Image.Image class. Because graphviz.py does
`from PIL import Image`, `Image` is the module, so `-> Image | None`
annotated the return with a module rather than the image class.

Correct the runtime annotation to `Image.Image | None` and the
`:returns:`/`:rtype:` docstring to `PIL.Image.Image`. The stub
(graphviz.pyi) already imported the class and was correct, so it is
left unchanged.

Add tests/visualization/test_graphviz_typing.py with two guards:
- a runtime check (get_type_hints + docstring) for the implementation,
  which is what actually regressed here since the stub shadows the
  implementation for static type checkers; and
- a static assert_type check for every stub overload, wired into the
  `stubs` nox session via mypy.

Fixes Qiskit#1357
@CLAassistant

CLAassistant commented Jul 15, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 29712307288

Coverage remained the same at 94.694%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 20299
Covered Lines: 19222
Line Coverage: 94.69%
Coverage Strength: 913006.18 hits per line

💛 - Coveralls

@IvanIsCoding

Copy link
Copy Markdown
Collaborator

Listen, the fix for the type annotations is correct and it will be merged. With that being said, the tests were so bad I had to revert them. I had to make the decision to test things manually rather than relying on that token waste.

The repository does not have an AI contribution policy yet, but your PR is closer to #1587 (comment) than to let's say #1594. If the fix wasn't that simple, this would have been rejected with no further discussion.

If you ask any LLM to perform an "adversarial review", it will highlight that the test you contributed is "weird". It's the only type checking test besides stubgen, it has bizarre docstring assertions we don't use anywhere else, and so many other oddities. Do you actively care about this project? Because if you cared, you would not have sent that file. Please send things from the most expensive model and that at least has some sort of human veto.

I already noticed in #1638 that you ignored comments from the original issue on how to fix things i.e. using IndexSet which I explicitly mentioned in the issue. You can try contributing again, but if you keep this "extractivist" style I'd rather as Codex or Antigravity to fix the issues myself. Show you care about the project and not about yourself.

@mergify

mergify Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@IvanIsCoding
IvanIsCoding added this pull request to the merge queue Jul 20, 2026
Merged via the queue into Qiskit:main with commit e44a675 Jul 20, 2026
40 checks passed
@juan52878911

Copy link
Copy Markdown
Contributor Author

Thank you for the honest feedback — you're right, and I appreciate you taking the time instead of just closing this.

The core mistake was mine: I didn't supervise the AI-generated code properly. I sent a test file I hadn't reviewed carefully enough against the repo's existing conventions, and reverting it was the right call. Same with #1638 — the issue clearly pointed at IndexSet and I should have followed that.

I do care about this project and want to keep learning from it. Going forward I won't open a PR with code I can't explain myself, and I'll follow what's already discussed in the issue before writing anything.

Sorry for the extra review work, and thanks for the fix.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

graphviz typing error

4 participants