From 1ac532b3d306067df16b7aa851cd08f608c1430d Mon Sep 17 00:00:00 2001 From: Einar Forselv Date: Fri, 19 Jul 2024 01:24:53 +0200 Subject: [PATCH] Clean up old type usage (#2280) * Clean up old type usage * Stop pytest after 10 failed tests * Missing future annotation import * derp * Fix 3.9 typing * More typing fixes * missing future import * future annotations imports * physics_engines * format * Fix old Optional typing * Update old typing * More typing cleanup * More type modernization --- .github/workflows/selfhosted_runner.yml | 2 +- arcade/__init__.py | 4 +- arcade/application.py | 86 +++++++-------- arcade/cache/hit_box.py | 8 +- arcade/cache/image_data.py | 8 +- arcade/cache/texture.py | 28 ++--- arcade/camera/camera_2d.py | 33 +++--- arcade/camera/default.py | 8 +- arcade/camera/orthographic.py | 16 +-- arcade/camera/perspective.py | 16 +-- arcade/camera/static.py | 50 ++++----- arcade/context.py | 22 ++-- arcade/draw/rect.py | 9 +- arcade/easing.py | 4 +- arcade/examples/particle_fireworks.py | 5 +- arcade/examples/performance_statistics.py | 8 +- arcade/examples/pymunk_demo_top_down.py | 4 +- arcade/examples/sections_demo_1.py | 4 +- arcade/examples/sections_demo_3.py | 6 +- arcade/experimental/depth_of_field.py | 8 +- arcade/experimental/shadertoy.py | 49 ++++----- arcade/future/background/__init__.py | 12 +- arcade/future/background/background.py | 22 ++-- .../future/background/background_texture.py | 6 +- arcade/future/background/groups.py | 30 +++-- arcade/future/input/input_manager_example.py | 3 +- arcade/future/input/manager.py | 6 +- arcade/future/light/lights.py | 4 +- arcade/future/video/video_cv2.py | 5 +- arcade/future/video/video_player.py | 7 +- arcade/gl/buffer.py | 4 +- arcade/gl/compute_shader.py | 6 +- arcade/gl/context.py | 54 +++++---- arcade/gl/framebuffer.py | 20 ++-- arcade/gl/glsl.py | 8 +- arcade/gl/program.py | 16 +-- arcade/gl/texture.py | 27 +++-- arcade/gl/types.py | 12 +- arcade/gl/vertex_array.py | 28 ++--- arcade/gui/surface.py | 4 +- arcade/gui/ui_manager.py | 4 +- arcade/hitbox/pymunk.py | 8 +- arcade/particles/emitter.py | 6 +- arcade/particles/emitter_simple.py | 6 +- arcade/particles/particle.py | 6 +- arcade/paths.py | 6 +- arcade/physics_engines.py | 25 ++--- arcade/pymunk_physics_engine.py | 46 ++++---- arcade/resources/__init__.py | 16 +-- arcade/scene.py | 26 ++--- arcade/screenshot.py | 6 +- arcade/sections.py | 104 +++++++++--------- arcade/shape_list.py | 7 +- arcade/sound.py | 7 +- arcade/sprite/animated.py | 7 +- arcade/sprite/colored.py | 3 +- arcade/sprite/mixins.py | 12 +- arcade/sprite/sprite.py | 20 ++-- arcade/sprite_list/collision.py | 3 +- arcade/sprite_list/sprite_list.py | 38 +++---- arcade/text.py | 10 +- arcade/texture/generate.py | 11 +- arcade/texture/loading.py | 11 +- arcade/texture/manager.py | 27 ++--- arcade/texture/spritesheet.py | 18 +-- arcade/texture/texture.py | 30 ++--- arcade/texture_atlas/atlas_array.py | 5 +- arcade/texture_atlas/atlas_bindless.py | 2 + arcade/texture_atlas/atlas_default.py | 12 +- arcade/texture_atlas/base.py | 12 +- arcade/texture_atlas/ref_counters.py | 2 + arcade/texture_atlas/region.py | 6 +- arcade/texture_atlas/uv_data.py | 2 + arcade/tilemap/tilemap.py | 72 ++++++------ arcade/types/__init__.py | 8 +- arcade/types/color.py | 18 +-- arcade/types/rect.py | 30 ++--- arcade/utils.py | 2 +- arcade/window_commands.py | 6 +- make.py | 6 +- 80 files changed, 633 insertions(+), 665 deletions(-) diff --git a/.github/workflows/selfhosted_runner.yml b/.github/workflows/selfhosted_runner.yml index 9dd4dd5a8..1ce832d4b 100644 --- a/.github/workflows/selfhosted_runner.yml +++ b/.github/workflows/selfhosted_runner.yml @@ -45,7 +45,7 @@ jobs: which python python -c "import pyglet; print('pyglet version', pyglet.__version__)" python -c "import PIL; print('Pillow version', PIL.__version__)" - pytest --maxfail=1 + pytest --maxfail=10 # Prepare the Pull Request Payload artifact. If this fails, we # we fail silently using the `continue-on-error` option. It's diff --git a/arcade/__init__.py b/arcade/__init__.py index ad401effb..69c3211bc 100644 --- a/arcade/__init__.py +++ b/arcade/__init__.py @@ -10,7 +10,7 @@ # Error out if we import Arcade with an incompatible version of Python. import sys import os -from typing import Final, Optional +from typing import Final from pathlib import Path @@ -18,7 +18,7 @@ sys.exit("The Arcade Library requires Python 3.9 or higher.") -def configure_logging(level: Optional[int] = None): +def configure_logging(level: int | None = None): """Set up basic logging. :param level: The log level. Defaults to DEBUG. """ diff --git a/arcade/application.py b/arcade/application.py index 93f3a2e9e..8fa562593 100644 --- a/arcade/application.py +++ b/arcade/application.py @@ -8,7 +8,7 @@ import logging import os import time -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING import pyglet import pyglet.gl as gl @@ -260,13 +260,13 @@ def __init__( self._ctx: ArcadeContext = ArcadeContext(self, gc_mode=gc_mode, gl_api=gl_api) self._background_color: Color = TRANSPARENT_BLACK - self._current_view: Optional[View] = None + self._current_view: View | None = None # See if we should center the window if center_window: self.center_window() - self.keyboard: Optional[pyglet.window.key.KeyStateHandler] = None + self.keyboard: pyglet.window.key.KeyStateHandler | None = None """ A pyglet KeyStateHandler that can be used to poll the state of the keyboard. @@ -275,7 +275,7 @@ def __init__( if self.window.keyboard[key.SPACE]: print("The space key is currently being held down.") """ - self.mouse: Optional[pyglet.window.mouse.MouseStateHandler] = None + self.mouse: pyglet.window.mouse.MouseStateHandler | None = None """ A pyglet MouseStateHandler that can be used to poll the state of the mouse. @@ -306,10 +306,10 @@ def __init__( # These are typically functions just at module level wrapped in # start_render and finish_render calls. The framebuffer is repeatedly # rendered to the window when the event loop starts. - self._start_finish_render_data: Optional[StartFinishRenderData] = None + self._start_finish_render_data: StartFinishRenderData | None = None @property - def current_view(self) -> Optional["View"]: + def current_view(self) -> View | None: """ The currently active view. @@ -330,9 +330,9 @@ def ctx(self) -> ArcadeContext: def clear( self, - color: Optional[RGBOrA255] = None, - color_normalized: Optional[RGBANormalized] = None, - viewport: Optional[tuple[int, int, int, int]] = None, + color: RGBOrA255 | None = None, + color_normalized: RGBANormalized | None = None, + viewport: tuple[int, int, int, int] | None = None, ) -> None: """ Clears the window with the configured background color @@ -461,7 +461,7 @@ def center_window(self) -> None: # Center the window self.set_location((screen_width - window_width) // 2, (screen_height - window_height) // 2) - def on_update(self, delta_time: float) -> Optional[bool]: + def on_update(self, delta_time: float) -> bool | None: """ This method can be implemented and is reserved for game logic. Move sprites. Perform collision checks and other game logic. @@ -535,7 +535,7 @@ def set_draw_rate(self, rate: float) -> None: pyglet.clock.unschedule(pyglet.app.event_loop._redraw_windows) pyglet.clock.schedule_interval(pyglet.app.event_loop._redraw_windows, self._draw_rate) - def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> Optional[bool]: + def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> bool | None: """ Called repeatedly while the mouse is moving in the window area. @@ -549,7 +549,7 @@ def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> Optional[bool]: """ pass - def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> Optional[bool]: + def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> bool | None: """ Called once whenever a mouse button gets pressed down. @@ -574,7 +574,7 @@ def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> Optiona def on_mouse_drag( self, x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int - ) -> Optional[bool]: + ) -> bool | None: """ Called repeatedly while the mouse moves with a button down. @@ -591,7 +591,7 @@ def on_mouse_drag( """ return self.on_mouse_motion(x, y, dx, dy) - def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> Optional[bool]: + def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> bool | None: """ Called once whenever a mouse button gets released. @@ -613,7 +613,7 @@ def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> Optio """ return False - def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int) -> Optional[bool]: + def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int) -> bool | None: """ Called repeatedly while a mouse scroll wheel moves. @@ -689,7 +689,7 @@ def on_action(self, action_name: str, state) -> None: """ pass - def on_key_press(self, symbol: int, modifiers: int) -> Optional[bool]: + def on_key_press(self, symbol: int, modifiers: int) -> bool | None: """ Called once when a key gets pushed down. @@ -707,7 +707,7 @@ def on_key_press(self, symbol: int, modifiers: int) -> Optional[bool]: """ return False - def on_key_release(self, symbol: int, modifiers: int) -> Optional[bool]: + def on_key_release(self, symbol: int, modifiers: int) -> bool | None: """ Called once when a key gets released. @@ -729,7 +729,7 @@ def on_key_release(self, symbol: int, modifiers: int) -> Optional[bool]: """ return False - def on_draw(self) -> Optional[bool]: + def on_draw(self) -> bool | None: """ Override this function to add your custom drawing code. @@ -747,7 +747,7 @@ def on_draw(self) -> Optional[bool]: return False - def _on_resize(self, width: int, height: int) -> Optional[bool]: + def _on_resize(self, width: int, height: int) -> bool | None: """ The internal method called when the window is resized. @@ -765,7 +765,7 @@ def _on_resize(self, width: int, height: int) -> Optional[bool]: return False - def on_resize(self, width: int, height: int) -> Optional[bool]: + def on_resize(self, width: int, height: int) -> bool | None: """ Override this method to add custom actions when the window is resized. @@ -1087,7 +1087,7 @@ def dispatch_events(self) -> None: """Dispatch events""" super().dispatch_events() - def on_mouse_enter(self, x: int, y: int) -> Optional[bool]: + def on_mouse_enter(self, x: int, y: int) -> bool | None: """ Called once whenever the mouse enters the window area on screen. @@ -1100,7 +1100,7 @@ def on_mouse_enter(self, x: int, y: int) -> Optional[bool]: """ pass - def on_mouse_leave(self, x: int, y: int) -> Optional[bool]: + def on_mouse_leave(self, x: int, y: int) -> bool | None: """ Called once whenever the mouse leaves the window area on screen. @@ -1175,7 +1175,7 @@ def fixed_delta_time(self) -> float: def open_window( width: int, height: int, - window_title: Optional[str] = None, + window_title: str | None = None, resizable: bool = False, antialiasing: bool = True, ) -> Window: @@ -1214,10 +1214,10 @@ class View: the current window is used. (Normally you don't need to provide this). """ - def __init__(self, window: Optional[Window] = None) -> None: + def __init__(self, window: Window | None = None) -> None: self.window = arcade.get_window() if window is None else window - self.key: Optional[int] = None - self._section_manager: Optional[SectionManager] = None + self.key: int | None = None + self._section_manager: SectionManager | None = None @property def section_manager(self) -> SectionManager: @@ -1240,8 +1240,8 @@ def has_sections(self) -> bool: def add_section( self, section: arcade.Section, - at_index: Optional[int] = None, - at_draw_order: Optional[int] = None, + at_index: int | None = None, + at_draw_order: int | None = None, ) -> None: """ Adds a section to the view Section Manager. @@ -1257,9 +1257,9 @@ def add_section( def clear( self, - color: Optional[RGBOrA255] = None, - color_normalized: Optional[RGBANormalized] = None, - viewport: Optional[tuple[int, int, int, int]] = None, + color: RGBOrA255 | None = None, + color_normalized: RGBANormalized | None = None, + viewport: tuple[int, int, int, int] | None = None, ) -> None: """ Clears the window with the configured background color @@ -1279,7 +1279,7 @@ def clear( """ self.window.clear(color=color, color_normalized=color_normalized, viewport=viewport) - def on_update(self, delta_time: float) -> Optional[bool]: + def on_update(self, delta_time: float) -> bool | None: """ This method can be implemented and is reserved for game logic. Move sprites. Perform collision checks and other game logic. @@ -1305,7 +1305,7 @@ def on_fixed_update(self, delta_time: float): """ pass - def on_draw(self) -> Optional[bool]: + def on_draw(self) -> bool | None: """ Override this function to add your custom drawing code. @@ -1329,7 +1329,7 @@ def on_hide_view(self) -> None: """Called once when this view is hidden.""" pass - def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> Optional[bool]: + def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> bool | None: """ Called repeatedly while the mouse is moving in the window area. @@ -1343,7 +1343,7 @@ def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> Optional[bool]: """ pass - def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> Optional[bool]: + def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> bool | None: """ Called once whenever a mouse button gets pressed down. @@ -1368,7 +1368,7 @@ def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> Optiona def on_mouse_drag( self, x: int, y: int, dx: int, dy: int, _buttons: int, _modifiers: int - ) -> Optional[bool]: + ) -> bool | None: """ Called repeatedly while the mouse moves with a button down. @@ -1386,7 +1386,7 @@ def on_mouse_drag( self.on_mouse_motion(x, y, dx, dy) return False - def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> Optional[bool]: + def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> bool | None: """ Called once whenever a mouse button gets released. @@ -1408,7 +1408,7 @@ def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> Optio """ pass - def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int) -> Optional[bool]: + def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int) -> bool | None: """ Called repeatedly while a mouse scroll wheel moves. @@ -1440,7 +1440,7 @@ def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int) -> Optio """ pass - def on_key_press(self, symbol: int, modifiers: int) -> Optional[bool]: + def on_key_press(self, symbol: int, modifiers: int) -> bool | None: """ Called once when a key gets pushed down. @@ -1458,7 +1458,7 @@ def on_key_press(self, symbol: int, modifiers: int) -> Optional[bool]: """ return False - def on_key_release(self, _symbol: int, _modifiers: int) -> Optional[bool]: + def on_key_release(self, _symbol: int, _modifiers: int) -> bool | None: """ Called once when a key gets released. @@ -1480,7 +1480,7 @@ def on_key_release(self, _symbol: int, _modifiers: int) -> Optional[bool]: """ return False - def on_resize(self, width: int, height: int) -> Optional[bool]: + def on_resize(self, width: int, height: int) -> bool | None: """ Override this method to add custom actions when the window is resized. @@ -1494,7 +1494,7 @@ def on_resize(self, width: int, height: int) -> Optional[bool]: """ pass - def on_mouse_enter(self, x: int, y: int) -> Optional[bool]: + def on_mouse_enter(self, x: int, y: int) -> bool | None: """ Called once whenever the mouse enters the window area on screen. @@ -1507,7 +1507,7 @@ def on_mouse_enter(self, x: int, y: int) -> Optional[bool]: """ pass - def on_mouse_leave(self, x: int, y: int) -> Optional[bool]: + def on_mouse_leave(self, x: int, y: int) -> bool | None: """ Called once whenever the mouse leaves the window area on screen. diff --git a/arcade/cache/hit_box.py b/arcade/cache/hit_box.py index 1dea6132f..9fe4a1d74 100644 --- a/arcade/cache/hit_box.py +++ b/arcade/cache/hit_box.py @@ -15,7 +15,7 @@ import json from collections import OrderedDict from pathlib import Path -from typing import TYPE_CHECKING, Optional, Union +from typing import TYPE_CHECKING from arcade.resources import resolve from arcade.types import Point2List @@ -46,7 +46,7 @@ def __len__(self) -> int: def __iter__(self): return iter(self._entries) - def get(self, name_or_texture: Union[str, "Texture"]) -> Optional[Point2List]: + def get(self, name_or_texture: str | Texture) -> Point2List | None: """ Get the hit box points for a texture with a given hash and hit box algorithm. @@ -70,7 +70,7 @@ def get(self, name_or_texture: Union[str, "Texture"]) -> Optional[Point2List]: else: raise TypeError(f"Expected str or Texture: {name_or_texture}") - def put(self, name_or_texture: Union[str, "Texture"], points: Point2List) -> None: + def put(self, name_or_texture: str | Texture, points: Point2List) -> None: """ Store hit box points for a texture. @@ -97,7 +97,7 @@ def put(self, name_or_texture: Union[str, "Texture"], points: Point2List) -> Non else: raise TypeError(f"Expected str or Texture: {name_or_texture}") - def load(self, path: Union[str, Path]) -> None: + def load(self, path: str | Path) -> None: """ Load a json file containing hit boxes. diff --git a/arcade/cache/image_data.py b/arcade/cache/image_data.py index c9e847c7f..177ff0c74 100644 --- a/arcade/cache/image_data.py +++ b/arcade/cache/image_data.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING if TYPE_CHECKING: from arcade.texture import ImageData @@ -42,7 +42,7 @@ def put(self, name: str, image: "ImageData"): self._entries[name] = image - def get(self, name: str) -> Optional["ImageData"]: + def get(self, name: str) -> ImageData | None: """ Attempts to retrieve an entry from the cache. @@ -71,10 +71,10 @@ def flush(self): def __len__(self): return len(self._entries) - def __getitem__(self, name: str) -> Optional["ImageData"]: + def __getitem__(self, name: str) -> ImageData | None: return self.get(name) - def __setitem__(self, name: str, image: "ImageData"): + def __setitem__(self, name: str, image: ImageData): self.put(name, image) def __delitem__(self, name: str): diff --git a/arcade/cache/texture.py b/arcade/cache/texture.py index 82df93f6d..24a5b5675 100644 --- a/arcade/cache/texture.py +++ b/arcade/cache/texture.py @@ -1,7 +1,9 @@ from __future__ import annotations from pathlib import Path -from typing import TYPE_CHECKING, Optional, Union +from typing import TYPE_CHECKING + +from arcade.texture.texture import Texture if TYPE_CHECKING: from arcade import Texture @@ -14,12 +16,12 @@ class TextureBucket: """ def __init__(self): - self._entries: dict[str, "Texture"] = {} + self._entries: dict[str, Texture] = {} - def put(self, name: str, texture: "Texture") -> None: + def put(self, name: str, texture: Texture) -> None: self._entries[name] = texture - def get(self, name: str) -> Optional["Texture"]: + def get(self, name: str) -> Texture | None: return self._entries.get(name) def delete(self, name: str, raise_if_not_exist: bool = True) -> None: @@ -81,7 +83,7 @@ def put(self, texture: "Texture") -> None: if image_cache_name: self._file_entries.put(image_cache_name, texture) - def get(self, name: str) -> Optional["Texture"]: + def get(self, name: str) -> Texture | None: """ Get a texture from the cache by cache name @@ -90,9 +92,7 @@ def get(self, name: str) -> Optional["Texture"]: """ return self._entries.get(name) - def get_with_config( - self, hash: str, hit_box_algorithm: "HitBoxAlgorithm" - ) -> Optional["Texture"]: + def get_with_config(self, hash: str, hit_box_algorithm: "HitBoxAlgorithm") -> Texture | None: """ Attempts to find a texture with a specific configuration. @@ -110,9 +110,9 @@ def get_with_config( def get_texture_by_filepath( self, - file_path: Union[str, Path], + file_path: str | Path, crop: tuple[int, int, int, int] = (0, 0, 0, 0), - ) -> Optional["Texture"]: + ) -> Texture | None: """ Get a texture from the cache by file path and crop values. @@ -123,17 +123,13 @@ def get_texture_by_filepath( file_cache_name = Texture.create_image_cache_name(file_path, crop) return self._file_entries.get(file_cache_name) - def delete( - self, texture_or_name: Union["Texture", str], raise_if_not_exist: bool = False - ) -> None: + def delete(self, texture_or_name: Texture | str, raise_if_not_exist: bool = False) -> None: """ Delete a texture from the cache by cache name. :param texture_or_name: The texture or cache name to delete :param ignore_error: If True, ignore errors when deleting """ - from arcade import Texture - if isinstance(texture_or_name, Texture): texture = texture_or_name name = texture.cache_name @@ -171,7 +167,7 @@ def __iter__(self): """Iterate over all unique textures""" return iter(self.get_all_textures()) - def __getitem__(self, name: str) -> Optional["Texture"]: + def __getitem__(self, name: str) -> Texture | None: """Get a texture from the cache by cache name""" return self.get(name) diff --git a/arcade/camera/camera_2d.py b/arcade/camera/camera_2d.py index 0e174047c..7138a3686 100644 --- a/arcade/camera/camera_2d.py +++ b/arcade/camera/camera_2d.py @@ -2,7 +2,7 @@ from contextlib import contextmanager from math import atan2, cos, degrees, radians, sin -from typing import TYPE_CHECKING, Generator, Optional +from typing import TYPE_CHECKING, Generator from pyglet.math import Vec2, Vec3 from typing_extensions import Self @@ -84,21 +84,20 @@ class Camera2D: def __init__( self, - viewport: Optional[Rect] = None, - position: Optional[Point2] = None, + viewport: Rect | None = None, + position: Point2 | None = None, up: tuple[float, float] = (0.0, 1.0), zoom: float = 1.0, - projection: Optional[Rect] = None, + projection: Rect | None = None, near: float = -100.0, far: float = 100.0, *, - scissor: Optional[Rect] = None, - render_target: Optional[Framebuffer] = None, - window: Optional["Window"] = None, + scissor: Rect | None = None, + render_target: Framebuffer | None = None, + window: Window | None = None, ): - - self._window: "Window" = window or get_window() - self.render_target: Optional[Framebuffer] = render_target + self._window: Window = window or get_window() + self.render_target: Framebuffer | None = render_target # We don't want to force people to use a render target, # but we need to have some form of default size. @@ -141,18 +140,18 @@ def __init__( ) self.viewport: Rect = viewport or LRBT(0, 0, width, height) - self.scissor: Optional[Rect] = scissor + self.scissor: Rect | None = scissor @classmethod def from_camera_data( cls, *, - camera_data: Optional[CameraData] = None, - projection_data: Optional[OrthographicProjectionData] = None, - render_target: Optional[Framebuffer] = None, - viewport: Optional[Rect] = None, - scissor: Optional[Rect] = None, - window: Optional["Window"] = None, + camera_data: CameraData | None = None, + projection_data: OrthographicProjectionData | None = None, + render_target: Framebuffer | None = None, + viewport: Rect | None = None, + scissor: Rect | None = None, + window: Window | None = None, ) -> Self: """ Make a ``Camera2D`` directly from data objects. diff --git a/arcade/camera/default.py b/arcade/camera/default.py index 2169facb3..8ae15e5fc 100644 --- a/arcade/camera/default.py +++ b/arcade/camera/default.py @@ -1,7 +1,7 @@ from __future__ import annotations from contextlib import contextmanager -from typing import TYPE_CHECKING, Generator, Optional +from typing import TYPE_CHECKING, Generator from pyglet.math import Mat4, Vec2, Vec3 from typing_extensions import Self @@ -29,9 +29,9 @@ class ViewportProjector: def __init__( self, - viewport: Optional[tuple[int, int, int, int]] = None, + viewport: tuple[int, int, int, int] | None = None, *, - context: Optional["ArcadeContext"] = None, + context: ArcadeContext | None = None, ): self._ctx = context or get_window().ctx self._viewport = viewport or self._ctx.viewport @@ -110,7 +110,7 @@ class DefaultProjector(ViewportProjector): :param window: The window to bind the camera to. Defaults to the currently active window. """ - def __init__(self, *, context: Optional["ArcadeContext"] = None): + def __init__(self, *, context: ArcadeContext | None = None): super().__init__(context=context) def use(self) -> None: diff --git a/arcade/camera/orthographic.py b/arcade/camera/orthographic.py index e30317f78..3ebc3039e 100644 --- a/arcade/camera/orthographic.py +++ b/arcade/camera/orthographic.py @@ -1,7 +1,7 @@ from __future__ import annotations from contextlib import contextmanager -from typing import TYPE_CHECKING, Generator, Optional +from typing import TYPE_CHECKING, Generator from pyglet.math import Mat4, Vec2, Vec3 from typing_extensions import Self @@ -51,16 +51,16 @@ class OrthographicProjector(Projector): def __init__( self, *, - window: Optional["Window"] = None, - view: Optional[CameraData] = None, - projection: Optional[OrthographicProjectionData] = None, - viewport: Optional[Rect] = None, - scissor: Optional[Rect] = None, + window: Window | None = None, + view: CameraData | None = None, + projection: OrthographicProjectionData | None = None, + viewport: Rect | None = None, + scissor: Rect | None = None, ): - self._window: "Window" = window or get_window() + self._window: Window = window or get_window() self.viewport: Rect = viewport or LBWH(0, 0, self._window.width, self._window.height) - self.scissor: Optional[Rect] = scissor + self.scissor: Rect | None = scissor self._view = view or CameraData( # Viewport (self._window.width / 2, self._window.height / 2, 0), # Position diff --git a/arcade/camera/perspective.py b/arcade/camera/perspective.py index c33449b49..9c24a99aa 100644 --- a/arcade/camera/perspective.py +++ b/arcade/camera/perspective.py @@ -2,7 +2,7 @@ from contextlib import contextmanager from math import radians, tan -from typing import TYPE_CHECKING, Generator, Optional +from typing import TYPE_CHECKING, Generator from pyglet.math import Mat4, Vec2, Vec3 from typing_extensions import Self @@ -52,16 +52,16 @@ class PerspectiveProjector(Projector): def __init__( self, *, - window: Optional["Window"] = None, - view: Optional[CameraData] = None, - projection: Optional[PerspectiveProjectionData] = None, - viewport: Optional[Rect] = None, - scissor: Optional[Rect] = None, + window: Window | None = None, + view: CameraData | None = None, + projection: PerspectiveProjectionData | None = None, + viewport: Rect | None = None, + scissor: Rect | None = None, ): - self._window: "Window" = window or get_window() + self._window: Window = window or get_window() self.viewport: Rect = viewport or LBWH(0, 0, self._window.width, self._window.height) - self.scissor: Optional[Rect] = scissor + self.scissor: Rect | None = scissor self._view = view or CameraData( # Viewport (self._window.width / 2, self._window.height / 2, 0), # Position diff --git a/arcade/camera/static.py b/arcade/camera/static.py index 53fd9cd97..ae1356d0f 100644 --- a/arcade/camera/static.py +++ b/arcade/camera/static.py @@ -1,7 +1,7 @@ from __future__ import annotations from contextlib import contextmanager -from typing import TYPE_CHECKING, Callable, Generator, Optional +from typing import TYPE_CHECKING, Callable, Generator from pyglet.math import Mat4, Vec2, Vec3 @@ -32,25 +32,23 @@ def __init__( self, view_matrix: Mat4, projection_matrix: Mat4, - viewport: Optional[tuple[int, int, int, int]] = None, + viewport: tuple[int, int, int, int] | None = None, *, - project_method: Optional[ - Callable[[Point, tuple[int, int, int, int], Mat4, Mat4], Vec2] - ] = None, - unproject_method: Optional[ - Callable[[Point, tuple[int, int, int, int], Mat4, Mat4], Vec3] - ] = None, - window: Optional[Window] = None, + project_method: ( + Callable[[Point, tuple[int, int, int, int], Mat4, Mat4], Vec2] | None + ) = None, + unproject_method: ( + Callable[[Point, tuple[int, int, int, int], Mat4, Mat4], Vec3] | None + ) = None, + window: Window | None = None, ): self._win: Window = window or get_window() self._viewport: tuple[int, int, int, int] = viewport or self._win.ctx.viewport self._view = view_matrix self._projection = projection_matrix - self._project_method: Optional[Callable[[Point, tuple, Mat4, Mat4], Vec2]] = project_method - self._unproject_method: Optional[Callable[[Point, tuple, Mat4, Mat4], Vec3]] = ( - unproject_method - ) + self._project_method: Callable[[Point, tuple, Mat4, Mat4], Vec2] | None = project_method + self._unproject_method: Callable[[Point, tuple, Mat4, Mat4], Vec3] | None = unproject_method def use(self): self._win.current_camera = self @@ -103,9 +101,9 @@ def unproject(self, screen_coordinate: Point) -> Vec3: def static_from_orthographic( view: CameraData, orthographic: OrthographicProjectionData, - viewport: Optional[tuple[int, int, int, int]] = None, + viewport: tuple[int, int, int, int] | None = None, *, - window: Optional[Window] = None, + window: Window | None = None, ) -> _StaticCamera: return _StaticCamera( generate_view_matrix(view), @@ -120,9 +118,9 @@ def static_from_orthographic( def static_from_perspective( view: CameraData, perspective: OrthographicProjectionData, - viewport: Optional[tuple[int, int, int, int]] = None, + viewport: tuple[int, int, int, int] | None = None, *, - window: Optional[Window] = None, + window: Window | None = None, ) -> _StaticCamera: return _StaticCamera( generate_view_matrix(view), @@ -142,9 +140,9 @@ def static_from_raw_orthographic( position: Point3 = (0.0, 0.0, 0.0), up: Point3 = (0.0, 1.0, 0.0), forward: Point3 = (0.0, 0.0, -1.0), - viewport: Optional[tuple[int, int, int, int]] = None, + viewport: tuple[int, int, int, int] | None = None, *, - window: Optional[Window] = None, + window: Window | None = None, ) -> _StaticCamera: view = generate_view_matrix(CameraData(position, up, forward, zoom)) proj = generate_orthographic_matrix( @@ -172,9 +170,9 @@ def static_from_raw_perspective( position: Point3 = (0.0, 0.0, 0.0), up: Point3 = (0.0, 1.0, 0.0), forward: Point3 = (0.0, 0.0, -1.0), - viewport: Optional[tuple[int, int, int, int]] = None, + viewport: tuple[int, int, int, int] | None = None, *, - window: Optional[Window] = None, + window: Window | None = None, ) -> _StaticCamera: view = generate_view_matrix(CameraData(position, up, forward, zoom)) proj = generate_perspective_matrix(PerspectiveProjectionData(aspect, fov, near, far), zoom) @@ -192,13 +190,11 @@ def static_from_raw_perspective( def static_from_matrices( view: Mat4, projection: Mat4, - viewport: Optional[tuple[int, int, int, int]], + viewport: tuple[int, int, int, int] | None, *, - window: Optional[Window] = None, - project_method: Optional[Callable[[Point, tuple[int, int, int, int], Mat4, Mat4], Vec2]] = None, - unproject_method: Optional[ - Callable[[Point, tuple[int, int, int, int], Mat4, Mat4], Vec3] - ] = None, + window: Window | None = None, + project_method: Callable[[Point, tuple[int, int, int, int], Mat4, Mat4], Vec2] | None = None, + unproject_method: Callable[[Point, tuple[int, int, int, int], Mat4, Mat4], Vec3] | None = None, ) -> _StaticCamera: return _StaticCamera( view, diff --git a/arcade/context.py b/arcade/context.py index dbb8e8395..af446650f 100644 --- a/arcade/context.py +++ b/arcade/context.py @@ -6,7 +6,7 @@ from __future__ import annotations from pathlib import Path -from typing import Any, Iterable, Optional, Sequence, Union +from typing import Any, Iterable, Sequence import pyglet from PIL import Image @@ -198,7 +198,7 @@ def __init__( ) self.geometry_empty: Geometry = self.geometry() - self._atlas: Optional[TextureAtlasBase] = None + self._atlas: TextureAtlasBase | None = None # Global labels we modify in `arcade.draw_text`. # These multiple labels with different configurations are stored self.label_cache: dict[str, arcade.Text] = {} @@ -326,14 +326,14 @@ def view_matrix(self, value: Mat4): def load_program( self, *, - vertex_shader: Union[str, Path], - fragment_shader: Optional[Union[str, Path]] = None, - geometry_shader: Optional[Union[str, Path]] = None, - tess_control_shader: Optional[Union[str, Path]] = None, - tess_evaluation_shader: Optional[Union[str, Path]] = None, - common: Iterable[Union[str, Path]] = (), - defines: Optional[dict[str, Any]] = None, - varyings: Optional[Sequence[str]] = None, + vertex_shader: str | Path, + fragment_shader: str | Path | None = None, + geometry_shader: str | Path | None = None, + tess_control_shader: str | Path | None = None, + tess_evaluation_shader: str | Path | None = None, + common: Iterable[str | Path] = (), + defines: dict[str, Any] | None = None, + varyings: Sequence[str] | None = None, varyings_capture_mode: str = "interleaved", ) -> Program: """ @@ -434,7 +434,7 @@ def load_compute_shader( def load_texture( self, - path: Union[str, Path], + path: str | Path, *, flip: bool = True, build_mipmaps: bool = False, diff --git a/arcade/draw/rect.py b/arcade/draw/rect.py index 34c069270..fa4367a68 100644 --- a/arcade/draw/rect.py +++ b/arcade/draw/rect.py @@ -1,5 +1,6 @@ +from __future__ import annotations + import array -from typing import Optional from arcade import gl from arcade.color import WHITE @@ -22,7 +23,7 @@ def draw_texture_rect( blend=True, alpha=255, pixelated=False, - atlas: Optional[TextureAtlasBase] = None, + atlas: TextureAtlasBase | None = None, ) -> None: """ Draw a texture on a rectangle. @@ -78,7 +79,7 @@ def draw_sprite( blend: bool = True, alpha=255, pixelated=False, - atlas: Optional[TextureAtlasBase] = None, + atlas: TextureAtlasBase | None = None, ) -> None: """ Draw a sprite. @@ -109,7 +110,7 @@ def draw_sprite_rect( blend: bool = True, alpha=255, pixelated=False, - atlas: Optional[TextureAtlasBase] = None, + atlas: TextureAtlasBase | None = None, ) -> None: """Draw a sprite. diff --git a/arcade/easing.py b/arcade/easing.py index 34e8e92f8..3d69dee3b 100644 --- a/arcade/easing.py +++ b/arcade/easing.py @@ -6,7 +6,7 @@ from dataclasses import dataclass from math import cos, pi, sin -from typing import Callable, Optional +from typing import Callable from .math import get_distance @@ -158,7 +158,7 @@ def ease_angle( time=None, rate=None, ease_function: Callable = linear, -) -> Optional[EasingData]: +) -> EasingData | None: """ Set up easing for angles. """ diff --git a/arcade/examples/particle_fireworks.py b/arcade/examples/particle_fireworks.py index 4ef7c93e8..f0bd5758a 100644 --- a/arcade/examples/particle_fireworks.py +++ b/arcade/examples/particle_fireworks.py @@ -6,9 +6,8 @@ If Python and Arcade are installed, this example can be run from the command line with: python -m arcade.examples.particle_fireworks """ - +from __future__ import annotations import random -from typing import Optional import pyglet from pyglet.math import Vec2 @@ -129,7 +128,7 @@ class AnimatedAlphaParticle(LifetimeParticle): def __init__( self, - filename_or_texture: Optional[PathOrTexture], + filename_or_texture: PathOrTexture | None, change_xy: Vec2, start_alpha: int = 0, duration1: float = 1.0, diff --git a/arcade/examples/performance_statistics.py b/arcade/examples/performance_statistics.py index b314312dd..6d4cdbc0a 100644 --- a/arcade/examples/performance_statistics.py +++ b/arcade/examples/performance_statistics.py @@ -19,8 +19,8 @@ command line with: python -m arcade.examples.performance_statistics """ +from __future__ import annotations import random -from typing import Optional import arcade @@ -81,9 +81,9 @@ def __init__(self): super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) # Variables to hold game objects and performance info - self.coin_list: Optional[arcade.SpriteList] = None - self.perf_graph_list: Optional[arcade.SpriteList] = None - self.fps_text: Optional[arcade.Text] = None + self.coin_list: arcade.SpriteList | None = None + self.perf_graph_list: arcade.SpriteList | None = None + self.fps_text: arcade.Text | None = None self.frame_count: int = 0 # for tracking the reset interval self.coin_texture = arcade.load_texture(":resources:images/items/coinGold.png") diff --git a/arcade/examples/pymunk_demo_top_down.py b/arcade/examples/pymunk_demo_top_down.py index 968490460..f0db35eac 100644 --- a/arcade/examples/pymunk_demo_top_down.py +++ b/arcade/examples/pymunk_demo_top_down.py @@ -5,10 +5,10 @@ If Python and Arcade are installed, this example can be run from the command line with: python -m arcade.examples.pymunk_demo_top_down """ +from __future__ import annotations import math import random import arcade -from typing import Optional from arcade.pymunk_physics_engine import PymunkPhysicsEngine SCREEN_TITLE = "PyMunk Top-Down" @@ -40,7 +40,7 @@ def __init__(self, width, height, title): self.rock_list = None self.gem_list = None self.player_sprite = None - self.physics_engine: Optional[PymunkPhysicsEngine] = None + self.physics_engine: PymunkPhysicsEngine | None = None # Track the current state of what key is pressed self.left_pressed = False diff --git a/arcade/examples/sections_demo_1.py b/arcade/examples/sections_demo_1.py index 5c782f6f3..202e92b9c 100644 --- a/arcade/examples/sections_demo_1.py +++ b/arcade/examples/sections_demo_1.py @@ -15,7 +15,7 @@ If Python and Arcade are installed, this example can be run from the command line with: python -m arcade.examples.sections_demo_1 """ -from typing import Optional +from __future__ import annotations import arcade @@ -59,7 +59,7 @@ def __init__(self, left: int, bottom: int, width: int, height: int, self.box.position = self.left + (self.width / 2), 50 # variable that will hold the Box when it's being dragged - self.hold_box: Optional[Box] = None + self.hold_box: Box | None = None def on_update(self, delta_time: float): # call on_update on the owned Box diff --git a/arcade/examples/sections_demo_3.py b/arcade/examples/sections_demo_3.py index ab2e4e42c..e25c47655 100644 --- a/arcade/examples/sections_demo_3.py +++ b/arcade/examples/sections_demo_3.py @@ -21,7 +21,7 @@ If Python and Arcade are installed, this example can be run from the command line with: python -m arcade.examples.sections_demo_3 """ -from typing import Optional +from __future__ import annotations from math import sqrt import arcade @@ -136,7 +136,7 @@ def __init__(self, left: int, bottom: int, width: int, height: int, self.button_show_modal = self.new_button(COLOR_2) # to show the key that's actually pressed - self.pressed_key: Optional[int] = None + self.pressed_key: int | None = None @staticmethod def new_button(color): @@ -211,7 +211,7 @@ def __init__(self, left: int, bottom: int, width: int, height: int, self.sprite_list: arcade.SpriteList = arcade.SpriteList() self.sprite_list.append(self.ball) - self.pressed_key: Optional[int] = None + self.pressed_key: int | None = None def on_update(self, delta_time: float): diff --git a/arcade/experimental/depth_of_field.py b/arcade/experimental/depth_of_field.py index 78a61f708..1fb23a8e2 100644 --- a/arcade/experimental/depth_of_field.py +++ b/arcade/experimental/depth_of_field.py @@ -11,7 +11,7 @@ 1. Render a depth value for pixel into a buffer 2. Render a gaussian blurred version of the scene 3. For each pixel, use the current depth value to lerp between the - blurred and unblurred versions of the scene. + blurred and un-blurred versions of the scene. This is more expensive than rendering the scene directly, but it's both easier and more performant than more accurate blur approaches. @@ -26,7 +26,7 @@ from math import cos, pi from random import randint, uniform from textwrap import dedent -from typing import Optional, cast +from typing import cast from pyglet.graphics import Batch @@ -46,7 +46,7 @@ class DepthOfField: def __init__( self, - size: Optional[tuple[int, int]] = None, + size: tuple[int, int] | None = None, clear_color: RGBA255 = (155, 155, 155, 255), ): self._geo = geometry.quad_2d_fs() @@ -86,7 +86,7 @@ def __init__( ) ] ) - self._blurred: Optional[Texture2D] = None + self._blurred: Texture2D | None = None # To keep this example in one file, we use strings for our # our shaders. You may want to use pathlib.Path.read_text in diff --git a/arcade/experimental/shadertoy.py b/arcade/experimental/shadertoy.py index 2f2218c5e..1a1f2b9fa 100644 --- a/arcade/experimental/shadertoy.py +++ b/arcade/experimental/shadertoy.py @@ -20,7 +20,6 @@ import string from datetime import datetime from pathlib import Path -from typing import Optional, Union import arcade from arcade import get_window @@ -70,10 +69,10 @@ def __init__(self, size: tuple[int, int], source: str): self._channel_time = [0.0, 0.0, 0.0, 0.0] self._channel_resolution = [0] * 3 * 4 # Shader inputs - self._channel_0: Optional[Texture2D] = None - self._channel_1: Optional[Texture2D] = None - self._channel_2: Optional[Texture2D] = None - self._channel_3: Optional[Texture2D] = None + self._channel_0: Texture2D | None = None + self._channel_1: Texture2D | None = None + self._channel_2: Texture2D | None = None + self._channel_3: Texture2D | None = None self._set_source(source) self._quad = geometry.quad_2d_fs() @@ -191,7 +190,7 @@ def channel_time(self) -> list[float]: return self._channel_time @property - def channel_0(self) -> Optional[Texture2D]: + def channel_0(self) -> Texture2D | None: """Get or set channel 0""" return self._channel_0 @@ -203,7 +202,7 @@ def channel_0(self, value: Texture2D): self._channel_0 = value @property - def channel_1(self) -> Optional[Texture2D]: + def channel_1(self) -> Texture2D | None: """Get or set channel 1""" return self._channel_1 @@ -215,7 +214,7 @@ def channel_1(self, value: Texture2D): self._channel_1 = value @property - def channel_2(self) -> Optional[Texture2D]: + def channel_2(self) -> Texture2D | None: """Get or set channel 2""" return self._channel_2 @@ -227,7 +226,7 @@ def channel_2(self, value: Texture2D): self._channel_2 = value @property - def channel_3(self) -> Optional[Texture2D]: + def channel_3(self) -> Texture2D | None: """Get or set channel 3""" return self._channel_3 @@ -255,12 +254,12 @@ def resize(self, size: tuple[int, int]) -> None: def render( self, *, - time: Optional[float] = None, - time_delta: Optional[float] = None, - mouse_position: Optional[tuple[float, float]] = None, - size: Optional[tuple[int, int]] = None, - frame: Optional[int] = None, - frame_rate: Optional[float] = None, + time: float | None = None, + time_delta: float | None = None, + mouse_position: tuple[float, float] | None = None, + size: tuple[int, int] | None = None, + frame: int | None = None, + frame_rate: float | None = None, ): """ Render the shadertoy project to the screen. @@ -438,13 +437,13 @@ def __init__(self, size: tuple[int, int], main_source: str): """ super().__init__(size, main_source) - self._buffer_a: Optional[ShadertoyBuffer] = None - self._buffer_b: Optional[ShadertoyBuffer] = None - self._buffer_c: Optional[ShadertoyBuffer] = None - self._buffer_d: Optional[ShadertoyBuffer] = None + self._buffer_a: ShadertoyBuffer | None = None + self._buffer_b: ShadertoyBuffer | None = None + self._buffer_c: ShadertoyBuffer | None = None + self._buffer_d: ShadertoyBuffer | None = None @property - def buffer_a(self) -> Optional[ShadertoyBuffer]: + def buffer_a(self) -> ShadertoyBuffer | None: """Get or set buffer a""" return self._buffer_a @@ -453,7 +452,7 @@ def buffer_a(self, value): self._buffer_a = value @property - def buffer_b(self) -> Optional[ShadertoyBuffer]: + def buffer_b(self) -> ShadertoyBuffer | None: """Get or set buffer b""" return self._buffer_b @@ -462,7 +461,7 @@ def buffer_b(self, value): self._buffer_b = value @property - def buffer_c(self) -> Optional[ShadertoyBuffer]: + def buffer_c(self) -> ShadertoyBuffer | None: """Get or set buffer c""" return self._buffer_c @@ -471,7 +470,7 @@ def buffer_c(self, value): self._buffer_c = value @property - def buffer_d(self) -> Optional[ShadertoyBuffer]: + def buffer_d(self) -> ShadertoyBuffer | None: """Get or set buffer d""" return self._buffer_d @@ -480,7 +479,7 @@ def buffer_d(self, value): self._buffer_d = value @classmethod - def create_from_file(cls, size: tuple[int, int], path: Union[str, Path]) -> "Shadertoy": + def create_from_file(cls, size: tuple[int, int], path: str | Path) -> "Shadertoy": """ Create a Shadertoy from a mainImage shader file. @@ -501,7 +500,7 @@ def create_buffer(self, source: str, repeat: bool = False) -> ShadertoyBuffer: """ return ShadertoyBuffer(self._size, source, repeat=repeat) - def create_buffer_from_file(self, path: Union[str, Path]) -> ShadertoyBuffer: + def create_buffer_from_file(self, path: str | Path) -> ShadertoyBuffer: """ Shortcut for creating a ShadertoyBuffer from shaders source. The size of the framebuffer will be the same as the Shadertoy. diff --git a/arcade/future/background/__init__.py b/arcade/future/background/__init__.py index a0d90d4d7..5951c1a59 100644 --- a/arcade/future/background/__init__.py +++ b/arcade/future/background/__init__.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Optional, Tuple +from typing import Tuple from PIL import Image @@ -44,16 +44,16 @@ def texture_from_file( def background_from_file( tex_src: str, pos: Tuple[float, float] = (0.0, 0.0), - size: Optional[Tuple[int, int]] = None, + size: Tuple[int, int] | None = None, offset: Tuple[float, float] = (0.0, 0.0), scale: float = 1.0, angle: float = 0.0, *, filters=(gl.NEAREST, gl.NEAREST), - color: Optional[Tuple[int, int, int]] = None, - color_norm: Optional[Tuple[float, float, float]] = None, - shader: Optional[gl.Program] = None, - geometry: Optional[gl.Geometry] = None, + color: Tuple[int, int, int] | None = None, + color_norm: Tuple[float, float, float] | None = None, + shader: gl.Program | None = None, + geometry: gl.Geometry | None = None, ) -> Background: texture = BackgroundTexture.from_file(tex_src, offset, scale, angle, filters) diff --git a/arcade/future/background/background.py b/arcade/future/background/background.py index 206d25c94..1d3c46cc4 100644 --- a/arcade/future/background/background.py +++ b/arcade/future/background/background.py @@ -1,7 +1,5 @@ from __future__ import annotations -from typing import Optional, Union - import arcade.gl as gl from arcade.future.background import BackgroundTexture from arcade.window_commands import get_window @@ -24,9 +22,9 @@ def __init__( texture: BackgroundTexture, pos: tuple[float, float], size: tuple[int, int], - color: Union[tuple[float, float, float], tuple[int, int, int]], - shader: Optional[gl.Program] = None, - geometry: Optional[gl.Geometry] = None, + color: tuple[float, float, float] | tuple[int, int, int], + shader: gl.Program | None = None, + geometry: gl.Geometry | None = None, ): self._ctx = get_window().ctx if shader is None: @@ -84,16 +82,16 @@ def __init__( def from_file( tex_src: str, pos: tuple[float, float] = (0.0, 0.0), - size: Optional[tuple[int, int]] = None, + size: tuple[int, int] | None = None, offset: tuple[float, float] = (0.0, 0.0), scale: float = 1.0, angle: float = 0.0, *, filters=(gl.NEAREST, gl.NEAREST), - color: Optional[tuple[int, int, int]] = None, - color_norm: Optional[tuple[float, float, float]] = None, - shader: Optional[gl.Program] = None, - geometry: Optional[gl.Geometry] = None, + color: tuple[int, int, int] | None = None, + color_norm: tuple[float, float, float] | None = None, + shader: gl.Program | None = None, + geometry: gl.Geometry | None = None, ): """ This will generate a Background from an input image source. @@ -106,8 +104,8 @@ def from_file( :param scale: The BackgroundTexture Scale. :param angle: The BackgroundTexture angle. :param filters: The OpenGl Texture filters (gl.Nearest by default). - :param color: This is a color defined from 0-255. Prioritises color_norm - :param color_norm: This is a color defined from 0.0-1.0. Prioritises color_norm + :param color: This is a color defined from 0-255. Priorities color_norm + :param color_norm: This is a color defined from 0.0-1.0. Priorities color_norm assumed to be in the range 0.0-1.0. :param shader: The shader used for rendering. :param geometry: The geometry used for rendering (a rectangle equal to the size by default). diff --git a/arcade/future/background/background_texture.py b/arcade/future/background/background_texture.py index 4e91322f0..369e98ba3 100644 --- a/arcade/future/background/background_texture.py +++ b/arcade/future/background/background_texture.py @@ -1,7 +1,5 @@ from __future__ import annotations -from typing import Optional - from PIL import Image from pyglet.math import Mat3 @@ -133,8 +131,8 @@ def use(self, unit: int = 0) -> None: def render_target( self, context: ArcadeContext, - color_attachments: Optional[list[gl.Texture2D]] = None, - depth_attachment: Optional[gl.Texture2D] = None, + color_attachments: list[gl.Texture2D] | None = None, + depth_attachment: gl.Texture2D | None = None, ) -> gl.Framebuffer: if color_attachments is None: color_attachments = [] diff --git a/arcade/future/background/groups.py b/arcade/future/background/groups.py index e29b6d263..b6ee80163 100644 --- a/arcade/future/background/groups.py +++ b/arcade/future/background/groups.py @@ -1,7 +1,5 @@ from __future__ import annotations -from typing import Optional, Union - import arcade.gl as gl from arcade.future.background import Background @@ -14,7 +12,7 @@ class BackgroundGroup: The offset of the BackgroundGroup is the same as each background. """ - def __init__(self, backgrounds: Optional[list[Background]] = None): + def __init__(self, backgrounds: list[Background] | None = None): self._backgrounds: list[Background] = [] if backgrounds is None else backgrounds self._pos = (0.0, 0.0) @@ -66,16 +64,16 @@ def add_from_file( self, tex_src: str, pos: tuple[float, float] = (0.0, 0.0), - size: Optional[tuple[int, int]] = None, + size: tuple[int, int] | None = None, offset: tuple[float, float] = (0.0, 0.0), scale: float = 1.0, angle: float = 0.0, *, filters=(gl.NEAREST, gl.NEAREST), - color: Optional[tuple[int, int, int]] = None, - color_norm: Optional[tuple[float, float, float]] = None, - shader: Optional[gl.Program] = None, - geometry: Optional[gl.Geometry] = None, + color: tuple[int, int, int] | None = None, + color_norm: tuple[float, float, float] | None = None, + shader: gl.Program | None = None, + geometry: gl.Geometry | None = None, ): background = Background.from_file( tex_src, @@ -104,8 +102,8 @@ class ParallaxGroup: def __init__( self, - backgrounds: Optional[list[Background]] = None, - depths: Optional[list[float]] = None, + backgrounds: list[Background] | None = None, + depths: list[float] | None = None, ): self._backgrounds: list[Background] = [] if backgrounds is None else backgrounds self._depths: list[float] = [] if depths is None else depths @@ -138,7 +136,7 @@ def offset(self, value: tuple[float, float]): def __getitem__(self, item: int): return self._backgrounds[item], self._depths[item] - def __setitem__(self, key: int, value: Union[Background, float]): + def __setitem__(self, key: int, value: Background | float): if isinstance(value, (float, int)): self._depths[key] = value else: @@ -171,17 +169,17 @@ def add_from_file( self, tex_src: str, pos: tuple[float, float] = (0.0, 0.0), - size: Optional[tuple[int, int]] = None, + size: tuple[int, int] | None = None, depth: float = 1, offset: tuple[float, float] = (0.0, 0.0), scale: float = 1.0, angle: float = 0.0, *, filters=(gl.NEAREST, gl.NEAREST), - color: Optional[tuple[int, int, int]] = None, - color_norm: Optional[tuple[float, float, float]] = None, - shader: Optional[gl.Program] = None, - geometry: Optional[gl.Geometry] = None, + color: tuple[int, int, int] | None = None, + color_norm: tuple[float, float, float] | None = None, + shader: gl.Program | None = None, + geometry: gl.Geometry | None = None, ): background = Background.from_file( tex_src, diff --git a/arcade/future/input/input_manager_example.py b/arcade/future/input/input_manager_example.py index 32e7f24fe..15ae07289 100644 --- a/arcade/future/input/input_manager_example.py +++ b/arcade/future/input/input_manager_example.py @@ -2,7 +2,6 @@ from __future__ import annotations import random -from typing import Optional import pyglet @@ -19,7 +18,7 @@ def __init__( self, walls: arcade.SpriteList, input_manager_template: InputManager, - controller: Optional[pyglet.input.Controller] = None, + controller: pyglet.input.Controller | None = None, ): super().__init__( ":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png" diff --git a/arcade/future/input/manager.py b/arcade/future/input/manager.py index 0e325f822..225ff5f6b 100644 --- a/arcade/future/input/manager.py +++ b/arcade/future/input/manager.py @@ -2,7 +2,7 @@ from __future__ import annotations from enum import Enum -from typing import Any, Callable, Optional, Union +from typing import Any, Callable, Union import pyglet from pyglet.input.base import Controller @@ -49,7 +49,7 @@ class InputManager: def __init__( self, - controller: Optional[Controller] = None, + controller: Controller | None = None, allow_keyboard: bool = True, action_handlers: Union[ Callable[[str, ActionState], Any], list[Callable[[str, ActionState], Any]] @@ -162,7 +162,7 @@ def copy_existing(self, existing: InputManager): def from_existing( cls, existing: InputManager, - controller: Optional[pyglet.input.Controller] = None, + controller: pyglet.input.Controller | None = None, ) -> InputManager: new = cls( allow_keyboard=existing.allow_keyboard, diff --git a/arcade/future/light/lights.py b/arcade/future/light/lights.py index 9ccfbba66..d09cd687c 100644 --- a/arcade/future/light/lights.py +++ b/arcade/future/light/lights.py @@ -1,7 +1,7 @@ from __future__ import annotations from array import array -from typing import Iterator, Optional, Sequence +from typing import Iterator, Sequence from arcade import gl from arcade.color import WHITE @@ -48,7 +48,7 @@ def __init__( self._radius = radius self._attenuation = Light.HARD if mode == "hard" else Light.SOFT self._color = color[:3] - self._light_layer: Optional[LightLayer] = None + self._light_layer: LightLayer | None = None if len(self._color) != 3: raise ValueError( diff --git a/arcade/future/video/video_cv2.py b/arcade/future/video/video_cv2.py index ef8447049..1fe142da7 100644 --- a/arcade/future/video/video_cv2.py +++ b/arcade/future/video/video_cv2.py @@ -13,7 +13,6 @@ from math import floor from pathlib import Path -from typing import Union import cv2 # type: ignore @@ -29,7 +28,7 @@ class VideoPlayerCV2: :param path: Path of the video that is to be played. """ - def __init__(self, path: Union[str, Path], loop: bool = False): + def __init__(self, path: str | Path, loop: bool = False): self.loop = loop self.ctx = arcade.get_window().ctx @@ -134,7 +133,7 @@ class CV2PlayerView(arcade.View): :param resize: Change the window size to the video size """ - def __init__(self, path: Union[str, Path], loop: bool = False, resize: bool = False): + def __init__(self, path: str | Path, loop: bool = False, resize: bool = False): super().__init__() self.video_player = VideoPlayerCV2(path, loop) diff --git a/arcade/future/video/video_player.py b/arcade/future/video/video_player.py index 895004d27..021294ed4 100644 --- a/arcade/future/video/video_player.py +++ b/arcade/future/video/video_player.py @@ -8,7 +8,6 @@ from __future__ import annotations from pathlib import Path -from typing import Optional, Union # import sys import pyglet @@ -24,7 +23,7 @@ class VideoPlayer: :param loop: Pass `True` to make the video loop. """ - def __init__(self, path: Union[str, Path], loop: bool = False): + def __init__(self, path: str | Path, loop: bool = False): self.player = pyglet.media.Player() self.player.loop = loop self.player.queue(pyglet.media.load(str(arcade.resources.resolve(path)))) @@ -35,7 +34,7 @@ def __init__(self, path: Union[str, Path], loop: bool = False): self._width = arcade.get_window().width self._height = arcade.get_window().height - def draw(self, left: int = 0, bottom: int = 0, size: Optional[tuple[int, int]] = None) -> None: + def draw(self, left: int = 0, bottom: int = 0, size: tuple[int, int] | None = None) -> None: """ Call this in `on_draw`. @@ -80,7 +79,7 @@ def get_video_size(self) -> tuple[int, int]: class VideoPlayerView(arcade.View): - def __init__(self, path: Union[str, Path]) -> None: + def __init__(self, path: str | Path) -> None: super().__init__() self.video_player = VideoPlayer(path) diff --git a/arcade/gl/buffer.py b/arcade/gl/buffer.py index b5a90b4eb..9bf823cdb 100644 --- a/arcade/gl/buffer.py +++ b/arcade/gl/buffer.py @@ -2,7 +2,7 @@ import weakref from ctypes import byref, string_at -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING from pyglet import gl @@ -48,7 +48,7 @@ class Buffer: def __init__( self, ctx: "Context", - data: Optional[BufferProtocol] = None, + data: BufferProtocol | None = None, reserve: int = 0, usage: str = "static", ): diff --git a/arcade/gl/compute_shader.py b/arcade/gl/compute_shader.py index 9af88d9de..d67ead9b4 100644 --- a/arcade/gl/compute_shader.py +++ b/arcade/gl/compute_shader.py @@ -12,7 +12,7 @@ create_string_buffer, pointer, ) -from typing import TYPE_CHECKING, Union +from typing import TYPE_CHECKING from pyglet import gl @@ -30,7 +30,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, UniformBlock | Uniform] = dict() from arcade.gl import ShaderException @@ -135,7 +135,7 @@ def run(self, group_x=1, group_y=1, group_z=1) -> None: self.use() gl.glDispatchCompute(group_x, group_y, group_z) - def __getitem__(self, item) -> Union[Uniform, UniformBlock]: + def __getitem__(self, item) -> Uniform | UniformBlock: """Get a uniform or uniform block""" try: uniform = self._uniforms[item] diff --git a/arcade/gl/context.py b/arcade/gl/context.py index b540937c4..26a721565 100644 --- a/arcade/gl/context.py +++ b/arcade/gl/context.py @@ -12,11 +12,9 @@ Iterable, List, Literal, - Optional, Sequence, Set, Tuple, - Union, overload, ) @@ -55,7 +53,7 @@ class Context: """ #: The active context - active: Optional["Context"] = None + active: Context | None = None #: The OpenGL api. Usually "gl" or "gles". gl_api: str = "gl" @@ -202,7 +200,7 @@ def __init__( # Detect the default framebuffer self._screen = DefaultFrameBuffer(self) # Tracking active program - self.active_program: Optional[Program] = None + self.active_program: Program | None = None # Tracking active framebuffer. On context creation the window is the default render target self.active_framebuffer: Framebuffer = self._screen self._stats: ContextStats = ContextStats(warn_threshold=1000) @@ -232,7 +230,7 @@ def __init__( gl.glEnable(gl.GL_SCISSOR_TEST) # States - self._blend_func: Union[Tuple[int, int], Tuple[int, int, int, int]] = self.BLEND_DEFAULT + self._blend_func: Tuple[int, int] | Tuple[int, int, int, int] = self.BLEND_DEFAULT self._point_size = 1.0 self._flags: Set[int] = set() self._wireframe = False @@ -388,7 +386,7 @@ def gc_mode(self, value: str): self._gc_mode = value @property - def error(self) -> Union[str, None]: + def error(self) -> str | None: """Check OpenGL error Returns a string representation of the occurring error @@ -551,7 +549,7 @@ def viewport(self, value: Tuple[int, int, int, int]): self.active_framebuffer.viewport = value @property - def scissor(self) -> Optional[Tuple[int, int, int, int]]: + def scissor(self) -> Tuple[int, int, int, int] | None: """ Get or set the scissor box for the active framebuffer. This is a shortcut for :py:meth:`~arcade.gl.Framebuffer.scissor`. @@ -576,7 +574,7 @@ def scissor(self, value): self.fbo.scissor = value @property - def blend_func(self) -> Union[Tuple[int, int], Tuple[int, int, int, int]]: + def blend_func(self) -> Tuple[int, int] | Tuple[int, int, int, int]: """ Get or set the blend function. This is tuple specifying how the color and @@ -624,7 +622,7 @@ def blend_func(self) -> Union[Tuple[int, int], Tuple[int, int, int, int]]: return self._blend_func @blend_func.setter - def blend_func(self, value: Union[Tuple[int, int], Tuple[int, int, int, int]]): + def blend_func(self, value: Tuple[int, int] | Tuple[int, int, int, int]): self._blend_func = value if len(value) == 2: gl.glBlendFunc(*value) @@ -833,7 +831,7 @@ def copy_framebuffer( # --- Resource methods --- def buffer( - self, *, data: Optional[BufferProtocol] = None, reserve: int = 0, usage: str = "static" + self, *, data: BufferProtocol | None = None, reserve: int = 0, usage: str = "static" ) -> Buffer: """ Create an OpenGL Buffer object. The buffer will contain all zero-bytes if @@ -882,8 +880,8 @@ def buffer( def framebuffer( self, *, - color_attachments: Optional[Union[Texture2D, List[Texture2D]]] = None, - depth_attachment: Optional[Texture2D] = None, + color_attachments: Texture2D | List[Texture2D] | None = None, + depth_attachment: Texture2D | None = None, ) -> Framebuffer: """Create a Framebuffer. @@ -900,13 +898,13 @@ 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[PyGLenum, PyGLenum]] = None, + data: BufferProtocol | None = None, + wrap_x: PyGLenum | None = None, + wrap_y: PyGLenum | None = None, + filter: Tuple[PyGLenum, PyGLenum] | None = None, samples: int = 0, immutable: bool = False, - internal_format: Optional[PyGLenum] = None, + internal_format: PyGLenum | None = None, compressed: bool = False, compressed_data: bool = False, ) -> Texture2D: @@ -985,7 +983,7 @@ def texture( ) def depth_texture( - self, size: Tuple[int, int], *, data: Optional[BufferProtocol] = None + self, size: Tuple[int, int], *, data: BufferProtocol | None = None ) -> Texture2D: """ Create a 2D depth texture. Can be used as a depth attachment @@ -1000,9 +998,9 @@ def depth_texture( def geometry( self, - content: Optional[Sequence[BufferDescription]] = None, - index_buffer: Optional[Buffer] = None, - mode: Optional[int] = None, + content: Sequence[BufferDescription] | None = None, + index_buffer: Buffer | None = None, + mode: int | None = None, index_element_size: int = 4, ): """ @@ -1087,13 +1085,13 @@ def program( self, *, vertex_shader: str, - fragment_shader: Optional[str] = None, - geometry_shader: Optional[str] = None, - tess_control_shader: Optional[str] = None, - tess_evaluation_shader: Optional[str] = None, - common: Optional[List[str]] = None, - defines: Optional[Dict[str, str]] = None, - varyings: Optional[Sequence[str]] = None, + fragment_shader: str | None = None, + geometry_shader: str | None = None, + tess_control_shader: str | None = None, + tess_evaluation_shader: str | None = None, + common: List[str] | None = None, + defines: Dict[str, str] | None = None, + varyings: Sequence[str] | None = None, varyings_capture_mode: str = "interleaved", ) -> Program: """Create a :py:class:`~arcade.gl.Program` given the vertex, fragment and geometry shader. diff --git a/arcade/gl/framebuffer.py b/arcade/gl/framebuffer.py index 4317e8eb9..82c0de0f5 100644 --- a/arcade/gl/framebuffer.py +++ b/arcade/gl/framebuffer.py @@ -3,7 +3,7 @@ import weakref from contextlib import contextmanager from ctypes import c_int, string_at -from typing import TYPE_CHECKING, Generator, Optional +from typing import TYPE_CHECKING, Generator from pyglet import gl @@ -66,7 +66,7 @@ def __init__( ctx: "Context", *, color_attachments=None, - depth_attachment: Optional[Texture2D] = None, + depth_attachment: Texture2D | None = None, ): self._glo = fbo_id = gl.GLuint() # The OpenGL alias/name self._ctx = ctx @@ -76,7 +76,7 @@ def __init__( self._color_attachments = ( color_attachments if isinstance(color_attachments, list) else [color_attachments] ) - self._depth_attachment: Optional[Texture2D] = depth_attachment + self._depth_attachment: Texture2D | None = depth_attachment self._samples = 0 # Leaving this at 0 for future sample support self._depth_mask = True # Determines if the depth buffer should be affected self._prev_fbo = None @@ -90,7 +90,7 @@ def __init__( # but let's keep this simple with high compatibility. self._width, self._height = self._detect_size() self._viewport = 0, 0, self._width, self._height - self._scissor: Optional[tuple[int, int, int, int]] = None + self._scissor: tuple[int, int, int, int] | None = None # Attach textures to it for i, tex in enumerate(self._color_attachments): @@ -176,7 +176,7 @@ def _set_viewport(self, value: tuple[int, int, int, int]): viewport = property(_get_viewport, _set_viewport) - def _get_scissor(self) -> Optional[tuple[int, int, int, int]]: + def _get_scissor(self) -> tuple[int, int, int, int] | None: """ Get or set the scissor box for this framebuffer. @@ -239,7 +239,7 @@ def color_attachments(self) -> list[Texture2D]: return self._color_attachments @property - def depth_attachment(self) -> Optional[Texture2D]: + def depth_attachment(self) -> Texture2D | None: """Depth attachment.""" return self._depth_attachment @@ -316,10 +316,10 @@ def _use(self, *, force: bool = False): def clear( self, *, - color: Optional[RGBOrA255] = None, - color_normalized: Optional[RGBOrANormalized] = None, + color: RGBOrA255 | None = None, + color_normalized: RGBOrANormalized | None = None, depth: float = 1.0, - viewport: Optional[tuple[int, int, int, int]] = None, + viewport: tuple[int, int, int, int] | None = None, ): """ Clears the framebuffer:: @@ -610,7 +610,7 @@ def _set_viewport(self, value: tuple[int, int, int, int]): viewport = property(_get_viewport, _set_viewport) - def _get_scissor(self) -> Optional[tuple[int, int, int, int]]: + def _get_scissor(self) -> tuple[int, int, int, int] | None: """ Get or set the scissor box for this framebuffer. diff --git a/arcade/gl/glsl.py b/arcade/gl/glsl.py index 1ae5e6370..29f635af8 100644 --- a/arcade/gl/glsl.py +++ b/arcade/gl/glsl.py @@ -1,7 +1,7 @@ from __future__ import annotations import re -from typing import TYPE_CHECKING, Iterable, Optional +from typing import TYPE_CHECKING, Iterable from pyglet import gl @@ -36,7 +36,7 @@ def __init__( self, ctx: "ArcadeGlContext", source: str, - common: Optional[Iterable[str]], + common: Iterable[str] | None, source_type: PyGLenum, ): """Create a shader source wrapper.""" @@ -79,7 +79,7 @@ def out_attributes(self) -> list[str]: """The out attributes for this program""" return self._out_attributes - def inject_common_sources(self, common: Optional[Iterable[str]]) -> None: + def inject_common_sources(self, common: Iterable[str] | None) -> None: """Inject common source code into the shader source""" if not common: return @@ -96,7 +96,7 @@ def inject_common_sources(self, common: Optional[Iterable[str]]) -> None: lines = source.split("\n") self._lines = self._lines[:line_number] + lines + self._lines[line_number:] - def get_source(self, *, defines: Optional[dict[str, str]] = None) -> str: + def get_source(self, *, defines: dict[str, str] | None = None) -> str: """Return the shader source :param defines: Defines to replace in the source. diff --git a/arcade/gl/program.py b/arcade/gl/program.py index 55ad576b5..fe46255df 100644 --- a/arcade/gl/program.py +++ b/arcade/gl/program.py @@ -13,7 +13,7 @@ create_string_buffer, pointer, ) -from typing import TYPE_CHECKING, Any, Iterable, Optional, Union +from typing import TYPE_CHECKING, Any, Iterable from pyglet import gl @@ -73,11 +73,11 @@ def __init__( ctx: "Context", *, vertex_shader: str, - fragment_shader: Optional[str] = None, - geometry_shader: Optional[str] = None, - tess_control_shader: Optional[str] = None, - tess_evaluation_shader: Optional[str] = None, - varyings: Optional[list[str]] = None, + fragment_shader: str | None = None, + geometry_shader: str | None = None, + tess_control_shader: str | None = None, + tess_evaluation_shader: str | None = None, + varyings: list[str] | None = None, varyings_capture_mode: str = "interleaved", ): self._ctx = ctx @@ -88,7 +88,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, Union[Uniform, UniformBlock]] = {} + self._uniforms: dict[str, Uniform | UniformBlock] = {} if self._varyings_capture_mode not in self._valid_capture_modes: raise ValueError( @@ -272,7 +272,7 @@ def delete_glo(ctx, prog_id): gl.glDeleteProgram(prog_id) ctx.stats.decr("program") - def __getitem__(self, item) -> Union[Uniform, UniformBlock]: + def __getitem__(self, item) -> Uniform | UniformBlock: """Get a uniform or uniform block""" try: uniform = self._uniforms[item] diff --git a/arcade/gl/texture.py b/arcade/gl/texture.py index 690bd1ffb..7063cc729 100644 --- a/arcade/gl/texture.py +++ b/arcade/gl/texture.py @@ -2,7 +2,7 @@ import weakref from ctypes import byref, string_at -from typing import TYPE_CHECKING, Optional, Union +from typing import TYPE_CHECKING from pyglet import gl @@ -119,15 +119,15 @@ def __init__( *, components: int = 4, dtype: str = "f1", - data: Optional[BufferProtocol] = None, - filter: Optional[tuple[PyGLuint, PyGLuint]] = None, - wrap_x: Optional[PyGLuint] = None, - wrap_y: Optional[PyGLuint] = None, + data: BufferProtocol | None = None, + filter: tuple[PyGLuint, PyGLuint] | None = None, + wrap_x: PyGLuint | None = None, + wrap_y: PyGLuint | None = None, target=gl.GL_TEXTURE_2D, depth=False, samples: int = 0, immutable: bool = False, - internal_format: Optional[PyGLuint] = None, + internal_format: PyGLuint | None = None, compressed: bool = False, compressed_data: bool = False, ): @@ -142,7 +142,7 @@ def __init__( self._samples = min(max(0, samples), self._ctx.info.MAX_SAMPLES) self._depth = depth self._immutable = immutable - self._compare_func: Optional[str] = None + self._compare_func: str | None = None self._anisotropy = 1.0 self._internal_format = internal_format self._compressed = compressed @@ -579,7 +579,7 @@ def anisotropy(self, value): gl.glTexParameterf(self._target, gl.GL_TEXTURE_MAX_ANISOTROPY, self._anisotropy) @property - def compare_func(self) -> Optional[str]: + def compare_func(self) -> str | None: """ Get or set the compare function for a depth texture:: @@ -598,7 +598,7 @@ def compare_func(self) -> Optional[str]: return self._compare_func @compare_func.setter - def compare_func(self, value: Union[str, None]): + def compare_func(self, value: str | None): if not self._depth: raise ValueError("Depth comparison function can only be set on depth textures") @@ -660,12 +660,11 @@ def write(self, data: BufferOrBufferProtocol, level: int = 0, viewport=None) -> :ref:`prog-guide-gl-buffer-protocol-typing` for more information. - :param data: :class:`~arcade.gl.Buffer` or - buffer protocol object with - data to write. + :param data: :class:`~arcade.gl.Buffer` or buffer protocol + object with data to write. :param level: The texture level to write - :param Union[Tuple[int, int], Tuple[int, int, int, int]] viewport: - The area of the texture to write. 2 or 4 component tuple + :param Tuple[int, int] | Tuple[int, int, int, int] viewport: + The area of the texture to write. 2 or 4 component tuple """ # TODO: Support writing to layers using viewport + alignment if self._samples > 0: diff --git a/arcade/gl/types.py b/arcade/gl/types.py index 6be8b7d48..a3f04e03c 100644 --- a/arcade/gl/types.py +++ b/arcade/gl/types.py @@ -1,7 +1,7 @@ from __future__ import annotations import re -from typing import Iterable, Optional, Sequence, Union +from typing import Iterable, Sequence, Union from pyglet import gl from typing_extensions import TypeAlias @@ -115,7 +115,7 @@ } -def gl_name(gl_type: Optional[PyGLenum]) -> Union[str, PyGLenum, None]: +def gl_name(gl_type: PyGLenum | None) -> str | PyGLenum | None: """Return the name of a gl type""" if gl_type is None: return None @@ -146,8 +146,8 @@ class AttribFormat: def __init__( self, - name: Optional[str], - gl_type: Optional[PyGLenum], + name: str | None, + gl_type: PyGLenum | None, components: int, bytes_per_component: int, offset=0, @@ -211,7 +211,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: dict[str, tuple[PyGLenum | None, int]] = { # (gl enum, byte size) # Floats "f": (gl.GL_FLOAT, 4), @@ -252,7 +252,7 @@ def __init__( buffer: Buffer, formats: str, attributes: Sequence[str], - normalized: Optional[Iterable[str]] = None, + normalized: Iterable[str] | None = None, instanced: bool = False, ): #: The :py:class:`~arcade.gl.Buffer` this description object describes diff --git a/arcade/gl/vertex_array.py b/arcade/gl/vertex_array.py index b83652970..61e895a44 100644 --- a/arcade/gl/vertex_array.py +++ b/arcade/gl/vertex_array.py @@ -2,7 +2,7 @@ import weakref from ctypes import byref, c_void_p -from typing import TYPE_CHECKING, Optional, Sequence, Union +from typing import TYPE_CHECKING, Sequence from pyglet import gl @@ -50,7 +50,7 @@ def __init__( ctx: "Context", program: Program, content: Sequence[BufferDescription], - index_buffer: Optional[Buffer] = None, + index_buffer: Buffer | None = None, index_element_size: int = 4, ) -> None: self._ctx = ctx @@ -93,7 +93,7 @@ def program(self) -> Program: return self._program @property - def ibo(self) -> Optional[Buffer]: + def ibo(self) -> Buffer | None: """ Element/index buffer """ @@ -131,7 +131,7 @@ def delete_glo(ctx: "Context", glo: gl.GLuint) -> None: ctx.stats.decr("vertex_array") def _build( - self, program: Program, content: Sequence[BufferDescription], index_buffer: Optional[Buffer] + self, program: Program, content: Sequence[BufferDescription], index_buffer: Buffer | None ) -> None: """Build a vertex array compatible with the program passed in""" gl.glGenVertexArrays(1, byref(self.glo)) @@ -448,9 +448,9 @@ class Geometry: def __init__( self, ctx: "Context", - content: Optional[Sequence[BufferDescription]], - index_buffer: Optional[Buffer] = None, - mode: Optional[int] = None, + content: Sequence[BufferDescription] | None, + index_buffer: Buffer | None = None, + mode: int | None = None, index_element_size: int = 4, ) -> None: self._ctx = ctx @@ -496,7 +496,7 @@ def ctx(self) -> "Context": return self._ctx @property - def index_buffer(self) -> Optional[Buffer]: + def index_buffer(self) -> Buffer | None: """ Index/element buffer if supplied at creation. @@ -547,9 +547,9 @@ def render( self, program: Program, *, - mode: Optional[GLenumLike] = None, + mode: GLenumLike | None = None, first: int = 0, - vertices: Optional[int] = None, + vertices: int | None = None, instances: int = 1, ) -> None: """Render the geometry with a specific program. @@ -619,7 +619,7 @@ def render_indirect( program: Program, buffer: Buffer, *, - mode: Optional[GLuintLike] = None, + mode: GLuintLike | None = None, count: int = -1, first: int = 0, stride: int = 0, @@ -670,10 +670,10 @@ def render_indirect( def transform( self, program: Program, - buffer: Union[Buffer, list[Buffer]], + buffer: Buffer | list[Buffer], *, first: int = 0, - vertices: Optional[int] = None, + vertices: int | None = None, instances: int = 1, buffer_offset: int = 0, ) -> None: @@ -683,7 +683,7 @@ def transform( If a geometry shader is used the output primitive mode is automatically detected. :param program: The Program to render with - :param Union[Buffer, Sequence[Buffer]] buffer: The buffer(s) we transform into. + :param Buffer | Sequence[Buffer] buffer: The buffer(s) we transform into. This depends on the programs ``varyings_capture_mode``. We can transform into one buffer interleaved or transform each attribute into separate buffers. :param first: Offset start vertex diff --git a/arcade/gui/surface.py b/arcade/gui/surface.py index aea7d84eb..16ac38d17 100644 --- a/arcade/gui/surface.py +++ b/arcade/gui/surface.py @@ -1,7 +1,7 @@ from __future__ import annotations from contextlib import contextmanager -from typing import Optional, Union +from typing import Optional import arcade from arcade import Texture @@ -102,7 +102,7 @@ def draw_texture( y: float, width: float, height: float, - tex: Union[Texture, NinePatchTexture], + tex: Texture | NinePatchTexture, angle: float = 0.0, alpha: int = 255, ): diff --git a/arcade/gui/ui_manager.py b/arcade/gui/ui_manager.py index 2c263dbb6..f8d0c5afb 100644 --- a/arcade/gui/ui_manager.py +++ b/arcade/gui/ui_manager.py @@ -12,7 +12,7 @@ from __future__ import annotations from collections import defaultdict -from typing import Iterable, Optional, Type, TypeVar, Union +from typing import Iterable, Optional, TypeVar, Union from pyglet.event import EVENT_HANDLED, EVENT_UNHANDLED, EventDispatcher from typing_extensions import TypeGuard @@ -164,7 +164,7 @@ def clear(self): for widget in layer[:]: self.remove(widget) - def get_widgets_at(self, pos: Point2, cls: Type[W] = UIWidget, layer=0) -> Iterable[W]: + def get_widgets_at(self, pos: Point2, cls: type[W] = UIWidget, layer=0) -> Iterable[W]: """ Yields all widgets containing a position, returns first top laying widgets which is instance of cls. diff --git a/arcade/hitbox/pymunk.py b/arcade/hitbox/pymunk.py index ef91fa6b1..cb2c0269f 100644 --- a/arcade/hitbox/pymunk.py +++ b/arcade/hitbox/pymunk.py @@ -1,7 +1,5 @@ from __future__ import annotations -from typing import Optional - import pymunk from PIL.Image import Image from pymunk import Vec2d @@ -27,16 +25,16 @@ class PymunkHitBoxAlgorithm(HitBoxAlgorithm): #: The default detail when creating a new instance. default_detail = 4.5 - def __init__(self, *, detail: Optional[float] = None): + def __init__(self, *, detail: float | None = None): super().__init__() self.detail = detail or self.default_detail self._cache_name += f"|detail={self.detail}" - def __call__(self, *, detail: Optional[float] = None) -> "PymunkHitBoxAlgorithm": + def __call__(self, *, detail: float | None = None) -> "PymunkHitBoxAlgorithm": """Create a new instance with new default values""" return PymunkHitBoxAlgorithm(detail=detail or self.detail) - def calculate(self, image: Image, detail: Optional[float] = None, **kwargs) -> Point2List: + def calculate(self, image: Image, detail: float | None = None, **kwargs) -> Point2List: """ Given an RGBA image, this returns points that make up a hit box around it. diff --git a/arcade/particles/emitter.py b/arcade/particles/emitter.py index ee29aeeed..6a1ab3ad4 100644 --- a/arcade/particles/emitter.py +++ b/arcade/particles/emitter.py @@ -5,7 +5,7 @@ from __future__ import annotations -from typing import Callable, Optional, cast +from typing import Callable, cast import arcade from arcade import Vec2 @@ -137,8 +137,8 @@ def __init__( emit_controller: EmitController, particle_factory: Callable[["Emitter"], Particle], change_xy: Velocity = (0.0, 0.0), - emit_done_cb: Optional[Callable[["Emitter"], None]] = None, - reap_cb: Optional[Callable[[], None]] = None, + emit_done_cb: Callable[[Emitter], None] | None = None, + reap_cb: Callable[[], None] | None = None, ): self.change_x = change_xy[0] self.change_y = change_xy[1] diff --git a/arcade/particles/emitter_simple.py b/arcade/particles/emitter_simple.py index 5a028cecc..b69bbdc41 100644 --- a/arcade/particles/emitter_simple.py +++ b/arcade/particles/emitter_simple.py @@ -8,7 +8,7 @@ from __future__ import annotations import random -from typing import Sequence, Type +from typing import Sequence from arcade.math import rand_in_circle, rand_on_circle from arcade.types import PathOrTexture, Point @@ -28,7 +28,7 @@ def make_burst_emitter( fade_particles: bool = True, ) -> Emitter: """Returns an emitter that emits all of its particles at once""" - particle_factory: Type[LifetimeParticle] = LifetimeParticle + particle_factory: type[LifetimeParticle] = LifetimeParticle if fade_particles: particle_factory = FadeParticle return Emitter( @@ -55,7 +55,7 @@ def make_interval_emitter( fade_particles: bool = True, ) -> Emitter: """Returns an emitter that emits its particles at a constant rate for a given amount of time""" - particle_factory: Type[LifetimeParticle] = LifetimeParticle + particle_factory: type[LifetimeParticle] = LifetimeParticle if fade_particles: particle_factory = FadeParticle return Emitter( diff --git a/arcade/particles/particle.py b/arcade/particles/particle.py index 8f8423b9e..ccbf3f87a 100644 --- a/arcade/particles/particle.py +++ b/arcade/particles/particle.py @@ -5,7 +5,7 @@ from __future__ import annotations -from typing import Literal, Optional +from typing import Literal from arcade.math import clamp, lerp from arcade.sprite import Sprite @@ -17,7 +17,7 @@ class Particle(Sprite): def __init__( self, - path_or_texture: Optional[PathOrTexture], + path_or_texture: PathOrTexture | None, change_xy: tuple[float, float], center_xy: Point = (0.0, 0.0), angle: float = 0.0, @@ -85,7 +85,7 @@ class LifetimeParticle(Particle): def __init__( self, - filename_or_texture: Optional[PathOrTexture], + filename_or_texture: PathOrTexture | None, change_xy: Velocity, lifetime: float, center_xy: Point = (0.0, 0.0), diff --git a/arcade/paths.py b/arcade/paths.py index 58fe131b1..e11484835 100644 --- a/arcade/paths.py +++ b/arcade/paths.py @@ -5,7 +5,7 @@ from __future__ import annotations import math -from typing import Optional, cast +from typing import cast from arcade import Sprite, SpriteList, check_for_collision_with_list, get_sprites_at_point from arcade.math import get_distance, lerp_2d @@ -138,7 +138,7 @@ def move_cost(self, a: Point, b: Point) -> float: return 1.42 -def _AStarSearch(start: Point2, end: Point2, graph: _AStarGraph) -> Optional[list[Point2]]: +def _AStarSearch(start: Point2, end: Point2, graph: _AStarGraph) -> list[Point2] | None: """ Returns a path from start to end using the AStarSearch Algorithm @@ -307,7 +307,7 @@ def astar_calculate_path( end_point: Point, astar_barrier_list: AStarBarrierList, diagonal_movement: bool = True, -) -> Optional[list[Point]]: +) -> list[Point] | None: """ Calculates the path using AStarSearch Algorithm and returns the path diff --git a/arcade/physics_engines.py b/arcade/physics_engines.py index 8bed712b9..fcf1efe08 100644 --- a/arcade/physics_engines.py +++ b/arcade/physics_engines.py @@ -4,9 +4,8 @@ from __future__ import annotations -# pylint: disable=too-many-arguments, too-many-locals, too-few-public-methods import math -from typing import Iterable, Optional, Union +from typing import Iterable from arcade import ( BasicSprite, @@ -281,9 +280,7 @@ def _move_sprite( return complete_hit_list -def _add_to_list( - dest: list[SpriteList], source: Optional[SpriteList | Iterable[SpriteList]] -) -> None: +def _add_to_list(dest: list[SpriteList], source: SpriteList | Iterable[SpriteList] | None) -> None: if not source: return elif isinstance(source, SpriteList): @@ -319,7 +316,7 @@ class PhysicsEngineSimple: def __init__( self, player_sprite: Sprite, - walls: Optional[Union[SpriteList, Iterable[SpriteList]]] = None, + walls: SpriteList | Iterable[SpriteList] | None = None, ) -> None: self.player_sprite: Sprite = player_sprite """The player-controlled :py:class:`.Sprite`.""" @@ -343,7 +340,7 @@ def walls(self) -> list[SpriteList]: return self._walls @walls.setter - def walls(self, walls: Optional[Union[SpriteList, Iterable[SpriteList]]] = None) -> None: + def walls(self, walls: SpriteList | Iterable[SpriteList] | None = None) -> None: if walls: _add_to_list(self._walls, walls) else: @@ -438,10 +435,10 @@ class PhysicsEnginePlatformer: def __init__( self, player_sprite: Sprite, - platforms: Optional[Union[SpriteList, Iterable[SpriteList]]] = None, + platforms: SpriteList | Iterable[SpriteList] | None = None, gravity_constant: float = 0.5, - ladders: Optional[Union[SpriteList, Iterable[SpriteList]]] = None, - walls: Optional[Union[SpriteList, Iterable[SpriteList]]] = None, + ladders: SpriteList | Iterable[SpriteList] | None = None, + walls: SpriteList | Iterable[SpriteList] | None = None, ) -> None: if not isinstance(player_sprite, Sprite): raise TypeError("player_sprite must be a Sprite, not a basic_sprite!") @@ -542,7 +539,7 @@ def ladders(self) -> list[SpriteList]: return self._ladders @ladders.setter - def ladders(self, ladders: Optional[Union[SpriteList, Iterable[SpriteList]]] = None) -> None: + def ladders(self, ladders: SpriteList | Iterable[SpriteList] | None = None) -> None: if ladders: _add_to_list(self._ladders, ladders) else: @@ -584,9 +581,7 @@ def platforms(self) -> list[SpriteList]: return self._platforms @platforms.setter - def platforms( - self, platforms: Optional[Union[SpriteList, Iterable[SpriteList]]] = None - ) -> None: + def platforms(self, platforms: SpriteList | Iterable[SpriteList] | None = None) -> None: if platforms: _add_to_list(self._platforms, platforms) else: @@ -622,7 +617,7 @@ def walls(self) -> list[SpriteList]: return self._walls @walls.setter - def walls(self, walls: Optional[Union[SpriteList, Iterable[SpriteList]]] = None) -> None: + def walls(self, walls: SpriteList | Iterable[SpriteList] | None = None) -> None: if walls: _add_to_list(self._walls, walls) else: diff --git a/arcade/pymunk_physics_engine.py b/arcade/pymunk_physics_engine.py index 0d62ad1a3..915fc501d 100644 --- a/arcade/pymunk_physics_engine.py +++ b/arcade/pymunk_physics_engine.py @@ -6,7 +6,7 @@ import logging import math -from typing import Callable, Optional, Union +from typing import Callable import pymunk from pyglet.math import Vec2 @@ -23,9 +23,9 @@ class PymunkPhysicsObject: """Object that holds pymunk body/shape for a sprite.""" - def __init__(self, body: Optional[pymunk.Body] = None, shape: Optional[pymunk.Shape] = None): - self.body: Optional[pymunk.Body] = body - self.shape: Optional[pymunk.Shape] = shape + def __init__(self, body: pymunk.Body | None = None, shape: pymunk.Shape | None = None): + self.body: pymunk.Body | None = body + self.shape: pymunk.Shape | None = shape class PymunkException(Exception): @@ -153,16 +153,16 @@ def add_sprite( sprite: Sprite, mass: float = 1.0, friction: float = 0.2, - elasticity: Optional[float] = None, - moment_of_inertia: Optional[float] = None, # correct spelling + elasticity: float | None = None, + moment_of_inertia: float | None = None, # correct spelling body_type: int = DYNAMIC, - damping: Optional[float] = None, - gravity: Optional[Union[pymunk.Vec2d, tuple[float, float], Vec2]] = None, - max_velocity: Optional[int] = None, - max_horizontal_velocity: Optional[int] = None, - max_vertical_velocity: Optional[int] = None, + damping: float | None = None, + gravity: pymunk.Vec2d | tuple[float, float] | Vec2 | None = None, + max_velocity: int | None = None, + max_horizontal_velocity: int | None = None, + max_vertical_velocity: int | None = None, radius: float = 0, - collision_type: Optional[str] = "default", + collision_type: str | None = "default", ): """Add a sprite to the physics engine. @@ -357,11 +357,11 @@ def add_sprite_list( sprite_list, mass: float = 1, friction: float = 0.2, - elasticity: Optional[float] = None, - moment_of_inertia: Optional[float] = None, + elasticity: float | None = None, + moment_of_inertia: float | None = None, body_type: int = DYNAMIC, - damping: Optional[float] = None, - collision_type: Optional[str] = None, + damping: float | None = None, + collision_type: str | None = None, ): """Add all sprites in a sprite list to the physics engine.""" for sprite in sprite_list: @@ -385,7 +385,7 @@ def remove_sprite(self, sprite: Sprite): if sprite in self.non_static_sprite_list: self.non_static_sprite_list.remove(sprite) - def get_sprite_for_shape(self, shape: Optional[pymunk.Shape]) -> Optional[Sprite]: + def get_sprite_for_shape(self, shape: pymunk.Shape | None) -> Sprite | None: """Try to get the sprite registered with this engine for ``shape``. This method returns ``None`` when: @@ -409,7 +409,7 @@ def get_sprite_for_shape(self, shape: Optional[pymunk.Shape]) -> Optional[Sprite def get_sprites_from_arbiter( self, arbiter: pymunk.Arbiter - ) -> tuple[Optional[Sprite], Optional[Sprite]]: + ) -> tuple[Sprite | None, Sprite | None]: """Given a collision arbiter, return the sprites associated with the collision.""" shape1, shape2 = arbiter.shapes sprite1 = self.get_sprite_for_shape(shape1) @@ -430,7 +430,7 @@ def apply_impulse(self, sprite: Sprite, impulse: tuple[float, float]): ) physics_object.body.apply_impulse_at_local_point(impulse) - def set_position(self, sprite: Sprite, position: Union[pymunk.Vec2d, tuple[float, float]]): + def set_position(self, sprite: Sprite, position: pymunk.Vec2d | tuple[float, float]): """Set the position of the sprite in the engine's simulation. To learn more, please see :py:attr:`pymunk.Body.position`. @@ -482,10 +482,10 @@ def add_collision_handler( self, first_type: str, second_type: str, - begin_handler: Optional[Callable] = None, - pre_handler: Optional[Callable] = None, - post_handler: Optional[Callable] = None, - separate_handler: Optional[Callable] = None, + begin_handler: Callable | None = None, + pre_handler: Callable | None = None, + post_handler: Callable | None = None, + separate_handler: Callable | None = None, ): """Add code to handle collisions between objects.""" diff --git a/arcade/resources/__init__.py b/arcade/resources/__init__.py index 0b7f5364f..2fb6ab359 100644 --- a/arcade/resources/__init__.py +++ b/arcade/resources/__init__.py @@ -1,7 +1,7 @@ from __future__ import annotations from pathlib import Path -from typing import Union, Optional, Sequence +from typing import Sequence from arcade.utils import warning, ReplacementWarning #: The absolute path to this directory @@ -24,7 +24,7 @@ @warning(warning_type=ReplacementWarning, new_name="resolve") -def resolve_resource_path(path: Union[str, Path]) -> Path: +def resolve_resource_path(path: str | Path) -> Path: """ Attempts to resolve a path to a resource including resource handles. @@ -39,12 +39,12 @@ def resolve_resource_path(path: Union[str, Path]) -> Path: resolve(":resources:images/cards/cardBack_blue1.png") resolve(":my_handle:music/combat.wav") - :param Union[str, Path] path: A Path or string + :param str | pathlib.Path path: A Path or string """ return resolve(path) -def resolve(path: Union[str, Path]) -> Path: +def resolve(path: str | Path) -> Path: """ Attempts to resolve a path to a resource including resource handles. @@ -59,7 +59,7 @@ def resolve(path: Union[str, Path]) -> Path: resolve(":resources:images/cards/cardBack_blue1.png") resolve(":my_handle:music/combat.wav") - :param Union[str, Path] path: A Path or string + :param str | pathlib.Path] path: A Path or string """ # Convert to a Path object and resolve resource handle if isinstance(path, str): @@ -117,7 +117,7 @@ def resolve(path: Union[str, Path]) -> Path: raise FileNotFoundError(f"Cannot locate resource : {path}") -def add_resource_handle(handle: str, path: Union[str, Path]) -> None: +def add_resource_handle(handle: str, path: str | Path) -> None: """ Add a resource handle or path to an existing handle. @@ -126,7 +126,7 @@ def add_resource_handle(handle: str, path: Union[str, Path]) -> None: is done in reverse order, so the last path added is searched first. :param handle: The name of the handle - :param Union[str, Path] path: The absolute path to a directory + :param str | pathlib.Path] path: The absolute path to a directory """ if isinstance(path, str): path = Path(path) @@ -163,7 +163,7 @@ def get_resource_handle_paths(handle: str) -> list[Path]: def list_built_in_assets( - *, name: Optional[str] = None, extensions: Optional[Sequence[str]] = None + *, name: str | None = None, extensions: Sequence[str] | None = None ) -> list[Path]: """ List built in assets in arcade. diff --git a/arcade/scene.py b/arcade/scene.py index cf0f1f337..37b43cb2b 100644 --- a/arcade/scene.py +++ b/arcade/scene.py @@ -12,7 +12,7 @@ from __future__ import annotations -from typing import Iterable, Optional, Union +from typing import Iterable from warnings import warn from arcade import Sprite, SpriteList @@ -78,7 +78,7 @@ def __len__(self) -> int: """ return len(self._sprite_lists) - def __delitem__(self, sprite_list: Union[int, str, SpriteList]) -> None: + def __delitem__(self, sprite_list: int | str | SpriteList) -> None: """ Remove a sprite list from this scene by its index, name, or instance value. @@ -177,7 +177,7 @@ def add_sprite_list( self, name: str, use_spatial_hash: bool = False, - sprite_list: Optional[SpriteList] = None, + sprite_list: SpriteList | None = None, ) -> None: """ Add a SpriteList to the scene with the specified name. @@ -208,7 +208,7 @@ def add_sprite_list_before( name: str, before: str, use_spatial_hash: bool = False, - sprite_list: Optional[SpriteList] = None, + sprite_list: SpriteList | None = None, ) -> None: """ Add a sprite list to the scene with the specified name before another SpriteList. @@ -272,7 +272,7 @@ def add_sprite_list_after( name: str, after: str, use_spatial_hash: bool = False, - sprite_list: Optional[SpriteList] = None, + sprite_list: SpriteList | None = None, ) -> None: """ Add a SpriteList to the scene with the specified name after a specific SpriteList. @@ -368,7 +368,7 @@ def remove_sprite_list_by_object(self, sprite_list: SpriteList) -> None: key: val for key, val in self._name_mapping.items() if val != sprite_list } - def update(self, names: Optional[Iterable[str]] = None) -> None: + def update(self, names: Iterable[str] | None = None) -> None: """ Call :py:meth:`~arcade.SpriteList.update` on the scene's sprite lists. @@ -390,7 +390,7 @@ def update(self, names: Optional[Iterable[str]] = None) -> None: for sprite_list in self._sprite_lists: sprite_list.update() - def on_update(self, delta_time: float = 1 / 60, names: Optional[Iterable[str]] = None) -> None: + def on_update(self, delta_time: float = 1 / 60, names: Iterable[str] | None = None) -> None: """ Call :py:meth:`~arcade.SpriteList.on_update` on the scene's sprite lists. @@ -413,7 +413,7 @@ def on_update(self, delta_time: float = 1 / 60, names: Optional[Iterable[str]] = for sprite_list in self._sprite_lists: sprite_list.on_update(delta_time) - def update_animation(self, delta_time: float, names: Optional[Iterable[str]] = None) -> None: + def update_animation(self, delta_time: float, names: Iterable[str] | None = None) -> None: """ Call :py:meth:`~arcade.SpriteList.update_animation` on the scene's sprite lists. @@ -438,10 +438,10 @@ def update_animation(self, delta_time: float, names: Optional[Iterable[str]] = N def draw( self, - names: Optional[Iterable[str]] = None, - filter: Optional[OpenGlFilter] = None, + names: Iterable[str] | None = None, + filter: OpenGlFilter | None = None, pixelated: bool = False, - blend_function: Optional[BlendFunction] = None, + blend_function: BlendFunction | None = None, **kwargs, ) -> None: """ @@ -487,7 +487,7 @@ def draw_hit_boxes( self, color: RGBA255 = Color(0, 0, 0, 255), line_thickness: float = 1.0, - names: Optional[Iterable[str]] = None, + names: Iterable[str] | None = None, ) -> None: """ Draw debug hit box outlines for sprites in the scene's layers. @@ -515,6 +515,6 @@ def __bool__(self) -> bool: """Returns whether or not `_sprite_lists` contains anything""" return bool(self._sprite_lists) - def __contains__(self, item: Union[str, SpriteList]) -> bool: + def __contains__(self, item: str | SpriteList) -> bool: """True when `item` is in `_sprite_lists` or is a value in `_name_mapping`""" return item in self._sprite_lists or item in self._name_mapping diff --git a/arcade/screenshot.py b/arcade/screenshot.py index 901e46a5d..364184d1b 100644 --- a/arcade/screenshot.py +++ b/arcade/screenshot.py @@ -4,7 +4,7 @@ These functions are flawed because they only read from the screen. """ -from typing import Optional +from __future__ import annotations import PIL.Image import PIL.ImageOps @@ -40,8 +40,8 @@ def get_pixel(x: int, y: int, components: int = 3) -> tuple[int, ...]: def get_image( x: int = 0, y: int = 0, - width: Optional[int] = None, - height: Optional[int] = None, + width: int | None = None, + height: int | None = None, components: int = 4, ) -> PIL.Image.Image: """ diff --git a/arcade/sections.py b/arcade/sections.py index 3f3e0698c..6ab1eeff5 100644 --- a/arcade/sections.py +++ b/arcade/sections.py @@ -1,7 +1,7 @@ from __future__ import annotations import math -from typing import TYPE_CHECKING, Generator, Iterable, Optional, Union +from typing import TYPE_CHECKING, Generator, Iterable from pyglet.event import EVENT_HANDLED, EVENT_UNHANDLED @@ -26,11 +26,11 @@ class Section: :param width: the width of this section :param height: the height of this section :param name: the name of this section - :param Union[bool, Iterable] accept_keyboard_keys: whether or not this section + :param bool | Iterable accept_keyboard_keys: whether or not this section captures keyboard keys through. keyboard events. If the param is an iterable means the keyboard keys that are captured in press/release events: for example: ``[arcade.key.UP, arcade.key.DOWN]`` will only capture this two keys - :param Union[bool, Iterable] accept_mouse_events: whether or not this section + :param bool Iterable accept_mouse_events: whether or not this section captures mouse events. If the param is an iterable means the mouse events that are captured. for example: ``['on_mouse_press', 'on_mouse_release']`` will only capture this two events. @@ -58,22 +58,22 @@ def __init__( width: int, height: int, *, - name: Optional[str] = None, - accept_keyboard_keys: Union[bool, Iterable] = True, - accept_mouse_events: Union[bool, Iterable] = True, - prevent_dispatch: Optional[Iterable] = None, - prevent_dispatch_view: Optional[Iterable] = None, + name: str | None = None, + accept_keyboard_keys: bool | Iterable = True, + accept_mouse_events: bool | Iterable = True, + prevent_dispatch: Iterable | None = None, + prevent_dispatch_view: Iterable | None = None, local_mouse_coordinates: bool = False, enabled: bool = True, modal: bool = False, draw_order: int = 1, ): # name of the section - self.name: Optional[str] = name + self.name: str | None = name # parent view: set by the SectionManager. Protected, you should not change # section.view manually - self._view: Optional["View"] = None + self._view: View | None = None # section options self._enabled: bool = enabled # enables or disables this section @@ -87,9 +87,9 @@ def __init__( self.block_updates: bool = False # arcade keyboard keys to accept. - self.accept_keyboard_keys: Union[bool, Iterable] = accept_keyboard_keys - # arcade moouse events to accept. - self.accept_mouse_events: Union[bool, Iterable] = accept_mouse_events + self.accept_keyboard_keys: bool | Iterable = accept_keyboard_keys + # arcade mouse events to accept. + self.accept_mouse_events: bool | Iterable = accept_mouse_events # prevents events to propagate self.prevent_dispatch: Iterable = prevent_dispatch or {True} @@ -116,7 +116,7 @@ def __init__( self._ec_top: int = self.window.height if self._modal else self._top # optional section camera - self.camera: Optional[Projector] = None + self.camera: Projector | None = None def __repr__(self): name = f"Section {self.name}" if self.name else "Section" @@ -129,7 +129,7 @@ def view(self): return self._view @property - def section_manager(self) -> Optional["SectionManager"]: + def section_manager(self) -> SectionManager | None: """Returns the section manager""" return self._view.section_manager if self._view else None @@ -356,13 +356,13 @@ def __init__(self, view: "View"): # True will call view.on_draw before sections on_draw, False after, # None will not call view on_draw - self.view_draw_first: Optional[bool] = True + self.view_draw_first: bool | None = True # True will call view.on_update before sections on_update, False after, # None will not call view on_update - self.view_update_first: Optional[bool] = True + self.view_update_first: bool | None = True # True will call view.on_resize before sections on_resize, False after, # None will not call view on_resize - self.view_resize_first: Optional[bool] = True + self.view_resize_first: bool | None = True # Events that the section manager should handle (instead of the View) if # sections are present in a View @@ -415,7 +415,7 @@ def enable(self) -> None: for section in self._sections: section.enabled = True - def get_section_by_name(self, name: str) -> Optional[Section]: + def get_section_by_name(self, name: str) -> Section | None: """ Returns the first section with the given name :param name: the name of the section you want @@ -429,8 +429,8 @@ def get_section_by_name(self, name: str) -> Optional[Section]: def add_section( self, section: "Section", - at_index: Optional[int] = None, - at_draw_order: Optional[int] = None, + at_index: int | None = None, + at_draw_order: int | None = None, ) -> None: """ Adds a section to this Section Manager @@ -564,7 +564,7 @@ def disable_all_keyboard_events(self) -> None: for section in self.sections: section.accept_keyboard_keys = False - def get_first_section(self, x: int, y: int, *, event_capture: bool = True) -> Optional[Section]: + def get_first_section(self, x: int, y: int, *, event_capture: bool = True) -> Section | None: """ Returns the first section based on x,y position @@ -607,9 +607,9 @@ def dispatch_mouse_event( x: int, y: int, *args, - current_section: Optional[Section] = None, + current_section: Section | None = None, **kwargs, - ) -> Optional[bool]: + ) -> bool | None: """ Generic method to dispatch mouse events to the correct Sections @@ -624,7 +624,7 @@ def dispatch_mouse_event( :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns """ - sections: Union[list, Generator] + sections: list | Generator if current_section: # affected section is already pre-computed @@ -678,12 +678,12 @@ def dispatch_mouse_event( prevent_dispatch_view = method(x, y, *args, **kwargs) return prevent_dispatch_view or prevent_dispatch - def dispatch_keyboard_event(self, event: str, *args, **kwargs) -> Optional[bool]: + def dispatch_keyboard_event(self, event: str, *args, **kwargs) -> bool | None: """ Generic method to dispatch keyboard events to the correct sections :param event: the keyboard event name to dispatch - :param args: any other position arguments that should be deliverd to the dispatched event + :param args: any other position arguments that should be delivered to the dispatched event :param kwargs: any other keyword arguments that should be delivered to the dispatched event :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns """ @@ -708,7 +708,7 @@ def dispatch_keyboard_event(self, event: str, *args, **kwargs) -> Optional[bool] if prevent_dispatch is EVENT_HANDLED or any( test in section.prevent_dispatch for test in [True, event] ): - # prevent_dispatch attributte from section only affect + # prevent_dispatch attributes from section only affect # if the method is implemented in the same section prevent_dispatch = EVENT_HANDLED if section.modal: @@ -725,25 +725,25 @@ def dispatch_keyboard_event(self, event: str, *args, **kwargs) -> Optional[bool] return method(*args, **kwargs) or prevent_dispatch return EVENT_UNHANDLED - def on_mouse_press(self, x: int, y: int, *args, **kwargs) -> Optional[bool]: + def on_mouse_press(self, x: int, y: int, *args, **kwargs) -> bool | None: """ - Triggers the on_mouse_press event on the appropiate sections or view + Triggers the on_mouse_press event on the appropriate sections or view :param x: the x axis coordinate :param y: the y axis coordinate - :param args: any other position arguments that should be deliverd to the dispatched event + :param args: any other position arguments that should be delivered to the dispatched event :param kwargs: any other keyword arguments that should be delivered to the dispatched event :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns """ return self.dispatch_mouse_event("on_mouse_press", x, y, *args, **kwargs) - def on_mouse_release(self, x: int, y: int, *args, **kwargs) -> Optional[bool]: + def on_mouse_release(self, x: int, y: int, *args, **kwargs) -> bool | None: """ - Triggers the on_mouse_release event on the appropiate sections or view + Triggers the on_mouse_release event on the appropriate sections or view :param x: the x axis coordinate :param y: the y axis coordinate - :param args: any other position arguments that should be deliverd to the dispatched event + :param args: any other position arguments that should be delivered to the dispatched event :param kwargs: any other keyword arguments that should be delivered to the dispatched event :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns """ @@ -751,7 +751,7 @@ def on_mouse_release(self, x: int, y: int, *args, **kwargs) -> Optional[bool]: def dispatch_mouse_enter_leave_events( self, event_origin: str, x: int, y: int, *args, **kwargs - ) -> Optional[bool]: + ) -> bool | None: """ This helper method will dispatch mouse enter / leave events to sections based on 'on_mouse_motion' and 'on_mouse_drag' events. @@ -799,7 +799,7 @@ def dispatch_mouse_enter_leave_events( # NOTE: the result from mouse enter/leave events is ignored here return prevent_dispatch_origin - def on_mouse_motion(self, x: int, y: int, *args, **kwargs) -> Optional[bool]: + def on_mouse_motion(self, x: int, y: int, *args, **kwargs) -> bool | None: """ This method dispatches the on_mouse_motion and also calculates if on_mouse_enter/leave should be fired. @@ -812,22 +812,22 @@ def on_mouse_motion(self, x: int, y: int, *args, **kwargs) -> Optional[bool]: """ return self.dispatch_mouse_enter_leave_events("on_mouse_motion", x, y, *args, **kwargs) - def on_mouse_drag(self, x: int, y: int, *args, **kwargs) -> Optional[bool]: + def on_mouse_drag(self, x: int, y: int, *args, **kwargs) -> bool | None: """ This method dispatches the on_mouse_drag and also calculates if on_mouse_enter/leave should be fired. :param x: the x axis coordinate :param y: the y axis coordinate - :param args: any other position arguments that should be deliverd to the dispatched event + :param args: any other position arguments that should be delivered to the dispatched event :param kwargs: any other keyword arguments that should be delivered to the dispatched event :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns """ return self.dispatch_mouse_enter_leave_events("on_mouse_drag", x, y, *args, **kwargs) - def on_mouse_scroll(self, x: int, y: int, *args, **kwargs) -> Optional[bool]: + def on_mouse_scroll(self, x: int, y: int, *args, **kwargs) -> bool | None: """ - Triggers the on_mouse_scroll event on the appropiate sections or view + Triggers the on_mouse_scroll event on the appropriate sections or view :param x: the x axis coordinate :param y: the y axis coordinate @@ -837,14 +837,14 @@ def on_mouse_scroll(self, x: int, y: int, *args, **kwargs) -> Optional[bool]: """ return self.dispatch_mouse_event("on_mouse_scroll", x, y, *args, **kwargs) - def on_mouse_enter(self, x: int, y: int, *args, **kwargs) -> Optional[bool]: + def on_mouse_enter(self, x: int, y: int, *args, **kwargs) -> bool | None: """ Triggered when the mouse enters the window space - Will trigger on_mouse_enter on the appropiate sections or view + Will trigger on_mouse_enter on the appropriate sections or view :param x: the x axis coordinate :param y: the y axis coordinate - :param args: any other position arguments that should be deliverd to the dispatched event + :param args: any other position arguments that should be delivered to the dispatched event :param kwargs: any other keyword arguments that should be delivered to the dispatched event :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns """ @@ -862,14 +862,14 @@ def on_mouse_enter(self, x: int, y: int, *args, **kwargs) -> Optional[bool]: ) return prevent_dispatch - def on_mouse_leave(self, x: int, y: int, *args, **kwargs) -> Optional[bool]: + def on_mouse_leave(self, x: int, y: int, *args, **kwargs) -> bool | None: """ Triggered when the mouse leaves the window space - Will trigger on_mouse_leave on the appropiate sections or view + Will trigger on_mouse_leave on the appropriate sections or view :param x: the x axis coordinate :param y: the y axis coordinate - :param args: any other position arguments that should be deliverd to the dispatched event + :param args: any other position arguments that should be delivered to the dispatched event :param kwargs: any other keyword arguments that should be delivered to the dispatched event :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns """ @@ -884,21 +884,21 @@ def on_mouse_leave(self, x: int, y: int, *args, **kwargs) -> Optional[bool]: self.mouse_over_sections = [] return prevent_dispatch - def on_key_press(self, *args, **kwargs) -> Optional[bool]: + def on_key_press(self, *args, **kwargs) -> bool | None: """ - Triggers the on_key_press event on the appropiate sections or view + Triggers the on_key_press event on the appropriate sections or view - :param args: any other position arguments that should be deliverd to the dispatched event + :param args: any other position arguments that should be delivered to the dispatched event :param kwargs: any other keyword arguments that should be delivered to the dispatched event :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns """ return self.dispatch_keyboard_event("on_key_press", *args, **kwargs) - def on_key_release(self, *args, **kwargs) -> Optional[bool]: + def on_key_release(self, *args, **kwargs) -> bool | None: """ - Triggers the on_key_release event on the appropiate sections or view + Triggers the on_key_release event on the appropriate sections or view - :param args: any other position arguments that should be deliverd to the dispatched event + :param args: any other position arguments that should be delivered to the dispatched event :param kwargs: any other keyword arguments that should be delivered to the dispatched event :return: EVENT_HANDLED or EVENT_UNHANDLED, or whatever the dispatched method returns """ diff --git a/arcade/shape_list.py b/arcade/shape_list.py index 4eda0b031..560b9b9bf 100644 --- a/arcade/shape_list.py +++ b/arcade/shape_list.py @@ -15,7 +15,6 @@ from typing import ( Generic, Iterable, - Optional, Sequence, TypeVar, cast, @@ -76,7 +75,7 @@ def __init__( # vao: Geometry, # vbo: Buffer, mode: int = gl.GL_TRIANGLES, - program: Optional[Program] = None, + program: Program | None = None, ) -> None: self.ctx = get_window().ctx self.program = program or self.ctx.line_generic_with_colors_program @@ -92,8 +91,8 @@ def __init__( self.data = array("f", [c for a in zip(self.points, self.colors) for b in a for c in b]) self.vertices = len(points) - self.geometry: Optional[Geometry] = None - self.buffer: Optional[Buffer] = None + self.geometry: Geometry | None = None + self.buffer: Buffer | None = None def _init_geometry(self) -> None: # NOTE: When drawing a single shape we're not using an index buffer diff --git a/arcade/sound.py b/arcade/sound.py index a0d363b11..c6484a013 100644 --- a/arcade/sound.py +++ b/arcade/sound.py @@ -8,7 +8,6 @@ import math import os from pathlib import Path -from typing import Optional, Union import pyglet from pyglet.media import Source @@ -32,7 +31,7 @@ class Sound: """This class represents a sound you can play.""" - def __init__(self, file_name: Union[str, Path], streaming: bool = False): + def __init__(self, file_name: str | Path, streaming: bool = False): self.file_name: str = "" file_name = resolve(file_name) @@ -163,7 +162,7 @@ def get_stream_position(self, player: media.Player) -> float: return player.time -def load_sound(path: Union[str, Path], streaming: bool = False) -> Sound: +def load_sound(path: str | Path, streaming: bool = False) -> Sound: """ Load a sound. @@ -194,7 +193,7 @@ def play_sound( pan: float = 0.0, loop: bool = False, speed: float = 1.0, -) -> Optional[media.Player]: +) -> media.Player | None: """ Play a sound. diff --git a/arcade/sprite/animated.py b/arcade/sprite/animated.py index 63979936e..16e97019f 100644 --- a/arcade/sprite/animated.py +++ b/arcade/sprite/animated.py @@ -3,7 +3,6 @@ import bisect import logging import math -from typing import Optional from arcade import Texture @@ -29,7 +28,7 @@ class TextureKeyframe: __slots__ = ("texture", "duration", "tile_id") - def __init__(self, texture: Texture, duration: int = 100, tile_id: Optional[int] = 0, **kwargs): + def __init__(self, texture: Texture, duration: int = 100, tile_id: int | None = 0, **kwargs): #: The texture to display for this keyframe. self.texture = texture #: Duration in milliseconds to display this keyframe. @@ -137,7 +136,7 @@ def __init__( center_x: float = 0.0, center_y: float = 0.0, scale: float = 1.0, - animation: Optional[TextureAnimation] = None, + animation: TextureAnimation | None = None, **kwargs, ): super().__init__( @@ -146,7 +145,7 @@ def __init__( center_y=center_y, ) self._time = 0.0 - self._animation: Optional[TextureAnimation] = None + self._animation: TextureAnimation | None = None if animation: self.animation = animation self._current_keyframe_index = 0 diff --git a/arcade/sprite/colored.py b/arcade/sprite/colored.py index 4e6696b3c..1e469fb2f 100644 --- a/arcade/sprite/colored.py +++ b/arcade/sprite/colored.py @@ -1,6 +1,5 @@ from __future__ import annotations -from typing import Optional from weakref import WeakValueDictionary import PIL @@ -43,7 +42,7 @@ class SpriteSolidColor(Sprite): """ __slots__ = () - _default_image: Optional[ImageData] = None + _default_image: ImageData | None = None # To avoid making lots of texture instances with the same configuration # we cache them here weakly. Making a 100 x 100 grid of white sprites # only create 1 texture instead of 1000. This saves memory and processing diff --git a/arcade/sprite/mixins.py b/arcade/sprite/mixins.py index 13fb178ab..5d2965a88 100644 --- a/arcade/sprite/mixins.py +++ b/arcade/sprite/mixins.py @@ -1,7 +1,5 @@ from __future__ import annotations -from typing import Optional - class PyMunk: """Object used to hold pymunk info for a sprite.""" @@ -15,11 +13,11 @@ class PyMunk: ) def __init__(self): - self.damping: Optional[float] = None - self.gravity: Optional[tuple[float, float]] = None - self.max_velocity: Optional[float] = None - self.max_horizontal_velocity: Optional[float] = None - self.max_vertical_velocity: Optional[float] = None + self.damping: float | None = None + self.gravity: tuple[float, float] | None = None + self.max_velocity: float | None = None + self.max_horizontal_velocity: float | None = None + self.max_vertical_velocity: float | None = None class PymunkMixin: diff --git a/arcade/sprite/sprite.py b/arcade/sprite/sprite.py index dcc014018..c87514cd5 100644 --- a/arcade/sprite/sprite.py +++ b/arcade/sprite/sprite.py @@ -2,7 +2,7 @@ import math from pathlib import Path -from typing import TYPE_CHECKING, Any, Optional, Union +from typing import TYPE_CHECKING, Any import arcade from arcade import Texture @@ -63,7 +63,7 @@ class Sprite(BasicSprite, PymunkMixin): def __init__( self, - path_or_texture: Optional[PathOrTexture] = None, + path_or_texture: PathOrTexture | None = None, scale: float = 1.0, center_x: float = 0.0, center_y: float = 0.0, @@ -97,34 +97,34 @@ def __init__( self.change_angle: float = 0.0 # Custom sprite properties - self._properties: Optional[dict[str, Any]] = None + self._properties: dict[str, Any] | None = None # Boundaries for moving platforms in tilemaps #: :py:class:`~arcade.physics_engines.PhysicsEnginePlatformer` #: uses this as the left boundary for moving #: :py:attr:`~arcade.physics_engines.PhysicsEnginePlatformer.platforms`. - self.boundary_left: Optional[float] = None + self.boundary_left: float | None = None #: :py:class:`~arcade.physics_engines.PhysicsEnginePlatformer` #: uses this as the right boundary for moving #: :py:attr:`~arcade.physics_engines.PhysicsEnginePlatformer.platforms`. - self.boundary_right: Optional[float] = None + self.boundary_right: float | None = None #: :py:class:`~arcade.physics_engines.PhysicsEnginePlatformer` #: uses this as the top boundary for moving #: :py:attr:`~arcade.physics_engines.PhysicsEnginePlatformer.platforms`. - self.boundary_top: Optional[float] = None + self.boundary_top: float | None = None #: :py:class:`~arcade.physics_engines.PhysicsEnginePlatformer` #: uses this as the top boundary for moving #: :py:attr:`~arcade.physics_engines.PhysicsEnginePlatformer.platforms`. - self.boundary_bottom: Optional[float] = None + self.boundary_bottom: float | None = None self.cur_texture_index: int = 0 self.textures: list[Texture] = _textures self.physics_engines: list[Any] = [] - self._sprite_list: Optional[SpriteList] = None + self._sprite_list: SpriteList | None = None # Debug properties - self.guid: Optional[str] = None + self.guid: str | None = None """str: A GUID for debugging purposes.""" self._hit_box: RotatableHitBox = self._hit_box.create_rotatable(angle=self._angle) @@ -216,7 +216,7 @@ def hit_box(self) -> HitBox: return self._hit_box @hit_box.setter - def hit_box(self, hit_box: Union[HitBox, RotatableHitBox]) -> None: + def hit_box(self, hit_box: HitBox | RotatableHitBox) -> None: if type(hit_box) is HitBox: self._hit_box = hit_box.create_rotatable(self.angle) else: diff --git a/arcade/sprite_list/collision.py b/arcade/sprite_list/collision.py index 804b47eef..df17496cb 100644 --- a/arcade/sprite_list/collision.py +++ b/arcade/sprite_list/collision.py @@ -4,7 +4,6 @@ from typing import ( Iterable, List, - Optional, Tuple, ) @@ -36,7 +35,7 @@ def get_distance_between_sprites(sprite1: SpriteType, sprite2: SpriteType) -> fl def get_closest_sprite( sprite: SpriteType, sprite_list: SpriteList -) -> Optional[Tuple[SpriteType, float]]: +) -> Tuple[SpriteType, float] | None: """ Given a Sprite and SpriteList, returns the closest sprite, and its distance. diff --git a/arcade/sprite_list/sprite_list.py b/arcade/sprite_list/sprite_list.py index b271dfb2e..d31eca502 100644 --- a/arcade/sprite_list/sprite_list.py +++ b/arcade/sprite_list/sprite_list.py @@ -20,9 +20,7 @@ Generic, Iterable, Iterator, - Optional, Sized, - Union, cast, ) @@ -113,13 +111,13 @@ def __init__( self, use_spatial_hash: bool = False, spatial_hash_cell_size: int = 128, - atlas: Optional[TextureAtlasBase] = None, + atlas: TextureAtlasBase | None = None, capacity: int = 100, lazy: bool = False, visible: bool = True, ) -> None: - self.program: Optional[Program] = None - self._atlas: Optional[TextureAtlasBase] = atlas + self.program: Program | None = None + self._atlas: TextureAtlasBase | None = atlas self._initialized = False self._lazy = lazy self._visible = visible @@ -153,18 +151,18 @@ def __init__( self._sprite_index_data = array("i", [0] * self._idx_capacity) # Define and annotate storage space for buffers - self._sprite_pos_buf: Optional[Buffer] = None - self._sprite_size_buf: Optional[Buffer] = None - self._sprite_angle_buf: Optional[Buffer] = None - self._sprite_color_buf: Optional[Buffer] = None - self._sprite_texture_buf: Optional[Buffer] = None + self._sprite_pos_buf: Buffer | None = None + self._sprite_size_buf: Buffer | None = None + self._sprite_angle_buf: Buffer | None = None + self._sprite_color_buf: Buffer | None = None + self._sprite_texture_buf: Buffer | None = None # Index buffer - self._sprite_index_buf: Optional[Buffer] = None + self._sprite_index_buf: Buffer | None = None - self._geometry: Optional[Geometry] = None + self._geometry: Geometry | None = None - # Flags for signaling if a buffer needs to be written to the opengl buffer + # Flags for signaling if a buffer needs to be written to the OpenGL buffer self._sprite_pos_changed: bool = False self._sprite_size_changed: bool = False self._sprite_angle_changed: bool = False @@ -176,11 +174,11 @@ def __init__( from .spatial_hash import SpatialHash self._spatial_hash_cell_size = spatial_hash_cell_size - self.spatial_hash: Optional[SpatialHash[SpriteType]] = None + self.spatial_hash: SpatialHash[SpriteType] | None = None if use_spatial_hash: self.spatial_hash = SpatialHash(cell_size=self._spatial_hash_cell_size) - self.properties: Optional[dict[str, Any]] = None + self.properties: dict[str, Any] | None = None # LOG.debug( # "[%s] Creating SpriteList use_spatial_hash=%s capacity=%s", @@ -408,7 +406,7 @@ def alpha_normalized(self, value: float) -> None: self._color = self._color[0], self._color[1], self._color[2], value @property - def atlas(self) -> Optional[TextureAtlasBase]: + def atlas(self) -> TextureAtlasBase | None: """Get the texture atlas for this sprite list""" return self._atlas @@ -724,7 +722,7 @@ def remove(self, sprite: SpriteType) -> None: if self.spatial_hash is not None: self.spatial_hash.remove(sprite) - def extend(self, sprites: Union[Iterable[SpriteType], SpriteList[SpriteType]]) -> None: + def extend(self, sprites: Iterable[SpriteType] | SpriteList[SpriteType]) -> None: """ Extends the current list with the given iterable @@ -1011,9 +1009,9 @@ def initialize(self) -> None: def draw( self, *, - filter: Optional[Union[PyGLenum, OpenGlFilter]] = None, - pixelated: Optional[bool] = None, - blend_function: Optional[BlendFunction] = None, + filter: PyGLenum | OpenGlFilter | None = None, + pixelated: bool | None = None, + blend_function: BlendFunction | None = None, ) -> None: """ Draw this list of sprites. diff --git a/arcade/text.py b/arcade/text.py index f662b376f..de1f978a5 100644 --- a/arcade/text.py +++ b/arcade/text.py @@ -18,7 +18,7 @@ __all__ = ["load_font", "Text", "create_text_sprite", "draw_text"] -def load_font(path: Union[str, Path]) -> None: +def load_font(path: str | Path) -> None: """ Load fonts in a file (usually .ttf) adding them to a global font registry. @@ -56,7 +56,7 @@ def _attempt_font_name_resolution(font_name: FontNameOrNames) -> str: argument for pyglet to attempt to resolve. This is consistent with the original behavior of this code before it was encapsulated. - :param Union[str, tuple[str, ...]] font_name: + :param str | tuple[str, ...] font_name: :return: Either a resolved path or the original tuple """ if font_name: @@ -83,7 +83,7 @@ def _attempt_font_name_resolution(font_name: FontNameOrNames) -> str: pass # failed to find it ourselves, hope pyglet can make sense of it - # Note this is the best approximation of what I unerstand the old + # Note this is the best approximation of what I understand the old # behavior to have been. return pyglet.font.load(font_list).name @@ -134,7 +134,7 @@ class Text: :param font_size: Size of the text in points :param width: A width limit in pixels :param align: Horizontal alignment; values other than "left" require width to be set - :param Union[str, tuple[str, ...]] font_name: A font name, path to a font file, or list of names + :param str | tuple[str, ...] font_name: A font name, path to a font file, or list of names :param bold: Whether to draw the text as bold, and if a string, how bold. See :py:attr:`.bold` to learn more. :param italic: Whether to draw the text as italic @@ -739,7 +739,7 @@ def draw_text( :param font_size: Size of the text in points :param width: A width limit in pixels :param align: Horizontal alignment; values other than "left" require width to be set - :param Union[str, tuple[str, ...]] font_name: A font name, path to a font file, or list of names + :param str | tuple[str, ...] font_name: A font name, path to a font file, or list of names :param bold: Whether to draw the text as bold, and if a :py:class:`str`, how bold to draw it. See :py:attr:`.Text.bold` to learn more. :param italic: Whether to draw the text as italic diff --git a/arcade/texture/generate.py b/arcade/texture/generate.py index 012ec9b4b..ca870d980 100644 --- a/arcade/texture/generate.py +++ b/arcade/texture/generate.py @@ -1,7 +1,6 @@ from __future__ import annotations import logging -from typing import Optional import PIL.Image import PIL.ImageDraw @@ -21,8 +20,8 @@ def make_circle_texture( diameter: int, color: RGBA255, - name: Optional[str] = None, - hitbox_algorithm: Optional[HitBoxAlgorithm] = None, + name: str | None = None, + hitbox_algorithm: HitBoxAlgorithm | None = None, ) -> Texture: """ Return a Texture of a circle with the given diameter and color. @@ -49,8 +48,8 @@ def make_soft_circle_texture( color: RGBA255, center_alpha: int = 255, outer_alpha: int = 0, - name: Optional[str] = None, - hit_box_algorithm: Optional[HitBoxAlgorithm] = None, + name: str | None = None, + hit_box_algorithm: HitBoxAlgorithm | None = None, ) -> Texture: """ Creates a :class:`Texture` of a circle with the given diameter and color, @@ -104,7 +103,7 @@ def make_soft_square_texture( color: RGBA255, center_alpha: int = 255, outer_alpha: int = 0, - name: Optional[str] = None, + name: str | None = None, ) -> Texture: """ Creates a :class:`Texture` of a square with the given diameter and color, diff --git a/arcade/texture/loading.py b/arcade/texture/loading.py index 1c1a929c9..bda58f83b 100644 --- a/arcade/texture/loading.py +++ b/arcade/texture/loading.py @@ -2,7 +2,6 @@ import logging from pathlib import Path -from typing import Optional, Union import PIL.Image @@ -16,10 +15,10 @@ def load_texture( - file_path: Union[str, Path], + file_path: str | Path, *, - hit_box_algorithm: Optional[HitBoxAlgorithm] = None, - hash: Optional[str] = None, + hit_box_algorithm: HitBoxAlgorithm | None = None, + hash: str | None = None, ) -> Texture: """ Load a texture from disk (no caching). @@ -61,7 +60,7 @@ def load_texture( def load_image( - file_path: Union[str, Path], + file_path: str | Path, *, mode: str = "RGBA", ) -> PIL.Image.Image: @@ -88,7 +87,7 @@ def load_image( return im -def load_spritesheet(file_name: Union[str, Path]) -> SpriteSheet: +def load_spritesheet(file_name: str | Path) -> SpriteSheet: """ Loads an image from disk returning a sprite sheet that can further be used to crop out smaller images. diff --git a/arcade/texture/manager.py b/arcade/texture/manager.py index 1fb444067..ace8f683a 100644 --- a/arcade/texture/manager.py +++ b/arcade/texture/manager.py @@ -1,6 +1,7 @@ +from __future__ import annotations + import logging from pathlib import Path -from typing import Optional, Union import PIL.Image import PIL.ImageDraw @@ -71,7 +72,7 @@ def flush( if hit_boxes: self._hit_box_cache.flush() - def _get_real_path(self, path: Union[str, Path]) -> Path: + def _get_real_path(self, path: str | Path) -> Path: """Resolve the path to the file.""" if isinstance(path, str): return arcade.resources.resolve(path) @@ -80,7 +81,7 @@ def _get_real_path(self, path: Union[str, Path]) -> Path: else: raise TypeError(f"Invalid path type: {type(path)} for {path}") - def load_or_get_spritesheet(self, path: Union[str, Path]) -> SpriteSheet: + def load_or_get_spritesheet(self, path: str | Path) -> SpriteSheet: """ Load a sprite sheet from disk, or return a cached version. @@ -99,12 +100,12 @@ def load_or_get_spritesheet(self, path: Union[str, Path]) -> SpriteSheet: def load_or_get_spritesheet_texture( self, - path: Union[str, Path], + path: str | Path, x: int, y: int, width: int, height: int, - hit_box_algorithm: Optional[hitbox.HitBoxAlgorithm] = None, + hit_box_algorithm: hitbox.HitBoxAlgorithm | None = None, ) -> Texture: """ Slice out a a texture at x, y, width, height from a sprite sheet. @@ -136,8 +137,8 @@ def load_or_get_spritesheet_texture( def load_or_get_image( self, - path: Union[str, Path], - hash: Optional[str] = None, + path: str | Path, + hash: str | None = None, mode="RGBA", ) -> ImageData: """ @@ -161,13 +162,13 @@ def load_or_get_image( def load_or_get_texture( self, - file_path: Union[str, Path], + file_path: str | Path, *, x: int = 0, y: int = 0, width: int = 0, height: int = 0, - hit_box_algorithm: Optional[hitbox.HitBoxAlgorithm] = None, + hit_box_algorithm: hitbox.HitBoxAlgorithm | None = None, ) -> Texture: """ Load an image from disk and create a texture. @@ -195,13 +196,13 @@ def load_or_get_texture( def _load_or_get_texture( self, file_path: Path, - hit_box_algorithm: Optional[hitbox.HitBoxAlgorithm] = None, + hit_box_algorithm: hitbox.HitBoxAlgorithm | None = None, crop: tuple[int, int, int, int] = (0, 0, 0, 0), - hash: Optional[str] = None, + hash: str | None = None, ) -> Texture: """Load a texture, or return a cached version if it's already loaded.""" hit_box_algorithm = hit_box_algorithm or hitbox.algo_default - image_data: Optional[ImageData] = None + image_data: ImageData | None = None texture = None # Load the image data from disk or get from cache @@ -242,7 +243,7 @@ def _load_or_get_texture( def _load_or_get_image( self, file_path: Path, - hash: Optional[str] = None, + hash: str | None = None, mode: str = "RGBA", ) -> tuple[ImageData, bool]: """ diff --git a/arcade/texture/spritesheet.py b/arcade/texture/spritesheet.py index d654914b7..6e18d17ee 100644 --- a/arcade/texture/spritesheet.py +++ b/arcade/texture/spritesheet.py @@ -1,8 +1,12 @@ +from __future__ import annotations + from pathlib import Path -from typing import TYPE_CHECKING, Literal, Optional, Union +from typing import TYPE_CHECKING, Literal from PIL import Image +from arcade.resources import resolve + # from arcade import Texture from arcade.texture import Texture @@ -27,11 +31,9 @@ class SpriteSheet: def __init__( self, - path: Optional[Union[str, Path]] = None, - image: Optional[Image.Image] = None, + path: str | Path | None = None, + image: Image.Image | None = None, ): - from arcade.resources import resolve - self._path = None if path: self._path = resolve(path) @@ -64,7 +66,7 @@ def image(self, image: Image.Image): self._image = image @property - def path(self) -> Optional[Path]: + def path(self) -> Path | None: """ The path to the sprite sheet. @@ -129,7 +131,7 @@ def get_texture( y: int, width: int, height: int, - hit_box_algorithm: Optional["HitBoxAlgorithm"] = None, + hit_box_algorithm: HitBoxAlgorithm | None = None, origin: OriginChoices = "upper_left", ) -> Texture: """ @@ -182,7 +184,7 @@ def get_texture_grid( columns: int, count: int, margin: tuple[int, int, int, int] = (0, 0, 0, 0), - hit_box_algorithm: Optional["HitBoxAlgorithm"] = None, + hit_box_algorithm: HitBoxAlgorithm | None = None, ) -> list[Texture]: """ Slice a grid of textures from the sprite sheet. diff --git a/arcade/texture/texture.py b/arcade/texture/texture.py index 15f6b6e4d..0b8274987 100644 --- a/arcade/texture/texture.py +++ b/arcade/texture/texture.py @@ -3,7 +3,7 @@ import hashlib import logging from pathlib import Path -from typing import Any, Optional, Type, Union +from typing import Any import PIL.Image import PIL.ImageDraw @@ -51,7 +51,7 @@ class ImageData: __slots__ = ("image", "hash", "__weakref__") hash_func = "sha256" - def __init__(self, image: PIL.Image.Image, hash: Optional[str] = None, **kwargs): + def __init__(self, image: PIL.Image.Image, hash: str | None = None, **kwargs): self.image = image self.hash = hash or self.calculate_hash(image) @@ -143,11 +143,11 @@ class Texture: def __init__( self, - image: Union[PIL.Image.Image, ImageData], + image: PIL.Image.Image | ImageData, *, - hit_box_algorithm: Optional[HitBoxAlgorithm] = None, - hit_box_points: Optional[Point2List] = None, - hash: Optional[str] = None, + hit_box_algorithm: HitBoxAlgorithm | None = None, + hit_box_points: Point2List | None = None, + hash: str | None = None, **kwargs, ): # Overrides the hash @@ -183,8 +183,8 @@ def __init__( self._hit_box_points: Point2List = hit_box_points or self._calculate_hit_box_points() # Optional filename for debugging - self._file_path: Optional[Path] = None - self._crop_values: Optional[tuple[int, int, int, int]] = None + self._file_path: Path | None = None + self._crop_values: tuple[int, int, int, int] | None = None self._properties: dict[str, Any] = {} @property @@ -207,7 +207,7 @@ def cache_name(self) -> str: return self._cache_name @property - def image_cache_name(self) -> Optional[str]: + def image_cache_name(self) -> str | None: """ Get the image cache name for this texture. Returns None if file_path is not set. @@ -264,7 +264,7 @@ def _update_cache_names(self): @classmethod def create_image_cache_name( - cls, path: Union[str, Path], crop: tuple[int, int, int, int] = (0, 0, 0, 0) + cls, path: str | Path, crop: tuple[int, int, int, int] = (0, 0, 0, 0) ): return f"{str(path)}|{crop}" @@ -278,7 +278,7 @@ def atlas_name(self) -> str: return self._atlas_name @property - def file_path(self) -> Optional[Path]: + def file_path(self) -> Path | None: """ A Path object to the file this texture was loaded from @@ -287,11 +287,11 @@ def file_path(self) -> Optional[Path]: return self._file_path @file_path.setter - def file_path(self, path: Optional[Path]): + def file_path(self, path: Path | None): self._file_path = path @property - def crop_values(self) -> Optional[tuple[int, int, int, int]]: + def crop_values(self) -> tuple[int, int, int, int] | None: """ The crop values used to create this texture in the referenced file @@ -300,7 +300,7 @@ def crop_values(self) -> Optional[tuple[int, int, int, int]]: return self._crop_values @crop_values.setter - def crop_values(self, crop: Optional[tuple[int, int, int, int]]): + def crop_values(self, crop: tuple[int, int, int, int] | None): self._crop_values = crop @property @@ -616,7 +616,7 @@ def rotate_270(self) -> "Texture": def transform( self, - transform: Type[Transform], + transform: type[Transform], ) -> "Texture": """ Create a new texture with the given transform applied. diff --git a/arcade/texture_atlas/atlas_array.py b/arcade/texture_atlas/atlas_array.py index dc0a5cef1..63cff73e1 100644 --- a/arcade/texture_atlas/atlas_array.py +++ b/arcade/texture_atlas/atlas_array.py @@ -2,9 +2,10 @@ THIS IS WORK IN PROGRESS. DO NOT USE. """ +from __future__ import annotations + from typing import ( TYPE_CHECKING, - Optional, Tuple, ) @@ -24,7 +25,7 @@ class TextureArrayAtlas(TextureAtlasBase): layers (int): The number of layers (number of textures to store) """ - def __init__(self, ctx: Optional[ArcadeContext], size: Tuple[int, int], layers: int): + def __init__(self, ctx: ArcadeContext | None, size: Tuple[int, int], layers: int): super().__init__(ctx) self._size = size self._layers = layers diff --git a/arcade/texture_atlas/atlas_bindless.py b/arcade/texture_atlas/atlas_bindless.py index 0db493305..0a3d4ce97 100644 --- a/arcade/texture_atlas/atlas_bindless.py +++ b/arcade/texture_atlas/atlas_bindless.py @@ -2,6 +2,8 @@ THIS IS WORK IN PROGRESS. DO NOT USE. """ +from __future__ import annotations + from typing import TYPE_CHECKING from .base import TextureAtlasBase diff --git a/arcade/texture_atlas/atlas_default.py b/arcade/texture_atlas/atlas_default.py index bfb151aac..28b2081ec 100644 --- a/arcade/texture_atlas/atlas_default.py +++ b/arcade/texture_atlas/atlas_default.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import contextlib import copy import logging @@ -5,9 +7,7 @@ from pathlib import Path from typing import ( TYPE_CHECKING, - Optional, Sequence, - Union, ) from weakref import WeakSet, WeakValueDictionary, finalize @@ -94,9 +94,9 @@ def __init__( size: tuple[int, int], *, border: int = 1, - textures: Optional[Sequence["Texture"]] = None, + textures: Sequence[Texture] | None = None, auto_resize: bool = True, - ctx: Optional["ArcadeContext"] = None, + ctx: ArcadeContext | None = None, capacity: int = 2, ): self._ctx = ctx or get_window().ctx @@ -727,7 +727,7 @@ def use_uv_texture(self, unit: int = 0) -> None: def render_into( self, texture: "Texture", - projection: Optional[tuple[float, float, float, float]] = None, + projection: tuple[float, float, float, float] | None = None, ): """ Render directly into a sub-section of the atlas. @@ -874,7 +874,7 @@ def show( def save( self, - path: Union[str, Path], + path: str | Path, flip: bool = False, components: int = 4, draw_borders: bool = False, diff --git a/arcade/texture_atlas/base.py b/arcade/texture_atlas/base.py index 7484ef1f6..e618c6996 100644 --- a/arcade/texture_atlas/base.py +++ b/arcade/texture_atlas/base.py @@ -28,11 +28,7 @@ import abc import contextlib from pathlib import Path -from typing import ( - TYPE_CHECKING, - Optional, - Union, -) +from typing import TYPE_CHECKING import PIL.Image @@ -64,7 +60,7 @@ class TextureAtlasBase(abc.ABC): _fbo: Framebuffer _texture: Texture2D - def __init__(self, ctx: Optional["ArcadeContext"]): + def __init__(self, ctx: ArcadeContext | None): self._ctx = ctx or arcade.get_window().ctx self._size: tuple[int, int] = 0, 0 self._layers: int = 1 @@ -237,7 +233,7 @@ def use_uv_texture(self, unit: int = 0) -> None: def render_into( self, texture: "Texture", - projection: Optional[tuple[float, float, float, float]] = None, + projection: tuple[float, float, float, float] | None = None, ): """ Render directly into a sub-section of the atlas. @@ -369,7 +365,7 @@ def show( @abc.abstractmethod def save( self, - path: Union[str, Path], + path: str | Path, flip: bool = False, components: int = 4, draw_borders: bool = False, diff --git a/arcade/texture_atlas/ref_counters.py b/arcade/texture_atlas/ref_counters.py index 044abbf21..50b127122 100644 --- a/arcade/texture_atlas/ref_counters.py +++ b/arcade/texture_atlas/ref_counters.py @@ -8,6 +8,8 @@ simply a texture using the same image and the same vertex order. """ +from __future__ import annotations + from typing import TYPE_CHECKING, Dict if TYPE_CHECKING: diff --git a/arcade/texture_atlas/region.py b/arcade/texture_atlas/region.py index 55bfbbcf0..ab79cde3f 100644 --- a/arcade/texture_atlas/region.py +++ b/arcade/texture_atlas/region.py @@ -2,7 +2,9 @@ Metadata about where an image is located in the atlas. """ -from typing import TYPE_CHECKING, Optional +from __future__ import annotations + +from typing import TYPE_CHECKING from .base import TexCoords, TextureAtlasBase @@ -59,7 +61,7 @@ def __init__( y: int, width: int, height: int, - texture_coordinates: Optional[TexCoords] = None, + texture_coordinates: TexCoords | None = None, ): #: X position of the texture in the atlas self.x = x diff --git a/arcade/texture_atlas/uv_data.py b/arcade/texture_atlas/uv_data.py index 7a8d4eef6..2a33355db 100644 --- a/arcade/texture_atlas/uv_data.py +++ b/arcade/texture_atlas/uv_data.py @@ -2,6 +2,8 @@ A helper class to keep track of texture coordinates stored in a texture. """ +from __future__ import annotations + from array import array from collections import deque from typing import TYPE_CHECKING, Dict diff --git a/arcade/tilemap/tilemap.py b/arcade/tilemap/tilemap.py index 32dda8a8e..6a1ffdf00 100644 --- a/arcade/tilemap/tilemap.py +++ b/arcade/tilemap/tilemap.py @@ -14,7 +14,7 @@ import os from collections import OrderedDict from pathlib import Path -from typing import TYPE_CHECKING, Any, Callable, Optional, Union, cast +from typing import TYPE_CHECKING, Any, Callable, cast import pytiled_parser import pytiled_parser.tiled_object @@ -80,8 +80,8 @@ def _get_image_info_from_tileset(tile: pytiled_parser.Tile) -> tuple[int, int, i def _get_image_source( tile: pytiled_parser.Tile, - map_directory: Optional[str], -) -> Optional[Path]: + map_directory: str | None, +) -> Path | None: image_file = None if tile.image: image_file = tile.image @@ -124,7 +124,7 @@ class TileMap: https://api.arcade.academy/en/latest/examples/platform_tutorial/step_09.html - :param Union[str, Path] map_file: A JSON map file for a Tiled map to initialize from + :param str | Path map_file: A JSON map file for a Tiled map to initialize from :param scaling: Global scaling to apply to all Sprites. :param Dict[str, Dict[str, Any]] layer_options: Extra parameters for each layer. :param use_spatial_hash: If set to True, this will make moving a sprite @@ -190,7 +190,7 @@ class TileMap: "The width in pixels of each tile." tile_height: float "The height in pixels of each tile." - background_color: Optional[Color] + background_color: Color | None "The background color of the map." scaling: float "A global scaling value to be applied to all Sprites in the map." @@ -207,16 +207,16 @@ class TileMap: def __init__( self, - map_file: Union[str, Path] = "", + map_file: str | Path = "", scaling: float = 1.0, - layer_options: Optional[dict[str, dict[str, Any]]] = None, + layer_options: dict[str, dict[str, Any]] | None = None, use_spatial_hash: bool = False, - hit_box_algorithm: Optional[HitBoxAlgorithm] = None, - tiled_map: Optional[pytiled_parser.TiledMap] = None, + hit_box_algorithm: HitBoxAlgorithm | None = None, + tiled_map: pytiled_parser.TiledMap | None = None, offset: Vec2 = Vec2(0, 0), - texture_atlas: Optional["TextureAtlasBase"] = None, + texture_atlas: TextureAtlasBase | None = None, lazy: bool = False, - texture_cache_manager: Optional[arcade.TextureCacheManager] = None, + texture_cache_manager: arcade.TextureCacheManager | None = None, ) -> None: if not map_file and not tiled_map: raise AttributeError( @@ -287,9 +287,9 @@ def _process_layer( self, layer: pytiled_parser.Layer, global_options: dict[str, Any], - layer_options: Optional[dict[str, dict[str, Any]]] = None, + layer_options: dict[str, dict[str, Any]] | None = None, ) -> None: - processed: Union[SpriteList, tuple[Optional[SpriteList], Optional[list[TiledObject]]]] + processed: SpriteList | tuple[SpriteList | None, list[TiledObject] | None] options = global_options @@ -344,7 +344,7 @@ def get_cartesian( return x, y - def get_tilemap_layer(self, layer_path: str) -> Optional[pytiled_parser.Layer]: + def get_tilemap_layer(self, layer_path: str) -> pytiled_parser.Layer | None: assert isinstance(layer_path, str) def _get_tilemap_layer(my_path, layers): @@ -362,8 +362,8 @@ def _get_tilemap_layer(my_path, layers): layer = _get_tilemap_layer(path, self.tiled_map.layers) return layer - def _get_tile_by_gid(self, tile_gid: int) -> Optional[pytiled_parser.Tile]: - tile_ref: Optional[pytiled_parser.Tile] + def _get_tile_by_gid(self, tile_gid: int) -> pytiled_parser.Tile | None: + tile_ref: pytiled_parser.Tile | None flipped_diagonally = False flipped_horizontally = False @@ -424,7 +424,7 @@ def _get_tile_by_gid(self, tile_gid: int) -> Optional[pytiled_parser.Tile]: def _get_tile_by_id( self, tileset: pytiled_parser.Tileset, tile_id: int - ) -> Optional[pytiled_parser.Tile]: + ) -> pytiled_parser.Tile | None: for tileset_key, cur_tileset in self.tiled_map.tilesets.items(): if cur_tileset is tileset: if cur_tileset.tiles: @@ -438,8 +438,8 @@ def _create_sprite_from_tile( self, tile: pytiled_parser.Tile, scaling: float = 1.0, - hit_box_algorithm: Optional[HitBoxAlgorithm] = None, - custom_class: Optional[type] = None, + hit_box_algorithm: HitBoxAlgorithm | None = None, + custom_class: type | None = None, custom_class_args: dict[str, Any] = {}, ) -> Sprite: """Given a tile from the parser, try and create a Sprite from it.""" @@ -645,9 +645,9 @@ def _process_image_layer( texture_atlas: "DefaultTextureAtlas", scaling: float = 1.0, use_spatial_hash: bool = False, - hit_box_algorithm: Optional[HitBoxAlgorithm] = None, + hit_box_algorithm: HitBoxAlgorithm | None = None, offset: Vec2 = Vec2(0, 0), - custom_class: Optional[type] = None, + custom_class: type | None = None, custom_class_args: dict[str, Any] = {}, ) -> SpriteList: sprite_list: SpriteList = SpriteList( @@ -730,9 +730,9 @@ def _process_tile_layer( texture_atlas: "DefaultTextureAtlas", scaling: float = 1.0, use_spatial_hash: bool = False, - hit_box_algorithm: Optional[HitBoxAlgorithm] = None, + hit_box_algorithm: HitBoxAlgorithm | None = None, offset: Vec2 = Vec2(0, 0), - custom_class: Optional[type] = None, + custom_class: type | None = None, custom_class_args: dict[str, Any] = {}, ) -> SpriteList: sprite_list: SpriteList = SpriteList( @@ -808,21 +808,21 @@ def _process_object_layer( texture_atlas: "DefaultTextureAtlas", scaling: float = 1.0, use_spatial_hash: bool = False, - hit_box_algorithm: Optional[HitBoxAlgorithm] = None, + hit_box_algorithm: HitBoxAlgorithm | None = None, offset: Vec2 = Vec2(0, 0), - custom_class: Optional[type] = None, + custom_class: type | None = None, custom_class_args: dict[str, Any] = {}, - ) -> tuple[Optional[SpriteList], Optional[list[TiledObject]]]: + ) -> tuple[SpriteList | None, list[TiledObject] | None]: if not scaling: scaling = self.scaling - sprite_list: Optional[SpriteList] = None - objects_list: Optional[list[TiledObject]] = [] + sprite_list: SpriteList | None = None + objects_list: list[TiledObject] | None = [] - shape: Union[list[Point2], tuple[int, int, int, int], Point2, None] = None + shape: list[Point2] | tuple[int, int, int, int] | Point2 | None = None for cur_object in layer.tiled_objects: - # shape: Optional[Union[Point, PointList, Rect]] = None + # shape: Optional[Point | PointList | Rect] = None if isinstance(cur_object, pytiled_parser.tiled_object.Tile): if not sprite_list: sprite_list = SpriteList( @@ -995,13 +995,13 @@ def _process_object_layer( def load_tilemap( - map_file: Union[str, Path], + map_file: str | Path, scaling: float = 1.0, - layer_options: Optional[dict[str, dict[str, Any]]] = None, + layer_options: dict[str, dict[str, Any]] | None = None, use_spatial_hash: bool = False, - hit_box_algorithm: Optional[HitBoxAlgorithm] = None, + hit_box_algorithm: HitBoxAlgorithm | None = None, offset: Vec2 = Vec2(0, 0), - texture_atlas: Optional["DefaultTextureAtlas"] = None, + texture_atlas: DefaultTextureAtlas | None = None, lazy: bool = False, ) -> TileMap: """ @@ -1013,7 +1013,7 @@ def load_tilemap( For more clarification on the layer_options key, see the `__init__` function of the `TileMap` class - :param Union[str, Path] map_file: The JSON map file. + :param str | Path map_file: The JSON map file. :param scaling: The global scaling to apply to all Sprite's within the map. :param use_spatial_hash: If set to True, this will make moving a sprite in the SpriteList slower, but it will speed up collision detection @@ -1038,7 +1038,7 @@ def load_tilemap( ) -def read_tmx(map_file: Union[str, Path]) -> pytiled_parser.TiledMap: +def read_tmx(map_file: str | Path) -> pytiled_parser.TiledMap: """ Deprecated function to raise a warning that it has been removed. diff --git a/arcade/types/__init__.py b/arcade/types/__init__.py index 3c66bfd1d..3a0fef99c 100644 --- a/arcade/types/__init__.py +++ b/arcade/types/__init__.py @@ -26,7 +26,7 @@ # flake8: noqa: E402 import sys from pathlib import Path -from typing import NamedTuple, Optional, Union, TYPE_CHECKING, TypeVar +from typing import NamedTuple, Union, TYPE_CHECKING, TypeVar from pytiled_parser import Properties @@ -187,6 +187,6 @@ class TiledObject(NamedTuple): shape: Union[Point, PointList, tuple[int, int, int, int]] - properties: Optional[Properties] = None - name: Optional[str] = None - type: Optional[str] = None + properties: Properties | None = None + name: str | None = None + type: str | None = None diff --git a/arcade/types/color.py b/arcade/types/color.py index 0294ab76a..1f474ad59 100644 --- a/arcade/types/color.py +++ b/arcade/types/color.py @@ -21,7 +21,7 @@ from __future__ import annotations import random -from typing import Iterable, Optional, TypeVar, Union +from typing import Iterable, TypeVar, Union from typing_extensions import Final, Self @@ -464,10 +464,10 @@ def from_hex_string(cls, code: str) -> Self: @classmethod def random( cls, - r: Optional[int] = None, - g: Optional[int] = None, - b: Optional[int] = None, - a: Optional[int] = None, + r: int | None = None, + g: int | None = None, + b: int | None = None, + a: int | None = None, ) -> Self: """Create a :py:class:`Color` by randomizing all unspecified channels. @@ -503,10 +503,10 @@ def random( def replace( self, - r: Optional[int] = None, - g: Optional[int] = None, - b: Optional[int] = None, - a: Optional[int] = None, + r: int | None = None, + g: int | None = None, + b: int | None = None, + a: int | None = None, ) -> Color: """Create a :py:class:`Color` with specified values replaced in a predefined color. diff --git a/arcade/types/rect.py b/arcade/types/rect.py index 9419000ee..c9fe5366c 100644 --- a/arcade/types/rect.py +++ b/arcade/types/rect.py @@ -3,7 +3,7 @@ from __future__ import annotations import math -from typing import NamedTuple, Optional, TypedDict +from typing import NamedTuple, TypedDict from pyglet.math import Vec2 @@ -187,8 +187,8 @@ def move(self, dx: AsFloat = 0.0, dy: AsFloat = 0.0) -> Rect: def resize( self, - width: Optional[AsFloat] = None, - height: Optional[AsFloat] = None, + width: AsFloat | None = None, + height: AsFloat | None = None, anchor: Vec2 = AnchorPoint.CENTER, ) -> Rect: """ @@ -307,8 +307,8 @@ def align_center_y(self, value: AsFloat) -> Rect: def min_size( self, - width: Optional[AsFloat] = None, - height: Optional[AsFloat] = None, + width: AsFloat | None = None, + height: AsFloat | None = None, anchor: Vec2 = AnchorPoint.CENTER, ) -> Rect: """ @@ -321,8 +321,8 @@ def min_size( def max_size( self, - width: Optional[AsFloat] = None, - height: Optional[AsFloat] = None, + width: AsFloat | None = None, + height: AsFloat | None = None, anchor: Vec2 = AnchorPoint.CENTER, ) -> Rect: """ @@ -335,8 +335,8 @@ def max_size( def clamp_height( self, - min_height: Optional[AsFloat] = None, - max_height: Optional[AsFloat] = None, + min_height: AsFloat | None = None, + max_height: AsFloat | None = None, anchor: Vec2 = AnchorPoint.CENTER, ) -> Rect: """ @@ -348,8 +348,8 @@ def clamp_height( def clamp_width( self, - min_width: Optional[AsFloat] = None, - max_width: Optional[AsFloat] = None, + min_width: AsFloat | None = None, + max_width: AsFloat | None = None, anchor: Vec2 = AnchorPoint.CENTER, ) -> Rect: """Return a :py:class:`.Rect` constrained to the passed dimension. @@ -372,10 +372,10 @@ def clamp_width( def clamp_size( self, - min_width: Optional[AsFloat] = None, - max_width: Optional[AsFloat] = None, - min_height: Optional[AsFloat] = None, - max_height: Optional[AsFloat] = None, + min_width: AsFloat | None = None, + max_width: AsFloat | None = None, + min_height: AsFloat | None = None, + max_height: AsFloat | None = None, anchor: Vec2 = AnchorPoint.CENTER, ) -> Rect: """Get a new clamped-size rectangle at the same position and anchored at ``anchor_point``. diff --git a/arcade/utils.py b/arcade/utils.py index 1900e12a6..20988b95b 100644 --- a/arcade/utils.py +++ b/arcade/utils.py @@ -197,7 +197,7 @@ class ReplacementWarning(Warning): pass -def warning(warning_type: Type[Warning], message: str = "", **kwargs): +def warning(warning_type: type[Warning], message: str = "", **kwargs): def actual_warning_decorator(func): nonlocal message if warning_type == ReplacementWarning and not message: diff --git a/arcade/window_commands.py b/arcade/window_commands.py index 250e0fcc1..2a8d34b4e 100644 --- a/arcade/window_commands.py +++ b/arcade/window_commands.py @@ -8,7 +8,7 @@ import gc import os -from typing import TYPE_CHECKING, Callable, Optional +from typing import TYPE_CHECKING, Callable import pyglet @@ -18,7 +18,7 @@ from arcade import Window -_window: Optional["Window"] = None +_window: Window | None = None __all__ = [ "get_display_size", @@ -64,7 +64,7 @@ def get_window() -> "Window": return _window -def set_window(window: Optional["Window"]) -> None: +def set_window(window: Window | None) -> None: """ Set a handle to the current window. diff --git a/make.py b/make.py index 28acd5a3a..1b74df39a 100755 --- a/make.py +++ b/make.py @@ -18,7 +18,7 @@ from contextlib import contextmanager from pathlib import Path from shutil import rmtree, which -from typing import Generator, Optional, Union +from typing import Generator, Union PathLike = Union[Path, str, bytes] @@ -141,7 +141,7 @@ def cd_context(directory: PathLike) -> Generator[Path, None, None]: os.chdir(_original_dir) -def run(args: Union[str, list[str]], cd: Optional[PathLike] = None) -> None: +def run(args: str | list[str], cd: PathLike | None = None) -> None: """ Try to run `args` with subprocess, switching into & out of `cd` if provided. @@ -162,7 +162,7 @@ def run(args: Union[str, list[str]], cd: Optional[PathLike] = None) -> None: exit(result.returncode) -def run_doc(args: Union[str, list[str]]) -> None: +def run_doc(args: str | list[str]) -> None: run(args, cd=FULL_DOC_DIR)