Merge lp:~benji/launchpad/wadl-refactoring into lp:launchpad
- wadl-refactoring
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Brad Crittenden |
Approved revision: | no longer in the source branch. |
Merged at revision: | 11755 |
Proposed branch: | lp:~benji/launchpad/wadl-refactoring |
Merge into: | lp:launchpad |
Diff against target: |
365 lines (+223/-53) 6 files modified
Makefile (+1/-1) lib/canonical/launchpad/ftests/test_wadl_generation.py (+35/-0) lib/canonical/launchpad/rest/wadl.py (+62/-0) lib/lp/testing/matchers.py (+35/-0) lib/lp/testing/tests/test_matchers.py (+35/-0) utilities/create-lp-wadl-and-apidoc.py (+55/-52) |
To merge this branch: | bzr merge lp:~benji/launchpad/wadl-refactoring |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella (community) | Approve | ||
Brad Crittenden (community) | code | Approve | |
Review via email: mp+36452@code.launchpad.net |
Commit message
Description of the change
This branch extracts the refactorings and tests from an earlier branch
that we've decided to scrap. All of the code in this branch has been
previously reviewed and approved.
The theme of the refactorings is to provide APIs to generate the WADL
and the web service documentation. The branch also includes smoke tests
to be sure that something resembling HTML and WADL are generated and no
exceptions are raised.
Some whitespace lint was fixed in this branch.
To run the added tests: bin/test -c test_wadl_
Benji York (benji) wrote : | # |
On Thu, Sep 23, 2010 at 12:34 PM, Gavin Panella
<email address hidden> wrote:
> Review: Needs Fixing code
> Nice clean up :)
>
> I have a few fairly minor comments. [4] needs fixing before this
> branch is safe to land.
>
>
> [1]
>
> + self.assert_
>
> I think this might be better as:
[snip]
Done.
> [2]
>
> + self.assert_('<html ' in html)
>
> Same as [1].
I had to implement a Contains matcher, but that wasn't hard.
> [3]
>
> Unless it's useless and/or noisy, I think stderr should be left alone,
Agreed.
> I also think the exit code should be checked, so:
Done.
> [4]
>
> -import _pythonpath
> -
>
> It's ugly, looks like lint, but you'll need this.
Fixed.
> It may be worth adding a test to show that the script can run
> successfully, even if it's only to show the help.
Since we can be sure that the script runs because it is run (almost)
every time make is run, I decided not to implement this.
--
Benji York
Brad Crittenden (bac) wrote : | # |
Hi Benji,
Your changes as suggested by Gavin look good. We discussed the following on IRC:
1) Capitalize and punctuate
import _pythonpath # not lint, actually needed
2) alphabetize:
20 from lp.testing.matchers import (
21 StartsWith,
22 Contains,
23 )
3) Use a tuple instead of a list:
54 args = ['xsltproc', stylesheet, wadl_filename]
Thanks for the branch. I enjoyed seeing how matchers work and are extended.
Brad Crittenden (bac) wrote : | # |
Hi Benji,
I notice this branch has not landed yet. Is there something blocking you or has the work been reconsidered?
The reason I saw that it has not landed is I remember you implementing the contains matcher and I wanted to use it.
Benji York (benji) wrote : | # |
On Mon, Oct 4, 2010 at 2:15 AM, Brad Crittenden <email address hidden> wrote:
> I notice this branch has not landed yet. Is there something blocking you or has the work been reconsidered?
>
> The reason I saw that it has not landed is I remember you implementing the contains matcher and I wanted to use it.
There have been some EC2 hitches that have kept it from landing. As
soon as the current EC2 issue is resolved, I'll be landing the branch.
--
Benji York
Preview Diff
1 | === modified file 'Makefile' | |||
2 | --- Makefile 2010-10-19 15:56:07 +0000 | |||
3 | +++ Makefile 2010-10-19 18:54:00 +0000 | |||
4 | @@ -60,7 +60,7 @@ | |||
5 | 60 | 60 | ||
6 | 61 | $(API_INDEX): $(BZR_VERSION_INFO) | 61 | $(API_INDEX): $(BZR_VERSION_INFO) |
7 | 62 | mkdir -p $(APIDOC_DIR).tmp | 62 | mkdir -p $(APIDOC_DIR).tmp |
9 | 63 | LPCONFIG=$(LPCONFIG) $(PY) ./utilities/create-lp-wadl-and-apidoc.py "$(WADL_TEMPLATE)" | 63 | LPCONFIG=$(LPCONFIG) $(PY) ./utilities/create-lp-wadl-and-apidoc.py --force "$(WADL_TEMPLATE)" |
10 | 64 | mv $(APIDOC_DIR).tmp $(APIDOC_DIR) | 64 | mv $(APIDOC_DIR).tmp $(APIDOC_DIR) |
11 | 65 | 65 | ||
12 | 66 | apidoc: compile $(API_INDEX) | 66 | apidoc: compile $(API_INDEX) |
13 | 67 | 67 | ||
14 | === added file 'lib/canonical/launchpad/ftests/test_wadl_generation.py' | |||
15 | --- lib/canonical/launchpad/ftests/test_wadl_generation.py 1970-01-01 00:00:00 +0000 | |||
16 | +++ lib/canonical/launchpad/ftests/test_wadl_generation.py 2010-10-19 18:54:00 +0000 | |||
17 | @@ -0,0 +1,35 @@ | |||
18 | 1 | # Copyright 2009 Canonical Ltd. This software is licensed under the | ||
19 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
20 | 3 | |||
21 | 4 | """Tests for the web service WADL and HTML generation APIs.""" | ||
22 | 5 | |||
23 | 6 | __metaclass__ = type | ||
24 | 7 | |||
25 | 8 | import pkg_resources | ||
26 | 9 | import shutil | ||
27 | 10 | import subprocess | ||
28 | 11 | import tempfile | ||
29 | 12 | |||
30 | 13 | from zope.component import getUtility | ||
31 | 14 | |||
32 | 15 | from canonical.launchpad.rest.wadl import generate_wadl, generate_html | ||
33 | 16 | from canonical.launchpad.systemhomes import WebServiceApplication | ||
34 | 17 | from canonical.testing import LaunchpadFunctionalLayer | ||
35 | 18 | from lazr.restful.interfaces import IWebServiceConfiguration | ||
36 | 19 | from lp.testing import TestCase | ||
37 | 20 | from lp.testing.matchers import ( | ||
38 | 21 | Contains, | ||
39 | 22 | StartsWith, | ||
40 | 23 | ) | ||
41 | 24 | |||
42 | 25 | |||
43 | 26 | class SmokeTestWadlAndDocGeneration(TestCase): | ||
44 | 27 | """Smoke test the WADL and HTML generation front-end functions.""" | ||
45 | 28 | |||
46 | 29 | layer = LaunchpadFunctionalLayer | ||
47 | 30 | |||
48 | 31 | def test_wadl(self): | ||
49 | 32 | config = getUtility(IWebServiceConfiguration) | ||
50 | 33 | for version in config.active_versions: | ||
51 | 34 | wadl = generate_wadl(version) | ||
52 | 35 | self.assertThat(wadl[:40], StartsWith('<?xml ')) | ||
53 | 0 | 36 | ||
54 | === added file 'lib/canonical/launchpad/rest/wadl.py' | |||
55 | --- lib/canonical/launchpad/rest/wadl.py 1970-01-01 00:00:00 +0000 | |||
56 | +++ lib/canonical/launchpad/rest/wadl.py 2010-10-19 18:54:00 +0000 | |||
57 | @@ -0,0 +1,62 @@ | |||
58 | 1 | # Copyright 2010 Canonical Ltd. This software is licensed under the | ||
59 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
60 | 3 | |||
61 | 4 | """APIs to generate the web sercice WADL and documentation HTML.""" | ||
62 | 5 | |||
63 | 6 | __metaclass__ = type | ||
64 | 7 | |||
65 | 8 | import pkg_resources | ||
66 | 9 | import subprocess | ||
67 | 10 | import urlparse | ||
68 | 11 | |||
69 | 12 | from canonical.launchpad.webapp.interaction import ( | ||
70 | 13 | ANONYMOUS, | ||
71 | 14 | setupInteractionByEmail, | ||
72 | 15 | ) | ||
73 | 16 | from canonical.launchpad.webapp.servers import ( | ||
74 | 17 | WebServicePublication, | ||
75 | 18 | WebServiceTestRequest, | ||
76 | 19 | ) | ||
77 | 20 | from canonical.launchpad.webapp.vhosts import allvhosts | ||
78 | 21 | |||
79 | 22 | |||
80 | 23 | def generate_wadl(version): | ||
81 | 24 | """Generate the WADL for the given version of the web service.""" | ||
82 | 25 | url = urlparse.urljoin(allvhosts.configs['api'].rooturl, version) | ||
83 | 26 | # Since we want HTTPS URLs we have to munge the request URL. | ||
84 | 27 | url = url.replace('http://', 'https://') | ||
85 | 28 | request = WebServiceTestRequest(version=version, environ={ | ||
86 | 29 | 'SERVER_URL': url, | ||
87 | 30 | 'HTTP_HOST': allvhosts.configs['api'].hostname, | ||
88 | 31 | 'HTTP_ACCEPT': 'application/vd.sun.wadl+xml', | ||
89 | 32 | }) | ||
90 | 33 | # We then bypass the usual publisher processing by associating | ||
91 | 34 | # the request with the WebServicePublication (usually done by the | ||
92 | 35 | # publisher) and then calling the root resource - retrieved | ||
93 | 36 | # through getApplication(). | ||
94 | 37 | request.setPublication(WebServicePublication(None)) | ||
95 | 38 | setupInteractionByEmail(ANONYMOUS, request) | ||
96 | 39 | return request.publication.getApplication(request)(request) | ||
97 | 40 | |||
98 | 41 | |||
99 | 42 | def generate_html(wadl_filename, suppress_stderr=True): | ||
100 | 43 | """Given a WADL file generate HTML documentation from it.""" | ||
101 | 44 | # If we're supposed to prevent the subprocess from generating output on | ||
102 | 45 | # stderr (like we want to do during test runs), we reassign the subprocess | ||
103 | 46 | # stderr file handle and then discard the output. Otherwise we let the | ||
104 | 47 | # subprocess inherit stderr. | ||
105 | 48 | stylesheet = pkg_resources.resource_filename( | ||
106 | 49 | 'launchpadlib', 'wadl-to-refhtml.xsl') | ||
107 | 50 | if suppress_stderr: | ||
108 | 51 | stderr = subprocess.PIPE | ||
109 | 52 | else: | ||
110 | 53 | stderr = None | ||
111 | 54 | args = ('xsltproc', stylesheet, wadl_filename) | ||
112 | 55 | process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=stderr) | ||
113 | 56 | |||
114 | 57 | output = process.communicate()[0] | ||
115 | 58 | if process.returncode != 0: | ||
116 | 59 | raise subprocess.CalledProcessError(process.returncode, args) | ||
117 | 60 | |||
118 | 61 | return output | ||
119 | 62 | |||
120 | 0 | 63 | ||
121 | === modified file 'lib/lp/testing/matchers.py' | |||
122 | --- lib/lp/testing/matchers.py 2010-09-19 23:52:49 +0000 | |||
123 | +++ lib/lp/testing/matchers.py 2010-10-19 18:54:00 +0000 | |||
124 | @@ -227,6 +227,41 @@ | |||
125 | 227 | return None | 227 | return None |
126 | 228 | 228 | ||
127 | 229 | 229 | ||
128 | 230 | class DoesNotContain(Mismatch): | ||
129 | 231 | |||
130 | 232 | def __init__(self, matchee, expected): | ||
131 | 233 | """Create a DoesNotContain Mismatch. | ||
132 | 234 | |||
133 | 235 | :param matchee: the string that did not match. | ||
134 | 236 | :param expected: the string that `matchee` was expected to contain. | ||
135 | 237 | """ | ||
136 | 238 | self.matchee = matchee | ||
137 | 239 | self.expected = expected | ||
138 | 240 | |||
139 | 241 | def describe(self): | ||
140 | 242 | return "'%s' does not contain '%s'." % ( | ||
141 | 243 | self.matchee, self.expected) | ||
142 | 244 | |||
143 | 245 | |||
144 | 246 | class Contains(Matcher): | ||
145 | 247 | """Checks whether one string contains another.""" | ||
146 | 248 | |||
147 | 249 | def __init__(self, expected): | ||
148 | 250 | """Create a Contains Matcher. | ||
149 | 251 | |||
150 | 252 | :param expected: the string that matchees should contain. | ||
151 | 253 | """ | ||
152 | 254 | self.expected = expected | ||
153 | 255 | |||
154 | 256 | def __str__(self): | ||
155 | 257 | return "Contains '%s'." % self.expected | ||
156 | 258 | |||
157 | 259 | def match(self, matchee): | ||
158 | 260 | if self.expected not in matchee: | ||
159 | 261 | return DoesNotContain(matchee, self.expected) | ||
160 | 262 | return None | ||
161 | 263 | |||
162 | 264 | |||
163 | 230 | class IsConfiguredBatchNavigator(Matcher): | 265 | class IsConfiguredBatchNavigator(Matcher): |
164 | 231 | """Check that an object is a batch navigator.""" | 266 | """Check that an object is a batch navigator.""" |
165 | 232 | 267 | ||
166 | 233 | 268 | ||
167 | === modified file 'lib/lp/testing/tests/test_matchers.py' | |||
168 | --- lib/lp/testing/tests/test_matchers.py 2010-08-20 20:31:18 +0000 | |||
169 | +++ lib/lp/testing/tests/test_matchers.py 2010-10-19 18:54:00 +0000 | |||
170 | @@ -20,6 +20,8 @@ | |||
171 | 20 | from lp.testing import TestCase | 20 | from lp.testing import TestCase |
172 | 21 | from lp.testing._webservice import QueryCollector | 21 | from lp.testing._webservice import QueryCollector |
173 | 22 | from lp.testing.matchers import ( | 22 | from lp.testing.matchers import ( |
174 | 23 | Contains, | ||
175 | 24 | DoesNotContain, | ||
176 | 23 | DoesNotCorrectlyProvide, | 25 | DoesNotCorrectlyProvide, |
177 | 24 | DoesNotProvide, | 26 | DoesNotProvide, |
178 | 25 | DoesNotStartWith, | 27 | DoesNotStartWith, |
179 | @@ -257,3 +259,36 @@ | |||
180 | 257 | matcher = StartsWith("bar") | 259 | matcher = StartsWith("bar") |
181 | 258 | mismatch = matcher.match("foo") | 260 | mismatch = matcher.match("foo") |
182 | 259 | self.assertEqual("bar", mismatch.expected) | 261 | self.assertEqual("bar", mismatch.expected) |
183 | 262 | |||
184 | 263 | |||
185 | 264 | class DoesNotContainTests(TestCase): | ||
186 | 265 | |||
187 | 266 | def test_describe(self): | ||
188 | 267 | mismatch = DoesNotContain("foo", "bar") | ||
189 | 268 | self.assertEqual( | ||
190 | 269 | "'foo' does not contain 'bar'.", mismatch.describe()) | ||
191 | 270 | |||
192 | 271 | |||
193 | 272 | class ContainsTests(TestCase): | ||
194 | 273 | |||
195 | 274 | def test_str(self): | ||
196 | 275 | matcher = Contains("bar") | ||
197 | 276 | self.assertEqual("Contains 'bar'.", str(matcher)) | ||
198 | 277 | |||
199 | 278 | def test_match(self): | ||
200 | 279 | matcher = Contains("bar") | ||
201 | 280 | self.assertIs(None, matcher.match("foo bar baz")) | ||
202 | 281 | |||
203 | 282 | def test_mismatch_returns_does_not_start_with(self): | ||
204 | 283 | matcher = Contains("bar") | ||
205 | 284 | self.assertIsInstance(matcher.match("foo"), DoesNotContain) | ||
206 | 285 | |||
207 | 286 | def test_mismatch_sets_matchee(self): | ||
208 | 287 | matcher = Contains("bar") | ||
209 | 288 | mismatch = matcher.match("foo") | ||
210 | 289 | self.assertEqual("foo", mismatch.matchee) | ||
211 | 290 | |||
212 | 291 | def test_mismatch_sets_expected(self): | ||
213 | 292 | matcher = Contains("bar") | ||
214 | 293 | mismatch = matcher.match("foo") | ||
215 | 294 | self.assertEqual("bar", mismatch.expected) | ||
216 | 260 | 295 | ||
217 | === modified file 'utilities/create-lp-wadl-and-apidoc.py' | |||
218 | --- utilities/create-lp-wadl-and-apidoc.py 2010-10-18 21:53:28 +0000 | |||
219 | +++ utilities/create-lp-wadl-and-apidoc.py 2010-10-19 18:54:00 +0000 | |||
220 | @@ -1,90 +1,93 @@ | |||
221 | 1 | #! /usr/bin/python -S | 1 | #! /usr/bin/python -S |
222 | 2 | # | 2 | # |
224 | 3 | # Copyright 2009 Canonical Ltd. This software is licensed under the | 3 | # Copyright 2010 Canonical Ltd. This software is licensed under the |
225 | 4 | # GNU Affero General Public License version 3 (see the file LICENSE). | 4 | # GNU Affero General Public License version 3 (see the file LICENSE). |
226 | 5 | 5 | ||
227 | 6 | """Create a static WADL file describing the current webservice. | 6 | """Create a static WADL file describing the current webservice. |
228 | 7 | 7 | ||
230 | 8 | Usage hint: | 8 | Example: |
231 | 9 | 9 | ||
233 | 10 | % LPCONFIG="edge" utilities/create-lp-wadl.py launchpad-%(version)s.wadl | 10 | % LPCONFIG=development bin/py utilities/create-lp-wadl-and-apidoc.py \\ |
234 | 11 | "lib/canonical/launchpad/apidoc/wadl-development-%(version)s.xml" | ||
235 | 11 | """ | 12 | """ |
239 | 12 | 13 | import _pythonpath # Not lint, actually needed. | |
240 | 13 | import _pythonpath | 14 | |
241 | 14 | 15 | import optparse | |
242 | 15 | import os | 16 | import os |
243 | 16 | import pkg_resources | ||
244 | 17 | import subprocess | ||
245 | 18 | import sys | 17 | import sys |
246 | 19 | import urlparse | ||
247 | 20 | 18 | ||
248 | 21 | from zope.component import getUtility | 19 | from zope.component import getUtility |
249 | 22 | from zope.pagetemplate.pagetemplatefile import PageTemplateFile | 20 | from zope.pagetemplate.pagetemplatefile import PageTemplateFile |
250 | 23 | 21 | ||
251 | 22 | from canonical.launchpad.rest.wadl import generate_wadl, generate_html | ||
252 | 24 | from canonical.launchpad.scripts import execute_zcml_for_scripts | 23 | from canonical.launchpad.scripts import execute_zcml_for_scripts |
253 | 25 | from canonical.launchpad.webapp.interaction import ( | ||
254 | 26 | ANONYMOUS, setupInteractionByEmail) | ||
255 | 27 | from canonical.launchpad.webapp.servers import ( | ||
256 | 28 | WebServicePublication, WebServiceTestRequest) | ||
257 | 29 | from canonical.launchpad.webapp.vhosts import allvhosts | ||
258 | 30 | from canonical.launchpad.systemhomes import WebServiceApplication | 24 | from canonical.launchpad.systemhomes import WebServiceApplication |
259 | 31 | from lazr.restful.interfaces import IWebServiceConfiguration | 25 | from lazr.restful.interfaces import IWebServiceConfiguration |
260 | 32 | 26 | ||
261 | 33 | 27 | ||
263 | 34 | def main(path_template): | 28 | def write(filename, content): |
264 | 29 | """Replace the named file with the given string.""" | ||
265 | 30 | f = open(filename, 'w') | ||
266 | 31 | f.write(content) | ||
267 | 32 | f.close() | ||
268 | 33 | |||
269 | 34 | |||
270 | 35 | def main(path_template, force=False): | ||
271 | 35 | WebServiceApplication.cached_wadl = None # do not use cached file version | 36 | WebServiceApplication.cached_wadl = None # do not use cached file version |
272 | 36 | execute_zcml_for_scripts() | 37 | execute_zcml_for_scripts() |
273 | 37 | config = getUtility(IWebServiceConfiguration) | 38 | config = getUtility(IWebServiceConfiguration) |
278 | 38 | directory, ignore = os.path.split(path_template) | 39 | directory = os.path.dirname(path_template) |
275 | 39 | |||
276 | 40 | stylesheet = pkg_resources.resource_filename( | ||
277 | 41 | 'launchpadlib', 'wadl-to-refhtml.xsl') | ||
279 | 42 | 40 | ||
280 | 43 | # First, create an index.html with links to all the HTML | 41 | # First, create an index.html with links to all the HTML |
281 | 44 | # documentation files we're about to generate. | 42 | # documentation files we're about to generate. |
282 | 45 | template_file = 'apidoc-index.pt' | 43 | template_file = 'apidoc-index.pt' |
283 | 46 | template = PageTemplateFile(template_file) | 44 | template = PageTemplateFile(template_file) |
285 | 47 | f = open(os.path.join(directory, "index.html"), 'w') | 45 | index_filename = os.path.join(directory, "index.html") |
286 | 46 | print "Writing index:", index_filename | ||
287 | 47 | f = open(index_filename, 'w') | ||
288 | 48 | f.write(template(config=config)) | 48 | f.write(template(config=config)) |
289 | 49 | 49 | ||
290 | 50 | # Request the WADL from the root resource. | ||
291 | 51 | # We do this by creating a request object asking for a WADL | ||
292 | 52 | # representation. | ||
293 | 53 | for version in config.active_versions: | 50 | for version in config.active_versions: |
312 | 54 | url = urlparse.urljoin(allvhosts.configs['api'].rooturl, version) | 51 | wadl_filename = path_template % {'version': version} |
313 | 55 | request = WebServiceTestRequest(version=version, environ={ | 52 | # If the WADL file doesn't exist or we're being forced to regenerate |
314 | 56 | 'SERVER_URL': url, | 53 | # it... |
315 | 57 | 'HTTP_HOST': allvhosts.configs['api'].hostname, | 54 | if (not os.path.exists(wadl_filename) or force): |
316 | 58 | 'HTTP_ACCEPT': 'application/vd.sun.wadl+xml' | 55 | print "Writing WADL for version %s to %s." % ( |
317 | 59 | }) | 56 | version, wadl_filename) |
318 | 60 | # We then bypass the usual publisher processing by associating | 57 | write(wadl_filename, generate_wadl(version)) |
319 | 61 | # the request with the WebServicePublication (usually done by the | 58 | else: |
320 | 62 | # publisher) and then calling the root resource - retrieved through | 59 | print "Skipping already present WADL file:", wadl_filename |
303 | 63 | # getApplication(). | ||
304 | 64 | request.setPublication(WebServicePublication(None)) | ||
305 | 65 | setupInteractionByEmail(ANONYMOUS, request) | ||
306 | 66 | filename = path_template % {'version' : version} | ||
307 | 67 | print "Writing WADL for version %s to %s." % (version, filename) | ||
308 | 68 | f = open(filename, 'w') | ||
309 | 69 | content = request.publication.getApplication(request)(request) | ||
310 | 70 | f.write(content) | ||
311 | 71 | f.close() | ||
321 | 72 | 60 | ||
322 | 73 | # Now, convert the WADL into an human-readable description and | 61 | # Now, convert the WADL into an human-readable description and |
323 | 74 | # put the HTML in the same directory as the WADL. | 62 | # put the HTML in the same directory as the WADL. |
324 | 75 | html_filename = os.path.join(directory, version + ".html") | 63 | html_filename = os.path.join(directory, version + ".html") |
330 | 76 | print "Writing apidoc for version %s to %s" % ( | 64 | # If the HTML file doesn't exist or we're being forced to regenerate |
331 | 77 | version, html_filename) | 65 | # it... |
332 | 78 | stdout = open(html_filename, "w") | 66 | if (not os.path.exists(html_filename) or force): |
333 | 79 | subprocess.Popen(['xsltproc', stylesheet, filename], stdout=stdout) | 67 | print "Writing apidoc for version %s to %s" % ( |
334 | 80 | stdout.close() | 68 | version, html_filename) |
335 | 69 | write(html_filename, generate_html(wadl_filename, | ||
336 | 70 | suppress_stderr=False)) | ||
337 | 71 | else: | ||
338 | 72 | print "Skipping already present HTML file:", html_filename | ||
339 | 81 | 73 | ||
340 | 82 | return 0 | 74 | return 0 |
341 | 83 | 75 | ||
342 | 76 | |||
343 | 77 | def parse_args(args): | ||
344 | 78 | usage = "usage: %prog [options] PATH_TEMPLATE" | ||
345 | 79 | parser = optparse.OptionParser(usage=usage) | ||
346 | 80 | parser.add_option( | ||
347 | 81 | "--force", action="store_true", | ||
348 | 82 | help="Replace any already-existing files.") | ||
349 | 83 | parser.set_defaults(force=False) | ||
350 | 84 | options, args = parser.parse_args(args) | ||
351 | 85 | if len(args) != 2: | ||
352 | 86 | parser.error("A path template is required.") | ||
353 | 87 | |||
354 | 88 | return options, args | ||
355 | 89 | |||
356 | 90 | |||
357 | 84 | if __name__ == '__main__': | 91 | if __name__ == '__main__': |
364 | 85 | if len(sys.argv) != 2: | 92 | options, args = parse_args(sys.argv) |
365 | 86 | print "Usage: %s [WADL path template]" % sys.argv[0] | 93 | sys.exit(main(args[1], options.force)) |
360 | 87 | print " Example: %s path/to/wadl/wadl-%%(version).xml" % ( | ||
361 | 88 | sys.argv[0]) | ||
362 | 89 | sys.exit(-1) | ||
363 | 90 | sys.exit(main(sys.argv[1])) |
Nice clean up :)
I have a few fairly minor comments. [4] needs fixing before this
branch is safe to land.
[1]
+ self.assert_ (wadl.startswit h('<?xml '))
I think this might be better as:
from lp.testing.matchers import Startswith assertThat( wadl, StartsWith('<?xml '))
self.
You'll need to inherit from lp.testing.TestCase (or, more accurately,
testtools.TestCase) to get assertThat().
[2]
+ self.assert_('<html ' in html)
Same as [1].
[3]
+ return subprocess.Popen( subprocess. PIPE, subprocess. PIPE).communica te()[0]
+ ['xsltproc', stylesheet, wadl_filename],
+ stdout=
+ stderr=
Unless it's useless and/or noisy, I think stderr should be left alone,
so:
return subprocess.Popen(
['xsltproc' , stylesheet, wadl_filename],
stdout= subprocess. PIPE).communica te()[0]
I also think the exit code should be checked, so:
args = ['xsltproc', stylesheet, wadl_filename] Popen(args, stdout= subprocess. PIPE) communicate( ) CalledProcessEr ror(
process. returncode, args)
process = subprocess.
out, err = process.
if process.returncode == 0:
return out
else
raise subprocess.
This is similar to how subprocess. check_call( ) behaves.
[4]
-import _pythonpath
-
It's ugly, looks like lint, but you'll need this.
It may be worth adding a test to show that the script can run
successfully, even if it's only to show the help.