← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~cjwatson/launchpad/code-pagetests-future-imports into lp:launchpad

 

Colin Watson has proposed merging lp:~cjwatson/launchpad/code-pagetests-future-imports into lp:launchpad with lp:~cjwatson/launchpad/code-doctests-future-imports as a prerequisite.

Commit message:
Convert pagetests under lp.code to Launchpad's preferred __future__ imports.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/code-pagetests-future-imports/+merge/345472

This is long, but it's almost all just boring mechanical print-statement-to-function conversion.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/code-pagetests-future-imports into lp:launchpad.
=== modified file 'lib/lp/code/stories/branches/xx-bazaar-home.txt'
--- lib/lp/code/stories/branches/xx-bazaar-home.txt	2017-10-23 00:16:39 +0000
+++ lib/lp/code/stories/branches/xx-bazaar-home.txt	2018-05-13 10:39:08 +0000
@@ -14,7 +14,7 @@
     >>> browser.open('http://code.launchpad.dev/')
     >>> footer = find_tag_by_id(browser.contents, 'application-footer')
 
-    >>> print extract_text(footer)
+    >>> print(extract_text(footer))
     30 branches registered in
     6 projects
     1 imported branches
@@ -30,11 +30,11 @@
 with a link to the complete listing.
 
     >>> preview = find_tag_by_id(browser.contents, 'project-cloud-preview')
-    >>> print extract_text(preview)
+    >>> print(extract_text(preview))
     Most active projects in the last month
     see all projects…
 
-    >>> print preview.findAll('a')[-1]['href']
+    >>> print(preview.findAll('a')[-1]['href'])
     /projects
 
 
@@ -44,7 +44,7 @@
 Any user can see the project search form.
 
     >>> form = find_tag_by_id(browser.contents, 'search-projects-form')
-    >>> print form['action']
+    >>> print(form['action'])
     http://launchpad.dev/projects
 
     >>> browser.getControl(name='text', index=0)
@@ -72,11 +72,11 @@
 registered branches first.
 
     >>> registered = find_tag_by_id(browser.contents, 'recently-registered')
-    >>> print registered.findAll('a')[-1]['href']
+    >>> print(registered.findAll('a')[-1]['href'])
     /+recently-registered-branches
 
     >>> browser.getLink(url='recently-registered-branches').click()
-    >>> print browser.title
+    >>> print(browser.title)
     Recently registered branches
 
 Since the view contains branches across different projects, the project
@@ -85,7 +85,7 @@
 
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.thead.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     Name
     Status
     Registered
@@ -105,16 +105,16 @@
 
     >>> browser.open('http://code.launchpad.dev/')
     >>> changed = find_tag_by_id(browser.contents, 'recently-changed')
-    >>> print changed.findAll('a')[-1]['href']
+    >>> print(changed.findAll('a')[-1]['href'])
     /+recently-changed-branches
 
     >>> browser.getLink(url='recently-changed-branches').click()
-    >>> print browser.title
+    >>> print(browser.title)
     Recently changed branches
 
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.thead.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     Name
     Status
     Registered
@@ -132,11 +132,11 @@
 
     >>> browser.open('http://code.launchpad.dev/')
     >>> imported = find_tag_by_id(browser.contents, 'recent-imports')
-    >>> print imported.findAll('a')[-1]['href']
+    >>> print(imported.findAll('a')[-1]['href'])
     /+recently-imported-branches
 
     >>> browser.getLink(url='recently-imported-branches').click()
-    >>> print browser.title
+    >>> print(browser.title)
     Recently imported branches
 
 Since imported branches are all owned by vcs-imports, and the authors
@@ -145,7 +145,7 @@
 
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.thead.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     Name
     Status
     Registered

=== modified file 'lib/lp/code/stories/branches/xx-branch-deletion.txt'
--- lib/lp/code/stories/branches/xx-branch-deletion.txt	2014-11-27 22:13:36 +0000
+++ lib/lp/code/stories/branches/xx-branch-deletion.txt	2018-05-13 10:39:08 +0000
@@ -23,20 +23,20 @@
 
     >>> browser = setupBrowser(auth="Basic alice@xxxxxxxxxxx:test")
     >>> browser.open('http://code.launchpad.dev/~alice/earthlynx/to-delete')
-    >>> print browser.title
+    >>> print(browser.title)
     to-delete : Code : Earth Lynx
 
 The newly created branch has an action 'Delete branch'.
 
     >>> delete_link = browser.getLink('Delete branch')
-    >>> print delete_link.url
+    >>> print(delete_link.url)
     http://code.launchpad.dev/~alice/earthlynx/to-delete/+delete
 
 When the user clicks on the link, they are informed what will happen if they
 delete the branch.
 
     >>> delete_link.click()
-    >>> print extract_text(find_main_content(browser.contents))
+    >>> print(extract_text(find_main_content(browser.contents)))
     Delete branch lp://dev/~alice/earthlynx/to-delete
     to-delete ...
     Branch deletion is permanent.
@@ -47,7 +47,7 @@
 the branch has been deleted.
 
     >>> browser.getControl('Delete').click()
-    >>> print browser.url
+    >>> print(browser.url)
     http://code.launchpad.dev/earthlynx
     >>> print_feedback_messages(browser.contents)
     Branch ~alice/earthlynx/to-delete deleted...
@@ -62,7 +62,7 @@
     >>> browser.open('http://code.launchpad.dev/~alice/+junk/to-delete')
     >>> browser.getLink('Delete branch').click()
     >>> browser.getControl('Delete').click()
-    >>> print browser.url
+    >>> print(browser.url)
     http://code.launchpad.dev/~alice
     >>> print_feedback_messages(browser.contents)
     Branch ~alice/+junk/to-delete deleted...
@@ -80,7 +80,7 @@
 
     >>> admin_browser.open(branch_location)
     >>> admin_browser.getLink('Delete branch').click()
-    >>> print extract_text(find_main_content(admin_browser.contents))
+    >>> print(extract_text(find_main_content(admin_browser.contents)))
     Delete branch...
     This branch cannot be deleted as it has 1 branch sharing revisions.
 

=== modified file 'lib/lp/code/stories/branches/xx-branch-edit.txt'
--- lib/lp/code/stories/branches/xx-branch-edit.txt	2015-09-02 16:50:04 +0000
+++ lib/lp/code/stories/branches/xx-branch-edit.txt	2018-05-13 10:39:08 +0000
@@ -44,7 +44,7 @@
 
 The form should have been filled with sample data values.
 
-    >>> print browser.getControl('Branch URL').value
+    >>> print(browser.getControl('Branch URL').value)
     http://trekkies.example.com/gnome-terminal/klingon
 
 Then, post the changes to the summary. Also add a trailing slash to the
@@ -78,19 +78,19 @@
     >>> len(stub.test_emails)
     0
 
-    >>> print browser.url
+    >>> print(browser.url)
     http://code.launchpad.dev/~name12/gnome-terminal/klingon
 
-    >>> print extract_text(find_tag_by_id(
-    ...     browser.contents, 'branch-info'))
+    >>> print(extract_text(find_tag_by_id(
+    ...     browser.contents, 'branch-info')))
     Branch information ...
     Project:  GNOME Terminal
     Status: Experimental Edit
     Location: http://trekkies.example.com/gnome-terminal/klingon
     Last mirrored: ...
 
-    >>> print extract_text(find_tag_by_id(browser.contents,
-    ...     'branch-description').p)
+    >>> print(extract_text(find_tag_by_id(browser.contents,
+    ...     'branch-description').p))
     Klingon support for Gnome Terminal
 
 
@@ -123,7 +123,7 @@
 
     >>> contents = browser.contents
     >>> status_tag = find_tag_by_id(contents, 'edit-lifecycle_status')
-    >>> print extract_text(status_tag)
+    >>> print(extract_text(status_tag))
     Merged Edit
 
 Set the branch status back to its initial state.
@@ -217,7 +217,7 @@
     ...     'http://acme.example.com/~foo/bar/baz')
     Traceback (most recent call last):
     ...
-    LookupError: label 'Branch URL'
+    LookupError: label u'Branch URL'
 
 
 Editing the whiteboard
@@ -255,7 +255,7 @@
 set.
 
     >>> stub.test_emails = []
-    >>> print whiteboard_tag
+    >>> print(whiteboard_tag)
     None
 
     >>> nopriv_browser.getLink('Edit whiteboard').click()
@@ -266,7 +266,7 @@
 
     >>> whiteboard_tag = find_tag_by_id(
     ...     nopriv_browser.contents, 'branch-whiteboard-value')
-    >>> print extract_text(whiteboard_tag)
+    >>> print(extract_text(whiteboard_tag))
     New whiteboard value
 
 The subscribers of the branch are notified that someone else has
@@ -276,7 +276,7 @@
     >>> len(stub.test_emails)
     1
 
-    >>> print stub.test_emails[0][2]
+    >>> print(stub.test_emails[0][2])
     Content-Type: ...
     ...
     To: Sample Person <test@xxxxxxxxxxxxx>
@@ -322,7 +322,7 @@
     >>> admin_browser.getLink('Change branch details').click()
     >>> admin_browser.getControl('Owner').value = 'mark'
     >>> admin_browser.getControl('Change Branch').click()
-    >>> print admin_browser.url
+    >>> print(admin_browser.url)
     http://code.launchpad.dev/~mark/firefox/main
 
 

=== modified file 'lib/lp/code/stories/branches/xx-branch-index.txt'
--- lib/lp/code/stories/branches/xx-branch-index.txt	2018-01-19 17:21:44 +0000
+++ lib/lp/code/stories/branches/xx-branch-index.txt	2018-05-13 10:39:08 +0000
@@ -57,9 +57,9 @@
     >>> def print_merge_links(browser):
     ...     links = find_tag_by_id(browser.contents, 'merge-links')
     ...     if not links:
-    ...         print None
+    ...         print(None)
     ...     else:
-    ...         print extract_text(links)
+    ...         print(extract_text(links))
     >>> print_merge_links(user_browser)
     None
 
@@ -76,7 +76,7 @@
     ...     revisions = find_tags_by_class(
     ...         browser.contents, 'revision-details')
     ...     for revision in revisions:
-    ...         print extract_text(revision).encode('ascii')
+    ...         print(extract_text(revision).encode('ascii'))
 
     >>> print_revisions(user_browser)
     5. By Eric on 2007-01-05
@@ -89,7 +89,7 @@
 
     >>> revision = find_tags_by_class(
     ...         user_browser.contents, 'revision-details', only_first=True)
-    >>> print revision.a
+    >>> print(revision.a)
     <a href="https://bazaar.launchpad.dev/~eric/fooix/trunk/revision/5";>5</a>
 
 
@@ -103,19 +103,19 @@
     ...     'http://code.launchpad.dev/~name12/+branch/+junk/junk.dev')
     >>> commit_messages = find_tags_by_class(
     ...         browser.contents, 'revision-comment')
-    >>> print commit_messages[0].p.renderContents()
+    >>> print(commit_messages[0].p.renderContents())
     fix bug in bar
 
 When a commit message refers to a bug using the form "bug <bugnumber>",
 a link to that bug is created.
 
-    >>> print commit_messages[3].p.renderContents()
+    >>> print(commit_messages[3].p.renderContents())
     fix <a ...>bug 1</a>
 
 This link can be followed to the bug's details page.
 
     >>> browser.getLink('bug 1').click()
-    >>> print browser.title
+    >>> print(browser.title)
     Bug #1 ...
 
 
@@ -132,8 +132,8 @@
 helpful message.
 
     >>> browser.open('http://code.launchpad.dev/~name12/firefox/main')
-    >>> print extract_text(
-    ...     find_tag_by_id(browser.contents, 'recent-revisions'))
+    >>> print(extract_text(
+    ...     find_tag_by_id(browser.contents, 'recent-revisions')))
     Recent revisions
     This branch has not been mirrored yet.
 
@@ -142,15 +142,15 @@
 
     >>> browser.open(
     ...     'http://code.launchpad.dev/~name12/gnome-terminal/pushed')
-    >>> print extract_text(
-    ...     find_tag_by_id(browser.contents, 'recent-revisions'))
+    >>> print(extract_text(
+    ...     find_tag_by_id(browser.contents, 'recent-revisions')))
     Recent revisions
     This branch has not been pushed to yet.
 
     >>> browser.open(
     ...     'http://code.launchpad.dev/~vcs-imports/evolution/main')
-    >>> print extract_text(
-    ...     find_tag_by_id(browser.contents, 'recent-revisions'))
+    >>> print(extract_text(
+    ...     find_tag_by_id(browser.contents, 'recent-revisions')))
     Recent revisions
     This branch has not been imported yet.
 
@@ -160,8 +160,8 @@
 
     >>> browser.open(
     ...     'http://code.launchpad.dev/~name12/gnome-terminal/mirrored')
-    >>> print extract_text(
-    ...     find_tag_by_id(browser.contents, 'recent-revisions'))
+    >>> print(extract_text(
+    ...     find_tag_by_id(browser.contents, 'recent-revisions')))
     Recent revisions
     This branch has not been scanned yet.
 
@@ -170,8 +170,8 @@
 
     >>> browser.open(
     ...     'http://code.launchpad.dev/~name12/gnome-terminal/scanned')
-    >>> print extract_text(
-    ...     find_tag_by_id(browser.contents, 'recent-revisions'))
+    >>> print(extract_text(
+    ...     find_tag_by_id(browser.contents, 'recent-revisions')))
     Recent revisions
     This branch is empty.
 
@@ -192,13 +192,13 @@
 
     >>> browser.open(
     ...     'http://code.launchpad.dev/~name12/gnome-terminal/scanned')
-    >>> print extract_text(get_branch_details_table())
+    >>> print(extract_text(get_branch_details_table()))
     Branch information
     Owner: Sample Person
     Project: GNOME Terminal
     Status: Development
 
-    >>> print extract_text(get_branch_management_portlet())
+    >>> print(extract_text(get_branch_management_portlet()))
     Only Sample Person can upload to this branch.
     If you are Sample Person please log in for upload directions.
     Browse the code
@@ -225,7 +225,7 @@
 
     >>> browser.open(
     ...     'http://code.launchpad.dev/~no-priv/+junk/mirrored')
-    >>> print extract_text(get_branch_details_table())
+    >>> print(extract_text(get_branch_details_table()))
     Branch information...
     Status: Development
     Location: http://example.com/mirrored
@@ -237,7 +237,7 @@
     >>> def get_branch_description(browser):
     ...     return extract_text(find_tag_by_id(
     ...         browser.contents, 'branch-description'))
-    >>> print get_branch_description(browser)
+    >>> print(get_branch_description(browser))
     Traceback (most recent call last):
     TypeError: expected string or buffer
 
@@ -246,7 +246,7 @@
 
     >>> browser.open(
     ...     'http://code.launchpad.dev/~name12/gnome-terminal/main')
-    >>> print extract_text(get_branch_details_table())
+    >>> print(extract_text(get_branch_details_table()))
     Branch information
     Owner: Sample Person
     Project: GNOME Terminal
@@ -255,7 +255,7 @@
     Last mirrored: Not mirrored yet
     Next mirror: Disabled
 
-    >>> print get_branch_description(browser)
+    >>> print(get_branch_description(browser))
     Main branch of development for GNOME Terminal.
     Stable branches are based on that one...
 
@@ -275,7 +275,7 @@
 
     >>> browser.open(
     ...     'http://code.launchpad.dev/~no-priv/+junk/mirror-disabled')
-    >>> print extract_text(get_branch_details_table())
+    >>> print(extract_text(get_branch_details_table()))
     Branch information
     Owner: No Privileges Person
     Status: Development
@@ -291,8 +291,8 @@
 
     >>> browser.open(
     ...     'http://code.launchpad.dev/~name12/gnome-terminal/scanned')
-    >>> print extract_text(find_tag_by_id(
-    ...     browser.contents, "recent-revisions"))
+    >>> print(extract_text(find_tag_by_id(
+    ...     browser.contents, "recent-revisions")))
     Recent revisions
     This branch is empty.
 
@@ -301,7 +301,7 @@
 
     >>> browser.open(
     ...     'http://code.launchpad.dev/~name12/+junk/junk.dev')
-    >>> print browser.getLink('All revisions').url
+    >>> print(browser.getLink('All revisions').url)
     https://bazaar.launchpad.dev/~name12/+junk/junk.dev/changes
 
 If the branch is private, the browse code link is not shown. In order to
@@ -338,8 +338,8 @@
 
     >>> browser.open(
     ...     'http://code.launchpad.dev/~landscape-developers/landscape/trunk')
-    >>> print extract_text(find_tag_by_id(
-    ...     browser.contents, 'branch-management'))
+    >>> print(extract_text(find_tag_by_id(
+    ...     browser.contents, 'branch-management')))
     Get this branch:
       bzr branch lp://dev/~landscape-developers/landscape/trunk
     ...
@@ -348,8 +348,8 @@
 
     >>> browser.open(
     ...     'http://code.launchpad.dev/~name12/gnome-terminal/scanned')
-    >>> print extract_text(find_tag_by_id(
-    ...     browser.contents, 'branch-management'))
+    >>> print(extract_text(find_tag_by_id(
+    ...     browser.contents, 'branch-management')))
     Get this branch: bzr branch lp://dev/~name12/gnome-terminal/scanned
     ...
 
@@ -367,12 +367,12 @@
 
 The data that we specified is shown on the web page.
 
-    >>> print extract_text(find_tag_by_id(
-    ...     browser.contents, 'branch-format'))
+    >>> print(extract_text(find_tag_by_id(
+    ...     browser.contents, 'branch-format')))
     Branch format: Branch format 5
 
-    >>> print extract_text(find_tag_by_id(
-    ...     browser.contents, 'repository-format'))
+    >>> print(extract_text(find_tag_by_id(
+    ...     browser.contents, 'repository-format')))
     Repository format:
     Bazaar pack repository format 1 (needs bzr 0.92)
 
@@ -397,7 +397,7 @@
 
 The stacked-on information appears in the branch summary:
 
-    >>> print extract_text(find_tag_by_id(browser.contents, 'stacked-on'))
+    >>> print(extract_text(find_tag_by_id(browser.contents, 'stacked-on')))
     Stacked on: lp://dev/~person-name.../product-name.../branch...
 
     >>> browser.getLink(stacked_on_name).url == stacked_on_url
@@ -410,7 +410,7 @@
 
     >>> browser.open(url)
     >>> content = find_tag_by_id(browser.contents, 'document')
-    >>> print extract_text(find_tag_by_id(content, 'privacy'))
+    >>> print(extract_text(find_tag_by_id(content, 'privacy')))
     This branch contains Public information...
 
 Navigation Context

=== modified file 'lib/lp/code/stories/branches/xx-branch-listings-merge-proposal-badge.txt'
--- lib/lp/code/stories/branches/xx-branch-listings-merge-proposal-badge.txt	2017-10-23 00:16:39 +0000
+++ lib/lp/code/stories/branches/xx-branch-listings-merge-proposal-badge.txt	2018-05-13 10:39:08 +0000
@@ -6,10 +6,10 @@
     ...         cells = row.findAll('td')
     ...         first_cell = cells[0]
     ...         anchors = first_cell.findAll('a')
-    ...         print anchors[0].get('href')
+    ...         print(anchors[0].get('href'))
     ...         # Badges in the next cell
     ...         for img in cells[1].findAll('img'):
-    ...             print img['title']
+    ...             print(img['title'])
 
 
     >>> login('foo.bar@xxxxxxxxxxxxx')

=== modified file 'lib/lp/code/stories/branches/xx-branch-listings.txt'
--- lib/lp/code/stories/branches/xx-branch-listings.txt	2017-10-23 00:16:39 +0000
+++ lib/lp/code/stories/branches/xx-branch-listings.txt	2018-05-13 10:39:08 +0000
@@ -23,13 +23,13 @@
     >>> browser = setupBrowser(auth='Basic test@xxxxxxxxxxxxx:test')
     >>> browser.open('http://code.launchpad.dev/~name12')
     >>> links = find_tag_by_id(browser.contents, 'branch-batch-links')
-    >>> print links.renderContents()
+    >>> print(links.renderContents())
     <BLANKLINE>
     ...1...&rarr;...6...of 10 results...
 
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.thead.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     Name
     Status
     Last Modified
@@ -40,7 +40,7 @@
 and are really just branch metadata without the revisions behind them.
 
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/~name12/firefox/main                Development  ...
     lp://dev/~name12/gnome-terminal/2.6          Mature       ...
     lp://dev/~name12/gnome-terminal/main         Development  ...
@@ -50,13 +50,13 @@
 
     >>> browser.getLink('Next').click()
     >>> links = find_tag_by_id(browser.contents, 'branch-batch-links')
-    >>> print links.renderContents()
+    >>> print(links.renderContents())
     <BLANKLINE>
     ...7...&rarr;...10...of 10 results...
 
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/~name12/gnome-terminal/klingon          Experimental  ...
     lp://dev/~name12/+junk/junk.contrib              Development   ...
     lp://dev/~name12/+junk/junk.dev                  Experimental  ...
@@ -83,7 +83,7 @@
     >>> browser.open('http://code.launchpad.dev/~name12')
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/~name12/firefox/main                 Development  ...
     lp://dev/~name12/gnome-terminal/2.6           Mature       ...
     lp://dev/~name12/gnome-terminal/main          Development  ...
@@ -112,13 +112,13 @@
 Now all types of branches should be shown.
 
     >>> links = find_tag_by_id(browser.contents, 'branch-batch-links')
-    >>> print links.renderContents()
+    >>> print(links.renderContents())
     <BLANKLINE>
     ...1...&rarr;...6...of 12 results...
 
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/~name12/firefox/main                 Development    ...
     lp://dev/~name12/gnome-terminal/2.4           Abandoned      ...
     lp://dev/~name12/gnome-terminal/slowness      Merged         ...
@@ -128,13 +128,13 @@
 
     >>> browser.getLink('Next').click()
     >>> links = find_tag_by_id(browser.contents, 'branch-batch-links')
-    >>> print links.renderContents()
+    >>> print(links.renderContents())
     <BLANKLINE>
     ...7...&rarr;...12...of 12 results...
 
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/~name12/gnome-terminal/pushed         Development     ...
     lp://dev/~name12/gnome-terminal/scanned        Development     ...
     lp://dev/~name12/gnome-terminal/klingon        Experimental    ...
@@ -149,7 +149,7 @@
     >>> browser.getControl('Filter').click()
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/~name12/gnome-terminal/2.4    Abandoned     ...
 
 If anyone tries to hack the URL, and put in an invalid
@@ -161,7 +161,7 @@
     ['Any active status']
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/~name12/firefox/main                  Development  ...
     lp://dev/~name12/gnome-terminal/2.6            Mature       ...
     lp://dev/~name12/gnome-terminal/main           Development  ...
@@ -177,7 +177,7 @@
     >>> browser.getControl(name='field.lifecycle').displayValue
     ['Mature']
     >>> message = find_tag_by_id(browser.contents, 'no-branch-message')
-    >>> print message.renderContents()
+    >>> print(message.renderContents())
     There are branches related to Launchpad Developers...
 
 Personal branch listings shouldn't show an option for sorting by "most
@@ -189,7 +189,7 @@
     ...     'field.category=subscribed')
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/~name12/firefox/main ...
     lp://dev/~launchpad/gnome-terminal/launchpad ...
     lp://dev/~name12/+junk/junk.dev ...
@@ -218,10 +218,10 @@
     ...         cells = row.findAll('td')
     ...         first_cell = cells[0]
     ...         anchors = first_cell.findAll('a')
-    ...         print anchors[0].get('href')
+    ...         print(anchors[0].get('href'))
     ...         # Badges in the next cell
     ...         for img in cells[1].findAll('img'):
-    ...             print img['title']
+    ...             print(img['title'])
 
     >>> browser.open(
     ...     'http://code.launchpad.dev/firefox/+branches'
@@ -280,7 +280,7 @@
     >>> sort_by_control.value
     ['most recently changed first']
     >>> for option in sort_by_control.options:
-    ...     print option
+    ...     print(option)
     by project name
     by status
     by branch name
@@ -300,9 +300,9 @@
     >>> sort_by_control.value = ['by project name']
     Traceback (most recent call last):
       ...
-    ItemNotFoundError: insufficient items with name 'by project name'
+    ItemNotFoundError: insufficient items with name u'by project name'
     >>> for option in sort_by_control.options:
-    ...     print option
+    ...     print(option)
     by most interesting
     by status
     by branch name
@@ -328,14 +328,14 @@
     >>> browser.getControl(name='field.sort_by').value
     Traceback (most recent call last):
     ...
-    LookupError: name 'field.sort_by'
+    LookupError: name u'field.sort_by'
 
 Finally, sorting by a particular criterion has the desired effect.
 
     >>> browser.open('http://code.launchpad.dev/gnome-terminal/+branches')
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     A development focus ...
     lp://dev/~name12/gnome-terminal/2.6            Mature       ...
     lp://dev/~launchpad/gnome-terminal/launchpad   Development  ...
@@ -348,7 +348,7 @@
     >>> browser.getControl('Filter').click()
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     A development focus ...
     lp://dev/~name12/gnome-terminal/2.6             Mature          ...
     lp://dev/~vcs-imports/gnome-terminal/import     Development             ...
@@ -382,7 +382,7 @@
     >>> # The development focus is always first.
     >>> row = table.tbody.findAll('tr')[0]
     >>> cols = row.findAll('td')
-    >>> print extract_text(cols[0])
+    >>> print(extract_text(cols[0]))
     lp://dev/gnome-terminal     Series: trunk
 
 If a branch is associated with more than one series, then the links
@@ -408,7 +408,7 @@
 
     >>> browser.open('http://code.launchpad.dev/gnome-terminal')
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
-    >>> print extract_text(table.tbody.findAll('tr')[0])
+    >>> print(extract_text(table.tbody.findAll('tr')[0]))
     lp://dev/gnome-terminal  Series: trunk, alpha, pre-1.0  ...
 
 
@@ -422,7 +422,7 @@
     >>> browser.open('http://code.launchpad.dev/gnome-terminal')
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/gnome-terminal   Series: trunk...    Development  ...
     lp://dev/~name12/gnome-terminal/2.6           Mature       ...
     lp://dev/~launchpad/gnome-terminal/launchpad  Development  ...
@@ -447,7 +447,7 @@
     >>> browser.getControl('Filter').click()
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/~name12/gnome-terminal/klingon       Experimental ...
 
 If the development focus matches the lifecycle selected, it is still shown
@@ -457,7 +457,7 @@
     >>> browser.getControl('Filter').click()
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/gnome-terminal   Series: trunk...    Development  ...
 
 
@@ -471,7 +471,7 @@
 
     >>> browser.open('http://code.launchpad.dev/firefox/+branches')
     >>> for commit in find_tags_by_class(browser.contents, 'lastCommit'):
-    ...     print extract_text(commit)
+    ...     print(extract_text(commit))
     1.  Import of Mozilla Firefox 0.9.1
     1.  Import of Mozilla Firefox 0.9
     1.  Import of Mozilla Firefox 0.9.2
@@ -480,7 +480,7 @@
 the user moves the mouse over the last commit for a particular branch.
 
     >>> for commit in find_tags_by_class(browser.contents, 'popupTitle'):
-    ...     print extract_text(commit)
+    ...     print(extract_text(commit))
     Author: mark.shuttleworth
     Revision Date: 2005-03-09 23:45:00 AWST
     Import of Mozilla Firefox 0.9.1

=== modified file 'lib/lp/code/stories/branches/xx-branch-mirror-failures.txt'
--- lib/lp/code/stories/branches/xx-branch-mirror-failures.txt	2012-01-15 13:32:27 +0000
+++ lib/lp/code/stories/branches/xx-branch-mirror-failures.txt	2018-05-13 10:39:08 +0000
@@ -20,9 +20,9 @@
     >>> def print_browser_tag(browser, tag_id):
     ...     tag = find_tag_by_id(browser.contents, tag_id)
     ...     if tag is None:
-    ...         print tag
+    ...         print(tag)
     ...     else:
-    ...         print extract_text(tag)
+    ...         print(extract_text(tag))
 
 The initial error message doesn't give a count or last failure.
 
@@ -196,7 +196,7 @@
 
     >>> browser = setupBrowser()
     >>> browser.open(branch_location)
-    >>> print find_tag_by_id(browser.contents, 'mirror-failure')
+    >>> print(find_tag_by_id(browser.contents, 'mirror-failure'))
     None
-    >>> print find_tag_by_id(browser.contents, 'mirror-of-ssh')
+    >>> print(find_tag_by_id(browser.contents, 'mirror-of-ssh'))
     None

=== modified file 'lib/lp/code/stories/branches/xx-branch-tag-cloud.txt'
--- lib/lp/code/stories/branches/xx-branch-tag-cloud.txt	2017-10-23 00:16:39 +0000
+++ lib/lp/code/stories/branches/xx-branch-tag-cloud.txt	2018-05-13 10:39:08 +0000
@@ -16,7 +16,7 @@
     >>> logout()
 
     >>> anon_browser.open("http://code.launchpad.dev/projects";)
-    >>> print anon_browser.title
+    >>> print(anon_browser.title)
     Projects with active branches
 
 The `Projects with active branches` page shows a link for each project that has
@@ -25,6 +25,6 @@
 
     >>> tags = find_tag_by_id(anon_browser.contents, 'project-tags')
     >>> for anchor in tags.findAll('a'):
-    ...     print anchor.renderContents(), anchor['class']
+    ...     print(anchor.renderContents(), anchor['class'])
     linux cloud-size-largest cloud-medium
     wibble cloud-size-smallest cloud-dark

=== modified file 'lib/lp/code/stories/branches/xx-branchmergeproposal-listings.txt'
--- lib/lp/code/stories/branches/xx-branchmergeproposal-listings.txt	2016-07-02 07:56:08 +0000
+++ lib/lp/code/stories/branches/xx-branchmergeproposal-listings.txt	2018-05-13 10:39:08 +0000
@@ -68,7 +68,7 @@
 The 'active reviews' text links to the active reviews page.
 
     >>> browser.getLink('active reviews').click()
-    >>> print browser.title
+    >>> print(browser.title)
     Active reviews : Code : Fooix
 
 The proposals are listed in a table that shows the source and target branches,
@@ -147,7 +147,7 @@
     3 branches proposed for merging into this one.
 
     >>> browser.getLink('3 branches').click()
-    >>> print browser.title
+    >>> print(browser.title)
     Active reviews : trunk : Code : Fooix
 
 

=== modified file 'lib/lp/code/stories/branches/xx-branchmergeproposals.txt'
--- lib/lp/code/stories/branches/xx-branchmergeproposals.txt	2018-03-16 21:20:00 +0000
+++ lib/lp/code/stories/branches/xx-branchmergeproposals.txt	2018-05-13 10:39:08 +0000
@@ -69,14 +69,14 @@
 Registering the merge proposal takes the user to the new merge proposal.
 
     >>> klingon_proposal = nopriv_browser.url
-    >>> print klingon_proposal
+    >>> print(klingon_proposal)
     http://code.launchpad.dev/~name12/gnome-terminal/klingon/+merge/...
 
 The summary reflects the selected target and prerequisite.
 
     >>> def print_summary(browser):
-    ...     print extract_text(find_tag_by_id(
-    ...         browser.contents, 'proposal-summary'))
+    ...     print(extract_text(find_tag_by_id(
+    ...         browser.contents, 'proposal-summary')))
     >>> print_summary(nopriv_browser)
     Status:
     ...
@@ -151,7 +151,7 @@
     >>> sample_browser.open(klingon_proposal)
     >>> pending = find_tag_by_id(
     ...     sample_browser.contents, 'code-review-votes')
-    >>> print extract_text(pending)
+    >>> print(extract_text(pending))
     Reviewer          Review Type    Date Requested    Status
     Sample Person                    ... ago           Pending [Review]
     Review via email: mp+...@xxxxxxxxxxxxxxxxxx
@@ -181,7 +181,7 @@
 
     >>> pending = find_tag_by_id(
     ...     sample_browser.contents, 'code-review-votes')
-    >>> print extract_text(pending)
+    >>> print(extract_text(pending))
     Reviewer          Review Type    Date Requested    Status
     Mark Shuttleworth                ... ago           Pending
     Sample Person     second         ... ago           Pending [Review]
@@ -210,7 +210,7 @@
     >>> nopriv_browser.getControl('Save Comment').click()
     >>> pending = find_tag_by_id(
     ...     nopriv_browser.contents, 'code-review-votes')
-    >>> print extract_text(pending)
+    >>> print(extract_text(pending))
     Reviewer                         Review Type  Date Requested Status
     No Privileges Person (community)                             Disapprove
     ...
@@ -224,7 +224,7 @@
     >>> sample_browser.getControl('Request Review').click()
     >>> pending = find_tag_by_id(
     ...     sample_browser.contents, 'code-review-votes')
-    >>> print extract_text(pending)
+    >>> print(extract_text(pending))
     Reviewer                         Review Type  Date Requested Status...
     HWDB Team                        claimable    ... ago        Pending ...
     >>> foobar_browser = setupBrowser(auth="Basic foo.bar@xxxxxxxxxxxxx:test")
@@ -235,7 +235,7 @@
 
 After claiming a review, the claimant is listed instead of their team.
 
-    >>> print extract_text(pending)
+    >>> print(extract_text(pending))
     Reviewer                         Review Type  Date Requested Status...
     Foo Bar                          claimable    ... ago        Pending ...
 
@@ -286,8 +286,8 @@
 The new merge proposal is created as needs review, and there is
 a link back to the superseded proposal.
 
-    >>> print extract_text(find_tag_by_id(
-    ...     eric_browser.contents, 'superseded-proposal'))
+    >>> print(extract_text(find_tag_by_id(
+    ...     eric_browser.contents, 'superseded-proposal')))
     This proposal supersedes a proposal from ...
 
     >>> import re
@@ -300,8 +300,8 @@
 The earlier superseded proposal also has a link back to the
 new proposal that supersedes it.
 
-    >>> print extract_text(find_tag_by_id(
-    ...     eric_browser.contents, 'superseded-by'))
+    >>> print(extract_text(find_tag_by_id(
+    ...     eric_browser.contents, 'superseded-by')))
     This proposal has been superseded by a proposal from ...
     >>> link = eric_browser.getLink(re.compile('proposal from .*'))
     >>> superseding_url = link.url
@@ -313,7 +313,7 @@
     >>> eric_browser.getLink('Edit status').click()
     >>> def print_options(field):
     ...     for option in field.options:
-    ...         print option
+    ...         print(option)
     >>> print_options(eric_browser.getControl(name='field.queue_status'))
     REJECTED
     MERGED
@@ -382,7 +382,7 @@
     ...     'http://code.launchpad.dev/~mark/firefox/release-0.8')
     >>> nopriv_browser.getLink('Propose for merging').click()
     >>> for widget in get_target_branch_widgets(nopriv_browser):
-    ...     print widget
+    ...     print(widget)
     <input type="text" ...
 
 Test validation of errors...
@@ -424,7 +424,7 @@
     ...                 checked = widget['checked']
     ...             except KeyError:
     ...                 checked = ''
-    ...             print widget['value'], checked
+    ...             print(widget['value'], checked)
 
 Also the main development focus is selected.
 
@@ -463,9 +463,9 @@
     ...     for id in 'related-bugs', 'related-blueprints':
     ...         links = find_tag_by_id(browser.contents, id)
     ...         if links == None:
-    ...             print links
+    ...             print(links)
     ...         else:
-    ...             print extract_text(links)
+    ...             print(extract_text(links))
 
     >>> login('admin@xxxxxxxxxxxxx')
     >>> bmp = factory.makeBranchMergeProposal()
@@ -551,8 +551,8 @@
     >>> from zope.security.proxy import removeSecurityProxy
     >>> from difflib import unified_diff
     >>> from lp.code.model.diff import PreviewDiff
-    >>> diff_text = ''.join(
-    ...     unified_diff('', ['Fake Diff' + u'\u1010'.encode('utf-8')]))
+    >>> diff_text = b''.join(
+    ...     unified_diff(b'', [b'Fake Diff' + u'\u1010'.encode('utf-8')]))
     >>> bmp = factory.makeBranchMergeProposal()
     >>> preview_diff = PreviewDiff.create(
     ...     bmp, diff_text, u'a', u'b', None, u'')
@@ -565,7 +565,7 @@
 
 The text of the review diff is in the page.
 
-    >>> print repr(extract_text(get_review_diff()))
+    >>> print(repr(extract_text(get_review_diff())))
     u'Preview Diff\n[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk\nDownload diff\nSide-by-side diff\n1\n---\n2\n+++\n3\n@@ -0,0 +1 @@\n4\n+Fake Diff\u1010'
 
 There is also a link to the diff URL, which is the preview diff URL plus
@@ -573,17 +573,17 @@
 restricted librarian.
 
     >>> link = get_review_diff().find('a')
-    >>> print extract_text(link)
+    >>> print(extract_text(link))
     Download diff
 
-    >>> print link['href']
+    >>> print(link['href'])
     http://.../+preview-diff/.../+files/preview.diff
 
     >>> from lazr.uri import URI
-    >>> print http(r"""
+    >>> print(http(r"""
     ... GET %s HTTP/1.1
     ... Authorization: Basic no-priv@xxxxxxxxxxxxx:test
-    ... """ % URI(link['href']).path)
+    ... """ % URI(link['href']).path))
     HTTP/1.1 303 See Other
     ...
     Location: https://...restricted.../...txt?token=...
@@ -595,15 +595,15 @@
     >>> Store.of(preview_diff).remove(preview_diff)
     >>> from lp.services.propertycache import get_property_cache
     >>> del get_property_cache(bmp).preview_diffs
-    >>> print get_review_diff()
+    >>> print(get_review_diff())
     None
 
 If the review diff is empty, then we say it is empty.
 
     >>> login('admin@xxxxxxxxxxxxx')
-    >>> preview_diff = PreviewDiff.create(bmp, '', u'c', u'd', None, u'')
+    >>> preview_diff = PreviewDiff.create(bmp, b'', u'c', u'd', None, u'')
     >>> logout()
-    >>> print extract_text(get_review_diff())
+    >>> print(extract_text(get_review_diff()))
     Preview Diff
     Empty
 
@@ -613,7 +613,7 @@
 
     >>> update = find_tag_by_id(
     ...     nopriv_browser.contents, 'diff-pending-update')
-    >>> print extract_text(update)
+    >>> print(extract_text(update))
     Updating diff...
     An updated diff will be available in a few minutes.  Reload to see the
     changes.
@@ -622,7 +622,7 @@
     >>> job.complete()
     >>> transaction.commit()
     >>> nopriv_browser.open(url)
-    >>> print find_tag_by_id(nopriv_browser.contents, 'diff-pending-update')
+    >>> print(find_tag_by_id(nopriv_browser.contents, 'diff-pending-update'))
     None
 
 

=== modified file 'lib/lp/code/stories/branches/xx-bug-branch-links.txt'
--- lib/lp/code/stories/branches/xx-bug-branch-links.txt	2017-05-23 13:44:44 +0000
+++ lib/lp/code/stories/branches/xx-bug-branch-links.txt	2018-05-13 10:39:08 +0000
@@ -26,10 +26,10 @@
     >>> def printBugBranchLinks(browser):
     ...     tags = find_tags_by_class(browser.contents, 'buglink-summary')
     ...     if len(tags) == 0:
-    ...         print 'No bug branch links'
+    ...         print('No bug branch links')
     ...     else:
     ...         for tag in tags:
-    ...             print extract_text(tag)
+    ...             print(extract_text(tag))
 
     >>> browser = setupBrowser(auth="Basic test@xxxxxxxxxxxxx:test")
     >>> browser.open(
@@ -38,7 +38,7 @@
     No bug branch links
 
     >>> browser.getLink('Link a bug report').click()
-    >>> print browser.title
+    >>> print(browser.title)
     Link branch...
 
 When linking from a branch to a bug, the bug widget is used.  This
@@ -76,7 +76,7 @@
     >>> admin_browser.open('http://launchpad.dev/firefox/+bug/4/+secrecy')
     >>> admin_browser.getControl('Private', index=1).click()
     >>> admin_browser.getControl('Change').click()
-    >>> print extract_text(find_tag_by_id(admin_browser.contents, 'privacy'))
+    >>> print(extract_text(find_tag_by_id(admin_browser.contents, 'privacy')))
     This report contains Private information...
 
 Sample person can see it...
@@ -155,7 +155,7 @@
     >>> admin_browser.open(grub_url)
     >>> admin_browser.getLink('Delete branch').click()
 
-    >>> print find_tag_by_id(admin_browser.contents, 'deletion-items')
+    >>> print(find_tag_by_id(admin_browser.contents, 'deletion-items'))
     <ul ...
     <a href...>Bug #...: bug-title...</a>...
 

=== modified file 'lib/lp/code/stories/branches/xx-claiming-team-code-reviews.txt'
--- lib/lp/code/stories/branches/xx-claiming-team-code-reviews.txt	2018-03-16 21:20:00 +0000
+++ lib/lp/code/stories/branches/xx-claiming-team-code-reviews.txt	2018-05-13 10:39:08 +0000
@@ -27,8 +27,8 @@
 
 The reviewer table shows both the Vikings team and Eric himself.
 
-    >>> print extract_text(find_tag_by_id(
-    ...     eric_browser.contents, 'code-review-votes'))
+    >>> print(extract_text(find_tag_by_id(
+    ...     eric_browser.contents, 'code-review-votes')))
     Reviewer         Review Type    Date Requested    Status
     Vikings                         ...               Pending [Review]
     Review via email: mp+...@xxxxxxxxxxxxxxxxxx
@@ -44,8 +44,8 @@
 
 The team review has been claimed.
 
-    >>> print extract_text(find_tag_by_id(
-    ...     eric_browser.contents, 'code-review-votes'))
+    >>> print(extract_text(find_tag_by_id(
+    ...     eric_browser.contents, 'code-review-votes')))
     Reviewer                   Review Type    Date Requested  Status
     Eric the Viking                                           Approve ... ago
     Review via email: mp+...@xxxxxxxxxxxxxxxxxx

=== modified file 'lib/lp/code/stories/branches/xx-code-review-comments.txt'
--- lib/lp/code/stories/branches/xx-code-review-comments.txt	2017-07-21 11:01:00 +0000
+++ lib/lp/code/stories/branches/xx-code-review-comments.txt	2018-05-13 10:39:08 +0000
@@ -35,7 +35,7 @@
     ...     tags = find_tags_by_class(browser.contents, klass)
     ...     for count, tag in enumerate(tags):
     ...         if count == index:
-    ...             print extract_text(tag)
+    ...             print(extract_text(tag))
 
     >>> print_comments('boardCommentDetails')
     Eric the Viking (eric) wrote ...
@@ -48,7 +48,7 @@
 
 The person's name links back to the main site for that person.
 
-    >>> print anon_browser.getLink('Eric the Viking').url
+    >>> print(anon_browser.getLink('Eric the Viking').url)
     http://launchpad.dev/~eric
 
 Reply link is displayed even if the user isn't logged in.
@@ -66,8 +66,8 @@
 XXX: Bjorn Tillenius 2010-05-19 bug=582842: Following test disabled,
 since it failed spuriously in buildbot.
 
-#    >>> print eric_browser.getControl(name='field.comment').value.replace(
-#    ...     '\r\n', '\n')
+#    >>> print(eric_browser.getControl(name='field.comment').value.replace(
+#    ...     '\r\n', '\n'))
 #    This is a very long comment about what things should be done to the
 #    source branch to land it.  When this comment is replied to, it should
 #    wrap the line properly.
@@ -115,7 +115,7 @@
     >>> details = find_tags_by_class(
     ...     anon_browser.contents, 'boardCommentDetails')[0]
     >>> links = details.findAll('a')
-    >>> print links[1]['href'] == merge_proposal_path
+    >>> print(links[1]['href'] == merge_proposal_path)
     True
 
 
@@ -143,8 +143,8 @@
 The summary of the votes that have been made for a code review are shown
 in a table at the top of the page.
 
-    >>> print extract_text(find_tag_by_id(
-    ...     eric_browser.contents, 'code-review-votes'))
+    >>> print(extract_text(find_tag_by_id(
+    ...     eric_browser.contents, 'code-review-votes')))
     Reviewer                     Review Type    Date Requested    Status
     Eric the Viking (community)  timeless       ...               Abstain...
     a moment ago

=== modified file 'lib/lp/code/stories/branches/xx-distribution-branches.txt'
--- lib/lp/code/stories/branches/xx-distribution-branches.txt	2011-08-03 11:00:11 +0000
+++ lib/lp/code/stories/branches/xx-distribution-branches.txt	2018-05-13 10:39:08 +0000
@@ -36,5 +36,5 @@
     lp://dev/~eric/mint/old/twisted/old      Development ...
     ...
     >>> ordering_control = browser.getControl(name='field.sort_by')
-    >>> print ordering_control.displayValue
+    >>> print(ordering_control.displayValue)
     ['most recently changed first']

=== modified file 'lib/lp/code/stories/branches/xx-distroseries-branches.txt'
--- lib/lp/code/stories/branches/xx-distroseries-branches.txt	2014-11-26 23:50:26 +0000
+++ lib/lp/code/stories/branches/xx-distroseries-branches.txt	2018-05-13 10:39:08 +0000
@@ -30,5 +30,5 @@
     lp://dev/~eric/mint/stable/zope/new         Development ...
     ...
     >>> ordering_control = browser.getControl(name='field.sort_by')
-    >>> print ordering_control.displayValue
+    >>> print(ordering_control.displayValue)
     ['most recently changed first']

=== modified file 'lib/lp/code/stories/branches/xx-nearby-branches.txt'
--- lib/lp/code/stories/branches/xx-nearby-branches.txt	2014-12-06 10:45:17 +0000
+++ lib/lp/code/stories/branches/xx-nearby-branches.txt	2018-05-13 10:39:08 +0000
@@ -19,6 +19,6 @@
 
     >>> div = find_tag_by_id(browser.contents, 'nearby-branches')
     >>> for anchor in div.findAll('a'):
-    ...     print anchor['href'], anchor.string
+    ...     print(anchor['href'], anchor.string)
     /fooix                      Other Fooix branches
     /~vikings                   Other branches owned by Vikings

=== modified file 'lib/lp/code/stories/branches/xx-person-branches.txt'
--- lib/lp/code/stories/branches/xx-person-branches.txt	2017-10-23 00:16:39 +0000
+++ lib/lp/code/stories/branches/xx-person-branches.txt	2018-05-13 10:39:08 +0000
@@ -7,7 +7,7 @@
 
     >>> browser = setupBrowser(auth='Basic test@xxxxxxxxxxxxx:test')
     >>> browser.open('http://code.launchpad.dev/~name12')
-    >>> print browser.title
+    >>> print(browser.title)
     Code : Sample Person
 
 
@@ -21,8 +21,8 @@
 message.
 
     >>> browser.open('http://code.launchpad.dev/~kinnison')
-    >>> print extract_text(
-    ...     find_tag_by_id(browser.contents, 'no-branch-message'))
+    >>> print(extract_text(
+    ...     find_tag_by_id(browser.contents, 'no-branch-message')))
     There are no branches related to Daniel Silverstone in Launchpad today.
 
 
@@ -32,8 +32,8 @@
 On the user's own code page, they will see directions on pushing a branch.
 
     >>> browser.open('http://code.launchpad.dev/~name12')
-    >>> print extract_text(
-    ...     find_tag_by_id(browser.contents, 'junk-branch-directions'))
+    >>> print(extract_text(
+    ...     find_tag_by_id(browser.contents, 'junk-branch-directions')))
     You can push (upload) personal branches
     (those not related to a project) with the following command:
     bzr push lp:~name12/+junk/BRANCHNAME
@@ -47,7 +47,7 @@
     >>> browser.open('http://code.launchpad.dev/~name12')
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/~name12/landscape/feature-x      Development
     ...
 
@@ -61,11 +61,11 @@
     >>> browser.getControl(name='field.category').displayValue = [
     ...     'Registered']
     >>> browser.getControl('Filter').click()
-    >>> print browser.title
+    >>> print(browser.title)
     Code : Sample Person
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/~name12/landscape/feature-x      Development
     ...
 
@@ -80,11 +80,11 @@
     >>> browser.getControl(name='field.category').displayValue = [
     ...     'Subscribed']
     >>> browser.getControl('Filter').click()
-    >>> print browser.title
+    >>> print(browser.title)
     Code : Sample Person
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/~launchpad/gnome-terminal/launchpad  Development           ...
     lp://dev/~name12/+junk/junk.dev               Experimental  ...
 

=== modified file 'lib/lp/code/stories/branches/xx-person-portlet-teambranches.txt'
--- lib/lp/code/stories/branches/xx-person-portlet-teambranches.txt	2012-01-15 13:32:27 +0000
+++ lib/lp/code/stories/branches/xx-person-portlet-teambranches.txt	2018-05-13 10:39:08 +0000
@@ -23,7 +23,7 @@
 
     >>> browser.open('http://code.launchpad.dev/~eric')
     >>> portlet = find_tag_by_id(browser.contents, 'portlet-team-branches')
-    >>> print portlet
+    >>> print(portlet)
     None
 
     >>> login(ANONYMOUS)
@@ -32,9 +32,9 @@
 
     >>> browser.open('http://code.launchpad.dev/~eric')
     >>> tb = find_tag_by_id(browser.contents, 'portlet-team-branches')
-    >>> print extract_text(tb.h2)
+    >>> print(extract_text(tb.h2))
     Branches owned by
-    >>> print tb.li
+    >>> print(tb.li)
     <li>
       <img src="http://.../vikings.png"; width="14" height="14" />
       <a href="/~vikings">Vikings</a>

=== modified file 'lib/lp/code/stories/branches/xx-private-branch-listings.txt'
--- lib/lp/code/stories/branches/xx-private-branch-listings.txt	2017-10-23 00:16:39 +0000
+++ lib/lp/code/stories/branches/xx-private-branch-listings.txt	2018-05-13 10:39:08 +0000
@@ -50,7 +50,7 @@
     ...     browser.open('http://code.launchpad.dev')
     ...     branches = find_tag_by_id(browser.contents, 'recently-registered')
     ...     for list_item in branches.ul.findAll('li'):
-    ...         print "%r" % list_item.renderContents()
+    ...         print("%r" % list_item.renderContents())
 
 When there is no logged in user, only public branches should be visible.
 
@@ -110,11 +110,11 @@
     ...     # If there are no branches, the table is not shown.
     ...     # So print the text shown in the application summary.
     ...     if table is None:
-    ...         print extract_text(find_tag_by_id(
-    ...             browser.contents, 'branch-summary'))
+    ...         print(extract_text(find_tag_by_id(
+    ...             browser.contents, 'branch-summary')))
     ...     else:
     ...         for row in table.tbody.findAll('tr'):
-    ...             print extract_text(row)
+    ...             print(extract_text(row))
 
     >>> print_landscape_code_listing(anon_browser)
     Launchpad does not know where The Landscape Project hosts its code...
@@ -157,12 +157,12 @@
     ...         branches.append(extract_text(row))
     ...     landscape_branches = [branch for branch in branches
     ...                           if 'landscape' in branch]
-    ...     print "Total of %d branches listed" % len(branches)
+    ...     print("Total of %d branches listed" % len(branches))
     ...     if landscape_branches:
     ...         for branch in landscape_branches:
-    ...             print branch
+    ...             print(branch)
     ...     else:
-    ...         print "No landscape branches"
+    ...         print("No landscape branches")
 
     >>> print_person_code_listing(anon_browser)
     Total of 9 branches listed
@@ -220,10 +220,10 @@
     >>> def printBugBranchLinks(browser):
     ...     tags = find_tags_by_class(browser.contents, 'buglink-summary')
     ...     if len(tags) == 0:
-    ...         print 'No bug branch links'
+    ...         print('No bug branch links')
     ...     else:
     ...         for tag in tags:
-    ...             print extract_text(tag)
+    ...             print(extract_text(tag))
 
     >>> printBugBranchLinks(landscape_dev_browser)
     No bug branch links
@@ -261,21 +261,21 @@
 Since the admin user is able to see all private branches the branch details
 are shown.
 
-    >>> print extract_text(
-    ...     find_tag_by_id(admin_browser.contents, 'branch-details'))
+    >>> print(extract_text(
+    ...     find_tag_by_id(admin_browser.contents, 'branch-details')))
     lp://dev/... - Landscape Developers ...
 
 Landscape developers can see it.
 
     >>> landscape_dev_browser.open('http://launchpad.dev/landscape/trunk')
-    >>> print extract_text(find_tag_by_id(
-    ...     landscape_dev_browser.contents, 'branch-details'))
+    >>> print(extract_text(find_tag_by_id(
+    ...     landscape_dev_browser.contents, 'branch-details')))
     lp://dev/... - Landscape Developers ...
 
 But normal people can't.
 
     >>> anon_browser.open('http://launchpad.dev/landscape/trunk')
-    >>> print extract_text(find_tag_by_id(
-    ...     anon_browser.contents, 'branch-details'))
+    >>> print(extract_text(find_tag_by_id(
+    ...     anon_browser.contents, 'branch-details')))
     No revision control details recorded for
     The Landscape Project trunk series.

=== modified file 'lib/lp/code/stories/branches/xx-product-branches.txt'
--- lib/lp/code/stories/branches/xx-product-branches.txt	2017-10-23 00:16:39 +0000
+++ lib/lp/code/stories/branches/xx-product-branches.txt	2018-05-13 10:39:08 +0000
@@ -28,7 +28,7 @@
 overview page.
 
     >>> browser.open('http://code.launchpad.dev/applets')
-    >>> print browser.title
+    >>> print(browser.title)
     Code : Gnome Applets
 
 If there are not any branches, a helpful message is shown.
@@ -36,7 +36,7 @@
     >>> def get_summary(browser):
     ...     return find_tag_by_id(browser.contents, 'branch-summary')
     >>> summary = get_summary(browser)
-    >>> print extract_text(summary)
+    >>> print(extract_text(summary))
     Launchpad does not know where Gnome Applets
     hosts its code.
     There are no branches for Gnome Applets
@@ -55,7 +55,7 @@
 The 'Help' links go to the help wiki.
 
     >>> for anchor in summary.findAll('a'):
-    ...     print anchor['href']
+    ...     print(anchor['href'])
     https://help.launchpad.net/Code
 
 
@@ -66,7 +66,7 @@
 in downloads that may have been added for the product.
 
     >>> browser.open('http://code.launchpad.dev/netapplet')
-    >>> print extract_text(get_summary(browser))
+    >>> print(extract_text(get_summary(browser)))
     Launchpad does not know where NetApplet hosts its code...
     There are no branches for NetApplet in Launchpad.
     ...
@@ -87,7 +87,7 @@
 
     >>> browser.open('http://code.launchpad.dev/evolution')
     >>> summary = get_summary(browser)
-    >>> print extract_text(get_summary(browser))
+    >>> print(extract_text(get_summary(browser)))
     Evolution hosts its code externally.
     You can learn more at the project's web page.
     Launchpad imports the master branch and you can create branches from
@@ -124,7 +124,7 @@
     >>> browser.open('http://code.launchpad.dev/firefox')
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr')[0:2]:
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/firefox
       Series: trunk, 1.0                     Development ...
     lp://dev/~mark/firefox/release--0.9.1  Development ...
@@ -139,7 +139,7 @@
     >>> browser.open('http://code.launchpad.dev/firefox')
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr')[0:2]:
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/firefox
       Series: trunk                 Development ...
     lp://dev/firefox/1.0
@@ -160,7 +160,7 @@
     >>> browser.open('http://code.launchpad.dev/firefox')
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr')[0:2]:
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/~mark/firefox/release-0.8     Development ...
 
 
@@ -185,10 +185,10 @@
     >>> def print_links(browser):
     ...     links = find_tag_by_id(browser.contents, 'involvement')
     ...     if links is None:
-    ...         print 'None'
+    ...         print('None')
     ...         return
     ...     for link in links.findAll('a'):
-    ...         print extract_text(link)
+    ...         print(extract_text(link))
 
     >>> def setup_code_hosting(productname):
     ...     with celebrity_logged_in('admin'):
@@ -199,7 +199,7 @@
 The involvement portlet is not shown if the product does not have code
 hosting configured or if it is not using Launchpad.
 
-    >>> print product.codehosting_usage.name
+    >>> print(product.codehosting_usage.name)
     UNKNOWN
     >>> logout()
     >>> admin_browser.open('http://code.launchpad.dev/firefox')
@@ -208,7 +208,7 @@
 
     >>> setup_code_hosting('firefox')
     >>> login(ANONYMOUS)
-    >>> print product.codehosting_usage.name
+    >>> print(product.codehosting_usage.name)
     LAUNCHPAD
     >>> logout()
     >>> admin_browser.open('http://code.launchpad.dev/firefox')
@@ -257,9 +257,9 @@
     ...     browser.open('http://code.launchpad.dev/%s' % product)
     ...     portlet = get_stats_portlet(browser)
     ...     if portlet is None:
-    ...         print 'None'
+    ...         print('None')
     ...     else:
-    ...         print normalize_whitespace(extract_text(portlet))
+    ...         print(normalize_whitespace(extract_text(portlet)))
 
     >>> setup_code_hosting('gnome-terminal')
     >>> print_portlet('gnome-terminal')
@@ -306,7 +306,7 @@
     None
 
     >>> message = find_tag_by_id(browser.contents, 'no-branch-message')
-    >>> print extract_text(message)
+    >>> print(extract_text(message))
     There are branches registered for iso-codes but none of them match the
     current filter criteria for this page. Try filtering on "Any Status".
 
@@ -321,6 +321,6 @@
     ...     'http://code.launchpad.dev/firefox/+branches'
     ...     '?field.lifecycle=Mature')
     >>> message = find_tag_by_id(browser.contents, 'no-branch-message')
-    >>> print extract_text(message)
+    >>> print(extract_text(message))
     There are branches registered for Mozilla Firefox but none of them match
     the current filter criteria for this page. Try filtering on "Any Status".

=== modified file 'lib/lp/code/stories/branches/xx-product-overview.txt'
--- lib/lp/code/stories/branches/xx-product-overview.txt	2017-10-23 00:16:39 +0000
+++ lib/lp/code/stories/branches/xx-product-overview.txt	2018-05-13 10:39:08 +0000
@@ -8,10 +8,10 @@
     ...     browser.open(url)
     ...     branches = find_portlet(browser.contents, 'Latest branches')
     ...     if branches is None:
-    ...         print "No 'Latest branches' portlet found at %s" % (url,)
+    ...         print("No 'Latest branches' portlet found at %s" % (url,))
     ...         return
     ...     for list_item in branches.findAll('li'):
-    ...         print extract_text(list_item)
+    ...         print(extract_text(list_item))
 
     >>> def make_branch_on_product(product, branch_name, person_name):
     ...     """Make a branch on `product`.

=== modified file 'lib/lp/code/stories/branches/xx-project-branches.txt'
--- lib/lp/code/stories/branches/xx-project-branches.txt	2017-10-23 00:16:39 +0000
+++ lib/lp/code/stories/branches/xx-project-branches.txt	2018-05-13 10:39:08 +0000
@@ -10,7 +10,7 @@
 
     >>> browser.open('http://launchpad.dev/mozilla')
     >>> browser.getLink('Code').click()
-    >>> print browser.title
+    >>> print(browser.title)
     Code : The Mozilla Project
 
 
@@ -25,7 +25,7 @@
     >>> browser.open('http://code.launchpad.dev/mozilla')
     >>> table = find_tag_by_id(browser.contents, 'branchtable')
     >>> for row in table.tbody.findAll('tr'):
-    ...     print extract_text(row)
+    ...     print(extract_text(row))
     lp://dev/~mark/firefox/release--0.9.1  Development   firefox ...
     lp://dev/~mark/firefox/release-0.8     Development   firefox ...
     lp://dev/~mark/firefox/release-0.9     Development   firefox ...
@@ -36,10 +36,10 @@
 If there are not any branches, a relevant message is shown.
 
     >>> browser.open('http://code.launchpad.dev/aaa')
-    >>> print browser.title
+    >>> print(browser.title)
     Code : the Test Project
     >>> message = find_tag_by_id(browser.contents, 'no-branchtable')
-    >>> print extract_text(message)
+    >>> print(extract_text(message))
     Launchpad does not know where any of
     the Test Project's
     projects host their code.

=== modified file 'lib/lp/code/stories/branches/xx-propose-for-merging.txt'
--- lib/lp/code/stories/branches/xx-propose-for-merging.txt	2010-12-19 22:59:04 +0000
+++ lib/lp/code/stories/branches/xx-propose-for-merging.txt	2018-05-13 10:39:08 +0000
@@ -33,7 +33,7 @@
     ...                 checked = '( )'
     ...         except KeyError:
     ...             checked = '( )'
-    ...         print checked, button['value']
+    ...         print(checked, button['value'])
 
     >>> print_radio_buttons(browser)
     (*) ~eric/fooix/trunk

=== modified file 'lib/lp/code/stories/branches/xx-source-package-branches-empty.txt'
--- lib/lp/code/stories/branches/xx-source-package-branches-empty.txt	2014-11-27 22:13:36 +0000
+++ lib/lp/code/stories/branches/xx-source-package-branches-empty.txt	2018-05-13 10:39:08 +0000
@@ -25,7 +25,7 @@
 
 Since there are no branches, there is no branch listing table:
 
-    >>> print find_tag_by_id(browser.contents, 'branchtable')
+    >>> print(find_tag_by_id(browser.contents, 'branchtable'))
     None
 
     >>> print_tag_with_id(browser.contents, 'branch-summary')
@@ -37,11 +37,11 @@
 
 Since there are no branches, there is no branch listing table:
 
-    >>> print find_tag_by_id(browser.contents, 'branchtable')
+    >>> print(find_tag_by_id(browser.contents, 'branchtable'))
     None
 
-    >>> print repr(extract_text(
-    ...     find_tag_by_id(browser.contents, 'branch-summary')))
+    >>> print(repr(extract_text(
+    ...     find_tag_by_id(browser.contents, 'branch-summary'))))
     u'There are no branches for the foo package in distro\nin Launchpad.'
 
     >>> print_tag_with_id(browser.contents, 'distro-branch-warning')

=== modified file 'lib/lp/code/stories/branches/xx-source-package-branches-listing.txt'
--- lib/lp/code/stories/branches/xx-source-package-branches-listing.txt	2017-10-23 00:16:39 +0000
+++ lib/lp/code/stories/branches/xx-source-package-branches-listing.txt	2018-05-13 10:39:08 +0000
@@ -35,7 +35,7 @@
     >>> def print_branches(browser):
     ...    table = find_tag_by_id(browser.contents, 'branchtable')
     ...    for row in table.tbody.findAll('tr'):
-    ...        print extract_text(row)
+    ...        print(extract_text(row))
     >>> print_branches(browser)
     lp://dev/~owner1/distro/series/foo/branch1 ...
     lp://dev/~owner2/distro/series/foo/branch2 ...

=== modified file 'lib/lp/code/stories/branches/xx-subscribing-branches.txt'
--- lib/lp/code/stories/branches/xx-subscribing-branches.txt	2017-10-23 00:16:39 +0000
+++ lib/lp/code/stories/branches/xx-subscribing-branches.txt	2018-05-13 10:39:08 +0000
@@ -7,17 +7,17 @@
     ...     subscriptions = find_tags_by_class(
     ...         contents, 'branch-subscribers')[0]
     ...     if subscriptions == None:
-    ...         print subscriptions
+    ...         print(subscriptions)
     ...         return
     ...     for subscriber in subscriptions.findAll('div'):
-    ...         print extract_text(subscriber.renderContents())
+    ...         print(extract_text(subscriber.renderContents()))
 
 Another to print the informational message.
 
     >>> def print_informational_message(contents):
     ...     message = find_tags_by_class(contents, 'informational message')
     ...     if message:
-    ...         print extract_text(message[0])
+    ...         print(extract_text(message[0]))
 
 
 Subscribing to Branches
@@ -238,7 +238,7 @@
 
     >>> browser.getLink(url='+subscription/landscape').click()
     >>> main_content = find_main_content(browser.contents)
-    >>> print extract_text(main_content.h1)
+    >>> print(extract_text(main_content.h1))
     Edit subscription to branch for Landscape Developers
 
 From this page the branch subscription can be altered...

=== modified file 'lib/lp/code/stories/branches/xx-upgrading-branches.txt'
--- lib/lp/code/stories/branches/xx-upgrading-branches.txt	2013-09-27 04:13:23 +0000
+++ lib/lp/code/stories/branches/xx-upgrading-branches.txt	2018-05-13 10:39:08 +0000
@@ -39,7 +39,7 @@
     ...     auth='Basic fats@xxxxxxxxxx:test')
     >>> domino_browser.open(branch_url)
     >>> domino_browser.getLink("Upgrade this branch").click()
-    >>> print domino_browser.url
+    >>> print(domino_browser.url)
     http://code.launchpad.dev/~domino/.../+upgrade
     >>> domino_browser.getControl('Upgrade').click()
 

=== modified file 'lib/lp/code/stories/branches/xx-upload-directions.txt'
--- lib/lp/code/stories/branches/xx-upload-directions.txt	2016-11-17 23:16:12 +0000
+++ lib/lp/code/stories/branches/xx-upload-directions.txt	2018-05-13 10:39:08 +0000
@@ -49,7 +49,7 @@
     >>> anon_browser.open(branch_page)
     >>> content = anon_browser.contents
     >>> instructions = find_tag_by_id(content, 'upload-directions')
-    >>> print instructions.renderContents()
+    >>> print(instructions.renderContents())
     Only
     <a href="http://launchpad.dev/~name12";>Sample Person</a>
     can upload to this branch. If you are Sample Person please
@@ -61,7 +61,7 @@
     >>> ddaa_browser.open(branch_page)
     >>> content = ddaa_browser.contents
     >>> instructions = find_tag_by_id(content, 'upload-directions')
-    >>> print instructions.renderContents()
+    >>> print(instructions.renderContents())
     <div...
     You cannot upload to this branch. Only
     <a href="http://launchpad.dev/~name12";>Sample Person</a>
@@ -74,7 +74,7 @@
     >>> name12_browser.open(branch_page)
     >>> content = name12_browser.contents
     >>> instructions = find_tag_by_id(content, 'upload-directions')
-    >>> print extract_text(instructions)
+    >>> print(extract_text(instructions))
     Update this branch:
     bzr push --use-existing-dir lp://dev/~name12/gnome-terminal/pushed
 
@@ -95,7 +95,7 @@
     >>> name12_browser.open(branch_page)
     >>> content = name12_browser.contents
     >>> instructions = find_tag_by_id(content, 'ssh-key-directions')
-    >>> print instructions.renderContents()
+    >>> print(instructions.renderContents())
     To authenticate with the Launchpad branch upload service, you need to
     <a href="http://launchpad.dev/~name12/+editsshkeys";>
     register an SSH key</a>.
@@ -110,7 +110,7 @@
 
     >>> name12_browser.open(branch_page)
     >>> content = name12_browser.contents
-    >>> print find_tag_by_id(content, 'ssh-key-directions')
+    >>> print(find_tag_by_id(content, 'ssh-key-directions'))
     None
 
 If the user is not logged in, or does have the permission to upload to the
@@ -120,12 +120,12 @@
 
     >>> anon_browser.open(branch_page)
     >>> content = anon_browser.contents
-    >>> print find_tag_by_id(content, 'ssh-key-directions')
+    >>> print(find_tag_by_id(content, 'ssh-key-directions'))
     None
 
     >>> ddaa_browser.open(branch_page)
     >>> content = ddaa_browser.contents
-    >>> print find_tag_by_id(content, 'ssh-key-directions')
+    >>> print(find_tag_by_id(content, 'ssh-key-directions'))
     None
 
 
@@ -154,7 +154,7 @@
     >>> anon_browser.open(branch_page)
     >>> content = anon_browser.contents
     >>> instructions = find_tag_by_id(content, 'upload-directions')
-    >>> print instructions.renderContents()
+    >>> print(instructions.renderContents())
     Members of <a
     href="http://launchpad.dev/~landscape-developers";>Landscape
     Developers</a> can upload to this branch. <a href="+login">Log in</a> for
@@ -166,7 +166,7 @@
     >>> ddaa_browser.open(branch_page)
     >>> content = ddaa_browser.contents
     >>> instructions = find_tag_by_id(content, 'upload-directions')
-    >>> print instructions.renderContents()
+    >>> print(instructions.renderContents())
     <div...
     You cannot upload to this branch. Members of <a
     href="http://launchpad.dev/~landscape-developers";>Landscape
@@ -181,7 +181,7 @@
     >>> name12_browser.open(branch_page)
     >>> content = name12_browser.contents
     >>> instructions = find_tag_by_id(content, 'upload-directions')
-    >>> print extract_text(instructions)
+    >>> print(extract_text(instructions))
     Update this branch:
     bzr push --use-existing-dir
     lp://dev/~landscape-developers/gnome-terminal/pushed
@@ -196,5 +196,5 @@
     >>> anon_browser.open(import_branch_page)
     >>> content = anon_browser.contents
     >>> instructions = find_tag_by_id(content, 'upload-directions')
-    >>> print instructions
+    >>> print(instructions)
     None

=== modified file 'lib/lp/code/stories/codeimport/xx-admin-codeimport.txt'
--- lib/lp/code/stories/codeimport/xx-admin-codeimport.txt	2016-10-13 14:46:41 +0000
+++ lib/lp/code/stories/codeimport/xx-admin-codeimport.txt	2018-05-13 10:39:08 +0000
@@ -69,7 +69,7 @@
     ...     if details is None:
     ...         details = find_tag_by_id(
     ...             browser.contents, 'repository-import-details')
-    ...     print extract_text(details.div.div)
+    ...     print(extract_text(details.div.div))
 
     >>> import_browser.open(svn_import_location)
     >>> print_import_details(import_browser)
@@ -116,7 +116,7 @@
     >>> def print_form_fields(browser):
     ...     tags = find_tags_by_class(browser.contents, 'textType')
     ...     for tag in tags:
-    ...         print '%s: %s' % (tag['name'], tag['value'])
+    ...         print('%s: %s' % (tag['name'], tag['value']))
 
     >>> print_form_fields(import_browser)
     field.url: svn://svn.example.com/fooix/trunk
@@ -333,7 +333,7 @@
     >>> anon_browser.getControl('Import Now')
     Traceback (most recent call last):
       ...
-    LookupError: label 'Import Now'
+    LookupError: label u'Import Now'
 
 If the logged in user clicks this button, the import will be scheduled
 to run ASAP and the fact that the import has been requested is

=== modified file 'lib/lp/code/stories/codeimport/xx-codeimport-machines.txt'
--- lib/lp/code/stories/codeimport/xx-codeimport-machines.txt	2011-12-24 15:18:32 +0000
+++ lib/lp/code/stories/codeimport/xx-codeimport-machines.txt	2018-05-13 10:39:08 +0000
@@ -13,7 +13,7 @@
     >>> def print_table(browser):
     ...    table = find_tag_by_id(
     ...        browser.contents, 'code-import-machine-listing')
-    ...    print extract_text(table)
+    ...    print(extract_text(table))
 
 Initially only the machine in sample data is shown.
 
@@ -66,13 +66,13 @@
 current status.
 
     >>> def print_heading(browser):
-    ...     print find_main_content(browser.contents).h1.renderContents()
+    ...     print(find_main_content(browser.contents).h1.renderContents())
     >>> print_heading(browser)
     apollo: Online
 
 The page also shows the current running jobs for that machine.
 
-    >>> print extract_text(find_tag_by_id(browser.contents, 'current-jobs'))
+    >>> print(extract_text(find_tag_by_id(browser.contents, 'current-jobs')))
     Current jobs
     lp://dev/~.../.../... Started: ... ago Last heartbeat: ... ago
          Creating changeset 1
@@ -84,7 +84,7 @@
 
     >>> def print_events(browser):
     ...     recent_events = find_tag_by_id(browser.contents, 'recent-events')
-    ...     print extract_text(recent_events)
+    ...     print(extract_text(recent_events))
     >>> print_events(browser)
     Related events
     ...: Job Started lp://dev/~.../.../...
@@ -97,13 +97,13 @@
 If the user is an admin or member of VCS Imports, they are able to change
 the status of the machine.
 
-    >>> print find_tag_by_id(browser.contents, 'update-status')
+    >>> print(find_tag_by_id(browser.contents, 'update-status'))
     None
 
     >>> admin_browser.open(browser.url)
 
-    >>> print find_tag_by_id(admin_browser.contents,
-    ...     'update-status').h2.renderContents()
+    >>> print(find_tag_by_id(admin_browser.contents,
+    ...     'update-status').h2.renderContents())
     Update machine status
 
     >>> admin_browser.getControl('Reason').value = (

=== modified file 'lib/lp/code/stories/codeimport/xx-codeimport-results.txt'
--- lib/lp/code/stories/codeimport/xx-codeimport-results.txt	2017-10-23 00:16:39 +0000
+++ lib/lp/code/stories/codeimport/xx-codeimport-results.txt	2018-05-13 10:39:08 +0000
@@ -30,7 +30,7 @@
 
     >>> browser.open(branch_url_1)
     >>> import_results = find_tag_by_id(browser.contents, 'import-results')
-    >>> print extract_text(import_results).replace('&mdash;', '--')
+    >>> print(extract_text(import_results).replace('&mdash;', '--'))
     Import started on 2007-12-07 on odin and finished on 2007-12-07
       taking 7 hours -- see the log
     Import started on 2007-12-06 on odin and finished on 2007-12-06
@@ -53,7 +53,7 @@
     >>> # The ordering here is dependant on the order the status values
     >>> # are declared in the enumeration.
     >>> for img in import_results.findAll('img'):
-    ...     print img
+    ...     print(img)
     <img src="/@@/no" title="Unsupported feature" />
     <img src="/@@/no" title="Foreign branch invalid" />
     <img src="/@@/no" title="Internal Failure" />
@@ -65,7 +65,7 @@
     >>> browser.open(branch_url_2)
     >>> import_results = find_tag_by_id(browser.contents, 'import-results')
     >>> for img in import_results.findAll('img'):
-    ...     print img
+    ...     print(img)
     <img src="/@@/no" title="Job killed" />
     <img src="/@@/no" title="Job reclaimed" />
     <img src="/@@/no" title="Broken remote branch" />

=== modified file 'lib/lp/code/stories/codeimport/xx-codeimport-view.txt'
--- lib/lp/code/stories/codeimport/xx-codeimport-view.txt	2016-10-13 14:21:35 +0000
+++ lib/lp/code/stories/codeimport/xx-codeimport-view.txt	2018-05-13 10:39:08 +0000
@@ -32,13 +32,13 @@
 
     >>> browser.open('http://code.launchpad.dev')
     >>> browser.getLink('3 imported branches').click()
-    >>> print browser.title
+    >>> print(browser.title)
     Code Imports
 
 Any user can look at the current list of imports.
 
     >>> anon_browser.open('http://code.launchpad.dev/+code-imports')
-    >>> print anon_browser.title
+    >>> print(anon_browser.title)
     Code Imports
 
 There are two CodeImports in the sample data and they both show up in
@@ -47,7 +47,7 @@
     >>> table = find_tag_by_id(browser.contents, 'code-import-listing')
     >>> names = [extract_text(tr.td) for tr in table.tbody('tr')]
     >>> for name in names:
-    ...     print name
+    ...     print(name)
     ~vcs-imports/gnome-terminal/import
     ~vcs-imports/evolution/import
     ~name12/gnome-terminal/+git/gnome-terminal
@@ -76,8 +76,8 @@
     ['Any']
     >>> control.displayValue = ["Invalid"]
     >>> browser.getControl(name="submit").click()
-    >>> print extract_text(
-    ...     find_tag_by_id(browser.contents, 'no-imports'))
+    >>> print(extract_text(
+    ...     find_tag_by_id(browser.contents, 'no-imports')))
     No matching code imports found.
 
 Of course selecting the "Any" filtering option ensures that all
@@ -88,7 +88,7 @@
     >>> table = find_tag_by_id(browser.contents, 'code-import-listing')
     >>> rows = [extract_text(tr) for tr in table('tr')]
     >>> for row in rows:
-    ...     print row
+    ...     print(row)
     Import                                     Created  Source type        Target type Location     Status
     ~vcs-imports/gnome-terminal/import         2007-... Subversion via ... Bazaar      http://sv... Reviewed
     ~vcs-imports/evolution/import              2007-... Concurrent Vers... Bazaar      :pserver:... Pending Review
@@ -105,7 +105,7 @@
     >>> table = find_tag_by_id(browser.contents, 'code-import-listing')
     >>> rows = [extract_text(tr) for tr in table('tr')]
     >>> for row in rows:
-    ...     print row
+    ...     print(row)
     Import                        Created  Source type        Target type Location     Status
     ~vcs-imports/evolution/import 2007-... Concurrent Vers... Bazaar      :pserver:... Pending Review
 
@@ -120,7 +120,7 @@
     >>> table = find_tag_by_id(browser.contents, 'code-import-listing')
     >>> rows = [extract_text(tr) for tr in table('tr')]
     >>> for row in rows:
-    ...     print row
+    ...     print(row)
     Import                                     Created  Source type        Target type Location     Status
     ~name12/gnome-terminal/+git/gnome-terminal ...      Git                Git         git://git... Reviewed
     ~name12/evolution/+git/evolution           ...      Git                Git         https://g... Reviewed

=== modified file 'lib/lp/code/stories/codeimport/xx-create-codeimport.txt'
--- lib/lp/code/stories/codeimport/xx-create-codeimport.txt	2016-11-12 02:24:09 +0000
+++ lib/lp/code/stories/codeimport/xx-create-codeimport.txt	2018-05-13 10:39:08 +0000
@@ -7,20 +7,20 @@
 
     >>> browser = setupBrowser(auth="Basic no-priv@xxxxxxxxxxxxx:test")
     >>> browser.open("http://code.launchpad.dev";)
-    >>> print find_tag_by_id(browser.contents, "new-code-import")
+    >>> print(find_tag_by_id(browser.contents, "new-code-import"))
     <a href="/+code-imports/+new" id="new-code-import">
        <img alt="Import your project" ...>
     </a>
 
     >>> browser.getLink(id="new-code-import").click()
-    >>> print browser.title
+    >>> print(browser.title)
     Request a code import...
 
 There is a cancel link on this page near the buttons to take the
 user back to the main code page.
 
     >>> browser.getLink('Cancel').click()
-    >>> print browser.url
+    >>> print(browser.url)
     http://code.launchpad.dev/
 
 For projects that don't officially use Launchpad for code, there is also a
@@ -73,7 +73,7 @@
 
 When the user clicks continue, the import branch is created
 
-    >>> print extract_text(find_tag_by_id(browser.contents, "import-details"))
+    >>> print(extract_text(find_tag_by_id(browser.contents, "import-details")))
     Import Status: Reviewed
     This branch is an import of the Bazaar branch
     at http://bzr.example.com/firefox/trunk.
@@ -92,7 +92,7 @@
     ...     "http://user:password@xxxxxxxxxxxxxxx/firefox/trunk";)
     >>> browser.getControl('Project').value = "firefox"
     >>> browser.getControl('Request Import').click()
-    >>> print extract_text(find_tag_by_id(browser.contents, "import-details"))
+    >>> print(extract_text(find_tag_by_id(browser.contents, "import-details")))
     Import Status: Reviewed
     This branch is an import of the Bazaar branch
     at http://user:password@xxxxxxxxxxxxxxx/firefox/trunk.
@@ -121,7 +121,7 @@
     >>> browser.getControl('Repo URL', index=0).value = (
     ...     "git://git.launchpad.net/firefox.git")
     >>> browser.getControl('Request Import').click()
-    >>> print extract_text(find_tag_by_id(browser.contents, "import-details"))
+    >>> print(extract_text(find_tag_by_id(browser.contents, "import-details")))
     Import Status: Reviewed
     This branch is an import of the HEAD branch of the Git repository at
     git://git.launchpad.net/firefox.git.
@@ -143,7 +143,7 @@
 
 When the user clicks continue, the import branch is created
 
-    >>> print extract_text(find_tag_by_id(browser.contents, "import-details"))
+    >>> print(extract_text(find_tag_by_id(browser.contents, "import-details")))
     Import Status: Reviewed
     This branch is an import of the Subversion branch
     from http://svn.example.com/firefox/trunk.
@@ -157,9 +157,9 @@
 attribute on the text of 'Subversion'.
 
     >>> svn_span = find_tag_by_id(browser.contents, 'svn-import-details').span
-    >>> print extract_text(svn_span)
+    >>> print(extract_text(svn_span))
     Subversion
-    >>> print svn_span['title']
+    >>> print(svn_span['title'])
     Subversion via bzr-svn
 
 If the user wants, they can include a username and password in the
@@ -172,7 +172,7 @@
     ...     "http://user:password@xxxxxxxxxxxxxxx/firefox/trunk";)
     >>> browser.getControl('Project').value = "firefox"
     >>> browser.getControl('Request Import').click()
-    >>> print extract_text(find_tag_by_id(browser.contents, "import-details"))
+    >>> print(extract_text(find_tag_by_id(browser.contents, "import-details")))
     Import Status: Reviewed
     This branch is an import of the Subversion branch
     from http://user:password@xxxxxxxxxxxxxxx/firefox/trunk.
@@ -196,7 +196,7 @@
 
 When the user clicks continue, the approved import branch is created.
 
-    >>> print extract_text(find_tag_by_id(browser.contents, "import-details"))
+    >>> print(extract_text(find_tag_by_id(browser.contents, "import-details")))
     Import Status: Reviewed
     This branch is an import of the HEAD branch of the Git repository at
     git://example.com/firefox.git.
@@ -229,7 +229,7 @@
 
 When the user clicks continue, the approved import repository is created.
 
-    >>> print extract_text(find_tag_by_id(browser.contents, "import-details"))
+    >>> print(extract_text(find_tag_by_id(browser.contents, "import-details")))
     Import Status: Reviewed
     This repository is an import of the Git repository at
     git://example.com/firefox.git.
@@ -251,7 +251,7 @@
     >>> browser.getControl('Module').value = "firefox"
     >>> browser.getControl('Request Import').click()
 
-    >>> print extract_text(find_tag_by_id(browser.contents, "import-details"))
+    >>> print(extract_text(find_tag_by_id(browser.contents, "import-details")))
     Import Status: Reviewed
     This branch is an import of the CVS module firefox from
     :pserver:anonymous@xxxxxxxxxxxxxxx:/mozilla/cvs.

=== modified file 'lib/lp/code/stories/codeimport/xx-edit-codeimport.txt'
--- lib/lp/code/stories/codeimport/xx-edit-codeimport.txt	2013-09-27 04:13:23 +0000
+++ lib/lp/code/stories/codeimport/xx-edit-codeimport.txt	2018-05-13 10:39:08 +0000
@@ -40,7 +40,7 @@
     >>> def print_import_details(browser):
     ...     div = find_tag_by_id(
     ...         browser.contents, 'branch-import-details').div.div
-    ...     print extract_text(div)
+    ...     print(extract_text(div))
     >>> anon_browser.open(svn_import_location)
     >>> print_import_details(anon_browser)
     Import Status: Reviewed
@@ -129,7 +129,7 @@
     >>> anon_browser.getControl('Import Now')
     Traceback (most recent call last):
       ...
-    LookupError: label 'Import Now'
+    LookupError: label u'Import Now'
 
 If the logged in user clicks this button, the import will be scheduled
 to run ASAP and the fact that the import has been requested is

=== modified file 'lib/lp/code/stories/codeimport/xx-failing-codeimport.txt'
--- lib/lp/code/stories/codeimport/xx-failing-codeimport.txt	2011-12-29 05:29:36 +0000
+++ lib/lp/code/stories/codeimport/xx-failing-codeimport.txt	2018-05-13 10:39:08 +0000
@@ -22,7 +22,8 @@
 
     >>> user_browser.open(
     ...     'http://code.launchpad.dev/~import-owner/imported/trunk')
-    >>> print extract_text(find_tag_by_id(user_browser.contents, 'failing-try-again'))
+    >>> print(extract_text(
+    ...     find_tag_by_id(user_browser.contents, 'failing-try-again')))
     The import has been suspended because it failed 5 or more times in succession.
 
 Any logged in user will also see a button that can request the import
@@ -45,7 +46,7 @@
 
     >>> def print_import_details(browser):
     ...     div = find_tag_by_id(browser.contents, 'import-details')
-    ...     print extract_text(div)
+    ...     print(extract_text(div))
     >>> user_browser.getControl('Try Again').click()
     >>> print_import_details(user_browser)
     Import Status: Reviewed

=== modified file 'lib/lp/code/stories/feeds/xx-branch-atom.txt'
--- lib/lp/code/stories/feeds/xx-branch-atom.txt	2015-01-29 14:14:01 +0000
+++ lib/lp/code/stories/feeds/xx-branch-atom.txt	2018-05-13 10:39:08 +0000
@@ -53,7 +53,7 @@
     [u'Branches for Mike Murphy']
     >>> def print_parse_ids(browser):
     ...     for id in parse_ids(browser.contents):
-    ...         print id
+    ...         print(id)
 
 Ignore the date associated with the id of 'mike' as this is the date created
 of the person, which will be different each time the test is run.
@@ -69,7 +69,7 @@
 
     >>> def print_parse_links(browser):
     ...     for link in parse_links(browser.contents, rel="self"):
-    ...         print link
+    ...         print(link)
     >>> print_parse_links(anon_browser)
     <link rel="self" href="http://feeds.launchpad.dev/~mike/branches.atom"; />
 
@@ -114,7 +114,7 @@
     ...     test_user).getBranches().order_by(Branch.id)
     >>> for branch in branches:
     ...     branch = removeSecurityProxy(branch)
-    ...     print branch.unique_name, branch.private
+    ...     print(branch.unique_name, branch.private)
     ~landscape-developers/landscape/trunk True
     ~name12/landscape/feature-x True
     >>> logout()
@@ -208,7 +208,7 @@
     No Errors
     >>> BSS(browser.contents).title.contents
     [u'Latest Revisions for Branch lp://dev/~mark/firefox/release--0.9.1']
-    >>> print browser.url
+    >>> print(browser.url)
     http://feeds.launchpad.dev/~mark/firefox/release--0.9.1/branch.atom
 
 The first <id> in a feed identifies the feed.  Each entry then has its
@@ -217,7 +217,7 @@
     >>> soup = BSS(browser.contents, parseOnlyThese=SoupStrainer('id'))
     >>> ids = parse_ids(browser.contents)
     >>> for id_ in ids:
-    ...     print id_
+    ...     print(id_)
     <id>tag:launchpad.net,2006-10-16:/code/~mark/firefox/release--0.9.1</id>
     <id>tag:launchpad.net,2005-03-09:/code/~mark/firefox/release--0.9.1/revision/1</id>
     >>> print_parse_links(browser)

=== modified file 'lib/lp/code/stories/feeds/xx-revision-atom.txt'
--- lib/lp/code/stories/feeds/xx-revision-atom.txt	2015-01-29 14:14:01 +0000
+++ lib/lp/code/stories/feeds/xx-revision-atom.txt	2018-05-13 10:39:08 +0000
@@ -79,7 +79,7 @@
     [u'Latest Revisions by Mike Murphy']
     >>> def print_parse_ids(browser):
     ...     for id in parse_ids(browser.contents):
-    ...         print id
+    ...         print(id)
 
 Ignore the date associated with the id of 'mike' as this is the date created
 of the person, which will be different each time the test is run.
@@ -94,7 +94,7 @@
 
     >>> def print_parse_links(browser):
     ...     for link in parse_links(browser.contents, rel="self"):
-    ...         print link
+    ...         print(link)
     >>> print_parse_links(anon_browser)
     <link rel="self" href="http://feeds.launchpad.dev/~mike/revisions.atom"; />
 

=== modified file 'lib/lp/code/stories/sourcepackagerecipes/xx-recipe-listings.txt'
--- lib/lp/code/stories/sourcepackagerecipes/xx-recipe-listings.txt	2017-10-23 00:16:39 +0000
+++ lib/lp/code/stories/sourcepackagerecipes/xx-recipe-listings.txt	2018-05-13 10:39:08 +0000
@@ -8,12 +8,12 @@
     >>> def print_recipe_listing_head(browser):
     ...     table = find_tag_by_id(browser.contents, 'recipetable')
     ...     for row in table.thead.findAll('tr'):
-    ...         print extract_text(row)
+    ...         print(extract_text(row))
 
     >>> def print_recipe_listing_contents(browser):
     ...     table = find_tag_by_id(browser.contents, 'recipetable')
     ...     for row in table.tbody.findAll('tr'):
-    ...         print extract_text(row)
+    ...         print(extract_text(row))
 
 
 Branch Recipe Listings
@@ -49,7 +49,7 @@
 
     >>> nopriv_browser.open(branch_url)
     >>> nopriv_browser.getLink('3 recipes').click()
-    >>> print nopriv_browser.url
+    >>> print(nopriv_browser.url)
     http://code.launchpad.dev/%7Eperson-name.../product-name.../branch.../+recipes
 
 The "Base Source" column should not be shown.
@@ -97,7 +97,7 @@
 
     >>> nopriv_browser.open(repository_url)
     >>> nopriv_browser.getLink('4 recipes').click()
-    >>> print nopriv_browser.url
+    >>> print(nopriv_browser.url)
     http://code.launchpad.dev/%7Eperson-name.../product-name.../+git/gitrepository.../+recipes
 
 The "Base Source" column should not be shown.
@@ -124,7 +124,7 @@
     >>> with GitHostingFixture():
     ...     nopriv_browser.open(ref1_url)
     >>> nopriv_browser.getLink('2 recipes').click()
-    >>> print nopriv_browser.url
+    >>> print(nopriv_browser.url)
     http://code.launchpad.dev/%7Eperson-name.../product-name.../+git/gitrepository.../+ref/a/+recipes
 
     >>> print_recipe_listing_head(nopriv_browser)
@@ -144,7 +144,7 @@
 
     >>> nopriv_browser.open(product_url)
     >>> nopriv_browser.getLink('View source package recipes').click()
-    >>> print nopriv_browser.url
+    >>> print(nopriv_browser.url)
     http://code.launchpad.dev/product-name.../+recipes
 
     >>> print_recipe_listing_head(nopriv_browser)
@@ -165,7 +165,7 @@
 
     >>> nopriv_browser.open(target_url)
     >>> nopriv_browser.getLink('View source package recipes').click()
-    >>> print nopriv_browser.url
+    >>> print(nopriv_browser.url)
     http://code.launchpad.dev/product-name.../+recipes
 
     >>> print_recipe_listing_head(nopriv_browser)
@@ -196,7 +196,7 @@
 
     >>> nopriv_browser.open(person_url)
     >>> nopriv_browser.getLink('View source package recipes').click()
-    >>> print nopriv_browser.url
+    >>> print(nopriv_browser.url)
     http://code.launchpad.dev/~person-name.../+recipes
 
 The "Owner" section should be missing.

=== modified file 'lib/lp/code/stories/webservice/xx-branch-links.txt'
--- lib/lp/code/stories/webservice/xx-branch-links.txt	2012-08-08 07:22:51 +0000
+++ lib/lp/code/stories/webservice/xx-branch-links.txt	2018-05-13 10:39:08 +0000
@@ -43,7 +43,7 @@
     ...     robots['self_link'], 'unlinkBug', bug=bug['self_link'])
     >>> bugs = webservice.get(
     ...     robots['linked_bugs_collection_link']).jsonBody()
-    >>> print len(bugs['entries'])
+    >>> print(len(bugs['entries']))
     0
 
 
@@ -73,5 +73,5 @@
     ...     robots['self_link'], 'unlinkSpecification', spec=spec['self_link'])
     >>> spec_links = webservice.get(
     ...     robots['spec_links_collection_link']).jsonBody()
-    >>> print len(spec_links['entries'])
+    >>> print(len(spec_links['entries']))
     0

=== modified file 'lib/lp/code/stories/webservice/xx-branch.txt'
--- lib/lp/code/stories/webservice/xx-branch.txt	2015-09-29 16:59:09 +0000
+++ lib/lp/code/stories/webservice/xx-branch.txt	2018-05-13 10:39:08 +0000
@@ -46,7 +46,7 @@
 
 At the moment, it's not scheduled to be mirrored.
 
-    >>> print branch.next_mirror_time
+    >>> print(branch.next_mirror_time)
     None
 
 But we can ask for it to be mirrored using the webservice:
@@ -62,7 +62,7 @@
 The new "next mirror time" is the time when we actually submitted the
 request for a mirror:
 
-    >>> print start_time < branch.next_mirror_time < end_time
+    >>> print(start_time < branch.next_mirror_time < end_time)
     True
 
 
@@ -153,7 +153,7 @@
     >>> landing_candidates = webservice.get(
     ...     fooix_trunk['landing_candidates_collection_link']).jsonBody()
     >>> for candidate in landing_candidates['entries']:
-    ...     print candidate['source_branch_link']
+    ...     print(candidate['source_branch_link'])
     http://.../~eric/fooix/feature-branch
 
 
@@ -163,13 +163,13 @@
     >>> feature_branch_link = \
     ...     '/~eric/fooix/feature-branch'
     >>> feature_branch = webservice.get(feature_branch_link).jsonBody()
-    >>> print feature_branch['unique_name']
+    >>> print(feature_branch['unique_name'])
     ~eric/fooix/feature-branch
 
     >>> landing_targets = webservice.get(
     ...     feature_branch['landing_targets_collection_link']).jsonBody()
     >>> for target in landing_targets['entries']:
-    ...     print target['target_branch_link']
+    ...     print(target['target_branch_link'])
     http://.../~eric/fooix/trunk
 
 The isPersonTrustedReviewer method is exposed, and takes a person link.
@@ -177,7 +177,7 @@
     >>> trusted = webservice.named_get(
     ...     feature_branch['self_link'], 'isPersonTrustedReviewer',
     ...     reviewer=feature_branch['owner_link']).jsonBody()
-    >>> print trusted
+    >>> print(trusted)
     True
 
 
@@ -187,7 +187,7 @@
 The branches of a project are also available.
 
     >>> def print_branch(branch):
-    ...     print branch['unique_name'] + ' - ' + branch['lifecycle_status']
+    ...     print(branch['unique_name'] + ' - ' + branch['lifecycle_status'])
     >>> def print_branches(webservice, url, status=None, modified_since=None):
     ...     branches = webservice.named_get(
     ...         url, 'getBranches',
@@ -255,20 +255,20 @@
 the named operation 'setPrivate'.
 
     >>> branch = webservice.get(branch_url).jsonBody()
-    >>> print branch['private']
+    >>> print(branch['private'])
     False
 
     >>> response = webservice.named_post(
     ...     branch_url, 'setPrivate', api_version='beta', private=True)
     >>> branch = webservice.get(branch_url).jsonBody()
-    >>> print branch['information_type']
+    >>> print(branch['information_type'])
     Private
 
 In subsequent versions, 'setPrivate' is gone; you have to use the
 'transitionToInformationType' method.
 
-    >>> print webservice.named_post(
-    ...     branch_url, 'setPrivate', api_version='devel', private=True)
+    >>> print(webservice.named_post(
+    ...     branch_url, 'setPrivate', api_version='devel', private=True))
     HTTP/1.1 400 Bad Request
     ...
     No such operation: setPrivate
@@ -281,19 +281,19 @@
 
     >>> deletable = webservice.named_get('/~eric/fooix/feature-branch',
     ...                                  'canBeDeleted').jsonBody()
-    >>> print deletable
+    >>> print(deletable)
     False
 
     Deleting only works on branches that do not have anything else
     depending on them.
 
     >>> response = webservice.delete('/~eric/fooix/feature-branch')
-    >>> print response
+    >>> print(response)
     HTTP/1.1 200 Ok
     ...
 
     >>> response = webservice.delete('/~mary/blob/bar')
-    >>> print response
+    >>> print(response)
     HTTP/1.1 200 Ok
     ...
 

=== modified file 'lib/lp/code/stories/webservice/xx-branches.txt'
--- lib/lp/code/stories/webservice/xx-branches.txt	2011-12-20 11:30:27 +0000
+++ lib/lp/code/stories/webservice/xx-branches.txt	2018-05-13 10:39:08 +0000
@@ -44,18 +44,18 @@
 
 We gave three URLs, so we get back a dict with three branches.
 
-    >>> print len(branches)
+    >>> print(len(branches))
     3
 
 The URL that refers to a branch that doesn't exist maps to None.
 
-    >>> print branches[doesnt_exist]
+    >>> print(branches[doesnt_exist])
     None
 
 The URLs that refer to real, honest-to-goodness existing branches map to those
 branches:
 
-    >>> print branches[branch_url]['unique_name'] == branch_unique_name
+    >>> print(branches[branch_url]['unique_name'] == branch_unique_name)
     True
-    >>> print branches[branch2_url]['unique_name'] == branch2_unique_name
+    >>> print(branches[branch2_url]['unique_name'] == branch2_unique_name)
     True

=== modified file 'lib/lp/code/stories/webservice/xx-branchmergeproposal.txt'
--- lib/lp/code/stories/webservice/xx-branchmergeproposal.txt	2016-06-24 15:44:48 +0000
+++ lib/lp/code/stories/webservice/xx-branchmergeproposal.txt	2018-05-13 10:39:08 +0000
@@ -85,12 +85,12 @@
 
 If we try and create the merge proposal again, we should get a ValueError.
 
-    >>> print registrant_webservice.named_post(
+    >>> print(registrant_webservice.named_post(
     ...     source_url, 'createMergeProposal', target_branch=target_url,
     ...     prerequisite_branch=prerequisite_url,
     ...     initial_comment='Merge\nit!', needs_review=True,
     ...     commit_message='It was merged!\n', reviewers=[reviewer_url],
-    ...     review_types=['green'])
+    ...     review_types=['green']))
     HTTP/1.1 400 Bad Request
     ...
     There is already a branch merge proposal registered for branch
@@ -192,7 +192,7 @@
 
     >>> all_comments = webservice.get(
     ...     merge_proposal['all_comments_collection_link']).jsonBody()
-    >>> print len(all_comments['entries'])
+    >>> print(len(all_comments['entries']))
     2
     >>> pprint_entry(all_comments['entries'][0])
     as_quoted_email: u'> This is great work'
@@ -233,7 +233,7 @@
 
     >>> votes = webservice.get(
     ...     merge_proposal['votes_collection_link']).jsonBody()['entries']
-    >>> print len(votes)
+    >>> print(len(votes))
     2
     >>> pprint_entry(votes[0])
     branch_merge_proposal_link: u'http://.../~source/fooix/fix-it/+merge/...'
@@ -260,7 +260,7 @@
     >>> reviewer = reviewer_webservice.named_post(
     ...     merge_proposal['self_link'], 'nominateReviewer',
     ...     reviewer=person['self_link'], review_type='code')
-    >>> print reviewer
+    >>> print(reviewer)
     HTTP/1.1 200 Ok ...
     >>> reviewer_entry = reviewer.jsonBody()
     >>> pprint_entry(reviewer_entry)
@@ -275,7 +275,7 @@
     self_link: u'http://.../~source/fooix/fix-it/+merge/.../+review/...'
 
     >>> vote = reviewer_webservice.get(reviewer_entry['self_link'])
-    >>> print vote
+    >>> print(vote)
     HTTP/1.1 200 Ok ...
 
 Now the code review should be made.
@@ -305,13 +305,13 @@
 
     >>> _unused = reviewer_webservice.named_post(
     ...     merge_proposal['self_link'], 'setStatus',
-    ...     status=u'Approved', revid=u'25')
+    ...     status=u'Approved', revid='25')
     >>> merge_proposal = reviewer_webservice.get(
     ...     merge_proposal['self_link']).jsonBody()
 
-    >>> print merge_proposal['queue_status']
+    >>> print(merge_proposal['queue_status'])
     Approved
-    >>> print merge_proposal['reviewed_revid']
+    >>> print(merge_proposal['reviewed_revid'])
     25
 
 However, there may have been breakage in the branch, and we need to revert back
@@ -323,9 +323,9 @@
     >>> merge_proposal = reviewer_webservice.get(
     ...     merge_proposal['self_link']).jsonBody()
 
-    >>> print merge_proposal['queue_status']
+    >>> print(merge_proposal['queue_status'])
     Work in progress
-    >>> print merge_proposal['reviewed_revid']
+    >>> print(merge_proposal['reviewed_revid'])
     None
 
 == Getting a Project's Pending Merge Proposals ==
@@ -334,8 +334,7 @@
 proposals by their status.
 
     >>> def print_proposal(proposal):
-    ...     print proposal['self_link'] + ' - ' + \
-    ...         proposal['queue_status']
+    ...     print(proposal['self_link'] + ' - ' + proposal['queue_status'])
 
 
     >>> proposals = webservice.named_get(

=== modified file 'lib/lp/code/stories/webservice/xx-branchsubscription.txt'
--- lib/lp/code/stories/webservice/xx-branchsubscription.txt	2011-01-26 19:35:17 +0000
+++ lib/lp/code/stories/webservice/xx-branchsubscription.txt	2018-05-13 10:39:08 +0000
@@ -44,7 +44,7 @@
     >>> def print_subscriber_count(branch):
     ...     subscribers = webservice.get(
     ...         corn['subscribers_collection_link']).jsonBody()
-    ...     print len(subscribers['entries'])
+    ...     print(len(subscribers['entries']))
     >>> print_subscriber_count(corn)
     2
 
@@ -52,7 +52,7 @@
     ...     subscribers = webservice.get(
     ...         corn['subscribers_collection_link']).jsonBody()
     ...     for subscriber in subscribers['entries']:
-    ...         print subscriber['display_name']
+    ...         print(subscriber['display_name'])
     >>> print_subscriber_names(corn)
     Farmer Bob
     Farmer Joe
@@ -68,7 +68,7 @@
     ...     corn['self_link'], 'getSubscription',
     ...     person=joe['self_link']).jsonBody()
 
-    >>> print subscription['self_link']
+    >>> print(subscription['self_link'])
     http://.../~farmer-bob/farm/corn/+subscription/farmer-joe
 
 

=== modified file 'lib/lp/code/stories/webservice/xx-code-import.txt'
--- lib/lp/code/stories/webservice/xx-code-import.txt	2016-10-13 15:52:36 +0000
+++ lib/lp/code/stories/webservice/xx-code-import.txt	2018-05-13 10:39:08 +0000
@@ -35,7 +35,7 @@
     >>> branch_url = '/' + no_import_branch.unique_name
     >>> response = import_webservice.get(branch_url)
     >>> representation = response.jsonBody()
-    >>> print representation['code_import_link']
+    >>> print(representation['code_import_link'])
     None
 
 For a branch with an import we get a link to the import entry in its
@@ -44,7 +44,7 @@
     >>> branch_url = '/' + code_import.branch.unique_name
     >>> response = import_webservice.get(branch_url)
     >>> representation = response.jsonBody()
-    >>> print representation['code_import_link']
+    >>> print(representation['code_import_link'])
     http://.../~import-owner/scruff/import/+code-import
 
 We can get some information about the import using this URL.
@@ -52,23 +52,23 @@
     >>> import_url = representation['code_import_link']
     >>> response = import_webservice.get(import_url)
     >>> representation = response.jsonBody()
-    >>> print representation['self_link'] == import_url
+    >>> print(representation['self_link'] == import_url)
     True
-    >>> print representation['branch_link']
+    >>> print(representation['branch_link'])
     http://.../~import-owner/scruff/import
-    >>> print representation['review_status']
+    >>> print(representation['review_status'])
     Reviewed
-    >>> print representation['rcs_type']
+    >>> print(representation['rcs_type'])
     Subversion via bzr-svn
-    >>> print representation['target_rcs_type']
+    >>> print(representation['target_rcs_type'])
     Bazaar
-    >>> print representation['url']
+    >>> print(representation['url'])
     http://svn.domain.com/source
-    >>> print representation['cvs_root']
-    None
-    >>> print representation['cvs_module']
-    None
-    >>> print representation['date_last_successful']
+    >>> print(representation['cvs_root'])
+    None
+    >>> print(representation['cvs_module'])
+    None
+    >>> print(representation['date_last_successful'])
     None
 
 
@@ -96,7 +96,7 @@
     >>> branch_url = '/' + code_import.branch.unique_name
     >>> response = import_webservice.get(branch_url)
     >>> representation = response.jsonBody()
-    >>> print representation['code_import_link']
+    >>> print(representation['code_import_link'])
     http://.../~import-owner/scruffbuntu/manic/scruff/import/+code-import
 
 and there is information available about the import itsef.
@@ -104,23 +104,23 @@
     >>> import_url = representation['code_import_link']
     >>> response = import_webservice.get(import_url)
     >>> representation = response.jsonBody()
-    >>> print representation['self_link'] == import_url
+    >>> print(representation['self_link'] == import_url)
     True
-    >>> print representation['branch_link']
+    >>> print(representation['branch_link'])
     http://.../~import-owner/scruffbuntu/manic/scruff/import
-    >>> print representation['review_status']
+    >>> print(representation['review_status'])
     Reviewed
-    >>> print representation['rcs_type']
+    >>> print(representation['rcs_type'])
     Subversion via bzr-svn
-    >>> print representation['target_rcs_type']
+    >>> print(representation['target_rcs_type'])
     Bazaar
-    >>> print representation['url']
+    >>> print(representation['url'])
     http://svn.domain.com/package_source
-    >>> print representation['cvs_root']
-    None
-    >>> print representation['cvs_module']
-    None
-    >>> print representation['date_last_successful']
+    >>> print(representation['cvs_root'])
+    None
+    >>> print(representation['cvs_module'])
+    None
+    >>> print(representation['date_last_successful'])
     None
 
 
@@ -134,28 +134,28 @@
     >>> response = import_webservice.named_post(product_url, 'newCodeImport',
     ...    branch_name='new-import', rcs_type='Git',
     ...    url=new_remote_url)
-    >>> print response.status
+    >>> print(response.status)
     201
     >>> location = response.getHeader('Location')
     >>> response = import_webservice.get(location)
     >>> representation = response.jsonBody()
-    >>> print representation['self_link']
+    >>> print(representation['self_link'])
     http://.../~import-owner/scruff/new-import/+code-import
-    >>> print representation['branch_link']
+    >>> print(representation['branch_link'])
     http://.../~import-owner/scruff/new-import
-    >>> print representation['git_repository_link']
+    >>> print(representation['git_repository_link'])
     None
-    >>> print representation['rcs_type']
+    >>> print(representation['rcs_type'])
     Git
-    >>> print representation['target_rcs_type']
+    >>> print(representation['target_rcs_type'])
     Bazaar
-    >>> print representation['url'] == new_remote_url
+    >>> print(representation['url'] == new_remote_url)
     True
-    >>> print representation['cvs_root']
-    None
-    >>> print representation['cvs_module']
-    None
-    >>> print representation['date_last_successful']
+    >>> print(representation['cvs_root'])
+    None
+    >>> print(representation['cvs_module'])
+    None
+    >>> print(representation['date_last_successful'])
     None
 
 If we must we can create a CVS import.
@@ -165,28 +165,28 @@
     >>> response = import_webservice.named_post(product_url, 'newCodeImport',
     ...    branch_name='cvs-import', rcs_type='Concurrent Versions System',
     ...    cvs_root=new_remote_url, cvs_module="foo")
-    >>> print response.status
+    >>> print(response.status)
     201
     >>> location = response.getHeader('Location')
     >>> response = import_webservice.get(location)
     >>> representation = response.jsonBody()
-    >>> print representation['self_link']
+    >>> print(representation['self_link'])
     http://.../~import-owner/scruff/cvs-import/+code-import
-    >>> print representation['branch_link']
+    >>> print(representation['branch_link'])
     http://.../~import-owner/scruff/cvs-import
-    >>> print representation['git_repository_link']
+    >>> print(representation['git_repository_link'])
     None
-    >>> print representation['rcs_type']
+    >>> print(representation['rcs_type'])
     Concurrent Versions System
-    >>> print representation['target_rcs_type']
+    >>> print(representation['target_rcs_type'])
     Bazaar
-    >>> print representation['url']
+    >>> print(representation['url'])
     None
-    >>> print representation['cvs_root'] == new_remote_url
-    True
-    >>> print representation['cvs_module'] == "foo"
-    True
-    >>> print representation['date_last_successful']
+    >>> print(representation['cvs_root'] == new_remote_url)
+    True
+    >>> print(representation['cvs_module'] == "foo")
+    True
+    >>> print(representation['date_last_successful'])
     None
 
 We can create a Git-to-Git import, provided that we have the feature flag.
@@ -201,37 +201,37 @@
     >>> response = import_webservice.named_post(
     ...     product_url, 'newCodeImport', branch_name='new-import',
     ...     rcs_type='Git', target_rcs_type='Git', url=new_remote_url)
-    >>> print response.status
+    >>> print(response.status)
     401
-    >>> print response.body
+    >>> print(response.body)
     You do not have permission to create Git-targeted code imports.
     >>> with FeatureFixture({CODE_IMPORT_GIT_TARGET_FEATURE_FLAG: u'on'}):
     ...     with GitHostingFixture():
     ...         response = import_webservice.named_post(
     ...             product_url, 'newCodeImport', branch_name='new-import',
     ...             rcs_type='Git', target_rcs_type='Git', url=new_remote_url)
-    >>> print response.status
+    >>> print(response.status)
     201
     >>> location = response.getHeader('Location')
     >>> response = import_webservice.get(location)
     >>> representation = response.jsonBody()
-    >>> print representation['self_link']
+    >>> print(representation['self_link'])
     http://.../~import-owner/scruff/+git/new-import/+code-import
-    >>> print representation['branch_link']
+    >>> print(representation['branch_link'])
     None
-    >>> print representation['git_repository_link']
+    >>> print(representation['git_repository_link'])
     http://.../~import-owner/scruff/+git/new-import
-    >>> print representation['rcs_type']
-    Git
-    >>> print representation['target_rcs_type']
-    Git
-    >>> print representation['url'] == new_remote_url
+    >>> print(representation['rcs_type'])
+    Git
+    >>> print(representation['target_rcs_type'])
+    Git
+    >>> print(representation['url'] == new_remote_url)
     True
-    >>> print representation['cvs_root']
-    None
-    >>> print representation['cvs_module']
-    None
-    >>> print representation['date_last_successful']
+    >>> print(representation['cvs_root'])
+    None
+    >>> print(representation['cvs_module'])
+    None
+    >>> print(representation['date_last_successful'])
     None
 
 We can also create an import targetting a source package.
@@ -243,28 +243,28 @@
     >>> response = import_webservice.named_post(source_package_url,
     ...    'newCodeImport', branch_name='new-import', rcs_type='Git',
     ...    url=new_remote_url)
-    >>> print response.status
+    >>> print(response.status)
     201
     >>> location = response.getHeader('Location')
     >>> response = import_webservice.get(location)
     >>> representation = response.jsonBody()
-    >>> print representation['self_link']
+    >>> print(representation['self_link'])
     http://.../~import-owner/scruffbuntu/manic/scruff/new-import/+code-import
-    >>> print representation['branch_link']
+    >>> print(representation['branch_link'])
     http://.../~import-owner/scruffbuntu/manic/scruff/new-import
-    >>> print representation['git_repository_link']
+    >>> print(representation['git_repository_link'])
     None
-    >>> print representation['rcs_type']
+    >>> print(representation['rcs_type'])
     Git
-    >>> print representation['target_rcs_type']
+    >>> print(representation['target_rcs_type'])
     Bazaar
-    >>> print representation['url'] == new_remote_url
+    >>> print(representation['url'] == new_remote_url)
     True
-    >>> print representation['cvs_root']
-    None
-    >>> print representation['cvs_module']
-    None
-    >>> print representation['date_last_successful']
+    >>> print(representation['cvs_root'])
+    None
+    >>> print(representation['cvs_module'])
+    None
+    >>> print(representation['date_last_successful'])
     None
 
 We can create a Git-to-Git import targetting a distribution source package.
@@ -278,28 +278,28 @@
     ...             distro_source_package_url, 'newCodeImport',
     ...             branch_name='new-import', rcs_type='Git',
     ...             target_rcs_type='Git', url=new_remote_url)
-    >>> print response.status
+    >>> print(response.status)
     201
     >>> location = response.getHeader('Location')
     >>> response = import_webservice.get(location)
     >>> representation = response.jsonBody()
-    >>> print representation['self_link']
+    >>> print(representation['self_link'])
     http://.../~import-owner/scruffbuntu/+source/scruff/+git/new-import/+code-import
-    >>> print representation['branch_link']
+    >>> print(representation['branch_link'])
     None
-    >>> print representation['git_repository_link']
+    >>> print(representation['git_repository_link'])
     http://.../~import-owner/scruffbuntu/+source/scruff/+git/new-import
-    >>> print representation['rcs_type']
-    Git
-    >>> print representation['target_rcs_type']
-    Git
-    >>> print representation['url'] == new_remote_url
+    >>> print(representation['rcs_type'])
+    Git
+    >>> print(representation['target_rcs_type'])
+    Git
+    >>> print(representation['url'] == new_remote_url)
     True
-    >>> print representation['cvs_root']
-    None
-    >>> print representation['cvs_module']
-    None
-    >>> print representation['date_last_successful']
+    >>> print(representation['cvs_root'])
+    None
+    >>> print(representation['cvs_module'])
+    None
+    >>> print(representation['date_last_successful'])
     None
 
 If we wish to create a branch owned by a team we are part of then we can.
@@ -309,28 +309,28 @@
     >>> response = import_webservice.named_post(product_url, 'newCodeImport',
     ...    branch_name='team-import', rcs_type='Git',
     ...    url=new_remote_url, owner=team_url)
-    >>> print response.status
+    >>> print(response.status)
     201
     >>> location = response.getHeader('Location')
     >>> response = import_webservice.get(location)
     >>> representation = response.jsonBody()
-    >>> print representation['self_link']
+    >>> print(representation['self_link'])
     http://.../~import-owner-team/scruff/team-import/+code-import
-    >>> print representation['branch_link']
+    >>> print(representation['branch_link'])
     http://.../~import-owner-team/scruff/team-import
-    >>> print representation['git_repository_link']
+    >>> print(representation['git_repository_link'])
     None
-    >>> print representation['rcs_type']
+    >>> print(representation['rcs_type'])
     Git
-    >>> print representation['target_rcs_type']
+    >>> print(representation['target_rcs_type'])
     Bazaar
-    >>> print representation['url'] == new_remote_url
+    >>> print(representation['url'] == new_remote_url)
     True
-    >>> print representation['cvs_root']
-    None
-    >>> print representation['cvs_module']
-    None
-    >>> print representation['date_last_successful']
+    >>> print(representation['cvs_root'])
+    None
+    >>> print(representation['cvs_module'])
+    None
+    >>> print(representation['date_last_successful'])
     None
 
 
@@ -351,7 +351,7 @@
     ...     person, permission=OAuthPermission.WRITE_PUBLIC)
     >>> response = import_webservice.named_post(
     ...     git_import_url, 'requestImport')
-    >>> print response.status
+    >>> print(response.status)
     200
-    >>> print response.jsonBody()
+    >>> print(response.jsonBody())
     None

=== modified file 'lib/lp/code/tests/test_doc.py'
--- lib/lp/code/tests/test_doc.py	2018-05-13 10:39:08 +0000
+++ lib/lp/code/tests/test_doc.py	2018-05-13 10:39:08 +0000
@@ -18,6 +18,7 @@
     LaunchpadFunctionalLayer,
     LaunchpadZopelessLayer,
     )
+from lp.testing.pages import setUpGlobs
 from lp.testing.systemdocs import (
     LayeredDocFileSuite,
     setGlobs,
@@ -89,4 +90,5 @@
 
 def test_suite():
     return build_test_suite(
-        here, special, setUp=lambda test: setUp(test, future=True))
+        here, special, setUp=lambda test: setUp(test, future=True),
+        pageTestsSetUp=lambda test: setUpGlobs(test, future=True))

=== modified file 'lib/lp/services/testing/__init__.py'
--- lib/lp/services/testing/__init__.py	2018-05-06 08:52:34 +0000
+++ lib/lp/services/testing/__init__.py	2018-05-13 10:39:08 +0000
@@ -64,7 +64,8 @@
 
 
 def build_test_suite(base_dir, special_tests={},
-                     layer=None, setUp=setUp, tearDown=tearDown):
+                     layer=None, setUp=setUp, tearDown=tearDown,
+                     pageTestsSetUp=None):
     """Build a test suite from a directory containing test files.
 
     The parent's 'stories' subdirectory will be checked for pagetests and
@@ -81,9 +82,14 @@
     :param layer: The layer in which to run the tests.
     """
     from lp.testing.layers import DatabaseFunctionalLayer
-    from lp.testing.pages import PageTestSuite
+    from lp.testing.pages import (
+        PageTestSuite,
+        setUpGlobs,
+        )
     if layer is None:
         layer = DatabaseFunctionalLayer
+    if pageTestsSetUp is None:
+        pageTestsSetUp = setUpGlobs
 
     suite = unittest.TestSuite()
 
@@ -94,14 +100,16 @@
     stories_dir = os.path.join(os.path.pardir, 'stories')
     stories_path = os.path.join(base_dir, stories_dir)
     if os.path.exists(stories_path):
-        suite.addTest(PageTestSuite(stories_dir, package))
+        suite.addTest(PageTestSuite(
+            stories_dir, package, setUp=pageTestsSetUp))
         for story_entry in scandir.scandir(stories_path):
             if not story_entry.is_dir():
                 continue
             story_path = os.path.join(stories_dir, story_entry.name)
             if story_path in special_tests:
                 continue
-            suite.addTest(PageTestSuite(story_path, package))
+            suite.addTest(PageTestSuite(
+                story_path, package, setUp=pageTestsSetUp))
 
     # Add the special doctests.
     for key, special_suite in sorted(special_tests.items()):

=== modified file 'lib/lp/testing/pages.py'
--- lib/lp/testing/pages.py	2018-04-13 20:47:03 +0000
+++ lib/lp/testing/pages.py	2018-05-13 10:39:08 +0000
@@ -782,7 +782,10 @@
         setSecurityPolicy(old_policy)
 
 
-def setUpGlobs(test):
+# XXX cjwatson 2018-05-13: Once all doctests are made safe for the standard
+# __future__ imports, the `future=True` behaviour should become
+# unconditional.
+def setUpGlobs(test, future=False):
     test.globs['transaction'] = transaction
     test.globs['http'] = UnstickyCookieHTTPCaller()
     test.globs['webservice'] = LaunchpadWebServiceCaller(
@@ -840,6 +843,12 @@
     test.globs['PageTestLayer'] = PageTestLayer
     test.globs['stop'] = stop
 
+    if future:
+        import __future__
+        for future_item in (
+                'absolute_import', 'print_function', 'unicode_literals'):
+            test.globs[future_item] = getattr(__future__, future_item)
+
 
 # This function name doesn't follow our standard naming conventions,
 # but does follow the convention of the other doctest related *Suite()


References