#!/usr/bin/env python
import os
import errno
import re
from pprint import pprint

def read_tasks(db_root):
    """ Load tasks from db. """
    entry_names = os.listdir(os.path.join(db_root, "entry"))
    entry_paths = {filename: os.path.join(db_root, "entry", filename) for filename in entry_names}
    tasks = {name: read_task(entry_paths[name]) for name in entry_names}
    return tasks

def read_task(filepath):
    """ Read a task from a file. """
    task = {}
    task['body'] = ""

    with open(filepath, 'r') as f:
        reading_headers = True
        for line in f.readlines():
            header_match = re.match(r"(?P<field>\w+): +(?P<value>.*)$", line)
            if reading_headers and header_match:
                field = header_match.group('field')
                value = header_match.group('value')
                assert field != 'body'
                assert field not in task
                task[field] = value.rstrip()
            else:
                reading_headers = False
                task['body'] += line.rstrip() + "\n"

    task['body'] = task['body'].rstrip()

    return task

def ensure_db(db_root):
    """ Make the storage directories exist. """
    mkdir_p(os.path.join(db_root, "entry"))
    mkdir_p(os.path.join(db_root, "done"))
    mkdir_p(os.path.join(db_root, "template"))

def mkdir_p(path):
    """ no error if existing, make parent directories as needed """
    try:
        os.makedirs(path)
    except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else:
            raise

if __name__ == "__main__":
    db_root = "tasks"
    ensure_db(db_root)
    tasks = read_tasks(db_root)
    pprint(tasks)

@@ -75,16 +75,420 @@
 pprint%0A%0A
+def show_by_course(tasks):%0A    courses = set(tasks%5Bname%5D.get('course') for name in tasks)%0A    courses -= set(%5BNone%5D)%0A    courses = sorted(courses)%0A%0A    for course in courses:%0A        print%0A        print %22Course: %25s%22 %25 course%0A        course_tasks = filter(%0A            lambda name: tasks%5Bname%5D.get('course') == course,%0A            tasks)%0A        for name in course_tasks:%0A            print %22%3E %25s%22 %25 name%0A%0A
 def read
@@ -2089,16 +2089,18 @@
 oot)%0A   
+ #
  pprint(
@@ -2102,12 +2102,38 @@
 rint(tasks)%0A
+    show_by_course(tasks)%0A

add show_by_course