launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #00840
[Merge] lp:~jtv/launchpad/recife-diverge into lp:~launchpad/launchpad/recife
Jeroen T. Vermeulen has proposed merging lp:~jtv/launchpad/recife-diverge into lp:~launchpad/launchpad/recife.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers): code
= approveAsDiverged =
For the Recife feature branch. This implements the option to approve a translation suggestion, not as the new shared translation as you'd normally want, but as a diverged translation specific to one particular POTemplate.
Interface-wise, the new method is on TranslationMessage: "approve this one in this POFile." The actual implementation is in POTMsgSet, where all the supporting infrastructure is, and the published one forwards to it.
To test:
{{{
./bin/test -vvc lp.translations.tests.test_translationmessage -t ApproveAsDiverged
}}}
(Although of course I ran the rest of 'em as well).
I also seized this opportunity to replace a factory method, previously a hack to work around the lack of this new method, to do things more properly.
No lint,
Jeroen
--
https://code.launchpad.net/~jtv/launchpad/recife-diverge/+merge/34407
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jtv/launchpad/recife-diverge into lp:~launchpad/launchpad/recife.
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2010-09-01 13:47:24 +0000
+++ lib/lp/testing/factory.py 2010-09-02 11:57:45 +0000
@@ -237,7 +237,6 @@
time_counter,
)
from lp.translations.interfaces.potemplate import IPOTemplateSet
-from lp.translations.interfaces.side import ITranslationSideTraitsSet
from lp.translations.interfaces.translationfileformat import (
TranslationFileFormat,
)
@@ -443,7 +442,6 @@
registry_team.addMember(user, registry_team.teamowner)
return user
-
def makeCopyArchiveLocation(self, distribution=None, owner=None,
name=None, enabled=True):
"""Create and return a new arbitrary location for copy packages."""
@@ -2300,18 +2298,16 @@
"""Create a diverged, current `TranslationMessage`."""
if pofile is None:
pofile = self.makePOFile('lt')
+ if reviewer is None:
+ reviewer = self.makePerson()
# This creates a suggestion, then diverges it, then activates it.
# Once we have a method for diverging messages, do this in a more
# proper way.
- message = self.makeSharedTranslationMessage(
+ message = self.makeSuggestion(
pofile=pofile, potmsgset=potmsgset, translator=translator,
- reviewer=reviewer, translations=translations, suggestion=True)
- traits = getUtility(ITranslationSideTraitsSet).getTraits(
- pofile.potemplate.translation_side)
- removeSecurityProxy(message).potemplate = pofile.potemplate
- traits.setFlag(message, True)
- return message
+ translations=translations)
+ return message.approveAsDiverged(pofile, reviewer)
def makeTranslation(self, pofile, sequence,
english=None, translated=None,
=== modified file 'lib/lp/testing/tests/test_factory.py'
--- lib/lp/testing/tests/test_factory.py 2010-08-24 07:12:53 +0000
+++ lib/lp/testing/tests/test_factory.py 2010-09-02 11:57:45 +0000
@@ -6,7 +6,6 @@
__metaclass__ = type
from datetime import datetime
-import unittest
import pytz
from zope.component import getUtility
=== modified file 'lib/lp/translations/interfaces/translationmessage.py'
--- lib/lp/translations/interfaces/translationmessage.py 2010-08-24 11:39:06 +0000
+++ lib/lp/translations/interfaces/translationmessage.py 2010-09-02 11:57:45 +0000
@@ -259,6 +259,9 @@
lock_timestamp=None):
"""Approve this suggestion, making it a current translation."""
+ def approveAsDiverged(pofile, reviewer, lock_timestamp=None):
+ """Approve this suggestion, as a diverged translation."""
+
# XXX CarlosPerelloMarin 20071022: We should move this into browser code.
def makeHTMLID(description):
"""Unique identifier for self, suitable for use in HTML element ids.
=== modified file 'lib/lp/translations/model/potmsgset.py'
--- lib/lp/translations/model/potmsgset.py 2010-09-01 15:11:18 +0000
+++ lib/lp/translations/model/potmsgset.py 2010-09-02 11:57:45 +0000
@@ -1145,6 +1145,61 @@
template.awardKarma(translator, 'translationsuggestionapproved')
template.awardKarma(reviewer, 'translationreview')
+ def approveAsDiverged(self, pofile, suggestion, reviewer,
+ lock_timestamp=None):
+ """Approve a suggestion to become a diverged translation."""
+ template = pofile.potemplate
+ traits = getUtility(ITranslationSideTraitsSet).getTraits(
+ template.translation_side)
+ if suggestion.potemplate == template and traits.getFlag(suggestion):
+ # The suggestion is already current and diverged for the
+ # right template.
+ return suggestion
+
+ incumbent = traits.getCurrentMessage(self, template, pofile.language)
+ if incumbent is not None:
+ self._checkForConflict(incumbent, lock_timestamp)
+ if incumbent.is_diverged:
+ # The incumbent is in the way. Disable it.
+ traits.setFlag(incumbent, False)
+ incumbent.shareIfPossible()
+ else:
+ # This incumbent isn't really in the way.
+ incumbent = None
+
+ if traits.other_side_traits.getFlag(suggestion):
+ # The suggestion is already current on the other side. Can't
+ # reuse it as a diverged message here, so clone it.
+ message = None
+ elif not traits.getFlag(suggestion):
+ # No obstacles. Diverge & activate.
+ suggestion.potemplate = template
+ traits.setFlag(suggestion, True)
+ message = reviewed_message = suggestion
+ elif suggestion.is_diverged:
+ # The suggestion is already current in another template.
+ # Can't reuse it as a diverged message here, so clone it.
+ message = None
+ else:
+ # This message is already the shared current message. If it
+ # was previously masked by a diverged message, it no longer
+ # is. This is probably the behaviour the user would expect.
+ message = suggestion
+ reviewed_message = incumbent
+
+ if message is None:
+ potranslations = self._findPOTranslations(
+ dict(enumerate(suggestion.translations)))
+ message = reviewed_message = self._makeTranslationMessage(
+ pofile, suggestion.submitter, potranslations,
+ suggestion.origin, diverged=True)
+ traits.setFlag(message, True)
+
+ pofile.markChanged()
+ if reviewed_message is not None:
+ reviewed_message.markReviewed(reviewer)
+ return message
+
def setCurrentTranslation(self, pofile, submitter, translations, origin,
share_with_other_side=False,
lock_timestamp=None):
=== modified file 'lib/lp/translations/model/translationmessage.py'
--- lib/lp/translations/model/translationmessage.py 2010-08-24 11:39:06 +0000
+++ lib/lp/translations/model/translationmessage.py 2010-09-02 11:57:45 +0000
@@ -175,6 +175,10 @@
"""See `ITranslationMessage`."""
raise NotImplementedError()
+ def approveAsDiverged(self, *args, **kwargs):
+ """See `ITranslationMessage`."""
+ raise NotImplementedError()
+
def getOnePOFile(self):
"""See `ITranslationMessage`."""
return None
@@ -348,6 +352,11 @@
share_with_other_side=share_with_other_side,
lock_timestamp=lock_timestamp)
+ def approveAsDiverged(self, pofile, reviewer, lock_timestamp=None):
+ """See `ITranslationMessage`."""
+ return self.potmsgset.approveAsDiverged(
+ pofile, self, reviewer, lock_timestamp=lock_timestamp)
+
def getOnePOFile(self):
"""See `ITranslationMessage`."""
from lp.translations.model.pofile import POFile
=== modified file 'lib/lp/translations/tests/test_translationmessage.py'
--- lib/lp/translations/tests/test_translationmessage.py 2010-08-24 11:39:06 +0000
+++ lib/lp/translations/tests/test_translationmessage.py 2010-09-02 11:57:45 +0000
@@ -269,6 +269,210 @@
pofile, self.factory.makePerson(), lock_timestamp=old)
+class TestApproveAsDiverged(TestCaseWithFactory):
+ """Tests for `TranslationMessage.approveAsDiverged`."""
+
+ layer = ZopelessDatabaseLayer
+
+ def _makeCounterpartPOFile(self, pofile):
+ """Make a `POFile` on the opposite translation side.
+
+ :param pofile: A `POFile` to match. Assumed to be on the
+ "upstream" translation side.
+ """
+ assert pofile.potemplate.productseries is not None, (
+ "This test needs a product template; got a package template.""")
+ other_template = self.factory.makePOTemplate(
+ distroseries=self.factory.makeDistroSeries(),
+ sourcepackagename=self.factory.makeSourcePackageName())
+
+ return self.factory.makePOFile(
+ pofile.language.code, potemplate=other_template)
+
+ def test_makeCounterpartPOFile(self):
+ # self.factory.makePOFile makes POFiles on the upstream side by
+ # default. self._makeCounterpartPOFile makes POFiles on the
+ # Ubuntu side.
+ pofile = self.factory.makePOFile('es')
+ other_pofile = self._makeCounterpartPOFile(pofile)
+
+ self.assertEqual(pofile.language, other_pofile.language)
+ self.assertNotEqual(
+ pofile.potemplate.translation_side,
+ other_pofile.potemplate.translation_side)
+
+ def test_no_change(self):
+ # Approving and diverging a message that's already active and
+ # diverged for this POFile does nothing. Even the reviewer
+ # stays unchanged.
+ translator = self.factory.makePerson()
+ original_reviewer = self.factory.makePerson()
+ later_reviewer = self.factory.makePerson()
+ pofile = self.factory.makePOFile('es_AR')
+ message = self.factory.makeDivergedTranslationMessage(
+ pofile=pofile, translator=translator, reviewer=original_reviewer)
+
+ resulting_message = message.approveAsDiverged(pofile, later_reviewer)
+
+ self.assertEqual(message, resulting_message)
+ self.assertEqual(translator, message.submitter)
+ self.assertEqual(original_reviewer, message.reviewer)
+ self.assertEqual(pofile.potemplate, message.potemplate)
+
+ def test_activates_and_diverges(self):
+ # Approving a simple suggestion activates and diverges it.
+ pofile = self.factory.makePOFile('es_BO')
+ suggestion = self.factory.makeSuggestion(pofile=pofile)
+
+ resulting_message = suggestion.approveAsDiverged(
+ pofile, self.factory.makePerson())
+
+ self.assertEqual(suggestion, resulting_message)
+ self.assertTrue(suggestion.is_current_upstream)
+ self.assertEqual(pofile.potemplate, suggestion.potemplate)
+
+ def test_activating_reviews(self):
+ # Activating a message marks it as reviewed.
+ pofile = self.factory.makePOFile('es_BO')
+ reviewer = self.factory.makePerson()
+ suggestion = self.factory.makeSuggestion(pofile=pofile)
+
+ resulting_message = suggestion.approveAsDiverged(pofile, reviewer)
+
+ self.assertEqual(reviewer, resulting_message.reviewer)
+
+ def test_diverge_current_shared_leaves_message_intact(self):
+ # Approving and diverging a message that's already the current
+ # shared message leaves it untouched.
+ original_reviewer = self.factory.makePerson()
+ later_reviewer = self.factory.makePerson()
+ pofile = self.factory.makePOFile('es_CL')
+ message = self.factory.makeCurrentTranslationMessage(
+ pofile=pofile, reviewer=original_reviewer)
+
+ resulting_message = message.approveAsDiverged(pofile, later_reviewer)
+
+ self.assertEqual(message, resulting_message)
+ self.assertEqual(original_reviewer, message.reviewer)
+ self.assertIs(None, message.potemplate)
+
+ def test_diverge_current_shared_message_unmasks_it(self):
+ pofile = self.factory.makePOFile('es_CO')
+ reviewer = self.factory.makePerson()
+ shared = self.factory.makeCurrentTranslationMessage(pofile=pofile)
+ diverged = self.factory.makeDivergedTranslationMessage(
+ pofile=pofile, potmsgset=shared.potmsgset)
+
+ self.assertTrue(shared.is_current_upstream)
+ self.assertTrue(diverged.is_current_upstream)
+ self.assertFalse(shared.is_diverged)
+ self.assertTrue(diverged.is_diverged)
+
+ shared.approveAsDiverged(pofile, reviewer)
+
+ self.assertTrue(shared.is_current_upstream)
+ self.assertFalse(diverged.is_current_upstream)
+ self.assertFalse(shared.is_diverged)
+
+ def test_does_not_affect_other_side(self):
+ # Approving a message that's current on the other side clones
+ # it, so that the other side remains unaffected by this local
+ # change.
+ reviewer = self.factory.makePerson()
+ pofile = self.factory.makePOFile('es_CR')
+ other_pofile = self._makeCounterpartPOFile(pofile)
+ suggestion = self.factory.makeCurrentTranslationMessage(
+ pofile=other_pofile)
+ self.assertEqual(
+ (False, True),
+ (suggestion.is_current_upstream, suggestion.is_current_ubuntu))
+
+ resulting_message = suggestion.approveAsDiverged(pofile, reviewer)
+
+ self.assertNotEqual(suggestion, resulting_message)
+ self.assertEqual(pofile.potemplate, resulting_message.potemplate)
+ self.assertIs(None, suggestion.potemplate)
+ self.assertTrue(resulting_message.is_current_upstream)
+ self.assertEqual(
+ (False, True),
+ (suggestion.is_current_upstream, suggestion.is_current_ubuntu))
+
+ def test_does_not_affect_diverged_elsewhere(self):
+ # Approving a message that's current and diverged to another
+ # template clones it, so that the other template remains
+ # unaffected by this local change.
+ reviewer = self.factory.makePerson()
+ pofile = self.factory.makePOFile('es_DO')
+ elsewhere = self.factory.makePOFile('es_DO')
+
+ suggestion = self.factory.makeDivergedTranslationMessage(
+ pofile=elsewhere)
+
+ resulting_message = suggestion.approveAsDiverged(pofile, reviewer)
+
+ self.assertNotEqual(suggestion, resulting_message)
+ self.assertEqual(pofile.potemplate, resulting_message.potemplate)
+ self.assertEqual(elsewhere.potemplate, suggestion.potemplate)
+ self.assertTrue(resulting_message.is_current_upstream)
+ self.assertTrue(suggestion.is_current_upstream)
+
+ def test_detects_conflict(self):
+ # Trying to approve and diverge a message based on outdated
+ # information raises TranslationConflict.
+ reviewer = self.factory.makePerson()
+ pofile = self.factory.makePOFile('es_EC')
+ suggestion = self.factory.makeSuggestion(pofile=pofile)
+ current = self.factory.makeDivergedTranslationMessage(
+ pofile=pofile, potmsgset=suggestion.potmsgset)
+ earlier = current.date_reviewed - timedelta(1)
+
+ self.assertRaises(
+ TranslationConflict,
+ suggestion.approveAsDiverged,
+ pofile, reviewer, lock_timestamp=earlier)
+
+ def test_passes_conflict_check_if_no_conflict(self):
+ # Trying to approve and diverge a message based on up-to-date
+ # works without raising a conflict.
+ reviewer = self.factory.makePerson()
+ pofile = self.factory.makePOFile('es_GT')
+ suggestion = self.factory.makeSuggestion(pofile=pofile)
+ current = self.factory.makeDivergedTranslationMessage(
+ pofile=pofile, potmsgset=suggestion.potmsgset)
+ later = current.date_reviewed + timedelta(1)
+
+ suggestion.approveAsDiverged(pofile, reviewer, lock_timestamp=later)
+
+ self.assertTrue(suggestion.is_current_upstream)
+
+ def test_passes_conflict_check_if_same_translations(self):
+ # Trying to approve and diverge a message based on outdated
+ # information works just fine if in the meantime the suggestion
+ # has become the diverged current translation.
+ reviewer = self.factory.makePerson()
+ pofile = self.factory.makePOFile('es_HN')
+ current = self.factory.makeDivergedTranslationMessage(pofile=pofile)
+ earlier = current.date_reviewed - timedelta(1)
+
+ current.approveAsDiverged(pofile, reviewer, lock_timestamp=earlier)
+
+ self.assertTrue(current.is_current_upstream)
+
+ def test_updates_pofile(self):
+ # Approving a message as a diverged translation marks the POFile
+ # as updated.
+ reviewer = self.factory.makePerson()
+ pofile = self.factory.makePOFile('es_MX')
+ suggestion = self.factory.makeSuggestion(pofile=pofile)
+ earlier = pofile.date_changed - timedelta(1)
+ pofile.markChanged(timestamp=earlier)
+
+ self.assertEqual(earlier, pofile.date_changed)
+ suggestion.approveAsDiverged(pofile, reviewer)
+ self.assertNotEqual(earlier, pofile.date_changed)
+ self.assertEqual(suggestion.date_reviewed, pofile.date_changed)
+
+
class TestTranslationMessageFindIdenticalMessage(TestCaseWithFactory):
"""Tests for `TranslationMessage.findIdenticalMessage`."""