|
28 | 28 | from email import utils
|
29 | 29 | from typing import TYPE_CHECKING, Any, TypeVar
|
30 | 30 |
|
| 31 | +from typing_extensions import Self |
| 32 | + |
31 | 33 | from .asset import Asset
|
32 | 34 | from .colour import Colour
|
33 | 35 | from .errors import InvalidArgument
|
34 | 36 | from .flags import RoleFlags
|
35 | 37 | from .mixins import Hashable
|
36 | 38 | from .permissions import Permissions
|
37 |
| -from .utils import MISSING, _bytes_to_base64_data, _get_as_snowflake, snowflake_time |
38 |
| - |
39 |
| -__all__ = ( |
40 |
| - "RoleTags", |
41 |
| - "Role", |
| 39 | +from .utils import ( |
| 40 | + MISSING, |
| 41 | + _bytes_to_base64_data, |
| 42 | + _get_as_snowflake, |
| 43 | + deprecated, |
| 44 | + snowflake_time, |
| 45 | + warn_deprecated, |
42 | 46 | )
|
43 | 47 |
|
| 48 | +__all__ = ("RoleTags", "Role", "RoleColours") |
| 49 | + |
44 | 50 | if TYPE_CHECKING:
|
45 | 51 | import datetime
|
46 | 52 |
|
|
49 | 55 | from .state import ConnectionState
|
50 | 56 | from .types.guild import RolePositionUpdate
|
51 | 57 | from .types.role import Role as RolePayload
|
| 58 | + from .types.role import RoleColours as RoleColoursPayload |
52 | 59 | from .types.role import RoleTags as RoleTagPayload
|
53 | 60 |
|
54 | 61 |
|
@@ -146,6 +153,96 @@ def __repr__(self) -> str:
|
146 | 153 | R = TypeVar("R", bound="Role")
|
147 | 154 |
|
148 | 155 |
|
| 156 | +class RoleColours: |
| 157 | + """Represents a role's gradient colours. |
| 158 | +
|
| 159 | + .. versionadded:: 2.7 |
| 160 | +
|
| 161 | + Attributes |
| 162 | + ---------- |
| 163 | + primary: :class:`Colour` |
| 164 | + The primary colour of the role. |
| 165 | + secondary: Optional[:class:`Colour`] |
| 166 | + The secondary colour of the role. |
| 167 | + tertiary: Optional[:class:`Colour`] |
| 168 | + The tertiary colour of the role. At the moment, only `16761760` is allowed. |
| 169 | + """ |
| 170 | + |
| 171 | + def __init__( |
| 172 | + self, |
| 173 | + primary: Colour, |
| 174 | + secondary: Colour | None = None, |
| 175 | + tertiary: Colour | None = None, |
| 176 | + ): |
| 177 | + """Initialises a :class:`RoleColours` object. |
| 178 | +
|
| 179 | + .. versionadded:: 2.7 |
| 180 | +
|
| 181 | + Parameters |
| 182 | + ---------- |
| 183 | + primary: :class:`Colour` |
| 184 | + The primary colour of the role. |
| 185 | + secondary: Optional[:class:`Colour`] |
| 186 | + The secondary colour of the role. |
| 187 | + tertiary: Optional[:class:`Colour`] |
| 188 | + The tertiary colour of the role. |
| 189 | + """ |
| 190 | + self.primary: Colour = primary |
| 191 | + self.secondary: Colour | None = secondary |
| 192 | + self.tertiary: Colour | None = tertiary |
| 193 | + |
| 194 | + @classmethod |
| 195 | + def _from_payload(cls, data: RoleColoursPayload) -> Self: |
| 196 | + primary = Colour(data["primary_color"]) |
| 197 | + secondary = ( |
| 198 | + Colour(data["secondary_color"]) if data.get("secondary_color") else None |
| 199 | + ) |
| 200 | + tertiary = ( |
| 201 | + Colour(data["tertiary_color"]) if data.get("tertiary_color") else None |
| 202 | + ) |
| 203 | + return cls(primary, secondary, tertiary) |
| 204 | + |
| 205 | + def _to_dict(self) -> RoleColoursPayload: |
| 206 | + """Converts the role colours to a dictionary.""" |
| 207 | + return { |
| 208 | + "primary_color": self.primary.value, |
| 209 | + "secondary_color": self.secondary.value if self.secondary else None, |
| 210 | + "tertiary_color": self.tertiary.value if self.tertiary else None, |
| 211 | + } # type: ignore |
| 212 | + |
| 213 | + @classmethod |
| 214 | + def default(cls) -> RoleColours: |
| 215 | + """Returns a default :class:`RoleColours` object with no colours set.""" |
| 216 | + return cls(Colour.default(), None, None) |
| 217 | + |
| 218 | + @classmethod |
| 219 | + def holographic(cls) -> RoleColours: |
| 220 | + """Returns a :class:`RoleColours` that makes the role look holographic. |
| 221 | +
|
| 222 | + Currently holographic roles are only supported with colours 11127295, 16759788, and 16761760. |
| 223 | + """ |
| 224 | + return cls(Colour(11127295), Colour(16759788), Colour(16761760)) |
| 225 | + |
| 226 | + @property |
| 227 | + def is_holographic(self) -> bool: |
| 228 | + """Whether the role is holographic. |
| 229 | +
|
| 230 | + Currently roles are holographic when colours are set to 11127295, 16759788, and 16761760. |
| 231 | + """ |
| 232 | + return ( |
| 233 | + self.primary.value == 11127295 |
| 234 | + and self.secondary.value == 16759788 |
| 235 | + and self.tertiary.value == 16761760 |
| 236 | + ) |
| 237 | + |
| 238 | + def __repr__(self) -> str: |
| 239 | + return ( |
| 240 | + f"<RoleColours primary={self.primary!r} " |
| 241 | + f"secondary={self.secondary!r} " |
| 242 | + f"tertiary={self.tertiary!r}>" |
| 243 | + ) |
| 244 | + |
| 245 | + |
149 | 246 | class Role(Hashable):
|
150 | 247 | """Represents a Discord role in a :class:`Guild`.
|
151 | 248 |
|
@@ -224,13 +321,19 @@ class Role(Hashable):
|
224 | 321 | Extra attributes of the role.
|
225 | 322 |
|
226 | 323 | .. versionadded:: 2.6
|
| 324 | +
|
| 325 | + colours: :class:`RoleColours` |
| 326 | + The role's colours. |
| 327 | +
|
| 328 | + .. versionadded:: 2.7 |
227 | 329 | """
|
228 | 330 |
|
229 | 331 | __slots__ = (
|
230 | 332 | "id",
|
231 | 333 | "name",
|
232 | 334 | "_permissions",
|
233 | 335 | "_colour",
|
| 336 | + "colours", |
234 | 337 | "position",
|
235 | 338 | "managed",
|
236 | 339 | "mentionable",
|
@@ -296,6 +399,7 @@ def _update(self, data: RolePayload):
|
296 | 399 | self._permissions: int = int(data.get("permissions", 0))
|
297 | 400 | self.position: int = data.get("position", 0)
|
298 | 401 | self._colour: int = data.get("color", 0)
|
| 402 | + self.colours: RoleColours | None = RoleColours._from_payload(data["colors"]) |
299 | 403 | self.hoist: bool = data.get("hoist", False)
|
300 | 404 | self.managed: bool = data.get("managed", False)
|
301 | 405 | self.mentionable: bool = data.get("mentionable", False)
|
@@ -367,14 +471,32 @@ def permissions(self) -> Permissions:
|
367 | 471 | return Permissions(self._permissions)
|
368 | 472 |
|
369 | 473 | @property
|
| 474 | + @deprecated("colours.primary", "2.7") |
370 | 475 | def colour(self) -> Colour:
|
371 |
| - """Returns the role colour. An alias exists under ``color``.""" |
372 |
| - return Colour(self._colour) |
| 476 | + """Returns the role colour. Equivalent to :attr:`colours.primary`. |
| 477 | + An alias exists under ``color``. |
| 478 | +
|
| 479 | + .. versionchanged:: 2.7 |
| 480 | + """ |
| 481 | + return self.colours.primary |
373 | 482 |
|
374 | 483 | @property
|
| 484 | + @deprecated("colors.primary", "2.7") |
375 | 485 | def color(self) -> Colour:
|
376 |
| - """Returns the role color. An alias exists under ``colour``.""" |
377 |
| - return self.colour |
| 486 | + """Returns the role's primary color. Equivalent to :attr:`colors.primary`. |
| 487 | + An alias exists under ``colour``. |
| 488 | +
|
| 489 | + .. versionchanged:: 2.7 |
| 490 | + """ |
| 491 | + return self.colours.primary |
| 492 | + |
| 493 | + @property |
| 494 | + def colors(self) -> RoleColours: |
| 495 | + """Returns the role's colours. Equivalent to :attr:`colours`. |
| 496 | +
|
| 497 | + .. versionadded:: 2.7 |
| 498 | + """ |
| 499 | + return self.colours |
378 | 500 |
|
379 | 501 | @property
|
380 | 502 | def created_at(self) -> datetime.datetime:
|
@@ -437,6 +559,9 @@ async def edit(
|
437 | 559 | permissions: Permissions | utils.Undefined = MISSING,
|
438 | 560 | colour: Colour | int | utils.Undefined = MISSING,
|
439 | 561 | color: Colour | int | utils.Undefined = MISSING,
|
| 562 | + colours: RoleColours | None | utils.Undefined = MISSING, |
| 563 | + colors: RoleColours | None | utils.Undefined = MISSING, |
| 564 | + holographic: bool | utils.Undefined = MISSING, |
440 | 565 | hoist: bool | utils.Undefined = MISSING,
|
441 | 566 | mentionable: bool | utils.Undefined = MISSING,
|
442 | 567 | position: int | utils.Undefined = MISSING,
|
@@ -508,8 +633,25 @@ async def edit(
|
508 | 633 | if color is not MISSING:
|
509 | 634 | colour = color
|
510 | 635 |
|
| 636 | + if colors is not MISSING: |
| 637 | + colours = colors |
| 638 | + |
511 | 639 | if colour is not MISSING:
|
512 |
| - payload["color"] = colour if isinstance(colour, int) else colour.value |
| 640 | + warn_deprecated("colour", "colours", "2.7") |
| 641 | + if isinstance(colour, int): |
| 642 | + colour = Colour(colour) |
| 643 | + colours = RoleColours(primary=colour) |
| 644 | + if holographic: |
| 645 | + colours = RoleColours.holographic() |
| 646 | + if colours is not MISSING: |
| 647 | + if not isinstance(colours, RoleColours): |
| 648 | + raise InvalidArgument("colours must be a RoleColours object") |
| 649 | + if "ENHANCED_ROLE_COLORS" not in self.guild.features: |
| 650 | + colours.secondary = None |
| 651 | + colours.tertiary = None |
| 652 | + |
| 653 | + payload["colors"] = colours._to_dict() |
| 654 | + |
513 | 655 | if name is not MISSING:
|
514 | 656 | payload["name"] = name
|
515 | 657 |
|
|
0 commit comments