Add convenience utilities (#3)
This commit is contained in:
parent
a580b9b093
commit
2d127c26a2
@ -25,7 +25,11 @@ from .errors import (
|
||||
HTTPException,
|
||||
GatewayException,
|
||||
AuthenticationError,
|
||||
Forbidden,
|
||||
NotFound,
|
||||
)
|
||||
from .color import Color
|
||||
from .utils import utcnow
|
||||
from .enums import GatewayIntent, GatewayOpcode # Export enums
|
||||
from .error_handler import setup_global_error_handler
|
||||
from .hybrid_context import HybridContext
|
||||
|
50
disagreement/color.py
Normal file
50
disagreement/color.py
Normal file
@ -0,0 +1,50 @@
|
||||
"""Simple color helper similar to discord.py's Color class."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Color:
|
||||
"""Represents an RGB color value."""
|
||||
|
||||
value: int
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if not 0 <= self.value <= 0xFFFFFF:
|
||||
raise ValueError("Color value must be between 0x000000 and 0xFFFFFF")
|
||||
|
||||
@classmethod
|
||||
def from_rgb(cls, r: int, g: int, b: int) -> "Color":
|
||||
"""Create a Color from red, green and blue components."""
|
||||
if not all(0 <= c <= 255 for c in (r, g, b)):
|
||||
raise ValueError("RGB components must be between 0 and 255")
|
||||
return cls((r << 16) + (g << 8) + b)
|
||||
|
||||
@classmethod
|
||||
def from_hex(cls, value: str) -> "Color":
|
||||
"""Create a Color from a hex string like ``"#ff0000"``."""
|
||||
value = value.lstrip("#")
|
||||
if len(value) != 6:
|
||||
raise ValueError("Hex string must be in RRGGBB format")
|
||||
return cls(int(value, 16))
|
||||
|
||||
@classmethod
|
||||
def default(cls) -> "Color":
|
||||
return cls(0)
|
||||
|
||||
@classmethod
|
||||
def red(cls) -> "Color":
|
||||
return cls(0xFF0000)
|
||||
|
||||
@classmethod
|
||||
def green(cls) -> "Color":
|
||||
return cls(0x00FF00)
|
||||
|
||||
@classmethod
|
||||
def blue(cls) -> "Color":
|
||||
return cls(0x0000FF)
|
||||
|
||||
def to_rgb(self) -> tuple[int, int, int]:
|
||||
return ((self.value >> 16) & 0xFF, (self.value >> 8) & 0xFF, self.value & 0xFF)
|
@ -77,14 +77,19 @@ class RateLimitError(HTTPException):
|
||||
)
|
||||
|
||||
|
||||
# You can add more specific exceptions as needed, e.g.:
|
||||
# class NotFound(HTTPException):
|
||||
# """Raised for 404 Not Found errors."""
|
||||
# pass
|
||||
# Specific HTTP error exceptions
|
||||
|
||||
# class Forbidden(HTTPException):
|
||||
# """Raised for 403 Forbidden errors."""
|
||||
# pass
|
||||
|
||||
class NotFound(HTTPException):
|
||||
"""Raised for 404 Not Found errors."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class Forbidden(HTTPException):
|
||||
"""Raised for 403 Forbidden errors."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class AppCommandError(DisagreementException):
|
||||
|
10
disagreement/utils.py
Normal file
10
disagreement/utils.py
Normal file
@ -0,0 +1,10 @@
|
||||
"""Utility helpers."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
|
||||
def utcnow() -> datetime:
|
||||
"""Return the current timezone-aware UTC time."""
|
||||
return datetime.now(timezone.utc)
|
13
tests/test_color.py
Normal file
13
tests/test_color.py
Normal file
@ -0,0 +1,13 @@
|
||||
from disagreement.color import Color
|
||||
|
||||
|
||||
def test_from_rgb():
|
||||
color = Color.from_rgb(255, 127, 0)
|
||||
assert color.value == 0xFF7F00
|
||||
assert color.to_rgb() == (255, 127, 0)
|
||||
|
||||
|
||||
def test_static_colors():
|
||||
assert Color.red().value == 0xFF0000
|
||||
assert Color.green().value == 0x00FF00
|
||||
assert Color.blue().value == 0x0000FF
|
@ -4,6 +4,8 @@ from disagreement.errors import (
|
||||
HTTPException,
|
||||
RateLimitError,
|
||||
AppCommandOptionConversionError,
|
||||
Forbidden,
|
||||
NotFound,
|
||||
)
|
||||
|
||||
|
||||
@ -21,3 +23,10 @@ def test_rate_limit_error_inherits_httpexception():
|
||||
def test_app_command_option_conversion_error():
|
||||
exc = AppCommandOptionConversionError("bad", option_name="opt", original_value="x")
|
||||
assert "opt" in str(exc) and "x" in str(exc)
|
||||
|
||||
|
||||
def test_specific_http_exceptions():
|
||||
not_found = NotFound(message="missing", status=404)
|
||||
forbidden = Forbidden(message="forbidden", status=403)
|
||||
assert isinstance(not_found, HTTPException)
|
||||
assert isinstance(forbidden, HTTPException)
|
||||
|
8
tests/test_utils.py
Normal file
8
tests/test_utils.py
Normal file
@ -0,0 +1,8 @@
|
||||
from datetime import timezone
|
||||
|
||||
from disagreement.utils import utcnow
|
||||
|
||||
|
||||
def test_utcnow_timezone():
|
||||
now = utcnow()
|
||||
assert now.tzinfo == timezone.utc
|
Loading…
x
Reference in New Issue
Block a user