Merge lp:~lifeless/launchpad/bug-793809 into lp:launchpad
- bug-793809
- Merge into devel
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | William Grant | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 13171 | ||||
Proposed branch: | lp:~lifeless/launchpad/bug-793809 | ||||
Merge into: | lp:launchpad | ||||
Diff against target: |
416 lines (+126/-100) 11 files modified
lib/lp/bugs/browser/bugtarget.py (+4/-15) lib/lp/bugs/doc/bug-tags.txt (+20/-21) lib/lp/bugs/interfaces/bugtarget.py (+9/-7) lib/lp/bugs/model/bug.py (+43/-30) lib/lp/registry/model/distribution.py (+7/-3) lib/lp/registry/model/distributionsourcepackage.py (+7/-5) lib/lp/registry/model/distroseries.py (+10/-3) lib/lp/registry/model/product.py (+6/-3) lib/lp/registry/model/productseries.py (+5/-2) lib/lp/registry/model/projectgroup.py (+8/-6) lib/lp/registry/model/sourcepackage.py (+7/-5) |
||||
To merge this branch: | bzr merge lp:~lifeless/launchpad/bug-793809 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
William Grant | code | Approve | |
Review via email: mp+63635@code.launchpad.net |
Commit message
[r=wgrant][bug=793809] Use BugSummary to do tag portlet calculations
Description of the change
Per the linked bug generating bug tag portlets is extraordinarily slow. This is meant to be addressed by querying bugsummary, which this branch implements.
I have changed the interface to match our needs allowing a faster query (the with clause on teams for visibility).
Other than that I can see a path to reduce the duplicate code that we use here, but its unrelated to fixing this bug, so I've focused on getting the bug fixed ;)
Robert Collins (lifeless) wrote : | # |
> 21 + tags = self.context.
> 10,
> 22 + official_tags)
>
> Nice cleanup. But bad indentation.
How so ?
> 33 + official_tags = self.context.
>
> Sure this doesn't need to be materialised?
The core function returns a list.
> 131 + :param tag_limit: The number of tags to return (excludes
> those found by
> 132 + matching include_tags). If 0 then all tags are returned.
> If
> 133 + non-zero then the most frequently used tags are returned.
>
> 0? Why not None?
Shrug; can change it to that, but 0 would be noddy. Using 0 as the flag avoids bad behaviour if a limit of 0 is passed in.
> 172 +def get_bug_
> 173 + include_tags=None):
>
> Bad indentation.
How so ?
> 200 + store = store.with_(SQL(
> 201 + "teams AS ("
> 202 + "SELECT team from TeamParticipation WHERE person=%s)" %
> user.id))
>
> String formatting in SQL: Australia says no.
>
> Also, calling that "store" is a bit too much of a lie for my tastes.
It meets the core contract and is better understood than 'resultset_
> 228 + BugSummary.
> teams"))
>
> What's the benefit of the WITH clause here? I doubt there is any performance
> gain, and including the full thing here is shorter and clearer.
Its faster. 150ms difference when I was testing.
Preview Diff
1 | === modified file 'lib/lp/bugs/browser/bugtarget.py' |
2 | --- lib/lp/bugs/browser/bugtarget.py 2011-06-06 06:44:23 +0000 |
3 | +++ lib/lp/bugs/browser/bugtarget.py 2011-06-07 05:39:33 +0000 |
4 | @@ -1405,19 +1405,8 @@ |
5 | def tags_cloud_data(self): |
6 | """The data for rendering a tags cloud""" |
7 | official_tags = self.context.official_bug_tags |
8 | - |
9 | - # Construct a dict of official and top 10 tags. |
10 | - # getUsedBugTagsWithOpenCounts is expensive, so do the union in |
11 | - # SQL. Also preseed with 0 for all the official tags, as gUBTWOC |
12 | - # won't return unused ones. |
13 | - top_ten = removeSecurityProxy( |
14 | - self.context.getUsedBugTagsWithOpenCounts(self.user)[:10]) |
15 | - official = removeSecurityProxy( |
16 | - self.context.getUsedBugTagsWithOpenCounts( |
17 | - self.user, official_tags)) |
18 | - tags = dict((tag, 0) for tag in official_tags) |
19 | - tags.update(dict(top_ten.union(official))) |
20 | - |
21 | + tags = self.context.getUsedBugTagsWithOpenCounts( |
22 | + self.user, 10, official_tags) |
23 | max_count = float(max([1] + tags.values())) |
24 | |
25 | return sorted( |
26 | @@ -1462,8 +1451,8 @@ |
27 | @property |
28 | def tags_js_data(self): |
29 | """Return the JSON representation of the bug tags.""" |
30 | - used_tags = dict(self.context.getUsedBugTagsWithOpenCounts(self.user)) |
31 | - official_tags = list(self.context.official_bug_tags) |
32 | + used_tags = self.context.getUsedBugTagsWithOpenCounts(self.user) |
33 | + official_tags = self.context.official_bug_tags |
34 | return """<script type="text/javascript"> |
35 | var used_bug_tags = %s; |
36 | var official_bug_tags = %s; |
37 | |
38 | === modified file 'lib/lp/bugs/doc/bug-tags.txt' |
39 | --- lib/lp/bugs/doc/bug-tags.txt 2011-04-12 06:40:51 +0000 |
40 | +++ lib/lp/bugs/doc/bug-tags.txt 2011-06-07 05:39:33 +0000 |
41 | @@ -332,35 +332,34 @@ |
42 | We can also get all the used tags, together with the number of open |
43 | bugs each tag has. Only tags having open bugs are returned. |
44 | |
45 | - >>> list(firefox.getUsedBugTagsWithOpenCounts(None)) |
46 | - [(u'doc', 1L), (u'sco', 1L), (u'svg', 1L)] |
47 | - |
48 | - >>> list(mozilla.getUsedBugTagsWithOpenCounts(None)) |
49 | - [(u'doc', 1L), (u'sco', 1L), (u'svg', 1L)] |
50 | - |
51 | - >>> list(ubuntu.getUsedBugTagsWithOpenCounts(None)) |
52 | + >>> sorted(firefox.getUsedBugTagsWithOpenCounts(None).items()) |
53 | + [(u'doc', 1L), (u'sco', 1L), (u'svg', 1L)] |
54 | + |
55 | + >>> sorted(mozilla.getUsedBugTagsWithOpenCounts(None).items()) |
56 | + [(u'doc', 1L), (u'sco', 1L), (u'svg', 1L)] |
57 | + |
58 | + >>> sorted(ubuntu.getUsedBugTagsWithOpenCounts(None).items()) |
59 | [(u'crash', 2L), (u'dataloss', 1L), (u'pebcak', 1L), |
60 | (u'sco', 1L), (u'svg', 1L)] |
61 | |
62 | -We can even ask for the counts for a particular set of tags. |
63 | +We can require that some tags be included in the output even when limiting the |
64 | +results. |
65 | |
66 | - >>> list(ubuntu.getUsedBugTagsWithOpenCounts( |
67 | - ... None, wanted_tags=['pebcak', 'svg', 'fake'])) |
68 | - [(u'pebcak', 1L), (u'svg', 1L)] |
69 | - >>> list(ubuntu.getUsedBugTagsWithOpenCounts(None, wanted_tags=[])) |
70 | - [] |
71 | + >>> sorted(ubuntu.getUsedBugTagsWithOpenCounts(None, |
72 | + ... tag_limit=1, include_tags=[u'pebcak', u'svg', u'fake']).items()) |
73 | + [(u'crash', 2L), (u'fake', 0), (u'pebcak', 1L), (u'svg', 1L)] |
74 | |
75 | Source packages are a bit special, they return all the tags that are |
76 | used in the whole distribution, while the bug count includes only bugs |
77 | in the specific package. |
78 | |
79 | - >>> list(ubuntu_thunderbird.getUsedBugTagsWithOpenCounts(None)) |
80 | - [(u'crash', 1L)] |
81 | + >>> ubuntu_thunderbird.getUsedBugTagsWithOpenCounts(None) |
82 | + {u'crash': 1L} |
83 | |
84 | - >>> list(debian_woody.getUsedBugTagsWithOpenCounts(None)) |
85 | + >>> sorted(debian_woody.getUsedBugTagsWithOpenCounts(None).items()) |
86 | [(u'dataloss', 1L), (u'layout-test', 1L), (u'pebcak', 1L)] |
87 | |
88 | - >>> list(debian_woody_firefox.getUsedBugTagsWithOpenCounts(None)) |
89 | + >>> sorted(debian_woody_firefox.getUsedBugTagsWithOpenCounts(None).items()) |
90 | [(u'dataloss', 1L), (u'layout-test', 1L), (u'pebcak', 1L)] |
91 | |
92 | Only bugs that the supplied user has access to will be counted: |
93 | @@ -370,14 +369,14 @@ |
94 | True |
95 | >>> flush_database_updates() |
96 | |
97 | - >>> list(ubuntu_thunderbird.getUsedBugTagsWithOpenCounts(None)) |
98 | - [] |
99 | + >>> ubuntu_thunderbird.getUsedBugTagsWithOpenCounts(None) |
100 | + {} |
101 | |
102 | >>> sample_person = getUtility(ILaunchBag).user |
103 | >>> bug_nine.isSubscribed(sample_person) |
104 | True |
105 | - >>> list(ubuntu_thunderbird.getUsedBugTagsWithOpenCounts(sample_person)) |
106 | - [(u'crash', 1L)] |
107 | + >>> ubuntu_thunderbird.getUsedBugTagsWithOpenCounts(sample_person) |
108 | + {u'crash': 1L} |
109 | |
110 | When context doesn't have any tags getUsedBugTags() returns a empty list. |
111 | |
112 | |
113 | === modified file 'lib/lp/bugs/interfaces/bugtarget.py' |
114 | --- lib/lp/bugs/interfaces/bugtarget.py 2011-04-12 06:21:39 +0000 |
115 | +++ lib/lp/bugs/interfaces/bugtarget.py 2011-06-07 05:39:33 +0000 |
116 | @@ -403,15 +403,17 @@ |
117 | def getUsedBugTags(): |
118 | """Return the tags used by the context as a sorted list of strings.""" |
119 | |
120 | - def getUsedBugTagsWithOpenCounts(user, wanted_tags=None): |
121 | + def getUsedBugTagsWithOpenCounts(user, tag_limit=0, include_tags=None): |
122 | """Return name and bug count of tags having open bugs. |
123 | |
124 | - It returns a list of tuples contining the tag name, and the |
125 | - number of open bugs having that tag. Only the bugs that the user |
126 | - has permission to see are counted, and only tags having open |
127 | - bugs will be returned. |
128 | - |
129 | - If wanted_tags is specified, only those tags will be returned. |
130 | + :param user: The user who wants the report. |
131 | + :param tag_limit: The number of tags to return (excludes those found by |
132 | + matching include_tags). If 0 then all tags are returned. If |
133 | + non-zero then the most frequently used tags are returned. |
134 | + :param include_tags: A list of string tags to return irrespective of |
135 | + usage. Tags in this list that have no open bugs are returned with a |
136 | + count of 0. May be None if there are tags to require inclusion of. |
137 | + :return: A dict from tag -> count. |
138 | """ |
139 | |
140 | def _getOfficialTagClause(): |
141 | |
142 | === modified file 'lib/lp/bugs/model/bug.py' |
143 | --- lib/lp/bugs/model/bug.py 2011-06-03 10:38:25 +0000 |
144 | +++ lib/lp/bugs/model/bug.py 2011-06-07 05:39:33 +0000 |
145 | @@ -63,6 +63,7 @@ |
146 | Select, |
147 | SQL, |
148 | SQLRaw, |
149 | + Sum, |
150 | Union, |
151 | ) |
152 | from storm.info import ClassAlias |
153 | @@ -242,11 +243,6 @@ |
154 | tag = StringCol(notNull=True) |
155 | |
156 | |
157 | -# We need to always use the same Count instance or the |
158 | -# get_bug_tags_open_count is not UNIONable. |
159 | -tag_count_columns = (BugTag.tag, Count()) |
160 | - |
161 | - |
162 | def get_bug_tags(context_clause): |
163 | """Return all the bug tags as a list of strings. |
164 | |
165 | @@ -266,39 +262,56 @@ |
166 | return shortlist([row[0] for row in cur.fetchall()]) |
167 | |
168 | |
169 | -def get_bug_tags_open_count(context_condition, user, wanted_tags=None): |
170 | - """Return all the used bug tags with their open bug count. |
171 | - |
172 | +def get_bug_tags_open_count(context_condition, user, tag_limit=0, |
173 | + include_tags=None): |
174 | + """Worker for IBugTarget.getUsedBugTagsWithOpenCounts. |
175 | + |
176 | + See `IBugTarget` for details. |
177 | + |
178 | + The only change is that this function takes a SQL expression for limiting |
179 | + the found tags. |
180 | :param context_condition: A Storm SQL expression, limiting the |
181 | used tags to a specific context. Only the BugTask table may be |
182 | used to choose the context. |
183 | - :param user: The user performing the search. |
184 | - :param wanted_tags: A set of tags within which to restrict the search. |
185 | - |
186 | - :return: A list of tuples, (tag name, open bug count). |
187 | """ |
188 | - tables = ( |
189 | - BugTag, |
190 | - Join(BugTask, BugTask.bugID == BugTag.bugID), |
191 | - ) |
192 | + # Circular fail. |
193 | + from lp.bugs.model.bugsummary import BugSummary |
194 | + tags = {} |
195 | + if include_tags: |
196 | + tags = dict((tag, 0) for tag in include_tags) |
197 | + store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) |
198 | + admin_team = getUtility(ILaunchpadCelebrities).admin |
199 | + if user is not None and not user.inTeam(admin_team): |
200 | + store = store.with_(SQL( |
201 | + "teams AS (" |
202 | + "SELECT team from TeamParticipation WHERE person=?)", (user.id,))) |
203 | where_conditions = [ |
204 | - BugTask.status.is_in(UNRESOLVED_BUGTASK_STATUSES), |
205 | + BugSummary.status.is_in(UNRESOLVED_BUGTASK_STATUSES), |
206 | + BugSummary.tag != None, |
207 | context_condition, |
208 | ] |
209 | - if wanted_tags is not None: |
210 | - where_conditions.append(BugTag.tag.is_in(wanted_tags)) |
211 | - privacy_filter = get_bug_privacy_filter(user) |
212 | - if privacy_filter: |
213 | - # The EXISTS sub-select avoids a join against Bug, improving |
214 | - # performance significantly. |
215 | + if user is None: |
216 | + where_conditions.append(BugSummary.viewed_by_id == None) |
217 | + elif not user.inTeam(admin_team): |
218 | where_conditions.append( |
219 | - Exists(Select( |
220 | - columns=[True], tables=[Bug], |
221 | - where=And(Bug.id == BugTag.bugID, SQLRaw(privacy_filter))))) |
222 | - store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) |
223 | - return store.using(*tables).find( |
224 | - tag_count_columns, *where_conditions).group_by(BugTag.tag).order_by( |
225 | - Desc(Count()), BugTag.tag) |
226 | + Or( |
227 | + BugSummary.viewed_by_id == None, |
228 | + BugSummary.viewed_by_id.is_in(SQL("SELECT team FROM teams")) |
229 | + )) |
230 | + tag_count_columns = (BugSummary.tag, Sum(BugSummary.count)) |
231 | + # Always query for used |
232 | + def _query(*args): |
233 | + return store.find(tag_count_columns, *(where_conditions + list(args)) |
234 | + ).group_by(BugSummary.tag).order_by( |
235 | + Desc(Sum(BugSummary.count)), BugSummary.tag) |
236 | + used = _query() |
237 | + if tag_limit: |
238 | + used = used[:tag_limit] |
239 | + if include_tags: |
240 | + # Union in a query for just include_tags. |
241 | + used = used.union(_query(BugSummary.tag.is_in(include_tags))) |
242 | + tags.update(dict(used)) |
243 | + return tags |
244 | |
245 | |
246 | class BugBecameQuestionEvent: |
247 | |
248 | === modified file 'lib/lp/registry/model/distribution.py' |
249 | --- lib/lp/registry/model/distribution.py 2011-05-27 21:12:25 +0000 |
250 | +++ lib/lp/registry/model/distribution.py 2011-06-07 05:39:33 +0000 |
251 | @@ -646,10 +646,14 @@ |
252 | """See `IBugTarget`.""" |
253 | return get_bug_tags("BugTask.distribution = %s" % sqlvalues(self)) |
254 | |
255 | - def getUsedBugTagsWithOpenCounts(self, user, wanted_tags=None): |
256 | - """See `IBugTarget`.""" |
257 | + def getUsedBugTagsWithOpenCounts(self, user, tag_limit=0, include_tags=None): |
258 | + """See IBugTarget.""" |
259 | + # Circular fail. |
260 | + from lp.bugs.model.bugsummary import BugSummary |
261 | return get_bug_tags_open_count( |
262 | - BugTask.distribution == self, user, wanted_tags=wanted_tags) |
263 | + And(BugSummary.distribution_id == self.id, |
264 | + BugSummary.sourcepackagename_id == None), |
265 | + user, tag_limit=tag_limit, include_tags=include_tags) |
266 | |
267 | def getMirrorByName(self, name): |
268 | """See `IDistribution`.""" |
269 | |
270 | === modified file 'lib/lp/registry/model/distributionsourcepackage.py' |
271 | --- lib/lp/registry/model/distributionsourcepackage.py 2011-05-12 04:18:32 +0000 |
272 | +++ lib/lp/registry/model/distributionsourcepackage.py 2011-06-07 05:39:33 +0000 |
273 | @@ -486,12 +486,14 @@ |
274 | """See `IBugTarget`.""" |
275 | return self.distribution.getUsedBugTags() |
276 | |
277 | - def getUsedBugTagsWithOpenCounts(self, user, wanted_tags=None): |
278 | - """See `IBugTarget`.""" |
279 | + def getUsedBugTagsWithOpenCounts(self, user, tag_limit=0, include_tags=None): |
280 | + """See IBugTarget.""" |
281 | + # Circular fail. |
282 | + from lp.bugs.model.bugsummary import BugSummary |
283 | return get_bug_tags_open_count( |
284 | - And(BugTask.distribution == self.distribution, |
285 | - BugTask.sourcepackagename == self.sourcepackagename), |
286 | - user, wanted_tags=wanted_tags) |
287 | + And(BugSummary.distribution == self.distribution, |
288 | + BugSummary.sourcepackagename == self.sourcepackagename), |
289 | + user, tag_limit=tag_limit, include_tags=include_tags) |
290 | |
291 | def _getOfficialTagClause(self): |
292 | return self.distribution._getOfficialTagClause() |
293 | |
294 | === modified file 'lib/lp/registry/model/distroseries.py' |
295 | --- lib/lp/registry/model/distroseries.py 2011-05-31 15:45:19 +0000 |
296 | +++ lib/lp/registry/model/distroseries.py 2011-06-07 05:39:33 +0000 |
297 | @@ -28,6 +28,7 @@ |
298 | StringCol, |
299 | ) |
300 | from storm.locals import ( |
301 | + And, |
302 | Desc, |
303 | Join, |
304 | SQL, |
305 | @@ -853,10 +854,16 @@ |
306 | """See `IHasBugs`.""" |
307 | return get_bug_tags("BugTask.distroseries = %s" % sqlvalues(self)) |
308 | |
309 | - def getUsedBugTagsWithOpenCounts(self, user, wanted_tags=None): |
310 | - """See `IHasBugs`.""" |
311 | + def getUsedBugTagsWithOpenCounts(self, user, tag_limit=0, include_tags=None): |
312 | + """See IBugTarget.""" |
313 | + # Circular fail. |
314 | + from lp.bugs.model.bugsummary import BugSummary |
315 | return get_bug_tags_open_count( |
316 | - BugTask.distroseries == self, user, wanted_tags=wanted_tags) |
317 | + And( |
318 | + BugSummary.distroseries_id == self.id, |
319 | + BugSummary.sourcepackagename_id == None |
320 | + ), |
321 | + user, tag_limit=tag_limit, include_tags=include_tags) |
322 | |
323 | @property |
324 | def has_any_specifications(self): |
325 | |
326 | === modified file 'lib/lp/registry/model/product.py' |
327 | --- lib/lp/registry/model/product.py 2011-05-27 21:12:25 +0000 |
328 | +++ lib/lp/registry/model/product.py 2011-06-07 05:39:33 +0000 |
329 | @@ -799,10 +799,13 @@ |
330 | """See `IBugTarget`.""" |
331 | return get_bug_tags("BugTask.product = %s" % sqlvalues(self)) |
332 | |
333 | - def getUsedBugTagsWithOpenCounts(self, user, wanted_tags=None): |
334 | - """See `IBugTarget`.""" |
335 | + def getUsedBugTagsWithOpenCounts(self, user, tag_limit=0, include_tags=None): |
336 | + """See IBugTarget.""" |
337 | + # Circular fail. |
338 | + from lp.bugs.model.bugsummary import BugSummary |
339 | return get_bug_tags_open_count( |
340 | - BugTask.product == self, user, wanted_tags=wanted_tags) |
341 | + BugSummary.product_id == self.id, |
342 | + user, tag_limit=tag_limit, include_tags=include_tags) |
343 | |
344 | series = SQLMultipleJoin('ProductSeries', joinColumn='product', |
345 | orderBy='name') |
346 | |
347 | === modified file 'lib/lp/registry/model/productseries.py' |
348 | --- lib/lp/registry/model/productseries.py 2011-05-27 21:12:25 +0000 |
349 | +++ lib/lp/registry/model/productseries.py 2011-06-07 05:39:33 +0000 |
350 | @@ -446,10 +446,13 @@ |
351 | """See IBugTarget.""" |
352 | return get_bug_tags("BugTask.productseries = %s" % sqlvalues(self)) |
353 | |
354 | - def getUsedBugTagsWithOpenCounts(self, user, wanted_tags=None): |
355 | + def getUsedBugTagsWithOpenCounts(self, user, tag_limit=0, include_tags=None): |
356 | """See IBugTarget.""" |
357 | + # Circular fail. |
358 | + from lp.bugs.model.bugsummary import BugSummary |
359 | return get_bug_tags_open_count( |
360 | - BugTask.productseries == self, user, wanted_tags=wanted_tags) |
361 | + BugSummary.productseries_id == self.id, user, tag_limit=tag_limit, |
362 | + include_tags=include_tags) |
363 | |
364 | def createBug(self, bug_params): |
365 | """See IBugTarget.""" |
366 | |
367 | === modified file 'lib/lp/registry/model/projectgroup.py' |
368 | --- lib/lp/registry/model/projectgroup.py 2011-04-26 16:22:11 +0000 |
369 | +++ lib/lp/registry/model/projectgroup.py 2011-06-07 05:39:33 +0000 |
370 | @@ -343,14 +343,16 @@ |
371 | return get_bug_tags( |
372 | "BugTask.product IN (%s)" % ",".join(product_ids)) |
373 | |
374 | - def getUsedBugTagsWithOpenCounts(self, user, wanted_tags=None): |
375 | - """See `IHasBugs`.""" |
376 | - if not self.products: |
377 | - return [] |
378 | + def getUsedBugTagsWithOpenCounts(self, user, tag_limit=0, include_tags=None): |
379 | + """See IBugTarget.""" |
380 | + # Circular fail. |
381 | + from lp.bugs.model.bugsummary import BugSummary |
382 | product_ids = [product.id for product in self.products] |
383 | + if not product_ids: |
384 | + return {} |
385 | return get_bug_tags_open_count( |
386 | - BugTask.productID.is_in(product_ids), user, |
387 | - wanted_tags=wanted_tags) |
388 | + BugSummary.product_id.is_in(product_ids), |
389 | + user, tag_limit=tag_limit, include_tags=include_tags) |
390 | |
391 | def _getBugTaskContextClause(self): |
392 | """See `HasBugsBase`.""" |
393 | |
394 | === modified file 'lib/lp/registry/model/sourcepackage.py' |
395 | --- lib/lp/registry/model/sourcepackage.py 2011-05-14 15:03:04 +0000 |
396 | +++ lib/lp/registry/model/sourcepackage.py 2011-06-07 05:39:33 +0000 |
397 | @@ -494,12 +494,14 @@ |
398 | """See `IBugTarget`.""" |
399 | return self.distroseries.getUsedBugTags() |
400 | |
401 | - def getUsedBugTagsWithOpenCounts(self, user, wanted_tags=None): |
402 | - """See `IBugTarget`.""" |
403 | + def getUsedBugTagsWithOpenCounts(self, user, tag_limit=0, include_tags=None): |
404 | + """See IBugTarget.""" |
405 | + # Circular fail. |
406 | + from lp.bugs.model.bugsummary import BugSummary |
407 | return get_bug_tags_open_count( |
408 | - And(BugTask.distroseries == self.distroseries, |
409 | - BugTask.sourcepackagename == self.sourcepackagename), |
410 | - user, wanted_tags=wanted_tags) |
411 | + And(BugSummary.distroseries == self.distroseries, |
412 | + BugSummary.sourcepackagename == self.sourcepackagename), |
413 | + user, tag_limit=tag_limit, include_tags=include_tags) |
414 | |
415 | @property |
416 | def max_bug_heat(self): |
21 + tags = self.context. getUsedBugTagsW ithOpenCounts( self.user, 10,
22 + official_tags)
Nice cleanup. But bad indentation.
33 + official_tags = self.context. official_ bug_tags
Sure this doesn't need to be materialised?
131 + :param tag_limit: The number of tags to return (excludes those found by
132 + matching include_tags). If 0 then all tags are returned. If
133 + non-zero then the most frequently used tags are returned.
0? Why not None?
172 +def get_bug_ tags_open_ count(context_ condition, user, tag_limit=0,
173 + include_tags=None):
Bad indentation.
200 + store = store.with_(SQL(
201 + "teams AS ("
202 + "SELECT team from TeamParticipation WHERE person=%s)" % user.id))
String formatting in SQL: Australia says no.
Also, calling that "store" is a bit too much of a lie for my tastes.
228 + BugSummary. viewed_ by_id.is_ in(SQL( "SELECT team FROM teams"))
What's the benefit of the WITH clause here? I doubt there is any performance gain, and including the full thing here is shorter and clearer.