user16592406
user16592406

Reputation:

Command raised an exception: AttributeError: 'Context' object has no attribute 'id' discord.py

I want to delete the Guild ID in a JSON file with an Command.

This is my code:

 @welcome.command(pass_context=True)
    @commands.has_permissions(administrator=True)
    async def reset(guild):
        with open('welcome.json', 'r') as f:
            welcome = json.load(f)
    
        welcome.pop(str(guild.id))
        with open('welcome.json', 'w',) as f:
            json.dump(welcomereset, f, indent=4)

This is the Error Message: discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'Context' object has no attribute 'id'

How can i fix this?

Upvotes: 1

Views: 1340

Answers (3)

Nir Deri
Nir Deri

Reputation: 26

 @welcome.command() #pass_context is deprecated, every command will always get passes Context as first param.
 @commands.has_permissions(administrator=True)
 async def reset(ctx: commands.Context): #Just normal typehint for you to easily understand.
        with open('welcome.json', 'r') as f:
            welcome = json.load(f)
    
        welcome.pop(str(ctx.guild.id)) #ctx.guild -> discord.Guild and than .id for it's id. I would put an if statement to check if the command was even in a guild, so NoneType attribute error won't raise.
        with open('welcome.json', 'w',) as f:
            json.dump(welcomereset, f, indent=4)

The first parameter in each command is ctx or context the represents discord.ext.commands.Context object, which as you can see, doesn't have id. If you are trying to get the guild id of where the command was invoked, doing ctx.guild will return Optional[discord.Guild](if command was invoked in a private channel). And than if it is not None, you can do ctx.guild.id, which is probably what you want. And you no longer need pass_context(which was used to pass discord.ext.commands.Context btw). Which means the right now, guild is your Context object.

Upvotes: 1

AkshuAgarwal
AkshuAgarwal

Reputation: 1

Since you didn't mentioned your discord.py version, I assume:

- It's before version 1.0:

You have pass_context=True, so Context will be passed as the first argument in the function.

async def reset(guild): # The word 'guild' is actually a Context object

The name guild is defined as Context so regardless of the name, it follows the properties of Context and not a Guild. Therefore you can still use guild and follow properties of Context but it's recommended to edit guild to context or ctx to prevent confusion.

You can also just do pass_context=False and make the guild argument to be accepted as an input via the user.

- It's after version 1.0:

The pass_context parameter is removed since then, so regardless if you use this or not, Context is always passed.

As above, you need to follow the properties of Context and use proper attributes. In your case, if you need to access id of the guild the command is invoked, you can do ctx.guild.id (ctx refers to Context object passed).

async def reset(ctx):
    ...
    welcome.pop(str(ctx.guild.id))
    ...

and this will work fine.

P.S.: I'm not sure but by looking at the code, I think you have passed wrong argument (welcomereset) in the .dump() and want to pass welcome instead. Ignore this if I'm wrong :P

Upvotes: 0

Nir Deri
Nir Deri

Reputation: 26

The first parameter in each command is ctx or context the represents discord.ext.commands.Context object, which as you can see, doesn't have id. If you are trying to get the guild id of where the command was invoked, doing ctx.guild will return Optional[discord.Guild](if command was invoked in a private channel). And than if it is not None, you can do ctx.guild.id, which is probably what you want. And you no longer need pass_context(which was used to pass discord.ext.commands.Context btw)

Upvotes: 0

Related Questions