Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
bbb8e45
fix(invite): guard against None code
vmphase Jul 21, 2026
2bd7ace
chore: update changelog
vmphase Jul 21, 2026
43af42c
style(pre-commit): auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 21, 2026
ed05041
fix(invite): return "" on id property when code is None
vmphase Jul 21, 2026
d348ffc
refactor(types/invite): do not inherit VanityInvite from _InviteMetadata
vmphase Jul 21, 2026
70099ec
fix(invite): raise ValueError when code is None
vmphase Jul 21, 2026
6a5cfa1
refactor(types/invite): inline _InviteMetadata into IncompleteInvite
vmphase Jul 21, 2026
1812204
chore: update changelog
vmphase Jul 21, 2026
bc00082
style(pre-commit): auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 21, 2026
6b657a8
Merge branch 'master' into fix/invite-optional-code
vmphase Jul 26, 2026
a665bcf
chore: simplify changelog
vmphase Jul 27, 2026
a1c109e
fix(invite): preserve `__str__` return value for invites with a code
vmphase Jul 27, 2026
5a04ef4
Merge branch 'master' into fix/invite-optional-code
vmphase Jul 27, 2026
442ccbc
feat(invite): deprecate Invite.id
vmphase Jul 27, 2026
c921a59
chore: fix changelog
vmphase Jul 27, 2026
7ab228a
feat(invite; guild): revert guards, cast data to IncompleteInvite
vmphase Jul 27, 2026
6a51a9b
chore: update changelog
vmphase Jul 27, 2026
0e6b178
Merge branch 'master' into fix/invite-optional-code
Lulalaby Jul 30, 2026
c648a25
Merge branch 'master' into fix/invite-optional-code
Lulalaby Jul 30, 2026
ad37500
revert: `__str__` and `.id` checks
vmphase Aug 3, 2026
2d2c542
chore(changelog): remove "changed" log
vmphase Aug 3, 2026
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ These changes are available on the `master` branch, but have not yet been releas

### Deprecated

- Deprecated `Invite.id` in favor of `Invite.code`.
([#3313](https://github.com/Pycord-Development/pycord/pull/3313))

### Removed

## [2.8.1] - 2026-07-25
Expand Down
10 changes: 9 additions & 1 deletion discord/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
Optional,
TypeVar,
Union,
cast,
overload,
)

Expand Down Expand Up @@ -119,6 +120,7 @@
from .types.guild import Guild as GuildPayload
from .types.guild import GuildFeature, MFALevel
from .types.guild import ModifyIncidents as ModifyIncidentsPayload
from .types.invite import IncompleteInvite
from .types.member import Member as MemberPayload
from .types.threads import Thread as ThreadPayload
from .types.voice import VoiceState as GuildVoiceState
Expand Down Expand Up @@ -3784,7 +3786,13 @@ async def vanity_invite(self) -> Invite | None:
payload["max_uses"] = 0
payload["max_age"] = 0
payload["uses"] = payload.get("uses", 0)
return Invite(state=self._state, data=payload, guild=self, channel=channel)

return Invite(
state=self._state,
data=cast("IncompleteInvite", payload),
guild=self,
channel=channel,
)

# TODO: use MISSING when async iterators get refactored
def audit_logs(
Expand Down
42 changes: 23 additions & 19 deletions discord/invite.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import os
from typing import TYPE_CHECKING, TypeVar, Union

from typing_extensions import override
from typing_extensions import deprecated, override

from .appinfo import PartialAppInfo
from .asset import Asset
Expand Down Expand Up @@ -62,12 +62,12 @@
from .state import ConnectionState
from .types.channel import PartialChannel as InviteChannelPayload
from .types.invite import GatewayInvite as GatewayInvitePayload
from .types.invite import IncompleteInvite as IncompleteInvitePayload
from .types.invite import Invite as InvitePayload
from .types.invite import InviteGuild as InviteGuildPayload
from .types.invite import (
InviteTargetUsersJobStatus as InviteTargetUsersJobStatusPayload,
)
from .types.invite import VanityInvite as VanityInvitePayload
from .types.role import Role as RolePayload
from .types.scheduled_events import ScheduledEvent as ScheduledEventPayload
from .types.snowflake import Snowflake
Expand Down Expand Up @@ -512,25 +512,25 @@ class Invite(Hashable):
"""

__slots__ = (
"max_age",
"code",
"guild",
"revoked",
"created_at",
"uses",
"temporary",
"max_uses",
"inviter",
"channel",
"target_user",
"target_type",
"_state",
"approximate_member_count",
"approximate_presence_count",
"scheduled_event",
"target_application",
"channel",
"code",
"created_at",
"expires_at",
"guild",
"inviter",
"max_age",
"max_uses",
"revoked",
"roles",
"scheduled_event",
"target_application",
"target_type",
"target_user",
"temporary",
"uses",
)

BASE = "https://discord.gg"
Expand All @@ -539,7 +539,7 @@ def __init__(
self,
*,
state: ConnectionState,
data: InvitePayload | VanityInvitePayload,
data: InvitePayload | IncompleteInvitePayload,
guild: PartialInviteGuild | Guild | None = None,
channel: PartialInviteChannel | GuildChannel | None = None,
):
Expand Down Expand Up @@ -705,13 +705,18 @@ def __hash__(self) -> int:
return hash(self.code)

@property
def id(self) -> str:
@deprecated(
"Invite.id is deprecated since version 2.9, consider using Invite.code instead."
)
def id(self) -> str: # type: ignore[override]
Comment thread
vmphase marked this conversation as resolved.
"""Returns the proper code portion of the invite."""
return self.code

@property
def url(self) -> str:
"""A property that retrieves the invite URL."""
if self.code is None:
raise ValueError("Cannot build an invite URL when code is None")
return f"{self.BASE}/{self.code}{f'?event={self.scheduled_event.id}' if self.scheduled_event else ''}"

@property
Expand Down Expand Up @@ -795,7 +800,6 @@ async def delete(self, *, reason: str | None = None):
HTTPException
Revoking the invite failed.
"""

await self._state.http.delete_invite(self.code, reason=reason)

def set_scheduled_event(self, event: ScheduledEvent) -> None:
Expand Down
20 changes: 9 additions & 11 deletions discord/types/invite.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,20 @@
InviteTargetType = Literal[1, 2]


class _InviteMetadata(TypedDict, total=False):
uses: int
max_uses: int
max_age: int
temporary: bool
created_at: str
expires_at: str | None


class VanityInvite(_InviteMetadata):
class VanityInvite(TypedDict):
code: str | None
uses: int


class IncompleteInvite(_InviteMetadata):
class IncompleteInvite(TypedDict):
code: str
channel: PartialChannel
uses: NotRequired[int]
max_uses: NotRequired[int]
max_age: NotRequired[int]
temporary: NotRequired[bool]
created_at: NotRequired[str]
expires_at: NotRequired[str | None]


class Invite(IncompleteInvite):
Expand Down