Skip to content

Commit f06a1b0

Browse files
authored
Separate exceptions/warnings from utils (#2292)
1 parent 3b8e52f commit f06a1b0

File tree

9 files changed

+167
-163
lines changed

9 files changed

+167
-163
lines changed

arcade/exceptions.py

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
"""
2+
Custom arcade errors, exceptions, and warnings.
3+
"""
4+
5+
import functools
6+
import warnings
7+
from typing import Type, TypeVar
8+
9+
__all__ = [
10+
"OutsideRangeError",
11+
"IntOutsideRangeError",
12+
"FloatOutsideRangeError",
13+
"ByteRangeError",
14+
"NormalizedRangeError",
15+
"PerformanceWarning",
16+
"ReplacementWarning",
17+
"warning",
18+
]
19+
20+
# Since this module forbids importing from the rest of
21+
# Arcade, we make our own local type variables.
22+
_TType = TypeVar("_TType", bound=Type)
23+
_CT = TypeVar("_CT") # Comparable type, ie supports the <= operator
24+
25+
26+
class OutsideRangeError(ValueError):
27+
"""
28+
Raised when a value is outside and expected range
29+
30+
This class and its subclasses are intended to be arcade-internal
31+
helpers to clearly signal exactly what went wrong. Each helps
32+
type annotate and template a string describing exactly what went
33+
wrong.
34+
35+
Args:
36+
var_name: The name of the variable or argument
37+
value: The value that fell outside the expected range
38+
lower: The lower bound, inclusive, of the range
39+
upper: The upper bound, inclusive, of the range
40+
"""
41+
42+
def __init__(self, var_name: str, value: _CT, lower: _CT, upper: _CT) -> None:
43+
super().__init__(f"{var_name} must be between {lower} and {upper}, inclusive, not {value}")
44+
self.var_name = var_name
45+
self.value = value
46+
self.lower = lower
47+
self.upper = upper
48+
49+
50+
class IntOutsideRangeError(OutsideRangeError):
51+
"""
52+
An integer was outside an expected range
53+
54+
This class was originally intended to assist deserialization from
55+
data packed into ints, such as :py:class:`~arcade.types.Color`.
56+
57+
Args:
58+
var_name: The name of the variable or argument
59+
value: The value that fell outside the expected range
60+
lower: The lower bound, inclusive, of the range
61+
upper: The upper bound, inclusive, of the range
62+
"""
63+
64+
def __init__(self, var_name: str, value: int, lower: int, upper: int) -> None:
65+
super().__init__(var_name, value, lower, upper)
66+
67+
68+
class FloatOutsideRangeError(OutsideRangeError):
69+
"""
70+
A float value was outside an expected range
71+
72+
Args:
73+
var_name: The name of the variable or argument
74+
value: The value that fell outside the expected range
75+
lower: The lower bound, inclusive, of the range
76+
upper: The upper bound, inclusive, of the range
77+
"""
78+
79+
def __init__(self, var_name: str, value: float, lower: float, upper: float) -> None:
80+
super().__init__(var_name, value, lower, upper)
81+
82+
83+
class ByteRangeError(IntOutsideRangeError):
84+
"""
85+
An int was outside the range of 0 to 255 inclusive
86+
87+
:param var_name: the name of the variable or argument
88+
:param value: the value to fall outside the expected range
89+
"""
90+
91+
def __init__(self, var_name: str, value: int) -> None:
92+
super().__init__(var_name, value, 0, 255)
93+
94+
95+
class NormalizedRangeError(FloatOutsideRangeError):
96+
"""
97+
A float was not between 0.0 and 1.0, inclusive
98+
99+
Note that normalized floats should not normally be bound-checked as
100+
before drawing as this is taken care of on the GPU side.
101+
102+
The exceptions to this are when processing data on the Python side,
103+
especially when it is cheaper to bound check two floats than call
104+
clamping functions.
105+
106+
:param var_name: the name of the variable or argument
107+
:param value: the value to fall outside the expected range
108+
"""
109+
110+
def __init__(self, var_name: str, value: float) -> None:
111+
super().__init__(var_name, value, 0.0, 1.0)
112+
113+
114+
class PerformanceWarning(Warning):
115+
"""Issuing performance warnings on slow paths."""
116+
117+
pass
118+
119+
120+
class ReplacementWarning(Warning):
121+
"""Issuing warnings about naming and functionality changes."""
122+
123+
pass
124+
125+
126+
def warning(warning_type: type[Warning], message: str = "", **kwargs):
127+
"""Warning decorator"""
128+
129+
def actual_warning_decorator(func):
130+
nonlocal message
131+
if warning_type == ReplacementWarning and not message:
132+
message = f"{func.__name__} is deprecated. Use {kwargs.get('new_name', '')} instead."
133+
134+
@functools.wraps(func)
135+
def wrapper(*args, **kwargs):
136+
warnings.warn(message, warning_type)
137+
return func(*args, **kwargs)
138+
139+
return wrapper
140+
141+
return actual_warning_decorator

arcade/resources/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from pathlib import Path
44
from typing import Sequence
5-
from arcade.utils import warning, ReplacementWarning
5+
from arcade.exceptions import warning, ReplacementWarning
66

77
#: The absolute path to this directory
88
RESOURCE_DIR = Path(__file__).parent.resolve()

arcade/sprite/base.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66

77
import arcade
88
from arcade.color import BLACK, WHITE
9+
from arcade.exceptions import ReplacementWarning, warning
910
from arcade.hitbox import HitBox
1011
from arcade.texture import Texture
1112
from arcade.types import LRBT, RGBA255, AsFloat, Color, Point, Point2, PointList, Rect, RGBOrA255
12-
from arcade.utils import ReplacementWarning, copy_dunders_unimplemented, warning
13+
from arcade.utils import copy_dunders_unimplemented
1314

1415
if TYPE_CHECKING:
1516
from arcade.sprite_list import SpriteList

arcade/text.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
import pyglet
1111

1212
import arcade
13+
from arcade.exceptions import PerformanceWarning, warning
1314
from arcade.resources import resolve
1415
from arcade.texture_atlas import TextureAtlasBase
1516
from arcade.types import Color, Point, RGBOrA255
16-
from arcade.utils import PerformanceWarning, warning
1717

1818
__all__ = ["load_font", "Text", "create_text_sprite", "draw_text"]
1919

arcade/types/color.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
from typing_extensions import Final, Self
2727

28-
from arcade.utils import ByteRangeError, IntOutsideRangeError, NormalizedRangeError
28+
from arcade.exceptions import ByteRangeError, IntOutsideRangeError, NormalizedRangeError
2929

3030
__all__ = (
3131
"Color",

0 commit comments

Comments
 (0)