Merge ~cjwatson/launchpad:app-future-imports-prepare into launchpad:master
- Git
- lp:~cjwatson/launchpad
- app-future-imports-prepare
- Merge into master
Proposed by
Colin Watson
Status: | Merged |
---|---|
Approved by: | Colin Watson |
Approved revision: | 2999a51c79861db2865fb526999f9fefb59e653e |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~cjwatson/launchpad:app-future-imports-prepare |
Merge into: | launchpad:master |
Diff against target: |
633 lines (+130/-113) 19 files modified
lib/lp/app/browser/doc/launchpad-search-pages.txt (+8/-3) lib/lp/app/doc/displaying-numbers.txt (+4/-4) lib/lp/app/doc/displaying-paragraphs-of-text.txt (+12/-7) lib/lp/app/doc/launchpadform.txt (+1/-1) lib/lp/app/doc/launchpadview.txt (+2/-2) lib/lp/app/doc/loginstatus-pages.txt (+12/-12) lib/lp/app/doc/menus.txt (+1/-1) lib/lp/app/doc/tales.txt (+67/-61) lib/lp/app/doc/textformatting.txt (+2/-2) lib/lp/app/tests/test_doc.py (+2/-1) lib/lp/app/validators/name.py (+4/-4) lib/lp/app/validators/username.py (+6/-6) lib/lp/app/widgets/doc/announcement-date-widget.txt (+1/-1) lib/lp/app/widgets/doc/project-scope-widget.txt (+2/-1) lib/lp/app/widgets/doc/stripped-text-widget.txt (+3/-3) lib/lp/bugs/stories/bugs/xx-incomplete-bugs.txt (+0/-2) lib/lp/registry/stories/teammembership/xx-teammembership.txt (+0/-2) lib/lp/testing/pages.py (+1/-0) lib/lp/testing/systemdocs.py (+2/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Thiago F. Pappacena (community) | Approve | ||
Review via email: mp+383046@code.launchpad.net |
Commit message
Prepare for __future__ imports in lp.app doctests
Description of the change
These are various non-mechanical fixes in preparation for converting the doctests under lp.app to Launchpad's preferred __future__ imports. Most of these are to avoid problems with unicode_literals; the fix is normally either to use print() rather than testing a value's __repr__, or to use six.ensure_str to cause input data to be str rather than unicode where appropriate.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lib/lp/app/browser/doc/launchpad-search-pages.txt b/lib/lp/app/browser/doc/launchpad-search-pages.txt |
2 | index 8edcf03..49442e7 100644 |
3 | --- a/lib/lp/app/browser/doc/launchpad-search-pages.txt |
4 | +++ b/lib/lp/app/browser/doc/launchpad-search-pages.txt |
5 | @@ -32,12 +32,17 @@ when there is no search text. |
6 | |
7 | When text is not None, the title indicates what was searched. |
8 | |
9 | + >>> from lp.services.encoding import wsgi_native_string |
10 | + |
11 | >>> def getSearchView(form): |
12 | ... search_param_list = [] |
13 | ... for name in sorted(form): |
14 | ... value = form[name] |
15 | - ... search_param_list.append('%s=%s' % (name, value)) |
16 | - ... query_string = '&'.join(search_param_list) |
17 | + ... if isinstance(value, six.text_type): |
18 | + ... value = wsgi_native_string(value) |
19 | + ... search_param_list.append(b'%s=%s' % ( |
20 | + ... wsgi_native_string(name), value)) |
21 | + ... query_string = b'&'.join(search_param_list) |
22 | ... request = LaunchpadTestRequest( |
23 | ... SERVER_URL='https://launchpad.test/+search', |
24 | ... QUERY_STRING=query_string, form=form, PATH_INFO='/+search') |
25 | @@ -540,7 +545,7 @@ error. Also disable warnings, since we are tossing around malformed Unicode. |
26 | >>> with warnings.catch_warnings(): |
27 | ... warnings.simplefilter('ignore') |
28 | ... search_view = getSearchView( |
29 | - ... form={'field.text': '\xfe\xfckr\xfc'}) |
30 | + ... form={'field.text': b'\xfe\xfckr\xfc'}) |
31 | >>> html = search_view() |
32 | >>> 'Can not convert your search term' in html |
33 | True |
34 | diff --git a/lib/lp/app/doc/displaying-numbers.txt b/lib/lp/app/doc/displaying-numbers.txt |
35 | index bc89a9f..fcae7bc 100644 |
36 | --- a/lib/lp/app/doc/displaying-numbers.txt |
37 | +++ b/lib/lp/app/doc/displaying-numbers.txt |
38 | @@ -45,13 +45,13 @@ to how the Python "%f" string formatter works: |
39 | For instance: |
40 | |
41 | >>> foo = 12345.67890 |
42 | - >>> test_tales('foo/fmt:float/7.2', foo=foo) |
43 | - '12345.68' |
44 | + >>> print(test_tales('foo/fmt:float/7.2', foo=foo)) |
45 | + 12345.68 |
46 | |
47 | Is the same as: |
48 | |
49 | - >>> "%7.2f" % foo |
50 | - '12345.68' |
51 | + >>> print("%7.2f" % foo) |
52 | + 12345.68 |
53 | |
54 | Here's a set of exhaustive examples: |
55 | |
56 | diff --git a/lib/lp/app/doc/displaying-paragraphs-of-text.txt b/lib/lp/app/doc/displaying-paragraphs-of-text.txt |
57 | index a2df0b4..1c48b85 100644 |
58 | --- a/lib/lp/app/doc/displaying-paragraphs-of-text.txt |
59 | +++ b/lib/lp/app/doc/displaying-paragraphs-of-text.txt |
60 | @@ -485,7 +485,7 @@ we want to replace a variable number of spaces with the same number of |
61 | |
62 | >>> from lp.app.browser.stringformatter import FormattersAPI |
63 | >>> import re |
64 | - >>> matchobj = re.match('foo(.*)bar', 'fooX Ybar') |
65 | + >>> matchobj = re.match('foo(.*)bar', six.ensure_str('fooX Ybar')) |
66 | >>> matchobj.groups() |
67 | ('X Y',) |
68 | >>> FormattersAPI._substitute_matchgroup_for_spaces(matchobj) |
69 | @@ -499,9 +499,10 @@ First, let's try a match of nothing it understands. This is a bug, so we get |
70 | an AssertionError. |
71 | |
72 | >>> matchobj = re.match( |
73 | - ... ('(?P<bug>xxx)?(?P<faq>www)?(?P<url>yyy)?(?P<oops>zzz)?' |
74 | - ... '(?P<lpbranchurl>www)?(?P<clbug>vvv)?'), |
75 | - ... 'fish') |
76 | + ... six.ensure_str( |
77 | + ... '(?P<bug>xxx)?(?P<faq>www)?(?P<url>yyy)?(?P<oops>zzz)?' |
78 | + ... '(?P<lpbranchurl>www)?(?P<clbug>vvv)?'), |
79 | + ... six.ensure_str('fish')) |
80 | >>> sorted(matchobj.groupdict().items()) |
81 | [('bug', None), |
82 | ('clbug', None), |
83 | @@ -517,7 +518,9 @@ an AssertionError. |
84 | When we have a URL, the URL is made into a link. A quote is added to the |
85 | url to demonstrate quoting in the HTML attribute. |
86 | |
87 | - >>> matchobj = re.match('(?P<bug>xxx)?(?P<url>y"y)?', 'y"y') |
88 | + >>> matchobj = re.match( |
89 | + ... six.ensure_str('(?P<bug>xxx)?(?P<url>y"y)?'), |
90 | + ... six.ensure_str('y"y')) |
91 | >>> sorted(matchobj.groupdict().items()) |
92 | [('bug', None), ('url', 'y"y')] |
93 | >>> FormattersAPI._linkify_substitution(matchobj) |
94 | @@ -527,7 +530,8 @@ When we have a bug reference, the 'bug' group is used as the text of the link, |
95 | and the 'bugnum' is used to look up the bug. |
96 | |
97 | >>> matchobj = re.match( |
98 | - ... '(?P<bug>xxxx)?(?P<bugnum>2)?(?P<url>yyy)?', 'xxxx2') |
99 | + ... six.ensure_str('(?P<bug>xxxx)?(?P<bugnum>2)?(?P<url>yyy)?'), |
100 | + ... six.ensure_str('xxxx2')) |
101 | >>> sorted(matchobj.groupdict().items()) |
102 | [('bug', 'xxxx'), ('bugnum', '2'), ('url', None)] |
103 | >>> FormattersAPI._linkify_substitution(matchobj) |
104 | @@ -537,7 +541,8 @@ When the bugnum doesn't match any bug, we still get a link, but get a message |
105 | in the link's title. |
106 | |
107 | >>> matchobj = re.match( |
108 | - ... '(?P<bug>xxxx)?(?P<bugnum>2000)?(?P<url>yyy)?', 'xxxx2000') |
109 | + ... six.ensure_str('(?P<bug>xxxx)?(?P<bugnum>2000)?(?P<url>yyy)?'), |
110 | + ... six.ensure_str('xxxx2000')) |
111 | >>> sorted(matchobj.groupdict().items()) |
112 | [('bug', 'xxxx'), ('bugnum', '2000'), ('url', None)] |
113 | >>> FormattersAPI._linkify_substitution(matchobj) |
114 | diff --git a/lib/lp/app/doc/launchpadform.txt b/lib/lp/app/doc/launchpadform.txt |
115 | index 6af879c..95bca7e 100644 |
116 | --- a/lib/lp/app/doc/launchpadform.txt |
117 | +++ b/lib/lp/app/doc/launchpadform.txt |
118 | @@ -221,7 +221,7 @@ setFieldError() method (for errors specific to a field): |
119 | ... self.addError('your password may not be the same ' |
120 | ... 'as your name') |
121 | ... if data.get('password') == 'password': |
122 | - ... self.setFieldError('password', |
123 | + ... self.setFieldError(six.ensure_str('password'), |
124 | ... 'your password must not be "password"') |
125 | |
126 | >>> context = FormTest() |
127 | diff --git a/lib/lp/app/doc/launchpadview.txt b/lib/lp/app/doc/launchpadview.txt |
128 | index b5617b8..07942aa 100644 |
129 | --- a/lib/lp/app/doc/launchpadview.txt |
130 | +++ b/lib/lp/app/doc/launchpadview.txt |
131 | @@ -62,7 +62,7 @@ an IStructuredString implementation. |
132 | >>> print view.info_message |
133 | None |
134 | |
135 | - >>> view.error_message = 'A simple string.' |
136 | + >>> view.error_message = six.ensure_str('A simple string.') |
137 | Traceback (most recent call last): |
138 | ... |
139 | ValueError: <type 'str'> is not a valid value for error_message, |
140 | @@ -70,7 +70,7 @@ an IStructuredString implementation. |
141 | >>> print view.error_message |
142 | None |
143 | |
144 | - >>> view.info_message = 'A simple string.' |
145 | + >>> view.info_message = six.ensure_str('A simple string.') |
146 | Traceback (most recent call last): |
147 | ... |
148 | ValueError: <type 'str'> is not a valid value for info_message, |
149 | diff --git a/lib/lp/app/doc/loginstatus-pages.txt b/lib/lp/app/doc/loginstatus-pages.txt |
150 | index 16fceaf..a07e314 100644 |
151 | --- a/lib/lp/app/doc/loginstatus-pages.txt |
152 | +++ b/lib/lp/app/doc/loginstatus-pages.txt |
153 | @@ -27,8 +27,8 @@ Generic request without query args. |
154 | False |
155 | >>> status.login_shown |
156 | True |
157 | - >>> status.login_url |
158 | - 'http://localhost/foo/bar/+login' |
159 | + >>> print(status.login_url) |
160 | + http://localhost/foo/bar/+login |
161 | |
162 | Virtual hosted request with a trailing slash. |
163 | |
164 | @@ -37,8 +37,8 @@ Virtual hosted request with a trailing slash. |
165 | ... '/++vh++https:staging.example.com:433/++/foo/bar/', '') |
166 | >>> context = object() |
167 | >>> status = LoginStatus(context, request) |
168 | - >>> status.login_url |
169 | - 'https://staging.example.com/foo/bar/+login' |
170 | + >>> print(status.login_url) |
171 | + https://staging.example.com/foo/bar/+login |
172 | |
173 | Virtual hosted request with no trailing slash. |
174 | |
175 | @@ -47,8 +47,8 @@ Virtual hosted request with no trailing slash. |
176 | ... '/++vh++https:staging.example.com:433/++/foo/bar', '') |
177 | >>> context = object() |
178 | >>> status = LoginStatus(context, request) |
179 | - >>> status.login_url |
180 | - 'https://staging.example.com/foo/bar/+login' |
181 | + >>> print(status.login_url) |
182 | + https://staging.example.com/foo/bar/+login |
183 | |
184 | Generic request with trailing slash and query parameters. |
185 | |
186 | @@ -56,8 +56,8 @@ Generic request with trailing slash and query parameters. |
187 | ... 'http://localhost', '/foo/bar/', 'x=1&y=2') |
188 | >>> context = object() |
189 | >>> status = LoginStatus(context, request) |
190 | - >>> status.login_url |
191 | - 'http://localhost/foo/bar/+login?x=1&y=2' |
192 | + >>> print(status.login_url) |
193 | + http://localhost/foo/bar/+login?x=1&y=2 |
194 | |
195 | The login page. |
196 | |
197 | @@ -80,8 +80,8 @@ The logout page. |
198 | False |
199 | >>> status.login_shown |
200 | True |
201 | - >>> status.login_url |
202 | - 'http://localhost/+login' |
203 | + >>> print(status.login_url) |
204 | + http://localhost/+login |
205 | |
206 | The +openid-callback page. |
207 | |
208 | @@ -93,8 +93,8 @@ The +openid-callback page. |
209 | False |
210 | >>> status.login_shown |
211 | True |
212 | - >>> status.login_url |
213 | - 'http://localhost/+login' |
214 | + >>> print(status.login_url) |
215 | + http://localhost/+login |
216 | |
217 | Logging in. |
218 | |
219 | diff --git a/lib/lp/app/doc/menus.txt b/lib/lp/app/doc/menus.txt |
220 | index e982b25..e761f1b 100644 |
221 | --- a/lib/lp/app/doc/menus.txt |
222 | +++ b/lib/lp/app/doc/menus.txt |
223 | @@ -33,7 +33,7 @@ later, implementations having facets and menus will be defined. |
224 | |
225 | >>> import sys |
226 | >>> import types |
227 | - >>> cookingexample = types.ModuleType('cookingexample') |
228 | + >>> cookingexample = types.ModuleType(six.ensure_str('cookingexample')) |
229 | >>> sys.modules['lp.app.cookingexample'] = cookingexample |
230 | |
231 | >>> cookingexample.ICookbook = ICookbook |
232 | diff --git a/lib/lp/app/doc/tales.txt b/lib/lp/app/doc/tales.txt |
233 | index cc7606e..682360a 100644 |
234 | --- a/lib/lp/app/doc/tales.txt |
235 | +++ b/lib/lp/app/doc/tales.txt |
236 | @@ -266,8 +266,8 @@ fmt:rfc822utcdatetime. |
237 | |
238 | To truncate a long string, use fmt:shorten: |
239 | |
240 | - >>> test_tales('foo/fmt:shorten/8', foo='abcdefghij') |
241 | - 'abcde...' |
242 | + >>> print(test_tales('foo/fmt:shorten/8', foo='abcdefghij')) |
243 | + abcde... |
244 | |
245 | To ellipsize the middle of a string. use fmt:ellipsize and pass the max |
246 | length. |
247 | @@ -1080,35 +1080,35 @@ the start of the string is not a letter. If any invalid characters are |
248 | stripped out, to ensure the id is unique, a base64 encoding is appended to the |
249 | id. |
250 | |
251 | - >>> test_tales('foo/fmt:css-id', foo='beta2-milestone') |
252 | - 'beta2-milestone' |
253 | + >>> print(test_tales('foo/fmt:css-id', foo='beta2-milestone')) |
254 | + beta2-milestone |
255 | |
256 | - >>> test_tales('foo/fmt:css-id', foo='user name') |
257 | - 'user-name-dXNlciBuYW1l' |
258 | + >>> print(test_tales('foo/fmt:css-id', foo='user name')) |
259 | + user-name-dXNlciBuYW1l |
260 | |
261 | - >>> test_tales('foo/fmt:css-id', foo='1.0.1_series') |
262 | - 'j1-0-1_series' |
263 | + >>> print(test_tales('foo/fmt:css-id', foo='1.0.1_series')) |
264 | + j1-0-1_series |
265 | |
266 | An optional prefix for the if can be added to the path. It too will be |
267 | escaped. |
268 | |
269 | - >>> test_tales('foo/fmt:css-id/series-', foo='1.0.1_series') |
270 | - 'series-1-0-1_series' |
271 | + >>> print(test_tales('foo/fmt:css-id/series-', foo='1.0.1_series')) |
272 | + series-1-0-1_series |
273 | |
274 | - >>> test_tales('foo/fmt:css-id/series_', foo='1.0.1_series') |
275 | - 'series_1-0-1_series' |
276 | + >>> print(test_tales('foo/fmt:css-id/series_', foo='1.0.1_series')) |
277 | + series_1-0-1_series |
278 | |
279 | - >>> test_tales('foo/fmt:css-id/0series-', foo='1.0.1_series') |
280 | - 'j0series-1-0-1_series' |
281 | + >>> print(test_tales('foo/fmt:css-id/0series-', foo='1.0.1_series')) |
282 | + j0series-1-0-1_series |
283 | |
284 | Zope fields are rendered with a period, and we need to ensure there is a way |
285 | to retain the periods in the css id even though we would prefer not to. |
286 | |
287 | - >>> test_tales('foo/fmt:zope-css-id', foo='field.bug.target') |
288 | - 'field.bug.target' |
289 | + >>> print(test_tales('foo/fmt:zope-css-id', foo='field.bug.target')) |
290 | + field.bug.target |
291 | |
292 | - >>> test_tales('foo/fmt:zope-css-id', foo='field.gtk+_package') |
293 | - 'field.gtk-_package-ZmllbGQuZ3RrK19wYWNrYWdl' |
294 | + >>> print(test_tales('foo/fmt:zope-css-id', foo='field.gtk+_package')) |
295 | + field.gtk-_package-ZmllbGQuZ3RrK19wYWNrYWdl |
296 | |
297 | The fmt: namespace to get strings (obfuscation) |
298 | ----------------------------------------------- |
299 | @@ -1119,32 +1119,36 @@ unauthenticated users, the email address can be hidden. The address is |
300 | replaced with the message '<email address hidden>'. |
301 | |
302 | >>> login(ANONYMOUS) |
303 | - >>> test_tales('foo/fmt:obfuscate-email', foo='name.surname@company.com') |
304 | - '<email address hidden>' |
305 | + >>> print(test_tales( |
306 | + ... 'foo/fmt:obfuscate-email', foo='name.surname@company.com')) |
307 | + <email address hidden> |
308 | |
309 | - >>> test_tales('foo/fmt:obfuscate-email', foo='name@organization.org.cc') |
310 | - '<email address hidden>' |
311 | + >>> print(test_tales( |
312 | + ... 'foo/fmt:obfuscate-email', foo='name@organization.org.cc')) |
313 | + <email address hidden> |
314 | |
315 | - >>> test_tales('foo/fmt:obfuscate-email', foo='name+sub@domain.org') |
316 | - '<email address hidden>' |
317 | + >>> print(test_tales( |
318 | + ... 'foo/fmt:obfuscate-email', foo='name+sub@domain.org')) |
319 | + <email address hidden> |
320 | |
321 | - >>> test_tales('foo/fmt:obfuscate-email', |
322 | - ... foo='long_name@host.long-network.org.cc') |
323 | - '<email address hidden>' |
324 | + >>> print(test_tales('foo/fmt:obfuscate-email', |
325 | + ... foo='long_name@host.long-network.org.cc')) |
326 | + <email address hidden> |
327 | |
328 | - >>> test_tales('foo/fmt:obfuscate-email', |
329 | - ... foo='"long/name="@organization.org') |
330 | - '"<email address hidden>' |
331 | + >>> print(test_tales('foo/fmt:obfuscate-email', |
332 | + ... foo='"long/name="@organization.org')) |
333 | + "<email address hidden> |
334 | |
335 | - >>> test_tales('foo/fmt:obfuscate-email', |
336 | - ... foo='long-name@building.museum') |
337 | - '<email address hidden>' |
338 | + >>> print(test_tales('foo/fmt:obfuscate-email', |
339 | + ... foo='long-name@building.museum')) |
340 | + <email address hidden> |
341 | |
342 | - >>> test_tales('foo/fmt:obfuscate-email', foo='foo@staticmethod.com') |
343 | - '<email address hidden>' |
344 | + >>> print(test_tales( |
345 | + ... 'foo/fmt:obfuscate-email', foo='foo@staticmethod.com')) |
346 | + <email address hidden> |
347 | |
348 | - >>> test_tales('foo/fmt:obfuscate-email', foo='<foo@bar.com>') |
349 | - '<email address hidden>' |
350 | + >>> print(test_tales('foo/fmt:obfuscate-email', foo='<foo@bar.com>')) |
351 | + <email address hidden> |
352 | |
353 | >>> print test_tales('foo/fmt:obfuscate-email/fmt:text-to-html', |
354 | ... foo=signature) |
355 | @@ -1153,41 +1157,43 @@ replaced with the message '<email address hidden>'. |
356 | <email address hidden><br /> |
357 | Guilty of stealing everything I am.</p> |
358 | |
359 | - >>> test_tales('foo/fmt:obfuscate-email', |
360 | - ... foo='mailto:long-name@very.long.dom.cc') |
361 | - 'mailto:<email address hidden>' |
362 | + >>> print(test_tales('foo/fmt:obfuscate-email', |
363 | + ... foo='mailto:long-name@very.long.dom.cc')) |
364 | + mailto:<email address hidden> |
365 | |
366 | - >>> test_tales('foo/fmt:obfuscate-email', |
367 | - ... foo='http://person:password@site.net') |
368 | - 'http://person:<email address hidden>' |
369 | + >>> print(test_tales('foo/fmt:obfuscate-email', |
370 | + ... foo='http://person:password@site.net')) |
371 | + http://person:<email address hidden> |
372 | |
373 | - >>> test_tales('foo/fmt:obfuscate-email', foo='name @ host.school.edu') |
374 | - 'name @ host.school.edu' |
375 | + >>> print(test_tales( |
376 | + ... 'foo/fmt:obfuscate-email', foo='name @ host.school.edu')) |
377 | + name @ host.school.edu |
378 | |
379 | - >>> test_tales('foo/fmt:obfuscate-email', foo='person@host') |
380 | - 'person@host' |
381 | + >>> print(test_tales('foo/fmt:obfuscate-email', foo='person@host')) |
382 | + person@host |
383 | |
384 | - >>> test_tales('foo/fmt:obfuscate-email', foo='(head, tail)=@array') |
385 | - '(head, tail)=@array' |
386 | + >>> print(test_tales( |
387 | + ... 'foo/fmt:obfuscate-email', foo='(head, tail)=@array')) |
388 | + (head, tail)=@array |
389 | |
390 | - >>> test_tales('foo/fmt:obfuscate-email', foo='@staticmethod') |
391 | - '@staticmethod' |
392 | + >>> print(test_tales('foo/fmt:obfuscate-email', foo='@staticmethod')) |
393 | + @staticmethod |
394 | |
395 | - >>> test_tales('foo/fmt:obfuscate-email', foo='element/@attribute') |
396 | - 'element/@attribute' |
397 | + >>> print(test_tales('foo/fmt:obfuscate-email', foo='element/@attribute')) |
398 | + element/@attribute |
399 | |
400 | >>> bad_address = ( |
401 | ... "medicalwei@sara:~$ Spinning................................" |
402 | ... "...........................................................not") |
403 | - >>> test_tales('foo/fmt:obfuscate-email', foo=bad_address) |
404 | - 'medicalwei@sara:~$ ...' |
405 | + >>> print(test_tales('foo/fmt:obfuscate-email', foo=bad_address)) |
406 | + medicalwei@sara:~$ ... |
407 | |
408 | However, if the user is authenticated, the email address is not |
409 | obfuscated. |
410 | |
411 | >>> login('no-priv@canonical.com') |
412 | - >>> test_tales('foo/fmt:obfuscate-email', foo='user@site.net') |
413 | - 'user@site.net' |
414 | + >>> print(test_tales('foo/fmt:obfuscate-email', foo='user@site.net')) |
415 | + user@site.net |
416 | |
417 | |
418 | Linkification of email addresses |
419 | @@ -1220,8 +1226,8 @@ Team addresses are linkified with a team icon: |
420 | |
421 | Unknown email addresses are not altered in any way: |
422 | |
423 | - >>> test_tales('foo/fmt:linkify-email', foo='nobody@example.com') |
424 | - 'nobody@example.com' |
425 | + >>> print(test_tales('foo/fmt:linkify-email', foo='nobody@example.com')) |
426 | + nobody@example.com |
427 | |
428 | Users who specify that their email addresses must be hidden also do not |
429 | get linkified. test@canonical.com is hidden: |
430 | @@ -1231,8 +1237,8 @@ get linkified. test@canonical.com is hidden: |
431 | >>> discreet_user.hide_email_addresses |
432 | True |
433 | |
434 | - >>> test_tales('foo/fmt:linkify-email', foo='test@canonical.com') |
435 | - 'test@canonical.com' |
436 | + >>> print(test_tales('foo/fmt:linkify-email', foo='test@canonical.com')) |
437 | + test@canonical.com |
438 | |
439 | |
440 | Test the 'fmt:' namespace where the context is a dict. |
441 | diff --git a/lib/lp/app/doc/textformatting.txt b/lib/lp/app/doc/textformatting.txt |
442 | index cda72a0..3d15a5b 100644 |
443 | --- a/lib/lp/app/doc/textformatting.txt |
444 | +++ b/lib/lp/app/doc/textformatting.txt |
445 | @@ -230,14 +230,14 @@ The line endings are normalized to \n, so if we get a text with |
446 | dos-style line endings, we get the following result: |
447 | |
448 | >>> mailwrapper = MailWrapper(width=56) |
449 | - >>> dos_style_comment = ( |
450 | + >>> dos_style_comment = six.ensure_str( |
451 | ... "This paragraph is longer than 56 characters, so it should" |
452 | ... " be wrapped even though the paragraphs are separated with" |
453 | ... " dos-style line endings." |
454 | ... "\r\n\r\n" |
455 | ... "Here's the second paragraph.") |
456 | >>> wrapped_text = mailwrapper.format(dos_style_comment) |
457 | - >>> wrapped_text.split('\n') |
458 | + >>> wrapped_text.split(six.ensure_str('\n')) |
459 | ['This paragraph is longer than 56 characters, so it', |
460 | 'should be wrapped even though the paragraphs are', |
461 | 'separated with dos-style line endings.', |
462 | diff --git a/lib/lp/app/tests/test_doc.py b/lib/lp/app/tests/test_doc.py |
463 | index 495499b..3e93aee 100644 |
464 | --- a/lib/lp/app/tests/test_doc.py |
465 | +++ b/lib/lp/app/tests/test_doc.py |
466 | @@ -16,6 +16,7 @@ from lp.testing.pages import ( |
467 | ) |
468 | from lp.testing.systemdocs import ( |
469 | LayeredDocFileSuite, |
470 | + setGlobs, |
471 | setUp, |
472 | tearDown, |
473 | ) |
474 | @@ -42,7 +43,7 @@ special = { |
475 | layer=LaunchpadFunctionalLayer, |
476 | ), |
477 | 'menus.txt': LayeredDocFileSuite( |
478 | - '../doc/menus.txt', layer=None, |
479 | + '../doc/menus.txt', setUp=setGlobs, layer=None, |
480 | ), |
481 | 'stories/launchpad-search(Bing)': PageTestSuite( |
482 | '../stories/launchpad-search/', |
483 | diff --git a/lib/lp/app/validators/name.py b/lib/lp/app/validators/name.py |
484 | index 307795b..5b2575f 100644 |
485 | --- a/lib/lp/app/validators/name.py |
486 | +++ b/lib/lp/app/validators/name.py |
487 | @@ -28,10 +28,10 @@ def sanitize_name(name): |
488 | The characters not allowed in Launchpad names are described by |
489 | invalid_name_pattern. |
490 | |
491 | - >>> sanitize_name('foo_bar') |
492 | - 'foobar' |
493 | - >>> sanitize_name('baz bar $fd') |
494 | - 'bazbarfd' |
495 | + >>> print(sanitize_name('foo_bar')) |
496 | + foobar |
497 | + >>> print(sanitize_name('baz bar $fd')) |
498 | + bazbarfd |
499 | """ |
500 | return invalid_name_pattern.sub('', name) |
501 | |
502 | diff --git a/lib/lp/app/validators/username.py b/lib/lp/app/validators/username.py |
503 | index cce4d4b..acfe874 100644 |
504 | --- a/lib/lp/app/validators/username.py |
505 | +++ b/lib/lp/app/validators/username.py |
506 | @@ -27,12 +27,12 @@ def sanitize_username(username): |
507 | The characters not allowed in Launchpad usernames are described by |
508 | `username_invalid_pattern`. |
509 | |
510 | - >>> sanitize_username('foo_bar') |
511 | - 'foobar' |
512 | - >>> sanitize_username('foo.bar+baz') |
513 | - 'foobarbaz' |
514 | - >>> sanitize_username('-#foo -$fd?.0+-') |
515 | - 'foo-fd0' |
516 | + >>> print(sanitize_username('foo_bar')) |
517 | + foobar |
518 | + >>> print(sanitize_username('foo.bar+baz')) |
519 | + foobarbaz |
520 | + >>> print(sanitize_username('-#foo -$fd?.0+-')) |
521 | + foo-fd0 |
522 | |
523 | """ |
524 | return username_invalid_pattern.sub('', username) |
525 | diff --git a/lib/lp/app/widgets/doc/announcement-date-widget.txt b/lib/lp/app/widgets/doc/announcement-date-widget.txt |
526 | index becbaad..d65b4f2 100644 |
527 | --- a/lib/lp/app/widgets/doc/announcement-date-widget.txt |
528 | +++ b/lib/lp/app/widgets/doc/announcement-date-widget.txt |
529 | @@ -8,7 +8,7 @@ future, or to manually publish it later. |
530 | >>> from lp.testing.pages import extract_text |
531 | >>> from lp.services.webapp.servers import LaunchpadTestRequest |
532 | >>> from lp.app.widgets.announcementdate import AnnouncementDateWidget |
533 | - >>> field = Field(__name__='foo', title=u'Foo') |
534 | + >>> field = Field(__name__=six.ensure_str('foo'), title=u'Foo') |
535 | >>> widget = AnnouncementDateWidget(field, LaunchpadTestRequest()) |
536 | >>> print extract_text(widget()) |
537 | Publish this announcement: |
538 | diff --git a/lib/lp/app/widgets/doc/project-scope-widget.txt b/lib/lp/app/widgets/doc/project-scope-widget.txt |
539 | index e497797..0a87803 100644 |
540 | --- a/lib/lp/app/widgets/doc/project-scope-widget.txt |
541 | +++ b/lib/lp/app/widgets/doc/project-scope-widget.txt |
542 | @@ -14,7 +14,8 @@ selected. |
543 | |
544 | >>> empty_request = LaunchpadTestRequest() |
545 | >>> scope_field = Choice( |
546 | - ... __name__='scope', vocabulary='ProjectGroup', required=False) |
547 | + ... __name__=six.ensure_str('scope'), vocabulary='ProjectGroup', |
548 | + ... required=False) |
549 | >>> scope_field = scope_field.bind(object()) |
550 | >>> widget = ProjectScopeWidget( |
551 | ... scope_field, scope_field.vocabulary, empty_request) |
552 | diff --git a/lib/lp/app/widgets/doc/stripped-text-widget.txt b/lib/lp/app/widgets/doc/stripped-text-widget.txt |
553 | index 26f3b06..fe9ed47 100644 |
554 | --- a/lib/lp/app/widgets/doc/stripped-text-widget.txt |
555 | +++ b/lib/lp/app/widgets/doc/stripped-text-widget.txt |
556 | @@ -15,8 +15,8 @@ set value. |
557 | >>> thing = Thing('abc') |
558 | |
559 | >>> non_required_field.set(thing, ' egf ') |
560 | - >>> non_required_field.get(thing) |
561 | - 'egf' |
562 | + >>> print(non_required_field.get(thing)) # doctest: -NORMALIZE_WHITESPACE |
563 | + egf |
564 | |
565 | None is an accepted field value. |
566 | |
567 | @@ -57,7 +57,7 @@ provided. |
568 | True |
569 | |
570 | >>> required_field = StrippedTextLine( |
571 | - ... __name__='field', title=u'Title', required=True) |
572 | + ... __name__=six.ensure_str('field'), title=u'Title', required=True) |
573 | >>> request = LaunchpadTestRequest(form={'field.field':' \n '}) |
574 | >>> widget = StrippedTextWidget(required_field, request) |
575 | >>> widget.getInputValue() |
576 | diff --git a/lib/lp/bugs/stories/bugs/xx-incomplete-bugs.txt b/lib/lp/bugs/stories/bugs/xx-incomplete-bugs.txt |
577 | index 7d1aade..48ef775 100644 |
578 | --- a/lib/lp/bugs/stories/bugs/xx-incomplete-bugs.txt |
579 | +++ b/lib/lp/bugs/stories/bugs/xx-incomplete-bugs.txt |
580 | @@ -261,8 +261,6 @@ Since no new comments have been added after we changed the status to |
581 | Incomplete, we can now find that bug searching for Incomplete (without |
582 | response) bugs. |
583 | |
584 | - >>> import six |
585 | - |
586 | >>> user_browser.open( |
587 | ... 'http://bugs.launchpad.test/jokosher/+bugs?advanced=1') |
588 | >>> user_browser.getControl(name='field.status:list').value = ( |
589 | diff --git a/lib/lp/registry/stories/teammembership/xx-teammembership.txt b/lib/lp/registry/stories/teammembership/xx-teammembership.txt |
590 | index 06208ac..873a275 100644 |
591 | --- a/lib/lp/registry/stories/teammembership/xx-teammembership.txt |
592 | +++ b/lib/lp/registry/stories/teammembership/xx-teammembership.txt |
593 | @@ -224,8 +224,6 @@ On a team's +members page we can see all active members of that team, as |
594 | well as the former members and the ones which proposed themselves or that |
595 | have been invited. |
596 | |
597 | - >>> import six |
598 | - |
599 | >>> def print_members(contents, type): |
600 | ... table = find_tag_by_id(contents, type) |
601 | ... for link in table.findAll('a'): |
602 | diff --git a/lib/lp/testing/pages.py b/lib/lp/testing/pages.py |
603 | index e552b4b..6fddbc1 100644 |
604 | --- a/lib/lp/testing/pages.py |
605 | +++ b/lib/lp/testing/pages.py |
606 | @@ -936,6 +936,7 @@ def setUpGlobs(test, future=False): |
607 | test.globs['print_tag_with_id'] = print_tag_with_id |
608 | test.globs['PageTestLayer'] = PageTestLayer |
609 | test.globs['stop'] = stop |
610 | + test.globs['six'] = six |
611 | |
612 | if future: |
613 | import __future__ |
614 | diff --git a/lib/lp/testing/systemdocs.py b/lib/lp/testing/systemdocs.py |
615 | index d609bc8..3fb72bf 100644 |
616 | --- a/lib/lp/testing/systemdocs.py |
617 | +++ b/lib/lp/testing/systemdocs.py |
618 | @@ -24,6 +24,7 @@ import pdb |
619 | import pprint |
620 | import sys |
621 | |
622 | +import six |
623 | import transaction |
624 | from zope.component import getUtility |
625 | from zope.testing.loggingsupport import Handler |
626 | @@ -234,6 +235,7 @@ def setGlobs(test, future=False): |
627 | test.globs['launchpadlib_for'] = launchpadlib_for |
628 | test.globs['launchpadlib_credentials_for'] = launchpadlib_credentials_for |
629 | test.globs['oauth_access_token_for'] = oauth_access_token_for |
630 | + test.globs['six'] = six |
631 | |
632 | if future: |
633 | import __future__ |
LGTM