mirror of
https://github.com/MelisaDev/melisa.git
synced 2024-09-23 03:32:01 +03:00
BREAKING CHANGE: fix my stupidity
This commit is contained in:
parent
a8c25264c0
commit
359ea514c0
13 changed files with 318 additions and 129 deletions
|
@ -1,6 +1,3 @@
|
||||||
# Copyright MelisaDev 2022 - Present
|
|
||||||
# Full MIT License can be found in `LICENSE.txt` at the project root.
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import asyncio
|
import asyncio
|
||||||
import signal
|
import signal
|
||||||
|
@ -26,9 +23,7 @@ _logger = logging.getLogger("melisa")
|
||||||
class Client:
|
class Client:
|
||||||
"""
|
"""
|
||||||
This is the main instance which is between the programmer and the Discord API.
|
This is the main instance which is between the programmer and the Discord API.
|
||||||
|
|
||||||
This Client represents your bot.
|
This Client represents your bot.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
token: :class:`str`
|
token: :class:`str`
|
||||||
|
@ -50,7 +45,6 @@ class Client:
|
||||||
If you pass a :class:`str` or a :class:`int`, it is interpreted as
|
If you pass a :class:`str` or a :class:`int`, it is interpreted as
|
||||||
the global logging level to use, and should match one of **DEBUG**,
|
the global logging level to use, and should match one of **DEBUG**,
|
||||||
**INFO**, **WARNING**, **ERROR** or **CRITICAL**, if :class:`str`.
|
**INFO**, **WARNING**, **ERROR** or **CRITICAL**, if :class:`str`.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
----------
|
----------
|
||||||
user: :class:`~models.user.user.User`
|
user: :class:`~models.user.user.User`
|
||||||
|
@ -126,7 +120,6 @@ class Client:
|
||||||
|
|
||||||
def listen(self, callback: Coro):
|
def listen(self, callback: Coro):
|
||||||
"""Method or Decorator to set the listener.
|
"""Method or Decorator to set the listener.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
callback : :class:`melisa.utils.types.Coro`
|
callback : :class:`melisa.utils.types.Coro`
|
||||||
|
@ -142,7 +135,6 @@ class Client:
|
||||||
async def dispatch(self, name: str, *args):
|
async def dispatch(self, name: str, *args):
|
||||||
"""
|
"""
|
||||||
Dispatches an event
|
Dispatches an event
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
name: :class:`str`
|
name: :class:`str`
|
||||||
|
@ -183,7 +175,6 @@ class Client:
|
||||||
def run_shards(self, num_shards: int, *, shard_ids: List[int] = None):
|
def run_shards(self, num_shards: int, *, shard_ids: List[int] = None):
|
||||||
"""
|
"""
|
||||||
Run Bot with shards specified by the user.
|
Run Bot with shards specified by the user.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
num_shards : :class:`int`
|
num_shards : :class:`int`
|
||||||
|
@ -226,7 +217,6 @@ class Client:
|
||||||
async def fetch_user(self, user_id: Union[Snowflake, str, int]):
|
async def fetch_user(self, user_id: Union[Snowflake, str, int]):
|
||||||
"""
|
"""
|
||||||
Fetch User from the Discord API (by id).
|
Fetch User from the Discord API (by id).
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
user_id : :class:`Union[Snowflake, str, int]`
|
user_id : :class:`Union[Snowflake, str, int]`
|
||||||
|
@ -242,7 +232,6 @@ class Client:
|
||||||
async def fetch_guild(self, guild_id: Union[Snowflake, str, int]):
|
async def fetch_guild(self, guild_id: Union[Snowflake, str, int]):
|
||||||
"""
|
"""
|
||||||
Fetch Guild from the Discord API (by id).
|
Fetch Guild from the Discord API (by id).
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
guild_id : :class:`Union[Snowflake, str, int]`
|
guild_id : :class:`Union[Snowflake, str, int]`
|
||||||
|
@ -262,7 +251,6 @@ class Client:
|
||||||
Fetch Channel from the Discord API (by id).
|
Fetch Channel from the Discord API (by id).
|
||||||
If type of channel is unknown:
|
If type of channel is unknown:
|
||||||
it will return just :class:`melisa.models.guild.channel.Channel` object.
|
it will return just :class:`melisa.models.guild.channel.Channel` object.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
channel_id : :class:`Union[Snowflake, str, int]`
|
channel_id : :class:`Union[Snowflake, str, int]`
|
||||||
|
@ -286,38 +274,28 @@ class Client:
|
||||||
timeout: Optional[float] = None,
|
timeout: Optional[float] = None,
|
||||||
):
|
):
|
||||||
"""|coro|
|
"""|coro|
|
||||||
|
|
||||||
Waits for a WebSocket event to be dispatched.
|
Waits for a WebSocket event to be dispatched.
|
||||||
|
|
||||||
This could be used to wait for a user to reply to a message,
|
This could be used to wait for a user to reply to a message,
|
||||||
or to react to a message.
|
or to react to a message.
|
||||||
|
|
||||||
The ``timeout`` parameter is passed onto :func:`asyncio.wait_for`. By default,
|
The ``timeout`` parameter is passed onto :func:`asyncio.wait_for`. By default,
|
||||||
it does not timeout. Note that this does propagate the
|
it does not timeout. Note that this does propagate the
|
||||||
:exc:`asyncio.TimeoutError` for you in case of timeout and is provided for
|
:exc:`asyncio.TimeoutError` for you in case of timeout and is provided for
|
||||||
ease of use.
|
ease of use.
|
||||||
|
|
||||||
In case the event returns multiple arguments, a :class:`tuple` containing those
|
In case the event returns multiple arguments, a :class:`tuple` containing those
|
||||||
arguments is returned instead.
|
arguments is returned instead.
|
||||||
|
|
||||||
This function returns the **first event that meets the requirements**.
|
This function returns the **first event that meets the requirements**.
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
Waiting for a user reply: ::
|
Waiting for a user reply: ::
|
||||||
|
|
||||||
@client.listen
|
@client.listen
|
||||||
async def on_message_create(message):
|
async def on_message_create(message):
|
||||||
if message.content.startswith('$greet'):
|
if message.content.startswith('$greet'):
|
||||||
channel = await client.fetch_channel(message.channel_id)
|
channel = await client.fetch_channel(message.channel_id)
|
||||||
await channel.send('Say hello!')
|
await channel.send('Say hello!')
|
||||||
|
|
||||||
def check(m):
|
def check(m):
|
||||||
return m.content == "hello" and channel.id == message.channel_id
|
return m.content == "hello" and channel.id == message.channel_id
|
||||||
|
|
||||||
msg = await client.wait_for('on_message_create', check=check, timeout=10.0)
|
msg = await client.wait_for('on_message_create', check=check, timeout=10.0)
|
||||||
await channel.send(f'Hello man!')
|
await channel.send(f'Hello man!')
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
event_name: :class:`str`
|
event_name: :class:`str`
|
||||||
|
@ -328,7 +306,6 @@ class Client:
|
||||||
timeout: Optional[:class:`float`]
|
timeout: Optional[:class:`float`]
|
||||||
The number of seconds to wait before timing out and raising
|
The number of seconds to wait before timing out and raising
|
||||||
:exc:`asyncio.TimeoutError`.
|
:exc:`asyncio.TimeoutError`.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
------
|
------
|
||||||
Any
|
Any
|
||||||
|
|
|
@ -9,7 +9,7 @@ from typing import Dict, Optional, Any
|
||||||
|
|
||||||
from aiohttp import ClientSession, ClientResponse
|
from aiohttp import ClientSession, ClientResponse
|
||||||
|
|
||||||
from melisa.exceptions import (
|
from ..exceptions import (
|
||||||
NotModifiedError,
|
NotModifiedError,
|
||||||
BadRequestError,
|
BadRequestError,
|
||||||
ForbiddenError,
|
ForbiddenError,
|
||||||
|
|
|
@ -63,10 +63,10 @@ class RateLimiter:
|
||||||
bucket = self.buckets[bucket_id]
|
bucket = self.buckets[bucket_id]
|
||||||
|
|
||||||
if bucket.remaining == 0:
|
if bucket.remaining == 0:
|
||||||
sleep_time = time() - bucket.since_timestamp + bucket.reset_after_timestamp
|
sleep_time = time() - bucket.since_timestamp + bucket.reset_after
|
||||||
|
|
||||||
_logger.info(
|
_logger.info(
|
||||||
"Waiting until rate limit for bucket %s is over.", sleep_time, bucket_id
|
"Waiting until rate limit for bucket %s is over.", bucket_id
|
||||||
)
|
)
|
||||||
|
|
||||||
await sleep(sleep_time)
|
await sleep(sleep_time)
|
||||||
|
|
|
@ -3,16 +3,12 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from ..models.guild.channel import _choose_channel_type
|
||||||
from ..utils.types import Coro
|
from ..utils.types import Coro
|
||||||
from ..models.guild import Channel, ChannelType, channel_types_for_converting
|
|
||||||
|
|
||||||
|
|
||||||
async def channel_create_listener(self, gateway, payload: dict):
|
async def channel_create_listener(self, gateway, payload: dict):
|
||||||
payload.update({"type": ChannelType(payload.pop("type"))})
|
channel = _choose_channel_type(payload)
|
||||||
|
|
||||||
channel_cls = channel_types_for_converting.get(payload["type"], Channel)
|
|
||||||
|
|
||||||
channel = channel_cls.from_dict(payload)
|
|
||||||
|
|
||||||
await self.dispatch("on_channel_create", channel)
|
await self.dispatch("on_channel_create", channel)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Copyright MelisaDev 2022 - Present
|
# Copyright MelisaDev 2022 - Present
|
||||||
# Full MIT License can be found in `LICENSE.txt` at the project root.
|
# Full MIT License can be found in `LICENSE.txt` at the project root.
|
||||||
|
|
||||||
from .app import *
|
from .app import Shard, Intents
|
||||||
from .guild import *
|
from .guild import *
|
||||||
from .user import *
|
from .user import *
|
||||||
from .message import *
|
from .message import *
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Copyright MelisaDev 2022 - Present
|
# Copyright MelisaDev 2022 - Present
|
||||||
# Full MIT License can be found in `LICENSE.txt` at the project root.
|
# Full MIT License can be found in `LICENSE.txt` at the project root.
|
||||||
|
|
||||||
from .intents import *
|
from .intents import Intents
|
||||||
from .shard import *
|
from .shard import Shard
|
||||||
|
|
|
@ -7,10 +7,11 @@ from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from typing import List, Union, Optional
|
from typing import List, Union, Optional, Dict, Any
|
||||||
|
|
||||||
from .colors import Color
|
from .colors import Color
|
||||||
from melisa.exceptions import EmbedFieldError
|
from melisa.exceptions import EmbedFieldError
|
||||||
|
from ...utils.conversion import try_enum
|
||||||
from ...utils.api_model import APIModelBase
|
from ...utils.api_model import APIModelBase
|
||||||
from ...utils.types import APINullable, UNDEFINED
|
from ...utils.types import APINullable, UNDEFINED
|
||||||
from melisa.utils.timestamp import Timestamp
|
from melisa.utils.timestamp import Timestamp
|
||||||
|
@ -64,9 +65,9 @@ class EmbedThumbnail:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
url: str
|
url: str
|
||||||
proxy_url: APINullable[str] = UNDEFINED
|
proxy_url: APINullable[str] = None
|
||||||
height: APINullable[int] = UNDEFINED
|
height: APINullable[int] = None
|
||||||
width: APINullable[int] = UNDEFINED
|
width: APINullable[int] = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass(repr=False)
|
@dataclass(repr=False)
|
||||||
|
@ -86,9 +87,9 @@ class EmbedVideo:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
url: str
|
url: str
|
||||||
proxy_url: APINullable[str] = UNDEFINED
|
proxy_url: APINullable[str] = None
|
||||||
height: APINullable[int] = UNDEFINED
|
height: APINullable[int] = None
|
||||||
width: APINullable[int] = UNDEFINED
|
width: APINullable[int] = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass(repr=False)
|
@dataclass(repr=False)
|
||||||
|
@ -108,9 +109,9 @@ class EmbedImage:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
url: str
|
url: str
|
||||||
proxy_url: APINullable[str] = UNDEFINED
|
proxy_url: APINullable[str] = None
|
||||||
height: APINullable[int] = UNDEFINED
|
height: APINullable[int] = None
|
||||||
width: APINullable[int] = UNDEFINED
|
width: APINullable[int] = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass(repr=False)
|
@dataclass(repr=False)
|
||||||
|
@ -125,8 +126,8 @@ class EmbedProvider:
|
||||||
Url of provider
|
Url of provider
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name: APINullable[str] = UNDEFINED
|
name: APINullable[str] = None
|
||||||
url: APINullable[str] = UNDEFINED
|
url: APINullable[str] = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass(repr=False)
|
@dataclass(repr=False)
|
||||||
|
@ -146,9 +147,9 @@ class EmbedAuthor:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
url: APINullable[str] = UNDEFINED
|
url: APINullable[str] = None
|
||||||
icon_url: APINullable[str] = UNDEFINED
|
icon_url: APINullable[str] = None
|
||||||
proxy_icon_url: APINullable[str] = UNDEFINED
|
proxy_icon_url: APINullable[str] = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass(repr=False)
|
@dataclass(repr=False)
|
||||||
|
@ -166,8 +167,8 @@ class EmbedFooter:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
text: str
|
text: str
|
||||||
icon_url: APINullable[str] = UNDEFINED
|
icon_url: APINullable[str] = None
|
||||||
proxy_icon_url: APINullable[str] = UNDEFINED
|
proxy_icon_url: APINullable[str] = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass(repr=False)
|
@dataclass(repr=False)
|
||||||
|
@ -227,19 +228,101 @@ class Embed(APIModelBase):
|
||||||
Video information.
|
Video information.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
title: APINullable[str] = UNDEFINED
|
title: APINullable[str] = None
|
||||||
type: APINullable[EmbedType] = UNDEFINED
|
type: APINullable[EmbedType] = None
|
||||||
description: APINullable[str] = UNDEFINED
|
description: APINullable[str] = None
|
||||||
url: APINullable[str] = UNDEFINED
|
url: APINullable[str] = None
|
||||||
timestamp: APINullable[Timestamp] = UNDEFINED
|
timestamp: APINullable[Timestamp] = None
|
||||||
color: APINullable[Color] = UNDEFINED
|
color: APINullable[Color] = None
|
||||||
footer: APINullable[EmbedFooter] = UNDEFINED
|
footer: APINullable[EmbedFooter] = None
|
||||||
image: APINullable[EmbedImage] = UNDEFINED
|
image: APINullable[EmbedImage] = None
|
||||||
thumbnail: APINullable[EmbedThumbnail] = UNDEFINED
|
thumbnail: APINullable[EmbedThumbnail] = None
|
||||||
video: APINullable[EmbedVideo] = UNDEFINED
|
video: APINullable[EmbedVideo] = None
|
||||||
provider: APINullable[EmbedProvider] = UNDEFINED
|
provider: APINullable[EmbedProvider] = None
|
||||||
author: APINullable[EmbedAuthor] = UNDEFINED
|
author: APINullable[EmbedAuthor] = None
|
||||||
fields: APINullable[List[EmbedField]] = UNDEFINED
|
fields: APINullable[List[EmbedField]] = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]):
|
||||||
|
"""Generate a message from the given data.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
data: :class:`dict`
|
||||||
|
The dictionary to convert into an unknown channel.
|
||||||
|
"""
|
||||||
|
self: Embed = super().__new__(cls)
|
||||||
|
|
||||||
|
self.title = data.get("title")
|
||||||
|
self.type = (
|
||||||
|
try_enum(EmbedType, data["type"]) if data.get("type") is not None else None
|
||||||
|
)
|
||||||
|
self.description = data.get("description")
|
||||||
|
self.url = data.get("url")
|
||||||
|
self.timestamp = (
|
||||||
|
Timestamp.parse(data["timestamp"])
|
||||||
|
if data.get("timestamp") is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
self.color = Color(data["color"]) if data.get("color") is not None else None
|
||||||
|
|
||||||
|
self.footer = None
|
||||||
|
self.image = None
|
||||||
|
self.thumbnail = None
|
||||||
|
self.video = None
|
||||||
|
self.provider = None
|
||||||
|
self.author = None
|
||||||
|
self.fields = []
|
||||||
|
|
||||||
|
if data.get("footer") is not None:
|
||||||
|
self.footer = EmbedFooter(
|
||||||
|
text=data["footer"]["text"],
|
||||||
|
icon_url=data["footer"].get("icon_url"),
|
||||||
|
proxy_icon_url=data["footer"].get("proxy_icon_url"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if data.get("image") is not None:
|
||||||
|
self.image = EmbedImage(
|
||||||
|
url=data["image"]["url"],
|
||||||
|
proxy_url=data["image"].get("proxy_url"),
|
||||||
|
height=data["image"].get("height"),
|
||||||
|
width=data["image"].get("width"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if data.get("video") is not None:
|
||||||
|
self.video = EmbedVideo(
|
||||||
|
url=data["video"]["url"],
|
||||||
|
proxy_url=data["video"].get("proxy_url"),
|
||||||
|
height=data["video"].get("height"),
|
||||||
|
width=data["video"].get("width"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if data.get("provider") is not None:
|
||||||
|
self.provider = EmbedProvider(
|
||||||
|
name=data["provider"].get("name"), url=data["provider"].get("url")
|
||||||
|
)
|
||||||
|
|
||||||
|
if data.get("author") is not None:
|
||||||
|
self.author = EmbedAuthor(
|
||||||
|
name=data["author"]["name"],
|
||||||
|
url=data["author"].get("url"),
|
||||||
|
icon_url=data["author"].get("icon_url"),
|
||||||
|
proxy_icon_url=data["author"].get("proxy_icon_url"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if data.get("fields") is not None:
|
||||||
|
for field in data["fields"]:
|
||||||
|
self.fields.append(
|
||||||
|
EmbedField(
|
||||||
|
name=field["name"],
|
||||||
|
value=field["value"],
|
||||||
|
inline=field["inline"]
|
||||||
|
if field.get("inline") is not None
|
||||||
|
else False,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
if self.title and len(self.title) > 256:
|
if self.title and len(self.title) > 256:
|
||||||
|
@ -420,7 +503,7 @@ class Embed(APIModelBase):
|
||||||
This embed.
|
This embed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.fields is UNDEFINED:
|
if self.fields is None:
|
||||||
self.fields = []
|
self.fields = []
|
||||||
|
|
||||||
self.fields.append(EmbedField(name=name, value=value, inline=inline))
|
self.fields.append(EmbedField(name=name, value=value, inline=inline))
|
||||||
|
|
|
@ -5,14 +5,14 @@ from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from typing import List, TYPE_CHECKING, Optional, Dict
|
from typing import List, TYPE_CHECKING, Optional, Dict, Any
|
||||||
|
|
||||||
from ...utils import Snowflake, Timestamp
|
from .embed import Embed
|
||||||
from ...utils import APIModelBase
|
from ...utils import Snowflake, Timestamp, try_enum, APIModelBase
|
||||||
from ...utils.types import APINullable, UNDEFINED
|
from ...utils.types import APINullable, UNDEFINED
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ..guild.channel import Thread
|
from ..guild.channel import Thread, _choose_channel_type
|
||||||
|
|
||||||
|
|
||||||
class MessageType(IntEnum):
|
class MessageType(IntEnum):
|
||||||
|
@ -144,7 +144,7 @@ class Message(APIModelBase):
|
||||||
Whether this message is pinned
|
Whether this message is pinned
|
||||||
webhook_id: :class:`~melisa.utils.types.snowflake.Snowflake`
|
webhook_id: :class:`~melisa.utils.types.snowflake.Snowflake`
|
||||||
If the message is generated by a webhook, this is the webhook's id
|
If the message is generated by a webhook, this is the webhook's id
|
||||||
type: :class:`int`
|
type: :class:`MessageType`
|
||||||
Type of message
|
Type of message
|
||||||
activity: :class:`typing.Any`
|
activity: :class:`typing.Any`
|
||||||
Sent with Rich Presence-related chat embeds
|
Sent with Rich Presence-related chat embeds
|
||||||
|
@ -170,36 +170,112 @@ class Message(APIModelBase):
|
||||||
Deprecated the stickers sent with the message
|
Deprecated the stickers sent with the message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
id: APINullable[Snowflake] = UNDEFINED
|
id: APINullable[Snowflake] = None
|
||||||
channel_id: APINullable[Snowflake] = UNDEFINED
|
channel_id: APINullable[Snowflake] = None
|
||||||
guild_id: APINullable[Snowflake] = UNDEFINED
|
guild_id: APINullable[Snowflake] = None
|
||||||
author: APINullable[Dict] = UNDEFINED
|
author: APINullable[Dict] = None
|
||||||
member: APINullable[Dict] = UNDEFINED
|
member: APINullable[Dict] = None
|
||||||
content: APINullable[str] = UNDEFINED
|
content: APINullable[str] = None
|
||||||
timestamp: APINullable[Timestamp] = UNDEFINED
|
timestamp: APINullable[Timestamp] = None
|
||||||
edited_timestamp: APINullable[Timestamp] = UNDEFINED
|
edited_timestamp: APINullable[Timestamp] = None
|
||||||
tts: APINullable[bool] = UNDEFINED
|
tts: APINullable[bool] = None
|
||||||
mention_everyone: APINullable[bool] = UNDEFINED
|
mention_everyone: APINullable[bool] = None
|
||||||
mentions: APINullable[List] = UNDEFINED
|
mentions: APINullable[List] = None
|
||||||
mention_roles: APINullable[List] = UNDEFINED
|
mention_roles: APINullable[List] = None
|
||||||
mention_channels: APINullable[List] = UNDEFINED
|
mention_channels: APINullable[List] = None
|
||||||
attachments: APINullable[List] = UNDEFINED
|
attachments: APINullable[List] = None
|
||||||
embeds: APINullable[List] = UNDEFINED
|
embeds: APINullable[List] = None
|
||||||
reactions: APINullable[List] = UNDEFINED
|
reactions: APINullable[List] = None
|
||||||
nonce: APINullable[int] or APINullable[str] = UNDEFINED
|
nonce: APINullable[int] or APINullable[str] = None
|
||||||
pinned: APINullable[bool] = UNDEFINED
|
pinned: APINullable[bool] = None
|
||||||
webhook_id: APINullable[Snowflake] = UNDEFINED
|
webhook_id: APINullable[Snowflake] = None
|
||||||
type: APINullable[int] = UNDEFINED
|
type: APINullable[MessageType] = None
|
||||||
activity: APINullable[Dict] = UNDEFINED
|
activity: APINullable[Dict] = None # ToDo Set model here
|
||||||
application: APINullable[Dict] = UNDEFINED
|
application: APINullable[Dict] = None
|
||||||
application_id: APINullable[Snowflake] = UNDEFINED
|
application_id: APINullable[Snowflake] = None
|
||||||
message_reference: APINullable[Dict] = UNDEFINED
|
message_reference: APINullable[Dict] = None
|
||||||
flags: APINullable[int] = UNDEFINED
|
flags: APINullable[int] = None
|
||||||
interaction: APINullable[Dict] = UNDEFINED
|
referenced_message: APINullable[Message] = None
|
||||||
thread: APINullable[Thread] = UNDEFINED
|
interaction: APINullable[Dict] = None
|
||||||
components: APINullable[List] = UNDEFINED
|
thread: APINullable[Thread] = None
|
||||||
sticker_items: APINullable[List] = UNDEFINED
|
components: APINullable[List] = None
|
||||||
stickers: APINullable[List] = UNDEFINED
|
sticker_items: APINullable[List] = None
|
||||||
|
stickers: APINullable[List] = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: Dict[str, Any]):
|
||||||
|
"""Generate a message from the given data.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
data: :class:`dict`
|
||||||
|
The dictionary to convert into an unknown channel.
|
||||||
|
"""
|
||||||
|
self: Message = super().__new__(cls)
|
||||||
|
|
||||||
|
self.id = data["id"]
|
||||||
|
self.channel_id = Snowflake(data["channel_id"])
|
||||||
|
self.guild_id = (
|
||||||
|
Snowflake(data["guild_id"]) if data.get("guild_id") is not None else None
|
||||||
|
)
|
||||||
|
self.author = data.get("author") # ToDo: User object
|
||||||
|
self.member = data.get("member")
|
||||||
|
self.content = data.get("content", "")
|
||||||
|
self.timestamp = Timestamp.parse(data["timestamp"])
|
||||||
|
self.edited_timestamp = (
|
||||||
|
Timestamp.parse(data["edited_timestamp"])
|
||||||
|
if data.get("edited_timestamp") is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
self.tts = data["tts"]
|
||||||
|
self.mention_everyone = data["mention_everyone"]
|
||||||
|
self.mentions = data["mentions"] # ToDo: Convert to models
|
||||||
|
self.mention_roles = data.get("mention_roles")
|
||||||
|
self.attachments = data.get("attachments", [])
|
||||||
|
self.reactions = data.get("reactions", [])
|
||||||
|
self.nonce = data.get("nonce")
|
||||||
|
self.pinned = data.get("pinned", False)
|
||||||
|
self.webhook_id = (
|
||||||
|
Snowflake(data["webhook_id"])
|
||||||
|
if data.get("webhook_id") is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
self.type = try_enum(MessageType, data.get("type", 0))
|
||||||
|
self.activity = data.get("activity")
|
||||||
|
self.application = data.get("application")
|
||||||
|
self.application_id = (
|
||||||
|
Snowflake(data["application_id"])
|
||||||
|
if data.get("application_id") is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
self.message_reference = data.get(
|
||||||
|
"message_reference"
|
||||||
|
) # ToDo: message reference object
|
||||||
|
self.flags = try_enum(MessageFlags, data.get("flags", 0))
|
||||||
|
self.referenced_message = (
|
||||||
|
Message.from_dict(data["referenced_message"])
|
||||||
|
if data.get("referenced_message") is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
self.interaction = data.get("interaction")
|
||||||
|
self.thread = (
|
||||||
|
Thread.from_dict(data["thread"]) if data.get("thread") is not None else None
|
||||||
|
)
|
||||||
|
self.components = data.get("components")
|
||||||
|
self.sticker_items = data.get("sticker_items")
|
||||||
|
self.stickers = data.get("stickers")
|
||||||
|
|
||||||
|
self.mention_channels = []
|
||||||
|
self.embeds = []
|
||||||
|
|
||||||
|
for channel in data.get("mention_channels", []):
|
||||||
|
channel = _choose_channel_type(channel)
|
||||||
|
self.mention_channels.append(channel)
|
||||||
|
|
||||||
|
for embed in data.get("embeds", []):
|
||||||
|
self.embeds.append(Embed.from_dict(embed))
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
async def pin(self, *, reason: Optional[str] = None):
|
async def pin(self, *, reason: Optional[str] = None):
|
||||||
"""|coro|
|
"""|coro|
|
||||||
|
|
|
@ -5,11 +5,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import (
|
from typing import Optional, Dict, Any
|
||||||
Optional,
|
|
||||||
Dict,
|
|
||||||
Any
|
|
||||||
)
|
|
||||||
|
|
||||||
from ...utils.conversion import try_enum
|
from ...utils.conversion import try_enum
|
||||||
from ...utils.api_model import APIModelBase
|
from ...utils.api_model import APIModelBase
|
||||||
|
@ -201,13 +197,6 @@ class User(APIModelBase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, data: Dict[str, Any]) -> User:
|
def from_dict(cls, data: Dict[str, Any]) -> User:
|
||||||
"""Generate a user from the given data.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
data: :class:`dict`
|
|
||||||
The dictionary to convert into a user.
|
|
||||||
"""
|
|
||||||
self: User = super().__new__(cls)
|
self: User = super().__new__(cls)
|
||||||
|
|
||||||
self.id = int(data["id"])
|
self.id = int(data["id"])
|
||||||
|
@ -222,11 +211,7 @@ class User(APIModelBase):
|
||||||
self.local = data.get("local")
|
self.local = data.get("local")
|
||||||
self.verified = data.get("verified", False)
|
self.verified = data.get("verified", False)
|
||||||
self.email = data.get("email")
|
self.email = data.get("email")
|
||||||
self.premium_type = try_enum(
|
self.premium_type = try_enum(PremiumTypes, data.get("premium_type"))
|
||||||
PremiumTypes, data.get("premium_type")
|
self.public_flags = try_enum(UserFlags, data.get("public_flags"))
|
||||||
)
|
|
||||||
self.public_flags = try_enum(
|
|
||||||
UserFlags, data.get("public_flags")
|
|
||||||
)
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
70
melisa/rest.py
Normal file
70
melisa/rest.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
# Copyright MelisaDev 2022 - Present
|
||||||
|
# Full MIT License can be found in `LICENSE.txt` at the project root.
|
||||||
|
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
from .core.http import HTTPClient
|
||||||
|
from .utils.snowflake import Snowflake
|
||||||
|
from .models.guild.guild import Guild
|
||||||
|
from .models.user.user import User
|
||||||
|
from .models.guild.channel import _choose_channel_type, Channel
|
||||||
|
|
||||||
|
|
||||||
|
class RESTApp:
|
||||||
|
"""
|
||||||
|
This instance may be used to send http requests to the Discord REST API.
|
||||||
|
|
||||||
|
**It will not cache anything.**
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
token: :class:`str`
|
||||||
|
The token to authorize (you can found it in the developer portal)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, token: str):
|
||||||
|
self.http: HTTPClient = HTTPClient(token)
|
||||||
|
|
||||||
|
async def fetch_user(self, user_id: Union[Snowflake, int, str]) -> User:
|
||||||
|
"""
|
||||||
|
Fetch User from the Discord API (by id).
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
user_id: Union[:class:`~melisa.utils.snowflake.Snowflake`, str, int]
|
||||||
|
Id of user to fetch
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = await self.http.get(f"users/{user_id}")
|
||||||
|
|
||||||
|
return User.from_dict(data)
|
||||||
|
|
||||||
|
async def fetch_guild(self, guild_id: Union[Snowflake, int, str]) -> Guild:
|
||||||
|
"""
|
||||||
|
Fetch Guild from the Discord API (by id).
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
guild_id : Union[:class:`~melisa.utils.snowflake.Snowflake`, str, int]
|
||||||
|
Id of guild to fetch
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = await self.http.get(f"guilds/{guild_id}")
|
||||||
|
|
||||||
|
return Guild.from_dict(data)
|
||||||
|
|
||||||
|
async def fetch_channel(self, channel_id: Union[Snowflake, str, int]) -> Channel:
|
||||||
|
"""
|
||||||
|
Fetch Channel from the Discord API (by id).
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
channel_id : Union[:class:`~melisa.utils.snowflake.Snowflake`, str, int]
|
||||||
|
Id of channel to fetch
|
||||||
|
"""
|
||||||
|
|
||||||
|
# ToDo: Update cache if CHANNEL_CACHE enabled.
|
||||||
|
|
||||||
|
data = await self.http.get(f"channels/{channel_id}")
|
||||||
|
|
||||||
|
return _choose_channel_type(data)
|
|
@ -5,6 +5,14 @@ from .types import Coro, UNDEFINED
|
||||||
from .timestamp import Timestamp
|
from .timestamp import Timestamp
|
||||||
from .snowflake import Snowflake
|
from .snowflake import Snowflake
|
||||||
from .api_model import APIModelBase
|
from .api_model import APIModelBase
|
||||||
from .conversion import remove_none
|
from .conversion import remove_none, try_enum
|
||||||
|
|
||||||
__all__ = ("Coro", "Snowflake", "APIModelBase", "remove_none", "Timestamp", "UNDEFINED")
|
__all__ = (
|
||||||
|
"Coro",
|
||||||
|
"Snowflake",
|
||||||
|
"APIModelBase",
|
||||||
|
"remove_none",
|
||||||
|
"Timestamp",
|
||||||
|
"UNDEFINED",
|
||||||
|
"try_enum",
|
||||||
|
)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
orjson==3.6.7
|
orjson==3.6.8
|
|
@ -71,9 +71,3 @@ class TestEmbed:
|
||||||
is correct.
|
is correct.
|
||||||
"""
|
"""
|
||||||
assert has_key_vals(EMBED.to_dict(), dict_embed)
|
assert has_key_vals(EMBED.to_dict(), dict_embed)
|
||||||
|
|
||||||
def test_embed_from_dict(self):
|
|
||||||
assert has_key_vals(
|
|
||||||
Embed.from_dict(dict_embed).to_dict(),
|
|
||||||
dict_embed
|
|
||||||
)
|
|
||||||
|
|
Loading…
Reference in a new issue