(discord.py) functions in a cog - python

I've been trying to develop a discord bot in python, and I want to make a bunch of "hidden" commands that don't show up in help. I want to make it so that whenever someone activates a hidden command, the bot sends them a pm. I tried to make a function to do it, but so far it doesn't work. Here is the code in the cog file:
import discord
from discord.ext import commands
class Hidden(commands.Cog):
def __init__(self, client):
self.client = client
def hidden_message(ctx):
ctx.author.send('You have found one of several hidden commands! :shushing_face:\nCan you find them all? :thinking:')
#commands.command()
async def example(self, ctx):
await ctx.send('yes')
hidden_message(ctx)
def setup(client):
client.add_cog(Hidden(client))
When the example command is run, the bot responds normally, but the function isn't called. There are no error messages in the console. I'm still pretty new to python so could someone tell me what I'm doing wrong?

You need to use await when calling async functions like ctx.author.send, and so the function you're wrapping that with needs to be async too
async def hidden_message(self, ctx):
await ctx.author.send('You have found one of several hidden commands! :shushing_face:\nCan you find them all? :thinking:')
And then
#commands.command()
async def example(self, ctx):
await ctx.send('yes')
await self.hidden_message(ctx)
Finally, to make a command hidden from the default help command, you can do
#commands.command(hidden=True)

In order to send a message, hidden_message would have to be a courotine, i.e. it uses async def instead of just def.
However, there is a second issue that arises because of how hidden_message is called. Calling hidden_message as hidden_message(ctx) would require the function to be defined in the global scope. Since it is a method of class Hidden, it needs to be called as such.
Highlighting the edits:
class Hidden(commands.Cog):
...
async def hidden_message(self, ctx):
...
#commands.command()
async def example(self, ctx):
await ctx.send("yes")
await self.hidden_message(ctx)

Related

discord py how to create function

how to create a function that gives a role and calls it.
I need a function that give a role and how to call it
I try to
async def test():
await bot.get_channel(870197219192614943).send('test')
and
asyncio.run(test())
but it's no working
Refer to the docs to learn how to use discord.py.
U need to use this:
#bot.command()
async def test(ctx):
await bot.get_channel(870197219192614943).send('Hello, World!')
Now if you send a test message with the bot prefix at the beginning to the guild chat, where there is a bot message, you will receive a response to the channel with this id
Just name the function differently if I understand you correctly
async def name_():
pass
async def name():
pass

Discord bot with discord.py

The context is that I want to make a discord bot with discord.py and when reading its documentation, it says that I can put attributes to the classes, but I don't know where to put them.
class discord.ext.commands.Command(func, **kwargs)
#discord.ext.commands.command(name=..., cls=..., **attrs)
If I put !test_1 hello world it returns only hello, but if I put !test_1 "hello world" it returns hello world.
the !test_2 command makes it so that there is no need to use quotes so !test_2 this is an example returns this is an example.
According to the documentation, with the rest_is_raw attribute I can make test_2 behave like test_1 and take only the first argument.
So my problem is that I don't know where to place the attribute.
My code:
`
import discord
from discord.ext import commands
bot = commands.Bot(command_prefix= '!', intents=discord.Intents.all())
# Example command 1
#bot.command()
async def test_1(ctx, arg):
await ctx.send(arg)
# Example command 2
#bot.command()
async def test_2(ctx, *, arg):
await ctx.send(arg)
#Ping-pong
#bot.command()
async def ping(ctx):
await ctx.send('pong')
#bot.event
async def on_ready():
await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name="!help"))
print('My bot is ready')
bot.run('mytokenissecret')
`
I tried to understand the documentation, and I put the attribute where I thought it would work, but no attempt worked.
I searched for videos but none answered my problem.
Documentation really helps you to find out what's argument used for your command. In your case test_1(ctx, arg) and test_2(ctx, *, arg) are completely different. Because, in test_2 you passing whatever you type and send in Discord. Using * make you passing all argument. Normally if there's no *, 1 argument only can accept 1 word. By using *, it can accept all of the words/sentence that you send in

Python Discord Bot: How to imitate an action from an event listener "on_guild_join" to a command "refresh"

I am creating a simple discord bot game. My on_guild_join function looks like this:
class BotEvents(commands.Cog):
#commands.Cog.listener()
async def on_guild_join(self, guild):
do something
Now, I want to add a command refresh which will do a similar action with the on_guild_join
class BotActionCommands(commands.Cog):
#commands.command()
async def refresh(self, ctx):
do same thing with on_guild_join
On my current code, i just copied everything and replaced guild with ctx.guild, but i'm wondering if there are better ways to do it. Maybe call the on_guild_join function inside the refresh command? But I don't know how.

Is there a way to run a function right after the __init__ of a class?

class SomeClass(commands.Cog):
def __init__(self, bot):
self.bot = bot
## Do something
print('LOADED')
#__init__.after_invoke #<-- Right here
async def after_init(self, ctx):
print('After')
I don't know how to do it, I tried many things but I can't really pick the __init__ like a function to do something like that
EDIT1:
What I want is an async method that is called because I'd like to interact with messages on discord right after the launch of the program
A decorator might be an overkill here. You can just call the method in __init__:
class SomeClass(commands.Cog):
def __init__(self, bot):
self.bot = bot
print('LOADED')
self.after_init(wherever_ctx_comes_from)
def after_init(self, ctx):
print('After')
If you want to start executing Discord operations as soon as possible, you should add an on_ready event listener to your cog. When your bot logs into Discord and has prepared its internal caches, it will execute that event:
class SomeClass(commands.Cog):
def __init__(self, bot):
self.bot = bot
#commands.Cog.listener()
async def on_ready(self):
print("ONLINE")
await some_coroutine()
Note that this may not be a perfect fit: if your bot has to reconnect for some reason, it will consider this a new session and execute on_ready again. It would be pretty simple to add a variable to your cog to prevent this.
You can similarly add an on_message event, commands, etc. just as you would a normal discord.py bot

How to call async function for discord bot

I have a (working) command that reads a file from my hard drive and plays it through my discord bot that reads:
#client.command(pass_context=True)
async def fp(ctx, file):
where file is the name of the item from a list. As some commands are used more often, I was wondering how I would go about referencing this function in another for the more common commands. Something along the lines of:
#client.command(pass_context=True)
async def crab(ctx):
client.commands.fp(ctx, "crab")
but I can't get this working after much tinkering. Any help is appreciated!
You can use the .invoke function like Patrick mentioned
#bot.command()
async def crab(ctx):
await fp.invoke(ctx, "crab")
or use a .callback function
#bot.command()
async def fp(ctx, file):
// do something.
bot.command(name="crab")(fp.callback)

Categories

Resources