9265.1.1
by Jonathan Lange
Add lp-dev-tools that lack license confusion, changing the license to match |
1 |
#!/usr/bin/env python
|
2 |
#
|
|
3 |
# Copyright 2009 Canonical Ltd. This software is licensed under the
|
|
4 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
|
5 |
||
6 |
# Use this to calculate priorities based on Wiki priority lists such as
|
|
7 |
# https://launchpad.canonical.com/VersionThreeDotO/Bugs/Inputs
|
|
8 |
||
9 |
||
10 |
import sys |
|
11 |
||
14612.2.6
by William Grant
utilities |
12 |
|
9265.1.1
by Jonathan Lange
Add lp-dev-tools that lack license confusion, changing the license to match |
13 |
class Row: |
14 |
def __init__(self, scores, trailing): |
|
15 |
self.scores = scores |
|
16 |
self.trailing = trailing |
|
17 |
||
18 |
||
19 |
def append_average(items, adjusted_scores, row): |
|
20 |
if len(adjusted_scores) == 0: |
|
21 |
avg = len(rows_of_scores) |
|
22 |
else: |
|
23 |
avg = sum(adjusted_scores)/len(adjusted_scores) |
|
24 |
items.append((avg, "||%4.1f||%s" % (avg, row.trailing))) |
|
25 |
||
26 |
||
27 |
def blanks_dont_count(rows_of_scores): |
|
28 |
items = [] |
|
29 |
for row in rows_of_scores: |
|
30 |
adjusted_scores = [] |
|
31 |
for score in row.scores: |
|
32 |
if score == -1: |
|
33 |
continue
|
|
34 |
adjusted_scores.append(score) |
|
35 |
append_average(items, adjusted_scores, row) |
|
36 |
items.sort() |
|
37 |
return items |
|
38 |
||
39 |
||
40 |
def blanks_are_heavy(rows_of_scores, half=False): |
|
41 |
items = [] |
|
42 |
for row in rows_of_scores: |
|
43 |
adjusted_scores = [] |
|
44 |
for score in row.scores: |
|
45 |
if score == -1: |
|
46 |
score = len(rows_of_scores) |
|
47 |
if half: |
|
48 |
score = score/2 |
|
49 |
adjusted_scores.append(score) |
|
50 |
append_average(items, adjusted_scores, row) |
|
51 |
items.sort() |
|
52 |
return items |
|
53 |
||
54 |
||
55 |
def less_is_more(rows_of_scores): |
|
56 |
total_per_column = {} |
|
57 |
for row in rows_of_scores: |
|
58 |
scores = row.scores |
|
59 |
for i in range(0, len(scores)): |
|
60 |
score = scores[i] |
|
61 |
total_per_column.setdefault(i, 0) |
|
62 |
if score != -1: |
|
63 |
total_per_column[i] += 1 |
|
64 |
print total_per_column |
|
65 |
items = [] |
|
66 |
for row in rows_of_scores: |
|
67 |
scores = row.scores |
|
68 |
adjusted_scores = [] |
|
69 |
for i in range(0, len(scores)): |
|
70 |
score = scores[i] |
|
71 |
if score == -1: |
|
72 |
score = len(rows_of_scores) |
|
73 |
weight = total_per_column[i] |
|
74 |
adjusted_scores.append(score*weight) |
|
75 |
append_average(items, adjusted_scores, row) |
|
76 |
items.sort() |
|
77 |
return items |
|
78 |
||
79 |
||
80 |
def condorcet(rows_of_scores): |
|
81 |
raise NotImplementedError |
|
82 |
||
83 |
||
84 |
def parse_scores(str): |
|
85 |
rows = [] |
|
86 |
head = [] |
|
87 |
tail = [] |
|
88 |
ate_first_line = False |
|
89 |
# We drop the first split element because the line starts with a ||
|
|
90 |
delta = 1 |
|
91 |
for s in str: |
|
92 |
if not s.strip().startswith("||"): |
|
93 |
# Regular output; just output it
|
|
94 |
if rows: |
|
95 |
tail.append(s) |
|
96 |
else: |
|
97 |
head.append(s) |
|
98 |
continue
|
|
99 |
||
100 |
if not ate_first_line: |
|
101 |
ate_first_line = True |
|
102 |
# Let's take a look at the header
|
|
103 |
if s.strip().startswith("|| * "): |
|
104 |
# Get rid of scores since we're recalculating
|
|
105 |
delta += 1 |
|
106 |
head.append(s) |
|
107 |
else: |
|
108 |
head.append("|| * " + s) |
|
109 |
continue
|
|
110 |
||
111 |
scores = [] |
|
112 |
columns = s.split("||")[delta:] |
|
113 |
for col_idx, score in enumerate(columns): |
|
114 |
score = score.strip() |
|
115 |
if score: |
|
116 |
first_char = score[0] |
|
117 |
if not first_char.isdigit() and not first_char == "-": |
|
118 |
# We hit some text, get out of here
|
|
119 |
break
|
|
120 |
try: |
|
121 |
score = float(score) |
|
122 |
except ValueError: |
|
123 |
# If no value was input, we assume it is equivalent to being
|
|
124 |
# the last option for this voter.
|
|
125 |
score = -1 |
|
126 |
scores.append(score) |
|
127 |
rows.append(Row(scores, '||'.join(columns))) |
|
128 |
return rows, head, tail |
|
129 |
||
130 |
||
131 |
if __name__ == "__main__": |
|
132 |
str = sys.stdin.read().strip().splitlines() |
|
133 |
rows_of_scores, head, tail = parse_scores(str) |
|
134 |
if len(sys.argv) > 1 and sys.argv[1] == "less-is-more": |
|
135 |
func = less_is_more |
|
136 |
elif len(sys.argv) > 1 and sys.argv[1] == "condorcet": |
|
137 |
func = condorcet |
|
138 |
elif len(sys.argv) > 1 and sys.argv[1] == "blanks-dont-count": |
|
139 |
func = blanks_dont_count |
|
140 |
else: |
|
141 |
func = blanks_are_heavy |
|
142 |
items = func(rows_of_scores) |
|
143 |
print "\n".join(head) |
|
144 |
print "\n".join([i[1] for i in items]) |
|
145 |
print "\n".join(tail) |
|
146 |