Merge lp:~wallyworld/launchpad/launchpadlib-services-974139 into lp:launchpad

Proposed by Ian Booth
Status: Work in progress
Proposed branch: lp:~wallyworld/launchpad/launchpadlib-services-974139
Merge into: lp:launchpad
Diff against target: 219 lines (+54/-56)
8 files modified
lib/lp/app/configure.zcml (+0/-8)
lib/lp/app/interfaces/services.py (+25/-1)
lib/lp/app/services.py (+13/-7)
lib/lp/app/tests/test_services.py (+9/-2)
lib/lp/registry/interfaces/webservice.py (+5/-1)
lib/lp/registry/services/tests/test_sharingservice.py (+1/-4)
lib/lp/services/webservice/services.py (+0/-32)
versions.cfg (+1/-1)
To merge this branch: bzr merge lp:~wallyworld/launchpad/launchpadlib-services-974139
Reviewer Review Type Date Requested Status
Launchpad code reviewers Pending
Review via email: mp+101349@code.launchpad.net

Commit message

Rework export of ServiceFactory so that launchpadlib top level 'services' collection can be used.

Description of the change

== Implementation ==

The changes in this branch allow launchpadlib to be used like so:

lp = Launchpad(...)
service = lp.services['myservice']
service.some_method()

Essentially, ServiceFactory is made a web service collection (requiring a collection_default_content to be defined). The default content method returns all registered services.

The changes mean that lp.services.webservice.services.ServicesLink needed to be removed.

This branch can be landed after lp:~wallyworld/launchpadlib/services-serviceroot

== Tests ==

The TestLaunchpadlib test case was changed to locate the service using the new syntax.
An additional test_registeredServices test was added for the new collection_default_content method.

== Lint ==

Checking for conflicts and issues in changed files.

Linting changed files:
  versions.cfg
  lib/lp/app/configure.zcml
  lib/lp/app/services.py
  lib/lp/app/interfaces/services.py
  lib/lp/app/tests/test_services.py
  lib/lp/registry/interfaces/webservice.py
  lib/lp/registry/services/tests/test_sharingservice.py

To post a comment you must log in.

Unmerged revisions

15073. By Ian Booth

Lint

15072. By Ian Booth

Rework export of ServiceFactory so that launchpadlib top level 'services' collection can be used

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/app/configure.zcml'
--- lib/lp/app/configure.zcml 2012-02-24 05:14:46 +0000
+++ lib/lp/app/configure.zcml 2012-04-10 10:20:44 +0000
@@ -74,13 +74,5 @@
74 <allow74 <allow
75 interface="zope.publisher.interfaces.IPublishTraverse"/>75 interface="zope.publisher.interfaces.IPublishTraverse"/>
76 </securedutility>76 </securedutility>
77 <securedutility
78 class="lp.services.webservice.services.ServicesLink"
79 provides="lp.services.webservice.services.IServicesLink">
80 <allow
81 interface="lazr.restful.interfaces.ITopLevelEntryLink"/>
82 <allow
83 interface="lp.services.webapp.interfaces.ICanonicalUrlData"/>
84 </securedutility>
8577
86</configure>78</configure>
8779
=== modified file 'lib/lp/app/interfaces/services.py'
--- lib/lp/app/interfaces/services.py 2012-02-28 04:24:19 +0000
+++ lib/lp/app/interfaces/services.py 2012-04-10 10:20:44 +0000
@@ -12,8 +12,15 @@
12 ]12 ]
1313
14from lazr.restful.declarations import (14from lazr.restful.declarations import (
15 collection_default_content,
16 export_as_webservice_collection,
15 export_as_webservice_entry,17 export_as_webservice_entry,
18 export_read_operation,
16 exported,19 exported,
20 operation_for_version,
21 operation_parameters,
22 operation_returns_collection_of,
23 operation_returns_entry,
17 )24 )
18from zope.interface import Interface25from zope.interface import Interface
19from zope.schema import TextLine26from zope.schema import TextLine
@@ -24,6 +31,9 @@
24class IService(Interface):31class IService(Interface):
25 """Base interface for services."""32 """Base interface for services."""
2633
34 export_as_webservice_entry(
35 'service', publish_web_link=False, as_of='beta')
36
27 name = exported(37 name = exported(
28 TextLine(38 TextLine(
29 title=_('Name'),39 title=_('Name'),
@@ -34,4 +44,18 @@
34class IServiceFactory(Interface):44class IServiceFactory(Interface):
35 """Interface representing a factory used to access named services."""45 """Interface representing a factory used to access named services."""
3646
37 export_as_webservice_entry(publish_web_link=False, as_of='beta')47 export_as_webservice_collection(IService)
48
49 @collection_default_content()
50 @operation_returns_collection_of(IService)
51 @export_read_operation()
52 @operation_for_version("beta")
53 def registeredServices():
54 """Return all the registered services."""
55
56 @operation_parameters(name=TextLine(required=True))
57 @operation_returns_entry(IService)
58 @export_read_operation()
59 @operation_for_version("beta")
60 def getByName(name):
61 """Lookup a service by name."""
3862
=== modified file 'lib/lp/app/services.py'
--- lib/lp/app/services.py 2012-02-23 10:13:48 +0000
+++ lib/lp/app/services.py 2012-04-10 10:20:44 +0000
@@ -8,7 +8,10 @@
8 'ServiceFactory',8 'ServiceFactory',
9 ]9 ]
1010
11from zope.component import getUtility11from zope.component import (
12 getAllUtilitiesRegisteredFor,
13 getUtility,
14 )
12from zope.interface import implements15from zope.interface import implements
1316
14from lp.app.interfaces.services import (17from lp.app.interfaces.services import (
@@ -19,9 +22,9 @@
1922
2023
21class ServiceFactory(Navigation):24class ServiceFactory(Navigation):
22 """Creates a named service.25 """Provides access to named services.
2326
24 Services are traversed via urls of the form /services/<name>27 Services are traversed via urls of the form /+services/<name>
25 Implementation classes are registered as named zope utilities.28 Implementation classes are registered as named zope utilities.
26 """29 """
2730
@@ -31,7 +34,10 @@
31 super(ServiceFactory, self).__init__(None)34 super(ServiceFactory, self).__init__(None)
3235
33 def traverse(self, name):36 def traverse(self, name):
34 return self.getService(name)37 return self.getByName(name)
3538
36 def getService(self, service_name):39 def getByName(self, name):
37 return getUtility(IService, service_name)40 return getUtility(IService, name)
41
42 def registeredServices(self):
43 return getAllUtilitiesRegisteredFor(IService)
3844
=== modified file 'lib/lp/app/tests/test_services.py'
--- lib/lp/app/tests/test_services.py 2012-02-28 04:24:19 +0000
+++ lib/lp/app/tests/test_services.py 2012-04-10 10:20:44 +0000
@@ -43,5 +43,12 @@
43 self.registerUtility(fake_service, IService, "fake")43 self.registerUtility(fake_service, IService, "fake")
44 context, view, request = test_traverse(44 context, view, request = test_traverse(
45 'https://launchpad.dev/api/devel/+services/fake')45 'https://launchpad.dev/api/devel/+services/fake')
46 self.assertEqual(getUtility(IServiceFactory), context)46 self.assertEqual(getUtility(IService, "fake"), context)
47 self.assertEqual(fake_service, view)47
48 def test_registeredServices(self):
49 # Test the ServiceFactory registeredServices method.
50 login(ANONYMOUS)
51 service_factory = getUtility(IServiceFactory)
52 self.assertEqual(
53 [service_factory.getByName('sharing')],
54 service_factory.registeredServices())
4855
=== modified file 'lib/lp/registry/interfaces/webservice.py'
--- lib/lp/registry/interfaces/webservice.py 2012-03-22 23:21:24 +0000
+++ lib/lp/registry/interfaces/webservice.py 2012-04-10 10:20:44 +0000
@@ -29,6 +29,7 @@
29 'IProductSet',29 'IProductSet',
30 'IProjectGroup',30 'IProjectGroup',
31 'IProjectGroupSet',31 'IProjectGroupSet',
32 'IService',
32 'IServiceFactory',33 'IServiceFactory',
33 'ISharingService',34 'ISharingService',
34 'ISSHKey',35 'ISSHKey',
@@ -43,7 +44,10 @@
43# XXX: JonathanLange 2010-11-09 bug=673083: Legacy work-around for circular44# XXX: JonathanLange 2010-11-09 bug=673083: Legacy work-around for circular
44# import bugs. Break this up into a per-package thing.45# import bugs. Break this up into a per-package thing.
45from lp import _schema_circular_imports46from lp import _schema_circular_imports
46from lp.app.interfaces.services import IServiceFactory47from lp.app.interfaces.services import (
48 IService,
49 IServiceFactory,
50 )
47from lp.registry.interfaces.commercialsubscription import (51from lp.registry.interfaces.commercialsubscription import (
48 ICommercialSubscription,52 ICommercialSubscription,
49 )53 )
5054
=== modified file 'lib/lp/registry/services/tests/test_sharingservice.py'
--- lib/lp/registry/services/tests/test_sharingservice.py 2012-04-06 17:28:25 +0000
+++ lib/lp/registry/services/tests/test_sharingservice.py 2012-04-10 10:20:44 +0000
@@ -758,10 +758,7 @@
758 def setUp(self):758 def setUp(self):
759 super(TestLaunchpadlib, self).setUp()759 super(TestLaunchpadlib, self).setUp()
760 self.launchpad = self.factory.makeLaunchpadService(person=self.owner)760 self.launchpad = self.factory.makeLaunchpadService(person=self.owner)
761 # XXX 2012-02-23 wallyworld bug 681767761 self.service = self.launchpad.services['sharing']
762 # Launchpadlib can't do relative url's
763 self.service = self.launchpad.load(
764 '%s/+services/sharing' % self.launchpad._root_uri)
765 flag = FeatureFixture(WRITE_FLAG)762 flag = FeatureFixture(WRITE_FLAG)
766 flag.setUp()763 flag.setUp()
767 self.addCleanup(flag.cleanUp)764 self.addCleanup(flag.cleanUp)
768765
=== removed file 'lib/lp/services/webservice/services.py'
--- lib/lp/services/webservice/services.py 2012-02-23 10:13:48 +0000
+++ lib/lp/services/webservice/services.py 1970-01-01 00:00:00 +0000
@@ -1,32 +0,0 @@
1# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""A class for the top-level link to the services factory."""
5
6__metaclass__ = type
7__all__ = [
8 'IServicesLink',
9 'ServicesLink',
10 ]
11
12from lazr.restful.interfaces import ITopLevelEntryLink
13from zope.interface import implements
14
15from lp.app.interfaces.services import IServiceFactory
16from lp.services.webapp.interfaces import ICanonicalUrlData
17
18
19class IServicesLink(ITopLevelEntryLink, ICanonicalUrlData):
20 """A marker interface."""
21
22
23class ServicesLink:
24 """The top-level link to the services factory."""
25 implements(IServicesLink)
26
27 link_name = 'services'
28 entry_type = IServiceFactory
29
30 inside = None
31 path = 'services'
32 rootsite = 'api'
330
=== modified file 'versions.cfg'
--- versions.cfg 2012-04-06 17:28:25 +0000
+++ versions.cfg 2012-04-10 10:20:44 +0000
@@ -35,7 +35,7 @@
35Jinja2 = 2.235Jinja2 = 2.2
36keyring = 0.6.236keyring = 0.6.2
37kombu = 2.1.137kombu = 2.1.1
38launchpadlib = 1.9.1238launchpadlib = 1.9.13
39lazr.amqp = 0.139lazr.amqp = 0.1
40lazr.authentication = 0.1.140lazr.authentication = 0.1.1
41lazr.batchnavigator = 1.2.1041lazr.batchnavigator = 1.2.10