Skip to content

Commit efd215b

Browse files
authored
Initial cleanup of arcade.types (#2065)
* Turn arcade.types into folder package * Move color types/aliases to arcade.types.color * Remove unused RGBAOrA255OrNormalized * Clean up arcade.types imports * Remove unused TypeVar import * Move BufferProtocol conditional import to the top * Make backport-related imports conditional instead of universal * Remove redundant NamedPoint named tuple * Simplify V_2D and V_3D in arcade.math * Remove Vec2 and Vec3 from the unions since pyglet's Vec tpyes are now tuples * Remove Vec2 and Vec3 imports from arcade.math * Remove Vector alias with 2 uses * Remove currently broken and useless ColorLike type * Broaden typing in V_2D, V_3D, and lerp * Add AsFloat to arcade.types.__all__ * Clean up Path-related annotations * Add subscriptable PathOr alias * Remove Optional from PathOrTexture * Wrap usages of PathOrTexture in Optional * Add bytes to PathLike Union alias * Clean up imports in some PathOrTexture-using files * Move the if TYPE_CHECKING import of Texture closer to the usage * Clean up whitespace in arcade/types/__init__.py * Add top-level docstring for arcade.types.color * Add top-level docstring for arcade.types * Use AsFloat in current stubbed Rect annotations * Remove unused import * Move __all__ to top of arcade.types.color * Try to fix imports / __all__ * Defer total Vector replacement until later PR * Add back Vector alias * Rename it to Velocity in arcade.types * Change imports in particles + annotations in particles to account for this * Add Point3 to arcade.types.__all__ * Use consistent Optional type for LifeTimePartic.__init__'s filename_or_texture * Skip linting import order in arcade.types * noqa linters wrongly marking a type checking import as unused * Add omitted color tuple aliases to __all__ * Mark color masking constants with Final[int] * Fix noqa prefix for conditional Texture import * Let someone else alphabetize the arcade.types.__all__ declaration; I'm just getting it to build. * Document Size2D[int] and Size2D[float] * Add types to the API doc build * Add Size2D to types.__all__ * Replace IPoint with Size2D in arcade.texture.tools
1 parent d625a01 commit efd215b

File tree

10 files changed

+264
-144
lines changed

10 files changed

+264
-144
lines changed

arcade/examples/particle_fireworks.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
python -m arcade.examples.particle_fireworks
88
"""
99
import random
10+
from typing import Optional
11+
1012
import pyglet
1113
from pyglet.math import Vec2
1214

1315
import arcade
14-
from arcade.types import Point
16+
from arcade.types import Point, PathOrTexture
1517
from arcade.math import rand_in_rect, clamp, lerp, rand_in_circle, rand_on_circle
16-
from arcade.types import PathOrTexture
1718
from arcade.particles import (
1819
Emitter,
1920
LifetimeParticle,
@@ -127,7 +128,7 @@ class AnimatedAlphaParticle(LifetimeParticle):
127128

128129
def __init__(
129130
self,
130-
filename_or_texture: PathOrTexture,
131+
filename_or_texture: Optional[PathOrTexture],
131132
change_xy: Vec2,
132133
start_alpha: int = 0,
133134
duration1: float = 1.0,

arcade/experimental/shapes_perf.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import random
99

1010
import arcade
11-
from arcade.types import NamedPoint
1211
from pyglet.math import Mat4
1312

1413
SCREEN_WIDTH = 800
@@ -93,12 +92,12 @@ def __init__(self, width, height, title):
9392

9493
# line strip
9594
self.line_strip = [
96-
NamedPoint(random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT))
95+
(random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT))
9796
for _ in range(10)
9897
]
9998
# Random list of points
10099
self.points = [
101-
NamedPoint(random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT))
100+
(random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT))
102101
for _ in range(10_000)
103102
]
104103

arcade/math.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
import math
44
import random
5-
from typing import Tuple, List, Union
6-
from pyglet.math import Vec2, Vec3
7-
from arcade.types import Point, Vector
5+
from typing import Sequence, Tuple, Union
6+
from arcade.types import AsFloat, Point
7+
88

99
_PRECISION = 2
1010

@@ -63,13 +63,13 @@ def clamp(a, low: float, high: float) -> float:
6363
return high if a > high else max(a, low)
6464

6565

66-
def lerp(v1: float, v2: float, u: float) -> float:
67-
"""linearly interpolate between two values"""
68-
return v1 + ((v2 - v1) * u)
66+
V_2D = Union[Tuple[AsFloat, AsFloat], Sequence[AsFloat]]
67+
V_3D = Union[Tuple[AsFloat, AsFloat, AsFloat], Sequence[AsFloat]]
6968

7069

71-
V_2D = Union[Vec2, Tuple[float, float], List[float]]
72-
V_3D = Union[Vec3, Tuple[float, float, float], List[float]]
70+
def lerp(v1: AsFloat, v2: AsFloat, u: float) -> float:
71+
"""linearly interpolate between two values"""
72+
return v1 + ((v2 - v1) * u)
7373

7474

7575
def lerp_2d(v1: V_2D, v2: V_2D, u: float) -> Tuple[float, float]:
@@ -202,7 +202,7 @@ def rand_vec_spread_deg(
202202
angle: float,
203203
half_angle_spread: float,
204204
length: float
205-
) -> Vector:
205+
) -> tuple[float, float]:
206206
"""
207207
Returns a random vector, within a spread of the given angle.
208208
@@ -220,7 +220,7 @@ def rand_vec_magnitude(
220220
angle: float,
221221
lo_magnitude: float,
222222
hi_magnitude: float,
223-
) -> Vector:
223+
) -> tuple[float, float]:
224224
"""
225225
Returns a random vector, within a spread of the given angle.
226226

arcade/particles/emitter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from .particle import Particle
99
from typing import Optional, Callable, cast
1010
from arcade.math import _Vec2
11-
from arcade.types import Point, Vector
11+
from arcade.types import Point, Velocity
1212

1313

1414
class EmitController:
@@ -110,7 +110,7 @@ def __init__(
110110
center_xy: Point,
111111
emit_controller: EmitController,
112112
particle_factory: Callable[["Emitter"], Particle],
113-
change_xy: Vector = (0.0, 0.0),
113+
change_xy: Velocity = (0.0, 0.0),
114114
emit_done_cb: Optional[Callable[["Emitter"], None]] = None,
115115
reap_cb: Optional[Callable[[], None]] = None
116116
):

arcade/particles/particle.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,20 @@
22
Particle - Object produced by an Emitter. Often used in large quantity to produce visual effects effects
33
"""
44
from __future__ import annotations
5-
from typing import Literal
5+
from typing import Literal, Optional, Tuple
66

77
from arcade.sprite import Sprite
88
from arcade.math import lerp, clamp
9-
from arcade.types import Point, Vector
10-
from arcade.types import PathOrTexture
9+
from arcade.types import Point, PathOrTexture, Velocity
1110

1211

1312
class Particle(Sprite):
1413
"""Sprite that is emitted from an Emitter"""
1514

1615
def __init__(
1716
self,
18-
path_or_texture: PathOrTexture,
19-
change_xy: Vector,
17+
path_or_texture: Optional[PathOrTexture],
18+
change_xy: Tuple[float, float],
2019
center_xy: Point = (0.0, 0.0),
2120
angle: float = 0.0,
2221
change_angle: float = 0.0,
@@ -54,7 +53,7 @@ class EternalParticle(Particle):
5453
def __init__(
5554
self,
5655
filename_or_texture: PathOrTexture,
57-
change_xy: Vector,
56+
change_xy: Velocity,
5857
center_xy: Point = (0.0, 0.0),
5958
angle: float = 0,
6059
change_angle: float = 0,
@@ -75,8 +74,8 @@ class LifetimeParticle(Particle):
7574

7675
def __init__(
7776
self,
78-
filename_or_texture: PathOrTexture,
79-
change_xy: Vector,
77+
filename_or_texture: Optional[PathOrTexture],
78+
change_xy: Velocity,
8079
lifetime: float,
8180
center_xy: Point = (0.0, 0.0),
8281
angle: float = 0,
@@ -106,7 +105,7 @@ class FadeParticle(LifetimeParticle):
106105
def __init__(
107106
self,
108107
filename_or_texture: PathOrTexture,
109-
change_xy: Vector,
108+
change_xy: Velocity,
110109
lifetime: float,
111110
center_xy: Point = (0.0, 0.0),
112111
angle: float = 0,

arcade/sprite/sprite.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class Sprite(BasicSprite, PymunkMixin):
6464

6565
def __init__(
6666
self,
67-
path_or_texture: PathOrTexture = None,
67+
path_or_texture: Optional[PathOrTexture] = None,
6868
scale: float = 1.0,
6969
center_x: float = 0.0,
7070
center_y: float = 0.0,

arcade/texture/tools.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import arcade
55
import arcade.cache
66
from .texture import ImageData, Texture
7-
from arcade.types import IPoint
7+
from arcade.types import Size2D
88
from arcade import cache
99

1010
_DEFAULT_TEXTURE = None
@@ -20,7 +20,7 @@ def cleanup_texture_cache():
2020
arcade.cache.image_data_cache.clear()
2121

2222

23-
def get_default_texture(size: IPoint = _DEFAULT_IMAGE_SIZE) -> Texture:
23+
def get_default_texture(size: Size2D[int] = _DEFAULT_IMAGE_SIZE) -> Texture:
2424
"""
2525
Creates and returns a default texture and caches it internally for future use.
2626
@@ -38,7 +38,7 @@ def get_default_texture(size: IPoint = _DEFAULT_IMAGE_SIZE) -> Texture:
3838
return _DEFAULT_TEXTURE
3939

4040

41-
def get_default_image(size: IPoint = _DEFAULT_IMAGE_SIZE) -> ImageData:
41+
def get_default_image(size: Size2D[int] = _DEFAULT_IMAGE_SIZE) -> ImageData:
4242
"""
4343
Generates and returns a default image and caches it internally for future use.
4444

arcade/types/__init__.py

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
"""Fundamental aliases, classes, and related constants.
2+
3+
As general rules:
4+
5+
#. Things only go in this module if they serve multiple purposes
6+
throughout arcade
7+
#. Only expose the most important classes at this module's top level
8+
9+
For example, color-related types and related aliases go in
10+
``arcade.types`` because they're used throughout the codebase. This
11+
includes all the following areas:
12+
13+
#. :py:class:`~arcade.Sprite`
14+
#. :py:class:`~arcade.SpriteList`
15+
#. :py:class:`~arcade.Text`
16+
#. The :py:mod:`arcade.gui` widgets
17+
#. Functions in :py:mod:`arcade.drawing_commands`
18+
19+
However, since the color types, aliases, and constants are all related,
20+
they go in the :py:mod:`arcade.types.color` submodule.
21+
"""
22+
from __future__ import annotations
23+
24+
# Don't lint import order since we have conditional compatibility shims
25+
# flake8: noqa: E402
26+
import sys
27+
from pathlib import Path
28+
from typing import (
29+
List,
30+
NamedTuple,
31+
Optional,
32+
Sequence,
33+
Tuple,
34+
Union,
35+
TYPE_CHECKING,
36+
TypeVar
37+
)
38+
39+
from pytiled_parser import Properties
40+
41+
42+
# Backward-compatibility for buffer protocol objects
43+
# To learn more, see https://docs.python.org/3.8/c-api/buffer.html
44+
if sys.version_info >= (3, 12):
45+
from collections.abc import Buffer as BufferProtocol
46+
else:
47+
# The most common built-in buffer protocol objects
48+
import ctypes
49+
from array import array
50+
from collections.abc import ByteString
51+
52+
# This is used instead of the typing_extensions version since they
53+
# use an ABC which registers virtual subclasses. This will not work
54+
# with ctypes.Array since virtual subclasses must be concrete.
55+
# See: https://peps.python.org/pep-0688/
56+
BufferProtocol = Union[ByteString, memoryview, array, ctypes.Array]
57+
58+
59+
#: 1. Makes pyright happier while also telling readers
60+
#: 2. Tells readers we're converting any ints to floats
61+
AsFloat = Union[float, int]
62+
63+
64+
# Generic color aliases
65+
from arcade.types.color import RGB
66+
from arcade.types.color import RGBA
67+
from arcade.types.color import RGBOrA
68+
69+
# Specific color aliases
70+
from arcade.types.color import RGB255
71+
from arcade.types.color import RGBA255
72+
from arcade.types.color import RGBNormalized
73+
from arcade.types.color import RGBANormalized
74+
from arcade.types.color import RGBOrA255
75+
from arcade.types.color import RGBOrANormalized
76+
77+
# The Color helper type
78+
from arcade.types.color import Color
79+
80+
81+
__all__ = [
82+
"AsFloat",
83+
"BufferProtocol",
84+
"Color",
85+
"IPoint",
86+
"PathOr",
87+
"PathOrTexture",
88+
"Point",
89+
"Point3",
90+
"PointList",
91+
"EMPTY_POINT_LIST",
92+
"Rect",
93+
"RectList",
94+
"RGB",
95+
"RGBA",
96+
"RGBOrA",
97+
"RGB255",
98+
"RGBA255",
99+
"RGBOrA255",
100+
"RGBNormalized",
101+
"RGBANormalized",
102+
"RGBOrANormalized",
103+
"Size2D",
104+
"TiledObject",
105+
"Velocity"
106+
]
107+
108+
109+
_T = TypeVar('_T')
110+
111+
#: ``Size2D`` helps mark int or float sizes. Use it like a
112+
#: :py:class:`typing.Generic`'s bracket notation as follows:
113+
#:
114+
#: .. code-block:: python
115+
#:
116+
#: def example_Function(size: Size2D[int], color: RGBA255) -> Texture:
117+
#: """An example of how to use Size2D.
118+
#:
119+
#: Look at signature above, not the missing function body. The
120+
#: ``size`` argument is how you can mark texture sizes, while
121+
#: you can use ``Size2D[float]`` to denote float regions.
122+
#:
123+
#: :param size: A made-up hypothetical argument.
124+
#: :param color: Hypothetical texture-related argument.
125+
#: """
126+
#: ... # No function definition
127+
#:
128+
Size2D = Tuple[_T, _T]
129+
130+
# Point = Union[Tuple[AsFloat, AsFloat], List[AsFloat]]
131+
Point = Tuple[AsFloat, AsFloat]
132+
Point3 = Tuple[AsFloat, AsFloat, AsFloat]
133+
IPoint = Tuple[int, int]
134+
135+
136+
# We won't keep this forever. It's a temp stub for particles we'll replace.
137+
Velocity = Tuple[AsFloat, AsFloat]
138+
139+
PointList = Sequence[Point]
140+
# Speed / typing workaround:
141+
# 1. Eliminate extra allocations
142+
# 2. Allows type annotation to be cleaner, primarily for HitBox & subclasses
143+
EMPTY_POINT_LIST: PointList = tuple()
144+
145+
146+
Rect = Union[Tuple[int, int, int, int], List[int]] # x, y, width, height
147+
RectList = Union[Tuple[Rect, ...], List[Rect]]
148+
FloatRect = Union[Tuple[AsFloat, AsFloat, AsFloat, AsFloat], List[AsFloat]] # x, y, width, height
149+
150+
151+
# Path handling
152+
PathLike = Union[str, Path, bytes]
153+
_POr = TypeVar('_POr') # Allows PathOr[TypeNameHere] syntax
154+
PathOr = Union[PathLike, _POr]
155+
156+
157+
# Specific utility resource aliases with type imports
158+
if TYPE_CHECKING:
159+
# The linters are wrong: this is used, so we noqa it
160+
from arcade.texture import Texture # noqa: F401
161+
162+
PathOrTexture = PathOr["Texture"]
163+
164+
165+
class TiledObject(NamedTuple):
166+
shape: Union[Point, PointList, Rect]
167+
properties: Optional[Properties] = None
168+
name: Optional[str] = None
169+
type: Optional[str] = None

0 commit comments

Comments
 (0)