Merge ~cjwatson/launchpad:py3-orderable into launchpad:master
- Git
- lp:~cjwatson/launchpad
- py3-orderable
- Merge into master
Proposed by
Colin Watson
Status: | Merged |
---|---|
Approved by: | Colin Watson |
Approved revision: | 939df80ba6f7981be9c1d3b228689eccf2387603 |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~cjwatson/launchpad:py3-orderable |
Merge into: | launchpad:master |
Diff against target: |
324 lines (+66/-30) 16 files modified
lib/lp/bugs/browser/bugtask.py (+7/-3) lib/lp/bugs/browser/tests/person-bug-views.txt (+1/-1) lib/lp/bugs/doc/externalbugtracker-sourceforge.txt (+3/-1) lib/lp/bugs/model/tests/test_bugtask.py (+9/-6) lib/lp/bugs/stories/webservice/xx-bug.txt (+5/-3) lib/lp/bugs/subscribers/bug.py (+2/-1) lib/lp/code/doc/revision.txt (+3/-1) lib/lp/code/model/branchmergeproposal.py (+3/-2) lib/lp/registry/stories/webservice/xx-person.txt (+4/-2) lib/lp/registry/tests/test_distroseriesdifferencecomment.py (+1/-1) lib/lp/services/doc/orderingcheck.txt (+7/-3) lib/lp/services/webservice/stories/multiversion.txt (+4/-1) lib/lp/soyuz/scripts/tests/test_ppa_apache_log_parser.py (+3/-1) lib/lp/soyuz/stories/webservice/xx-hasbuildrecords.txt (+3/-1) lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt (+2/-2) lib/lp/translations/utilities/translationmerger.py (+9/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Cristian Gonzalez (community) | Approve | ||
Review via email: mp+398876@code.launchpad.net |
Commit message
Fix sorting of unorderable objects on Python 3
Description of the change
On Python 3, objects without a meaningful natural ordering can't be ordered. Fix a number of places that were trying to do this: sometimes this involves using better sort keys, while sometimes we can use various strategies to avoid ordering them in the first place.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lib/lp/bugs/browser/bugtask.py b/lib/lp/bugs/browser/bugtask.py | |||
2 | index a9d9953..2a139c0 100644 | |||
3 | --- a/lib/lp/bugs/browser/bugtask.py | |||
4 | +++ b/lib/lp/bugs/browser/bugtask.py | |||
5 | @@ -690,10 +690,14 @@ class BugTaskView(LaunchpadView, BugViewMixin, FeedsMixin): | |||
6 | 690 | """ | 690 | """ |
7 | 691 | event_groups = self._event_groups | 691 | event_groups = self._event_groups |
8 | 692 | 692 | ||
9 | 693 | def activity_sort_key(activity): | ||
10 | 694 | target = activity.target | ||
11 | 695 | return ( | ||
12 | 696 | activity.datechanged, 0 if target is None else 1, target, | ||
13 | 697 | activity.attribute) | ||
14 | 698 | |||
15 | 693 | def group_activities_by_target(activities): | 699 | def group_activities_by_target(activities): |
19 | 694 | activities = sorted( | 700 | activities = sorted(activities, key=activity_sort_key) |
17 | 695 | activities, key=attrgetter( | ||
18 | 696 | "datechanged", "target", "attribute")) | ||
20 | 697 | return [ | 701 | return [ |
21 | 698 | {"target": target, "activity": list(activity)} | 702 | {"target": target, "activity": list(activity)} |
22 | 699 | for target, activity in groupby( | 703 | for target, activity in groupby( |
23 | diff --git a/lib/lp/bugs/browser/tests/person-bug-views.txt b/lib/lp/bugs/browser/tests/person-bug-views.txt | |||
24 | index 439512d..5f1d5ab 100644 | |||
25 | --- a/lib/lp/bugs/browser/tests/person-bug-views.txt | |||
26 | +++ b/lib/lp/bugs/browser/tests/person-bug-views.txt | |||
27 | @@ -356,7 +356,7 @@ particular bug (see bug 1357): | |||
28 | 356 | 356 | ||
29 | 357 | >>> commented_bugtasks_view = create_view(no_priv, '+commentedbugs') | 357 | >>> commented_bugtasks_view = create_view(no_priv, '+commentedbugs') |
30 | 358 | >>> commented_bugs = list(commented_bugtasks_view.search().batch) | 358 | >>> commented_bugs = list(commented_bugtasks_view.search().batch) |
32 | 359 | >>> [bugtask.bug.id for bugtask in sorted(commented_bugs)] | 359 | >>> [bugtask.bug.id for bugtask in commented_bugs] |
33 | 360 | [1, 1, 1] | 360 | [1, 1, 1] |
34 | 361 | 361 | ||
35 | 362 | 362 | ||
36 | diff --git a/lib/lp/bugs/doc/externalbugtracker-sourceforge.txt b/lib/lp/bugs/doc/externalbugtracker-sourceforge.txt | |||
37 | index a01dbdc..bcaf316 100644 | |||
38 | --- a/lib/lp/bugs/doc/externalbugtracker-sourceforge.txt | |||
39 | +++ b/lib/lp/bugs/doc/externalbugtracker-sourceforge.txt | |||
40 | @@ -215,9 +215,11 @@ been checked. | |||
41 | 215 | 215 | ||
42 | 216 | >>> transaction.commit() | 216 | >>> transaction.commit() |
43 | 217 | 217 | ||
44 | 218 | >>> from operator import attrgetter | ||
45 | 218 | >>> with sourceforge.responses(trace_calls=True): | 219 | >>> with sourceforge.responses(trace_calls=True): |
46 | 219 | ... bug_watch_updater.updateBugWatches( | 220 | ... bug_watch_updater.updateBugWatches( |
48 | 220 | ... sourceforge, sorted(example_bug_tracker.watches)) | 221 | ... sourceforge, |
49 | 222 | ... sorted(example_bug_tracker.watches, key=attrgetter('id'))) | ||
50 | 221 | INFO Updating 1 watches for 1 bugs on http://bugs.some.where | 223 | INFO Updating 1 watches for 1 bugs on http://bugs.some.where |
51 | 222 | GET http://bugs.some.where/support/tracker.php?aid=1722251 | 224 | GET http://bugs.some.where/support/tracker.php?aid=1722251 |
52 | 223 | 225 | ||
53 | diff --git a/lib/lp/bugs/model/tests/test_bugtask.py b/lib/lp/bugs/model/tests/test_bugtask.py | |||
54 | index 527120e..21a91e4 100644 | |||
55 | --- a/lib/lp/bugs/model/tests/test_bugtask.py | |||
56 | +++ b/lib/lp/bugs/model/tests/test_bugtask.py | |||
57 | @@ -11,7 +11,11 @@ import unittest | |||
58 | 11 | 11 | ||
59 | 12 | from lazr.lifecycle.snapshot import Snapshot | 12 | from lazr.lifecycle.snapshot import Snapshot |
60 | 13 | from storm.store import Store | 13 | from storm.store import Store |
62 | 14 | from testtools.matchers import Equals | 14 | from testtools.matchers import ( |
63 | 15 | Equals, | ||
64 | 16 | MatchesSetwise, | ||
65 | 17 | MatchesStructure, | ||
66 | 18 | ) | ||
67 | 15 | from testtools.testcase import ExpectedException | 19 | from testtools.testcase import ExpectedException |
68 | 16 | import transaction | 20 | import transaction |
69 | 17 | from zope.component import getUtility | 21 | from zope.component import getUtility |
70 | @@ -199,12 +203,11 @@ class TestBugTaskCreation(TestCaseWithFactory): | |||
71 | 199 | bug_many, mark, | 203 | bug_many, mark, |
72 | 200 | [evolution, a_distro, warty], | 204 | [evolution, a_distro, warty], |
73 | 201 | status=BugTaskStatus.FIXRELEASED) | 205 | status=BugTaskStatus.FIXRELEASED) |
74 | 202 | tasks = [(t.product, t.distribution, t.distroseries) for t in taskset] | ||
75 | 203 | tasks.sort() | ||
76 | 204 | 206 | ||
80 | 205 | self.assertEqual(tasks[0][2], warty) | 207 | self.assertThat(taskset, MatchesSetwise( |
81 | 206 | self.assertEqual(tasks[1][1], a_distro) | 208 | MatchesStructure.byEquality(product=evolution), |
82 | 207 | self.assertEqual(tasks[2][0], evolution) | 209 | MatchesStructure.byEquality(distribution=a_distro), |
83 | 210 | MatchesStructure.byEquality(distroseries=warty))) | ||
84 | 208 | 211 | ||
85 | 209 | def test_accesspolicyartifacts_updated(self): | 212 | def test_accesspolicyartifacts_updated(self): |
86 | 210 | # createManyTasks updates the AccessPolicyArtifacts related | 213 | # createManyTasks updates the AccessPolicyArtifacts related |
87 | diff --git a/lib/lp/bugs/stories/webservice/xx-bug.txt b/lib/lp/bugs/stories/webservice/xx-bug.txt | |||
88 | index 04480a5..6121737 100644 | |||
89 | --- a/lib/lp/bugs/stories/webservice/xx-bug.txt | |||
90 | +++ b/lib/lp/bugs/stories/webservice/xx-bug.txt | |||
91 | @@ -312,9 +312,11 @@ Bug tasks | |||
92 | 312 | Each bug may be associated with one or more bug tasks. Much of the | 312 | Each bug may be associated with one or more bug tasks. Much of the |
93 | 313 | data in a bug task is derived from the bug. | 313 | data in a bug task is derived from the bug. |
94 | 314 | 314 | ||
95 | 315 | >>> from operator import itemgetter | ||
96 | 315 | >>> bug_one_bugtasks_url = bug_one['bug_tasks_collection_link'] | 316 | >>> bug_one_bugtasks_url = bug_one['bug_tasks_collection_link'] |
97 | 316 | >>> bug_one_bugtasks = sorted(webservice.get( | 317 | >>> bug_one_bugtasks = sorted(webservice.get( |
99 | 317 | ... bug_one_bugtasks_url).jsonBody()['entries']) | 318 | ... bug_one_bugtasks_url).jsonBody()['entries'], |
100 | 319 | ... key=itemgetter('self_link')) | ||
101 | 318 | >>> len(bug_one_bugtasks) | 320 | >>> len(bug_one_bugtasks) |
102 | 319 | 3 | 321 | 3 |
103 | 320 | 322 | ||
104 | @@ -825,7 +827,6 @@ Bug subscriptions | |||
105 | 825 | 827 | ||
106 | 826 | We can get the collection of subscriptions to a bug. | 828 | We can get the collection of subscriptions to a bug. |
107 | 827 | 829 | ||
108 | 828 | >>> from operator import itemgetter | ||
109 | 829 | >>> bug_one_subscriptions_url = bug_one['subscriptions_collection_link'] | 830 | >>> bug_one_subscriptions_url = bug_one['subscriptions_collection_link'] |
110 | 830 | >>> subscriptions = webservice.get(bug_one_subscriptions_url).jsonBody() | 831 | >>> subscriptions = webservice.get(bug_one_subscriptions_url).jsonBody() |
111 | 831 | >>> subscription_entries = sorted( | 832 | >>> subscription_entries = sorted( |
112 | @@ -1056,7 +1057,8 @@ case aspects of the bugtask (like status) are slaved to the remote bug | |||
113 | 1056 | report described by the bugwatch. | 1057 | report described by the bugwatch. |
114 | 1057 | 1058 | ||
115 | 1058 | >>> bug_one_bug_watches = sorted(webservice.get( | 1059 | >>> bug_one_bug_watches = sorted(webservice.get( |
117 | 1059 | ... bug_one['bug_watches_collection_link']).jsonBody()['entries']) | 1060 | ... bug_one['bug_watches_collection_link']).jsonBody()['entries'], |
118 | 1061 | ... key=itemgetter('self_link')) | ||
119 | 1060 | >>> len(bug_one_bug_watches) | 1062 | >>> len(bug_one_bug_watches) |
120 | 1061 | 4 | 1063 | 4 |
121 | 1062 | 1064 | ||
122 | diff --git a/lib/lp/bugs/subscribers/bug.py b/lib/lp/bugs/subscribers/bug.py | |||
123 | index 11851eb..d88d27b 100644 | |||
124 | --- a/lib/lp/bugs/subscribers/bug.py | |||
125 | +++ b/lib/lp/bugs/subscribers/bug.py | |||
126 | @@ -15,6 +15,7 @@ __all__ = [ | |||
127 | 15 | 15 | ||
128 | 16 | 16 | ||
129 | 17 | import datetime | 17 | import datetime |
130 | 18 | from operator import attrgetter | ||
131 | 18 | 19 | ||
132 | 19 | from zope.security.proxy import removeSecurityProxy | 20 | from zope.security.proxy import removeSecurityProxy |
133 | 20 | 21 | ||
134 | @@ -227,7 +228,7 @@ def send_bug_details_to_new_bug_subscribers( | |||
135 | 227 | recipients = bug.getBugNotificationRecipients() | 228 | recipients = bug.getBugNotificationRecipients() |
136 | 228 | 229 | ||
137 | 229 | bug_notification_builder = BugNotificationBuilder(bug, event_creator) | 230 | bug_notification_builder = BugNotificationBuilder(bug, event_creator) |
139 | 230 | for to_person in sorted(to_persons): | 231 | for to_person in sorted(to_persons, key=attrgetter('id')): |
140 | 231 | reason, rationale = recipients.getReason( | 232 | reason, rationale = recipients.getReason( |
141 | 232 | str(removeSecurityProxy(to_person).preferredemail.email)) | 233 | str(removeSecurityProxy(to_person).preferredemail.email)) |
142 | 233 | subject, contents = generate_bug_add_email( | 234 | subject, contents = generate_bug_add_email( |
143 | diff --git a/lib/lp/code/doc/revision.txt b/lib/lp/code/doc/revision.txt | |||
144 | index 46f0219..e514d69 100644 | |||
145 | --- a/lib/lp/code/doc/revision.txt | |||
146 | +++ b/lib/lp/code/doc/revision.txt | |||
147 | @@ -112,7 +112,9 @@ sequence attribute is None. | |||
148 | 112 | >>> ancestry = IStore(BranchRevision).find( | 112 | >>> ancestry = IStore(BranchRevision).find( |
149 | 113 | ... BranchRevision, BranchRevision.branch == branch) | 113 | ... BranchRevision, BranchRevision.branch == branch) |
150 | 114 | >>> for branch_revision in sorted(ancestry, | 114 | >>> for branch_revision in sorted(ancestry, |
152 | 115 | ... key=lambda r:(r.sequence, r.revision.id), reverse=True): | 115 | ... key=lambda r: ( |
153 | 116 | ... 0 if r.sequence is None else 1, r.sequence, r.revision.id), | ||
154 | 117 | ... reverse=True): | ||
155 | 116 | ... print(branch_revision.sequence, branch_revision.revision.id) | 118 | ... print(branch_revision.sequence, branch_revision.revision.id) |
156 | 117 | 6 9 | 119 | 6 9 |
157 | 118 | 5 8 | 120 | 5 8 |
158 | diff --git a/lib/lp/code/model/branchmergeproposal.py b/lib/lp/code/model/branchmergeproposal.py | |||
159 | index 061fb1e..55a9197 100644 | |||
160 | --- a/lib/lp/code/model/branchmergeproposal.py | |||
161 | +++ b/lib/lp/code/model/branchmergeproposal.py | |||
162 | @@ -1290,9 +1290,10 @@ class BranchMergeProposal(SQLBase, BugLinkTargetMixin): | |||
163 | 1290 | 1290 | ||
164 | 1291 | def getRevisionsSinceReviewStart(self): | 1291 | def getRevisionsSinceReviewStart(self): |
165 | 1292 | """Get the grouped revisions since the review started.""" | 1292 | """Get the grouped revisions since the review started.""" |
166 | 1293 | all_comments = list(self.all_comments) | ||
167 | 1293 | entries = [ | 1294 | entries = [ |
170 | 1294 | ((comment.date_created, -1), comment) for comment | 1295 | ((comment.date_created, i - len(all_comments)), comment) |
171 | 1295 | in self.all_comments] | 1296 | for i, comment in enumerate(all_comments)] |
172 | 1296 | entries.extend(self._getNewerRevisions()) | 1297 | entries.extend(self._getNewerRevisions()) |
173 | 1297 | entries.sort() | 1298 | entries.sort() |
174 | 1298 | current_group = [] | 1299 | current_group = [] |
175 | diff --git a/lib/lp/registry/stories/webservice/xx-person.txt b/lib/lp/registry/stories/webservice/xx-person.txt | |||
176 | index 73450d0..619784c 100644 | |||
177 | --- a/lib/lp/registry/stories/webservice/xx-person.txt | |||
178 | +++ b/lib/lp/registry/stories/webservice/xx-person.txt | |||
179 | @@ -303,8 +303,10 @@ Team memberships are first-class objects with their own URLs. | |||
180 | 303 | 303 | ||
181 | 304 | Team memberships also have data fields. | 304 | Team memberships also have data fields. |
182 | 305 | 305 | ||
185 | 306 | >>> salgado_landscape = sorted(webservice.get( | 306 | >>> salgado_landscape = [ |
186 | 307 | ... salgado_memberships).jsonBody()['entries'])[1] | 307 | ... entry for entry in webservice.get( |
187 | 308 | ... salgado_memberships).jsonBody()['entries'] | ||
188 | 309 | ... if entry['team_link'].endswith('~landscape-developers')][0] | ||
189 | 308 | >>> for key in sorted(salgado_landscape): | 310 | >>> for key in sorted(salgado_landscape): |
190 | 309 | ... print(key) | 311 | ... print(key) |
191 | 310 | date_expires | 312 | date_expires |
192 | diff --git a/lib/lp/registry/tests/test_distroseriesdifferencecomment.py b/lib/lp/registry/tests/test_distroseriesdifferencecomment.py | |||
193 | index f95aac7..6276647 100644 | |||
194 | --- a/lib/lp/registry/tests/test_distroseriesdifferencecomment.py | |||
195 | +++ b/lib/lp/registry/tests/test_distroseriesdifferencecomment.py | |||
196 | @@ -33,7 +33,7 @@ def get_comment_source(): | |||
197 | 33 | 33 | ||
198 | 34 | def randomize_list(original_list): | 34 | def randomize_list(original_list): |
199 | 35 | """Sort a list (or other iterable) in random order. Return list.""" | 35 | """Sort a list (or other iterable) in random order. Return list.""" |
201 | 36 | return sorted(original_list, key=lambda _: random) | 36 | return sorted(original_list, key=lambda _: random()) |
202 | 37 | 37 | ||
203 | 38 | 38 | ||
204 | 39 | class DistroSeriesDifferenceCommentTestCase(TestCaseWithFactory): | 39 | class DistroSeriesDifferenceCommentTestCase(TestCaseWithFactory): |
205 | diff --git a/lib/lp/services/doc/orderingcheck.txt b/lib/lp/services/doc/orderingcheck.txt | |||
206 | index 209b6e0..e2367aa 100644 | |||
207 | --- a/lib/lp/services/doc/orderingcheck.txt | |||
208 | +++ b/lib/lp/services/doc/orderingcheck.txt | |||
209 | @@ -10,8 +10,12 @@ seem worth the trouble. | |||
210 | 10 | >>> from lp.services.orderingcheck import OrderingCheck | 10 | >>> from lp.services.orderingcheck import OrderingCheck |
211 | 11 | 11 | ||
212 | 12 | >>> def sort_key(item): | 12 | >>> def sort_key(item): |
215 | 13 | ... """Simple sorting key for integers: the integer itself.""" | 13 | ... """Simple sorting key for integers. |
216 | 14 | ... return item | 14 | ... |
217 | 15 | ... This could just be the integer itself, but in order to support | ||
218 | 16 | ... None on Python 3 we need an additional term. | ||
219 | 17 | ... """ | ||
220 | 18 | ... return (0 if item is None else 1, item) | ||
221 | 15 | 19 | ||
222 | 16 | The OrderingCheck makes it clean and easy. You create an OrderingCheck | 20 | The OrderingCheck makes it clean and easy. You create an OrderingCheck |
223 | 17 | with the same arguments that go into Python's standard sorting | 21 | with the same arguments that go into Python's standard sorting |
224 | @@ -51,7 +55,7 @@ error. | |||
225 | 51 | Edge cases | 55 | Edge cases |
226 | 52 | ---------- | 56 | ---------- |
227 | 53 | 57 | ||
229 | 54 | It is safe to use the None value. Python places it below any other | 58 | It is safe to use the None value. sort_key places it below any other |
230 | 55 | integer. | 59 | integer. |
231 | 56 | 60 | ||
232 | 57 | >>> checker = OrderingCheck(key=sort_key) | 61 | >>> checker = OrderingCheck(key=sort_key) |
233 | diff --git a/lib/lp/services/webservice/stories/multiversion.txt b/lib/lp/services/webservice/stories/multiversion.txt | |||
234 | index 22f9722..683325f 100644 | |||
235 | --- a/lib/lp/services/webservice/stories/multiversion.txt | |||
236 | +++ b/lib/lp/services/webservice/stories/multiversion.txt | |||
237 | @@ -46,11 +46,14 @@ In the 'beta' version of the web service, mutator methods like | |||
238 | 46 | IBugTask.transitionToStatus are published as named operations. In | 46 | IBugTask.transitionToStatus are published as named operations. In |
239 | 47 | subsequent versions, those named operations are not published. | 47 | subsequent versions, those named operations are not published. |
240 | 48 | 48 | ||
241 | 49 | >>> from operator import itemgetter | ||
242 | 50 | |||
243 | 49 | >>> def get_bugtask_path(version): | 51 | >>> def get_bugtask_path(version): |
244 | 50 | ... bug_one = webservice.get("/bugs/1", api_version=version).jsonBody() | 52 | ... bug_one = webservice.get("/bugs/1", api_version=version).jsonBody() |
245 | 51 | ... bug_one_bugtasks_url = bug_one['bug_tasks_collection_link'] | 53 | ... bug_one_bugtasks_url = bug_one['bug_tasks_collection_link'] |
246 | 52 | ... bug_one_bugtasks = sorted(webservice.get( | 54 | ... bug_one_bugtasks = sorted(webservice.get( |
248 | 53 | ... bug_one_bugtasks_url).jsonBody()['entries']) | 55 | ... bug_one_bugtasks_url).jsonBody()['entries'], |
249 | 56 | ... key=itemgetter('self_link')) | ||
250 | 54 | ... bugtask_path = bug_one_bugtasks[0]['self_link'] | 57 | ... bugtask_path = bug_one_bugtasks[0]['self_link'] |
251 | 55 | ... return bugtask_path | 58 | ... return bugtask_path |
252 | 56 | 59 | ||
253 | diff --git a/lib/lp/soyuz/scripts/tests/test_ppa_apache_log_parser.py b/lib/lp/soyuz/scripts/tests/test_ppa_apache_log_parser.py | |||
254 | index 0b82990..187323c 100644 | |||
255 | --- a/lib/lp/soyuz/scripts/tests/test_ppa_apache_log_parser.py | |||
256 | +++ b/lib/lp/soyuz/scripts/tests/test_ppa_apache_log_parser.py | |||
257 | @@ -152,4 +152,6 @@ class TestScriptRunning(TestCaseWithFactory): | |||
258 | 152 | sorted( | 152 | sorted( |
259 | 153 | [(result.binary_package_release, result.archive, result.day, | 153 | [(result.binary_package_release, result.archive, result.day, |
260 | 154 | result.country, result.count) for result in results], | 154 | result.country, result.count) for result in results], |
262 | 155 | key=lambda r: (r[0].id, r[2], r[3].name if r[3] else None))) | 155 | key=lambda r: ( |
263 | 156 | r[0].id, r[2], | ||
264 | 157 | r[3] is not None, r[3].name if r[3] else None))) | ||
265 | diff --git a/lib/lp/soyuz/stories/webservice/xx-hasbuildrecords.txt b/lib/lp/soyuz/stories/webservice/xx-hasbuildrecords.txt | |||
266 | index 3246cca..4b3ca4e 100644 | |||
267 | --- a/lib/lp/soyuz/stories/webservice/xx-hasbuildrecords.txt | |||
268 | +++ b/lib/lp/soyuz/stories/webservice/xx-hasbuildrecords.txt | |||
269 | @@ -42,8 +42,10 @@ Celso Providelo PPA builds can be browsed via the API. | |||
270 | 42 | 42 | ||
271 | 43 | An entry can be selected in the returned collection. | 43 | An entry can be selected in the returned collection. |
272 | 44 | 44 | ||
273 | 45 | >>> from operator import itemgetter | ||
274 | 45 | >>> from lazr.restful.testing.webservice import pprint_entry | 46 | >>> from lazr.restful.testing.webservice import pprint_entry |
276 | 46 | >>> pprint_entry(sorted(ppa_builds['entries'])[0]) | 47 | >>> pprint_entry( |
277 | 48 | ... sorted(ppa_builds['entries'], key=itemgetter('title'))[0]) | ||
278 | 47 | arch_tag: 'hppa' | 49 | arch_tag: 'hppa' |
279 | 48 | ... | 50 | ... |
280 | 49 | title: 'hppa build of mozilla-firefox 0.9 in ubuntu warty RELEASE' | 51 | title: 'hppa build of mozilla-firefox 0.9 in ubuntu warty RELEASE' |
281 | diff --git a/lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt b/lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt | |||
282 | index 761b7aa..92e2764 100644 | |||
283 | --- a/lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt | |||
284 | +++ b/lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt | |||
285 | @@ -292,7 +292,7 @@ binaries have been copied and published in the same context archive. | |||
286 | 292 | >>> source_pub = pubs['entries'][0] | 292 | >>> source_pub = pubs['entries'][0] |
287 | 293 | >>> builds = webservice.named_get( | 293 | >>> builds = webservice.named_get( |
288 | 294 | ... source_pub['self_link'], 'getBuilds').jsonBody() | 294 | ... source_pub['self_link'], 'getBuilds').jsonBody() |
290 | 295 | >>> for entry in sorted(builds['entries']): | 295 | >>> for entry in builds['entries']: |
291 | 296 | ... print(entry['title']) | 296 | ... print(entry['title']) |
292 | 297 | i386 build of pmount 0.1-1 in ubuntu warty RELEASE | 297 | i386 build of pmount 0.1-1 in ubuntu warty RELEASE |
293 | 298 | 298 | ||
294 | @@ -310,7 +310,7 @@ of that publication. | |||
295 | 310 | >>> source_pub = pubs['entries'][0] | 310 | >>> source_pub = pubs['entries'][0] |
296 | 311 | >>> builds = webservice.named_get( | 311 | >>> builds = webservice.named_get( |
297 | 312 | ... source_pub['self_link'], 'getPublishedBinaries').jsonBody() | 312 | ... source_pub['self_link'], 'getPublishedBinaries').jsonBody() |
299 | 313 | >>> for entry in sorted(builds['entries']): | 313 | >>> for entry in builds['entries']: |
300 | 314 | ... print(entry['display_name']) | 314 | ... print(entry['display_name']) |
301 | 315 | pmount 0.1-1 in warty hppa | 315 | pmount 0.1-1 in warty hppa |
302 | 316 | pmount 0.1-1 in warty i386 | 316 | pmount 0.1-1 in warty i386 |
303 | diff --git a/lib/lp/translations/utilities/translationmerger.py b/lib/lp/translations/utilities/translationmerger.py | |||
304 | index 192c32b..7164395 100644 | |||
305 | --- a/lib/lp/translations/utilities/translationmerger.py | |||
306 | +++ b/lib/lp/translations/utilities/translationmerger.py | |||
307 | @@ -282,8 +282,16 @@ class MessageSharingMerge(LaunchpadScript): | |||
308 | 282 | class_count = len(equivalence_classes) | 282 | class_count = len(equivalence_classes) |
309 | 283 | log.info("Merging %d template equivalence classes." % class_count) | 283 | log.info("Merging %d template equivalence classes." % class_count) |
310 | 284 | 284 | ||
311 | 285 | def equivalence_class_sort_key(name): | ||
312 | 286 | template_name, package_name = name | ||
313 | 287 | if package_name is None: | ||
314 | 288 | return template_name, 0, None | ||
315 | 289 | else: | ||
316 | 290 | return template_name, 1, package_name | ||
317 | 291 | |||
318 | 285 | tm = TransactionManager(self.txn, self.options.dry_run) | 292 | tm = TransactionManager(self.txn, self.options.dry_run) |
320 | 286 | for number, name in enumerate(sorted(equivalence_classes)): | 293 | for number, name in enumerate(sorted( |
321 | 294 | equivalence_classes, key=equivalence_class_sort_key)): | ||
322 | 287 | templates = equivalence_classes[name] | 295 | templates = equivalence_classes[name] |
323 | 288 | log.info( | 296 | log.info( |
324 | 289 | "Merging equivalence class '%s': %d template(s) (%d / %d)" % ( | 297 | "Merging equivalence class '%s': %d template(s) (%d / %d)" % ( |
Looks good!