disnakedev / disnake Goto Github PK
View Code? Open in Web Editor NEWAn API wrapper for Discord written in Python.
Home Page: https://docs.disnake.dev
License: MIT License
An API wrapper for Discord written in Python.
Home Page: https://docs.disnake.dev
License: MIT License
HTTPClient
has several methods for app commands which are not represented in Client
The core library
HTTPClient
methods only work with dicts and return only dicts. Client
methods will wrap all of that pretty nicely.
No response
No response
Add support for fail_if_not_exists to discord.Message.reply
The core library
I'd like to use ctx.reply (which shortcuts to ctx.message.reply) to reply to a message, however the invoke may have been deleted before the command. It would be nice to fully support message references, and be able to pass fail_if_not_exists as false to ctx.reply.
Narrowing this down, I see two solutions
The clear solution is to add fail_if_not_exists to Message.reply()
The question is how, since looking at the implementation, making a reference just to set it to False seems not the best.
I feel like adding a property to the Message objects, fail_if_not_exists
and using that for the replies would make the most sense. This would be set if provided to the reply method
There's a few implementations here, but it should make sure to not create objects to just not use them in the next method.
Currently a user has to create a reference from a method and set fail_if_not_exists to False, then pass the reference to ctx.send.
Being able to just pass fail_if_not_exists to a reply method would be awesome.
No response
Embed.set_author creates an invalid embed payload if you set icon_url=None
Where author
is a member with no avatar set, meaning author.avatar
is None
, the code
embed.set_author(
name=author.name,
icon_url=author.avatar
)
await send(embed=embed)
Will cause a 400 as embed payload being sent has an author with icon_url equal to the string 'None'
, as Embed.set_author
simply do str(icon_url)
if icon_url
is not EmptyEmbed
.
The issue here is that User.avatar
can be null, and if passing in None
as icon_url
into Embed.set_author
, the actual url will be set to the string 'None'
.
One can solve this in userland by doing:
embed.set_author(
name=author.name,
icon_url=author.avatar or disnake.Embed.Empty
)
await send(embed=embed)
-- but surely that's not a recommended solution?
No response
not applicable
not applicable
not applicable
disnake 2.3.0
No response
It seems that permission overwrite data is missing from guild channels when used with slash commands. channel.overwrites
will always return an empty dictionary.
1). Create a slash command with a channel option
2). Check the overwrites for that channel
async def lock(
self,
interaction: disnake.ApplicationCommandInteraction,
channel: disnake.TextChannel
) -> None:
# Will always be {}
print(channel.overwrites)
To receive the permission overwrites for that channel.
An empty dictionary at all times.
NA
No response
When assigning a slash command parameter to and integer and then putting a really long number as the parameter in your Discord client, Discord will give an error.
import disnake
from disnake.ext import commands
bot = commands.Bot(command_prefix=';')
@bot.slash_command(name='test', description='Test command for long number')
async def test(inter, integer: int):
await inter.response.send_message('Test succesful')
bot.run('TOKEN')
I expected the number to be usable. The integer is an emoji id so it's going to be unavoidably long.
Discord rejected then number. I don't know if this is a problem with this library or some limitation with Discord though.
None
If something doesn't make sense, I can clarify.
A context menu from the main page example doesn't appear
Hello. I've moved to disnake
today to test the context menu functionality I wasn't able to see in with Discord-interactions.
I have used my Discord token, copied the server ID in Discord and I don't see any changes in the context menu of a Discord message.
I expected to see an item like avatar
, but there's none.
No exception to see why that did not happen, as well.
It doesn't matter if the decorator is located in __init__
or on_ready
, it also doesn't matter if I set up a name for a command like here:
@self.user_command(name="Avatar") # optional
async def avatar(inter: disnake.UserCommandInteraction):
# inter.target is the user you clicked on
emb = disnake.Embed(title=f"{inter.target}'s avatar")
emb.set_image(url=inter.target.display_avatar.url)
await inter.response.send_message(embed=emb)
The only difference is how I construct the class, but everything else works.
GUILD_ID = 765671
DISCORD_TOKEN = 'I-am-a-bot-token'
class TestInterface(commands.Bot):
def __init__(self):
super().__init__(test_guilds=[GUILD_ID])
async def on_ready(self):
@self.user_command()
async def avatar(inter):
embed = disnake.Embed(title=str(inter.author))
embed.set_image(url=inter.author.avatar.url)
await inter.response.send_message(embed=embed)
def main():
client = TestInterface()
try:
client.loop.run_until_complete(client.start(DISCORD_TOKEN)
except KeyboardInterrupt:
client.loop.run_until_complete(client.close())
finally:
client.loop.close()
I expect to be able to right-click a message, see a context menu and use an "avatar" item in it.
I see no new items in a message context menu.
I don't know about them, sorry
Add a shortcut for User.name + str(User.discriminator)
The core library
It is inconvenient to write every time you want to show user's full nickname user.name + str(user.discriminator)
I want to something like .tag
attribute in discord.js
None
No response
No response
user modifiable default color for embeds
The core library
All embed objects default to black
Add a class attribute, default_colour (I don't think an alias is necessary, I also don't think its possible) to disnake.Embed to provide a default colour. This will be used as the default if colour or color is not provided. Additionally, by implementing this way, a user can change the defualt colour for new embed objects during runtime.
monkeypatch disnake.Embed to add a default colour in the __init__
No response
Using disnake with python 3.10 = error
No response
Just run with no error
Error like this
/home/teamcloud/.local/lib/python3.10/site-packages/aiohttp/connector.py:964: RuntimeWarning: coroutine 'TCPConnector._resolve_host' was never awaited
hosts = await asyncio.shield(self._resolve_host(
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
Traceback (most recent call last):
File "/home/teamcloud/바탕화면/Cloud/Bot/main.py", line 18, in <module>
bot.run('token')
File "/home/teamcloud/.local/lib/python3.10/site-packages/disnake/client.py", line 834, in run
return future.result()
File "/home/teamcloud/.local/lib/python3.10/site-packages/disnake/client.py", line 813, in runner
await self.start(*args, **kwargs)
File "/home/teamcloud/.local/lib/python3.10/site-packages/disnake/client.py", line 776, in start
await self.login(token)
File "/home/teamcloud/.local/lib/python3.10/site-packages/disnake/client.py", line 635, in login
data = await self.http.static_login(token.strip())
File "/home/teamcloud/.local/lib/python3.10/site-packages/disnake/http.py", line 423, in static_login
data = await self.request(Route("GET", "/users/@me"))
File "/home/teamcloud/.local/lib/python3.10/site-packages/disnake/http.py", line 299, in request
async with self.__session.request(method, url, **kwargs) as response:
File "/home/teamcloud/.local/lib/python3.10/site-packages/aiohttp/client.py", line 1012, in __aenter__
self._resp = await self._coro
File "/home/teamcloud/.local/lib/python3.10/site-packages/aiohttp/client.py", line 480, in _request
conn = await self._connector.connect(
File "/home/teamcloud/.local/lib/python3.10/site-packages/aiohttp/connector.py", line 523, in connect
proto = await self._create_connection(req, traces, timeout)
File "/home/teamcloud/.local/lib/python3.10/site-packages/aiohttp/connector.py", line 858, in _create_connection
_, proto = await self._create_direct_connection(
File "/home/teamcloud/.local/lib/python3.10/site-packages/aiohttp/connector.py", line 964, in _create_direct_connection
hosts = await asyncio.shield(self._resolve_host(
TypeError: shield() got an unexpected keyword argument 'loop'
all
No response
Unable to install disnake on my Raspberry Pi
OS: Raspbian GNU/Linux 10 (buster) armv7l
Host: Raspberry Pi 4 Model B Rev 1.4
Kernel: 5.4.83-v7l+
Uptime: 6 days, 13 hours, 12 mins
Packages: 784 (dpkg)
Shell: bash 5.0.3
Terminal: /dev/pts/0
CPU: BCM2711 (4) @ 1.500GHz
Memory: 255MiB / 1867MiB
My raspberry pi is running python version 3.7.3
.
I'm trying to run a bot that I coded locally (on mac OS Big Sur) on my raspberry Pi, that I'm accessing via SSH.
I created a new python3 virtual environment (python3 -m venv envi
) that I activated doing (source envi/bin/activate
), as usual. The environment is activated as it should be and running (python3 -m pip list
) returns
Package Version
------------- -------
pip 21.3.1
pkg_resources 0.0.0
setuptools 40.8.0
just as expected.
I'm then trying to run the command python3 -m pip install disnake
, as usual (I normally use a requirements.txt file but the error is the exact same, so let's keep the most minimal example.).
But then I get this error message :
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
ERROR: Could not find a version that satisfies the requirement disnake (from versions: none)
ERROR: No matching distribution found for disnake
Could it be possible that the pip depots are not the same on mac OS and raspbian ? If so, how can I install disnake on my raspberry ? I mean, Python is still Python and the library should work everywhere...
Thanks for your help ! I tried to be as precise as possible but if my issue is not complete enough, just tell me and I'll do my best to correct it.
python3 -m pip install disnake
disnake installing successfully
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
ERROR: Could not find a version that satisfies the requirement disnake (from versions: none)
ERROR: No matching distribution found for disnake
Not relevant here, I guess
see "how to reproduce" tab to see my system information
No response
The confirm button example is incorrect - it does not work.
Copy and pasted disnake/examples/views/button/confirm.py in two different files - the class and the command in two different files.
Then, I imported the file (and class). When I ran the command, I got an error.
import disnake
from disnake.ext import commands
class Confirm(disnake.ui.View):
def __init__(self):
super().__init__()
self.value = None
# When the confirm button is pressed, set the inner value to `True` and
# stop the View from listening to more input.
# We also send the user an ephemeral message that we're confirming their choice.
@disnake.ui.button(label="Confirm", style=disnake.ButtonStyle.blurple)
async def confirm(ctx: commands.Context, self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
await interaction.response.send_message("Confirming", ephemeral=True)
self.value = True
self.stop()
# This one is similar to the confirmation button except sets the inner value to `False`
@disnake.ui.button(label="Cancel", style=disnake.ButtonStyle.grey)
async def cancel(ctx: commands.Context, self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
await interaction.response.send_message("Cancelling", ephemeral=True)
self.value = False
self.stop()
# This is in another file
@bot.command()
async def ask(ctx: commands.Context):
"""Asks the user a question to confirm something."""
# We create the view and assign it to a variable so we can wait for it later.
view = Confirm()
await ctx.send("Do you want to continue?", view=view)
# Wait for the View to stop listening for input...
await view.wait()
if view.value is None:
print("Timed out...")
elif view.value:
print("Confirmed...")
else:
print("Cancelled...")
I expected the buttons to be made. However, it gave me an error.
I got a traceback error.
Ignoring exception in on_message
Traceback (most recent call last):
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/disnake/ext/commands/core.py", line 752, in _parse_arguments
next(iterator)
StopIteration
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/disnake/client.py", line 505, in _run_event
await coro(*args, **kwargs)
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/disnake/ext/commands/bot_base.py", line 600, in on_message
await self.process_commands(message)
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/disnake/ext/commands/bot_base.py", line 597, in process_commands
await self.invoke(ctx)
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/disnake/ext/commands/bot_base.py", line 560, in invoke
await ctx.command.invoke(ctx)
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/disnake/ext/commands/core.py", line 921, in invoke
await self.prepare(ctx)
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/disnake/ext/commands/core.py", line 855, in prepare
await self._parse_arguments(ctx)
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/disnake/ext/commands/core.py", line 754, in _parse_arguments
raise disnake.ClientException(
disnake.errors.ClientException: Callback for ask command is missing "ctx" parameter.
all intents
- Python v3.8.12-final
- disnake v2.2.2-beta
- disnake pkg_resources: v2.2.2
- aiohttp v3.7.4.post0
- system info: Linux 5.11.0-1023-gcp #25~20.04.1-Ubuntu SMP Mon Nov 15 15:54:39 UTC 2021
No response
The library seems to run into an issue (randomly) where the guild's member count is None
.
NA
NA
NA
Traceback (most recent call last):
File "bot.py", line 112, in <module>
libertas_support.run()
File "bot.py", line 91, in run
super().run(config.TOKEN)
File "/usr/local/lib/python3.8/dist-packages/disnake/client.py", line 834, in run
return future.result()
File "/usr/local/lib/python3.8/dist-packages/disnake/client.py", line 813, in runner
await self.start(*args, **kwargs)
File "/usr/local/lib/python3.8/dist-packages/disnake/client.py", line 777, in start
await self.connect(reconnect=reconnect)
File "/usr/local/lib/python3.8/dist-packages/disnake/client.py", line 674, in connect
await self.ws.poll_event()
File "/usr/local/lib/python3.8/dist-packages/disnake/gateway.py", line 588, in poll_event
await self.received_message(msg.data)
File "/usr/local/lib/python3.8/dist-packages/disnake/gateway.py", line 538, in received_message
func(data)
File "/usr/local/lib/python3.8/dist-packages/disnake/state.py", line 1167, in parse_guild_member_add
guild._member_count += 1
TypeError: unsupported operand type(s) for +=: 'NoneType' and 'int'
NA
No response
While trying to get user's status it returns offline in Slash Commands, even though the user isn't offline.
When trying to get user's status in a @bot.command()
command it works well and it returns the correctly status, but when using it in a @bot.slash_command
, it returns offline. (I don't know if it works well in context menus)
Also, it just works when you have both Members and Presences intents.
Prefix commands that I'm using:
@bot.command()
async def status(ctx):
# This one works well
await ctx.send(ctx.author.status)
Slash commands that I'm using:
@bot.slash_command(name="status")
async def status(
inter: disnake.ApplicationCommandInteraction,
user: disnake.Member = commands.Param(description="user"),
):
# This one returrns offline
await inter.response.send_message(f"Your status is {user.status}")
Extra comment: Using `disnake.ApplicationCommandInteraction.author.status` returns also offline.
Get the user's status.
Returning offline in Slash Commands.
Presences and Members
Important comment:
It seems that using this way to use intents doesn't work (I may be wrong but at least for the code listed above didn't work)
intents = disnake.Intents()
intents.members = True
intents.presences = True
The way I used to use intents is this one:
intents = disnake.Intents.default()
intents.members = True
intents.presences = True
No response
Search doesn't come up with any results since Color
is just aliased to Colour
:
https://docs.disnake.dev/en/latest/search.html?q=Color.blurple
Line 333 in 860bede
Currently, there is no way to only allow for private threads. This feature request would allow for that.
disnake.ext.commands
Currently, there is no way to only allow for private threads. This feature request would allow for that.
The option to pass channel types to commands.Param
.
NA
No response
This implementation will allow users to work with disnake to easily communicate with a webserver
disnake.ext.commands
This is based off a somewhat well used repo that got abandoned since discord.py has stopped.
Source: discord-ext-ipc
This implementation will allow the user to easily talk to the webserver and easily send information to it.
It's also much faster. I'm pretty active in the official python and whilists there are not many requests on how to make a dashboard, most people easily abandon the matter since it is not well documented and not so user friendly anymore.
I'd also like to see it as a way of being unique since not many forks have this.
Maby later even have something like an implemented Quart, Quart for discord if it really is a succes.
This feature would make it easier for beginners to get started making Discord dashboards. This would also have routing for faster response times.
This is currently not implemented inside any discord.py fork.
I'm also willing to make a PR or give a concept to the idea, i've not made that yet since i firstly want some more insight of wheter this will be added since it is not a small implementation. This also does not require any manipulation of the core code.
A new field was added to the thread creation endpoints, which we should support
The core library
We're not fully covering the threads API.
Docs commit here: discord/discord-api-docs@d56be86
Add support for the new field.
No response
This is a fairly straight forward change, and is a good issue for a new contributor to tackle.
Discord is working on this new component and interaction, which we should support. Currently, modals are in closed beta.
I already have a draft implementation that works well, but I will submit a PR once the API becomes public or if I get access to modals.
ref:
discord/discord-api-docs#4143
discord/discord-api-docs#4459
Use logger for application command sync
disnake.ext.commands
The application command sync debug logs use print statements rather than log statements, which are quite a bit worse than actual logs, as they can't be filtered, there's no timestamp etc.
Use the library's logger.
No response
No response
Guild.timeout(Member) is not working
member = guild.get_member(123456789012345678)
await guild.timeout(user=member, seconds=10, reason="some reason")
This should put user in timeout.
It actually returns
disnake.errors.HTTPException: 400 Bad Request (error code: 50035): Invalid Form Body
In user_id: Value "member's name" is not snowflake.
disnake.Intents.all()
Windows Server 2019, 64-bit
Python 3.9.7
disnake @ latest commit in master
It actually works when use
await guild.timeout(user=123456789012345678)
Unable to fetch message that triggered interaction
Interaction#original_message
@commands.slash_command()
async def ping(inter: disnake.ApplicationCommandInteraction):
msg = await inter.original_message()
print(msg.author.id)
Interaction#original_message
to resolve as an instance of InteractionMessage
The following error is produced even if the message still exists:
disnake.errors.NotFound: 404 Not Found (error code: 10015): Unknown Webhook
Traceback:
bot_1 | Traceback (most recent call last):
bot_1 | File "/usr/local/lib/python3.9/site-packages/disnake/ext/commands/slash_core.py", line 482, in invoke
bot_1 | await self(inter, **kwargs)
bot_1 | File "/usr/local/lib/python3.9/site-packages/disnake/ext/commands/base_core.py", line 145, in __call__
bot_1 | return await self.callback(self.cog, interaction, *args, **kwargs)
bot_1 | File "/app/cmds/eval.py", line 19, in eval
bot_1 | msg = await inter.original_message()
bot_1 | File "/usr/local/lib/python3.9/site-packages/disnake/interactions/base.py", line 264, in original_message
bot_1 | data = await adapter.get_original_interaction_response(
bot_1 | File "/usr/local/lib/python3.9/site-packages/disnake/webhook/async_.py", line 189, in request
bot_1 | raise NotFound(response, data)
bot_1 | disnake.errors.NotFound: 404 Not Found (error code: 10015): Unknown Webhook
bot_1 |
bot_1 | The above exception was the direct cause of the following exception:
bot_1 |
bot_1 | Traceback (most recent call last):
bot_1 | File "/usr/local/lib/python3.9/site-packages/disnake/ext/commands/bot.py", line 1887, in process_application_commands
bot_1 | await app_command.invoke(interaction)
bot_1 | File "/usr/local/lib/python3.9/site-packages/disnake/ext/commands/slash_core.py", line 491, in invoke
bot_1 | raise CommandInvokeError(exc) from exc
bot_1 | disnake.ext.commands.errors.CommandInvokeError: Command raised an exception: NotFound: 404 Not Found (error code: 10015): Unknown Webhook
Default + Members
Running in a Docker container based on python:3.9-slim-buster
No response
ConnectionState._get_guild_channel
uses DMChannel._from_message
, which always sets recipient
to None
. This applies to both parse_message_create
and parse_typing_start
, and results in the typing
event not being dispatched (among other things):
Lines 1687 to 1688 in 6fe2b89
Lines 1702 to 1706 in 6fe2b89
The typing
event gets dispatched
it doesn't get dispatched (duh)
all
https://discord.com/channels/808030843078836254/883342278280745030/914696216850354196
Discord added a way to provide slash commands for only some of the users.
disnake.ext.commands
Discord added a way to provide slash commands for only the members who have the permission. Currently, we can't use this feature with the library.
I would like the library to add a permission
parameter to the commands.slash_command
object, to use this feature.
No response
Doing ctx.send with disnake.Context returns a disnake. Message object, while inter.send doesn't return anything. I suggest to return the message
The core library
Disclaimer: I'm going to use ctx
as a keyword, but that's still an interaction.
If I use ctx.send('Hello world')
in a message command (with disnake.Context
), the method returns a disnake.Message
.
In the contrary, using ctx.send('Hello world')
in a slash command, component... (with disnake.Interaction
), the method doesn't return anything.
Using ctx.send('Hello world')
with disnake.Interaction
returns a disnake.Message
object.
Using ctx.send('Hello world')
with disnake.Interaction
doesn't return anything (because the API doesn't return anything, I consider fetching the message after sending it to return an object).
No response
commands.Group(), but for slash commands (sub-commands)
disnake.ext.commands
I am trying to use sub-commands (for slash commands) with commands.Bot, but the only Group
I found in the documentation is commands.Group()
which is for regular commands.
Adding something like commands.SlashCommandGroup()
that will allow us to make sub-commands with commands.SlashCommandGroup().slash_command()
No response
No response
Discord is experimenting with this new feature which is basically like a Muted role but even better and easier.
This is something that the library should really support.
When I try to use slash commands on mobile they don't work
go on mobile and use slash commands
No response
members
No response
It seems that context menus commands in cogs aren't working on Python 3.10.
However, the current GitHub version seems to fix that, so I'll leave this issue just to make sure it's a known bug, but this will be fixed in the next version. (Probably 2.3)
shiftinv figured out why it was happening, full conversation here.
At certain resolutions, the doc site layout table of contents overlays the actual content
No response
Content not to overlay other elements on the page that are intended for reading
The sidebar overlaps the main content, either clipping the content (in dark mode), or displaying the scrollbar over the content (in light mode) impairing or preventing reading.
None
OSX 11.61
Firefox 95.0 Stable
Safari 15.1
No response
Change the readme entirely to be different than the inherited readme
The documentation
Readme looks the same as every other fork.
New readme, new format, new examples. Showcase what disnake has to offer.
No response
No response
Slash commands can not be used in a direct message, as they error.
Create a global command, and try to invoke it in a direct message.
No response
The command works.
An error occurs:
AttributeError: 'PartialMessageable' object has no attribute 'permissions_for'
File "disnake/ext/commands/slash_core.py", line 562, in invoke
await self.invoke_children(inter)
File "disnake/ext/commands/slash_core.py", line 547, in invoke_children
await subcmd.invoke(inter, **kwargs)
File "disnake/ext/commands/slash_core.py", line 271, in invoke
return await super().invoke(inter, *args, **kwargs)
File "disnake/ext/commands/base_core.py", line 281, in invoke
await self.prepare(inter)
File "disnake/ext/commands/base_core.py", line 204, in prepare
if not await self.can_run(inter):
File "disnake/ext/commands/base_core.py", line 523, in can_run
return await async_all(predicate(inter) for predicate in predicates) # type: ignore
File "disnake/utils.py", line 554, in async_all
for elem in gen:
File "disnake/ext/commands/base_core.py", line 523, in <genexpr>
return await async_all(predicate(inter) for predicate in predicates) # type: ignore
File "disnake/ext/commands/core.py", line 2060, in predicate
permissions = ch.permissions_for(ctx.author) # type: ignore
CommandInvokeError: Command raised an exception: AttributeError: 'PartialMessageable' object has no attribute 'permissions_for'
File "disnake/client.py", line 505, in _run_event
await coro(*args, **kwargs)
File "apollo/cogs/command_error/__init__.py", line 29, in on_slash_command_error
raise error
File "disnake/ext/commands/interaction_bot_base.py", line 1297, in process_application_commands
await app_command.invoke(interaction)
File "disnake/ext/commands/slash_core.py", line 578, in invoke
raise CommandInvokeError(exc) from exc
N/A
2.2.2
No response
Recording Voice In A VC
The core library
Not being able to
Possibly implementing a speaking state cacher in the gateway which when called if voice record is on will record voice to whatever format the user chooses
No response
No response
Add support for converters for slash command options
disnake.ext.commands
I cannot eassaly use power of converters in slash commands.
@commands.slash_command(
description = '...',
options = [disnake.Option('name', 'description', disnake.OptionType.string, True, converter=CustomConverter)]
)
async def test(self, interaction, name):
...
or
@commands.slash_command(
description = '...',
options = [disnake.Option('name', 'description', disnake.OptionType.string, True)]
)
async def test(self, interaction, name: CustomConverter):
...
@commands.slash_command(...)
async def test(self, interaction, name):
converted = CustomConverter().convert(interaction, name)
Maybe, for custom converters slash_convert
(or something different to convert
) will be called instead of convert
We need a way to handle components without being forced to use a view.
Currently, a huge problem left over from discord.py is the enforced usage of views. Generally, most components could be handled using just information gotten from the interaction dispatched through the gateway. But instead, we are forced to use views that either timeout or make all views permanent which would however inevitably cause a memory leak.
on_message_interaction
is a very good alternative but it's missing highly needed abstraction.
Say we're working with a message that has an embed with a specific rule and buttons to get the previous (custom_id="help:prev"
) and next rules (custom_id="help:next"
) and a button to delete the message (custom_id="delete"
).
The simplest thing we could do is simply add our own built-in listener which dispatches other handlers.
The usage would be as follows.
def get_page(interaction: disnake.MessageInteraction) -> int:
string = interaction.message.embeds[0].title
return int(string.split(":")[0])
@commands.component("delete")
async def delete_message(interaction: disnake.MessageInteraction):
await interaction.message.delete()
await interaction.response.send_message("Deleted message", ephemeral=True)
@commands.component("help:next")
async def delete_message(interaction: disnake.MessageInteraction):
page = get_page(interaction)
embed = my_utils.get_rule_embed(page=page + 1)
await interaction.response.edit_message(embed=embed)
@commands.component("help:prev")
async def delete_message(interaction: disnake.MessageInteraction):
page = get_page(interaction)
embed = my_utils.get_rule_embed(page=page - 1)
await interaction.response.edit_message(embed=embed)
This solution would change custom_id handling to embed encoded data (for simplicity in the form of json here). The new custom ids would be as follows (assuming the current rule page is 2): help:next#{"page":2}
The usage would be as follows.
# make this a custom class in the future maybe? More abstraction is always welcome
class PageButtonState(TypedDict):
page: int
@commands.component("delete")
async def delete_message(interaction: disnake.MessageInteraction, state: Dict[str, Any]):
await interaction.message.delete()
await interaction.response.send_message("Deleted message", ephemeral=True)
@commands.component("help:next")
async def delete_message(interaction: disnake.MessageInteraction, state: PageButtonState):
embed = my_utils.get_rule_embed(page=state["page"] + 1)
await interaction.response.edit_message(embed=embed)
@commands.component("help:prev")
async def delete_message(interaction: disnake.MessageInteraction, state: PageButtonState):
page = get_page(interaction)
embed = my_utils.get_rule_embed(page=state["page"] - 1)
await interaction.response.edit_message(embed=embed)
Enforced views / permanent views / low level event handling.low-level
@listener()
async def on_message_interaction(interaction: disnake.MessageInteraction):
custom_id = interaction.data.custom_id
if custom_id == "delete":
await interaction.message.delete()
await interaction.response.send_message("Deleted message", ephemeral=True)
if custom_id not in ["help:next", "help:prev"]:
return
string = interaction.message.embeds[0].title
page = int(string.split(":")[0])
if custom_id == "help:next":
page += 1
if custom_id == "help:prev":
page -= 1
embed = my_utils.get_rule_embed(page=page)
await interaction.response.edit_message(embed=embed)
This is also being discussed over in the disnake discord server.
A "commit convention" simply refers to a commit name and/or message template that is followed by all commits and PRs to the repository.
The core library
(The feature request is for the GitHub repository.)
Currently, our repo's commit names do not fully imply the contribution made, the section changed/added, which part of the repo is affected by it, and so on. This also causes an inconsistency in the commit history, which can later on make it difficult to search as to which commit made a specific change.
Our commit history can have an impression of our development practices and standard on a user browsing the repository, and thus can make or break what a user believes about our library.
Having a convention/set of rules for the commits makes it easier to search for specific requirements - let it be for docs, feature additions, revert commits, or breaking changes. It also creates a discipline and uniformity that is followed by all contributors.
Implementing this can also give us an edge over competing forks. Think of it as type-safety, but for our commits. :P
My current notion is that we learn and implement from discord.js's commit convention guidelines. This includes a regex as follows:
/^(revert: )?(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|types|wip)(\(.+\))?: .{1,72}/;
The library will probably require tweaking this according to our directory structure, but this essentially introduces a "tag" that each commit would accordingly include, listing the section changed in parantheses. We can also alternatively refer to https://www.conventionalcommits.org/
For example, a commit to the documentation would include docs(on_message): Update parameter descriptions
. This can make it simpler to search for documentation-only commits later, as well as make it easier to understand commits on the repo's frontpage (and in GitHub notifications) as to which part of the library was modified.
The example of discord.js's contribution guidelines is ofcourse, a suggestion and just one of the ways to do it. The intention is that we:
When creating a slash command with params, I get this error: [WARNING] Failed to overwrite global commands due to Option.__init__() got an unexpected keyword argument 'name_localizations'
. It appears randomly, whether test_guilds
is used or not.
Create a simple slash command with a parameter.
When trying to run the command, it just disappears and all other slash commands too. The error seems to appear randomly.
@bot.slash_command()
async def test(
inter: disnake.ApplicationCommandInteraction,
text: str,
):
await inter.response.send_message(text)
Slash commands to work properly.
Slash commands disappear.
None
I have tried reproducing the error with the GitHub version, and it seems to be working fine.
If someone could reproduce this error, I would appreciate it.
Code from examples dont work
I inserted the code from the examples into the project
https://github.com/EQUENOS/disnake/blob/master/examples/slash_commands/param.py
# Commands may be limited only to guilds with a special interaction annotation
@bot.slash_command()
async def guild_command(
inter: disnake.GuildCommandInteraction
) -> None:
...
That the code will work
The code doesn't work
None
$ pip show disnake
Name: disnake
Version: 2.1.2
Summary: A Python wrapper for the Discord API
Home-page: https://github.com/EQUENOS/disnake
Author: Rapptz, EQUENOS
Author-email:
License: MIT
Location: /home/lev145/PycharmProjects/MusicBot/venv/lib/python3.9/site-packages
Requires: aiohttp
Required-by: discord-disnake
I love cats
lower level component iterface that doesn't involve views
The core library
disnake.ui.View requires a lot of code for some complex features. I'd like to be able to use components at a lower level. Because on_message_interaction exists in the dispatched events, that is usable after sending the component. However, a view has to be used to send components with disnake.abc.Messegeable.send
A solution here seems like it would be in the source of send, to expose components
as a kwarg, and document how to pass buttons and the like to that.
Make a view and send that, but then intercept the params with on_message_component.
No response
Descendants of Interaction
(like MessageInteraction
or ApplicationCommandInteraction
) are missing inherited members like edit_original_message
in the documentation, which can lead to confusion.
Current implementation puts all invokable app commands to global dicts which isn't a correct solution.
disnake.ext.commands
The current implementation works, but it breaks if you try to initialize more than 1 Client
instance.
Store the app commands similarly to text commands by adding them to the Bot
instance.
In case of cogs, collect all invokable slash commands on cog load and add them to the Bot
instance.
Is bad
No response
I'm using the disnake.Thread
annotation in my slash command, but the conversion spits out an exception.
Reproduction steps:
1). Create a slash command that has the channels OptionType
. This option should only allow thread channel types
2). Annotate disnake.Thread
for your channel/thread parameter
3). Run the command within Discord and pass a thread to it
Traceback:
Traceback (most recent call last):
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\ext\commands\params.py", line 253, in convert_argument
return await argument
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\ext\commands\converter.py", line 608, in convert
return GuildChannelConverter._resolve_thread(ctx, argument, "threads", disnake.Thread)
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\ext\commands\converter.py", line 465, in _resolve_thread
match = IDConverter._get_id_match(argument) or re.match(r"<#([0-9]{15,20})>$", argument)
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\ext\commands\converter.py", line 145, in _get_id_match
return _ID_REGEX.match(argument)
TypeError: expected string or bytes-like object
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\ext\commands\interaction_bot_base.py", line 1296, in process_application_commands
await app_command.invoke(interaction)
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\ext\commands\slash_core.py", line 568, in invoke
kwargs = await resolve_param_kwargs(self.callback, inter, kwargs)
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\ext\commands\params.py", line 439, in resolve_param_kwargs
kwargs[param.param_name] = await param.convert_argument(inter, kwargs[param.param_name])
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\ext\commands\params.py", line 257, in convert_argument
raise errors.ConversionError(self.converter, e) from e
disnake.ext.commands.errors.ConversionError: (<bound method ThreadConverter.convert of <disnake.ext.commands.converter.ThreadConverter object at 0x000001DB827B6DF0>>, TypeError('expected string or bytes-like object'))
@commands.slash_command(
options=[
disnake.Option(
name='thread',
type=disnake.OptionType.channel,
required=True,
channel_types=[disnake.ChannelType.public_thread, disnake.ChannelType.private_thread],
),
],
)
async def test(
self,
interaction: disnake.ApplicationCommandInteraction,
ticket: disnake.Thread,
) -> None:
pass
The converter should not throw an error.
The converter throws an error.
NA
No response
Discord is rolling out scheduled events, which the library should support.
Relevant docs API PR: discord/discord-api-docs#3586
Passing a thread to a slash command will result in the bot shutting down. The cause for this is that the owner ID is missing within the payload.
Reproduction steps:
1). Create a slash command that has the channels OptionType
2). Run the command within Discord and pass a thread to it
Traceback:
Traceback (most recent call last):
File "bot.py", line 98, in <module>
libertas_support.run()
File "bot.py", line 76, in run
super().run(environ.get('TOKEN'))
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\client.py", line 795, in run
return future.result()
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\client.py", line 774, in runner
await self.start(*args, **kwargs)
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\client.py", line 738, in start
await self.connect(reconnect=reconnect)
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\client.py", line 644, in connect
await self.ws.poll_event()
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\gateway.py", line 568, in poll_event
await self.received_message(msg.data)
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\gateway.py", line 518, in received_message
func(data)
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\state.py", line 806, in parse_interaction_create
interaction = ApplicationCommandInteraction(data=data, state=self)
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\interactions\application_command.py", line 115, in __init__
self.data = ApplicationCommandInteractionData(
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\interactions\application_command.py", line 214, in __init__
self.resolved = ApplicationCommandInteractionDataResolved(
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\interactions\application_command.py", line 380, in __init__
self.channels[int(str_id)] = factory(guild=guild, state=state, data=channel) # type: ignore
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\threads.py", line 152, in __init__
self._from_data(data)
File "C:\Users\Sebastiaan\AppData\Roaming\Python\Python38\site-packages\disnake\threads.py", line 170, in _from_data
self.owner_id = int(data['owner_id'])
KeyError: 'owner_id'
@commands.slash_command(
name='test',
options=[
disnake.Option(
name='thread',
type=disnake.OptionType.channel,
required=True,
channel_types=[disnake.ChannelType.private_thread],
),
],
)
async def test(
self,
interaction: disnake.ApplicationCommandInteraction,
thread: disnake.Thread,
) -> None:
pass
I expect a thread to be returned.
The bot shuts down.
NA
No response
The library sometimes complains about deferring an interaction
When creating a slash command, using it would log an error in a console about the interaction already being responded to, or not responded to or something.
@disnake.slash_command(
name="do",
description="stuff"
)
async def doStuff(inter):
if (var):
await inter.response.send_message("Random error here.", ephemeral=True")
await inter.response.send_message("Success")
The expected result is to the slash command sending "Success"
The slash command sends "Random error here." and logs an error in the console
dinake.Intents.all()
A slash command in my discord bot throws an error on inter.response.defer()
in less than 3 seconds, so I think this isn't lag or a discord issue, and throw Unknown Interaction.
When clicking on a button, the bot will receive an unknown interaction while it has not restarted.
on_message_interaction
event and write the code to respond this inter inside the on_message_interaction
event.disnake.errors.NotFound
error.disnake.NotFound
.import disnake
from disnake.ext import commands
class Cog(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.slash_command(guild_ids=["ids"])
async def test(self, inter):
view = disnake.ui.View()
view.add_item(disnake.ui.Button(style=disnake.ButtonStyle.blurple, emoji="❤"))
await inter.response.send_message("Do you love me?", view=view)
@commands.Cog.listener()
async def on_message_interaction(self, inter):
await inter.response.send_message(f'You interacted with a component', ephemeral=True)
def setup(bot):
bot.add_cog(Cog(bot))
The inter.response.send_message
responds to the message interaction without restarting the bot.
The inter.response.send_message
doesn't respond to the message interaction without restarting the bot.
None
from that message to that message
on disnake & dislash.py (https://discord.gg/gJDbCw8aQy)
Discord is adding a new gateway event for for a member leaves a server before passing server verification, which the library should support.
Discord has marked the feature as not yet released, but it looks like bots are already receiving this gateway event.
Docs PR: discord/discord-api-docs#3871
Add PermissionsConverter to disnake/ext/commands/converter.py, so we can use disnake.Permissions as a converter in function defenitions, like disnake.Member or disnake.Channel
disnake.ext.commands
There is a code i used to implement converter for disnake.Permissions
in my bot:
def PermissionsConverter(value):
if value == None:
return discord.Permissions.none()
try:
value = int(value)
except ValueError:
pass
if isinstance(value, int):
return disnake.Permissions(permissions=value)
else:
v = value.lower()
if v == 'advanced':
return disnake.Permissions.advanced()
elif v == 'all':
return disnake.Permissions.all()
elif v == 'all_channel':
return disnake.Permissions.all_channel()
elif v == 'general':
return disnake.Permissions.general()
elif v == 'membership':
return disnake.Permissions.membership()
elif v == 'none':
return disnake.Permissions.none()
elif v == 'stage':
return disnake.Permissions.stage()
elif v == 'stage_moderator':
return disnake.Permissions.stage_moderator()
elif v == 'text':
return disnake.Permissions.text()
elif v == 'voice':
return disnake.Permissions.voice()
else:
v = v.replace(',', '')
v = v.split(' ')
P = disnake.Permissions()
for perm in v:
if perm == 'add_reactions':
P.add_reactions = True
elif perm == 'administrator':
P.administrator = True
elif perm == 'attach_files':
P.attach_files = True
elif perm == 'ban_members':
P.ban_members = True
elif perm == 'change_nickname':
P.change_nickname == True
elif perm == 'connect':
P.connect == True
elif perm == 'create_instant_invite':
P.create_instant_invite == True
elif perm == 'create_private_threads':
P.create_private_threads == True
elif perm == 'create_public_threads':
P.create_public_threads == True
elif perm == 'deafen_members':
P.deafen_members == True
elif perm == 'embed_links':
P.embed_links == True
elif perm == 'external_emojis':
P.external_emojis == True
elif perm == 'external_stickers':
P.external_stickers == True
elif perm == 'kick_members':
P.kick_members == True
elif perm == 'manage_channels':
P.manage_channels == True
elif perm == 'manage_emojis':
P.manage_emojis == True
elif perm == 'manage_emojis_and_stickers':
P.manage_emojis_and_stickers == True
elif perm == 'manage_events':
P.manage_events == True
elif perm in ['manage_guild', 'manage_server']:
P.manage_guild == True
elif perm == 'manage_messages':
P.manage_messages == True
elif perm == 'manage_nicknames':
P.manage_nicknames == True
elif perm == 'manage_permissions':
P.manage_permissions == True
elif perm == 'manage_roles':
P.manage_roles == True
elif perm == 'manage_threads':
P.manage_threads == True
elif perm == 'manage_webhooks':
P.manage_webhooks == True
elif perm == 'mention_everyone':
P.mention_everyone == True
elif perm == 'move_members':
P.move_members == True
elif perm == 'mute_members':
P.mute_members == True
elif perm == 'priority_speaker':
P.priority_speaker == True
elif perm == 'read_message_history':
P.read_message_history == True
elif perm == 'read_messages':
P.read_messages == True
elif perm == 'request_to_speak':
P.request_to_speak == True
elif perm == 'send_messages':
P.send_messages == True
elif perm == 'send_messages_in_threads':
P.send_messages_in_threads == True
elif perm == 'send_tts_messages':
P.send_tts_messages == True
elif perm == 'speak':
P.speak == True
elif perm == 'stream':
P.stream == True
elif perm == 'use_external_emojis':
P.use_external_emojis == True
elif perm == 'use_external_stickers':
P.use_external_stickers == True
elif perm == 'use_slash_commands':
P.use_slash_commands = True
elif perm == 'use_voice_activation':
P.use_voice_activation = True
elif perm == 'view_audit_log':
P.view_audit_log = True
elif perm == 'view_channel':
P.view_channel = True
elif perm == 'view_guild_insights':
P.view_guild_insights = True
else:
pass
return P
The command where I used this converter:
@bot.command(name="create role")
async def create_role(ctx, name: str, color: disnake.Color, *, permissions: PermissionsConverter = None):
pass
So, if user does not provide permssions for role, PermissionsConverter
returns disnake.Permissions.none()
. Also, if user provided 'none', PermissionsConverter
too returns disnake.Permissions.none()
.
If user provided a "keyword" string, such as advanced
or general
, PermissionsConverter
returns a special group of permissions, e.g.:
"advanced" -> return disnake.Permissions.advanced()
"general" -> return disnake.Permissions.general()
"stage_moderator" -> return disnake.Permissions.stage_moderator()
If string that user provided can be converted to int
, PermissionsConverter
returns disnake.Permissions
with value=int(string_that_user_provided)
, e.g.:
"8" -> return disnake.Permissions(value=8) # Administrator perms
"2013274160" -> return disnake.Permissions(value=2013274160) # All "manage_" permissions
"2148006976" -> return disnake.Permissions(value=2148006976) # All text permissions
If any trigger was triggered, PermissionsConverter
trying to split()
string and "extract" permissions from created list
.
Example:
# P = disnake.Permissions()
"manage_roles administrator" ->
P.manage_roles = True
P.administrator = True
return P
"view_audit_log manage_guild mention_everyone" ->
P.view_audit_log = True
P.manage_guild = True
P.mention_everyone = True
return P
Add my code to disnake/ext/commands/converter.py
:)
No response
I'm cheking that string can be converted to int
by doing so:
try:
value = int(value)
except ValueError:
pass
if isinstance(value, int):
return disnake.Permissions(value=value)
I'm used this permissions calculator.
Because many users may don't understand what means guild
, permission manage_guild
aliased as manage_server
Delayed command sync is not cancelled on termination
When shutting down the bot, the delayed_command_sync
task fails to be cancelled as it's in a pending state. Note that this occurs when no slash commands are registered.
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending name='disnake: delayed_command_sync' coro=<InteractionBotBase._delayed_command_sync() done, defined at disnake/ext/commands/interaction_bot_base.py:795> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x10af24160>()]>>
No response
There should not be unhandled errors when shutting down.
There are internal errors on shutdown.
N/A
No response
The API currently reads attachment data for interaction responses from payload["attachments"]
, which is also where we put attachment data. This, however, does not match the API documentation, which correctly specifies payload["data"]["attachments"]
; the API side of things is subject to change soon:
We recently discovered our API had a bug where attachments wasn't nested under data - our API was reading from payload_json["attachments"] instead of payload_json["data"]["attachments"]. This isn't what we have documented, and we're considering it an implementation bug (it was introduced when I shipped multi-upload support a few weeks ago).
(full quote here: https://discord.com/channels/808030843078836254/847513235536216085/922602341151162418, private channel)
disnake is affected by this change as well:
disnake/disnake/webhook/async_.py
Lines 414 to 419 in 9bb3821
Since API v10 isn't a thing yet and providing an attachments
value is hence not required, this only affects attachment descriptions and removing existing files on edit, and not plain file upload, as far as I can tell.
Coordinating this might be difficult, since there will likely be no transitional phase where both options work, so we should have a PR and a bugfix release ready - the change will happen "shortly after we come back from our break in the new year" (also taken from the quote mentioned above), which according to an announcement in games-lab will end January 3rd.
Edit: this does not in fact affect removing files on edit, since the endpoint currently doesn't even support that (see discord/discord-api-docs#3335)
Enum to be able to quickly access thread archive limits
The core library
Current usage to archive a thread requires setting the close time yourself, it would be nice to have a disnake maintained enum.
Right now, we have to pass 1440 to the archive duration manually.
a enum part of the public api somewhat like the below:
class ThreadArchive(enum.Enum):
HOUR = 60
DAY = 1440
THREE_DAY = 4320
WEEK = 10080
Current solution is defining this ourselves
No response
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.