Skip to content

Commit 98f106f

Browse files
authored
Merge branch 'master' into components-v2
Signed-off-by: UK <[email protected]>
2 parents 00ee61d + 8e97cb5 commit 98f106f

File tree

16 files changed

+80
-73
lines changed

16 files changed

+80
-73
lines changed

.github/workflows/docs-localization-download.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
working-directory: ./docs
4141
- name: "Crowdin"
4242
id: crowdin
43-
uses: crowdin/[email protected].0
43+
uses: crowdin/[email protected].1
4444
with:
4545
upload_sources: false
4646
upload_translations: false

.github/workflows/docs-localization-upload.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444
sphinx-intl update -p ./build/locales ${{ vars.SPHINX_LANGUAGES }}
4545
working-directory: ./docs
4646
- name: "Crowdin"
47-
uses: crowdin/[email protected].0
47+
uses: crowdin/[email protected].1
4848
with:
4949
upload_sources: true
5050
upload_translations: false

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ repos:
2121
# - --remove-duplicate-keys
2222
# - --remove-unused-variables
2323
- repo: https://github.com/asottile/pyupgrade
24-
rev: v3.19.1
24+
rev: v3.20.0
2525
hooks:
2626
- id: pyupgrade
2727
exclude: \.(po|pot|yml|yaml)$

CHANGELOG.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,10 @@ These changes are available on the `master` branch, but have not yet been releas
5353
([#2598](https://github.com/Pycord-Development/pycord/pull/2598))
5454
- Added the ability to change the API's base URL with `Route.API_BASE_URL`.
5555
([#2714](https://github.com/Pycord-Development/pycord/pull/2714))
56-
- Added the ability to pass a `datetime.time` object to `format_dt`
56+
- Added the ability to pass a `datetime.time` object to `format_dt`.
5757
([#2747](https://github.com/Pycord-Development/pycord/pull/2747))
58+
- Added `discord.Interaction.created_at`.
59+
([#2801](https://github.com/Pycord-Development/pycord/pull/2801))
5860

5961
### Fixed
6062

@@ -105,12 +107,18 @@ These changes are available on the `master` branch, but have not yet been releas
105107
([#2739](https://github.com/Pycord-Development/pycord/pull/2739))
106108
- Fixed missing `None` type hints in `Select.__init__`.
107109
([#2746](https://github.com/Pycord-Development/pycord/pull/2746))
110+
- Fixed `TypeError` when using `Flag` with Python 3.11+.
111+
([#2759](https://github.com/Pycord-Development/pycord/pull/2759))
112+
- Fixed `TypeError` when specifying `thread_name` in `Webhook.send`.
113+
([#2761](https://github.com/Pycord-Development/pycord/pull/2761))
108114
- Updated `valid_locales` to support `in` and `es-419`.
109115
([#2767](https://github.com/Pycord-Development/pycord/pull/2767))
110116
- Fixed `Webhook.edit` not working with `attachments=[]`.
111117
([#2779](https://github.com/Pycord-Development/pycord/pull/2779))
112118
- Fixed GIF-based `Sticker` returning the wrong `url`.
113119
([#2781](https://github.com/Pycord-Development/pycord/pull/2781))
120+
- Fixed `VoiceClient` crashing randomly while receiving audio
121+
([#2800](https://github.com/Pycord-Development/pycord/pull/2800))
114122

115123
### Changed
116124

@@ -140,6 +148,11 @@ These changes are available on the `master` branch, but have not yet been releas
140148
- Deprecated `Interaction.cached_channel` in favor of `Interaction.channel`.
141149
([#2658](https://github.com/Pycord-Development/pycord/pull/2658))
142150

151+
### Removed
152+
153+
- Removed deprecated support for `Option` in `BridgeCommand`. Use `BridgeOption`
154+
instead. ([#2731])(https://github.com/Pycord-Development/pycord/pull/2731))
155+
143156
## [2.6.1] - 2024-09-15
144157

145158
### Fixed

discord/ext/bridge/core.py

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -98,26 +98,12 @@ class BridgeExtCommand(Command):
9898
def __init__(self, func, **kwargs):
9999
super().__init__(func, **kwargs)
100100

101-
# TODO: v2.7: Remove backwards support for Option in bridge commands.
102-
for name, option in self.params.items():
101+
for option in self.params.values():
103102
if isinstance(option.annotation, Option) and not isinstance(
104103
option.annotation, BridgeOption
105104
):
106-
# Warn not to do this
107-
warn_deprecated(
108-
"Using Option for bridge commands",
109-
"BridgeOption",
110-
"2.5",
111-
"2.7",
112-
reference="https://github.com/Pycord-Development/pycord/pull/2417",
113-
stacklevel=6,
114-
)
115-
# Override the convert method of the parameter's annotated Option.
116-
# We can use the convert method from BridgeOption, and bind "self"
117-
# using a manual invocation of the descriptor protocol.
118-
# Definitely not a good approach, but gets the job done until removal.
119-
self.params[name].annotation.convert = BridgeOption.convert.__get__(
120-
self.params[name].annotation
105+
raise TypeError(
106+
f"{option.annotation.__class__.__name__} is not supported in bridge commands. Use BridgeOption instead."
121107
)
122108

123109
async def dispatch_error(self, ctx: BridgeExtContext, error: Exception) -> None:

discord/ext/commands/flags.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,11 @@
3131
from dataclasses import dataclass, field
3232
from typing import TYPE_CHECKING, Any, Iterator, Literal, Pattern, TypeVar, Union
3333

34-
from discord.utils import MISSING, MissingField, maybe_coroutine, resolve_annotation
35-
36-
if sys.version_info >= (3, 11):
37-
_MISSING = MissingField
38-
else:
39-
_MISSING = MISSING
34+
from discord.utils import (
35+
MISSING,
36+
maybe_coroutine,
37+
resolve_annotation,
38+
)
4039

4140
from .converter import run_converters
4241
from .errors import (
@@ -59,6 +58,10 @@
5958
from .context import Context
6059

6160

61+
def _missing_field_factory() -> field:
62+
return field(default_factory=lambda: MISSING)
63+
64+
6265
@dataclass
6366
class Flag:
6467
"""Represents a flag parameter for :class:`FlagConverter`.
@@ -86,13 +89,13 @@ class Flag:
8689
Whether multiple given values overrides the previous value.
8790
"""
8891

89-
name: str = _MISSING
92+
name: str = _missing_field_factory()
9093
aliases: list[str] = field(default_factory=list)
91-
attribute: str = _MISSING
92-
annotation: Any = _MISSING
93-
default: Any = _MISSING
94-
max_args: int = _MISSING
95-
override: bool = _MISSING
94+
attribute: str = _missing_field_factory()
95+
annotation: Any = _missing_field_factory()
96+
default: Any = _missing_field_factory()
97+
max_args: int = _missing_field_factory()
98+
override: bool = _missing_field_factory()
9699
cast_to_dict: bool = False
97100

98101
@property

discord/guild.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
from .welcome_screen import WelcomeScreen, WelcomeScreenChannel
8989
from .widget import Widget
9090

91-
__all__ = ("Guild",)
91+
__all__ = ("BanEntry", "Guild")
9292

9393
MISSING = utils.MISSING
9494

discord/interactions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from __future__ import annotations
2727

2828
import asyncio
29+
import datetime
2930
from typing import TYPE_CHECKING, Any, Coroutine, Union
3031

3132
from . import utils
@@ -319,6 +320,11 @@ def guild(self) -> Guild | None:
319320
return self._guild
320321
return self._state and self._state._get_guild(self.guild_id)
321322

323+
@property
324+
def created_at(self) -> datetime.datetime:
325+
"""Returns the interaction's creation time in UTC."""
326+
return utils.snowflake_time(self.id)
327+
322328
def is_command(self) -> bool:
323329
"""Indicates whether the interaction is an application command."""
324330
return self.type == InteractionType.application_command

discord/ui/view.py

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
import time
3232
from functools import partial
3333
from itertools import groupby
34-
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Iterator, Sequence
34+
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Iterator, Sequence, TypeVar
3535

3636
from ..components import ActionRow as ActionRowComponent
3737
from ..components import Button as ButtonComponent
@@ -57,6 +57,8 @@
5757
from ..state import ConnectionState
5858
from ..types.components import Component as ComponentPayload
5959

60+
V = TypeVar("V", bound="View", covariant=True)
61+
6062

6163
def _walk_all_components(components: list[Component]) -> Iterator[Component]:
6264
for item in components:
@@ -66,6 +68,7 @@ def _walk_all_components(components: list[Component]) -> Iterator[Component]:
6668
yield item
6769

6870

71+
6972
def _walk_all_components_v2(components: list[Component]) -> Iterator[Component]:
7073
for item in components:
7174
if isinstance(item, ActionRowComponent):
@@ -74,9 +77,10 @@ def _walk_all_components_v2(components: list[Component]) -> Iterator[Component]:
7477
yield from item.walk_components()
7578
else:
7679
yield item
80+
81+
82+
def _component_to_item(component: Component) -> Item[V]:
7783

78-
79-
def _component_to_item(component: Component) -> Item:
8084
if isinstance(component, ButtonComponent):
8185
from .button import Button
8286

@@ -123,7 +127,7 @@ def _component_to_item(component: Component) -> Item:
123127
class _ViewWeights:
124128
__slots__ = ("weights",)
125129

126-
def __init__(self, children: list[Item]):
130+
def __init__(self, children: list[Item[V]]):
127131
self.weights: list[int] = [0, 0, 0, 0, 0]
128132

129133
key = lambda i: sys.maxsize if i.row is None else i.row
@@ -132,7 +136,7 @@ def __init__(self, children: list[Item]):
132136
for item in group:
133137
self.add_item(item)
134138

135-
def find_open_space(self, item: Item) -> int:
139+
def find_open_space(self, item: Item[V]) -> int:
136140
for index, weight in enumerate(self.weights):
137141
# check if open space AND (next row has no items OR this is the last row)
138142
if (weight + item.width <= 5) and (
@@ -143,11 +147,12 @@ def find_open_space(self, item: Item) -> int:
143147

144148
raise ValueError("could not find open space for item")
145149

146-
def add_item(self, item: Item) -> None:
150+
def add_item(self, item: Item[V]) -> None:
147151
if (
148152
item._underlying.is_v2() or not self.fits_legacy(item)
149153
) and not self.requires_v2():
150154
self.weights.extend([0, 0, 0, 0, 0] * 7)
155+
151156
if item.row is not None:
152157
total = self.weights[item.row] + item.width
153158
if total > 5:
@@ -161,7 +166,7 @@ def add_item(self, item: Item) -> None:
161166
self.weights[index] += item.width
162167
item._rendered_row = index
163168

164-
def remove_item(self, item: Item) -> None:
169+
def remove_item(self, item: Item[V]) -> None:
165170
if item._rendered_row is not None:
166171
self.weights[item._rendered_row] -= item.width
167172
item._rendered_row = None
@@ -227,15 +232,15 @@ def __init_subclass__(cls) -> None:
227232

228233
def __init__(
229234
self,
230-
*items: Item,
235+
*items: Item[V],
231236
timeout: float | None = 180.0,
232237
disable_on_timeout: bool = False,
233238
):
234239
self.timeout = timeout
235240
self.disable_on_timeout = disable_on_timeout
236-
self.children: list[Item] = []
241+
self.children: list[Item[V]] = []
237242
for func in self.__view_children_items__:
238-
item: Item = func.__discord_ui_model_type__(
243+
item: Item[V] = func.__discord_ui_model_type__(
239244
**func.__discord_ui_model_kwargs__
240245
)
241246
item.callback = partial(func, self, item)
@@ -278,7 +283,7 @@ async def __timeout_task_impl(self) -> None:
278283
await asyncio.sleep(self.__timeout_expiry - now)
279284

280285
def to_components(self) -> list[dict[str, Any]]:
281-
def key(item: Item) -> int:
286+
def key(item: Item[V]) -> int:
282287
return item._rendered_row or 0
283288

284289
children = sorted(self.children, key=key)
@@ -365,7 +370,7 @@ def _expires_at(self) -> float | None:
365370
return time.monotonic() + self.timeout
366371
return None
367372

368-
def add_item(self, item: Item) -> None:
373+
def add_item(self, item: Item[V]) -> None:
369374
"""Adds an item to the view.
370375
371376
Parameters
@@ -397,7 +402,7 @@ def add_item(self, item: Item) -> None:
397402
self.children.append(item)
398403
return self
399404

400-
def remove_item(self, item: Item | int | str) -> None:
405+
def remove_item(self, item: Item[V] | int | str) -> None:
401406
"""Removes an item from the view. If an int or str is passed, it will remove by Item :attr:`id` or ``custom_id`` respectively.
402407
403408
Parameters
@@ -422,7 +427,7 @@ def clear_items(self) -> None:
422427
self.__weights.clear()
423428
return self
424429

425-
def get_item(self, custom_id: str | int) -> Item | None:
430+
def get_item(self, custom_id: str | int) -> Item[V] | None:
426431
"""Get an item from the view. Roughly equal to `utils.get(view.children, ...)`.
427432
If an ``int`` is provided it will retrieve by ``id``, otherwise it will check ``custom_id``.
428433
This method will also search nested items.
@@ -508,7 +513,7 @@ async def on_check_failure(self, interaction: Interaction) -> None:
508513
"""
509514

510515
async def on_error(
511-
self, error: Exception, item: Item, interaction: Interaction
516+
self, error: Exception, item: Item[V], interaction: Interaction
512517
) -> None:
513518
"""|coro|
514519
@@ -528,7 +533,7 @@ async def on_error(
528533
"""
529534
interaction.client.dispatch("view_error", error, item, interaction)
530535

531-
async def _scheduled_task(self, item: Item, interaction: Interaction):
536+
async def _scheduled_task(self, item: Item[V], interaction: Interaction):
532537
try:
533538
if self.timeout:
534539
self.__timeout_expiry = time.monotonic() + self.timeout
@@ -560,7 +565,7 @@ def _dispatch_timeout(self):
560565
self.on_timeout(), name=f"discord-ui-view-timeout-{self.id}"
561566
)
562567

563-
def _dispatch_item(self, item: Item, interaction: Interaction):
568+
def _dispatch_item(self, item: Item[V], interaction: Interaction):
564569
if self.__stopped.done():
565570
return
566571

@@ -656,7 +661,7 @@ async def wait(self) -> bool:
656661
"""
657662
return await self.__stopped
658663

659-
def disable_all_items(self, *, exclusions: list[Item] | None = None) -> None:
664+
def disable_all_items(self, *, exclusions: list[Item[V]] | None = None) -> None:
660665
"""
661666
Disables all buttons and select menus in the view.
662667
@@ -674,7 +679,7 @@ def disable_all_items(self, *, exclusions: list[Item] | None = None) -> None:
674679
child.disable_all_items(exclusions=exclusions)
675680
return self
676681

677-
def enable_all_items(self, *, exclusions: list[Item] | None = None) -> None:
682+
def enable_all_items(self, *, exclusions: list[Item[V]] | None = None) -> None:
678683
"""
679684
Enables all buttons and select menus in the view.
680685
@@ -715,7 +720,7 @@ def message(self, value):
715720
class ViewStore:
716721
def __init__(self, state: ConnectionState):
717722
# (component_type, message_id, custom_id): (View, Item)
718-
self._views: dict[tuple[int, int | None, str], tuple[View, Item]] = {}
723+
self._views: dict[tuple[int, int | None, str], tuple[View, Item[V]]] = {}
719724
# message_id: View
720725
self._synced_message_views: dict[int, View] = {}
721726
self._state: ConnectionState = state

0 commit comments

Comments
 (0)