Browse Source

Merge remote-tracking branch 'upstream/master' into feature/guild/onboarding

pull/10226/head
Soheab_ 1 week ago
parent
commit
050a076bcc
  1. 17
      discord/app_commands/commands.py
  2. 48
      discord/enums.py
  3. 6
      discord/ext/commands/hybrid.py
  4. 48
      discord/guild.py
  5. 2
      discord/http.py
  6. 86
      discord/role.py
  7. 1
      discord/types/guild.py
  8. 7
      discord/types/role.py

17
discord/app_commands/commands.py

@ -686,9 +686,9 @@ class Command(Generic[GroupT, P, T]):
self._params: Dict[str, CommandParameter] = _extract_parameters_from_callback(callback, callback.__globals__)
self.checks: List[Check] = getattr(callback, '__discord_app_commands_checks__', [])
self._guild_ids: Optional[List[int]] = guild_ids or getattr(
callback, '__discord_app_commands_default_guilds__', None
)
self._guild_ids: Optional[List[int]] = guild_ids
if self._guild_ids is None:
self._guild_ids = getattr(callback, '__discord_app_commands_default_guilds__', None)
self.default_permissions: Optional[Permissions] = getattr(
callback, '__discord_app_commands_default_permissions__', None
)
@ -1249,7 +1249,9 @@ class ContextMenu:
self._param_name = param
self._annotation = annotation
self.module: Optional[str] = callback.__module__
self._guild_ids = guild_ids or getattr(callback, '__discord_app_commands_default_guilds__', None)
self._guild_ids = guild_ids
if self._guild_ids is None:
self._guild_ids = getattr(callback, '__discord_app_commands_default_guilds__', None)
self.on_error: Optional[UnboundError] = None
self.default_permissions: Optional[Permissions] = getattr(
callback, '__discord_app_commands_default_permissions__', None
@ -1586,7 +1588,9 @@ class Group:
self._attr: Optional[str] = None
self._owner_cls: Optional[Type[Any]] = None
self._guild_ids: Optional[List[int]] = guild_ids or getattr(cls, '__discord_app_commands_default_guilds__', None)
self._guild_ids: Optional[List[int]] = guild_ids
if self._guild_ids is None:
self._guild_ids = getattr(cls, '__discord_app_commands_default_guilds__', None)
if default_permissions is MISSING:
if cls.__discord_app_commands_default_permissions__ is MISSING:
@ -2366,6 +2370,9 @@ def guilds(*guild_ids: Union[Snowflake, int]) -> Callable[[T], T]:
specified by this decorator become the default guilds that it's added to rather
than being a global command.
If no arguments are given, then the command will not be synced anywhere. This may
be modified later using the :meth:`CommandTree.add_command` method.
.. note::
Due to an implementation quirk and Python limitation, if this is used in conjunction

48
discord/enums.py

@ -21,6 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
"""
from __future__ import annotations
import types
@ -712,6 +713,42 @@ class MFALevel(Enum, comparable=True):
require_2fa = 1
_UNICODE_LANG_MAP: Dict[str, str] = {
'bg': 'bg-BG',
'zh-CN': 'zh-CN',
'zh-TW': 'zh-TW',
'hr': 'hr-HR',
'cs': 'cs-CZ',
'da': 'da-DK',
'nl': 'nl-NL',
'en-US': 'en-US',
'en-GB': 'en-GB',
'fi': 'fi-FI',
'fr': 'fr-FR',
'de': 'de-DE',
'el': 'el-GR',
'hi': 'hi-IN',
'hu': 'hu-HU',
'id': 'id-ID',
'it': 'it-IT',
'ja': 'ja-JP',
'ko': 'ko-KR',
'lt': 'lt-LT',
'no': 'no-NO',
'pl': 'pl-PL',
'pt-BR': 'pt-BR',
'ro': 'ro-RO',
'ru': 'ru-RU',
'es-ES': 'es-ES',
'es-419': 'es-419',
'sv-SE': 'sv-SE',
'th': 'th-TH',
'tr': 'tr-TR',
'uk': 'uk-UA',
'vi': 'vi-VN',
}
class Locale(Enum):
american_english = 'en-US'
british_english = 'en-GB'
@ -749,6 +786,17 @@ class Locale(Enum):
def __str__(self) -> str:
return self.value
@property
def language_code(self) -> str:
""":class:`str`: Returns the locale's BCP 47 language code in the format of ``language-COUNTRY``.
This is derived from a predefined mapping based on Discord's supported locales.
If no mapping exists for the current locale, this returns the raw locale value as a fallback.
.. versionadded:: 2.6
"""
return _UNICODE_LANG_MAP.get(self.value, self.value)
E = TypeVar('E', bound='Enum')

6
discord/ext/commands/hybrid.py

@ -656,9 +656,9 @@ class HybridGroup(Group[CogT, P, T]):
self.fallback_locale: Optional[app_commands.locale_str] = fallback_locale
if self.with_app_command:
guild_ids = attrs.pop('guild_ids', None) or getattr(
self.callback, '__discord_app_commands_default_guilds__', None
)
guild_ids = attrs.pop('guild_ids', None)
if guild_ids is None:
guild_ids = getattr(self.callback, '__discord_app_commands_default_guilds__', None)
guild_only = getattr(self.callback, '__discord_app_commands_guild_only__', False)
default_permissions = getattr(self.callback, '__discord_app_commands_default_permissions__', None)
nsfw = getattr(self.callback, '__discord_app_commands_is_nsfw__', False)

48
discord/guild.py

@ -3650,6 +3650,8 @@ class Guild(Hashable):
hoist: bool = ...,
display_icon: Union[bytes, str] = MISSING,
mentionable: bool = ...,
secondary_colour: Optional[Union[Colour, int]] = ...,
tertiary_colour: Optional[Union[Colour, int]] = ...,
) -> Role:
...
@ -3664,6 +3666,8 @@ class Guild(Hashable):
hoist: bool = ...,
display_icon: Union[bytes, str] = MISSING,
mentionable: bool = ...,
secondary_color: Optional[Union[Colour, int]] = ...,
tertiary_color: Optional[Union[Colour, int]] = ...,
) -> Role:
...
@ -3678,6 +3682,10 @@ class Guild(Hashable):
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|
@ -3697,6 +3705,10 @@ class Guild(Hashable):
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`
@ -3706,6 +3718,15 @@ class Guild(Hashable):
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``.
@ -3740,11 +3761,34 @@ class Guild(Hashable):
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

2
discord/http.py

@ -1898,7 +1898,7 @@ class HTTPClient:
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)

86
discord/role.py

@ -222,6 +222,8 @@ class Role(Hashable):
'tags',
'_flags',
'_state',
'_secondary_colour',
'_tertiary_colour',
)
def __init__(self, *, guild: Guild, state: ConnectionState, data: RolePayload):
@ -273,10 +275,11 @@ class Role(Hashable):
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')
@ -284,6 +287,8 @@ class Role(Hashable):
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]
@ -323,6 +328,38 @@ class Role(Hashable):
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."""
@ -330,12 +367,12 @@ class Role(Hashable):
@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
@ -425,6 +462,10 @@ class Role(Hashable):
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|
@ -447,6 +488,9 @@ class Role(Hashable):
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`
@ -455,6 +499,15 @@ class Role(Hashable):
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`]]
@ -490,14 +543,17 @@ class Role(Hashable):
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
@ -519,6 +575,26 @@ class Role(Hashable):
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)

1
discord/types/guild.py

@ -90,6 +90,7 @@ GuildFeature = Literal[
'VERIFIED',
'VIP_REGIONS',
'WELCOME_SCREEN_ENABLED',
'ENHANCED_ROLE_COLORS',
'RAID_ALERTS_DISABLED',
'SOUNDBOARD',
'MORE_SOUNDBOARD',

7
discord/types/role.py

@ -30,10 +30,17 @@ from typing_extensions import NotRequired
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

Loading…
Cancel
Save