Merge lp:~bac/launchpad/bug-487965 into lp:launchpad

Proposed by Brad Crittenden
Status: Merged
Approved by: Edwin Grubbs
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~bac/launchpad/bug-487965
Merge into: lp:launchpad
Diff against target: 136 lines (+68/-17)
2 files modified
lib/lp/registry/browser/product.py (+24/-17)
lib/lp/registry/browser/tests/packaging-views.txt (+44/-0)
To merge this branch: bzr merge lp:~bac/launchpad/bug-487965
Reviewer Review Type Date Requested Status
Edwin Grubbs (community) code Approve
Review via email: mp+15251@code.launchpad.net

Commit message

Fix an error in the product/+packages view code that is causing an OOPS.

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

= Summary =

Bug 487965 reports an OOPS that occurs when attempting to look at
packages for a product when there are more than one distribution
represented.

== Proposed fix ==

The dictionaries representing the distros and packaging used to have an
entry with the distribution name in it. Since the name was used as the
key for the containing dictionary it, having the name in the distro
dictionary looked redundant and it was inadvertently removed.

While I could've just stuffed it back in I though restructuring the code
to be less fragile was a better solution.

== Pre-implementation notes ==

None.

== Implementation details ==

As above.

== Tests ==

bin/test -vvt packaging-views.txt

== Demo and Q/A ==

Visit the product in the bug report and ensure it doesn't OOPS.

= Launchpad lint =

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

Linting changed files:
  lib/lp/registry/browser/product.py
  lib/lp/registry/browser/tests/packaging-views.txt

== Pylint notices ==

lib/lp/registry/browser/product.py
    54: [F0401] Unable to import 'lazr.delegates' (No module named
delegates)

Revision history for this message
Edwin Grubbs (edwin-grubbs) wrote :
Download full text (3.4 KiB)

Hi Brad,

This is a nice improvement.

merge-conditional

-Edwin

>=== modified file 'lib/lp/registry/browser/product.py'
>--- lib/lp/registry/browser/product.py 2009-11-23 14:52:25 +0000
>+++ lib/lp/registry/browser/product.py 2009-11-25 18:30:38 +0000
>@@ -474,9 +474,9 @@
>
> def _sort_distros(a, b):

Since this function doesn't actually sort a & b, it should be
called _compare_distros.

> """Put Ubuntu first, otherwise in alpha order."""
>- if a['name'] == 'ubuntu':
>+ if a == 'ubuntu':
> return -1

This only works if 'ubuntu' is always passed in as the first
parameter. There needs to be a corresponding if-statement for
b=='ubuntu'.

>- return cmp(a['name'], b['name'])
>+ return cmp(a, b)
>
>
> class ProductSetBreadcrumb(Breadcrumb):
>@@ -947,29 +947,33 @@
> title, and an attribute "packagings" which is a list of the relevant
> packagings for this distro and product.
> """
>- distros = {}
>- # first get a list of all relevant packagings
>+ # First get a list of all relevant packagings.
> all_packagings = []
> for series in self.context.series:
> for packaging in series.packagings:
> all_packagings.append(packaging)
>- # we sort it so that the packagings will always be displayed in the
>- # distroseries version, then productseries name order
>+ # We sort it so that the packagings will always be displayed in the
>+ # distroseries version, then productseries name order.
> all_packagings.sort(key=lambda a: (a.distroseries.version,
> a.productseries.name, a.id))
>+
>+ distros = {}
> for packaging in all_packagings:
>- if distros.has_key(packaging.distroseries.distribution.name):
>- distro = distros[packaging.distroseries.distribution.name]
>+ distribution = packaging.distroseries.distribution
>+ if distribution.name in distros:
>+ distro = distros[distribution.name]
> else:
>- distro = {}
>- distro['distribution'] = packaging.distroseries.distribution
>- distro['packagings'] = []
>+ # Create a dictionary for the distribution.
>+ distro = dict(
>+ distribution=packaging.distroseries.distribution,

Since you created the new distribution variable, this could be shortened to:
  distribution=distribution

>+ packagings=[])
> distros[packaging.distroseries.distribution.name] = distro

The index could be shortened to just distribution.name.
Alternatively, the entire if-else-statement could be replaced with:
    distro = distros.setdefault(
        distribution.name, dict(distribution=distribution, packaging=[]))
but that is up to you, since you might find it less readable.

> distro['packagings'].append(packaging)
>- # now we sort the resulting set of "distro" objects, and return that
>- result = distros.values()
>- result.sort(cmp=_sort_distros)
>- return result
>+ # Now we sort the resulting list of "distro" objects, and re...

Read more...

review: Approve (code)

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 2009-11-23 14:52:25 +0000
+++ lib/lp/registry/browser/product.py 2009-11-25 19:24:17 +0000
@@ -472,11 +472,14 @@
472 links = ['listall', 'doc', 'assignments', 'new', 'register_sprint']472 links = ['listall', 'doc', 'assignments', 'new', 'register_sprint']
473473
474474
475def _sort_distros(a, b):475def _cmp_distros(a, b):
476 """Put Ubuntu first, otherwise in alpha order."""476 """Put Ubuntu first, otherwise in alpha order."""
477 if a['name'] == 'ubuntu':477 if a == 'ubuntu':
478 return -1478 return -1
479 return cmp(a['name'], b['name'])479 elif b == 'ubuntu':
480 return 1
481 else:
482 return cmp(a, b)
480483
481484
482class ProductSetBreadcrumb(Breadcrumb):485class ProductSetBreadcrumb(Breadcrumb):
@@ -947,29 +950,33 @@
947 title, and an attribute "packagings" which is a list of the relevant950 title, and an attribute "packagings" which is a list of the relevant
948 packagings for this distro and product.951 packagings for this distro and product.
949 """952 """
950 distros = {}953 # First get a list of all relevant packagings.
951 # first get a list of all relevant packagings
952 all_packagings = []954 all_packagings = []
953 for series in self.context.series:955 for series in self.context.series:
954 for packaging in series.packagings:956 for packaging in series.packagings:
955 all_packagings.append(packaging)957 all_packagings.append(packaging)
956 # we sort it so that the packagings will always be displayed in the958 # We sort it so that the packagings will always be displayed in the
957 # distroseries version, then productseries name order959 # distroseries version, then productseries name order.
958 all_packagings.sort(key=lambda a: (a.distroseries.version,960 all_packagings.sort(key=lambda a: (a.distroseries.version,
959 a.productseries.name, a.id))961 a.productseries.name, a.id))
962
963 distros = {}
960 for packaging in all_packagings:964 for packaging in all_packagings:
961 if distros.has_key(packaging.distroseries.distribution.name):965 distribution = packaging.distroseries.distribution
962 distro = distros[packaging.distroseries.distribution.name]966 if distribution.name in distros:
967 distro = distros[distribution.name]
963 else:968 else:
964 distro = {}969 # Create a dictionary for the distribution.
965 distro['distribution'] = packaging.distroseries.distribution970 distro = dict(
966 distro['packagings'] = []971 distribution=distribution,
967 distros[packaging.distroseries.distribution.name] = distro972 packagings=[])
973 distros[distribution.name] = distro
968 distro['packagings'].append(packaging)974 distro['packagings'].append(packaging)
969 # now we sort the resulting set of "distro" objects, and return that975 # Now we sort the resulting list of "distro" objects, and return that.
970 result = distros.values()976 distro_names = distros.keys()
971 result.sort(cmp=_sort_distros)977 distro_names.sort(cmp=_cmp_distros)
972 return result978 results = [distros[name] for name in distro_names]
979 return results
973980
974981
975class ProductDownloadFilesView(LaunchpadView,982class ProductDownloadFilesView(LaunchpadView,
976983
=== modified file 'lib/lp/registry/browser/tests/packaging-views.txt'
--- lib/lp/registry/browser/tests/packaging-views.txt 2009-11-19 22:16:06 +0000
+++ lib/lp/registry/browser/tests/packaging-views.txt 2009-11-25 19:24:17 +0000
@@ -274,6 +274,40 @@
274 <input type="hidden" name="field.packaging" .../>274 <input type="hidden" name="field.packaging" .../>
275 trunk275 trunk
276276
277The view provides the distro_packaging property that is a list of
278dictionaries for the distributions and their packaging. The list is
279sorted by distribution with Ubuntu first and the rest in alphabetic
280order.
281
282 >>> form = {
283 ... 'field.distroseries': 'redhat/7.0',
284 ... 'field.sourcepackagename': 'hot',
285 ... 'field.packaging': 'Primary Project',
286 ... 'field.actions.continue': 'Continue',
287 ... }
288
289 >>> view = create_initialized_view(
290 ... productseries, '+addpackage', form=form)
291 >>> view.errors
292 []
293 >>> form = {
294 ... 'field.distroseries': 'debian/sarge',
295 ... 'field.sourcepackagename': 'hot',
296 ... 'field.packaging': 'Primary Project',
297 ... 'field.actions.continue': 'Continue',
298 ... }
299
300 >>> view = create_initialized_view(
301 ... productseries, '+addpackage', form=form)
302 >>> view.errors
303 []
304 >>> view = create_initialized_view(product, name='+packages')
305 >>> for distro_dict in view.distro_packaging:
306 ... print distro_dict['distribution'].name
307 ubuntu
308 debian
309 redhat
310
277The +packages named view descends from PackagingDeleteView to provide remove311The +packages named view descends from PackagingDeleteView to provide remove
278link actions for the product's linked packages.312link actions for the product's linked packages.
279313
@@ -285,6 +319,14 @@
285A packaging link can be deleted if the owner believes it is an error. The319A packaging link can be deleted if the owner believes it is an error. The
286package linked to hoary is wrong; thunderbird is the wrong sourcepackage.320package linked to hoary is wrong; thunderbird is the wrong sourcepackage.
287321
322 >>> view = create_initialized_view(product, name='+packages')
323 >>> for package in view.all_packaging:
324 ... print package.distroseries.name, package.productseries.name
325 sarge hotter
326 7.0 hotter
327 grumpy hotter
328 hoary hotter
329
288 >>> [hoary_package] = [package for package in view.all_packaging330 >>> [hoary_package] = [package for package in view.all_packaging
289 ... if package.distroseries.name == 'hoary']331 ... if package.distroseries.name == 'hoary']
290 >>> form = {332 >>> form = {
@@ -296,4 +338,6 @@
296 []338 []
297 >>> for package in view.all_packaging:339 >>> for package in view.all_packaging:
298 ... print package.distroseries.name, package.productseries.name340 ... print package.distroseries.name, package.productseries.name
341 sarge hotter
342 7.0 hotter
299 grumpy hotter343 grumpy hotter