Skip to content

Make mypy and pyright fail CI, and fix their errors - #2942

Merged
pvcraven merged 2 commits into
developmentfrom
ci/blocking-type-checks
Oct 8, 2026
Merged

pvcraven merged 2 commits into
developmentfrom
ci/blocking-type-checks

Conversation

@pvcraven

@pvcraven pvcraven commented Oct 8, 2026

Copy link
Copy Markdown
Member

Summary

mypy and pyright now fail the Code Quality check, like the ruff steps since #2940. Both had existing errors (40 mypy, 11 pyright), and all of them are fixed. Three were real crashes:

Bugs found

  • self.camera on a window crashed: platformer tutorial steps 07–19, gl/custom_sprite, the lights tutorial and experimental/perspective_parallax stored their camera as self.camera on an arcade.Window subclass. Since the move to pyglet 3, Window.camera is the default camera pyglet draws Labels and batches with (update pyglet to version 3.0.dev7 and improve camera compatibility #2880), so they all crashed on startup with AttributeError: property 'camera' ... has no setter. Before update pyglet to version 3.0.dev7 and improve camera compatibility #2880, pyglet's own setter would have rejected an arcade camera anyway.
    • The examples now use self.world_camera, which pairs with the tutorial's gui_camera. Renames stay on the same lines, so the tutorial's emphasize-lines still match.
    • Window.camera now has a setter that raises a clearer AttributeError: "Window.camera is the default camera pyglet draws with, and can't be assigned. Store your camera under another name, such as self.world_camera." User code with the old tutorial pattern still fails, but now it says how to fix it. A setter that accepted the camera would break pyglet's text drawing.
  • pixelated_ui() crashed: it set pyglet 2's Font.texture_min_filter/texture_mag_filter through pyglet.gl, which pyglet 3 doesn't have. It now sets Font.filters = TextureFilter.NEAREST. The exp_animations_2 example had the same code.
  • InputManager.parse() crashed: it called inputs.parse_instance(), which More future.input cleanup work #2289 renamed to parse_mapping_input_enum(). The input modules had a file-wide # type: ignore, which hid this. It also made mypy see arcade.input as empty, which caused 10 of the errors.

Other fixes

  • application.py imports GraphicsAPI from pyglet.enums and OpenGLUserConfig from pyglet.config.gl, instead of their private re-exports.
  • UIDropdown's overlay: add_option() returns the type it's given, so button.on_click type checks.
  • UIRenderGroup.scale is annotated as float | tuple[float, float]. It still shadows UIWidget.scale() on purpose.
  • Window.camera returns arcade's DefaultProjector, not a pyglet camera, so its override is ignored with a comment.
  • Smaller fixes:
    • a duplicate annotation in context.py;
    • the algo_detailed fallback type in hitbox;
    • the invalid type: ignore syntax in the CLI;
    • the _clean_dicts key type (its dicts have int and str keys).
  • Examples:
    • the easing examples: Easing used as a type, None sprite lists, and int endpoints;
    • sprite_bullets_sweep annotations;
    • a mypy override for numpy, which only numpy_sprite uses and isn't a dependency.

Tests

  • InputManager.parse() round trip: serialize, parse, and compare. Mappings are kept in sets, so the comparison ignores order.
  • pixelated_ui() sets nearest font filtering. Global settings are restored afterwards.
  • Assigning window.camera raises the new error, and window.camera stays the default camera.

All three fail on development and pass here.

I ran every example I changed, plus the lights tutorial and perspective_parallax, for one frame in a hidden window. All ran. With the old 07_camera.py, the same check fails.

make.py mypy and make.py pyright exit with 1 when there's an error, so CI will fail on them. Locally:

  • uv run mypy arcade: no issues in 402 files.
  • uv run pyright: 0 errors.
  • ruff: format and lint pass.
  • Full suite: 1744 passed.

The changelog has the three crashes under Unreleased → Fixes, and the CI change under Misc Changes.

🤖 Generated with Claude Code

Paul V Craven and others added 2 commits October 8, 2026 08:57
Fixing the type errors turned up three crashes:
- Window subclasses that stored a camera as self.camera (platformer
  tutorial steps 7-19, custom_sprite, the lights tutorial) raised
  AttributeError on startup. Window.camera is pyglet's default camera.
  They now use self.world_camera, and assigning Window.camera explains.
- pixelated_ui() used pyglet 2 font filter attributes.
- InputManager.parse() called a function renamed in #2289. A file-wide
  type: ignore had hidden it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pvcraven
pvcraven merged commit 353f287 into development Oct 8, 2026
7 checks passed
@pvcraven
pvcraven deleted the ci/blocking-type-checks branch October 8, 2026 14:35
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