Does not work Context Menus in cog - Discord.py - discord.py

I wanted to create a context menu in my bot. For example, he took the documentation code.
#app_commands.context_menu(name='react')
async def react_(self, interaction: discord.Interaction, message: discord.Message):
await interaction.response.send_message('Very cool message!', ephemeral=True)
But when the code was launched in the console, the following error appeared:TypeError: context menus cannot be defined inside a class. How can I fix this?

You cannot use the decorator to create a context menu in Cogs, as explained by Danny here.
The quick way to create them in cogs is to create them by using the app_commands.ContextMenu class. Like so:
class MyCog(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
self.ctx_menu = app_commands.ContextMenu(
name='Cool Command Name',
callback=self.my_cool_context_menu, # set the callback of the context menu to "my_cool_context_menu"
)
self.bot.tree.add_command(self.ctx_menu) # add the context menu to the tree
async def my_cool_context_menu(self, interaction, message):
...
You can check out Danny's explanation for more information.

Related

'AsyncTeleBot' object has no attribute 'register_next_step_handler'

Trying to create simple ask, answer, remember telegram bot with pyTelegramBot.
Everything were normal, when TeleBot were used. TeleBot.register_next_message_handler helped me a lot.
Example:
...
#bot.message_handler(func=lambda msg: msg.text is not None and '/start' in msg.text)
def send_welcome(msg):
global cur_user
cur_user = msg.from_user.id
keyboard = types.InlineKeyboardMarkup()
keyboard.add(types.InlineKeyboardButton('Да', callback_data='old'),
types.InlineKeyboardButton('Нет', callback_data='new'))
keyboard.add(types.InlineKeyboardButton('Пора остановиться', callback_data='stop_bot'))
greet = 'Бла...бла...бла\nМы знакомы?'
bot.send_message(msg.chat.id, greet, reply_markup=keyboard)
...
#bot.callback_query_handler(func=lambda call: True)
def query_processing(call):
global user
global cur_user
if call.data == 'new':
user = dict.fromkeys(user, None)
nxt = bot.send_message(call.message.chat.id, 'Как звать?')
bot.register_next_step_handler(nxt, get_name_ask_goal)
...
Still I need my bot to be asynchronous because of sleep time till message to be send from bot and with simultaneous possibility for user to send messages.
Tried to use AsyncTeleBot, but there is no register_next_step_handler function. I did't find out how to make bot wait user for the name typing and it is almost impossible to me to add register_next_step_handler function into particular files. Although found issue in gitHub and no solution from 2017.
Tried
...
bot = AsyncTeleBot(os.getenv('token2'))
...
async def beep(chat_id) -> None:
"""Send the beep message."""
await bot.send_message(chat_id, text='Beep!')
aioschedule.clear(chat_id)
async def scheduler():
global chat_id
aioschedule.every(5).seconds.do(beep, chat_id).tag(chat_id)
while True:
await aioschedule.run_pending()
await asyncio.sleep(1)
async def main():
await asyncio.gather(scheduler(), bot.polling(non_stop=True))
if __name__ == "__main__":
asyncio.run(main(), debug=True)
...
Result:
TypeError: An asyncio.Future, a coroutine or an awaitable is required
I'm wondering:
is there other appropriate libraries for my task?
is there any simple solution to save user's message?
is it possible to use asyncio with TeleBot that made Thread-style?
Hoping for any help.

How to add Select Table to the response?

How can I add a select option to the bot's response so when I select one, it edits the message with another content?
Please help me. I do not have a example code just to add this to.
Those select menus or dropdowns are available in discord.py 2.0
Example
import discord
from discord import commands, ui
class Dropdown(ui.Select):
def __init__(self):
# The options which can be chosen inside the dropdown
options = [
discord.SelectOption(label="Moderation", description="Shows all moderation commands", emoji="🚨"),
discord.SelectOption(label="Config", description="Shows all config commands", emoji="⚙️"),
discord.SelectOption(label="Games", description="Shows all meme commands", emoji="🎮")
]
# placeholder: Will be shown when no option is chosen
# options: The dropdown options which can be chosen
# min_values, max_values: Indicates that only one of the three options can be picked
super().__init__(placeholder="Choose a section", options=options, min_values=1, max_values=1)
async def callback(self, interaction: discord.Interaction):
# This function is called when the user has chosen an option
# With the interaction parameter, you can send a response message.
# With self.values you get a list of the user's selected options. We only want the first one.
await interaction.response.send_message(f"You've chosen {self.values[0]}")
#bot.command()
async def dropdown(ctx: commands.Context):
# Create a view
view = ui.View()
# Add the dropdown to this view
view.add_item(Dropdown())
# Send a message containing the view
await ctx.send(f"**Dropdown**", view=view)
If you want to disable the ui.Select you can do that with the disabled kwarg. See more in the docs.
References:
ui.Select
ui.View
discord.SelectOption
discord.Interaction

SelectMenu keeping selection after message edit

This is using the discord.py 2.0 alpha SelectMenu. After editing the original message the selections clears any idea on how to keep the selection after the edit?
I think this is how it should be done but I can't implement that in-code:
Create a variable that stores play_status_view()
Save the user choice within the object
Use the new object when editing
class play_status_view(discord.ui.View):
def __init__(self):
super().__init__(timeout=None)
#discord.ui.select(custom_id="squad_play_status", placeholder="Signup status",
min_values=1, max_values=1,
options=[discord.SelectOption(label="A"),
discord.SelectOption(label="B"),
discord.SelectOption(label="C")])
async def signup_callback(self, select: discord.ui.select, interaction: discord.Interaction):
print(select.values[0])
await interaction.response.edit_message(embed=discord.Embed(title='Test'))
# or
await interaction.response.edit_message(embed=discord.Embed(title='Test'), view=self)

discord.py rewrite/delete standard help command

I want to make a custom !help command but I have to disable the standard one first. When I do:
client = commands.Bot(command_prefix='!')
client.remove_command('help')
Or
client = commands.Bot(command_prefix='!', help_command=None)
It still shows this message:
[1]: https://i.stack.imgur.com/Ut9dO.png
Anyone how to delete it?
A better way of making a help command is by using groups.
Firstly remove the default command;
client.remove_command("help")
After that make a help command by using this method:
#client.group(invoke_without_command= True)
async def help(ctx):
# insert your help command embed or message here
embed= discord.Embed(title="Help", description="List of commands")
embed.add_field(name="Moderation", value="!help moderation")
embed.add_field(name="Misc", value="!help misc")
await ctx.send(embed=embed)
You are done with the help command, now when you have to make help for a category or command. You can do it like this:
#help.command()
async def moderation(ctx):
embed= discord.Embed(title="Moderation", description="List of Moderation commands")
embed.add_field(name="Commands", value="ban, kick, warn, mute, unban")
await ctx.send(embed=embed)
Now if user will type, !help moderation the above embed/message will be sent.
With the recent changes in discord.py-rewrite you do not need to delete the standard help command to create your own help command. To achieve what you want you will need to subclass HelpCommand or MinimalHelpCommand, then pass it to bot.help_command.
The following code shows the standard way of subclassing MinimalHelpCommand:
class MyHelpCommand(commands.MinimalHelpCommand):
def get_command_signature(self, command):
return '{0.clean_prefix}{1.qualified_name} {1.signature}'.format(self, command)
class MyCog(commands.Cog):
def __init__(self, bot):
self._original_help_command = bot.help_command
bot.help_command = MyHelpCommand()
bot.help_command.cog = self
def cog_unload(self):
self.bot.help_command = self._original_help_command
Following the code above you will get the behaviour that you want to achieve, but if you still want to disable the default help command for any reasons, nowadays you can do it passing None to the help_command kwarg.
For more info, discord.py documentation:
https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#help-commands

how to test event in discord.py

lets say on_member_join event
#commands.Cog.listener()
async def on_member_join(self, member):
# On member joins we find a channel called general and if it exists,
# send an embed welcoming them to our guild
channel = discord.utils.get(member.guild.text_channels, name="welcome")
if channel:
embed = discord.Embed(
description="Welcome to our guild!",
color=random.choice(self.bot.color_list),
)
embed.set_thumbnail(url=member.avatar_url)
embed.set_author(name=member.name, icon_url=member.avatar_url)
embed.set_footer(text=member.guild, icon_url=member.guild.icon_url)
embed.timestamp = datetime.datetime.utcnow()
await channel.send(embed=embed)
This is my event (I know it works) how can I test it in any way to execute command to emit the event (not manually by adding and removing someone)?
[something like .emit on_member_join #user where arg1 is event and if needed arg2 is mention or id of channel ]
Any command for that ?
something like Discord.js: Manually triggering events but in discord.py not in JavaScript
Currently there isn't official support in the discord.py api to do something like that but you can always make a command in the cog like follows:
#commands.command()
async def test_join(self, ctx, member: discord.Member):
await self.on_member_join(member)
Technically there is a way to probably do it that isn't documented...
Line 131 in here. I will not offer addition support for that because it isn't documented.

Resources