Merge ~cjwatson/launchpad:testing-print-function into launchpad:master
- Git
- lp:~cjwatson/launchpad
- testing-print-function
- Merge into master
Status: | Merged |
---|---|
Approved by: | Colin Watson |
Approved revision: | 1724d19e4228a63c404e32d4df2bd1d8e926a01f |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~cjwatson/launchpad:testing-print-function |
Merge into: | launchpad:master |
Diff against target: |
761 lines (+126/-107) 13 files modified
lib/lp/testing/__init__.py (+8/-8) lib/lp/testing/doc/pagetest-helpers.txt (+35/-35) lib/lp/testing/doc/sample-data-assertions.txt (+1/-1) lib/lp/testing/faketransaction.py (+3/-1) lib/lp/testing/karma.py (+3/-1) lib/lp/testing/layers.py (+4/-2) lib/lp/testing/mail_helpers.py (+14/-12) lib/lp/testing/menu.py (+5/-3) lib/lp/testing/pages.py (+37/-35) lib/lp/testing/publication.py (+7/-5) lib/lp/testing/systemdocs.py (+4/-2) lib/lp/testing/tests/test_doc.py (+2/-1) lib/lp/testing/yuixhr.py (+3/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Colin Watson (community) | Approve | ||
Kristian Glass (community) | Approve | ||
Review via email: mp+373699@code.launchpad.net |
Commit message
Convert lp.testing to print_function
I also added unicode_literals in a few places where it could be done
with minimal disruption.
The build_test_suite change is because for doctests we can't just do
"from __future__ import print_function" etc. at the top of the file, and
instead have to insert print_function etc. into their globals when
constructing the corresponding test suite; this is a way of spelling
that without having to incur too much verbiage at every site.
Description of the change
Kristian Glass (doismellburning) wrote : | # |
Colin Watson (cjwatson) wrote : | # |
I think the best context for the build_test_suite change is probably to look at the end of https:/
Kristian Glass (doismellburning) wrote : | # |
Great, thank you
What do you think about adding that context to the commit message? I approve the change either way, but I know if I found myself hitting that line in `git blame`, I'd appreciate the additional explanation
Colin Watson (cjwatson) wrote : | # |
Sure - I've amended the commit message.
Otto Co-Pilot (otto-copilot) wrote : | # |
Voting criteria not met
https:/
Colin Watson (cjwatson) wrote : | # |
Self-approving to work around incorrect reviewer on this MP (since fixed).
Preview Diff
1 | diff --git a/lib/lp/testing/__init__.py b/lib/lp/testing/__init__.py | |||
2 | index 81e0f1f..5f91c86 100644 | |||
3 | --- a/lib/lp/testing/__init__.py | |||
4 | +++ b/lib/lp/testing/__init__.py | |||
5 | @@ -1,7 +1,7 @@ | |||
6 | 1 | # Copyright 2009-2018 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2018 Canonical Ltd. This software is licensed under the |
7 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
8 | 3 | 3 | ||
10 | 4 | from __future__ import absolute_import | 4 | from __future__ import absolute_import, print_function |
11 | 5 | 5 | ||
12 | 6 | 6 | ||
13 | 7 | __metaclass__ = type | 7 | __metaclass__ = type |
14 | @@ -258,21 +258,21 @@ class FakeTime: | |||
15 | 258 | calls of advance() or next_now(). | 258 | calls of advance() or next_now(). |
16 | 259 | 259 | ||
17 | 260 | >>> faketime = FakeTime(1000) | 260 | >>> faketime = FakeTime(1000) |
19 | 261 | >>> print faketime.now() | 261 | >>> print(faketime.now()) |
20 | 262 | 1000 | 262 | 1000 |
22 | 263 | >>> print faketime.now() | 263 | >>> print(faketime.now()) |
23 | 264 | 1000 | 264 | 1000 |
24 | 265 | >>> faketime.advance(10) | 265 | >>> faketime.advance(10) |
26 | 266 | >>> print faketime.now() | 266 | >>> print(faketime.now()) |
27 | 267 | 1010 | 267 | 1010 |
29 | 268 | >>> print faketime.next_now() | 268 | >>> print(faketime.next_now()) |
30 | 269 | 1011 | 269 | 1011 |
32 | 270 | >>> print faketime.next_now(100) | 270 | >>> print(faketime.next_now(100)) |
33 | 271 | 1111 | 271 | 1111 |
34 | 272 | >>> faketime = FakeTime(1000, 5) | 272 | >>> faketime = FakeTime(1000, 5) |
36 | 273 | >>> print faketime.next_now() | 273 | >>> print(faketime.next_now()) |
37 | 274 | 1005 | 274 | 1005 |
39 | 275 | >>> print faketime.next_now() | 275 | >>> print(faketime.next_now()) |
40 | 276 | 1010 | 276 | 1010 |
41 | 277 | """ | 277 | """ |
42 | 278 | 278 | ||
43 | diff --git a/lib/lp/testing/doc/pagetest-helpers.txt b/lib/lp/testing/doc/pagetest-helpers.txt | |||
44 | index e0bb718..21b6e8f 100644 | |||
45 | --- a/lib/lp/testing/doc/pagetest-helpers.txt | |||
46 | +++ b/lib/lp/testing/doc/pagetest-helpers.txt | |||
47 | @@ -30,32 +30,32 @@ one should be use for all anonymous browsing tests. | |||
48 | 30 | ... return dict(browser.mech_browser.addheaders).get('Authorization','') | 30 | ... return dict(browser.mech_browser.addheaders).get('Authorization','') |
49 | 31 | 31 | ||
50 | 32 | >>> anon_browser = test.globs['anon_browser'] | 32 | >>> anon_browser = test.globs['anon_browser'] |
53 | 33 | >>> getAuthorizationHeader(anon_browser) | 33 | >>> print(getAuthorizationHeader(anon_browser)) |
54 | 34 | '' | 34 | <BLANKLINE> |
55 | 35 | 35 | ||
56 | 36 | A browser with a logged in user without any privileges is available | 36 | A browser with a logged in user without any privileges is available |
57 | 37 | under 'user_browser'. This one should be use all workflows involving | 37 | under 'user_browser'. This one should be use all workflows involving |
58 | 38 | logged in users, when it shouldn't require any special privileges. | 38 | logged in users, when it shouldn't require any special privileges. |
59 | 39 | 39 | ||
60 | 40 | >>> user_browser = test.globs['user_browser'] | 40 | >>> user_browser = test.globs['user_browser'] |
63 | 41 | >>> getAuthorizationHeader(user_browser) | 41 | >>> print(getAuthorizationHeader(user_browser)) |
64 | 42 | 'Basic no-priv@canonical.com:test' | 42 | Basic no-priv@canonical.com:test |
65 | 43 | 43 | ||
66 | 44 | A browser with a logged in user with administrative privileges is | 44 | A browser with a logged in user with administrative privileges is |
67 | 45 | available under 'admin_browser'. This one should be used for testing | 45 | available under 'admin_browser'. This one should be used for testing |
68 | 46 | administrative workflows. | 46 | administrative workflows. |
69 | 47 | 47 | ||
70 | 48 | >>> admin_browser = test.globs['admin_browser'] | 48 | >>> admin_browser = test.globs['admin_browser'] |
73 | 49 | >>> getAuthorizationHeader(admin_browser) | 49 | >>> print(getAuthorizationHeader(admin_browser)) |
74 | 50 | 'Basic foo.bar@canonical.com:test' | 50 | Basic foo.bar@canonical.com:test |
75 | 51 | 51 | ||
76 | 52 | Finally, here is a 'browser' instance that simply contain a pre- | 52 | Finally, here is a 'browser' instance that simply contain a pre- |
77 | 53 | initialized Browser instance. It doesn't have any authentication | 53 | initialized Browser instance. It doesn't have any authentication |
78 | 54 | configured. It can be used when you need to configure another user. | 54 | configured. It can be used when you need to configure another user. |
79 | 55 | 55 | ||
80 | 56 | >>> browser = test.globs['browser'] | 56 | >>> browser = test.globs['browser'] |
83 | 57 | >>> getAuthorizationHeader(browser) | 57 | >>> print(getAuthorizationHeader(browser)) |
84 | 58 | '' | 58 | <BLANKLINE> |
85 | 59 | 59 | ||
86 | 60 | All these browser instances are configured with handleErrors set to | 60 | All these browser instances are configured with handleErrors set to |
87 | 61 | False. This means that exception are raised instead of returning the | 61 | False. This means that exception are raised instead of returning the |
88 | @@ -111,15 +111,15 @@ This routine will return the tag with the given id: | |||
89 | 111 | ... </html> | 111 | ... </html> |
90 | 112 | ... ''' | 112 | ... ''' |
91 | 113 | 113 | ||
93 | 114 | >>> print find_tag_by_id(content, 'para-1') | 114 | >>> print(find_tag_by_id(content, 'para-1')) |
94 | 115 | <p id="para-1">Paragraph 1</p> | 115 | <p id="para-1">Paragraph 1</p> |
95 | 116 | 116 | ||
97 | 117 | >>> print find_tag_by_id(content, 'para-2') | 117 | >>> print(find_tag_by_id(content, 'para-2')) |
98 | 118 | <p id="para-2">Paragraph <b>2</b></p> | 118 | <p id="para-2">Paragraph <b>2</b></p> |
99 | 119 | 119 | ||
100 | 120 | If an unknown ID is used, None is returned: | 120 | If an unknown ID is used, None is returned: |
101 | 121 | 121 | ||
103 | 122 | >>> print find_tag_by_id(content, 'para-3') | 122 | >>> print(find_tag_by_id(content, 'para-3')) |
104 | 123 | None | 123 | None |
105 | 124 | 124 | ||
106 | 125 | If more than one element has the requested id, raise a DuplicateIdError | 125 | If more than one element has the requested id, raise a DuplicateIdError |
107 | @@ -140,10 +140,10 @@ A BeautifulSoup PageElement can be passed instead of a string so that | |||
108 | 140 | content can be retrieved without reparsing the entire page. | 140 | content can be retrieved without reparsing the entire page. |
109 | 141 | 141 | ||
110 | 142 | >>> parsed_content = find_tag_by_id(content, 'root') | 142 | >>> parsed_content = find_tag_by_id(content, 'root') |
112 | 143 | >>> print parsed_content.name | 143 | >>> print(parsed_content.name) |
113 | 144 | html | 144 | html |
114 | 145 | 145 | ||
116 | 146 | >>> print find_tag_by_id(parsed_content, 'para-1') | 146 | >>> print(find_tag_by_id(parsed_content, 'para-1')) |
117 | 147 | <p id="para-1">Paragraph 1</p> | 147 | <p id="para-1">Paragraph 1</p> |
118 | 148 | 148 | ||
119 | 149 | 149 | ||
120 | @@ -172,18 +172,18 @@ class: | |||
121 | 172 | ... ''' | 172 | ... ''' |
122 | 173 | 173 | ||
123 | 174 | >>> for tag in find_tags_by_class(content, 'message'): | 174 | >>> for tag in find_tags_by_class(content, 'message'): |
125 | 175 | ... print tag | 175 | ... print(tag) |
126 | 176 | <p class="message">Message</p> | 176 | <p class="message">Message</p> |
127 | 177 | <p class="error message">Error message</p> | 177 | <p class="error message">Error message</p> |
128 | 178 | <p class="warning message">Warning message</p> | 178 | <p class="warning message">Warning message</p> |
129 | 179 | 179 | ||
130 | 180 | >>> for tag in find_tags_by_class(content, 'error'): | 180 | >>> for tag in find_tags_by_class(content, 'error'): |
132 | 181 | ... print tag | 181 | ... print(tag) |
133 | 182 | <p class="error message">Error message</p> | 182 | <p class="error message">Error message</p> |
134 | 183 | <p class="error">Error</p> | 183 | <p class="error">Error</p> |
135 | 184 | 184 | ||
136 | 185 | >>> for tag in find_tags_by_class(content, 'warning'): | 185 | >>> for tag in find_tags_by_class(content, 'warning'): |
138 | 186 | ... print tag | 186 | ... print(tag) |
139 | 187 | <p class="warning message">Warning message</p> | 187 | <p class="warning message">Warning message</p> |
140 | 188 | <p class="warning"> | 188 | <p class="warning"> |
141 | 189 | Warning (outer) | 189 | Warning (outer) |
142 | @@ -218,7 +218,7 @@ matching Tag object, if one exists: | |||
143 | 218 | ... </html> | 218 | ... </html> |
144 | 219 | ... ''' | 219 | ... ''' |
145 | 220 | 220 | ||
147 | 221 | >>> print first_tag_by_class(content, 'light') | 221 | >>> print(first_tag_by_class(content, 'light')) |
148 | 222 | <p class="light">Error message</p> | 222 | <p class="light">Error message</p> |
149 | 223 | 223 | ||
150 | 224 | If no tags have the given class, then "None" is returned. | 224 | If no tags have the given class, then "None" is returned. |
151 | @@ -235,7 +235,7 @@ If no tags have the given class, then "None" is returned. | |||
152 | 235 | ... </html> | 235 | ... </html> |
153 | 236 | ... ''' | 236 | ... ''' |
154 | 237 | 237 | ||
156 | 238 | >>> print first_tag_by_class(content, 'light') | 238 | >>> print(first_tag_by_class(content, 'light')) |
157 | 239 | None | 239 | None |
158 | 240 | 240 | ||
159 | 241 | 241 | ||
160 | @@ -276,11 +276,11 @@ find a portlet by its title and return it: | |||
161 | 276 | ... </html> | 276 | ... </html> |
162 | 277 | ... ''' | 277 | ... ''' |
163 | 278 | 278 | ||
165 | 279 | >>> print find_portlet(content, 'Portlet 1') | 279 | >>> print(find_portlet(content, 'Portlet 1')) |
166 | 280 | <div... | 280 | <div... |
167 | 281 | ...Contents of portlet 1... | 281 | ...Contents of portlet 1... |
168 | 282 | 282 | ||
170 | 283 | >>> print find_portlet(content, 'Portlet 2') | 283 | >>> print(find_portlet(content, 'Portlet 2')) |
171 | 284 | <div class="portlet"> | 284 | <div class="portlet"> |
172 | 285 | <h2>Portlet 2</h2> | 285 | <h2>Portlet 2</h2> |
173 | 286 | Contents of portlet 2 | 286 | Contents of portlet 2 |
174 | @@ -290,14 +290,14 @@ When looking for a portlet to match, any two sequences of whitespace are | |||
175 | 290 | considered equivalent. Whitespace at the beginning or end of the title | 290 | considered equivalent. Whitespace at the beginning or end of the title |
176 | 291 | is also ignored. | 291 | is also ignored. |
177 | 292 | 292 | ||
180 | 293 | >>> print find_portlet( | 293 | >>> print(find_portlet( |
181 | 294 | ... content, 'Portlet with title broken on multiple lines ') | 294 | ... content, 'Portlet with title broken on multiple lines ')) |
182 | 295 | <div class="portlet"> | 295 | <div class="portlet"> |
183 | 296 | <h2> Portlet with title... | 296 | <h2> Portlet with title... |
184 | 297 | 297 | ||
185 | 298 | If the portlet doesn't exist, then None is returned: | 298 | If the portlet doesn't exist, then None is returned: |
186 | 299 | 299 | ||
188 | 300 | >>> print find_portlet(content, 'No such portlet') | 300 | >>> print(find_portlet(content, 'No such portlet')) |
189 | 301 | None | 301 | None |
190 | 302 | 302 | ||
191 | 303 | 303 | ||
192 | @@ -309,7 +309,7 @@ the main content of the page. The find_main_content() method can be | |||
193 | 309 | used to do this: | 309 | used to do this: |
194 | 310 | 310 | ||
195 | 311 | >>> find_main_content = test.globs['find_main_content'] | 311 | >>> find_main_content = test.globs['find_main_content'] |
197 | 312 | >>> print find_main_content(content) | 312 | >>> print(find_main_content(content)) |
198 | 313 | <... | 313 | <... |
199 | 314 | Main content area | 314 | Main content area |
200 | 315 | ... | 315 | ... |
201 | @@ -323,16 +323,16 @@ to the end user, and we don't want necessarily to check how the text is | |||
202 | 323 | displayed (ie. bold, italics, coloured et al). | 323 | displayed (ie. bold, italics, coloured et al). |
203 | 324 | 324 | ||
204 | 325 | >>> extract_text = test.globs['extract_text'] | 325 | >>> extract_text = test.globs['extract_text'] |
207 | 326 | >>> print extract_text( | 326 | >>> print(extract_text( |
208 | 327 | ... '<p>A paragraph with <b>inline</b> <i>style</i>.</p>') | 327 | ... '<p>A paragraph with <b>inline</b> <i>style</i>.</p>')) |
209 | 328 | A paragraph with inline style. | 328 | A paragraph with inline style. |
210 | 329 | 329 | ||
211 | 330 | The function also takes care of inserting proper white space for block | 330 | The function also takes care of inserting proper white space for block |
212 | 331 | level and other elements introducing a visual separation: | 331 | level and other elements introducing a visual separation: |
213 | 332 | 332 | ||
215 | 333 | >>> print extract_text( # doctest: -NORMALIZE_WHITESPACE | 333 | >>> print(extract_text( # doctest: -NORMALIZE_WHITESPACE |
216 | 334 | ... '<p>Para 1</p><p>Para 2<br>Line 2</p><ul><li>Item 1</li>' | 334 | ... '<p>Para 1</p><p>Para 2<br>Line 2</p><ul><li>Item 1</li>' |
218 | 335 | ... '<li>Item 2</li></ul><div>Div 1</div><h1>A heading</h1>') | 335 | ... '<li>Item 2</li></ul><div>Div 1</div><h1>A heading</h1>')) |
219 | 336 | Para 1 | 336 | Para 1 |
220 | 337 | Para 2 | 337 | Para 2 |
221 | 338 | Line 2 | 338 | Line 2 |
222 | @@ -344,9 +344,9 @@ level and other elements introducing a visual separation: | |||
223 | 344 | Of course, the function ignores processing instructions, declaration, | 344 | Of course, the function ignores processing instructions, declaration, |
224 | 345 | comments and render CDATA section has plain text. | 345 | comments and render CDATA section has plain text. |
225 | 346 | 346 | ||
227 | 347 | >>> print extract_text( | 347 | >>> print(extract_text( |
228 | 348 | ... '<?php echo("Hello world!")?><!-- A comment -->' | 348 | ... '<?php echo("Hello world!")?><!-- A comment -->' |
230 | 349 | ... '<?A declaration.><![CDATA[Some << characters >>]]>') | 349 | ... '<?A declaration.><![CDATA[Some << characters >>]]>')) |
231 | 350 | Some << characters >> | 350 | Some << characters >> |
232 | 351 | 351 | ||
233 | 352 | The function also does some white space normalization, since formatted | 352 | The function also does some white space normalization, since formatted |
234 | @@ -358,10 +358,10 @@ single space. Runs of newlines is replaced by one newline. (Note also | |||
235 | 358 | that non-breaking space entities are also transformed into regular | 358 | that non-breaking space entities are also transformed into regular |
236 | 359 | space.) | 359 | space.) |
237 | 360 | 360 | ||
239 | 361 | >>> print extract_text( # doctest: -NORMALIZE_WHITESPACE | 361 | >>> print(extract_text( # doctest: -NORMALIZE_WHITESPACE |
240 | 362 | ... ' <p>Some \t white space <br /></p> ' | 362 | ... ' <p>Some \t white space <br /></p> ' |
241 | 363 | ... '<p>Another   paragraph.</p><p><p>' | 363 | ... '<p>Another   paragraph.</p><p><p>' |
243 | 364 | ... '<p>A final one</p> ') | 364 | ... '<p>A final one</p> ')) |
244 | 365 | Some white space | 365 | Some white space |
245 | 366 | Another paragraph. | 366 | Another paragraph. |
246 | 367 | A final one | 367 | A final one |
247 | @@ -369,10 +369,10 @@ space.) | |||
248 | 369 | The function also knows about the sortkey class used in many tables. The | 369 | The function also knows about the sortkey class used in many tables. The |
249 | 370 | sortkey is not displayed but is used for the javascript table sorting. | 370 | sortkey is not displayed but is used for the javascript table sorting. |
250 | 371 | 371 | ||
252 | 372 | >>> print extract_text( | 372 | >>> print(extract_text( |
253 | 373 | ... '<table><tr><td><span class="sortkey">1</span>First</td></tr>' | 373 | ... '<table><tr><td><span class="sortkey">1</span>First</td></tr>' |
254 | 374 | ... '<tr><td><span class="sortkey">2</span>Second</td></tr>' | 374 | ... '<tr><td><span class="sortkey">2</span>Second</td></tr>' |
256 | 375 | ... '<tr><td><span class="sortkey">3</span>Third</td></tr></table>') | 375 | ... '<tr><td><span class="sortkey">3</span>Third</td></tr></table>')) |
257 | 376 | First Second Third | 376 | First Second Third |
258 | 377 | 377 | ||
259 | 378 | The extract_text method is often used in conjunction with the other | 378 | The extract_text method is often used in conjunction with the other |
260 | @@ -380,7 +380,7 @@ find_xxx helper methods to identify the text to display. Because of | |||
261 | 380 | this the function also accepts BeautifulSoup instance as a parameter | 380 | this the function also accepts BeautifulSoup instance as a parameter |
262 | 381 | rather than a plain string. | 381 | rather than a plain string. |
263 | 382 | 382 | ||
265 | 383 | >>> print extract_text(find_portlet(content, 'Portlet 2')) | 383 | >>> print(extract_text(find_portlet(content, 'Portlet 2'))) |
266 | 384 | Portlet 2 | 384 | Portlet 2 |
267 | 385 | Contents of portlet 2 | 385 | Contents of portlet 2 |
268 | 386 | 386 | ||
269 | diff --git a/lib/lp/testing/doc/sample-data-assertions.txt b/lib/lp/testing/doc/sample-data-assertions.txt | |||
270 | index 7f9548e..d50015c 100644 | |||
271 | --- a/lib/lp/testing/doc/sample-data-assertions.txt | |||
272 | +++ b/lib/lp/testing/doc/sample-data-assertions.txt | |||
273 | @@ -29,5 +29,5 @@ specifically referenced in Launchpad tests. | |||
274 | 29 | This user is supposed to be a member of only one team, the "Simple Team". | 29 | This user is supposed to be a member of only one team, the "Simple Team". |
275 | 30 | 30 | ||
276 | 31 | >>> one_membership = personset.getByName('one-membership') | 31 | >>> one_membership = personset.getByName('one-membership') |
278 | 32 | >>> for t in one_membership.team_memberships: print t.team.displayname | 32 | >>> for t in one_membership.team_memberships: print(t.team.displayname) |
279 | 33 | Simple Team | 33 | Simple Team |
280 | diff --git a/lib/lp/testing/faketransaction.py b/lib/lp/testing/faketransaction.py | |||
281 | index 8bf2386..1c41916 100644 | |||
282 | --- a/lib/lp/testing/faketransaction.py | |||
283 | +++ b/lib/lp/testing/faketransaction.py | |||
284 | @@ -3,6 +3,8 @@ | |||
285 | 3 | 3 | ||
286 | 4 | """Fake transaction manager.""" | 4 | """Fake transaction manager.""" |
287 | 5 | 5 | ||
288 | 6 | from __future__ import absolute_import, print_function, unicode_literals | ||
289 | 7 | |||
290 | 6 | __metaclass__ = type | 8 | __metaclass__ = type |
291 | 7 | __all__ = ['FakeTransaction'] | 9 | __all__ = ['FakeTransaction'] |
292 | 8 | 10 | ||
293 | @@ -23,7 +25,7 @@ class FakeTransaction: | |||
294 | 23 | def _log(self, call): | 25 | def _log(self, call): |
295 | 24 | """Print calls that are being made, if desired.""" | 26 | """Print calls that are being made, if desired.""" |
296 | 25 | if self.log_calls: | 27 | if self.log_calls: |
298 | 26 | print call | 28 | print(call) |
299 | 27 | 29 | ||
300 | 28 | def begin(self): | 30 | def begin(self): |
301 | 29 | """Pretend to begin a transaction. Does not log.""" | 31 | """Pretend to begin a transaction. Does not log.""" |
302 | diff --git a/lib/lp/testing/karma.py b/lib/lp/testing/karma.py | |||
303 | index d8b2ea3..c0eaf8a 100644 | |||
304 | --- a/lib/lp/testing/karma.py | |||
305 | +++ b/lib/lp/testing/karma.py | |||
306 | @@ -3,6 +3,8 @@ | |||
307 | 3 | 3 | ||
308 | 4 | """Helper functions/classes to be used when testing the karma framework.""" | 4 | """Helper functions/classes to be used when testing the karma framework.""" |
309 | 5 | 5 | ||
310 | 6 | from __future__ import absolute_import, print_function, unicode_literals | ||
311 | 7 | |||
312 | 6 | __metaclass__ = type | 8 | __metaclass__ = type |
313 | 7 | __all__ = [ | 9 | __all__ = [ |
314 | 8 | 'KarmaAssignedEventListener', | 10 | 'KarmaAssignedEventListener', |
315 | @@ -123,4 +125,4 @@ class KarmaAssignedEventListener(KarmaRecorder): | |||
316 | 123 | text += " distribution=%s" % karma.distribution.name | 125 | text += " distribution=%s" % karma.distribution.name |
317 | 124 | if self.show_person: | 126 | if self.show_person: |
318 | 125 | text += ", person=%s" % karma.person.name | 127 | text += ", person=%s" % karma.person.name |
320 | 126 | print text | 128 | print(text) |
321 | diff --git a/lib/lp/testing/layers.py b/lib/lp/testing/layers.py | |||
322 | index ffac753..647fbb1 100644 | |||
323 | --- a/lib/lp/testing/layers.py | |||
324 | +++ b/lib/lp/testing/layers.py | |||
325 | @@ -18,6 +18,8 @@ of one, forcing us to attempt to make some sort of layer tree. | |||
326 | 18 | -- StuartBishop 20060619 | 18 | -- StuartBishop 20060619 |
327 | 19 | """ | 19 | """ |
328 | 20 | 20 | ||
329 | 21 | from __future__ import absolute_import, print_function | ||
330 | 22 | |||
331 | 21 | __metaclass__ = type | 23 | __metaclass__ = type |
332 | 22 | __all__ = [ | 24 | __all__ = [ |
333 | 23 | 'AppServerLayer', | 25 | 'AppServerLayer', |
334 | @@ -447,9 +449,9 @@ class BaseLayer: | |||
335 | 447 | # tests that leave threads behind from failing. Its use | 449 | # tests that leave threads behind from failing. Its use |
336 | 448 | # should only ever be temporary. | 450 | # should only ever be temporary. |
337 | 449 | if BaseLayer.disable_thread_check: | 451 | if BaseLayer.disable_thread_check: |
339 | 450 | print ( | 452 | print(( |
340 | 451 | "ERROR DISABLED: " | 453 | "ERROR DISABLED: " |
342 | 452 | "Test left new live threads: %s") % repr(new_threads) | 454 | "Test left new live threads: %s") % repr(new_threads)) |
343 | 453 | else: | 455 | else: |
344 | 454 | BaseLayer.flagTestIsolationFailure( | 456 | BaseLayer.flagTestIsolationFailure( |
345 | 455 | "Test left new live threads: %s" % repr(new_threads)) | 457 | "Test left new live threads: %s" % repr(new_threads)) |
346 | diff --git a/lib/lp/testing/mail_helpers.py b/lib/lp/testing/mail_helpers.py | |||
347 | index e5a27a9..3ac740a 100644 | |||
348 | --- a/lib/lp/testing/mail_helpers.py | |||
349 | +++ b/lib/lp/testing/mail_helpers.py | |||
350 | @@ -1,8 +1,10 @@ | |||
351 | 1 | # Copyright 2009-2019 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2019 Canonical Ltd. This software is licensed under the |
352 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
353 | 3 | 3 | ||
356 | 4 | """Helper functions dealing with emails in tests. | 4 | """Helper functions dealing with emails in tests.""" |
357 | 5 | """ | 5 | |
358 | 6 | from __future__ import absolute_import, print_function | ||
359 | 7 | |||
360 | 6 | __metaclass__ = type | 8 | __metaclass__ = type |
361 | 7 | 9 | ||
362 | 8 | import email | 10 | import email |
363 | @@ -102,23 +104,23 @@ def print_emails(include_reply_to=False, group_similar=False, | |||
364 | 102 | distinct_bodies[body] = (message, recipients) | 104 | distinct_bodies[body] = (message, recipients) |
365 | 103 | for body in sorted(distinct_bodies): | 105 | for body in sorted(distinct_bodies): |
366 | 104 | message, recipients = distinct_bodies[body] | 106 | message, recipients = distinct_bodies[body] |
369 | 105 | print 'From:', message['From'] | 107 | print('From:', message['From']) |
370 | 106 | print 'To:', ", ".join(sorted(recipients)) | 108 | print('To:', ", ".join(sorted(recipients))) |
371 | 107 | if include_reply_to: | 109 | if include_reply_to: |
373 | 108 | print 'Reply-To:', message['Reply-To'] | 110 | print('Reply-To:', message['Reply-To']) |
374 | 109 | rationale_header = 'X-Launchpad-Message-Rationale' | 111 | rationale_header = 'X-Launchpad-Message-Rationale' |
375 | 110 | if include_rationale and rationale_header in message: | 112 | if include_rationale and rationale_header in message: |
377 | 111 | print '%s: %s' % (rationale_header, message[rationale_header]) | 113 | print('%s: %s' % (rationale_header, message[rationale_header])) |
378 | 112 | for_header = 'X-Launchpad-Message-For' | 114 | for_header = 'X-Launchpad-Message-For' |
379 | 113 | if include_for and for_header in message: | 115 | if include_for and for_header in message: |
381 | 114 | print '%s: %s' % (for_header, message[for_header]) | 116 | print('%s: %s' % (for_header, message[for_header])) |
382 | 115 | notification_type_header = 'X-Launchpad-Notification-Type' | 117 | notification_type_header = 'X-Launchpad-Notification-Type' |
383 | 116 | if include_notification_type and notification_type_header in message: | 118 | if include_notification_type and notification_type_header in message: |
389 | 117 | print '%s: %s' % ( | 119 | print('%s: %s' % ( |
390 | 118 | notification_type_header, message[notification_type_header]) | 120 | notification_type_header, message[notification_type_header])) |
391 | 119 | print 'Subject:', message['Subject'] | 121 | print('Subject:', message['Subject']) |
392 | 120 | print body | 122 | print(body) |
393 | 121 | print "-" * 40 | 123 | print("-" * 40) |
394 | 122 | 124 | ||
395 | 123 | 125 | ||
396 | 124 | def print_distinct_emails(include_reply_to=False, include_rationale=True, | 126 | def print_distinct_emails(include_reply_to=False, include_rationale=True, |
397 | diff --git a/lib/lp/testing/menu.py b/lib/lp/testing/menu.py | |||
398 | index 43ed314..f0f3676 100644 | |||
399 | --- a/lib/lp/testing/menu.py | |||
400 | +++ b/lib/lp/testing/menu.py | |||
401 | @@ -3,6 +3,8 @@ | |||
402 | 3 | 3 | ||
403 | 4 | """Helpers for testing menus.""" | 4 | """Helpers for testing menus.""" |
404 | 5 | 5 | ||
405 | 6 | from __future__ import absolute_import, print_function | ||
406 | 7 | |||
407 | 6 | __metaclass__ = type | 8 | __metaclass__ = type |
408 | 7 | __all__ = [ | 9 | __all__ = [ |
409 | 8 | 'summarise_tal_links', | 10 | 'summarise_tal_links', |
410 | @@ -62,14 +64,14 @@ def summarise_tal_links(links): | |||
411 | 62 | else: | 64 | else: |
412 | 63 | link = key | 65 | link = key |
413 | 64 | if ILink.providedBy(link): | 66 | if ILink.providedBy(link): |
415 | 65 | print 'link %s' % link.name | 67 | print('link %s' % link.name) |
416 | 66 | attributes = ('url', 'enabled', 'menu', 'selected', 'linked') | 68 | attributes = ('url', 'enabled', 'menu', 'selected', 'linked') |
417 | 67 | for attrname in attributes: | 69 | for attrname in attributes: |
418 | 68 | if not safe_hasattr(link, attrname): | 70 | if not safe_hasattr(link, attrname): |
419 | 69 | continue | 71 | continue |
421 | 70 | print ' %s:' % attrname, getattr(link, attrname) | 72 | print(' %s:' % attrname, getattr(link, attrname)) |
422 | 71 | else: | 73 | else: |
424 | 72 | print 'attribute %s: %s' % (key, link) | 74 | print('attribute %s: %s' % (key, link)) |
425 | 73 | 75 | ||
426 | 74 | 76 | ||
427 | 75 | def make_fake_request(url, traversed_objects=None): | 77 | def make_fake_request(url, traversed_objects=None): |
428 | diff --git a/lib/lp/testing/pages.py b/lib/lp/testing/pages.py | |||
429 | index b73d004..9e1b0c3 100644 | |||
430 | --- a/lib/lp/testing/pages.py | |||
431 | +++ b/lib/lp/testing/pages.py | |||
432 | @@ -3,6 +3,8 @@ | |||
433 | 3 | 3 | ||
434 | 4 | """Testing infrastructure for page tests.""" | 4 | """Testing infrastructure for page tests.""" |
435 | 5 | 5 | ||
436 | 6 | from __future__ import absolute_import, print_function | ||
437 | 7 | |||
438 | 6 | __metaclass__ = type | 8 | __metaclass__ = type |
439 | 7 | 9 | ||
440 | 8 | from contextlib import contextmanager | 10 | from contextlib import contextmanager |
441 | @@ -216,7 +218,7 @@ def find_tag_by_id(content, id): | |||
442 | 216 | return elements_with_id[0] | 218 | return elements_with_id[0] |
443 | 217 | else: | 219 | else: |
444 | 218 | raise DuplicateIdError( | 220 | raise DuplicateIdError( |
446 | 219 | 'Found %d elements with id %r' % (len(elements_with_id), id)) | 221 | "Found %d elements with id '%s'" % (len(elements_with_id), id)) |
447 | 220 | 222 | ||
448 | 221 | 223 | ||
449 | 222 | def first_tag_by_class(content, class_): | 224 | def first_tag_by_class(content, class_): |
450 | @@ -286,7 +288,7 @@ def get_feedback_messages(content): | |||
451 | 286 | def print_feedback_messages(content, formatter='minimal'): | 288 | def print_feedback_messages(content, formatter='minimal'): |
452 | 287 | """Print out the feedback messages.""" | 289 | """Print out the feedback messages.""" |
453 | 288 | for message in get_feedback_messages(content): | 290 | for message in get_feedback_messages(content): |
455 | 289 | print extract_text(message, formatter=formatter) | 291 | print(extract_text(message, formatter=formatter)) |
456 | 290 | 292 | ||
457 | 291 | 293 | ||
458 | 292 | def print_table(content, columns=None, skip_rows=None, sep="\t"): | 294 | def print_table(content, columns=None, skip_rows=None, sep="\t"): |
459 | @@ -307,7 +309,7 @@ def print_table(content, columns=None, skip_rows=None, sep="\t"): | |||
460 | 307 | if columns is None or col_num in columns: | 309 | if columns is None or col_num in columns: |
461 | 308 | row_content.append(extract_text(item)) | 310 | row_content.append(extract_text(item)) |
462 | 309 | if len(row_content) > 0: | 311 | if len(row_content) > 0: |
464 | 310 | print sep.join(row_content) | 312 | print(sep.join(row_content)) |
465 | 311 | 313 | ||
466 | 312 | 314 | ||
467 | 313 | def get_radio_button_text_for_field(soup, name): | 315 | def get_radio_button_text_for_field(soup, name): |
468 | @@ -340,7 +342,7 @@ def print_radio_button_field(content, name): | |||
469 | 340 | """ | 342 | """ |
470 | 341 | main = BeautifulSoup(content) | 343 | main = BeautifulSoup(content) |
471 | 342 | for field in get_radio_button_text_for_field(main, name): | 344 | for field in get_radio_button_text_for_field(main, name): |
473 | 343 | print field | 345 | print(field) |
474 | 344 | 346 | ||
475 | 345 | 347 | ||
476 | 346 | def strip_label(label): | 348 | def strip_label(label): |
477 | @@ -474,48 +476,48 @@ def parse_relationship_section(content): | |||
478 | 474 | section = soup.find('ul') | 476 | section = soup.find('ul') |
479 | 475 | whitespace_re = re.compile('\s+') | 477 | whitespace_re = re.compile('\s+') |
480 | 476 | if section is None: | 478 | if section is None: |
482 | 477 | print 'EMPTY SECTION' | 479 | print('EMPTY SECTION') |
483 | 478 | return | 480 | return |
484 | 479 | for li in section.findAll('li'): | 481 | for li in section.findAll('li'): |
485 | 480 | if li.a: | 482 | if li.a: |
486 | 481 | link = li.a | 483 | link = li.a |
487 | 482 | content = whitespace_re.sub(' ', link.string.strip()) | 484 | content = whitespace_re.sub(' ', link.string.strip()) |
488 | 483 | url = link['href'] | 485 | url = link['href'] |
490 | 484 | print 'LINK: "%s" -> %s' % (content, url) | 486 | print('LINK: "%s" -> %s' % (content, url)) |
491 | 485 | else: | 487 | else: |
492 | 486 | content = whitespace_re.sub(' ', li.string.strip()) | 488 | content = whitespace_re.sub(' ', li.string.strip()) |
494 | 487 | print 'TEXT: "%s"' % content | 489 | print('TEXT: "%s"' % content) |
495 | 488 | 490 | ||
496 | 489 | 491 | ||
497 | 490 | def print_action_links(content): | 492 | def print_action_links(content): |
498 | 491 | """Print action menu urls.""" | 493 | """Print action menu urls.""" |
499 | 492 | actions = find_tag_by_id(content, 'actions') | 494 | actions = find_tag_by_id(content, 'actions') |
500 | 493 | if actions is None: | 495 | if actions is None: |
502 | 494 | print "No actions portlet" | 496 | print("No actions portlet") |
503 | 495 | return | 497 | return |
504 | 496 | entries = actions.findAll('li') | 498 | entries = actions.findAll('li') |
505 | 497 | for entry in entries: | 499 | for entry in entries: |
506 | 498 | if entry.a: | 500 | if entry.a: |
508 | 499 | print '%s: %s' % (entry.a.string, entry.a['href']) | 501 | print('%s: %s' % (entry.a.string, entry.a['href'])) |
509 | 500 | elif entry.strong: | 502 | elif entry.strong: |
511 | 501 | print entry.strong.string | 503 | print(entry.strong.string) |
512 | 502 | 504 | ||
513 | 503 | 505 | ||
514 | 504 | def print_navigation_links(content): | 506 | def print_navigation_links(content): |
515 | 505 | """Print navigation menu urls.""" | 507 | """Print navigation menu urls.""" |
516 | 506 | navigation_links = find_tag_by_id(content, 'navigation-tabs') | 508 | navigation_links = find_tag_by_id(content, 'navigation-tabs') |
517 | 507 | if navigation_links is None: | 509 | if navigation_links is None: |
519 | 508 | print "No navigation links" | 510 | print("No navigation links") |
520 | 509 | return | 511 | return |
521 | 510 | title = navigation_links.find('label') | 512 | title = navigation_links.find('label') |
522 | 511 | if title is not None: | 513 | if title is not None: |
524 | 512 | print '= %s =' % title.string | 514 | print('= %s =' % title.string) |
525 | 513 | entries = navigation_links.findAll(['strong', 'a']) | 515 | entries = navigation_links.findAll(['strong', 'a']) |
526 | 514 | for entry in entries: | 516 | for entry in entries: |
527 | 515 | try: | 517 | try: |
529 | 516 | print '%s: %s' % (entry.span.string, entry['href']) | 518 | print('%s: %s' % (entry.span.string, entry['href'])) |
530 | 517 | except KeyError: | 519 | except KeyError: |
532 | 518 | print entry.span.string | 520 | print(entry.span.string) |
533 | 519 | 521 | ||
534 | 520 | 522 | ||
535 | 521 | def print_portlet_links(content, name, base=None): | 523 | def print_portlet_links(content, name, base=None): |
536 | @@ -536,15 +538,15 @@ def print_portlet_links(content, name, base=None): | |||
537 | 536 | 538 | ||
538 | 537 | portlet_contents = find_portlet(content, name) | 539 | portlet_contents = find_portlet(content, name) |
539 | 538 | if portlet_contents is None: | 540 | if portlet_contents is None: |
541 | 539 | print "No portlet found with name:", name | 541 | print("No portlet found with name:", name) |
542 | 540 | return | 542 | return |
543 | 541 | portlet_links = portlet_contents.findAll('a') | 543 | portlet_links = portlet_contents.findAll('a') |
544 | 542 | if len(portlet_links) == 0: | 544 | if len(portlet_links) == 0: |
546 | 543 | print "No links were found in the portlet." | 545 | print("No links were found in the portlet.") |
547 | 544 | return | 546 | return |
548 | 545 | for portlet_link in portlet_links: | 547 | for portlet_link in portlet_links: |
551 | 546 | print '%s: %s' % (portlet_link.string, | 548 | print('%s: %s' % (portlet_link.string, |
552 | 547 | extract_link_from_tag(portlet_link, base)) | 549 | extract_link_from_tag(portlet_link, base))) |
553 | 548 | 550 | ||
554 | 549 | 551 | ||
555 | 550 | def print_submit_buttons(content): | 552 | def print_submit_buttons(content): |
556 | @@ -555,10 +557,10 @@ def print_submit_buttons(content): | |||
557 | 555 | buttons = find_main_content(content).findAll( | 557 | buttons = find_main_content(content).findAll( |
558 | 556 | 'input', attrs={'class': 'button', 'type': 'submit'}) | 558 | 'input', attrs={'class': 'button', 'type': 'submit'}) |
559 | 557 | if buttons is None: | 559 | if buttons is None: |
561 | 558 | print "No buttons found" | 560 | print("No buttons found") |
562 | 559 | else: | 561 | else: |
563 | 560 | for button in buttons: | 562 | for button in buttons: |
565 | 561 | print button['value'] | 563 | print(button['value']) |
566 | 562 | 564 | ||
567 | 563 | 565 | ||
568 | 564 | def print_comments(page): | 566 | def print_comments(page): |
569 | @@ -566,31 +568,31 @@ def print_comments(page): | |||
570 | 566 | main_content = find_main_content(page) | 568 | main_content = find_main_content(page) |
571 | 567 | for comment in main_content('div', 'boardCommentBody'): | 569 | for comment in main_content('div', 'boardCommentBody'): |
572 | 568 | for li_tag in comment('li'): | 570 | for li_tag in comment('li'): |
576 | 569 | print "Attachment: %s" % li_tag.a.renderContents() | 571 | print("Attachment: %s" % li_tag.a.renderContents()) |
577 | 570 | print comment.div.renderContents() | 572 | print(comment.div.renderContents()) |
578 | 571 | print "-" * 40 | 573 | print("-" * 40) |
579 | 572 | 574 | ||
580 | 573 | 575 | ||
581 | 574 | def print_batch_header(soup): | 576 | def print_batch_header(soup): |
582 | 575 | """Print the batch navigator header.""" | 577 | """Print the batch navigator header.""" |
583 | 576 | navigation = soup.find('td', {'class': 'batch-navigation-index'}) | 578 | navigation = soup.find('td', {'class': 'batch-navigation-index'}) |
585 | 577 | print extract_text(navigation).encode('ASCII', 'backslashreplace') | 579 | print(extract_text(navigation).encode('ASCII', 'backslashreplace')) |
586 | 578 | 580 | ||
587 | 579 | 581 | ||
588 | 580 | def print_self_link_of_entries(json_body): | 582 | def print_self_link_of_entries(json_body): |
589 | 581 | """Print the self_link attribute of each entry in the given JSON body.""" | 583 | """Print the self_link attribute of each entry in the given JSON body.""" |
590 | 582 | links = sorted(entry['self_link'] for entry in json_body['entries']) | 584 | links = sorted(entry['self_link'] for entry in json_body['entries']) |
591 | 583 | for link in links: | 585 | for link in links: |
593 | 584 | print link | 586 | print(link) |
594 | 585 | 587 | ||
595 | 586 | 588 | ||
596 | 587 | def print_ppa_packages(contents): | 589 | def print_ppa_packages(contents): |
597 | 588 | packages = find_tags_by_class(contents, 'archive_package_row') | 590 | packages = find_tags_by_class(contents, 'archive_package_row') |
598 | 589 | for pkg in packages: | 591 | for pkg in packages: |
600 | 590 | print extract_text(pkg) | 592 | print(extract_text(pkg)) |
601 | 591 | empty_section = find_tag_by_id(contents, 'empty-result') | 593 | empty_section = find_tag_by_id(contents, 'empty-result') |
602 | 592 | if empty_section is not None: | 594 | if empty_section is not None: |
604 | 593 | print extract_text(empty_section) | 595 | print(extract_text(empty_section)) |
605 | 594 | 596 | ||
606 | 595 | 597 | ||
607 | 596 | def print_location(contents): | 598 | def print_location(contents): |
608 | @@ -614,8 +616,8 @@ def print_location(contents): | |||
609 | 614 | else: | 616 | else: |
610 | 615 | breadcrumbs = ' > '.join(segments) | 617 | breadcrumbs = ' > '.join(segments) |
611 | 616 | 618 | ||
614 | 617 | print 'Hierarchy:', breadcrumbs | 619 | print('Hierarchy:', breadcrumbs) |
615 | 618 | print 'Tabs:' | 620 | print('Tabs:') |
616 | 619 | print_location_apps(contents) | 621 | print_location_apps(contents) |
617 | 620 | main_heading = doc.h1 | 622 | main_heading = doc.h1 |
618 | 621 | if main_heading: | 623 | if main_heading: |
619 | @@ -623,7 +625,7 @@ def print_location(contents): | |||
620 | 623 | 'us-ascii', 'replace') | 625 | 'us-ascii', 'replace') |
621 | 624 | else: | 626 | else: |
622 | 625 | main_heading = '(No main heading)' | 627 | main_heading = '(No main heading)' |
624 | 626 | print "Main heading: %s" % main_heading | 628 | print("Main heading: %s" % main_heading) |
625 | 627 | 629 | ||
626 | 628 | 630 | ||
627 | 629 | def print_location_apps(contents): | 631 | def print_location_apps(contents): |
628 | @@ -636,9 +638,9 @@ def print_location_apps(contents): | |||
629 | 636 | else: | 638 | else: |
630 | 637 | location_apps = location_apps.findAll('span') | 639 | location_apps = location_apps.findAll('span') |
631 | 638 | if location_apps is None: | 640 | if location_apps is None: |
633 | 639 | print "(Application tabs omitted)" | 641 | print("(Application tabs omitted)") |
634 | 640 | elif len(location_apps) == 0: | 642 | elif len(location_apps) == 0: |
636 | 641 | print "(No application tabs)" | 643 | print("(No application tabs)") |
637 | 642 | else: | 644 | else: |
638 | 643 | for tab in location_apps: | 645 | for tab in location_apps: |
639 | 644 | tab_text = extract_text(tab) | 646 | tab_text = extract_text(tab) |
640 | @@ -652,13 +654,13 @@ def print_location_apps(contents): | |||
641 | 652 | link = tab.a['href'] | 654 | link = tab.a['href'] |
642 | 653 | else: | 655 | else: |
643 | 654 | link = 'not linked' | 656 | link = 'not linked' |
645 | 655 | print "* %s - %s" % (tab_text, link) | 657 | print("* %s - %s" % (tab_text, link)) |
646 | 656 | 658 | ||
647 | 657 | 659 | ||
648 | 658 | def print_tag_with_id(contents, id): | 660 | def print_tag_with_id(contents, id): |
649 | 659 | """A simple helper to print the extracted text of the tag.""" | 661 | """A simple helper to print the extracted text of the tag.""" |
650 | 660 | tag = find_tag_by_id(contents, id) | 662 | tag = find_tag_by_id(contents, id) |
652 | 661 | print extract_text(tag) | 663 | print(extract_text(tag)) |
653 | 662 | 664 | ||
654 | 663 | 665 | ||
655 | 664 | def print_errors(contents): | 666 | def print_errors(contents): |
656 | @@ -666,7 +668,7 @@ def print_errors(contents): | |||
657 | 666 | errors = find_tags_by_class(contents, 'error') | 668 | errors = find_tags_by_class(contents, 'error') |
658 | 667 | error_texts = [extract_text(error) for error in errors] | 669 | error_texts = [extract_text(error) for error in errors] |
659 | 668 | for error in error_texts: | 670 | for error in error_texts: |
661 | 669 | print error | 671 | print(error) |
662 | 670 | 672 | ||
663 | 671 | 673 | ||
664 | 672 | def setupBrowser(auth=None): | 674 | def setupBrowser(auth=None): |
665 | diff --git a/lib/lp/testing/publication.py b/lib/lp/testing/publication.py | |||
666 | index 929c643..7f8ee3a 100644 | |||
667 | --- a/lib/lp/testing/publication.py | |||
668 | +++ b/lib/lp/testing/publication.py | |||
669 | @@ -3,6 +3,8 @@ | |||
670 | 3 | 3 | ||
671 | 4 | """Helpers for testing out publication related code.""" | 4 | """Helpers for testing out publication related code.""" |
672 | 5 | 5 | ||
673 | 6 | from __future__ import absolute_import, print_function | ||
674 | 7 | |||
675 | 6 | __metaclass__ = type | 8 | __metaclass__ = type |
676 | 7 | __all__ = [ | 9 | __all__ = [ |
677 | 8 | 'get_request_and_publication', | 10 | 'get_request_and_publication', |
678 | @@ -67,15 +69,15 @@ def print_request_and_publication(host='localhost', port=None, | |||
679 | 67 | request, publication = get_request_and_publication( | 69 | request, publication = get_request_and_publication( |
680 | 68 | host, port, method, mime_type, | 70 | host, port, method, mime_type, |
681 | 69 | extra_environment=extra_environment) | 71 | extra_environment=extra_environment) |
683 | 70 | print type(request).__name__.split('.')[-1] | 72 | print(type(request).__name__.split('.')[-1]) |
684 | 71 | publication_classname = type(publication).__name__.split('.')[-1] | 73 | publication_classname = type(publication).__name__.split('.')[-1] |
685 | 72 | if isinstance(publication, ProtocolErrorPublication): | 74 | if isinstance(publication, ProtocolErrorPublication): |
688 | 73 | print "%s: status=%d" % ( | 75 | print("%s: status=%d" % ( |
689 | 74 | publication_classname, publication.status) | 76 | publication_classname, publication.status)) |
690 | 75 | for name, value in publication.headers.items(): | 77 | for name, value in publication.headers.items(): |
692 | 76 | print " %s: %s" % (name, value) | 78 | print(" %s: %s" % (name, value)) |
693 | 77 | else: | 79 | else: |
695 | 78 | print publication_classname | 80 | print(publication_classname) |
696 | 79 | 81 | ||
697 | 80 | 82 | ||
698 | 81 | def test_traverse(url): | 83 | def test_traverse(url): |
699 | diff --git a/lib/lp/testing/systemdocs.py b/lib/lp/testing/systemdocs.py | |||
700 | index d72d7e7..5a34004 100644 | |||
701 | --- a/lib/lp/testing/systemdocs.py | |||
702 | +++ b/lib/lp/testing/systemdocs.py | |||
703 | @@ -3,6 +3,8 @@ | |||
704 | 3 | 3 | ||
705 | 4 | """Infrastructure for setting up doctests.""" | 4 | """Infrastructure for setting up doctests.""" |
706 | 5 | 5 | ||
707 | 6 | from __future__ import absolute_import, print_function | ||
708 | 7 | |||
709 | 6 | __metaclass__ = type | 8 | __metaclass__ = type |
710 | 7 | __all__ = [ | 9 | __all__ = [ |
711 | 8 | 'default_optionflags', | 10 | 'default_optionflags', |
712 | @@ -85,8 +87,8 @@ class StdoutHandler(Handler): | |||
713 | 85 | """ | 87 | """ |
714 | 86 | def emit(self, record): | 88 | def emit(self, record): |
715 | 87 | Handler.emit(self, record) | 89 | Handler.emit(self, record) |
718 | 88 | print >> sys.stdout, '%s:%s:%s' % ( | 90 | print('%s:%s:%s' % ( |
719 | 89 | record.levelname, record.name, self.format(record)) | 91 | record.levelname, record.name, self.format(record))) |
720 | 90 | 92 | ||
721 | 91 | 93 | ||
722 | 92 | def LayeredDocFileSuite(paths, id_extensions=None, **kw): | 94 | def LayeredDocFileSuite(paths, id_extensions=None, **kw): |
723 | diff --git a/lib/lp/testing/tests/test_doc.py b/lib/lp/testing/tests/test_doc.py | |||
724 | index 7ce594c..66783e9 100644 | |||
725 | --- a/lib/lp/testing/tests/test_doc.py | |||
726 | +++ b/lib/lp/testing/tests/test_doc.py | |||
727 | @@ -8,10 +8,11 @@ Run the doctests and pagetests. | |||
728 | 8 | import os | 8 | import os |
729 | 9 | 9 | ||
730 | 10 | from lp.services.testing import build_test_suite | 10 | from lp.services.testing import build_test_suite |
731 | 11 | from lp.testing.systemdocs import setUp | ||
732 | 11 | 12 | ||
733 | 12 | 13 | ||
734 | 13 | here = os.path.dirname(os.path.realpath(__file__)) | 14 | here = os.path.dirname(os.path.realpath(__file__)) |
735 | 14 | 15 | ||
736 | 15 | 16 | ||
737 | 16 | def test_suite(): | 17 | def test_suite(): |
739 | 17 | return build_test_suite(here) | 18 | return build_test_suite(here, setUp=lambda test: setUp(test, future=True)) |
740 | diff --git a/lib/lp/testing/yuixhr.py b/lib/lp/testing/yuixhr.py | |||
741 | index 13a9cd6..8a601e8 100644 | |||
742 | --- a/lib/lp/testing/yuixhr.py | |||
743 | +++ b/lib/lp/testing/yuixhr.py | |||
744 | @@ -3,6 +3,8 @@ | |||
745 | 3 | 3 | ||
746 | 4 | """Fixture code for YUITest + XHR integration testing.""" | 4 | """Fixture code for YUITest + XHR integration testing.""" |
747 | 5 | 5 | ||
748 | 6 | from __future__ import absolute_import, print_function | ||
749 | 7 | |||
750 | 6 | __metaclass__ = type | 8 | __metaclass__ = type |
751 | 7 | __all__ = [ | 9 | __all__ = [ |
752 | 8 | 'login_as_person', | 10 | 'login_as_person', |
753 | @@ -146,7 +148,7 @@ class CloseDbResult: | |||
754 | 146 | yield '' | 148 | yield '' |
755 | 147 | LibrarianLayer.testSetUp() | 149 | LibrarianLayer.testSetUp() |
756 | 148 | except Exception: | 150 | except Exception: |
758 | 149 | print "Hm, serious error when trying to clean up the test." | 151 | print("Hm, serious error when trying to clean up the test.") |
759 | 150 | traceback.print_exc() | 152 | traceback.print_exc() |
760 | 151 | # We're done, so we can yield the body. | 153 | # We're done, so we can yield the body. |
761 | 152 | yield '\n' | 154 | yield '\n' |
Looks fab, thanks - generally approve but I'd appreciate context on the build_test_suite change please