#!/usr/bin/env python # -*- coding: utf-8 -*- """ Convert questions for the famous Penta News Game Show from some yaml format to json. It's just a helper to write the questions in a more human readeable format assuming yaml is more human readable Note: - Media files are looked for relative to the questions file - Media files are expected relative to the generated json files TODO: * Add own constructor to Question() / nice to have * Use import logging for debug logging """ __author__ = "Frank Becker " __version__ = "0.0.2" __date__ = "Fri 18 Nov 2011 18:10:44 CET" __copyright__ = "Copyright (c) 2011 Frank Becker" __license__ = "Python" import os import sys import random import json from reportlab.lib.pagesizes import A5, LETTER, landscape, portrait from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import inch, cm from reportlab.platypus.flowables import PageBreak from optparse import OptionParser try: import yaml except ImportError: print 'You need to install PyYAML first. E. g. "pip install pyyaml"' class Question(yaml.YAMLObject): """Represents a question """ yaml_tag = u"!Question" web_root = "data" # Generate random points in range of points_per_round gen_random_points = True points_per_round = { 1: (1, 100), 2: (100, 1000), 3: (10000, 100000), 4: (5, 42), 5: (13, 80), } # {round_no1: [tier1, tier2, ...], round_no2: [tier1, ...]} registered_questions = {} def __init__(self, question=u"", tier=0, answers=[], game_round=0, media=("", "", ""), media_path="data", web_root="data"): """docstring for __init__ @question - the Question @rank - number of the question in the game @game_round - number of the round in the game @answers - list of answers, assumed are 4 @media - (media show at question time, media shown at answer time, media shown at resolution time) @media_path - path to the media files """ self.question = question self.answers = answers self.tier = tier self.game_round = game_round self.media = media self.media_path = media_path self.web_root = web_root def __type_by_extension(self, media_file): """returns the media type looked up by it's extension FIXME (a8): maybe use file magic in the future @media_file - path to the media file """ media_types = dict( video = ('webm'), image = ('png', 'jpg', 'gif'), ) if not os.path.isfile(media_file): raise IOError("The file {0} does not exist.".format(media_file,)) ext = media_file.rsplit('.', 1)[1] for k, v in media_types.items(): if ext in v: return k raise KeyError("Media type for {0} not found".format(media_file,)) def __repr__(self): """docstring for __repr__""" return "%s(%r)" % (self.__class__.__name__, self.question) def _get_points(self, game_round, tier): """returns the points by game_round/tier combo""" points_fixed = { 1: 100, 2: 150, 3: 225, 4: 337, 5: 506, 6: 759, 7: 1139, 8: 1709, 9: 2563, 10: 3844, 11: 5555, 12: 7531, } if not self.gen_random_points: return points_fixed.get(tier, 0) range = self.points_per_round.get(game_round) points = random.randint(*range) return points @property def as_dict(self): """dump data suiteable for json conversion""" data = {} data['text'] = self.question data['tier'] = self._get_points(int(self.game_round), int(self.tier)) try: data['source'] = self.source except AttributeError: data['source'] = False print self.question print self.answers data['answers'] = [ {'text': answer[False]} if answer.has_key(False) \ else {'text': answer[True], 'right': True} \ for answer in self.answers ] if hasattr(self, 'media'): def gen_questions(): q_data = {} for f in self.media['question']: q_data[self.__type_by_extension( os.path.sep.join(os.path.join([self.media_path, f])) )] = os.sep.join([self.web_root, f]) return q_data def gen_explanation(): """Sorry, hacky. Quick fix required only 1st element is taken""" f = self.media['explanation'][0] k = self.__type_by_extension(os.path.sep.join( os.path.join([self.media_path, f]))) v = [os.sep.join([self.web_root, expl]) \ for expl in self.media['explanation']] if v: v = v[0] else: v = "" return {'explanation': {k: v}} #): os.sep.join([self.web_root, f]) #[os.sep.join([self.web_root, expl]) \ # for expl in self.media['explanation']]} def k_not_found(): raise KeyError("Media keyword not found") for k in self.media.keys(): m_data = dict( question = gen_questions, explanation= gen_explanation, k_not_found = "lambda x: pass", ).get(k, 'k_not_found')() for key, value in m_data.items(): data[key] = value return data @property def as_pdf_dict(self): """Return full data set. Includes comment field""" data = self.as_dict try: data['comment'] = self.comment except AttributeError: data['comment'] = "" return data @classmethod def get_points(cls): """docstring for get_points""" for key in sorted(cls.points.keys()): yield cls.points[key] @staticmethod def register_question(obj): """register object in class so no question with the same tier/round combo can exist""" if Question.registered_questions.has_key(obj.game_round) and \ obj.tier in Question.registered_questions[obj.game_round]: raise IndexError("Slot for Question {0} is alredy taken".format( obj.question,)) elif Question.registered_questions.has_key(obj.game_round): Question.registered_questions[obj.game_round].append(obj.tier) else: Question.registered_questions[obj.game_round] = [obj.tier] def init_parser(): """Read command line options returns: options:dict -- config options """ parser = OptionParser() parser.add_option( "-d", "--debug", dest="debug", help="Toggle debugging", action="store_true", default=False, ) parser.add_option( "-f", "--questions-file", dest="file", help=("Use this file instead of the default " "questions.yaml"), metavar="FILE", ) parser.add_option( "-p", "--generate-pdf", dest="pdf", help=("Generate the speaker PDF"), action="store_true", default=False, ) parser.add_option( "-v", "--version", dest="version", help="Show program version", action="store_true", default=False, ) options = parser.parse_args()[0] return options def questions_per_round(questions, game_round=None): """docstring for questions_per_round""" return [q for q in questions if q.game_round == game_round] def write_json_file(questions): """docstring for write_json_file""" game_round = questions[0].game_round file_name = 'round_{0}.json'.format(game_round) fh = open(file_name, 'w') fh.writelines(json.dumps([q.as_dict for q in questions], indent=2)) def gen_pdf(questions, game_rounds): """generate speaker PDF""" styles = getSampleStyleSheet() doc = SimpleDocTemplate("pngs-speaker.pdf") doc.pagesize = landscape(A5) style = styles["Normal"] page_elements = [] for round in game_rounds: for num, question in enumerate( questions_per_round(questions, game_round=round)): q_data = question.as_pdf_dict page_elements.append( Paragraph("Game Round: {0}".format(round), style) ) page_elements.append(Spacer(0, 0.1*cm)) page_elements.append( Paragraph( "Question {0}: {1}" "".format(num + 1, q_data['text'].encode('utf-8')), style) ) page_elements.append(Spacer(0, 0.2*cm)) page_elements.append( Paragraph("Comment: {0}".format(q_data.get('comment').encode('utf-8')), style) ) page_elements.append(Spacer(0, 0.2*cm)) page_elements.append( Paragraph("Answers:", style) ) page_elements.append( Paragraph("* " + "
* ".join([unicode(t['text']) for t in q_data['answers']]), style) ) page_elements.append( Paragraph("Points: {0}".format(q_data.get('tier')), style) ) page_elements.append(PageBreak()) doc.build(page_elements) return Story = [Spacer(0, 1*cm)] p = Paragraph("Blubber1", styles["Normal"]) Story.append(p) p = Paragraph("Blubber2", styles["Normal"]) Story.append(p) Story.append(Spacer(10, 5*cm)) p = Paragraph("Blubber3", styles["Normal"]) Story.append(p) #doc.build(Story, onFirstPage=myFirstPage, onLaterPages=myLaterPages) doc.build(Story) def gen_answers_html(questions, game_rounds): """generate html""" fh = open("answers.html", 'w') html_header = """ """ html_footer = """ """ #fh.write(html_header) fh.write('\n') #fh.write(html_footer) fh.close() def main(): """docstring for main""" options = init_parser() if options.version: print "Version: {0}".format(__version__,) sys.exit() if options.file: questions_fh = open(options.file) else: questions_fh = open('questions.yaml') questions = [] for q in yaml.load_all(questions_fh.read()): #FIXME (fb@alien8.de) 11-11-18 23:16:34 use yaml constructor # yaml.add_constructor Question.register_question(q) if options.file: q.media_path = os.path.abspath(os.path.dirname(options.file)) questions.append(q) if options.debug: print Question.registered_questions print [q.media for q in questions] game_rounds = sorted(Question.registered_questions.keys()) for r in game_rounds: write_json_file(questions_per_round(questions, game_round=r)) if options.debug: print "Written file for game round: {0}".format(r) if options.pdf: gen_pdf(questions, game_rounds) #gen_answers_html(questions, game_rounds) if __name__ == '__main__': main() # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 fileencoding=utf-8 :