Merge lp:~wgrant/launchpad/bug-1340010 into lp:launchpad

Proposed by William Grant
Status: Merged
Merged at revision: 17111
Proposed branch: lp:~wgrant/launchpad/bug-1340010
Merge into: lp:launchpad
Diff against target: 78 lines (+37/-2)
2 files modified
lib/lp/translations/model/translationmessage.py (+3/-1)
lib/lp/translations/tests/test_translationmessage.py (+34/-1)
To merge this branch: bzr merge lp:~wgrant/launchpad/bug-1340010
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+226246@code.launchpad.net

Commit message

TranslationMessageSet.preloadDetails now copes with TranslationMessages that have no corresponding POFile.

Description of the change

POFile:+translate OOPSes like OOPS-179ec78410b8af059254cb47ab76a328 when it attempts to preloadDetails on a suggestion that doesn't have a corresponding POFile.

In the only known case so far, POTMsgSet 3203927 ("Delete") exists in POTemplate 14011 (https://launchpad.net/listen/0.4/+pots/listen) and has a TranslationMessage for Language 540 (en_GB), but there's no POFile for Language 540 in POTemplate 14011. TranslationMessageSet.preloadDetails crashes when it tries to preload the POTemplate for a POFile that is None.

_buildAllSuggestions has a browser_pofile is not None check to handle this case, so it probably is a legal situation. The fix is trivial, the test slightly less so.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/translations/model/translationmessage.py'
2--- lib/lp/translations/model/translationmessage.py 2014-07-02 01:31:08 +0000
3+++ lib/lp/translations/model/translationmessage.py 2014-07-10 05:54:31 +0000
4@@ -558,7 +558,9 @@
5 if need_pofile:
6 self.preloadPOFilesAndSequences(tms, pofile)
7 if need_potemplate:
8- pofiles = [tm.browser_pofile for tm in tms]
9+ pofiles = [
10+ tm.browser_pofile for tm in tms
11+ if tm.browser_pofile is not None]
12 pots = load_related(
13 POTemplate,
14 (removeSecurityProxy(pofile) for pofile in pofiles),
15
16=== modified file 'lib/lp/translations/tests/test_translationmessage.py'
17--- lib/lp/translations/tests/test_translationmessage.py 2014-06-10 11:25:51 +0000
18+++ lib/lp/translations/tests/test_translationmessage.py 2014-07-10 05:54:31 +0000
19@@ -12,21 +12,27 @@
20
21 from pytz import UTC
22 from storm.locals import Store
23+import transaction
24 from zope.component import getUtility
25 from zope.security.proxy import removeSecurityProxy
26
27+from lp.services.propertycache import clear_property_cache
28 from lp.services.worlddata.interfaces.language import ILanguageSet
29 from lp.testing import (
30 TestCaseWithFactory,
31 verifyObject,
32 )
33-from lp.testing.layers import ZopelessDatabaseLayer
34+from lp.testing.layers import (
35+ DatabaseFunctionalLayer,
36+ ZopelessDatabaseLayer,
37+ )
38 from lp.translations.interfaces.side import (
39 ITranslationSideTraitsSet,
40 TranslationSide,
41 )
42 from lp.translations.interfaces.translationmessage import (
43 ITranslationMessage,
44+ ITranslationMessageSet,
45 TranslationConflict,
46 )
47 from lp.translations.interfaces.translations import TranslationConstants
48@@ -1096,3 +1102,30 @@
49 self.assertTrue(translation.is_diverged)
50 translation.shareIfPossible()
51 self.assertTrue(translation.is_diverged)
52+
53+
54+class TestPreloading(TestCaseWithFactory):
55+
56+ layer = DatabaseFunctionalLayer
57+
58+ def test_preloadDetails_handles_orphaned_message(self):
59+ # preloadDetails works when given a TranslationMessage that has
60+ # no POFile. This happens occasionally on production, and the
61+ # suggestion rendering code copes with it, so we should too.
62+ lang = self.factory.makeLanguage()
63+ tm1 = self.factory.makeCurrentTranslationMessage(language=lang)
64+ tm2 = self.factory.makeCurrentTranslationMessage(language=lang)
65+
66+ tm1_pofile = tm1.getOnePOFile()
67+ tm2_pofile = tm2.getOnePOFile()
68+
69+ # Get rid of tm1's POFile.
70+ removeSecurityProxy(tm1_pofile).language = self.factory.makeLanguage()
71+
72+ getUtility(ITranslationMessageSet).preloadDetails(
73+ [tm1, tm2], need_pofile=True, need_potemplate=True,
74+ need_potemplate_context=True, need_potranslation=True,
75+ need_potmsgset=True, need_people=True)
76+
77+ self.assertIs(None, tm1.browser_pofile)
78+ self.assertEqual(tm2_pofile, tm2.browser_pofile)