Merge lp:~adiroiban/launchpad/bug-462013-try-2 into lp:launchpad
- bug-462013-try-2
- Merge into devel
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Michael Nelson | ||||
Approved revision: | not available | ||||
Merged at revision: | not available | ||||
Proposed branch: | lp:~adiroiban/launchpad/bug-462013-try-2 | ||||
Merge into: | lp:launchpad | ||||
Diff against target: |
210 lines (+128/-18) 3 files modified
lib/lp/translations/browser/product.py (+12/-5) lib/lp/translations/browser/tests/test_product_view.py (+58/-12) lib/lp/translations/stories/productseries/xx-productseries-translations.txt (+58/-1) |
||||
To merge this branch: | bzr merge lp:~adiroiban/launchpad/bug-462013-try-2 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Nelson (community) | code | Approve | |
Review via email: mp+18186@code.launchpad.net |
Commit message
Don't include series in the list of series that can be set up for translations.
Description of the change
Adi Roiban (adiroiban) wrote : | # |
Michael Nelson (michael.nelson) wrote : | # |
<noodles775> adiroiban: I can take a look at that branch, or did you want someone specific to look at it?
<adiroiban> noodles775: hi. nope. you can review it
<noodles775> adiroiban: hi, your new test seems to pass even when I revert the change to product.py?
<noodles775> (BTW: thanks for adding extra tests too!)
<adiroiban> noodles775: uh... yes. I forget to test „obsolete is _not_ in extracted_text”
<adiroiban> noodles775: I pushed the missing test
<noodles775> adiroiban: thanks... I'm actually looking at the pagetest, and thinking that most of it is really testing the *view* functionality and should really be in a view/browser test...
<noodles775> I mean, you're really testing the untranslatable_
<adiroiban> noodles775: yes. I will move them in browser/tests
<noodles775> adiroiban: So perhaps just add one series in the pagetest and verify that it appears, then yes, the rest can go in the view test.
<adiroiban> noodles775: or 2...one active and one obsolete
<noodles775> adiroiban: also, I (personally) think it would be worth sorting the results of untranslatable_
<noodles775> adiroiban: well, the fact that the obsolete series won't be included should be in the view test (as it's view code).
<adiroiban> noodles775: ok. alphabetically sorted?
<noodles775> adiroiban: if that make the most sense, yes (another option would be by the status, but you'll know more about which makes most sense :)
<noodles775> adiroiban: So I'll make this as needs-fixing for the moment. Just ping me when you're done and I'll go through the code in detail. Thanks!
<adiroiban> noodles775: ok. thanks
Adi Roiban (adiroiban) wrote : | # |
Hi Michael,
I have moved the full test to unit testing layer and listed the series sorted alphabetically.
When you have time, please take a look at the latest diff. No hurry. Thanks!
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -85,7 +85,7 @@
@cachedpro
def uses_translatio
"""Whether this product has translatable templates."""
- return (self.context.
+ return (self.context.
@cachedpro
@@ -114,13 +114,15 @@
@cachedpro
def untranslatable_
"""Return series which are not yet set up for translations.
-
- Obsolete series will be excluded from this list.
+
+ The list is sorted in alphabetically order and obsolete series
+ will be excluded.
"""
[serie for serie in self.context.series if (
- return all_active_series - translatable
-
+ return sorted(
+ all_active_series - translatable,
+ key=lambda series: series.name)
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -9,6 +9,7 @@
from canonical.testing import LaunchpadZopele
from lp.translations
from lp.testing import TestCaseWithFactory
+from lp.registry.
class TestProduct(
@@ -17,27 +18,82 @@
layer = LaunchpadZopele
def setUp(self):
- # Create a product that uses translations.
- self.product = self.factory.
- self.series = self.product.
- self.product.
- self.view = ProductView(
- LaunchpadTestRe
def test_primary_
+ # Create a product that uses translations.
+ product = self.factory.
+ series = product.
+ product.
+ view = ProductView(
+
# If development focus series is linked to
# a distribution package with translations,
# we do not try to show translation statistics
# for the package.
- sourcepackage.
+ sourcepackage.
pot = self.factory.
...
Michael Nelson (michael.nelson) wrote : | # |
Hi Adi,
Thanks for moving those tests to a unit-test, you'll make a lot of people happy :) (We're trying to keep documentation nice and readable, with all non-documentati
I think you've got everything in the right place, but I do have a few suggestions below for simplifying the implementation and test a bit. I'll mark this as approved, but I'm keen to see which of the suggestions below you agree or disagree with.
Cheers,
Michael
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -18,6 +18,7 @@
> from canonical.
> from lp.registry.
> from lp.registry.
> +from lp.registry.
> from lp.registry.
> from lp.translations
>
> @@ -84,7 +85,7 @@
> @cachedproperty
> def uses_translatio
> """Whether this product has translatable templates."""
> - return (self.context.
> + return (self.context.
Thanks for the drive-by!
> self.primary_
>
> @cachedproperty
> @@ -112,7 +113,16 @@
>
> @cachedproperty
> def untranslatable_
> - """Return series which are not yet set up for translations."""
> - all_series = set(self.
> + """Return series which are not yet set up for translations.
> +
> + The list is sorted in alphabetically order and obsolete series
> + will be excluded.
s/will be/are ?
> + """
> +
> + all_active_series = set(
> + [serie for serie in self.context.series if (
> + serie.status != SeriesStatus.
It's pretty confusing, but grepping through the code a bit shows that
we seem to have a precedent of:
series for series in self.context.series
Take a look and see what you think.
> translatable = set(self.
> - return all_series - translatable
> + return sorted(
> + all_active_series - translatable,
> + key=lambda series: series.name)
We're meant to avoid using lambda (search for it in
https:/
using attrgetter for your specific use-case here.
But that said, I wonder if this could be simpler, given that IProduct.series
already orders by name? I've just tested the following which also works:
def untranslatable_
"""..."""
return [series for series in self.context.series if (
series not in translatable)]
Let me know if there was a specific reason for converting to sets - given
that we're iterating anyway for the list comprehension, I'm not sure
there's a benefit in using the...
Adi Roiban (adiroiban) wrote : | # |
Hey,
Thanks for the review.
Have no mercy reviewing my branches. It is your project and you should not accept bad code.
Don't worry, I will not take offence.
Here is the latest diff.
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -116,13 +116,10 @@
"""Return series which are not yet set up for translations.
The list is sorted in alphabetically order and obsolete series
- will be excluded.
+ are excluded.
"""
- all_active_series = set(
- [serie for serie in self.context.series if (
- serie.status != SeriesStatus.
- translatable = set(self.
- return sorted(
- all_active_series - translatable,
- key=lambda series: series.name)
+ translatable = self.context.
+ return [series for series in self.context.series if (
+ series.status != SeriesStatus.
+ series not in translatable)]
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -7,9 +7,9 @@
from canonical.
from canonical.testing import LaunchpadZopele
+from lp.registry.
from lp.translations
from lp.testing import TestCaseWithFactory
-from lp.registry.
class TestProduct(
@@ -17,9 +17,6 @@
layer = LaunchpadZopele
- def setUp(self):
- TestCaseWithFac
-
def test_primary_
# Create a product that uses translations.
product = self.factory.
@@ -75,24 +72,17 @@
- # 'untranslatable
- # check it after adding all series.
- self.assertTrue
- self.assertTrue
- self.assertTrue
- self.assertTrue
- self.assertTrue
- self.assertTrue
-
- # Obsolete series are not included
- self.assertFals
-
- # Series are listed in alphabetical order, 'evo-current'
- # is firsts, while 'trunk' is last.
- self.assertTrue(
- series_current == view.untranslat
- self.assertTrue(
- series_trunk == view.untranslat
+ # The series are return...
Michael Nelson (michael.nelson) wrote : | # |
Thanks Adi. Looks good. Still r=me.
Adi Roiban (adiroiban) wrote : | # |
Thanks.
Do you have time to land this branch or should I ask someone else?
Cheers,
Adi
Michael Nelson (michael.nelson) wrote : | # |
On Tue, Feb 2, 2010 at 4:35 PM, Adi Roiban <email address hidden> wrote:
> Thanks.
> Do you have time to land this branch or should I ask someone else?
Sure. It's on ec2 to land now :)
Preview Diff
1 | === modified file 'lib/lp/translations/browser/product.py' |
2 | --- lib/lp/translations/browser/product.py 2010-01-23 21:42:36 +0000 |
3 | +++ lib/lp/translations/browser/product.py 2010-01-29 16:28:23 +0000 |
4 | @@ -18,6 +18,7 @@ |
5 | from canonical.launchpad.webapp.menu import NavigationMenu |
6 | from lp.registry.interfaces.product import IProduct |
7 | from lp.registry.interfaces.productseries import IProductSeries |
8 | +from lp.registry.interfaces.series import SeriesStatus |
9 | from lp.registry.browser.product import ProductEditView |
10 | from lp.translations.browser.translations import TranslationsMixin |
11 | |
12 | @@ -88,7 +89,7 @@ |
13 | @cachedproperty |
14 | def uses_translations(self): |
15 | """Whether this product has translatable templates.""" |
16 | - return (self.context.official_rosetta and |
17 | + return (self.context.official_rosetta and |
18 | self.primary_translatable is not None) |
19 | |
20 | @cachedproperty |
21 | @@ -116,7 +117,13 @@ |
22 | |
23 | @cachedproperty |
24 | def untranslatable_series(self): |
25 | - """Return series which are not yet set up for translations.""" |
26 | - all_series = set(self.context.series) |
27 | - translatable = set(self.context.translatable_series) |
28 | - return all_series - translatable |
29 | + """Return series which are not yet set up for translations. |
30 | + |
31 | + The list is sorted in alphabetically order and obsolete series |
32 | + are excluded. |
33 | + """ |
34 | + |
35 | + translatable = self.context.translatable_series |
36 | + return [series for series in self.context.series if ( |
37 | + series.status != SeriesStatus.OBSOLETE and |
38 | + series not in translatable)] |
39 | |
40 | === modified file 'lib/lp/translations/browser/tests/test_product_view.py' |
41 | --- lib/lp/translations/browser/tests/test_product_view.py 2010-01-16 08:45:58 +0000 |
42 | +++ lib/lp/translations/browser/tests/test_product_view.py 2010-01-29 16:28:23 +0000 |
43 | @@ -7,6 +7,7 @@ |
44 | |
45 | from canonical.launchpad.webapp.servers import LaunchpadTestRequest |
46 | from canonical.testing import LaunchpadZopelessLayer |
47 | +from lp.registry.interfaces.series import SeriesStatus |
48 | from lp.translations.browser.product import ProductView |
49 | from lp.testing import TestCaseWithFactory |
50 | |
51 | @@ -16,28 +17,73 @@ |
52 | |
53 | layer = LaunchpadZopelessLayer |
54 | |
55 | - def setUp(self): |
56 | - # Create a product that uses translations. |
57 | - TestCaseWithFactory.setUp(self) |
58 | - self.product = self.factory.makeProduct() |
59 | - self.series = self.product.development_focus |
60 | - self.product.official_rosetta = True |
61 | - self.view = ProductView(self.product, |
62 | - LaunchpadTestRequest()) |
63 | - |
64 | def test_primary_translatable_with_package_link(self): |
65 | + # Create a product that uses translations. |
66 | + product = self.factory.makeProduct() |
67 | + series = product.development_focus |
68 | + product.official_rosetta = True |
69 | + view = ProductView(product, LaunchpadTestRequest()) |
70 | + |
71 | # If development focus series is linked to |
72 | # a distribution package with translations, |
73 | # we do not try to show translation statistics |
74 | # for the package. |
75 | sourcepackage = self.factory.makeSourcePackage() |
76 | - sourcepackage.setPackaging(self.series, None) |
77 | + sourcepackage.setPackaging(series, None) |
78 | sourcepackage.distroseries.distribution.official_rosetta = True |
79 | pot = self.factory.makePOTemplate( |
80 | distroseries=sourcepackage.distroseries, |
81 | sourcepackagename=sourcepackage.sourcepackagename) |
82 | - self.assertEquals(None, self.view.primary_translatable) |
83 | + self.assertEquals(None, view.primary_translatable) |
84 | + |
85 | + def test_untranslatable_series(self): |
86 | + # Create a product that uses translations. |
87 | + product = self.factory.makeProduct() |
88 | + series_trunk = product.development_focus |
89 | + product.official_rosetta = True |
90 | + view = ProductView(product, LaunchpadTestRequest()) |
91 | + |
92 | + # New series are added, one for each type of status |
93 | + series_experimental = self.factory.makeProductSeries( |
94 | + product=product, name='evo-experimental') |
95 | + series_experimental.status = SeriesStatus.EXPERIMENTAL |
96 | + |
97 | + series_development = self.factory.makeProductSeries( |
98 | + product=product, name='evo-development') |
99 | + series_development.status = SeriesStatus.DEVELOPMENT |
100 | + |
101 | + series_frozen = self.factory.makeProductSeries( |
102 | + product=product, name='evo-frozen') |
103 | + series_frozen.status = SeriesStatus.FROZEN |
104 | + |
105 | + series_current = self.factory.makeProductSeries( |
106 | + product=product, name='evo-current') |
107 | + series_current.status = SeriesStatus.CURRENT |
108 | + |
109 | + series_supported = self.factory.makeProductSeries( |
110 | + product=product, name='evo-supported') |
111 | + series_supported.status = SeriesStatus.SUPPORTED |
112 | + |
113 | + series_obsolete = self.factory.makeProductSeries( |
114 | + product=product, name='evo-obsolete') |
115 | + series_obsolete.status = SeriesStatus.OBSOLETE |
116 | + |
117 | + series_future = self.factory.makeProductSeries( |
118 | + product=product, name='evo-future') |
119 | + series_future.status = SeriesStatus.FUTURE |
120 | + |
121 | + # The series are returned in alphabetical order and do not |
122 | + # include obsolete series. |
123 | + series_names = [series.name for series in view.untranslatable_series] |
124 | + self.assertEqual([ |
125 | + u'evo-current', |
126 | + u'evo-development', |
127 | + u'evo-experimental', |
128 | + u'evo-frozen', |
129 | + u'evo-future', |
130 | + u'evo-supported', |
131 | + u'trunk'], series_names) |
132 | + |
133 | |
134 | def test_suite(): |
135 | return unittest.TestLoader().loadTestsFromName(__name__) |
136 | - |
137 | |
138 | === modified file 'lib/lp/translations/stories/productseries/xx-productseries-translations.txt' |
139 | --- lib/lp/translations/stories/productseries/xx-productseries-translations.txt 2010-01-05 16:19:13 +0000 |
140 | +++ lib/lp/translations/stories/productseries/xx-productseries-translations.txt 2010-01-29 16:28:23 +0000 |
141 | @@ -148,7 +148,7 @@ |
142 | |
143 | # Use the raw DB object to bypass the security proxy. |
144 | >>> from lp.registry.model.product import Product |
145 | - >>> Product.byName('evolution').official_rosetta = False |
146 | + >>> Product.byName('bazaar').official_rosetta = False |
147 | |
148 | When the owner now visits the upload page for trunk, there's a notice. |
149 | |
150 | @@ -268,3 +268,60 @@ |
151 | >>> print extract_text( |
152 | ... find_tag_by_id(admin_browser.contents, 'translation-focus')) |
153 | Launchpad currently recommends translating 1.6. |
154 | + |
155 | + |
156 | +Setting up translations for series |
157 | +---------------------------------- |
158 | + |
159 | +When visiting product translations main page, project developers sees |
160 | +status for current series configured for translations. |
161 | +Beside the "All translatable series" section, they will find the |
162 | +"Set up translations for a series" section with links to other series |
163 | +that can be configured for translations. |
164 | + |
165 | +When projects have only one active series, and it is already configured, |
166 | +project admin does not see the link for configuring other branches. |
167 | + |
168 | + >>> admin_browser.open( |
169 | + ... 'http://translations.launchpad.dev/evolution') |
170 | + >>> untranslatable = find_tag_by_id( |
171 | + ... admin_browser.contents, 'portlet-untranslatable-branches') |
172 | + >>> untranslatable is None |
173 | + True |
174 | + |
175 | +A new series is added. |
176 | + |
177 | + >>> from lp.registry.model.product import Product |
178 | + >>> from lp.registry.interfaces.series import SeriesStatus |
179 | + >>> login('foo.bar@canonical.com') |
180 | + >>> evolution = Product.byName('evolution') |
181 | + >>> series = factory.makeProductSeries( |
182 | + ... product=evolution, name='evo-new') |
183 | + >>> series.status = SeriesStatus.EXPERIMENTAL |
184 | + >>> logout() |
185 | + |
186 | +Project administrator will see links to configuring translations for |
187 | +the new series. |
188 | + |
189 | + >>> admin_browser.open( |
190 | + ... 'http://translations.launchpad.dev/evolution') |
191 | + >>> untranslatable = find_tag_by_id( |
192 | + ... admin_browser.contents, 'portlet-untranslatable-branches') |
193 | + >>> print extract_text(untranslatable) |
194 | + Set up translations for a series... |
195 | + evo-new series — manual or automatic... |
196 | + |
197 | +For each series there is a link for accesing the series translations |
198 | +page togheter with link for uploading a template from that series |
199 | +(manual) and setting automatic imports. |
200 | + |
201 | + >>> print admin_browser.getLink('Evolution evo-new series').url |
202 | + http://translations.launchpad.dev/evolution/evo-new/+translations |
203 | + |
204 | + >>> print admin_browser.getLink( |
205 | + ... 'manual', url='/evolution/evo-new/+translations-upload').url |
206 | + http://translations.launchpad.dev/evolution/evo-new/+translations-upload |
207 | + |
208 | + >>> print admin_browser.getLink( |
209 | + ... 'automatic', url='/evolution/evo-new/+translations-settings').url |
210 | + http://translations.launchpad.dev/evolution/evo-new/+translations-settings |
= Bug 462013 =
On a project's main translation page, there is a little box ("Set up translations for other series") that suggests I import templates for any series in my project that isn't yet imported. But it shouldn't bother listing obsolete series.
== Proposed fix ==
Don't include series with status OBSOLETE in the prompt list of series that can be set up for translations
== Pre-implementation notes ==
This was initially branch was submitted together with DistroSeries to Series refactoring (bug 496352).
Danilo took a look and decided to split the branch in refactoring and this new branch.
== Implementation details ==
The test from xx-productserie s-translations. txt , line 150 was setting the status for 'evolution' but then the test were done for 'bazaar'.
I've changed the code to set the status bazaar.
The series are listed in random order. This is why I used `u'serie name' in extracted_text`.
== Tests == translations
lp-test -t productseries-
== Demo and Q/A ==
In a product, create 2 new series, one in developlment and the other obsolete. translations. launchpad. dev/evolution
Go to product translation page. ie: http://
The obsolete series should not appear in the 'Set up translations for a series' list.
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files: translations/ browser/ product. py translations/ stories/ productseries/ xx-productserie s-translations. txt
lib/lp/
lib/lp/