Back to index

freevial  1.2
questions.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002  
00003 #
00004 # Freevial
00005 # Questions Importer
00006 #
00007 # Copyright (C) 2007, 2008 The Freevial Team
00008 #
00009 # By Carles Oriol i Margarit <carles@kumbaworld.com>
00010 # By Siegfried-Angel Gevatter Pujals <siggi.gevatter@gmail.com>
00011 #
00012 # This program is free software: you can redistribute it and/or modify
00013 # it under the terms of the GNU General Public License as published by
00014 # the Free Software Foundation, either version 3 of the License, or
00015 # (at your option) any later version.
00016 #
00017 # This program is distributed in the hope that it will be useful,
00018 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 # GNU General Public License for more details.
00021 #
00022 # You should have received a copy of the GNU General Public License
00023 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
00024 #
00025 
00026 import os
00027 import sys
00028 from lxml import etree, objectify
00029 import gettext
00030 
00031 from common.freevialglob import *
00032 from common.uncompress import Uncompressor
00033 from common.globals import GlobalVar, Global
00034 from common.database import Database
00035 
00036 
00037 class LoadDatabase:
00038        
00039        def __init__(self, directory):
00040               """ Load a question database (directory or compressed file). """
00041               
00042               try:
00043                      self.files = self._xml_in_path(self._get_real_path(directory))
00044               
00045               except IOError:
00046                      print _('Error: Couldn\'t find the current questions database.')
00047                      print _('You can provide the location to that one you want to use by passing the --database option.')
00048                      print _('For example: freevial --database ~/questions.tar.gz')
00049                      sys.exit(1)
00050        
00051        def get(self):
00052               
00053               return self.files
00054        
00055        def _get_real_path(self, directory):
00056               """ If the given path is directory it is returned as-is, if it's
00057               is a compressed file the path to a extracted version to it (on a
00058               temporal directory) is returned. Else ValueError is raised; if
00059               the directory/file doesn't exist at all, it raises IOError."""
00060               
00061               if not os.path.exists(directory):
00062                      raise IOError, _('Indicated directory of file doesn\'t exist or has wrong permissions.')
00063               
00064               if os.path.isdir(directory):
00065                      return directory
00066               
00067               ext = os.path.splitext(directory)[1][1:]  # Get the extension
00068               
00069               if ext in ('gz', 'bz2', 'zip'):
00070                      return self._extract(directory)
00071               
00072               raise ValueError, _('Expected a directory or compressed file.')
00073        
00074        def _extract(self, directory):
00075               """ Extracts a compressed file to a temporal directory and returns
00076               the URL to it. """
00077               
00078               file = Uncompressor(directory)
00079               tempdir = self._get_temp()
00080               
00081               file.extractall(tempdir)
00082               return tempdir
00083        
00084        def _get_temp(self):
00085               """ Creates a temporary directory."""
00086               
00087               import tempfile
00088               return tempfile.mkdtemp('', 'freevial-') + '/'
00089        
00090        def _xml_in_path(self, directory):
00091               
00092               files = []
00093               
00094               for file in self._files_in_path(directory):
00095                      if file[-4:] == '.xml': files.append(file)
00096               
00097               return files
00098        
00099        def _files_in_path(self, directory):
00100               """ Returns a list with the name of all the files in the given directory. """
00101               
00102               for files in (files for dirpath, dirnames, files in os.walk(directory)):
00103                      return [ '%s' % os.path.abspath(os.path.join(directory, file)) for file in files ]
00104 
00105 
00106 # Create the XML parser
00107 parser = etree.XMLParser(remove_blank_text = True)
00108 parser.setElementClassLookup(objectify.ObjectifyElementClassLookup())
00109 
00110 def GetDatabase( num, xmlFile ):
00111        """ Returns a Database instance loaded with the questions from a XML file. """
00112        
00113        root = etree.parse(xmlFile, parser).getroot()
00114        
00115        if float(root.get('version')) != 1.0:
00116               print >> sys.stderr, _('Warning: «%»: Database\'s version is %s, which is not supported by the installed version of Freevial. It might not work as expected.') % (xmlFile, root.get('version'))
00117        
00118        database = Database(
00119               num,
00120               root.information.name.text,
00121               root.get('language'),
00122               root.information.description.text,
00123               root.information.destination.text,
00124               ', '.join(["%s" % author.text.split(',')[0] for author in root.information.authors.getchildren()]),
00125               (int(root.information.timestamp_creation.text), int(root.information.timestamp_modification.text)),
00126               root.appearance.image.text,
00127               root.appearance.sound.text,
00128        )
00129        
00130        for question in root.questions.getchildren():
00131               
00132               if question.answers.countchildren() != 3:
00133                      print >> sys.stderr, _('Warning: «%»: Found question with an incorrect number of answers; ignoring it.') % xmlFile
00134                      continue
00135               
00136               answers = []
00137               has_correct_answer = False
00138               
00139               # Process answers
00140               for answer in question.answers.getchildren():
00141                      if answer.get('correct') is not None:
00142                             if has_correct_answer:
00143                                    print >> sys.stderr, _('Warning: «%»: Found question with two correct answers; ignoring it.') % xmlFile
00144                                    continue
00145                             answers.insert(0, answer.text)
00146                             has_correct_answer = True
00147                      else:
00148                             answers.append(answer.text)
00149               
00150               if not has_correct_answer:
00151                      print >> sys.stderr, _('Warning: «%»: Found question without any correct answer; ignoring it.') % xmlFile
00152                      continue
00153               
00154               if hasattr(question, 'comments') and question.comments.text is not None:
00155                      comment = question.comments.text
00156               else:
00157                      comment = u''
00158               
00159               database.addQuestion(
00160                      question = question.sentence.text,
00161                      answ1 = answers[0],
00162                      answ2 = answers[1],
00163                      answ3 = answers[2],
00164                      author = question.author.text,
00165                      comment = comment,
00166               )
00167        
00168        return database
00169 
00170 
00171 alldatabases = []
00172 database_files = LoadDatabase(Global.database).get()
00173 
00174 for num in range(0, len(database_files) ):
00175        try:
00176               cat = GetDatabase( num + 1, os.path.join(Global.database, database_files[num]) )
00177               alldatabases.append( cat )
00178        except ValueError:
00179               print 'Error with «%s».' % database_files[num]
00180 
00181 def shuffle_databases():
00182        random.shuffle(alldatabases)
00183 
00184 def get_databases( database = None ):
00185        
00186        if database is not None:
00187               return alldatabases[database]
00188        else:
00189               return alldatabases