Compare commits
5 Commits
addons
...
wip-weekly
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c963ba41ae | ||
|
|
b4ef59b637 | ||
|
|
90b80268d3 | ||
|
|
7dde1fbab6 | ||
|
|
b3e0f791a7 |
@@ -2,196 +2,198 @@
|
|||||||
|
|
||||||
""" TODO.TXT Bird's Eye View Reporter
|
""" TODO.TXT Bird's Eye View Reporter
|
||||||
USAGE:
|
USAGE:
|
||||||
birdseye.py [todo.txt] [done.txt]
|
birdseye.py [todo.txt] [done.txt]
|
||||||
|
|
||||||
USAGE NOTES:
|
USAGE NOTES:
|
||||||
Expects two text files as parameters, each of which formatted as follows:
|
Expects two text files as parameters, each of which formatted as follows:
|
||||||
- One todo per line, ie, "call Mom"
|
- One todo per line, ie, "call Mom"
|
||||||
- with an optional project association indicated as such: "+projectname"
|
- with an optional project association indicated as such: "+projectname"
|
||||||
- with the context in which the tasks should be completed, indicated as such: "@context"
|
- with the context in which the tasks should be completed, indicated as such: "@context"
|
||||||
- with the task priority optionally listed at the front of the line, in parens, ie, "(A)"
|
- with the task priority optionally listed at the front of the line, in parens, ie, "(A)"
|
||||||
|
|
||||||
For example, 4 lines of todo.txt might look like this:
|
For example, 4 lines of todo.txt might look like this:
|
||||||
|
|
||||||
+garagesale @phone schedule Goodwill pickup
|
+garagesale @phone schedule Goodwill pickup
|
||||||
(A) @phone Tell Mom I love her
|
(A) @phone Tell Mom I love her
|
||||||
+writing draft Great American Novel
|
+writing draft Great American Novel
|
||||||
(B) smell the roses
|
(B) smell the roses
|
||||||
|
|
||||||
The done.txt file is a list of completed todos from todo.txt.
|
The done.txt file is a list of completed todos from todo.txt.
|
||||||
|
|
||||||
See more on todo.txt here:
|
See more on todo.txt here:
|
||||||
http://todotxt.com
|
http://todotxt.com
|
||||||
|
|
||||||
|
|
||||||
OUTPUT:
|
OUTPUT:
|
||||||
Displays a list of:
|
Displays a list of:
|
||||||
- working projects and their percentage complete
|
- working projects and their percentage complete
|
||||||
- contexts in which open todos exist
|
- contexts in which open todos exist
|
||||||
- contexts and projects with tasks that have been prioritized
|
- contexts and projects with tasks that have been prioritized
|
||||||
- projects which are completely done (don't have any open todos)
|
- projects which are completely done (don't have any open todos)
|
||||||
|
|
||||||
CHANGELOG:
|
CHANGELOG:
|
||||||
2006.07.29 - Now supports p:, p- and + project notation. Tx, Pedro!
|
2016.03.17 - Update for Python 3. Tx, JonathanReeve!
|
||||||
2006.05.02 - Released
|
2006.07.29 - Now supports p:, p- and + project notation. Tx, Pedro!
|
||||||
|
2006.05.02 - Released
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
#import datetime
|
|
||||||
|
|
||||||
__version__ = "1.1"
|
__version__ = "1.2"
|
||||||
__date__ = "2006/05/02"
|
__date__ = "2006/05/02"
|
||||||
__updated__ = "2006/07/29"
|
__updated__ = "2016/03/17"
|
||||||
__author__ = "Gina Trapani (ginatrapani@gmail.com)"
|
__author__ = "Gina Trapani (ginatrapani@gmail.com)"
|
||||||
__copyright__ = "Copyright 2006, Gina Trapani"
|
__copyright__ = "Copyright 2006 - 2016, Gina Trapani"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
__history__ = """
|
__history__ = """
|
||||||
|
1.2 - Update for Python 3. Tx, JonathanReeve!
|
||||||
|
1.1 - Now supports p:, p- and + project notation. Tx, Pedro!
|
||||||
1.0 - Released.
|
1.0 - Released.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def usage():
|
def usage():
|
||||||
print("USAGE: %s [todo.txt] [done.txt]" % (sys.argv[0], ))
|
print("USAGE: %s [todo.txt] [done.txt]" % (sys.argv[0], ))
|
||||||
|
|
||||||
def printTaskGroups(title, taskDict, priorityList, percentages):
|
def printTaskGroups(title, taskDict, priorityList, percentages):
|
||||||
print("")
|
print("")
|
||||||
print("%s"% (title,))
|
print("%s"% (title,))
|
||||||
separator("-")
|
separator("-")
|
||||||
if not taskDict:
|
if not taskDict:
|
||||||
print("No items to list.")
|
print("No items to list.")
|
||||||
else:
|
else:
|
||||||
# sort the dictionary by value
|
# sort the dictionary by value
|
||||||
# http://python.fyxm.net/peps/pep-0265.html
|
# http://python.fyxm.net/peps/pep-0265.html
|
||||||
items = [(v, k) for k, v in list(taskDict.items())]
|
items = [(v, k) for k, v in list(taskDict.items())]
|
||||||
items.sort()
|
items.sort()
|
||||||
items.reverse() # so largest is first
|
items.reverse() # so largest is first
|
||||||
items = [(k, v) for v, k in items]
|
items = [(k, v) for v, k in items]
|
||||||
|
|
||||||
for item in items:
|
for item in items:
|
||||||
if item[0] in priorityList:
|
if item[0] in priorityList:
|
||||||
if item[0] not in percentages:
|
if item[0] not in percentages:
|
||||||
printTaskGroup(item, -1, "*")
|
printTaskGroup(item, -1, "*")
|
||||||
else:
|
else:
|
||||||
printTaskGroup(item, percentages[item[0]], "*")
|
printTaskGroup(item, percentages[item[0]], "*")
|
||||||
|
|
||||||
for item in items:
|
for item in items:
|
||||||
if item[0] not in priorityList:
|
if item[0] not in priorityList:
|
||||||
if item[0] not in percentages:
|
if item[0] not in percentages:
|
||||||
printTaskGroup(item, -1, " ")
|
printTaskGroup(item, -1, " ")
|
||||||
else:
|
else:
|
||||||
printTaskGroup(item, percentages[item[0]], " ")
|
printTaskGroup(item, percentages[item[0]], " ")
|
||||||
|
|
||||||
def printTaskGroup(p, pctage, star):
|
def printTaskGroup(p, pctage, star):
|
||||||
if pctage > -1:
|
if pctage > -1:
|
||||||
progressBar = ""
|
progressBar = ""
|
||||||
numStars = int(pctage//10)
|
numStars = int(pctage//10)
|
||||||
progressBar = "=" * numStars
|
progressBar = "=" * numStars
|
||||||
numSpaces = 10 - numStars
|
numSpaces = 10 - numStars
|
||||||
for n in range(numSpaces):
|
for n in range(numSpaces):
|
||||||
progressBar += " "
|
progressBar += " "
|
||||||
|
|
||||||
if pctage > 9:
|
if pctage > 9:
|
||||||
displayTotal = " %d%%"% (pctage, );
|
displayTotal = " %d%%"% (pctage, );
|
||||||
else:
|
else:
|
||||||
displayTotal = " %d%%"% (pctage, );
|
displayTotal = " %d%%"% (pctage, );
|
||||||
print("%s %s [%s] %s (%d todos)"% (star, displayTotal, progressBar, p[0], p[1],))
|
print("%s %s [%s] %s (%d todos)"% (star, displayTotal, progressBar, p[0], p[1],))
|
||||||
else:
|
else:
|
||||||
print("%s %s (%d todos)"% (star, p[0], p[1], ))
|
print("%s %s (%d todos)"% (star, p[0], p[1], ))
|
||||||
|
|
||||||
def separator(c):
|
def separator(c):
|
||||||
sep = ""
|
sep = ""
|
||||||
sep = c * 42
|
sep = c * 42
|
||||||
print(sep)
|
print(sep)
|
||||||
|
|
||||||
|
|
||||||
def main(argv):
|
def main(argv):
|
||||||
# make sure you have all your args
|
# make sure you have all your args
|
||||||
if len(argv) < 2:
|
if len(argv) < 2:
|
||||||
usage()
|
usage()
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
# process todo.txt
|
# process todo.txt
|
||||||
try:
|
try:
|
||||||
f = open (argv[0], "r")
|
f = open (argv[0], "r")
|
||||||
projects = {}
|
projects = {}
|
||||||
contexts = {}
|
contexts = {}
|
||||||
projectPriority = []
|
projectPriority = []
|
||||||
contextPriority = []
|
contextPriority = []
|
||||||
for line in f:
|
for line in f:
|
||||||
prioritized = False
|
prioritized = False
|
||||||
words = line.split()
|
words = line.split()
|
||||||
if words and words[0].startswith("("):
|
if words and words[0].startswith("("):
|
||||||
prioritized = True
|
prioritized = True
|
||||||
for word in words:
|
for word in words:
|
||||||
if word[0:2] == "p:" or word[0:2] == "p-" or word[0:1] == "+":
|
if word[0:2] == "p:" or word[0:2] == "p-" or word[0:1] == "+":
|
||||||
if word not in projects:
|
if word not in projects:
|
||||||
projects[word] = 1
|
projects[word] = 1
|
||||||
else:
|
else:
|
||||||
projects[word] = projects.setdefault(word,0) + 1
|
projects[word] = projects.setdefault(word,0) + 1
|
||||||
if prioritized:
|
if prioritized:
|
||||||
projectPriority.append(word)
|
projectPriority.append(word)
|
||||||
if word[0:1] == "@":
|
if word[0:1] == "@":
|
||||||
if word not in contexts:
|
if word not in contexts:
|
||||||
contexts[word] = 1
|
contexts[word] = 1
|
||||||
else:
|
else:
|
||||||
contexts[word] = contexts.setdefault(word, 0) + 1
|
contexts[word] = contexts.setdefault(word, 0) + 1
|
||||||
if prioritized:
|
if prioritized:
|
||||||
contextPriority.append(word)
|
contextPriority.append(word)
|
||||||
f.close()
|
f.close()
|
||||||
except IOError:
|
except IOError:
|
||||||
print("ERROR: The file named %s could not be read."% (argv[0], ))
|
print("ERROR: The file named %s could not be read."% (argv[0], ))
|
||||||
usage()
|
usage()
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
# process done.txt
|
# process done.txt
|
||||||
try:
|
try:
|
||||||
completedTasks = {}
|
completedTasks = {}
|
||||||
f = open (argv[1], "r")
|
f = open (argv[1], "r")
|
||||||
for line in f:
|
for line in f:
|
||||||
words = line.split()
|
words = line.split()
|
||||||
for word in words:
|
for word in words:
|
||||||
if word[0:2] == "p:" or word[0:2] == "p-" or word[0:1] == "+":
|
if word[0:2] == "p:" or word[0:2] == "p-" or word[0:1] == "+":
|
||||||
if word not in completedTasks:
|
if word not in completedTasks:
|
||||||
completedTasks[word] = 1
|
completedTasks[word] = 1
|
||||||
else:
|
else:
|
||||||
completedTasks[word] = completedTasks.setdefault(word, 0) + 1
|
completedTasks[word] = completedTasks.setdefault(word, 0) + 1
|
||||||
f.close()
|
f.close()
|
||||||
except IOError:
|
except IOError:
|
||||||
print("ERROR: The file named %s could not be read."% (argv[1], ))
|
print("ERROR: The file named %s could not be read."% (argv[1], ))
|
||||||
usage()
|
usage()
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
# calculate percentages
|
# calculate percentages
|
||||||
projectPercentages = {}
|
projectPercentages = {}
|
||||||
for project in projects:
|
for project in projects:
|
||||||
openTasks = projects[project]
|
openTasks = projects[project]
|
||||||
if project in completedTasks:
|
if project in completedTasks:
|
||||||
closedTasks = completedTasks[project]
|
closedTasks = completedTasks[project]
|
||||||
else:
|
else:
|
||||||
closedTasks = 0
|
closedTasks = 0
|
||||||
totalTasks = openTasks + closedTasks
|
totalTasks = openTasks + closedTasks
|
||||||
projectPercentages[project] = (closedTasks*100) / totalTasks
|
projectPercentages[project] = (closedTasks*100) / totalTasks
|
||||||
|
|
||||||
# get projects all done
|
# get projects all done
|
||||||
projectsWithNoIncompletes = {}
|
projectsWithNoIncompletes = {}
|
||||||
for task in completedTasks:
|
for task in completedTasks:
|
||||||
if task not in projects:
|
if task not in projects:
|
||||||
projectsWithNoIncompletes[task] = 0
|
projectsWithNoIncompletes[task] = 0
|
||||||
|
|
||||||
# print out useful info
|
# print out useful info
|
||||||
#print "TODO.TXT Bird's Eye View Report %s"% ( datetime.date.today().isoformat(), )
|
#print "TODO.TXT Bird's Eye View Report %s"% ( datetime.date.today().isoformat(), )
|
||||||
print("")
|
print("")
|
||||||
print("TODO.TXT Bird's Eye View Report")
|
print("TODO.TXT Bird's Eye View Report")
|
||||||
|
|
||||||
separator("=")
|
separator("=")
|
||||||
|
|
||||||
printTaskGroups("Projects with Open TODOs", projects, projectPriority, projectPercentages)
|
printTaskGroups("Projects with Open TODOs", projects, projectPriority, projectPercentages)
|
||||||
printTaskGroups("Contexts with Open TODOs", contexts, contextPriority, projectPercentages)
|
printTaskGroups("Contexts with Open TODOs", contexts, contextPriority, projectPercentages)
|
||||||
printTaskGroups("Completed Projects (No open TODOs)", projectsWithNoIncompletes, projectPriority, projectPercentages)
|
printTaskGroups("Completed Projects (No open TODOs)", projectsWithNoIncompletes, projectPriority, projectPercentages)
|
||||||
print("")
|
print("")
|
||||||
print("* Projects and contexts with an asterisk next to them denote prioritized tasks.")
|
print("* Projects and contexts with an asterisk next to them denote prioritized tasks.")
|
||||||
print("Project with prioritized tasks are listed first, then sorted by number of open todos.")
|
print("Project with prioritized tasks are listed first, then sorted by number of open todos.")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
199
.todo.actions.d/weeklyreview.py
Normal file
199
.todo.actions.d/weeklyreview.py
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
""" TODO.TXT Weekly Review
|
||||||
|
USAGE:
|
||||||
|
weeklyreview.py [todo.txt] [done.txt] [projects.txt]
|
||||||
|
|
||||||
|
USAGE NOTES:
|
||||||
|
Expects three text files as parameters:
|
||||||
|
1 & 2. Properly-formatted todo.txt and done.txt files.
|
||||||
|
3. A projects.txt file which lists one project per line, and any number of #goals associated with it.
|
||||||
|
|
||||||
|
See more on todo.txt here:
|
||||||
|
http://todotxt.com
|
||||||
|
|
||||||
|
OUTPUT:
|
||||||
|
Displays a count of how many tasks were completed associated with a goal.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
__version__ = "1.2"
|
||||||
|
__date__ = "2016/03/17"
|
||||||
|
__updated__ = "2016/03/17"
|
||||||
|
__author__ = "Gina Trapani (ginatrapani@gmail.com)"
|
||||||
|
__copyright__ = "Copyright 2016, Gina Trapani"
|
||||||
|
__license__ = "GPL"
|
||||||
|
__history__ = """
|
||||||
|
0.1 - WIP
|
||||||
|
"""
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print("USAGE: %s [todo.txt] [done.txt] [projects.txt]" % (sys.argv[0], ))
|
||||||
|
|
||||||
|
def separator(c, r=42):
|
||||||
|
sep = ""
|
||||||
|
sep = c * r
|
||||||
|
print(sep)
|
||||||
|
|
||||||
|
def printTitle(text):
|
||||||
|
print("")
|
||||||
|
r = len(text)
|
||||||
|
print(text)
|
||||||
|
separator("=", r)
|
||||||
|
|
||||||
|
def printHeader(text):
|
||||||
|
r = len(text)
|
||||||
|
print("")
|
||||||
|
print(text)
|
||||||
|
separator("-", r)
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
# make sure you have all your args
|
||||||
|
if len(argv) < 3:
|
||||||
|
usage()
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
goal_projects = getGoalProjects(argv)
|
||||||
|
#print(goal_projects)
|
||||||
|
|
||||||
|
last_7_days = getLast7Days()
|
||||||
|
#print(last_7_days)
|
||||||
|
|
||||||
|
last_7_days_of_completions = getLast7DaysOfCompletions(argv, last_7_days)
|
||||||
|
#print(last_7_days_of_completions)
|
||||||
|
|
||||||
|
project_completions = getProjectCompletions(argv, last_7_days_of_completions)
|
||||||
|
#print(project_completions)
|
||||||
|
|
||||||
|
goal_completions = getGoalCompletions(goal_projects, project_completions)
|
||||||
|
# print(goal_completions)
|
||||||
|
|
||||||
|
# Print report: For each item in goal_projects, print the goal, the number of tasks completed,
|
||||||
|
# then each project and the number of tasks completed
|
||||||
|
printTitle("Weekly Review for the past 7 days")
|
||||||
|
|
||||||
|
goals_not_moved = []
|
||||||
|
goals_moved = []
|
||||||
|
for goal in goal_projects:
|
||||||
|
total_done = 0
|
||||||
|
if goal in goal_completions:
|
||||||
|
total_done = len(goal_completions[goal])
|
||||||
|
goal_header = goal + " - " + str(total_done) + " done"
|
||||||
|
if total_done > 0:
|
||||||
|
printHeader(goal_header)
|
||||||
|
for project in goal_projects[goal]:
|
||||||
|
if project in project_completions:
|
||||||
|
print(project + " - " + str(len(project_completions[project])) + " done" )
|
||||||
|
for task in project_completions[project]:
|
||||||
|
print(" " + task.strip())
|
||||||
|
goals_moved.append(goal)
|
||||||
|
else:
|
||||||
|
goals_not_moved.append(goal)
|
||||||
|
|
||||||
|
# Print a list of goals that had no movement
|
||||||
|
if len(goals_not_moved) > 0:
|
||||||
|
printTitle("Goals with no progress")
|
||||||
|
for goal in goals_not_moved:
|
||||||
|
print(goal)
|
||||||
|
|
||||||
|
# Print summary
|
||||||
|
print("")
|
||||||
|
summary = str(len(last_7_days_of_completions)) + " completed tasks moved " + str(len(goals_moved)) + " out of " + str(len(goal_projects)) + " goals forward."
|
||||||
|
separator("-", len(summary))
|
||||||
|
print(summary)
|
||||||
|
separator("-", len(summary))
|
||||||
|
|
||||||
|
# Warnings
|
||||||
|
crossCheckCompletedProjects(project_completions, goal_projects)
|
||||||
|
|
||||||
|
|
||||||
|
# Return an array of goals with total tasks completed.
|
||||||
|
def getGoalCompletions(goal_projects, project_completions):
|
||||||
|
goal_completions = {}
|
||||||
|
goals = goal_projects.keys()
|
||||||
|
for goal in goal_projects:
|
||||||
|
for project in project_completions:
|
||||||
|
if project in goal_projects[goal]:
|
||||||
|
if goal not in goal_completions:
|
||||||
|
goal_completions[goal] = project_completions[project]
|
||||||
|
else:
|
||||||
|
goal_completions[goal] = goal_completions[goal] + project_completions[project]
|
||||||
|
return goal_completions
|
||||||
|
|
||||||
|
# Return the goal/project list as an array of arrays goalProjects[goal] = projects[]
|
||||||
|
def getGoalProjects(argv):
|
||||||
|
try:
|
||||||
|
goal_projects = {}
|
||||||
|
f = open (argv[2], "r")
|
||||||
|
for line in f:
|
||||||
|
words = line.split()
|
||||||
|
for word in words:
|
||||||
|
# Project
|
||||||
|
if word[0:1] == "+":
|
||||||
|
current_project = word
|
||||||
|
# Goal
|
||||||
|
if word[0:1] == "#":
|
||||||
|
if word not in goal_projects:
|
||||||
|
goal_projects[word] = [current_project];
|
||||||
|
else:
|
||||||
|
goal_projects[word].append(current_project)
|
||||||
|
f.close()
|
||||||
|
return goal_projects
|
||||||
|
except IOError:
|
||||||
|
print("ERROR: The file named %s could not be read."% (argv[1], ))
|
||||||
|
usage()
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
|
||||||
|
# Get the last 7 days as an array of todo.txt-formatted dates.
|
||||||
|
def getLast7Days():
|
||||||
|
today = datetime.date.today()
|
||||||
|
last7Days = []
|
||||||
|
for d in range(8):
|
||||||
|
day_this_week = today - datetime.timedelta(days=d)
|
||||||
|
last7Days.append(day_this_week.strftime('%Y-%m-%d'))
|
||||||
|
return last7Days
|
||||||
|
|
||||||
|
# Return last 7 days of completed tasks from done.txt
|
||||||
|
def getLast7DaysOfCompletions(argv, last_7_days):
|
||||||
|
try:
|
||||||
|
last_7_days_of_completions = []
|
||||||
|
f = open (argv[1], "r")
|
||||||
|
for line in f:
|
||||||
|
words = line.split()
|
||||||
|
if len(words) > 2 and words[1] in last_7_days:
|
||||||
|
last_7_days_of_completions.append(line)
|
||||||
|
f.close()
|
||||||
|
return last_7_days_of_completions
|
||||||
|
except IOError:
|
||||||
|
print("ERROR: The file named %s could not be read."% (argv[1], ))
|
||||||
|
usage()
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
# Return an array of projects with the total tasks completed.
|
||||||
|
def getProjectCompletions(argv, last_7_days_of_completions):
|
||||||
|
project_completions = {}
|
||||||
|
for task in last_7_days_of_completions:
|
||||||
|
words = task.split()
|
||||||
|
for word in words:
|
||||||
|
if word[0:2] == "p:" or word[0:2] == "p-" or word[0:1] == "+":
|
||||||
|
if word not in project_completions:
|
||||||
|
project_completions[word] = [task]
|
||||||
|
else:
|
||||||
|
project_completions[word].append(task)
|
||||||
|
return project_completions
|
||||||
|
|
||||||
|
def crossCheckCompletedProjects(project_completions, goal_projects):
|
||||||
|
for project in project_completions:
|
||||||
|
goal_in_project = False
|
||||||
|
for goal in goal_projects:
|
||||||
|
if project in goal_projects[goal]:
|
||||||
|
goal_in_project = True
|
||||||
|
if goal_in_project == False:
|
||||||
|
print("WARNING: Project " + project + " not in goal.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main(sys.argv[1:])
|
||||||
Reference in New Issue
Block a user