Python Forum
Input validation goes south.
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Input validation goes south.
#1
Question 
Hi,

I'm trying to validate the number of answers per question but I can't seem to get the var to change to False when the input is wrong.

what am I missing?

def get_question_score(s):

    try:
        s = int(input("Enter Question Score: "))

    except ValueError:
        print("[!]Error! Use numbers.")
        return 0

    return s


def check_sum(s):

    try:
        if sum(scores) + s > 100:
            print("Score sum is higher than 100")
            print(f"{100 - sum(scores)} left")
            score = 0
            if len(scores) != 0:
                scores.pop()
            return False

    except ValueError:
        scores_local.clear()
        print("Use Numbers.")
        return False

    scores_local.append(s)
    scores.append(s)

    return True


def get_number_of_answers(n_o_a):

    try:
        n_o_a = int(input("Number of answers (Max 4)? "))

    except ValueError:
        number_of_answers.clear()
        print("*** Please select [2-4]")
        return False

    return True


def big_small(n_o_a):

    number_of_answers.clear()

    if n_o_a < 2 or n_o_a > 4:
        number_of_answers.clear()
        return False

    else:

        number_of_answers.append(n_o_a)

        return True


def main(question, question_score, num_of_answers):

    questions = get_questions()
    question_score = get_question_score(s=0)
    if question_score == 0:
        scores.pop()
        scores_local.pop()
        question_score = get_question_score(s=0)

    score_sum = check_sum(question_score)   # Returns True/False
    num_of_answers = get_number_of_answers(n_o_a=0)
    while not num_of_answers:
        number_of_answers.clear()
        num_of_answers = get_number_of_answers(n_o_a=0)

    is_bigger = big_small(num_of_answers)   # Returns True/False
    while not is_bigger:
        print(f"Question score: {question_score}, Total Score: {sum(scores)}, Valid: {score_sum}")
        question_score = 0
        number_of_answers.clear()
        num_of_answers = False
        num_of_answers = get_number_of_answers(n_o_a=0)

    question = questions[-1]
    multiple_answers = get_answers(num_of_answers, answer="")
    right_answer_number_var = get_right_answer_number(num=0)
    answers_local.clear()
    is_right = check_right_answer_number(right_answer_number_var)

    if not is_right:
        print(f"Error! Please select [1={number_of_answers[0]}")
        right_answer_number_var = get_right_answer_number(num=0)

    while is_right:
        print("Summery will replace this line.\n")
        sure = ask_if_sure(ans="")

        while sure:
            if number_of_answers[0] < len(questions):
                lines = len(questions)
            else:
                lines = number_of_answers[0]

            answers.append(right_answer_number_var)
            ask_if_continue = ask_continue()
            if not ask_if_continue:
                finish(lines)

            while ask_if_continue:
                restart()
                break
            break
        break


if __name__ == "__main__":

    question_list = []
    scores = []
    scores_local = []
    number_of_answers = []
    answers = []
    answers_local = []
    right_answer_number = []

    main(question="", question_score=0, num_of_answers=False)
let me know if you need/want the full code.
Thanks!
Reply
#2
In get_number_of_answers, you don't do anything with that number after validating it as an int. You only return True or False. I would expect that function to instead loop on input until an int is found and then that number is returned, not true/false.
Reply
#3
Relevant excerpts:

def get_number_of_answers(n_o_a):
 
    try:
        n_o_a = int(input("Number of answers (Max 4)? "))
 
    except ValueError:
        number_of_answers.clear()
        print("*** Please select [2-4]")
        return False
 
    return True

def big_small(n_o_a):
 
    number_of_answers.clear()
 
    if n_o_a < 2 or n_o_a > 4:
        number_of_answers.clear()
        return False
 
    else:
 
        number_of_answers.append(n_o_a)
 
        return True

num_of_answers = get_number_of_answers(n_o_a=0)
is_bigger = big_small(num_of_answers)
I'm guessing this is where the problem is. get_number_of_answers return True or False, not n_o_a as you may have intended. Because you are passing True or False to big_small, the if condition in big_small never gets executed and is_bigger will always be True. You need to return n_o_a, instead of returning True at line 45.

I'm only guessing based on what I can see; a runnable code with relevant datasets will help immensely. You can check if the above hypothesis is true by printing number_of_answers list.
Reply
#4
Try to provide code that others can run. It's a little more work for you, but you are the one asking for help. Make it easy for others to help you.

Your code uses a convoluted way to do something pretty simple. Get input, validate input, return input. It should only be a few lines long. Why don't you do something simple like:
def input_number(prompt='', minv=None, maxv=None, convert=int):
    while True:  # Keep asking until you get what you want
        try:
            value = convert(input(prompt))  # Allow for int or float
            # Can have upper limit, lower limit, both or none
            if minv and minv > value:
                raise ValueError  # May as well use exceptions
            if maxv and maxv < value:
                raise ValueError
            return value  # Got an acceptable input.
        except ValueError:
            print('Input is not valid.  Try again.')

print(input_number('Enter number of answers [2-4]: ', 2, 4))
print(input_number('What is the value of pi? ', convert=float))
Write something that you can reuse. You could use something like this to get the number of answers when building the quiz and you could reuse it to get the selected answer when taking the quiz.

Finally, don't be afraid to throw out code. Most early code is rubbish as are most early designs. If you have a hard time understanding why your code doesn't work there's a good chance you don't really understand the problem. Step away from the keyboard and think about the problem you are trying to solve, not how to write the code. Solve first, then write.
palladium likes this post
Reply
#5
I love you all!

My python knowlege comes from around 2 months of course study in a class for about 8 hrs a week as a small part of larger Cyber Security course.
We didn't really went deep into it like what mindset do I need for example, so I had to invest my own personal time outside the frame to get ahead.
I'll probably have more 'dumb' or 'noob' questions so now you know why and i'm sorry in advance.
I use this forum only after i'm maxed out of answers (stackoverflow, google and others) and suprise suprise, everytime I post a question here I get to actually understand the answers!

and as for your answers, I actually DID returned n.o.a but I think that I just skipped the right outcome because I got distracted by the bug after it (lol)

i'll change the code and report back. (I work 12hrs/day so it might take some time)

thanks again and really appriciated!


here's the full code if you want to try to run it as is.

def get_questions():

    question = input("Enter your question: ")
    if len(question) == 0:
        print("No Empty Questions.")
        get_questions()

    question_list.append(question)

    return question


def get_question_score(s):

    try:
        s = int(input("Enter Question Score: "))

    except ValueError:
        print("[!]Error! Use numbers.")
        return 0

    return s


def check_sum(s):

    try:
        if sum(scores) + s > 100:
            print("Score sum is higher than 100")
            print(f"{100 - sum(scores)} left")
            score = 0
            if len(scores) != 0:
                scores.pop()
            return False

    except ValueError:
        scores_local.clear()
        print("Use Numbers.")
        return False

    scores_local.append(s)
    scores.append(s)

    return True


def get_number_of_answers(n_o_a):

    try:
        n_o_a = int(input("Number of answers (Max 4)? "))

    except ValueError:
        number_of_answers.clear()
        print("*** Please select [2-4]")
        return False

    return True


def big_small(n_o_a):

    number_of_answers.clear()

    if n_o_a < 2 or n_o_a > 4:
        number_of_answers.clear()
        return False

    else:

        number_of_answers.append(n_o_a)

        return True


def get_answers(num_of_answers, answer):

    for ans in range(number_of_answers[0]):
        answer = input(f"Answer #{ans+1}: ")    # Start indexing from 1
        if len(answer) == 0:
            print("Error! No Input!")
            get_answers(num_of_answers, answer="")

        answers_local_dictionary[ans+1] = answer
        answers_local.append(answer)
        answers.append(answer)
        answers_dict[ans+1] = answer

    return answer


def get_right_answer_number(num):

    try:
        num = int(input("Type the Right Answer Number: "))

    except ValueError:
        print("Error! Please type numbers only.")

    return num


def check_right_answer_number(num):

    if 0 < num <= number_of_answers[0]:
        return True

    else:
        return False


def ask_if_sure(ans):   # Returns True

    ask_sure = input("Are you sure? [Y/n]: ")
    if ask_sure.lower() == "n":
        number_of_answers.clear()
        check_right_answer_number(num=number_of_answers[0])

    elif ask_sure.lower() == "y":
        return True

    else:
        print("Error! Please type [Y/n]")
        ask_if_sure(ans="")


def ask_continue():

    a_continue = input("Do you wish to add more questions? [Y/n]: ")
    if a_continue.lower() == "y":
        return True

    elif a_continue.lower() == "n":
        return False

    else:
        print("Error! Please choose [Y/N]")
        ask_continue()


def restart():

    answers_local.clear()
    number_of_answers.clear()
    right_answer_number.clear()
    scores_local.clear()
    main(question="", question_score=0, num_of_answers=0)


def finish(lines):
    question_list_dup = []
    answers_dup = []
    scores_dup = []

    print("\n\n==============RESULTS==============\n")
    print("#\t Question\t Answer\t\t Score")
    number_of_questions = len(question_list)
    for num in range(number_of_questions):
        print(f"{num+1}\t {question_list[num]}\t\t {answers[num]}\t {scores[num]}")


def main(question, question_score, num_of_answers):

    questions = get_questions()
    question_score = get_question_score(s=0)
    if question_score == 0:
        scores.pop()
        scores_local.pop()
        question_score = get_question_score(s=0)

    score_sum = check_sum(question_score)   # Returns True/False
    num_of_answers = get_number_of_answers(n_o_a=0)
    while not num_of_answers:
        number_of_answers.clear()
        num_of_answers = get_number_of_answers(n_o_a=0)

    is_bigger = big_small(num_of_answers)   # Returns True/False
    while not is_bigger:
        print(num_of_answers)
        print(number_of_answers)
        print(f"Question score: {question_score}, Total Score: {sum(scores)}, Valid: {score_sum}")
        question_score = 0
        number_of_answers.clear()
        num_of_answers = False
        num_of_answers = get_number_of_answers(n_o_a=0)

    question = questions[-1]
    multiple_answers = get_answers(num_of_answers, answer="")
    right_answer_number_var = get_right_answer_number(num=0)
    answers_local.clear()
    is_right = check_right_answer_number(right_answer_number_var)

    if not is_right:
        print(f"Error! Please select [1={number_of_answers[0]}")
        right_answer_number_var = get_right_answer_number(num=0)

    while is_right:
        print("Summery will replace this line.\n")
        sure = ask_if_sure(ans="")

        while sure:
            if number_of_answers[0] < len(questions):
                lines = len(questions)
            else:
                lines = number_of_answers[0]

            answers.append(right_answer_number_var)
            ask_if_continue = ask_continue()
            if not ask_if_continue:
                finish(lines)

            while ask_if_continue:
                restart()
                break
            break
        break


if __name__ == "__main__":

    question_list = []
    scores = []
    scores_local = []
    number_of_answers = []
    answers = []
    answers_local = []
    answers_local_dictionary = {}
    right_answer_number = []

    answers_dict = {}

    main(question="", question_score=0, num_of_answers=False)
Reply
#6
# Can have upper limit, lower limit, both or none
            if minv and minv > value:
                raise ValueError  # May as well use exceptions
            if maxv and maxv < value:
                raise ValueError
            return value  # Got an acceptable input.
why did you write minv and maxv twice?
Reply
#7
Ok so I took your advise and implemented it in my code. I love it!

Don't mind the rest of the bugs I havn't got to them yet.

def get_questions():

    question = input("Enter your question: ")
    if len(question) == 0:
        print("No Empty Questions.")
        get_questions()

    question_list.append(question)

    return question


def get_question_score(s):

    try:
        s = int(input("Enter Question Score: "))
        if not float(s):
            raise ValueError

    except ValueError:
        print("[!]Error! Numbers Only.")
        if len(scores) != 0:
            scores.pop()
        get_question_score(s=0)

    return s


def check_sum(s):

    try:
        if (sum(scores) + s) > 100:
            raise ValueError

    except ValueError:
        print(f"[!]Error! {(sum(scores) + s)} > 100")
        print(f"{100 - sum(scores)} left")
        if len(scores) != 0:
            scores.pop()

        return False

    scores.append(s)
    return True


def get_number_of_answers(num=None, minv=None, maxv=None):

    print(f"Number Of Answers: {number_of_answers}")

    print(f"\tMin={minv} | Max={maxv}")

    try:
        num = int(input(f"Number of Answers [{minv}-{maxv}]: "))
        if minv and minv > num:
            print(f"[!]Error! {num} < {minv}")
            raise ValueError

        if maxv and maxv < num:
            print(f"[!]Error! {num} > {maxv}")
            raise ValueError

        return num

    except ValueError:
        print("[!]Input Not Valid")
        get_number_of_answers(num=0, minv=2, maxv=4)

    return int(num)


def get_answers(num_of_answers, answer):

    for ans in range(1, num_of_answers+1):  # Start Index from 1.
        answer = input(f"Answer #{ans}: ")
        if len(answer) == 0:
            print("Error! No Input!")
            get_answers(num_of_answers, answer="")

        answers_local.append(answer)
        answers.append(answer)

    return answer


def get_right_answer_number(num):

    try:
        num = int(input("Type the Right Answer Number: "))

    except ValueError:
        print("Error! Please type numbers only.")

    return num


def check_right_answer_number(num):

    if 0 < num <= number_of_answers:
        return True

    else:
        return False


def ask_if_sure(ans):   # Returns True

    ask_sure = input("Are you sure? [Y/n]: ")
    if ask_sure.lower() == "n":
        check_right_answer_number(num=number_of_answers)

    elif ask_sure.lower() == "y":
        return True

    else:
        print("Error! Please type [Y/n]")
        ask_if_sure(ans="")


def ask_continue():

    a_continue = input("Do you wish to add more questions? [Y/n]: ")
    if a_continue.lower() == "y":
        return True

    elif a_continue.lower() == "n":
        return False

    else:
        print("Error! Please choose [Y/N]")
        ask_continue()


def restart():

    answers_local.clear()
    right_answer_number.clear()
    scores_local.clear()
    main(question="", question_score=0, num_of_answers=0)


def finish(lines):
    question_list_dup = []
    answers_dup = []
    scores_dup = []

    print("\n\n==============RESULTS==============\n")
    print("#\t Question\t Answer\t\t Score")
    number_of_questions = len(question_list)
    for num in range(number_of_questions):
        print(f"{num+1}\t {question_list[num]}\t\t {answers[num]}\t {scores[num]}")


def main(question, question_score, num_of_answers):

    questions = get_questions()

    question_score = get_question_score(s=0)
    if question_score == 0:
        scores.pop()
        scores_local.pop()
        question_score = get_question_score(s=0)

    score_sum = check_sum(question_score)   # Returns True/False
    while score_sum:
        print(f"Question score: {question_score}, Total Score: {sum(scores)}, Valid: {score_sum}")
        num_of_answers = get_number_of_answers(num=0, minv=2, maxv=4)
        multiple_answers = get_answers(num_of_answers, answer="")
        question = questions[-1]
        right_answer_number_var = get_right_answer_number(num=0)
        answers_local.clear()
        is_right = check_right_answer_number(right_answer_number_var)

        if not is_right:
            print(f"Error! Please select 1-{number_of_answers}")
            right_answer_number_var = get_right_answer_number(num=0)

        while is_right:
            print("Summery will replace this line.\n")
            sure = ask_if_sure(ans="")

            while sure:
                if number_of_answers < len(questions):
                    lines = len(questions)
                else:
                    lines = number_of_answers

                answers.append(right_answer_number_var)
                ask_if_continue = ask_continue()
                if not ask_if_continue:
                    finish(lines)

                while ask_if_continue:
                    restart()
                    break
                break
            break
        break


if __name__ == "__main__":

    question_list = []
    scores = []
    scores_local = []
    number_of_answers = 0
    answers = []
    answers_local = []
    right_answer_number = []

    main(question="", question_score=0, num_of_answers=0)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  input data validation plumberpy 2 1,775 Aug-11-2021, 12:04 PM
Last Post: plumberpy
  Regex Subdomain Validation & Input website manual rtzki 1 3,235 Sep-16-2018, 03:10 PM
Last Post: ichabod801

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020