How do I make a code that uses while loops work properly in a discord bot and not get looping error message if the user makes an input mistake?

Question:

I’ve made a program that can calculate the users age based on their birth year, month and day input. It uses a while loop for each user input and the continue command for every possible error. The code is working properly in the console but I am struggling to make it work inside a discord bot because whenever someone enters something that would warrant an error, the error keeps infinitely looping and I don’t know how to bypass that while also making the program work as intended.

Here is the full code before any alternations:

from datetime import datetime
current_time = datetime.now()

print('Welcome to the Age Calculator!nPlease enter the following information to have your age precisely calculated:n')

while True:
    try:
        year = int(input('What is your birth year?n'))
        if year < current_time.year and year >= current_time.year - 100:
            break

        else:
            print('Error: You must enter a valid year.n')
            continue

    except ValueError:
        print('Error: You must enter a whole number.nFor example: 1996n')
        continue

monthConversions = {'january': 1,'february': 2, 'march': 3, 'april': 4, 'may': 5, 'june': 6, 'july': 7, 'august': 8, 'september': 9, 'october': 10, 'november': 11, 'december': 12}

while True:
    in_str = input('What is your birth month?n')
    in_str = monthConversions.get(in_str.lower(), in_str)

    try:
        month = int(in_str)

        if month > 12 or month < 1:
            raise ValueError
        break

    except ValueError:
        print('Error: You must enter the full name of the month or a whole number from 1 to 12.n')

while True:
    try:
        day = int(input('What is your birth day?n'))
        if month in [1, 3, 5, 7, 8, 10, 12] and day < 32 and day > 0:
            break

        elif month in [4, 6, 9, 11] and day < 31 and day > 0:
            break

        elif year % 400 == 0  and month == 2 and day < 30 and day > 0:
            break

        elif year % 4 == 0 and month == 2 and day < 30 and day > 0:
            break

        elif month == 2 and day <29 and day >0:
            break

        else:
            print('Error: You must enter a valid day.')
            continue

    except ValueError:
        print('Error: You must enter a whole number.nFor example: 25')
        continue

print('nYour birth date is ' + str(day) + '.' + str(month) + '.' + str(year) + '.')

ageyear = current_time.year - int(year)

if int(month) < current_time.month:
    ageyear = current_time.year - int(year)

elif int(month) >= current_time.month:
    ageyear = current_time.year - int(year) - 1

agemonth = current_time.month - int(month) + 12

if int(month) < current_time.month:
    agemonth = current_time.month - int(month) + 12

elif int(month) > current_time.month:
    agemonth = current_time.month - int(month) + 11

ageday = current_time.day - int(day) + 31

if int(day) == 31:
    ageday = current_time.day - int(day) + 31

elif int(day) <= 30:
    ageday = current_time.day - int(day) + 30

if int(month) == current_time.month and int(day) == current_time.day:
    agemonth = 0
    ageday = 0
    ageyear = current_time.year - int(year)

elif int(month) == current_time.month and ageday < 30:
    agemonth = current_time.month - int(month) + 11

elif int(month) == current_time.month and ageday > 30:
    agemonth = 0
    ageday = current_time.day - int(day)
    ageyear = current_time.year - int(year)

print('You are ' + str(ageyear) + ' years, ' + str(agemonth) + ' months, ' + 'and ' + str(ageday) + ' days old.')

Here is the code after I’ve tried implementing it on a bot:

from datetime import datetime
import discord
from discord.ext import commands
import asyncio

current_time = datetime.now()

token = '' 
bot = commands.Bot(command_prefix='', intents=discord.Intents.all())
bot.Prefix = '!'

@bot.event
async def on_message(message):
    args = str(message.content).lower().split(' ')
    if args[0] == bot.Prefix + 'agecheck':
        year = int(args[1])
        month = int(args[2])
        day = int(args[3])
    valid = False
    while not valid:
        try:
            if year < current_time.year and year >= current_time.year - 100:
                valid = True
                break
            else:
                await message.channel.send('Error: You must enter a valid year.n')

        except ValueError:
            await message.channel.send('Error: You must enter a whole number.nFor example: 1996n')


    monthConversions = {'january': 1,'february': 2, 'march': 3, 'april': 4, 'may': 5, 'june': 6, 'july': 7, 'august': 8, 'september': 9, 'october': 10, 'november': 11, 'december': 12}

    while not valid:
        in_str = ''
        in_str = monthConversions.get(in_str.lower(), in_str)

        try:
            month = int(in_str)

            if month > 12 or month < 1:
                raise ValueError
            valid = True


        except ValueError:
            await message.channel.send('Error: You must enter the full name of the month or a whole number from 1 to 12.n')

    while True:
        try:
            if month in [1, 3, 5, 7, 8, 10, 12] and day < 32 and day > 0:
                break

            elif month in [4, 6, 9, 11] and day < 31 and day > 0:
                break

            elif year % 400 == 0  and month == 2 and day < 30 and day > 0:
                break

            elif year % 4 == 0 and month == 2 and day < 30 and day > 0:
                break

            elif month == 2 and day <29 and day >0:
                break
                valid = True

            else:
                await message.channel.send('Error: You must enter a valid day.')

        except ValueError:
            await message.channel.send('Error: You must enter a whole number.nFor example: 25')

    await message.channel.send('nYour birth date is ' + str(day) + '.' + str(month) + '.' + str(year) + '.')

    ageyear = current_time.year - int(year)

    if int(month) < current_time.month:
        ageyear = current_time.year - int(year)

    elif int(month) >= current_time.month:
        ageyear = current_time.year - int(year) - 1

    agemonth = current_time.month - int(month) + 12

    if int(month) < current_time.month:
        agemonth = current_time.month - int(month) + 12

    elif int(month) > current_time.month:
        agemonth = current_time.month - int(month) + 11

    ageday = current_time.day - int(day) + 31

    if int(day) == 31:
        ageday = current_time.day - int(day) + 31

    elif int(day) <= 30:
        ageday = current_time.day - int(day) + 30

    if int(month) == current_time.month and int(day) == current_time.day:
        agemonth = 0
        ageday = 0
        ageyear = current_time.year - int(year)

    elif int(month) == current_time.month and ageday < 30:
        agemonth = current_time.month - int(month) + 11

    elif int(month) == current_time.month and ageday > 30:
        agemonth = 0
        ageday = current_time.day - int(day)
        ageyear = current_time.year - int(year)

    await message.channel.send('You are ' + str(ageyear) + ' years, ' + str(agemonth) + ' months, ' + 'and ' + str(ageday) + ' days old.')

bot.run(token)

While it does work as intended if the user enters correct year, month and age – it starts looping the error message if the user makes any errors. I tried making every continue part of the loop be a break instead, but that did not work and it would simply let the errors pass through.

It also does not work if the user inputs the name of the month instead of the number of the month, despite that part working in the original code.

Any help/suggestions are appreciated!

Asked By: Q99

||

Answers:

Here is an example of the fixed code that checks conditions before going forward with the command to prevent any loops:

if args[0].startswith(bot.Prefix) and (args[0][len(bot.Prefix):] == 'agecalc' or args[0][len(bot.Prefix):] == 'ac'):
        year = args[1]
        month = args[2]
        day = args[3]
        year_error = False
        value_error = False
        month_error = False
while year_error == False:
    try:
        year = args[1]
        if int(year) < current_time.year and int(year) >= current_time.year - 100:
            break
        else:
            year_error = True
            value_error = True
            await message.channel.send('**Error:** This bot uses ``YYYY/MM/DD`` input system.nYou must enter a valid year in the form of a whole number.')
            break
    except ValueError:
        year_error = True
        await message.channel.send('**Error:** This bot uses ``YYYY/MM/DD`` input system.nYou must enter a valid year in the form of a whole number.n*Please correct your input and try again.*')
        break


monthConversions = {'january': 1,'february': 2, 'march': 3, 'april': 4, 'may': 5, 'june': 6, 'july': 7, 'august': 8, 'september': 9, 'october': 10, 'november': 11, 'december': 12}

global in_str
in_str = ''

while True:
    try:
        in_str = args[2]
        in_str = monthConversions.get(in_str.lower(), in_str)
        month = int(in_str)
        if 0 < month < 13:
            break
        else:
            month_error = True
            value_error = True
            await message.channel.send('**Error:** You must enter the full name of the month or a whole number from 1 to 12.n')
            break
    except ValueError:
        month_error = True
        value_error = True
        await message.channel.send('**Error:** You must enter the full name of the month or a whole number from 1 to 12.n*Please correct your input and try again.*')
        break


while month_error == False and year_error == False:
    try:
        day = args[3]
        if int(month) in [1, 3, 5, 7, 8, 10, 12] and int(day) < 32 and int(day) > 0:
            break

        elif int(month) in [4, 6, 9, 11] and int(day) < 31 and int(day) > 0:
            break

        elif int(year) % 400 == 0  and int(month) == 2 and int(day) < 30 and int(day) > 0:
            break

        elif int(year) % 4 == 0 and int(month) == 2 and int(day) < 30 and int(day) > 0:
            break

        elif int(month) == 2 and int(day) <29 and int(day) >0:
            break

        else:
            value_error = True
            await message.channel.send('**Error:** You must enter a valid day in the form of a whole number.')
            break

    except ValueError:
        value_error = True
        await message.channel.send('**Error:** You must enter a valid day in the form of a whole number.n*Please correct your input and try again.*')
        break

if int(month) == current_time.month and int(day) == current_time.day and year_error == False:
    agemonth = current_time.month - int(month)
    ageday = current_time.day - int(day)
    ageyear = current_time.year - int(year)
    await message.channel.send('https://giphy.com/gifs/moodman-happy-birthday-cat-eRXQ9JRiOHSNwVoGxt')

elif int(month) == current_time.month and int(day) > current_time.day and year_error == False:
    agemonth = current_time.month - int(month) + 12
    ageday = current_time.day - int(day) + 30
    ageyear = current_time.year - int(year) - 1

elif int(month) == current_time.month and int(day) < current_time.day and year_error == False:
    agemonth = current_time.month - int(month)
    ageday = current_time.day - int(day)
    ageyear = current_time.year - int(year)

elif int(month) > current_time.month and int(day) == current_time.day and year_error == False:
    agemonth = current_time.month + 12 - int(month)
    ageday = current_time.day - int(day)
    ageyear = current_time.year - int(year) - 1

elif int(month) > current_time.month and int(day) > current_time.day and year_error == False:
    agemonth = current_time.month + 12 - int(month) - 1
    ageday = current_time.day - int(day) + 30
    ageyear = current_time.year - int(year) - 1

elif int(month) > current_time.month and int(day) < current_time.day and year_error == False:
    agemonth = current_time.month + 12 - int(month)
    ageday = current_time.day - int(day)
    ageyear = current_time.year - int(year) - 1

elif int(month) < current_time.month and int(day) == current_time.day and year_error == False:
    agemonth = current_time.month - int(month)
    ageday = current_time.day - int(day)
    ageyear = current_time.year - int(year)

elif int(month) < current_time.month and int(day) > current_time.day and year_error == False:
    agemonth = current_time.month - int(month) + 12
    ageday = current_time.day - int(day) + 30
    ageyear = current_time.year - int(year) - 1

elif int(month) < current_time.month and int(day) < current_time.day and year_error == False:
    agemonth = current_time.month - int(month)
    ageday = current_time.day - int(day)
    ageyear = current_time.year - int(year)

if value_error == False and year_error == False:
    embed = discord.Embed(title = '**Your age has been successfully calculated!**', color = discord.Color.from_rgb(235, 219, 171))
    embed.set_thumbnail(url="https://images.vexels.com/media/users/3/143394/isolated/preview/bd28922a768d08852f3023ed90b37248-bolo-de-anivers-rio-plano-by-vexels.png")
    embed.add_field(name ='nYour birth date is:',
                    value = str(day) + '.' + str(month) + '.' + str(year) + '.n',
                    inline = True)
    embed.add_field(name='nYou are:',
                    value= str(ageyear) + ' years, ' + str(agemonth) + ' months, ' + 'and ' + str(ageday) + ' days old.',
                    inline=False)
    await message.channel.send(embed = embed)
elif value_error == True:
    await message.channel.send('*Please correct your input and try again.*')

It has also been made more intuitive and user-friendly.

Answered By: Q99