launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #02556
[Merge] lp:~abentley/launchpad/sharingKey into lp:launchpad
Aaron Bentley has proposed merging lp:~abentley/launchpad/sharingKey into lp:launchpad with lp:~abentley/launchpad/refactor-migration as a prerequisite.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~abentley/launchpad/sharingKey/+merge/49091
= Summary =
Support mixed product and package POTemplates in TranslationMerger.
== Proposed fix ==
Rewrite POTemplateSet.compareSharingPrecedence as POTemplate.sharingKey.
== Pre-implementation notes ==
None.
== Implementation details ==
POTemplate.sharingKey is supplied as a sort key rather than a comparison
operation, which is more efficient, AIUI. I believe it is also easier to
understand.
The ordering is exactly the inverse of compareSharingPrecedence, for cases that
were already supported-- the "most relevant" templates sort last rather than
first. For mixed product and package templates, product translation foci have
precedence over package translation foci.
== Tests ==
bin/test -v test_potemplate
== Demo and Q/A ==
None
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/translations/tests/test_potemplate.py
lib/lp/translations/interfaces/potemplate.py
lib/lp/translations/tests/test_translationmerger.py
lib/lp/translations/translationmerger.py
lib/lp/translations/model/potemplate.py
scripts/rosetta/message-sharing-merge.py
./scripts/rosetta/message-sharing-merge.py
10: '_pythonpath' imported but unused
24: E303 too many blank lines (3)
--
https://code.launchpad.net/~abentley/launchpad/sharingKey/+merge/49091
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~abentley/launchpad/sharingKey into lp:launchpad.
=== modified file 'lib/lp/translations/interfaces/potemplate.py'
--- lib/lp/translations/interfaces/potemplate.py 2011-01-06 12:03:35 +0000
+++ lib/lp/translations/interfaces/potemplate.py 2011-02-09 16:57:01 +0000
@@ -385,6 +385,15 @@
"""Same as getPOTMsgSetByMsgIDText(), with only_current=True
"""
+ def sharingKey():
+ """A key for determining the sharing precedence of a template.
+
+ Active templates have precedence over inactive ones.
+ Development foci have precendence over non-development foci.
+ Product development foci have precedence over Package development
+ foci.
+ """
+
def getPOTMsgSetByID(id):
"""Return the POTMsgSet object related to this POTemplate with the id.
@@ -659,14 +668,6 @@
Return None if there is no such `IPOTemplate`.
"""
- def compareSharingPrecedence(left, right):
- """Sort comparison: order sharing templates by precedence.
-
- Sort using this function to order sharing templates from most
- representative to least representative, as per the message-sharing
- migration spec.
- """
-
def wipeSuggestivePOTemplatesCache():
"""Erase suggestive-templates cache.
=== modified file 'lib/lp/translations/model/potemplate.py'
--- lib/lp/translations/model/potemplate.py 2011-01-26 22:52:03 +0000
+++ lib/lp/translations/model/potemplate.py 2011-02-09 16:57:01 +0000
@@ -269,6 +269,22 @@
else:
return potmsgset
+ def sharingKey(self):
+ """See `IPOTemplate.`"""
+ if self.productseries is not None:
+ product_focus = (
+ self.productseries ==
+ self.productseries.product.primary_translatable)
+ else:
+ product_focus = False
+ if self.distroseries is not None:
+ distro_focus = (
+ self.distroseries ==
+ self.distroseries.distribution.translation_focus)
+ else:
+ distro_focus = False
+ return self.iscurrent, product_focus, distro_focus, self.id
+
@property
def displayname(self):
"""See `IPOTemplate`."""
@@ -1347,42 +1363,6 @@
len(preferred_matches))
return None
- @staticmethod
- def compareSharingPrecedence(left, right):
- """See `IPOTemplateSet`."""
- if left == right:
- return 0
-
- # Current templates always have precedence over non-current ones.
- if left.iscurrent != right.iscurrent:
- if left.iscurrent:
- return -1
- else:
- return 1
-
- if left.productseries:
- left_series = left.productseries
- right_series = right.productseries
- assert left_series.product == right_series.product
- focus = left_series.product.primary_translatable
- else:
- left_series = left.distroseries
- right_series = right.distroseries
- assert left_series.distribution == right_series.distribution
- focus = left_series.distribution.translation_focus
-
- # Translation focus has precedence. In case of a tie, newest
- # template wins.
- if left_series == focus:
- return -1
- elif right_series == focus:
- return 1
- elif left.id > right.id:
- return -1
- else:
- assert left.id < right.id, "Got unordered ids."
- return 1
-
def wipeSuggestivePOTemplatesCache(self):
"""See `IPOTemplateSet`."""
return IMasterStore(POTemplate).execute(
@@ -1576,7 +1556,7 @@
for equivalence_list in equivalents.itervalues():
# Sort potemplates from "most representative" to "least
# representative."
- equivalence_list.sort(cmp=POTemplateSet.compareSharingPrecedence)
+ equivalence_list.sort(key=POTemplate.sharingKey, reverse=True)
return equivalents
=== modified file 'lib/lp/translations/tests/test_potemplate.py'
--- lib/lp/translations/tests/test_potemplate.py 2010-12-02 16:13:51 +0000
+++ lib/lp/translations/tests/test_potemplate.py 2011-02-09 16:57:01 +0000
@@ -10,11 +10,17 @@
from lp.app.enums import ServiceUsage
from lp.registry.interfaces.distribution import IDistributionSet
from lp.services.worlddata.interfaces.language import ILanguageSet
-from lp.testing import TestCaseWithFactory
+from lp.testing import (
+ person_logged_in,
+ TestCaseWithFactory,
+ )
from lp.translations.interfaces.potemplate import IPOTemplateSet
+from lp.translations.interfaces.side import (
+ TranslationSide,
+ )
from lp.translations.model.potemplate import (
get_pofiles_for,
- POTemplateSet,
+ POTemplate,
)
@@ -414,7 +420,7 @@
"""Order templates by precedence."""
if templates is None:
templates = self.templates
- return sorted(templates, cmp=POTemplateSet.compareSharingPrecedence)
+ return sorted(templates, key=POTemplate.sharingKey, reverse=True)
def _getPrimaryTemplate(self, templates=None):
"""Get first template in order of precedence."""
@@ -481,6 +487,75 @@
self.test_ageBreaksTie()
+class TestTranslationFoci(TestCaseWithFactory):
+ """Test the precedence rules for tranlation foci."""
+
+ layer = DatabaseFunctionalLayer
+
+ def assertFirst(self, expected, templates):
+ templates = sorted(
+ templates, key=POTemplate.sharingKey)
+ self.assertEqual(expected, templates[0])
+
+ @staticmethod
+ def makeProductFocus(template):
+ with person_logged_in(template.productseries.product.owner):
+ template.productseries.product.translation_focus = (
+ template.productseries)
+
+ @staticmethod
+ def makePackageFocus(template):
+ distribution = template.distroseries.distribution
+ removeSecurityProxy(distribution).translation_focus = (
+ template.distroseries)
+
+ def makeProductPOTemplate(self):
+ """Create a product that is not the translation focus."""
+ # Manually creating a productseries to get one that is not the
+ # translation focus.
+ other_productseries = self.factory.makeProductSeries()
+ other_template = self.factory.makePOTemplate(
+ productseries=other_productseries)
+ product = other_productseries.product
+ productseries = self.factory.makeProductSeries(
+ product=product,
+ owner=product.owner)
+ with person_logged_in(product.owner):
+ product.translation_focus = other_productseries
+ other_productseries.product.translations_usage = (
+ ServiceUsage.LAUNCHPAD)
+ productseries.product.translations_usage = ServiceUsage.LAUNCHPAD
+ return self.factory.makePOTemplate(productseries=productseries)
+
+ def test_product_focus(self):
+ """Template priority respects product translation focus."""
+ product = self.makeProductPOTemplate()
+ package = self.factory.makePOTemplate(side=TranslationSide.UBUNTU)
+ # default ordering is database id.
+ self.assertFirst(package, [package, product])
+ self.makeProductFocus(product)
+ self.assertFirst(product, [package, product])
+
+ def test_package_focus(self):
+ """Template priority respects package translation focus."""
+ package = self.factory.makePOTemplate(side=TranslationSide.UBUNTU)
+ product = self.makeProductPOTemplate()
+ self.assertFirst(product, [package, product])
+ # default ordering is database id.
+ self.makePackageFocus(package)
+ self.assertFirst(package, [package, product])
+
+ def test_product_package_focus(self):
+ """Template priority respects product translation focus."""
+ product = self.makeProductPOTemplate()
+ package = self.factory.makePOTemplate(side=TranslationSide.UBUNTU)
+ # default ordering is database id.
+ self.assertFirst(package, [package, product])
+ self.makeProductFocus(product)
+ self.makePackageFocus(package)
+ self.assertFirst(product, [package, product])
+
+
class TestGetPOFilesFor(TestCaseWithFactory):
"""Test `get_pofiles_for`."""
=== modified file 'lib/lp/translations/translationmerger.py'
--- lib/lp/translations/translationmerger.py 2011-02-09 16:57:01 +0000
+++ lib/lp/translations/translationmerger.py 2011-02-09 16:57:01 +0000
@@ -9,6 +9,8 @@
]
+from operator import methodcaller
+
from storm.locals import Store
from zope.component import getUtility
from zope.security.proxy import removeSecurityProxy
@@ -205,8 +207,6 @@
"""
if self.template_set is None:
self.template_set = getUtility(IPOTemplateSet)
- self.compare_template_precedence = (
- self.template_set.compareSharingPrecedence)
def main(self):
actions = (
@@ -347,16 +347,14 @@
:param potemplates: The templates to merge across.
"""
- self.template_set = getUtility(IPOTemplateSet)
- self.compare_template_precedence = (
- self.template_set.compareSharingPrecedence)
self.potemplates = potemplates
self.tm = tm
def _removeDuplicateMessages(self):
"""Get rid of duplicate `TranslationMessages` where needed."""
representatives = {}
- order_check = OrderingCheck(cmp=self.compare_template_precedence)
+ order_check = OrderingCheck(
+ key=methodcaller('sharingKey'), reverse=True)
for template in self.potemplates:
order_check.check(template)
@@ -397,7 +395,8 @@
# through the templates, starting at the most representative and
# moving towards the least representative. For any unique potmsgset
# key we find, the first POTMsgSet is the representative one.
- order_check = OrderingCheck(cmp=self.compare_template_precedence)
+ order_check = OrderingCheck(
+ key=methodcaller('sharingKey'), reverse=True)
for template in self.potemplates:
order_check.check(template)
@@ -496,7 +495,8 @@
def mergeTranslationMessages(self):
"""Share `TranslationMessage`s between templates where possible."""
- order_check = OrderingCheck(cmp=self.compare_template_precedence)
+ order_check = OrderingCheck(
+ key=methodcaller('sharingKey'), reverse=True)
for template_number, template in enumerate(self.potemplates):
log.info("Merging template %d/%d." % (
template_number + 1, len(self.potemplates)))
@@ -672,7 +672,8 @@
# least one template by making it diverged.
target_ttis = source_potmsgset.getAllTranslationTemplateItems()
target_templates = [tti.potemplate for tti in target_ttis]
- target_templates.sort(self.compare_template_precedence)
+ target_templates.sort(
+ key=methodcaller('sharingKey'), reverse=True)
for template in target_templates:
if self._divergeTo(message, target_potmsgset, template):
return True