Merge lp:~leonardr/lazr.restful/active-versions into lp:lazr.restful
- active-versions
- Merge into trunk
Proposed by
Leonard Richardson
Status: | Merged |
---|---|
Approved by: | Aaron Bentley |
Approved revision: | not available |
Merged at revision: | not available |
Proposed branch: | lp:~leonardr/lazr.restful/active-versions |
Merge into: | lp:lazr.restful |
Diff against target: |
583 lines (+287/-62) 18 files modified
src/lazr/restful/NEWS.txt (+10/-0) src/lazr/restful/docs/absoluteurl.txt (+7/-7) src/lazr/restful/docs/django.txt (+2/-2) src/lazr/restful/docs/webservice-declarations.txt (+1/-1) src/lazr/restful/docs/webservice-request.txt (+1/-1) src/lazr/restful/docs/webservice.txt (+1/-1) src/lazr/restful/example/base/root.py (+1/-1) src/lazr/restful/example/base/tests/service.txt (+12/-31) src/lazr/restful/example/multiversion/README.txt (+6/-0) src/lazr/restful/example/multiversion/resources.py (+35/-0) src/lazr/restful/example/multiversion/root.py (+53/-0) src/lazr/restful/example/multiversion/site.zcml (+13/-0) src/lazr/restful/example/multiversion/tests/introduction.txt (+64/-0) src/lazr/restful/example/multiversion/tests/test_integration.py (+53/-0) src/lazr/restful/example/wsgi/root.py (+1/-1) src/lazr/restful/interfaces/_rest.py (+14/-10) src/lazr/restful/publisher.py (+12/-6) src/lazr/restful/testing/webservice.py (+1/-1) |
To merge this branch: | bzr merge lp:~leonardr/lazr.restful/active-versions |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Aaron Bentley (community) | code | Approve | |
Review via email: mp+14912@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Leonard Richardson (leonardr) wrote : | # |
Revision history for this message
Aaron Bentley (abentley) wrote : | # |
Looks fine.
review:
Approve
(code)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/lazr/restful/NEWS.txt' |
2 | --- src/lazr/restful/NEWS.txt 2009-11-12 16:30:50 +0000 |
3 | +++ src/lazr/restful/NEWS.txt 2009-11-16 15:00:27 +0000 |
4 | @@ -5,6 +5,10 @@ |
5 | Development |
6 | =========== |
7 | |
8 | +Special note: this version contains backwards-incompatible |
9 | +changes. You *must* change your configuration object to get your code |
10 | +to work in this version! See "active_versions" below. |
11 | + |
12 | Added the precursor of a versioning system for web services. Clients |
13 | can now request the "trunk" of a web service as well as one published |
14 | version. Apart from the URIs served, the two web services are exactly |
15 | @@ -16,6 +20,12 @@ |
16 | BaseWebServiceConfiguration or one of its subclasses, you'll need to |
17 | set a value for this. |
18 | |
19 | +This release _replaces_ one of the fields in |
20 | +IWebServiceConfiguration. The string service_version_uri_prefix has |
21 | +become the list active_versions. The simplest way to deal with this is |
22 | +to just put your service_version_uri_prefix into a list and call it |
23 | +active_versions. |
24 | + |
25 | 0.9.17 (2009-11-10) |
26 | =================== |
27 | |
28 | |
29 | === modified file 'src/lazr/restful/docs/absoluteurl.txt' |
30 | --- src/lazr/restful/docs/absoluteurl.txt 2009-11-12 17:03:06 +0000 |
31 | +++ src/lazr/restful/docs/absoluteurl.txt 2009-11-16 15:00:27 +0000 |
32 | @@ -29,7 +29,7 @@ |
33 | ... implements(IWebServiceConfiguration) |
34 | ... hostname = "hostname" |
35 | ... service_root_uri_prefix = "root_uri_prefix/" |
36 | - ... service_version_uri_prefix = "service_version_uri_prefix" |
37 | + ... active_versions = ['active_version'] |
38 | ... latest_version_uri_prefix = "latest_version_uri_prefix" |
39 | ... port = 1000 |
40 | ... use_https = True |
41 | @@ -50,20 +50,20 @@ |
42 | >>> resource = RootResource() |
43 | >>> request = Request("", {}) |
44 | >>> request.annotations[request.VERSION_ANNOTATION] = ( |
45 | - ... 'service_version_uri_prefix') |
46 | + ... 'active_version') |
47 | >>> adapter = getMultiAdapter((resource, request), IAbsoluteURL) |
48 | |
49 | Calling the RootResourceAbsoluteURL will give the service root's |
50 | absolute URL. |
51 | |
52 | >>> print adapter() |
53 | - https://hostname:1000/root_uri_prefix/service_version_uri_prefix/ |
54 | + https://hostname:1000/root_uri_prefix/active_version/ |
55 | |
56 | Converting the adapter to a string will give the same result, but |
57 | without the trailing slash. |
58 | |
59 | >>> print str(adapter) |
60 | - https://hostname:1000/root_uri_prefix/service_version_uri_prefix |
61 | + https://hostname:1000/root_uri_prefix/active_version |
62 | |
63 | (This is useful for the recursive case. When finding the URL to a |
64 | subordinate resource, Zope's AbsoluteURL implementation calls str() on |
65 | @@ -75,11 +75,11 @@ |
66 | |
67 | >>> configuration.use_https = False |
68 | >>> print getMultiAdapter((resource, request), IAbsoluteURL)() |
69 | - http://hostname:1000/root_uri_prefix/service_version_uri_prefix/ |
70 | + http://hostname:1000/root_uri_prefix/active_version/ |
71 | |
72 | >>> configuration.port = None |
73 | >>> print getMultiAdapter((resource, request), IAbsoluteURL)() |
74 | - http://hostname/root_uri_prefix/service_version_uri_prefix/ |
75 | + http://hostname/root_uri_prefix/active_version/ |
76 | |
77 | The URL generated includes a version identifier taken from the |
78 | value of the 'lazr.restful.version' annotation. |
79 | @@ -106,7 +106,7 @@ |
80 | Cleanup. |
81 | |
82 | >>> request.annotations[request.VERSION_ANNOTATION] = ( |
83 | - ... 'service_version_uri_prefix') |
84 | + ... 'active_version') |
85 | |
86 | |
87 | MultiplePathPartAbsoluteURL |
88 | |
89 | === modified file 'src/lazr/restful/docs/django.txt' |
90 | --- src/lazr/restful/docs/django.txt 2009-09-08 13:33:01 +0000 |
91 | +++ src/lazr/restful/docs/django.txt 2009-11-16 15:00:27 +0000 |
92 | @@ -110,8 +110,8 @@ |
93 | Attributes that don't have values in settings.py are given their |
94 | default value. |
95 | |
96 | - >>> utility.service_version_uri_prefix |
97 | - u'' |
98 | + >>> utility.active_versions |
99 | + [] |
100 | >>> utility.use_https |
101 | True |
102 | |
103 | |
104 | === modified file 'src/lazr/restful/docs/webservice-declarations.txt' |
105 | --- src/lazr/restful/docs/webservice-declarations.txt 2009-06-08 20:03:55 +0000 |
106 | +++ src/lazr/restful/docs/webservice-declarations.txt 2009-11-16 15:00:27 +0000 |
107 | @@ -953,7 +953,7 @@ |
108 | >>> class MyWebServiceConfiguration: |
109 | ... implements(IWebServiceConfiguration) |
110 | ... view_permission = "lazr.View" |
111 | - ... service_version_uri_prefix = "beta" |
112 | + ... active_versions = ["beta"] |
113 | ... code_revision = "1.0b" |
114 | ... default_batch_size = 50 |
115 | ... |
116 | |
117 | === modified file 'src/lazr/restful/docs/webservice-request.txt' |
118 | --- src/lazr/restful/docs/webservice-request.txt 2009-08-11 18:36:20 +0000 |
119 | +++ src/lazr/restful/docs/webservice-request.txt 2009-11-16 15:00:27 +0000 |
120 | @@ -22,7 +22,7 @@ |
121 | >>> class SimpleWebServiceConfiguration: |
122 | ... implements(IWebServiceConfiguration) |
123 | ... path_override = 'api' |
124 | - ... service_version_uri_prefix = 'beta' |
125 | + ... active_versions = ['beta'] |
126 | ... |
127 | ... def createRequest(self, body_stream, environ): |
128 | ... request = Request(body_stream, environ) |
129 | |
130 | === modified file 'src/lazr/restful/docs/webservice.txt' |
131 | --- src/lazr/restful/docs/webservice.txt 2009-11-12 16:30:50 +0000 |
132 | +++ src/lazr/restful/docs/webservice.txt 2009-11-16 15:00:27 +0000 |
133 | @@ -517,7 +517,7 @@ |
134 | |
135 | >>> class WebServiceConfiguration(BaseWebServiceConfiguration): |
136 | ... use_https = False |
137 | - ... service_version_uri_prefix = 'beta' |
138 | + ... active_versions = ['beta'] |
139 | ... latest_version_uri_prefix = 'devel' |
140 | ... code_revision = 'test' |
141 | ... max_batch_size = 100 |
142 | |
143 | === modified file 'src/lazr/restful/example/base/root.py' |
144 | --- src/lazr/restful/example/base/root.py 2009-11-12 16:43:57 +0000 |
145 | +++ src/lazr/restful/example/base/root.py 2009-11-16 15:00:27 +0000 |
146 | @@ -387,7 +387,7 @@ |
147 | default_batch_size=5 |
148 | hostname='cookbooks.dev' |
149 | match_batch_size=50 |
150 | - service_version_uri_prefix='1.0' |
151 | + active_versions=['1.0'] |
152 | use_https=False |
153 | view_permission='lazr.restful.example.base.View' |
154 | |
155 | |
156 | === modified file 'src/lazr/restful/example/base/tests/service.txt' |
157 | --- src/lazr/restful/example/base/tests/service.txt 2009-11-12 16:35:38 +0000 |
158 | +++ src/lazr/restful/example/base/tests/service.txt 2009-11-16 15:00:27 +0000 |
159 | @@ -10,37 +10,18 @@ |
160 | Versioning |
161 | ========== |
162 | |
163 | -In addition to the published version of the web service, lazr.restful |
164 | -publishes a "development" version which may contain backwards |
165 | -incompatible changes. The default name of the development version is |
166 | -"devel". |
167 | - |
168 | - >>> body = webservice.get('/', api_version="devel").jsonBody() |
169 | - |
170 | -The development version serves URLs that reflect its version name. |
171 | - |
172 | - >>> print body['recipes_collection_link'] |
173 | - http://cookbooks.dev/devel/recipes |
174 | - >>> print body['resource_type_link'] |
175 | - http://cookbooks.dev/devel/#service-root |
176 | - |
177 | -Currently there is no way to publish multiple versions of the web |
178 | -service, so apart from the URLs, the development version is exactly |
179 | -the same as the only published version. |
180 | - |
181 | -All versions of the web service can be accessed through Ajax. |
182 | - |
183 | - >>> from lazr.restful.testing.webservice import WebServiceAjaxCaller |
184 | - >>> ajax = WebServiceAjaxCaller(domain='cookbooks.dev') |
185 | - >>> body = ajax.get('/', api_version="devel").jsonBody() |
186 | - >>> print body['resource_type_link'] |
187 | - http://cookbooks.dev/devel/#service-root |
188 | - |
189 | -An attempt to access a nonexistent version yields a 404 error. |
190 | - |
191 | - >>> print webservice.get('/', api_version="no_such_version") |
192 | - HTTP/1.1 404 Not Found |
193 | - ... |
194 | +lazr.restful allows you to publish multiple named versions of a web |
195 | +service, as well as a "development" version which includes changes you |
196 | +have yet to batch together into a named version. The default name of |
197 | +the development version is "devel". |
198 | + |
199 | + >>> top_level_response = webservice.get( |
200 | + ... "/", api_version="devel").jsonBody() |
201 | + >>> print top_level_response['resource_type_link'] |
202 | + http://cookbooks.dev/devel/#service-root |
203 | + |
204 | +The web service in examples/multiversion is devoted solely to testing |
205 | +the versioning code. |
206 | |
207 | Nonexistent resources |
208 | ===================== |
209 | |
210 | === added directory 'src/lazr/restful/example/multiversion' |
211 | === added file 'src/lazr/restful/example/multiversion/README.txt' |
212 | --- src/lazr/restful/example/multiversion/README.txt 1970-01-01 00:00:00 +0000 |
213 | +++ src/lazr/restful/example/multiversion/README.txt 2009-11-16 15:00:27 +0000 |
214 | @@ -0,0 +1,6 @@ |
215 | +Multiversion web service |
216 | +************************ |
217 | + |
218 | +This web service demonstrates lazr.restful's ability to serve multiple |
219 | +backwards-incompatible versions of a web service from the same |
220 | +underlying code. |
221 | |
222 | === added file 'src/lazr/restful/example/multiversion/__init__.py' |
223 | === added file 'src/lazr/restful/example/multiversion/resources.py' |
224 | --- src/lazr/restful/example/multiversion/resources.py 1970-01-01 00:00:00 +0000 |
225 | +++ src/lazr/restful/example/multiversion/resources.py 2009-11-16 15:00:27 +0000 |
226 | @@ -0,0 +1,35 @@ |
227 | +__metaclass__ = type |
228 | + |
229 | +__all__ = ['IKeyValuePair', |
230 | + 'IPairSet', |
231 | + 'KeyValuePair', |
232 | + 'PairSet'] |
233 | + |
234 | +from zope.schema import Text |
235 | +from zope.location.interfaces import ILocation |
236 | + |
237 | +from lazr.restful.declarations import ( |
238 | + collection_default_content, export_as_webservice_collection, |
239 | + export_as_webservice_entry, exported) |
240 | + |
241 | +# We don't need separate implementations of these classes, so borrow |
242 | +# the implementations from the WSGI example. |
243 | +from lazr.restful.example.wsgi.resources import PairSet, KeyValuePair |
244 | + |
245 | +# Our interfaces _will_ diverge from the WSGI example interfaces, so |
246 | +# define them separately. |
247 | +class IKeyValuePair(ILocation): |
248 | + export_as_webservice_entry() |
249 | + key = exported(Text(title=u"The key")) |
250 | + value = exported(Text(title=u"The value")) |
251 | + |
252 | + |
253 | +class IPairSet(ILocation): |
254 | + export_as_webservice_collection(IKeyValuePair) |
255 | + |
256 | + @collection_default_content() |
257 | + def getPairs(): |
258 | + """Return the key-value pairs.""" |
259 | + |
260 | + def get(request, name): |
261 | + """Retrieve a key-value pair by its key.""" |
262 | |
263 | === added file 'src/lazr/restful/example/multiversion/root.py' |
264 | --- src/lazr/restful/example/multiversion/root.py 1970-01-01 00:00:00 +0000 |
265 | +++ src/lazr/restful/example/multiversion/root.py 2009-11-16 15:00:27 +0000 |
266 | @@ -0,0 +1,53 @@ |
267 | +"""The RESTful service root.""" |
268 | + |
269 | +__metaclass__ = type |
270 | +__all__ = [ |
271 | + 'BelowRootAbsoluteURL', |
272 | + 'RootAbsoluteURL', |
273 | + 'WebServiceConfiguration', |
274 | + 'MultiversionWebServiceRootResource', |
275 | + ] |
276 | + |
277 | +from zope.traversing.browser import AbsoluteURL |
278 | + |
279 | +from lazr.restful.wsgi import BaseWSGIWebServiceConfiguration |
280 | +from lazr.restful.simple import RootResource, RootResourceAbsoluteURL |
281 | +from lazr.restful.example.multiversion.resources import ( |
282 | + IKeyValuePair, PairSet, KeyValuePair) |
283 | + |
284 | + |
285 | +class RootAbsoluteURL(RootResourceAbsoluteURL): |
286 | + """A technique for generating the service's root URL. |
287 | + |
288 | + This class contains no code of its own. It's defined so that |
289 | + grok will pick it up. |
290 | + """ |
291 | + |
292 | + |
293 | +class BelowRootAbsoluteURL(AbsoluteURL): |
294 | + """A technique for generating a root URL given an ILocation. |
295 | + |
296 | + This class contains no code of its own. It's defined so that |
297 | + grok will pick it up. |
298 | + """ |
299 | + |
300 | + |
301 | +class WebServiceConfiguration(BaseWSGIWebServiceConfiguration): |
302 | + code_revision = '1' |
303 | + active_versions = ['beta', '1.0', '2.0'] |
304 | + latest_version_uri_prefix = 'trunk' |
305 | + use_https = False |
306 | + view_permission = 'zope.Public' |
307 | + |
308 | + |
309 | +class MultiversionWebServiceRootResource(RootResource): |
310 | + """The root resource for the WSGI example web service.""" |
311 | + def _build_top_level_objects(self): |
312 | + pairset = PairSet() |
313 | + pairset.pairs = [ |
314 | + KeyValuePair(self, "foo", "bar"), |
315 | + KeyValuePair(self, "1", "2") |
316 | + ] |
317 | + collections = dict(pairs=(IKeyValuePair, pairset)) |
318 | + return collections, {} |
319 | + |
320 | |
321 | === added file 'src/lazr/restful/example/multiversion/site.zcml' |
322 | --- src/lazr/restful/example/multiversion/site.zcml 1970-01-01 00:00:00 +0000 |
323 | +++ src/lazr/restful/example/multiversion/site.zcml 2009-11-16 15:00:27 +0000 |
324 | @@ -0,0 +1,13 @@ |
325 | +<configure |
326 | + xmlns="http://namespaces.zope.org/zope" |
327 | + xmlns:webservice="http://namespaces.canonical.com/webservice" |
328 | + xmlns:grok="http://namespaces.zope.org/grok"> |
329 | + |
330 | + <include package="lazr.restful" file="basic-site.zcml" /> |
331 | + <webservice:register |
332 | + module="lazr.restful.example.multiversion.resources" /> |
333 | + <grok:grok package="lazr.restful.example.multiversion" /> |
334 | + |
335 | + <securityPolicy |
336 | + component="zope.security.simplepolicies.PermissiveSecurityPolicy" /> |
337 | +</configure> |
338 | |
339 | === added directory 'src/lazr/restful/example/multiversion/tests' |
340 | === added file 'src/lazr/restful/example/multiversion/tests/__init__.py' |
341 | === added file 'src/lazr/restful/example/multiversion/tests/introduction.txt' |
342 | --- src/lazr/restful/example/multiversion/tests/introduction.txt 1970-01-01 00:00:00 +0000 |
343 | +++ src/lazr/restful/example/multiversion/tests/introduction.txt 2009-11-16 15:00:27 +0000 |
344 | @@ -0,0 +1,64 @@ |
345 | +Multi-version web services |
346 | +************************** |
347 | + |
348 | +lazr.restful lets you publish two or more mutually incompatible |
349 | +web services from the same underlying code. This lets you improve your |
350 | +web service to take advantage of new features of lazr.restful, without |
351 | +sacrificing backwards compatibility. |
352 | + |
353 | +The web service in example/multiversion illustrates the multiversion |
354 | +features of lazr.restful. |
355 | + |
356 | + >>> from lazr.restful.testing.webservice import WebServiceCaller |
357 | + >>> webservice = WebServiceCaller(domain='multiversion.dev') |
358 | + |
359 | +The multiversion web service serves three named versions of the same |
360 | +web service: "beta", "1.0", and "2.0". Once you make a request to the |
361 | +service root of a particular version, the web service only serves you |
362 | +links within that version. |
363 | + |
364 | + >>> top_level_response = webservice.get( |
365 | + ... "/", api_version="beta").jsonBody() |
366 | + >>> print top_level_response['key_value_pairs_collection_link'] |
367 | + http://multiversion.dev/beta/pairs |
368 | + |
369 | + >>> top_level_response = webservice.get( |
370 | + ... "/", api_version="1.0").jsonBody() |
371 | + >>> print top_level_response['key_value_pairs_collection_link'] |
372 | + http://multiversion.dev/1.0/pairs |
373 | + |
374 | + >>> top_level_response = webservice.get( |
375 | + ... "/", api_version="2.0").jsonBody() |
376 | + >>> print top_level_response['key_value_pairs_collection_link'] |
377 | + http://multiversion.dev/2.0/pairs |
378 | + |
379 | +Like all web services, the multiversion service also serves a |
380 | +development version which tracks the current state of the web service, |
381 | +including all changes that have not yet been folded into a named |
382 | +version. The default name for the development version is "devel" (see |
383 | +example/base/tests/service.txt), but in this web service it's called |
384 | +"trunk". |
385 | + |
386 | + >>> top_level_response = webservice.get( |
387 | + ... "/", api_version="trunk").jsonBody() |
388 | + >>> print top_level_response['key_value_pairs_collection_link'] |
389 | + http://multiversion.dev/trunk/pairs |
390 | + |
391 | +All versions of the web service can be accessed through Ajax. |
392 | + |
393 | + >>> from lazr.restful.testing.webservice import WebServiceAjaxCaller |
394 | + >>> ajax = WebServiceAjaxCaller(domain='multiversion.dev') |
395 | + |
396 | + >>> body = ajax.get('/', api_version="1.0").jsonBody() |
397 | + >>> print body['resource_type_link'] |
398 | + http://multiversion.dev/1.0/#service-root |
399 | + |
400 | + >>> body = ajax.get('/', api_version="trunk").jsonBody() |
401 | + >>> print body['resource_type_link'] |
402 | + http://multiversion.dev/trunk/#service-root |
403 | + |
404 | +An attempt to access a nonexistent version yields a 404 error. |
405 | + |
406 | + >>> print webservice.get('/', api_version="no_such_version") |
407 | + HTTP/1.1 404 Not Found |
408 | + ... |
409 | |
410 | === added file 'src/lazr/restful/example/multiversion/tests/test_integration.py' |
411 | --- src/lazr/restful/example/multiversion/tests/test_integration.py 1970-01-01 00:00:00 +0000 |
412 | +++ src/lazr/restful/example/multiversion/tests/test_integration.py 2009-11-16 15:00:27 +0000 |
413 | @@ -0,0 +1,53 @@ |
414 | +# Copyright 2008 Canonical Ltd. All rights reserved. |
415 | + |
416 | +"""Test harness for doctests for lazr.restful multiversion example service.""" |
417 | + |
418 | +__metaclass__ = type |
419 | +__all__ = [] |
420 | + |
421 | +import os |
422 | +import doctest |
423 | +from pkg_resources import resource_filename |
424 | + |
425 | +from zope.component import getUtility |
426 | +from van.testing.layer import zcml_layer, wsgi_intercept_layer |
427 | + |
428 | +from lazr.restful.example.multiversion.root import ( |
429 | + MultiversionWebServiceRootResource) |
430 | +from lazr.restful.interfaces import IWebServiceConfiguration |
431 | +from lazr.restful.simple import Publication |
432 | +from lazr.restful.testing.webservice import WebServiceApplication |
433 | + |
434 | + |
435 | +DOCTEST_FLAGS = ( |
436 | + doctest.ELLIPSIS | |
437 | + doctest.NORMALIZE_WHITESPACE | |
438 | + doctest.REPORT_NDIFF) |
439 | + |
440 | + |
441 | +class FunctionalLayer: |
442 | + zcml = os.path.abspath(resource_filename( |
443 | + 'lazr.restful.example.multiversion', 'site.zcml')) |
444 | +zcml_layer(FunctionalLayer) |
445 | + |
446 | + |
447 | +class WSGILayer(FunctionalLayer): |
448 | + |
449 | + @classmethod |
450 | + def make_application(self): |
451 | + getUtility(IWebServiceConfiguration).hostname = "multiversion.dev" |
452 | + getUtility(IWebServiceConfiguration).port = None |
453 | + root = MultiversionWebServiceRootResource() |
454 | + return WebServiceApplication(root, Publication) |
455 | +wsgi_intercept_layer(WSGILayer) |
456 | + |
457 | + |
458 | +def additional_tests(): |
459 | + """See `zope.testing.testrunner`.""" |
460 | + tests = sorted( |
461 | + [name |
462 | + for name in os.listdir(os.path.dirname(__file__)) |
463 | + if name.endswith('.txt')]) |
464 | + suite = doctest.DocFileSuite(optionflags=DOCTEST_FLAGS, *tests) |
465 | + suite.layer = WSGILayer |
466 | + return suite |
467 | |
468 | === modified file 'src/lazr/restful/example/wsgi/root.py' |
469 | --- src/lazr/restful/example/wsgi/root.py 2009-11-12 16:43:57 +0000 |
470 | +++ src/lazr/restful/example/wsgi/root.py 2009-11-16 15:00:27 +0000 |
471 | @@ -34,7 +34,7 @@ |
472 | |
473 | class WebServiceConfiguration(BaseWSGIWebServiceConfiguration): |
474 | code_revision = '1' |
475 | - service_version_uri_prefix = '1.0' |
476 | + active_versions = ['1.0'] |
477 | use_https = False |
478 | view_permission = 'zope.Public' |
479 | |
480 | |
481 | === modified file 'src/lazr/restful/interfaces/_rest.py' |
482 | --- src/lazr/restful/interfaces/_rest.py 2009-11-12 16:43:57 +0000 |
483 | +++ src/lazr/restful/interfaces/_rest.py 2009-11-16 15:00:27 +0000 |
484 | @@ -51,7 +51,7 @@ |
485 | 'IWebServiceLayer', |
486 | ] |
487 | |
488 | -from zope.schema import Bool, Int, TextLine |
489 | +from zope.schema import Bool, Int, List, TextLine |
490 | from zope.interface import Attribute, Interface |
491 | # These two should really be imported from zope.interface, but |
492 | # the import fascist complains because they are not in __all__ there. |
493 | @@ -417,15 +417,19 @@ |
494 | "put the URL prefix here. (In the example case, the URL prefix " |
495 | "is 'web-service/').") |
496 | |
497 | - service_version_uri_prefix = TextLine( |
498 | - default=u"", |
499 | - description=u"""The versioning string, if any, to use as the |
500 | - URI prefix for web service URIs. A popular string is 'beta', |
501 | - but you could also use a version number or the date the API |
502 | - was finalized. |
503 | - |
504 | - The service version URI prefix shows up in URIs *after* any |
505 | - value for service_root_uri_prefix.""") |
506 | + active_versions = List( |
507 | + value_type=TextLine(), |
508 | + default = [], |
509 | + title=u"The active versions of the web service.", |
510 | + description = u"""A list of names of active versions of this |
511 | + web service. They might be version numbers, names such as |
512 | + "beta", or the date a particular version was finalized. |
513 | + |
514 | + Newer versions should show up later in the list than earlier |
515 | + versions. The most recent active version should be at the end |
516 | + of the list. |
517 | + |
518 | + Currently this list must contain at least one version name.""") |
519 | |
520 | latest_version_uri_prefix = TextLine( |
521 | default=u"devel", |
522 | |
523 | === modified file 'src/lazr/restful/publisher.py' |
524 | --- src/lazr/restful/publisher.py 2009-11-12 17:03:06 +0000 |
525 | +++ src/lazr/restful/publisher.py 2009-11-16 15:00:27 +0000 |
526 | @@ -231,11 +231,11 @@ |
527 | alsoProvides(self, IWebBrowserInitiatedRequest) |
528 | |
529 | # Only accept versioned URLs. Either the |
530 | - # service_version_uri_prefix or the |
531 | - # latest_version_uri_prefix is acceptable. |
532 | + # latest_version_uri_prefix or one of the active_versions is |
533 | + # acceptable. |
534 | version = None |
535 | - for version_string in [config.service_version_uri_prefix, |
536 | - config.latest_version_uri_prefix]: |
537 | + for version_string in ( |
538 | + config.active_versions + [config.latest_version_uri_prefix]): |
539 | if version_string is not None: |
540 | version = self._popTraversal(version_string) |
541 | if version is not None: |
542 | @@ -265,13 +265,17 @@ |
543 | |
544 | @implementer(IWebServiceClientRequest) |
545 | @adapter(IBrowserRequest) |
546 | -def browser_request_to_web_service_request(website_request): |
547 | +def browser_request_to_web_service_request( |
548 | + website_request, web_service_version=None): |
549 | """An adapter from a browser request to a web service request. |
550 | |
551 | Used to instantiate Resource objects when handling normal web |
552 | browser requests. |
553 | """ |
554 | config = getUtility(IWebServiceConfiguration) |
555 | + if web_service_version is None: |
556 | + web_service_version = config.active_versions[-1] |
557 | + |
558 | body = website_request.bodyStream.getCacheStream().read() |
559 | environ = dict(website_request.environment) |
560 | # Zope picks up on SERVER_URL when setting the _app_server attribute |
561 | @@ -279,6 +283,8 @@ |
562 | environ['SERVER_URL'] = website_request.getApplicationURL() |
563 | web_service_request = config.createRequest(body, environ) |
564 | web_service_request.setVirtualHostRoot( |
565 | - names=[config.path_override, config.service_version_uri_prefix]) |
566 | + names=[config.path_override, web_service_version]) |
567 | + web_service_request.annotations[web_service_request.VERSION_ANNOTATION] = ( |
568 | + web_service_request) |
569 | web_service_request._vh_root = website_request.getVirtualHostRoot() |
570 | return web_service_request |
571 | |
572 | === modified file 'src/lazr/restful/testing/webservice.py' |
573 | --- src/lazr/restful/testing/webservice.py 2009-11-12 16:30:50 +0000 |
574 | +++ src/lazr/restful/testing/webservice.py 2009-11-16 15:00:27 +0000 |
575 | @@ -163,7 +163,7 @@ |
576 | @property |
577 | def default_api_version(self): |
578 | return getUtility( |
579 | - IWebServiceConfiguration).service_version_uri_prefix |
580 | + IWebServiceConfiguration).active_versions[-1] |
581 | |
582 | def getAbsoluteUrl(self, resource_path, api_version=None): |
583 | """Convenience method for creating a url in tests. |
This branch makes two major changes:
1. It introduces a new web service specifically for testing the multiversion code. This is pretty much a full copy of the WSGI test service, though I was able to import a few classes from the WSGI test service rather than re-defining them. (Many classes, even empty ones, had to be re-defined so that grok would handle them properly.)
Most of the multiversion tests in examples/ base/tests/ service. txt have been moved to examples/ multiversion/ tests/introduct ion.txt
2. It replaces the string service_ version_ uri_prefix (this is "beta" in the Launchpad web service) with a list of active_versions (this would be ["beta"] in the Launchpad web service). A request to any of the versions in active_versions will succeed, and although all versions still serve the exact same resources, the URLs to those resources will change depending on the version number.