From 1bcc9c130d604e68eb8052c74d4c765243f916f5 Mon Sep 17 00:00:00 2001 From: cspotcode Date: Thu, 4 May 2023 17:53:50 -0400 Subject: [PATCH 01/17] Fix pyright errors --- arcade/cache/texture.py | 1 + arcade/camera.py | 4 ++-- arcade/context.py | 2 +- arcade/gl/buffer.py | 3 ++- arcade/gl/compute_shader.py | 6 ++++-- arcade/gl/context.py | 12 ++++++++---- arcade/gl/geometry.py | 6 +++--- arcade/gl/program.py | 10 ++++++---- arcade/gl/vertex_array.py | 2 +- arcade/gui/widgets/layout.py | 8 ++++---- arcade/gui/widgets/slider.py | 2 +- arcade/shape_list.py | 2 +- arcade/sprite_list/collision.py | 4 ++-- arcade/text.py | 4 ++-- arcade/tilemap/tilemap.py | 27 +++++++++++++++------------ arcade/types.py | 9 ++++++++- pyproject.toml | 12 ++++++++++++ 17 files changed, 73 insertions(+), 41 deletions(-) diff --git a/arcade/cache/texture.py b/arcade/cache/texture.py index 3df7e83a26..c188e9d601 100644 --- a/arcade/cache/texture.py +++ b/arcade/cache/texture.py @@ -89,6 +89,7 @@ def put( # TODO: Consider using Texture.origin instead of file_path # Consider also caching origin that is not a file name name = texture.cache_name + file_path = str(file_path) if strong: self._strong_entries.put(name, texture) if self._strong_file_entries.get(file_path): diff --git a/arcade/camera.py b/arcade/camera.py index e8a2f283eb..529c4c0bbf 100644 --- a/arcade/camera.py +++ b/arcade/camera.py @@ -384,7 +384,7 @@ def scale(self) -> Tuple[float, float]: return self._scale @scale.setter - def scale(self, new_scale: Tuple[int, int]) -> None: + def scale(self, new_scale: Tuple[int | float, int | float]) -> None: """ Sets the x, y scale (zoom property just sets scale to the same value). This also updates the projection matrix with an orthogonal @@ -393,7 +393,7 @@ def scale(self, new_scale: Tuple[int, int]) -> None: if new_scale[0] <= 0 or new_scale[1] <= 0: raise ValueError("Scale must be greater than zero") - self._scale = new_scale + self._scale = (float(new_scale[0]), float(new_scale[1])) # Changing the scale (zoom) affects both projection_matrix and view_matrix self._set_projection_matrix( diff --git a/arcade/context.py b/arcade/context.py index c7489b3605..9bb3d7fbcb 100644 --- a/arcade/context.py +++ b/arcade/context.py @@ -313,7 +313,7 @@ def view_matrix_2d(self) -> Mat4: :type: pyglet.math.Mat4 """ - self.window.view + return self.window.view @view_matrix_2d.setter def view_matrix_2d(self, value: Mat4): diff --git a/arcade/gl/buffer.py b/arcade/gl/buffer.py index 8918bd97d6..9034814482 100644 --- a/arcade/gl/buffer.py +++ b/arcade/gl/buffer.py @@ -66,7 +66,8 @@ def __init__( elif reserve > 0: self._size = reserve # populate the buffer with zero byte values - data = (gl.GLubyte * self._size)(0) + gl.GLubyte.__mul__ + data = (gl.GLubyte * self._size)() gl.glBufferData(gl.GL_ARRAY_BUFFER, self._size, data, self._usage) else: raise ValueError("Buffer takes byte data or number of reserved bytes") diff --git a/arcade/gl/compute_shader.py b/arcade/gl/compute_shader.py index 6d1650a03a..c2b933f9d8 100644 --- a/arcade/gl/compute_shader.py +++ b/arcade/gl/compute_shader.py @@ -17,7 +17,7 @@ class ComputeShader: def __init__(self, ctx: "Context", glsl_source: str) -> None: self._ctx = ctx self._source = glsl_source - self._uniforms: Dict[str, Uniform] = dict() + self._uniforms: Dict[str, UniformBlock | Uniform] = dict() from arcade.gl import ShaderException @@ -129,6 +129,7 @@ def __getitem__(self, item) -> Union[Uniform, UniformBlock]: except KeyError: raise KeyError(f"Uniform with the name `{item}` was not found.") + assert uniform.getter return uniform.getter() def __setitem__(self, key, value): @@ -142,6 +143,7 @@ def __setitem__(self, key, value): except KeyError: raise KeyError(f"Uniform with the name `{key}` was not found.") + assert uniform.setter uniform.setter(value) def __hash__(self) -> int: @@ -216,7 +218,7 @@ def _query_uniform(self, location: int) -> Tuple[str, int, int]: of Matrices. """ u_size = gl.GLint() - u_type = gl.GLenum() + u_type = gl.GLenumActual() buf_size = 192 # max uniform character length u_name = create_string_buffer(buf_size) gl.glGetActiveUniform( diff --git a/arcade/gl/context.py b/arcade/gl/context.py index c804ad2ae3..516717f1d0 100644 --- a/arcade/gl/context.py +++ b/arcade/gl/context.py @@ -1,4 +1,5 @@ import logging +import typing import weakref from collections import deque from contextlib import contextmanager @@ -7,6 +8,7 @@ Union) import pyglet +import pyglet.gl.lib from pyglet import gl from pyglet.window import Window @@ -1266,7 +1268,7 @@ def get_int_tuple(self, enum: gl.GLenum, length: int): values = (c_int * length)() gl.glGetIntegerv(enum, values) return tuple(values) - except gl.lib.GLException: + except pyglet.gl.lib.GLException: return tuple([0] * length) def get(self, enum: gl.GLenum, default=0) -> int: @@ -1275,7 +1277,7 @@ def get(self, enum: gl.GLenum, default=0) -> int: value = c_int() gl.glGetIntegerv(enum, value) return value.value - except gl.lib.GLException: + except pyglet.gl.lib.GLException: return default def get_float(self, enum: gl.GLenum, default=0.0) -> float: @@ -1284,12 +1286,14 @@ def get_float(self, enum: gl.GLenum, default=0.0) -> float: value = c_float() gl.glGetFloatv(enum, value) return value.value - except gl.lib.GLException: + except pyglet.gl.lib.GLException: return default def get_str(self, enum: gl.GLenum) -> str: """Get a string limit""" try: return cast(gl.glGetString(enum), c_char_p).value.decode() # type: ignore - except gl.lib.GLException: + except pyglet.gl.lib.GLException: return "Unknown" + +__typecheck_1__: pyglet.gl.base.Context = typing.cast(Context, 'dummy') \ No newline at end of file diff --git a/arcade/gl/geometry.py b/arcade/gl/geometry.py index 8b45e3b17f..4356c51936 100644 --- a/arcade/gl/geometry.py +++ b/arcade/gl/geometry.py @@ -231,9 +231,9 @@ def sphere( R = 1.0 / (rings - 1) S = 1.0 / (sectors - 1) - vertices = [0] * (rings * sectors * 3) - normals = [0] * (rings * sectors * 3) - uvs = [0] * (rings * sectors * 2) + vertices = [0.0] * (rings * sectors * 3) + normals = [0.0] * (rings * sectors * 3) + uvs = [0.0] * (rings * sectors * 2) v, n, t = 0, 0, 0 for r in range(rings): diff --git a/arcade/gl/program.py b/arcade/gl/program.py index ecf6ada874..093544cf2f 100644 --- a/arcade/gl/program.py +++ b/arcade/gl/program.py @@ -85,7 +85,7 @@ def __init__( self._attributes = [] # type: List[AttribFormat] #: Internal cache key used with vertex arrays self.attribute_key = "INVALID" # type: str - self._uniforms: Dict[str, Uniform] = {} + self._uniforms: Dict[str, Uniform | UniformBlock] = {} if self._varyings_capture_mode not in self._valid_capture_modes: raise ValueError( @@ -93,7 +93,7 @@ def __init__( f"Valid modes are: {self._valid_capture_modes}." ) - shaders = [(vertex_shader, gl.GL_VERTEX_SHADER)] + shaders: list[tuple[str, int]] = [(vertex_shader, gl.GL_VERTEX_SHADER)] if fragment_shader: shaders.append((fragment_shader, gl.GL_FRAGMENT_SHADER)) if geometry_shader: @@ -276,6 +276,7 @@ def __getitem__(self, item) -> Union[Uniform, UniformBlock]: except KeyError: raise KeyError(f"Uniform with the name `{item}` was not found.") + assert uniform.getter return uniform.getter() def __setitem__(self, key, value): @@ -290,6 +291,7 @@ def __setitem__(self, key, value): except KeyError: raise KeyError(f"Uniform with the name `{key}` was not found.") + assert uniform.setter uniform.setter(value) def set_uniform_safe(self, name: str, value: Any): @@ -373,7 +375,7 @@ def _introspect_attributes(self): for i in range(num_attrs.value): c_name = create_string_buffer(256) c_size = gl.GLint() - c_type = gl.GLenum() + c_type = gl.GLenumActual() gl.glGetActiveAttrib( self._glo, # program to query i, # index (not the same as location) @@ -449,7 +451,7 @@ def _query_uniform(self, location: int) -> Tuple[str, int, int]: of Matrices. """ u_size = gl.GLint() - u_type = gl.GLenum() + u_type = gl.GLenumActual() buf_size = 192 # max uniform character length u_name = create_string_buffer(buf_size) gl.glGetActiveUniform( diff --git a/arcade/gl/vertex_array.py b/arcade/gl/vertex_array.py index d4b45bac2c..d0493a53cd 100644 --- a/arcade/gl/vertex_array.py +++ b/arcade/gl/vertex_array.py @@ -537,7 +537,7 @@ def render( self, program: Program, *, - mode: Optional[gl.GLenum] = None, + mode: Optional[gl.GLenum | int] = None, first: int = 0, vertices: Optional[int] = None, instances: int = 1, diff --git a/arcade/gui/widgets/layout.py b/arcade/gui/widgets/layout.py index c97a9f0fcc..3de5d15819 100644 --- a/arcade/gui/widgets/layout.py +++ b/arcade/gui/widgets/layout.py @@ -553,10 +553,10 @@ def _update_size_hints(self): [None for _ in range(self.column_count)] for _ in range(self.row_count) ] - max_width_per_column = [ + max_width_per_column: list[list[tuple[int, int]]] = [ [(0, 1) for _ in range(self.row_count)] for _ in range(self.column_count) ] - max_height_per_row = [ + max_height_per_row: list[list[tuple[int, int]]] = [ [(0, 1) for _ in range(self.column_count)] for _ in range(self.row_count) ] @@ -662,10 +662,10 @@ def do_layout(self): [None for _ in range(self.column_count)] for _ in range(self.row_count) ] - max_width_per_column = [ + max_width_per_column: list[list[tuple[int | float, int]]] = [ [(0, 1) for _ in range(self.row_count)] for _ in range(self.column_count) ] - max_height_per_row = [ + max_height_per_row: list[list[tuple[int | float, int]]] = [ [(0, 1) for _ in range(self.column_count)] for _ in range(self.row_count) ] diff --git a/arcade/gui/widgets/slider.py b/arcade/gui/widgets/slider.py index 3e9249c421..31d4c4724e 100644 --- a/arcade/gui/widgets/slider.py +++ b/arcade/gui/widgets/slider.py @@ -226,7 +226,7 @@ def do_render(self, surface: Surface): ) def _cursor_pos(self) -> Tuple[int, int]: - return self.value_x, self.y + self.height // 2 + return self.value_x, int(self.y + self.height // 2) def _is_on_cursor(self, x: float, y: float) -> bool: cursor_center_x, cursor_center_y = self._cursor_pos() diff --git a/arcade/shape_list.py b/arcade/shape_list.py index bb60b3d54b..8d0fcc1f45 100644 --- a/arcade/shape_list.py +++ b/arcade/shape_list.py @@ -118,7 +118,7 @@ def draw(self): if self.geometry is None: self._init_geometry() - self.geometry.render(self.program, mode=self.mode) + self.geometry.render(self.program, mode=self.mode) # pyright: ignore [reportOptionalMemberAccess] def create_line( diff --git a/arcade/sprite_list/collision.py b/arcade/sprite_list/collision.py index 413558d64a..7edd6c0d15 100644 --- a/arcade/sprite_list/collision.py +++ b/arcade/sprite_list/collision.py @@ -299,7 +299,7 @@ def get_sprites_at_point(point: Point, sprite_list: SpriteList[SpriteType]) -> L ] -def get_sprites_at_exact_point(point: Point, sprite_list: SpriteList) -> List[SpriteType]: +def get_sprites_at_exact_point(point: Point, sprite_list: SpriteList[SpriteType]) -> List[SpriteType]: """ Get a list of sprites whose center_x, center_y match the given point. This does NOT return sprites that overlap the point, the center has to be an exact match. @@ -328,7 +328,7 @@ def get_sprites_at_exact_point(point: Point, sprite_list: SpriteList) -> List[Sp return [s for s in sprites_to_check if s.position == point] -def get_sprites_in_rect(rect: Rect, sprite_list: SpriteList) -> List[SpriteType]: +def get_sprites_in_rect(rect: Rect, sprite_list: SpriteList[SpriteType]) -> List[SpriteType]: """ Get a list of sprites in a particular rectangle. This function sees if any sprite overlaps the specified rectangle. If a sprite has a different center_x/center_y but touches the rectangle, diff --git a/arcade/text.py b/arcade/text.py index 1f55244017..eb61d66e2e 100644 --- a/arcade/text.py +++ b/arcade/text.py @@ -7,7 +7,7 @@ import pyglet import arcade -from arcade.types import Color, Point, RGBA255 +from arcade.types import Color, Point, RGBA255, Point3 from arcade.resources import resolve from arcade.utils import PerformanceWarning, warning @@ -569,7 +569,7 @@ def position(self) -> Point: return self._label.x, self._label.y @position.setter - def position(self, point: Point): + def position(self, point: Point | Point3): # Starting with Pyglet 2.0b2 label positions take a z parameter. if len(point) == 3: self._label.position = point diff --git a/arcade/tilemap/tilemap.py b/arcade/tilemap/tilemap.py index 9d86e2708b..65b4c1b76c 100644 --- a/arcade/tilemap/tilemap.py +++ b/arcade/tilemap/tilemap.py @@ -12,7 +12,7 @@ import os from collections import OrderedDict from pathlib import Path -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union, cast +from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Union, cast import pytiled_parser import pytiled_parser.tiled_object @@ -34,7 +34,7 @@ from arcade.math import rotate_point from arcade.resources import resolve -from arcade.types import Point, TiledObject +from arcade.types import MutablePoint, Point, TiledObject _FLIPPED_HORIZONTALLY_FLAG = 0x80000000 _FLIPPED_VERTICALLY_FLAG = 0x40000000 @@ -46,6 +46,7 @@ "read_tmx" ] +prop_to_float = cast(Callable[[pytiled_parser.Property], float], float) def _get_image_info_from_tileset(tile: pytiled_parser.Tile): image_x = 0 @@ -442,6 +443,8 @@ def _create_sprite_from_tile( # Can image_file be None? image_x, image_y, width, height = _get_image_info_from_tileset(tile) + assert width + assert height texture = _load_tilemap_texture( image_file, # type: ignore x=image_x, @@ -556,18 +559,18 @@ def _create_sprite_from_tile( if tile.flipped_vertically: for point in points: - point[1] *= -1 + point = point[0], point[1] * -1 if tile.flipped_horizontally: for point in points: - point[0] *= -1 + point = point[0] * -1, point[1] if tile.flipped_diagonally: for point in points: - point[0], point[1] = point[1], point[0] + point = point[1], point[0] my_sprite.hit_box = RotatableHitBox( - points, + cast(list[Point], points), position=my_sprite.position, angle=my_sprite.angle, scale=my_sprite.scale_xy, @@ -859,28 +862,28 @@ def _process_object_layer( my_sprite.alpha = int(opacity * 255) if cur_object.properties and "change_x" in cur_object.properties: - my_sprite.change_x = float(cur_object.properties["change_x"]) + my_sprite.change_x = prop_to_float(cur_object.properties["change_x"]) if cur_object.properties and "change_y" in cur_object.properties: - my_sprite.change_y = float(cur_object.properties["change_y"]) + my_sprite.change_y = prop_to_float(cur_object.properties["change_y"]) if cur_object.properties and "boundary_bottom" in cur_object.properties: - my_sprite.boundary_bottom = float( + my_sprite.boundary_bottom = prop_to_float( cur_object.properties["boundary_bottom"] ) if cur_object.properties and "boundary_top" in cur_object.properties: - my_sprite.boundary_top = float( + my_sprite.boundary_top = prop_to_float( cur_object.properties["boundary_top"] ) if cur_object.properties and "boundary_left" in cur_object.properties: - my_sprite.boundary_left = float( + my_sprite.boundary_left = prop_to_float( cur_object.properties["boundary_left"] ) if cur_object.properties and "boundary_right" in cur_object.properties: - my_sprite.boundary_right = float( + my_sprite.boundary_right = prop_to_float( cur_object.properties["boundary_right"] ) diff --git a/arcade/types.py b/arcade/types.py index 024250a42b..da49b24c30 100644 --- a/arcade/types.py +++ b/arcade/types.py @@ -2,6 +2,7 @@ Module specifying data custom types used for type hinting. """ from array import array +import ctypes import random from collections import namedtuple from collections.abc import ByteString @@ -9,8 +10,10 @@ from typing import ( Iterable, List, + Literal, NamedTuple, Optional, + Protocol, Sequence, Tuple, Union, @@ -415,6 +418,10 @@ def random( # Point = Union[Tuple[float, float], List[float]] # Vector = Point Point = Tuple[float, float] +Point3 = Tuple[float, float, float] +class MutablePoint(Protocol): + def __getitem__(self, key: Literal[0] | Literal[1]) -> float: ... + def __setitem__(self, key: Literal[0] | Literal[1], value: float) -> None: ... IPoint = Tuple[int, int] Vector = Point NamedPoint = namedtuple("NamedPoint", ["x", "y"]) @@ -440,4 +447,4 @@ class TiledObject(NamedTuple): # the PEP and Python doc for more information: # https://peps.python.org/pep-0688/ # https://docs.python.org/3/c-api/buffer.html -BufferProtocol = Union[ByteString, memoryview, array] +BufferProtocol = Union[ByteString, memoryview, array, ctypes.Array] diff --git a/pyproject.toml b/pyproject.toml index 991a94720e..52f5f96892 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -108,6 +108,18 @@ exclude = ["venv", "arcade/examples", "arcade/experimental", "tests", "doc"] useLibraryCodeForTypes = true reportMissingTypeStubs = "none" +typeCheckingMode = "basic" +# Use type info from pytiled_parser and pyglet, which do not ship `py.typed` file +useLibraryCodeForTypes = true +reportMissingTypeStubs = "none" +# Ignore diagnostics where something might be `None`; too many of them +reportOptionalCall = none", +reportOptionalContextManager = "none" +reportOptionalIterable = "none" +reportOptionalMemberAccess = "none" +reportOptionalOperand = "none" +reportOptionalSubscript = "none" + [tool.coverage.run] source = ["arcade"] omit = ["./arcade/examples/*", "./arcade/gui/examples/*", "./arcade/experimental/*", "./env/*", "./tests/*", "./doc/*", "./Win*/*"] From c98f9263de332251623e735d55b1fd19e95e9d5f Mon Sep 17 00:00:00 2001 From: cspotcode Date: Fri, 5 May 2023 11:36:06 -0400 Subject: [PATCH 02/17] Fix last few diagnostics --- doc/conf.py | 2 +- pyproject.toml | 15 +++++++++------ tests/conftest.py | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 6a820e888a..39b6512dba 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -33,7 +33,7 @@ # Don't change to # from arcade.version import VERSION # or read the docs build will fail. -from version import VERSION +from version import VERSION # pyright: ignore [reportMissingImports] RELEASE = VERSION diff --git a/pyproject.toml b/pyproject.toml index 52f5f96892..018f2cafe0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -103,16 +103,19 @@ norecursedirs = ["doc", "holding", "arcade/examples", "build", ".venv", "env", " [tool.pyright] include = ["arcade"] -exclude = ["venv", "arcade/examples", "arcade/experimental", "tests", "doc"] -# Use type info from pytiled_parser and pyglet, which do not ship `py.typed` file -useLibraryCodeForTypes = true -reportMissingTypeStubs = "none" - +exclude = [ + "venv", + "arcade/__pyinstaller", + "arcade/examples", + "arcade/experimental", + "tests", + "doc" +] typeCheckingMode = "basic" # Use type info from pytiled_parser and pyglet, which do not ship `py.typed` file useLibraryCodeForTypes = true reportMissingTypeStubs = "none" -# Ignore diagnostics where something might be `None`; too many of them +# Ignore diagnostics about values that might be `None` reportOptionalCall = none", reportOptionalContextManager = "none" reportOptionalIterable = "none" diff --git a/tests/conftest.py b/tests/conftest.py index 595264ea08..c65d1668d6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,7 +2,7 @@ from pathlib import Path if os.environ.get("ARCADE_PYTEST_USE_RUST"): - import arcade_accelerate + import arcade_accelerate # pyright: ignore [reportMissingImports] arcade_accelerate.bootstrap() import pytest From 66aad0b18e7eb937512692716937c5c1d07a9bf4 Mon Sep 17 00:00:00 2001 From: cspotcode Date: Fri, 5 May 2023 13:19:26 -0400 Subject: [PATCH 03/17] amending pyright config in pyproject.toml --- pyproject.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 018f2cafe0..d199c4a97b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -109,14 +109,15 @@ exclude = [ "arcade/examples", "arcade/experimental", "tests", - "doc" + "doc", + "make.py" ] typeCheckingMode = "basic" # Use type info from pytiled_parser and pyglet, which do not ship `py.typed` file useLibraryCodeForTypes = true reportMissingTypeStubs = "none" # Ignore diagnostics about values that might be `None` -reportOptionalCall = none", +reportOptionalCall = "none" reportOptionalContextManager = "none" reportOptionalIterable = "none" reportOptionalMemberAccess = "none" From e6d960447d18f30a5f17b2d95f7cd5fa0c0decc5 Mon Sep 17 00:00:00 2001 From: cspotcode Date: Fri, 5 May 2023 13:33:33 -0400 Subject: [PATCH 04/17] fix more type diagnostics --- arcade/gl/buffer.py | 1 - arcade/gl/compute_shader.py | 4 +--- arcade/gl/context.py | 23 +++++++++++++---------- arcade/gl/glsl.py | 4 ++-- arcade/gl/program.py | 12 +++++------- arcade/gl/texture.py | 6 +++--- arcade/gl/types.py | 12 ++++++++---- arcade/gl/uniform.py | 3 +-- arcade/gl/vertex_array.py | 26 +++++++++++++------------- arcade/gui/widgets/text.py | 6 +++--- arcade/hitbox/base.py | 4 ++-- arcade/text.py | 4 ++-- arcade/texture/tools.py | 6 +++--- arcade/texture/transforms.py | 2 +- arcade/texture_atlas/base.py | 3 ++- arcade/tilemap/tilemap.py | 1 + arcade/types.py | 1 + make.py | 8 ++++---- 18 files changed, 65 insertions(+), 61 deletions(-) diff --git a/arcade/gl/buffer.py b/arcade/gl/buffer.py index 9034814482..2980d686e5 100644 --- a/arcade/gl/buffer.py +++ b/arcade/gl/buffer.py @@ -66,7 +66,6 @@ def __init__( elif reserve > 0: self._size = reserve # populate the buffer with zero byte values - gl.GLubyte.__mul__ data = (gl.GLubyte * self._size)() gl.glBufferData(gl.GL_ARRAY_BUFFER, self._size, data, self._usage) else: diff --git a/arcade/gl/compute_shader.py b/arcade/gl/compute_shader.py index c2b933f9d8..bd1712848b 100644 --- a/arcade/gl/compute_shader.py +++ b/arcade/gl/compute_shader.py @@ -129,7 +129,6 @@ def __getitem__(self, item) -> Union[Uniform, UniformBlock]: except KeyError: raise KeyError(f"Uniform with the name `{item}` was not found.") - assert uniform.getter return uniform.getter() def __setitem__(self, key, value): @@ -143,7 +142,6 @@ def __setitem__(self, key, value): except KeyError: raise KeyError(f"Uniform with the name `{key}` was not found.") - assert uniform.setter uniform.setter(value) def __hash__(self) -> int: @@ -218,7 +216,7 @@ def _query_uniform(self, location: int) -> Tuple[str, int, int]: of Matrices. """ u_size = gl.GLint() - u_type = gl.GLenumActual() + u_type = gl.GLenum() buf_size = 192 # max uniform character length u_name = create_string_buffer(buf_size) gl.glGetActiveUniform( diff --git a/arcade/gl/context.py b/arcade/gl/context.py index 516717f1d0..a27b90290c 100644 --- a/arcade/gl/context.py +++ b/arcade/gl/context.py @@ -4,7 +4,7 @@ from collections import deque from contextlib import contextmanager from ctypes import c_char_p, c_float, c_int, cast -from typing import (Any, Deque, Dict, Iterable, List, Optional, Sequence, Set, Tuple, +from typing import (TYPE_CHECKING, Any, Deque, Dict, Iterable, List, Optional, Sequence, Set, Tuple, Union) import pyglet @@ -19,7 +19,7 @@ from .program import Program from .query import Query from .texture import Texture2D -from .types import BufferDescription +from .types import BufferDescription, GLenumLike, PyGLenum from .vertex_array import Geometry from ..types import BufferProtocol @@ -821,9 +821,9 @@ def texture( components: int = 4, dtype: str = "f1", data: Optional[BufferProtocol] = None, - wrap_x: Optional[gl.GLenum] = None, - wrap_y: Optional[gl.GLenum] = None, - filter: Optional[Tuple[gl.GLenum, gl.GLenum]] = None, + wrap_x: Optional[PyGLenum] = None, + wrap_y: Optional[PyGLenum] = None, + filter: Optional[Tuple[GLenumLike, GLenumLike]] = None, samples: int = 0, immutable: bool = False, ) -> Texture2D: @@ -1262,7 +1262,7 @@ def __init__(self, ctx): warn("Error happened while querying of limits. Moving on ..") - def get_int_tuple(self, enum: gl.GLenum, length: int): + def get_int_tuple(self, enum: GLenumLike, length: int): """Get an enum as an int tuple""" try: values = (c_int * length)() @@ -1271,7 +1271,7 @@ def get_int_tuple(self, enum: gl.GLenum, length: int): except pyglet.gl.lib.GLException: return tuple([0] * length) - def get(self, enum: gl.GLenum, default=0) -> int: + def get(self, enum: GLenumLike, default=0) -> int: """Get an integer limit""" try: value = c_int() @@ -1280,7 +1280,7 @@ def get(self, enum: gl.GLenum, default=0) -> int: except pyglet.gl.lib.GLException: return default - def get_float(self, enum: gl.GLenum, default=0.0) -> float: + def get_float(self, enum: GLenumLike, default=0.0) -> float: """Get a float limit""" try: value = c_float() @@ -1289,11 +1289,14 @@ def get_float(self, enum: gl.GLenum, default=0.0) -> float: except pyglet.gl.lib.GLException: return default - def get_str(self, enum: gl.GLenum) -> str: + def get_str(self, enum: GLenumLike) -> str: """Get a string limit""" try: return cast(gl.glGetString(enum), c_char_p).value.decode() # type: ignore except pyglet.gl.lib.GLException: return "Unknown" -__typecheck_1__: pyglet.gl.base.Context = typing.cast(Context, 'dummy') \ No newline at end of file +if TYPE_CHECKING: + # Arcade's Context is passed into code paths that require a pyglet Context + # So we must prove they are compatible. + __typecheck__: pyglet.gl.base.Context = typing.cast(Context, '__typecheck__') diff --git a/arcade/gl/glsl.py b/arcade/gl/glsl.py index 05569e9ca9..81f2546e93 100644 --- a/arcade/gl/glsl.py +++ b/arcade/gl/glsl.py @@ -4,7 +4,7 @@ from pyglet import gl from .exceptions import ShaderException -from .types import SHADER_TYPE_NAMES +from .types import SHADER_TYPE_NAMES, PyGLenum class ShaderSource: @@ -31,7 +31,7 @@ def __init__( ctx: gl.Context, source: str, common: Optional[Iterable[str]], - source_type: gl.GLenum, + source_type: PyGLenum, ): """Create a shader source wrapper.""" self._source = source.strip() diff --git a/arcade/gl/program.py b/arcade/gl/program.py index 093544cf2f..ba3c8cc2bc 100644 --- a/arcade/gl/program.py +++ b/arcade/gl/program.py @@ -15,7 +15,7 @@ from pyglet import gl from .uniform import Uniform, UniformBlock -from .types import AttribFormat, GLTypes, SHADER_TYPE_NAMES +from .types import AttribFormat, GLTypes, SHADER_TYPE_NAMES, PyGLenum from .exceptions import ShaderException if TYPE_CHECKING: # handle import cycle caused by type hinting @@ -85,7 +85,7 @@ def __init__( self._attributes = [] # type: List[AttribFormat] #: Internal cache key used with vertex arrays self.attribute_key = "INVALID" # type: str - self._uniforms: Dict[str, Uniform | UniformBlock] = {} + self._uniforms: Dict[str, Uniform] = {} if self._varyings_capture_mode not in self._valid_capture_modes: raise ValueError( @@ -276,7 +276,6 @@ def __getitem__(self, item) -> Union[Uniform, UniformBlock]: except KeyError: raise KeyError(f"Uniform with the name `{item}` was not found.") - assert uniform.getter return uniform.getter() def __setitem__(self, key, value): @@ -291,7 +290,6 @@ def __setitem__(self, key, value): except KeyError: raise KeyError(f"Uniform with the name `{key}` was not found.") - assert uniform.setter uniform.setter(value) def set_uniform_safe(self, name: str, value: Any): @@ -375,7 +373,7 @@ def _introspect_attributes(self): for i in range(num_attrs.value): c_name = create_string_buffer(256) c_size = gl.GLint() - c_type = gl.GLenumActual() + c_type = gl.GLenum() gl.glGetActiveAttrib( self._glo, # program to query i, # index (not the same as location) @@ -451,7 +449,7 @@ def _query_uniform(self, location: int) -> Tuple[str, int, int]: of Matrices. """ u_size = gl.GLint() - u_type = gl.GLenumActual() + u_type = gl.GLenum() buf_size = 192 # max uniform character length u_name = create_string_buffer(buf_size) gl.glGetActiveUniform( @@ -488,7 +486,7 @@ def _query_uniform_block(self, location: int) -> Tuple[int, int, str]: return index, b_size.value, u_name.value.decode() @staticmethod - def compile_shader(source: str, shader_type: gl.GLenum) -> gl.GLuint: + def compile_shader(source: str, shader_type: PyGLenum) -> gl.GLuint: """Compile the shader code of the given type. `shader_type` could be GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, ... diff --git a/arcade/gl/texture.py b/arcade/gl/texture.py index 44474d8e48..685e8ca817 100644 --- a/arcade/gl/texture.py +++ b/arcade/gl/texture.py @@ -6,7 +6,7 @@ from .buffer import Buffer from .utils import data_to_ctypes -from .types import pixel_formats, BufferOrBufferProtocol +from .types import PyGLuint, pixel_formats, BufferOrBufferProtocol from ..types import BufferProtocol if TYPE_CHECKING: # handle import cycle caused by type hinting @@ -115,8 +115,8 @@ def __init__( dtype: str = "f1", data: Optional[BufferProtocol] = None, filter: Optional[Tuple[gl.GLuint, gl.GLuint]] = None, - wrap_x: Optional[gl.GLuint] = None, - wrap_y: Optional[gl.GLuint] = None, + wrap_x: Optional[PyGLuint] = None, + wrap_y: Optional[PyGLuint] = None, target=gl.GL_TEXTURE_2D, depth=False, samples: int = 0, diff --git a/arcade/gl/types.py b/arcade/gl/types.py index 76bf0ce693..cf6fd3853c 100644 --- a/arcade/gl/types.py +++ b/arcade/gl/types.py @@ -9,6 +9,10 @@ BufferOrBufferProtocol = Union[BufferProtocol, Buffer] +GLenumLike = gl.GLenum | int +PyGLenum = int +GLuintLike = gl.GLuint | int +PyGLuint = int _float_base_format = (0, gl.GL_RED, gl.GL_RG, gl.GL_RGB, gl.GL_RGBA) _int_base_format = ( @@ -102,7 +106,7 @@ } -def gl_name(gl_type: gl.GLenum) -> str: +def gl_name(gl_type: PyGLenum) -> str | PyGLenum: """Return the name of a gl type""" return GL_NAMES.get(gl_type, gl_type) @@ -112,7 +116,7 @@ class AttribFormat: Represents an attribute in a BufferDescription or a Program. :param str name: Name of the attribute - :param gl.GLEnum gl_type: The OpenGL type such as GL_FLOAT, GL_HALF_FLOAT etc. + :param GLenumLike gl_type: The OpenGL type such as GL_FLOAT, GL_HALF_FLOAT etc. :param int bytes_per_component: Number of bytes a single component takes :param int offset: (Optional offset for BufferDescription) :param int location: (Optional location for program attribute) @@ -128,7 +132,7 @@ class AttribFormat: ) def __init__( - self, name: str, gl_type: gl.GLenum, components: int, bytes_per_component: int, offset=0, location=0 + self, name: str, gl_type: PyGLenum, components: int, bytes_per_component: int, offset=0, location=0 ): self.name: str = name self.gl_type = gl_type @@ -344,7 +348,7 @@ class TypeInfo: """ __slots__ = "name", "enum", "gl_type", "gl_size", "components" - def __init__(self, name: str, enum: gl.GLenum, gl_type: gl.GLenum, gl_size: int, components: int): + def __init__(self, name: str, enum: GLenumLike, gl_type: PyGLenum, gl_size: int, components: int): self.name = name self.enum = enum self.gl_type = gl_type diff --git a/arcade/gl/uniform.py b/arcade/gl/uniform.py index 5a3c3a9fec..d23aa5200b 100644 --- a/arcade/gl/uniform.py +++ b/arcade/gl/uniform.py @@ -1,4 +1,5 @@ from ctypes import cast, POINTER +from typing import Callable from pyglet import gl from .exceptions import ShaderException @@ -114,8 +115,6 @@ def __init__(self, ctx, program_id, location, name, data_type, array_length): self._components = 0 #: The getter function configured for this uniform #: The setter function configured for this uniform - self.getter = None - self.setter = None self._setup_getters_and_setters() @property diff --git a/arcade/gl/vertex_array.py b/arcade/gl/vertex_array.py index d0493a53cd..e630ffb7c2 100644 --- a/arcade/gl/vertex_array.py +++ b/arcade/gl/vertex_array.py @@ -5,7 +5,7 @@ from pyglet import gl from .buffer import Buffer -from .types import BufferDescription, gl_name +from .types import BufferDescription, GLenumLike, GLuintLike, gl_name from .program import Program if TYPE_CHECKING: # handle import cycle caused by type hinting @@ -239,7 +239,7 @@ def _build( gl.glVertexAttribDivisor(prog_attr.location, 1) def render( - self, mode: gl.GLenum, first: int = 0, vertices: int = 0, instances: int = 1 + self, mode: GLenumLike, first: int = 0, vertices: int = 0, instances: int = 1 ): """Render the VertexArray to the currently active framebuffer. @@ -259,7 +259,7 @@ def render( else: gl.glDrawArraysInstanced(mode, first, vertices, instances) - def render_indirect(self, buffer: Buffer, mode: gl.GLuint, count, first, stride): + def render_indirect(self, buffer: Buffer, mode: GLuintLike, count, first, stride): """ Render the VertexArray to the framebuffer using indirect rendering. @@ -300,8 +300,8 @@ def render_indirect(self, buffer: Buffer, mode: gl.GLuint, count, first, stride) def transform_interleaved( self, buffer: Buffer, - mode: gl.GLenum, - output_mode: gl.GLenum, + mode: GLenumLike, + output_mode: GLenumLike, first: int = 0, vertices: int = 0, instances: int = 1, @@ -310,8 +310,8 @@ def transform_interleaved( """Run a transform feedback. :param Buffer buffer: The buffer to write the output - :param gl.GLenum mode: The input primitive mode - :param gl.GLenum output_mode: The output primitive mode + :param GLenumLike mode: The input primitive mode + :param GLenumLike output_mode: The output primitive mode :param int first: Offset start vertex :param int vertices: Number of vertices to render :param int instances: Number of instances to render @@ -355,8 +355,8 @@ def transform_interleaved( def transform_separate( self, buffers: List[Buffer], - mode: gl.GLenum, - output_mode: gl.GLenum, + mode: GLenumLike, + output_mode: GLenumLike, first: int = 0, vertices: int = 0, instances: int = 1, @@ -366,8 +366,8 @@ def transform_separate( Run a transform feedback writing to separate buffers. :param List[Buffer] buffers: The buffers to write the output - :param gl.GLenum mode: The input primitive mode - :param gl.GLenum output_mode: The output primitive mode + :param GLenumLike mode: The input primitive mode + :param GLenumLike output_mode: The output primitive mode :param int first: Offset start vertex :param int vertices: Number of vertices to render :param int instances: Number of instances to render @@ -537,7 +537,7 @@ def render( self, program: Program, *, - mode: Optional[gl.GLenum | int] = None, + mode: Optional[GLenumLike] = None, first: int = 0, vertices: Optional[int] = None, instances: int = 1, @@ -549,7 +549,7 @@ def render( or have resized the buffers after the geometry instance was created. :param Program program: The Program to render with - :param gl.GLenum mode: Override what primitive mode should be used + :param GLenumLike mode: Override what primitive mode should be used :param int first: Offset start vertex :param int vertices: Override the number of vertices to render :param int instances: Number of instances to render diff --git a/arcade/gui/widgets/text.py b/arcade/gui/widgets/text.py index 16daadb6d1..4d8b55f6ed 100644 --- a/arcade/gui/widgets/text.py +++ b/arcade/gui/widgets/text.py @@ -20,7 +20,7 @@ from arcade.gui.surface import Surface from arcade.gui.widgets import UIWidget, Rect from arcade.gui.widgets.layout import UIAnchorLayout -from arcade.types import RGBA255, Color +from arcade.types import RGBA255, Color, RGBOrA255 class UILabel(UIWidget): @@ -62,7 +62,7 @@ def __init__( text: str = "", font_name=("Arial",), font_size: float = 12, - text_color: RGBA255 = (255, 255, 255, 255), + text_color: RGBOrA255 = (255, 255, 255, 255), bold=False, italic=False, align="left", @@ -244,7 +244,7 @@ def __init__( text: str = "", font_name=("Arial",), font_size: float = 12, - text_color: RGBA255 = (0, 0, 0, 255), + text_color: RGBOrA255 = (0, 0, 0, 255), multiline=False, size_hint=None, size_hint_min=None, diff --git a/arcade/hitbox/base.py b/arcade/hitbox/base.py index 5453c83a55..f1ec10dbdf 100644 --- a/arcade/hitbox/base.py +++ b/arcade/hitbox/base.py @@ -111,9 +111,9 @@ def create_rotatable( self._points, position=self._position, scale=self._scale, angle=angle ) - def get_adjusted_points(self): + def get_adjusted_points(self) -> list[Point]: if not self._adjusted_cache_dirty: - return self._adjusted_points + return self._adjusted_points # pyright: ignore def _adjust_point(point) -> Point: x, y = point diff --git a/arcade/text.py b/arcade/text.py index eb61d66e2e..c8249f7c8c 100644 --- a/arcade/text.py +++ b/arcade/text.py @@ -7,7 +7,7 @@ import pyglet import arcade -from arcade.types import Color, Point, RGBA255, Point3 +from arcade.types import Color, Point, RGBA255, Point3, RGBOrA255 from arcade.resources import resolve from arcade.utils import PerformanceWarning, warning @@ -180,7 +180,7 @@ def __init__( text: str, start_x: float, start_y: float, - color: RGBA255 = arcade.color.WHITE, + color: RGBOrA255 = arcade.color.WHITE, font_size: float = 12, width: Optional[int] = 0, align: str = "left", diff --git a/arcade/texture/tools.py b/arcade/texture/tools.py index 4585a1e458..91882515f4 100644 --- a/arcade/texture/tools.py +++ b/arcade/texture/tools.py @@ -1,7 +1,7 @@ from PIL import Image, ImageDraw import arcade from .texture import ImageData, Texture -from arcade.types import Point +from arcade.types import IntPoint from arcade import cache _DEFAULT_TEXTURE = None @@ -17,7 +17,7 @@ def cleanup_texture_cache(): arcade.cache.image_data_cache.clear() -def get_default_texture(size: Point = _DEFAULT_IMAGE_SIZE) -> Texture: +def get_default_texture(size: IntPoint = _DEFAULT_IMAGE_SIZE) -> Texture: """ Creates and returns a default texture and caches it internally for future use. @@ -35,7 +35,7 @@ def get_default_texture(size: Point = _DEFAULT_IMAGE_SIZE) -> Texture: return _DEFAULT_TEXTURE -def get_default_image(size: Point = _DEFAULT_IMAGE_SIZE) -> ImageData: +def get_default_image(size: IntPoint = _DEFAULT_IMAGE_SIZE) -> ImageData: """ Generates and returns a default image and caches it internally for future use. diff --git a/arcade/texture/transforms.py b/arcade/texture/transforms.py index 8ebd82dae9..17dfb2d21d 100644 --- a/arcade/texture/transforms.py +++ b/arcade/texture/transforms.py @@ -217,7 +217,7 @@ def transform_hit_box_points( # but it's faster to just pre-calculate it. # Key is the vertex order # Value is the orientation (flip_left_right, flip_top_down, rotation) -ORIENTATIONS = { +ORIENTATIONS: dict[tuple[int, int, int, int], tuple[int, bool, bool]] = { (0, 1, 2, 3): (0, False, False), # Default (2, 0, 3, 1): (90, False, False), # Rotate 90 (3, 2, 1, 0): (180, False, False), # Rotate 180 diff --git a/arcade/texture_atlas/base.py b/arcade/texture_atlas/base.py index 85a0ab5f95..f5f7883b8a 100644 --- a/arcade/texture_atlas/base.py +++ b/arcade/texture_atlas/base.py @@ -31,6 +31,7 @@ from weakref import WeakSet import PIL +import PIL.Image from PIL import Image, ImageDraw from pyglet.image.atlas import ( Allocator, @@ -1003,7 +1004,7 @@ def to_image( for rg in self._image_regions.values(): p1 = rg.x, rg.y p2 = rg.x + rg.width - 1, rg.y + rg.height - 1 - draw.rectangle([p1, p2], outline=border_color, width=1) + draw.rectangle((p1, p2), outline=border_color, width=1) if flip: image = image.transpose(Image.Transpose.FLIP_TOP_BOTTOM) diff --git a/arcade/tilemap/tilemap.py b/arcade/tilemap/tilemap.py index 65b4c1b76c..49a86ca260 100644 --- a/arcade/tilemap/tilemap.py +++ b/arcade/tilemap/tilemap.py @@ -412,6 +412,7 @@ def _create_sprite_from_tile( # --- Step 1, Find a reference to an image this is going to be based off of map_source = self.tiled_map.map_file + assert map_source map_directory = os.path.dirname(map_source) image_file = _get_image_source(tile, map_directory) diff --git a/arcade/types.py b/arcade/types.py index da49b24c30..8f138666ae 100644 --- a/arcade/types.py +++ b/arcade/types.py @@ -419,6 +419,7 @@ def random( # Vector = Point Point = Tuple[float, float] Point3 = Tuple[float, float, float] +IntPoint = Tuple[int, int] class MutablePoint(Protocol): def __getitem__(self, key: Literal[0] | Literal[1]) -> float: ... def __setitem__(self, key: Literal[0] | Literal[1], value: float) -> None: ... diff --git a/make.py b/make.py index 7e9f777e6e..50551b356a 100755 --- a/make.py +++ b/make.py @@ -290,8 +290,8 @@ def latex(): run_doc([SPHINXBUILD, "-b", "latex", *ALLSPHINXOPTS, f"{BUILDDIR}/latex"]) print() print(f"Build finished; the LaTeX files are in {FULL_BUILD_PREFIX}/latex.") - print("Run \`make' in that directory to run these through (pdf)latex" + - "(use \`make latexpdf' here to do that automatically).") + print("Run `make' in that directory to run these through (pdf)latex" + + "(use `make latexpdf' here to do that automatically).") @app.command(rich_help_panel="Additional Doc Formats") @@ -344,8 +344,8 @@ def texinfo(): run_doc([SPHINXBUILD, "-b", "texinfo", *ALLSPHINXOPTS, f"{BUILDDIR}/texinfo"]) print() print(f"Build finished. The Texinfo files are in {FULL_BUILD_PREFIX}/texinfo.") - print("Run \`make' in that directory to run these through makeinfo" + - "(use \`make info' here to do that automatically).") + print("Run `make' in that directory to run these through makeinfo" + + "(use `make info' here to do that automatically).") @app.command(rich_help_panel="Additional Doc Formats") From a06fd147d016f0d835730cc58190fc76c5bddb31 Mon Sep 17 00:00:00 2001 From: cspotcode Date: Fri, 5 May 2023 14:05:04 -0400 Subject: [PATCH 05/17] more type diagnostic fixes --- arcade/gui/examples/scroll_area.py | 7 ++++--- arcade/gui/property.py | 27 ++++++++++++--------------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/arcade/gui/examples/scroll_area.py b/arcade/gui/examples/scroll_area.py index a03f254b54..18196ff090 100644 --- a/arcade/gui/examples/scroll_area.py +++ b/arcade/gui/examples/scroll_area.py @@ -16,12 +16,13 @@ from arcade import Window from arcade.gui import UIManager, UIWidget, Property, Surface, UIDummy, UIEvent, bind, \ UIMouseDragEvent, UIMouseScrollEvent, UIMouseEvent, UIBoxLayout, UIFlatButton, UIInputText +from arcade.types import Point class UIScrollArea(UIWidget): - scroll_x = Property(default=0) - scroll_y = Property(default=0) - canvas_size = Property(default=(300, 300)) + scroll_x = Property[float](default=0) + scroll_y = Property[float](default=0) + canvas_size = Property[Point](default=(300, 300)) scroll_speed = 1.3 invert_scroll = False diff --git a/arcade/gui/property.py b/arcade/gui/property.py index f4003e735f..c903419666 100644 --- a/arcade/gui/property.py +++ b/arcade/gui/property.py @@ -1,26 +1,24 @@ import sys import traceback -from typing import TypeVar +from typing import Any, Callable, Generic, Optional, TypeVar, cast from weakref import WeakKeyDictionary, ref +P = TypeVar("P") -class _Obs: +class _Obs(Generic[P]): """ Internal holder for Property value and change listeners """ __slots__ = "value", "listeners" - def __init__(self): - self.value = None + def __init__(self, value: P): + self.value = value # This will keep any added listener even if it is not referenced anymore and would be garbage collected self.listeners = set() -P = TypeVar("P") - - -class Property: +class Property(Generic[P]): """ An observable property which triggers observers when changed. @@ -31,9 +29,9 @@ class Property: __slots__ = "name", "default_factory", "obs" name: str - def __init__(self, default=None, default_factory=None): + def __init__(self, default: Optional[P] = None, default_factory: Optional[Callable[[Any, Any], P]] = None): if default_factory is None: - default_factory = lambda prop, instance: default + default_factory = lambda prop, instance: cast(P, default) self.default_factory = default_factory self.obs = WeakKeyDictionary() @@ -41,12 +39,11 @@ def __init__(self, default=None, default_factory=None): def _get_obs(self, instance) -> _Obs: obs = self.obs.get(instance) if obs is None: - obs = _Obs() - obs.value = self.default_factory(self, instance) + obs = _Obs(self.default_factory(self, instance)) self.obs[instance] = obs return obs - def get(self, instance): + def get(self, instance) -> P: obs = self._get_obs(instance) return obs.value @@ -77,9 +74,9 @@ def bind(self, instance, callback): def __set_name__(self, owner, name): self.name = name - def __get__(self, instance, owner): + def __get__(self, instance, owner) -> P: if instance is None: - return self + return self # pyright: ignore return self.get(instance) def __set__(self, instance, value): From 6b1342bb1729b9e675ab1e26bb30e87a5619fce6 Mon Sep 17 00:00:00 2001 From: cspotcode Date: Fri, 5 May 2023 15:04:53 -0400 Subject: [PATCH 06/17] lint fixes --- arcade/gl/types.py | 14 ++++++++------ arcade/gl/uniform.py | 1 - arcade/gui/property.py | 6 +++--- arcade/hitbox/base.py | 10 +++++----- arcade/sprite/base.py | 4 ++-- arcade/texture/tools.py | 6 +++--- arcade/tilemap/tilemap.py | 2 +- arcade/types.py | 6 ------ 8 files changed, 22 insertions(+), 27 deletions(-) diff --git a/arcade/gl/types.py b/arcade/gl/types.py index cf6fd3853c..28f01f3e70 100644 --- a/arcade/gl/types.py +++ b/arcade/gl/types.py @@ -1,5 +1,5 @@ import re -from typing import Optional, Iterable, List, Union +from typing import Optional, Iterable, List, Sequence, Union from pyglet import gl @@ -9,9 +9,9 @@ BufferOrBufferProtocol = Union[BufferProtocol, Buffer] -GLenumLike = gl.GLenum | int +GLenumLike = Union[gl.GLenum, int] PyGLenum = int -GLuintLike = gl.GLuint | int +GLuintLike = Union[gl.GLuint, int] PyGLuint = int _float_base_format = (0, gl.GL_RED, gl.GL_RG, gl.GL_RGB, gl.GL_RGBA) @@ -192,7 +192,7 @@ class BufferDescription: # Describe all variants of a format string to simplify parsing (single component) # format: gl_type, byte_size - _formats = { + _formats: dict[str, tuple[Optional[PyGLenum], int]] = { # (gl enum, byte size) # Floats "f": (gl.GL_FLOAT, 4), @@ -231,7 +231,7 @@ def __init__( self, buffer: Buffer, formats: str, - attributes: Iterable[str], + attributes: Sequence[str], normalized: Optional[Iterable[str]] = None, instanced: bool = False, ): @@ -270,7 +270,7 @@ def __init__( f"attributes ({len(self.attributes)})" ) - def zip_attrs(formats, attributes): + def zip_attrs(formats: list[str], attributes: Sequence[str]): """Join together formats and attribute names taking padding into account""" attr_index = 0 for f in formats: @@ -306,6 +306,8 @@ def zip_attrs(formats, attributes): ) gl_type, byte_size = self._formats[data_type] + assert attr_name + assert gl_type self.formats.append( AttribFormat( attr_name, gl_type, components, byte_size, offset=self.stride diff --git a/arcade/gl/uniform.py b/arcade/gl/uniform.py index d23aa5200b..778d5b0f1b 100644 --- a/arcade/gl/uniform.py +++ b/arcade/gl/uniform.py @@ -1,5 +1,4 @@ from ctypes import cast, POINTER -from typing import Callable from pyglet import gl from .exceptions import ShaderException diff --git a/arcade/gui/property.py b/arcade/gui/property.py index c903419666..4c5b7dc3dd 100644 --- a/arcade/gui/property.py +++ b/arcade/gui/property.py @@ -15,7 +15,7 @@ class _Obs(Generic[P]): def __init__(self, value: P): self.value = value # This will keep any added listener even if it is not referenced anymore and would be garbage collected - self.listeners = set() + self.listeners: set[Callable[[], Any]] = set() class Property(Generic[P]): @@ -34,7 +34,7 @@ def __init__(self, default: Optional[P] = None, default_factory: Optional[Callab default_factory = lambda prop, instance: cast(P, default) self.default_factory = default_factory - self.obs = WeakKeyDictionary() + self.obs: WeakKeyDictionary[Any, _Obs] = WeakKeyDictionary() def _get_obs(self, instance) -> _Obs: obs = self.obs.get(instance) @@ -76,7 +76,7 @@ def __set_name__(self, owner, name): def __get__(self, instance, owner) -> P: if instance is None: - return self # pyright: ignore + return self # type: ignore return self.get(instance) def __set__(self, instance, value): diff --git a/arcade/hitbox/base.py b/arcade/hitbox/base.py index f1ec10dbdf..505f609815 100644 --- a/arcade/hitbox/base.py +++ b/arcade/hitbox/base.py @@ -1,7 +1,7 @@ from __future__ import annotations from math import cos, radians, sin -from typing import Any, Tuple +from typing import Any, Optional, Sequence, Tuple from PIL.Image import Image @@ -54,7 +54,7 @@ def __init__( self._bottom = None self._top = None - self._adjusted_points = None + self._adjusted_points: Optional[PointList] = None self._adjusted_cache_dirty = True @property @@ -111,9 +111,9 @@ def create_rotatable( self._points, position=self._position, scale=self._scale, angle=angle ) - def get_adjusted_points(self) -> list[Point]: + def get_adjusted_points(self) -> Sequence[Point]: if not self._adjusted_cache_dirty: - return self._adjusted_points # pyright: ignore + return self._adjusted_points # type: ignore def _adjust_point(point) -> Point: x, y = point @@ -125,7 +125,7 @@ def _adjust_point(point) -> Point: self._adjusted_points = [_adjust_point(point) for point in self.points] self._adjusted_cache_dirty = False - return self._adjusted_points + return self._adjusted_points # type: ignore [return-value] class RotatableHitBox(HitBox): diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 53d0bd05fb..ecbda85f53 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -1,7 +1,7 @@ from typing import TYPE_CHECKING, Iterable, List, TypeVar import arcade -from arcade.types import Point, Color, RGBA255 +from arcade.types import Point, Color, RGBA255, PointList from arcade.color import BLACK from arcade.hitbox import HitBox from arcade.texture import Texture @@ -579,7 +579,7 @@ def draw_hit_box(self, color: RGBA255 = BLACK, line_thickness: float = 2.0) -> N :param color: Color of box :param line_thickness: How thick the box should be """ - points = self.hit_box.get_adjusted_points() + points: PointList = self.hit_box.get_adjusted_points() # NOTE: This is a COPY operation. We don't want to modify the points. points = tuple(points) + tuple(points[:-1]) arcade.draw_line_strip(points, color=color, line_width=line_thickness) diff --git a/arcade/texture/tools.py b/arcade/texture/tools.py index 91882515f4..ee4bf89b46 100644 --- a/arcade/texture/tools.py +++ b/arcade/texture/tools.py @@ -1,7 +1,7 @@ from PIL import Image, ImageDraw import arcade from .texture import ImageData, Texture -from arcade.types import IntPoint +from arcade.types import IPoint from arcade import cache _DEFAULT_TEXTURE = None @@ -17,7 +17,7 @@ def cleanup_texture_cache(): arcade.cache.image_data_cache.clear() -def get_default_texture(size: IntPoint = _DEFAULT_IMAGE_SIZE) -> Texture: +def get_default_texture(size: IPoint = _DEFAULT_IMAGE_SIZE) -> Texture: """ Creates and returns a default texture and caches it internally for future use. @@ -35,7 +35,7 @@ def get_default_texture(size: IntPoint = _DEFAULT_IMAGE_SIZE) -> Texture: return _DEFAULT_TEXTURE -def get_default_image(size: IntPoint = _DEFAULT_IMAGE_SIZE) -> ImageData: +def get_default_image(size: IPoint = _DEFAULT_IMAGE_SIZE) -> ImageData: """ Generates and returns a default image and caches it internally for future use. diff --git a/arcade/tilemap/tilemap.py b/arcade/tilemap/tilemap.py index 49a86ca260..2436409fbd 100644 --- a/arcade/tilemap/tilemap.py +++ b/arcade/tilemap/tilemap.py @@ -34,7 +34,7 @@ from arcade.math import rotate_point from arcade.resources import resolve -from arcade.types import MutablePoint, Point, TiledObject +from arcade.types import Point, TiledObject _FLIPPED_HORIZONTALLY_FLAG = 0x80000000 _FLIPPED_VERTICALLY_FLAG = 0x40000000 diff --git a/arcade/types.py b/arcade/types.py index 8f138666ae..e66f7ca714 100644 --- a/arcade/types.py +++ b/arcade/types.py @@ -10,10 +10,8 @@ from typing import ( Iterable, List, - Literal, NamedTuple, Optional, - Protocol, Sequence, Tuple, Union, @@ -419,10 +417,6 @@ def random( # Vector = Point Point = Tuple[float, float] Point3 = Tuple[float, float, float] -IntPoint = Tuple[int, int] -class MutablePoint(Protocol): - def __getitem__(self, key: Literal[0] | Literal[1]) -> float: ... - def __setitem__(self, key: Literal[0] | Literal[1], value: float) -> None: ... IPoint = Tuple[int, int] Vector = Point NamedPoint = namedtuple("NamedPoint", ["x", "y"]) From c9e9df6ce889a493d75505865eff2b8e8c48f723 Mon Sep 17 00:00:00 2001 From: cspotcode Date: Fri, 5 May 2023 16:16:00 -0400 Subject: [PATCH 07/17] Fix some test failures; others are pending #1752 --- arcade/cache/texture.py | 5 ++--- arcade/gl/types.py | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/arcade/cache/texture.py b/arcade/cache/texture.py index c188e9d601..725a60e941 100644 --- a/arcade/cache/texture.py +++ b/arcade/cache/texture.py @@ -89,16 +89,15 @@ def put( # TODO: Consider using Texture.origin instead of file_path # Consider also caching origin that is not a file name name = texture.cache_name - file_path = str(file_path) if strong: self._strong_entries.put(name, texture) - if self._strong_file_entries.get(file_path): + if self._strong_file_entries.get(str(file_path)): raise ValueError(f"File path {file_path} already in cache") if file_path: self._strong_file_entries.put(str(file_path), texture) else: self._weak_entires.put(name, texture) - if self._weak_file_entries.get(file_path): + if self._weak_file_entries.get(str(file_path)): raise ValueError(f"File path {file_path} already in cache") if file_path: self._weak_file_entries.put(str(file_path), texture) diff --git a/arcade/gl/types.py b/arcade/gl/types.py index 28f01f3e70..58673b478f 100644 --- a/arcade/gl/types.py +++ b/arcade/gl/types.py @@ -132,9 +132,9 @@ class AttribFormat: ) def __init__( - self, name: str, gl_type: PyGLenum, components: int, bytes_per_component: int, offset=0, location=0 + self, name: Optional[str], gl_type: Optional[PyGLenum], components: int, bytes_per_component: int, offset=0, location=0 ): - self.name: str = name + self.name = name self.gl_type = gl_type self.components = components self.bytes_per_component = bytes_per_component @@ -306,8 +306,6 @@ def zip_attrs(formats: list[str], attributes: Sequence[str]): ) gl_type, byte_size = self._formats[data_type] - assert attr_name - assert gl_type self.formats.append( AttribFormat( attr_name, gl_type, components, byte_size, offset=self.stride From 0bd6525a2640d9c674a88e35c95ee70fce9ef08c Mon Sep 17 00:00:00 2001 From: cspotcode Date: Wed, 10 May 2023 16:52:38 -0400 Subject: [PATCH 08/17] collapse int|float into float --- arcade/camera.py | 2 +- arcade/gui/widgets/layout.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arcade/camera.py b/arcade/camera.py index 529c4c0bbf..4fdaabf246 100644 --- a/arcade/camera.py +++ b/arcade/camera.py @@ -384,7 +384,7 @@ def scale(self) -> Tuple[float, float]: return self._scale @scale.setter - def scale(self, new_scale: Tuple[int | float, int | float]) -> None: + def scale(self, new_scale: Tuple[float, float]) -> None: """ Sets the x, y scale (zoom property just sets scale to the same value). This also updates the projection matrix with an orthogonal diff --git a/arcade/gui/widgets/layout.py b/arcade/gui/widgets/layout.py index 3de5d15819..2beeba3b61 100644 --- a/arcade/gui/widgets/layout.py +++ b/arcade/gui/widgets/layout.py @@ -662,10 +662,10 @@ def do_layout(self): [None for _ in range(self.column_count)] for _ in range(self.row_count) ] - max_width_per_column: list[list[tuple[int | float, int]]] = [ + max_width_per_column: list[list[tuple[float, int]]] = [ [(0, 1) for _ in range(self.row_count)] for _ in range(self.column_count) ] - max_height_per_row: list[list[tuple[int | float, int]]] = [ + max_height_per_row: list[list[tuple[float, int]]] = [ [(0, 1) for _ in range(self.column_count)] for _ in range(self.row_count) ] From 42b270461eee9942c7918f66fecf600669c9bfc3 Mon Sep 17 00:00:00 2001 From: cspotcode Date: Wed, 10 May 2023 16:53:06 -0400 Subject: [PATCH 09/17] Use `Union` instead of `|` --- arcade/gl/compute_shader.py | 2 +- arcade/gl/types.py | 2 +- arcade/text.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arcade/gl/compute_shader.py b/arcade/gl/compute_shader.py index bd1712848b..f52f74ca42 100644 --- a/arcade/gl/compute_shader.py +++ b/arcade/gl/compute_shader.py @@ -17,7 +17,7 @@ class ComputeShader: def __init__(self, ctx: "Context", glsl_source: str) -> None: self._ctx = ctx self._source = glsl_source - self._uniforms: Dict[str, UniformBlock | Uniform] = dict() + self._uniforms: Dict[str, Union[UniformBlock, Uniform]] = dict() from arcade.gl import ShaderException diff --git a/arcade/gl/types.py b/arcade/gl/types.py index 58673b478f..e0c9bac4e6 100644 --- a/arcade/gl/types.py +++ b/arcade/gl/types.py @@ -106,7 +106,7 @@ } -def gl_name(gl_type: PyGLenum) -> str | PyGLenum: +def gl_name(gl_type: PyGLenum) -> Union[str, PyGLenum]: """Return the name of a gl type""" return GL_NAMES.get(gl_type, gl_type) diff --git a/arcade/text.py b/arcade/text.py index c8249f7c8c..646abd0d4d 100644 --- a/arcade/text.py +++ b/arcade/text.py @@ -569,7 +569,7 @@ def position(self) -> Point: return self._label.x, self._label.y @position.setter - def position(self, point: Point | Point3): + def position(self, point: Union[Point, Point3]): # Starting with Pyglet 2.0b2 label positions take a z parameter. if len(point) == 3: self._label.position = point From 3ad08b2b3350f5fdaccb80897e71b2654abb8304 Mon Sep 17 00:00:00 2001 From: cspotcode Date: Wed, 10 May 2023 16:58:05 -0400 Subject: [PATCH 10/17] fix line length lint --- arcade/gl/types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arcade/gl/types.py b/arcade/gl/types.py index e0c9bac4e6..96ee8efdc2 100644 --- a/arcade/gl/types.py +++ b/arcade/gl/types.py @@ -132,7 +132,8 @@ class AttribFormat: ) def __init__( - self, name: Optional[str], gl_type: Optional[PyGLenum], components: int, bytes_per_component: int, offset=0, location=0 + self, name: Optional[str], gl_type: Optional[PyGLenum], components: int, bytes_per_component: int, offset=0, + location=0 ): self.name = name self.gl_type = gl_type From 966aa2b719b4dfa5e04d59ff985a0afe18731cdb Mon Sep 17 00:00:00 2001 From: cspotcode Date: Wed, 10 May 2023 17:07:38 -0400 Subject: [PATCH 11/17] address review feedback --- arcade/gui/examples/scroll_area.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arcade/gui/examples/scroll_area.py b/arcade/gui/examples/scroll_area.py index 3d6ce79fd5..24936d6343 100644 --- a/arcade/gui/examples/scroll_area.py +++ b/arcade/gui/examples/scroll_area.py @@ -26,9 +26,9 @@ class UIScrollArea(UIWidget): - scroll_x = Property[float](default=0) - scroll_y = Property[float](default=0) - canvas_size = Property[Point](default=(300, 300)) + scroll_x = Property[float](default=0.0) + scroll_y = Property[float](default=0.0) + canvas_size = Property[Point](default=(300.0, 300.0)) scroll_speed = 1.3 invert_scroll = False From bfee79a186a1188f788a26155a3bf0218ea7f0b7 Mon Sep 17 00:00:00 2001 From: cspotcode Date: Wed, 10 May 2023 17:10:13 -0400 Subject: [PATCH 12/17] Revert all the `arcade.gl` changes to put them into a separate PR --- arcade/gl/buffer.py | 2 +- arcade/gl/compute_shader.py | 2 +- arcade/gl/context.py | 33 +++++++++++++-------------------- arcade/gl/geometry.py | 6 +++--- arcade/gl/glsl.py | 4 ++-- arcade/gl/program.py | 6 +++--- arcade/gl/texture.py | 6 +++--- arcade/gl/types.py | 23 +++++++++-------------- arcade/gl/uniform.py | 2 ++ arcade/gl/vertex_array.py | 26 +++++++++++++------------- 10 files changed, 50 insertions(+), 60 deletions(-) diff --git a/arcade/gl/buffer.py b/arcade/gl/buffer.py index 2980d686e5..8918bd97d6 100644 --- a/arcade/gl/buffer.py +++ b/arcade/gl/buffer.py @@ -66,7 +66,7 @@ def __init__( elif reserve > 0: self._size = reserve # populate the buffer with zero byte values - data = (gl.GLubyte * self._size)() + data = (gl.GLubyte * self._size)(0) gl.glBufferData(gl.GL_ARRAY_BUFFER, self._size, data, self._usage) else: raise ValueError("Buffer takes byte data or number of reserved bytes") diff --git a/arcade/gl/compute_shader.py b/arcade/gl/compute_shader.py index f52f74ca42..6d1650a03a 100644 --- a/arcade/gl/compute_shader.py +++ b/arcade/gl/compute_shader.py @@ -17,7 +17,7 @@ class ComputeShader: def __init__(self, ctx: "Context", glsl_source: str) -> None: self._ctx = ctx self._source = glsl_source - self._uniforms: Dict[str, Union[UniformBlock, Uniform]] = dict() + self._uniforms: Dict[str, Uniform] = dict() from arcade.gl import ShaderException diff --git a/arcade/gl/context.py b/arcade/gl/context.py index a27b90290c..c804ad2ae3 100644 --- a/arcade/gl/context.py +++ b/arcade/gl/context.py @@ -1,14 +1,12 @@ import logging -import typing import weakref from collections import deque from contextlib import contextmanager from ctypes import c_char_p, c_float, c_int, cast -from typing import (TYPE_CHECKING, Any, Deque, Dict, Iterable, List, Optional, Sequence, Set, Tuple, +from typing import (Any, Deque, Dict, Iterable, List, Optional, Sequence, Set, Tuple, Union) import pyglet -import pyglet.gl.lib from pyglet import gl from pyglet.window import Window @@ -19,7 +17,7 @@ from .program import Program from .query import Query from .texture import Texture2D -from .types import BufferDescription, GLenumLike, PyGLenum +from .types import BufferDescription from .vertex_array import Geometry from ..types import BufferProtocol @@ -821,9 +819,9 @@ def texture( components: int = 4, dtype: str = "f1", data: Optional[BufferProtocol] = None, - wrap_x: Optional[PyGLenum] = None, - wrap_y: Optional[PyGLenum] = None, - filter: Optional[Tuple[GLenumLike, GLenumLike]] = None, + wrap_x: Optional[gl.GLenum] = None, + wrap_y: Optional[gl.GLenum] = None, + filter: Optional[Tuple[gl.GLenum, gl.GLenum]] = None, samples: int = 0, immutable: bool = False, ) -> Texture2D: @@ -1262,41 +1260,36 @@ def __init__(self, ctx): warn("Error happened while querying of limits. Moving on ..") - def get_int_tuple(self, enum: GLenumLike, length: int): + def get_int_tuple(self, enum: gl.GLenum, length: int): """Get an enum as an int tuple""" try: values = (c_int * length)() gl.glGetIntegerv(enum, values) return tuple(values) - except pyglet.gl.lib.GLException: + except gl.lib.GLException: return tuple([0] * length) - def get(self, enum: GLenumLike, default=0) -> int: + def get(self, enum: gl.GLenum, default=0) -> int: """Get an integer limit""" try: value = c_int() gl.glGetIntegerv(enum, value) return value.value - except pyglet.gl.lib.GLException: + except gl.lib.GLException: return default - def get_float(self, enum: GLenumLike, default=0.0) -> float: + def get_float(self, enum: gl.GLenum, default=0.0) -> float: """Get a float limit""" try: value = c_float() gl.glGetFloatv(enum, value) return value.value - except pyglet.gl.lib.GLException: + except gl.lib.GLException: return default - def get_str(self, enum: GLenumLike) -> str: + def get_str(self, enum: gl.GLenum) -> str: """Get a string limit""" try: return cast(gl.glGetString(enum), c_char_p).value.decode() # type: ignore - except pyglet.gl.lib.GLException: + except gl.lib.GLException: return "Unknown" - -if TYPE_CHECKING: - # Arcade's Context is passed into code paths that require a pyglet Context - # So we must prove they are compatible. - __typecheck__: pyglet.gl.base.Context = typing.cast(Context, '__typecheck__') diff --git a/arcade/gl/geometry.py b/arcade/gl/geometry.py index 4356c51936..8b45e3b17f 100644 --- a/arcade/gl/geometry.py +++ b/arcade/gl/geometry.py @@ -231,9 +231,9 @@ def sphere( R = 1.0 / (rings - 1) S = 1.0 / (sectors - 1) - vertices = [0.0] * (rings * sectors * 3) - normals = [0.0] * (rings * sectors * 3) - uvs = [0.0] * (rings * sectors * 2) + vertices = [0] * (rings * sectors * 3) + normals = [0] * (rings * sectors * 3) + uvs = [0] * (rings * sectors * 2) v, n, t = 0, 0, 0 for r in range(rings): diff --git a/arcade/gl/glsl.py b/arcade/gl/glsl.py index 81f2546e93..05569e9ca9 100644 --- a/arcade/gl/glsl.py +++ b/arcade/gl/glsl.py @@ -4,7 +4,7 @@ from pyglet import gl from .exceptions import ShaderException -from .types import SHADER_TYPE_NAMES, PyGLenum +from .types import SHADER_TYPE_NAMES class ShaderSource: @@ -31,7 +31,7 @@ def __init__( ctx: gl.Context, source: str, common: Optional[Iterable[str]], - source_type: PyGLenum, + source_type: gl.GLenum, ): """Create a shader source wrapper.""" self._source = source.strip() diff --git a/arcade/gl/program.py b/arcade/gl/program.py index ba3c8cc2bc..ecf6ada874 100644 --- a/arcade/gl/program.py +++ b/arcade/gl/program.py @@ -15,7 +15,7 @@ from pyglet import gl from .uniform import Uniform, UniformBlock -from .types import AttribFormat, GLTypes, SHADER_TYPE_NAMES, PyGLenum +from .types import AttribFormat, GLTypes, SHADER_TYPE_NAMES from .exceptions import ShaderException if TYPE_CHECKING: # handle import cycle caused by type hinting @@ -93,7 +93,7 @@ def __init__( f"Valid modes are: {self._valid_capture_modes}." ) - shaders: list[tuple[str, int]] = [(vertex_shader, gl.GL_VERTEX_SHADER)] + shaders = [(vertex_shader, gl.GL_VERTEX_SHADER)] if fragment_shader: shaders.append((fragment_shader, gl.GL_FRAGMENT_SHADER)) if geometry_shader: @@ -486,7 +486,7 @@ def _query_uniform_block(self, location: int) -> Tuple[int, int, str]: return index, b_size.value, u_name.value.decode() @staticmethod - def compile_shader(source: str, shader_type: PyGLenum) -> gl.GLuint: + def compile_shader(source: str, shader_type: gl.GLenum) -> gl.GLuint: """Compile the shader code of the given type. `shader_type` could be GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, ... diff --git a/arcade/gl/texture.py b/arcade/gl/texture.py index 685e8ca817..44474d8e48 100644 --- a/arcade/gl/texture.py +++ b/arcade/gl/texture.py @@ -6,7 +6,7 @@ from .buffer import Buffer from .utils import data_to_ctypes -from .types import PyGLuint, pixel_formats, BufferOrBufferProtocol +from .types import pixel_formats, BufferOrBufferProtocol from ..types import BufferProtocol if TYPE_CHECKING: # handle import cycle caused by type hinting @@ -115,8 +115,8 @@ def __init__( dtype: str = "f1", data: Optional[BufferProtocol] = None, filter: Optional[Tuple[gl.GLuint, gl.GLuint]] = None, - wrap_x: Optional[PyGLuint] = None, - wrap_y: Optional[PyGLuint] = None, + wrap_x: Optional[gl.GLuint] = None, + wrap_y: Optional[gl.GLuint] = None, target=gl.GL_TEXTURE_2D, depth=False, samples: int = 0, diff --git a/arcade/gl/types.py b/arcade/gl/types.py index 96ee8efdc2..76bf0ce693 100644 --- a/arcade/gl/types.py +++ b/arcade/gl/types.py @@ -1,5 +1,5 @@ import re -from typing import Optional, Iterable, List, Sequence, Union +from typing import Optional, Iterable, List, Union from pyglet import gl @@ -9,10 +9,6 @@ BufferOrBufferProtocol = Union[BufferProtocol, Buffer] -GLenumLike = Union[gl.GLenum, int] -PyGLenum = int -GLuintLike = Union[gl.GLuint, int] -PyGLuint = int _float_base_format = (0, gl.GL_RED, gl.GL_RG, gl.GL_RGB, gl.GL_RGBA) _int_base_format = ( @@ -106,7 +102,7 @@ } -def gl_name(gl_type: PyGLenum) -> Union[str, PyGLenum]: +def gl_name(gl_type: gl.GLenum) -> str: """Return the name of a gl type""" return GL_NAMES.get(gl_type, gl_type) @@ -116,7 +112,7 @@ class AttribFormat: Represents an attribute in a BufferDescription or a Program. :param str name: Name of the attribute - :param GLenumLike gl_type: The OpenGL type such as GL_FLOAT, GL_HALF_FLOAT etc. + :param gl.GLEnum gl_type: The OpenGL type such as GL_FLOAT, GL_HALF_FLOAT etc. :param int bytes_per_component: Number of bytes a single component takes :param int offset: (Optional offset for BufferDescription) :param int location: (Optional location for program attribute) @@ -132,10 +128,9 @@ class AttribFormat: ) def __init__( - self, name: Optional[str], gl_type: Optional[PyGLenum], components: int, bytes_per_component: int, offset=0, - location=0 + self, name: str, gl_type: gl.GLenum, components: int, bytes_per_component: int, offset=0, location=0 ): - self.name = name + self.name: str = name self.gl_type = gl_type self.components = components self.bytes_per_component = bytes_per_component @@ -193,7 +188,7 @@ class BufferDescription: # Describe all variants of a format string to simplify parsing (single component) # format: gl_type, byte_size - _formats: dict[str, tuple[Optional[PyGLenum], int]] = { + _formats = { # (gl enum, byte size) # Floats "f": (gl.GL_FLOAT, 4), @@ -232,7 +227,7 @@ def __init__( self, buffer: Buffer, formats: str, - attributes: Sequence[str], + attributes: Iterable[str], normalized: Optional[Iterable[str]] = None, instanced: bool = False, ): @@ -271,7 +266,7 @@ def __init__( f"attributes ({len(self.attributes)})" ) - def zip_attrs(formats: list[str], attributes: Sequence[str]): + def zip_attrs(formats, attributes): """Join together formats and attribute names taking padding into account""" attr_index = 0 for f in formats: @@ -349,7 +344,7 @@ class TypeInfo: """ __slots__ = "name", "enum", "gl_type", "gl_size", "components" - def __init__(self, name: str, enum: GLenumLike, gl_type: PyGLenum, gl_size: int, components: int): + def __init__(self, name: str, enum: gl.GLenum, gl_type: gl.GLenum, gl_size: int, components: int): self.name = name self.enum = enum self.gl_type = gl_type diff --git a/arcade/gl/uniform.py b/arcade/gl/uniform.py index 778d5b0f1b..5a3c3a9fec 100644 --- a/arcade/gl/uniform.py +++ b/arcade/gl/uniform.py @@ -114,6 +114,8 @@ def __init__(self, ctx, program_id, location, name, data_type, array_length): self._components = 0 #: The getter function configured for this uniform #: The setter function configured for this uniform + self.getter = None + self.setter = None self._setup_getters_and_setters() @property diff --git a/arcade/gl/vertex_array.py b/arcade/gl/vertex_array.py index e630ffb7c2..d4b45bac2c 100644 --- a/arcade/gl/vertex_array.py +++ b/arcade/gl/vertex_array.py @@ -5,7 +5,7 @@ from pyglet import gl from .buffer import Buffer -from .types import BufferDescription, GLenumLike, GLuintLike, gl_name +from .types import BufferDescription, gl_name from .program import Program if TYPE_CHECKING: # handle import cycle caused by type hinting @@ -239,7 +239,7 @@ def _build( gl.glVertexAttribDivisor(prog_attr.location, 1) def render( - self, mode: GLenumLike, first: int = 0, vertices: int = 0, instances: int = 1 + self, mode: gl.GLenum, first: int = 0, vertices: int = 0, instances: int = 1 ): """Render the VertexArray to the currently active framebuffer. @@ -259,7 +259,7 @@ def render( else: gl.glDrawArraysInstanced(mode, first, vertices, instances) - def render_indirect(self, buffer: Buffer, mode: GLuintLike, count, first, stride): + def render_indirect(self, buffer: Buffer, mode: gl.GLuint, count, first, stride): """ Render the VertexArray to the framebuffer using indirect rendering. @@ -300,8 +300,8 @@ def render_indirect(self, buffer: Buffer, mode: GLuintLike, count, first, stride def transform_interleaved( self, buffer: Buffer, - mode: GLenumLike, - output_mode: GLenumLike, + mode: gl.GLenum, + output_mode: gl.GLenum, first: int = 0, vertices: int = 0, instances: int = 1, @@ -310,8 +310,8 @@ def transform_interleaved( """Run a transform feedback. :param Buffer buffer: The buffer to write the output - :param GLenumLike mode: The input primitive mode - :param GLenumLike output_mode: The output primitive mode + :param gl.GLenum mode: The input primitive mode + :param gl.GLenum output_mode: The output primitive mode :param int first: Offset start vertex :param int vertices: Number of vertices to render :param int instances: Number of instances to render @@ -355,8 +355,8 @@ def transform_interleaved( def transform_separate( self, buffers: List[Buffer], - mode: GLenumLike, - output_mode: GLenumLike, + mode: gl.GLenum, + output_mode: gl.GLenum, first: int = 0, vertices: int = 0, instances: int = 1, @@ -366,8 +366,8 @@ def transform_separate( Run a transform feedback writing to separate buffers. :param List[Buffer] buffers: The buffers to write the output - :param GLenumLike mode: The input primitive mode - :param GLenumLike output_mode: The output primitive mode + :param gl.GLenum mode: The input primitive mode + :param gl.GLenum output_mode: The output primitive mode :param int first: Offset start vertex :param int vertices: Number of vertices to render :param int instances: Number of instances to render @@ -537,7 +537,7 @@ def render( self, program: Program, *, - mode: Optional[GLenumLike] = None, + mode: Optional[gl.GLenum] = None, first: int = 0, vertices: Optional[int] = None, instances: int = 1, @@ -549,7 +549,7 @@ def render( or have resized the buffers after the geometry instance was created. :param Program program: The Program to render with - :param GLenumLike mode: Override what primitive mode should be used + :param gl.GLenum mode: Override what primitive mode should be used :param int first: Offset start vertex :param int vertices: Override the number of vertices to render :param int instances: Number of instances to render From f70bbb81bfd20ff26d5888ed73f131ccd5c1ec33 Mon Sep 17 00:00:00 2001 From: cspotcode Date: Wed, 10 May 2023 17:18:00 -0400 Subject: [PATCH 13/17] revert behavioral change that breaks tests, pending einarf fixing on his branch --- arcade/cache/texture.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arcade/cache/texture.py b/arcade/cache/texture.py index 725a60e941..3df7e83a26 100644 --- a/arcade/cache/texture.py +++ b/arcade/cache/texture.py @@ -91,13 +91,13 @@ def put( name = texture.cache_name if strong: self._strong_entries.put(name, texture) - if self._strong_file_entries.get(str(file_path)): + if self._strong_file_entries.get(file_path): raise ValueError(f"File path {file_path} already in cache") if file_path: self._strong_file_entries.put(str(file_path), texture) else: self._weak_entires.put(name, texture) - if self._weak_file_entries.get(str(file_path)): + if self._weak_file_entries.get(file_path): raise ValueError(f"File path {file_path} already in cache") if file_path: self._weak_file_entries.put(str(file_path), texture) From 54cb0609e9cdcc8ba9c8928aa1016a7f4e1228ab Mon Sep 17 00:00:00 2001 From: cspotcode Date: Wed, 10 May 2023 17:25:05 -0400 Subject: [PATCH 14/17] fix mypy failures --- arcade/gui/property.py | 4 ++-- arcade/texture/transforms.py | 4 ++-- arcade/tilemap/tilemap.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arcade/gui/property.py b/arcade/gui/property.py index 4c5b7dc3dd..bc4a84bfc5 100644 --- a/arcade/gui/property.py +++ b/arcade/gui/property.py @@ -1,6 +1,6 @@ import sys import traceback -from typing import Any, Callable, Generic, Optional, TypeVar, cast +from typing import Any, Callable, Generic, Optional, Set, TypeVar, cast from weakref import WeakKeyDictionary, ref P = TypeVar("P") @@ -15,7 +15,7 @@ class _Obs(Generic[P]): def __init__(self, value: P): self.value = value # This will keep any added listener even if it is not referenced anymore and would be garbage collected - self.listeners: set[Callable[[], Any]] = set() + self.listeners: Set[Callable[[], Any]] = set() class Property(Generic[P]): diff --git a/arcade/texture/transforms.py b/arcade/texture/transforms.py index 17dfb2d21d..d5c28675e9 100644 --- a/arcade/texture/transforms.py +++ b/arcade/texture/transforms.py @@ -5,7 +5,7 @@ We don't actually transform pixel data, we simply transform the texture coordinates and hit box points. """ -from typing import Tuple +from typing import Dict, Tuple from enum import Enum from arcade.math import rotate_point from arcade.types import PointList @@ -217,7 +217,7 @@ def transform_hit_box_points( # but it's faster to just pre-calculate it. # Key is the vertex order # Value is the orientation (flip_left_right, flip_top_down, rotation) -ORIENTATIONS: dict[tuple[int, int, int, int], tuple[int, bool, bool]] = { +ORIENTATIONS: Dict[Tuple[int, int, int, int], Tuple[int, bool, bool]] = { (0, 1, 2, 3): (0, False, False), # Default (2, 0, 3, 1): (90, False, False), # Rotate 90 (3, 2, 1, 0): (180, False, False), # Rotate 180 diff --git a/arcade/tilemap/tilemap.py b/arcade/tilemap/tilemap.py index 2436409fbd..84fdd9466a 100644 --- a/arcade/tilemap/tilemap.py +++ b/arcade/tilemap/tilemap.py @@ -571,7 +571,7 @@ def _create_sprite_from_tile( point = point[1], point[0] my_sprite.hit_box = RotatableHitBox( - cast(list[Point], points), + cast(List[Point], points), position=my_sprite.position, angle=my_sprite.angle, scale=my_sprite.scale_xy, From 4d7d846b5c853a509ae818bf98152623451eeb6f Mon Sep 17 00:00:00 2001 From: cspotcode Date: Fri, 12 May 2023 16:23:33 -0400 Subject: [PATCH 15/17] Addressing review feedback --- arcade/tilemap/tilemap.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arcade/tilemap/tilemap.py b/arcade/tilemap/tilemap.py index 84fdd9466a..8906d53696 100644 --- a/arcade/tilemap/tilemap.py +++ b/arcade/tilemap/tilemap.py @@ -48,7 +48,7 @@ prop_to_float = cast(Callable[[pytiled_parser.Property], float], float) -def _get_image_info_from_tileset(tile: pytiled_parser.Tile): +def _get_image_info_from_tileset(tile: pytiled_parser.Tile) -> Tuple[int, int, int, int]: image_x = 0 image_y = 0 if tile.tileset.image is not None: @@ -67,6 +67,10 @@ def _get_image_info_from_tileset(tile: pytiled_parser.Tile): image_y = tile.y width = tile.width height = tile.height + if TYPE_CHECKING: + # pytiled_parser guarantees this will be set despite the typehint + assert width is not None + assert height is not None return image_x, image_y, width, height @@ -412,7 +416,9 @@ def _create_sprite_from_tile( # --- Step 1, Find a reference to an image this is going to be based off of map_source = self.tiled_map.map_file - assert map_source + if TYPE_CHECKING: + # pytiled_parser guarantees this will be set despite the typehint + assert map_source is not None map_directory = os.path.dirname(map_source) image_file = _get_image_source(tile, map_directory) @@ -444,8 +450,6 @@ def _create_sprite_from_tile( # Can image_file be None? image_x, image_y, width, height = _get_image_info_from_tileset(tile) - assert width - assert height texture = _load_tilemap_texture( image_file, # type: ignore x=image_x, From 6ec26d62d2f5c1807abad73a25d54148dabd16e3 Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Wed, 17 May 2023 20:15:38 -0400 Subject: [PATCH 16/17] Upgrade pytiled parser to remove type assertions --- arcade/tilemap/tilemap.py | 7 ------- pyproject.toml | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/arcade/tilemap/tilemap.py b/arcade/tilemap/tilemap.py index 8906d53696..a0d23d3019 100644 --- a/arcade/tilemap/tilemap.py +++ b/arcade/tilemap/tilemap.py @@ -67,10 +67,6 @@ def _get_image_info_from_tileset(tile: pytiled_parser.Tile) -> Tuple[int, int, i image_y = tile.y width = tile.width height = tile.height - if TYPE_CHECKING: - # pytiled_parser guarantees this will be set despite the typehint - assert width is not None - assert height is not None return image_x, image_y, width, height @@ -416,9 +412,6 @@ def _create_sprite_from_tile( # --- Step 1, Find a reference to an image this is going to be based off of map_source = self.tiled_map.map_file - if TYPE_CHECKING: - # pytiled_parser guarantees this will be set despite the typehint - assert map_source is not None map_directory = os.path.dirname(map_source) image_file = _get_image_source(tile, map_directory) diff --git a/pyproject.toml b/pyproject.toml index 44e38174d5..bfa9dcfc9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ dependencies = [ "pyglet>=2.0.7,<2.1", "pillow~=9.4.0", "pymunk~=6.4.0", - "pytiled-parser~=2.2.0" + "pytiled-parser~=2.2.3" ] dynamic = ["version"] From f0a842629a409c669eefad507d8369ff4cdcbe95 Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Wed, 17 May 2023 20:25:22 -0400 Subject: [PATCH 17/17] lint fix --- arcade/hitbox/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcade/hitbox/base.py b/arcade/hitbox/base.py index bca7ac07c1..0065af3ee7 100644 --- a/arcade/hitbox/base.py +++ b/arcade/hitbox/base.py @@ -1,7 +1,7 @@ from __future__ import annotations from math import cos, radians, sin -from typing import Any, Optional, Sequence, Tuple +from typing import Any, Sequence, Tuple from PIL.Image import Image