Last active
April 30, 2019 20:31
-
-
Save narthur/3c1dac894b413979121c3aba53df32b7 to your computer and use it in GitHub Desktop.
Script for generating Beeminder journal updates
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import os | |
import yaml | |
from beeminderpy import Beeminder | |
import json | |
from pprint import pprint | |
from tabulate import tabulate | |
import datetime | |
import time | |
import random | |
class Bm: | |
config = None | |
b = None | |
username = None | |
goals = [] | |
time_floor = time.time() - (60 * 60 * 24 * 7) | |
_new_derails = {} | |
def __init__(self, configuration): | |
self.config = configuration | |
self.b = Beeminder(configuration["auth"]["beeminder"]["token"]) | |
self.username = self.config["auth"]["beeminder"]["username"] | |
self._load_goals() | |
def _load_goals(self): | |
goals = json.loads(self.b.get_goals(self.username)) | |
self.goals = [goal for goal in goals if goal['slug'] not in self.config["journal"]["excluded"]] | |
def get_highest_pledge_goal(self): | |
candidate = self.goals[0] | |
for goal in self.goals: | |
if goal['pledge'] > candidate['pledge']: | |
candidate = goal | |
return candidate | |
def get_oldest_goal(self): | |
candidate = self.goals[0] | |
for goal in self.goals: | |
if goal['initday'] < candidate['initday']: | |
candidate = goal | |
return candidate | |
def get_newest_goal(self): | |
candidate = self.goals[0] | |
for goal in self.goals: | |
if goal['initday'] > candidate['initday']: | |
candidate = goal | |
return candidate | |
def get_new_goals(self): | |
return [goal for goal in self.goals if goal['initday'] > self.time_floor] | |
def total_pledges(self): | |
total = 0 | |
for goal in self.goals: | |
total += goal['pledge'] | |
return total | |
def get_new_derails(self): | |
if self._new_derails: | |
return self._new_derails | |
derails = {} | |
for goal in self.goals: | |
datapoints = json.loads(self.b.get_datapoints(self.username, goal['slug'])) | |
derails[goal["slug"]] = [point for point in datapoints if point["timestamp"] > self.time_floor and "RECOMMITTED" in point["comment"]] | |
self._new_derails = {slug: points for slug, points in derails.items() if len(points) > 0} | |
return self._new_derails | |
def count_new_derails(self): | |
new_derails = self.get_new_derails() | |
count = 0 | |
for _slug, _points in new_derails.items(): | |
count += len(_points) | |
return count | |
def count_systems_upgrades(self): | |
points = json.loads(self.b.get_datapoints(self.username, "systems-upgrade")) | |
return len([point for point in points if point['timestamp'] > self.time_floor]) | |
def get_graph(self, slug): | |
return json.loads(self.b.get_goal(self.username, slug))['graph_url'] | |
def get_random_goal(self): | |
date = time_to_string(time.time()) | |
random.seed(date) | |
return random.choice(self.goals) | |
def time_to_string(unix): | |
return datetime.datetime.fromtimestamp(unix).strftime("%Y-%m-%d") | |
def link_slug(slug): | |
return f'[{slug}](https://www.beeminder.com/narthur/{slug})' | |
def markdown_list(items): | |
return "\n".join([f"- {item}" for item in items]) | |
directory = os.path.dirname(os.path.realpath(__file__)) | |
config = yaml.load(open(f"{directory}/config.yaml", "r")) | |
bm = Bm(config) | |
highest_pledge_goal = bm.get_highest_pledge_goal() | |
oldest_goal = bm.get_oldest_goal() | |
newest_goal = bm.get_newest_goal() | |
new_goals = bm.get_new_goals() | |
headers = ["Key", "Value"] | |
table = [ | |
["Number of goals", len(bm.goals)], | |
["New goals this week", len(new_goals)], | |
["Newest goal", f'{link_slug(newest_goal["slug"])} ({time_to_string(newest_goal["initday"])})'], | |
["Oldest goal", f'{link_slug(oldest_goal["slug"])} ({time_to_string(oldest_goal["initday"])})'], | |
["Highest pledge", f'{link_slug(highest_pledge_goal["slug"])} (${highest_pledge_goal["pledge"]})'], | |
["Total pledges", f'${bm.total_pledges()}'], | |
["Derails this week", bm.count_new_derails()], | |
["Systems upgrades this week", bm.count_systems_upgrades()] | |
] | |
summary_table = tabulate(table, headers, tablefmt="github") | |
rand_goal = bm.get_random_goal() | |
markdown_new_goals = [f'**{link_slug(new_goal["slug"])}:** Created {time_to_string(new_goal["initday"])}. TK' for new_goal in new_goals] | |
derails = bm.get_new_derails() | |
markdown_derails = [] | |
for slug, points in derails.items(): | |
dates = [time_to_string(point["timestamp"]) for point in points] | |
markdown_derails.append(f'**{link_slug(slug)}:** {", ".join(dates)}. TK') | |
output = f""" | |
# Update {time_to_string(time.time())} | |
## Summary | |
{summary_table} | |
## Random Goal: {link_slug(rand_goal['slug'])} | |
TK | |
## New Goals | |
{markdown_list(markdown_new_goals)} | |
## Derails | |
{markdown_list(markdown_derails)} | |
## Max-Min Buffer Over Time | |
This chart shows the largest that the minimum buffer for any goal was during each day. (I really need a better way to | |
explain this.) | |
{bm.get_graph("buffer")} | |
*A skeleton of this summary generated using a Python script and then carefully filled-in by hand.* | |
""" | |
print(output) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment