mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-04-22 08:44:10 +00:00
Add typings for invites, templates, and bans
This commit is contained in:
parent
3e92196a2b
commit
1efdef3ac3
@ -27,6 +27,7 @@ import logging
|
||||
import signal
|
||||
import sys
|
||||
import traceback
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
import aiohttp
|
||||
|
||||
@ -1070,7 +1071,7 @@ class Client:
|
||||
"""
|
||||
code = utils.resolve_template(code)
|
||||
data = await self.http.get_template(code)
|
||||
return Template(data=data, state=self._connection)
|
||||
return Template(data=data, state=self._connection) # type: ignore
|
||||
|
||||
async def fetch_guild(self, guild_id):
|
||||
"""|coro|
|
||||
@ -1106,7 +1107,7 @@ class Client:
|
||||
data = await self.http.get_guild(guild_id)
|
||||
return Guild(data=data, state=self._connection)
|
||||
|
||||
async def create_guild(self, name, region=None, icon=None, *, code=None):
|
||||
async def create_guild(self, name: str, region: Optional[VoiceRegion] = None, icon: Any = None, *, code: str = None):
|
||||
"""|coro|
|
||||
|
||||
Creates a :class:`.Guild`.
|
||||
@ -1155,7 +1156,7 @@ class Client:
|
||||
|
||||
# Invite management
|
||||
|
||||
async def fetch_invite(self, url, *, with_counts=True):
|
||||
async def fetch_invite(self, url: Union[Invite, str], *, with_counts: bool = True) -> Invite:
|
||||
"""|coro|
|
||||
|
||||
Gets an :class:`.Invite` from a discord.gg URL or ID.
|
||||
@ -1192,7 +1193,7 @@ class Client:
|
||||
data = await self.http.get_invite(invite_id, with_counts=with_counts)
|
||||
return Invite.from_incomplete(state=self._connection, data=data)
|
||||
|
||||
async def delete_invite(self, invite):
|
||||
async def delete_invite(self, invite: Union[Invite, str]) -> None:
|
||||
"""|coro|
|
||||
|
||||
Revokes an :class:`.Invite`, URL, or ID to an invite.
|
||||
|
@ -24,6 +24,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import copy
|
||||
from collections import namedtuple
|
||||
from typing import List, TYPE_CHECKING
|
||||
|
||||
from . import utils
|
||||
from .role import Role
|
||||
@ -48,6 +49,11 @@ __all__ = (
|
||||
'Guild',
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .types.guild import (
|
||||
Ban as BanPayload
|
||||
)
|
||||
|
||||
BanEntry = namedtuple('BanEntry', 'reason user')
|
||||
_GuildLimit = namedtuple('_GuildLimit', 'emoji bitrate filesize')
|
||||
|
||||
@ -1429,7 +1435,7 @@ class Guild(Hashable):
|
||||
:class:`BanEntry`
|
||||
The :class:`BanEntry` object for the specified user.
|
||||
"""
|
||||
data = await self._state.http.get_ban(user.id, self.id)
|
||||
data: BanPayload = await self._state.http.get_ban(user.id, self.id)
|
||||
return BanEntry(
|
||||
user=User(state=self._state, data=data['user']),
|
||||
reason=data['reason']
|
||||
@ -1456,7 +1462,7 @@ class Guild(Hashable):
|
||||
A list of :class:`BanEntry` objects.
|
||||
"""
|
||||
|
||||
data = await self._state.http.get_bans(self.id)
|
||||
data: List[BanPayload] = await self._state.http.get_bans(self.id)
|
||||
return [BanEntry(user=User(state=self._state, data=e['user']),
|
||||
reason=e['reason'])
|
||||
for e in data]
|
||||
@ -1606,7 +1612,7 @@ class Guild(Hashable):
|
||||
data = await self._state.http.estimate_pruned_members(self.id, days, roles)
|
||||
return data['pruned']
|
||||
|
||||
async def invites(self):
|
||||
async def invites(self) -> List[Invite]:
|
||||
"""|coro|
|
||||
|
||||
Returns a list of all active instant invites from the guild.
|
||||
@ -2056,7 +2062,7 @@ class Guild(Hashable):
|
||||
"""
|
||||
await self._state.http.unban(user.id, self.id, reason=reason)
|
||||
|
||||
async def vanity_invite(self):
|
||||
async def vanity_invite(self) -> Invite:
|
||||
"""|coro|
|
||||
|
||||
Returns the guild's special vanity invite.
|
||||
|
@ -22,6 +22,9 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from .asset import Asset
|
||||
from .utils import parse_time, snowflake_time, _get_as_snowflake
|
||||
from .object import Object
|
||||
@ -34,6 +37,16 @@ __all__ = (
|
||||
'Invite',
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .types.invite import (
|
||||
Invite as InvitePayload,
|
||||
InviteGuild as InviteGuildPayload,
|
||||
)
|
||||
from .types.channel import (
|
||||
PartialChannel as PartialChannelPayload,
|
||||
)
|
||||
import datetime
|
||||
|
||||
|
||||
class PartialInviteChannel:
|
||||
"""Represents a "partial" invite channel.
|
||||
@ -72,7 +85,7 @@ class PartialInviteChannel:
|
||||
__slots__ = ('id', 'name', 'type')
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.id = kwargs.pop('id')
|
||||
self.id = int(kwargs.pop('id'))
|
||||
self.name = kwargs.pop('name')
|
||||
self.type = kwargs.pop('type')
|
||||
|
||||
@ -139,7 +152,7 @@ class PartialInviteGuild:
|
||||
|
||||
__slots__ = ('_state', 'features', 'icon', 'banner', 'id', 'name', 'splash', 'verification_level', 'description')
|
||||
|
||||
def __init__(self, state, data, id):
|
||||
def __init__(self, state, data: InviteGuildPayload, id: int):
|
||||
self._state = state
|
||||
self.id = id
|
||||
self.name = data['name']
|
||||
@ -150,33 +163,33 @@ class PartialInviteGuild:
|
||||
self.verification_level = try_enum(VerificationLevel, data.get('verification_level'))
|
||||
self.description = data.get('description')
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f'<{self.__class__.__name__} id={self.id} name={self.name!r} features={self.features} '
|
||||
f'description={self.description!r}>'
|
||||
)
|
||||
|
||||
@property
|
||||
def created_at(self):
|
||||
def created_at(self) -> datetime.datetime:
|
||||
""":class:`datetime.datetime`: Returns the guild's creation time in UTC."""
|
||||
return snowflake_time(self.id)
|
||||
|
||||
@property
|
||||
def icon_url(self):
|
||||
def icon_url(self) -> Asset:
|
||||
""":class:`Asset`: Returns the guild's icon asset."""
|
||||
return self.icon_url_as()
|
||||
|
||||
def is_icon_animated(self):
|
||||
def is_icon_animated(self) -> bool:
|
||||
""":class:`bool`: Returns ``True`` if the guild has an animated icon.
|
||||
|
||||
.. versionadded:: 1.4
|
||||
"""
|
||||
return bool(self.icon and self.icon.startswith('a_'))
|
||||
|
||||
def icon_url_as(self, *, format=None, static_format='webp', size=1024):
|
||||
def icon_url_as(self, *, format=None, static_format='webp', size=1024) -> Asset:
|
||||
"""The same operation as :meth:`Guild.icon_url_as`.
|
||||
|
||||
Returns
|
||||
@ -187,11 +200,11 @@ class PartialInviteGuild:
|
||||
return Asset._from_guild_icon(self._state, self, format=format, static_format=static_format, size=size)
|
||||
|
||||
@property
|
||||
def banner_url(self):
|
||||
def banner_url(self) -> Asset:
|
||||
""":class:`Asset`: Returns the guild's banner asset."""
|
||||
return self.banner_url_as()
|
||||
|
||||
def banner_url_as(self, *, format='webp', size=2048):
|
||||
def banner_url_as(self, *, format='webp', size=2048) -> Asset:
|
||||
"""The same operation as :meth:`Guild.banner_url_as`.
|
||||
|
||||
Returns
|
||||
@ -202,11 +215,11 @@ class PartialInviteGuild:
|
||||
return Asset._from_guild_image(self._state, self.id, self.banner, 'banners', format=format, size=size)
|
||||
|
||||
@property
|
||||
def splash_url(self):
|
||||
def splash_url(self) -> Asset:
|
||||
""":class:`Asset`: Returns the guild's invite splash asset."""
|
||||
return self.splash_url_as()
|
||||
|
||||
def splash_url_as(self, *, format='webp', size=2048):
|
||||
def splash_url_as(self, *, format='webp', size=2048) -> Asset:
|
||||
"""The same operation as :meth:`Guild.splash_url_as`.
|
||||
|
||||
Returns
|
||||
@ -313,13 +326,13 @@ class Invite(Hashable):
|
||||
|
||||
BASE = 'https://discord.gg'
|
||||
|
||||
def __init__(self, *, state, data):
|
||||
def __init__(self, *, state, data: InvitePayload):
|
||||
self._state = state
|
||||
self.max_age = data.get('max_age')
|
||||
self.code = data.get('code')
|
||||
self.code = data['code']
|
||||
self.guild = data.get('guild')
|
||||
self.revoked = data.get('revoked')
|
||||
self.created_at = parse_time(data.get('created_at'))
|
||||
self.created_at: Optional[datetime.datetime] = parse_time(data.get('created_at')) # type: ignore
|
||||
self.temporary = data.get('temporary')
|
||||
self.uses = data.get('uses')
|
||||
self.max_uses = data.get('max_uses')
|
||||
@ -346,7 +359,7 @@ class Invite(Hashable):
|
||||
|
||||
# As far as I know, invites always need a channel
|
||||
# So this should never raise.
|
||||
channel_data = data['channel']
|
||||
channel_data: PartialChannelPayload = data['channel']
|
||||
channel_id = int(channel_data['id'])
|
||||
channel_type = try_enum(ChannelType, channel_data['type'])
|
||||
channel = PartialInviteChannel(id=channel_id, name=channel_data['name'], type=channel_type)
|
||||
@ -373,30 +386,30 @@ class Invite(Hashable):
|
||||
data['channel'] = channel
|
||||
return cls(state=state, data=data)
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return self.url
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f'<Invite code={self.code!r} guild={self.guild!r} '
|
||||
f'online={self.approximate_presence_count} '
|
||||
f'members={self.approximate_member_count}>'
|
||||
)
|
||||
|
||||
def __hash__(self):
|
||||
def __hash__(self) -> int:
|
||||
return hash(self.code)
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
def id(self) -> str:
|
||||
""":class:`str`: Returns the proper code portion of the invite."""
|
||||
return self.code
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
def url(self) -> str:
|
||||
""":class:`str`: A property that retrieves the invite URL."""
|
||||
return self.BASE + '/' + self.code
|
||||
|
||||
async def delete(self, *, reason=None):
|
||||
async def delete(self, *, reason: Optional[str] = None):
|
||||
"""|coro|
|
||||
|
||||
Revokes the instant invite.
|
||||
|
@ -22,6 +22,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
from typing import Any, Optional, TYPE_CHECKING, overload
|
||||
from .utils import parse_time, _get_as_snowflake, _bytes_to_base64_data
|
||||
from .enums import VoiceRegion
|
||||
from .guild import Guild
|
||||
@ -30,6 +31,9 @@ __all__ = (
|
||||
'Template',
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .types.template import Template as TemplatePayload
|
||||
|
||||
|
||||
class _FriendlyHttpAttributeErrorHelper:
|
||||
__slots__ = ()
|
||||
@ -101,11 +105,11 @@ class Template:
|
||||
The source guild.
|
||||
"""
|
||||
|
||||
def __init__(self, *, state, data):
|
||||
def __init__(self, *, state, data: TemplatePayload):
|
||||
self._state = state
|
||||
self._store(data)
|
||||
|
||||
def _store(self, data):
|
||||
def _store(self, data: TemplatePayload):
|
||||
self.code = data['code']
|
||||
self.uses = data['usage_count']
|
||||
self.name = data['name']
|
||||
@ -120,7 +124,7 @@ class Template:
|
||||
|
||||
guild = self._state._get_guild(id)
|
||||
|
||||
if guild is None:
|
||||
if guild is None and id:
|
||||
source_serialised = data['serialized_source_guild']
|
||||
source_serialised['id'] = id
|
||||
state = _PartialTemplateState(state=self._state)
|
||||
@ -128,13 +132,13 @@ class Template:
|
||||
|
||||
self.source_guild = guild
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f'<Template code={self.code!r} uses={self.uses} name={self.name!r}'
|
||||
f' creator={self.creator!r} source_guild={self.source_guild!r}>'
|
||||
)
|
||||
|
||||
async def create_guild(self, name, region=None, icon=None):
|
||||
async def create_guild(self, name: str, region: Optional[VoiceRegion] = None, icon: Any = None):
|
||||
"""|coro|
|
||||
|
||||
Creates a :class:`.Guild` using the template.
|
||||
@ -174,7 +178,7 @@ class Template:
|
||||
data = await self._state.http.create_from_template(self.code, name, region_value, icon)
|
||||
return Guild(data=data, state=self._state)
|
||||
|
||||
async def sync(self):
|
||||
async def sync(self) -> None:
|
||||
"""|coro|
|
||||
|
||||
Sync the template to the guild's current state.
|
||||
@ -197,7 +201,20 @@ class Template:
|
||||
data = await self._state.http.sync_template(self.source_guild.id, self.code)
|
||||
self._store(data)
|
||||
|
||||
async def edit(self, **kwargs):
|
||||
@overload
|
||||
async def edit(
|
||||
self,
|
||||
*,
|
||||
name: Optional[str] = ...,
|
||||
description: Optional[str] = ...,
|
||||
) -> None:
|
||||
...
|
||||
|
||||
@overload
|
||||
async def edit(self) -> None:
|
||||
...
|
||||
|
||||
async def edit(self, **kwargs) -> None:
|
||||
"""|coro|
|
||||
|
||||
Edit the template metadata.
|
||||
@ -226,7 +243,7 @@ class Template:
|
||||
data = await self._state.http.edit_template(self.source_guild.id, self.code, kwargs)
|
||||
self._store(data)
|
||||
|
||||
async def delete(self):
|
||||
async def delete(self) -> None:
|
||||
"""|coro|
|
||||
|
||||
Delete the template.
|
||||
|
@ -31,6 +31,12 @@ from .activity import PartialPresenceUpdate
|
||||
from .role import Role
|
||||
from .member import Member
|
||||
from .emoji import Emoji
|
||||
from .user import User
|
||||
|
||||
|
||||
class Ban(TypedDict):
|
||||
reason: Optional[str]
|
||||
user: User
|
||||
|
||||
|
||||
class _UnavailableGuildOptional(TypedDict, total=False):
|
||||
|
60
discord/types/invite.py
Normal file
60
discord/types/invite.py
Normal file
@ -0,0 +1,60 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-present Rapptz
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
|
||||
from typing import Literal, TypedDict
|
||||
|
||||
from .guild import InviteGuild, _GuildPreviewUnique
|
||||
from .channel import PartialChannel
|
||||
from .user import PartialUser
|
||||
|
||||
TargetUserType = Literal[1]
|
||||
|
||||
|
||||
class _InviteOptional(TypedDict, total=False):
|
||||
guild: InviteGuild
|
||||
inviter: PartialUser
|
||||
target_user: PartialUser
|
||||
target_user_type: TargetUserType
|
||||
|
||||
|
||||
class _InviteMetadata(TypedDict, total=False):
|
||||
uses: int
|
||||
max_uses: int
|
||||
temporary: bool
|
||||
created_at: str
|
||||
|
||||
|
||||
class IncompleteInvite(_InviteMetadata):
|
||||
code: str
|
||||
channel: PartialChannel
|
||||
|
||||
|
||||
class Invite(IncompleteInvite, _InviteOptional):
|
||||
...
|
||||
|
||||
|
||||
class InviteWithCounts(Invite, _GuildPreviewUnique):
|
||||
...
|
44
discord/types/template.py
Normal file
44
discord/types/template.py
Normal file
@ -0,0 +1,44 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-present Rapptz
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
|
||||
from typing import Optional, TypedDict
|
||||
from .snowflake import Snowflake
|
||||
from .user import User
|
||||
from .guild import Guild
|
||||
|
||||
|
||||
class Template(TypedDict):
|
||||
code: str
|
||||
name: str
|
||||
description: Optional[str]
|
||||
usage_count: int
|
||||
creator_id: Snowflake
|
||||
creator: User
|
||||
created_at: str
|
||||
updated_at: str
|
||||
source_guild_id: Snowflake
|
||||
serialized_source_guild: Guild
|
||||
is_dirty: Optional[bool]
|
Loading…
x
Reference in New Issue
Block a user