← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~cjwatson/launchpad/answers-doctests-future-imports into lp:launchpad

 

Colin Watson has proposed merging lp:~cjwatson/launchpad/answers-doctests-future-imports into lp:launchpad.

Commit message:
Convert doctests under lp.answers to Launchpad's preferred __future__ imports.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/answers-doctests-future-imports/+merge/347316
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/answers-doctests-future-imports into lp:launchpad.
=== modified file 'lib/lp/answers/doc/expiration.txt'
--- lib/lp/answers/doc/expiration.txt	2015-09-25 03:02:28 +0000
+++ lib/lp/answers/doc/expiration.txt	2018-06-01 23:51:54 +0000
@@ -52,7 +52,7 @@
 
     # An old question in NEEDSINFO the state.
     >>> old_needs_info_question = questionset.get(7)
-    >>> print old_needs_info_question.status.title
+    >>> print(old_needs_info_question.status.title)
     Needs information
 
     # An open question assigned to somebody.
@@ -135,7 +135,7 @@
     ...     stdin=subprocess.PIPE, stdout=subprocess.PIPE,
     ...     stderr=subprocess.PIPE)
     >>> (out, err) = process.communicate()
-    >>> print err
+    >>> print(err)
     INFO    Creating lockfile: /var/lock/launchpad-expire-questions.lock
     INFO    Expiring OPEN and NEEDSINFO questions without activity for the
             last 15 days.
@@ -143,7 +143,7 @@
     INFO    Expired 5 questions.
     INFO    Finished expiration run.
     <BLANKLINE>
-    >>> print out
+    >>> print(out)
     <BLANKLINE>
     >>> process.returncode
     0
@@ -156,43 +156,41 @@
 The status of the OPEN and NEEDSINFO questions that had recent activity
 wasn't modified by the script:
 
-    >>> print recent_open_question.status.title
+    >>> print(recent_open_question.status.title)
     Open
-    >>> print recent_needsinfo_question.status.title
+    >>> print(recent_needsinfo_question.status.title)
     Needs information
 
 Neither the old one which was assigned to Foo Bar:
 
-    >>> print old_assigned_open_question.status.title
+    >>> print(old_assigned_open_question.status.title)
     Open
 
 The old question with non-Invalid bug link is still Open status:
 
-    >>> print bug_link_question.status.title
+    >>> print(bug_link_question.status.title)
     Open
 
 But the other ones status was changed to 'Expired':
 
-    >>> print old_needs_info_question.status.title
-    Expired
-    >>> print old_open_question.status.title
-    Expired
-    >>> print invalid_bug_question.status.title
+    >>> print(old_needs_info_question.status.title)
+    Expired
+    >>> print(old_open_question.status.title)
+    Expired
+    >>> print(invalid_bug_question.status.title)
     Expired
 
 The message explaining the reason for the expiration was posted by the
 Launchpad Janitor celebrity:
 
     >>> expiration_message = old_needs_info_question.messages[-1]
-    >>> print expiration_message.action.name
+    >>> print(expiration_message.action.name)
     EXPIRE
-    >>> print expiration_message.new_status.title
+    >>> print(expiration_message.new_status.title)
     Expired
-    >>> print expiration_message.owner.name
+    >>> print(expiration_message.owner.name)
     janitor
 
-    >>> print expiration_message.text_contents
+    >>> print(expiration_message.text_contents)
     This question was expired because it remained in the
     'Needs information' state without activity for the last 15 days.
-
-

=== modified file 'lib/lp/answers/doc/faq-vocabulary.txt'
--- lib/lp/answers/doc/faq-vocabulary.txt	2012-12-26 01:32:19 +0000
+++ lib/lp/answers/doc/faq-vocabulary.txt	2018-06-01 23:51:54 +0000
@@ -1,4 +1,5 @@
-= FAQ Vocabulary =
+FAQ Vocabulary
+==============
 
 The FAQ vocabulary contains all the FAQs available in a particular
 collection. It provides the IHugeVocabulary interface.
@@ -15,7 +16,7 @@
     >>> verifyObject(IHugeVocabulary, vocabulary)
     True
 
-    >>> print vocabulary.displayname
+    >>> print(vocabulary.displayname)
     Select a FAQ
 
 It contains all the FAQs of the collection, but not those from other
@@ -37,7 +38,7 @@
     >>> term = vocabulary.getTerm(firefox_faq)
     >>> term.token
     '10'
-    >>> print term.title
+    >>> print(term.title)
     How do I install plugins (Shockwave, QuickTime, etc.)?
 
 Asking for something which isn't a FAQ of the target raises LookupError:
@@ -55,7 +56,7 @@
 be retrieved by token:
 
     >>> term = vocabulary.getTermByToken(u'10')
-    >>> print term.title
+    >>> print(term.title)
     How do I install plugins (Shockwave, QuickTime, etc.)?
 
 Trying to retrieve an invalid or non-existent token raises LookupError:
@@ -81,6 +82,6 @@
     >>> terms.count()
     2
     >>> for term in terms:
-    ...     print term.title
+    ...     print(term.title)
     How do I install Extensions?
     How do I troubleshoot problems with extensions/themes?

=== modified file 'lib/lp/answers/doc/faq.txt'
--- lib/lp/answers/doc/faq.txt	2013-05-01 00:23:31 +0000
+++ lib/lp/answers/doc/faq.txt	2018-06-01 23:51:54 +0000
@@ -37,7 +37,7 @@
 
     >>> from lp.services.webapp.interfaces import ILaunchBag
     >>> sample_person = getUtility(ILaunchBag).user
-    >>> print firefox.owner.displayname
+    >>> print(firefox.owner.displayname)
     Sample Person
 
     >>> firefox_faq = firefox.newFAQ(
@@ -128,28 +128,28 @@
 
 The FAQ document information is available in the object attributes.
 
-    >>> print firefox_faq.title
+    >>> print(firefox_faq.title)
     How can I see the Fnords?
 
-    >>> print firefox_faq.content
+    >>> print(firefox_faq.content)
     Install the Fnords highlighter extension and see the Fnords!
 
-    >>> print firefox_faq.owner.displayname
+    >>> print(firefox_faq.owner.displayname)
     Sample Person
 
 The project that contains the FAQ is available using the target
 attribute:
 
-    >>> print firefox_faq.target.name
+    >>> print(firefox_faq.target.name)
     firefox
 
 IFAQ has two attributes used to track the last modification to the FAQ.
 Initially, the last_updated_by and date_last_updated are not set.
 
-    >>> print firefox_faq.last_updated_by
+    >>> print(firefox_faq.last_updated_by)
     None
 
-    >>> print firefox_faq.date_last_updated
+    >>> print(firefox_faq.date_last_updated)
     None
 
 When the FAQ is modified, the attributes are automatically updated.
@@ -163,7 +163,7 @@
     >>> notify(ObjectModifiedEvent(
     ...     firefox_faq, old_faq, ['keywords'], user=sample_person))
 
-    >>> print firefox_faq.last_updated_by.displayname
+    >>> print(firefox_faq.last_updated_by.displayname)
     Sample Person
 
     >>> firefox_faq.date_last_updated is not None
@@ -184,7 +184,7 @@
 So Sample Person (the project owner) has edit permission:
 
     >>> login('test@xxxxxxxxxxxxx')
-    >>> print firefox.owner.displayname
+    >>> print(firefox.owner.displayname)
     Sample Person
 
     >>> check_permission('launchpad.Edit', firefox_faq)
@@ -233,7 +233,7 @@
     >>> foo_bar = getUtility(IPersonSet).getByEmail('foo.bar@xxxxxxxxxxxxx')
     >>> for faq in faqset.searchFAQs(
     ...     search_text=u'java OR flash', owner=foo_bar):
-    ...     print '%s (%s)' % (faq.title, faq.target.displayname)
+    ...     print('%s (%s)' % (faq.title, faq.target.displayname))
     How do I install plugins (Shockwave, QuickTime, etc.)? (Mozilla Firefox)
     How can I play MP3/Divx/DVDs/Quicktime/Realmedia files
         or view Flash/Java web pages (Ubuntu)
@@ -262,15 +262,15 @@
 
 Once the FAQ is linked, the question is considered 'answered':
 
-    >>> print message.action.title
+    >>> print(message.action.title)
     Answer
 
-    >>> print fnord_question.status.title
+    >>> print(fnord_question.status.title)
     Answered
 
 The 'faq' attribute contains the FAQ supposed to answer the question:
 
-    >>> print fnord_question.faq.title
+    >>> print(fnord_question.faq.title)
     How can I see the Fnords?
 
 The FAQ's 'related_questions' attribute contains the questions that are
@@ -279,7 +279,7 @@
     # Flush the faq attribute change.
 
     >>> for question in firefox_faq.related_questions:
-    ...     print question.title
+    ...     print(question.title)
     Are there Fnords on the web?
 
 A FAQ can be linked to multiple question:
@@ -289,14 +289,14 @@
     ...     no_priv, firefox_faq,
     ...     'If you lose focus and gets stuck it must be the fnords!')
 
-    >>> print other_question.faq.title
+    >>> print(other_question.faq.title)
     How can I see the Fnords?
 
-    >>> print other_question.status.title
+    >>> print(other_question.status.title)
     Answered
 
     >>> for question in firefox_faq.related_questions:
-    ...     print question.title
+    ...     print(question.title)
     Firefox loses focus and gets stuck
     Are there Fnords on the web?
 
@@ -305,21 +305,21 @@
 
     >>> message = other_question.linkFAQ(
     ...     no_priv, None, "This has nothing to do with Fnords.")
-    >>> print other_question.faq
+    >>> print(other_question.faq)
     None
 
 After this, only the original question will remain linked to the FAQ.
 
     >>> for question in firefox_faq.related_questions:
-    ...     print question.title
+    ...     print(question.title)
     Are there Fnords on the web?
 
 That change is also considered an answer:
 
-    >>> print message.action.title
+    >>> print(message.action.title)
     Answer
 
-    >>> print other_question.status.title
+    >>> print(other_question.status.title)
     Answered
 
 It is not possible to modify the faq attribute directly:
@@ -343,17 +343,15 @@
     >>> login('foo.bar@xxxxxxxxxxxxx')
     >>> confirm_message = other_question.confirmAnswer(
     ...     "That answered my question.", answer=other_question.messages[-1])
-    >>> print other_question.status.title
+    >>> print(other_question.status.title)
     Solved
 
     >>> login('no-priv@xxxxxxxxxxxxx')
     >>> message = other_question.linkFAQ(
     ...     no_priv, firefox_faq,
     ...     'If you look carefully, you will find the fnords!')
-    >>> print message.action.title
+    >>> print(message.action.title)
     Comment
 
-    >>> print other_question.status.title
+    >>> print(other_question.status.title)
     Solved
-
-

=== modified file 'lib/lp/answers/doc/faqcollection.txt'
--- lib/lp/answers/doc/faqcollection.txt	2013-05-01 00:23:31 +0000
+++ lib/lp/answers/doc/faqcollection.txt	2018-06-01 23:51:54 +0000
@@ -76,7 +76,7 @@
 
 It returns None when there is FAQ with that ID in the context:
 
-    >>> print collection.getFAQ(12345)
+    >>> print(collection.getFAQ(12345))
     None
 
 It also returns None when using the ID of a FAQ that isn't in the
@@ -96,7 +96,7 @@
     ...     'https://help.ubuntu.com/community/Installation')
 
     >>> login(ANONYMOUS)
-    >>> print collection.getFAQ(ubuntu_faq.id)
+    >>> print(collection.getFAQ(ubuntu_faq.id))
     None
 
 
@@ -110,7 +110,7 @@
 (The default sort order is most recent first.)
 
     >>> for faq in collection.searchFAQs():
-    ...     print faq.title
+    ...     print(faq.title)
     What were the famous last words?
     Who really shot JFK?
     How do I play the Game of Life?
@@ -127,7 +127,7 @@
 keywords field of the FAQ.
 
     >>> for faq in collection.searchFAQs(search_text=u'install'):
-    ...     print faq.title
+    ...     print(faq.title)
     How do I install Foo?
     How do I play the Game of Life?
     How do I make money quickly off the Internet?
@@ -144,7 +144,7 @@
 were created by the specified user.
 
     >>> for faq in collection.searchFAQs(owner=no_priv):
-    ...     print faq.title
+    ...     print(faq.title)
     What were the famous last words?
     How do I play the Game of Life?
     How do I install Foo?
@@ -161,7 +161,7 @@
 
     >>> for faq in collection.searchFAQs(
     ...         search_text=u'install', owner=no_priv):
-    ...     print faq.title
+    ...     print(faq.title)
     How do I install Foo?
     How do I play the Game of Life?
 
@@ -177,7 +177,7 @@
     >>> from lp.answers.interfaces.faqcollection import FAQSort
     >>> for faq in collection.searchFAQs(
     ...         search_text=u'install', sort=FAQSort.NEWEST_FIRST):
-    ...     print faq.title
+    ...     print(faq.title)
     How do I play the Game of Life?
     How do I make money quickly off the Internet?
     How do I install Foo?
@@ -186,12 +186,10 @@
 first:
 
     >>> for faq in collection.searchFAQs(sort=FAQSort.OLDEST_FIRST):
-    ...     print faq.title
+    ...     print(faq.title)
     How do I install Foo?
     What is The Meaning of Life?
     How do I make money quickly off the Internet?
     How do I play the Game of Life?
     Who really shot JFK?
     What were the famous last words?
-
-

=== modified file 'lib/lp/answers/doc/faqtarget.txt'
--- lib/lp/answers/doc/faqtarget.txt	2015-03-16 00:04:20 +0000
+++ lib/lp/answers/doc/faqtarget.txt	2018-06-01 23:51:54 +0000
@@ -37,7 +37,7 @@
     False
 
     >>> no_priv = getUtility(ILaunchBag).user
-    >>> #target.newFAQ(no_priv, 'Title', 'Summary', content='Content')
+    >>> target.newFAQ(no_priv, 'Title', 'Summary', content='Content')
     Traceback (most recent call last):
       ...
     Unauthorized: ...
@@ -89,16 +89,16 @@
     ...     no_priv, 'How to do something', 'Explain how to do something.',
     ...     keywords='documentation howto', date_created=now)
 
-    >>> print faq.owner.displayname
+    >>> print(faq.owner.displayname)
     No Privileges Person
 
-    >>> print faq.title
+    >>> print(faq.title)
     How to do something
 
-    >>> print faq.content
+    >>> print(faq.content)
     Explain how to do something.
 
-    >>> print faq.keywords
+    >>> print(faq.keywords)
     documentation howto
 
     >>> faq.date_created == now
@@ -122,7 +122,7 @@
 
 It returns None when there is FAQ with that ID in the context:
 
-    >>> print target.getFAQ(12345)
+    >>> print(target.getFAQ(12345))
     None
 
 It also returns None when asking an ID for a FAQ that isn't in the
@@ -144,7 +144,7 @@
     ...     'https://help.ubuntu.com/community/Installation')
 
     >>> login('no-priv@xxxxxxxxxxxxx')
-    >>> print target.getFAQ(ubuntu_faq.id)
+    >>> print(target.getFAQ(ubuntu_faq.id))
     None
 
 
@@ -176,7 +176,7 @@
     ...     'https://help.launchpad.net/BugTrackerEmailInterface')
 
     >>> for faq in target.findSimilarFAQs('How do I use the Answer Tracker'):
-    ...     print faq.title
+    ...     print(faq.title)
     How to answer a question
     How to become a Launchpad king
 
@@ -187,7 +187,7 @@
 If there are no similar FAQ, no result should be returned:
 
     >>> for faq in target.findSimilarFAQs('How do I do this?'):
-    ...     print faq.title
+    ...     print(faq.title)
 
 Since only common and stop words are in that summary, no similar FAQ
 could be found.

=== modified file 'lib/lp/answers/doc/notifications.txt'
--- lib/lp/answers/doc/notifications.txt	2016-01-26 15:47:37 +0000
+++ lib/lp/answers/doc/notifications.txt	2018-06-01 23:51:54 +0000
@@ -42,13 +42,13 @@
 
     >>> add_notification = notifications[0]
 
-    >>> print add_notification.subject
+    >>> print(add_notification.subject)
     [Question #...]: Can't install Ubuntu
 
 Like all Launchpad notifications should, the message contain in the
 footer the reason why the user is receiving the notification.
 
-    >>> print add_notification.body
+    >>> print(add_notification.body)
     New question #... on Ubuntu:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -57,7 +57,7 @@
 The notification also includes a 'X-Launchpad-Question' header that
 contains information about the question.
 
-    >>> print add_notification.headers['X-Launchpad-Question']
+    >>> print(add_notification.headers['X-Launchpad-Question'])
     distribution=ubuntu; sourcepackage=None; status=Open;
     assignee=None; priority=Normal; language=en
 
@@ -107,10 +107,10 @@
 
     >>> notifications = pop_questionemailjobs()
     >>> edit_notification = notifications[1]
-    >>> print edit_notification.subject
+    >>> print(edit_notification.subject)
     Re: [Question #...]: Installer doesn't work on a Mac
 
-    >>> print edit_notification.body
+    >>> print(edit_notification.body)
     Question #... libstdc++ in Ubuntu changed:
     http://.../ubuntu/+source/libstdc++/+question/...
     <BLANKLINE>
@@ -137,7 +137,7 @@
     ...     ubuntu_question, unmodified_question, ['target']))
     >>> notifications = pop_questionemailjobs()
     >>> edit_notification = notifications[1]
-    >>> print edit_notification.body
+    >>> print(edit_notification.body)
     Question #... Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -154,7 +154,7 @@
     ...     ubuntu_question, unmodified_question, ['assignee']))
     >>> notifications = pop_questionemailjobs()
     >>> edit_notification = notifications[1]
-    >>> print edit_notification.body
+    >>> print(edit_notification.body)
     Question #... Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -207,7 +207,7 @@
     2
 
     >>> edit_notification = notifications[1]
-    >>> print edit_notification.body
+    >>> print(edit_notification.body)
     Question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -234,7 +234,7 @@
     2
 
     >>> edit_notification = notifications[1]
-    >>> print edit_notification.body
+    >>> print(edit_notification.body)
     Question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -263,7 +263,7 @@
 
     >>> notifications = pop_questionemailjobs()
     >>> support_notification = notifications[1]
-    >>> print support_notification.subject
+    >>> print(support_notification.subject)
     Re: [Question #...]: Installer doesn't work on a Mac
 
 For workflow notifications, the content of the notification is slightly
@@ -272,7 +272,7 @@
 For example, the notification to the answer contacts and every other
 subscribers except the question owner will look like this:
 
-    >>> print support_notification.body
+    >>> print(support_notification.body)
     Question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -284,7 +284,7 @@
 But the owner notification has a slightly different preamble and has an
 extra footer.
 
-    >>> print notifications[0].body
+    >>> print(notifications[0].body)
     Your question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -306,7 +306,7 @@
     >>> message = ubuntu_question.giveInfo('A PowerMac 7200.')
 
     >>> notifications = pop_questionemailjobs()
-    >>> print notifications[1].body
+    >>> print(notifications[1].body)
     Question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -319,7 +319,7 @@
 header to the previous message for threading purpose.
 
     >>> references = notifications[0].headers['References']
-    >>> print references
+    >>> print(references)
     <...>
 
     >>> references == ubuntu_question.messages[-2].rfc822msgid
@@ -345,7 +345,7 @@
 
 Default notification when the question is expired:
 
-    >>> print notifications[1].body
+    >>> print(notifications[1].body)
     Question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -357,7 +357,7 @@
 
 Notification received by the owner:
 
-    >>> print notifications[0].body
+    >>> print(notifications[0].body)
     Your question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -395,12 +395,12 @@
 
 Notice also how the 'Re' handling is handled nicely:
 
-    >>> print notifications[0].subject
+    >>> print(notifications[0].subject)
     Re: [Question #...]: Installer doesn't work on a Mac
 
 Default notification when the owner reopens the question:
 
-    >>> print notifications[1].body
+    >>> print(notifications[1].body)
     Question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -414,7 +414,7 @@
 
 Notification received by the owner:
 
-    >>> print notifications[0].body
+    >>> print(notifications[0].body)
     Your question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -443,7 +443,7 @@
 
 Default notification when an answer is proposed:
 
-    >>> print notifications[1].body
+    >>> print(notifications[1].body)
     Question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -459,7 +459,7 @@
 
 Notification received by the owner:
 
-    >>> print notifications[0].body
+    >>> print(notifications[0].body)
     Your question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -495,7 +495,7 @@
 
 Default notification when the owner confirms an answer:
 
-    >>> print notifications[1].body
+    >>> print(notifications[1].body)
     Question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -506,7 +506,7 @@
 
 Notification received by the owner:
 
-    >>> print notifications[0].body
+    >>> print(notifications[0].body)
     Your question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -528,7 +528,7 @@
 
 Default notification when a comment is posted:
 
-    >>> print notifications[1].body
+    >>> print(notifications[1].body)
     Question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -538,7 +538,7 @@
 
 Notification received by the owner:
 
-    >>> print notifications[0].body
+    >>> print(notifications[0].body)
     Your question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -559,7 +559,7 @@
 
 Default notification when the question is rejected:
 
-    >>> print notifications[1].body
+    >>> print(notifications[1].body)
     Question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -571,7 +571,7 @@
 
 Notification received by the owner:
 
-    >>> print notifications[0].body
+    >>> print(notifications[0].body)
     Your question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -599,7 +599,7 @@
 
 Default notification when somebody changes the status:
 
-    >>> print notifications[1].body
+    >>> print(notifications[1].body)
     Question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -610,7 +610,7 @@
 
 Notification received by the owner:
 
-    >>> print notifications[0].body
+    >>> print(notifications[0].body)
     Your question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -635,14 +635,14 @@
 
     >>> login('test@xxxxxxxxxxxxx')
     >>> firefox_faq = firefox.getFAQ(10)
-    >>> print firefox_faq.title
+    >>> print(firefox_faq.title)
     How do I install plugins (Shockwave, QuickTime, etc.)?
 
     >>> message = firefox_question.linkFAQ(
     ...     sample_person, firefox_faq, "Read the FAQ.")
     >>> notifications = pop_questionemailjobs()
 
-    >>> print notifications[0].body
+    >>> print(notifications[0].body)
     Your question #... on Mozilla Firefox changed:
     http://answers.launchpad.dev/firefox/+question/...
     <BLANKLINE>
@@ -663,7 +663,7 @@
     ...     sample_person, None, "Sorry, this wasn't so useful.")
     >>> notifications = pop_questionemailjobs()
 
-    >>> print notifications[0].body
+    >>> print(notifications[0].body)
     Your question #... on Mozilla Firefox changed:
     http://answers.launchpad.dev/firefox/+question/...
     <BLANKLINE>
@@ -720,7 +720,7 @@
     ...     language=getUtility(ILanguageSet)['pt_BR'])
     >>> notifications = pop_questionemailjobs()
 
-    >>> print notifications[0].subject.encode('ASCII', 'backslashreplace')
+    >>> print(notifications[0].subject.encode('ASCII', 'backslashreplace'))
     [Question #...]: Abrir uma p\xe1gina que requer java quebra o firefox
 
 Similarly, when a question in a non-English language is modified or its
@@ -749,7 +749,7 @@
     ...     language=french)
     >>> notifications = pop_questionemailjobs()
 
-    >>> print notifications[1].subject
+    >>> print(notifications[1].subject)
     [Question #...]: (French) Impossible d'installer Ubuntu
 
     # Define a function that will replace non-ascii character with
@@ -760,7 +760,7 @@
     ...     return notification.body.encode('ASCII', 'backslashreplace')
 
     >>> notification_body = recode_text(notifications[1])
-    >>> print notification_body
+    >>> print(notification_body)
     A question was asked in a language (French) spoken by
     none of the registered Ubuntu answer contacts.
     <BLANKLINE>
@@ -771,11 +771,11 @@
 The notification received by the question owner contain a warning that
 the question is in a language spoken by none of the answer contacts:
 
-    >>> print notifications[0].subject
+    >>> print(notifications[0].subject)
     [Question #...]: Impossible d'installer Ubuntu
 
     >>> notification_body = recode_text(notifications[0])
-    >>> print notification_body
+    >>> print(notification_body)
     New question #... on Ubuntu:
     http://.../ubuntu/+question/...
     <BLANKLINE>
@@ -796,7 +796,7 @@
     >>> notifications = pop_questionemailjobs()
 
     >>> notification_body = recode_text(notifications[0])
-    >>> print notification_body
+    >>> print(notification_body)
     Your question #... on Ubuntu changed:
     http://.../ubuntu/+question/...
     <BLANKLINE>

=== modified file 'lib/lp/answers/doc/person.txt'
--- lib/lp/answers/doc/person.txt	2016-01-26 15:47:37 +0000
+++ lib/lp/answers/doc/person.txt	2018-06-01 23:51:54 +0000
@@ -28,7 +28,7 @@
 the query using the regular full text algorithm.
 
     >>> for question in foo_bar.searchQuestions(search_text=u'firefox'):
-    ...     print question.title, question.status.title
+    ...     print(question.title, question.status.title)
     Firefox loses focus and gets stuck              Open
     mailto: problem in webpage                      Solved
     Newly installed plug-in doesn't seem to be used Answered
@@ -44,7 +44,7 @@
     >>> from lp.answers.enums import QuestionSort
     >>> for question in foo_bar.searchQuestions(
     ...     search_text=u'firefox', sort=QuestionSort.OLDEST_FIRST):
-    ...     print question.id, question.title, question.status.title
+    ...     print(question.id, question.title, question.status.title)
     4 Firefox loses focus and gets stuck              Open
     6 Newly installed plug-in doesn't seem to be used Answered
     9 mailto: problem in webpage                      Solved
@@ -52,7 +52,7 @@
 When no text search is done, the default sort order is newest first.
 
     >>> for question in foo_bar.searchQuestions():
-    ...     print question.id, question.title, question.status.title
+    ...     print(question.id, question.title, question.status.title)
     11 Continue playing after shutdown                      Open
     10 Play DVDs in Totem                                   Answered
      9 mailto: problem in webpage                           Solved
@@ -71,14 +71,14 @@
     >>> from lp.answers.enums import QuestionStatus
     >>> for question in foo_bar.searchQuestions(
     ...         status=QuestionStatus.INVALID):
-    ...     print question.title, question.status.title
+    ...     print(question.title, question.status.title)
     Firefox is slow and consumes too much RAM   Invalid
 
 The status parameter can also take a list of statuses.
 
     >>> for question in foo_bar.searchQuestions(
     ...         status=(QuestionStatus.SOLVED, QuestionStatus.INVALID)):
-    ...     print question.title, question.status.title
+    ...     print(question.title, question.status.title)
     mailto: problem in webpage                  Solved
     Firefox is slow and consumes too much RAM   Invalid
 
@@ -96,7 +96,7 @@
     >>> from lp.answers.enums import QuestionParticipation
     >>> for question in foo_bar.searchQuestions(
     ...         participation=QuestionParticipation.COMMENTER, status=None):
-    ...     print question.title
+    ...     print(question.title)
     Continue playing after shutdown
     Play DVDs in Totem
     mailto: problem in webpage
@@ -108,7 +108,7 @@
 
     >>> for question in foo_bar.searchQuestions(
     ...         participation=QuestionParticipation.SUBSCRIBER, status=None):
-    ...     print question.title
+    ...     print(question.title)
     Slow system
     Firefox is slow and consumes too much RAM
 
@@ -116,7 +116,7 @@
 
     >>> for question in foo_bar.searchQuestions(
     ...         participation=QuestionParticipation.OWNER, status=None):
-    ...     print question.title
+    ...     print(question.title)
     Slow system
     Firefox loses focus and gets stuck
     Firefox is slow and consumes too much RAM
@@ -126,7 +126,7 @@
 
     >>> for question in foo_bar.searchQuestions(
     ...         participation=QuestionParticipation.ANSWERER, status=None):
-    ...     print question.title
+    ...     print(question.title)
     mailto: problem in webpage
     Firefox is slow and consumes too much RAM
 
@@ -144,7 +144,7 @@
     ...         participation=(QuestionParticipation.OWNER,
     ...                        QuestionParticipation.ANSWERER),
     ...         status=None):
-    ...     print question.title
+    ...     print(question.title)
     mailto: problem in webpage
     Slow system
     Firefox loses focus and gets stuck
@@ -174,7 +174,7 @@
     >>> carlos = IQuestionsPerson(carlos_raw)
     >>> for question in carlos.searchQuestions(
     ...         language=(english, spanish)):
-    ...     print question.title, question.language.code
+    ...     print(question.title, question.language.code)
     Problema al recompilar kernel con soporte smp (doble-núcleo)    es
 
 
@@ -187,8 +187,8 @@
 an answer and are back in the OPEN state.
 
     >>> for question in foo_bar.searchQuestions(needs_attention=True):
-    ...     print question.status.title, question.owner.displayname, (
-    ...         question.title)
+    ...     print(question.status.title, question.owner.displayname,
+    ...           question.title)
     Open              Sample Person Continue playing after shutdown
     Needs information Foo Bar       Slow system
 
@@ -202,7 +202,7 @@
     ...         search_text=u'firefox OR Java',
     ...         status=QuestionStatus.ANSWERED,
     ...         participation=QuestionParticipation.COMMENTER):
-    ...     print question.title, question.status.title
+    ...     print(question.title, question.status.title)
     Installation of Java Runtime Environment for Mozilla    Answered
     Newly installed plug-in doesn't seem to be used         Answered
 
@@ -214,9 +214,9 @@
 contains the set of languages used by all of the questions in which this
 person is involved.
 
-    >>> print ', '.join(
+    >>> print(', '.join(
     ...     sorted(language.code
-    ...            for language in foo_bar.getQuestionLanguages()))
+    ...            for language in foo_bar.getQuestionLanguages())))
     en
 
 This includes questions which the person owns, and questions that the user is
@@ -228,9 +228,9 @@
     >>> pt_BR_question.subscribe(foo_bar_raw)
     <QuestionSubscription...>
 
-    >>> print ', '.join(
+    >>> print(', '.join(
     ...     sorted(language.code
-    ...            for language in foo_bar.getQuestionLanguages()))
+    ...            for language in foo_bar.getQuestionLanguages())))
     en, pt_BR
 
 ...and questions for which they're the answerer...
@@ -239,17 +239,17 @@
     >>> es_question.reject(foo_bar_raw, 'Reject question.')
     <QuestionMessage...>
 
-    >>> print ', '.join(
+    >>> print(', '.join(
     ...     sorted(language.code
-    ...            for language in foo_bar.getQuestionLanguages()))
+    ...            for language in foo_bar.getQuestionLanguages())))
     en, es, pt_BR
 
 ...as well as questions which are assigned to the user...
 
     >>> pt_BR_question.assignee = carlos_raw
-    >>> print ', '.join(
+    >>> print(', '.join(
     ...     sorted(language.code
-    ...            for language in carlos.getQuestionLanguages()))
+    ...            for language in carlos.getQuestionLanguages())))
     es, pt_BR
 
 ...and questions on which the user commented.
@@ -259,9 +259,9 @@
     >>> en_question.addComment(carlos_raw, 'A simple comment.')
     <QuestionMessage...>
 
-    >>> print ', '.join(
+    >>> print(', '.join(
     ...     sorted(language.code
-    ...            for language in carlos.getQuestionLanguages()))
+    ...            for language in carlos.getQuestionLanguages())))
     en, es, pt_BR
 
 
@@ -286,7 +286,7 @@
     True
 
     >>> for target in no_priv.getDirectAnswerQuestionTargets():
-    ...    print target.name
+    ...    print(target.name)
     firefox
 
 
@@ -308,9 +308,9 @@
     >>> ubuntu.addAnswerContact(landscape_team, landscape_team.teamowner)
     True
 
-    >>> print ', '.join(
+    >>> print(', '.join(
     ...     sorted(target.name
-    ...            for target in no_priv.getTeamAnswerQuestionTargets()))
+    ...            for target in no_priv.getTeamAnswerQuestionTargets())))
     ubuntu
 
 Indirect team membership is also taken in consideration.  For example, when
@@ -336,9 +336,9 @@
     >>> evolution_package.addAnswerContact(
     ...     translator_team, translator_team.teamowner)
     True
-    >>> print ', '.join(
+    >>> print(', '.join(
     ...     sorted(target.name
-    ...            for target in no_priv.getTeamAnswerQuestionTargets()))
+    ...            for target in no_priv.getTeamAnswerQuestionTargets())))
     evolution, ubuntu
 
 
@@ -366,7 +366,7 @@
 deactivated for a short period.
 
     >>> firefox.active = True
-    >>> print ', '.join(
+    >>> print(', '.join(
     ...     sorted(target.name
-    ...            for target in no_priv.getDirectAnswerQuestionTargets()))
+    ...            for target in no_priv.getDirectAnswerQuestionTargets())))
     firefox

=== modified file 'lib/lp/answers/doc/projectgroup.txt'
--- lib/lp/answers/doc/projectgroup.txt	2013-05-01 00:23:31 +0000
+++ lib/lp/answers/doc/projectgroup.txt	2018-06-01 23:51:54 +0000
@@ -37,7 +37,7 @@
     ...     " inlined.")
 
     >>> for question in mozilla_project.searchQuestions(search_text=u'svg'):
-    ...     print question.title, question.target.displayname
+    ...     print(question.title, question.target.displayname)
     SVG attachments aren't displayed            Mozilla Thunderbird
     Problem showing the SVG demo on W3C site    Mozilla Firefox
 
@@ -55,7 +55,7 @@
     >>> for question in mozilla_project.searchQuestions(
     ...     owner=sample_person, status=QuestionStatus.OPEN,
     ...     sort=QuestionSort.OLDEST_FIRST):
-    ...     print question.title, question.target.displayname
+    ...     print(question.title, question.target.displayname)
     Problem showing the SVG demo on W3C site    Mozilla Firefox
     SVG attachments aren't displayed            Mozilla Thunderbird
 
@@ -68,9 +68,9 @@
 
     # The Firefox project group has one question created in Brazilian
     # Portuguese.
-    >>> print ', '.join(
+    >>> print(', '.join(
     ...     sorted(language.code
-    ...            for language in mozilla_project.getQuestionLanguages()))
+    ...            for language in mozilla_project.getQuestionLanguages())))
     en, pt_BR
 
 In the case where a project group has no projects, there are no results.

=== modified file 'lib/lp/answers/doc/question.txt'
--- lib/lp/answers/doc/question.txt	2016-01-26 15:47:37 +0000
+++ lib/lp/answers/doc/question.txt	2018-06-01 23:51:54 +0000
@@ -64,9 +64,9 @@
 the Answer Tracker.  This status is set by the answers_usage attribute on
 the IProduct and IDistribution.
 
-    >>> print ubuntu.answers_usage.name
+    >>> print(ubuntu.answers_usage.name)
     LAUNCHPAD
-    >>> print firefox.answers_usage.name
+    >>> print(firefox.answers_usage.name)
     LAUNCHPAD
 
 
@@ -96,13 +96,13 @@
     ...     people = [subscription.person
     ...               for subscription in question.subscriptions]
     ...     for person in sorted(people, key=attrgetter('name')):
-    ...         print person.displayname
+    ...         print(person.displayname)
     >>> print_subscribers(firefox_question)
     Sample Person
 
 The question status is 'Open'.
 
-    >>> print firefox_question.status.title
+    >>> print(firefox_question.status.title)
     Open
 
 The question has a creation time.
@@ -115,7 +115,7 @@
 
 The target onto which the question was created is also available.
 
-    >>> print firefox_question.target.displayname
+    >>> print(firefox_question.target.displayname)
     Mozilla Firefox
 
 It is also possible to adapt a question to its IQuestionTarget.
@@ -128,40 +128,40 @@
 
     >>> thunderbird = getUtility(IProductSet)['thunderbird']
     >>> firefox_question.target = thunderbird
-    >>> print firefox_question.target.displayname
+    >>> print(firefox_question.target.displayname)
     Mozilla Thunderbird
 
 When a question is reassigned, its product, distribution and
 sourcepackagename attributes are reconciled with the IQuestionTarget.
 
     >>> firefox_question.target = ubuntu
-    >>> print firefox_question.target.displayname
+    >>> print(firefox_question.target.displayname)
     Ubuntu
-    >>> print firefox_question.distribution.name
+    >>> print(firefox_question.distribution.name)
     ubuntu
-    >>> print firefox_question.sourcepackagename
+    >>> print(firefox_question.sourcepackagename)
     None
-    >>> print firefox_question.product
+    >>> print(firefox_question.product)
     None
 
     >>> firefox_question.target = evolution_in_ubuntu
-    >>> print firefox_question.target.displayname
+    >>> print(firefox_question.target.displayname)
     evolution in Ubuntu
-    >>> print firefox_question.distribution.name
+    >>> print(firefox_question.distribution.name)
     ubuntu
-    >>> print firefox_question.sourcepackagename.name
+    >>> print(firefox_question.sourcepackagename.name)
     evolution
-    >>> print firefox_question.product
+    >>> print(firefox_question.product)
     None
 
     >>> firefox_question.target = firefox
-    >>> print firefox_question.target.displayname
+    >>> print(firefox_question.target.displayname)
     Mozilla Firefox
-    >>> print firefox_question.distribution
-    None
-    >>> print firefox_question.sourcepackagename
-    None
-    >>> print firefox_question.product.name
+    >>> print(firefox_question.distribution)
+    None
+    >>> print(firefox_question.sourcepackagename)
+    None
+    >>> print(firefox_question.product.name)
     firefox
 
 
@@ -186,7 +186,7 @@
 direct_recipients method.
 
     >>> for person in firefox_question.getDirectSubscribers():
-    ...     print person.displayname
+    ...     print(person.displayname)
     No Privileges Person
     Sample Person
 
@@ -214,7 +214,7 @@
     ...     for person in subscribers:
     ...         reason, header = subscribers.getReason(person)
     ...         text = removeSecurityProxy(reason).getReason()
-    ...         print header, person.displayname, text
+    ...         print(header, person.displayname, text)
     >>> print_reason(subscribers)
     Asker Sample Person
     You received this question notification because you asked the question.
@@ -270,12 +270,12 @@
     >>> del get_property_cache(firefox_question).indirect_recipients
     >>> indirect_subscribers = package_question.indirect_recipients
     >>> for person in indirect_subscribers:
-    ...     print person.displayname
+    ...     print(person.displayname)
     No Privileges Person
     Ubuntu Team
 
     >>> reason, header = indirect_subscribers.getReason(ubuntu_team)
-    >>> print header, removeSecurityProxy(reason).getReason()
+    >>> print(header, removeSecurityProxy(reason).getReason())
     Answer Contact (ubuntu) @ubuntu-team
     You received this question notification because your team Ubuntu Team is
     an answer contact for Ubuntu.
@@ -287,14 +287,14 @@
     >>> del get_property_cache(package_question).indirect_recipients
     >>> indirect_subscribers = package_question.indirect_recipients
     >>> for person in indirect_subscribers:
-    ...     print person.displayname
+    ...     print(person.displayname)
     Foo Bar
     No Privileges Person
     Ubuntu Team
 
     >>> reason, header = indirect_subscribers.getReason(
     ...     package_question.assignee)
-    >>> print header, removeSecurityProxy(reason).getReason()
+    >>> print(header, removeSecurityProxy(reason).getReason())
     Assignee
     You received this question notification because you are assigned to this
     question.
@@ -305,7 +305,7 @@
 
     >>> indirect_subscribers = package_question.getIndirectSubscribers()
     >>> for person in indirect_subscribers:
-    ...     print person.displayname
+    ...     print(person.displayname)
     Foo Bar
     No Privileges Person
     Ubuntu Team
@@ -319,7 +319,7 @@
     >>> verifyObject(INotificationRecipientSet, subscribers)
     True
     >>> for person in subscribers:
-    ...     print person.displayname
+    ...     print(person.displayname)
     No Privileges Person
     Sample Person
 

=== modified file 'lib/lp/answers/doc/questionsets.txt'
--- lib/lp/answers/doc/questionsets.txt	2017-10-07 02:32:32 +0000
+++ lib/lp/answers/doc/questionsets.txt	2018-06-01 23:51:54 +0000
@@ -18,7 +18,7 @@
 The get() method can be used to retrieve a question with a specific id.
 
     >>> question_one = question_set.get(1)
-    >>> print question_one.title
+    >>> print(question_one.title)
     Firefox cannot render Bank Site
 
 If no question exists, a default value is returned.
@@ -30,7 +30,7 @@
 
 If no default value is given, None is returned.
 
-    >>> print question_set.get(123456)
+    >>> print(question_set.get(123456))
     None
 
 
@@ -49,7 +49,7 @@
 
     # Because not everyone uses a real editor <wink>
     >>> for question in question_set.searchQuestions(search_text=u'firefox'):
-    ...     print question.title, question.target.displayname
+    ...     print(question.title, question.target.displayname)
     Problemas de Impressão no Firefox                Mozilla Firefox
     Firefox loses focus and gets stuck               Mozilla Firefox
     Firefox cannot render Bank Site                  Mozilla Firefox
@@ -69,16 +69,16 @@
     >>> from lp.answers.enums import QuestionStatus
     >>> for question in question_set.searchQuestions(
     ...         status=QuestionStatus.INVALID):
-    ...     print question.title, question.status.title, (
-    ...         question.target.displayname)
+    ...     print(question.title, question.status.title,
+    ...           question.target.displayname)
     Firefox is slow and consumes too ...   Invalid mozilla-firefox in Ubuntu
 
 The status parameter can also take a list of statuses.
 
     >>> for question in question_set.searchQuestions(
     ...         status=[QuestionStatus.SOLVED, QuestionStatus.INVALID]):
-    ...     print question.title, question.status.title, (
-    ...          question.target.displayname)
+    ...     print(question.title, question.status.title,
+    ...           question.target.displayname)
     mailto: problem in webpage             Solved mozilla-firefox in Ubuntu
     Firefox is slow and consumes too ...   Invalid mozilla-firefox in Ubuntu
 
@@ -92,7 +92,7 @@
     >>> from lp.services.worlddata.interfaces.language import ILanguageSet
     >>> spanish = getUtility(ILanguageSet)['es']
     >>> for t in question_set.searchQuestions(language=spanish):
-    ...     print t.title
+    ...     print(t.title)
     Problema al recompilar kernel con soporte smp (doble-núcleo)
 
 
@@ -105,7 +105,7 @@
     >>> for question in question_set.searchQuestions(
     ...     search_text=u'firefox',
     ...     status=(QuestionStatus.OPEN, QuestionStatus.INVALID)):
-    ...     print question.title, question.status.title, (
+    ...     print(question.title, question.status.title,
     ...           question.target.displayname)
     Problemas de Impressão no Firefox Open           Mozilla Firefox
     Firefox is slow and consumes too much ...        mozilla-firefox in Ubuntu
@@ -125,8 +125,7 @@
     >>> from lp.answers.enums import QuestionSort
     >>> for question in question_set.searchQuestions(
     ...     search_text=u'firefox', sort=QuestionSort.OLDEST_FIRST):
-    ...     print question.id, question.title, (
-    ...          question.target.displayname)
+    ...     print(question.id, question.title, question.target.displayname)
     14 عكس التغييرات غير المحفوظة للمستن؟               Ubuntu
     1 Firefox cannot render Bank Site                   Mozilla Firefox
     2 Problem showing the SVG demo on W3C site          Mozilla Firefox
@@ -139,8 +138,7 @@
 
     >>> for question in question_set.searchQuestions(
     ...         status=QuestionStatus.OPEN)[:5]:
-    ...     print question.id, question.title, (
-    ...         question.target.displayname)
+    ...     print(question.id, question.title, question.target.displayname)
     13 Problemas de Impressão no Firefox                Mozilla Firefox
     12 Problema al recompilar kernel con soporte smp (doble-núcleo) Ubuntu
     11 Continue playing after shutdown                  Ubuntu
@@ -154,9 +152,9 @@
 The getQuestionLanguages() method returns the set of languages in which
 questions are written in launchpad.
 
-    >>> print ', '.join(
+    >>> print(', '.join(
     ...     sorted(language.code
-    ...            for language in question_set.getQuestionLanguages()))
+    ...            for language in question_set.getQuestionLanguages())))
     ar, en, es, pt_BR
 
 
@@ -226,19 +224,19 @@
 order of the returned projects is based on the number of questions asked
 during the period.
 
-    >>> print ubuntu.answers_usage.name
-    LAUNCHPAD
-    >>> print firefox.answers_usage.name
-    LAUNCHPAD
-    >>> print landscape.answers_usage.name
+    >>> print(ubuntu.answers_usage.name)
+    LAUNCHPAD
+    >>> print(firefox.answers_usage.name)
+    LAUNCHPAD
+    >>> print(landscape.answers_usage.name)
     UNKNOWN
-    >>> print launchpad.answers_usage.name
+    >>> print(launchpad.answers_usage.name)
     LAUNCHPAD
 
     # Launchpad is not returned because the question was not asked in
     # the last 60 days.  Inactive projects are not returned either.
     >>> for project in question_set.getMostActiveProjects():
-    ...     print project.displayname
+    ...     print(project.displayname)
     Ubuntu
     Mozilla Firefox
 
@@ -247,7 +245,7 @@
 project returned:
 
     >>> for project in question_set.getMostActiveProjects(limit=1):
-    ...     print project.displayname
+    ...     print(project.displayname)
     Ubuntu
 
 
@@ -285,9 +283,7 @@
     >>> len(packages)
     4
     >>> for package in packages:
-    ...     print "%s: %s" % (
-    ...         package.bugtargetname,
-    ...         package_counts[package])
+    ...     print("%s: %s" % (package.bugtargetname, package_counts[package]))
     evolution (Ubuntu): 1
     pmount (Ubuntu): 4
     evolution (Debian): 3

=== modified file 'lib/lp/answers/doc/questiontarget.txt'
--- lib/lp/answers/doc/questiontarget.txt	2016-01-26 15:47:37 +0000
+++ lib/lp/answers/doc/questiontarget.txt	2018-06-01 23:51:54 +0000
@@ -44,11 +44,11 @@
 
     >>> question = target.newQuestion(sample_person, 'New question',
     ...     'Question description', datecreated=now)
-    >>> print question.title
+    >>> print(question.title)
     New question
-    >>> print question.description
+    >>> print(question.description)
     Question description
-    >>> print question.owner.displayname
+    >>> print(question.owner.displayname)
     Sample Person
     >>> question.datecreated == now
     True
@@ -58,18 +58,18 @@
 The created question starts in the 'Open' status and should have the owner
 subscribed to the question.
 
-    >>> print question.status.title
+    >>> print(question.status.title)
     Open
 
     >>> for subscription in question.subscriptions:
-    ...     print subscription.person.displayname
+    ...     print(subscription.person.displayname)
     Sample Person
 
 Questions can be written in any languages supported in Launchpad.  The
 language of the request is available in the 'language' attribute.  By default,
 requests are assumed to be written in English.
 
-    >>> print question.language.code
+    >>> print(question.language.code)
     en
 
 It is possible to create questions in another language than English, by
@@ -81,7 +81,7 @@
     ...     sample_person, "De l'aide S.V.P.",
     ...     "Pouvez-vous m'aider?", language=french,
     ...     datecreated=now + timedelta(seconds=30))
-    >>> print question.language.code
+    >>> print(question.language.code)
     fr
 
 Anonymous users cannot use newQuestion().
@@ -106,9 +106,9 @@
 If you pass in a non-existent id or a question for a different target, the
 method returns None.
 
-    >>> print target.getQuestion(2)
+    >>> print(target.getQuestion(2))
     None
-    >>> print target.getQuestion(12345)
+    >>> print(target.getQuestion(12345))
     None
 
 
@@ -164,7 +164,7 @@
 ../../../canonical/launchpad/doct/textsearching.txt.
 
     >>> for t in target.searchQuestions(search_text=u'new'):
-    ...     print t.title
+    ...     print(t.title)
     New question
     Another question
 
@@ -180,7 +180,7 @@
 
     >>> from lp.answers.enums import QuestionStatus
     >>> for t in target.searchQuestions(status=QuestionStatus.OPEN):
-    ...     print t.title
+    ...     print(t.title)
     Another question
     Question title2
     Question title1
@@ -192,7 +192,7 @@
 default sort order is from newest to oldest.
 
     >>> for t in target.searchQuestions(status=QuestionStatus.INVALID):
-    ...     print t.title
+    ...     print(t.title)
     Question title4
 
 You can pass in a list of statuses, and you can also use the search_text and
@@ -202,7 +202,7 @@
     >>> for t in target.searchQuestions(
     ...     search_text=u'request index',
     ...     status=(QuestionStatus.OPEN, QuestionStatus.INVALID)):
-    ...     print t.title
+    ...     print(t.title)
     Question title4
     Question title2
     Question title1
@@ -220,7 +220,7 @@
     >>> from lp.answers.enums import QuestionSort
     >>> for t in target.searchQuestions(search_text='new',
     ...                                 sort=QuestionSort.OLDEST_FIRST):
-    ...     print t.title
+    ...     print(t.title)
     New question
     Another question
 
@@ -232,7 +232,7 @@
     >>> for t in target.searchQuestions(search_text='request index',
     ...                                 status=None,
     ...                                 sort=QuestionSort.STATUS):
-    ...     print t.status.title, t.title
+    ...     print(t.status.title, t.title)
     Open Question title2
     Open Question title1
     Open Question title0
@@ -245,7 +245,7 @@
     # 'Question title4' is not shown in this case because it has INVALID as
     # its status.
     >>> for t in target.searchQuestions(sort=QuestionSort.RELEVANCY):
-    ...     print t.title
+    ...     print(t.title)
     Another question
     Question title3
     Question title2
@@ -262,7 +262,7 @@
     # after the others were created.
     >>> for t in target.searchQuestions(
     ...                             sort=QuestionSort.RECENT_OWNER_ACTIVITY):
-    ...     print t.title
+    ...     print(t.title)
     Question title0
     Another question
     Question title3
@@ -278,7 +278,7 @@
 You can find question owned by a particular user by using the owner parameter.
 
     >>> for t in target.searchQuestions(owner=foo_bar):
-    ...     print t.title
+    ...     print(t.title)
     Question title3
     Question title1
 
@@ -291,11 +291,11 @@
 
     >>> english = getUtility(ILanguageSet)['en']
     >>> for t in target.searchQuestions(language=french):
-    ...     print t.title
+    ...     print(t.title)
     De l'aide S.V.P.
 
     >>> for t in target.searchQuestions(language=(english, french)):
-    ...     print t.title
+    ...     print(t.title)
     Another question
     Question title3
     Question title2
@@ -330,7 +330,7 @@
 
     >>> login(ANONYMOUS)
     >>> for t in target.searchQuestions(needs_attention_from=foo_bar):
-    ...     print t.status.title, t.title, t.owner.displayname
+    ...     print(t.status.title, t.title, t.owner.displayname)
     Answered Question title3 Foo Bar
     Needs information Question title1 Foo Bar
     Open Question title0 Sample Person
@@ -343,7 +343,7 @@
 language that is not spoken by any of the Support Contacts.
 
     >>> for t in target.searchQuestions(unsupported=True):
-    ...     print t.title
+    ...     print(t.title)
     De l'aide S.V.P.
 
 
@@ -357,7 +357,7 @@
     # all other words in the text are either common ('question', 'title') or
     # stop words ('with', 'a').
     >>> for t in target.findSimilarQuestions('new questions with a title'):
-    ...     print t.title
+    ...     print(t.title)
     New question
     Another question
 
@@ -400,12 +400,12 @@
     >>> people = [p.name for p in target.answer_contacts]
     >>> len(people)
     1
-    >>> print people[0]
+    >>> print(people[0])
     name18
     >>> people = [p.name for p in target.direct_answer_contacts]
     >>> len(people)
     1
-    >>> print people[0]
+    >>> print(people[0])
     name18
     >>> target.addAnswerContact(name18, name18)
     False
@@ -455,14 +455,14 @@
     >>> codes = [lang.code for lang in target.getSupportedLanguages()]
     >>> len(codes)
     1
-    >>> print codes[0]
+    >>> print(codes[0])
     en
 
     # Let's add some answer contacts which speak different languages.
     >>> login('carlos@xxxxxxxxxxxxx')
     >>> carlos = getUtility(IPersonSet).getByName('carlos')
     >>> for language in carlos.languages:
-    ...     print language.code
+    ...     print(language.code)
     ca
     en
     es
@@ -474,7 +474,7 @@
     >>> login('daf@xxxxxxxxxxxxx')
     >>> daf = getUtility(IPersonSet).getByName('daf')
     >>> for language in daf.languages:
-    ...     print language.code
+    ...     print(language.code)
     en_GB
     ja
     cy
@@ -485,10 +485,10 @@
 English variants are converted to English.
 
     >>> from operator import attrgetter
-    >>> print ', '.join(
+    >>> print(', '.join(
     ...     language.code
     ...     for language in sorted(target.getSupportedLanguages(),
-    ...                            key=attrgetter('code')))
+    ...                            key=attrgetter('code'))))
     ca, cy, en, es, ja
 
 
@@ -502,12 +502,12 @@
     >>> spanish = getUtility(ILanguageSet)['es']
     >>> answer_contacts = target.getAnswerContactsForLanguage(spanish)
     >>> for person in answer_contacts:
-    ...     print person.name
+    ...     print(person.name)
     carlos
 
     >>> answer_contacts = target.getAnswerContactsForLanguage(english)
     >>> for person in sorted(answer_contacts, key=lambda person: person.name):
-    ...     print person.name
+    ...     print(person.name)
     carlos
     daf
 
@@ -518,9 +518,9 @@
 The getQuestionLanguages() method returns the set of languages used by all
 of the target's questions.
 
-    >>> print ', '.join(
+    >>> print(', '.join(
     ...     sorted(language.code
-    ...            for language in target.getQuestionLanguages()))
+    ...            for language in target.getQuestionLanguages())))
     en, fr
 
 
@@ -549,20 +549,20 @@
 
     >>> target_question = target.createQuestionFromBug(target_bug)
 
-    >>> print target_question.owner.displayname
+    >>> print(target_question.owner.displayname)
     Sample Person
-    >>> print target_question.title
+    >>> print(target_question.title)
     Print is broken
-    >>> print target_question.description
+    >>> print(target_question.description)
     blah blah blah
     >>> question_message = target_question.messages[-1]
-    >>> print question_message.text_contents
+    >>> print(question_message.text_contents)
     This is really a question.
 
     >>> for bug in target_question.bugs:
-    ...     print bug.title
+    ...     print(bug.title)
     Print is broken
-    >>> print target_question.messages[-1].text_contents
+    >>> print(target_question.messages[-1].text_contents)
     This is really a question.
 
 The question's creation date is the same as the bug's creation date.  The
@@ -578,5 +578,5 @@
 The question language is always English because all bugs in Launchpad are
 written in English.
 
-    >>> print target_question.language.code
+    >>> print(target_question.language.code)
     en

=== modified file 'lib/lp/answers/doc/workflow.txt'
--- lib/lp/answers/doc/workflow.txt	2016-01-26 15:47:37 +0000
+++ lib/lp/answers/doc/workflow.txt	2018-06-01 23:51:54 +0000
@@ -7,7 +7,7 @@
 
     >>> from lp.answers.enums import QuestionStatus
     >>> for status in QuestionStatus.items:
-    ...     print status.name
+    ...     print(status.name)
     OPEN
     NEEDSINFO
     ANSWERED
@@ -20,7 +20,7 @@
 
     >>> from lp.answers.enums import QuestionAction
     >>> for status in QuestionAction.items:
-    ...     print status.name
+    ...     print(status.name)
     REQUESTINFO
     GIVEINFO
     COMMENT
@@ -73,7 +73,7 @@
     ...     datecreated=now,
     ...     )
     >>> question = ubuntu.newQuestion(**new_question_args)
-    >>> print question.status.title
+    >>> print(question.status.title)
     Open
 
 The following scenarios are now possible.
@@ -108,29 +108,29 @@
     True
     >>> request_message.datecreated == now_plus_one_hour
     True
-    >>> print request_message.owner.displayname
+    >>> print(request_message.owner.displayname)
     Sample Person
 
 The question message contains the action that was executed and the status of
 the question after the action was executed.
 
-    >>> print request_message.action.name
+    >>> print(request_message.action.name)
     REQUESTINFO
-    >>> print request_message.new_status.name
+    >>> print(request_message.new_status.name)
     NEEDSINFO
 
-    >>> print request_message.text_contents
+    >>> print(request_message.text_contents)
     What is your Mac model?
 
 The subject of the message was generated automatically.
 
-    >>> print request_message.subject
+    >>> print(request_message.subject)
     Re: Unable to boot installer
 
 The question is moved to the NEEDSINFO state and the last response date is
 updated to the message's timestamp.
 
-    >>> print question.status.name
+    >>> print(question.status.name)
     NEEDSINFO
     >>> question.datelastresponse == now_plus_one_hour
     True
@@ -143,19 +143,19 @@
     >>> reply_message = question.giveInfo(
     ...     "I have a PowerMac 7200.", datecreated=now_plus_two_hours)
 
-    >>> print reply_message.action.name
+    >>> print(reply_message.action.name)
     GIVEINFO
-    >>> print reply_message.new_status.name
+    >>> print(reply_message.new_status.name)
     OPEN
     >>> reply_message == question.messages[-1]
     True
-    >>> print reply_message.owner.displayname
+    >>> print(reply_message.owner.displayname)
     No Privileges Person
 
 The question is moved back to the OPEN state and the last query date is
 updated to the message's creation date.
 
-    >>> print question.status.name
+    >>> print(question.status.name)
     OPEN
     >>> question.datelastquery == now_plus_two_hours
     True
@@ -174,15 +174,15 @@
     ...     "https://help.ubuntu.com/community/Installation/OldWorldMacs "
     ...     "for all the details.",
     ...     datecreated=now_plus_three_hours)
-    >>> print answer_message.action.name
+    >>> print(answer_message.action.name)
     ANSWER
-    >>> print answer_message.new_status.name
+    >>> print(answer_message.new_status.name)
     ANSWERED
 
 The question's status is changed to ANSWERED and the last response date is
 updated to contain the date of the message.
 
-    >>> print question.status.name
+    >>> print(question.status.name)
     ANSWERED
     >>> question.datelastresponse == now_plus_three_hours
     True
@@ -198,17 +198,17 @@
     ...     "boot screen. But soon after the Ubuntu progress bar appears, I "
     ...     "get a OOM Killer message appearing on the screen.",
     ...      datecreated=tomorrow)
-    >>> print reopen_message.action.name
+    >>> print(reopen_message.action.name)
     REOPEN
-    >>> print reopen_message.new_status.name
+    >>> print(reopen_message.new_status.name)
     OPEN
-    >>> print reopen_message.owner.displayname
+    >>> print(reopen_message.owner.displayname)
     No Privileges Person
 
 This moves back the question to the OPEN state and the last query date is
 updated to the message's creation date.
 
-    >>> print question.status.name
+    >>> print(question.status.name)
     OPEN
     >>> question.datelastquery == tomorrow
     True
@@ -225,7 +225,7 @@
 
 The question is moved back to the ANSWERED state.
 
-    >>> print question.status.name
+    >>> print(question.status.name)
     ANSWERED
 
 The question owner will hopefully come back to confirm that their problem is
@@ -238,22 +238,22 @@
     ...     "I upgraded to 512M of RAM (found on eBay) and I've successfully "
     ...     "managed to install Ubuntu. Thanks for all the help.",
     ...     datecreated=two_weeks_from_now, answer=answer_message)
-    >>> print confirm_message.action.name
+    >>> print(confirm_message.action.name)
     CONFIRM
-    >>> print confirm_message.new_status.name
+    >>> print(confirm_message.new_status.name)
     SOLVED
-    >>> print confirm_message.owner.displayname
+    >>> print(confirm_message.owner.displayname)
     No Privileges Person
 
 The question is moved to the SOLVED state, and the message that solved the
 question is saved.  The date the question was solved and answerer are also
 updated.
 
-    >>> print question.status.name
+    >>> print(question.status.name)
     SOLVED
     >>> question.date_solved == two_weeks_from_now
     True
-    >>> print question.answerer.displayname
+    >>> print(question.answerer.displayname)
     Sample Person
     >>> question.answer == answer_message
     True
@@ -298,18 +298,18 @@
 solved and the question is moved to the SOLVED state.  The 'answerer'
 will be the question owner.
 
-    >>> print self_answer_message.action.name
+    >>> print(self_answer_message.action.name)
     CONFIRM
-    >>> print self_answer_message.new_status.name
+    >>> print(self_answer_message.new_status.name)
     SOLVED
 
-    >>> print question.status.name
+    >>> print(question.status.name)
     SOLVED
-    >>> print question.answerer.displayname
+    >>> print(question.answerer.displayname)
     No Privileges Person
     >>> question.date_solved == now_plus_one_hour
     True
-    >>> print question.answer
+    >>> print(question.answer)
     None
 
 The question owner can still specify which message helped them solve their
@@ -323,16 +323,16 @@
     ...     "Ubuntu on my Mac.",
     ...     datecreated=now_plus_one_hour,
     ...     answer=alt_answer_message)
-    >>> print confirm_message.action.name
+    >>> print(confirm_message.action.name)
     CONFIRM
-    >>> print confirm_message.new_status.name
+    >>> print(confirm_message.new_status.name)
     SOLVED
-    >>> print confirm_message.owner.displayname
+    >>> print(confirm_message.owner.displayname)
     No Privileges Person
 
-    >>> print question.status.name
+    >>> print(question.status.name)
     SOLVED
-    >>> print question.answerer.displayname
+    >>> print(question.answerer.displayname)
     Marilize Coetzee
     >>> question.answer == alt_answer_message
     True
@@ -356,15 +356,15 @@
     ...     "this problem you should reopen the question and provide more "
     ...     "information about your problem.",
     ...     datecreated=two_weeks_from_now)
-    >>> print expire_message.action.name
+    >>> print(expire_message.action.name)
     EXPIRE
-    >>> print expire_message.new_status.name
+    >>> print(expire_message.new_status.name)
     EXPIRED
 
 The question is moved to the EXPIRED state and the last response date is
 updated to the message creation date.
 
-    >>> print question.status.name
+    >>> print(question.status.name)
     EXPIRED
     >>> question.datelastresponse == two_weeks_from_now
     True
@@ -378,13 +378,13 @@
     ...     "I insert the CD and restart the computer, it boots straight "
     ...     "into Mac OS/9 instead of booting the installer.",
     ...     datecreated=much_later)
-    >>> print reopen_message.action.name
+    >>> print(reopen_message.action.name)
     REOPEN
 
 The question status is changed back to OPEN and the last query date is
 updated.
 
-    >>> print question.status.name
+    >>> print(question.status.name)
     OPEN
     >>> question.datelastquery == much_later
     True
@@ -436,15 +436,15 @@
     >>> reject_message = spam_question.reject(
     ...     sample_person, "We don't send free CDs any more.",
     ...     datecreated=now_plus_one_hour)
-    >>> print reject_message.action.name
+    >>> print(reject_message.action.name)
     REJECT
-    >>> print reject_message.new_status.name
+    >>> print(reject_message.new_status.name)
     INVALID
 
 After rejection, the question is marked as invalid and the last response date
 is updated.
 
-    >>> print spam_question.status.name
+    >>> print(spam_question.status.name)
     INVALID
     >>> spam_question.datelastresponse == now_plus_one_hour
     True
@@ -454,7 +454,7 @@
 
     >>> spam_question.answer == reject_message
     True
-    >>> print spam_question.answerer.displayname
+    >>> print(spam_question.answerer.displayname)
     Sample Person
     >>> spam_question.date_solved == now_plus_one_hour
     True
@@ -500,11 +500,11 @@
 
 The method returns the IQuestionMessage recording the change.
 
-    >>> print status_change_message.action.name
+    >>> print(status_change_message.action.name)
     SETSTATUS
-    >>> print status_change_message.new_status.name
+    >>> print(status_change_message.new_status.name)
     INVALID
-    >>> print question.status.name
+    >>> print(question.status.name)
     INVALID
 
 The status change updates the last response date.
@@ -532,9 +532,9 @@
     ...     stub, QuestionStatus.OPEN, 'Reopen the question',
     ...     datecreated=now_plus_one_hour)
 
-    >>> print question.date_solved
+    >>> print(question.date_solved)
     None
-    >>> print question.answer
+    >>> print(question.answer)
     None
 
 When the status is changed by a user who doesn't have the launchpad.Admin
@@ -560,7 +560,7 @@
     ...     no_priv, 'This is a comment.',
     ...     datecreated=now_plus_two_hours)
 
-    >>> print comment.action.name
+    >>> print(comment.action.name)
     COMMENT
     >>> comment.new_status == old_status
     True
@@ -583,7 +583,7 @@
 
     >>> login('test@xxxxxxxxxxxxx')
     >>> question.assignee = stub
-    >>> print question.assignee.displayname
+    >>> print(question.assignee.displayname)
     Stuart Bishop
 
 Users without launchpad.Moderator privileges cannot set the assignee.
@@ -608,9 +608,9 @@
     >>> from lp.answers.interfaces.question import IQuestion
 
     >>> def print_event(object, event):
-    ...     print "Received %s on %s" % (
+    ...     print("Received %s on %s" % (
     ...         event.__class__.__name__.split('.')[-1],
-    ...         object.__class__.__name__.split('.')[-1])
+    ...         object.__class__.__name__.split('.')[-1]))
     >>> questionmessage_event_listener = TestEventListener(
     ...     IQuestionMessage, IObjectCreatedEvent, print_event)
     >>> question_event_listener = TestEventListener(
@@ -689,17 +689,17 @@
 
     >>> reopening.datecreated == now_plus_three_hours
     True
-    >>> print reopening.reopener.displayname
+    >>> print(reopening.reopener.displayname)
     No Privileges Person
 
 It also contains the question's prior answerer, the date created, and the
 prior status of the question.
 
-    >>> print reopening.answerer.displayname
+    >>> print(reopening.answerer.displayname)
     Sample Person
     >>> reopening.date_solved == now_plus_two_hours
     True
-    >>> print reopening.priorstate.name
+    >>> print(reopening.priorstate.name)
     SOLVED
 
 A reopening also occurs when the question status is set back to OPEN after
@@ -720,15 +720,15 @@
     Received ObjectCreatedEvent on QuestionReopening
 
     >>> reopening = question.reopenings[0]
-    >>> print reopening.reopener.name
+    >>> print(reopening.reopener.name)
     stub
     >>> reopening.datecreated == now_plus_two_hours
     True
-    >>> print reopening.answerer.displayname
+    >>> print(reopening.answerer.displayname)
     Sample Person
     >>> reopening.date_solved == now_plus_one_hour
     True
-    >>> print reopening.priorstate.name
+    >>> print(reopening.priorstate.name)
     INVALID
 
     # Cleanup
@@ -748,9 +748,9 @@
     >>> reject_message = messageset.fromText(
     ...     'Reject', 'Because I feel like it.', sample_person)
     >>> question_message = question.reject(sample_person, reject_message)
-    >>> print question_message.subject
+    >>> print(question_message.subject)
     Reject
-    >>> print question_message.text_contents
+    >>> print(question_message.text_contents)
     Because I feel like it.
     >>> question_message.rfc822msgid == reject_message.rfc822msgid
     True

=== modified file 'lib/lp/answers/tests/test_doc.py'
--- lib/lp/answers/tests/test_doc.py	2017-10-25 10:02:12 +0000
+++ lib/lp/answers/tests/test_doc.py	2018-06-01 23:51:54 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2010 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """
@@ -34,7 +34,7 @@
 
 def productSetUp(test):
     """Test environment for product."""
-    setUp(test)
+    setUp(test, future=True)
     thunderbird = getUtility(IProductSet).getByName('thunderbird')
     test.globs['target'] = thunderbird
     test.globs['collection'] = thunderbird
@@ -45,7 +45,7 @@
 
 def distributionSetUp(test):
     """Test environment for distribution."""
-    setUp(test)
+    setUp(test, future=True)
     kubuntu = getUtility(IDistributionSet).getByName('kubuntu')
     test.globs['target'] = kubuntu
     test.globs['collection'] = kubuntu
@@ -56,7 +56,7 @@
 
 def projectSetUp(test):
     """Test environment for project."""
-    setUp(test)
+    setUp(test, future=True)
     gnome_project = getUtility(IProjectGroupSet).getByName('gnome')
     products_queue = list(gnome_project.products)
 
@@ -73,7 +73,7 @@
 
 
 def distributionsourcepackageSetUp(test):
-    setUp(test)
+    setUp(test, future=True)
     ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
     test.globs['target'] = ubuntu.getSourcePackage('evolution')
 
@@ -116,11 +116,12 @@
          ]),
     'emailinterface.txt': LayeredDocFileSuite(
         'emailinterface.txt',
-        setUp=setUp, tearDown=tearDown,
+        setUp=lambda test: setUp(test, future=True), tearDown=tearDown,
         layer=ProcessMailLayer,
         stdout_logging=False)
     }
 
 
 def test_suite():
-    return build_test_suite(here, special)
+    return build_test_suite(
+        here, special, setUp=lambda test: setUp(test, future=True))


Follow ups