Skip to content

Import game controller code on first use - #2964

Merged
pvcraven merged 1 commit into
developmentfrom
lazy-input-media-imports
Oct 9, 2026
Merged

pvcraven merged 1 commit into
developmentfrom
lazy-input-media-imports

Conversation

@pvcraven

@pvcraven pvcraven commented Oct 9, 2026

Copy link
Copy Markdown
Member

Closes #1159. Related to #2402: this PR covers import time only, not which names should be top-level.

Why import arcade was slow

Measured with python -X importtime on Windows:

Import Time Cause
pyglet.input (via arcade.joysticks) 1.35 s pyglet creates DirectInput and lists the connected devices when imported
pyglet.media (via arcade.sound) 0.50 s pyglet opens the audio driver when imported
everything else about 0.4 s window, graphics and text

Change

  • get_controllers, ControllerManager, get_joysticks, get_game_controllers, and the arcade.controller / arcade.joysticks modules are loaded on first use, through a module __getattr__.
    • Type checkers still see them through TYPE_CHECKING imports.
    • from arcade import ... and from arcade import * work as before.
    • In headless mode they're still missing, as before.
  • Loading Arcade's extra controller mappings (gamecontrollerdb.txt) moved from arcade/__init__.py to arcade/controller.py.
  • arcade/input/manager.py, arcade/gui/ui_manager.py and arcade/experimental/controller_window.py only used pyglet's Controller for type hints. They now import it for type checkers only. ControllerWindow imports ControllerManager when it's created.
  • The experimental input_manager_example uses arcade.ControllerManager() instead of pyglet's, so it keeps Arcade's mappings.

Sound is unchanged. It still loads at import. Making it lazy would cut another 0.5 s, but then the first load_sound could make the game stutter if it happens mid-game. A pause when connecting controllers is fine, because that normally happens at startup.

Results (Windows)

Before After
import arcade about 2.7 s about 0.9 s
first load_sound / play() instant instant (audio driver opened at import)
first get_controllers() (paid at import) about 1.5 s

Behavior change

Code that calls pyglet.input.get_controllers() directly, without using Arcade's controller functions first, now gets pyglet's 302 built-in mappings instead of Arcade's 2147. The changelog says so.

Testing

  • The full test suite passes (1843), and ruff, mypy, pyright and the docs build are clean.
  • The sound, controller and InputManager examples, and the GUI controller examples (ControllerWindow), run without errors.
  • Headless mode can't run on Windows, so CI's Linux job covers it.

🤖 Generated with Claude Code

pyglet lists the input devices when pyglet.input is imported, which took
about 1.4 of the 2.7 seconds of `import arcade` on Windows. Arcade's
controller functions are now imported on first use through a module
__getattr__, and the modules that only used pyglet's Controller for type
hints import it for type checkers only. Sound still loads at import so
the first sound doesn't stutter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pvcraven
pvcraven merged commit 35c607b into development Oct 9, 2026
7 checks passed
@pvcraven
pvcraven deleted the lazy-input-media-imports branch October 9, 2026 15:11
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.

Look into improving Arcade's startup time

1 participant