Search code examples
pythondiscorddiscord.pybots

How to take an input while using a command in discord.py


So I want to make a program that permits members by giving them roles for some amount of time

This is my current code

PLEASE NOTE I HAVE GOT THE SOLUTION THANKS TO @curlybracesenjoyer AND IF YOU ARE LOOKING FOR THE CODE SCROLL DOWN AND SEE THE NEW CODE .....TY


**OLD CODE**
**FOR NEW CODE PLEASE SEE THE ANSWERS WHERE I HAVE POSTED THE ANSWER MYSELF**
import discord
import os
import time
from discord.ext import commands
from discord.ext.commands import Bot
from discord.utils import get

x=0.0#want to use it for float input
y=0.0#want to covert x from hours to seconds

bot = commands.Bot(command_prefix=";")

@bot.command('role')
@commands.has_permissions(administrator=True) #permissions
async def role(ctx, user : discord.Member, *, role : discord.Role):
  if role.position > ctx.author.top_role.position: #if the role is above users top role it sends error
    return await ctx.send('**:x: | That role is above your top role!**') 
  await ctx.channel.send('Enter time in hours')
  #problem 
  #i want to take in x as float input
  #and i want to convert x into seconds and store into y
  await user.add_roles(role) #adds role if not already has it
  await ctx.send(f"Added {role} to {user.mention}") 
  time.sleep()#i want to use y here
  await user.remove_roles(role) #removes the role if user already has
  await ctx.send(f"Removed {role} from {user.mention}") 

bot.run(os.getenv('TOKEN'))

Solution

  • Before moving on the answer, I wanted to mention a few things :

    1. We could be using variables attached to bot (instance) so we don't have to use global which is considered a bad practice
    2. We should be using more verbose variable names than x and y
    3. Just having a sleep is very bad, because it is blocking the entire functioning of the bot

    In asynchronous programming, a blocking call is essentially all the parts of the function that are not await. Do not despair, however, because not all forms of blocking are bad! Using blocking calls is inevitable, but you must work to make sure that you don’t excessively block functions. Remember, if you block for too long then your bot will freeze since it has not stopped the function’s execution at that point to do other things.

    A common source of blocking for too long is something like time.sleep(). Don’t do that. Use asyncio.sleep() instead. Similar to this example:

    # bad
    time.sleep(10)
    
    # good
    await asyncio.sleep(10)
    

    Just waiting for a timing to end is also a bad idea because of how volatile it is, say if you're bot goes offline then the user gets to keep that role forever.
    Don't worry too much, you can fix some of those later.

    Answer :

    To get an floating point number from the same user that has invoked the command, this has to be done :

    @bot.command()
    async def foo(ctx):
        def check(m):
            if m.author == ctx.author and m.channel == ctx.channel:
                try:
                    float(m.content)
                    return True
                except ValueError:
                    return False
            return False
    
        await ctx.send("Tell me the hours")
        res = await bot.wait_for("message", check=check)
        bot.seconds = float(res.content) * 3600
        await ctx.send(f"The seconds are {bot.seconds}")
        # This bot.seconds can be accessed in everywhere
    

    result