Skip to content

Commit 711c5e0

Browse files
committed
Lazy import implementation for surfarray, sndarray
1 parent 02716db commit 711c5e0

File tree

3 files changed

+35
-7
lines changed

3 files changed

+35
-7
lines changed

docs/reST/ref/sndarray.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ Each sample is an 8-bit or 16-bit integer, depending on the data format. A
2323
stereo sound file has two values per sample, while a mono sound file only has
2424
one.
2525

26+
.. versionchanged:: 2.5.3 sndarray module is lazily loaded to avoid loading NumPy needlessly
27+
2628
.. function:: array
2729

2830
| :sl:`copy Sound samples into an array`

docs/reST/ref/surfarray.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ pixels from the surface and any changes performed to the array will make changes
3535
in the surface. As this last functions share memory with the surface, this one
3636
will be locked during the lifetime of the array.
3737

38+
.. versionchanged:: 2.5.3 surfarray module is lazily loaded to avoid loading NumPy needlessly
39+
3840
.. function:: array2d
3941

4042
| :sl:`Copy pixels into a 2d array`

src_py/__init__.py

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -300,16 +300,36 @@ def PixelArray(surface): # pylint: disable=unused-argument
300300
except (ImportError, OSError):
301301
scrap = MissingModule("scrap", urgent=0)
302302

303-
try:
304-
import pygame.surfarray
305-
except (ImportError, OSError):
306-
surfarray = MissingModule("surfarray", urgent=0)
303+
# Two lazily imported modules to avoid loading numpy unnecessarily
307304

308-
try:
309-
import pygame.sndarray
310-
except (ImportError, OSError):
305+
from importlib.util import LazyLoader, find_spec, module_from_spec
306+
307+
308+
def lazy_import(name):
309+
"""See https://docs.python.org/3/library/importlib.html#implementing-lazy-imports
310+
311+
Only load modules upon their first attribute access.
312+
Lazily imported modules are directly referenced in packager_imports function.
313+
"""
314+
spec = find_spec("pygame." + name)
315+
loader = LazyLoader(spec.loader)
316+
spec.loader = loader
317+
module = module_from_spec(spec)
318+
sys.modules[spec.name] = module
319+
loader.exec_module(module)
320+
return module
321+
322+
323+
if find_spec("numpy") is not None:
324+
surfarray = lazy_import("surfarray")
325+
sndarray = lazy_import("sndarray")
326+
else:
327+
# Preserve MissingModule behavior when numpy is not installed
328+
surfarray = MissingModule("surfarray", urgent=0)
311329
sndarray = MissingModule("sndarray", urgent=0)
312330

331+
del LazyLoader, find_spec, lazy_import, module_from_spec
332+
313333
try:
314334
import pygame._debug
315335
from pygame._debug import print_debug_info
@@ -366,6 +386,10 @@ def packager_imports():
366386
import pygame.macosx
367387
import pygame.colordict
368388

389+
# lazy imports
390+
import pygame.surfarray
391+
import pygame.sndarray
392+
369393

370394
# make Rects pickleable
371395

0 commit comments

Comments
 (0)