Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Utils lazy import #386

Merged
merged 2 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
Loading