Skip to content

Guard get_ipython() being Optional (fixes mypy on master) - #1088

Merged
emeryberger merged 1 commit into
masterfrom
fix-ipython-mypy-union-attr
Jul 31, 2026
Merged

Guard get_ipython() being Optional (fixes mypy on master)#1088
emeryberger merged 1 commit into
masterfrom
fix-ipython-mypy-union-attr

Conversation

@emeryberger

Copy link
Copy Markdown
Member

The linters workflow is failing on master, independently of any PR.

IPython 9.16 annotates get_ipython() as returning Optional[InteractiveShell], and history_manager is itself optional. mypy 2.3 therefore reports four union-attr errors in scalene_tracing.py:157 and scalene_magics.py:43. The existing # type: ignore[no-untyped-call, unused-ignore] on those lines doesn't cover that error code — mypy says so explicitly:

scalene/scalene_tracing.py:157: error: Item "None" of "InteractiveShell | None" has no attribute "history_manager"  [union-attr]
scalene/scalene_tracing.py:157: note: Error code "union-attr" not covered by "type: ignore[no-untyped-call, unused-ignore]" comment
scalene/scalene_tracing.py:157: error: Item "None" of "Any | None" has no attribute "input_hist_raw"  [union-attr]
scalene/scalene_magics.py:43: error: Item "None" of "InteractiveShell | None" has no attribute "history_manager"  [union-attr]
scalene/scalene_magics.py:43: note: Error code "union-attr" not covered by "type: ignore[no-untyped-call, unused-ignore]" comment
scalene/scalene_magics.py:43: error: Item "None" of "Any | None" has no attribute "input_hist_raw"  [union-attr]
Found 4 errors in 2 files (checked 66 source files)

No commit caused this. Master's last linters run was 2026-07-05 and passed, and nothing has landed since — it broke on its own when CI's unpinned pip install mypy ruff types-PyYAML pydantic started resolving newer versions. Confirmed by dispatching the workflow against unmodified master: run 30640136643 fails with the identical four errors.

Fix

Guard both levels — the shell and its history manager:

  • _handle_jupyter_cell() returns False without a live shell, falling through to the ordinary filename rules. That's the behavior it already had when the cell regex didn't match.
  • run_code() prints a plain message and returns. Neither value can really be None there — a magic only runs inside a live shell — so this exists to satisfy the type checker without an AttributeError as the fallback.

The # type: ignore comments stay: on older IPython get_ipython() is untyped, so no-untyped-call still applies, and unused-ignore keeps the comment valid once it no longer does.

Verification

  • Reproduced in a venv pinned to CI's exact versions (mypy 2.3.0, IPython 9.16.0): 4 errors before, Success: no issues found in 66 source files after. ruff check scalene clean.
  • Re-checked against the older pair (mypy 1.19.0, IPython 9.9.0) so the fix holds in both directions — no new errors; only the unrelated, pre-existing scalene_signal_manager.py:314 one that mypy 2.3 doesn't flag.
  • Behavior spot-checked for all three shapes: live shell (recovers the cell contents, writes the file, returns True), get_ipython() returning None, and history_manager being None — the last two return cleanly instead of raising.
  • Full pytest suite: 442 passed, 13 skipped.

Found while checking CI on #1087, which is blocked by this same failure.

🤖 Generated with Claude Code

The linters workflow has been failing on master since IPython 9.16
started annotating get_ipython() as returning Optional[InteractiveShell]
(history_manager is optional too). mypy 2.3 reports four union-attr
errors in scalene_tracing.py and scalene_magics.py; the existing
"type: ignore[no-untyped-call, unused-ignore]" on those lines does not
cover that error code, and says so.

No commit caused this -- master's last linters run (2026-07-05) passed
and nothing has landed since, so it broke when CI's unpinned
"pip install mypy ruff ..." picked up the newer versions.

Guard both levels. _handle_jupyter_cell() returns False without a live
shell, falling through to the ordinary filename rules, which is the
behavior it already had when the cell regex didn't match. run_code()
prints a plain message and returns; neither value can actually be None
there, since a magic only runs inside a live shell.

The ignore comments stay put: on older IPython, get_ipython() is
untyped, so no-untyped-call still applies, and unused-ignore keeps the
comment valid once it doesn't.

Verified in a venv pinned to CI's exact versions (mypy 2.3.0, IPython
9.16.0): 4 errors before, clean after, ruff clean. Also re-checked
against the older pair (mypy 1.19.0, IPython 9.9.0) so the fix holds in
both directions. Behavior spot-checked for all three shapes -- live
shell (recovers the cell and returns True), get_ipython() None, and
history_manager None. Full pytest suite: 442 passed, 13 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@emeryberger
emeryberger merged commit 202ae93 into master Jul 31, 2026
38 of 41 checks passed
@emeryberger
emeryberger deleted the fix-ipython-mypy-union-attr branch July 31, 2026 15:56
emeryberger added a commit that referenced this pull request Jul 31, 2026
Picks up the get_ipython() Optional guard (#1088) so this branch's
linters check runs against a fixed master.
emeryberger added a commit that referenced this pull request Jul 31, 2026
Brings in the non-ASCII path fix (#1087), the get_ipython() Optional
guard (#1088), and the free-threaded CI setup fix (#1089).
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.

1 participant