godot-platformer-2d/docs/feedback-report/process.py

224 lines
7 KiB
Python

"""
Convert the data to org, to read the entries more easily, and to export to a revealjs presentation with Emacs
Prints to standard output (STDOUT), redirect the stream to a file to save it, e.g. python3 process.py > out.org
"""
import csv
import os
from pprint import pprint
def parse_csv_from_file(path=""):
"""
Returns a list of OrderedDict instances, one for each row in the csv file
"""
if path == '' or not os.path.splitext(path)[1] == '.csv':
return []
content = []
with open(path) as csv_file:
reader = csv.DictReader(csv_file)
for row in reader:
content.append(row)
return content
class OrgDocument:
"""
Basic representation of an org document, with a name, a description, and a list of OrgTree instances
"""
def __init__(self, title="", description="", author="", trees=[]):
self.title = title
self.description = description
self.author = author
self.trees = trees
def add_child(self, node):
assert isinstance(node, OrgTree)
self.trees.append(node)
def add_children(self, node_list=[]):
for node in node_list:
self.add_child(node)
def __str__(self):
text = ""
if self.title:
text += "#+TITLE: {}\n".format(self.title)
if self.description:
text += "#+DESCRIPTION: {}\n".format(self.description)
if self.author:
text += "#+AUTHOR: {}\n".format(self.author)
text += "\n"
for tree in self.trees:
text += str(tree)
return text
class OrgTree:
"""
Holds one branch of an org document, starting from a level 1 heading, including all subtrees
"""
def __init__(self, name="", content="", children=[], start_level=-1):
self.name = name
self.content = content
self.level = start_level if start_level != -1 else 1
self.parent = None
self.children = []
if children != []:
for node in children:
self.add_child(node)
def add_child(self, node):
"""
Adds and stores a subheading
"""
assert isinstance(node, OrgTree)
self.children.append(node)
node.parent = self
def add_children(self, node_list=[]):
for node in node_list:
self.add_child(node)
def get_child_count(self):
return len(self.children)
@property
def parent(self):
return self.__parent
@parent.setter
def parent(self, node):
if node is None:
self.level = 1
return
self.__parent = node
self.update_level()
def update_level(self):
if not self.parent:
self.level = 1
self.level = self.parent.level + 1
for child in self.children:
child.update_level()
def as_string(self):
heading = "*" * self.level + " " + self.name
string = heading + "\n" * 2
if self.content:
string += self.content + "\n" * 2
for child in self.children:
string += child.as_string()
return string
def __str__(self):
return self.as_string()
class FormAnswers:
"""
Data container for form answers, splits the OrderedDict into 5 dictionaries
"""
def __init__(self, answers, name=""):
"""
answers: OrderedDict
"""
self.name = name
self.profile = {
'gamedev': answers['gamedev'],
'dev': answers['dev'],
'godot': answers['godot'],
'assignements': answers['assignments'],
'topics': answers['topics']}
self.expectations = {
'expectations': answers['expectations'],
'struggles': answers['struggles']}
self.tutorials = {
'tutorial_disliked': answers['tutorial_disliked'],
'tutorial_liked': answers['tutorial_liked']}
self.improve = answers['improve']
self.comments = answers['comments']
def as_tree(self):
"""
Returns the data as an Org tree with subtrees
"""
main_tree = OrgTree(self.name)
subtrees = []
# Profile
profile = OrgTree("Profile")
profile.content += "- Gamedev: " + self.profile['gamedev'] + "\n"
profile.content += "- Development: " + self.profile['dev'] + "\n"
profile.content += "- Godot: " + self.profile['godot'] + "\n"
assignments_string = ""
if self.profile['assignements'].lower() == "yes":
assignments_string = "Wants"
elif self.profile['assignements'].lower() == "maybe":
assignments_string = "May want"
else:
assignments_string = "Doesn't want"
if assignments_string:
profile.content += "- {} assignements \n".format(assignments_string)
interests_string = ""
for interest in self.profile['topics'].split(';'):
interests_string += " + {}\n".format(interest)
if interests_string:
profile.content += "- Interested in \n" + interests_string[:-1]
subtrees.append(profile)
# Expectations
expectations = OrgTree("Expectations")
wishes = OrgTree("Wishes")
wishes.content = self.expectations['expectations']
if wishes.content:
expectations.add_child(wishes)
struggles = OrgTree("Struggles")
struggles.content = self.expectations['struggles']
if struggles.content:
expectations.add_child(struggles)
if expectations.get_child_count() > 0:
subtrees.append(expectations)
# Tutorials
tutorials = OrgTree("Tutorials")
liked_most = OrgTree("Most Liked")
liked_most.content = self.tutorials['tutorial_liked']
if liked_most.content:
tutorials.add_child(liked_most)
liked_least = OrgTree("Least Liked")
liked_least.content = self.tutorials['tutorial_disliked']
if liked_least.content:
tutorials.add_child(liked_least)
if tutorials.get_child_count() > 0:
subtrees.append(tutorials)
# Improve and Comments
improve = OrgTree("How can we improve?", self.improve)
if improve.content:
subtrees.append(improve)
comments = OrgTree("Anything else?", self.comments)
if comments.content:
subtrees.append(comments)
main_tree.add_children(subtrees)
return main_tree
if __name__ == '__main__':
data_list = parse_csv_from_file("data.csv")
document = OrgDocument("Godot course 2: backers feedback", "Processed and filtered data from the backers' feedback on the course's form, converted to org mode to read more easily and export to revealjs", "Nathan Lovato")
counter = 1
for row in data_list:
answer = FormAnswers(row, name=str(counter).zfill(3))
tree = answer.as_tree()
if tree.get_child_count() == 1:
continue
document.add_child(tree)
counter += 1
print(document)