Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
48 changes: 46 additions & 2 deletions discord/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -3648,6 +3648,8 @@ async def create_role(
hoist: bool = ...,
display_icon: Union[bytes, str] = MISSING,
mentionable: bool = ...,
secondary_colour: Optional[Union[Colour, int]] = ...,
tertiary_colour: Optional[Union[Colour, int]] = ...,
) -> Role:
...

Expand All @@ -3662,6 +3664,8 @@ async def create_role(
hoist: bool = ...,
display_icon: Union[bytes, str] = MISSING,
mentionable: bool = ...,
secondary_color: Optional[Union[Colour, int]] = ...,
tertiary_color: Optional[Union[Colour, int]] = ...,
) -> Role:
...

Expand All @@ -3676,6 +3680,10 @@ async def create_role(
display_icon: Union[bytes, str] = MISSING,
mentionable: bool = MISSING,
reason: Optional[str] = None,
secondary_color: Optional[Union[Colour, int]] = MISSING,
tertiary_color: Optional[Union[Colour, int]] = MISSING,
secondary_colour: Optional[Union[Colour, int]] = MISSING,
tertiary_colour: Optional[Union[Colour, int]] = MISSING,
) -> Role:
"""|coro|

Expand All @@ -3695,6 +3703,10 @@ async def create_role(
This function will now raise :exc:`TypeError` instead of
``InvalidArgument``.

.. versionchanged:: 2.6
The ``colour`` and ``color`` parameters now set the role's primary color.


Parameters
-----------
name: :class:`str`
Expand All @@ -3704,6 +3716,15 @@ async def create_role(
colour: Union[:class:`Colour`, :class:`int`]
The colour for the role. Defaults to :meth:`Colour.default`.
This is aliased to ``color`` as well.
secondary_colour: Optional[Union[:class:`Colour`, :class:`int`]]
The secondary colour for the role.

.. versionadded:: 2.6
tertiary_colour: Optional[Union[:class:`Colour`, :class:`int`]]
The tertiary colour for the role. Can only be used for the holographic role preset,
which is ``(11127295, 16759788, 16761760)``

.. versionadded:: 2.6
hoist: :class:`bool`
Indicates if the role should be shown separately in the member list.
Defaults to ``False``.
Expand Down Expand Up @@ -3738,11 +3759,34 @@ async def create_role(
else:
fields['permissions'] = '0'

colours: Dict[str, Any] = {}

actual_colour = colour or color or Colour.default()
if isinstance(actual_colour, int):
fields['color'] = actual_colour
colours['primary_color'] = actual_colour
else:
fields['color'] = actual_colour.value
colours['primary_color'] = actual_colour.value

actual_secondary_colour = secondary_colour or secondary_color
actual_tertiary_colour = tertiary_colour or tertiary_color

if actual_secondary_colour is not MISSING:
if actual_secondary_colour is None:
colours['secondary_color'] = None
elif isinstance(actual_secondary_colour, int):
colours['secondary_color'] = actual_secondary_colour
else:
colours['secondary_color'] = actual_secondary_colour.value

if actual_tertiary_colour is not MISSING:
if actual_tertiary_colour is None:
colours['tertiary_color'] = None
elif isinstance(actual_tertiary_colour, int):
colours['tertiary_color'] = actual_tertiary_colour
else:
colours['tertiary_color'] = actual_tertiary_colour.value

fields['colors'] = colours

if hoist is not MISSING:
fields['hoist'] = hoist
Expand Down
2 changes: 1 addition & 1 deletion discord/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -1894,7 +1894,7 @@ def edit_role(
self, guild_id: Snowflake, role_id: Snowflake, *, reason: Optional[str] = None, **fields: Any
) -> Response[role.Role]:
r = Route('PATCH', '/guilds/{guild_id}/roles/{role_id}', guild_id=guild_id, role_id=role_id)
valid_keys = ('name', 'permissions', 'color', 'hoist', 'icon', 'unicode_emoji', 'mentionable')
valid_keys = ('name', 'permissions', 'color', 'hoist', 'icon', 'unicode_emoji', 'mentionable', 'colors')
payload = {k: v for k, v in fields.items() if k in valid_keys}
return self.request(r, json=payload, reason=reason)

Expand Down
82 changes: 77 additions & 5 deletions discord/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ class Role(Hashable):
'tags',
'_flags',
'_state',
'_secondary_colour',
'_tertiary_colour',
)

def __init__(self, *, guild: Guild, state: ConnectionState, data: RolePayload):
Expand Down Expand Up @@ -273,17 +275,20 @@ def __ge__(self, other: object) -> bool:
return not r

def _update(self, data: RolePayload):
colors = data.get('colors', {})
self.name: str = data['name']
self._permissions: int = int(data.get('permissions', 0))
self.position: int = data.get('position', 0)
self._colour: int = data.get('color', 0)
self._colour: int = colors.get('primary_color', 0)
self.hoist: bool = data.get('hoist', False)
self._icon: Optional[str] = data.get('icon')
self.unicode_emoji: Optional[str] = data.get('unicode_emoji')
self.managed: bool = data.get('managed', False)
self.mentionable: bool = data.get('mentionable', False)
self.tags: Optional[RoleTags]
self._flags: int = data.get('flags', 0)
self._secondary_colour = colors.get('secondary_color', None)
self._tertiary_colour = colors.get('tertiary_color', None)

try:
self.tags = RoleTags(data['tags']) # pyright: ignore[reportTypedDictNotRequiredAccess]
Expand Down Expand Up @@ -323,19 +328,47 @@ def is_assignable(self) -> bool:
me = self.guild.me
return not self.is_default() and not self.managed and (me.top_role > self or me.id == self.guild.owner_id)

@property
def secondary_colour(self) -> Optional[Colour]:
"""Optional[:class:`Colour`]: The role's secondary colour.
.. versionadded:: 2.6
"""
return Colour(self._secondary_colour) if self._secondary_colour is not None else None

@property
def secondary_color(self) -> Optional[Colour]:
"""Optional[:class:`Colour`]: Alias for :attr:`secondary_colour`.
.. versionadded:: 2.6
"""
return self.secondary_colour

@property
def tertiary_colour(self) -> Optional[Colour]:
"""Optional[:class:`Colour`]: The role's tertiary colour.
.. versionadded:: 2.6
"""
return Colour(self._tertiary_colour) if self._tertiary_colour is not None else None

@property
def tertiary_color(self) -> Optional[Colour]:
"""Optional[:class:`Colour`]: Alias for :attr:`tertiary_colour`.
.. versionadded:: 2.6
"""
return self.tertiary_colour

@property
def permissions(self) -> Permissions:
""":class:`Permissions`: Returns the role's permissions."""
return Permissions(self._permissions)

@property
def colour(self) -> Colour:
""":class:`Colour`: Returns the role colour. An alias exists under ``color``."""
""":class:`Colour`: Returns the role's primary colour. An alias exists under ``color``."""
return Colour(self._colour)

@property
def color(self) -> Colour:
""":class:`Colour`: Returns the role color. An alias exists under ``colour``."""
""":class:`Colour`: Returns the role's primary colour. An alias exists under ``colour``."""
return self.colour

@property
Expand Down Expand Up @@ -425,6 +458,10 @@ async def edit(
mentionable: bool = MISSING,
position: int = MISSING,
reason: Optional[str] = MISSING,
secondary_color: Optional[Union[Colour, int]] = MISSING,
tertiary_color: Optional[Union[Colour, int]] = MISSING,
secondary_colour: Optional[Union[Colour, int]] = MISSING,
tertiary_colour: Optional[Union[Colour, int]] = MISSING,
) -> Optional[Role]:
"""|coro|

Expand All @@ -447,6 +484,9 @@ async def edit(
This function will now raise :exc:`ValueError` instead of
``InvalidArgument``.

.. versionchanged:: 2.6
The ``colour`` and ``color`` parameters now set the role's primary color.

Parameters
-----------
name: :class:`str`
Expand All @@ -455,6 +495,15 @@ async def edit(
The new permissions to change to.
colour: Union[:class:`Colour`, :class:`int`]
The new colour to change to. (aliased to color as well)
secondary_colour: Optional[Union[:class:`Colour`, :class:`int`]]
The new secondary colour for the role.

.. versionadded:: 2.6
tertiary_colour: Optional[Union[:class:`Colour`, :class:`int`]]
The new tertiary colour for the role. Can only be used for the holographic role preset,
which is ``(11127295, 16759788, 16761760)``

.. versionadded:: 2.6
hoist: :class:`bool`
Indicates if the role should be shown separately in the member list.
display_icon: Optional[Union[:class:`bytes`, :class:`str`]]
Expand Down Expand Up @@ -490,14 +539,17 @@ async def edit(
await self._move(position, reason=reason)

payload: Dict[str, Any] = {}

colours: Dict[str, Any] = {}

if color is not MISSING:
colour = color

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

if name is not MISSING:
payload['name'] = name
Expand All @@ -519,6 +571,26 @@ async def edit(
if mentionable is not MISSING:
payload['mentionable'] = mentionable

actual_secondary_colour = secondary_colour or secondary_color
actual_tertiary_colour = tertiary_colour or tertiary_color

if actual_secondary_colour is not MISSING:
if actual_secondary_colour is None:
colours['secondary_color'] = None
elif isinstance(actual_secondary_colour, int):
colours['secondary_color'] = actual_secondary_colour
else:
colours['secondary_color'] = actual_secondary_colour.value
if actual_tertiary_colour is not MISSING:
if actual_tertiary_colour is None:
colours['tertiary_color'] = None
elif isinstance(actual_tertiary_colour, int):
colours['tertiary_color'] = actual_tertiary_colour
else:
colours['tertiary_color'] = actual_tertiary_colour.value

if colours:
payload['colors'] = colours
data = await self._state.http.edit_role(self.guild.id, self.id, reason=reason, **payload)
return Role(guild=self.guild, data=data, state=self._state)

Expand Down
1 change: 1 addition & 0 deletions discord/types/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class IncidentData(TypedDict):
'VERIFIED',
'VIP_REGIONS',
'WELCOME_SCREEN_ENABLED',
'ENHANCED_ROLE_COLORS',
'RAID_ALERTS_DISABLED',
'SOUNDBOARD',
'MORE_SOUNDBOARD',
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,10 +30,17 @@
from .snowflake import Snowflake


class RoleColours(TypedDict):
primary_color: int
secondary_color: Optional[int]
tertiary_color: Optional[int]


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