Merge lp:~bac/launchpad/bug-488762-snapshot into lp:launchpad

Proposed by Brad Crittenden
Status: Merged
Approved by: Paul Hummer
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~bac/launchpad/bug-488762-snapshot
Merge into: lp:launchpad
Diff against target: 240 lines (+80/-52)
6 files modified
lib/canonical/launchpad/webapp/snapshot.py (+1/-1)
lib/lp/registry/doc/person.txt (+1/-3)
lib/lp/registry/interfaces/person.py (+62/-45)
lib/lp/registry/model/product.py (+0/-2)
lib/lp/registry/tests/test_person.py (+15/-0)
versions.cfg (+1/-1)
To merge this branch: bzr merge lp:~bac/launchpad/bug-488762-snapshot
Reviewer Review Type Date Requested Status
Paul Hummer (community) Approve
Review via email: mp+15628@code.launchpad.net

Commit message

Remove large collections from IPerson snapshots.

To post a comment you must log in.
Revision history for this message
Brad Crittenden (bac) wrote :
Download full text (3.6 KiB)

= Summary =

Editing large teams fails because taking a snapshot of the team includes all of the
collections for that team, big stuff like all of the members. There is no reason for
those collections to be part of the snapshot.

== Proposed fix ==

lazr.lifecycle has a new method 'doNotSnapshot' that can encapuslate a Field and make
it not be included in the snapshot. On IPerson all of the collections have been
wrapped in that method to prevent their inclusion.

== Pre-implementation notes ==

Chats with Curtis.

== Implementation details ==

As above.

== Tests ==

I've added a test to show that the fields I currently expect to be omitted from the
snapshot are in fact omitted. It's not a very interesting test but there to prevent
regression.

bin/test -vvm lp.registry -t test_person_snapshot

== Demo and Q/A ==

On staging become an admin and try to edit the team in the bug report. It should
succeed.

= Launchpad lint =

Bah!

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/canonical/launchpad/webapp/snapshot.py
  versions.cfg
  lib/lp/registry/doc/person.txt
  lib/lp/registry/interfaces/person.py
  lib/lp/registry/model/product.py
  lib/lp/registry/tests/test_person.py

== Pylint notices ==

lib/canonical/launchpad/webapp/snapshot.py
    11: [F0401] Unable to import 'lazr.lifecycle.interfaces' (No module named lifecycle)

lib/lp/registry/interfaces/person.py
    52: [F0401] Unable to import 'lazr.enum' (No module named enum)
    53: [F0401] Unable to import 'lazr.lifecycle.snapshot' (No module named lifecycle)
    54: [F0401] Unable to import 'lazr.restful.interface' (No module named restful)
    55: [F0401] Unable to import 'lazr.restful.declarations' (No module named restful)
    62: [F0401] Unable to import 'lazr.restful.fields' (No module named restful)
    406: [E1002, PersonNameField._validate] Use super on an old style class
    1401: [C0322, IPersonEditRestricted.addMember] Operator not preceded by a space
    status=copy_field(ITeamMembership['status']),
    ^
    comment=Text(required=False))
    @export_write_operation()
    def addMember(person, reviewer, status=TeamMembershipStatus.APPROVED,
    comment=None, force_team_add=False,
    may_subscribe_to_list=True):
    1433: [C0322, IPersonEditRestricted.acceptInvitationToBeMemberOf] Operator not
preceded by a space
    comment=Text())
    ^
    @export_write_operation()
    def acceptInvitationToBeMemberOf(team, comment):
    1445: [C0322, IPersonEditRestricted.declineInvitationToBeMemberOf] Operator not
preceded by a space
    comment=Text())
    ^
    @export_write_operation()
    def declineInvitationToBeMemberOf(team, comment):
    1737: [C0322, IPersonSet.newTeam] Operator not preceded by a space
    defaultmembershipperiod='default_membership_period',
    ^
    defaultrenewalperiod='default_renewal_period')
    @operation_parameters(
    subscriptionpolicy=Choice(
    title=_('Subscription policy'), vocabulary=TeamSubscriptionPolicy,
    required=False, default=TeamSubscriptionPolicy.MODERATED))
    @export_factory_operation(
    ITeam, ['name', 'displayname'...

Read more...

Revision history for this message
Paul Hummer (rockstar) wrote :

Please fix the "# DO NOT CHECK IN" code. Other than that, this is ready to land.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/webapp/snapshot.py'
--- lib/canonical/launchpad/webapp/snapshot.py 2009-06-25 05:30:52 +0000
+++ lib/canonical/launchpad/webapp/snapshot.py 2009-12-05 12:29:16 +0000
@@ -19,4 +19,4 @@
19 # SelectResults, which doesn't really help the Snapshot19 # SelectResults, which doesn't really help the Snapshot
20 # object. We therefore list()ify the values; this isn't20 # object. We therefore list()ify the values; this isn't
21 # perfect but allows deltas to be generated reliably.21 # perfect but allows deltas to be generated reliably.
22 return shortlist(value, longest_expected=100, hardlimit=5000)22 return shortlist(value, longest_expected=100, hardlimit=1000)
2323
=== modified file 'lib/lp/registry/doc/person.txt'
--- lib/lp/registry/doc/person.txt 2009-08-13 19:03:36 +0000
+++ lib/lp/registry/doc/person.txt 2009-12-05 12:29:16 +0000
@@ -626,9 +626,7 @@
626 {}626 {}
627627
628** See lib/canonical/launchpad/doc/teammembership.txt for more628** See lib/canonical/launchpad/doc/teammembership.txt for more
629information629information about team membership/participation.
630
631 about team membership/participation.
632630
633631
634=== Email notifications to teams ===632=== Email notifications to teams ===
635633
=== modified file 'lib/lp/registry/interfaces/person.py'
--- lib/lp/registry/interfaces/person.py 2009-12-04 22:24:18 +0000
+++ lib/lp/registry/interfaces/person.py 2009-12-05 12:29:16 +0000
@@ -50,7 +50,7 @@
50from zope.interface.interface import invariant50from zope.interface.interface import invariant
51from zope.component import getUtility51from zope.component import getUtility
52from lazr.enum import DBEnumeratedType, DBItem, EnumeratedType, Item52from lazr.enum import DBEnumeratedType, DBItem, EnumeratedType, Item
5353from lazr.lifecycle.snapshot import doNotSnapshot
54from lazr.restful.interface import copy_field54from lazr.restful.interface import copy_field
55from lazr.restful.declarations import (55from lazr.restful.declarations import (
56 LAZR_WEBSERVICE_EXPORTED, REQUEST_USER, call_with,56 LAZR_WEBSERVICE_EXPORTED, REQUEST_USER, call_with,
@@ -1198,75 +1198,92 @@
1198 # activemembers.value_type.schema will be set to IPerson once1198 # activemembers.value_type.schema will be set to IPerson once
1199 # IPerson is defined.1199 # IPerson is defined.
1200 activemembers = exported(1200 activemembers = exported(
1201 CollectionField(1201 doNotSnapshot(
1202 title=_("List of members with ADMIN or APPROVED status"),1202 CollectionField(
1203 value_type=Reference(schema=Interface)),1203 title=_("List of members with ADMIN or APPROVED status"),
1204 value_type=Reference(schema=Interface))),
1204 exported_as='members')1205 exported_as='members')
1205 adminmembers = exported(1206 adminmembers = exported(
1206 CollectionField(1207 doNotSnapshot(
1207 title=_("List of this team's admins."),1208 CollectionField(
1208 value_type=Reference(schema=Interface)),1209 title=_("List of this team's admins."),
1210 value_type=Reference(schema=Interface))),
1209 exported_as='admins')1211 exported_as='admins')
1210 all_member_count = Attribute(1212 all_member_count = Attribute(
1211 "The total number of real people who are members of this team, "1213 "The total number of real people who are members of this team, "
1212 "including subteams.")1214 "including subteams.")
1213 allmembers = exported(1215 allmembers = exported(
1214 CollectionField(1216 doNotSnapshot(
1215 title=_("All participants of this team."),1217 CollectionField(
1216 description=_(1218 title=_("All participants of this team."),
1217 "List of all direct and indirect people and teams who, one "1219 description=_(
1218 "way or another, are a part of this team. If you want a "1220 "List of all direct and indirect people and teams who, "
1219 "method to check if a given person is a member of a team, "1221 "one way or another, are a part of this team. If you "
1220 "you should probably look at IPerson.inTeam()."),1222 "want a method to check if a given person is a member "
1221 value_type=Reference(schema=Interface)),1223 "of a team, you should probably look at "
1224 "IPerson.inTeam()."),
1225 value_type=Reference(schema=Interface))),
1222 exported_as='participants')1226 exported_as='participants')
1223 approvedmembers = Attribute("List of members with APPROVED status")1227 approvedmembers = doNotSnapshot(
1228 Attribute("List of members with APPROVED status"))
1224 deactivated_member_count = Attribute("Number of deactivated members")1229 deactivated_member_count = Attribute("Number of deactivated members")
1225 deactivatedmembers = Attribute("List of members with DEACTIVATED status")
1226 deactivatedmembers = exported(1230 deactivatedmembers = exported(
1227 CollectionField(1231 doNotSnapshot(
1228 title=_(1232 CollectionField(
1229 "All members whose membership is in the DEACTIVATED state"),1233 title=_(
1230 value_type=Reference(schema=Interface)),1234 "All members whose membership is in the "
1235 "DEACTIVATED state"),
1236 value_type=Reference(schema=Interface))),
1231 exported_as='deactivated_members')1237 exported_as='deactivated_members')
1232 expired_member_count = Attribute("Number of EXPIRED members.")1238 expired_member_count = Attribute("Number of EXPIRED members.")
1233 expiredmembers = exported(1239 expiredmembers = exported(
1234 CollectionField(1240 doNotSnapshot(
1235 title=_("All members whose membership is in the EXPIRED state"),1241 CollectionField(
1236 value_type=Reference(schema=Interface)),1242 title=_("All members whose membership is in the "
1243 "EXPIRED state"),
1244 value_type=Reference(schema=Interface))),
1237 exported_as='expired_members')1245 exported_as='expired_members')
1238 inactivemembers = Attribute(1246 inactivemembers = doNotSnapshot(
1239 "List of members with EXPIRED or DEACTIVATED status")1247 Attribute(
1248 "List of members with EXPIRED or DEACTIVATED status"))
1240 inactive_member_count = Attribute("Number of inactive members")1249 inactive_member_count = Attribute("Number of inactive members")
1241 invited_members = exported(1250 invited_members = exported(
1242 CollectionField(1251 doNotSnapshot(
1243 title=_("All members whose membership is in the INVITED state"),1252 CollectionField(
1244 value_type=Reference(schema=Interface)))1253 title=_("All members whose membership is "
1254 "in the INVITED state"),
1255 value_type=Reference(schema=Interface))))
1256
1245 invited_member_count = Attribute("Number of members with INVITED status")1257 invited_member_count = Attribute("Number of members with INVITED status")
1246 member_memberships = exported(1258 member_memberships = exported(
1247 CollectionField(1259 doNotSnapshot(
1248 title=_("Active TeamMemberships for this object's members."),1260 CollectionField(
1249 description=_(1261 title=_("Active TeamMemberships for this object's members."),
1250 "Active TeamMemberships are the ones with the ADMIN or "1262 description=_(
1251 "APPROVED status. The results are ordered using "1263 "Active TeamMemberships are the ones with the ADMIN or "
1252 "Person.sortingColumns."),1264 "APPROVED status. The results are ordered using "
1253 readonly=True, required=False,1265 "Person.sortingColumns."),
1254 value_type=Reference(schema=ITeamMembership)),1266 readonly=True, required=False,
1267 value_type=Reference(schema=ITeamMembership))),
1255 exported_as='members_details')1268 exported_as='members_details')
1256 pendingmembers = Attribute(1269 pendingmembers = doNotSnapshot(
1257 "List of members with INVITED or PROPOSED status")1270 Attribute(
1271 "List of members with INVITED or PROPOSED status"))
1258 proposedmembers = exported(1272 proposedmembers = exported(
1259 CollectionField(1273 doNotSnapshot(
1260 title=_("All members whose membership is in the PROPOSED state"),1274 CollectionField(
1261 value_type=Reference(schema=Interface)),1275 title=_("All members whose membership is in the "
1276 "PROPOSED state"),
1277 value_type=Reference(schema=Interface))),
1262 exported_as='proposed_members')1278 exported_as='proposed_members')
1263 proposed_member_count = Attribute("Number of PROPOSED members")1279 proposed_member_count = Attribute("Number of PROPOSED members")
12641280
1265 mapped_participants_count = Attribute(1281 mapped_participants_count = Attribute(
1266 "The number of mapped participants")1282 "The number of mapped participants")
1267 unmapped_participants = CollectionField(1283 unmapped_participants = doNotSnapshot(
1268 title=_("List of participants with no coordinates recorded."),1284 CollectionField(
1269 value_type=Reference(schema=Interface))1285 title=_("List of participants with no coordinates recorded."),
1286 value_type=Reference(schema=Interface)))
1270 unmapped_participants_count = Attribute(1287 unmapped_participants_count = Attribute(
1271 "The number of unmapped participants")1288 "The number of unmapped participants")
12721289
12731290
=== modified file 'lib/lp/registry/model/product.py'
--- lib/lp/registry/model/product.py 2009-11-20 07:32:32 +0000
+++ lib/lp/registry/model/product.py 2009-12-05 12:29:16 +0000
@@ -546,8 +546,6 @@
546 """See `IBugTarget`."""546 """See `IBugTarget`."""
547 return get_bug_tags_open_count(BugTask.product == self, user)547 return get_bug_tags_open_count(BugTask.product == self, user)
548548
549 branches = SQLMultipleJoin('Branch', joinColumn='product',
550 orderBy='id')
551 series = SQLMultipleJoin('ProductSeries', joinColumn='product',549 series = SQLMultipleJoin('ProductSeries', joinColumn='product',
552 orderBy='name')550 orderBy='name')
553551
554552
=== modified file 'lib/lp/registry/tests/test_person.py'
--- lib/lp/registry/tests/test_person.py 2009-10-01 11:21:31 +0000
+++ lib/lp/registry/tests/test_person.py 2009-12-05 12:29:16 +0000
@@ -8,6 +8,7 @@
8import pytz8import pytz
99
10from zope.component import getUtility10from zope.component import getUtility
11from zope.interface import providedBy
11from zope.security.proxy import removeSecurityProxy12from zope.security.proxy import removeSecurityProxy
1213
13from canonical.database.sqlbase import cursor14from canonical.database.sqlbase import cursor
@@ -16,6 +17,7 @@
16from lp.bugs.interfaces.bug import CreateBugParams, IBugSet17from lp.bugs.interfaces.bug import CreateBugParams, IBugSet
17from canonical.launchpad.interfaces.emailaddress import (18from canonical.launchpad.interfaces.emailaddress import (
18 EmailAddressAlreadyTaken, IEmailAddressSet, InvalidEmailAddress)19 EmailAddressAlreadyTaken, IEmailAddressSet, InvalidEmailAddress)
20from lazr.lifecycle.snapshot import Snapshot
19from lp.blueprints.interfaces.specification import ISpecificationSet21from lp.blueprints.interfaces.specification import ISpecificationSet
20from lp.registry.interfaces.person import InvalidName22from lp.registry.interfaces.person import InvalidName
21from lp.registry.interfaces.product import IProductSet23from lp.registry.interfaces.product import IProductSet
@@ -406,6 +408,19 @@
406 self.assertEqual(self.otherteam.visibility,408 self.assertEqual(self.otherteam.visibility,
407 PersonVisibility.PRIVATE_MEMBERSHIP)409 PersonVisibility.PRIVATE_MEMBERSHIP)
408410
411 def test_person_snapshot(self):
412 omitted = (
413 'activemembers', 'adminmembers', 'allmembers', 'approvedmembers',
414 'deactivatedmembers', 'expiredmembers', 'inactivemembers',
415 'invited_members', 'member_memberships', 'pendingmembers',
416 'proposedmembers', 'unmapped_participants',
417 )
418 snap = Snapshot(self.myteam, providing=providedBy(self.myteam))
419 for name in omitted:
420 self.assertFalse(
421 hasattr(snap, name),
422 "%s should be omitted from the snapshot but is not." % name)
423
409424
410class TestPersonSet(unittest.TestCase):425class TestPersonSet(unittest.TestCase):
411 """Test `IPersonSet`."""426 """Test `IPersonSet`."""
412427
=== modified file 'versions.cfg'
--- versions.cfg 2009-11-26 23:08:57 +0000
+++ versions.cfg 2009-12-05 12:29:16 +0000
@@ -25,7 +25,7 @@
25lazr.config = 1.1.325lazr.config = 1.1.3
26lazr.delegates = 1.1.026lazr.delegates = 1.1.0
27lazr.enum = 1.1.227lazr.enum = 1.1.2
28lazr.lifecycle = 1.028lazr.lifecycle = 1.1
29lazr.restful = 0.9.1729lazr.restful = 0.9.17
30lazr.restfulclient = 0.9.1030lazr.restfulclient = 0.9.10
31lazr.smtptest = 1.131lazr.smtptest = 1.1