launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #24958
[Merge] ~cjwatson/launchpad:stormify-poll into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:stormify-poll into launchpad:master.
Commit message:
Convert Poll and friends to Storm
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/386813
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:stormify-poll into launchpad:master.
diff --git a/lib/lp/registry/adapters.py b/lib/lp/registry/adapters.py
index ac453fe..e5016c4 100644
--- a/lib/lp/registry/adapters.py
+++ b/lib/lp/registry/adapters.py
@@ -89,29 +89,29 @@ class PollSubset:
"""See IPollSubset."""
assert self.team is not None, (
'team cannot be None to call this method.')
- return getUtility(IPollSet).selectByTeam(self.team)
+ return getUtility(IPollSet).findByTeam(self.team)
def getOpenPolls(self, when=None):
"""See IPollSubset."""
assert self.team is not None, (
'team cannot be None to call this method.')
- return getUtility(IPollSet).selectByTeam(
- self.team, [PollStatus.OPEN], orderBy='datecloses', when=when)
+ return getUtility(IPollSet).findByTeam(
+ self.team, [PollStatus.OPEN], order_by='datecloses', when=when)
def getClosedPolls(self, when=None):
"""See IPollSubset."""
assert self.team is not None, (
'team cannot be None to call this method.')
- return getUtility(IPollSet).selectByTeam(
- self.team, [PollStatus.CLOSED], orderBy='datecloses', when=when)
+ return getUtility(IPollSet).findByTeam(
+ self.team, [PollStatus.CLOSED], order_by='datecloses', when=when)
def getNotYetOpenedPolls(self, when=None):
"""See IPollSubset."""
assert self.team is not None, (
'team cannot be None to call this method.')
- return getUtility(IPollSet).selectByTeam(
+ return getUtility(IPollSet).findByTeam(
self.team, [PollStatus.NOT_YET_OPENED],
- orderBy='dateopens', when=when)
+ order_by='dateopens', when=when)
def productseries_to_product(productseries):
diff --git a/lib/lp/registry/browser/person.py b/lib/lp/registry/browser/person.py
index e46cce4..8ece6c2 100644
--- a/lib/lp/registry/browser/person.py
+++ b/lib/lp/registry/browser/person.py
@@ -1676,17 +1676,17 @@ class PersonView(LaunchpadView, FeedsMixin, ContactViaWebLinksMixin):
@cachedproperty
def openpolls(self):
assert self.context.is_team
- return IPollSubset(self.context).getOpenPolls()
+ return list(IPollSubset(self.context).getOpenPolls())
@cachedproperty
def closedpolls(self):
assert self.context.is_team
- return IPollSubset(self.context).getClosedPolls()
+ return list(IPollSubset(self.context).getClosedPolls())
@cachedproperty
def notyetopenedpolls(self):
assert self.context.is_team
- return IPollSubset(self.context).getNotYetOpenedPolls()
+ return list(IPollSubset(self.context).getNotYetOpenedPolls())
@cachedproperty
def contributions(self):
diff --git a/lib/lp/registry/browser/tests/poll-views.txt b/lib/lp/registry/browser/tests/poll-views.txt
index 2b67312..b9e1e65 100644
--- a/lib/lp/registry/browser/tests/poll-views.txt
+++ b/lib/lp/registry/browser/tests/poll-views.txt
@@ -60,7 +60,7 @@ has not opened.
>>> close_date = open_date + timedelta(weeks=1)
>>> poll_subset = IPollSubset(team)
>>> poll = poll_subset.new(
- ... 'name', 'title', 'proposition', open_date, close_date,
+ ... u'name', u'title', u'proposition', open_date, close_date,
... PollSecrecy.OPEN, False)
>>> ignored = login_person(user)
diff --git a/lib/lp/registry/browser/tests/poll-views_0.txt b/lib/lp/registry/browser/tests/poll-views_0.txt
index b55c376..a89220f 100644
--- a/lib/lp/registry/browser/tests/poll-views_0.txt
+++ b/lib/lp/registry/browser/tests/poll-views_0.txt
@@ -53,7 +53,8 @@ Now we successfully create a poll which starts 12h from now.
== Displaying results of condorcet polls ==
- >>> poll = getUtility(IPollSet).getByTeamAndName(ubuntu_team, 'director-2004')
+ >>> poll = getUtility(IPollSet).getByTeamAndName(
+ ... ubuntu_team, u'director-2004')
>>> poll.type.title
'Condorcet Voting'
diff --git a/lib/lp/registry/browser/tests/test_breadcrumbs.py b/lib/lp/registry/browser/tests/test_breadcrumbs.py
index 020dfe5..6c30093 100644
--- a/lib/lp/registry/browser/tests/test_breadcrumbs.py
+++ b/lib/lp/registry/browser/tests/test_breadcrumbs.py
@@ -1,12 +1,15 @@
# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
from zope.component import getUtility
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
from lp.registry.browser.tests.test_pillar_sharing import SharingBaseTestCase
+from lp.registry.interfaces.nameblacklist import INameBlacklistSet
from lp.services.webapp.publisher import canonical_url
from lp.testing import login_person
from lp.testing.breadcrumbs import BaseBreadcrumbTestCase
@@ -153,8 +156,6 @@ class TestPollBreadcrumb(BaseBreadcrumbTestCase):
last_crumb = crumbs[-1]
self.assertEqual(self.poll.title, last_crumb.text)
-from lp.registry.interfaces.nameblacklist import INameBlacklistSet
-
class TestNameblacklistBreadcrumb(BaseBreadcrumbTestCase):
"""Test breadcrumbs for +nameblacklist."""
diff --git a/lib/lp/registry/browser/tests/test_poll.py b/lib/lp/registry/browser/tests/test_poll.py
index 8dc202a..825bb81 100644
--- a/lib/lp/registry/browser/tests/test_poll.py
+++ b/lib/lp/registry/browser/tests/test_poll.py
@@ -3,6 +3,8 @@
"""Tests for IPoll views."""
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
import os
diff --git a/lib/lp/registry/doc/person-merge.txt b/lib/lp/registry/doc/person-merge.txt
index ffb12b9..40b7030 100644
--- a/lib/lp/registry/doc/person-merge.txt
+++ b/lib/lp/registry/doc/person-merge.txt
@@ -384,7 +384,7 @@ hand, are carried over just like when merging people.
>>> today = datetime.now(pytz.timezone('UTC'))
>>> tomorrow = today + timedelta(days=1)
>>> poll = IPollSubset(test_team).new(
- ... 'test-poll', 'Title', 'Proposition', today, tomorrow,
+ ... u'test-poll', u'Title', u'Proposition', today, tomorrow,
... PollSecrecy.OPEN, allowspoilt=True)
# test_team has a superteam, one active member and a poll.
@@ -399,7 +399,7 @@ hand, are carried over just like when merging people.
[u'name12']
>>> list(IPollSubset(test_team).getAll())
- [<Poll at ...]
+ [<lp.registry.model.poll.Poll object at ...]
# Landscape-developers has no super teams, two members and no polls.
diff --git a/lib/lp/registry/doc/poll-preconditions.txt b/lib/lp/registry/doc/poll-preconditions.txt
index a4b5374..f1fcc1c 100644
--- a/lib/lp/registry/doc/poll-preconditions.txt
+++ b/lib/lp/registry/doc/poll-preconditions.txt
@@ -18,9 +18,9 @@ should be threated as so.
>>> pollset = getUtility(IPollSet)
>>> director_election = pollset.getByTeamAndName(ubuntu_team,
- ... 'director-2004')
+ ... u'director-2004')
>>> director_options = director_election.getActiveOptions()
- >>> leader_election = pollset.getByTeamAndName(ubuntu_team, 'leader-2004')
+ >>> leader_election = pollset.getByTeamAndName(ubuntu_team, u'leader-2004')
>>> leader_options = leader_election.getActiveOptions()
>>> opendate = leader_election.dateopens
>>> onesec = timedelta(seconds=1)
diff --git a/lib/lp/registry/doc/poll.txt b/lib/lp/registry/doc/poll.txt
index 269b9ec..6ef79a1 100644
--- a/lib/lp/registry/doc/poll.txt
+++ b/lib/lp/registry/doc/poll.txt
@@ -41,12 +41,12 @@ a given team (in our case, the 'Ubuntu Team')
Now we create a new poll on this team.
>>> opendate = datetime(2005, 1, 1, tzinfo=pytz.timezone('UTC'))
>>> closedate = opendate + timedelta(weeks=2)
- >>> title = "2005 Leader's Elections"
- >>> proposition = "Who's going to be the next leader?"
+ >>> title = u"2005 Leader's Elections"
+ >>> proposition = u"Who's going to be the next leader?"
>>> type = PollAlgorithm.SIMPLE
>>> secrecy = PollSecrecy.SECRET
>>> allowspoilt = True
- >>> poll = pollsubset.new("leader-election", title, proposition, opendate,
+ >>> poll = pollsubset.new(u"leader-election", title, proposition, opendate,
... closedate, secrecy, allowspoilt, type)
Now we test the if the poll is open or closed in some specific dates.
@@ -82,9 +82,9 @@ start with zero options. We're responsible for adding new ones.
0
Let's add some options to this poll, so people can start voting. :)
- >>> will = poll.newOption('wgraham', 'Will Graham')
- >>> jack = poll.newOption('jcrawford', 'Jack Crawford')
- >>> francis = poll.newOption('fd', 'Francis Dolarhyde')
+ >>> will = poll.newOption(u'wgraham', u'Will Graham')
+ >>> jack = poll.newOption(u'jcrawford', u'Jack Crawford')
+ >>> francis = poll.newOption(u'fd', u'Francis Dolarhyde')
>>> [o.title for o in poll.getActiveOptions()]
[u'Francis Dolarhyde', u'Jack Crawford', u'Will Graham']
@@ -111,17 +111,17 @@ still open.
Now we create a Condorcet poll on this team and add some options to it, so
people can start voting.
- >>> title = "2005 Director's Elections"
- >>> proposition = "Who's going to be the next director?"
+ >>> title = u"2005 Director's Elections"
+ >>> proposition = u"Who's going to be the next director?"
>>> type = PollAlgorithm.CONDORCET
>>> secrecy = PollSecrecy.SECRET
>>> allowspoilt = True
- >>> poll2 = pollsubset.new("director-election", title, proposition, opendate,
- ... closedate, secrecy, allowspoilt, type)
- >>> a = poll2.newOption('A', 'Option A')
- >>> b = poll2.newOption('B', 'Option B')
- >>> c = poll2.newOption('C', 'Option C')
- >>> d = poll2.newOption('D', 'Option D')
+ >>> poll2 = pollsubset.new(u"director-election", title, proposition,
+ ... opendate, closedate, secrecy, allowspoilt, type)
+ >>> a = poll2.newOption(u'A', u'Option A')
+ >>> b = poll2.newOption(u'B', u'Option B')
+ >>> c = poll2.newOption(u'C', u'Option C')
+ >>> d = poll2.newOption(u'D', u'Option D')
>>> options = {b: 1, d: 2, c: 3}
>>> votes = poll2.storeCondorcetVote(member, options, when=opendate)
diff --git a/lib/lp/registry/interfaces/poll.py b/lib/lp/registry/interfaces/poll.py
index a6dd40d..8fab288 100644
--- a/lib/lp/registry/interfaces/poll.py
+++ b/lib/lp/registry/interfaces/poll.py
@@ -296,16 +296,16 @@ class IPollSet(Interface):
secrecy, allowspoilt, poll_type=PollAlgorithm.SIMPLE):
"""Create a new Poll for the given team."""
- def selectByTeam(team, status=PollStatus.ALL, orderBy=None, when=None):
+ def findByTeam(team, status=PollStatus.ALL, order_by=None, when=None):
"""Return all Polls for the given team, filtered by status.
:status: is a sequence containing as many values as you want from
PollStatus.
- :orderBy: can be either a string with the column name you want to sort
- or a list of column names as strings.
- If no orderBy is specified the results will be ordered using the
- default ordering specified in Poll._defaultOrder.
+ :order_by: can be either a string with the column name you want to
+ sort or a list of column names as strings.
+ If no order_by is specified the results will be ordered using the
+ default ordering specified in Poll.sortingColumns.
The optional :when argument is used only by our tests, to test if the
poll is/was/will-be open at a specific date.
@@ -407,7 +407,7 @@ class IPollOptionSet(Interface):
def new(poll, name, title, active=True):
"""Create a new PollOption."""
- def selectByPoll(poll, only_active=False):
+ def findByPoll(poll, only_active=False):
"""Return all PollOptions of the given poll.
If :only_active is True, then return only the active polls.
diff --git a/lib/lp/registry/model/poll.py b/lib/lp/registry/model/poll.py
index b75852a..b34786b 100644
--- a/lib/lp/registry/model/poll.py
+++ b/lib/lp/registry/model/poll.py
@@ -1,6 +1,8 @@
# Copyright 2009 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
+from __future__ import absolute_import, print_function, unicode_literals
+
__metaclass__ = type
__all__ = [
'Poll',
@@ -16,16 +18,16 @@ __all__ = [
from datetime import datetime
import pytz
-from sqlobject import (
- AND,
- BoolCol,
- ForeignKey,
- IntCol,
- OR,
- SQLObjectNotFound,
- StringCol,
+from storm.locals import (
+ And,
+ Bool,
+ DateTime,
+ Int,
+ Or,
+ Reference,
+ Store,
+ Unicode,
)
-from storm.store import Store
from zope.component import getUtility
from zope.interface import implementer
@@ -44,43 +46,57 @@ from lp.registry.interfaces.poll import (
PollSecrecy,
PollStatus,
)
-from lp.services.database.datetimecol import UtcDateTimeCol
-from lp.services.database.enumcol import EnumCol
-from lp.services.database.sqlbase import (
- SQLBase,
- sqlvalues,
- )
+from lp.services.database.enumcol import DBEnum
+from lp.services.database.interfaces import IStore
+from lp.services.database.sqlbase import sqlvalues
+from lp.services.database.stormbase import StormBase
from lp.services.tokens import create_token
@implementer(IPoll)
-class Poll(SQLBase):
+class Poll(StormBase):
"""See IPoll."""
- _table = 'Poll'
+ __storm_table__ = 'Poll'
sortingColumns = ['title', 'id']
- _defaultOrder = sortingColumns
+ __storm_order__ = sortingColumns
+
+ id = Int(primary=True)
+
+ team_id = Int(
+ name='team', validator=validate_public_person, allow_none=False)
+ team = Reference(team_id, 'Person.id')
- team = ForeignKey(
- dbName='team', foreignKey='Person',
- storm_validator=validate_public_person, notNull=True)
+ name = Unicode(name='name', allow_none=False)
- name = StringCol(dbName='name', notNull=True)
+ title = Unicode(name='title', allow_none=False)
- title = StringCol(dbName='title', notNull=True, unique=True)
+ dateopens = DateTime(tzinfo=pytz.UTC, name='dateopens', allow_none=False)
- dateopens = UtcDateTimeCol(dbName='dateopens', notNull=True)
+ datecloses = DateTime(tzinfo=pytz.UTC, name='datecloses', allow_none=False)
- datecloses = UtcDateTimeCol(dbName='datecloses', notNull=True)
+ proposition = Unicode(name='proposition', allow_none=False)
- proposition = StringCol(dbName='proposition', notNull=True)
+ type = DBEnum(
+ name='type', enum=PollAlgorithm, default=PollAlgorithm.SIMPLE)
- type = EnumCol(dbName='type', enum=PollAlgorithm,
- default=PollAlgorithm.SIMPLE)
+ allowspoilt = Bool(name='allowspoilt', default=True, allow_none=False)
- allowspoilt = BoolCol(dbName='allowspoilt', default=True, notNull=True)
+ secrecy = DBEnum(
+ name='secrecy', enum=PollSecrecy, default=PollSecrecy.SECRET)
- secrecy = EnumCol(dbName='secrecy', enum=PollSecrecy,
- default=PollSecrecy.SECRET)
+ def __init__(self, team, name, title, proposition, dateopens, datecloses,
+ secrecy=PollSecrecy.SECRET, allowspoilt=True,
+ type=PollAlgorithm.SIMPLE):
+ super(Poll, self).__init__()
+ self.team = team
+ self.name = name
+ self.title = title
+ self.proposition = proposition
+ self.dateopens = dateopens
+ self.datecloses = datecloses
+ self.secrecy = secrecy
+ self.allowspoilt = allowspoilt
+ self.type = type
def newOption(self, name, title, active=True):
"""See IPoll."""
@@ -116,20 +132,20 @@ class Poll(SQLBase):
def getAllOptions(self):
"""See IPoll."""
- return getUtility(IPollOptionSet).selectByPoll(self)
+ return getUtility(IPollOptionSet).findByPoll(self)
def getActiveOptions(self):
"""See IPoll."""
- return getUtility(IPollOptionSet).selectByPoll(self, only_active=True)
+ return getUtility(IPollOptionSet).findByPoll(self, only_active=True)
def getVotesByPerson(self, person):
"""See IPoll."""
- return Vote.selectBy(person=person, poll=self)
+ return IStore(Vote).find(Vote, person=person, poll=self)
def personVoted(self, person):
"""See IPoll."""
- results = VoteCast.selectBy(person=person, poll=self)
- return bool(results.count())
+ results = IStore(VoteCast).find(VoteCast, person=person, poll=self)
+ return not results.is_empty()
def removeOption(self, option, when=None):
"""See IPoll."""
@@ -141,7 +157,7 @@ class Poll(SQLBase):
def getOptionByName(self, name):
"""See IPoll."""
- return PollOption.selectOneBy(poll=self, name=name)
+ return IStore(PollOption).find(PollOption, poll=self, name=name).one()
def _assertEverythingOkAndGetVoter(self, person, when=None):
"""Use assertions to Make sure all pre-conditions for a person to vote
@@ -210,7 +226,7 @@ class Poll(SQLBase):
def getTotalVotes(self):
"""See IPoll."""
assert self.isClosed()
- return Vote.selectBy(poll=self).count()
+ return IStore(Vote).find(Vote, poll=self).count()
def getWinners(self):
"""See IPoll."""
@@ -235,7 +251,7 @@ class Poll(SQLBase):
results = Store.of(self).execute(query).get_all()
if not results:
return None
- return [PollOption.get(id) for (id,) in results]
+ return [IStore(PollOption).get(PollOption, id) for (id,) in results]
def getPairwiseMatrix(self):
"""See IPoll."""
@@ -278,59 +294,72 @@ class PollSet:
def new(self, team, name, title, proposition, dateopens, datecloses,
secrecy, allowspoilt, poll_type=PollAlgorithm.SIMPLE):
"""See IPollSet."""
- return Poll(team=team, name=name, title=title,
- proposition=proposition, dateopens=dateopens,
- datecloses=datecloses, secrecy=secrecy,
- allowspoilt=allowspoilt, type=poll_type)
-
- def selectByTeam(self, team, status=PollStatus.ALL, orderBy=None,
- when=None):
+ poll = Poll(
+ team=team, name=name, title=title,
+ proposition=proposition, dateopens=dateopens,
+ datecloses=datecloses, secrecy=secrecy,
+ allowspoilt=allowspoilt, type=poll_type)
+ IStore(Poll).add(poll)
+ return poll
+
+ def findByTeam(self, team, status=PollStatus.ALL, order_by=None,
+ when=None):
"""See IPollSet."""
if when is None:
when = datetime.now(pytz.timezone('UTC'))
- if orderBy is None:
- orderBy = Poll.sortingColumns
+ if order_by is None:
+ order_by = Poll.sortingColumns
status = set(status)
status_clauses = []
if PollStatus.OPEN in status:
- status_clauses.append(AND(Poll.q.dateopens <= when,
- Poll.q.datecloses > when))
+ status_clauses.append(
+ And(Poll.dateopens <= when, Poll.datecloses > when))
if PollStatus.CLOSED in status:
- status_clauses.append(Poll.q.datecloses <= when)
+ status_clauses.append(Poll.datecloses <= when)
if PollStatus.NOT_YET_OPENED in status:
- status_clauses.append(Poll.q.dateopens > when)
+ status_clauses.append(Poll.dateopens > when)
assert len(status_clauses) > 0, "No poll statuses were selected"
- results = Poll.select(AND(Poll.q.teamID == team.id,
- OR(*status_clauses)))
+ results = IStore(Poll).find(
+ Poll, Poll.team == team, Or(*status_clauses))
- return results.orderBy(orderBy)
+ return results.order_by(order_by)
def getByTeamAndName(self, team, name, default=None):
"""See IPollSet."""
- query = AND(Poll.q.teamID == team.id, Poll.q.name == name)
- try:
- return Poll.selectOne(query)
- except SQLObjectNotFound:
- return default
+ poll = IStore(Poll).find(Poll, team=team, name=name).one()
+ return poll if poll is not None else default
@implementer(IPollOption)
-class PollOption(SQLBase):
+class PollOption(StormBase):
"""See IPollOption."""
- _table = 'PollOption'
- _defaultOrder = ['title', 'id']
+ __storm_table__ = 'PollOption'
+ __storm_order__ = ['title', 'id']
+
+ id = Int(primary=True)
+
+ poll_id = Int(name='poll', allow_none=False)
+ poll = Reference(poll_id, 'Poll.id')
- poll = ForeignKey(dbName='poll', foreignKey='Poll', notNull=True)
+ name = Unicode(allow_none=False)
- name = StringCol(notNull=True)
+ title = Unicode(allow_none=False)
- title = StringCol(notNull=True)
+ active = Bool(allow_none=False, default=False)
- active = BoolCol(notNull=True, default=False)
+ def __init__(self, poll, name, title, active=False):
+ super(PollOption, self).__init__()
+ self.poll = poll
+ self.name = name
+ self.title = title
+ self.active = active
+
+ def destroySelf(self):
+ IStore(PollOption).remove(self)
@implementer(IPollOptionSet)
@@ -339,36 +368,43 @@ class PollOptionSet:
def new(self, poll, name, title, active=True):
"""See IPollOptionSet."""
- return PollOption(poll=poll, name=name, title=title, active=active)
+ option = PollOption(poll=poll, name=name, title=title, active=active)
+ IStore(PollOption).add(option)
+ return option
- def selectByPoll(self, poll, only_active=False):
+ def findByPoll(self, poll, only_active=False):
"""See IPollOptionSet."""
- query = PollOption.q.pollID == poll.id
+ clauses = [PollOption.poll == poll]
if only_active:
- query = AND(query, PollOption.q.active == True)
- return PollOption.select(query)
+ clauses.append(PollOption.active)
+ return IStore(PollOption).find(PollOption, *clauses)
def getByPollAndId(self, poll, option_id, default=None):
"""See IPollOptionSet."""
- query = AND(PollOption.q.pollID == poll.id,
- PollOption.q.id == option_id)
- try:
- return PollOption.selectOne(query)
- except SQLObjectNotFound:
- return default
+ option = IStore(PollOption).find(
+ PollOption, poll=poll, id=option_id).one()
+ return option if option is not None else default
@implementer(IVoteCast)
-class VoteCast(SQLBase):
+class VoteCast(StormBase):
"""See IVoteCast."""
- _table = 'VoteCast'
- _defaultOrder = 'id'
+ __storm_table__ = 'VoteCast'
+ __storm_order__ = 'id'
+
+ id = Int(primary=True)
+
+ person_id = Int(
+ name='person', validator=validate_public_person, allow_none=False)
+ person = Reference(person_id, 'Person.id')
- person = ForeignKey(
- dbName='person', foreignKey='Person',
- storm_validator=validate_public_person, notNull=True)
+ poll_id = Int(name='poll', allow_none=False)
+ poll = Reference(poll_id, 'Poll.id')
- poll = ForeignKey(dbName='poll', foreignKey='Poll', notNull=True)
+ def __init__(self, person, poll):
+ super(VoteCast, self).__init__()
+ self.person = person
+ self.poll = poll
@implementer(IVoteCastSet)
@@ -377,26 +413,39 @@ class VoteCastSet:
def new(self, poll, person):
"""See IVoteCastSet."""
- return VoteCast(poll=poll, person=person)
+ vote_cast = VoteCast(poll=poll, person=person)
+ IStore(VoteCast).add(vote_cast)
+ return vote_cast
@implementer(IVote)
-class Vote(SQLBase):
+class Vote(StormBase):
"""See IVote."""
- _table = 'Vote'
- _defaultOrder = ['preference', 'id']
+ __storm_table__ = 'Vote'
+ __storm_order__ = ['preference', 'id']
- person = ForeignKey(
- dbName='person', foreignKey='Person',
- storm_validator=validate_public_person)
+ id = Int(primary=True)
- poll = ForeignKey(dbName='poll', foreignKey='Poll', notNull=True)
+ person_id = Int(name='person', validator=validate_public_person)
+ person = Reference(person_id, 'Person.id')
- option = ForeignKey(dbName='option', foreignKey='PollOption')
+ poll_id = Int(name='poll', allow_none=False)
+ poll = Reference(poll_id, 'Poll.id')
- preference = IntCol(dbName='preference')
+ option_id = Int(name='option')
+ option = Reference(option_id, 'PollOption.id')
- token = StringCol(dbName='token', notNull=True, unique=True)
+ preference = Int(name='preference')
+
+ token = Unicode(name='token', allow_none=False)
+
+ def __init__(self, poll, token, person=None, option=None, preference=None):
+ super(Vote, self).__init__()
+ self.poll = poll
+ self.token = token
+ self.person = person
+ self.option = option
+ self.preference = preference
@implementer(IVoteSet)
@@ -405,16 +454,19 @@ class VoteSet:
def new(self, poll, option, preference, token, person):
"""See IVoteSet."""
- return Vote(poll=poll, option=option, preference=preference,
- token=token, person=person)
+ vote = Vote(
+ poll=poll, option=option, preference=preference, token=token,
+ person=person)
+ IStore(Vote).add(vote)
+ return vote
def getByToken(self, token):
"""See IVoteSet."""
- return Vote.selectBy(token=token)
+ return IStore(Vote).find(Vote, token=token)
def getVotesByOption(self, option):
"""See IVoteSet."""
if option.poll.type != PollAlgorithm.SIMPLE:
raise OptionIsNotFromSimplePoll(
'%r is not an option of a simple-style poll.' % option)
- return Vote.selectBy(option=option).count()
+ return IStore(Vote).find(Vote, option=option).count()
diff --git a/lib/lp/registry/stories/team-polls/create-poll-options.txt b/lib/lp/registry/stories/team-polls/create-poll-options.txt
index 2a9711a..2af52e0 100644
--- a/lib/lp/registry/stories/team-polls/create-poll-options.txt
+++ b/lib/lp/registry/stories/team-polls/create-poll-options.txt
@@ -9,8 +9,8 @@ First we create a new poll to use throughout this test.
>>> from zope.component import getUtility
>>> from lp.registry.interfaces.person import IPersonSet
>>> factory.makePoll(getUtility(IPersonSet).getByName('ubuntu-team'),
- ... 'dpl-2080', 'dpl-2080', 'dpl-2080')
- <Poll...
+ ... u'dpl-2080', u'dpl-2080', u'dpl-2080')
+ <lp.registry.model.poll.Poll...
>>> logout()
Our poll is not yet open, so new options can be added to it.
diff --git a/lib/lp/registry/stories/team-polls/edit-poll.txt b/lib/lp/registry/stories/team-polls/edit-poll.txt
index 2590f56..7265ff3 100644
--- a/lib/lp/registry/stories/team-polls/edit-poll.txt
+++ b/lib/lp/registry/stories/team-polls/edit-poll.txt
@@ -9,8 +9,8 @@ First we create a new poll to use throughout this test.
>>> from zope.component import getUtility
>>> from lp.registry.interfaces.person import IPersonSet
>>> factory.makePoll(getUtility(IPersonSet).getByName('ubuntu-team'),
- ... 'dpl-2080', 'dpl-2080', 'dpl-2080')
- <Poll...
+ ... u'dpl-2080', u'dpl-2080', u'dpl-2080')
+ <lp.registry.model.poll.Poll...
>>> logout()
Now we'll try to change its name to something that is already in use.
diff --git a/lib/lp/registry/templates/poll-index.pt b/lib/lp/registry/templates/poll-index.pt
index de586e1..69a60f5 100644
--- a/lib/lp/registry/templates/poll-index.pt
+++ b/lib/lp/registry/templates/poll-index.pt
@@ -22,7 +22,7 @@
/>
<br />
- <p tal:condition="not: context/getActiveOptions">
+ <p tal:condition="python: context.getActiveOptions().is_empty()">
This poll does not yet have any voting options. Please <a
href="+newoption">add an option</a>. Note, you need more than one option
for a real poll, of course :-)
diff --git a/lib/lp/registry/tests/test_poll.py b/lib/lp/registry/tests/test_poll.py
index ad5386c..e2297fc 100644
--- a/lib/lp/registry/tests/test_poll.py
+++ b/lib/lp/registry/tests/test_poll.py
@@ -1,6 +1,8 @@
# Copyright 2009 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
+from __future__ import absolute_import, print_function, unicode_literals
+
from datetime import (
datetime,
timedelta,