Skip to content

Fix mypy 2.4 errors and enable warn_unused_ignores - #1768

Merged
tleonhardt merged 2 commits into
mainfrom
fix-mypy-2.4
Oct 2, 2026
Merged

tleonhardt merged 2 commits into
mainfrom
fix-mypy-2.4

Conversation

@tleonhardt

Copy link
Copy Markdown
Member

Summary

mypy 2.4.0 switched to its new Ruff-based native parser by default. That parser rejects third-party codes such as ty:unresolved-attribute inside # type: ignore[...] comments, so every combined mypy/ty ignore in cmd2/ produced an Invalid "type: ignore" comment [syntax] error and stopped suppressing the diagnostic it was there for (75 errors in total). Running with --no-native-parser produced no errors, so nothing else in 2.4 affects cmd2.

Commit 1: Split combined ignore comments

The 43 combined comments are now two separate pragmas:

# before
action.get_nargs_range()  # type: ignore[attr-defined, ty:unresolved-attribute]
# after
action.get_nargs_range()  # type: ignore[attr-defined]  # ty: ignore[unresolved-attribute]

This form works with mypy's native and legacy parsers and with ty. The mypy pragma has to come first, and ty still needs its own rule code. This also bumps the ruff pre-commit hook to v0.16.10.

Commit 2: Enable warn_unused_ignores and remove stale ignores

warn_unused_ignores was turned off because mypy's legacy parser reported every ty: code as unused. With the comments split it can be turned back on. That exposed 25 stale or platform-specific ignores. I checked each one with Python 3.11–3.15 on linux, darwin, and win32 so that ignores needed only on some platforms or versions are kept:

  • Removed: 18 ignores that are unused in every configuration. Where a line also had a ty code, the # ty: ignore[...] half stays.
  • Narrowed: the AnsiDecoder.decode monkey-patch ignore, from assignment to method-assign.
  • NoConsoleScreenBufferError: now [no-redef, unused-ignore], because the redefinition only exists on win32.
  • Cmd2HelpFormatter._set_color(): uses if sys.version_info >= (3, 14): instead of an early return. mypy skips version-guarded blocks instead of reporting the rest of the method as unreachable on older Pythons. Behavior is unchanged.
  • Cmd._initial_termios_settings: annotated as list[Any] | None, with an explicit not sys.platform.startswith("win") check added to the two termios restore conditions. mypy had inferred the attribute as always None on win32, so it never checked that POSIX-only code there. The new check changes nothing at runtime: the attribute is always None on Windows, and the termios tests already skip on Windows.

Testing

  • make check, make test, and make docs-test pass.
  • mypy 2.4.0 passes with warn_unused_ignores = true for Python 3.11, 3.12, 3.13, 3.14, and 3.15, each on linux, darwin, and win32. The 3.11–3.14 runs used environments built like the TypeCheck workflow's (--no-default-groups --group validate).
  • ty passes in the 3.11 and 3.14 environments, and reports no unused ty: ignore comments with --warn unused-ignore-comment.

mypy 2.4 switched to its new Ruff-based native parser by default. That
parser rejects third-party codes such as "ty:unresolved-attribute" inside
"# type: ignore[...]" comments, reporting the whole comment as an invalid
"type: ignore" [syntax] error and therefore no longer suppressing the
original diagnostic either.

Split each combined comment into separate mypy and ty pragmas:

    # type: ignore[attr-defined]  # ty: ignore[unresolved-attribute]

The mypy pragma must come first for mypy to recognize it, and ty still
needs its own rule code. This form is accepted by mypy's native and
legacy parsers as well as by ty.

Also bump the ruff pre-commit hook to v0.16.10.
The combined "type: ignore[code, ty:rule]" comments made mypy's legacy
parser flag every ty code as unused, which is why warn_unused_ignores was
disabled. With those split into separate mypy and ty pragmas it can be
turned back on.

Verified against Python 3.11-3.15 on linux, darwin, and win32 so that
ignores needed only on some platforms or versions are kept:

- Remove 18 ignores that are unused in every configuration, keeping the
  "ty: ignore" half where ty still needs it.
- Narrow the AnsiDecoder.decode monkey patch ignore to [method-assign].
- Mark the NoConsoleScreenBufferError fallback ignore as
  [no-redef, unused-ignore] since the redefinition only exists on win32.
- Guard Cmd2HelpFormatter._set_color() with a positive version check
  instead of an early return so mypy skips it on Python < 3.14 rather
  than reporting the rest of the method as unreachable.
- Annotate Cmd._initial_termios_settings as list[Any] | None and add an
  explicit platform check to the termios restore code. Previously mypy
  inferred the attribute as always None on win32 and only avoided
  checking that POSIX-only code because it looked unreachable.
@tleonhardt
tleonhardt requested a review from kmvanbrunt as a code owner October 2, 2026 03:51
@codecov

codecov Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.66%. Comparing base (89bf0a0) to head (1553bf8).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1768      +/-   ##
==========================================
- Coverage   99.66%   99.66%   -0.01%     
==========================================
  Files          23       23              
  Lines        5974     5973       -1     
==========================================
- Hits         5954     5953       -1     
  Misses         20       20              
Flag Coverage Δ
unittests 99.66% <100.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@tleonhardt tleonhardt self-assigned this Oct 2, 2026
@tleonhardt tleonhardt added bug dependencies Pull requests that update a dependency file labels Oct 2, 2026
@tleonhardt
tleonhardt merged commit 4cc2471 into main Oct 2, 2026
31 checks passed
@tleonhardt
tleonhardt deleted the fix-mypy-2.4 branch October 2, 2026 21:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug dependencies Pull requests that update a dependency file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant