Merge lp:~leonardr/lazr.restful/bump-version into lp:lazr.restful

Proposed by Leonard Richardson
Status: Merged
Merged at revision: not available
Proposed branch: lp:~leonardr/lazr.restful/bump-version
Merge into: lp:lazr.restful
Diff against target: 193 lines (+113/-14)
6 files modified
src/lazr/restful/NEWS.txt (+9/-8)
src/lazr/restful/_resource.py (+27/-3)
src/lazr/restful/example/multiversion/tests/introduction.txt (+2/-1)
src/lazr/restful/example/multiversion/tests/wadl.txt (+67/-0)
src/lazr/restful/tales.py (+7/-1)
src/lazr/restful/version.txt (+1/-1)
To merge this branch: bzr merge lp:~leonardr/lazr.restful/bump-version
Reviewer Review Type Date Requested Status
Michael Nelson (community) code Approve
Review via email: mp+19107@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Leonard Richardson (leonardr) wrote :

This branch adds multi-version tests for the WADL generation. When I tried to give multi-version features to lazr.restfulclient, it didn't work because the WADL was malformed. The two main problems were:

1. Unless you got the WADL for the latest version, lazr.restful saw multiple registrations for an entry adapter and crashed. This is because lazr.restful was looking for registrations that matched the marker interface (let's say) IWebServiceVersion1_0. But IWebServiceVersion2_0 and IWebServiceVersion3_0 subclass IWebServiceVersion1_0, so the entry adpater registrations for those versions were picked up as well.

2. The stub function that signals the removal of a named operation as of a particular version was being treated as a (malformed) named operation in its own right.

I fixed these problems in ways that should make sense when you look at the code.

This branch also fixes a test failure and prepares a new release of lazr.restful. (I thought that would be the only purpose of this branch, until lazr.restfulclient started failing on me.)

115. By Leonard Richardson

Added missing file.

Revision history for this message
Michael Nelson (michael.nelson) wrote :
Download full text (5.1 KiB)

Thanks for all the changes Leonard. IRC log below for the record (and sorry Bjorn if you read this - I normally put the quoted diff, but I had to rush to finish this one on time!)

17:02 < noodles775> leonardr: on line 45 of the MP diff, is this really the earliest version, or the earliest *active* version? (which
                    line 47 seems to imply?)
17:03 < leonardr> noodles775: inactive versions don't exist in the lazr.restful installation, only in peoples' memories, so the
                  concepts are equivalent
17:03 < leonardr> i can change the wording

17:04 < noodles775> leonardr: in which case, why can len(config.active_versions) == 0, but we still have an earliest_version? or is
                    that what you'll re-word?
17:04 < leonardr> noodles775: it's kind of confusing but i don't want to change the interface becuase that'll cause backward
                  incompatibility problems
17:04 < leonardr> there are two fields in the interface
17:04 < leonardr> active_versions and latest_version_uri_prefix
17:05 < leonardr> active_versions is a list, the other is a stirng
17:05 < leonardr> lazr.restful serves web services for all of those strings
17:05 -!- danilos [~danilo@canonical/launchpad/danilos] has quit [Ping timeout: 265 seconds]
17:05 < leonardr> so if active_versions is =['beta', '1.0'] and latest_version_uri_prefix is 'devel' there are three versions being
                  served
17:05 < leonardr> if active_versions is [] and latest_version_uri_prefix is 'beta' then there is one version
17:05 < leonardr> though i don't recommend doing that
17:06 < noodles775> So if active_versions is =['beta', '1.0'] and latest_version_uri_prefix is 'devel', why are we evaluating
                    earliest_version = 'beta', is that right?
17:06 < noodles775> leonardr: ^^
17:07 < leonardr> noodles775: i'm having trouble parsing that sentence, but i can tell you that in that case earliest_version is 'beta'
17:07 < leonardr> latest_version_uri_prefix can only be the earliest version if active_versions is empty
17:07 < noodles775> OK, as the code implies, I'm just confused by the names.
17:08 < leonardr> noodles775: i'm kind of leaning towards treating the last item in active_versions as latest_version_uri_prefix

17:08 < leonardr> but that would be a separate job
17:09 -!- salgado-lunch is now known as salgado
17:09 < noodles775> Right, that would make sense. (do you mind adding an XXX?)
17:09 < leonardr> sure
17:11 < noodles775> leonardr: just a style question, is the comment on the empty line 69 intentional?
17:11 < leonardr> yeah, it's like a para break. i don't know if we allow that though
17:12 < noodles775> Yeah, I think a blank line (without the comment) serves just as well, but if the style guide doesn't say either
                    way, whatever you prefer :)
17:12 < leonardr> style guide doesn't mention it
17:13 < leonardr> if i see a blank line i think the first comment was talking about the blank line and the second comment is different
17:13 < noodles775> leonardr: s/marker_interface/version_marker on line 72
17:13 < noodles775> sure
17:19 -!- danilos [~danilo@canonical/launchpad/danilos] has joined #launchp...

Read more...

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/lazr/restful/NEWS.txt'
--- src/lazr/restful/NEWS.txt 2010-01-12 17:41:25 +0000
+++ src/lazr/restful/NEWS.txt 2010-02-11 15:31:14 +0000
@@ -2,19 +2,20 @@
2NEWS for lazr.restful2NEWS for lazr.restful
3=====================3=====================
44
5Development50.9.18 (2010-02-11)
6===========6===================
77
8Special note: this version contains backwards-incompatible8Special note: this version contains backwards-incompatible
9changes. You *must* change your configuration object to get your code9changes. You *must* change your configuration object to get your code
10to work in this version! See "active_versions" below.10to work in this version! See "active_versions" and
11"latest_version_uri_prefix" below.
1112
12Added a versioning system for web services. Clients can now request13Added a versioning system for web services. Clients can now request
13the "trunk" of a web service as well as one published version. Apart14any number of distinct versions as well as a floating "trunk" which is
14from the URIs served, the two web services are exactly the same. There15always the most recent version. By using version-aware annotations,
15is no way to serve two different versions of a web service without16developers can publish the same data model differently over time. See
16defining both versions from scratch. (There will eventually be17the example web service in example/multiversion/ to see how the
17annotations to make this easy.)18annotations work.
1819
19This release introduces a new field to IWebServiceConfiguration:20This release introduces a new field to IWebServiceConfiguration:
20latest_version_uri_prefix. If you are rolling your own21latest_version_uri_prefix. If you are rolling your own
2122
=== modified file 'src/lazr/restful/_resource.py'
--- src/lazr/restful/_resource.py 2010-02-03 21:22:19 +0000
+++ src/lazr/restful/_resource.py 2010-02-11 15:31:14 +0000
@@ -1598,6 +1598,14 @@
1598 collection_classes = []1598 collection_classes = []
1599 singular_names = {}1599 singular_names = {}
1600 plural_names = {}1600 plural_names = {}
1601
1602 # Determine the name of the earliest version. We'll be using this later.
1603 config = getUtility(IWebServiceConfiguration)
1604 if len(config.active_versions) > 0:
1605 earliest_version = config.active_versions[0]
1606 else:
1607 earliest_version = config.latest_version_uri_prefix
1608
1601 for registration in sorted(site_manager.registeredAdapters()):1609 for registration in sorted(site_manager.registeredAdapters()):
1602 provided = registration.provided1610 provided = registration.provided
1603 if IInterface.providedBy(provided):1611 if IInterface.providedBy(provided):
@@ -1610,10 +1618,26 @@
1610 # of the classes with schemas, which we do describe.1618 # of the classes with schemas, which we do describe.
16111619
1612 # Make sure we have a registration relevant to1620 # Make sure we have a registration relevant to
1613 # this version. A given entry may be have one1621 # this version. A given entry may have one
1614 # registration for every web service version.1622 # registration for every web service version.
1615 schema, version = registration.required1623 schema, version_marker = registration.required
1616 if not version.providedBy(self.request):1624
1625 if (version_marker is IWebServiceClientRequest
1626 and self.request.version != earliest_version):
1627 # We are generating WADL for some version
1628 # other than the earliest version, and this is
1629 # a registration for the earliest version. We
1630 # can ignore it.
1631 #
1632 # We need this special test because the normal
1633 # test (below) is useless when
1634 # marker_interface is
1635 # IWebServiceClientRequest. Since all request
1636 # objects provide IWebServiceClientRequest
1637 # directly, it will always show up in
1638 # providedBy(self.request).
1639 continue
1640 if not version_marker in providedBy(self.request):
1617 continue1641 continue
16181642
1619 # Make sure that no other entry class is using this1643 # Make sure that no other entry class is using this
16201644
=== modified file 'src/lazr/restful/example/multiversion/tests/introduction.txt'
--- src/lazr/restful/example/multiversion/tests/introduction.txt 2010-02-08 18:59:13 +0000
+++ src/lazr/restful/example/multiversion/tests/introduction.txt 2010-02-11 15:31:14 +0000
@@ -232,7 +232,8 @@
232If an entry field is not published in a certain version, the232If an entry field is not published in a certain version, the
233corresponding field resource does not exist for that version.233corresponding field resource does not exist for that version.
234234
235 >>> webservice.get('/pairs/foo/deleted', api_version='beta')235 >>> print webservice.get('/pairs/foo/deleted', api_version='beta').body
236 Object: ...
236 Traceback (most recent call last):237 Traceback (most recent call last):
237 ...238 ...
238 NotFound: ... name: u'deleted'239 NotFound: ... name: u'deleted'
239240
=== added file 'src/lazr/restful/example/multiversion/tests/wadl.txt'
--- src/lazr/restful/example/multiversion/tests/wadl.txt 1970-01-01 00:00:00 +0000
+++ src/lazr/restful/example/multiversion/tests/wadl.txt 2010-02-11 15:31:14 +0000
@@ -0,0 +1,67 @@
1Multi-version WADL documents
2****************************
3
4A given version of the web service generates a WADL document which
5describes that version only. Let's go through the WADL documents for
6the different versions and see how they differ.
7
8 >>> from lazr.restful.testing.webservice import WebServiceCaller
9 >>> webservice = WebServiceCaller(domain='multiversion.dev')
10
11We'll start with a helper function that retrieves the WADL description
12for a given version of the key-value web service, and decomposes the
13top-level tags in the WADL document into a dictionary for easy access
14later. This works because all versions of the web service publish a
15single top-level collection and a single entry type, so the document's
16top-level structure is always the same.
17
18 >>> from lxml import etree
19 >>> from lxml.etree import _Comment
20 >>> def wadl_contents_for_version(version):
21 ... """Parse the key-value service's WADL into a dictionary."""
22 ... wadl = webservice.get(
23 ... '/', media_type='application/vnd.sun.wadl+xml',
24 ... api_version=version).body
25 ... tree = etree.fromstring(wadl)
26 ...
27 ... keys = ("base service_root service_root_json pair_collection "
28 ... "pair_entry pair_full_json pair_diff_jaon pair_page "
29 ... "pair_page_json hosted_file hosted_file_representation"
30 ... ).split()
31 ...
32 ... tags = [child for child in tree if not isinstance(child, _Comment)]
33 ... contents = {}
34 ... for i in range(0, len(keys)):
35 ... contents[keys[i]] = tags[i]
36 ... return contents
37
38Let's take a look at the differences. in 'beta', the 'by_value' method
39is not present at all.
40
41 >>> contents = wadl_contents_for_version('beta')
42 >>> print contents['base'].attrib['base']
43 http://multiversion.dev/beta/
44
45 >>> pair_collection = contents['pair_collection']
46 >>> sorted([method.attrib['id'] for method in pair_collection])
47 ['key_value_pairs-get']
48
49In '2.0', the by_value method is called 'byValue'.
50
51 >>> contents = wadl_contents_for_version('2.0')
52 >>> print contents['base'].attrib['base']
53 http://multiversion.dev/2.0/
54
55 >>> pair_collection = contents['pair_collection']
56 >>> sorted([method.attrib['id'] for method in pair_collection])
57 ['key_value_pairs-byValue', 'key_value_pairs-get']
58
59In '3.0', the method changes its name to 'byValue'.
60
61 >>> contents = wadl_contents_for_version('3.0')
62 >>> print contents['base'].attrib['base']
63 http://multiversion.dev/3.0/
64
65 >>> pair_collection = contents['pair_collection']
66 >>> sorted([method.attrib['id'] for method in pair_collection])
67 ['key_value_pairs-by_value', 'key_value_pairs-get']
068
=== modified file 'src/lazr/restful/tales.py'
--- src/lazr/restful/tales.py 2010-01-11 18:27:43 +0000
+++ src/lazr/restful/tales.py 2010-02-11 15:31:14 +0000
@@ -291,7 +291,13 @@
291 for interface in (IResourceGETOperation, IResourcePOSTOperation):291 for interface in (IResourceGETOperation, IResourcePOSTOperation):
292 operations.extend(getGlobalSiteManager().adapters.lookupAll(292 operations.extend(getGlobalSiteManager().adapters.lookupAll(
293 (model_class, request_interface), interface))293 (model_class, request_interface), interface))
294 return [{'name' : name, 'op' : op} for name, op in operations]294
295 # An operation that was present in an earlier version but was
296 # removed in the current version will show up in this list as
297 # an stub function that returns None. Since we don't want that
298 # operation to show up in this version, we'll filter it out.
299 return [{'name' : name, 'op' : op} for name, op in operations
300 if IResourceOperation.implementedBy(op)]
295301
296302
297class WadlEntryInterfaceAdapterAPI(WadlResourceAdapterAPI):303class WadlEntryInterfaceAdapterAPI(WadlResourceAdapterAPI):
298304
=== modified file 'src/lazr/restful/version.txt'
--- src/lazr/restful/version.txt 2009-11-10 14:30:52 +0000
+++ src/lazr/restful/version.txt 2010-02-11 15:31:14 +0000
@@ -1,1 +1,1 @@
10.9.1710.9.18

Subscribers

People subscribed via source and target branches