Skip to content
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

Initial cleanup of arcade.types #2065

Merged
merged 31 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
61d3d0d
Turn arcade.types into folder package
pushfoo Apr 17, 2024
124f5b8
Move color types/aliases to arcade.types.color
pushfoo Apr 18, 2024
71d242b
Remove unused RGBAOrA255OrNormalized
pushfoo Apr 18, 2024
25ec5b4
Clean up arcade.types imports
pushfoo Apr 18, 2024
d328edb
Remove redundant NamedPoint named tuple
pushfoo Apr 18, 2024
a3dc13c
Simplify V_2D and V_3D in arcade.math
pushfoo Apr 18, 2024
fc9a708
Remove Vector alias with 2 uses
pushfoo Apr 18, 2024
3f8c0e7
Remove currently broken and useless ColorLike type
pushfoo Apr 18, 2024
19c9eb4
Broaden typing in V_2D, V_3D, and lerp
pushfoo Apr 18, 2024
ce129ac
Add AsFloat to arcade.types.__all__
pushfoo Apr 18, 2024
328bf99
Clean up Path-related annotations
pushfoo Apr 18, 2024
2e10d63
Clean up whitespace in arcade/types/__init__.py
pushfoo Apr 18, 2024
676d104
Add top-level docstring for arcade.types.color
pushfoo Apr 18, 2024
6bd84a1
Add top-level docstring for arcade.types
pushfoo Apr 18, 2024
6f35f9f
Use AsFloat in current stubbed Rect annotations
pushfoo Apr 18, 2024
fe071fd
Remove unused import
pushfoo Apr 18, 2024
26aa06c
Move __all__ to top of arcade.types.color
pushfoo Apr 18, 2024
60654e6
Try to fix imports / __all__
pushfoo Apr 18, 2024
2b2dd45
Defer total Vector replacement until later PR
pushfoo Apr 18, 2024
f8e0a42
Add Point3 to arcade.types.__all__
pushfoo Apr 18, 2024
ea53edf
Use consistent Optional type for LifeTimePartic.__init__'s filename_o…
pushfoo Apr 18, 2024
058968a
Skip linting import order in arcade.types
pushfoo Apr 18, 2024
92bde13
noqa linters wrongly marking a type checking import as unused
pushfoo Apr 18, 2024
5db8917
Add omitted color tuple aliases to __all__
pushfoo Apr 18, 2024
cae0920
Mark color masking constants with Final[int]
pushfoo Apr 18, 2024
bfc3069
Fix noqa prefix for conditional Texture import
pushfoo Apr 18, 2024
272b3c4
Let someone else alphabetize the arcade.types.__all__ declaration; I'…
pushfoo Apr 18, 2024
71f2550
Document Size2D[int] and Size2D[float]
pushfoo Apr 18, 2024
3a54e4d
Add types to the API doc build
pushfoo Apr 18, 2024
8102887
Add Size2D to types.__all__
pushfoo Apr 18, 2024
44e1a08
Replace IPoint with Size2D in arcade.texture.tools
pushfoo Apr 18, 2024
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
7 changes: 4 additions & 3 deletions arcade/examples/particle_fireworks.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
python -m arcade.examples.particle_fireworks
"""
import random
from typing import Optional

import pyglet
from pyglet.math import Vec2

import arcade
from arcade.types import Point
from arcade.types import Point, PathOrTexture
from arcade.math import rand_in_rect, clamp, lerp, rand_in_circle, rand_on_circle
from arcade.types import PathOrTexture
from arcade.particles import (
Emitter,
LifetimeParticle,
Expand Down Expand Up @@ -127,7 +128,7 @@ class AnimatedAlphaParticle(LifetimeParticle):

def __init__(
self,
filename_or_texture: PathOrTexture,
filename_or_texture: Optional[PathOrTexture],
change_xy: Vec2,
start_alpha: int = 0,
duration1: float = 1.0,
Expand Down
5 changes: 2 additions & 3 deletions arcade/experimental/shapes_perf.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import random

import arcade
from arcade.types import NamedPoint
from pyglet.math import Mat4

SCREEN_WIDTH = 800
Expand Down Expand Up @@ -93,12 +92,12 @@ def __init__(self, width, height, title):

# line strip
self.line_strip = [
NamedPoint(random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT))
(random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT))
for _ in range(10)
]
# Random list of points
self.points = [
NamedPoint(random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT))
(random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT))
for _ in range(10_000)
]

Expand Down
20 changes: 10 additions & 10 deletions arcade/math.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import math
import random
from typing import Tuple, List, Union
from pyglet.math import Vec2, Vec3
from arcade.types import Point, Vector
from typing import Sequence, Tuple, Union
from arcade.types import AsFloat, Point


_PRECISION = 2

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


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


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


def lerp_2d(v1: V_2D, v2: V_2D, u: float) -> Tuple[float, float]:
Expand Down Expand Up @@ -202,7 +202,7 @@ def rand_vec_spread_deg(
angle: float,
half_angle_spread: float,
length: float
) -> Vector:
) -> tuple[float, float]:
"""
Returns a random vector, within a spread of the given angle.

Expand All @@ -220,7 +220,7 @@ def rand_vec_magnitude(
angle: float,
lo_magnitude: float,
hi_magnitude: float,
) -> Vector:
) -> tuple[float, float]:
"""
Returns a random vector, within a spread of the given angle.

Expand Down
4 changes: 2 additions & 2 deletions arcade/particles/emitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from .particle import Particle
from typing import Optional, Callable, cast
from arcade.math import _Vec2
from arcade.types import Point, Vector
from arcade.types import Point, Velocity


class EmitController:
Expand Down Expand Up @@ -110,7 +110,7 @@ def __init__(
center_xy: Point,
emit_controller: EmitController,
particle_factory: Callable[["Emitter"], Particle],
change_xy: Vector = (0.0, 0.0),
change_xy: Velocity = (0.0, 0.0),
emit_done_cb: Optional[Callable[["Emitter"], None]] = None,
reap_cb: Optional[Callable[[], None]] = None
):
Expand Down
17 changes: 8 additions & 9 deletions arcade/particles/particle.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@
Particle - Object produced by an Emitter. Often used in large quantity to produce visual effects effects
"""
from __future__ import annotations
from typing import Literal
from typing import Literal, Optional, Tuple

from arcade.sprite import Sprite
from arcade.math import lerp, clamp
from arcade.types import Point, Vector
from arcade.types import PathOrTexture
from arcade.types import Point, PathOrTexture, Velocity


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

def __init__(
self,
path_or_texture: PathOrTexture,
change_xy: Vector,
path_or_texture: Optional[PathOrTexture],
change_xy: Tuple[float, float],
center_xy: Point = (0.0, 0.0),
angle: float = 0.0,
change_angle: float = 0.0,
Expand Down Expand Up @@ -54,7 +53,7 @@ class EternalParticle(Particle):
def __init__(
self,
filename_or_texture: PathOrTexture,
change_xy: Vector,
change_xy: Velocity,
center_xy: Point = (0.0, 0.0),
angle: float = 0,
change_angle: float = 0,
Expand All @@ -75,8 +74,8 @@ class LifetimeParticle(Particle):

def __init__(
self,
filename_or_texture: PathOrTexture,
change_xy: Vector,
filename_or_texture: Optional[PathOrTexture],
change_xy: Velocity,
lifetime: float,
center_xy: Point = (0.0, 0.0),
angle: float = 0,
Expand Down Expand Up @@ -106,7 +105,7 @@ class FadeParticle(LifetimeParticle):
def __init__(
self,
filename_or_texture: PathOrTexture,
change_xy: Vector,
change_xy: Velocity,
lifetime: float,
center_xy: Point = (0.0, 0.0),
angle: float = 0,
Expand Down
2 changes: 1 addition & 1 deletion arcade/sprite/sprite.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Sprite(BasicSprite, PymunkMixin):

def __init__(
self,
path_or_texture: PathOrTexture = None,
path_or_texture: Optional[PathOrTexture] = None,
scale: float = 1.0,
center_x: float = 0.0,
center_y: float = 0.0,
Expand Down
6 changes: 3 additions & 3 deletions arcade/texture/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import arcade
import arcade.cache
from .texture import ImageData, Texture
from arcade.types import IPoint
from arcade.types import Size2D
from arcade import cache

_DEFAULT_TEXTURE = None
Expand All @@ -20,7 +20,7 @@ def cleanup_texture_cache():
arcade.cache.image_data_cache.clear()


def get_default_texture(size: IPoint = _DEFAULT_IMAGE_SIZE) -> Texture:
def get_default_texture(size: Size2D[int] = _DEFAULT_IMAGE_SIZE) -> Texture:
"""
Creates and returns a default texture and caches it internally for future use.

Expand All @@ -38,7 +38,7 @@ def get_default_texture(size: IPoint = _DEFAULT_IMAGE_SIZE) -> Texture:
return _DEFAULT_TEXTURE


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

Expand Down
169 changes: 169 additions & 0 deletions arcade/types/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
"""Fundamental aliases, classes, and related constants.

As general rules:

#. Things only go in this module if they serve multiple purposes
throughout arcade
#. Only expose the most important classes at this module's top level

For example, color-related types and related aliases go in
``arcade.types`` because they're used throughout the codebase. This
includes all the following areas:

#. :py:class:`~arcade.Sprite`
#. :py:class:`~arcade.SpriteList`
#. :py:class:`~arcade.Text`
#. The :py:mod:`arcade.gui` widgets
#. Functions in :py:mod:`arcade.drawing_commands`

However, since the color types, aliases, and constants are all related,
they go in the :py:mod:`arcade.types.color` submodule.
"""
from __future__ import annotations

# Don't lint import order since we have conditional compatibility shims
# flake8: noqa: E402
import sys
from pathlib import Path
from typing import (
List,
NamedTuple,
Optional,
Sequence,
Tuple,
Union,
TYPE_CHECKING,
TypeVar
)

from pytiled_parser import Properties


# Backward-compatibility for buffer protocol objects
# To learn more, see https://docs.python.org/3.8/c-api/buffer.html
if sys.version_info >= (3, 12):
from collections.abc import Buffer as BufferProtocol
else:
# The most common built-in buffer protocol objects
import ctypes
from array import array
from collections.abc import ByteString

# This is used instead of the typing_extensions version since they
# use an ABC which registers virtual subclasses. This will not work
# with ctypes.Array since virtual subclasses must be concrete.
# See: https://peps.python.org/pep-0688/
BufferProtocol = Union[ByteString, memoryview, array, ctypes.Array]


#: 1. Makes pyright happier while also telling readers
#: 2. Tells readers we're converting any ints to floats
AsFloat = Union[float, int]


# Generic color aliases
from arcade.types.color import RGB
from arcade.types.color import RGBA
from arcade.types.color import RGBOrA

# Specific color aliases
from arcade.types.color import RGB255
from arcade.types.color import RGBA255
from arcade.types.color import RGBNormalized
from arcade.types.color import RGBANormalized
from arcade.types.color import RGBOrA255
from arcade.types.color import RGBOrANormalized

# The Color helper type
from arcade.types.color import Color


__all__ = [
"AsFloat",
"BufferProtocol",
"Color",
"IPoint",
"PathOr",
"PathOrTexture",
"Point",
"Point3",
"PointList",
"EMPTY_POINT_LIST",
"Rect",
"RectList",
"RGB",
"RGBA",
"RGBOrA",
"RGB255",
"RGBA255",
"RGBOrA255",
"RGBNormalized",
"RGBANormalized",
"RGBOrANormalized",
"Size2D",
"TiledObject",
"Velocity"
]


_T = TypeVar('_T')

#: ``Size2D`` helps mark int or float sizes. Use it like a
#: :py:class:`typing.Generic`'s bracket notation as follows:
#:
#: .. code-block:: python
#:
#: def example_Function(size: Size2D[int], color: RGBA255) -> Texture:
#: """An example of how to use Size2D.
#:
#: Look at signature above, not the missing function body. The
#: ``size`` argument is how you can mark texture sizes, while
#: you can use ``Size2D[float]`` to denote float regions.
#:
#: :param size: A made-up hypothetical argument.
#: :param color: Hypothetical texture-related argument.
#: """
#: ... # No function definition
#:
Size2D = Tuple[_T, _T]

# Point = Union[Tuple[AsFloat, AsFloat], List[AsFloat]]
Point = Tuple[AsFloat, AsFloat]
Point3 = Tuple[AsFloat, AsFloat, AsFloat]
IPoint = Tuple[int, int]


# We won't keep this forever. It's a temp stub for particles we'll replace.
Velocity = Tuple[AsFloat, AsFloat]

PointList = Sequence[Point]
# Speed / typing workaround:
# 1. Eliminate extra allocations
# 2. Allows type annotation to be cleaner, primarily for HitBox & subclasses
EMPTY_POINT_LIST: PointList = tuple()


Rect = Union[Tuple[int, int, int, int], List[int]] # x, y, width, height
RectList = Union[Tuple[Rect, ...], List[Rect]]
FloatRect = Union[Tuple[AsFloat, AsFloat, AsFloat, AsFloat], List[AsFloat]] # x, y, width, height


# Path handling
PathLike = Union[str, Path, bytes]
_POr = TypeVar('_POr') # Allows PathOr[TypeNameHere] syntax
PathOr = Union[PathLike, _POr]


# Specific utility resource aliases with type imports
if TYPE_CHECKING:
# The linters are wrong: this is used, so we noqa it
from arcade.texture import Texture # noqa: F401

PathOrTexture = PathOr["Texture"]


class TiledObject(NamedTuple):
shape: Union[Point, PointList, Rect]
properties: Optional[Properties] = None
name: Optional[str] = None
type: Optional[str] = None
Loading
Loading