In discord.py 1.0.1 (Only version Repl.it has), the cogs are giving me a hard time.
import discord
from discord.ext import commands
class Coding(commands, Cog):
def __init__(self, client):
self.client = client
#commands.Cog.listener()
async def on_ready(self):
print("Kahoot Bot 0.1 ALPHA")
client.remove_command("help")
#commands.command()
async def clear(self, ctx, amount = 5):
await ctx.channel.purge(limit = amount + 1)
#commands.command()
async def ping(self, ctx):
await ctx.send(f"Pong! {round(client.latency * 1000)}ms.")
#client.command(pass_context = True, aliases = ["print"])
async def printing(ctx, *, what_to_print):
await ctx.send(what_to_print)
print(what_to_print)
def setup(client):
client.add_cog(Coding(client))
The gist of the errors is:
A) client is not defined
B) init() should return None, not coroutine
I've tried changing all my code to bot and back to client, but nothing's helped. No idea what's going on.
You do the inheritance wrong. You dont inherit from class: "commands" and "Cog". You inherit from class: "commands.Cog". thus changing: class Coding(commands, Cog): to class Coding(commands.Cog): will fix some of the errors.
You also do the following wrong (the "client does not exist" error):
#commands.Cog.listener()
async def on_ready(self):
print("Kahoot Bot 0.1 ALPHA")
client.remove_command("help") # this line
When we want to access a class variable we use self. in the beginning of that variable to indicate that we are using the class variable. This case you dont use self.client. but client.
As client is not defined in that function it will give an error. But it is defined as a class variable (the "init" function). To access it use: self.client.
Related
I'm trying to make a discord.py bot with the help of nextcord and i've come far enough to make the code work in theory but nothing happens when i try to kick / ban, it just throws an
nextcord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'Context' object has no attribute 'ban'
and i have no idea why it does so, i want it to work as inteded.
Note, the command(s) are class commands so the main bot loads in the command from another file.
Main Bot Script
# import nextcord
from nextcord.ext import commands
# import asyncio
import json
# Import all of the commands
from cogs.ban import ban
from cogs.hello import hello
from cogs.help import help
from cogs.info import info
from cogs.kick import kick
from cogs.test import test
#Define bot prefix and also remove the help command built in.
bot = commands.Bot(command_prefix=json.load(open("config.json"))["prefix"])
bot.remove_command("help")
#bot.event
async def on_ready():
print(f'Logged in as {bot.user}')
bot.add_cog(hello(bot))
bot.add_cog(help(bot))
bot.add_cog(info(bot))
bot.add_cog(test(bot))
bot.add_cog(ban(bot))
bot.add_cog(kick(bot))
bot.run(json.load(open("config.json"))["token"])
Problematic command
import discord
from nextcord.ext import commands
from nextcord.ext.commands import has_permissions, CheckFailure
bot = commands.bot
class ban(commands.Cog):
def __init__(self, client):
self.client = client
self._last_member = None
#commands.Cog.listener()
async def on_ready(self):
print('ban Cog Ready')
#commands.command()
#has_permissions(ban_members=True)
async def ban(ctx, user: discord.Member = None, *, Reason = None):
if user == None:
await ctx.send("Could you please enter a valid user?")
return
try:
await user.ban(reason=Reason)
await ctx.send(f'**{0}** has been banned.'.format(str(user)))
except Exception as error:
if isinstance(error, CheckFailure):
await ctx.send("Looks like you don't have the permissions to use this command.")
else:
await ctx.send(error)
You are doing:
user: discord.Member
You need to use nextcord instead.
user: nextcord.Member
#commands.command()
#has_permissions(ban_members=True)
async def ban(ctx, user: nextcord.Member = None, *, Reason = None):#
#The rest of your code here
You can do the following
For Normal bot
#client.command(name="ban", aliases=["modbancmd"], description="Bans the mentioned user.")
#commands.has_permissions(ban_members=True)
async def ban(self, ctx, member: nextcord.Member, *, reason=None):
# Code for embed (optional)
await member.ban(reason=reason)
# (optional) await ctx.send(embed=banembed)
You can do the following
For Cogs
#commands.command(name="ban", aliases=["modbancmd"], description="Bans the mentioned user.")
#commands.has_permissions(ban_members=True)
async def ban(self, ctx, member: nextcord.Member, *, reason=None):
# Code for embed (optional)
await member.ban(reason=reason)
# (optional) await ctx.send(embed=banembed)
Well, here are the problems:
Your command is in a cog therefore you need to say (self, ctx, and so on)
You need to change the discord to nextcord
You should change the commands.bot to commands.Bot()
And if I'm correct, you should change the self.client to self.bot since your commands.Bot() is defined as bot
And uhh yeah it should work perfectly after you fix those.
I want to change the presence when a user executes a command.
I have the Discord bot in an own Class. To change the presence I need the self argument.
But when I write
#bot.command()
async def change(self, ctx):
await self.client.change_presence(activity=discord.Game("P-Hub"))
I get the Error:
discord.ext.commands.errors.MissingRequiredArgument: ctx is a required argument that is missing.
And when I write:
#bot.command()
async def change(ctx, self):
await self.client.change_presence(activity=discord.Game("P-Hub"))
I get this error:
discord.ext.commands.errors.MissingRequiredArgument: self is a required argument that is missing.
The whole code is:
class DiscordBot():
def __init__(self, client, token):
self.client = client
self.token = token
def run(self):
self.client.run(self.token)
#bot.command()
async def change(ctx, self):
await self.client.change_presence(activity=discord.Game("P-Hub"))
#bot.event
async def on_ready():
print("My Ready is Body")
#bot.listen()
async def on_message(message):
print(str(message.author) + ": " + message.content)
if __name__ == '__main__':
client = DiscordBot(bot, 'token')
client.run()
Does anyone have a solution?
Why do you put it in a class? It works fine when you leave it like the examples. If it's about running 2 bots in the same script then using this question will help you.
#bot.event
async def on_ready():
print("My Ready is Body")
#bot.command()
async def change(ctx):
await self.client.change_presence(activity=discord.Game("P-Hub"))
bot.run('token')
If you need to use multiple files, have a look at cogs.
i tried to make cog for organize my bot but i have an error that i dont find how to fix. The bot successful find command in cog but when i write the command i have this error:
Could you help me pls ? Here is my code:
import discord
import asyncio
import re
import os
import random
from discord.ext import commands
class Moderation(commands.Cog):
def __init__(self, bot):
self.bot = bot
#Purge
#commands.command()
async def purge(ctx, amount=10):
await ctx.channel.purge(limit=amount)
Your first parameter must be self.
class Moderation(commands.Cog):
def __init__(self, bot):
self.bot = bot
#Purge
#commands.command()
async def purge(self, ctx, amount=10):
await ctx.channel.purge(limit=amount)
Add self as parameter in purge function.
async def purge(self,ctx,amount=10):
await ctx.channel.purge(limit=amount)
I am trying to make a class, that will be eventually turned into a library. To do this, I am trying to do something like what discord.py made, and the idea comes from it.
The code that discord makes is:
#bot.event
async def on_ready():
print('discord bot is ready')
Where the '#bot' is just an object that I created before by doing
bot = discord()
And the '.event' is a preprogramed and ready to use method.
on_ready() is a function that is called already.
I want to have a way to create this from my own class, and from there mannage the entire code using async functions.
How to do it in my own code?
You need to implement a class whose public methods are decorators. For example, this class implements a scheduler that exposes scheduling through a decorator:
class Scheduler:
def __init__(self):
self._torun = []
def every_second(self, fn):
self._torun.append(fn)
async def _main(self):
while True:
for fn in self._torun:
asyncio.create_task(fn())
await asyncio.sleep(1)
def run(self):
asyncio.run(self._main())
You'd use it like this:
sched = Scheduler()
#sched.every_second
async def hello():
print('hello')
#sched.every_second
async def world():
print('world')
sched.run()
The class mimics discord in that it has a run method that calls asyncio.run for you. I would prefer to expose an async main instead, so the user can call asyncio.run(bot.main()) and have control over which event loop is used. But the example follows discord's convention, to make the API more familiar to users of discord.py.
I'm trying to write tests for a method that uses "async with" statements (in this case, aioredis's connection pool), i want to mock the connection to redis, but i'm having trouble figuring out how.
Here's what i have so far:
from asyncio import Future
from unittest.mock import MagicMock
import pytest
# The thing i'm trying to test
async def set_value(redis, value):
# Do things
async with redis.get() as conn:
await conn.set("key", value)
#My Mock classes
class MockRedis():
def get(self):
return MockAsyncPool()
class MockAsyncPool(MagicMock):
async def __aenter__(self):
conn = MagicMock()
f = Future()
f.set_result(True)
conn.set = MagicMock(return_value=f)
return conn
def __aexit__(self, exc_type, exc_val, exc_tb):
pass
# The actual test
#pytest.mark.asyncio
async def test_get_token():
redis = MockRedis()
token = await set_value(redis, 'something')
assert token is not None
I run it with:
py.test path/to/file.py
And i'm getting this error:
> await conn.set("key", value)
E TypeError: object NoneType can't be used in 'await' expression
__aexit__ needs to also be asyncronous (needs to return an awaitable):
async def __aexit__(self, exc_type, exc_val, exc_tb):
pass
Without being async it is returning None instead of a coroutine so it raises an error, as for the very misleading error message I have created this issue to point out that the error message could be greatly improved.