diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ecd09af8..22c50ac5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,13 +25,16 @@ jobs: uses: actions/setup-python@v5 with: python-version: '3.12' - - name: Install dev dependencies + - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -U -e .[lint] - - name: Flake8 + pip install ruff + - name: Ruff lint + run: | + ruff check --output-format=github . + - name: Ruff format run: | - flake8 . + ruff format --check . test-codegen-build: name: Test Codegen @@ -140,7 +143,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -U -e .[tests] glfw pyinstaller + pip install -U -e . + pip install -U pytest numpy psutil pyinstaller glfw - name: Test PyInstaller run: | pyinstaller --version diff --git a/README.md b/README.md index be33400e..5f4f68f0 100644 --- a/README.md +++ b/README.md @@ -120,9 +120,8 @@ This code is distributed under the 2-clause BSD license. binaries. * You can use `python tools/download_wgpu_native.py` when needed. * Or point the `WGPU_LIB_PATH` environment variable to a custom build of `wgpu-native`. -* Use `black .` to apply autoformatting. -* Use `flake8 .` to check for flake errors. -* Use `pytest .` to run the tests. +* Use `ruff format` to apply autoformatting. +* Use `ruff check` to check for linting errors. ### Updating to a later version of WebGPU or wgpu-native @@ -136,11 +135,11 @@ for more information. The test suite is divided into multiple parts: -* `pytest -v tests` runs the core unit tests. +* `pytest -v tests` runs the unit tests. * `pytest -v examples` tests the examples. -* `pytest -v wgpu/__pyinstaller` tests if wgpu is properly supported by - pyinstaller. -* `pytest -v codegen` lints the generated binding code. +* `pytest -v wgpu/__pyinstaller` tests if wgpu is properly supported by pyinstaller. +* `pytest -v codegen` tests the code that autogenerates the API. +* `pytest -v tests_mem` tests against memoryleaks. There are two types of tests for examples included: diff --git a/codegen/__main__.py b/codegen/__main__.py index 9c8a261c..db5a5fc9 100644 --- a/codegen/__main__.py +++ b/codegen/__main__.py @@ -11,7 +11,7 @@ sys.path.insert(0, os.path.abspath(os.path.join(__file__, "..", ".."))) -from codegen import main, file_cache # noqa: E402 +from codegen import main, file_cache if __name__ == "__main__": diff --git a/codegen/apipatcher.py b/codegen/apipatcher.py index d6058a66..4452dfe2 100644 --- a/codegen/apipatcher.py +++ b/codegen/apipatcher.py @@ -3,7 +3,7 @@ spec (IDL), and the backend implementations from the base API. """ -from codegen.utils import print, blacken, to_snake_case, to_camel_case, Patcher +from codegen.utils import print, format_code, to_snake_case, to_camel_case, Patcher from codegen.idlparser import get_idl_parser from codegen.files import file_cache @@ -268,7 +268,6 @@ def __init__(self): self.detect_async_props_and_methods() def detect_async_props_and_methods(self): - self.async_idl_names = async_idl_names = {} # (sync-name, async-name) for classname, interface in self.idl.classes.items(): @@ -434,13 +433,13 @@ def get_method_def(self, classname, methodname): py_args = [self._arg_from_struct_field(field) for field in fields] if py_args[0].startswith("label: str"): py_args[0] = 'label=""' - py_args = ["self", "*"] + py_args + py_args = ["self", "*", *py_args] else: - py_args = ["self"] + argnames + py_args = ["self", *argnames] # Construct final def line = preamble + ", ".join(py_args) + "): pass\n" - line = blacken(line, True).split("):")[0] + "):" + line = format_code(line, True).split("):")[0] + "):" return " " + line def _arg_from_struct_field(self, field): diff --git a/codegen/apiwriter.py b/codegen/apiwriter.py index 1cdc0a5f..88a2f36f 100644 --- a/codegen/apiwriter.py +++ b/codegen/apiwriter.py @@ -4,7 +4,7 @@ import re -from codegen.utils import print, blacken, to_snake_case +from codegen.utils import print, format_code, to_snake_case from codegen.idlparser import get_idl_parser from codegen.files import file_cache @@ -59,7 +59,7 @@ def write_flags(): pylines.append(f" {key} = {val!r}") # note: can add docs using "#: " pylines.append("\n") # Write - code = blacken("\n".join(pylines)) + code = format_code("\n".join(pylines)) file_cache.write("flags.py", code) print(f"Wrote {n} flags to flags.py") @@ -88,7 +88,7 @@ def write_enums(): pylines.append(f' {key} = "{val}"') # note: can add docs using "#: " pylines.append("\n") # Write - code = blacken("\n".join(pylines)) + code = format_code("\n".join(pylines)) file_cache.write("enums.py", code) print(f"Wrote {n} enums to enums.py") @@ -135,6 +135,6 @@ def write_structs(): pylines.append(")\n") # Write - code = blacken("\n".join(pylines)) + code = format_code("\n".join(pylines)) file_cache.write("structs.py", code) print(f"Wrote {n} structs to structs.py") diff --git a/codegen/idlparser.py b/codegen/idlparser.py index 6446a2b6..c203f0af 100644 --- a/codegen/idlparser.py +++ b/codegen/idlparser.py @@ -161,7 +161,7 @@ def _remove_comments(self, text): return "\n".join(lines) def resolve_type(self, typename): - """Resolve a type to a suitable name that is also valid so that flake8 + """Resolve a type to a suitable name that is also valid so that the linter wont complain when this is used as a type annotation. """ diff --git a/codegen/tests/test_codegen_apipatcher.py b/codegen/tests/test_codegen_apipatcher.py index 31d66a89..fbf8575e 100644 --- a/codegen/tests/test_codegen_apipatcher.py +++ b/codegen/tests/test_codegen_apipatcher.py @@ -1,7 +1,6 @@ -""" Test some parts of apipatcher.py, and Implicitly tests idlparser.py. -""" +"""Test some parts of apipatcher.py, and Implicitly tests idlparser.py.""" -from codegen.utils import blacken +from codegen.utils import format_code from codegen.apipatcher import CommentRemover, AbstractCommentInjector, IdlPatcherMixin @@ -101,7 +100,7 @@ def spam(self): def eggs(self): pass """ - code3 = blacken(dedent(code3)).strip() + code3 = format_code(dedent(code3)).strip() p = MyCommentInjector() p.apply(dedent(code1)) @@ -111,7 +110,6 @@ def eggs(self): def test_async_api_logic(): - class Object(object): pass diff --git a/codegen/tests/test_codegen_result.py b/codegen/tests/test_codegen_result.py index 44c3b830..459230f3 100644 --- a/codegen/tests/test_codegen_result.py +++ b/codegen/tests/test_codegen_result.py @@ -1,5 +1,4 @@ -""" Test some aspects of the generated code. -""" +"""Test some aspects of the generated code.""" from codegen.files import read_file diff --git a/codegen/tests/test_codegen_rspatcher.py b/codegen/tests/test_codegen_rspatcher.py index 6b6e80ff..29d5e0ee 100644 --- a/codegen/tests/test_codegen_rspatcher.py +++ b/codegen/tests/test_codegen_rspatcher.py @@ -1,5 +1,4 @@ -""" Test some parts of rsbackend.py, and implicitly tests hparser.py. -""" +"""Test some parts of rsbackend.py, and implicitly tests hparser.py.""" from codegen.wgpu_native_patcher import patch_wgpu_native_backend diff --git a/codegen/tests/test_codegen_utils.py b/codegen/tests/test_codegen_utils.py index f92741da..80b8ff72 100644 --- a/codegen/tests/test_codegen_utils.py +++ b/codegen/tests/test_codegen_utils.py @@ -4,7 +4,7 @@ from codegen.utils import ( remove_c_comments, - blacken, + format_code, Patcher, to_snake_case, to_camel_case, @@ -59,7 +59,7 @@ def test_remove_c_comments(): assert code2 == code3 -def test_blacken_singleline(): +def test_format_code_singleline(): code1 = """ def foo(): pass @@ -98,20 +98,20 @@ def foo(a1, a2, a3): code1 = dedent(code1).strip() code2 = dedent(code2).strip() - code3 = blacken(code1, True) + code3 = format_code(code1, True) code3 = code3.replace("\n\n", "\n").replace("\n\n", "\n").strip() assert code3 == code2 # Also test simply long lines - code = "foo = 1" + " + 1" * 100 - assert len(code) > 300 + code = "foo = 1" + " + 1" * 75 + assert len(code) > 300 # Ruff's max line-length is 320 assert code.count("\n") == 0 - assert blacken(code, False).strip().count("\n") > 3 - assert blacken(code, True).strip().count("\n") == 0 + assert format_code(code, False).strip().count("\n") > 3 + assert format_code(code, True).strip().count("\n") == 0 -def test_blacken_comments(): +def test_format_code_comments(): code1 = """ def foo(): # hi pass @@ -133,7 +133,7 @@ def foo(a1, a2, a3): # hi ha ho code1 = dedent(code1).strip() code2 = dedent(code2).strip() - code3 = blacken(code1, True) + code3 = format_code(code1, True) code3 = code3.replace("\n\n", "\n").replace("\n\n", "\n").strip() assert code3 == code2 @@ -160,7 +160,7 @@ def bar3(self): pass """ - code = blacken(dedent(code)) + code = format_code(dedent(code)) p = Patcher(code) # Dump before doing anything, should yield original @@ -201,7 +201,7 @@ def bar3(self): for line, i in p.iter_lines(): if line.lstrip().startswith("#"): p.replace_line(i, "# comment") - with raises(Exception): + with raises(AssertionError): p.replace_line(i, "# comment") code2 = p.dumps() assert code2.count("#") == 4 diff --git a/codegen/utils.py b/codegen/utils.py index e4f68c84..841ed801 100644 --- a/codegen/utils.py +++ b/codegen/utils.py @@ -5,8 +5,7 @@ import os import sys import tempfile - -import black +import subprocess def to_snake_case(name): @@ -48,7 +47,7 @@ def print(*args, **kwargs): """Report something (will be printed and added to a file.""" # __builtins__.print(*args, **kwargs) if args and not args[0].lstrip().startswith("#"): - args = ("*",) + args + args = ("*", *args) for f in _file_objects_to_print_to: __builtins__["print"](*args, file=f, flush=True, **kwargs) @@ -103,14 +102,35 @@ def remove_c_comments(code): return new_code -def blacken(src, singleline=False): - """Format the given src string using black. If singleline is True, - all function signatures become single-line, so they can be parsed - and updated. +class FormatError(Exception): + pass + + +def format_code(src, singleline=False): + """Format the given src string. If singleline is True, all function + signatures become single-line, so they can be parsed and updated. """ - # Normal black - mode = black.FileMode(line_length=999 if singleline else 88) - result = black.format_str(src, mode=mode) + + # Use Ruff to format the line. Ruff does not yet have a Python API, so we use its CLI. + tempfilename = os.path.join(tempfile.gettempdir(), "wgpupy_codegen_format.py") + with open(tempfilename, "wb") as fp: + fp.write(src.encode()) + line_length = 320 if singleline else 88 + cmd = [ + sys.executable, + "-m", + "ruff", + "format", + "--line-length", + str(line_length), + tempfilename, + ] + p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + if p.returncode: + raise FormatError(p.stdout.decode(errors="ignore")) + with open(tempfilename, "rb") as fp: + result = fp.read().decode() + os.remove(tempfilename) # Make defs single-line. You'd think that setting the line length # to a very high number would do the trick, but it does not. @@ -175,7 +195,7 @@ def _init(self, code): self._diffs = {} self._classes = {} if code: - self.lines = blacken(code, True).splitlines() # inf line length + self.lines = format_code(code, True).splitlines() # inf line length def remove_line(self, i): """Remove the line at the given position. There must not have been @@ -221,8 +241,8 @@ def dumps(self, format=True): text = "\n".join(lines) if format: try: - text = blacken(text) - except black.InvalidInput as err: # pragma: no cover + text = format_code(text) + except FormatError as err: # pragma: no cover # If you get this error, it really helps to load the code # in an IDE to see where the error is. Let's help with that ... filename = os.path.join(tempfile.gettempdir(), "wgpu_patcher_fail.py") @@ -233,8 +253,8 @@ def dumps(self, format=True): raise RuntimeError( f"It appears that the patcher has generated invalid Python:" f"\n\n {err}\n\n" - f'Wrote the generated (but unblackened) code to:\n\n "{filename}"' - ) + f'Wrote the generated (but unformatted) code to:\n\n "{filename}"' + ) from None return text diff --git a/codegen/wgpu_native_patcher.py b/codegen/wgpu_native_patcher.py index 08d45eb5..e683aadc 100644 --- a/codegen/wgpu_native_patcher.py +++ b/codegen/wgpu_native_patcher.py @@ -16,7 +16,7 @@ import re from collections import defaultdict -from codegen.utils import print, blacken, Patcher, to_snake_case +from codegen.utils import print, format_code, Patcher, to_snake_case from codegen.hparser import get_h_parser from codegen.idlparser import get_idl_parser from codegen.files import file_cache @@ -27,7 +27,6 @@ # THIS CODE IS AUTOGENERATED - DO NOT EDIT -# flake8: noqa '''.lstrip() @@ -169,7 +168,7 @@ def write_mappings(): pylines.append("}") # Wrap up - code = blacken("\n".join(pylines)) # just in case; code is already black + code = format_code("\n".join(pylines)) file_cache.write("backends/wgpu_native/_mappings.py", code) print( f"Wrote {len(enummap)} enum mappings and {len(cstructfield2enum)} struct-field mappings to wgpu_native/_mappings.py" @@ -236,7 +235,7 @@ def apply(self, code): else: detected.add(var_name) anno = hp.functions[var_name].replace(var_name, "f").strip(";") - self.insert_line(i, indent + f"# H: " + anno) + self.insert_line(i, indent + "# H: " + anno) count += 1 elif match := re.search(r"(_\w+_function) = libf?\.(wgpu\w*)", line): # Assignment of libf function to a class variable. We'll point the @@ -266,7 +265,7 @@ def apply(self, code): count += len(lib_names) for lib_name in lib_names: self.insert_line( - i, indent + f"# H: " + hp.functions[lib_name].strip(";") + i, indent + "# H: " + hp.functions[lib_name].strip(";") ) # At this point, generic_class_var_assignment should be empty. # If it is not, we've done an assignment to a class variable name, but have @@ -354,7 +353,7 @@ def _validate_struct(self, hp, i1, i2): self.replace_line(i1 + 1, self.lines[i1 + 1] + ",") return - # We can assume that the struct is multi-line and formatted by Black! + # We can assume that the struct is multi-line and formatted assert len(lines) >= 3 # Get struct name, and verify @@ -363,12 +362,12 @@ def _validate_struct(self, hp, i1, i2): if name.endswith("*"): if "new_struct_p" not in lines[0]: self.insert_line( - i1, indent + f"# FIXME: invalid C struct, use new_struct_p()" + i1, indent + "# FIXME: invalid C struct, use new_struct_p()" ) else: if "new_struct_p" in lines[0]: self.insert_line( - i1, indent + f"# FIXME: invalid C struct, use new_struct()" + i1, indent + "# FIXME: invalid C struct, use new_struct()" ) # Get struct object and create annotation line @@ -380,7 +379,7 @@ def _validate_struct(self, hp, i1, i2): else: struct = hp.structs[struct_name] fields = ", ".join(f"{key}: {val}" for key, val in struct.items()) - self.insert_line(i1, indent + f"# H: " + fields) + self.insert_line(i1, indent + "# H: " + fields) # Check keys keys_found = [] diff --git a/examples/imgui_backend_sea.py b/examples/imgui_backend_sea.py index 77d6af87..ff5348ef 100644 --- a/examples/imgui_backend_sea.py +++ b/examples/imgui_backend_sea.py @@ -380,9 +380,8 @@ def render(): global_time = current_time canvas_texture = present_context.get_current_texture() - render_pass_descriptor["color_attachments"][0][ - "view" - ] = canvas_texture.create_view() + ca0 = render_pass_descriptor["color_attachments"][0] + ca0["view"] = canvas_texture.create_view() # Update uniform buffer uniform_data["resolution"] = (canvas_texture.size[0], canvas_texture.size[1]) diff --git a/examples/imgui_renderer_sea.py b/examples/imgui_renderer_sea.py index 4ebba4a0..dbd7472c 100644 --- a/examples/imgui_renderer_sea.py +++ b/examples/imgui_renderer_sea.py @@ -349,9 +349,8 @@ def render(): global_time = current_time canvas_texture = present_context.get_current_texture() - render_pass_descriptor["color_attachments"][0][ - "view" - ] = canvas_texture.create_view() + ca0 = render_pass_descriptor["color_attachments"][0] + ca0["view"] = canvas_texture.create_view() # Update uniform buffer uniform_data["resolution"] = (canvas_texture.size[0], canvas_texture.size[1]) diff --git a/examples/tests/test_examples.py b/examples/tests/test_examples.py index a001bbdd..f701c19f 100644 --- a/examples/tests/test_examples.py +++ b/examples/tests/test_examples.py @@ -149,5 +149,5 @@ def test_examples_run(module, force_offscreen): # Enable tweaking in an IDE by running in an interactive session. os.environ["WGPU_FORCE_OFFSCREEN"] = "true" pytest.getoption = lambda x: False - is_lavapipe = True # noqa: F811 + is_lavapipe = True test_examples_screenshots("validate_volume", pytest, None, None) diff --git a/examples/triangle_auto.py b/examples/triangle_auto.py index 4a1ad99b..66b6bbd9 100644 --- a/examples/triangle_auto.py +++ b/examples/triangle_auto.py @@ -11,7 +11,7 @@ sys.path.insert(0, str(Path(__file__).parent)) -from triangle import main # noqa: E402, The function to call to run the visualization +from triangle import main canvas = WgpuCanvas() diff --git a/examples/triangle_glfw.py b/examples/triangle_glfw.py index b2b34b77..fa89ffa1 100644 --- a/examples/triangle_glfw.py +++ b/examples/triangle_glfw.py @@ -11,7 +11,7 @@ sys.path.insert(0, str(Path(__file__).parent)) -from triangle import main # noqa: E402, The function to call to run the visualization +from triangle import main canvas = WgpuCanvas() diff --git a/examples/triangle_glfw_direct.py b/examples/triangle_glfw_direct.py index 16aaa1e0..8c6e89ff 100644 --- a/examples/triangle_glfw_direct.py +++ b/examples/triangle_glfw_direct.py @@ -20,7 +20,7 @@ sys.path.insert(0, str(Path(__file__).parent)) -from triangle import setup_draw # noqa: E402 +from triangle import setup_draw class GlfwCanvas: diff --git a/examples/triangle_qt.py b/examples/triangle_qt.py index ce0293ba..cbf8cb58 100644 --- a/examples/triangle_qt.py +++ b/examples/triangle_qt.py @@ -16,9 +16,9 @@ pass -from wgpu.gui.qt import WgpuCanvas # WgpuCanvas is a QWidget subclass +from wgpu.gui.qt import WgpuCanvas # noqa: E402 -from triangle import main # The function to call to run the visualization +from triangle import main # noqa: E402 app = QtWidgets.QApplication([]) diff --git a/examples/triangle_qt_embed.py b/examples/triangle_qt_embed.py index ebc76141..00ee5809 100644 --- a/examples/triangle_qt_embed.py +++ b/examples/triangle_qt_embed.py @@ -16,9 +16,9 @@ pass -from wgpu.gui.qt import WgpuWidget +from wgpu.gui.qt import WgpuWidget # noqa: E402 -from triangle import main +from triangle import main # noqa: E402 class ExampleWidget(QtWidgets.QWidget): diff --git a/examples/wgpu-examples.ipynb b/examples/wgpu-examples.ipynb index 9ae2417e..bb580c7f 100644 --- a/examples/wgpu-examples.ipynb +++ b/examples/wgpu-examples.ipynb @@ -58,9 +58,9 @@ } ], "source": [ - "from wgpu.gui.auto import WgpuCanvas, run\n", + "from wgpu.gui.auto import WgpuCanvas\n", "import triangle\n", - " \n", + "\n", "canvas = WgpuCanvas(size=(640, 480), title=\"wgpu triangle with GLFW\")\n", "\n", "triangle.main(canvas)\n", @@ -165,11 +165,13 @@ "\n", "out = ipywidgets.Textarea(rows=10)\n", "\n", + "\n", "@canvas.add_event_handler(\"*\")\n", "def show_events(event):\n", " if event[\"event_type\"] != \"pointer_move\":\n", " out.value = str(event)\n", "\n", + "\n", "out" ] }, diff --git a/pyproject.toml b/pyproject.toml index e770d266..4ae5a436 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,12 +18,12 @@ glfw = ["glfw>=1.9"] imgui = ["imgui-bundle>=1.2.1"] # For devs / ci build = ["build", "hatchling", "requests", "twine"] -codegen = ["pytest", "numpy", "black"] -lint = ["black", "flake8", "flake8-black", "pep8-naming"] -docs = ["sphinx>7.2", "sphinx_rtd_theme"] +codegen = ["pytest", "numpy", "ruff"] +lint = ["ruff"] tests = ["numpy", "pytest", "psutil", "imageio"] examples = [] -dev = ["wgpu[build,codegen,lint,docs,tests,examples]"] +docs = ["sphinx>7.2", "sphinx_rtd_theme"] +dev = ["wgpu[build,codegen,lint,tests,examples,docs]"] [project.entry-points."pyinstaller40"] hook-dirs = "wgpu.__pyinstaller:get_hook_dirs" @@ -65,6 +65,20 @@ path = "tools/hatch_build.py" # ===== Tooling +[tool.ruff] +line-length = 88 + +[tool.ruff.lint] +select = ["F", "E", "W", "N", "B", "RUF"] +ignore = [ + "E501", # Line too long + "E731", # Do not assign a `lambda` expression, use a `def` + "B006", # Do not use mutable data structures for argument defaults + "B007", # Loop control variable `x` not used within loop body + "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar` + "RUF013", # PEP 484 prohibits implicit `Optional` - we should fix this! +] + [tool.coverage.report] exclude_also = [ # Have to re-enable the standard pragma, plus a less-ugly flavor diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 67c6424a..00000000 --- a/setup.cfg +++ /dev/null @@ -1,24 +0,0 @@ -[flake8] - -max_line_length = 88 - -exclude = build,dist,*.egg-info,.venv - -# E501 line too long -# E203 whitespace before ':' -# F722 syntax error in forward annotation -# F821 undefined name -> we must get rid of this! -# B006 Do not use mutable data structures for argument defaults. -# B007 Loop control variable 'j2' not used within the loop body. -# D docstring checks -extend-ignore = E501, E203, B006, B007, D - -per-file-ignores = - tests/test_compute.py: F821,F722 - tests/test_gui_glfw.py: F821,F722 - tests/test_wgpu_native_basics.py: F821,F722 - tests/test_wgpu_native_render.py: F821,F722 - tests/test_wgpu_native_render_tex.py: F821,F722 - tests/test_wgpu_native_compute_tex.py : F821,F722 - examples/*.py: F821,F722 - examples/triangle_qt*.py: E402 diff --git a/tests/renderutils.py b/tests/renderutils.py index 618ee198..7f8ad4d3 100644 --- a/tests/renderutils.py +++ b/tests/renderutils.py @@ -1,11 +1,11 @@ -""" Utils to render to a texture or screen. Tuned to the tests, so quite some +"""Utils to render to a texture or screen. Tuned to the tests, so quite some assumptions here. """ import ctypes import numpy as np -import wgpu.backends.wgpu_native # noqa +import wgpu.backends.wgpu_native def upload_to_texture(device, texture, data, nx, ny, nz): diff --git a/tests/test_api.py b/tests/test_api.py index 52599f62..22551366 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -9,7 +9,7 @@ def test_basic_api(): - import wgpu # noqa: F401 + import wgpu assert isinstance(wgpu.__version__, str) assert isinstance(wgpu.version_info, tuple) @@ -188,7 +188,7 @@ class GPU: fake_gpu = GPU() - ori_gpu = wgpu.gpu # noqa: N806 + ori_gpu = wgpu.gpu try: wgpu.gpu = wgpu.classes.GPU() diff --git a/tests/test_gui_base.py b/tests/test_gui_base.py index 5f06dddc..7174ebac 100644 --- a/tests/test_gui_base.py +++ b/tests/test_gui_base.py @@ -7,7 +7,7 @@ import subprocess import numpy as np -import wgpu.gui # noqa +import wgpu.gui from testutils import run_tests, can_use_wgpu_lib, is_pypy from pytest import mark, raises @@ -31,7 +31,8 @@ def bar_method(self): raise Exception("call-failed-" + "but-test-passed") def spam_method(self): - 1 / 0 + msg = "intended-fail" # avoid line with the message to show in the tb + raise Exception(msg) def test_base_canvas_context(): @@ -64,7 +65,7 @@ def test_canvas_logging(caplog): assert text.count("(5)") == 0 assert text.count("spam_method") == 0 - assert text.count("division by zero") == 0 + assert text.count("intended-fail") == 0 canvas._draw_frame_and_present() # prints traceback canvas._draw_frame_and_present() # prints short logs ... @@ -77,7 +78,7 @@ def test_canvas_logging(caplog): assert text.count("call-failed-but-test-passed") == 4 assert text.count("spam_method") == 2 - assert text.count("division by zero") == 4 + assert text.count("intended-fail") == 4 class MyOffscreenCanvas(wgpu.gui.WgpuCanvasBase): diff --git a/tests/test_gui_glfw.py b/tests/test_gui_glfw.py index 67d9be29..f2c4f1cc 100644 --- a/tests/test_gui_glfw.py +++ b/tests/test_gui_glfw.py @@ -12,7 +12,7 @@ import wgpu from pytest import skip from testutils import run_tests, can_use_glfw, can_use_wgpu_lib, is_pypy -from renderutils import render_to_texture, render_to_screen # noqa +# from renderutils import render_to_texture, render_to_screen if not can_use_glfw or not can_use_wgpu_lib: diff --git a/tests/test_not_finite.py b/tests/test_not_finite.py index 625a645e..cabba21f 100644 --- a/tests/test_not_finite.py +++ b/tests/test_not_finite.py @@ -118,7 +118,6 @@ def test_finite_using_uint(): def detect_finites(title, shader, expect_detection_nan, expect_detection_inf): - base_shader = """ @group(0) @@ -227,7 +226,7 @@ def detect_finites(title, shader, expect_detection_nan, expect_detection_inf): good_reals = bool(np.all(real == real_ref)) # Print, for when run as a script - checkmark = lambda x: "x✓"[x] # noqa + checkmark = lambda x: "x✓"[x] print( f"{title:>10}: {checkmark(detected_nan)} is_nan {checkmark(detected_inf)} is_inf {checkmark(detected_finite)} is_finite {checkmark(good_reals)} good_reals" ) @@ -243,7 +242,6 @@ def detect_finites(title, shader, expect_detection_nan, expect_detection_inf): if __name__ == "__main__": - test_finite_using_nequal() test_finite_using_min_max() test_finite_using_uint() diff --git a/tests/test_set_constant.py b/tests/test_set_constant.py index b12957a3..f0803d19 100644 --- a/tests/test_set_constant.py +++ b/tests/test_set_constant.py @@ -2,7 +2,7 @@ import pytest import wgpu.utils -from tests.testutils import can_use_wgpu_lib, run_tests +from testutils import can_use_wgpu_lib, run_tests from wgpu import TextureFormat from wgpu.backends.wgpu_native.extras import create_pipeline_layout, set_push_constants diff --git a/tests/test_set_override.py b/tests/test_set_override.py index 1f3b8251..2e352244 100644 --- a/tests/test_set_override.py +++ b/tests/test_set_override.py @@ -1,7 +1,7 @@ import pytest import wgpu.utils -from tests.testutils import can_use_wgpu_lib, run_tests +from testutils import can_use_wgpu_lib, run_tests from wgpu import TextureFormat if not can_use_wgpu_lib: @@ -170,7 +170,7 @@ def test_no_overridden_constants_render(runner): def test_no_constants_compute(runner): - runner.run_test(compute=True) == [1, 2, 3, 0] + assert runner.run_test(compute=True) == [1, 2, 3, 0] def test_override_vertex_constants(runner): diff --git a/tests/test_wgpu_native_errors.py b/tests/test_wgpu_native_errors.py index 7931f44d..15006d77 100644 --- a/tests/test_wgpu_native_errors.py +++ b/tests/test_wgpu_native_errors.py @@ -4,7 +4,7 @@ from pytest import raises -dedent = lambda s: s.replace("\n ", "\n").strip() # noqa +dedent = lambda s: s.replace("\n ", "\n").strip() def test_parse_shader_error1(caplog): diff --git a/tests/test_wgpu_native_render.py b/tests/test_wgpu_native_render.py index 85b93884..9c6988e0 100644 --- a/tests/test_wgpu_native_render.py +++ b/tests/test_wgpu_native_render.py @@ -11,7 +11,8 @@ import wgpu from pytest import skip from testutils import run_tests, can_use_wgpu_lib, is_ci, get_default_device -from renderutils import render_to_texture, render_to_screen # noqa +from renderutils import render_to_texture +from renderutils import render_to_screen # noqa: F401 - sometimes used for debugging if not can_use_wgpu_lib: diff --git a/tests/test_wgpu_native_render_tex.py b/tests/test_wgpu_native_render_tex.py index f11b7fed..343b152f 100644 --- a/tests/test_wgpu_native_render_tex.py +++ b/tests/test_wgpu_native_render_tex.py @@ -2,15 +2,15 @@ Test render pipeline by rendering to a texture. """ -import ctypes -import numpy as np import sys +import ctypes +import numpy as np import wgpu from pytest import skip from testutils import run_tests, get_default_device from testutils import can_use_wgpu_lib, is_ci -from renderutils import upload_to_texture, render_to_texture, render_to_screen # noqa +from renderutils import upload_to_texture, render_to_texture if not can_use_wgpu_lib: @@ -552,7 +552,7 @@ def render_textured_square(fragment_shader, texture_format, texture_size, textur [150, 150, 150, 50, 50, 50], [50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50], ] - ref1, ref2 = sum(ref1, []), sum(ref2, []) + ref1, ref2 = sum(ref1, []), sum(ref2, []) # noqa: RUF017 assert np.allclose(sq[0, :, 0], ref1, atol=1) assert np.allclose(sq[:, 0, 0], ref2, atol=1) diff --git a/tests/test_wgpu_vertex_instance.py b/tests/test_wgpu_vertex_instance.py index dfba3e42..966ed9bf 100644 --- a/tests/test_wgpu_vertex_instance.py +++ b/tests/test_wgpu_vertex_instance.py @@ -3,7 +3,7 @@ import numpy as np import pytest import wgpu.utils -from tests.testutils import can_use_wgpu_lib, run_tests +from testutils import can_use_wgpu_lib, run_tests from wgpu import TextureFormat from wgpu.backends.wgpu_native.extras import ( multi_draw_indexed_indirect, diff --git a/tests/testutils.py b/tests/testutils.py index d02a5b56..618e5bd6 100644 --- a/tests/testutils.py +++ b/tests/testutils.py @@ -6,7 +6,7 @@ from io import StringIO from pathlib import Path -from wgpu.utils import get_default_device # noqa +from wgpu.utils import get_default_device # noqa: F401 - imported by tests ROOT = Path(__file__).parent.parent # repo root diff --git a/tests_mem/test_destroy.py b/tests_mem/test_destroy.py index 3424cc1f..6af78aea 100644 --- a/tests_mem/test_destroy.py +++ b/tests_mem/test_destroy.py @@ -5,8 +5,8 @@ """ import pytest -import testutils # noqa from testutils import can_use_wgpu_lib, create_and_release +import testutils # noqa: F401 - sometimes used in debugging if not can_use_wgpu_lib: diff --git a/tests_mem/test_gui.py b/tests_mem/test_gui.py index 7f67bc01..3cb6eb95 100644 --- a/tests_mem/test_gui.py +++ b/tests_mem/test_gui.py @@ -7,8 +7,8 @@ import wgpu import pytest -import testutils # noqa from testutils import can_use_wgpu_lib, create_and_release, is_pypy +import testutils # noqa: F401 - sometimes used in debugging if not can_use_wgpu_lib: diff --git a/tests_mem/test_gui_glfw.py b/tests_mem/test_gui_glfw.py index 2cad4181..bbfeb523 100644 --- a/tests_mem/test_gui_glfw.py +++ b/tests_mem/test_gui_glfw.py @@ -8,9 +8,9 @@ import wgpu import pytest -import testutils # noqa from testutils import create_and_release, can_use_glfw, can_use_wgpu_lib from test_gui import make_draw_func_for_canvas +import testutils # noqa: F401 - sometimes used in debugging if not can_use_wgpu_lib: @@ -38,7 +38,7 @@ def test_release_canvas_context(n): # Texture and a TextureView, but these are released in present(), # so we don't see them in the counts. - from wgpu.gui.glfw import WgpuCanvas # noqa + from wgpu.gui.glfw import WgpuCanvas yield { "ignore": {"CommandBuffer"}, diff --git a/tests_mem/test_gui_qt.py b/tests_mem/test_gui_qt.py index aec6c046..99cdc1c3 100644 --- a/tests_mem/test_gui_qt.py +++ b/tests_mem/test_gui_qt.py @@ -7,9 +7,9 @@ import wgpu import pytest -import testutils # noqa from testutils import create_and_release, can_use_pyside6, can_use_wgpu_lib from test_gui import make_draw_func_for_canvas +import testutils # noqa: F401 - sometimes used in debugging if not can_use_wgpu_lib: @@ -29,8 +29,8 @@ def test_release_canvas_context(n): # Texture and a TextureView, but these are released in present(), # so we don't see them in the counts. - import PySide6 # noqa - from wgpu.gui.qt import WgpuCanvas # noqa + import PySide6 + from wgpu.gui.qt import WgpuCanvas app = PySide6.QtWidgets.QApplication.instance() if app is None: diff --git a/tests_mem/test_meta.py b/tests_mem/test_meta.py index 22bb0ea0..7f90f468 100644 --- a/tests_mem/test_meta.py +++ b/tests_mem/test_meta.py @@ -64,7 +64,7 @@ def test_meta_buffers_2(): ori = wgpu.backends.wgpu_native.GPUBuffer._release wgpu.backends.wgpu_native.GPUBuffer._release = lambda self: None - from test_objects import test_release_buffer # noqa + from test_objects import test_release_buffer try: with pytest.raises(AssertionError): diff --git a/tests_mem/test_objects.py b/tests_mem/test_objects.py index ce34a10a..5a53a8cb 100644 --- a/tests_mem/test_objects.py +++ b/tests_mem/test_objects.py @@ -3,8 +3,8 @@ """ import pytest -import testutils # noqa from testutils import can_use_wgpu_lib, create_and_release +import testutils # noqa: F401 - sometimes used in debugging if not can_use_wgpu_lib: diff --git a/tools/build_all_wheels.py b/tools/build_all_wheels.py index f8bc2cf3..8bd0328d 100644 --- a/tools/build_all_wheels.py +++ b/tools/build_all_wheels.py @@ -12,7 +12,7 @@ import zipfile from subprocess import run -from download_wgpu_native import main as download_lib # noqa +from download_wgpu_native import main as download_lib # Define platform tags. These are pairs of wgpu-native-tag and wheel-tag. The diff --git a/tools/hatch_build.py b/tools/hatch_build.py index a1759c0f..6c006c4a 100644 --- a/tools/hatch_build.py +++ b/tools/hatch_build.py @@ -32,7 +32,7 @@ root_dir = os.path.abspath(os.path.join(__file__, "..", "..")) sys.path.insert(0, os.path.join(root_dir, "tools")) -from download_wgpu_native import main as download_lib # noqa +from download_wgpu_native import main as download_lib # noqa: E402 class CustomBuildHook(BuildHookInterface): @@ -44,7 +44,6 @@ def initialize(self, version, build_data): # we go pure-Python mode, and expect the user to set WGPU_LIB_PATH. if self.target_name == "wheel" and is_git_repo(): - # Prepare check_git_status() remove_all_libs() diff --git a/wgpu/__init__.py b/wgpu/__init__.py index 646eef13..745bc4b3 100644 --- a/wgpu/__init__.py +++ b/wgpu/__init__.py @@ -2,15 +2,17 @@ WebGPU for Python. """ -from ._coreutils import logger # noqa: F401,F403 -from ._diagnostics import diagnostics, DiagnosticsBase # noqa: F401,F403 -from .flags import * # noqa: F401,F403 -from .enums import * # noqa: F401,F403 -from .classes import * # noqa: F401,F403 -from .gui import WgpuCanvasInterface # noqa: F401,F403 -from . import utils # noqa: F401,F403 -from . import backends # noqa: F401,F403 -from . import resources # noqa: F401,F403 +# ruff: noqa: F401, F403 + +from ._coreutils import logger +from ._diagnostics import diagnostics, DiagnosticsBase +from .flags import * +from .enums import * +from .classes import * +from .gui import WgpuCanvasInterface +from . import utils +from . import backends +from . import resources __version__ = "0.18.1" diff --git a/wgpu/__pyinstaller/conftest.py b/wgpu/__pyinstaller/conftest.py index 7f8b7373..1fb31cfc 100644 --- a/wgpu/__pyinstaller/conftest.py +++ b/wgpu/__pyinstaller/conftest.py @@ -1 +1 @@ -from PyInstaller.utils.conftest import * # noqa +from PyInstaller.utils.conftest import * # noqa: F403 diff --git a/wgpu/__pyinstaller/hook-wgpu.py b/wgpu/__pyinstaller/hook-wgpu.py index 70ba7832..8bb26de5 100644 --- a/wgpu/__pyinstaller/hook-wgpu.py +++ b/wgpu/__pyinstaller/hook-wgpu.py @@ -1,3 +1,5 @@ +# ruff: noqa: N999 + from PyInstaller.utils.hooks import collect_data_files, collect_dynamic_libs # Init variables that PyInstaller will pick up. @@ -20,7 +22,7 @@ # code below. Makes the binaray a bit larger, but only marginally (less # than 300kb). try: - import glfw # noqa + import glfw # noqa: F401 except ImportError: pass else: diff --git a/wgpu/_classes.py b/wgpu/_classes.py index 2504554f..a4e06288 100644 --- a/wgpu/_classes.py +++ b/wgpu/_classes.py @@ -89,7 +89,7 @@ def request_adapter_sync( Provided by wgpu-py, but not compatible with WebGPU. """ # If this method gets called, no backend has been loaded yet, let's do that now! - from .backends.auto import gpu # noqa + from .backends.auto import gpu return gpu.request_adapter_sync( power_preference=power_preference, @@ -113,7 +113,7 @@ async def request_adapter_async( be able to render to. This can typically be left to None. """ # If this method gets called, no backend has been loaded yet, let's do that now! - from .backends.auto import gpu # noqa + from .backends.auto import gpu return await gpu.request_adapter_async( power_preference=power_preference, @@ -129,7 +129,7 @@ def enumerate_adapters_sync(self): """ # If this method gets called, no backend has been loaded yet, let's do that now! - from .backends.auto import gpu # noqa + from .backends.auto import gpu return gpu.enumerate_adapters_sync() @@ -159,7 +159,7 @@ async def enumerate_adapters_async(self): # and then return both or one (if they represent the same adapter). # If this method gets called, no backend has been loaded yet, let's do that now! - from .backends.auto import gpu # noqa + from .backends.auto import gpu return await gpu.enumerate_adapters_async() @@ -309,8 +309,8 @@ def configure( if not isinstance(usage, int): usage = str_flag_to_int(flags.TextureUsage, usage) - color_space # not really supported, just assume srgb for now - tone_mapping # not supported yet + color_space # noqa - not really supported, just assume srgb for now + tone_mapping # noqa - not supported yet if alpha_mode not in enums.CanvasAlphaMode: raise ValueError( @@ -406,7 +406,6 @@ def get_current_texture(self): return self._texture def _create_texture_image(self): - canvas = self._get_canvas() width, height = canvas.get_physical_size() width, height = max(width, 1), max(height, 1) @@ -509,7 +508,7 @@ class GPUAdapterInfo: """Represents information about an adapter.""" def __init__(self, info): - self._info + self._info = info # IDL: readonly attribute DOMString vendor; @property @@ -1075,7 +1074,7 @@ def create_render_pipeline( properties, including the testing, operations, and bias. Optional. multisample (structs.MultisampleState): Describes the multi-sampling properties of the pipeline. fragment (structs.FragmentState): Describes the fragment shader - entry point of the pipeline and its output colors. If it’s + entry point of the pipeline and its output colors. If it's None, the No-Color-Output mode is enabled: the pipeline does not produce any color attachment outputs. It still performs rasterization and produces depth values based on @@ -1370,7 +1369,7 @@ async def map_async(self, mode, offset=0, size=None): def unmap(self): """Unmaps the buffer. - Unmaps the mapped range of the GPUBuffer and makes it’s contents + Unmaps the mapped range of the GPUBuffer and makes it's contents available for use by the GPU again. """ raise NotImplementedError() diff --git a/wgpu/_coreutils.py b/wgpu/_coreutils.py index 559fc34d..28117936 100644 --- a/wgpu/_coreutils.py +++ b/wgpu/_coreutils.py @@ -149,7 +149,7 @@ def str_flag_to_int(flag, s): v = flag.__dict__[p.upper()] value += v except KeyError: - raise ValueError(f"Invalid flag value for {flag}: '{p}'") + raise ValueError(f"Invalid flag value for {flag}: '{p}'") from None _flag_cache[cache_key] = value return value diff --git a/wgpu/_diagnostics.py b/wgpu/_diagnostics.py index b94e349f..55cd0a3e 100644 --- a/wgpu/_diagnostics.py +++ b/wgpu/_diagnostics.py @@ -473,7 +473,7 @@ class VersionDiagnostics(DiagnosticsBase): def get_dict(self): core_libs = ["wgpu", "cffi"] qt_libs = ["PySide6", "PyQt6", "PySide2", "PyQt5"] - gui_libs = qt_libs + ["glfw", "jupyter_rfb", "wx"] + gui_libs = [*qt_libs, "glfw", "jupyter_rfb", "wx"] extra_libs = ["numpy", "pygfx", "pylinalg", "fastplotlib"] info = {} diff --git a/wgpu/backends/__init__.py b/wgpu/backends/__init__.py index 577708cd..b082f920 100644 --- a/wgpu/backends/__init__.py +++ b/wgpu/backends/__init__.py @@ -4,7 +4,7 @@ import sys -from ..classes import GPU as _base_GPU # noqa +from ..classes import GPU as _base_GPU # noqa: N811 def _register_backend(gpu): diff --git a/wgpu/backends/auto.py b/wgpu/backends/auto.py index f2c87bf7..30332bdd 100644 --- a/wgpu/backends/auto.py +++ b/wgpu/backends/auto.py @@ -6,9 +6,9 @@ def _load_backend(backend_name): """Load a wgpu backend by name.""" if backend_name == "wgpu_native": - from . import wgpu_native as module # noqa: F401,F403 + from . import wgpu_native as module elif backend_name == "js_webgpu": - from . import js_webgpu as module # noqa: F401,F403 + from . import js_webgpu as module else: # no-cover raise ImportError(f"Unknown wgpu backend: '{backend_name}'") diff --git a/wgpu/backends/js_webgpu/__init__.py b/wgpu/backends/js_webgpu/__init__.py index d8842abf..7317b133 100644 --- a/wgpu/backends/js_webgpu/__init__.py +++ b/wgpu/backends/js_webgpu/__init__.py @@ -16,7 +16,7 @@ def request_adapter_sync(self, **parameters): raise NotImplementedError("Cannot use sync API functions in JS.") async def request_adapter_async(self, **parameters): - gpu = window.navigator.gpu # noqa + gpu = window.navigator.gpu # noqa: F821 return await gpu.request_adapter(**parameters) def get_preferred_canvas_format(self): diff --git a/wgpu/backends/rs.py b/wgpu/backends/rs.py index cfe3f2aa..3b0ef542 100644 --- a/wgpu/backends/rs.py +++ b/wgpu/backends/rs.py @@ -1,6 +1,6 @@ # Termporaty alias for backwards compatibility. -from .wgpu_native import gpu # noqa +from .wgpu_native import gpu # noqa: F401 _deprecation_msg = """ WARNING: wgpu.backends.rs is deprecated. Instead you can use: diff --git a/wgpu/backends/wgpu_native/__init__.py b/wgpu/backends/wgpu_native/__init__.py index 0e81c859..9e202fc3 100644 --- a/wgpu/backends/wgpu_native/__init__.py +++ b/wgpu/backends/wgpu_native/__init__.py @@ -2,8 +2,10 @@ The wgpu-native backend. """ -from ._api import * # noqa: F401, F403 -from ._ffi import ffi, lib, lib_path, lib_version_info # noqa: F401 +# ruff: noqa: F401, E402, F403 + +from ._api import * +from ._ffi import ffi, lib, lib_path, lib_version_info from ._ffi import _check_expected_version from .. import _register_backend @@ -16,7 +18,7 @@ # Instantiate and register this backend gpu = GPU() # noqa: F405 -_register_backend(gpu) # noqa: F405 +_register_backend(gpu) -from .extras import enumerate_adapters # noqa: F401, E402 -from .extras import request_device_sync, request_device # noqa: F401, E402 +from .extras import enumerate_adapters +from .extras import request_device_sync, request_device diff --git a/wgpu/backends/wgpu_native/_api.py b/wgpu/backends/wgpu_native/_api.py index 0326ba09..36cfb440 100644 --- a/wgpu/backends/wgpu_native/_api.py +++ b/wgpu/backends/wgpu_native/_api.py @@ -36,7 +36,7 @@ SafeLibCalls, ) -logger = logging.getLogger("wgpu") # noqa +logger = logging.getLogger("wgpu") # The API is prettu well defined @@ -153,7 +153,7 @@ def _tuple_from_tuple_or_dict(ob, fields, defaults=()): for index, key in enumerate(fields) ) except KeyError: - raise ValueError(error_msg.format(", ".join(fields))) + raise ValueError(error_msg.format(", ".join(fields))) from None else: raise TypeError(error_msg.format(", ".join(fields))) @@ -276,10 +276,10 @@ def _get_features(id: int, device: bool = False, adapter: bool = False): if adapter: # H: WGPUBool f(WGPUAdapter adapter, WGPUFeatureName feature) - has_feature = lambda feature: libf.wgpuAdapterHasFeature(id, feature) # noqa + has_feature = lambda feature: libf.wgpuAdapterHasFeature(id, feature) else: # H: WGPUBool f(WGPUDevice device, WGPUFeatureName feature) - has_feature = lambda feature: libf.wgpuDeviceHasFeature(id, feature) # noqa + has_feature = lambda feature: libf.wgpuDeviceHasFeature(id, feature) features = set() @@ -309,7 +309,6 @@ def _get_features(id: int, device: bool = False, adapter: bool = False): class GPU(classes.GPU): - def request_adapter_sync( self, *, power_preference=None, force_fallback_adapter=False, canvas=None ): @@ -601,7 +600,6 @@ def _configure_screen( tone_mapping, alpha_mode, ): - capabilities = self._get_capabilities(device.adapter) # Convert to C values @@ -615,11 +613,10 @@ def _configure_screen( c_alpha_mode = getattr(lib, f"WGPUCompositeAlphaMode_{alpha_mode.capitalize()}") # The color_space is not used for now - color_space - # Same for tone mapping + color_space # noqa - not used yet check_struct("CanvasToneMapping", tone_mapping) tone_mapping_mode = tone_mapping.get("mode", "standard") - tone_mapping_mode + tone_mapping_mode # noqa - not used yet # Select the present mode to determine vsync behavior. # * https://docs.rs/wgpu/latest/wgpu/enum.PresentMode.html @@ -683,7 +680,6 @@ def _unconfigure_screen(self): libf.wgpuSurfaceUnconfigure(self._surface_id) def _create_texture_screen(self): - surface_id = self._surface_id # Reconfigure when the canvas has resized. @@ -832,7 +828,6 @@ class GPUAdapterInfo(classes.GPUAdapterInfo): class GPUAdapter(classes.GPUAdapter): - def request_device_sync( self, *, @@ -1833,7 +1828,6 @@ def create_render_bundle_encoder( depth_read_only: bool = False, stencil_read_only: bool = False, ): - c_color_formats, color_formats_count = ffi.NULL, 0 if color_formats: color_formats_list = [enummap["TextureFormat." + x] for x in color_formats] @@ -2345,7 +2339,7 @@ def pop_debug_group(self): # H: void wgpuComputePassEncoderPopDebugGroup(WGPUComputePassEncoder computePassEncoder) # H: void wgpuRenderPassEncoderPopDebugGroup(WGPURenderPassEncoder renderPassEncoder) # H: void wgpuRenderBundleEncoderPopDebugGroup(WGPURenderBundleEncoder renderBundleEncoder) - function = type(self)._pop_debug_group_function # noqa + function = type(self)._pop_debug_group_function function(self._internal) def insert_debug_marker(self, marker_label): @@ -2388,7 +2382,7 @@ def set_vertex_buffer(self, slot, buffer, offset=0, size=None): def draw(self, vertex_count, instance_count=1, first_vertex=0, first_instance=0): # H: void wgpuRenderPassEncoderDraw(WGPURenderPassEncoder renderPassEncoder, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) # H: void wgpuRenderBundleEncoderDraw(WGPURenderBundleEncoder renderBundleEncoder, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) - function = type(self)._draw_function # noqa + function = type(self)._draw_function function( self._internal, vertex_count, instance_count, first_vertex, first_instance ) @@ -2397,7 +2391,7 @@ def draw_indirect(self, indirect_buffer, indirect_offset): buffer_id = indirect_buffer._internal # H: void wgpuRenderPassEncoderDrawIndirect(WGPURenderPassEncoder renderPassEncoder, WGPUBuffer indirectBuffer, uint64_t indirectOffset) # H: void wgpuRenderBundleEncoderDrawIndirect(WGPURenderBundleEncoder renderBundleEncoder, WGPUBuffer indirectBuffer, uint64_t indirectOffset) - function = type(self)._draw_indirect_function # noqa + function = type(self)._draw_indirect_function function(self._internal, buffer_id, int(indirect_offset)) def draw_indexed( @@ -2431,7 +2425,6 @@ def draw_indexed_indirect(self, indirect_buffer, indirect_offset): class GPUCommandEncoder( classes.GPUCommandEncoder, GPUCommandsMixin, GPUDebugCommandsMixin, GPUObjectBase ): - # GPUDebugCommandsMixin _push_debug_group_function = libf.wgpuCommandEncoderPushDebugGroup _pop_debug_group_function = libf.wgpuCommandEncoderPopDebugGroup @@ -2840,7 +2833,6 @@ class GPUComputePassEncoder( GPUBindingCommandsMixin, GPUObjectBase, ): - # GPUDebugCommandsMixin _push_debug_group_function = libf.wgpuComputePassEncoderPushDebugGroup _pop_debug_group_function = libf.wgpuComputePassEncoderPopDebugGroup @@ -3244,12 +3236,9 @@ def read_texture(self, source, data_layout, size): data2 = memoryview((ctypes.c_uint8 * data_length2)()).cast(data.format) for i in range(size[1] * size[2]): row = data[i * full_stride : i * full_stride + ori_stride] - data2[ - ori_offset - + i * ori_stride : ori_offset - + i * ori_stride - + ori_stride - ] = row + i_start = ori_offset + i * ori_stride + i_end = ori_offset + i * ori_stride + ori_stride + data2[i_start:i_end] = row data = data2 return data diff --git a/wgpu/backends/wgpu_native/_ffi.py b/wgpu/backends/wgpu_native/_ffi.py index b174aa32..60d7066a 100644 --- a/wgpu/backends/wgpu_native/_ffi.py +++ b/wgpu/backends/wgpu_native/_ffi.py @@ -1,5 +1,4 @@ -"""Loading the header, the lib, and setting up its logging. -""" +"""Loading the header, the lib, and setting up its logging.""" import os import sys @@ -10,7 +9,7 @@ from cffi import FFI, __version_info__ as cffi_version_info -logger = logging.getLogger("wgpu") # noqa +logger = logging.getLogger("wgpu") if cffi_version_info < (1, 10): # no-cover @@ -116,7 +115,7 @@ def _maybe_get_pip_hint(): # Get pip version pip_version = () try: - import pip # noqa + import pip parts = [] for x in pip.__version__.split("."): diff --git a/wgpu/backends/wgpu_native/_helpers.py b/wgpu/backends/wgpu_native/_helpers.py index 05e6dee2..798d01a8 100644 --- a/wgpu/backends/wgpu_native/_helpers.py +++ b/wgpu/backends/wgpu_native/_helpers.py @@ -1,5 +1,4 @@ -"""Utilities used in the wgpu-native backend. -""" +"""Utilities used in the wgpu-native backend.""" import sys import ctypes @@ -100,7 +99,7 @@ def get_surface_id_from_info(present_info): """ if sys.platform.startswith("win"): # no-cover - GetModuleHandle = ctypes.windll.kernel32.GetModuleHandleW # noqa + GetModuleHandle = ctypes.windll.kernel32.GetModuleHandleW # noqa: N806 struct = ffi.new("WGPUSurfaceDescriptorFromWindowsHWND *") struct.hinstance = ffi.cast("void *", GetModuleHandle(lib_path)) struct.hwnd = ffi.cast("void *", int(present_info["window"])) diff --git a/wgpu/backends/wgpu_native/_mappings.py b/wgpu/backends/wgpu_native/_mappings.py index b33712b9..0a9d9f2a 100644 --- a/wgpu/backends/wgpu_native/_mappings.py +++ b/wgpu/backends/wgpu_native/_mappings.py @@ -1,8 +1,7 @@ -""" Mappings for the wgpu-native backend. """ +"""Mappings for the wgpu-native backend.""" # THIS CODE IS AUTOGENERATED - DO NOT EDIT -# flake8: noqa # There are 236 enum mappings diff --git a/wgpu/classes.py b/wgpu/classes.py index 20190141..03b8f888 100644 --- a/wgpu/classes.py +++ b/wgpu/classes.py @@ -4,5 +4,5 @@ but are also available in the root wgpu namespace. """ -from ._classes import * # noqa: F401, F403 +from ._classes import * # noqa: F403 from ._classes import __all__ # noqa: F401 diff --git a/wgpu/enums.py b/wgpu/enums.py index 5a713341..75ea9ad2 100644 --- a/wgpu/enums.py +++ b/wgpu/enums.py @@ -59,13 +59,11 @@ class Enum(_BaseEnum): class PowerPreference(Enum): - low_power = "low-power" high_performance = "high-performance" class FeatureName(Enum): - depth_clip_control = "depth-clip-control" depth32float_stencil8 = "depth32float-stencil8" texture_compression_bc = "texture-compression-bc" @@ -83,21 +81,18 @@ class FeatureName(Enum): class BufferMapState(Enum): - unmapped = "unmapped" pending = "pending" mapped = "mapped" class TextureDimension(Enum): - d1 = "1d" d2 = "2d" d3 = "3d" class TextureViewDimension(Enum): - d1 = "1d" d2 = "2d" d2_array = "2d-array" @@ -107,14 +102,12 @@ class TextureViewDimension(Enum): class TextureAspect(Enum): - all = "all" stencil_only = "stencil-only" depth_only = "depth-only" class TextureFormat(Enum): - r8unorm = "r8unorm" r8snorm = "r8snorm" r8uint = "r8uint" @@ -213,26 +206,22 @@ class TextureFormat(Enum): class AddressMode(Enum): - clamp_to_edge = "clamp-to-edge" repeat = "repeat" mirror_repeat = "mirror-repeat" class FilterMode(Enum): - nearest = "nearest" linear = "linear" class MipmapFilterMode(Enum): - nearest = "nearest" linear = "linear" class CompareFunction(Enum): - never = "never" less = "less" equal = "equal" @@ -244,21 +233,18 @@ class CompareFunction(Enum): class BufferBindingType(Enum): - uniform = "uniform" storage = "storage" read_only_storage = "read-only-storage" class SamplerBindingType(Enum): - filtering = "filtering" non_filtering = "non-filtering" comparison = "comparison" class TextureSampleType(Enum): - float = "float" unfilterable_float = "unfilterable-float" depth = "depth" @@ -267,32 +253,27 @@ class TextureSampleType(Enum): class StorageTextureAccess(Enum): - write_only = "write-only" read_only = "read-only" read_write = "read-write" class CompilationMessageType(Enum): - error = "error" warning = "warning" info = "info" class PipelineErrorReason(Enum): - validation = "validation" internal = "internal" class AutoLayoutMode(Enum): - auto = "auto" class PrimitiveTopology(Enum): - point_list = "point-list" line_list = "line-list" line_strip = "line-strip" @@ -301,20 +282,17 @@ class PrimitiveTopology(Enum): class FrontFace(Enum): - ccw = "ccw" cw = "cw" class CullMode(Enum): - none = "none" front = "front" back = "back" class BlendFactor(Enum): - zero = "zero" one = "one" src = "src" @@ -335,7 +313,6 @@ class BlendFactor(Enum): class BlendOperation(Enum): - add = "add" subtract = "subtract" reverse_subtract = "reverse-subtract" @@ -344,7 +321,6 @@ class BlendOperation(Enum): class StencilOperation(Enum): - keep = "keep" zero = "zero" replace = "replace" @@ -356,13 +332,11 @@ class StencilOperation(Enum): class IndexFormat(Enum): - uint16 = "uint16" uint32 = "uint32" class VertexFormat(Enum): - uint8x2 = "uint8x2" uint8x4 = "uint8x4" sint8x2 = "sint8x2" @@ -397,49 +371,41 @@ class VertexFormat(Enum): class VertexStepMode(Enum): - vertex = "vertex" instance = "instance" class LoadOp(Enum): - load = "load" clear = "clear" class StoreOp(Enum): - store = "store" discard = "discard" class QueryType(Enum): - occlusion = "occlusion" timestamp = "timestamp" class CanvasAlphaMode(Enum): - opaque = "opaque" premultiplied = "premultiplied" class CanvasToneMappingMode(Enum): - standard = "standard" extended = "extended" class DeviceLostReason(Enum): - unknown = "unknown" destroyed = "destroyed" class ErrorFilter(Enum): - validation = "validation" out_of_memory = "out-of-memory" internal = "internal" diff --git a/wgpu/flags.py b/wgpu/flags.py index 26eede28..5bd06793 100644 --- a/wgpu/flags.py +++ b/wgpu/flags.py @@ -31,7 +31,6 @@ class Flags(_BaseEnum): class BufferUsage(Flags): - MAP_READ = 1 MAP_WRITE = 2 COPY_SRC = 4 @@ -45,13 +44,11 @@ class BufferUsage(Flags): class MapMode(Flags): - READ = 1 WRITE = 2 class TextureUsage(Flags): - COPY_SRC = 1 COPY_DST = 2 TEXTURE_BINDING = 4 @@ -60,14 +57,12 @@ class TextureUsage(Flags): class ShaderStage(Flags): - VERTEX = 1 FRAGMENT = 2 COMPUTE = 4 class ColorWrite(Flags): - RED = 1 GREEN = 2 BLUE = 4 diff --git a/wgpu/gui/__init__.py b/wgpu/gui/__init__.py index ac542717..cb74d27e 100644 --- a/wgpu/gui/__init__.py +++ b/wgpu/gui/__init__.py @@ -3,7 +3,7 @@ """ from . import _gui_utils # noqa: F401 -from .base import WgpuCanvasInterface, WgpuCanvasBase, WgpuAutoGui # noqa: F401 +from .base import WgpuCanvasInterface, WgpuCanvasBase, WgpuAutoGui __all__ = [ "WgpuCanvasInterface", diff --git a/wgpu/gui/_gui_utils.py b/wgpu/gui/_gui_utils.py index 99ed527e..75fe3261 100644 --- a/wgpu/gui/_gui_utils.py +++ b/wgpu/gui/_gui_utils.py @@ -1,5 +1,4 @@ -""" Private gui utilities. -""" +"""Private gui utilities.""" import os import sys @@ -35,7 +34,7 @@ def get_imported_qt_lib(): # Get which of these have an application object imported_libs_with_app = [] for libname in imported_libs: - QtWidgets = sys.modules.get(libname + ".QtWidgets", None) # noqa + QtWidgets = sys.modules.get(libname + ".QtWidgets", None) # noqa: N806 if QtWidgets: app = QtWidgets.QApplication.instance() if app is not None: diff --git a/wgpu/gui/auto.py b/wgpu/gui/auto.py index cd28c0ea..d34c4c63 100644 --- a/wgpu/gui/auto.py +++ b/wgpu/gui/auto.py @@ -20,15 +20,15 @@ def _load_backend(backend_name): """Load a gui backend by name.""" if backend_name == "glfw": - from . import glfw as module # noqa + from . import glfw as module elif backend_name == "qt": - from . import qt as module # noqa + from . import qt as module elif backend_name == "jupyter": - from . import jupyter as module # noqa + from . import jupyter as module elif backend_name == "wx": - from . import wx as module # noqa + from . import wx as module elif backend_name == "offscreen": - from . import offscreen as module # noqa + from . import offscreen as module else: # no-cover raise ImportError("Unknown wgpu gui backend: '{backend_name}'") return module diff --git a/wgpu/gui/base.py b/wgpu/gui/base.py index ab21c1bd..cc957673 100644 --- a/wgpu/gui/base.py +++ b/wgpu/gui/base.py @@ -115,7 +115,7 @@ def __init__(self, *args, max_fps=30, vsync=True, present_method=None, **kwargs) self._last_draw_time = 0 self._max_fps = float(max_fps) self._vsync = bool(vsync) - present_method # We just catch the arg here in case a backend does implement support it + present_method # noqa - We just catch the arg here in case a backend does implement support it def __del__(self): # On delete, we call the custom close method. diff --git a/wgpu/gui/glfw.py b/wgpu/gui/glfw.py index 595a99ea..483e2b3f 100644 --- a/wgpu/gui/glfw.py +++ b/wgpu/gui/glfw.py @@ -35,9 +35,9 @@ # Some glfw functions are not always available -set_window_content_scale_callback = lambda *args: None # noqa: E731 -set_window_maximize_callback = lambda *args: None # noqa: E731 -get_window_content_scale = lambda *args: (1, 1) # noqa: E731 +set_window_content_scale_callback = lambda *args: None +set_window_maximize_callback = lambda *args: None +get_window_content_scale = lambda *args: (1, 1) if hasattr(glfw, "set_window_content_scale_callback"): set_window_content_scale_callback = glfw.set_window_content_scale_callback @@ -105,7 +105,6 @@ def get_glfw_present_info(window): - if sys.platform.startswith("win"): return { "method": "screen", diff --git a/wgpu/resources/__init__.py b/wgpu/resources/__init__.py index eca5e0ff..ebc3331f 100644 --- a/wgpu/resources/__init__.py +++ b/wgpu/resources/__init__.py @@ -1,2 +1 @@ -""" This module exists to have importlib.resources and setuptools recognize the folder as a module. -""" +"""This module exists to have importlib.resources and setuptools recognize the folder as a module.""" diff --git a/wgpu/utils/__init__.py b/wgpu/utils/__init__.py index 5f6777c0..a8803595 100644 --- a/wgpu/utils/__init__.py +++ b/wgpu/utils/__init__.py @@ -13,10 +13,12 @@ # GPU/wgpu semantics), but without using low level details of the wgpu # API itself. -from .._coreutils import BaseEnum # noqa: F401 +# ruff: noqa: F401 + +from .._coreutils import BaseEnum # The get_default_device() is so small and generally convenient that we import it by default. -from .device import get_default_device # noqa: F401 +from .device import get_default_device class _StubModule: diff --git a/wgpu/utils/compute.py b/wgpu/utils/compute.py index c6c8289a..0166b33b 100644 --- a/wgpu/utils/compute.py +++ b/wgpu/utils/compute.py @@ -75,7 +75,9 @@ def compute_with_buffers(input_arrays, output_arrays, shader, n=None): try: format_size = FORMAT_SIZES[format] except KeyError: - raise ValueError(f"Invalid format for output array {key}: {format}") + raise ValueError( + f"Invalid format for output array {key}: {format}" + ) from None shape = tuple(int(i) for i in array_descr[:-1]) if not (shape and all(i > 0 for i in shape)): raise ValueError(f"Invalid shape for output array {key}: {shape}") @@ -101,7 +103,7 @@ def compute_with_buffers(input_arrays, output_arrays, shader, n=None): # Get nx, ny, nz from n if n is None: - output_info = list(output_infos.values())[0] + output_info = next(iter(output_infos.values())) nx, ny, nz = output_info["length"], 1, 1 elif isinstance(n, int): nx, ny, nz = int(n), 1, 1 diff --git a/wgpu/utils/device.py b/wgpu/utils/device.py index c50dbbae..7becddee 100644 --- a/wgpu/utils/device.py +++ b/wgpu/utils/device.py @@ -10,7 +10,7 @@ def get_default_device(): global _default_device if _default_device is None: - import wgpu.backends.auto # noqa + import wgpu.backends.auto adapter = wgpu.gpu.request_adapter_sync(power_preference="high-performance") _default_device = adapter.request_device_sync() diff --git a/wgpu/utils/imgui/__init__.py b/wgpu/utils/imgui/__init__.py index 087b46ba..4138061b 100644 --- a/wgpu/utils/imgui/__init__.py +++ b/wgpu/utils/imgui/__init__.py @@ -1,2 +1,2 @@ -from .imgui_backend import ImguiWgpuBackend # noqa -from .imgui_renderer import ImguiRenderer # noqa +from .imgui_backend import ImguiWgpuBackend # noqa: F401 +from .imgui_renderer import ImguiRenderer # noqa: F401 diff --git a/wgpu/utils/imgui/imgui_backend.py b/wgpu/utils/imgui/imgui_backend.py index da93a1be..bc8ad2e0 100644 --- a/wgpu/utils/imgui/imgui_backend.py +++ b/wgpu/utils/imgui/imgui_backend.py @@ -94,7 +94,6 @@ class ImguiWgpuBackend: """Basic integration base class.""" def __init__(self, device, target_format): - if not imgui.get_current_context(): raise RuntimeError( "No valid ImGui context. Use imgui.create_context() first and/or " @@ -183,7 +182,6 @@ def create_fonts_texture(self): self.io.fonts.clear_tex_data() def _create_device_objects(self): - vertex_shader_program = self._device.create_shader_module( label="triangle_vert", code=VERTEX_SHADER_SRC ) @@ -290,7 +288,7 @@ def _create_device_objects(self): def _set_render_state(self, draw_data: imgui.ImDrawData): # update the uniform buffer (mvp and gamma) - l = draw_data.display_pos.x # noqa + l = draw_data.display_pos.x # noqa: E741 r = draw_data.display_pos.x + draw_data.display_size.x t = draw_data.display_pos.y b = draw_data.display_pos.y + draw_data.display_size.y @@ -316,7 +314,6 @@ def _set_render_state(self, draw_data: imgui.ImDrawData): ) def _update_vertex_buffer(self, draw_data: imgui.ImDrawData): - # check if we need to recreate the vertex buffer and index buffer vtx_count = draw_data.total_vtx_count if self._vertex_buffer is None or self._vertex_buffer_size < vtx_count: diff --git a/wgpu/utils/imgui/imgui_renderer.py b/wgpu/utils/imgui/imgui_renderer.py index 88e07aaa..036d529e 100644 --- a/wgpu/utils/imgui/imgui_renderer.py +++ b/wgpu/utils/imgui/imgui_renderer.py @@ -53,7 +53,6 @@ class ImguiRenderer: def __init__( self, device, canvas: wgpu.gui.WgpuCanvasBase, render_target_format=None ): - # Prepare present context self._canvas_context = canvas.get_context()