Browse Source

Merge remote-tracking branch 'upstream/master' into new-pins-endpoint

pull/10205/head
Soheab_ 1 month ago
parent
commit
cf08f4b3a8
  1. 6
      discord/client.py
  2. 83
      discord/colour.py
  3. 3
      discord/components.py
  4. 6
      discord/embeds.py
  5. 8
      discord/ext/commands/context.py
  6. 5
      discord/guild.py
  7. 7
      discord/http.py
  8. 8
      discord/interactions.py
  9. 10
      discord/permissions.py
  10. 4
      discord/shard.py
  11. 6
      discord/template.py
  12. 1
      discord/types/interactions.py
  13. 3
      discord/ui/view.py
  14. 6
      docs/api.rst
  15. 4
      docs/interactions/api.rst
  16. 2
      tests/test_app_commands_invoke.py
  17. 13
      tests/test_colour.py
  18. 11
      tests/test_embed.py

6
discord/client.py

@ -67,7 +67,7 @@ from .voice_client import VoiceClient
from .http import HTTPClient from .http import HTTPClient
from .state import ConnectionState from .state import ConnectionState
from . import utils from . import utils
from .utils import MISSING, time_snowflake from .utils import MISSING, time_snowflake, deprecated
from .object import Object from .object import Object
from .backoff import ExponentialBackoff from .backoff import ExponentialBackoff
from .webhook import Webhook from .webhook import Webhook
@ -2388,6 +2388,7 @@ class Client:
data = await self.http.get_guild_preview(guild_id) data = await self.http.get_guild_preview(guild_id)
return GuildPreview(data=data, state=self._connection) return GuildPreview(data=data, state=self._connection)
@deprecated()
async def create_guild( async def create_guild(
self, self,
*, *,
@ -2408,6 +2409,9 @@ class Client:
This function will now raise :exc:`ValueError` instead of This function will now raise :exc:`ValueError` instead of
``InvalidArgument``. ``InvalidArgument``.
.. deprecated:: 2.6
This function is deprecated and will be removed in a future version.
Parameters Parameters
---------- ----------
name: :class:`str` name: :class:`str`

83
discord/colour.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 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
""" """
from __future__ import annotations from __future__ import annotations
import colorsys import colorsys
@ -457,20 +458,59 @@ class Colour:
""" """
return cls(0x99AAB5) return cls(0x99AAB5)
@classmethod
def ash_theme(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x2E2E34``.
This will appear transparent on Discord's ash theme.
.. colour:: #2E2E34
.. versionadded:: 2.6
"""
return cls(0x2E2E34)
@classmethod @classmethod
def dark_theme(cls) -> Self: def dark_theme(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x313338``. """A factory method that returns a :class:`Colour` with a value of ``0x1A1A1E``.
This will appear transparent on Discord's dark theme. This will appear transparent on Discord's dark theme.
.. colour:: #313338 .. colour:: #1A1A1E
.. versionadded:: 1.5 .. versionadded:: 1.5
.. versionchanged:: 2.2 .. versionchanged:: 2.2
Updated colour from previous ``0x36393F`` to reflect discord theme changes. Updated colour from previous ``0x36393F`` to reflect discord theme changes.
.. versionchanged:: 2.6
Updated colour from previous ``0x313338`` to reflect discord theme changes.
""" """
return cls(0x313338) return cls(0x1A1A1E)
@classmethod
def onyx_theme(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x070709``.
This will appear transparent on Discord's onyx theme.
.. colour:: #070709
.. versionadded:: 2.6
"""
return cls(0x070709)
@classmethod
def light_theme(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xFBFBFB``.
This will appear transparent on Discord's light theme.
.. colour:: #FBFBFB
.. versionadded:: 2.6
"""
return cls(0xFBFBFB)
@classmethod @classmethod
def fuchsia(cls) -> Self: def fuchsia(cls) -> Self:
@ -492,25 +532,52 @@ class Colour:
""" """
return cls(0xFEE75C) return cls(0xFEE75C)
@classmethod
def ash_embed(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x37373E``.
.. colour:: #37373E
.. versionadded:: 2.6
"""
return cls(0x37373E)
@classmethod @classmethod
def dark_embed(cls) -> Self: def dark_embed(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x2B2D31``. """A factory method that returns a :class:`Colour` with a value of ``0x242429``.
.. colour:: #2B2D31 .. colour:: #242429
.. versionadded:: 2.2 .. versionadded:: 2.2
.. versionchanged:: 2.6
Updated colour from previous ``0x2B2D31`` to reflect discord theme changes.
"""
return cls(0x242429)
@classmethod
def onyx_embed(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x131416``.
.. colour:: #131416
.. versionadded:: 2.6
""" """
return cls(0x2B2D31) return cls(0x131416)
@classmethod @classmethod
def light_embed(cls) -> Self: def light_embed(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xEEEFF1``. """A factory method that returns a :class:`Colour` with a value of ``0xFFFFFF``.
.. colour:: #EEEFF1 .. colour:: #EEEFF1
.. versionadded:: 2.2 .. versionadded:: 2.2
.. versionchanged:: 2.6
Updated colour from previous ``0xEEEFF1`` to reflect discord theme changes.
""" """
return cls(0xEEEFF1) return cls(0xFFFFFF)
@classmethod @classmethod
def pink(cls) -> Self: def pink(cls) -> Self:

3
discord/components.py

@ -442,6 +442,9 @@ class SelectOption:
return payload return payload
def copy(self) -> SelectOption:
return self.__class__.from_dict(self.to_dict())
class TextInput(Component): class TextInput(Component):
"""Represents a text input from the Discord Bot UI Kit. """Represents a text input from the Discord Bot UI Kit.

6
discord/embeds.py

@ -61,6 +61,12 @@ class EmbedMediaProxy(EmbedProxy):
super().__init__(layer) super().__init__(layer)
self._flags = self.__dict__.pop('flags', 0) self._flags = self.__dict__.pop('flags', 0)
def __bool__(self) -> bool:
# This is a nasty check to see if we only have the `_flags` attribute which is created regardless in init.
# Had we had any of the other items, like image/video data this would be >1 and therefor
# would not be "empty".
return len(self.__dict__) > 1
@property @property
def flags(self) -> AttachmentFlags: def flags(self) -> AttachmentFlags:
return AttachmentFlags._from_value(self._flags or 0) return AttachmentFlags._from_value(self._flags or 0)

8
discord/ext/commands/context.py

@ -924,7 +924,7 @@ class Context(discord.abc.Messageable, Generic[BotT]):
suppress_embeds: bool = False, suppress_embeds: bool = False,
ephemeral: bool = False, ephemeral: bool = False,
silent: bool = False, silent: bool = False,
poll: Poll = MISSING, poll: Optional[Poll] = None,
) -> Message: ) -> Message:
"""|coro| """|coro|
@ -1014,10 +1014,12 @@ class Context(discord.abc.Messageable, Generic[BotT]):
.. versionadded:: 2.2 .. versionadded:: 2.2
poll: :class:`~discord.Poll` poll: Optional[:class:`~discord.Poll`]
The poll to send with this message. The poll to send with this message.
.. versionadded:: 2.4 .. versionadded:: 2.4
.. versionchanged:: 2.6
This can now be ``None`` and defaults to ``None`` instead of ``MISSING``.
Raises Raises
-------- --------
@ -1072,7 +1074,7 @@ class Context(discord.abc.Messageable, Generic[BotT]):
'suppress_embeds': suppress_embeds, 'suppress_embeds': suppress_embeds,
'ephemeral': ephemeral, 'ephemeral': ephemeral,
'silent': silent, 'silent': silent,
'poll': poll, 'poll': MISSING if poll is None else poll,
} }
if self.interaction.response.is_done(): if self.interaction.response.is_done():

5
discord/guild.py

@ -2921,6 +2921,11 @@ class Guild(Hashable):
The name of the template. The name of the template.
description: :class:`str` description: :class:`str`
The description of the template. The description of the template.
Returns
--------
:class:`Template`
The created template.
""" """
from .template import Template from .template import Template

7
discord/http.py

@ -461,7 +461,12 @@ class Ratelimit:
future = self._loop.create_future() future = self._loop.create_future()
self._pending_requests.append(future) self._pending_requests.append(future)
try: try:
await future while not future.done():
# 30 matches the smallest allowed max_ratelimit_timeout
max_wait_time = self.expires - self._loop.time() if self.expires else 30
await asyncio.wait([future], timeout=max_wait_time)
if not future.done():
await self._refresh()
except: except:
future.cancel() future.cancel()
if self.remaining > 0 and not future.cancelled(): if self.remaining > 0 and not future.cancelled():

8
discord/interactions.py

@ -154,6 +154,10 @@ class Interaction(Generic[ClientT]):
The context of the interaction. The context of the interaction.
.. versionadded:: 2.4 .. versionadded:: 2.4
filesize_limit: int
The maximum number of bytes a file can have when responding to this interaction.
.. versionadded:: 2.6
""" """
__slots__: Tuple[str, ...] = ( __slots__: Tuple[str, ...] = (
@ -172,7 +176,8 @@ class Interaction(Generic[ClientT]):
'command_failed', 'command_failed',
'entitlement_sku_ids', 'entitlement_sku_ids',
'entitlements', 'entitlements',
"context", 'context',
'filesize_limit',
'_integration_owners', '_integration_owners',
'_permissions', '_permissions',
'_app_permissions', '_app_permissions',
@ -214,6 +219,7 @@ class Interaction(Generic[ClientT]):
self.application_id: int = int(data['application_id']) self.application_id: int = int(data['application_id'])
self.entitlement_sku_ids: List[int] = [int(x) for x in data.get('entitlement_skus', []) or []] self.entitlement_sku_ids: List[int] = [int(x) for x in data.get('entitlement_skus', []) or []]
self.entitlements: List[Entitlement] = [Entitlement(self._state, x) for x in data.get('entitlements', [])] self.entitlements: List[Entitlement] = [Entitlement(self._state, x) for x in data.get('entitlements', [])]
self.filesize_limit: int = data['attachment_size_limit']
# This is not entirely useful currently, unsure how to expose it in a way that it is. # This is not entirely useful currently, unsure how to expose it in a way that it is.
self._integration_owners: Dict[int, Snowflake] = { self._integration_owners: Dict[int, Snowflake] = {
int(k): int(v) for k, v in data.get('authorizing_integration_owners', {}).items() int(k): int(v) for k, v in data.get('authorizing_integration_owners', {}).items()

10
discord/permissions.py

@ -363,6 +363,16 @@ class Permissions(BaseFlags):
""" """
return cls(0b0000_0000_0000_0000_0000_0001_0000_0100_0111_0000_0000_0000_0010_0000_0011_1110) return cls(0b0000_0000_0000_0000_0000_0001_0000_0100_0111_0000_0000_0000_0010_0000_0011_1110)
@classmethod
def apps(cls) -> Self:
"""A factory method that creates a :class:`Permissions` with all
"Apps" permissions from the official Discord UI set to ``True``.
.. versionadded:: 2.6
"""
return cls(0b0000_0000_0000_0100_0000_0000_1000_0000_1000_0000_0000_0000_0000_0000_0000_0000)
@classmethod @classmethod
def events(cls) -> Self: def events(cls) -> Self:
"""A factory method that creates a :class:`Permissions` with all """A factory method that creates a :class:`Permissions` with all

4
discord/shard.py

@ -517,10 +517,10 @@ class AutoShardedClient(Client):
if item.type == EventType.close: if item.type == EventType.close:
await self.close() await self.close()
if isinstance(item.error, ConnectionClosed): if isinstance(item.error, ConnectionClosed):
if item.error.code != 1000:
raise item.error
if item.error.code == 4014: if item.error.code == 4014:
raise PrivilegedIntentsRequired(item.shard.id) from None raise PrivilegedIntentsRequired(item.shard.id) from None
if item.error.code != 1000:
raise item.error
return return
elif item.type in (EventType.identify, EventType.resume): elif item.type in (EventType.identify, EventType.resume):
await item.shard.reidentify(item.error) await item.shard.reidentify(item.error)

6
discord/template.py

@ -25,7 +25,7 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations from __future__ import annotations
from typing import Any, Optional, TYPE_CHECKING, List from typing import Any, Optional, TYPE_CHECKING, List
from .utils import parse_time, _bytes_to_base64_data, MISSING from .utils import parse_time, _bytes_to_base64_data, MISSING, deprecated
from .guild import Guild from .guild import Guild
# fmt: off # fmt: off
@ -164,6 +164,7 @@ class Template:
f' creator={self.creator!r} source_guild={self.source_guild!r} is_dirty={self.is_dirty}>' f' creator={self.creator!r} source_guild={self.source_guild!r} is_dirty={self.is_dirty}>'
) )
@deprecated()
async def create_guild(self, name: str, icon: bytes = MISSING) -> Guild: async def create_guild(self, name: str, icon: bytes = MISSING) -> Guild:
"""|coro| """|coro|
@ -178,6 +179,9 @@ class Template:
This function will now raise :exc:`ValueError` instead of This function will now raise :exc:`ValueError` instead of
``InvalidArgument``. ``InvalidArgument``.
.. deprecated:: 2.6
This function is deprecated and will be removed in a future version.
Parameters Parameters
---------- ----------
name: :class:`str` name: :class:`str`

1
discord/types/interactions.py

@ -233,6 +233,7 @@ class _BaseInteraction(TypedDict):
entitlements: NotRequired[List[Entitlement]] entitlements: NotRequired[List[Entitlement]]
authorizing_integration_owners: Dict[Literal['0', '1'], Snowflake] authorizing_integration_owners: Dict[Literal['0', '1'], Snowflake]
context: NotRequired[InteractionContextType] context: NotRequired[InteractionContextType]
attachment_size_limit: int
class PingInteraction(_BaseInteraction): class PingInteraction(_BaseInteraction):

3
discord/ui/view.py

@ -33,6 +33,7 @@ import sys
import time import time
import os import os
from .item import Item, ItemCallbackType from .item import Item, ItemCallbackType
from .select import Select
from .dynamic import DynamicItem from .dynamic import DynamicItem
from ..components import ( from ..components import (
Component, Component,
@ -179,6 +180,8 @@ class View:
item: Item = func.__discord_ui_model_type__(**func.__discord_ui_model_kwargs__) item: Item = func.__discord_ui_model_type__(**func.__discord_ui_model_kwargs__)
item.callback = _ViewCallback(func, self, item) # type: ignore item.callback = _ViewCallback(func, self, item) # type: ignore
item._view = self item._view = self
if isinstance(item, Select):
item.options = [option.copy() for option in item.options]
setattr(self, func.__name__, item) setattr(self, func.__name__, item)
children.append(item) children.append(item)
return children return children

6
docs/api.rst

@ -1354,8 +1354,10 @@ Soundboard
.. versionadded:: 2.5 .. versionadded:: 2.5
:param sound: The soundboard sound that was updated. :param before: The soundboard sound before the update.
:type sound: :class:`SoundboardSound` :type before: :class:`SoundboardSound`
:param after: The soundboard sound after the update.
:type after: :class:`SoundboardSound`
Stages Stages

4
docs/interactions/api.rst

@ -329,6 +329,10 @@ Enumerations
Represents a select in which both users and roles can be selected. Represents a select in which both users and roles can be selected.
.. attribute:: channel_select
Represents a channel select component.
.. class:: ButtonStyle .. class:: ButtonStyle
Represents the style of the button component. Represents the style of the button component.

2
tests/test_app_commands_invoke.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 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
""" """
from __future__ import annotations from __future__ import annotations
@ -90,6 +91,7 @@ class MockCommandInteraction(discord.Interaction):
"version": 1, "version": 1,
"type": 2, "type": 2,
"data": self._get_command_data(command, self._get_command_options(**options)), "data": self._get_command_data(command, self._get_command_options(**options)),
"attachment_size_limit": 0,
} }
super().__init__(data=data, state=client._connection) super().__init__(data=data, state=client._connection)

13
tests/test_colour.py

@ -106,11 +106,16 @@ def test_from_str_failures(value):
(discord.Colour.og_blurple(), 0x7289DA), (discord.Colour.og_blurple(), 0x7289DA),
(discord.Colour.blurple(), 0x5865F2), (discord.Colour.blurple(), 0x5865F2),
(discord.Colour.greyple(), 0x99AAB5), (discord.Colour.greyple(), 0x99AAB5),
(discord.Colour.dark_theme(), 0x313338), (discord.Colour.ash_theme(), 0x2E2E34),
(discord.Colour.dark_theme(), 0x1A1A1E),
(discord.Colour.onyx_theme(), 0x070709),
(discord.Colour.light_theme(), 0xFBFBFB),
(discord.Colour.fuchsia(), 0xEB459E), (discord.Colour.fuchsia(), 0xEB459E),
(discord.Colour.yellow(), 0xFEE75C), (discord.Colour.yellow(), 0xFEE75C),
(discord.Colour.dark_embed(), 0x2B2D31), (discord.Colour.ash_embed(), 0x37373E),
(discord.Colour.light_embed(), 0xEEEFF1), (discord.Colour.dark_embed(), 0x242429),
(discord.Colour.onyx_embed(), 0x131416),
(discord.Colour.light_embed(), 0xFFFFFF),
(discord.Colour.pink(), 0xEB459F), (discord.Colour.pink(), 0xEB459F),
], ],
) )
@ -118,8 +123,6 @@ def test_static_colours(value, expected):
assert value.value == expected assert value.value == expected
@pytest.mark.parametrize( @pytest.mark.parametrize(
('value', 'property', 'expected'), ('value', 'property', 'expected'),
[ [

11
tests/test_embed.py

@ -267,3 +267,14 @@ def test_embed_colour_setter_failure(value):
embed = discord.Embed() embed = discord.Embed()
with pytest.raises(TypeError): with pytest.raises(TypeError):
embed.colour = value embed.colour = value
@pytest.mark.parametrize(
('title', 'return_val'),
[
('test', True),
(None, False)
]
)
def test_embed_truthiness(title: str, return_val: bool) -> None:
embed = discord.Embed(title=title)
assert bool(embed) is return_val

Loading…
Cancel
Save