← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~henninge/launchpad/devel-741571-filter-templates-in-upload into lp:launchpad

 

Henning Eggers has proposed merging lp:~henninge/launchpad/devel-741571-filter-templates-in-upload into lp:launchpad with lp:~henninge/launchpad/devel-605924-hastranslationtemplates as a prerequisite.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #741571 in Launchpad itself: "Translation templates should always be uploaded from soyuz builds."
  https://bugs.launchpad.net/launchpad/+bug/741571

For more details, see:
https://code.launchpad.net/~henninge/launchpad/devel-741571-filter-templates-in-upload/+merge/54688

= Summary =

Apart from fixing bug 741571 as described in the bug, this branch also
addresses a left-over issue from the previous branch. It implements
has_sharing_translation_templates which encapsualates a pattern that
appeared in many places. This makes the code shorter and much better to
read.

I also removed some lint that was already there.

== Implementation details ==

I find this a very straight forward branch and enjoyed coding it. I
hope you can follow along just as easily.

== Tests ==

Lot of stuff has been touched so I'd advise a full test run.

== Demo and Q/A ==

I am not sure how to QA soyuz stuff but you should see only templates
appear in the import queue of a sourcepackage that has upstream
templates.

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/translations/tests/test_potemplate.py
  lib/lp/registry/tests/test_productseries.py
  lib/lp/translations/templates/distroseries-translations.pt
  lib/lp/translations/tests/test_hastranslationtemplates.py
  lib/lp/translations/interfaces/potemplate.py
  lib/lp/registry/model/productseries.py
  lib/lp/translations/model/translationimportqueue.py
  lib/lp/soyuz/tests/test_sourcepackagerelease.py
  lib/lp/translations/browser/pofile.py
  lib/lp/translations/model/pofile.py
  lib/lp/soyuz/model/sourcepackagerelease.py
  lib/lp/translations/templates/productseries-translations.pt
  lib/lp/translations/doc/translationimportqueue.txt
  lib/lp/registry/interfaces/productseries.py
  lib/lp/registry/model/sourcepackage.py
  lib/lp/translations/browser/productseries.py
  lib/lp/registry/model/product.py
  lib/lp/translations/model/hastranslationtemplates.py
  lib/lp/registry/model/distroseries.py
  lib/lp/translations/utilities/translation_import.py
  lib/lp/translations/interfaces/hastranslationtemplates.py
  lib/lp/translations/model/potemplate.py
  lib/lp/registry/model/distribution.py
  lib/lp/translations/browser/sourcepackage.py
  lib/lp/translations/browser/potemplate.py
  lib/lp/translations/tests/test_translationtemplatescollection.py
  lib/lp/translations/interfaces/translationimportqueue.py
  lib/lp/translations/doc/distroseries-language.txt

./lib/lp/translations/browser/pofile.py
     788: E301 expected 1 blank line, found 2
     904: E301 expected 1 blank line, found 2
./lib/lp/soyuz/model/sourcepackagerelease.py
     201: redefinition of function 'copyright' from line 192
./lib/lp/registry/model/distroseries.py
     392: E301 expected 1 blank line, found 2
-- 
https://code.launchpad.net/~henninge/launchpad/devel-741571-filter-templates-in-upload/+merge/54688
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~henninge/launchpad/devel-741571-filter-templates-in-upload into lp:launchpad.
=== modified file 'lib/lp/registry/model/distribution.py'
--- lib/lp/registry/model/distribution.py	2011-03-24 12:04:21 +0000
+++ lib/lp/registry/model/distribution.py	2011-03-24 12:04:23 +0000
@@ -1822,11 +1822,7 @@
         assert sourcepackage is not None, (
             "Translations sharing policy requires a SourcePackage.")
 
-        productseries = sourcepackage.productseries
-        has_upstream_translations = (
-            productseries is not None and
-            productseries.has_current_translation_templates)
-        if not has_upstream_translations:
+        if not sourcepackage.has_sharing_translation_templates:
             # There is no known upstream template or series.  Take the
             # uploader's word for whether these are upstream translations
             # (in which case they're shared) or not.
@@ -1841,6 +1837,7 @@
             # translations for upstream.
             return purportedly_upstream
 
+        productseries = sourcepackage.productseries
         return productseries.product.invitesTranslationEdits(person, language)
 
 

=== modified file 'lib/lp/registry/model/distroseries.py'
--- lib/lp/registry/model/distroseries.py	2011-03-24 12:04:21 +0000
+++ lib/lp/registry/model/distroseries.py	2011-03-24 12:04:23 +0000
@@ -463,17 +463,18 @@
         translatable messages, and the source package release's component.
         """
         find_spec = (
-            SQL("DISTINCT ON (score, sourcepackagename.name) TRUE as _ignored"),
+            SQL("DISTINCT ON (score, sourcepackagename.name) "
+                "TRUE as _ignored"),
             SourcePackageName,
             SQL("""
                 coalesce(total_bug_heat, 0) + coalesce(po_messages, 0) +
                 CASE WHEN component = 1 THEN 1000 ELSE 0 END AS score"""),
             SQL("coalesce(bug_count, 0) AS bug_count"),
             SQL("coalesce(total_messages, 0) AS total_messages"))
-        # This does not use _current_sourcepackage_joins_and_conditions because
-        # the two queries are working on different data sets - +needs-packaging
-        # was timing out and +packaging wasn't, and destabilising things
-        # unnecessarily is not good.
+        # This does not use _current_sourcepackage_joins_and_conditions
+        # because the two queries are working on different data sets -
+        # +needs-packaging was timing out and +packaging wasn't, and
+        # destabilising things unnecessarily is not good.
         origin = SQL("""
             SourcePackageName, (SELECT
         spr.sourcepackagename,
@@ -515,7 +516,7 @@
             distroseries=self,
             active_status=active_publishing_status,
             primary=ArchivePurpose.PRIMARY))
-        condition = SQL("""sourcepackagename.id = spn_info.sourcepackagename""")
+        condition = SQL("sourcepackagename.id = spn_info.sourcepackagename")
         results = IStore(self).using(origin).find(find_spec, condition)
         results = results.order_by('score DESC', SourcePackageName.name)
 
@@ -571,7 +572,7 @@
 
     @property
     def _current_sourcepackage_po_weight(self):
-        """See getPrioritized*.""" 
+        """See getPrioritized*."""
         # Bugs and PO messages are heuristically scored. These queries
         # can easily timeout so filters and weights are used to create
         # an acceptable prioritization of packages that is fast to excecute.
@@ -580,7 +581,7 @@
     @property
     def _current_sourcepackage_joins_and_conditions(self):
         """The SQL joins and conditions to prioritize source packages.
-        
+
         Used for getPrioritizedPackagings only.
         """
         # Bugs and PO messages are heuristically scored. These queries
@@ -1907,6 +1908,11 @@
         """See `IHasTranslationTemplates`."""
         return TranslationTemplatesCollection().restrictDistroSeries(self)
 
+    def getSharingPartner(self):
+        """See `IHasTranslationTemplates`."""
+        # No sharing partner is defined for DistroSeries.
+        return None
+
     def getSuite(self, pocket):
         """See `IDistroSeries`."""
         if pocket == PackagePublishingPocket.RELEASE:

=== modified file 'lib/lp/registry/model/product.py'
--- lib/lp/registry/model/product.py	2011-03-24 12:04:21 +0000
+++ lib/lp/registry/model/product.py	2011-03-24 12:04:23 +0000
@@ -1588,6 +1588,7 @@
             conditions.append(
                 SQL("Product.fti @@ ftq(%s) " % sqlvalues(text)))
         result = IStore(Product).find(Product, *conditions)
+
         def eager_load(rows):
             product_ids = set(obj.id for obj in rows)
             if not product_ids:
@@ -1601,7 +1602,7 @@
                 if not safe_hasattr(cache, '_cached_licenses'):
                     cache._cached_licenses = []
             for subscription in IStore(CommercialSubscription).find(
-                CommercialSubscription, 
+                CommercialSubscription,
                 CommercialSubscription.productID.is_in(product_ids)):
                 cache = caches[subscription.productID]
                 cache.commercial_subscription = subscription

=== modified file 'lib/lp/registry/model/productseries.py'
--- lib/lp/registry/model/productseries.py	2011-03-24 12:04:21 +0000
+++ lib/lp/registry/model/productseries.py	2011-03-24 12:04:23 +0000
@@ -537,6 +537,10 @@
         """See `IHasTranslationTemplates`."""
         return TranslationTemplatesCollection().restrictProductSeries(self)
 
+    def getSharingPartner(self):
+        """See `IHasTranslationTemplates`."""
+        return self.getUbuntuTranslationFocusPackage()
+
     @property
     def potemplate_count(self):
         """See `IProductSeries`."""

=== modified file 'lib/lp/registry/model/sourcepackage.py'
--- lib/lp/registry/model/sourcepackage.py	2011-03-04 21:15:00 +0000
+++ lib/lp/registry/model/sourcepackage.py	2011-03-24 12:04:23 +0000
@@ -676,6 +676,10 @@
         collection = collection.restrictDistroSeries(self.distroseries)
         return collection.restrictSourcePackageName(self.sourcepackagename)
 
+    def getSharingPartner(self):
+        """See `IHasTranslationTemplates`."""
+        return self.productseries
+
     def getBranch(self, pocket):
         """See `ISourcePackage`."""
         store = Store.of(self.sourcepackagename)

=== modified file 'lib/lp/soyuz/model/sourcepackagerelease.py'
--- lib/lp/soyuz/model/sourcepackagerelease.py	2011-03-24 12:04:21 +0000
+++ lib/lp/soyuz/model/sourcepackagerelease.py	2011-03-24 12:04:23 +0000
@@ -623,20 +623,13 @@
 
         queue = getUtility(ITranslationImportQueue)
 
-        # We do not want to override upstream translations, if
-        # translation sharing is enabled.
-        # Avoid circular imports.
-        productseries = self.sourcepackage.productseries
-        has_upstream_templates = (
-            productseries is not None and
-            productseries.has_translation_templates
-            )
-        if not has_upstream_templates:
-            queue.addOrUpdateEntriesFromTarball(
-                tarball, by_maintainer, importer,
-                sourcepackagename=self.sourcepackagename,
-                distroseries=self.upload_distroseries,
-                filename_filter=_filter_ubuntu_translation_file)
+        only_templates=self.sourcepackage.has_sharing_translation_templates
+        queue.addOrUpdateEntriesFromTarball(
+            tarball, by_maintainer, importer,
+            sourcepackagename=self.sourcepackagename,
+            distroseries=self.upload_distroseries,
+            filename_filter=_filter_ubuntu_translation_file,
+            only_templates=only_templates)
 
     def getDiffTo(self, to_sourcepackagerelease):
         """See ISourcePackageRelease."""

=== modified file 'lib/lp/soyuz/tests/test_sourcepackagerelease.py'
--- lib/lp/soyuz/tests/test_sourcepackagerelease.py	2011-03-24 12:04:21 +0000
+++ lib/lp/soyuz/tests/test_sourcepackagerelease.py	2011-03-24 12:04:23 +0000
@@ -19,13 +19,6 @@
     )
 
 
-def has_upstream_template(sourcepackage):
-    productseries = sourcepackage.productseries
-    if productseries is None:
-        return False
-    return productseries.has_translation_templates
-
-
 class TestSourcePackageRelease(TestCaseWithFactory):
 
     layer = LaunchpadFunctionalLayer
@@ -76,6 +69,7 @@
         """Create an LibraryFileAlias containing dummy translation data."""
         test_tar_content = {
             'source/po/foo.pot': 'Foo template',
+            'source/po/eo.po': 'Foo translation',
             }
         tarfile_content = LaunchpadWriteTarFile.files_to_string(
             test_tar_content)
@@ -86,18 +80,19 @@
         # SourcePackageRelease.attachTranslationFiles() creates a job
         # in the translation import queue.
         spr = self.factory.makeSourcePackageRelease()
-        self.assertFalse(has_upstream_template(spr.sourcepackage))
+        self.assertFalse(spr.sourcepackage.has_sharing_translation_templates)
         lfa = self.makeTranslationsLFA()
         transaction.commit()
         spr.attachTranslationFiles(lfa, True, spr.maintainer)
         translation_import_queue = getUtility(ITranslationImportQueue)
         entries_in_queue = translation_import_queue.getAllEntries(
                 target=spr.sourcepackage).count()
-        self.assertEqual(1, entries_in_queue)
+        self.assertEqual(2, entries_in_queue)
 
     def test_attachTranslationFiles__translation_sharing(self):
         # If translation sharing is enabled,
-        # SourcePackageRelease.attachTranslationFiles() does nothing.
+        # SourcePackageRelease.attachTranslationFiles() only attaches
+        # templates.
         spr = self.factory.makeSourcePackageRelease()
         sourcepackage = spr.sourcepackage
         productseries = self.factory.makeProductSeries()
@@ -105,11 +100,12 @@
         with person_logged_in(sourcepackage.distroseries.owner):
             sourcepackage.setPackaging(
                 productseries, sourcepackage.distroseries.owner)
-        self.assertTrue(has_upstream_template(sourcepackage))
+        self.assertTrue(sourcepackage.has_sharing_translation_templates)
         lfa = self.makeTranslationsLFA()
         transaction.commit()
         spr.attachTranslationFiles(lfa, True, spr.maintainer)
         translation_import_queue = getUtility(ITranslationImportQueue)
-        entries_in_queue = translation_import_queue.getAllEntries(
-                target=sourcepackage).count()
-        self.assertEqual(0, entries_in_queue)
+        entries = translation_import_queue.getAllEntries(
+                target=sourcepackage)
+        self.assertEqual(1, entries.count())
+        self.assertTrue(entries[0].path.endswith('.pot'))

=== modified file 'lib/lp/translations/browser/productseries.py'
--- lib/lp/translations/browser/productseries.py	2011-03-24 12:04:21 +0000
+++ lib/lp/translations/browser/productseries.py	2011-03-24 12:04:23 +0000
@@ -456,10 +456,7 @@
         return check_permission("launchpad.TranslationsAdmin", self.context)
 
     def is_sharing(self):
-        sourcepackage = self.context.getUbuntuTranslationFocusPackage()
-        if sourcepackage is None:
-            return False
-        return sourcepackage.has_current_translation_templates
+        return self.context.has_sharing_translation_templates
 
     @property
     def sharing_sourcepackage(self):

=== modified file 'lib/lp/translations/browser/sourcepackage.py'
--- lib/lp/translations/browser/sourcepackage.py	2011-03-24 12:04:21 +0000
+++ lib/lp/translations/browser/sourcepackage.py	2011-03-24 12:04:23 +0000
@@ -55,10 +55,7 @@
         return "Translations for %s" % self.context.displayname
 
     def is_sharing(self):
-        productseries = self.context.productseries
-        if productseries is None:
-            return False
-        return productseries.has_current_translation_templates
+        return self.context.has_sharing_translation_templates
 
     @property
     def sharing_productseries(self):
@@ -119,10 +116,7 @@
     page_title = "Sharing details"
 
     def is_sharing(self):
-        productseries = self.context.productseries
-        if productseries is None:
-            return False
-        return productseries.has_current_translation_templates
+        return self.context.has_sharing_translation_templates
 
     def initialize(self):
         if not getFeatureFlag('translations.sharing_information.enabled'):

=== modified file 'lib/lp/translations/doc/translationimportqueue.txt'
--- lib/lp/translations/doc/translationimportqueue.txt	2010-12-23 10:21:21 +0000
+++ lib/lp/translations/doc/translationimportqueue.txt	2011-03-24 12:04:23 +0000
@@ -1151,7 +1151,32 @@
     warty evolution | None               | po/sr.po
 
 Attach the sample tarball to the 'evolution-2.2-test' template in evolution
-product. There will be three new entries from the tarball.
+product. We can ask to only upload the template from the tarball and ignore
+the other files.
+
+    >>> translationimportqueue.addOrUpdateEntriesFromTarball(
+    ...     tarfile_content, by_maintainer, rosetta_experts,
+    ...     productseries=evolution_productseries,
+    ...     potemplate=evolution_22_test_template,
+    ...     only_templates=True)
+    (1, [])
+
+And this new entry in the queue appears in the list.
+
+    >>> print_queue_entries(queue)
+    hoary evolution | evolution          | po/sr.po
+    firefox         | firefox            | foo/bar.pot
+    evolution       | evolution-2.2-test | po/evolution-2.2-test.pot
+    evolution       | evolution-2.2-test | po/pt_BR.po
+    firefox         | None               | foo/bar.po
+    evolution       | None               | po/sr.po
+    hoary evolution | None               | po/evolution-2.2.pot
+    warty evolution | None               | po/sr.po
+    evolution       | evolution-2.2-test | foo.pot
+
+
+But we really want all files from the tarball, so we upload them all.
+There will be three new entries from the tarball.
 
     >>> translationimportqueue.addOrUpdateEntriesFromTarball(
     ...     tarfile_content, by_maintainer, rosetta_experts,
@@ -1170,8 +1195,8 @@
     evolution       | None               | po/sr.po
     hoary evolution | None               | po/evolution-2.2.pot
     warty evolution | None               | po/sr.po
+    evolution       | evolution-2.2-test | foo.pot
     evolution       | evolution-2.2-test | es.po
-    evolution       | evolution-2.2-test | foo.pot
     evolution       | evolution-2.2-test | fr.po
 
 It is possible to update the content of an entry in the queue.
@@ -1244,8 +1269,8 @@
     >>> print_queue_entries(queue)
     hoary ...
     ...
+    evolution       | evolution-2.2-test | foo.pot
     evolution       | evolution-2.2-test | es.po
-    evolution       | evolution-2.2-test | foo.pot
     evolution       | evolution-2.2-test | fr.po
     evolution       | evolution-2.2      | es.po
     evolution       | evolution-2.2      | foo.pot

=== modified file 'lib/lp/translations/interfaces/hastranslationtemplates.py'
--- lib/lp/translations/interfaces/hastranslationtemplates.py	2011-03-24 12:04:21 +0000
+++ lib/lp/translations/interfaces/hastranslationtemplates.py	2011-03-24 12:04:23 +0000
@@ -36,6 +36,10 @@
         title=_("Does this object have obsolete translation templates?"),
         readonly=True)
 
+    has_sharing_translation_templates = Bool(
+        title=_("Does this object have sharing translation templates?"),
+        readonly=True)
+
     has_translation_files = Bool(
         title=_("Does this object have translation files?"),
         readonly=True)
@@ -47,6 +51,13 @@
         translation target that implements this interface.
         """
 
+    def getSharingPartner():
+        """Return the object on the other side of the packaging link.
+
+        Return the object that is sharing translations with this one on the
+        other side of a packaging link. It must also implement this interface.
+        """
+
     def getCurrentTemplatesCollection():
         """Return `TranslationTemplatesCollection` of current templates.
 
@@ -54,8 +65,6 @@
         `IPOTemplate`.iscurrent and the `official_rosetta` flag for its
         containing `Product` or `Distribution` are set to True.
         """
-        # XXX JeroenVermeulen 2010-07-16 bug=605924: Move the
-        # official_rosetta distinction into browser code.
 
     def getCurrentTranslationTemplates(just_ids=False):
         """Return an iterator over all active translation templates.
@@ -68,8 +77,6 @@
         `IPOTemplate`.iscurrent and the `official_rosetta` flag for its
         containing `Product` or `Distribution` are set to True.
         """
-        # XXX JeroenVermeulen 2010-07-16 bug=605924: Move the
-        # official_rosetta distinction into browser code.
 
     def getCurrentTranslationFiles(just_ids=False):
         """Return an iterator over all active translation files.

=== modified file 'lib/lp/translations/interfaces/translationimportqueue.py'
--- lib/lp/translations/interfaces/translationimportqueue.py	2011-01-21 20:37:59 +0000
+++ lib/lp/translations/interfaces/translationimportqueue.py	2011-03-24 12:04:23 +0000
@@ -335,7 +335,8 @@
 
     def addOrUpdateEntriesFromTarball(content, by_maintainer, importer,
         sourcepackagename=None, distroseries=None, productseries=None,
-        potemplate=None, filename_filter=None, approver_factory=None):
+        potemplate=None, filename_filter=None, approver_factory=None,
+        only_templates=False):
         """Add all .po or .pot files from the tarball at :content:.
 
         :arg content: is a tarball stream.
@@ -350,6 +351,8 @@
         :arg approver_factory: is a factory that can be called to create an
             approver.  The method invokes the approver on any queue entries
             that it creates. If this is None, no approval is performed.
+        :arg only_templates: Flag to indicate that only translation templates
+            in the tarball should be used.
         :return: A tuple of the number of successfully processed files and a
             list of those filenames that could not be processed correctly.
 

=== modified file 'lib/lp/translations/model/hastranslationtemplates.py'
--- lib/lp/translations/model/hastranslationtemplates.py	2011-03-24 12:04:21 +0000
+++ lib/lp/translations/model/hastranslationtemplates.py	2011-03-24 12:04:23 +0000
@@ -34,6 +34,14 @@
         raise NotImplementedError(
             "Child class must provide getTemplatesCollection.")
 
+    def getSharingPartner(self):
+        """See `IHasTranslationTemplates`.
+
+        To be provided by derived classes.
+        """
+        raise NotImplementedError(
+            "Child class must provide getSharingPartner.")
+
     def _orderTemplates(self, result):
         """Apply the conventional ordering to a result set of templates."""
         return result.order_by(Desc(POTemplate.priority), POTemplate.name)
@@ -72,6 +80,14 @@
             self.getCurrentTranslationTemplates(
                 just_ids=True, current_value=False).any())
 
+    @property
+    def has_sharing_translation_templates(self):
+        """See `IHasTranslationTemplates`."""
+        other_side_obj = self.getSharingPartner()
+        if other_side_obj is None:
+            return False
+        return other_side_obj.has_current_translation_templates
+
     def getCurrentTranslationFiles(self, just_ids=False):
         """See `IHasTranslationTemplates`."""
         if just_ids:

=== modified file 'lib/lp/translations/model/translationimportqueue.py'
--- lib/lp/translations/model/translationimportqueue.py	2011-01-11 16:15:52 +0000
+++ lib/lp/translations/model/translationimportqueue.py	2011-03-24 12:04:23 +0000
@@ -1009,7 +1009,7 @@
             path = path_filter(path)
         return path
 
-    def _isTranslationFile(self, path):
+    def _isTranslationFile(self, path, only_templates):
         """Is this a translation file that should be uploaded?"""
         if path is None or path == '':
             return False
@@ -1024,11 +1024,15 @@
             # Doesn't look like a supported translation file type.
             return False
 
+        if only_templates and not translation_importer.isTemplateName(path):
+            return False
+
         return True
 
     def addOrUpdateEntriesFromTarball(self, content, by_maintainer, importer,
         sourcepackagename=None, distroseries=None, productseries=None,
-        potemplate=None, filename_filter=None, approver_factory=None):
+        potemplate=None, filename_filter=None, approver_factory=None,
+        only_templates=False):
         """See ITranslationImportQueue."""
         num_files = 0
         conflict_files = []
@@ -1045,7 +1049,7 @@
         upload_files = {}
         for name in self._iterTarballFiles(tarball):
             path = self._makePath(name, filename_filter)
-            if self._isTranslationFile(path):
+            if self._isTranslationFile(path, only_templates):
                 upload_files[name] = path
         tarball.close()
 

=== modified file 'lib/lp/translations/tests/test_hastranslationtemplates.py'
--- lib/lp/translations/tests/test_hastranslationtemplates.py	2011-03-24 12:04:21 +0000
+++ lib/lp/translations/tests/test_hastranslationtemplates.py	2011-03-24 12:04:23 +0000
@@ -6,7 +6,6 @@
 from zope.interface.verify import verifyObject
 
 from canonical.testing.layers import ZopelessDatabaseLayer
-from lp.app.enums import ServiceUsage
 from lp.testing import TestCaseWithFactory
 from lp.translations.interfaces.hastranslationtemplates import (
     IHasTranslationTemplates,
@@ -36,6 +35,16 @@
         raise NotImplementedError(
             'This must be provided by an executable test.')
 
+    def createPackaging(self):
+        """Creates a packaging link for the container."""
+        raise NotImplementedError(
+            'This must be provided by an executable test.')
+
+    def createSharingTranslationTemplate(self):
+        """Attaches a template to the sharing partner of the container."""
+        raise NotImplementedError(
+            'This must be provided by an executable test.')
+
     def test_implements_interface(self):
         # Make sure container implements IHasTranslationTemplates.
         verifyObject(IHasTranslationTemplates, self.container)
@@ -187,6 +196,21 @@
         self.createTranslationTemplate()
         self.assertTrue(self.container.has_obsolete_translation_templates)
 
+    def test_has_sharing_translation_templates__no_link(self):
+        # Without a packaging link, no sharing templates are found.
+        self.assertFalse(self.container.has_sharing_translation_templates)
+
+    def test_has_sharing_translation_templates__no_templates(self):
+        # Without templates on the other side, no sharing templates are found.
+        self.createPackaging()
+        self.assertFalse(self.container.has_sharing_translation_templates)
+
+    def test_has_sharing_translation_templates__templates(self):
+        # Without templates on the other side, no sharing templates are found.
+        self.createPackaging()
+        self.createSharingTranslationTemplate()
+        self.assertTrue(self.container.has_sharing_translation_templates)
+
     def test_has_translation_files(self):
         # has_translations_files should only return true if the object has
         # pofiles.
@@ -264,11 +288,18 @@
             potemplate=potemplate)
         return pofile
 
+    def createPackaging(self):
+        self.packaging = self.factory.makePackagingLink(
+            productseries=self.container, in_ubuntu=True)
+        return self.packaging
+
+    def createSharingTranslationTemplate(self):
+        return self.factory.makePOTemplate(
+            sourcepackage=self.packaging.sourcepackage)
+
     def setUp(self):
         super(TestProductSeriesHasTranslationTemplates, self).setUp()
         self.container = self.factory.makeProductSeries()
-        self.product_or_distro = self.container.product
-        self.product_or_distro.translations_usage = ServiceUsage.LAUNCHPAD
 
 
 class TestSourcePackageHasTranslationTemplates(
@@ -289,11 +320,18 @@
             potemplate=potemplate)
         return pofile
 
+    def createPackaging(self):
+        self.packaging = self.factory.makePackagingLink(
+            sourcepackage=self.container)
+        return self.packaging
+
+    def createSharingTranslationTemplate(self):
+        return self.factory.makePOTemplate(
+            productseries=self.packaging.productseries)
+
     def setUp(self):
         super(TestSourcePackageHasTranslationTemplates, self).setUp()
         self.container = self.factory.makeSourcePackage()
-        self.product_or_distro = self.container.distroseries.distribution
-        self.product_or_distro.translations_usage = ServiceUsage.LAUNCHPAD
 
 
 class TestDistroSeriesHasTranslationTemplates(
@@ -316,8 +354,23 @@
             potemplate=potemplate)
         return pofile
 
+    def createPackaging(self):
+        sourcepackage = self.factory.makeSourcePackage(
+            distroseries=self.container)
+        self.packaging = self.factory.makePackagingLink(
+            sourcepackage=sourcepackage)
+        return self.packaging
+
+    def createSharingTranslationTemplate(self):
+        return self.factory.makePOTemplate(
+            productseries=self.packaging.productseries)
+
     def setUp(self):
         super(TestDistroSeriesHasTranslationTemplates, self).setUp()
         self.container = self.factory.makeDistroRelease()
-        self.product_or_distro = self.container.distribution
-        self.product_or_distro.translations_usage = ServiceUsage.LAUNCHPAD
+
+    def test_has_sharing_translation_templates__templates(self):
+        # This attribute is always False for DistroSeries
+        self.createPackaging()
+        self.createSharingTranslationTemplate()
+        self.assertFalse(self.container.has_sharing_translation_templates)

=== modified file 'lib/lp/translations/utilities/translation_import.py'
--- lib/lp/translations/utilities/translation_import.py	2011-03-24 12:04:21 +0000
+++ lib/lp/translations/utilities/translation_import.py	2011-03-24 12:04:23 +0000
@@ -444,10 +444,7 @@
         sourcepackage = getUtility(ISourcePackageFactory).new(
             self.translation_import_queue_entry.sourcepackagename,
             self.translation_import_queue_entry.distroseries)
-        productseries = sourcepackage.productseries
-        if productseries is None:
-            return True
-        return not productseries.has_current_translation_templates
+        return not sourcepackage.has_sharing_translation_templates
 
     @cachedproperty
     def translations_are_msgids(self):