~launchpad-pqm/launchpad/devel

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