~launchpad-pqm/launchpad/devel

2162 by Canonical.com Patch Queue Manager
cleanup and portlet love [r=stevea]
1
Polls
2
=====
3
4
In Launchpad, we have teams as a way to group free software
5
developers/contributors usually based on the free software
6
product/project/distribution they're involved in. This is the case with teams
7
like the 'Gnome Team' and the 'Ubuntu Team'. These teams often have leaders
8
whose ellection depends on the vote of all members, and this is one of the
9
reasons why we teams can have polls attached to them.
10
11666.3.1 by Curtis Hovey
Merged apocalypse-0 into this branch to fix translations and codehosting.
11
  >>> import pytz
12
  >>> from datetime import datetime, timedelta
13
  >>> from zope.component import getUtility
14
  >>> from canonical.database.sqlbase import flush_database_updates
14600.1.2 by Curtis Hovey
Updated callsites to import from lp.testing, where the code has been for years.
15
  >>> from lp.testing import login
11716.1.6 by Curtis Hovey
Converted glob imports in doctests to import for the true module.
16
  >>> from lp.registry.interfaces.person import IPersonSet
11716.1.15 by Curtis Hovey
Fixed multiline import statements in doctests.
17
  >>> from lp.registry.interfaces.poll import (
11716.1.12 by Curtis Hovey
Sorted imports in doctests.
18
  ...     IPollSubset,
19
  ...     PollAlgorithm,
20
  ...     PollSecrecy,
21
  ...     )
2162 by Canonical.com Patch Queue Manager
cleanup and portlet love [r=stevea]
22
11666.3.1 by Curtis Hovey
Merged apocalypse-0 into this branch to fix translations and codehosting.
23
  >>> team = getUtility(IPersonSet).getByName('ubuntu-team')
24
  >>> member = getUtility(IPersonSet).getByName('stevea')
25
  >>> member2 = getUtility(IPersonSet).getByName('jdub')
26
  >>> member3 = getUtility(IPersonSet).getByName('kamion')
27
  >>> member4 = getUtility(IPersonSet).getByName('name16')
28
  >>> member5 = getUtility(IPersonSet).getByName('limi')
29
  >>> nonmember = getUtility(IPersonSet).getByName('justdave')
30
  >>> now = datetime.now(pytz.timezone('UTC'))
31
  >>> onesec = timedelta(seconds=1)
2162 by Canonical.com Patch Queue Manager
cleanup and portlet love [r=stevea]
32
2865.2.7 by Celso Providelo
Integrating DB tweaks required for upload-and-queue and breezy-autotest, renaming and fixing tests.
33
We need to login with one of the administrators of the team named 
34
'ubuntu-team' to be able to create/edit polls.
2162 by Canonical.com Patch Queue Manager
cleanup and portlet love [r=stevea]
35
  >>> login('colin.watson@ubuntulinux.com')
36
37
First we get an object implementing IPollSubset, which is the set of polls for
38
a given team (in our case, the 'Ubuntu Team')
39
  >>> pollsubset = IPollSubset(team)
40
41
Now we create a new poll on this team.
42
  >>> opendate = datetime(2005, 01, 01, tzinfo=pytz.timezone('UTC'))
43
  >>> closedate = opendate + timedelta(weeks=2)
2219 by Canonical.com Patch Queue Manager
Some fixes as per Steve review. Do not use Subsets to traverse; instead do the traversal by consuming items from the traversal stack. r=SteveA
44
  >>> title = "2005 Leader's Elections"
45
  >>> proposition = "Who's going to be the next leader?"
46
  >>> type = PollAlgorithm.SIMPLE
47
  >>> secrecy = PollSecrecy.SECRET
48
  >>> allowspoilt = True
49
  >>> poll = pollsubset.new("leader-election", title, proposition, opendate,
2491 by Canonical.com Patch Queue Manager
Simple and Condorcet polls (although the latter is disabled for now) for teams. r=BjornT
50
  ...                       closedate, secrecy, allowspoilt, type)
2162 by Canonical.com Patch Queue Manager
cleanup and portlet love [r=stevea]
51
52
Now we test the if the poll is open or closed in some specific dates.
53
  >>> poll.isOpen(when=opendate)
54
  True
55
  >>> poll.isOpen(when=opendate - onesec)
56
  False
57
  >>> poll.isOpen(when=closedate)
58
  True
59
  >>> poll.isOpen(when=closedate + onesec)
60
  False
61
62
To know what polls are open/closed/not-yet-opened in a team, you can use the
63
methods of PollSubset.
64
Here we'll query using three different dates:
65
66
Query for open polls in the exact second the poll is opening.
67
  >>> [p.name for p in pollsubset.getOpenPolls(when=opendate)]
12156.3.1 by Curtis Hovey
Restored polls so that they can be used by a handful of important teams once a year.
68
  [u'leader-election', u'never-closes', u'never-closes2', u'never-closes3',
69
   u'never-closes4']
2162 by Canonical.com Patch Queue Manager
cleanup and portlet love [r=stevea]
70
71
Query for closed polls, one second after the poll closes.
72
  >>> [p.name for p in pollsubset.getClosedPolls(when=closedate + onesec)]
2491 by Canonical.com Patch Queue Manager
Simple and Condorcet polls (although the latter is disabled for now) for teams. r=BjornT
73
  [u'director-2004', u'leader-2004', u'leader-election']
2162 by Canonical.com Patch Queue Manager
cleanup and portlet love [r=stevea]
74
75
Query for not-yet-opened polls, one second before the poll opens.
76
  >>> [p.name for p in pollsubset.getNotYetOpenedPolls(when=opendate - onesec)]
12156.3.1 by Curtis Hovey
Restored polls so that they can be used by a handful of important teams once a year.
77
  [u'leader-election', u'not-yet-opened']
2162 by Canonical.com Patch Queue Manager
cleanup and portlet love [r=stevea]
78
79
All polls must have a set of options for people to choose, and they'll always
80
start with zero options. We're responsible for adding new ones.
12156.3.1 by Curtis Hovey
Restored polls so that they can be used by a handful of important teams once a year.
81
  >>> poll.getAllOptions().count()
2162 by Canonical.com Patch Queue Manager
cleanup and portlet love [r=stevea]
82
  0
83
84
Let's add some options to this poll, so people can start voting. :)
2736.1.11 by Mark Shuttleworth
poll system fixes
85
  >>> will = poll.newOption('wgraham', 'Will Graham')
86
  >>> jack = poll.newOption('jcrawford', 'Jack Crawford')
87
  >>> francis = poll.newOption('fd', 'Francis Dolarhyde')
88
  >>> [o.title for o in poll.getActiveOptions()]
2162 by Canonical.com Patch Queue Manager
cleanup and portlet love [r=stevea]
89
  [u'Francis Dolarhyde', u'Jack Crawford', u'Will Graham']
90
91
Now, what happens if the poll is already open and, let's say, Francis Dolarhyde
2219 by Canonical.com Patch Queue Manager
Some fixes as per Steve review. Do not use Subsets to traverse; instead do the traversal by consuming items from the traversal stack. r=SteveA
92
is convicted and thus becomes ineligible? We'll have to mark that option as
2162 by Canonical.com Patch Queue Manager
cleanup and portlet love [r=stevea]
93
inactive, so people can't vote on it.
94
  >>> francis.active = False
95
  >>> flush_database_updates()
2736.1.11 by Mark Shuttleworth
poll system fixes
96
  >>> [o.title for o in poll.getActiveOptions()]
2162 by Canonical.com Patch Queue Manager
cleanup and portlet love [r=stevea]
97
  [u'Jack Crawford', u'Will Graham']
98
2491 by Canonical.com Patch Queue Manager
Simple and Condorcet polls (although the latter is disabled for now) for teams. r=BjornT
99
If the poll is not yet opened, it's possible to simply remove a given option.
100
  >>> poll.removeOption(will, when=opendate - onesec)
2736.1.11 by Mark Shuttleworth
poll system fixes
101
  >>> [o.title for o in poll.getAllOptions()]
2491 by Canonical.com Patch Queue Manager
Simple and Condorcet polls (although the latter is disabled for now) for teams. r=BjornT
102
  [u'Francis Dolarhyde', u'Jack Crawford']
103
104
Any member of the team this poll refers to is eligible to vote, if the poll is
105
still open.
106
107
  >>> vote1 = poll.storeSimpleVote(member, jack, when=opendate)
108
  >>> vote2 = poll.storeSimpleVote(member2, None, when=opendate)
109
110
111
Now we create a Condorcet poll on this team and add some options to it, so
112
people can start voting.
113
114
  >>> title = "2005 Director's Elections"
115
  >>> proposition = "Who's going to be the next director?"
116
  >>> type = PollAlgorithm.CONDORCET
117
  >>> secrecy = PollSecrecy.SECRET
118
  >>> allowspoilt = True
119
  >>> poll2 = pollsubset.new("director-election", title, proposition, opendate,
120
  ...                        closedate, secrecy, allowspoilt, type)
2736.1.11 by Mark Shuttleworth
poll system fixes
121
  >>> a = poll2.newOption('A', 'Option A')
122
  >>> b = poll2.newOption('B', 'Option B')
123
  >>> c = poll2.newOption('C', 'Option C')
124
  >>> d = poll2.newOption('D', 'Option D')
2491 by Canonical.com Patch Queue Manager
Simple and Condorcet polls (although the latter is disabled for now) for teams. r=BjornT
125
126
  >>> options = {b: 1, d: 2, c: 3}
127
  >>> votes = poll2.storeCondorcetVote(member, options, when=opendate)
128
  >>> options = {d: 1, b: 2}
129
  >>> votes = poll2.storeCondorcetVote(member2, options, when=opendate)
130
  >>> options = {a: 1, c: 2, b: 3}
131
  >>> votes = poll2.storeCondorcetVote(member3, options, when=opendate)
132
  >>> options = {a: 1}
133
  >>> votes = poll2.storeCondorcetVote(member4, options, when=opendate)
134
  >>> for row in poll2.getPairwiseMatrix():
135
  ...     print row
136
  [None, 2L, 2L, 2L]
137
  [2L, None, 2L, 2L]
138
  [1L, 1L, None, 1L]
139
  [2L, 1L, 2L, None]
2162 by Canonical.com Patch Queue Manager
cleanup and portlet love [r=stevea]
140