Merge lp:~leonardr/launchpadlib/delay-http-requests into lp:launchpadlib

Proposed by Leonard Richardson
Status: Merged
Merged at revision: 89
Proposed branch: lp:~leonardr/launchpadlib/delay-http-requests
Merge into: lp:launchpadlib
Diff against target: 198 lines (+94/-19)
5 files modified
setup.py (+1/-1)
src/launchpadlib/NEWS.txt (+6/-0)
src/launchpadlib/__init__.py (+1/-1)
src/launchpadlib/docs/toplevel.txt (+54/-14)
src/launchpadlib/launchpad.py (+32/-3)
To merge this branch: bzr merge lp:~leonardr/launchpadlib/delay-http-requests
Reviewer Review Type Date Requested Status
Henning Eggers (community) code Approve
Review via email: mp+27759@code.launchpad.net

Description of the change

This branch makes launchpadlib use the new performance optimization introduced by https://code.edge.launchpad.net/~leonardr/lazr.restfulclient/shim-objects/. Basically, if you write launchpad.bugs[1] we can now delay the GET to "/bugs/1" until you actually need some data from that bug. If you're invoking a named operation on the bug, the GET doesn't need to happen at all.

Since it's pretty common for scripts to look up an object in a top-level collection and immediately invoke a named operation on it, this has a good chance of giving a modest performance boost to any given script.

The one top-level collection that doesn't have this feature is the collection of users. Without making that GET request, there's no way to know whether launchpad.user['foo'] is a 'person' or a 'team' type object, so I punted.

To post a comment you must log in.
Revision history for this message
Henning Eggers (henninge) wrote :

Thanks!

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'setup.py'
2--- setup.py 2010-02-15 16:34:26 +0000
3+++ setup.py 2010-06-16 19:58:22 +0000
4@@ -60,7 +60,7 @@
5 license='LGPL v3',
6 install_requires=[
7 'httplib2',
8- 'lazr.restfulclient>=0.9.11',
9+ 'lazr.restfulclient>=0.9.18',
10 'lazr.uri',
11 'oauth',
12 'setuptools',
13
14=== modified file 'src/launchpadlib/NEWS.txt'
15--- src/launchpadlib/NEWS.txt 2010-04-06 19:54:35 +0000
16+++ src/launchpadlib/NEWS.txt 2010-06-16 19:58:22 +0000
17@@ -2,6 +2,12 @@
18 NEWS for launchpadlib
19 =====================
20
21+1.6.1 (2010-06-16)
22+==================
23+
24+- Added an optimization that lets launchpadlib avoid making an HTTP
25+ request in some situations.
26+
27 1.6.0 (2010-04-07)
28 ==================
29
30
31=== modified file 'src/launchpadlib/__init__.py'
32--- src/launchpadlib/__init__.py 2010-04-06 19:54:35 +0000
33+++ src/launchpadlib/__init__.py 2010-06-16 19:58:22 +0000
34@@ -14,4 +14,4 @@
35 # You should have received a copy of the GNU Lesser General Public License
36 # along with launchpadlib. If not, see <http://www.gnu.org/licenses/>.
37
38-__version__ = '1.6.0'
39+__version__ = '1.6.1'
40
41=== modified file 'src/launchpadlib/docs/toplevel.txt'
42--- src/launchpadlib/docs/toplevel.txt 2009-04-16 19:30:01 +0000
43+++ src/launchpadlib/docs/toplevel.txt 2010-06-16 19:58:22 +0000
44@@ -1,31 +1,71 @@
45 The launchpad web service's top-level collections provide access to
46 Launchpad-wide objects like projects and people.
47
48+ >>> import httplib2
49+ >>> httplib2.debuglevel = 1
50+
51 >>> from launchpadlib.testing.helpers import salgado_with_full_permissions
52 >>> launchpad = salgado_with_full_permissions.login()
53+ connect: ...
54+ ...
55
56 It's possible to do key-based lookups on the top-level
57 collections. The bug collection does lookups by bug ID.
58
59- >>> launchpad.bugs[1].id
60+ >>> bug = launchpad.bugs[1]
61+
62+For most top-level collections, simply looking up an object will not
63+trigger an HTTP request. The HTTP request happens when you try to
64+access one of the object's properties.
65+
66+ >>> print bug.id
67+ send: 'GET /.../bugs/1 ...'
68+ ...
69 1
70
71-The person collection does lookups by a person's Launchpad name.
72-
73- >>> launchpad.people['salgado'].name
74- u'salgado'
75-
76-The project collection does lookups by project name.
77-
78- >>> launchpad.projects['firefox'].name
79- u'firefox'
80+Let's look at some more collections. The project collection does
81+lookups by project name.
82+
83+ >>> project = launchpad.projects['firefox']
84+ >>> print project.name
85+ send: 'GET /.../firefox ...'
86+ ...
87+ firefox
88
89 The project group collection does lookups by project group name.
90
91- >>> launchpad.project_groups['firefox'].name
92- u'firefox'
93+ >>> group = launchpad.project_groups['gnome']
94+ >>> print group.name
95+ send: 'GET /.../gnome ...'
96+ ...
97+ gnome
98
99 The distribution collection does lookups by distribution name.
100
101- >>> launchpad.distributions['ubuntu'].name
102- u'ubuntu'
103+ >>> distribution = launchpad.distributions['ubuntu']
104+ >>> print distribution.name
105+ send: 'GET /.../ubuntu ...'
106+ ...
107+ ubuntu
108+
109+The person collection does lookups by a person's Launchpad
110+name. Looking up a person from the top-level collection of people
111+*does* trigger an HTTP request, since there's no other way to tell
112+whether a given person should be represented by a 'person' object or a
113+'team' object.
114+
115+ >>> person = launchpad.people['salgado']
116+ send: 'GET /.../~salgado ...'
117+ ...
118+ >>> print person.name
119+ salgado
120+
121+ >>> team = launchpad.people['rosetta-admins']
122+ send: 'GET /1.0/~rosetta-admins ...'
123+ ...
124+ >>> print team.name
125+ rosetta-admins
126+
127+Cleanup.
128+
129+ >>> httplib2.debuglevel = None
130
131=== modified file 'src/launchpadlib/launchpad.py'
132--- src/launchpadlib/launchpad.py 2010-03-24 16:09:40 +0000
133+++ src/launchpadlib/launchpad.py 2010-06-16 19:58:22 +0000
134@@ -47,6 +47,11 @@
135 """Transform a username into the URL to a person resource."""
136 return str(self._root._root_uri.ensureSlash()) + '~' + str(key)
137
138+ # The only way to determine whether a string corresponds to a
139+ # person or a team object is to ask the server, so looking up an
140+ # entry from the PersonSet always requires making an HTTP request.
141+ collection_of = None
142+
143
144 class BugSet(CollectionWithKeyBasedLookup):
145 """A custom subclass capable of bug lookup by bug ID."""
146@@ -55,6 +60,8 @@
147 """Transform a bug ID into the URL to a bug resource."""
148 return str(self._root._root_uri.ensureSlash()) + 'bugs/' + str(key)
149
150+ collection_of = 'bug'
151+
152
153 class PillarSet(CollectionWithKeyBasedLookup):
154 """A custom subclass capable of lookup by pillar name.
155@@ -66,6 +73,28 @@
156 """Transform a project name into the URL to a project resource."""
157 return str(self._root._root_uri.ensureSlash()) + str(key)
158
159+ # The subclasses for projects, project groups, and distributions
160+ # all define this property differently.
161+ collection_of = None
162+
163+
164+class ProjectSet(PillarSet):
165+ """A custom subclass for accessing the collection of projects."""
166+
167+ collection_of = 'project'
168+
169+
170+class ProjectGroupSet(PillarSet):
171+ """A custom subclass for accessing the collection of project groups."""
172+
173+ collection_of = 'project_group'
174+
175+
176+class DistributionSet(PillarSet):
177+ """A custom subclass for accessing the collection of project groups."""
178+
179+ collection_of = 'distribution'
180+
181
182 class Launchpad(ServiceRoot):
183 """Root Launchpad API class.
184@@ -78,11 +107,11 @@
185
186 RESOURCE_TYPE_CLASSES = {
187 'bugs': BugSet,
188- 'distributions': PillarSet,
189+ 'distributions': DistributionSet,
190 'HostedFile': HostedFile,
191 'people': PersonSet,
192- 'project_groups': PillarSet,
193- 'projects': PillarSet,
194+ 'project_groups': ProjectGroupSet,
195+ 'projects': ProjectSet,
196 }
197
198 def __init__(self, credentials, service_root=uris.STAGING_SERVICE_ROOT,

Subscribers

People subscribed via source and target branches