Merge ~cjwatson/launchpad:app-future-imports-prepare into launchpad: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)
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.
Revision history for this message
Thiago F. Pappacena (pappacena) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/app/browser/doc/launchpad-search-pages.txt b/lib/lp/app/browser/doc/launchpad-search-pages.txt
2index 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
34diff --git a/lib/lp/app/doc/displaying-numbers.txt b/lib/lp/app/doc/displaying-numbers.txt
35index 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
56diff --git a/lib/lp/app/doc/displaying-paragraphs-of-text.txt b/lib/lp/app/doc/displaying-paragraphs-of-text.txt
57index 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)
114diff --git a/lib/lp/app/doc/launchpadform.txt b/lib/lp/app/doc/launchpadform.txt
115index 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()
127diff --git a/lib/lp/app/doc/launchpadview.txt b/lib/lp/app/doc/launchpadview.txt
128index 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,
149diff --git a/lib/lp/app/doc/loginstatus-pages.txt b/lib/lp/app/doc/loginstatus-pages.txt
150index 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
219diff --git a/lib/lp/app/doc/menus.txt b/lib/lp/app/doc/menus.txt
220index 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
232diff --git a/lib/lp/app/doc/tales.txt b/lib/lp/app/doc/tales.txt
233index 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 &lt;email address hidden&gt;<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.
441diff --git a/lib/lp/app/doc/textformatting.txt b/lib/lp/app/doc/textformatting.txt
442index 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.',
462diff --git a/lib/lp/app/tests/test_doc.py b/lib/lp/app/tests/test_doc.py
463index 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/',
483diff --git a/lib/lp/app/validators/name.py b/lib/lp/app/validators/name.py
484index 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
502diff --git a/lib/lp/app/validators/username.py b/lib/lp/app/validators/username.py
503index 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)
525diff --git a/lib/lp/app/widgets/doc/announcement-date-widget.txt b/lib/lp/app/widgets/doc/announcement-date-widget.txt
526index 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:
538diff --git a/lib/lp/app/widgets/doc/project-scope-widget.txt b/lib/lp/app/widgets/doc/project-scope-widget.txt
539index 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)
552diff --git a/lib/lp/app/widgets/doc/stripped-text-widget.txt b/lib/lp/app/widgets/doc/stripped-text-widget.txt
553index 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()
576diff --git a/lib/lp/bugs/stories/bugs/xx-incomplete-bugs.txt b/lib/lp/bugs/stories/bugs/xx-incomplete-bugs.txt
577index 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 = (
589diff --git a/lib/lp/registry/stories/teammembership/xx-teammembership.txt b/lib/lp/registry/stories/teammembership/xx-teammembership.txt
590index 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'):
602diff --git a/lib/lp/testing/pages.py b/lib/lp/testing/pages.py
603index 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__
614diff --git a/lib/lp/testing/systemdocs.py b/lib/lp/testing/systemdocs.py
615index 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__

Subscribers

People subscribed via source and target branches

to status/vote changes: