1 # Copyright (C) 2013 W. Trevor King <wking@tremily.us>
3 # This file is part of quizzer.
5 # quizzer is free software: you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation, either version 3 of the License, or (at your option) any later
10 # quizzer is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License along with
15 # quizzer. If not, see <http://www.gnu.org/licenses/>.
17 import codecs as _codecs
19 import os.path as _os_path
21 from . import __version__
22 from . import question as _question
26 def __init__(self, questions=None, path=None, encoding=None,
27 copyright=None, introduction=None):
30 super(Quiz, self).__init__(questions)
32 self.encoding = encoding
33 self.copyright = copyright
34 self.introduction = introduction
36 def _open(self, mode='r', path=None, encoding=None):
40 self.encoding = encoding
41 return _codecs.open(self.path, mode, self.encoding)
43 def load(self, **kwargs):
44 with self._open(mode='r', **kwargs) as f:
46 version = data.get('version', None)
47 if version != __version__:
50 self, '_upgrade_from_{}'.format(version.replace('.', '_')))
51 except AttributeError as e:
52 raise NotImplementedError('upgrade from {} to {}'.format(
53 version, __version__)) from e
55 self.copyright = data.get('copyright', None)
56 self.introduction = data.get('introduction', None)
57 for state in data['questions']:
58 question_class_name = state.pop('class', 'Question')
59 question_class = _question.QUESTION_CLASS[question_class_name]
64 def save(self, **kwargs):
67 state = question.__getstate__()
68 state['class'] = type(question).__name__
70 'version': __version__,
71 'copyright': self.copyright,
72 'introduction': self.introduction,
73 'questions': questions,
75 with self._open(mode='w', **kwargs) as f:
77 data, f, indent=2, separators=(',', ': '), sort_keys=True)
80 def leaf_questions(self):
81 "Questions that are not dependencies of other question"
84 dependents.update(question.dependencies)
85 return [q for q in self if q.id not in dependents]
87 def get(self, id=None):
88 matches = [q for q in self if q.id == id]
91 elif len(matches) == 0:
93 raise NotImplementedError(
94 'multiple questions with one ID: {}'.format(matches))
96 def multimedia_path(self, multimedia):
97 if 'path' in multimedia:
98 basedir = _os_path.dirname(self.path)
99 path = multimedia['path']
100 if _os_path.sep != '/': # convert to native separators
101 path = path.replace('/', _os_path.sep)
102 return _os_path.join(basedir, multimedia['path'])
104 raise NotImplementedError(question.multimedia)
106 def _upgrade_from_0_1(self, data):
107 data['version'] = __version__
110 _upgrade_from_0_2 = _upgrade_from_0_1
111 _upgrade_from_0_3 = _upgrade_from_0_1