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/>.
19 import readline as _readline
20 except ImportError as _readline_import_error:
24 from pygments.console import colorize as _colorize
25 except ImportError as e:
26 def _colorize(color_key=None, text=None):
30 from .. import error as _error
31 from . import UserInterface as _UserInterface
34 class QuestionCommandLine (_cmd.Cmd):
36 'Type help or ? to list commands.',
37 'Non-commands will be interpreted as answers.',
38 'Use a blank line to terminate multi-line answers.',
40 intro = '\n'.join(['Welcome to the quizzer shell.'] + _help)
43 def __init__(self, ui):
44 super(QuestionCommandLine, self).__init__()
46 if self.ui.quiz.introduction:
47 self.intro = '\n\n'.join([self.intro, self.ui.quiz.introduction])
50 def get_question(self):
51 self.question = self.ui.get_question()
55 return True # out of questions
63 self._tempdir.cleanup() # occasionally redundant, but that's ok
68 "Pose a question and prompt"
70 self.prompt = '\n{}\n{}'.format(
72 self.ui.colors['question'], self.question.format_prompt()),
73 _colorize(self.ui.colors['prompt'], self._prompt))
75 self.prompt = _colorize(self.ui.colors['prompt'], self._prompt)
78 "Just prompt (without the question, e.g. for multi-line answers)"
79 self.prompt = _colorize(self.ui.colors['prompt'], self._prompt)
81 def default(self, line):
82 self.answers.append(line)
83 if self.question.multiline:
92 if self.question.multiline:
95 answer = self.answers[0]
100 kwargs['tempdir'] = self._tempdir
101 correct = self.ui.process_answer(
102 question=self.question, answer=answer, **kwargs)
104 print(_colorize(self.ui.colors['correct'], 'correct\n'))
106 print(_colorize(self.ui.colors['incorrect'], 'incorrect\n'))
107 return self.get_question()
109 def do_answer(self, arg):
110 """Explicitly add a line to your answer
112 This is useful if the line you'd like to add starts with a
113 quizzer-shell command. For example:
115 quizzer? answer help=5
117 return self.default(arg)
119 def do_shell(self, arg):
120 """Run a shell command in the question temporary directory
122 For example, you can spawn an interactive session with:
126 If the question does not allow interactive sessions, this
129 if getattr(self.question, 'allow_interactive', False):
130 if not self._tempdir:
131 self._tempdir = self.question.setup_tempdir()
133 self._tempdir.invoke(
134 interpreter='/bin/sh', text=arg, stdout=None, stderr=None,
135 universal_newlines=False,
136 env=self.question.get_environment())
137 except (KeyboardInterrupt, _error.CommandError) as e:
138 if isinstance(e, KeyboardInterrupt):
139 LOG.warning('KeyboardInterrupt')
142 self._tempdir.cleanup()
145 def do_quit(self, arg):
146 "Stop taking the quiz"
150 def do_skip(self, arg):
151 "Skip the current question, and continue with the quiz"
152 self.ui.stack.append(self.question)
153 return self.get_question()
155 def do_hint(self, arg):
156 "Show a hint for the current question"
158 print(self.question.format_help())
160 def do_copyright(self, arg):
161 "Print the quiz copyright notice"
162 if self.ui.quiz.copyright:
163 print('\n'.join(self.ui.quiz.copyright))
165 print(self.ui.quiz.copyright)
167 def do_help(self, arg):
168 'List available commands with "help" or detailed help with "help cmd"'
170 print('\n'.join(self._help))
171 super(QuestionCommandLine, self).do_help(arg)
174 class CommandLineInterface (_UserInterface):
175 colors = { # listed in pygments.console.light_colors
176 'question': 'turquoise',
185 cmd = QuestionCommandLine(ui=self)
188 self._display_results()
190 def _display_results(self):
191 print(_colorize(self.colors['result'], 'results:'))
192 for question in self.quiz:
193 if question.id in self.answers:
194 self._display_result(question=question)
196 self._display_totals()
198 def _display_result(self, question):
199 answers = self.answers.get(question.id, [])
203 self.colors['question'],
204 question.format_prompt(newline='\n '))))
206 lc = len([a for a in answers if a['correct']])
208 print('answers: {}/{} ({:.2f})'.format(lc, la, float(lc)/la))
209 for answer in answers:
210 if answer['correct']:
213 correct = 'incorrect'
214 correct = _colorize(self.colors[correct], correct)
215 ans = answer['answer']
216 if question.multiline:
217 ans = '\n '.join(ans)
218 print(' you answered: {}'.format(ans))
219 print(' which was: {}'.format(correct))
221 def _display_totals(self):
222 answered = self.answers.get_answered(questions=self.quiz)
223 correctly_answered = self.answers.get_correctly_answered(
226 lc = len(correctly_answered)
227 print('answered {} of {} questions'.format(la, len(self.quiz)))
229 print(('of the answered questions, '
230 '{} ({:.2f}) were answered correctly'
231 ).format(lc, float(lc)/la))