← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~jcsackett/launchpad/series-need-usage-attributes-643902 into lp:launchpad/devel

 

j.c.sackett has proposed merging lp:~jcsackett/launchpad/series-need-usage-attributes-643902 into lp:launchpad/devel.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  #643902 Series need usage attributes
  https://bugs.launchpad.net/bugs/643902


Summary
=======

Adds the usage attributes to productseries and distroseries, largely as a mirror of the attributes on the series related pillar.

Proposed Fix
============

Add the usage attributes as properties to the series.

Pre-implementation notes
========================

Spoke with Curtis Hovey (sinzui) and jtv about what was needed in usage attributes on the series, especially for translations.

Implementation details
======================

As in proposed fix.

Translations use the current status of templates to determine usage; however, that is overridden by requirements in the translations application (see bug 605924). That requirement will be resolve by lp:~jcsackett/launchpad/unknown-translations-service-643545, which is dependent on this branch.

Tests
=====

bin/test -t test_service_usage

Demo and Q/A
============

Currently usage of the various series should see no change from this branch.

Lint
====
Output:

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/registry/adapters.py
  lib/lp/registry/configure.zcml
  lib/lp/registry/interfaces/distroseries.py
  lib/lp/registry/interfaces/productseries.py
  lib/lp/registry/model/distroseries.py
  lib/lp/registry/model/productseries.py
  lib/lp/registry/tests/test_service_usage.py

./lib/lp/registry/interfaces/distroseries.py
     417: E301 expected 1 blank line, found 2
     458: E301 expected 1 blank line, found 0
./lib/lp/registry/model/distroseries.py
     364: E301 expected 1 blank line, found 2
     708: E301 expected 1 blank line, found 2

Both errors related to lint's issue with comments and blank lines
-- 
https://code.launchpad.net/~jcsackett/launchpad/series-need-usage-attributes-643902/+merge/36145
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jcsackett/launchpad/series-need-usage-attributes-643902 into lp:launchpad/devel.
=== modified file 'lib/lp/registry/adapters.py'
--- lib/lp/registry/adapters.py	2010-09-13 12:09:30 +0000
+++ lib/lp/registry/adapters.py	2010-09-21 13:57:44 +0000
@@ -13,19 +13,11 @@
     ]
 
 
-from zope.component import (
-    adapter,
-    getUtility,
-    )
+from zope.component import getUtility
 from zope.component.interfaces import ComponentLookupError
-from zope.interface import (
-    implementer,
-    implements,
-    )
+from zope.interface import implements
 
 from canonical.launchpad.webapp.interfaces import ILaunchpadPrincipal
-from lp.app.interfaces.launchpad import IServiceUsage
-from lp.registry.interfaces.distroseries import IDistroSeries
 from lp.registry.interfaces.poll import (
     IPollSet,
     IPollSubset,
@@ -34,15 +26,11 @@
     )
 
 
-@implementer(IServiceUsage)
-@adapter(IDistroSeries)
-def distroseries_to_serviceusage(distroseries):
-    """Adapts `IDistroSeries` object to `IServiceUsage`."""
-    return distroseries.distribution
-
-
-def distroseries_to_launchpadusage(distroseries):
-    """Adapts `IDistroSeries` object to `ILaunchpadUsage`."""
+def distroseries_to_distribution(distroseries):
+    """Adapts `IDistroSeries` object to `IDistribution`.
+
+    This is useful for adapting to `IServiceUsage`
+    or `ILaunchpadUsage`."""
     return distroseries.distribution
 
 

=== modified file 'lib/lp/registry/configure.zcml'
--- lib/lp/registry/configure.zcml	2010-09-18 00:17:07 +0000
+++ lib/lp/registry/configure.zcml	2010-09-21 13:57:44 +0000
@@ -142,6 +142,9 @@
             interface="canonical.launchpad.interfaces.ICanPublishPackages"/>
         <require
             permission="launchpad.Edit"
+            set_schema="lp.app.interfaces.launchpad.IServiceUsage"/>
+        <require
+            permission="launchpad.Edit"
             interface="lp.registry.interfaces.distroseries.IDistroSeriesEditRestricted"/>
         <require
             permission="launchpad.TranslationsAdmin"
@@ -194,11 +197,9 @@
     <adapter
         provides="lp.app.interfaces.launchpad.ILaunchpadUsage"
         for="lp.registry.interfaces.distroseries.IDistroSeries"
-        factory="lp.registry.adapters.distroseries_to_launchpadusage"
+        factory="lp.registry.adapters.distroseries_to_distribution"
         permission="zope.Public"/>
     <adapter
-        factory="lp.registry.adapters.distroseries_to_serviceusage" />
-    <adapter
         provides="canonical.launchpad.webapp.interfaces.IBreadcrumb"
         for="lp.registry.interfaces.distroseries.IDistroSeries"
         factory="lp.registry.browser.distroseries.DistroSeriesBreadcrumb"
@@ -1374,6 +1375,9 @@
             interface="lp.translations.interfaces.translationimportqueue.IHasTranslationImports"/>
         <require
             permission="launchpad.Edit"
+            set_schema="lp.app.interfaces.launchpad.IServiceUsage"/>
+        <require
+            permission="launchpad.Edit"
             set_attributes="product name owner driver summary branch
                             translations_branch status releasefileglob
                             translations_autoimport_mode"/>
@@ -1407,11 +1411,6 @@
         factory="lp.registry.adapters.productseries_to_product"
         permission="zope.Public"/>
     <adapter
-        provides="lp.app.interfaces.launchpad.IServiceUsage"
-        for="lp.registry.interfaces.productseries.IProductSeries"
-        factory="lp.registry.adapters.productseries_to_product"
-        permission="zope.Public"/>
-    <adapter
         provides="lp.app.interfaces.launchpad.ILaunchpadUsage"
         for="lp.registry.interfaces.productseries.IProductSeries"
         factory="lp.registry.adapters.productseries_to_product"

=== modified file 'lib/lp/registry/interfaces/distroseries.py'
--- lib/lp/registry/interfaces/distroseries.py	2010-08-30 19:06:34 +0000
+++ lib/lp/registry/interfaces/distroseries.py	2010-09-21 13:57:44 +0000
@@ -52,6 +52,7 @@
 from canonical.launchpad.validators.name import name_validator
 from canonical.launchpad.validators.version import sane_version
 from lp.app.errors import NameLookupFailed
+from lp.app.interfaces.launchpad import IServiceUsage
 from lp.blueprints.interfaces.specificationtarget import ISpecificationGoal
 from lp.bugs.interfaces.bugtarget import (
     IBugTarget,
@@ -173,7 +174,7 @@
 class IDistroSeriesPublic(
     ISeriesMixin, IHasAppointedDriver, IHasOwner, IBugTarget,
     ISpecificationGoal, IHasMilestones, IHasOfficialBugTags,
-    IHasBuildRecords, IHasTranslationTemplates):
+    IHasBuildRecords, IHasTranslationTemplates, IServiceUsage):
     """Public IDistroSeries properties."""
 
     id = Attribute("The distroseries's unique number.")

=== modified file 'lib/lp/registry/interfaces/productseries.py'
--- lib/lp/registry/interfaces/productseries.py	2010-08-31 00:02:42 +0000
+++ lib/lp/registry/interfaces/productseries.py	2010-09-21 13:57:44 +0000
@@ -48,6 +48,7 @@
 from canonical.launchpad.validators.name import name_validator
 from canonical.launchpad.webapp.url import urlparse
 from lp.app.errors import NameLookupFailed
+from lp.app.interfaces.launchpad import IServiceUsage
 from lp.blueprints.interfaces.specificationtarget import ISpecificationGoal
 from lp.bugs.interfaces.bugtarget import (
     IBugTarget,
@@ -120,7 +121,7 @@
 class IProductSeriesPublic(
     ISeriesMixin, IHasAppointedDriver, IHasOwner, IBugTarget,
     ISpecificationGoal, IHasMilestones, IHasOfficialBugTags,
-    IHasTranslationTemplates):
+    IHasTranslationTemplates, IServiceUsage):
     """Public IProductSeries properties."""
     # XXX Mark Shuttleworth 2004-10-14: Would like to get rid of id in
     # interfaces, as soon as SQLobject allows using the object directly

=== modified file 'lib/lp/registry/model/distroseries.py'
--- lib/lp/registry/model/distroseries.py	2010-09-03 15:02:39 +0000
+++ lib/lp/registry/model/distroseries.py	2010-09-21 13:57:44 +0000
@@ -63,6 +63,8 @@
     SLAVE_FLAVOR,
     )
 from lp.app.errors import NotFoundError
+from lp.app.enums import ServiceUsage
+from lp.app.interfaces.launchpad import IServiceUsage
 from lp.blueprints.interfaces.specification import (
     SpecificationFilter,
     SpecificationGoalStatus,
@@ -186,7 +188,7 @@
     """A particular series of a distribution."""
     implements(
         ICanPublishPackages, IDistroSeries, IHasBugHeat, IHasBuildRecords,
-        IHasQueueItems)
+        IHasQueueItems, IServiceUsage)
 
     _table = 'DistroSeries'
     _defaultOrder = ['distribution', 'version']
@@ -263,6 +265,41 @@
             """ % self.id,
             clauseTables=["ComponentSelection"])
 
+    @property
+    def answers_usage(self):
+        """See `IServiceUsage.`"""
+        return self.distribution.answers_usage
+
+    @property
+    def blueprints_usage(self):
+        """See `IServiceUsage.`"""
+        return self.distribution.blueprints_usage
+
+    @property
+    def translations_usage(self):
+        """See `IServiceUsage.`"""
+        # If translations_usage is set for the Product, respect it.
+        usage = self.distribution.translations_usage
+        if usage != ServiceUsage.UNKNOWN:
+            return usage
+
+        # If not, usage is based on the presence of current translation
+        # templates for the series.
+        if self.getCurrentTranslationTemplates().count() > 0:
+            return ServiceUsage.LAUNCHPAD
+        else:
+            return ServiceUsage.UNKNOWN
+
+    @property
+    def codehosting_usage(self):
+        """See `IServiceUsage.`"""
+        return self.distribution.codehosting_usage
+
+    @property
+    def bug_tracking_usage(self):
+        """See `IServiceUsage.`"""
+        return self.distribution.bug_tracking_usage
+
     # DistroArchSeries lookup properties/methods.
     architectures = SQLMultipleJoin(
         'DistroArchSeries', joinColumn='distroseries',

=== modified file 'lib/lp/registry/model/productseries.py'
--- lib/lp/registry/model/productseries.py	2010-08-31 00:02:42 +0000
+++ lib/lp/registry/model/productseries.py	2010-09-21 13:57:44 +0000
@@ -43,6 +43,8 @@
 from canonical.launchpad.webapp.publisher import canonical_url
 from canonical.launchpad.webapp.sorting import sorted_dotted_numbers
 from lp.app.errors import NotFoundError
+from lp.app.enums import ServiceUsage
+from lp.app.interfaces.launchpad import IServiceUsage
 from lp.blueprints.interfaces.specification import (
     SpecificationDefinitionStatus,
     SpecificationFilter,
@@ -115,7 +117,7 @@
                     HasTranslationImportsMixin, HasTranslationTemplatesMixin,
                     StructuralSubscriptionTargetMixin, SeriesMixin):
     """A series of product releases."""
-    implements(IHasBugHeat, IProductSeries)
+    implements(IHasBugHeat, IProductSeries, IServiceUsage)
 
     _table = 'ProductSeries'
 
@@ -151,6 +153,41 @@
     packagings = SQLMultipleJoin('Packaging', joinColumn='productseries',
                             orderBy=['-id'])
 
+    @property
+    def answers_usage(self):
+        """See `IServiceUsage.`"""
+        return self.product.answers_usage
+
+    @property
+    def blueprints_usage(self):
+        """See `IServiceUsage.`"""
+        return self.product.blueprints_usage
+
+    @property
+    def translations_usage(self):
+        """See `IServiceUsage.`"""
+        # If translations_usage is set for the Product, respect it.
+        usage = self.product.translations_usage
+        if usage != ServiceUsage.UNKNOWN:
+            return usage
+
+        # If not, usage is based on the presence of current translation
+        # templates for the series.
+        if self.potemplate_count > 0:
+            return ServiceUsage.LAUNCHPAD
+        else:
+            return ServiceUsage.UNKNOWN
+
+    @property
+    def codehosting_usage(self):
+        """See `IServiceUsage.`"""
+        return self.product.codehosting_usage
+
+    @property
+    def bug_tracking_usage(self):
+        """See `IServiceUsage.`"""
+        return self.product.bug_tracking_usage
+
     def _getMilestoneCondition(self):
         """See `HasMilestonesMixin`."""
         return (Milestone.productseries == self)

=== modified file 'lib/lp/registry/tests/test_service_usage.py'
--- lib/lp/registry/tests/test_service_usage.py	2010-08-22 17:21:46 +0000
+++ lib/lp/registry/tests/test_service_usage.py	2010-09-21 13:57:44 +0000
@@ -143,6 +143,29 @@
             self.target.official_blueprints)
 
 
+class SeriesUsageEnumsMixin(object):
+
+    def setUp(self):
+        self.series = None
+        self.series_pillar = None
+
+    def _addCurrentPOTemplate(self):
+        raise NotImplementedError("Child class must provide _addPOTTemplate.")
+
+    def test_translations_usage_pillar(self):
+        self.assertEqual(
+            ServiceUsage.UNKNOWN,
+            self.series_pillar.translations_usage)
+        self.assertEqual(
+            ServiceUsage.UNKNOWN,
+            self.series.translations_usage)
+
+        self._addCurrentPOTemplate()
+        self.assertEqual(
+            ServiceUsage.LAUNCHPAD,
+            self.series.translations_usage)
+
+
 class TestDistributionUsageEnums(TestCaseWithFactory, UsageEnumsMixin):
     """Tests the usage enums for the distribution."""
 
@@ -170,5 +193,54 @@
         self.target = self.factory.makeProduct()
 
 
+class TestProductSeriesUsageEnums(
+    TestCaseWithFactory,
+    SeriesUsageEnumsMixin):
+
+    layer = DatabaseFunctionalLayer
+
+    def setUp(self):
+        super(TestProductSeriesUsageEnums, self).setUp()
+        self.series_pillar = self.factory.makeProduct()
+        self.series = self.factory.makeProductSeries(
+            product=self.series_pillar)
+        login_person(self.series_pillar.owner)
+
+    def _addCurrentPOTemplate(self):
+        self.factory.makePOTemplate(productseries=self.series)
+        # XXX j.c.sackett 2010-09-21 bug=605924: Right now for it to
+        # be current, the series pillar must be marked as using
+        # using translations.
+        self.series_pillar.translations_usage = ServiceUsage.LAUNCHPAD
+
+
+class TestDistroSeriesUsageEnums(
+    TestCaseWithFactory,
+    SeriesUsageEnumsMixin):
+
+    layer = DatabaseFunctionalLayer
+
+    def setUp(self):
+        super(TestDistroSeriesUsageEnums, self).setUp()
+        self.series_pillar = self.factory.makeDistribution()
+        self.series = self.factory.makeDistroSeries(
+            distribution=self.series_pillar)
+        login_person(self.series_pillar.owner)
+
+    def _addCurrentPOTemplate(self):
+        sp_name = self.factory.makeSourcePackageName()
+        self.factory.makeSourcePackage(
+            sourcepackagename=sp_name,
+            distroseries=self.series)
+        self.factory.makePOTemplate(
+            distroseries=self.series,
+            sourcepackagename=sp_name)
+
+        # XXX j.c.sackett 2010-09-21 bug=605924: Right now for it to
+        # be current, the series pillar must be marked as using
+        # using translations.
+        self.series_pillar.translations_usage = ServiceUsage.LAUNCHPAD
+
+
 def test_suite():
     return unittest.TestLoader().loadTestsFromName(__name__)