question: Add Question._state_attributes for easier subclassing
[quizzer.git] / quizzer / question.py
1 QUESTION_CLASS = {}
2
3
4 def register_question(question_class):
5     QUESTION_CLASS[question_class.__name__] = question_class
6
7
8 class Question (object):
9     _state_attributes = [
10         'id',
11         'prompt',
12         'answer',
13         'help',
14         'dependencies',
15         ]
16
17     def __init__(self, id=None, prompt=None, answer=None, help=None,
18                  dependencies=None):
19         if id is None:
20             id = prompt
21         self.id = id
22         self.prompt = prompt
23         self.answer = answer
24         self.help = help
25         if dependencies is None:
26             dependencies = []
27         self.dependencies = dependencies
28
29     def __str__(self):
30         return '<{} id:{!r}>'.format(type(self).__name__, self.id)
31
32     def __repr__(self):
33         return '<{} id:{!r} at {:#x}>'.format(
34             type(self).__name__, self.id, id(self))
35
36     def __getstate__(self):
37         return {attr: getattr(self, attr)
38                 for attr in self._state_attributes} 
39
40     def __setstate__(self, state):
41         if 'id' not in state:
42             state['id'] = state.get('prompt', None)
43         if 'dependencies' not in state:
44             state['dependencies'] = []
45         self.__dict__.update(state)
46
47     def check(self, answer):
48         return answer == self.answer
49
50
51 class NormalizedStringQuestion (Question):
52     def normalize(self, string):
53         return string.strip().lower()
54
55     def check(self, answer):
56         return self.normalize(answer) == self.normalize(self.answer)
57
58
59 for name,obj in list(locals().items()):
60     if name.startswith('_'):
61         continue
62     try:
63         subclass = issubclass(obj, Question)
64     except TypeError:  # obj is not a class
65         continue
66     if subclass:
67         register_question(obj)
68 del name, obj