~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to utilities/prioritygrid.py

  • Committer: Jonathan Lange
  • Date: 2009-08-31 05:15:30 UTC
  • mto: This revision was merged to the branch mainline in revision 9271.
  • Revision ID: jml@canonical.com-20090831051530-pex7jge5d54ixay2
Add lp-dev-tools that lack license confusion, changing the license to match
the rest of the Launchpad source tree.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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