Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion discord/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
from .monetization import Entitlement
from .onboarding import Onboarding
from .permissions import PermissionOverwrite
from .role import Role
from .role import Role, RoleColours
from .scheduled_events import ScheduledEvent, ScheduledEventLocation
from .stage_instance import StageInstance
from .sticker import GuildSticker
Expand Down Expand Up @@ -2908,6 +2908,8 @@ async def create_role(
permissions: Permissions = MISSING,
color: Colour | int = MISSING,
colour: Colour | int = MISSING,
colors: RoleColours = MISSING,
colours: RoleColours = MISSING,
hoist: bool = MISSING,
mentionable: bool = MISSING,
reason: str | None = None,
Expand Down Expand Up @@ -2972,6 +2974,8 @@ async def create_role(
fields["permissions"] = "0"

actual_colour = colour or color or Colour.default()
colours or colors or RoleColours.default()

if isinstance(actual_colour, int):
fields["color"] = actual_colour
else:
Expand Down
78 changes: 78 additions & 0 deletions discord/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

from typing import TYPE_CHECKING, Any, TypeVar

from typing_extensions import Self

from .asset import Asset
from .colour import Colour
from .errors import InvalidArgument
Expand All @@ -48,6 +50,7 @@
from .state import ConnectionState
from .types.guild import RolePositionUpdate
from .types.role import Role as RolePayload
from .types.role import RoleColours as RoleColoursPayload
from .types.role import RoleTags as RoleTagPayload


Expand Down Expand Up @@ -149,6 +152,69 @@ def __repr__(self) -> str:
R = TypeVar("R", bound="Role")


class RoleColours:
"""Represents a role's gradient colours.

.. versionadded:: 2.7

Attributes
----------
primary: :class:`Colour`
The primary colour of the role.
secondary: Optional[:class:`Colour`]
The secondary colour of the role.
tertiary: Optional[:class:`Colour`]
The tertiary colour of the role.
"""

def __init__(
self,
primary: Colour,
secondary: Colour | None = None,
tertiary: Colour | None = None,
):
"""Initialises a :class:`RoleColours` object.

.. versionadded:: 2.7

Parameters
----------
primary: :class:`Colour`
The primary colour of the role.
secondary: Optional[:class:`Colour`]
The secondary colour of the role.
tertiary: Optional[:class:`Colour`]
The tertiary colour of the role.
"""
self.primary: Colour = primary
self.secondary: Colour | None = secondary
self.tertiary: Colour | None = tertiary

@classmethod
def _from_payload(cls, data: RoleColoursPayload) -> Self:
primary = Colour(data["primary_color"])
secondary = (
Colour(data["secondary_color"]) if data.get("secondary_color") else None
)
tertiary = (
Colour(data["tertiary_color"]) if data.get("tertiary_color") else None
)
return cls(primary, secondary, tertiary)

def _to_dict(self) -> RoleColoursPayload:
"""Converts the role colours to a dictionary."""
return {
"primary_color": self.primary.value,
"secondary_color": self.secondary.value if self.secondary else None,
"tertiary_color": self.tertiary.value if self.tertiary else None,
}

@classmethod
def default(cls) -> RoleColours:
"""Returns a default :class:`RoleColours` object with no colours set."""
return cls(Colour.default(), None, None)


class Role(Hashable):
"""Represents a Discord role in a :class:`Guild`.

Expand Down Expand Up @@ -299,6 +365,7 @@ def _update(self, data: RolePayload):
self._permissions: int = int(data.get("permissions", 0))
self.position: int = data.get("position", 0)
self._colour: int = data.get("color", 0)
self.colours: RoleColours | None = RoleColours._from_payload(data)
self.hoist: bool = data.get("hoist", False)
self.managed: bool = data.get("managed", False)
self.mentionable: bool = data.get("mentionable", False)
Expand Down Expand Up @@ -452,6 +519,8 @@ async def edit(
permissions: Permissions = MISSING,
colour: Colour | int = MISSING,
color: Colour | int = MISSING,
colours: RoleColours | None = MISSING,
colors: RoleColours | None = MISSING,
hoist: bool = MISSING,
mentionable: bool = MISSING,
position: int = MISSING,
Expand Down Expand Up @@ -523,8 +592,17 @@ async def edit(
if color is not MISSING:
colour = color

if colors is not MISSING:
colours = colors

if colour is not MISSING:
payload["color"] = colour if isinstance(colour, int) else colour.value

if colours is not MISSING:
if not isinstance(colours, RoleColours):
raise InvalidArgument("colours must be a RoleColours object")
payload["colors"] = colours._to_dict()

if name is not MISSING:
payload["name"] = name

Expand Down
1 change: 1 addition & 0 deletions discord/types/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class UnavailableGuild(TypedDict):
"VERIFIED",
"VIP_REGIONS",
"WELCOME_SCREEN_ENABLED",
"ENHANCED_ROLE_COLORS",
]


Expand Down
7 changes: 7 additions & 0 deletions discord/types/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,18 @@
from .snowflake import Snowflake


class RoleColours(TypedDict):
primary_color: int
secondary_color: int | None
tertiary_color: int | None


class Role(TypedDict):
tags: NotRequired[RoleTags]
id: Snowflake
name: str
color: int
colors: NotRequired[RoleColours]
hoist: bool
position: int
permissions: str
Expand Down
Loading