This allows us to specify questions with alternate processing classes.
As a simple example, I've added NormalizedStringQuestion, which
softens the string comparison used in the basic Question. The next
step is to add a command-line question ;).
]
},
{
+ "class": "NormalizedStringQuestion",
"prompt": "What is your favourite color?",
- "answer": "Blue",
+ "answer": "blue",
"hint": "Channel Sir Lancelot",
"dependencies": [
"What is your quest?"
+QUESTION_CLASS = {}
+
+
+def register_question(question_class):
+ QUESTION_CLASS[question_class.__name__] = question_class
+
+
class Question (object):
def __init__(self, id=None, prompt=None, answer=None, help=None,
dependencies=None):
def check(self, answer):
return answer == self.answer
+
+
+class NormalizedStringQuestion (Question):
+ def normalize(self, string):
+ return string.strip().lower()
+
+ def check(self, answer):
+ return self.normalize(answer) == self.normalize(self.answer)
+
+
+for name,obj in list(locals().items()):
+ if name.startswith('_'):
+ continue
+ try:
+ subclass = issubclass(obj, Question)
+ except TypeError: # obj is not a class
+ continue
+ if subclass:
+ register_question(obj)
+del name, obj
raise NotImplementedError('upgrade from {} to {}'.format(
version, __version__))
for state in data['questions']:
- q = _question.Question()
+ question_class_name = state.pop('class', 'Question')
+ question_class = _question.QUESTION_CLASS[question_class_name]
+ q = question_class()
q.__setstate__(state)
self.append(q)
def save(self, **kwargs):
+ questions = []
+ for question in self:
+ state = question.__getstate__()
+ state['class'] = type(question).__name__
data = {
'version': __version__,
- 'questions': [question.__getstate__() for question in self],
+ 'questions': questions,
}
with self._open(mode='w', **kwargs) as f:
_json.dump(