moved ex3->ex03

This commit is contained in:
2019-02-02 16:59:18 +01:00
parent c488cfa1a9
commit 55f0f2c2be
8 changed files with 0 additions and 0 deletions

78
exam/ex03/callbacks.py Normal file
View File

@@ -0,0 +1,78 @@
from gi.repository import Gtk
from settings import load_words_from_file, manually_add_question, save_questions_to_file
from exercise import Question
class CallbackHandler(object):
def __init__(self, gtk_builder):
self.builder = gtk_builder
self.question = None
def on_manually_add_submit_button_clicked(self, widget):
question_view = self.builder.get_object("add_question_question_view")
answer_view = self.builder.get_object("add_question_answer_view")
question = question_view.get_text()
answer = answer_view.get_text()
try:
manually_add_question(question, answer)
except:
return
question_view.set_text("")
answer_view.set_text("")
def on_load_from_file_chooser_file_set(self, widget):
file_chooser = self.builder.get_object("load_from_file_chooser")
file_name = file_chooser.get_filename()
load_words_from_file(file_name)
def on_save_questions_to_file_button_clicked(self, widget):
dialog = Gtk.FileChooserDialog("Please choose a file", None
, Gtk.FileChooserAction.SAVE
, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL
, Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
response = dialog.run()
if(response == Gtk.ResponseType.CANCEL):
dialog.destroy()
return
file_name = dialog.get_filename()
dialog.destroy()
save_questions_to_file(file_name)
def on_submit_answer_button_clicked(self, widget):
answer_view = self.builder.get_object("answer_view")
correct_answer_view = self.builder.get_object("correct_answer_view")
answer_was_correct_view = self.builder.get_object("answer_was_correct_view")
dispatch_answer_was_correct = {True: "That is correct:"
, False: "Wrong, correct was:"}
submit_answer_button = widget
submit_answer_button.set_sensitive(False)
answer = answer_view.get_text()
was_correct = self.question.submit_answer(answer)
correct_answer_view.set_text(self.question.answer)
answer_was_correct_view.set_text(dispatch_answer_was_correct[was_correct])
def on_next_question_button_clicked(self, widget):
answer_view = self.builder.get_object("answer_view")
correct_answer_view = self.builder.get_object("correct_answer_view")
answer_was_correct_view = self.builder.get_object("answer_was_correct_view")
submit_answer_button = self.builder.get_object("submit_answer_button")
question_view = self.builder.get_object("question_view")
submit_answer_button.set_sensitive(True)
answer_view.set_text("")
correct_answer_view.set_text("")
answer_was_correct_view.set_text("")
self.question = Question.fetch()
question_view.set_text(self.question.question)

4
exam/ex03/cfg.py Normal file
View File

@@ -0,0 +1,4 @@
config = {"APP_PATH": "."
, "WORD_BUCKET_SIZE": 5
}

86
exam/ex03/database.py Normal file
View File

@@ -0,0 +1,86 @@
import os
import sqlite3
import random
from cfg import config
database_path = os.path.join(config["APP_PATH"], "app.sqlite")
def create_database():
# truncate the file if it exists
with open(database_path, "w") as database_file:
pass
db = sqlite3.connect(database_path)
db.execute('''CREATE TABLE QUESTIONS(question TEXT UNIQUE, answer TEXT, correct INT)''')
db.commit()
db.close()
def open_database():
if(not os.path.exists(database_path)):
create_database()
return sqlite3.connect(database_path)
def update_correct(question, correct):
"""
Correct has to be +1 (for a correct answer) or -1 (for a wrong answer).
"""
db = open_database()
cursor = db.cursor()
try:
cursor.execute("UPDATE QUESTIONS SET correct=correct + ? WHERE question = ?", (correct, question))
except sqlite3.IntegrityError:
pass
db.commit()
db.close()
def add_word(question, answer):
db = open_database()
cursor = db.cursor()
cursor.execute("INSERT INTO QUESTIONS(question, answer, correct) VALUES(?, ?, 0)", (question, answer))
db.commit()
db.close()
def add_words(input_data):
db = open_database()
cursor = db.cursor()
cursor.executemany("INSERT INTO QUESTIONS(question, answer, correct) VALUES(?, ?, 0)", list(input_data.items()))
db.commit()
db.close()
def fetch_question():
"""
Fetches a new question from the database.
The list of question is sorted ascending by number of
times the question has been answered correctly
and from the least n elements one is chosen randomly.
n is either the number of questions in the database divided
by ``cfg.config["WORD_BUCKET_SIZE"]`` or (if this number is zero)
or one.
"""
db = open_database()
cursor = db.cursor()
cursor.execute("SELECT COUNT(question) FROM questions")
number_of_questions = cursor.fetchone()[0]
if(number_of_questions == 0):
raise Exception("No questions in the database")
fetch_questions = number_of_questions // config["WORD_BUCKET_SIZE"]
if(fetch_questions == 0):
fetch_questions = 1
cursor.execute("SELECT question, answer, correct FROM QUESTIONS ORDER BY correct ASC")
result = cursor.fetchmany(fetch_questions)
my_result = random.choice(result)
return my_result[:2]

41
exam/ex03/exercise.py Normal file
View File

@@ -0,0 +1,41 @@
from database import fetch_question, update_correct
class Question(object):
"""
This is the throwaway container types for questions.
It basically stores the question and the answer and
handles the database access.
One can fetch a (semi random (see database.fetch_question))
question from the database using Question.fetch()
and use submit_question() to both update the database and
check whether the answer was correct.
"""
__slots__ = ["question", "answer"]
def __init__(self, question, answer):
self.question = question
self.answer = answer
@classmethod
def fetch(cls):
data = fetch_question()
return cls(data[0], data[1])
def submit_answer(self, answer):
"""
Check whether ``answer`` is correct,
update the database accordingly and
return ``True`` if the answer was correct,
``False`` otherwise.
"""
correct = -1
if(answer == self.answer):
correct = 1
update_correct(self.question, correct)
return correct > 0

345
exam/ex03/main.glade Normal file
View File

@@ -0,0 +1,345 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<signal name="destroy" handler="onDestroy" swapped="no"/>
<child>
<object class="GtkNotebook">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="question_view">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Question</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="answer_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="placeholder_text" translatable="yes">Answer</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkButton" id="submit_answer_button">
<property name="label" translatable="yes">Submit Answer</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_submit_answer_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">4</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="answer_was_correct_view">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">No question has been answered </property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="correct_answer_view">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">No question has been answered </property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="next_question_button">
<property name="label" translatable="yes">Next Question</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_next_question_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">2</property>
<property name="position">3</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
<child type="tab">
<object class="GtkLabel" id="exercise_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Exercises</property>
</object>
<packing>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Load questions from file</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFileChooserButton" id="load_from_file_chooser">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes"/>
<signal name="file-set" handler="on_load_from_file_chooser_file_set" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Manually add question</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkEntry" id="add_question_question_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="placeholder_text" translatable="yes">Question</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="add_question_answer_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="placeholder_text" translatable="yes">Answer</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="manually_add_submit_button">
<property name="label" translatable="yes">Submit</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_manually_add_submit_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">25</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Save questions to file</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="save_questions_to_file_button">
<property name="label" translatable="yes">Save Questions to File</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_save_questions_to_file_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel" id="settings_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Settings</property>
</object>
<packing>
<property name="position">1</property>
<property name="tab_fill">False</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

28
exam/ex03/main.py Normal file
View File

@@ -0,0 +1,28 @@
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from callbacks import CallbackHandler
builder = Gtk.Builder()
builder.add_from_file("main.glade")
callback_handler = CallbackHandler(builder)
handlers = {
"onDestroy": Gtk.main_quit
, "on_manually_add_submit_button_clicked": callback_handler.on_manually_add_submit_button_clicked
, "on_load_from_file_chooser_file_set": callback_handler.on_load_from_file_chooser_file_set
, "on_save_questions_to_file_button_clicked": callback_handler.on_save_questions_to_file_button_clicked
, "on_submit_answer_button_clicked": callback_handler.on_submit_answer_button_clicked
, "on_next_question_button_clicked": callback_handler.on_next_question_button_clicked
}
builder.connect_signals(handlers)
window = builder.get_object("window1")
window.show_all()
Gtk.main()

26
exam/ex03/settings.py Normal file
View File

@@ -0,0 +1,26 @@
import os
import json
from database import add_word, add_words, open_database
def load_words_from_file(file_name):
if(not os.path.exists(file_name)):
raise Exception("File does not exist")
with open(file_name) as fin:
data = {line[0]: line[1] for line in
[ line.split() for line in fin if line]
if len(line) == 2}
add_words(data)
def manually_add_question(question, answer):
add_word(question, answer)
def save_questions_to_file(file_name):
db = open_database()
with open(file_name, "w") as fout:
cursor = db.cursor()
cursor.execute("SELECT question, answer, correct FROM QUESTIONS")
data = [{"question":i[0], "answer": i[1], "correct": i[2]} for i in cursor.fetchall()]
json.dump(data, fout)
db.close()

5
exam/ex03/words.tx Normal file
View File

@@ -0,0 +1,5 @@
gut good
schlecht bad
tag day
dummkopf furkan