|
27 | 27 |
|
28 | 28 | from typing import TYPE_CHECKING, Any, TypeVar
|
29 | 29 |
|
| 30 | +from typing_extensions import Self |
| 31 | + |
30 | 32 | from .asset import Asset
|
31 | 33 | from .colour import Colour
|
32 | 34 | from .errors import InvalidArgument
|
33 | 35 | from .flags import RoleFlags
|
34 | 36 | from .mixins import Hashable
|
35 | 37 | from .permissions import Permissions
|
36 |
| -from .utils import MISSING, _bytes_to_base64_data, _get_as_snowflake, snowflake_time |
37 |
| - |
38 |
| -__all__ = ( |
39 |
| - "RoleTags", |
40 |
| - "Role", |
| 38 | +from .utils import ( |
| 39 | + MISSING, |
| 40 | + _bytes_to_base64_data, |
| 41 | + _get_as_snowflake, |
| 42 | + deprecated, |
| 43 | + snowflake_time, |
| 44 | + warn_deprecated, |
41 | 45 | )
|
42 | 46 |
|
| 47 | +__all__ = ("RoleTags", "Role", "RoleColours") |
| 48 | + |
43 | 49 | if TYPE_CHECKING:
|
44 | 50 | import datetime
|
45 | 51 |
|
|
48 | 54 | from .state import ConnectionState
|
49 | 55 | from .types.guild import RolePositionUpdate
|
50 | 56 | from .types.role import Role as RolePayload
|
| 57 | + from .types.role import RoleColours as RoleColoursPayload |
51 | 58 | from .types.role import RoleTags as RoleTagPayload
|
52 | 59 |
|
53 | 60 |
|
@@ -149,6 +156,96 @@ def __repr__(self) -> str:
|
149 | 156 | R = TypeVar("R", bound="Role")
|
150 | 157 |
|
151 | 158 |
|
| 159 | +class RoleColours: |
| 160 | + """Represents a role's gradient colours. |
| 161 | +
|
| 162 | + .. versionadded:: 2.7 |
| 163 | +
|
| 164 | + Attributes |
| 165 | + ---------- |
| 166 | + primary: :class:`Colour` |
| 167 | + The primary colour of the role. |
| 168 | + secondary: Optional[:class:`Colour`] |
| 169 | + The secondary colour of the role. |
| 170 | + tertiary: Optional[:class:`Colour`] |
| 171 | + The tertiary colour of the role. At the moment, only `16761760` is allowed. |
| 172 | + """ |
| 173 | + |
| 174 | + def __init__( |
| 175 | + self, |
| 176 | + primary: Colour, |
| 177 | + secondary: Colour | None = None, |
| 178 | + tertiary: Colour | None = None, |
| 179 | + ): |
| 180 | + """Initialises a :class:`RoleColours` object. |
| 181 | +
|
| 182 | + .. versionadded:: 2.7 |
| 183 | +
|
| 184 | + Parameters |
| 185 | + ---------- |
| 186 | + primary: :class:`Colour` |
| 187 | + The primary colour of the role. |
| 188 | + secondary: Optional[:class:`Colour`] |
| 189 | + The secondary colour of the role. |
| 190 | + tertiary: Optional[:class:`Colour`] |
| 191 | + The tertiary colour of the role. |
| 192 | + """ |
| 193 | + self.primary: Colour = primary |
| 194 | + self.secondary: Colour | None = secondary |
| 195 | + self.tertiary: Colour | None = tertiary |
| 196 | + |
| 197 | + @classmethod |
| 198 | + def _from_payload(cls, data: RoleColoursPayload) -> Self: |
| 199 | + primary = Colour(data["primary_color"]) |
| 200 | + secondary = ( |
| 201 | + Colour(data["secondary_color"]) if data.get("secondary_color") else None |
| 202 | + ) |
| 203 | + tertiary = ( |
| 204 | + Colour(data["tertiary_color"]) if data.get("tertiary_color") else None |
| 205 | + ) |
| 206 | + return cls(primary, secondary, tertiary) |
| 207 | + |
| 208 | + def _to_dict(self) -> RoleColoursPayload: |
| 209 | + """Converts the role colours to a dictionary.""" |
| 210 | + return { |
| 211 | + "primary_color": self.primary.value, |
| 212 | + "secondary_color": self.secondary.value if self.secondary else None, |
| 213 | + "tertiary_color": self.tertiary.value if self.tertiary else None, |
| 214 | + } # type: ignore |
| 215 | + |
| 216 | + @classmethod |
| 217 | + def default(cls) -> RoleColours: |
| 218 | + """Returns a default :class:`RoleColours` object with no colours set.""" |
| 219 | + return cls(Colour.default(), None, None) |
| 220 | + |
| 221 | + @classmethod |
| 222 | + def holographic(cls) -> RoleColours: |
| 223 | + """Returns a :class:`RoleColours` that makes the role look holographic. |
| 224 | +
|
| 225 | + Currently holographic roles are only supported with colours 11127295, 16759788, and 16761760. |
| 226 | + """ |
| 227 | + return cls(Colour(11127295), Colour(16759788), Colour(16761760)) |
| 228 | + |
| 229 | + @property |
| 230 | + def is_holographic(self) -> bool: |
| 231 | + """Whether the role is holographic. |
| 232 | +
|
| 233 | + Currently roles are holographic when colours are set to 11127295, 16759788, and 16761760. |
| 234 | + """ |
| 235 | + return ( |
| 236 | + self.primary.value == 11127295 |
| 237 | + and self.secondary.value == 16759788 |
| 238 | + and self.tertiary.value == 16761760 |
| 239 | + ) |
| 240 | + |
| 241 | + def __repr__(self) -> str: |
| 242 | + return ( |
| 243 | + f"<RoleColours primary={self.primary!r} " |
| 244 | + f"secondary={self.secondary!r} " |
| 245 | + f"tertiary={self.tertiary!r}>" |
| 246 | + ) |
| 247 | + |
| 248 | + |
152 | 249 | class Role(Hashable):
|
153 | 250 | """Represents a Discord role in a :class:`Guild`.
|
154 | 251 |
|
@@ -227,13 +324,19 @@ class Role(Hashable):
|
227 | 324 | Extra attributes of the role.
|
228 | 325 |
|
229 | 326 | .. versionadded:: 2.6
|
| 327 | +
|
| 328 | + colours: :class:`RoleColours` |
| 329 | + The role's colours. |
| 330 | +
|
| 331 | + .. versionadded:: 2.7 |
230 | 332 | """
|
231 | 333 |
|
232 | 334 | __slots__ = (
|
233 | 335 | "id",
|
234 | 336 | "name",
|
235 | 337 | "_permissions",
|
236 | 338 | "_colour",
|
| 339 | + "colours", |
237 | 340 | "position",
|
238 | 341 | "managed",
|
239 | 342 | "mentionable",
|
@@ -299,6 +402,7 @@ def _update(self, data: RolePayload):
|
299 | 402 | self._permissions: int = int(data.get("permissions", 0))
|
300 | 403 | self.position: int = data.get("position", 0)
|
301 | 404 | self._colour: int = data.get("color", 0)
|
| 405 | + self.colours: RoleColours | None = RoleColours._from_payload(data["colors"]) |
302 | 406 | self.hoist: bool = data.get("hoist", False)
|
303 | 407 | self.managed: bool = data.get("managed", False)
|
304 | 408 | self.mentionable: bool = data.get("mentionable", False)
|
@@ -374,14 +478,32 @@ def permissions(self) -> Permissions:
|
374 | 478 | return Permissions(self._permissions)
|
375 | 479 |
|
376 | 480 | @property
|
| 481 | + @deprecated("colours.primary", "2.7") |
377 | 482 | def colour(self) -> Colour:
|
378 |
| - """Returns the role colour. An alias exists under ``color``.""" |
379 |
| - return Colour(self._colour) |
| 483 | + """Returns the role colour. Equivalent to :attr:`colours.primary`. |
| 484 | + An alias exists under ``color``. |
| 485 | +
|
| 486 | + .. versionchanged:: 2.7 |
| 487 | + """ |
| 488 | + return self.colours.primary |
380 | 489 |
|
381 | 490 | @property
|
| 491 | + @deprecated("colors.primary", "2.7") |
382 | 492 | def color(self) -> Colour:
|
383 |
| - """Returns the role color. An alias exists under ``colour``.""" |
384 |
| - return self.colour |
| 493 | + """Returns the role's primary color. Equivalent to :attr:`colors.primary`. |
| 494 | + An alias exists under ``colour``. |
| 495 | +
|
| 496 | + .. versionchanged:: 2.7 |
| 497 | + """ |
| 498 | + return self.colours.primary |
| 499 | + |
| 500 | + @property |
| 501 | + def colors(self) -> RoleColours: |
| 502 | + """Returns the role's colours. Equivalent to :attr:`colours`. |
| 503 | +
|
| 504 | + .. versionadded:: 2.7 |
| 505 | + """ |
| 506 | + return self.colours |
385 | 507 |
|
386 | 508 | @property
|
387 | 509 | def created_at(self) -> datetime.datetime:
|
@@ -452,6 +574,9 @@ async def edit(
|
452 | 574 | permissions: Permissions = MISSING,
|
453 | 575 | colour: Colour | int = MISSING,
|
454 | 576 | color: Colour | int = MISSING,
|
| 577 | + colours: RoleColours | None = MISSING, |
| 578 | + colors: RoleColours | None = MISSING, |
| 579 | + holographic: bool = MISSING, |
455 | 580 | hoist: bool = MISSING,
|
456 | 581 | mentionable: bool = MISSING,
|
457 | 582 | position: int = MISSING,
|
@@ -523,8 +648,25 @@ async def edit(
|
523 | 648 | if color is not MISSING:
|
524 | 649 | colour = color
|
525 | 650 |
|
| 651 | + if colors is not MISSING: |
| 652 | + colours = colors |
| 653 | + |
526 | 654 | if colour is not MISSING:
|
527 |
| - payload["color"] = colour if isinstance(colour, int) else colour.value |
| 655 | + warn_deprecated("colour", "colours", "2.7") |
| 656 | + if isinstance(colour, int): |
| 657 | + colour = Colour(colour) |
| 658 | + colours = RoleColours(primary=colour) |
| 659 | + if holographic: |
| 660 | + colours = RoleColours.holographic() |
| 661 | + if colours is not MISSING: |
| 662 | + if not isinstance(colours, RoleColours): |
| 663 | + raise InvalidArgument("colours must be a RoleColours object") |
| 664 | + if "ENHANCED_ROLE_COLORS" not in self.guild.features: |
| 665 | + colours.secondary = None |
| 666 | + colours.tertiary = None |
| 667 | + |
| 668 | + payload["colors"] = colours._to_dict() |
| 669 | + |
528 | 670 | if name is not MISSING:
|
529 | 671 | payload["name"] = name
|
530 | 672 |
|
|
0 commit comments