How to get User object from id discord.py

Viewed 561

I have a bot that sends dm pings to a user whos Id is given as a parameter in a command.
This is the command:.spam ID #_OF_PINGS
I run into the following error:

Ignoring exception in command spam:
Traceback (most recent call last):
File "/app/.heroku/python/lib/python3.6/site-packages/discord/ext/commands/core.py", line 85, in wrapped
ret = await coro(*args, **kwargs)
File "bot.py", line 16, in spam
     await ctx.send(f'Started pinging {user.name} {num} times.')
AttributeError: 'NoneType' object has no attribute 'name'

The above exception was the direct cause of the following exception:
Traceback (most recent call last):
   File "/app/.heroku/python/lib/python3.6/site-packages/discord/ext/commands/bot.py", line 903, in invoke
     await ctx.command.invoke(ctx)
   File "/app/.heroku/python/lib/python3.6/site-packages/discord/ext/commands/core.py", line 859, in invoke
     await injected(*ctx.args, **ctx.kwargs)
    File "/app/.heroku/python/lib/python3.6/site-packages/discord/ext/commands/core.py", line 94, in wrapped
     raise CommandInvokeError(exc) from exc
     discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'NoneType' object has no attribute 'name'

Here is my code:

from discord.ext import commands
token = 'MyBotTokenHere'
prefix = '.'
client = commands.Bot(command_prefix=prefix)
client.remove_command("help")


@client.event
async def on_ready():
    print('Ready')


@client.command()
async def spam(ctx, id1: int, num: int):
    user = client.get_user(id1)
    await ctx.send(f'Started pinging {user.name} {num} times.')
    for i in range(num):
        await user.send(f'<@{str(id1)}>')
    await ctx.send(f'Finished {num} pings for {user.name}')


client.run(token)

It was working fine yesterday, but today, it broke down for some reason. How do I fix it?
P.S. I hosted it on Heroku

1 Answers

You can use a converter for this:

@client.command()
async def spam(ctx, user: discord.User, num: int):
    await ctx.send(f'Started pinging {user.name} {num} times.')
    for i in range(num):
        await user.send(f'<@{str(id1)}>')
    await ctx.send(f'Finished {num} pings for {user.name}')

This way, Discord will automatically try to get the discord.User instance that corresponds to the id that you pass as an argument, and you can also @mention someone if you want to & it'll still work.

Also, starting from Discord 1.5.0, you now need to pass in intents when initializing a bot, which you clearly aren't doing yet. Update your Discord, and use the following to initialize your bot:

intents = discord.Intents.default()
intents.members = True
client = commands.Bot(command_prefix=prefix, intents=intents)

More info on the how's and why's of intents in the relevant API documentation. You'll also want to enable members on your bot's Privileged Intents page, which is explained in the linked API docs as well.

Related