Commit 31000819 authored by Jonathan Harker's avatar Jonathan Harker

Refactor, add very basic support for MoxQuizz questions.

 - Add rudimentary classes for reading MoxQuizz questions.
 - Add a very simple ask command. No scores or quiz game-play yet.
 - Refactor SQL models out into a separate file.
 - Make the code more Python 3 friendly.
 - PEP8 and pyflakes.
parent 4f546f18
This diff is collapsed.
from mechanize import Browser
from datetime import datetime
from sqlalchemy import (Column, String, Text, Integer, DateTime)
from sqlalchemy.ext.declarative import (declarative_base)
Model = declarative_base()
class Log(Model):
"""
This class represents an event in the log table and inherits from a SQLAlchemy
convenience ORM class.
"""
__tablename__ = "log"
id = Column(Integer, primary_key=True)
timestamp = Column(DateTime)
nickname = Column(String(20))
text = Column(Text)
def __init__(self, nickname, text, timestamp=None):
"""
Creates an event log for the IRC logger.
"""
if timestamp is None:
timestamp = datetime.now()
self.timestamp = timestamp
self.nickname = nickname
self.text = text
def __repr__(self):
return "(%s) %s: %s" % (self.timestamp.strftime("%Y-%m-%d %H:%M:%S"), self.nickname, self.text)
class Url(Model):
"""
This class represents a saved URL and inherits from a SQLAlchemy convenience
ORM class.
"""
__tablename__ = "url"
id = Column(Integer, primary_key=True)
timestamp = Column(DateTime)
nickname = Column(String(20))
url = Column(String(200), unique=True)
title = Column(Text)
def __init__(self, nickname, url, title=None, timestamp=None):
if timestamp is None:
timestamp = datetime.now()
self.timestamp = timestamp
self.nickname = nickname
self.url = url
self.title = title
# populate the title from the URL if not given.
if title is None:
try:
br = Browser()
br.open(self.url)
self.title = br.title()
except Exception:
self.title = ''
def __repr__(self):
if not self.title:
return "%s: %s" % (self.nickname, self.url)
else:
return "%s: %s - %s" % (self.nickname, self.url, self.title)
#!/usr/bin/env python
## -*- coding: utf-8 -*-
from __future__ import unicode_literals, print_function
from io import open
class Question:
"""
Represents one MoxQuizz question.
"""
category = None
question = None
answer = None
regexp = None
author = None
level = None
comment = None
score = 0
tip = list()
tipcycle = 0
TRIVIAL = 1
EASY = 2
NORMAL = 3
HARD = 4
EXTREME = 5
LEVELS = (TRIVIAL, EASY, NORMAL, HARD, EXTREME)
def __init__(self, attributes_dict):
self.parse(attributes_dict)
def parse(self, attributes_dict):
"""
Populate fields from a dictionary of attributes (from a question bank).
"""
## Valid keys:
# ----------
# Category? (should always be on top!)
# Question (should always stand after Category)
# Answer (will be matched if no regexp is provided)
# Regexp? (use UNIX-style expressions)
# Author? (the brain behind this question)
# Level? [baby|easy|normal|hard|extreme] (difficulty)
# Comment? (comment line)
# Score? [#] (credits for answering this question)
# Tip* (provide one or more hints)
# TipCycle? [#] (Specify number of generated tips)
if 'Question' in attributes_dict.keys():
self.question = attributes_dict['Question']
else:
raise Exception("Cannot instantiate Question: 'Question' attribute required.")
if 'Category' in attributes_dict.keys():
self.category = attributes_dict['Category']
if 'Answer' in attributes_dict.keys():
self.answer = attributes_dict['Answer']
else:
raise Exception("Cannot instantiate Question: 'Answer' attribute required.")
if 'Regexp' in attributes_dict.keys():
self.regexp = attributes_dict['Regexp']
if 'Author' in attributes_dict.keys():
self.category = attributes_dict['Author']
if 'Level' in attributes_dict.keys() and attributes_dict['Level'] in self.LEVELS:
self.level = attributes_dict['level']
if 'Comment' in attributes_dict.keys():
self.comment = attributes_dict['Comment']
if 'Score' in attributes_dict.keys():
self.score = attributes_dict['Score']
if 'Tip' in attributes_dict.keys():
self.tip = attributes_dict['Tip']
if 'Tipcycle' in attributes_dict.keys():
self.tipcycle = attributes_dict['Tipcycle']
class QuestionBank:
"""
Represents a MoxQuizz question bank.
"""
filename = ''
questions = list()
# Case sensitive, to remain backwards-compatible with MoxQuizz.
KEYS = ('Answer',
'Author',
'Category',
'Comment',
'Level',
'Question',
'Regexp',
'Score',
'Tip',
'Tipcycle',
)
def __init__(self, filename):
"""
Construct a question bank from a file.
"""
self.filename = filename
self.questions = self.parse(filename)
def parse(self, filename):
"""
Read a Moxquizz question bank file into a list.
"""
questions = list()
with open(filename) as f:
key = ''
i = 0
# new question
q = dict()
q['Tip'] = list()
for line in f:
line = line.strip()
i += 1
# Ignore comments.
if line.startswith('#'):
continue
# A blank line starts a new question.
if line == '':
# Store the previous question, if valid.
if 'Question' in q.keys() and 'Answer' in q.keys():
question = Question(q)
questions.append(question)
# Start a new question.
q = dict()
q['Tip'] = list()
continue
# Fetch the next parameter.
try:
(key, value) = line.split(':', 1)
except ValueError:
print("Unexpected weirdness in MoxQuizz questionbank '%s', line %s." % (self.filename, i))
continue
# break # TODO: is it appropriate to bail on broken bank files?
# Ignore bad parameters.
if key not in self.KEYS:
print("Unexpected key '%s' in MoxQuizz questionbank '%s', line %s." % (key, self.filename, i))
continue
# Enumerate the Tips.
if key == 'Tip':
q['Tip'].append(value.strip())
else:
q[key] = value.strip()
return questions
# A crappy test.
if __name__ == '__main__':
qb = QuestionBank('questions.doctorlard.en')
for q in qb.questions:
print(q.question)
a = unicode(raw_input('A: '), 'utf8')
#a = input('A: ') # Python 3
if a.lower() == q.answer.lower():
print("Correct!")
else:
print("Incorrect - the answer is '%s'" % q.answer)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment