Skip to content

Commit

Permalink
Utils lazy import (#386)
Browse files Browse the repository at this point in the history
Co-authored-by: Korijn van Golen <[email protected]>
  • Loading branch information
almarklein and Korijn authored Oct 23, 2023
1 parent d151048 commit 871319f
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 12 deletions.
2 changes: 1 addition & 1 deletion examples/compute_noop.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import wgpu
import wgpu.backends.rs # Select backend
from wgpu.utils import compute_with_buffers # Convenience function
from wgpu.utils.compute import compute_with_buffers # Convenience function


# %% Shader and data
Expand Down
20 changes: 13 additions & 7 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,24 +123,30 @@ def get_output_from_subprocess(code):
return p.stdout.decode(errors="ignore")


def test_do_not_import_utils_subpackage():
def test_do_not_import_utils_submodules():
# OK: use something from root package
code = "import wgpu; print(wgpu.__version__)"
out = get_output_from_subprocess(code)
assert "Error" not in out
assert wgpu.__version__ in out

# OK: use something from utils if we import it first
code = "import wgpu.utils; print(wgpu.utils.compute_with_buffers)"
# OK: wgpu.utils itself is always there
code = "import wgpu; print(wgpu.utils)"
out = get_output_from_subprocess(code)
assert "Error" not in out
assert "function compute_with_buffers" in out
assert "module 'wgpu.utils' from " in out

# FAIL: use something from utils if we only import wgpu
code = "import wgpu; print(wgpu.utils.compute_with_buffers)"
# OK: wgpu.utils itself is always there
code = "import wgpu; print(wgpu.utils.get_default_device)"
out = get_output_from_subprocess(code)
assert "Error" not in out
assert "function get_default_device" in out

# FAIL: use something from utils that's not imported
code = "import wgpu; print(wgpu.utils.compute.compute_with_buffers)"
out = get_output_from_subprocess(code)
assert "Error" in out
assert "has no attribute" in out and "utils" in out
assert "must be explicitly imported" in out and "utils" in out

# Also, no numpy
code = "import sys, wgpu.utils; print('numpy' in sys.modules)"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_util_compute.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import sys

import wgpu.backends.rs # noqa
from wgpu.utils import compute_with_buffers
from wgpu.utils.compute import compute_with_buffers

from pytest import skip, mark, raises
from testutils import run_tests, can_use_wgpu_lib, is_ci, iters_equal
Expand Down
2 changes: 2 additions & 0 deletions wgpu/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from .enums import * # noqa: F401,F403
from .base import * # noqa: F401,F403
from .gui import WgpuCanvasInterface # noqa: F401,F403
from . import utils # noqa: F401,F403


__version__ = "0.11.0"
version_info = tuple(map(int, __version__.split(".")))
Expand Down
31 changes: 28 additions & 3 deletions wgpu/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Higher level utility functions. This module is not imported by default.
Higher level utilities. Must be explicitly imported from ``wgpu.utils.xx``.
"""

# The purpose of wgpu-py is to provide a Pythonic wrapper around
Expand All @@ -13,5 +13,30 @@
# GPU/wgpu semantics), but without using low level details of the wgpu
# API itself.

from ._device import get_default_device # noqa: F401
from ._compute import compute_with_buffers # noqa: F401
# The get_default_device() is so small and generally convenient that we import it by default.
from .device import get_default_device # noqa: F401


class _StubModule:
def __init__(self, module):
self._module = module
self.must_be_explicitly_imported = True

def __getattr__(self, *args, **kwargs):
raise RuntimeError(f"wgpu.utils.{self._module} must be explicitly imported.")

def __repr__(self):
return f"<Stub for wgpu.utils.{self._module} - {self._module} must be explicitly imported>"


# Create stubs


def compute_with_buffers(*args, **kwargs):
raise DeprecationWarning(
"wgpu.utils.compute_with_buffers() must now be imported from wgpu.utils.compute"
)


compute = _StubModule("compute")
shadertoy = _StubModule("shadertoy")
File renamed without changes.
File renamed without changes.

0 comments on commit 871319f

Please sign in to comment.