I've not covered the 'Excel' part of this, as I'm not a Excel user, but from what I do know, I can't see that part being a huge challenge: I see the QandA dictionary being built, in part, from your Excel file, with which I'm sure OPs will be able to help, if needs be.
This is one way that one could begin to build the Q&A part:
from random import shuffle, randint
answered = 'answered'
answer = 'answer'
question = 'question'
answers = 'answers'
QandA = {
1:{
answered: False,
answer: '',
question: "This will be the text for question 1.", # place holder
answers: ("Answer 1", "Answer 2", "Answer 3", "Answer 4", "Answer 5") # place holder
},
2:{
answered: False,
answer: '',
question: "This will be the text for question 2.", # place holder
answers: ("Answer 1", "Answer 2", "Answer 3", "Answer 4", "Answer 5") # place holder
},
3:{
answered: False,
answer: '',
question: "This will be the text for question 3.", # place holder
answers: ("Answer 1", "Answer 2", "Answer 3", "Answer 4", "Answer 5") # place holder
},
4:{
answered: False,
answer: '',
question: "This will be the text for question 4.", # place holder
answers: ("Answer 1", "Answer 2", "Answer 3", "Answer 4", "Answer 5") # place holder
},
5:{
answered: False,
answer: '',
question: "This will be the text for question 5.", # place holder
answers: ("True", "False") # place holder
}
}
# the driver
no_of_qs = len(QandA)
print(f"There will be {no_of_qs} questions.\n")
q_asked = [] #holds the index of the question asked
q = 0
done = False
while not done:
q = randint(1,no_of_qs)
if len(q_asked) < no_of_qs:
if q not in q_asked:
q_asked.append(q)
ask = QandA[q][question]
print(ask)
options = [option for option in range(0,len(QandA[q][answers]))]
if len(options) > 2: # no need to shuffle True/False
shuffle(options)
for choose, ans in enumerate(options,1):
print(f"{choose}: {QandA[q][answers][ans]}")
the_answer = False
while not the_answer:
the_answer = input(f"\n1 to {len(options)} or 0 to pass.\n> ")
if len(the_answer) > 1 or the_answer.isalpha() or int(the_answer)not in range(0,len(options)+1):
the_answer = False
print("Invalid answer.")
if the_answer != '0':
QandA[q][answered] = True
QandA[q][answer] = QandA[q][answers][options[int(the_answer)-1]]
print()
else:
done = True
for q in range(1,no_of_qs+1):
if QandA[q][answered]:
print(f"Question {q} was answered: {QandA[q][answer]}.")
else:
print(f"Question {q} was not answered.")
Not too sure if this is going to be of any help, or if anyone else has a better way for this to be done. I've also not covered the binary part of this (questions that have a simple yes/no answer), but I don't see why that could not be implemented in some way; I'll have a look at that next, if you're still interested in moving this forward.
Code update: Some minor changes, just to make for a better base solution...
Added a True/False option and also a feedback for the questions that have been answered, from which a score could be calculated, based on whatever system you choose.