Skip to content

Commit 952e309

Browse files
refactor: ♻️ Replace utils.deprecated with warnings.deprecated (#3042)
* ♻️ Replace `utils.deprecated` with `typing(_extensions).deprecated` * 🔥 Remove `deprecated` from `discord.utils.__all__` * 📝 CHANGELOG.md * style(pre-commit): auto fixes from pre-commit.com hooks * 📝 Reword CHANGELOG.md entry --------- Signed-off-by: Paillat <paillat@pycord.dev> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 320d7bc commit 952e309

7 files changed

Lines changed: 62 additions & 87 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ These changes are available on the `master` branch, but have not yet been releas
6161

6262
### Changed
6363

64+
- Migrated away from `utils.deprecated` in favor of `warnings.deprecated`. Added type
65+
checker warnings support for function deprecations.
66+
([#3042](https://github.com/Pycord-Development/pycord/pull/3042))
6467
- Updated `Role.is_assignable()` to also check whether the bot has the `MANAGE_ROLES`
6568
permission. ([#3048](https://github.com/Pycord-Development/pycord/pull/3048))
6669
- Updated the docs' Sphinx version to v9.

discord/_version.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,12 @@
3030
import warnings
3131
from importlib.metadata import PackageNotFoundError, version
3232

33-
from typing_extensions import TypedDict
33+
from typing_extensions import TypedDict, deprecated
3434

3535
__all__ = ("__version__", "VersionInfo", "version_info")
3636

3737
from typing import Literal, NamedTuple
3838

39-
from .utils import deprecated
40-
4139
try:
4240
__version__ = version("py-cord")
4341
except PackageNotFoundError:
@@ -84,27 +82,37 @@ def advanced(self, value: object) -> None:
8482
_advanced = value
8583

8684
@property
87-
@deprecated("releaselevel", "2.4")
85+
@deprecated(
86+
"VersionInfo.release_level is deprecated since version 2.4, consider using releaselevel instead."
87+
)
8888
def release_level(self) -> Literal["alpha", "beta", "candidate", "final"]:
8989
return self.releaselevel
9090

9191
@property
92-
@deprecated('.advanced["serial"]', "2.4")
92+
@deprecated(
93+
'VersionInfo.serial is deprecated since version 2.4, consider using .advanced["serial"] instead.'
94+
)
9395
def serial(self) -> int:
9496
return self.advanced["serial"]
9597

9698
@property
97-
@deprecated('.advanced["build"]', "2.4")
99+
@deprecated(
100+
'VersionInfo.build is deprecated since version 2.4, consider using .advanced["build"] instead.'
101+
)
98102
def build(self) -> int | None:
99103
return self.advanced["build"]
100104

101105
@property
102-
@deprecated('.advanced["commit"]', "2.4")
106+
@deprecated(
107+
'VersionInfo.commit is deprecated since version 2.4, consider using .advanced["commit"] instead.'
108+
)
103109
def commit(self) -> str | None:
104110
return self.advanced["commit"]
105111

106112
@property
107-
@deprecated('.advanced["date"]', "2.4")
113+
@deprecated(
114+
'VersionInfo.date is deprecated since version 2.4, consider using .advanced["date"] instead.'
115+
)
108116
def date(self) -> datetime.date | None:
109117
return self.advanced["date"]
110118

discord/channel.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
overload,
3939
)
4040

41+
from typing_extensions import deprecated
42+
4143
import discord.abc
4244

4345
from . import utils
@@ -3118,21 +3120,17 @@ async def create_forum_channel(self, name: str, **options: Any) -> ForumChannel:
31183120
"""
31193121
return await self.guild.create_forum_channel(name, category=self, **options)
31203122

3121-
@utils.deprecated(
3122-
since="2.7",
3123-
removed="3.0",
3124-
reference="NSFW categories are not available in the Discord API.",
3123+
@deprecated(
3124+
"CategoryChannel.is_nsfw is deprecated since version 2.7 and will be removed in version 3.0. NSFW categories are not available in the Discord API."
31253125
)
31263126
def is_nsfw(self) -> bool:
31273127
return False
31283128

31293129
# TODO: Remove in 3.0
31303130

31313131
@property
3132-
@utils.deprecated(
3133-
since="2.7",
3134-
removed="3.0",
3135-
reference="NSFW categories are not available in the Discord API.",
3132+
@deprecated(
3133+
"CategoryChannel.nsfw is deprecated since version 2.7 and will be removed in version 3.0. NSFW categories are not available in the Discord API."
31363134
)
31373135
def nsfw(self) -> bool:
31383136
return False

discord/client.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
)
4343

4444
import aiohttp
45+
from typing_extensions import deprecated
4546

4647
from . import utils
4748
from .activity import ActivityTypes, BaseActivity, create_activity
@@ -1185,10 +1186,8 @@ def get_all_members(self) -> Generator[Member]:
11851186
for guild in self.guilds:
11861187
yield from guild.members
11871188

1188-
@utils.deprecated(
1189-
instead="Client.get_or_fetch(User, id)",
1190-
since="2.7",
1191-
removed="3.0",
1189+
@deprecated(
1190+
"Client.get_or_fetch_user is deprecated since version 2.7 and will be removed in version 3.0, consider using Client.get_or_fetch(User, id) instead."
11921191
)
11931192
async def get_or_fetch_user(self, id: int, /) -> User | None: # TODO: Remove in 3.0
11941193
"""|coro|

discord/interactions.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import datetime
3030
from typing import TYPE_CHECKING, Any, Coroutine, Union, overload
3131

32+
from typing_extensions import deprecated
33+
3234
from . import utils
3335
from .channel import ChannelType, PartialMessageable, _threaded_channel_factory
3436
from .enums import (
@@ -223,6 +225,7 @@ def __init__(self, *, data: InteractionPayload, state: ConnectionState):
223225
self._session: ClientSession = state.http._HTTPClient__session
224226
self._original_response: InteractionMessage | None = None
225227
self.callback: InteractionCallback | None = None
228+
self._cs_channel: InteractionChannel | None = MISSING
226229
self._from_data(data)
227230

228231
def _from_data(self, data: InteractionPayload):
@@ -357,14 +360,19 @@ def is_component(self) -> bool:
357360
"""Indicates whether the interaction is a message component."""
358361
return self.type == InteractionType.component
359362

360-
@utils.cached_slot_property("_cs_channel")
361-
@utils.deprecated("Interaction.channel", "2.7", stacklevel=4)
363+
@property
364+
@deprecated(
365+
"Interaction.cached_channel is deprecated since version 2.7, consider using Interaction.channel instead."
366+
)
362367
def cached_channel(self) -> InteractionChannel | None:
363368
"""The cached channel from which the interaction was sent.
364369
DM channels are not resolved. These are :class:`PartialMessageable` instead.
365370
366371
.. deprecated:: 2.7
367372
"""
373+
if self._cs_channel is not MISSING:
374+
return self._cs_channel
375+
r: InteractionChannel | None = None
368376
guild = self.guild
369377
channel = guild and guild._resolve_channel(self.channel_id)
370378
if channel is None:
@@ -374,11 +382,11 @@ def cached_channel(self) -> InteractionChannel | None:
374382
if self.guild_id is not None
375383
else ChannelType.private
376384
)
377-
return PartialMessageable(
378-
state=self._state, id=self.channel_id, type=type
379-
)
380-
return None
381-
return channel
385+
r = PartialMessageable(state=self._state, id=self.channel_id, type=type)
386+
else:
387+
r = channel
388+
self._cs_channel = r
389+
return r
382390

383391
@property
384392
def permissions(self) -> Permissions:
@@ -496,7 +504,9 @@ async def original_response(self) -> InteractionMessage:
496504
self._original_response = message
497505
return message
498506

499-
@utils.deprecated("Interaction.original_response", "2.2")
507+
@deprecated(
508+
"Interaction.original_message is deprecated since version 2.2, consider using Interaction.original_response instead."
509+
)
500510
async def original_message(self):
501511
"""An alias for :meth:`original_response`.
502512
@@ -642,7 +652,9 @@ async def edit_original_response(
642652

643653
return message
644654

645-
@utils.deprecated("Interaction.edit_original_response", "2.2")
655+
@deprecated(
656+
"Interaction.edit_original_message is deprecated since version 2.2, consider using Interaction.edit_original_response instead."
657+
)
646658
async def edit_original_message(self, **kwargs):
647659
"""An alias for :meth:`edit_original_response`.
648660
@@ -700,7 +712,9 @@ async def delete_original_response(self, *, delay: float | None = None) -> None:
700712
else:
701713
await func
702714

703-
@utils.deprecated("Interaction.delete_original_response", "2.2")
715+
@deprecated(
716+
"Interaction.delete_original_message is deprecated since version 2.2, consider using Interaction.delete_original_response instead."
717+
)
704718
async def delete_original_message(self, **kwargs):
705719
"""An alias for :meth:`delete_original_response`.
706720
@@ -1487,7 +1501,9 @@ async def send_modal(self, modal: BaseModal) -> Interaction:
14871501
self._parent._state.store_modal(modal, self._parent.user.id)
14881502
return self._parent
14891503

1490-
@utils.deprecated("a button with type ButtonType.premium", "2.6")
1504+
@deprecated(
1505+
"InteractionResponse.premium_required is deprecated since version 2.6, consider using a button with type ButtonType.premium instead."
1506+
)
14911507
async def premium_required(self) -> Interaction:
14921508
"""|coro|
14931509

discord/role.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
from typing import TYPE_CHECKING, Any, TypeVar
2929

30-
from typing_extensions import Self
30+
from typing_extensions import Self, deprecated
3131

3232
from .asset import Asset
3333
from .colour import Colour
@@ -39,7 +39,6 @@
3939
MISSING,
4040
_bytes_to_base64_data,
4141
_get_as_snowflake,
42-
deprecated,
4342
snowflake_time,
4443
warn_deprecated,
4544
)
@@ -489,7 +488,9 @@ def permissions(self) -> Permissions:
489488
return Permissions(self._permissions)
490489

491490
@property
492-
@deprecated("colours.primary", "2.7")
491+
@deprecated(
492+
"Role.colour is deprecated since version 2.7, consider using colours.primary instead."
493+
)
493494
def colour(self) -> Colour:
494495
"""Returns the role colour. Equivalent to :attr:`colours.primary`.
495496
An alias exists under ``color``.
@@ -499,7 +500,9 @@ def colour(self) -> Colour:
499500
return self.colours.primary
500501

501502
@property
502-
@deprecated("colors.primary", "2.7")
503+
@deprecated(
504+
"Role.color is deprecated since version 2.7, consider using colors.primary instead."
505+
)
503506
def color(self) -> Colour:
504507
"""Returns the role's primary color. Equivalent to :attr:`colors.primary`.
505508
An alias exists under ``colour``.

discord/utils.py

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@
9494
__all__ = (
9595
"parse_time",
9696
"warn_deprecated",
97-
"deprecated",
9897
"oauth_url",
9998
"snowflake_time",
10099
"time_snowflake",
@@ -345,57 +344,6 @@ def warn_deprecated(
345344
warnings.warn(message, stacklevel=stacklevel, category=DeprecationWarning)
346345

347346

348-
def deprecated(
349-
instead: str | None = None,
350-
since: str | None = None,
351-
removed: str | None = None,
352-
reference: str | None = None,
353-
stacklevel: int = 3,
354-
*,
355-
use_qualname: bool = True,
356-
) -> Callable[[Callable[[P], T]], Callable[[P], T]]:
357-
"""A decorator implementation of :func:`warn_deprecated`. This will automatically call :func:`warn_deprecated` when
358-
the decorated function is called.
359-
360-
Parameters
361-
----------
362-
instead: Optional[:class:`str`]
363-
A recommended alternative to the function.
364-
since: Optional[:class:`str`]
365-
The version in which the function was deprecated. This should be in the format ``major.minor(.patch)``, where
366-
the patch version is optional.
367-
removed: Optional[:class:`str`]
368-
The version in which the function is planned to be removed. This should be in the format
369-
``major.minor(.patch)``, where the patch version is optional.
370-
reference: Optional[:class:`str`]
371-
A reference that explains the deprecation, typically a URL to a page such as a changelog entry or a GitHub
372-
issue/PR.
373-
stacklevel: :class:`int`
374-
The stacklevel kwarg passed to :func:`warnings.warn`. Defaults to 3.
375-
use_qualname: :class:`bool`
376-
Whether to use the qualified name of the function in the deprecation warning. If ``False``, the short name of
377-
the function will be used instead. For example, __qualname__ will display as ``Client.login`` while __name__
378-
will display as ``login``. Defaults to ``True``.
379-
"""
380-
381-
def actual_decorator(func: Callable[[P], T]) -> Callable[[P], T]:
382-
@functools.wraps(func)
383-
def decorated(*args: P.args, **kwargs: P.kwargs) -> T:
384-
warn_deprecated(
385-
name=func.__qualname__ if use_qualname else func.__name__,
386-
instead=instead,
387-
since=since,
388-
removed=removed,
389-
reference=reference,
390-
stacklevel=stacklevel,
391-
)
392-
return func(*args, **kwargs)
393-
394-
return decorated
395-
396-
return actual_decorator
397-
398-
399347
def oauth_url(
400348
client_id: int | str,
401349
*,

0 commit comments

Comments
 (0)