Browse Source

Add typings for audit logs, integrations, and webhooks

pull/6692/head
Nadir Chowdhury 4 years ago
committed by GitHub
parent
commit
3e92196a2b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      discord/asset.py
  2. 22
      discord/audit_logs.py
  3. 74
      discord/integrations.py
  4. 85
      discord/iterators.py
  5. 106
      discord/types/audit_log.py
  6. 76
      discord/types/integration.py
  7. 70
      discord/types/webhook.py
  8. 4
      discord/utils.py

5
discord/asset.py

@ -23,6 +23,7 @@ DEALINGS IN THE SOFTWARE.
""" """
import io import io
from typing import Literal, TYPE_CHECKING
from .errors import DiscordException from .errors import DiscordException
from .errors import InvalidArgument from .errors import InvalidArgument
from . import utils from . import utils
@ -31,6 +32,10 @@ __all__ = (
'Asset', 'Asset',
) )
if TYPE_CHECKING:
ValidStaticFormatTypes = Literal['webp', 'jpeg', 'jpg', 'png']
ValidAvatarFormatTypes = Literal['webp', 'jpeg', 'jpg', 'png', 'gif']
VALID_STATIC_FORMATS = frozenset({"jpeg", "jpg", "webp", "png"}) VALID_STATIC_FORMATS = frozenset({"jpeg", "jpg", "webp", "png"})
VALID_AVATAR_FORMATS = VALID_STATIC_FORMATS | {"gif"} VALID_AVATAR_FORMATS = VALID_STATIC_FORMATS | {"gif"}

22
discord/audit_logs.py

@ -22,6 +22,9 @@ 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 typing import Dict, List, TYPE_CHECKING
from . import utils, enums from . import utils, enums
from .object import Object from .object import Object
from .permissions import PermissionOverwrite, Permissions from .permissions import PermissionOverwrite, Permissions
@ -35,6 +38,15 @@ __all__ = (
'AuditLogEntry', 'AuditLogEntry',
) )
if TYPE_CHECKING:
from .types.audit_log import (
AuditLogChange as AuditLogChangePayload,
AuditLogEntry as AuditLogEntryPayload,
)
from .guild import Guild
from .user import User
def _transform_verification_level(entry, data): def _transform_verification_level(entry, data):
return enums.try_enum(enums.VerificationLevel, data) return enums.try_enum(enums.VerificationLevel, data)
@ -123,7 +135,7 @@ class AuditLogChanges:
'default_message_notifications': ('default_notifications', _transform_default_notifications), 'default_message_notifications': ('default_notifications', _transform_default_notifications),
} }
def __init__(self, entry, data): def __init__(self, entry, data: List[AuditLogChangePayload]):
self.before = AuditLogDiff() self.before = AuditLogDiff()
self.after = AuditLogDiff() self.after = AuditLogDiff()
@ -177,7 +189,7 @@ class AuditLogChanges:
setattr(first, 'roles', []) setattr(first, 'roles', [])
data = [] data = []
g = entry.guild g: Guild = entry.guild
for e in elem: for e in elem:
role_id = int(e['id']) role_id = int(e['id'])
@ -185,7 +197,7 @@ class AuditLogChanges:
if role is None: if role is None:
role = Object(id=role_id) role = Object(id=role_id)
role.name = e['name'] role.name = e['name'] # type: ignore
data.append(role) data.append(role)
@ -234,7 +246,7 @@ class AuditLogEntry(Hashable):
which actions have this field filled out. which actions have this field filled out.
""" """
def __init__(self, *, users, data, guild): def __init__(self, *, users: Dict[str, User], data: AuditLogEntryPayload, guild: Guild):
self._state = guild._state self._state = guild._state
self.guild = guild self.guild = guild
self._users = users self._users = users
@ -284,7 +296,7 @@ class AuditLogEntry(Hashable):
role = self.guild.get_role(instance_id) role = self.guild.get_role(instance_id)
if role is None: if role is None:
role = Object(id=instance_id) role = Object(id=instance_id)
role.name = self.extra.get('role_name') role.name = self.extra.get('role_name') # type: ignore
self.extra = role self.extra = role
# this key is not present when the above is present, typically. # this key is not present when the above is present, typically.

74
discord/integrations.py

@ -22,7 +22,10 @@ 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
import datetime import datetime
from typing import Optional, TYPE_CHECKING, overload
from .utils import _get_as_snowflake, get, parse_time from .utils import _get_as_snowflake, get, parse_time
from .user import User from .user import User
from .errors import InvalidArgument from .errors import InvalidArgument
@ -33,6 +36,14 @@ __all__ = (
'Integration', 'Integration',
) )
if TYPE_CHECKING:
from .types.integration import (
IntegrationAccount as IntegrationAccountPayload,
Integration as IntegrationPayload,
)
from .guild import Guild
class IntegrationAccount: class IntegrationAccount:
"""Represents an integration account. """Represents an integration account.
@ -48,13 +59,14 @@ class IntegrationAccount:
__slots__ = ('id', 'name') __slots__ = ('id', 'name')
def __init__(self, **kwargs): def __init__(self, data: IntegrationAccountPayload) -> None:
self.id = kwargs.pop('id') self.id: Optional[int] = _get_as_snowflake(data, 'id')
self.name = kwargs.pop('name') self.name: str = data.pop('name')
def __repr__(self): def __repr__(self) -> str:
return f'<IntegrationAccount id={self.id} name={self.name!r}>' return f'<IntegrationAccount id={self.id} name={self.name!r}>'
class Integration: class Integration:
"""Represents a guild integration. """Represents a guild integration.
@ -90,20 +102,34 @@ class Integration:
An aware UTC datetime representing when the integration was last synced. An aware UTC datetime representing when the integration was last synced.
""" """
__slots__ = ('id', '_state', 'guild', 'name', 'enabled', 'type', __slots__ = (
'syncing', 'role', 'expire_behaviour', 'expire_behavior', 'id',
'expire_grace_period', 'synced_at', 'user', 'account', '_state',
'enable_emoticons', '_role_id') 'guild',
'name',
def __init__(self, *, data, guild): 'enabled',
'type',
'syncing',
'role',
'expire_behaviour',
'expire_behavior',
'expire_grace_period',
'synced_at',
'user',
'account',
'enable_emoticons',
'_role_id',
)
def __init__(self, *, data: IntegrationPayload, guild: Guild) -> None:
self.guild = guild self.guild = guild
self._state = guild._state self._state = guild._state
self._from_data(data) self._from_data(data)
def __repr__(self): def __repr__(self) -> str:
return f'<Integration id={self.id} name={self.name!r} type={self.type!r}>' return f'<Integration id={self.id} name={self.name!r} type={self.type!r}>'
def _from_data(self, integ): def _from_data(self, integ: IntegrationPayload):
self.id = _get_as_snowflake(integ, 'id') self.id = _get_as_snowflake(integ, 'id')
self.name = integ['name'] self.name = integ['name']
self.type = integ['type'] self.type = integ['type']
@ -118,9 +144,23 @@ class Integration:
self.synced_at = parse_time(integ['synced_at']) self.synced_at = parse_time(integ['synced_at'])
self.user = User(state=self._state, data=integ['user']) self.user = User(state=self._state, data=integ['user'])
self.account = IntegrationAccount(**integ['account']) self.account = IntegrationAccount(integ['account'])
async def edit(self, **fields): @overload
async def edit(
self,
*,
expire_behaviour: Optional[ExpireBehaviour] = ...,
expire_grace_period: Optional[int] = ...,
enable_emoticons: Optional[bool] = ...,
) -> None:
...
@overload
async def edit(self, **fields) -> None:
...
async def edit(self, **fields) -> None:
"""|coro| """|coro|
Edits the integration. Edits the integration.
@ -173,7 +213,7 @@ class Integration:
self.expire_grace_period = expire_grace_period self.expire_grace_period = expire_grace_period
self.enable_emoticons = enable_emoticons self.enable_emoticons = enable_emoticons
async def sync(self): async def sync(self) -> None:
"""|coro| """|coro|
Syncs the integration. Syncs the integration.
@ -191,7 +231,7 @@ class Integration:
await self._state.http.sync_integration(self.guild.id, self.id) await self._state.http.sync_integration(self.guild.id, self.id)
self.synced_at = datetime.datetime.now(datetime.timezone.utc) self.synced_at = datetime.datetime.now(datetime.timezone.utc)
async def delete(self): async def delete(self) -> None:
"""|coro| """|coro|
Deletes the integration. Deletes the integration.

85
discord/iterators.py

@ -42,6 +42,19 @@ __all__ = (
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from .types.audit_log import (
AuditLog as AuditLogPayload,
)
from .types.guild import (
Guild as GuildPayload,
)
from .types.message import (
Message as MessagePayload,
)
from .types.user import (
PartialUser as PartialUserPayload,
)
from .member import Member from .member import Member
from .user import User from .user import User
from .message import Message from .message import Message
@ -54,6 +67,7 @@ _Func = Callable[[T], Union[OT, Awaitable[OT]]]
OLDEST_OBJECT = Object(id=0) OLDEST_OBJECT = Object(id=0)
class _AsyncIterator(AsyncIterator[T]): class _AsyncIterator(AsyncIterator[T]):
__slots__ = () __slots__ = ()
@ -105,9 +119,11 @@ class _AsyncIterator(AsyncIterator[T]):
except NoMoreItems: except NoMoreItems:
raise StopAsyncIteration() raise StopAsyncIteration()
def _identity(x): def _identity(x):
return x return x
class _ChunkedAsyncIterator(_AsyncIterator[List[T]]): class _ChunkedAsyncIterator(_AsyncIterator[List[T]]):
def __init__(self, iterator, max_size): def __init__(self, iterator, max_size):
self.iterator = iterator self.iterator = iterator
@ -128,6 +144,7 @@ class _ChunkedAsyncIterator(_AsyncIterator[List[T]]):
n += 1 n += 1
return ret return ret
class _MappedAsyncIterator(_AsyncIterator[T]): class _MappedAsyncIterator(_AsyncIterator[T]):
def __init__(self, iterator, func): def __init__(self, iterator, func):
self.iterator = iterator self.iterator = iterator
@ -138,6 +155,7 @@ class _MappedAsyncIterator(_AsyncIterator[T]):
item = await self.iterator.next() item = await self.iterator.next()
return await maybe_coroutine(self.func, item) return await maybe_coroutine(self.func, item)
class _FilteredAsyncIterator(_AsyncIterator[T]): class _FilteredAsyncIterator(_AsyncIterator[T]):
def __init__(self, iterator, predicate): def __init__(self, iterator, predicate):
self.iterator = iterator self.iterator = iterator
@ -157,6 +175,7 @@ class _FilteredAsyncIterator(_AsyncIterator[T]):
if ret: if ret:
return item return item
class ReactionIterator(_AsyncIterator[Union['User', 'Member']]): class ReactionIterator(_AsyncIterator[Union['User', 'Member']]):
def __init__(self, message, emoji, limit=100, after=None): def __init__(self, message, emoji, limit=100, after=None):
self.message = message self.message = message
@ -187,7 +206,9 @@ class ReactionIterator(_AsyncIterator[Union['User', 'Member']]):
retrieve = self.limit if self.limit <= 100 else 100 retrieve = self.limit if self.limit <= 100 else 100
after = self.after.id if self.after else None after = self.after.id if self.after else None
data = await self.getter(self.channel_id, self.message.id, self.emoji, retrieve, after=after) data: List[PartialUserPayload] = await self.getter(
self.channel_id, self.message.id, self.emoji, retrieve, after=after
)
if data: if data:
self.limit -= retrieve self.limit -= retrieve
@ -205,6 +226,7 @@ class ReactionIterator(_AsyncIterator[Union['User', 'Member']]):
else: else:
await self.users.put(User(state=self.state, data=element)) await self.users.put(User(state=self.state, data=element))
class HistoryIterator(_AsyncIterator['Message']): class HistoryIterator(_AsyncIterator['Message']):
"""Iterator for receiving a channel's message history. """Iterator for receiving a channel's message history.
@ -239,8 +261,7 @@ class HistoryIterator(_AsyncIterator['Message']):
``True`` if `after` is specified, otherwise ``False``. ``True`` if `after` is specified, otherwise ``False``.
""" """
def __init__(self, messageable, limit, def __init__(self, messageable, limit, before=None, after=None, around=None, oldest_first=None):
before=None, after=None, around=None, oldest_first=None):
if isinstance(before, datetime.datetime): if isinstance(before, datetime.datetime):
before = Object(id=time_snowflake(before, high=False)) before = Object(id=time_snowflake(before, high=False))
@ -274,7 +295,7 @@ class HistoryIterator(_AsyncIterator['Message']):
elif self.limit == 101: elif self.limit == 101:
self.limit = 100 # Thanks discord self.limit = 100 # Thanks discord
self._retrieve_messages = self._retrieve_messages_around_strategy self._retrieve_messages = self._retrieve_messages_around_strategy # type: ignore
if self.before and self.after: if self.before and self.after:
self._filter = lambda m: self.after.id < int(m['id']) < self.before.id self._filter = lambda m: self.after.id < int(m['id']) < self.before.id
elif self.before: elif self.before:
@ -283,12 +304,12 @@ class HistoryIterator(_AsyncIterator['Message']):
self._filter = lambda m: self.after.id < int(m['id']) self._filter = lambda m: self.after.id < int(m['id'])
else: else:
if self.reverse: if self.reverse:
self._retrieve_messages = self._retrieve_messages_after_strategy self._retrieve_messages = self._retrieve_messages_after_strategy # type: ignore
if (self.before): if self.before:
self._filter = lambda m: int(m['id']) < self.before.id self._filter = lambda m: int(m['id']) < self.before.id
else: else:
self._retrieve_messages = self._retrieve_messages_before_strategy self._retrieve_messages = self._retrieve_messages_before_strategy # type: ignore
if (self.after and self.after != OLDEST_OBJECT): if self.after and self.after != OLDEST_OBJECT:
self._filter = lambda m: int(m['id']) > self.after.id self._filter = lambda m: int(m['id']) > self.after.id
async def next(self) -> Message: async def next(self) -> Message:
@ -318,7 +339,7 @@ class HistoryIterator(_AsyncIterator['Message']):
if self._get_retrieve(): if self._get_retrieve():
data = await self._retrieve_messages(self.retrieve) data = await self._retrieve_messages(self.retrieve)
if len(data) < 100: if len(data) < 100:
self.limit = 0 # terminate the infinite loop self.limit = 0 # terminate the infinite loop
if self.reverse: if self.reverse:
data = reversed(data) data = reversed(data)
@ -329,14 +350,14 @@ class HistoryIterator(_AsyncIterator['Message']):
for element in data: for element in data:
await self.messages.put(self.state.create_message(channel=channel, data=element)) await self.messages.put(self.state.create_message(channel=channel, data=element))
async def _retrieve_messages(self, retrieve): async def _retrieve_messages(self, retrieve) -> List[Message]:
"""Retrieve messages and update next parameters.""" """Retrieve messages and update next parameters."""
pass raise NotImplementedError
async def _retrieve_messages_before_strategy(self, retrieve): async def _retrieve_messages_before_strategy(self, retrieve):
"""Retrieve messages using before parameter.""" """Retrieve messages using before parameter."""
before = self.before.id if self.before else None before = self.before.id if self.before else None
data = await self.logs_from(self.channel.id, retrieve, before=before) data: List[MessagePayload] = await self.logs_from(self.channel.id, retrieve, before=before)
if len(data): if len(data):
if self.limit is not None: if self.limit is not None:
self.limit -= retrieve self.limit -= retrieve
@ -346,7 +367,7 @@ class HistoryIterator(_AsyncIterator['Message']):
async def _retrieve_messages_after_strategy(self, retrieve): async def _retrieve_messages_after_strategy(self, retrieve):
"""Retrieve messages using after parameter.""" """Retrieve messages using after parameter."""
after = self.after.id if self.after else None after = self.after.id if self.after else None
data = await self.logs_from(self.channel.id, retrieve, after=after) data: List[MessagePayload] = await self.logs_from(self.channel.id, retrieve, after=after)
if len(data): if len(data):
if self.limit is not None: if self.limit is not None:
self.limit -= retrieve self.limit -= retrieve
@ -357,11 +378,12 @@ class HistoryIterator(_AsyncIterator['Message']):
"""Retrieve messages using around parameter.""" """Retrieve messages using around parameter."""
if self.around: if self.around:
around = self.around.id if self.around else None around = self.around.id if self.around else None
data = await self.logs_from(self.channel.id, retrieve, around=around) data: List[MessagePayload] = await self.logs_from(self.channel.id, retrieve, around=around)
self.around = None self.around = None
return data return data
return [] return []
class AuditLogIterator(_AsyncIterator['AuditLogEntry']): class AuditLogIterator(_AsyncIterator['AuditLogEntry']):
def __init__(self, guild, limit=None, before=None, after=None, oldest_first=None, user_id=None, action_type=None): def __init__(self, guild, limit=None, before=None, after=None, oldest_first=None, user_id=None, action_type=None):
if isinstance(before, datetime.datetime): if isinstance(before, datetime.datetime):
@ -369,7 +391,6 @@ class AuditLogIterator(_AsyncIterator['AuditLogEntry']):
if isinstance(after, datetime.datetime): if isinstance(after, datetime.datetime):
after = Object(id=time_snowflake(after, high=True)) after = Object(id=time_snowflake(after, high=True))
if oldest_first is None: if oldest_first is None:
self.reverse = after is not None self.reverse = after is not None
else: else:
@ -386,12 +407,10 @@ class AuditLogIterator(_AsyncIterator['AuditLogEntry']):
self._users = {} self._users = {}
self._state = guild._state self._state = guild._state
self._filter = None # entry dict -> bool self._filter = None # entry dict -> bool
self.entries = asyncio.Queue() self.entries = asyncio.Queue()
if self.reverse: if self.reverse:
self._strategy = self._after_strategy self._strategy = self._after_strategy
if self.before: if self.before:
@ -403,8 +422,9 @@ class AuditLogIterator(_AsyncIterator['AuditLogEntry']):
async def _before_strategy(self, retrieve): async def _before_strategy(self, retrieve):
before = self.before.id if self.before else None before = self.before.id if self.before else None
data = await self.request(self.guild.id, limit=retrieve, user_id=self.user_id, data: AuditLogPayload = await self.request(
action_type=self.action_type, before=before) self.guild.id, limit=retrieve, user_id=self.user_id, action_type=self.action_type, before=before
)
entries = data.get('audit_log_entries', []) entries = data.get('audit_log_entries', [])
if len(data) and entries: if len(data) and entries:
@ -415,8 +435,9 @@ class AuditLogIterator(_AsyncIterator['AuditLogEntry']):
async def _after_strategy(self, retrieve): async def _after_strategy(self, retrieve):
after = self.after.id if self.after else None after = self.after.id if self.after else None
data = await self.request(self.guild.id, limit=retrieve, user_id=self.user_id, data: AuditLogPayload = await self.request(
action_type=self.action_type, after=after) self.guild.id, limit=retrieve, user_id=self.user_id, action_type=self.action_type, after=after
)
entries = data.get('audit_log_entries', []) entries = data.get('audit_log_entries', [])
if len(data) and entries: if len(data) and entries:
if self.limit is not None: if self.limit is not None:
@ -448,7 +469,7 @@ class AuditLogIterator(_AsyncIterator['AuditLogEntry']):
if self._get_retrieve(): if self._get_retrieve():
users, data = await self._strategy(self.retrieve) users, data = await self._strategy(self.retrieve)
if len(data) < 100: if len(data) < 100:
self.limit = 0 # terminate the infinite loop self.limit = 0 # terminate the infinite loop
if self.reverse: if self.reverse:
data = reversed(data) data = reversed(data)
@ -495,6 +516,7 @@ class GuildIterator(_AsyncIterator['Guild']):
after: Optional[Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]] after: Optional[Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]]
Object after which all guilds must be. Object after which all guilds must be.
""" """
def __init__(self, bot, limit, before=None, after=None): def __init__(self, bot, limit, before=None, after=None):
if isinstance(before, datetime.datetime): if isinstance(before, datetime.datetime):
@ -514,12 +536,12 @@ class GuildIterator(_AsyncIterator['Guild']):
self.guilds = asyncio.Queue() self.guilds = asyncio.Queue()
if self.before and self.after: if self.before and self.after:
self._retrieve_guilds = self._retrieve_guilds_before_strategy self._retrieve_guilds = self._retrieve_guilds_before_strategy # type: ignore
self._filter = lambda m: int(m['id']) > self.after.id self._filter = lambda m: int(m['id']) > self.after.id
elif self.after: elif self.after:
self._retrieve_guilds = self._retrieve_guilds_after_strategy self._retrieve_guilds = self._retrieve_guilds_after_strategy # type: ignore
else: else:
self._retrieve_guilds = self._retrieve_guilds_before_strategy self._retrieve_guilds = self._retrieve_guilds_before_strategy # type: ignore
async def next(self) -> Guild: async def next(self) -> Guild:
if self.guilds.empty(): if self.guilds.empty():
@ -541,6 +563,7 @@ class GuildIterator(_AsyncIterator['Guild']):
def create_guild(self, data): def create_guild(self, data):
from .guild import Guild from .guild import Guild
return Guild(state=self.state, data=data) return Guild(state=self.state, data=data)
async def fill_guilds(self): async def fill_guilds(self):
@ -555,14 +578,14 @@ class GuildIterator(_AsyncIterator['Guild']):
for element in data: for element in data:
await self.guilds.put(self.create_guild(element)) await self.guilds.put(self.create_guild(element))
async def _retrieve_guilds(self, retrieve): async def _retrieve_guilds(self, retrieve) -> List[Guild]:
"""Retrieve guilds and update next parameters.""" """Retrieve guilds and update next parameters."""
pass raise NotImplementedError
async def _retrieve_guilds_before_strategy(self, retrieve): async def _retrieve_guilds_before_strategy(self, retrieve):
"""Retrieve guilds using before parameter.""" """Retrieve guilds using before parameter."""
before = self.before.id if self.before else None before = self.before.id if self.before else None
data = await self.get_guilds(retrieve, before=before) data: List[GuildPayload] = await self.get_guilds(retrieve, before=before)
if len(data): if len(data):
if self.limit is not None: if self.limit is not None:
self.limit -= retrieve self.limit -= retrieve
@ -572,13 +595,14 @@ class GuildIterator(_AsyncIterator['Guild']):
async def _retrieve_guilds_after_strategy(self, retrieve): async def _retrieve_guilds_after_strategy(self, retrieve):
"""Retrieve guilds using after parameter.""" """Retrieve guilds using after parameter."""
after = self.after.id if self.after else None after = self.after.id if self.after else None
data = await self.get_guilds(retrieve, after=after) data: List[GuildPayload] = await self.get_guilds(retrieve, after=after)
if len(data): if len(data):
if self.limit is not None: if self.limit is not None:
self.limit -= retrieve self.limit -= retrieve
self.after = Object(id=int(data[0]['id'])) self.after = Object(id=int(data[0]['id']))
return data return data
class MemberIterator(_AsyncIterator['Member']): class MemberIterator(_AsyncIterator['Member']):
def __init__(self, guild, limit=1000, after=None): def __init__(self, guild, limit=1000, after=None):
@ -620,7 +644,7 @@ class MemberIterator(_AsyncIterator['Member']):
return return
if len(data) < 1000: if len(data) < 1000:
self.limit = 0 # terminate loop self.limit = 0 # terminate loop
self.after = Object(id=int(data[-1]['user']['id'])) self.after = Object(id=int(data[-1]['user']['id']))
@ -629,4 +653,5 @@ class MemberIterator(_AsyncIterator['Member']):
def create_member(self, data): def create_member(self, data):
from .member import Member from .member import Member
return Member(data=data, guild=self.guild, state=self.state) return Member(data=data, guild=self.guild, state=self.state)

106
discord/types/audit_log.py

@ -0,0 +1,106 @@
"""
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 Any, List, Literal, Optional, TypedDict
from .webhook import Webhook
from .integration import PartialIntegration
from .user import User
from .snowflake import Snowflake
AuditLogEvent = Literal[
1,
10,
11,
12,
13,
14,
15,
20,
21,
22,
23,
24,
25,
26,
27,
28,
30,
31,
32,
40,
41,
42,
50,
51,
52,
60,
61,
62,
72,
73,
74,
75,
80,
81,
82,
]
class AuditLogChange(TypedDict):
key: str
new_value: Any
old_value: Any
class AuditEntryInfo(TypedDict):
delete_member_days: str
members_removed: str
channel_id: Snowflake
message_id: Snowflake
count: str
id: Snowflake
type: Literal['0', '1']
role_name: str
class _AuditLogEntryOptional(TypedDict, total=False):
changes: List[AuditLogChange]
options: AuditEntryInfo
reason: str
class AuditLogEntry(_AuditLogEntryOptional):
target_id: Optional[str]
user_id: Snowflake
id: Snowflake
action_type: AuditLogEvent
class AuditLog(TypedDict):
webhooks: List[Webhook]
users: List[User]
audit_log_entries: List[AuditLogEntry]
integrations: List[PartialIntegration]

76
discord/types/integration.py

@ -0,0 +1,76 @@
"""
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, Optional, TypedDict
from .snowflake import Snowflake
from .user import User
class _IntegrationApplicationOptional(TypedDict, total=False):
bot: User
class IntegrationApplication(_IntegrationApplicationOptional):
id: Snowflake
name: str
icon: Optional[str]
description: str
summary: str
class IntegrationAccount(TypedDict):
id: str
name: str
IntegrationExpireBehavior = Literal[0, 1]
class PartialIntegration(TypedDict):
id: Snowflake
name: str
type: IntegrationType
account: IntegrationAccount
class _IntegrationOptional(TypedDict, total=False):
role_id: Snowflake
enable_emoticons: bool
subscriber_count: int
revoked: bool
application: IntegrationApplication
IntegrationType = Literal['twitch', 'youtube', 'discord']
class Integration(PartialIntegration, _IntegrationOptional):
enabled: bool
syncing: bool
synced_at: str
user: User
expire_behavior: IntegrationExpireBehavior
expire_grace_period: int

70
discord/types/webhook.py

@ -0,0 +1,70 @@
"""
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, Optional, TypedDict
from .snowflake import Snowflake
from .user import User
from .channel import PartialChannel
class SourceGuild(TypedDict):
id: int
name: str
icon: str
class _WebhookOptional(TypedDict, total=False):
guild_id: Snowflake
user: User
token: str
WebhookType = Literal[1, 2]
class _FollowerWebhookOptional(TypedDict, total=False):
source_channel: PartialChannel
source_guild: SourceGuild
class FollowerWebhook(_FollowerWebhookOptional):
channel_id: Snowflake
webhook_id: Snowflake
class PartialWebhook(_WebhookOptional):
id: Snowflake
type: WebhookType
class _FullWebhook(TypedDict, total=False):
name: Optional[str]
avatar: Optional[str]
channel_id: Snowflake
application_id: Optional[Snowflake]
class Webhook(PartialWebhook, _FullWebhook):
...

4
discord/utils.py

@ -25,7 +25,7 @@ DEALINGS IN THE SOFTWARE.
import array import array
import asyncio import asyncio
import collections.abc import collections.abc
from typing import Optional, overload from typing import Any, Optional, overload
import unicodedata import unicodedata
from base64 import b64encode from base64 import b64encode
from bisect import bisect_left from bisect import bisect_left
@ -325,7 +325,7 @@ def _unique(iterable):
adder = seen.add adder = seen.add
return [x for x in iterable if not (x in seen or adder(x))] return [x for x in iterable if not (x in seen or adder(x))]
def _get_as_snowflake(data, key): def _get_as_snowflake(data: Any, key: str) -> Optional[int]:
try: try:
value = data[key] value = data[key]
except KeyError: except KeyError:

Loading…
Cancel
Save