From cba01d8b8460ca5b29ccd854bb5bc6c50f5eaa55 Mon Sep 17 00:00:00 2001 From: Paul V Craven Date: Fri, 9 Oct 2026 15:29:33 -0500 Subject: [PATCH] Turn on ruff's pyupgrade rules The rules were turned off in #2677 until the arcade.gl abstraction and the pyglet 3 migration merged, to avoid conflicts. Both have merged. Most changes are ruff's own fixes in arcade.gl: typing.List/Dict/Tuple become builtins, Iterable/Sequence/Callable come from collections.abc, Union/Optional become X | Y, and .format() becomes f-strings. By hand: a Union type alias in arcade.gl.types, an unused import ruff won't remove from an __init__.py, and four __repr__ lines ruff made too long. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + arcade/anim/easing.py | 2 +- arcade/cli/cli.py | 3 +- arcade/gl/backends/opengl/buffer.py | 8 ++-- arcade/gl/backends/opengl/compute_shader.py | 2 +- arcade/gl/backends/opengl/context.py | 22 +++++----- arcade/gl/backends/opengl/framebuffer.py | 6 +-- arcade/gl/backends/opengl/glsl.py | 15 ++++--- arcade/gl/backends/opengl/program.py | 9 ++-- arcade/gl/backends/opengl/texture.py | 17 ++++---- arcade/gl/backends/opengl/texture_array.py | 17 ++++---- arcade/gl/backends/opengl/uniform.py | 2 +- arcade/gl/backends/opengl/vertex_array.py | 27 +++++------- arcade/gl/backends/webgl/context.py | 21 +++++----- arcade/gl/backends/webgl/framebuffer.py | 2 +- arcade/gl/backends/webgl/glsl.py | 15 ++++--- arcade/gl/backends/webgl/program.py | 7 ++-- arcade/gl/backends/webgl/texture.py | 9 ++-- arcade/gl/backends/webgl/texture_array.py | 5 ++- arcade/gl/backends/webgl/uniform.py | 3 +- arcade/gl/backends/webgl/utils.py | 4 +- arcade/gl/backends/webgl/vertex_array.py | 25 +++++------ arcade/gl/buffer.py | 2 +- arcade/gl/context.py | 42 ++++++++----------- arcade/gl/framebuffer.py | 9 ++-- arcade/gl/program.py | 5 ++- arcade/gl/provider.py | 4 +- arcade/gl/sampler.py | 2 +- arcade/gl/types.py | 9 ++-- arcade/gl/vertex_array.py | 21 ++++------ arcade/gui/experimental/animate.py | 7 ++-- arcade/gui/experimental/transition.py | 9 ++-- pyproject.toml | 3 +- .../sprite_collision_inspector.py | 7 ++-- tests/unit/camera/test_camera2d.py | 5 +-- tests/unit/color/test_color_type.py | 4 +- tests/unit/gui/__init__.py | 5 +-- tests/unit/gui/test_interactions.py | 15 ++++--- tests/unit/gui/test_property_dict.py | 11 +++-- tests/unit/gui/test_property_list.py | 3 +- tests/unit/rect/test_rect_instances.py | 5 ++- tests/unit/spritelist/test_spritelist.py | 16 ++++--- tests/unit/test_utils.py | 3 +- tests/unit/text/test_text.py | 4 +- 44 files changed, 196 insertions(+), 217 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3c87daa64..70d4099c64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,7 @@ Arcade [PyPi Release History](https://pypi.org/project/arcade/#history) page. - Added `arcade.sweep_line(start, end, sprite_list)`, which returns a `SweepInfo` for the first sprite a line hits (its `fraction`, `distance`, and surface `normal`), or `None`. It's `sweep_sprite` for a point: for lasers, hitscan weapons, or seeing what's in the way. Added the `sprite_laser_mirrors` example, where a laser bounces off rotating mirrors using the normal. ### Misc Changes +- Ruff's pyupgrade rules are on for `arcade` and `tests`. Type annotations use `list`, `dict`, `X | Y` and `collections.abc` instead of the deprecated `typing` aliases, mostly in `arcade.gl` ([#2676](https://github.com/pythonarcade/arcade/issues/2676)). Nothing changes at runtime. - `draw_lines`, `draw_points`, `draw_line_strip`, `draw_polygon_filled` and `draw_polygon_outline` raise a `ValueError` naming the first point that isn't 2 numbers, such as `point_list[2] is 7, but each point must be 2 numbers, such as (x, y)` ([#2215](https://github.com/pythonarcade/arcade/issues/2215)). Before, a bad point raised a confusing error like `'int' object is not iterable`, and in `draw_lines`, `draw_points` and `draw_line_strip` a point with 1 or 3 numbers silently shifted every number after it. The check costs one length comparison per call, and the points are now converted faster: drawing 1,000 lines or points went from about 137 to 90 µs per call. - The card game tutorial no longer passes `hit_box_algorithm="None"` to `Sprite`, an Arcade 2 argument that `Sprite` silently ignores. Its text no longer says hit box calculation is slow: loading all 52 cards with their default hit boxes takes about 40 ms. - Removed the docs build's workaround for Sphinx not copying changed CSS files (`util/sphinx_static_file_temp_fix.py` and its `.ENABLE_DEVMACHINE_SPHINX_STATIC_FIX` switch). Sphinx fixed it upstream, and the pinned Sphinx 9.1.0 copies changed CSS on incremental builds and with `make.py serve` ([#2266](https://github.com/pythonarcade/arcade/issues/2266)). diff --git a/arcade/anim/easing.py b/arcade/anim/easing.py index 5f361b133f..862ffcbce5 100644 --- a/arcade/anim/easing.py +++ b/arcade/anim/easing.py @@ -118,7 +118,7 @@ def LINEAR(t: float) -> float: @staticmethod def SINE_IN(t: float) -> float: """http://easings.net/#easeInSine""" - return 1 - cos((t * pi / 2)) + return 1 - cos(t * pi / 2) @staticmethod def SINE_OUT(t: float) -> float: diff --git a/arcade/cli/cli.py b/arcade/cli/cli.py index 11e682e2d0..fdf0344095 100644 --- a/arcade/cli/cli.py +++ b/arcade/cli/cli.py @@ -1,6 +1,5 @@ import argparse import sys -from typing import Type from .commands import BaseCommand, InfoCommand @@ -11,7 +10,7 @@ def __init__(self): self.prog: str = "arcade" self.description: str = "Arcade Game Library CLI" - def register_command(self, command_class: Type[BaseCommand]) -> None: + def register_command(self, command_class: type[BaseCommand]) -> None: # BaseCommand has a different constructor than its implementations command = command_class() # type: ignore[call-arg] self.commands[command.name] = command diff --git a/arcade/gl/backends/opengl/buffer.py b/arcade/gl/backends/opengl/buffer.py index 8990eb4f99..b43b9e01c4 100644 --- a/arcade/gl/backends/opengl/buffer.py +++ b/arcade/gl/backends/opengl/buffer.py @@ -149,11 +149,9 @@ def read(self, size: int = -1, offset: int = 0) -> bytes: # Manually detect this so it doesn't raise a confusing INVALID_VALUE error if size + offset > self._size: raise ValueError( - ( - "Attempting to read outside the buffer. " - f"Buffer size: {self._size} " - f"Reading from {offset} to {size + offset}" - ) + "Attempting to read outside the buffer. " + f"Buffer size: {self._size} " + f"Reading from {offset} to {size + offset}" ) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._glo) diff --git a/arcade/gl/backends/opengl/compute_shader.py b/arcade/gl/backends/opengl/compute_shader.py index 7f853e1060..1ff47e894e 100644 --- a/arcade/gl/backends/opengl/compute_shader.py +++ b/arcade/gl/backends/opengl/compute_shader.py @@ -88,7 +88,7 @@ def __init__(self, ctx: Context, glsl_source: str) -> None: gl.glGetProgramiv(self._glo, gl.GL_INFO_LOG_LENGTH, length) log = c_buffer(length.value) gl.glGetProgramInfoLog(self._glo, len(log), None, log) - raise ShaderException("Program link error: {}".format(log.value.decode())) + raise ShaderException(f"Program link error: {log.value.decode()}") self._introspect_uniforms() self._introspect_uniform_blocks() diff --git a/arcade/gl/backends/opengl/context.py b/arcade/gl/backends/opengl/context.py index 81cbe78e06..bea5f0ac09 100644 --- a/arcade/gl/backends/opengl/context.py +++ b/arcade/gl/backends/opengl/context.py @@ -1,5 +1,5 @@ +from collections.abc import Iterable, Sequence from ctypes import c_char_p, c_float, c_int, cast -from typing import Dict, Iterable, List, Sequence, Tuple import pyglet from pyglet.graphics.api import gl @@ -77,7 +77,7 @@ def __init__( gl.glEnable(gl.GL_SCISSOR_TEST) @property - def gl_version(self) -> Tuple[int, int]: + def gl_version(self) -> tuple[int, int]: """ The OpenGL major and minor version as a tuple. @@ -147,7 +147,7 @@ def disable(self, *args): gl.glDisable(flag) @Context.blend_func.setter - def blend_func(self, value: Tuple[int, int] | Tuple[int, int, int, int]): + def blend_func(self, value: tuple[int, int] | tuple[int, int, int, int]): self._blend_func = value if len(value) == 2: gl.glBlendFunc(*value) @@ -240,8 +240,8 @@ def program( geometry_shader: str | None = None, tess_control_shader: str | None = None, tess_evaluation_shader: str | None = None, - common: List[str] | None = None, - defines: Dict[str, str] | None = None, + common: list[str] | None = None, + defines: dict[str, str] | None = None, varyings: Sequence[str] | None = None, varyings_capture_mode: str = "interleaved", ) -> OpenGLProgram: @@ -308,14 +308,14 @@ def compute_shader(self, *, source: str, common: Iterable[str] = ()) -> OpenGLCo def texture( self, - size: Tuple[int, int], + size: tuple[int, int], *, components: int = 4, dtype: str = "f1", data: BufferProtocol | None = None, wrap_x: PyGLenum | None = None, wrap_y: PyGLenum | None = None, - filter: Tuple[PyGLenum, PyGLenum] | None = None, + filter: tuple[PyGLenum, PyGLenum] | None = None, samples: int = 0, immutable: bool = False, internal_format: PyGLenum | None = None, @@ -341,14 +341,14 @@ def texture( ) def depth_texture( - self, size: Tuple[int, int], *, data: BufferProtocol | None = None + self, size: tuple[int, int], *, data: BufferProtocol | None = None ) -> OpenGLTexture2D: return OpenGLTexture2D(self, size, data=data, depth=True) def framebuffer( self, *, - color_attachments: OpenGLTexture2D | List[OpenGLTexture2D] | None = None, + color_attachments: OpenGLTexture2D | list[OpenGLTexture2D] | None = None, depth_attachment: OpenGLTexture2D | None = None, ) -> OpenGLFramebuffer: return OpenGLFramebuffer( @@ -404,14 +404,14 @@ def sampler(self, texture: OpenGLTexture2D) -> OpenGLSampler: def texture_array( self, - size: Tuple[int, int, int], + size: tuple[int, int, int], *, components: int = 4, dtype: str = "f1", data: BufferProtocol | None = None, wrap_x: PyGLenum | None = None, wrap_y: PyGLenum | None = None, - filter: Tuple[PyGLenum, PyGLenum] | None = None, + filter: tuple[PyGLenum, PyGLenum] | None = None, ) -> OpenGLTextureArray: return OpenGLTextureArray( self, diff --git a/arcade/gl/backends/opengl/framebuffer.py b/arcade/gl/backends/opengl/framebuffer.py index 08480158b4..053343d665 100644 --- a/arcade/gl/backends/opengl/framebuffer.py +++ b/arcade/gl/backends/opengl/framebuffer.py @@ -52,7 +52,7 @@ class OpenGLFramebuffer(Framebuffer): def __init__( self, - ctx: "Context", + ctx: Context, *, color_attachments: OpenGLTexture2D | list[OpenGLTexture2D], depth_attachment: OpenGLTexture2D | None = None, @@ -352,7 +352,7 @@ def _check_completeness() -> None: ) def __repr__(self): - return "".format(self._glo.value) + return f"" class OpenGLDefaultFrameBuffer(DefaultFrameBuffer, OpenGLFramebuffer): @@ -373,7 +373,7 @@ class OpenGLDefaultFrameBuffer(DefaultFrameBuffer, OpenGLFramebuffer): is_default = True """Is this the default framebuffer? (window buffer)""" - def __init__(self, ctx: "Context"): + def __init__(self, ctx: Context): super().__init__(ctx) value = c_int() diff --git a/arcade/gl/backends/opengl/glsl.py b/arcade/gl/backends/opengl/glsl.py index 2827f6b683..c53e310c47 100644 --- a/arcade/gl/backends/opengl/glsl.py +++ b/arcade/gl/backends/opengl/glsl.py @@ -1,5 +1,6 @@ import re -from typing import TYPE_CHECKING, Iterable +from collections.abc import Iterable +from typing import TYPE_CHECKING from pyglet.graphics.api import gl @@ -124,12 +125,10 @@ def _find_glsl_version(self) -> int: source = "\n".join(f"{str(i + 1).zfill(3)}: {line} " for i, line in enumerate(self._lines)) raise ShaderException( - ( - "Cannot find #version in shader source. " - "Please provide at least a #version 330 statement in the beginning of the shader.\n" - f"---- [{SHADER_TYPE_NAMES[self._type]}] ---\n" - f"{source}" - ) + "Cannot find #version in shader source. " + "Please provide at least a #version 330 statement in the beginning of the shader.\n" + f"---- [{SHADER_TYPE_NAMES[self._type]}] ---\n" + f"{source}" ) @staticmethod @@ -151,7 +150,7 @@ def apply_defines(lines: list[str], defines: dict[str, str]) -> list[str]: if value is None: continue - lines[nr] = "#define {} {}".format(name, str(value)) + lines[nr] = f"#define {name} {str(value)}" except IndexError: pass diff --git a/arcade/gl/backends/opengl/program.py b/arcade/gl/backends/opengl/program.py index c9398e53aa..d15b94467d 100644 --- a/arcade/gl/backends/opengl/program.py +++ b/arcade/gl/backends/opengl/program.py @@ -2,6 +2,7 @@ import typing import weakref +from collections.abc import Iterable from ctypes import ( POINTER, byref, @@ -13,7 +14,7 @@ create_string_buffer, pointer, ) -from typing import TYPE_CHECKING, Any, Iterable +from typing import TYPE_CHECKING, Any from pyglet.graphics import core from pyglet.graphics.api import gl @@ -173,7 +174,7 @@ def __del__(self): self._ctx.objects.append(self) @property - def ctx(self) -> "Context": + def ctx(self) -> Context: """The context this program belongs to.""" return self._ctx @@ -547,7 +548,7 @@ def link(glo): gl.glGetProgramiv(glo, gl.GL_INFO_LOG_LENGTH, length) log = c_buffer(length.value) gl.glGetProgramInfoLog(glo, len(log), None, log) - raise ShaderException("Program link error: {}".format(log.value.decode())) + raise ShaderException(f"Program link error: {log.value.decode()}") def __repr__(self): - return "".format(self._glo) + return f"" diff --git a/arcade/gl/backends/opengl/texture.py b/arcade/gl/backends/opengl/texture.py index 0b1f86cd2a..a5cc626e27 100644 --- a/arcade/gl/backends/opengl/texture.py +++ b/arcade/gl/backends/opengl/texture.py @@ -296,12 +296,10 @@ def _texture_2d(self, data): ) except gl.GLException as ex: raise gl.GLException( - ( - f"Unable to create texture: {ex} : dtype={self._dtype} " - f"size={self.size} components={self._components} " - f"MAX_TEXTURE_SIZE = {self.ctx.info.MAX_TEXTURE_SIZE}" - f": {ex}" - ) + f"Unable to create texture: {ex} : dtype={self._dtype} " + f"size={self.size} components={self._components} " + f"MAX_TEXTURE_SIZE = {self.ctx.info.MAX_TEXTURE_SIZE}" + f": {ex}" ) @property @@ -654,7 +652,7 @@ def delete(self): self._glo.value = 0 @staticmethod - def delete_glo(ctx: "Context", glo: gl.GLuint): + def delete_glo(ctx: Context, glo: gl.GLuint): """ Destroy the texture. @@ -754,6 +752,7 @@ def get_handle(self, resident: bool = True) -> int: return handle def __repr__(self) -> str: - return "".format( - self._glo.value, self._width, self._height, self._components + return ( + f"" ) diff --git a/arcade/gl/backends/opengl/texture_array.py b/arcade/gl/backends/opengl/texture_array.py index 359614394c..8af34c2030 100644 --- a/arcade/gl/backends/opengl/texture_array.py +++ b/arcade/gl/backends/opengl/texture_array.py @@ -306,12 +306,10 @@ def _texture_2d_array(self, data): ) except gl.GLException as ex: raise gl.GLException( - ( - f"Unable to create texture: {ex} : dtype={self._dtype} " - f"size={self.size} components={self._components} " - f"MAX_TEXTURE_SIZE = {self.ctx.info.MAX_TEXTURE_SIZE}" - f": {ex}" - ) + f"Unable to create texture: {ex} : dtype={self._dtype} " + f"size={self.size} components={self._components} " + f"MAX_TEXTURE_SIZE = {self.ctx.info.MAX_TEXTURE_SIZE}" + f": {ex}" ) @property @@ -598,7 +596,7 @@ def delete(self): self._glo.value = 0 @staticmethod - def delete_glo(ctx: "Context", glo: gl.GLuint): + def delete_glo(ctx: Context, glo: gl.GLuint): """ Destroy the texture. @@ -698,6 +696,7 @@ def get_handle(self, resident: bool = True) -> int: return handle def __repr__(self) -> str: - return "".format( - self._glo.value, self._width, self._layers, self._height, self._components + return ( + f"" ) diff --git a/arcade/gl/backends/opengl/uniform.py b/arcade/gl/backends/opengl/uniform.py index 55059cded7..96e4e17616 100644 --- a/arcade/gl/backends/opengl/uniform.py +++ b/arcade/gl/backends/opengl/uniform.py @@ -1,6 +1,6 @@ import struct +from collections.abc import Callable from ctypes import POINTER, c_double, c_float, c_int, c_uint, cast -from typing import Callable from pyglet.graphics.api import gl diff --git a/arcade/gl/backends/opengl/vertex_array.py b/arcade/gl/backends/opengl/vertex_array.py index 78aee3d6cb..f9460f63b2 100644 --- a/arcade/gl/backends/opengl/vertex_array.py +++ b/arcade/gl/backends/opengl/vertex_array.py @@ -1,8 +1,9 @@ from __future__ import annotations import weakref +from collections.abc import Sequence from ctypes import byref, c_void_p -from typing import TYPE_CHECKING, Sequence +from typing import TYPE_CHECKING from pyglet.graphics import core from pyglet.graphics.api import gl @@ -148,20 +149,16 @@ def _build( buff_descr, attr_descr = descr_attribs[prog_attr.name] except KeyError: raise ValueError( - ( - f"Program needs attribute '{prog_attr.name}', but is not present in buffer " - f"description. Buffer descriptions: {content}" - ) + f"Program needs attribute '{prog_attr.name}', but is not present in buffer " + f"description. Buffer descriptions: {content}" ) # Make sure components described in BufferDescription and in the shader match if prog_attr.components != attr_descr.components: raise ValueError( - ( - f"Program attribute '{prog_attr.name}' has {prog_attr.components} " - f"components while the buffer description has {attr_descr.components} " - " components. " - ) + f"Program attribute '{prog_attr.name}' has {prog_attr.components} " + f"components while the buffer description has {attr_descr.components} " + " components. " ) gl.glEnableVertexAttribArray(prog_attr.location) @@ -189,11 +186,9 @@ def _build( # Sanity check attribute types between shader and buffer description if attrib_type != prog_attr.gl_type: raise ValueError( - ( - f"Program attribute '{prog_attr.name}' has type " - f"{gl_name(prog_attr.gl_type)} " - f"while the buffer description has type {gl_name(attr_descr.gl_type)}. " - ) + f"Program attribute '{prog_attr.name}' has type " + f"{gl_name(prog_attr.gl_type)} " + f"while the buffer description has type {gl_name(attr_descr.gl_type)}. " ) if attrib_type in float_types: @@ -471,7 +466,7 @@ class OpenGLGeometry(Geometry): def __init__( self, - ctx: "Context", + ctx: Context, content: Sequence[BufferDescription] | None, index_buffer: Buffer | None = None, mode: int | None = None, diff --git a/arcade/gl/backends/webgl/context.py b/arcade/gl/backends/webgl/context.py index 7902fcd622..7bc3c92bce 100644 --- a/arcade/gl/backends/webgl/context.py +++ b/arcade/gl/backends/webgl/context.py @@ -1,4 +1,5 @@ -from typing import TYPE_CHECKING, Dict, Iterable, List, Sequence, Tuple +from collections.abc import Iterable, Sequence +from typing import TYPE_CHECKING import pyglet import pyglet.graphics.api @@ -141,7 +142,7 @@ def disable(self, *args): self._gl.disable(flag) @Context.blend_func.setter - def blend_func(self, value: Tuple[int, int] | Tuple[int, int, int, int]): + def blend_func(self, value: tuple[int, int] | tuple[int, int, int, int]): self._blend_func = value if len(value) == 2: self._gl.blendFunc(*value) @@ -215,8 +216,8 @@ def program( geometry_shader: str | None = None, tess_control_shader: str | None = None, tess_evaluation_shader: str | None = None, - common: List[str] | None = None, - defines: Dict[str, str] | None = None, + common: list[str] | None = None, + defines: dict[str, str] | None = None, varyings: Sequence[str] | None = None, varyings_capture_mode: str = "interleaved", ): @@ -271,14 +272,14 @@ def compute_shader(self, *, source: str, common: Iterable[str] = ()) -> None: def texture( self, - size: Tuple[int, int], + size: tuple[int, int], *, components: int = 4, dtype: str = "f1", data: BufferProtocol | None = None, wrap_x: int | None = None, wrap_y: int | None = None, - filter: Tuple[int, int] | None = None, + filter: tuple[int, int] | None = None, samples: int = 0, immutable: bool = False, internal_format: int | None = None, @@ -302,14 +303,14 @@ def texture( ) def depth_texture( - self, size: Tuple[int, int], *, data: BufferProtocol | None = None + self, size: tuple[int, int], *, data: BufferProtocol | None = None ) -> WebGLTexture2D: return WebGLTexture2D(self, size, data=data, depth=True) def framebuffer( self, *, - color_attachments: WebGLTexture2D | List[WebGLTexture2D] | None = None, + color_attachments: WebGLTexture2D | list[WebGLTexture2D] | None = None, depth_attachment: WebGLTexture2D | None = None, ) -> WebGLFramebuffer: return WebGLFramebuffer( @@ -352,14 +353,14 @@ def sampler(self, texture: WebGLTexture2D): def texture_array( self, - size: Tuple[int, int, int], + size: tuple[int, int, int], *, components: int = 4, dtype: str = "f1", data: BufferProtocol | None = None, wrap_x: int | None = None, wrap_y: int | None = None, - filter: Tuple[int, int] | None = None, + filter: tuple[int, int] | None = None, ) -> WebGLTextureArray: return WebGLTextureArray( self, diff --git a/arcade/gl/backends/webgl/framebuffer.py b/arcade/gl/backends/webgl/framebuffer.py index f7f338d7a6..38b8a404ab 100644 --- a/arcade/gl/backends/webgl/framebuffer.py +++ b/arcade/gl/backends/webgl/framebuffer.py @@ -235,7 +235,7 @@ def _check_completeness(ctx: WebGLContext) -> None: ) def __repr__(self): - return "".format(self._glo) + return f"" class WebGLDefaultFrameBuffer(DefaultFrameBuffer, WebGLFramebuffer): # type: ignore diff --git a/arcade/gl/backends/webgl/glsl.py b/arcade/gl/backends/webgl/glsl.py index b6c43de2f5..83d8284794 100644 --- a/arcade/gl/backends/webgl/glsl.py +++ b/arcade/gl/backends/webgl/glsl.py @@ -1,5 +1,6 @@ import re -from typing import TYPE_CHECKING, Iterable +from collections.abc import Iterable +from typing import TYPE_CHECKING if TYPE_CHECKING: from .context import Context as ArcadeGlContext @@ -117,12 +118,10 @@ def _find_glsl_version(self) -> int: source = "\n".join(f"{str(i + 1).zfill(3)}: {line} " for i, line in enumerate(self._lines)) raise ShaderException( - ( - "Cannot find #version in shader source. " - "Please provide at least a #version 330 statement in the beginning of the shader.\n" - f"---- [{SHADER_TYPE_NAMES[self._type]}] ---\n" - f"{source}" - ) + "Cannot find #version in shader source. " + "Please provide at least a #version 330 statement in the beginning of the shader.\n" + f"---- [{SHADER_TYPE_NAMES[self._type]}] ---\n" + f"{source}" ) @staticmethod @@ -144,7 +143,7 @@ def apply_defines(lines: list[str], defines: dict[str, str]) -> list[str]: if value is None: continue - lines[nr] = "#define {} {}".format(name, str(value)) + lines[nr] = f"#define {name} {str(value)}" except IndexError: pass diff --git a/arcade/gl/backends/webgl/program.py b/arcade/gl/backends/webgl/program.py index 14f0c3754b..b618407089 100644 --- a/arcade/gl/backends/webgl/program.py +++ b/arcade/gl/backends/webgl/program.py @@ -1,7 +1,8 @@ from __future__ import annotations import weakref -from typing import TYPE_CHECKING, Any, Iterable, cast +from collections.abc import Iterable +from typing import TYPE_CHECKING, Any, cast from arcade.gl import enums from arcade.gl.exceptions import ShaderException @@ -352,7 +353,7 @@ def link(ctx: WebGLContext, glo: JSWebGLProgram): status = ctx._gl.getProgramParameter(glo, enums.LINK_STATUS) if not status: log = ctx._gl.getProgramInfoLog(glo) - raise ShaderException("Program link error: {}".format(log)) + raise ShaderException(f"Program link error: {log}") def __repr__(self): - return "".format(self._glo) + return f"" diff --git a/arcade/gl/backends/webgl/texture.py b/arcade/gl/backends/webgl/texture.py index 82080b3474..0364136852 100644 --- a/arcade/gl/backends/webgl/texture.py +++ b/arcade/gl/backends/webgl/texture.py @@ -1,7 +1,7 @@ from __future__ import annotations import weakref -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING from pyodide.ffi import to_js @@ -168,7 +168,7 @@ def ctx(self) -> WebGLContext: return self._ctx @property - def glo(self) -> Optional[WebGLTexture]: + def glo(self) -> WebGLTexture | None: return self._glo @property @@ -377,6 +377,7 @@ def get_handle(self, resident: bool = True) -> int: raise NotImplementedError("get_handle is not supported with WebGL") def __repr__(self) -> str: - return "".format( - self._glo, self._width, self._height, self._components + return ( + f"" ) diff --git a/arcade/gl/backends/webgl/texture_array.py b/arcade/gl/backends/webgl/texture_array.py index ceb20638d2..5631d712c8 100644 --- a/arcade/gl/backends/webgl/texture_array.py +++ b/arcade/gl/backends/webgl/texture_array.py @@ -322,6 +322,7 @@ def get_handle(self, resident: bool = True) -> int: raise NotImplementedError("get_handle is not supported with WebGL") def __repr__(self) -> str: - return "".format( - self._glo, self._width, self._layers, self._height, self._components + return ( + f"" ) diff --git a/arcade/gl/backends/webgl/uniform.py b/arcade/gl/backends/webgl/uniform.py index 34741557af..40fa106746 100644 --- a/arcade/gl/backends/webgl/uniform.py +++ b/arcade/gl/backends/webgl/uniform.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Callable +from collections.abc import Callable +from typing import TYPE_CHECKING from arcade.gl import enums from arcade.gl.exceptions import ShaderException diff --git a/arcade/gl/backends/webgl/utils.py b/arcade/gl/backends/webgl/utils.py index 334e8682f9..17120f20c7 100644 --- a/arcade/gl/backends/webgl/utils.py +++ b/arcade/gl/backends/webgl/utils.py @@ -3,10 +3,10 @@ """ from array import array -from typing import Any, Union +from typing import Any -def data_to_memoryview(data: Any) -> tuple[int, Union[bytes, memoryview]]: +def data_to_memoryview(data: Any) -> tuple[int, bytes | memoryview]: """ Attempts to convert the data to a memoryview if needed diff --git a/arcade/gl/backends/webgl/vertex_array.py b/arcade/gl/backends/webgl/vertex_array.py index 680c37dc9e..b23686765e 100644 --- a/arcade/gl/backends/webgl/vertex_array.py +++ b/arcade/gl/backends/webgl/vertex_array.py @@ -1,7 +1,8 @@ from __future__ import annotations import weakref -from typing import TYPE_CHECKING, Sequence +from collections.abc import Sequence +from typing import TYPE_CHECKING from arcade.gl import enums from arcade.gl.types import BufferDescription, gl_name @@ -85,19 +86,15 @@ def _build( buff_descr, attr_descr = descr_attribs[prog_attr.name] except KeyError: raise ValueError( - ( - f"Program needs attribute '{prog_attr.name}', but is not present in buffer " - f"description. Buffer descriptions: {content}" - ) + f"Program needs attribute '{prog_attr.name}', but is not present in buffer " + f"description. Buffer descriptions: {content}" ) if prog_attr.components != attr_descr.components: raise ValueError( - ( - f"Program attribute '{prog_attr.name}' has {prog_attr.components} " - f"components while the buffer description has {attr_descr.components} " - " components. " - ) + f"Program attribute '{prog_attr.name}' has {prog_attr.components} " + f"components while the buffer description has {attr_descr.components} " + " components. " ) self._ctx._gl.enableVertexAttribArray(prog_attr.location) @@ -120,11 +117,9 @@ def _build( if attrib_type != prog_attr.gl_type: raise ValueError( - ( - f"Program attribute '{prog_attr.name}' has type " - f"{gl_name(prog_attr.gl_type)}" - f"while the buffer description has type {gl_name(attr_descr.gl_type)}. " - ) + f"Program attribute '{prog_attr.name}' has type " + f"{gl_name(prog_attr.gl_type)}" + f"while the buffer description has type {gl_name(attr_descr.gl_type)}. " ) if attrib_type in float_types or attrib_type in int_types: diff --git a/arcade/gl/buffer.py b/arcade/gl/buffer.py index 47769b6dd0..d3d68ed673 100644 --- a/arcade/gl/buffer.py +++ b/arcade/gl/buffer.py @@ -56,7 +56,7 @@ def size(self) -> int: return self._size @property - def ctx(self) -> "Context": + def ctx(self) -> Context: """The context this resource belongs to.""" return self._ctx diff --git a/arcade/gl/context.py b/arcade/gl/context.py index 35c775cb24..6b57367fa3 100644 --- a/arcade/gl/context.py +++ b/arcade/gl/context.py @@ -4,17 +4,11 @@ import weakref from abc import ABC, abstractmethod from collections import deque +from collections.abc import Iterable, Sequence from contextlib import contextmanager from typing import ( Any, - Deque, - Dict, - Iterable, - List, Literal, - Sequence, - Set, - Tuple, overload, ) @@ -227,9 +221,9 @@ def __init__( self._primitive_restart_index = -1 # States - self._blend_func: Tuple[int, int] | Tuple[int, int, int, int] = self.BLEND_DEFAULT + self._blend_func: tuple[int, int] | tuple[int, int, int, int] = self.BLEND_DEFAULT self._point_size = 1.0 - self._flags: Set[int] = set() + self._flags: set[int] = set() self._wireframe = False # Options for cull_face self._cull_face_options = { @@ -248,7 +242,7 @@ def __init__( self.gc_mode = gc_mode #: Collected objects to gc when gc_mode is "context_gc". #: This can be used during debugging. - self.objects: Deque[Any] = deque() + self.objects: deque[Any] = deque() @abstractmethod def _create_default_framebuffer(self) -> DefaultFrameBuffer: @@ -516,7 +510,7 @@ def is_enabled(self, flag) -> bool: return flag in self._flags @property - def viewport(self) -> Tuple[int, int, int, int]: + def viewport(self) -> tuple[int, int, int, int]: """ Get or set the viewport for the currently active framebuffer. The viewport simply describes what pixels of the screen @@ -533,11 +527,11 @@ def viewport(self) -> Tuple[int, int, int, int]: return self.active_framebuffer.viewport @viewport.setter - def viewport(self, value: Tuple[int, int, int, int]): + def viewport(self, value: tuple[int, int, int, int]): self.active_framebuffer.viewport = value @property - def scissor(self) -> Tuple[int, int, int, int] | None: + def scissor(self) -> tuple[int, int, int, int] | None: """ Get or set the scissor box for the active framebuffer. This is a shortcut for :py:meth:`~arcade.gl.Framebuffer.scissor`. @@ -562,7 +556,7 @@ def scissor(self, value): self.fbo.scissor = value @property - def blend_func(self) -> Tuple[int, int] | Tuple[int, int, int, int]: + def blend_func(self) -> tuple[int, int] | tuple[int, int, int, int]: """ Get or set the blend function. This is tuple specifying how the color and @@ -611,7 +605,7 @@ def blend_func(self) -> Tuple[int, int] | Tuple[int, int, int, int]: @blend_func.setter @abstractmethod - def blend_func(self, value: Tuple[int, int] | Tuple[int, int, int, int]): + def blend_func(self, value: tuple[int, int] | tuple[int, int, int, int]): raise NotImplementedError("The enabled graphics backend does not support this method.") # def blend_equation(self) @@ -844,7 +838,7 @@ def buffer( def framebuffer( self, *, - color_attachments: Texture2D | List[Texture2D] | None = None, + color_attachments: Texture2D | list[Texture2D] | None = None, depth_attachment: Texture2D | None = None, ) -> Framebuffer: """Create a Framebuffer. @@ -860,7 +854,7 @@ def framebuffer( @abstractmethod def texture( self, - size: Tuple[int, int], + size: tuple[int, int], *, components: int = 4, dtype: str = "f1", @@ -948,7 +942,7 @@ def texture( @abstractmethod def texture_array( self, - size: Tuple[int, int, int], + size: tuple[int, int, int], *, components: int = 4, dtype: str = "f1", @@ -973,7 +967,7 @@ def texture_array( @abstractmethod def depth_texture( - self, size: Tuple[int, int], *, data: BufferProtocol | None = None + self, size: tuple[int, int], *, data: BufferProtocol | None = None ) -> Texture2D: """ Create a 2D depth texture. Can be used as a depth attachment @@ -1094,8 +1088,8 @@ def program( geometry_shader: str | None = None, tess_control_shader: str | None = None, tess_evaluation_shader: str | None = None, - common: List[str] | None = None, - defines: Dict[str, str] | None = None, + common: list[str] | None = None, + defines: dict[str, str] | None = None, varyings: Sequence[str] | None = None, varyings_capture_mode: str = "interleaved", ) -> Program: @@ -1365,7 +1359,7 @@ def __init__(self, ctx): self.MAX_TEXTURE_MAX_ANISOTROPY = self.get_float(enums.MAX_TEXTURE_MAX_ANISOTROPY, 1.0) """The highest supported anisotropy value. Usually 8.0 or 16.0.""" - self.MAX_VIEWPORT_DIMS: Tuple[int, int] = self.get_int_tuple(enums.MAX_VIEWPORT_DIMS, 2) + self.MAX_VIEWPORT_DIMS: tuple[int, int] = self.get_int_tuple(enums.MAX_VIEWPORT_DIMS, 2) """ The maximum support window or framebuffer viewport. This is usually the same as the maximum texture size @@ -1380,10 +1374,10 @@ def __init__(self, ctx): """ @overload - def get_int_tuple(self, enum, length: Literal[2]) -> Tuple[int, int]: ... + def get_int_tuple(self, enum, length: Literal[2]) -> tuple[int, int]: ... @overload - def get_int_tuple(self, enum, length: int) -> Tuple[int, ...]: ... + def get_int_tuple(self, enum, length: int) -> tuple[int, ...]: ... @abstractmethod def get_int_tuple(self, enum, length: int): diff --git a/arcade/gl/framebuffer.py b/arcade/gl/framebuffer.py index 5af0b5cab5..b091d483d4 100644 --- a/arcade/gl/framebuffer.py +++ b/arcade/gl/framebuffer.py @@ -1,8 +1,9 @@ from __future__ import annotations from abc import ABC, abstractmethod +from collections.abc import Generator from contextlib import contextmanager -from typing import TYPE_CHECKING, Generator +from typing import TYPE_CHECKING from arcade.types import RGBOrA255, RGBOrANormalized @@ -62,7 +63,7 @@ class Framebuffer(ABC): def __init__( self, - ctx: "Context", + ctx: Context, *, color_attachments: Texture2D | list[Texture2D], depth_attachment: Texture2D | None = None, @@ -139,7 +140,7 @@ def scissor(self, value): raise NotImplementedError("The enabled graphics backend does not support this method.") @property - def ctx(self) -> "Context": + def ctx(self) -> Context: """The context this object belongs to.""" return self._ctx @@ -343,7 +344,7 @@ class DefaultFrameBuffer(Framebuffer, ABC): is_default = True """Is this the default framebuffer? (window buffer)""" - def __init__(self, ctx: "Context"): + def __init__(self, ctx: Context): self._ctx = ctx # TODO: Can we query this? self._samples = 0 diff --git a/arcade/gl/program.py b/arcade/gl/program.py index 3d8b8be7ab..6852bbda77 100644 --- a/arcade/gl/program.py +++ b/arcade/gl/program.py @@ -1,7 +1,8 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Any, Iterable +from collections.abc import Iterable +from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from arcade.gl import Context @@ -67,7 +68,7 @@ def __init__( self._ctx.stats.incr("program") @property - def ctx(self) -> "Context": + def ctx(self) -> Context: """The context this program belongs to.""" return self._ctx diff --git a/arcade/gl/provider.py b/arcade/gl/provider.py index c014be94c0..ce402ccbee 100644 --- a/arcade/gl/provider.py +++ b/arcade/gl/provider.py @@ -2,14 +2,14 @@ import importlib from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING if TYPE_CHECKING: from arcade.context import ArcadeContext from .context import Context, Info -_current_provider: Optional[BaseProvider] = None +_current_provider: BaseProvider | None = None def set_provider(provider_name: str): diff --git a/arcade/gl/sampler.py b/arcade/gl/sampler.py index 8e8259ad1f..64b1436fd8 100644 --- a/arcade/gl/sampler.py +++ b/arcade/gl/sampler.py @@ -17,7 +17,7 @@ class Sampler(ABC): def __init__( self, - ctx: "Context", + ctx: Context, texture: Texture2D, *, filter=None, # TODO: Typing, should be tuple[PyGLuint, PyGLuint] | None diff --git a/arcade/gl/types.py b/arcade/gl/types.py index c52d69de03..1907bc9e70 100644 --- a/arcade/gl/types.py +++ b/arcade/gl/types.py @@ -1,12 +1,13 @@ import re -from typing import Iterable, Sequence, TypeAlias, Union +from collections.abc import Iterable, Sequence +from typing import TypeAlias from arcade.types import BufferProtocol from . import enums from .buffer import Buffer -BufferOrBufferProtocol = Union[BufferProtocol, Buffer] +BufferOrBufferProtocol = BufferProtocol | Buffer GLenumLike = int PyGLenum = int @@ -15,9 +16,7 @@ OpenGlFilter: TypeAlias = tuple[PyGLenum, PyGLenum] -BlendFunction: TypeAlias = Union[ - tuple[PyGLenum, PyGLenum], tuple[PyGLenum, PyGLenum, PyGLenum, PyGLenum] -] +BlendFunction: TypeAlias = tuple[PyGLenum, PyGLenum] | tuple[PyGLenum, PyGLenum, PyGLenum, PyGLenum] #: Depth compare functions compare_funcs: dict[str | None, int] = { diff --git a/arcade/gl/vertex_array.py b/arcade/gl/vertex_array.py index 6106567340..95f5d36621 100644 --- a/arcade/gl/vertex_array.py +++ b/arcade/gl/vertex_array.py @@ -2,7 +2,8 @@ import weakref from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Sequence +from collections.abc import Sequence +from typing import TYPE_CHECKING from .buffer import Buffer from .program import Program @@ -273,7 +274,7 @@ def __init__( self._ctx.stats.incr("geometry") @property - def ctx(self) -> "Context": + def ctx(self) -> Context: """The context this geometry belongs to.""" return self._ctx @@ -500,11 +501,9 @@ def transform( if program._varyings_capture_mode == "interleaved": if not isinstance(buffer, Buffer): raise ValueError( - ( - "Buffer must be a single Buffer object " - "because the capture mode of the program is: " - f"{program.varyings_capture_mode}" - ) + "Buffer must be a single Buffer object " + "because the capture mode of the program is: " + f"{program.varyings_capture_mode}" ) vao.transform_interleaved( buffer, @@ -518,11 +517,9 @@ def transform( else: if not isinstance(buffer, list): raise ValueError( - ( - "buffer must be a list of Buffer object " - "because the capture mode of the program is: " - f"{program.varyings_capture_mode}" - ) + "buffer must be a list of Buffer object " + "because the capture mode of the program is: " + f"{program.varyings_capture_mode}" ) vao.transform_separate( buffer, diff --git a/arcade/gui/experimental/animate.py b/arcade/gui/experimental/animate.py index fa1dad2cf4..4fa67e3992 100644 --- a/arcade/gui/experimental/animate.py +++ b/arcade/gui/experimental/animate.py @@ -15,7 +15,8 @@ from __future__ import annotations -from typing import Any, Callable +from collections.abc import Callable +from typing import Any from arcade.anim import Easing from arcade.anim.easing import EasingFunction @@ -187,7 +188,7 @@ def then( ease: EasingFunction = Easing.LINEAR, delay: float = 0.0, **properties: Any, - ) -> "Animation": + ) -> Animation: """Append a segment which runs after the previous one finished. Accepts the same arguments as the constructor (except ``repeat`` and @@ -204,7 +205,7 @@ def then( self._segments.append(_Segment(dict(properties), float(duration), float(delay), ease)) return self - def on_finish(self, callback: Callable[[], Any]) -> "Animation": + def on_finish(self, callback: Callable[[], Any]) -> Animation: """Register a callback invoked once when the animation completes. Not invoked when the animation is stopped via :meth:`stop` or diff --git a/arcade/gui/experimental/transition.py b/arcade/gui/experimental/transition.py index b9fc545b07..2f4bd5b02e 100644 --- a/arcade/gui/experimental/transition.py +++ b/arcade/gui/experimental/transition.py @@ -1,5 +1,6 @@ from abc import ABC, abstractmethod -from typing import Any, Callable, List, Optional, TypeVar +from collections.abc import Callable +from typing import Any, TypeVar from pyglet.event import EventDispatcher @@ -105,7 +106,7 @@ def __init__( mutation_function: Callable[[Any, str, float], None] = setattr, ): super().__init__(duration=duration, delay=delay) - self._start: Optional[float] = start + self._start: float | None = start self._end = end self._attribute = attribute @@ -188,7 +189,7 @@ class TransitionParallel(TransitionBase): def __init__(self, *transactions: TransitionBase): super().__init__() - self._transitions: List[TransitionBase] = list(transactions) + self._transitions: list[TransitionBase] = list(transactions) def add(self, transition: T) -> T: self._transitions.append(transition) @@ -219,7 +220,7 @@ class TransitionChain(TransitionBase): def __init__(self, *transactions: TransitionBase): super().__init__() - self._transitions: List[TransitionBase] = list(transactions) + self._transitions: list[TransitionBase] = list(transactions) def add(self, transition: T) -> T: self._transitions.append(transition) diff --git a/pyproject.toml b/pyproject.toml index 2470bb34f0..71ee184b94 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -115,7 +115,8 @@ lint.select = [ # Whitespace linting must be re-enabled manually for ruff # see https://beta.ruff.rs/docs/configuration/#using-pyprojecttoml "W", - # "UP", wait for arcade.gl abstraction merge + # pyupgrade: modern syntax, such as list[int] and collections.abc imports + "UP", ] [tool.ruff.format] diff --git a/tests/manual_smoke/sprite_collision_inspector.py b/tests/manual_smoke/sprite_collision_inspector.py index f858993823..21b7923372 100644 --- a/tests/manual_smoke/sprite_collision_inspector.py +++ b/tests/manual_smoke/sprite_collision_inspector.py @@ -1,5 +1,6 @@ import builtins -from typing import Any, Callable, Generic, Type, TypeVar +from collections.abc import Callable +from typing import Any, Generic, TypeVar from pyglet.math import Vec2 @@ -27,7 +28,7 @@ def _tname(t: Any) -> str: class TypedTextInput(UIInputText, Generic[T]): def __init__( self, - parsed_type: Type[T], + parsed_type: type[T], *, to_str: Callable[[T], str] = repr, from_str: Callable[[str], T] | None = None, @@ -65,7 +66,7 @@ def __init__( **kwargs, ) self._error_color = error_color - self._parsed_type: Type[T] = parsed_type + self._parsed_type: type[T] = parsed_type self._to_str = to_str self._from_str = from_str or parsed_type self._parsed_value: T = self._from_str(self.text) diff --git a/tests/unit/camera/test_camera2d.py b/tests/unit/camera/test_camera2d.py index f73ffcf3e4..757ad7dcf4 100644 --- a/tests/unit/camera/test_camera2d.py +++ b/tests/unit/camera/test_camera2d.py @@ -1,5 +1,4 @@ from math import radians -from typing import Tuple import pytest as pytest from pyglet.math import Vec2 @@ -51,7 +50,7 @@ def same_near_far(request): def test_camera2d_from_camera_data_projection_xy_pairs_equal_raises_zeroprojectiondimension( window: Window, - bad_projection: Tuple[float, float, float, float], # Clarify type for PyCharm + bad_projection: tuple[float, float, float, float], # Clarify type for PyCharm camera_class, ): data = OrthographicProjectionData(*bad_projection, -100.0, 100.0) @@ -61,7 +60,7 @@ def test_camera2d_from_camera_data_projection_xy_pairs_equal_raises_zeroprojecti def test_camera2d_init_xy_pairs_equal_raises_zeroprojectiondimension( - window: Window, bad_projection: Tuple[float, float, float, float], camera_class + window: Window, bad_projection: tuple[float, float, float, float], camera_class ): with pytest.raises(ZeroProjectionDimension): _ = camera_class(projection=LRBT(*bad_projection)) diff --git a/tests/unit/color/test_color_type.py b/tests/unit/color/test_color_type.py index f7d3ae896c..c9f93a33f3 100644 --- a/tests/unit/color/test_color_type.py +++ b/tests/unit/color/test_color_type.py @@ -1,7 +1,7 @@ import math +from collections.abc import Callable, Iterable from copy import deepcopy from itertools import product -from typing import Callable, Iterable, Tuple from unittest.mock import Mock import pytest @@ -94,7 +94,7 @@ def test_color_from_normalized(): # some helper callables at_least_one_bad = at_least_one_in(BAD_NORMALIZED) - def local_convert(i: Iterable[float]) -> Tuple[int]: + def local_convert(i: Iterable[float]) -> tuple[int]: """Local helper converter, normalized float to byte ints""" return tuple(math.floor(c * 255) for c in i) diff --git a/tests/unit/gui/__init__.py b/tests/unit/gui/__init__.py index 99f284eaf9..e0f67f6c37 100644 --- a/tests/unit/gui/__init__.py +++ b/tests/unit/gui/__init__.py @@ -1,6 +1,5 @@ from abc import abstractmethod from contextlib import contextmanager -from typing import List import arcade from arcade.gui.events import UIEvent @@ -9,7 +8,7 @@ class InteractionMixin: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.event_history: List[UIEvent] = [] + self.event_history: list[UIEvent] = [] def move_mouse(self, x: int | float, y: int | float): self.on_mouse_motion(x, y, 0, 0) @@ -55,7 +54,7 @@ def dispatch_ui_event(self, event): @contextmanager -def record_ui_events(widget, *names) -> List[UIEvent]: +def record_ui_events(widget, *names) -> list[UIEvent]: events = [] def record(event): diff --git a/tests/unit/gui/test_interactions.py b/tests/unit/gui/test_interactions.py index 3ec32ef685..2a87c0a3f8 100644 --- a/tests/unit/gui/test_interactions.py +++ b/tests/unit/gui/test_interactions.py @@ -1,4 +1,3 @@ -from typing import List from unittest.mock import Mock import arcade @@ -46,7 +45,7 @@ def test_left_click_on_widget(ui): ui.click(widget1.center_x, widget1.center_y, button=arcade.MOUSE_BUTTON_LEFT) # THEN - records: List[UIEvent] + records: list[UIEvent] assert len(records) == 3 assert isinstance(records[0], UIMousePressEvent) assert isinstance(records[1], UIMouseReleaseEvent) @@ -73,7 +72,7 @@ def test_ignores_right_click_on_widget(ui): ui.click(widget1.center_x, widget1.center_y, button=arcade.MOUSE_BUTTON_RIGHT) # THEN - records: List[UIEvent] + records: list[UIEvent] assert len(records) == 2 assert isinstance(records[0], UIMousePressEvent) assert isinstance(records[1], UIMouseReleaseEvent) @@ -92,7 +91,7 @@ def test_click_on_widget_if_disabled(ui): ui.click(widget1.center_x, widget1.center_y) # THEN - records: List[UIEvent] + records: list[UIEvent] assert len(records) == 2 assert isinstance(records[0], UIMousePressEvent) assert isinstance(records[1], UIMouseReleaseEvent) @@ -114,11 +113,11 @@ def test_click_on_overlay_widget_consumes_events(ui): # THEN # events are consumed before they get to underlying widget - w1_records: List[UIEvent] + w1_records: list[UIEvent] assert len(w1_records) == 0 # events are dispatched on widget2 - w2_records: List[UIEvent] + w2_records: list[UIEvent] assert len(w2_records) == 1 click_event = w2_records[0] assert isinstance(click_event, UIOnClickEvent) @@ -141,11 +140,11 @@ def test_click_consumed_by_nested_widget(ui): # THEN # events are consumed before they get to underlying widget - w1_records: List[UIEvent] + w1_records: list[UIEvent] assert len(w1_records) == 0 # events are dispatched on widget2 - w2_records: List[UIEvent] + w2_records: list[UIEvent] assert len(w2_records) == 1 click_event = w2_records[0] assert isinstance(click_event, UIOnClickEvent) diff --git a/tests/unit/gui/test_property_dict.py b/tests/unit/gui/test_property_dict.py index 4bf6a89f60..61b78c9459 100644 --- a/tests/unit/gui/test_property_dict.py +++ b/tests/unit/gui/test_property_dict.py @@ -1,5 +1,4 @@ import gc -from typing import Dict from arcade.gui.property import DictProperty, _ObservableDict, bind @@ -65,7 +64,7 @@ class MyDictHolder: def test_dict_property_clear(): class MyDictHolder: - data: Dict = DictProperty() + data: dict = DictProperty() obj = MyDictHolder() observer = Observer() @@ -78,7 +77,7 @@ class MyDictHolder: def test_dict_property_pop(): class MyDictHolder: - data: Dict = DictProperty() + data: dict = DictProperty() obj = MyDictHolder() obj.data["test"] = 5 @@ -93,7 +92,7 @@ class MyDictHolder: def test_dict_property_pop_item(): class MyDictHolder: - data: Dict = DictProperty() + data: dict = DictProperty() obj = MyDictHolder() obj.data["test"] = 5 @@ -108,7 +107,7 @@ class MyDictHolder: def test_dict_property_set_default(): class MyDictHolder: - data: Dict = DictProperty() + data: dict = DictProperty() obj = MyDictHolder() obj.data["test"] = 5 @@ -123,7 +122,7 @@ class MyDictHolder: def test_dict_property_update(): class MyDictHolder: - data: Dict = DictProperty() + data: dict = DictProperty() obj = MyDictHolder() obj.data["test"] = 5 diff --git a/tests/unit/gui/test_property_list.py b/tests/unit/gui/test_property_list.py index 9285bbfad5..79d4fc1d84 100644 --- a/tests/unit/gui/test_property_list.py +++ b/tests/unit/gui/test_property_list.py @@ -1,5 +1,4 @@ import gc -from typing import List from arcade.gui.property import ListProperty, _ObservableList, bind @@ -7,7 +6,7 @@ class MyListHolder: - data: List = ListProperty() + data: list = ListProperty() def test_list_property_gc(): diff --git a/tests/unit/rect/test_rect_instances.py b/tests/unit/rect/test_rect_instances.py index 53413c87b1..7a55a5f9cb 100644 --- a/tests/unit/rect/test_rect_instances.py +++ b/tests/unit/rect/test_rect_instances.py @@ -1,4 +1,5 @@ -from typing import Any, Callable +from collections.abc import Callable +from typing import Any from pyglet.math import Vec2 @@ -95,7 +96,7 @@ def test_views(): class SubclassedRect(Rect): ... -ALL_ZEROES = tuple((0 for _ in Rect._fields)) +ALL_ZEROES = tuple(0 for _ in Rect._fields) def _formats_correctly(func: Callable[[Any], str], starts_with_format: str, instance: Any) -> bool: diff --git a/tests/unit/spritelist/test_spritelist.py b/tests/unit/spritelist/test_spritelist.py index 6558e2424b..c5df0004bc 100644 --- a/tests/unit/spritelist/test_spritelist.py +++ b/tests/unit/spritelist/test_spritelist.py @@ -69,16 +69,14 @@ def test_it_can_extend_a_spritelist_from_a_list(): def test_it_can_extend_a_spritelist_from_a_generator_expression(): sprite_list = arcade.SpriteList() sprite_list.extend( - ( - arcade.SpriteSolidColor( - width=32, - height=32, - center_x=coord, - center_y=coord, - color=arcade.color.RED, - ) - for coord in range(5) + arcade.SpriteSolidColor( + width=32, + height=32, + center_x=coord, + center_y=coord, + color=arcade.color.RED, ) + for coord in range(5) ) for coord, sprite in enumerate(sprite_list): assert sprite.position == (coord, coord) diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index bb970811e8..006b4a06b0 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -5,7 +5,8 @@ python -m pytest tests/unit/test_utils.py """ -from typing import Any, Callable +from collections.abc import Callable +from typing import Any from arcade import utils diff --git a/tests/unit/text/test_text.py b/tests/unit/text/test_text.py index 94c586bb6e..57001908ad 100644 --- a/tests/unit/text/test_text.py +++ b/tests/unit/text/test_text.py @@ -1,5 +1,3 @@ -from typing import List - import pytest import arcade @@ -137,7 +135,7 @@ def test_text_instances(window): window.clear() current_x = 20 - text_list: List[arcade.Text] = [] + text_list: list[arcade.Text] = [] def new_text(*args, **kwargs) -> None: """