Merge lp:~edwin-grubbs/launchpad/bug-663857-product-packages-timeout into lp:launchpad

Proposed by Edwin Grubbs
Status: Merged
Approved by: Curtis Hovey
Approved revision: no longer in the source branch.
Merged at revision: 12236
Proposed branch: lp:~edwin-grubbs/launchpad/bug-663857-product-packages-timeout
Merge into: lp:launchpad
Diff against target: 308 lines (+86/-59)
5 files modified
lib/lp/registry/browser/product.py (+4/-19)
lib/lp/registry/browser/tests/packaging-views.txt (+19/-20)
lib/lp/registry/interfaces/product.py (+3/-0)
lib/lp/registry/model/product.py (+27/-7)
lib/lp/registry/templates/product-packages.pt (+33/-13)
To merge this branch: bzr merge lp:~edwin-grubbs/launchpad/bug-663857-product-packages-timeout
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code ui Approve
Review via email: mp+46222@code.launchpad.net

Commit message

[r=sinzui][ui=sinzui][bug=663857] Fixed timeout on $project/+packages page.

Description of the change

Summary
-------

This branch fixes the timeout on the $project/+packages page. It
restricts the results to series that are active or have packages. It
also batches the results.

I cleaned up the formatting, since a list of tables is fairly
confusing. I also sorted the results descending. If the series are named
by version number, the latest versions will appear at the top.

Implementation details
----------------------

    lib/lp/registry/browser/product.py
lib/lp/registry/browser/tests/packaging-views.txt
lib/lp/registry/interfaces/product.py
lib/lp/registry/model/product.py
lib/lp/registry/templates/product-packages.pt

Tests
-----

./bin/test -vv -t 'packaging-views.txt|xx-product-package-pages.txt'

Demo and Q/A
------------

* Open https://code.edge.launchpad.net/obsolete-junk/+packages
  * The page should not timeout.

Lint
----

The one remaining lint item shouldn't be fixed.

Linting changed files:
  lib/lp/registry/browser/product.py
  lib/lp/registry/browser/tests/packaging-views.txt
  lib/lp/registry/interfaces/product.py
  lib/lp/registry/model/product.py
  lib/lp/registry/templates/product-packages.pt

./lib/lp/registry/interfaces/product.py
     981: E301 expected 1 blank line, found 2

To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

Hi Edwin.

Thank you for improving the layout while address the timeout. This makes the page much easier to read.

review: Approve (code ui)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/registry/browser/product.py'
--- lib/lp/registry/browser/product.py 2010-12-30 16:22:22 +0000
+++ lib/lp/registry/browser/product.py 2011-01-19 15:36:00 +0000
@@ -1117,25 +1117,10 @@
1117 page_title = label1117 page_title = label
11181118
1119 @cachedproperty1119 @cachedproperty
1120 def series_packages(self):1120 def series_batch(self):
1121 """A hierarchy of product series, packaging and field data.1121 """A batch of series that are active or have packages."""
11221122 return BatchNavigator(
1123 A dict of series and packagings. Each packaging is a dict of the1123 self.context.active_or_packaged_series, self.request)
1124 packaging and a hidden HTML field for forms:
1125 [{series: <hoary>,
1126 packagings: {
1127 packaging: <packaging>,
1128 field: '<input type=''hidden' ...>},
1129 }]
1130 """
1131 packaged_series = []
1132 for series in self.context.series:
1133 packagings = []
1134 for packaging in series.packagings:
1135 packagings.append(packaging)
1136 packaged_series.append(dict(
1137 series=series, packagings=packagings))
1138 return packaged_series
11391124
1140 @property1125 @property
1141 def distro_packaging(self):1126 def distro_packaging(self):
11421127
=== modified file 'lib/lp/registry/browser/tests/packaging-views.txt'
--- lib/lp/registry/browser/tests/packaging-views.txt 2010-05-27 04:22:46 +0000
+++ lib/lp/registry/browser/tests/packaging-views.txt 2011-01-19 15:36:00 +0000
@@ -224,20 +224,19 @@
224 >>> print view.label224 >>> print view.label
225 Linked packages225 Linked packages
226226
227The view provides the series_packages property that returns a list of227The view provides the series_batch property.
228dicts. Each dict as a series and a list of packages.
229228
230 >>> def print_packages(view):229 >>> def print_packages(view):
231 ... for series_dict in view.series_packages:230 ... for series in view.series_batch.batch:
232 ... print series_dict['series'].name231 ... print series.name
233 ... for package in series_dict['packagings']:232 ... for package in series.packagings:
234 ... print package.distroseries.name233 ... print ' Package:', package.distroseries.name
235 >>> print_packages(view)234 >>> print_packages(view)
235 trunk
236 hotter
237 Package: grumpy
238 Package: hoary
236 cold239 cold
237 hotter
238 grumpy
239 hoary
240 trunk
241240
242The view provides the distro_packaging property that is a list of241The view provides the distro_packaging property that is a list of
243dictionaries for the distributions and their packaging. The list is242dictionaries for the distributions and their packaging. The list is
@@ -255,11 +254,11 @@
255 >>> view = create_initialized_view(254 >>> view = create_initialized_view(
256 ... product, name='+packages', principal=a_user)255 ... product, name='+packages', principal=a_user)
257 >>> print_packages(view)256 >>> print_packages(view)
257 trunk
258 hotter
259 Package: grumpy
260 Package: hoary
258 cold261 cold
259 hotter
260 grumpy
261 hoary
262 trunk
263262
264 # There are links to the +remove-packaging page.263 # There are links to the +remove-packaging page.
265 >>> table = find_tag_by_id(view.render(), 'packages-hotter')264 >>> table = find_tag_by_id(view.render(), 'packages-hotter')
@@ -270,8 +269,8 @@
270 http://launchpad.dev/ubuntu/hoary/+source/thunderbird/+remove-packaging269 http://launchpad.dev/ubuntu/hoary/+source/thunderbird/+remove-packaging
271270
272 >>> [hoary_package] = [271 >>> [hoary_package] = [
273 ... package for series_dict in view.series_packages272 ... package for series in view.series_batch.batch
274 ... for package in series_dict['packagings']273 ... for package in series.packagings
275 ... if package.distroseries.name == 'hoary']274 ... if package.distroseries.name == 'hoary']
276 >>> form = {'field.actions.unlink': 'Unlink'}275 >>> form = {'field.actions.unlink': 'Unlink'}
277 >>> unlink_view = create_initialized_view(276 >>> unlink_view = create_initialized_view(
@@ -279,13 +278,13 @@
279 >>> unlink_view.errors278 >>> unlink_view.errors
280 []279 []
281280
282 # The view has to be reloaded since view.series_packages is cached.281 # The view has to be reloaded since view.series_batch is cached.
283 >>> view = create_initialized_view(product, name='+packages')282 >>> view = create_initialized_view(product, name='+packages')
284 >>> print_packages(view)283 >>> print_packages(view)
284 trunk
285 hotter
286 Package: grumpy
285 cold287 cold
286 hotter
287 grumpy
288 trunk
289288
290289
291Distro series +packaging view290Distro series +packaging view
292291
=== modified file 'lib/lp/registry/interfaces/product.py'
--- lib/lp/registry/interfaces/product.py 2010-12-31 03:39:53 +0000
+++ lib/lp/registry/interfaces/product.py 2011-01-19 15:36:00 +0000
@@ -732,6 +732,9 @@
732 "Some bug trackers host multiple projects at the same URL "732 "Some bug trackers host multiple projects at the same URL "
733 "and require an identifier for the specific project.")))733 "and require an identifier for the specific project.")))
734734
735 active_or_packaged_series = Attribute(
736 _("Series that are active and/or have been packaged."))
737
735 def getVersionSortedSeries(statuses=None, filter_statuses=None):738 def getVersionSortedSeries(statuses=None, filter_statuses=None):
736 """Return all the series sorted by the name field as a version.739 """Return all the series sorted by the name field as a version.
737740
738741
=== modified file 'lib/lp/registry/model/product.py'
--- lib/lp/registry/model/product.py 2010-12-02 16:13:51 +0000
+++ lib/lp/registry/model/product.py 2011-01-19 15:36:00 +0000
@@ -28,13 +28,17 @@
28 SQLObjectNotFound,28 SQLObjectNotFound,
29 StringCol,29 StringCol,
30 )30 )
31from storm.expr import NamedFunc31from storm.expr import (
32 LeftJoin,
33 NamedFunc,
34 )
32from storm.locals import (35from storm.locals import (
33 And,36 And,
34 Desc,37 Desc,
35 Int,38 Int,
36 Join,39 Join,
37 Not,40 Not,
41 Or,
38 Select,42 Select,
39 SQL,43 SQL,
40 Store,44 Store,
@@ -48,9 +52,6 @@
48 )52 )
49from zope.security.proxy import removeSecurityProxy53from zope.security.proxy import removeSecurityProxy
5054
51from canonical.launchpad.components.decoratedresultset import (
52 DecoratedResultSet,
53 )
54from canonical.database.constants import UTC_NOW55from canonical.database.constants import UTC_NOW
55from canonical.database.datetimecol import UtcDateTimeCol56from canonical.database.datetimecol import UtcDateTimeCol
56from canonical.database.enumcol import EnumCol57from canonical.database.enumcol import EnumCol
@@ -59,6 +60,9 @@
59 SQLBase,60 SQLBase,
60 sqlvalues,61 sqlvalues,
61 )62 )
63from canonical.launchpad.components.decoratedresultset import (
64 DecoratedResultSet,
65 )
62from canonical.launchpad.interfaces.launchpad import (66from canonical.launchpad.interfaces.launchpad import (
63 IHasIcon,67 IHasIcon,
64 IHasLogo,68 IHasLogo,
@@ -74,7 +78,6 @@
74 IStoreSelector,78 IStoreSelector,
75 MAIN_STORE,79 MAIN_STORE,
76 )80 )
77from lp.registry.model.series import ACTIVE_STATUSES
78from lp.answers.interfaces.faqtarget import IFAQTarget81from lp.answers.interfaces.faqtarget import IFAQTarget
79from lp.answers.interfaces.questioncollection import (82from lp.answers.interfaces.questioncollection import (
80 QUESTION_STATUS_DEFAULT_SEARCH,83 QUESTION_STATUS_DEFAULT_SEARCH,
@@ -145,6 +148,7 @@
145from lp.registry.model.commercialsubscription import CommercialSubscription148from lp.registry.model.commercialsubscription import CommercialSubscription
146from lp.registry.model.distribution import Distribution149from lp.registry.model.distribution import Distribution
147from lp.registry.model.distroseries import DistroSeries150from lp.registry.model.distroseries import DistroSeries
151from lp.registry.model.hasdrivers import HasDriversMixin
148from lp.registry.model.karma import KarmaContextMixin152from lp.registry.model.karma import KarmaContextMixin
149from lp.registry.model.milestone import (153from lp.registry.model.milestone import (
150 HasMilestonesMixin,154 HasMilestonesMixin,
@@ -156,7 +160,7 @@
156from lp.registry.model.productlicense import ProductLicense160from lp.registry.model.productlicense import ProductLicense
157from lp.registry.model.productrelease import ProductRelease161from lp.registry.model.productrelease import ProductRelease
158from lp.registry.model.productseries import ProductSeries162from lp.registry.model.productseries import ProductSeries
159from lp.registry.model.hasdrivers import HasDriversMixin163from lp.registry.model.series import ACTIVE_STATUSES
160from lp.registry.model.sourcepackagename import SourcePackageName164from lp.registry.model.sourcepackagename import SourcePackageName
161from lp.registry.model.structuralsubscription import (165from lp.registry.model.structuralsubscription import (
162 StructuralSubscriptionTargetMixin,166 StructuralSubscriptionTargetMixin,
@@ -801,6 +805,22 @@
801 orderBy='name')805 orderBy='name')
802806
803 @property807 @property
808 def active_or_packaged_series(self):
809 store = Store.of(self)
810 tables = [
811 ProductSeries,
812 LeftJoin(Packaging, Packaging.productseries == ProductSeries.id),
813 ]
814 result = store.using(*tables).find(
815 ProductSeries,
816 ProductSeries.product == self,
817 Or(ProductSeries.status.is_in(ACTIVE_STATUSES),
818 Packaging.id != None))
819 result = result.order_by(Desc(ProductSeries.name))
820 result.config(distinct=True)
821 return result
822
823 @property
804 def name_with_project(self):824 def name_with_project(self):
805 """See lib.canonical.launchpad.interfaces.IProduct"""825 """See lib.canonical.launchpad.interfaces.IProduct"""
806 if self.project and self.project.name != self.name:826 if self.project and self.project.name != self.name:
@@ -1572,7 +1592,7 @@
15721592
1573 def getTranslatables(self):1593 def getTranslatables(self):
1574 """See `IProductSet`"""1594 """See `IProductSet`"""
1575 # XXX j.c.sackett 2010-11-19 bug=677532 It's less than ideal that 1595 # XXX j.c.sackett 2010-11-19 bug=677532 It's less than ideal that
1576 # this query is using _translations_usage, but there's no cleaner1596 # this query is using _translations_usage, but there's no cleaner
1577 # way to deal with it. Once the bug above is resolved, this should1597 # way to deal with it. Once the bug above is resolved, this should
1578 # should be fixed to use translations_usage.1598 # should be fixed to use translations_usage.
15791599
=== modified file 'lib/lp/registry/templates/product-packages.pt'
--- lib/lp/registry/templates/product-packages.pt 2010-03-03 18:35:08 +0000
+++ lib/lp/registry/templates/product-packages.pt 2011-01-19 15:36:00 +0000
@@ -10,28 +10,44 @@
10<body>10<body>
1111
12<div metal:fill-slot="main">12<div metal:fill-slot="main">
13 <div class="top-portlet">13 <div class="top-portlet"
14 tal:define="batch_nav view/series_batch">
14 <h2>Packages by project series</h2>15 <h2>Packages by project series</h2>
1516
16 <tal:series_dict repeat="series_dict view/series_packages">17 <tal:multipage tal:condition="batch_nav/has_multiple_pages">
17 <tal:series_packagings18 <tal:navigation
18 define="series series_dict/series;19 replace="structure batch_nav/@@+navigation-links-upper"/>
19 packagings series_dict/packagings">20 </tal:multipage>
21 <table class="listing">
22 <tr tal:repeat="series batch_nav/batch">
23 <td tal:define="packagings series/packagings">
24 <table style="width: 100%; margin: 0.5em 0 0 0">
25 <tr>
26 <td style="width: 33%">
20 <h3>27 <h3>
21 <a tal:attributes="href series/name">28 <a tal:attributes="href series/name">
22 <span tal:replace="series/name">main</span> series29 <span tal:replace="series/name">main</span> series
23 </a>30 </a>
24 </h3>31 </h3>
32 </td>
2533
26 <p tal:condition="not: packagings">34 <tal:no-packages condition="not: packagings">
35 <td style="width: 33%; text-align: center">
27 No packages linked to this series.36 No packages linked to this series.
28 </p>37 </td>
38 <td style="width: 33%; padding: 0 1.5em 0 0; text-align: right">
39 <a tal:condition="series/menu:overview/ubuntupkg/linked"
40 tal:replace="structure series/menu:overview/ubuntupkg/fmt:link" />
41 </td>
42 </tal:no-packages>
43 </tr>
44 </table>
2945
30 <tal:comment condition="nothing">46 <tal:comment condition="nothing">
31 This DIV is necessary for the table-actions:nth-child stylesheet.47 This DIV is necessary for the table-actions:nth-child stylesheet.
32 </tal:comment>48 </tal:comment>
33 <div>49 <div>
34 <table class="listing"50 <table class="listing" style="border: 0"
35 tal:condition="packagings"51 tal:condition="packagings"
36 tal:attributes="id series/name/fmt:css-id/packages-">52 tal:attributes="id series/name/fmt:css-id/packages-">
37 <thead>53 <thead>
@@ -73,15 +89,19 @@
73 </tbody>89 </tbody>
74 </table>90 </table>
7591
76 <ul class="table-actions"92 <ul class="table-actions" tal:condition="packagings">
77 tal:condition="series/menu:overview/ubuntupkg/linked">93 <li tal:condition="series/menu:overview/ubuntupkg/linked">
78 <li>
79 <a tal:replace="structure series/menu:overview/ubuntupkg/fmt:link" />94 <a tal:replace="structure series/menu:overview/ubuntupkg/fmt:link" />
80 </li>95 </li>
81 </ul>96 </ul>
82 </div>97 </div>
83 </tal:series_packagings>98 </td>
84 </tal:series_dict>99 </tr>
100 </table>
101 <tal:multipage condition="batch_nav/has_multiple_pages">
102 <tal:navigation
103 replace="structure batch_nav/@@+navigation-links-lower"/>
104 </tal:multipage>
85 </div>105 </div>
86106
87 <div class="portlet">107 <div class="portlet">