doc/meek: tab-meek-costs.py

File tab-meek-costs.py, 3.5 KB (added by dcf, 10 months ago)

Program to generate table of monthly costs.

Line 
1#!/usr/bin/env python
2# encoding: utf-8
3
4import csv
5import datetime
6import getopt
7import sys
8
9def fmt_dollar(n):
10    return "[[span(style=color:gray,$)]]{:,.2f}".format(n)
11
12class Summer(object):
13    def __init__(self, value=None, plus=False):
14        self.value = value
15        self.plus = plus
16
17    @staticmethod
18    def parse(s):
19        if s is None:
20            return Summer(None, False)
21        if s == "?":
22            return Summer(0.0, True)
23        return Summer(float(s), False)
24
25    def __add__(self, other):
26        if other.value is None:
27            return Summer(self.value, self.plus or other.plus)
28        if self.value is None:
29            return Summer(other.value, self.plus or other.plus)
30        return Summer(self.value + other.value, self.plus or other.plus)
31
32    def fmt(self):
33        if self.value is None:
34            return r'[[span(style=color:gray,—)]]'
35        if self.value == 0.0 and self.plus:
36            return r'[[span(style=color:gray,?)]]'
37        f = fmt_dollar(self.value)
38        if self.plus:
39            f += r'+'
40        return f
41
42def read_input(f):
43    data = {}
44    for row in csv.DictReader(f):
45        data.setdefault(row["month"], {})
46        assert row["backend"] not in data[row["month"]]
47        data[row["month"]][row["backend"]] = row["cost"]
48    return data
49
50def fmt_year(d):
51    d = datetime.datetime.strptime(d, "%Y-%m")
52    return d.strftime("%Y")
53
54def fmt_month(d):
55    d = datetime.datetime.strptime(d, "%Y-%m")
56    return d.strftime("%b")
57
58_, args = getopt.gnu_getopt(sys.argv[1:], "")
59
60filename, = args
61with open(filename) as f:
62    data = read_input(f)
63
64grand_total_google = Summer()
65grand_total_amazon = Summer()
66grand_total_azure = Summer()
67
68def year_table(year):
69    global grand_total_google, grand_total_amazon, grand_total_azure
70    year_total_google = Summer()
71    year_total_amazon = Summer()
72    year_total_azure = Summer()
73    for month in range(1, 13):
74        date = "%04d-%02d" % (year, month)
75        data_month = data.get(date)
76        if not data_month:
77            continue
78        google = Summer.parse(data_month.get("google"))
79        amazon = Summer.parse(data_month.get("amazon"))
80        azure = Summer.parse(data_month.get("azure"))
81        year_total_google += google
82        year_total_amazon += amazon
83        year_total_azure += azure
84        print "|| {}||{} || {}|| {}|| {}|| {}||".format(
85            fmt_year(date),
86            fmt_month(date),
87            google.fmt(),
88            amazon.fmt(),
89            azure.fmt(),
90            (google + amazon + azure).fmt()
91        )
92    print "||||= '''{} total'''=|| {}|| {}|| {}|| {}||".format(
93        year,
94        year_total_google.fmt(),
95        year_total_amazon.fmt(),
96        year_total_azure.fmt(),
97        (year_total_google + year_total_amazon + year_total_azure).fmt()
98    )
99    grand_total_google += year_total_google
100    grand_total_amazon += year_total_amazon
101    grand_total_azure += year_total_azure
102
103def print_header():
104    print r'|||| ||' + r'||'.join("= {} =".format(x) for x in ("Google", "Amazon", "Azure", "total")) + r'||'
105
106print_header()
107year_table(2014)
108print "|||||||||||| ||"
109print_header()
110year_table(2015)
111print "|||||||||||| ||"
112print_header()
113year_table(2016)
114print "|||||||||||| ||"
115print_header()
116year_table(2017)
117print "|||||||||||| ||"
118print_header()
119print "||||= '''grand total'''=|| {}|| {}|| {}|| {}||".format(
120    grand_total_google.fmt(),
121    grand_total_amazon.fmt(),
122    grand_total_azure.fmt(),
123    (grand_total_google + grand_total_amazon + grand_total_azure).fmt()
124)