diff options
author | bipasa <bipasac2000@gmail.com> | 2012-01-13 13:01:12 -0500 |
---|---|---|
committer | bipasa <bipasac2000@gmail.com> | 2012-01-13 13:01:12 -0500 |
commit | 34f017590712c9906836ddf996bdc65b55fd745c (patch) | |
tree | e0df7c5834999d3445dec91d9b8c3ac65cdab431 /conferences.py | |
parent | 405287fa6dd51e682ae4b7e39432f5859865fc24 (diff) | |
parent | e8f30c862d050c74b4d72c9353bcf90255baba56 (diff) |
Merge branch 'master' of ssh://cvs.cs.unc.edu/cvs/proj/litmus/repo/rthp
Diffstat (limited to 'conferences.py')
-rwxr-xr-x | conferences.py | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/conferences.py b/conferences.py new file mode 100755 index 0000000..067eb6e --- /dev/null +++ b/conferences.py | |||
@@ -0,0 +1,170 @@ | |||
1 | #!/usr/bin/env python | ||
2 | |||
3 | from __future__ import print_function | ||
4 | |||
5 | import sys | ||
6 | import csv | ||
7 | from functools import total_ordering | ||
8 | from datetime import datetime | ||
9 | from operator import attrgetter | ||
10 | |||
11 | """Read CSV and make HTML for the conference page. | ||
12 | |||
13 | Handles sorting dates, TBD dates, dates in the past, and more. | ||
14 | No guarantees that this is bug free :) | ||
15 | |||
16 | Author: Christopher Kenna (2012) | ||
17 | |||
18 | """ | ||
19 | |||
20 | @total_ordering | ||
21 | class ConferenceDate(object): | ||
22 | TBD_STR = 'tbd' | ||
23 | TBD_VAL = 'tbd' | ||
24 | |||
25 | def __init__(self, date): | ||
26 | if isinstance(date, datetime): | ||
27 | self.dt = date | ||
28 | else: | ||
29 | self.dt = self.date_from_str(date) | ||
30 | |||
31 | @classmethod | ||
32 | def date_from_str(cls, date_str): | ||
33 | try: | ||
34 | return datetime.strptime(date_str, '%m/%d/%Y') | ||
35 | except ValueError: | ||
36 | if cls.TBD_STR == date_str.lower(): | ||
37 | return cls.TBD_VAL | ||
38 | die('bad date: {0}'.format(date_str)) | ||
39 | |||
40 | @classmethod | ||
41 | def get_timespan(cls, start, end): | ||
42 | ret = [] | ||
43 | if start is end: | ||
44 | ret.append(cls.html_date(start)) | ||
45 | elif (not start.is_tbd() and not end.is_tbd() and | ||
46 | start.dt.month == end.dt.month): | ||
47 | ret.append(start.dt.strftime('%b. {0}'.format(start.dt.day))) | ||
48 | ret.append('–') | ||
49 | ret.append(end.dt.strftime('{0}, %Y'.format(end.dt.day))) | ||
50 | else: | ||
51 | ret.extend([cls.html_date(start), '&endash;', | ||
52 | cls.html_date(end)]) | ||
53 | return ' '.join(ret) | ||
54 | |||
55 | @classmethod | ||
56 | def html_date(cls, d): | ||
57 | if d.is_tbd(): | ||
58 | return 'TBD' | ||
59 | # using string format to get '2' and not '02' | ||
60 | return d.dt.strftime('%b. {0}, %Y'.format(d.dt.day)) | ||
61 | |||
62 | def __eq__(self, other): | ||
63 | a_is_tbd, b_is_tbd = self.is_tbd(), other.is_tbd() | ||
64 | if a_is_tbd and b_is_tbd: | ||
65 | return True | ||
66 | elif a_is_tbd or b_is_tbd: | ||
67 | return False | ||
68 | else: | ||
69 | return self.dt == other.dt | ||
70 | |||
71 | def __lt__(self, other): | ||
72 | a_is_tbd, b_is_tbd = self.is_tbd(), other.is_tbd() | ||
73 | if not a_is_tbd and not b_is_tbd: | ||
74 | return self.dt < other.dt | ||
75 | if not a_is_tbd and b_is_tbd: | ||
76 | return True | ||
77 | else: | ||
78 | # (a_is_tbd and not b_is_tbd) or (a_is_tbd and b_is_tbd) | ||
79 | return False | ||
80 | |||
81 | def is_tbd(self): | ||
82 | return ConferenceDate.TBD_VAL == self.dt | ||
83 | |||
84 | def in_past(self): | ||
85 | return self < ConferenceDate(datetime.now()) | ||
86 | |||
87 | def in_past_style(self): | ||
88 | return 'color: red' if self.in_past() else None | ||
89 | |||
90 | |||
91 | @total_ordering | ||
92 | class Conference(object): | ||
93 | def __init__(self, name, url, location, deadline, start, end=None): | ||
94 | self.name = name | ||
95 | self.url = url | ||
96 | self.location = location | ||
97 | self.deadline = ConferenceDate(deadline) | ||
98 | self.start = ConferenceDate(start) | ||
99 | self.end = self.start if end is None else ConferenceDate(end) | ||
100 | |||
101 | if self.end < self.start: | ||
102 | die('start before end for {0}'.format(self.name)) | ||
103 | |||
104 | @classmethod | ||
105 | def make_td(cls, contents, style=None): | ||
106 | _style = '' | ||
107 | if style is not None: | ||
108 | _style = ' style="{0}"'.format(style) | ||
109 | return '<td{0}>{1}</td>'.format(_style, contents) | ||
110 | |||
111 | def __eq__(self, other): | ||
112 | cmps = ('deadline', 'name', 'url', 'location', 'start', 'end') | ||
113 | for s in cmps: | ||
114 | ag = attrgetter(s) | ||
115 | if ag(self) != ag(other): | ||
116 | return False | ||
117 | return True | ||
118 | |||
119 | def __lt__(self, other): | ||
120 | cmps = ('deadline', 'name', 'url', 'location', 'start', 'end') | ||
121 | for s in cmps: | ||
122 | ag = attrgetter(s) | ||
123 | a, b = ag(self), ag(other) | ||
124 | if a < b: | ||
125 | return True | ||
126 | elif a > b: | ||
127 | return False | ||
128 | return False | ||
129 | |||
130 | def html(self): | ||
131 | s = ['<tr>'] | ||
132 | s.append(self.make_td(ConferenceDate.html_date(self.deadline), | ||
133 | style=self.deadline.in_past_style())) | ||
134 | s.append(self.make_td('<a href="{0}">{1}</a>'.format( | ||
135 | self.url, self.name))) | ||
136 | s.append(self.make_td(self.location)) | ||
137 | s.append(self.make_td(ConferenceDate.get_timespan(self.start, self.end))) | ||
138 | s.append('</tr>') | ||
139 | return ''.join(s) | ||
140 | |||
141 | |||
142 | def die(msg, e=None): | ||
143 | print(msg, file=sys.stderr) | ||
144 | sys.exit(1) | ||
145 | |||
146 | |||
147 | def load_conferences(in_f): | ||
148 | c = [] | ||
149 | r = csv.reader(open(in_f, 'r')) | ||
150 | for row in r: | ||
151 | try: | ||
152 | c.append(Conference(*row)) | ||
153 | except TypeError as e: | ||
154 | print('error on {0}'.format(row), file=sys.stderr) | ||
155 | die('error message: {0}'.format(e.message)) | ||
156 | return c | ||
157 | |||
158 | |||
159 | def main(): | ||
160 | if len(sys.argv) < 2: | ||
161 | die('usage: {0} <CSV file>'.format(sys.argv[0])) | ||
162 | |||
163 | in_f = sys.argv[1] | ||
164 | conferences = load_conferences(in_f) | ||
165 | for c in sorted(conferences): | ||
166 | print(c.html()) | ||
167 | |||
168 | |||
169 | if __name__ == '__main__': | ||
170 | main() | ||