Skip to content

Address type issues #1751

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions arcade/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -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[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
Expand All @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion arcade/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
7 changes: 4 additions & 3 deletions arcade/gui/examples/scroll_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,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.0)
scroll_y = Property[float](default=0.0)
canvas_size = Property[Point](default=(300.0, 300.0))

scroll_speed = 1.3
invert_scroll = False
Expand Down
31 changes: 14 additions & 17 deletions arcade/gui/property.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
import sys
import traceback
from typing import TypeVar
from typing import Any, Callable, Generic, Optional, Set, 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")
self.listeners: Set[Callable[[], Any]] = set()


class Property:
class Property(Generic[P]):
"""
An observable property which triggers observers when changed.

Expand All @@ -31,22 +29,21 @@ 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()
self.obs: WeakKeyDictionary[Any, _Obs] = WeakKeyDictionary()

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

Expand Down Expand Up @@ -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 # type: ignore
return self.get(instance)

def __set__(self, instance, value):
Expand Down
8 changes: 4 additions & 4 deletions arcade/gui/widgets/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
]

Expand Down Expand Up @@ -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[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[float, int]]] = [
[(0, 1) for _ in range(self.column_count)] for _ in range(self.row_count)
]

Expand Down
2 changes: 1 addition & 1 deletion arcade/gui/widgets/slider.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
6 changes: 3 additions & 3 deletions arcade/gui/widgets/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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,
Expand Down
8 changes: 4 additions & 4 deletions arcade/hitbox/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from math import cos, radians, sin
from typing import Any, Tuple
from typing import Any, Sequence, Tuple

from PIL.Image import Image

Expand Down Expand Up @@ -196,7 +196,7 @@ def create_rotatable(
self._points, position=self._position, scale=self._scale, angle=angle
)

def get_adjusted_points(self) -> PointList:
def get_adjusted_points(self) -> Sequence[Point]:
"""
Return the positions of points, scaled and offset from the center.

Expand All @@ -207,7 +207,7 @@ def get_adjusted_points(self) -> PointList:
* After properties affecting adjusted position were changed
"""
if not self._adjusted_cache_dirty:
return self._adjusted_points
return self._adjusted_points # type: ignore

def _adjust_point(point) -> Point:
x, y = point
Expand All @@ -219,7 +219,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):
Expand Down
2 changes: 1 addition & 1 deletion arcade/shape_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
4 changes: 2 additions & 2 deletions arcade/sprite/base.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions arcade/sprite_list/collision.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions arcade/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import pyglet

import arcade
from arcade.types import Color, Point, RGBA255
from arcade.types import Color, Point, RGBA255, Point3, RGBOrA255
from arcade.resources import resolve
from arcade.utils import PerformanceWarning, warning

Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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: Union[Point, Point3]):
# Starting with Pyglet 2.0b2 label positions take a z parameter.
if len(point) == 3:
self._label.position = point
Expand Down
6 changes: 3 additions & 3 deletions arcade/texture/tools.py
Original file line number Diff line number Diff line change
@@ -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 IPoint
from arcade import cache

_DEFAULT_TEXTURE = None
Expand All @@ -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: IPoint = _DEFAULT_IMAGE_SIZE) -> Texture:
"""
Creates and returns a default texture and caches it internally for future use.

Expand All @@ -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: IPoint = _DEFAULT_IMAGE_SIZE) -> ImageData:
"""
Generates and returns a default image and caches it internally for future use.

Expand Down
4 changes: 2 additions & 2 deletions arcade/texture/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion arcade/texture_atlas/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from weakref import WeakSet

import PIL
import PIL.Image
from PIL import Image, ImageDraw
from pyglet.image.atlas import (
Allocator,
Expand Down Expand Up @@ -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)
Expand Down
Loading