-2
import random
import sys
import shelve

def get_input_or_quit(prompt, quit="Q"):
    prompt += " (Press '{}' to exit) : ".format(quit)
    val = input(prompt).strip()
    if val.upper() == quit:
        sys.exit("Goodbye")
    return val

def prompt_bool(prompt):
    while True:
        val = get_input_or_quit(prompt).lower()
        if val == 'yes':
          return True
        elif val == 'no':
          return False
        else:
         print ("Invalid input '{}', please try again".format(val))


def prompt_int_small(prompt='', choices=(1,2)):
    while True:
        val = get_input_or_quit(prompt)
        try:
            val = int(val)
            if choices and val not in choices:
                raise ValueError("{} is not in {}".format(val, choices))
            return val
        except (TypeError, ValueError) as e:
                print(
                    "Not a valid number ({}), please try again".format(e)
                    )

def prompt_int_big(prompt='', choices=(1,2,3)):
    while True:
        val = get_input_or_quit(prompt)
        try:
            val = int(val)
            if choices and val not in choices:
                raise ValueError("{} is not in {}".format(val, choices))
            return val
        except (TypeError, ValueError) as e:
                print(
                    "Not a valid number ({}), please try again".format(e)
                    )

role = prompt_int_small("Are you a teacher or student? Press 1 if you are a student or 2 if you are a teacher")
if role == 1:
    score=0
    name=input("What is your name?")
    print ("Alright",name,"welcome to your maths quiz."
            " Remember to round all answers to 5 decimal places.")
    level_of_difficulty = prompt_int_big("What level of difficulty are you working at?\n"
                                 "Press 1 for low, 2 for intermediate "
                                    "or 3 for high\n")


    if level_of_difficulty == 3:
        ops = ['+', '-', '*', '/']
    else:
        ops = ['+', '-', '*']

    for question_num in range(1, 11):
        if level_of_difficulty == 1:
            max_number = 10
        else:
            max_number = 20

        number_1 = random.randrange(1, max_number)
        number_2 = random.randrange(1, max_number)
        operation = random.choice(ops)

        maths = round(eval(str(number_1) + operation + str(number_2)),5)
        print('\nQuestion number: {}'.format(question_num))
        print ("The question is",number_1,operation,number_2)
        answer = float(input("What is your answer: "))
        if answer == maths:
            print("Correct")
            score = score + 1
        else:
            print ("Incorrect. The actual answer is",maths)

    if score >5:
        print("Well done you scored",score,"out of 10")
    else:
        print("Unfortunately you only scored",score,"out of 10. Better luck next time")


    class_number = prompt_int_big("Before your score is saved ,are you in class 1, 2 or 3? Press the matching number")

    filename = (str(class_number) + "txt")
    with shelve.open(filename) as db: # This is the effected line
        old_scores = db.get(name, [])
        old_scores.extend(score)
        db[name] =score[-3:]


    if prompt_bool("Do you wish to view previous results for your class"):
        for line in lines:
            print (line)
    else:
        sys.exit("Thanks for taking part in the quiz, your teacher should discuss your score with you later")

if role == 2:
    class_number = prompt_int_big("Which class' scores would you like to see? Press 1 for class 1, 2 for class 2 or 3 for class 3")
    filename = (str(class_number) + "txt")
    sort_or_not = int(input("Would youlike to sort these scores in any way? Press 1 if the answer is no or 2 if the answer is yes"))
    if sort_or_not == 1:
        f = open(filename, "r")
        lines = [line for line in f if line.strip()]
        lines.sort()
        for line in lines:
            print (line)
    if sort_or_not == 2:
        type_of_sort = int(input("How would you like to sort these scores? Press 1 for scores in alphabetical order with each student's highest score for the tests, 2 if you would like to see the students' highest scores sorted from highest to lowest and 3 if you like to see these student's average scores sorted from highest to lowest"))
        if type_of_sort == 1:
            with open(filename , 'r') as r:
                for line in sorted(r):
                    print(line, end='')
        if type_of_sort == 2:
            file = open(filename, 'r')
            lines = file.read().splitlines()
            s = {lines[i]:[int(k) for k in lines[i+1:i+4]] for i in range(0,len(lines),4)}
            for i in sorted(s.keys()):
                print (i,max(s[i]))

            avg_mark = lambda name:sum(s[name])/len(s[name])
            for i in sorted(s.keys(),key=avg_mark,reverse=True):
                print (i,avg_mark(i))
        if type_of_sort == 3:
            file = open(filename, 'r')
            lines = file.read().splitlines()
            s = {lines[i]:[int(k) for k in lines[i+1:i+4]] for i in range(0,len(lines),4)}
            for i in sorted(s.keys()):
                print (i,max(s[i]))

            high_mark = lambda name:max(s[name])
            for i in sorted(s.keys(),key=high_mark,reverse=True):
                print (i,high_mark(i))

The shelve module part of my code is not working and I don't understand what the error is trying to say. I am trying to save the last three scores to a students name and then sort it in a variety of ways . The error comes up after the quiz is completed as a student.

Ibrahim
  • 7
  • 5

1 Answers1

0

Try deleting the file at filename and running the script again, so that the script is responsible for creating the database file in the correct format. If you ask it to open an empty file or a file that was created by some other means (e.g. CSV, JSON, etc.) then it doesn't know how to handle it.

Alex Hall
  • 34,833
  • 5
  • 57
  • 89
  • When i have done that it comes up with another error stating that filename is not defined – Ibrahim Apr 09 '16 at 11:48
  • No, delete the actual file on your computer that has whatever name `filename` is equal to. Don't change the python code. You still need the variable. – Alex Hall Apr 09 '16 at 11:52
  • It now says the db type could not be determined – Ibrahim Apr 09 '16 at 12:26
  • Maybe I'm not explaining clearly, so try this. Replace `shelve.open(filename)` with `shelve.open('dbfile')`. DON'T create a file (not even an empty one) called `dbfile` yourself - it is essential that the script is responsible for creating the file from scratch. After running the script the file will be created. It won't be in a human readable format and the other parts of your script where you open and process the file manually won't work. You have to either use *only* `shelve` to process the file or not use it at all. – Alex Hall Apr 09 '16 at 14:01
  • I have done this and again it comes up with the an error: 'AttributeError:_exit_' – Ibrahim Apr 09 '16 at 14:43
  • That means you're not meant to use it directly as a context manager (i.e. in a `with` statement) because it hasn't been implemented as such. See [here](http://stackoverflow.com/a/7489828/2482744) on what to do. – Alex Hall Apr 09 '16 at 15:21
  • Now its come up with another error saying that str has no attribute extend – Ibrahim Apr 09 '16 at 17:54
  • That's because you're putting `score` into the database with `db[name] =score[-3:]`. So when `old_scores = db.get(name, [])` is run later, `old_scores` isn't a list, it's a `str`. Anyway, I can't debug all your problems for you. We've moved well past the issue you originally asked about and this latest problem was one you could have figured out simply by printing `old_scores` just before the error occurred (or just by looking closely at the code as I did). Please do your best to solve any further problems you have on your own, then ask a new question if you get stuck. – Alex Hall Apr 09 '16 at 18:15