launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #04049
[Merge] lp:~bac/launchpad/bug-776437 into lp:launchpad
Brad Crittenden has proposed merging lp:~bac/launchpad/bug-776437 into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #776437 in Launchpad itself: "Enable ARM builders for PPA via API"
https://bugs.launchpad.net/launchpad/+bug/776437
For more details, see:
https://code.launchpad.net/~bac/launchpad/bug-776437/+merge/65692
= Summary =
Expose a way to set enabled restricted families for OEM's use.
== Proposed fix ==
Expose attributes for IProcessor, IProcessorFamily, and IProcessorFamilySet.
== Pre-implementation notes ==
Many chats with Francis, Gary, Benji, and Curtis.
== Implementation details ==
I used to <3 the API. Now not so much.
== Tests ==
bin/test -vvm lp.soyuz -t TestProcessorFamilies
== Demo and Q/A ==
Fire up a server and hit it with launchpadlib. Items of interest are
archive.enabled_restricted_families and archive.enableRestrictedFamily.
For the latter you must be logged in as a member of the commercial
team. bac@xxxxxxxxxxxxx/test works.
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/soyuz/stories/webservice/xx-archive.txt
lib/lp/soyuz/interfaces/processor.py
lib/lp/soyuz/interfaces/archive.py
lib/lp/app/browser/launchpad.py
lib/lp/soyuz/configure.zcml
lib/lp/testing/__init__.py
lib/lp/soyuz/interfaces/webservice.py
lib/lp/soyuz/browser/configure.zcml
lib/lp/soyuz/browser/tests/test_archive_webservice.py
lib/lp/soyuz/model/archive.py
lib/lp/soyuz/browser/processor.py
lib/canonical/launchpad/interfaces/_schema_circular_imports.py
./lib/lp/soyuz/stories/webservice/xx-archive.txt
37: source exceeds 78 characters.
40: want exceeds 78 characters.
44: want exceeds 78 characters.
165: want exceeds 78 characters.
181: want exceeds 78 characters.
197: want exceeds 78 characters.
213: want exceeds 78 characters.
301: want exceeds 78 characters.
362: want exceeds 78 characters.
493: want exceeds 78 characters.
./lib/lp/soyuz/model/archive.py
348: redefinition of function 'private' from line 344
--
https://code.launchpad.net/~bac/launchpad/bug-776437/+merge/65692
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~bac/launchpad/bug-776437 into lp:launchpad.
=== modified file 'lib/canonical/launchpad/interfaces/_schema_circular_imports.py'
--- lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2011-06-11 00:49:33 +0000
+++ lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2011-06-23 16:21:19 +0000
@@ -200,6 +200,10 @@
IPackageset,
IPackagesetSet,
)
+from lp.soyuz.interfaces.processor import (
+ IProcessor,
+ IProcessorFamily,
+ )
from lp.soyuz.interfaces.publishing import (
IBinaryPackagePublishingHistory,
ISourcePackagePublishingHistory,
@@ -377,6 +381,8 @@
# IArchive apocalypse.
patch_reference_property(IArchive, 'distribution', IDistribution)
patch_collection_property(IArchive, 'dependencies', IArchiveDependency)
+patch_collection_property(
+ IArchive, 'enabled_restricted_families', IProcessorFamily)
patch_collection_return_type(
IArchive, 'getPermissionsForPerson', IArchivePermission)
patch_collection_return_type(
@@ -442,6 +448,8 @@
IArchive, '_addArchiveDependency', 'pocket', PackagePublishingPocket)
patch_entry_return_type(
IArchive, '_addArchiveDependency', IArchiveDependency)
+patch_plain_parameter_type(
+ IArchive, 'enableRestrictedFamily', 'family', IProcessorFamily)
# IBuildFarmJob
@@ -540,6 +548,10 @@
patch_reference_property(IPackageUpload, 'distroseries', IDistroSeries)
patch_reference_property(IPackageUpload, 'archive', IArchive)
+# IProcessor
+patch_reference_property(
+ IProcessor, 'family', IProcessorFamily)
+
# IStructuralSubscription
patch_collection_property(
IStructuralSubscription, 'bug_filters', IBugSubscriptionFilter)
=== modified file 'lib/lp/app/browser/launchpad.py'
--- lib/lp/app/browser/launchpad.py 2011-05-29 01:59:15 +0000
+++ lib/lp/app/browser/launchpad.py 2011-06-23 16:21:19 +0000
@@ -147,6 +147,7 @@
from lp.services.worlddata.interfaces.language import ILanguageSet
from lp.soyuz.interfaces.binarypackagename import IBinaryPackageNameSet
from lp.soyuz.interfaces.packageset import IPackagesetSet
+from lp.soyuz.interfaces.processor import IProcessorFamilySet
from lp.testopenid.interfaces.server import ITestOpenIDApplication
from lp.translations.interfaces.translationgroup import ITranslationGroupSet
from lp.translations.interfaces.translationimportqueue import (
@@ -617,6 +618,7 @@
'package-sets': IPackagesetSet,
'people': IPersonSet,
'pillars': IPillarNameSet,
+ '+processor-families': IProcessorFamilySet,
'projects': IProductSet,
'projectgroups': IProjectGroupSet,
'sourcepackagenames': ISourcePackageNameSet,
=== modified file 'lib/lp/soyuz/browser/configure.zcml'
--- lib/lp/soyuz/browser/configure.zcml 2011-05-29 21:18:09 +0000
+++ lib/lp/soyuz/browser/configure.zcml 2011-06-23 16:21:19 +0000
@@ -32,6 +32,18 @@
path_expression="string:+binarypub"
attribute_to_parent="archive"
urldata="lp.soyuz.browser.publishing.BinaryPublicationURL"/>
+ <browser:url
+ for="lp.soyuz.interfaces.processor.IProcessorFamilySet"
+ path_expression="string:+processor-families"
+ parent_utility="canonical.launchpad.webapp.interfaces.ILaunchpadRoot"/>
+ <browser:url
+ for="lp.soyuz.interfaces.processor.IProcessorFamily"
+ path_expression="string:${name}"
+ parent_utility="lp.soyuz.interfaces.processor.IProcessorFamilySet" />
+ <browser:url
+ for="lp.soyuz.interfaces.processor.IProcessor"
+ path_expression="string:${id}"
+ attribute_to_parent="family" />
</facet>
<browser:navigation
module="lp.soyuz.browser.binarypackagerelease"
@@ -217,8 +229,11 @@
name="+index"/>
<browser:navigation
module="lp.soyuz.browser.archive"
- classes="
- ArchiveNavigation"/>
+ classes="ArchiveNavigation" />
+ <browser:navigation
+ module="lp.soyuz.browser.processor"
+ classes="
+ ProcessorFamilySetNavigation ProcessorFamilyNavigation"/>
<browser:url
for="lp.soyuz.interfaces.archive.IPPA"
path_expression="string:+archive"
=== added file 'lib/lp/soyuz/browser/processor.py'
--- lib/lp/soyuz/browser/processor.py 1970-01-01 00:00:00 +0000
+++ lib/lp/soyuz/browser/processor.py 2011-06-23 16:21:19 +0000
@@ -0,0 +1,46 @@
+# Copyright 2011 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Navigation views for processors."""
+
+
+__metaclass__ = type
+
+__all__ = [
+ 'ProcessorFamilySetNavigation',
+ 'ProcessorFamilyNavigation',
+ ]
+
+
+from canonical.launchpad.webapp import Navigation
+from lp.app.errors import NotFoundError
+from lp.soyuz.interfaces.processor import (
+ IProcessorFamily,
+ IProcessorFamilySet,
+ )
+
+
+class ProcessorFamilySetNavigation(Navigation):
+ """IProcessorFamilySet navigation."""
+ usedfor = IProcessorFamilySet
+
+ def traverse(self, name):
+ family = self.context.getByName(name)
+ # Raise NotFoundError on invalid processor family name.
+ if family is None:
+ raise NotFoundError(name)
+ return family
+
+
+class ProcessorFamilyNavigation(Navigation):
+ """IProcessorFamily navigation."""
+
+ usedfor = IProcessorFamily
+
+ def traverse(self, id_):
+ id_ = int(id_)
+ processors = self.processors
+ for p in processors:
+ if p.id == id_:
+ return p
+ raise NotFoundError(id_)
=== modified file 'lib/lp/soyuz/browser/tests/test_archive_webservice.py'
--- lib/lp/soyuz/browser/tests/test_archive_webservice.py 2011-06-20 17:48:12 +0000
+++ lib/lp/soyuz/browser/tests/test_archive_webservice.py 2011-06-23 16:21:19 +0000
@@ -20,6 +20,7 @@
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
from lp.registry.interfaces.pocket import PackagePublishingPocket
from lp.soyuz.enums import ArchivePurpose
+from lp.soyuz.interfaces.processor import IProcessorFamilySet
from lp.testing import (
celebrity_logged_in,
launchpadlib_for,
@@ -200,5 +201,113 @@
self.assertContentEqual([], ws_archive.dependencies)
+class TestProcessorFamilies(WebServiceTestCase):
+ """Test the enabled_restricted_families property and methods."""
+
+ def test_erfNotAvailableInBeta(self):
+ """The enabled_restricted_families property is not in beta."""
+ self.ws_version = 'beta'
+ archive = self.factory.makeArchive()
+ commercial = getUtility(ILaunchpadCelebrities).commercial_admin
+ commercial_admin = self.factory.makePerson(member_of=[commercial])
+ transaction.commit()
+ ws_archive = self.wsObject(archive, user=commercial_admin)
+ expected_re = (
+ "(.|\n)*'Entry' object has no attribute "
+ "'enabled_restricted_families'(.|\n)*")
+ with ExpectedException(AttributeError, expected_re):
+ ws_archive.enabled_restricted_families
+
+ def test_erfAvailableInDevel(self):
+ """The enabled_restricted_families property is in devel."""
+ self.ws_version = 'devel'
+ archive = self.factory.makeArchive()
+ commercial = getUtility(ILaunchpadCelebrities).commercial_admin
+ commercial_admin = self.factory.makePerson(member_of=[commercial])
+ transaction.commit()
+ ws_archive = self.wsObject(archive, user=commercial_admin)
+ self.assertContentEqual([], ws_archive.enabled_restricted_families)
+
+ def test_getByName(self):
+ """The getByName method returns a processor family."""
+ self.ws_version = 'devel'
+ transaction.commit()
+ arm = self.service.processor_families.getByName(name='arm')
+ self.assertEqual(u'arm', arm.name)
+ self.assertEqual(u'ARM Processors', arm.title)
+ self.assertEqual(
+ u'The ARM and compatible processors', arm.description)
+ self.assertEqual(True, arm.restricted)
+
+ def test_processors(self):
+ """Attributes about processors are available."""
+ self.ws_version = 'devel'
+ product_family_set = getUtility(IProcessorFamilySet)
+ ws_arm = self.service.processor_families.getByName(name='arm')
+ self.assertContentEqual([], ws_arm.processors)
+ product_family_set = getUtility(IProcessorFamilySet)
+ arm = product_family_set.getByName('arm')
+ arm.addProcessor('new-arm', 'New ARM Title', 'New ARM Description')
+ transaction.commit()
+ ws_proc = ws_arm.processors[0]
+ self.assertEqual('new-arm', ws_proc.name)
+ self.assertEqual('New ARM Title', ws_proc.title)
+ self.assertEqual('New ARM Description', ws_proc.description)
+
+ def test_enableRestrictedFamily(self):
+ """A new family can be added to the enabled restricted set."""
+ self.ws_version = 'devel'
+ archive = self.factory.makeArchive()
+ commercial = getUtility(ILaunchpadCelebrities).commercial_admin
+ commercial_admin = self.factory.makePerson(member_of=[commercial])
+ transaction.commit()
+ ws_arm = self.service.processor_families.getByName(name='arm')
+ ws_archive = self.wsObject(archive, user=commercial_admin)
+ self.assertContentEqual([], ws_archive.enabled_restricted_families)
+ ws_archive.enableRestrictedFamily(family=ws_arm)
+ self.assertContentEqual(
+ [ws_arm], ws_archive.enabled_restricted_families)
+
+ def test_enableRestrictedFamily_owner(self):
+ """A new family can be added to the enabled restricted set.
+
+ An unauthorized user, even the archive owner, is not allowed.
+ """
+ self.ws_version = 'devel'
+ archive = self.factory.makeArchive()
+ transaction.commit()
+ ws_arm = self.service.processor_families.getByName(name='arm')
+ ws_archive = self.wsObject(archive, user=archive.owner)
+ self.assertContentEqual([], ws_archive.enabled_restricted_families)
+ expected_re = (
+ "(.|\n)*'launchpad\.Commercial'(.|\n)*")
+ with ExpectedException(LRUnauthorized, expected_re):
+ ws_archive.enableRestrictedFamily(family=ws_arm)
+
+ def test_enableRestrictedFamily_nonPrivUser(self):
+ """A new family can be added to the enabled restricted set.
+
+ An unauthorized user, some regular user, is not allowed.
+ """
+ self.ws_version = 'devel'
+ archive = self.factory.makeArchive()
+ just_some_guy = self.factory.makePerson()
+ transaction.commit()
+ ws_arm = self.service.processor_families.getByName(name='arm')
+ ws_archive = self.wsObject(archive, user=just_some_guy)
+ self.assertContentEqual([], ws_archive.enabled_restricted_families)
+ expected_re = (
+ "(.|\n)*'launchpad\.Commercial'(.|\n)*")
+ with ExpectedException(LRUnauthorized, expected_re):
+ ws_archive.enableRestrictedFamily(family=ws_arm)
+
+ def test_defaultCollection(self):
+ """getRestricted will return all of the restricted families."""
+ self.ws_version = 'devel'
+ ws_arm = self.service.processor_families.getByName(name='arm')
+ self.assertContentEqual(
+ [ws_arm], self.service.processor_families)
+
+
def test_suite():
return unittest.TestLoader().loadTestsFromName(__name__)
=== modified file 'lib/lp/soyuz/configure.zcml'
--- lib/lp/soyuz/configure.zcml 2011-06-15 02:41:34 +0000
+++ lib/lp/soyuz/configure.zcml 2011-06-23 16:21:19 +0000
@@ -399,6 +399,7 @@
set_attributes="description displayname publish status"/>
<require
permission="launchpad.Commercial"
+ interface="lp.soyuz.interfaces.archive.IArchiveCommercial"
set_attributes="authorized_size build_debug_symbols buildd_secret
commercial enabled_restricted_families
external_dependencies private
=== modified file 'lib/lp/soyuz/interfaces/archive.py'
--- lib/lp/soyuz/interfaces/archive.py 2011-06-16 15:13:51 +0000
+++ lib/lp/soyuz/interfaces/archive.py 2011-06-23 16:21:19 +0000
@@ -23,6 +23,7 @@
'FULL_COMPONENT_SUPPORT',
'IArchive',
'IArchiveAppend',
+ 'IArchiveCommercial',
'IArchiveEdit',
'IArchiveView',
'IArchiveEditDependenciesForm',
@@ -100,7 +101,6 @@
from lp.soyuz.enums import ArchivePurpose
from lp.soyuz.interfaces.buildrecords import IHasBuildRecords
from lp.soyuz.interfaces.component import IComponent
-from lp.soyuz.interfaces.processor import IProcessorFamily
@error_status(httplib.BAD_REQUEST)
@@ -433,13 +433,16 @@
"context build.\n"
"NOTE: This is for migration of OEM PPAs only!")))
- enabled_restricted_families = CollectionField(
+ enabled_restricted_families = exported(
+ CollectionField(
title=_("Enabled restricted families"),
description=_(
"The restricted architecture families on which the archive "
"can build."),
- value_type=Reference(schema=IProcessorFamily),
- readonly=False)
+ value_type=Reference(schema=Interface),
+ # Really IProcessorFamily.
+ readonly=True),
+ as_of='devel')
commercial = exported(
Bool(
@@ -1506,7 +1509,24 @@
"""
-class IArchive(IArchivePublic, IArchiveAppend, IArchiveEdit, IArchiveView):
+class IArchiveCommercial(Interface):
+ """Archive interface for operations restricted by commercial."""
+
+ @operation_parameters(
+ family=Reference(schema=Interface, required=True),
+ # Really IProcessorFamily.
+ )
+ @export_write_operation()
+ @operation_for_version('devel')
+ def enableRestrictedFamily(family):
+ """Add the processor family to the set of enabled restricted families.
+
+ :param family: is an `IProcessorFamily` object.
+ """
+
+
+class IArchive(IArchivePublic, IArchiveAppend, IArchiveEdit, IArchiveView,
+ IArchiveCommercial):
"""Main Archive interface."""
export_as_webservice_entry()
=== modified file 'lib/lp/soyuz/interfaces/processor.py'
--- lib/lp/soyuz/interfaces/processor.py 2010-08-20 20:31:18 +0000
+++ lib/lp/soyuz/interfaces/processor.py 2011-06-23 16:21:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
# pylint: disable-msg=E0211,E0213
@@ -17,27 +17,101 @@
Attribute,
Interface,
)
-from zope.schema import Bool
+from zope.schema import (
+ Bool,
+ Text,
+ TextLine,
+ )
from canonical.launchpad import _
+from lazr.restful.declarations import (
+ collection_default_content,
+ export_as_webservice_collection,
+ export_as_webservice_entry,
+ export_read_operation,
+ exported,
+ operation_for_version,
+ operation_parameters,
+ operation_returns_entry,
+ )
+from lazr.restful.fields import (
+ CollectionField,
+ Reference,
+ )
class IProcessor(Interface):
"""The SQLObject Processor Interface"""
+
+ # XXX: BradCrittenden 2011-06-20 bug=760849: The following use of 'beta'
+ # is a work-around to allow the WADL to be generated. It is a bald-faced
+ # lie, though. The class is being exported in 'devel' but in order to get
+ # the WADL generation work it must be back-dated to the earliest version.
+ # Note that individual attributes and methods can and must truthfully set
+ # 'devel' as their version.
+ export_as_webservice_entry(publish_web_link=True, as_of='beta')
id = Attribute("The Processor ID")
- family = Attribute("The Processor Family Reference")
- name = Attribute("The Processor Name")
- title = Attribute("The Processor Title")
- description = Attribute("The Processor Description")
+ family = exported(
+ Reference(
+ schema=Interface,
+ # Really IProcessorFamily.
+ required=True, readonly=True,
+ title=_("Processor Family"),
+ description=_("The Processor Family Reference")),
+ as_of='devel', readonly=True)
+ name = exported(
+ TextLine(title=_("Name"),
+ description=_("The Processor Name")),
+ as_of='devel', readonly=True)
+ title = exported(
+ TextLine(title=_("Title"),
+ description=_("The Processor Title")),
+ as_of='devel', readonly=True)
+ description = exported(
+ Text(title=_("Description"),
+ description=_("The Processor Description")),
+ as_of='devel', readonly=True)
+
class IProcessorFamily(Interface):
"""The SQLObject ProcessorFamily Interface"""
+
+ # XXX: BradCrittenden 2011-06-20 bug=760849: The following use of 'beta'
+ # is a work-around to allow the WADL to be generated. It is a bald-faced
+ # lie, though. The class is being exported in 'devel' but in order to get
+ # the WADL generation work it must be back-dated to the earliest version.
+ # Note that individual attributes and methods can and must truthfully set
+ # 'devel' as their version.
+ export_as_webservice_entry(
+ plural_name='processor_families',
+ publish_web_link=True,
+ as_of='beta')
+
id = Attribute("The ProcessorFamily ID")
- name = Attribute("The Processor Family Name")
- title = Attribute("The Processor Family Title")
- description = Attribute("The Processor Name Description")
- processors = Attribute("The Processors in this family.")
- restricted = Bool(title=_("Whether this family is restricted."))
+ name = exported(
+ TextLine(
+ title=_("Name"),
+ description=_("The Processor Family Name")),
+ as_of='devel', readonly=True)
+ title = exported(
+ TextLine(
+ title=_("Title"),
+ description=_("The Processor Family Title")),
+ as_of='devel', readonly=True)
+ description = exported(
+ Text(
+ title=_("Description"),
+ description=_("The Processor Name Description")),
+ as_of='devel', readonly=True)
+ processors = exported(
+ CollectionField(
+ title=_("Processors"),
+ description=_("The Processors in this family."),
+ value_type=Reference(IProcessor)),
+ as_of='devel', readonly=True)
+ restricted = exported(
+ Bool(title=_("Whether this family is restricted.")),
+ as_of='devel', readonly=True)
def addProcessor(name, title, description):
"""Add a new processor to this family.
@@ -48,9 +122,17 @@
:return: A `IProcessor`
"""
+
class IProcessorFamilySet(Interface):
"""Operations related to ProcessorFamily instances."""
+ export_as_webservice_collection(Interface)
+
+ @operation_parameters(
+ name=TextLine(required=True))
+ @operation_returns_entry(Interface)
+ @export_read_operation()
+ @operation_for_version('devel')
def getByName(name):
"""Return the ProcessorFamily instance with the matching name.
@@ -59,6 +141,7 @@
:return: A `IProcessorFamily` instance if found, None otherwise.
"""
+ @collection_default_content()
def getRestricted():
"""Return a sequence of all restricted architectures.
=== modified file 'lib/lp/soyuz/interfaces/webservice.py'
--- lib/lp/soyuz/interfaces/webservice.py 2011-06-16 14:56:55 +0000
+++ lib/lp/soyuz/interfaces/webservice.py 2011-06-23 16:21:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""All the interfaces that are exposed through the webservice.
@@ -32,6 +32,9 @@
'IPackageUpload',
'IPackageset',
'IPackagesetSet',
+ 'IProcessor',
+ 'IProcessorFamily',
+ 'IProcessorFamilySet',
'ISourcePackagePublishingHistory',
'IncompatibleArguments',
'InsufficientUploadRights',
@@ -89,12 +92,28 @@
IPackagesetSet,
NoSuchPackageSet,
)
+from lp.soyuz.interfaces.processor import (
+ IProcessor,
+ IProcessorFamily,
+ IProcessorFamilySet,
+ )
from lp.soyuz.interfaces.publishing import (
IBinaryPackagePublishingHistory,
ISourcePackagePublishingHistory,
)
from lp.soyuz.interfaces.queue import IPackageUpload
+
+from canonical.launchpad.components.apihelpers import (
+ patch_entry_return_type,
+ )
+
# XXX: JonathanLange 2010-11-09 bug=673083: Legacy work-around for circular
# import bugs. Break this up into a per-package thing.
from canonical.launchpad.interfaces import _schema_circular_imports
_schema_circular_imports
+
+from lazr.restful.declarations import LAZR_WEBSERVICE_EXPORTED
+IProcessorFamilySet.queryTaggedValue(
+ LAZR_WEBSERVICE_EXPORTED)['collection_entry_schema'] = IProcessorFamily
+
+patch_entry_return_type(IProcessorFamilySet, 'getByName', IProcessorFamily)
=== modified file 'lib/lp/soyuz/model/archive.py'
--- lib/lp/soyuz/model/archive.py 2011-06-21 17:22:38 +0000
+++ lib/lp/soyuz/model/archive.py 2011-06-23 16:21:19 +0000
@@ -1828,6 +1828,12 @@
enabled_restricted_families = property(_getEnabledRestrictedFamilies,
_setEnabledRestrictedFamilies)
+ def enableRestrictedFamily(self, family):
+ """See `IArchive`."""
+ restricted = set(self.enabled_restricted_families)
+ restricted.add(family)
+ self.enabled_restricted_families = restricted
+
@classmethod
def validatePPA(self, person, proposed_name):
ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
=== modified file 'lib/lp/soyuz/stories/webservice/xx-archive.txt'
--- lib/lp/soyuz/stories/webservice/xx-archive.txt 2011-06-16 20:12:00 +0000
+++ lib/lp/soyuz/stories/webservice/xx-archive.txt 2011-06-23 16:21:19 +0000
@@ -32,6 +32,26 @@
signing_key_fingerprint: None
web_link: u'http://launchpad.../~cprov/+archive/ppa'
+For "devel" additional attributes are available.
+
+ >>> cprov_archive_devel = webservice.get("/~cprov/+archive/ppa", api_version='devel').jsonBody()
+ >>> pprint_entry(cprov_archive_devel)
+ commercial: False
+ dependencies_collection_link: u'http://.../~cprov/+archive/ppa/dependencies'
+ description: u'packages to help my friends.'
+ displayname: u'PPA for Celso Providelo'
+ distribution_link: u'http://.../ubuntu'
+ enabled_restricted_families_collection_link: u'http://.../~cprov/+archive/ppa/enabled_restricted_families'
+ external_dependencies: None
+ name: u'ppa'
+ owner_link: u'http://.../~cprov'
+ private: False
+ require_virtualized: True
+ resource_type_link: u'http://.../#archive'
+ self_link: u'http://.../~cprov/+archive/ppa'
+ signing_key_fingerprint: None
+ web_link: u'http://launchpad.../~cprov/+archive/ppa'
+
While the Archive signing key is being generated its
'signing_key_fingerprint' attribute is None.
=== modified file 'lib/lp/testing/__init__.py'
--- lib/lp/testing/__init__.py 2011-06-21 14:04:50 +0000
+++ lib/lp/testing/__init__.py 2011-06-23 16:21:19 +0000
@@ -894,7 +894,7 @@
:param obj: The object to find the launchpadlib equivalent of.
:param user: The user to use for accessing the object over
- lauchpadlib. Defaults to an arbitrary logged-in user.
+ launchpadlib. Defaults to an arbitrary logged-in user.
"""
if user is not None:
service = self.factory.makeLaunchpadService(