← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:six-xmlrpclib into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:six-xmlrpclib into launchpad:master.

Commit message:
Import xmlrpclib from six.moves.xmlrpc_client

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/379509

This part of the standard library was rearranged in Python 3.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:six-xmlrpclib into launchpad:master.
diff --git a/cronscripts/code-import-dispatcher.py b/cronscripts/code-import-dispatcher.py
index 0bcf6b1..df269ca 100755
--- a/cronscripts/code-import-dispatcher.py
+++ b/cronscripts/code-import-dispatcher.py
@@ -7,7 +7,7 @@
 
 import _pythonpath
 
-from xmlrpclib import ServerProxy
+from six.moves.xmlrpc_client import ServerProxy
 
 from lp.codehosting.codeimport.dispatcher import CodeImportDispatcher
 from lp.services.config import config
diff --git a/lib/launchpad_loggerhead/app.py b/lib/launchpad_loggerhead/app.py
index 59225d7..a671d73 100644
--- a/lib/launchpad_loggerhead/app.py
+++ b/lib/launchpad_loggerhead/app.py
@@ -4,7 +4,6 @@
 import logging
 import os
 import threading
-import xmlrpclib
 
 from breezy import (
     errors,
@@ -40,6 +39,7 @@ from paste.request import (
     parse_querystring,
     path_info_pop,
     )
+from six.moves import xmlrpc_client
 from six.moves.urllib.parse import (
     urlencode,
     urljoin,
@@ -75,7 +75,7 @@ set_default_openid_fetcher()
 def check_fault(fault, *fault_classes):
     """Check if 'fault's faultCode matches any of 'fault_classes'.
 
-    :param fault: An instance of `xmlrpclib.Fault`.
+    :param fault: An instance of `xmlrpc_client.Fault`.
     :param fault_classes: Any number of `LaunchpadFault` subclasses.
     """
     for cls in fault_classes:
@@ -101,7 +101,7 @@ class RootApp:
     def get_branchfs(self):
         t = getattr(thread_locals, 'branchfs', None)
         if t is None:
-            thread_locals.branchfs = xmlrpclib.ServerProxy(
+            thread_locals.branchfs = xmlrpc_client.ServerProxy(
                 config.codehosting.codehosting_endpoint)
         return thread_locals.branchfs
 
@@ -224,7 +224,7 @@ class RootApp:
                 branchfs = self.get_branchfs()
                 transport_type, info, trail = branchfs.translatePath(
                     identity_url, urlutils.escape(path))
-            except xmlrpclib.Fault as f:
+            except xmlrpc_client.Fault as f:
                 if check_fault(f, faults.PathTranslationError):
                     raise HTTPNotFound()
                 elif check_fault(f, faults.PermissionDenied):
diff --git a/lib/lp/app/stories/basics/xx-opstats.txt b/lib/lp/app/stories/basics/xx-opstats.txt
index 47e7780..655b7d0 100644
--- a/lib/lp/app/stories/basics/xx-opstats.txt
+++ b/lib/lp/app/stories/basics/xx-opstats.txt
@@ -4,9 +4,9 @@ Operational Statistics and Metrics
 We make Zope 3 give us real time statistics about Launchpad's operation.
 We can access them via XML-RPC:
 
-    >>> import xmlrpclib
+    >>> from six.moves import xmlrpc_client
     >>> from lp.testing.xmlrpc import XMLRPCTestTransport
-    >>> lp_xmlrpc = xmlrpclib.ServerProxy(
+    >>> lp_xmlrpc = xmlrpc_client.ServerProxy(
     ...     'http://xmlrpc.launchpad.test/+opstats',
     ...     transport=XMLRPCTestTransport()
     ...     )
@@ -147,7 +147,7 @@ Number of XML-RPC Faults
     >>> try:
     ...     opstats = lp_xmlrpc.invalid() # XXX: Need a HTTP test too
     ...     print 'Should have raised a Fault exception!'
-    ... except xmlrpclib.Fault:
+    ... except xmlrpc_client.Fault:
     ...     pass
     >>> report()
     requests: 1
diff --git a/lib/lp/bugs/doc/bugtracker-tokens.txt b/lib/lp/bugs/doc/bugtracker-tokens.txt
index 630209c..a32f050 100644
--- a/lib/lp/bugs/doc/bugtracker-tokens.txt
+++ b/lib/lp/bugs/doc/bugtracker-tokens.txt
@@ -3,12 +3,12 @@ Using BugTracker Login Tokens
 
 Launchpad offers an XML-RPC interface for generating bug tracker tokens.
 
-    >>> import xmlrpclib
+    >>> from six.moves import xmlrpc_client
     >>> from zope.component import getUtility
     >>> from lp.testing.xmlrpc import XMLRPCTestTransport
     >>> from lp.services.verification.interfaces.logintoken import (
     ...     ILoginTokenSet)
-    >>> bugtracker_api = xmlrpclib.ServerProxy(
+    >>> bugtracker_api = xmlrpc_client.ServerProxy(
     ...     'http://xmlrpc-private.launchpad.test:8087/bugs',
     ...     transport=XMLRPCTestTransport())
 
diff --git a/lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt b/lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt
index ce19c31..465265e 100644
--- a/lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt
+++ b/lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt
@@ -130,7 +130,7 @@ login_required() and will retry the method call.
 
 If authentication fails, a BugTrackerAuthenticationError will be raised.
 
-    >>> from xmlrpclib import Fault, ProtocolError
+    >>> from six.moves.xmlrpc_client import Fault, ProtocolError
     >>> class TestAuthFailingBugzillaXMLRPCTransport(
     ...         ZopelessBugzillaXMLRPCTransport):
     ...     error = Fault(100, "Sorry, you can't log in.")
diff --git a/lib/lp/bugs/doc/externalbugtracker-bugzilla.txt b/lib/lp/bugs/doc/externalbugtracker-bugzilla.txt
index 0230d40..ddaf53b 100644
--- a/lib/lp/bugs/doc/externalbugtracker-bugzilla.txt
+++ b/lib/lp/bugs/doc/externalbugtracker-bugzilla.txt
@@ -86,25 +86,25 @@ ExternalBugTracker will be returned.
 The Bugzilla ExternalBugTracker has a _test_xmlrpc_proxy property which
 we override for the purpose of this test.
 
-    >>> import xmlrpclib
-    >>> class FailingXMLRPCTransport(xmlrpclib.Transport):
+    >>> from six.moves import xmlrpc_client
+    >>> class FailingXMLRPCTransport(xmlrpc_client.Transport):
     ...
-    ...     error = xmlrpclib.Fault(
-    ...         xmlrpclib.METHOD_NOT_FOUND, "Method doesn't exist")
+    ...     error = xmlrpc_client.Fault(
+    ...         xmlrpc_client.METHOD_NOT_FOUND, "Method doesn't exist")
     ...
     ...     def request(self, host, handler, request, verbose=None):
     ...         if self.error is not None:
     ...             raise self.error
     ...         else:
     ...             # We need to return something here, otherwise
-    ...             # xmlrpclib will explode.
+    ...             # xmlrpc_client will explode.
     ...             return '0.42-test'
     ...
     >>> test_transport = FailingXMLRPCTransport()
 
     >>> class BugzillaWithFakeProxy(Bugzilla):
     ...
-    ...     _test_xmlrpc_proxy = xmlrpclib.ServerProxy(
+    ...     _test_xmlrpc_proxy = xmlrpc_client.ServerProxy(
     ...         'http://example.com/xmlrpc.cgi', transport=test_transport)
 
     >>> bugzilla = BugzillaWithFakeProxy('http://example.com')
@@ -129,7 +129,7 @@ BugzillaAPI instance.
 The same is true if getExternalBugTrackerToUse() receives a 404 error
 from the remote server.
 
-    >>> test_transport.error = xmlrpclib.ProtocolError(
+    >>> test_transport.error = xmlrpc_client.ProtocolError(
     ...     'http://example.com/xmlrpc.cgi', 404, 'Not Found', None)
 
     >>> bugzilla_to_use = bugzilla.getExternalBugTrackerToUse()
@@ -141,7 +141,7 @@ from the remote server.
 Some Bugzillas respond to an invalid XML-RPC method call by returning a
 500 error. getExternalBugTrackerToUse() handles those, too.
 
-    >>> test_transport.error = xmlrpclib.ProtocolError(
+    >>> test_transport.error = xmlrpc_client.ProtocolError(
     ...     'http://example.com/xmlrpc.cgi', 500, 'Server Error', None)
 
     >>> bugzilla_to_use = bugzilla.getExternalBugTrackerToUse()
@@ -153,7 +153,7 @@ Some Bugzillas respond to an invalid XML-RPC method call by returning a
 Some other Bugzillas generate an unparsable response, causing
 ResponseError to be raised.
 
-    >>> test_transport.error = xmlrpclib.ResponseError()
+    >>> test_transport.error = xmlrpc_client.ResponseError()
     >>> bugzilla_to_use = bugzilla.getExternalBugTrackerToUse()
 
     >>> (isinstance(bugzilla_to_use, Bugzilla) and
@@ -164,22 +164,22 @@ If the remote Bugzilla offers the Bugzilla 3.4 API, an instance of
 BuzillaAPI will be returned. To test this, we use a specially-crafted
 XML-RPC proxy that behaves like a Bugzilla 3.4 instance.
 
-    >>> class APIXMLRPCTransport(xmlrpclib.Transport):
+    >>> class APIXMLRPCTransport(xmlrpc_client.Transport):
     ...
     ...     version = '3.4.2'
     ...
     ...     def request(self, host, handler, request, verbose=None):
-    ...         args, method_name = xmlrpclib.loads(request)
+    ...         args, method_name = xmlrpc_client.loads(request)
     ...
     ...         if method_name == 'Bugzilla.version':
     ...             return [{'version': self.version}]
     ...         else:
-    ...             raise xmlrpclib.Fault(
-    ...                 xmlrpclib.METHOD_NOT_FOUND, 'No such method')
+    ...             raise xmlrpc_client.Fault(
+    ...                 xmlrpc_client.METHOD_NOT_FOUND, 'No such method')
     ...
     >>> test_transport = APIXMLRPCTransport()
 
-    >>> bugzilla._test_xmlrpc_proxy = xmlrpclib.ServerProxy(
+    >>> bugzilla._test_xmlrpc_proxy = xmlrpc_client.ServerProxy(
     ...     'http://example.com/xmlrpc.cgi',
     ...     transport=test_transport)
 
@@ -193,7 +193,7 @@ A version older than 3.4 is not accepted.
     >>> test_transport = APIXMLRPCTransport()
     >>> test_transport.version = '3.3'
 
-    >>> bugzilla._test_xmlrpc_proxy = xmlrpclib.ServerProxy(
+    >>> bugzilla._test_xmlrpc_proxy = xmlrpc_client.ServerProxy(
     ...     'http://example.com/xmlrpc.cgi',
     ...     transport=test_transport)
 
@@ -206,7 +206,7 @@ bugzilla.mozilla.org uses a date-based version scheme.  This is accepted.
     >>> test_transport = APIXMLRPCTransport()
     >>> test_transport.version = '20181108.1'
 
-    >>> bugzilla._test_xmlrpc_proxy = xmlrpclib.ServerProxy(
+    >>> bugzilla._test_xmlrpc_proxy = xmlrpc_client.ServerProxy(
     ...     'http://example.com/xmlrpc.cgi',
     ...     transport=test_transport)
 
@@ -218,20 +218,20 @@ bugzilla.mozilla.org uses a date-based version scheme.  This is accepted.
 If the remote system has the Launchpad plugin installed, an
 getExternalBugTrackerToUse() will return a BugzillaLPPlugin instance.
 
-    >>> class PluginXMLRPCTransport(xmlrpclib.Transport):
+    >>> class PluginXMLRPCTransport(xmlrpc_client.Transport):
     ...
     ...     def request(self, host, handler, request, verbose=None):
-    ...         args, method_name = xmlrpclib.loads(request)
+    ...         args, method_name = xmlrpc_client.loads(request)
     ...
     ...         if method_name == 'Launchpad.plugin_version':
     ...             return [{'version': '0.2'}]
     ...         else:
-    ...             raise xmlrpclib.Fault(
-    ...                 xmlrpclib.METHOD_NOT_FOUND, 'No such method')
+    ...             raise xmlrpc_client.Fault(
+    ...                 xmlrpc_client.METHOD_NOT_FOUND, 'No such method')
     ...
     >>> test_transport = PluginXMLRPCTransport()
 
-    >>> bugzilla._test_xmlrpc_proxy = xmlrpclib.ServerProxy(
+    >>> bugzilla._test_xmlrpc_proxy = xmlrpc_client.ServerProxy(
     ...     'http://example.com/xmlrpc.cgi',
     ...     transport=test_transport)
 
@@ -244,19 +244,19 @@ in response to XML-RPC calls. When something other than a mapping is
 returned, the standard non-API non-plugin external bug tracker is
 selected.
 
-    >>> class OldXMLRPCTransport(xmlrpclib.Transport):
+    >>> class OldXMLRPCTransport(xmlrpc_client.Transport):
     ...     def request(self, host, handler, request, verbose=None):
-    ...         args, method_name = xmlrpclib.loads(request)
+    ...         args, method_name = xmlrpc_client.loads(request)
     ...
     ...         if method_name == 'Bugzilla.version':
     ...             return ('versionResponse', {'version': '3.2.5+'})
     ...         else:
-    ...             raise xmlrpclib.Fault(
-    ...                 xmlrpclib.METHOD_NOT_FOUND, 'No such method')
+    ...             raise xmlrpc_client.Fault(
+    ...                 xmlrpc_client.METHOD_NOT_FOUND, 'No such method')
     ...
     >>> test_transport = OldXMLRPCTransport()
 
-    >>> bugzilla._test_xmlrpc_proxy = xmlrpclib.ServerProxy(
+    >>> bugzilla._test_xmlrpc_proxy = xmlrpc_client.ServerProxy(
     ...     'http://example.com/xmlrpc.cgi',
     ...     transport=test_transport)
 
@@ -270,18 +270,18 @@ is not discovered over XML-RPC. It's not clear if this is an error in
 Bugzilla or in and XML-RPC library used by Bugzilla. In any case, we
 recognize and treat it the same as METHOD_NOT_FOUND.
 
-    >>> class OldBrokenXMLRPCTransport(xmlrpclib.Transport):
+    >>> class OldBrokenXMLRPCTransport(xmlrpc_client.Transport):
     ...     def request(self, host, handler, request, verbose=None):
-    ...         args, method_name = xmlrpclib.loads(request)
+    ...         args, method_name = xmlrpc_client.loads(request)
     ...
     ...         if method_name == 'Bugzilla.version':
     ...             return ('versionResponse', {'version': '3.2.5+'})
     ...         else:
-    ...             raise xmlrpclib.Fault('Client', 'No such method')
+    ...             raise xmlrpc_client.Fault('Client', 'No such method')
     ...
     >>> test_transport = OldBrokenXMLRPCTransport()
 
-    >>> bugzilla._test_xmlrpc_proxy = xmlrpclib.ServerProxy(
+    >>> bugzilla._test_xmlrpc_proxy = xmlrpc_client.ServerProxy(
     ...     'http://example.com/xmlrpc.cgi',
     ...     transport=test_transport)
 
diff --git a/lib/lp/bugs/doc/malone-xmlrpc.txt b/lib/lp/bugs/doc/malone-xmlrpc.txt
index 1d4ace3..465dca7 100644
--- a/lib/lp/bugs/doc/malone-xmlrpc.txt
+++ b/lib/lp/bugs/doc/malone-xmlrpc.txt
@@ -3,9 +3,9 @@ XML-RPC Integration with Malone
 
 Malone provides an XML-RPC interface for filing bugs.
 
-    >>> import xmlrpclib
+    >>> from six.moves import xmlrpc_client
     >>> from lp.testing.xmlrpc import XMLRPCTestTransport
-    >>> filebug_api = xmlrpclib.ServerProxy(
+    >>> filebug_api = xmlrpc_client.ServerProxy(
     ...     'http://test@xxxxxxxxxxxxx:test@xxxxxxxxxxxxxxxxxxxxx/bugs/',
     ...     transport=XMLRPCTestTransport())
 
@@ -277,7 +277,7 @@ The LoginToken generated will be of the LoginTokenType BUGTRACKER.
 
 These requests are all handled by the private xml-rpc server.
 
-    >>> bugtracker_api = xmlrpclib.ServerProxy(
+    >>> bugtracker_api = xmlrpc_client.ServerProxy(
     ...     'http://xmlrpc-private.launchpad.test:8087/bugs',
     ...     transport=XMLRPCTestTransport())
 
diff --git a/lib/lp/bugs/externalbugtracker/bugzilla.py b/lib/lp/bugs/externalbugtracker/bugzilla.py
index ffdb35e..43f8c74 100644
--- a/lib/lp/bugs/externalbugtracker/bugzilla.py
+++ b/lib/lp/bugs/externalbugtracker/bugzilla.py
@@ -15,12 +15,12 @@ from email.utils import parseaddr
 import re
 import string
 import xml.parsers.expat
-import xmlrpclib
 
 from defusedxml import minidom
 import pytz
 import requests
 import six
+from six.moves import xmlrpc_client
 from six.moves.http_client import BadStatusLine
 from zope.component import getUtility
 from zope.interface import (
@@ -92,15 +92,15 @@ class Bugzilla(ExternalBugTracker):
             # We try calling Bugzilla.version() on the remote
             # server because it's the most lightweight method there is.
             remote_version = proxy.Bugzilla.version()
-        except xmlrpclib.Fault as fault:
+        except xmlrpc_client.Fault as fault:
             # 'Client' is a hangover. Either Bugzilla or the Perl
             # XML-RPC lib in use returned it as faultCode. It's wrong,
             # but it's known wrongness, so we recognize it here.
-            if fault.faultCode in (xmlrpclib.METHOD_NOT_FOUND, 'Client'):
+            if fault.faultCode in (xmlrpc_client.METHOD_NOT_FOUND, 'Client'):
                 return False
             else:
                 raise
-        except xmlrpclib.ProtocolError as error:
+        except xmlrpc_client.ProtocolError as error:
             # We catch 404s, which occur when xmlrpc.cgi doesn't exist
             # on the remote server, and 500s, which sometimes occur when
             # an invalid request is made to the remote server. We allow
@@ -109,7 +109,7 @@ class Bugzilla(ExternalBugTracker):
                 return False
             else:
                 raise
-        except (xmlrpclib.ResponseError, xml.parsers.expat.ExpatError):
+        except (xmlrpc_client.ResponseError, xml.parsers.expat.ExpatError):
             # The server returned an unparsable response.
             return False
         else:
@@ -134,15 +134,15 @@ class Bugzilla(ExternalBugTracker):
             # We try calling Launchpad.plugin_version() on the remote
             # server because it's the most lightweight method there is.
             proxy.Launchpad.plugin_version()
-        except xmlrpclib.Fault as fault:
+        except xmlrpc_client.Fault as fault:
             # 'Client' is a hangover. Either Bugzilla or the Perl
             # XML-RPC lib in use returned it as faultCode. It's wrong,
             # but it's known wrongness, so we recognize it here.
-            if fault.faultCode in (xmlrpclib.METHOD_NOT_FOUND, 'Client'):
+            if fault.faultCode in (xmlrpc_client.METHOD_NOT_FOUND, 'Client'):
                 return False
             else:
                 raise
-        except xmlrpclib.ProtocolError as error:
+        except xmlrpc_client.ProtocolError as error:
             # We catch 404s, which occur when xmlrpc.cgi doesn't exist
             # on the remote server, and 500s, which sometimes occur when
             # the Launchpad Plugin isn't installed. Everything else we
@@ -152,7 +152,7 @@ class Bugzilla(ExternalBugTracker):
                 return False
             else:
                 raise
-        except (xmlrpclib.ResponseError, xml.parsers.expat.ExpatError):
+        except (xmlrpc_client.ResponseError, xml.parsers.expat.ExpatError):
             # The server returned an unparsable response.
             return False
         else:
@@ -171,7 +171,7 @@ class Bugzilla(ExternalBugTracker):
                 return BugzillaLPPlugin(self.baseurl)
             elif self._remoteSystemHasBugzillaAPI():
                 return BugzillaAPI(self.baseurl)
-        except (xmlrpclib.ProtocolError, requests.RequestException,
+        except (xmlrpc_client.ProtocolError, requests.RequestException,
                 BadStatusLine):
             pass
         return self
@@ -540,14 +540,14 @@ class Bugzilla(ExternalBugTracker):
 def needs_authentication(func):
     """Decorator for automatically authenticating if needed.
 
-    If an `xmlrpclib.Fault` with error code 410 is raised by the
+    If an `xmlrpc_client.Fault` with error code 410 is raised by the
     function, we'll try to authenticate and call the function again.
     """
 
     def decorator(self, *args, **kwargs):
         try:
             return func(self, *args, **kwargs)
-        except xmlrpclib.Fault as fault:
+        except xmlrpc_client.Fault as fault:
             # Catch authentication errors only.
             if fault.faultCode != 410:
                 raise
@@ -589,8 +589,8 @@ class BugzillaAPI(Bugzilla):
 
     @property
     def xmlrpc_proxy(self):
-        """Return an `xmlrpclib.ServerProxy` to self.xmlrpc_endpoint."""
-        return xmlrpclib.ServerProxy(
+        """Return an `xmlrpc_client.ServerProxy` to self.xmlrpc_endpoint."""
+        return xmlrpc_client.ServerProxy(
             self.xmlrpc_endpoint, transport=self.xmlrpc_transport)
 
     @property
@@ -624,7 +624,7 @@ class BugzillaAPI(Bugzilla):
         """
         try:
             self.xmlrpc_proxy.User.login(self.credentials)
-        except xmlrpclib.Fault as fault:
+        except xmlrpc_client.Fault as fault:
             raise BugTrackerAuthenticationError(
                 self.baseurl,
                 "Fault %s: %s" % (fault.faultCode, fault.faultString))
@@ -974,7 +974,7 @@ class BugzillaLPPlugin(BugzillaAPI):
         Bugzilla_logincookie, which we can then use to re-authenticate
         ourselves for each subsequent method call.
         """
-        internal_xmlrpc_server = xmlrpclib.ServerProxy(
+        internal_xmlrpc_server = xmlrpc_client.ServerProxy(
             config.checkwatches.xmlrpc_url,
             transport=self.internal_xmlrpc_transport)
 
@@ -983,12 +983,12 @@ class BugzillaLPPlugin(BugzillaAPI):
         try:
             self.xmlrpc_proxy.Launchpad.login(
                 {'token': token_text})
-        except xmlrpclib.Fault as fault:
+        except xmlrpc_client.Fault as fault:
             message = 'XML-RPC Fault: %s "%s"' % (
                 fault.faultCode, fault.faultString)
             raise BugTrackerAuthenticationError(
                 self.baseurl, message)
-        except xmlrpclib.ProtocolError as error:
+        except xmlrpc_client.ProtocolError as error:
             message = 'Protocol error: %s "%s"' % (
                 error.errcode, error.errmsg)
             raise BugTrackerAuthenticationError(
diff --git a/lib/lp/bugs/externalbugtracker/tests/test_bugzilla.py b/lib/lp/bugs/externalbugtracker/tests/test_bugzilla.py
index 12d5881..92447ac 100644
--- a/lib/lp/bugs/externalbugtracker/tests/test_bugzilla.py
+++ b/lib/lp/bugs/externalbugtracker/tests/test_bugzilla.py
@@ -6,9 +6,9 @@
 __metaclass__ = type
 
 from xml.parsers.expat import ExpatError
-import xmlrpclib
 
 import responses
+from six.moves import xmlrpc_client
 import transaction
 
 from lp.bugs.externalbugtracker.base import UnparsableBugData
@@ -73,11 +73,11 @@ class TestBugzillaSniffing(TestCase):
         # it is taken to mean that no XML-RPC capabilities exist.
         bugzilla = Bugzilla("http://not.real";)
 
-        class Transport(xmlrpclib.Transport):
+        class Transport(xmlrpc_client.Transport):
             def request(self, host, handler, request, verbose=None):
                 raise ExpatError("mismatched tag")
 
-        bugzilla._test_xmlrpc_proxy = xmlrpclib.ServerProxy(
+        bugzilla._test_xmlrpc_proxy = xmlrpc_client.ServerProxy(
             '%s/xmlrpc.cgi' % bugzilla.baseurl, transport=Transport())
 
         # We must abort any existing transactions before attempting to call
diff --git a/lib/lp/bugs/externalbugtracker/tests/test_xmlrpc.py b/lib/lp/bugs/externalbugtracker/tests/test_xmlrpc.py
index 6522ab8..3591e98 100644
--- a/lib/lp/bugs/externalbugtracker/tests/test_xmlrpc.py
+++ b/lib/lp/bugs/externalbugtracker/tests/test_xmlrpc.py
@@ -22,15 +22,16 @@ class TestRequestsTransport(TestCase):
 
     @responses.activate
     def test_expat_error(self):
-        # Malformed XML-RPC responses cause xmlrpclib to raise an ExpatError.
+        # Malformed XML-RPC responses cause xmlrpc_client to raise an
+        # ExpatError.
         responses.add(
             "POST", "http://www.example.com/xmlrpc";,
             body="<params><mis></match></params>")
         transport = RequestsTransport("http://not.real/";)
 
         # The Launchpad production environment selects Expat at present. This
-        # is quite strict compared to the other parsers that xmlrpclib can
-        # possibly select.
+        # is quite strict compared to the other parsers that xmlrpc_client
+        # can possibly select.
         ensure_response_parser_is_expat(transport)
 
         self.assertRaises(
diff --git a/lib/lp/bugs/externalbugtracker/trac.py b/lib/lp/bugs/externalbugtracker/trac.py
index 895f1aa..d10d8f2 100644
--- a/lib/lp/bugs/externalbugtracker/trac.py
+++ b/lib/lp/bugs/externalbugtracker/trac.py
@@ -10,12 +10,12 @@ import csv
 from datetime import datetime
 from email.utils import parseaddr
 import time
-import xmlrpclib
 
 from mimeparse import parse_mime_type
 import pytz
 import requests
 from requests.cookies import RequestsCookieJar
+from six.moves import xmlrpc_client
 from zope.component import getUtility
 from zope.interface import implementer
 
@@ -304,14 +304,14 @@ class Trac(ExternalBugTracker):
 def needs_authentication(func):
     """Decorator for automatically authenticating if needed.
 
-    If an `xmlrpclib.ProtocolError` with error code 403 is raised by the
+    If an `xmlrpc_client.ProtocolError` with error code 403 is raised by the
     function, we'll try to authenticate and call the function again.
     """
 
     def decorator(self, *args, **kwargs):
         try:
             return func(self, *args, **kwargs)
-        except xmlrpclib.ProtocolError as error:
+        except xmlrpc_client.ProtocolError as error:
             # Catch authentication errors only.
             if error.errcode != 403:
                 raise
@@ -339,7 +339,7 @@ class TracLPPlugin(Trac):
         self._internal_xmlrpc_transport = internal_xmlrpc_transport
 
         xmlrpc_endpoint = urlappend(self.baseurl, 'xmlrpc')
-        self._server = xmlrpclib.ServerProxy(
+        self._server = xmlrpc_client.ServerProxy(
             xmlrpc_endpoint, transport=self._xmlrpc_transport)
 
     def makeRequest(self, method, url, **kwargs):
@@ -364,7 +364,7 @@ class TracLPPlugin(Trac):
     @ensure_no_transaction
     def _generateAuthenticationToken(self):
         """Create an authentication token and return it."""
-        internal_xmlrpc = xmlrpclib.ServerProxy(
+        internal_xmlrpc = xmlrpc_client.ServerProxy(
             config.checkwatches.xmlrpc_url,
             transport=self._internal_xmlrpc_transport)
         return internal_xmlrpc.newBugTrackerToken()
@@ -490,7 +490,7 @@ class TracLPPlugin(Trac):
         try:
             timestamp, lp_bug_id = self._server.launchpad.get_launchpad_bug(
                 remote_bug)
-        except xmlrpclib.Fault as fault:
+        except xmlrpc_client.Fault as fault:
             # Deal with "Ticket does not exist" faults. We re-raise
             # anything else, since they're a sign of a bigger problem.
             if fault.faultCode == FAULT_TICKET_NOT_FOUND:
@@ -521,7 +521,7 @@ class TracLPPlugin(Trac):
         try:
             self._server.launchpad.set_launchpad_bug(
                 remote_bug, launchpad_bug_id)
-        except xmlrpclib.Fault as fault:
+        except xmlrpc_client.Fault as fault:
             # Deal with "Ticket does not exist" faults. We re-raise
             # anything else, since they're a sign of a bigger problem.
             if fault.faultCode == FAULT_TICKET_NOT_FOUND:
diff --git a/lib/lp/bugs/externalbugtracker/xmlrpc.py b/lib/lp/bugs/externalbugtracker/xmlrpc.py
index 6257d52..d82f03a 100644
--- a/lib/lp/bugs/externalbugtracker/xmlrpc.py
+++ b/lib/lp/bugs/externalbugtracker/xmlrpc.py
@@ -10,10 +10,6 @@ __all__ = [
 
 
 from io import BytesIO
-from xmlrpclib import (
-    ProtocolError,
-    Transport,
-    )
 
 from defusedxml.xmlrpc import monkey_patch
 import requests
@@ -23,6 +19,10 @@ from six.moves.urllib.parse import (
     urlparse,
     urlunparse,
     )
+from six.moves.xmlrpc_client import (
+    ProtocolError,
+    Transport,
+    )
 
 from lp.bugs.externalbugtracker.base import repost_on_redirect_hook
 from lp.services.config import config
diff --git a/lib/lp/bugs/scripts/checkwatches/core.py b/lib/lp/bugs/scripts/checkwatches/core.py
index 5d47b6e..e3c41f6 100644
--- a/lib/lp/bugs/scripts/checkwatches/core.py
+++ b/lib/lp/bugs/scripts/checkwatches/core.py
@@ -28,9 +28,9 @@ import socket
 import sys
 import threading
 import time
-from xmlrpclib import ProtocolError
 
 import pytz
+from six.moves.xmlrpc_client import ProtocolError
 from twisted.internet import reactor
 from twisted.internet.defer import DeferredList
 from twisted.internet.threads import deferToThreadPool
diff --git a/lib/lp/bugs/scripts/checkwatches/tests/test_core.py b/lib/lp/bugs/scripts/checkwatches/tests/test_core.py
index f92f606..ba87699 100644
--- a/lib/lp/bugs/scripts/checkwatches/tests/test_core.py
+++ b/lib/lp/bugs/scripts/checkwatches/tests/test_core.py
@@ -7,8 +7,8 @@ __metaclass__ = type
 from datetime import datetime
 import threading
 import unittest
-from xmlrpclib import ProtocolError
 
+from six.moves.xmlrpc_client import ProtocolError
 import transaction
 from zope.component import getUtility
 
diff --git a/lib/lp/bugs/scripts/checkwatches/utilities.py b/lib/lp/bugs/scripts/checkwatches/utilities.py
index bd04094..ad149a2 100644
--- a/lib/lp/bugs/scripts/checkwatches/utilities.py
+++ b/lib/lp/bugs/scripts/checkwatches/utilities.py
@@ -10,7 +10,8 @@ __all__ = [
     ]
 
 import socket
-from xmlrpclib import ProtocolError
+
+from six.moves.xmlrpc_client import ProtocolError
 
 from lp.bugs.externalbugtracker import (
     BugNotFound,
diff --git a/lib/lp/bugs/stories/bugtracker/xx-bugtracker-handshake-tokens.txt b/lib/lp/bugs/stories/bugtracker/xx-bugtracker-handshake-tokens.txt
index 8586bc6..5474381 100644
--- a/lib/lp/bugs/stories/bugtracker/xx-bugtracker-handshake-tokens.txt
+++ b/lib/lp/bugs/stories/bugtracker/xx-bugtracker-handshake-tokens.txt
@@ -4,9 +4,9 @@ Launchpad can generate LoginTokens which can then be used to
 authenticate it with remote bug trackers. Generating these tokens is
 done using the internal XML-RPC service.
 
-    >>> import xmlrpclib
+    >>> from six.moves import xmlrpc_client
     >>> from lp.testing.xmlrpc import XMLRPCTestTransport
-    >>> bugtracker_api = xmlrpclib.ServerProxy(
+    >>> bugtracker_api = xmlrpc_client.ServerProxy(
     ...     'http://xmlrpc-private.launchpad.test:8087/bugs',
     ...     transport=XMLRPCTestTransport())
 
diff --git a/lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt b/lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt
index b88517f..c2c0c45 100644
--- a/lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt
+++ b/lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt
@@ -9,12 +9,12 @@ very similar to the TestBugzillaXMLRPCTransport, which it subclasses.
 Only the parts of TestBugzillaAPIXMLRPCTransport that are different from
 its ancestor will be tested here.
 
-    >>> import xmlrpclib
+    >>> from six.moves import xmlrpc_client
     >>> from lp.bugs.tests.externalbugtracker import (
     ...     TestBugzillaAPIXMLRPCTransport)
     >>> bugzilla_transport = TestBugzillaAPIXMLRPCTransport(
     ...     'http://example.com/xmlrpc.cgi')
-    >>> server = xmlrpclib.ServerProxy(
+    >>> server = xmlrpc_client.ServerProxy(
     ...     'http://example.com/xmlrpc.cgi', transport=bugzilla_transport)
 
 
diff --git a/lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt b/lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt
index a90478a..078bad7 100644
--- a/lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt
+++ b/lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt
@@ -4,12 +4,12 @@ TestBugzillaXMLRPCTransport
 The TestBugzillaXMLRPCTransport is an XML-RPC transport which simulates
 a remote Bugzilla instance that implements the Launchpad plugin API.
 
-    >>> import xmlrpclib
+    >>> from six.moves import xmlrpc_client
     >>> from lp.bugs.tests.externalbugtracker import (
     ...     TestBugzillaXMLRPCTransport)
     >>> bugzilla_transport = TestBugzillaXMLRPCTransport(
     ...     'http://example.com/xmlrpc.cgi')
-    >>> server = xmlrpclib.ServerProxy(
+    >>> server = xmlrpc_client.ServerProxy(
     ...     'http://example.com/xmlrpc.cgi', transport=bugzilla_transport)
 
 The test transport will only allow calls to methods in a predefined set
diff --git a/lib/lp/bugs/tests/externalbugtracker-xmlrpc-transport.txt b/lib/lp/bugs/tests/externalbugtracker-xmlrpc-transport.txt
index f5c1d7c..4b9c6cb 100644
--- a/lib/lp/bugs/tests/externalbugtracker-xmlrpc-transport.txt
+++ b/lib/lp/bugs/tests/externalbugtracker-xmlrpc-transport.txt
@@ -71,7 +71,7 @@ In addition to cookies sent by the server, we can set cookies locally.
     foo=bar
 
 If an error occurs trying to make the request, an
-``xmlrpclib.ProtocolError`` is raised.
+``xmlrpc_client.ProtocolError`` is raised.
 
     >>> request_body = """<?xml version="1.0"?>
     ... <methodCall>
diff --git a/lib/lp/bugs/tests/externalbugtracker.py b/lib/lp/bugs/tests/externalbugtracker.py
index 7802c56..b8a5b9d 100644
--- a/lib/lp/bugs/tests/externalbugtracker.py
+++ b/lib/lp/bugs/tests/externalbugtracker.py
@@ -15,9 +15,9 @@ import os
 import random
 import re
 import time
-import xmlrpclib
 
 import responses
+from six.moves import xmlrpc_client
 from six.moves.urllib_parse import (
     parse_qs,
     urljoin,
@@ -564,7 +564,7 @@ class TestBugzillaXMLRPCTransport(RequestsTransport):
         method on this class with the same name as the XML-RPC method is
         called, with the extracted arguments passed on to it.
         """
-        args, method_name = xmlrpclib.loads(request)
+        args, method_name = xmlrpc_client.loads(request)
         method_prefix, method_name = method_name.split('.')
 
         assert method_prefix in self.methods, (
@@ -579,7 +579,7 @@ class TestBugzillaXMLRPCTransport(RequestsTransport):
         # cookie, throw a Fault.
         if (method_name in self.auth_required_methods and
             not self.has_valid_auth_cookie):
-            raise xmlrpclib.Fault(410, 'Login Required')
+            raise xmlrpc_client.Fault(410, 'Login Required')
 
         if self.print_method_calls:
             if len(args) > 0:
@@ -638,7 +638,7 @@ class TestBugzillaXMLRPCTransport(RequestsTransport):
         self._setAuthCookie()
 
         # We always return the same user ID.
-        # This has to be listified because xmlrpclib tries to expand
+        # This has to be listified because xmlrpc_client tries to expand
         # sequences of length 1.
         return [{'user_id': 42}]
 
@@ -762,7 +762,7 @@ class TestBugzillaXMLRPCTransport(RequestsTransport):
 
         # If the bug doesn't exist, raise a fault.
         if int(bug_id) not in self.bugs:
-            raise xmlrpclib.Fault(101, "Bug #%s does not exist." % bug_id)
+            raise xmlrpc_client.Fault(101, "Bug #%s does not exist." % bug_id)
 
         # If we don't have comments for the bug already, create an empty
         # comment dict.
@@ -790,7 +790,7 @@ class TestBugzillaXMLRPCTransport(RequestsTransport):
 
         self.comment_id_index = comment_id
 
-        # We have to return a list here because xmlrpclib will try to
+        # We have to return a list here because xmlrpc_client will try to
         # expand sequences of length 1. Trying to do that on a dict will
         # cause it to explode.
         return [{'comment_id': comment_id}]
@@ -810,7 +810,7 @@ class TestBugzillaXMLRPCTransport(RequestsTransport):
         old_launchpad_id = bug['internals'].get('launchpad_id', 0)
         bug['internals']['launchpad_id'] = launchpad_id
 
-        # We need to return a list here because xmlrpclib will try to
+        # We need to return a list here because xmlrpc_client will try to
         # expand sequences of length 1, which will fail horribly when
         # the sequence is in fact a dict.
         return [{'launchpad_id': old_launchpad_id}]
@@ -908,7 +908,7 @@ class TestBugzillaAPIXMLRPCTransport(TestBugzillaXMLRPCTransport):
 
     def version(self):
         """Return the version of Bugzilla being used."""
-        # This is to work around the old "xmlrpclib tries to expand
+        # This is to work around the old "xmlrpc_client tries to expand
         # sequences of length 1" problem (see above).
         return [{'version': '3.4.1+'}]
 
@@ -924,7 +924,7 @@ class TestBugzillaAPIXMLRPCTransport(TestBugzillaXMLRPCTransport):
                 self._setAuthCookie()
                 return [{'id': self.users.index(user)}]
             else:
-                raise xmlrpclib.Fault(
+                raise xmlrpc_client.Fault(
                     300,
                     "The username or password you entered is not valid.")
 
@@ -1043,7 +1043,7 @@ class TestBugzillaAPIXMLRPCTransport(TestBugzillaXMLRPCTransport):
 
         # If the bug doesn't exist, raise a fault.
         if int(bug_id) not in self.bugs:
-            raise xmlrpclib.Fault(101, "Bug #%s does not exist." % bug_id)
+            raise xmlrpc_client.Fault(101, "Bug #%s does not exist." % bug_id)
 
         # If we don't have comments for the bug already, create an empty
         # comment dict.
@@ -1072,7 +1072,7 @@ class TestBugzillaAPIXMLRPCTransport(TestBugzillaXMLRPCTransport):
 
         self.comment_id_index = comment_id
 
-        # We have to return a list here because xmlrpclib will try to
+        # We have to return a list here because xmlrpc_client will try to
         # expand sequences of length 1. Trying to do that on a dict will
         # cause it to explode.
         return [{'id': comment_id}]
@@ -1091,7 +1091,8 @@ class TestBugzillaAPIXMLRPCTransport(TestBugzillaXMLRPCTransport):
 
             # If the bug ID doesn't exist, raise a Fault.
             if bug_id not in self.bugs:
-                raise xmlrpclib.Fault(101, "Bug #%s does not exist." % bug_id)
+                raise xmlrpc_client.Fault(
+                    101, "Bug #%s does not exist." % bug_id)
 
             see_also_list = self.bugs[bug_id].get('see_also', [])
 
@@ -1121,7 +1122,7 @@ class TestBugzillaAPIXMLRPCTransport(TestBugzillaXMLRPCTransport):
 
                 if ('launchpad' not in url and
                     'show_bug.cgi' not in url):
-                    raise xmlrpclib.Fault(
+                    raise xmlrpc_client.Fault(
                         112, "Bug URL %s is invalid." % url)
 
                 if changes.get(bug_id) is None:
@@ -1139,7 +1140,7 @@ class TestBugzillaAPIXMLRPCTransport(TestBugzillaXMLRPCTransport):
             # Replace the bug's existing see_also list.
             self.bugs[bug_id]['see_also'] = see_also_list
 
-        # We have to return a list here because xmlrpclib will try to
+        # We have to return a list here because xmlrpc_client will try to
         # expand sequences of length 1. Trying to do that on a dict will
         # cause it to explode.
         return [{'changes': changes}]
@@ -1266,7 +1267,7 @@ class TestInternalXMLRPCTransport:
         self.quiet = quiet
 
     def request(self, host, handler, request, verbose=None):
-        args, method_name = xmlrpclib.loads(request)
+        args, method_name = xmlrpc_client.loads(request)
         method = getattr(self, method_name)
         with lp_dbuser():
             return method(*args)
@@ -1326,14 +1327,14 @@ class TestTracXMLRPCTransport(RequestsTransport):
         """
         assert handler.endswith('/xmlrpc'), (
             'The Trac endpoint must end with /xmlrpc')
-        args, method_name = xmlrpclib.loads(request)
+        args, method_name = xmlrpc_client.loads(request)
         prefix = 'launchpad.'
         assert method_name.startswith(prefix), (
             'All methods should be in the launchpad namespace')
         if (self.auth_cookie is None or
             self.auth_cookie == self.expired_cookie):
             # All the Trac XML-RPC methods need authentication.
-            raise xmlrpclib.ProtocolError(
+            raise xmlrpc_client.ProtocolError(
                 method_name, errcode=403, errmsg="Forbidden",
                 headers=None)
 
@@ -1520,7 +1521,7 @@ class TestTracXMLRPCTransport(RequestsTransport):
         return 0. Otherwise return the mapped Launchpad bug ID.
         """
         if bugid not in self.remote_bugs:
-            raise xmlrpclib.Fault(
+            raise xmlrpc_client.Fault(
                 FAULT_TICKET_NOT_FOUND, 'Ticket does not exist')
 
         return [self.utc_time, self.launchpad_bugs.get(bugid, 0)]
@@ -1534,12 +1535,12 @@ class TestTracXMLRPCTransport(RequestsTransport):
         Return the current UTC timestamp.
         """
         if bugid not in self.remote_bugs:
-            raise xmlrpclib.Fault(
+            raise xmlrpc_client.Fault(
                 FAULT_TICKET_NOT_FOUND, 'Ticket does not exist')
 
         self.launchpad_bugs[bugid] = launchpad_bug
 
-        # Return a list, since xmlrpclib insists on trying to expand
+        # Return a list, since xmlrpc_client insists on trying to expand
         # results.
         return [self.utc_time]
 
@@ -1695,17 +1696,17 @@ class TestDebBugs(DebBugs):
 def ensure_response_parser_is_expat(transport):
     """Ensure the transport always selects the Expat-based response parser.
 
-    The response parser is chosen by xmlrpclib at runtime from a number of
-    choices, but the main Launchpad production environment selects Expat at
-    present.
+    The response parser is chosen by xmlrpc_client at runtime from a number
+    of choices, but the main Launchpad production environment selects Expat
+    at present.
 
     Developer's machines could have other packages, `python-reportlab-accel`
     (which provides the `sgmlop` module) for example, that cause different
     response parsers to be chosen.
     """
     def getparser():
-        target = xmlrpclib.Unmarshaller(
+        target = xmlrpc_client.Unmarshaller(
             use_datetime=transport._use_datetime)
-        parser = xmlrpclib.ExpatParser(target)
+        parser = xmlrpc_client.ExpatParser(target)
         return parser, target
     transport.getparser = getparser
diff --git a/lib/lp/bugs/tests/trac-xmlrpc-transport.txt b/lib/lp/bugs/tests/trac-xmlrpc-transport.txt
index cf64146..baa4880 100644
--- a/lib/lp/bugs/tests/trac-xmlrpc-transport.txt
+++ b/lib/lp/bugs/tests/trac-xmlrpc-transport.txt
@@ -5,11 +5,11 @@ Trac plugin. It can be used to avoid network traffic while testing, and
 it implements the same API that Trac instances having the LP plugin
 installed implement.
 
-    >>> import xmlrpclib
+    >>> from six.moves import xmlrpc_client
     >>> from lp.bugs.tests.externalbugtracker import (
     ...     TestTracXMLRPCTransport)
     >>> trac_transport = TestTracXMLRPCTransport('http://example.com/xmlrpc')
-    >>> server = xmlrpclib.ServerProxy(
+    >>> server = xmlrpc_client.ServerProxy(
     ...     'http://example.com/xmlrpc', transport=trac_transport)
 
 All the methods need an authentication cookie to be sent.
diff --git a/lib/lp/buildmaster/model/buildqueue.py b/lib/lp/buildmaster/model/buildqueue.py
index fe9fad4..2af380a 100644
--- a/lib/lp/buildmaster/model/buildqueue.py
+++ b/lib/lp/buildmaster/model/buildqueue.py
@@ -186,7 +186,7 @@ class BuildQueue(SQLBase):
         if builder_status == "BuilderStatus.ABORTING":
             self.logtail = "Waiting for slave process to be terminated"
         elif slave_status.get("logtail") is not None:
-            # slave_status["logtail"] is normally an xmlrpclib.Binary
+            # slave_status["logtail"] is normally an xmlrpc_client.Binary
             # instance, and the contents might include invalid UTF-8 due to
             # being a fixed number of bytes from the tail of the log.  Turn
             # it into Unicode as best we can.
diff --git a/lib/lp/buildmaster/tests/mock_slaves.py b/lib/lp/buildmaster/tests/mock_slaves.py
index 8b00c32..a19a85d 100644
--- a/lib/lp/buildmaster/tests/mock_slaves.py
+++ b/lib/lp/buildmaster/tests/mock_slaves.py
@@ -24,10 +24,10 @@ __all__ = [
 import os
 import sys
 import types
-import xmlrpclib
 
 import fixtures
 from lpbuildd.tests.harness import BuilddSlaveTestSetup
+from six.moves import xmlrpc_client
 from testtools.content import Content
 from testtools.content_type import UTF8_TEXT
 from twisted.internet import defer
@@ -159,7 +159,7 @@ class BuildingSlave(OkSlave):
 
     def status(self):
         self.call_log.append('status')
-        buildlog = xmlrpclib.Binary(
+        buildlog = xmlrpc_client.Binary(
             "This is a build log: %d" % self.status_count)
         self.status_count += 1
         return defer.succeed({
@@ -231,7 +231,7 @@ class AbortingSlave(OkSlave):
 class LostBuildingBrokenSlave:
     """A mock slave building bogus Build/BuildQueue IDs that can't be aborted.
 
-    When 'aborted' it raises an xmlrpclib.Fault(8002, 'Could not abort')
+    When 'aborted' it raises an xmlrpc_client.Fault(8002, 'Could not abort')
     """
 
     def __init__(self):
@@ -246,7 +246,7 @@ class LostBuildingBrokenSlave:
 
     def abort(self):
         self.call_log.append('abort')
-        return defer.fail(xmlrpclib.Fault(8002, "Could not abort"))
+        return defer.fail(xmlrpc_client.Fault(8002, "Could not abort"))
 
     def resume(self):
         self.call_log.append('resume')
@@ -261,7 +261,7 @@ class BrokenSlave:
 
     def status(self):
         self.call_log.append('status')
-        return defer.fail(xmlrpclib.Fault(8001, "Broken slave"))
+        return defer.fail(xmlrpc_client.Fault(8001, "Broken slave"))
 
 
 class TrivialBehaviour:
diff --git a/lib/lp/buildmaster/tests/test_interactor.py b/lib/lp/buildmaster/tests/test_interactor.py
index 4327116..8514bb5 100644
--- a/lib/lp/buildmaster/tests/test_interactor.py
+++ b/lib/lp/buildmaster/tests/test_interactor.py
@@ -14,10 +14,10 @@ import hashlib
 import os
 import signal
 import tempfile
-import xmlrpclib
 
 from lpbuildd.slave import BuilderStatus
 from lpbuildd.tests.harness import BuilddSlaveTestSetup
+from six.moves import xmlrpc_client
 from testtools.matchers import (
     ContainsAll,
     HasLength,
@@ -293,7 +293,7 @@ class TestBuilderInteractorCleanSlave(TestCase):
         try:
             yield BuilderInteractor.cleanSlave(
                 vitals, slave, MockBuilderFactory(builder, None))
-        except xmlrpclib.Fault:
+        except xmlrpc_client.Fault:
             self.assertEqual(['status', 'abort'], slave.call_log)
         else:
             self.fail("abort() should crash.")
@@ -327,7 +327,7 @@ class TestBuilderSlaveStatus(TestCase):
             del status["build_id"]
         if logtail:
             tail = status.pop("logtail")
-            self.assertIsInstance(tail, xmlrpclib.Binary)
+            self.assertIsInstance(tail, xmlrpc_client.Binary)
 
         self.assertEqual(expected, status)
 
@@ -546,7 +546,7 @@ class TestSlave(TestCase):
         status = yield slave.status()
         self.assertEqual(BuilderStatus.BUILDING, status['builder_status'])
         self.assertEqual(build_id, status['build_id'])
-        self.assertIsInstance(status['logtail'], xmlrpclib.Binary)
+        self.assertIsInstance(status['logtail'], xmlrpc_client.Binary)
 
     def test_ensurepresent_not_there(self):
         # ensurepresent checks to see if a file is there.
diff --git a/lib/lp/buildmaster/tests/test_manager.py b/lib/lp/buildmaster/tests/test_manager.py
index f645e25..491d2d5 100644
--- a/lib/lp/buildmaster/tests/test_manager.py
+++ b/lib/lp/buildmaster/tests/test_manager.py
@@ -12,8 +12,8 @@ from __future__ import absolute_import, print_function, unicode_literals
 import os
 import signal
 import time
-import xmlrpclib
 
+from six.moves import xmlrpc_client
 from testtools.matchers import Equals
 from testtools.testcase import ExpectedException
 from testtools.twistedsupport import (
@@ -316,7 +316,7 @@ class TestSlaveScannerScan(TestCaseWithFactory):
         transaction.commit()
         scanner = self._getScanner(builder_name=builder.name)
         d = scanner.scan()
-        return assert_fails_with(d, xmlrpclib.Fault)
+        return assert_fails_with(d, xmlrpc_client.Fault)
 
     def test_scan_of_partial_utf8_logtail(self):
         # The builder returns a fixed number of bytes from the tail of the
@@ -325,7 +325,7 @@ class TestSlaveScannerScan(TestCaseWithFactory):
             @defer.inlineCallbacks
             def status(self):
                 status = yield super(BrokenUTF8Slave, self).status()
-                status["logtail"] = xmlrpclib.Binary(
+                status["logtail"] = xmlrpc_client.Binary(
                     u"───".encode("UTF-8")[1:])
                 defer.returnValue(status)
 
@@ -354,7 +354,7 @@ class TestSlaveScannerScan(TestCaseWithFactory):
             @defer.inlineCallbacks
             def status(self):
                 status = yield super(NULSlave, self).status()
-                status["logtail"] = xmlrpclib.Binary(b"foo\0bar\0baz")
+                status["logtail"] = xmlrpc_client.Binary(b"foo\0bar\0baz")
                 defer.returnValue(status)
 
         builder = getUtility(IBuilderSet)[BOB_THE_BUILDER_NAME]
@@ -1087,7 +1087,7 @@ class TestCancellationChecking(TestCaseWithFactory):
         slave = LostBuildingBrokenSlave()
         self.builder.current_build.cancel()
         with ExpectedException(
-                xmlrpclib.Fault, "<Fault 8002: u'Could not abort'>"):
+                xmlrpc_client.Fault, "<Fault 8002: u'Could not abort'>"):
             yield self._getScanner().checkCancellation(self.vitals, slave)
 
 
diff --git a/lib/lp/code/doc/branch-xmlrpc.txt b/lib/lp/code/doc/branch-xmlrpc.txt
index dc6b227..e7da5ad 100644
--- a/lib/lp/code/doc/branch-xmlrpc.txt
+++ b/lib/lp/code/doc/branch-xmlrpc.txt
@@ -1,7 +1,7 @@
 IPublicCodehostingAPI
 =====================
 
-    >>> import xmlrpclib
+    >>> from six.moves import xmlrpc_client
     >>> from lp.testing.xmlrpc import XMLRPCTestTransport
 
 
@@ -17,7 +17,7 @@ Bazaar is strictly unsupported.
 This API is deprecated, and will eventually be replaced with an
 equivalent method in the new Launchpad API infrastructure.
 
-    >>> public_codehosting_api = xmlrpclib.ServerProxy(
+    >>> public_codehosting_api = xmlrpc_client.ServerProxy(
     ...     'http://xmlrpc.launchpad.test/bazaar/',
     ...     transport=XMLRPCTestTransport())
 
diff --git a/lib/lp/code/doc/xmlrpc-codeimport-scheduler.txt b/lib/lp/code/doc/xmlrpc-codeimport-scheduler.txt
index e4bb535..0b6404d 100644
--- a/lib/lp/code/doc/xmlrpc-codeimport-scheduler.txt
+++ b/lib/lp/code/doc/xmlrpc-codeimport-scheduler.txt
@@ -42,9 +42,9 @@ can be found in the tests for ICodeImportJobSet.
 
 The point of all this is for it to be accessed over XMLRPC.
 
-    >>> import xmlrpclib
+    >>> from six.moves import xmlrpc_client
     >>> from lp.testing.xmlrpc import XMLRPCTestTransport
-    >>> codeimportscheduler = xmlrpclib.ServerProxy(
+    >>> codeimportscheduler = xmlrpc_client.ServerProxy(
     ...     'http://xmlrpc-private.launchpad.test:8087/codeimportscheduler',
     ...     transport=XMLRPCTestTransport())
     >>> codeimportscheduler.getJobForMachine('bazaar-importer', 2)
diff --git a/lib/lp/code/xmlrpc/branch.py b/lib/lp/code/xmlrpc/branch.py
index bd45c11..d15a335 100644
--- a/lib/lp/code/xmlrpc/branch.py
+++ b/lib/lp/code/xmlrpc/branch.py
@@ -10,7 +10,7 @@ __all__ = [
     ]
 
 
-from xmlrpclib import Fault
+from six.moves.xmlrpc_client import Fault
 
 from breezy import urlutils
 from zope.component import getUtility
diff --git a/lib/lp/code/xmlrpc/tests/test_branch.py b/lib/lp/code/xmlrpc/tests/test_branch.py
index d035177..2affa3a 100644
--- a/lib/lp/code/xmlrpc/tests/test_branch.py
+++ b/lib/lp/code/xmlrpc/tests/test_branch.py
@@ -6,10 +6,10 @@
 __metaclass__ = type
 
 import os
-import xmlrpclib
 
 from breezy import urlutils
 from lazr.uri import URI
+from six.moves import xmlrpc_client
 from zope.security.proxy import removeSecurityProxy
 
 from lp.app.enums import InformationType
@@ -81,7 +81,7 @@ class TestExpandURL(TestCaseWithFactory):
         api = PublicCodehostingAPI(None, None)
         fault = api.resolve_lp_path(lp_url_path)
         self.assertTrue(
-            isinstance(fault, xmlrpclib.Fault),
+            isinstance(fault, xmlrpc_client.Fault),
             "resolve_lp_path(%r) returned %r, not a Fault."
             % (lp_url_path, fault))
         self.assertEqual(expected_fault.__class__, fault.__class__)
diff --git a/lib/lp/code/xmlrpc/tests/test_codeimportscheduler.py b/lib/lp/code/xmlrpc/tests/test_codeimportscheduler.py
index e2b8d7a..60ad9ce 100644
--- a/lib/lp/code/xmlrpc/tests/test_codeimportscheduler.py
+++ b/lib/lp/code/xmlrpc/tests/test_codeimportscheduler.py
@@ -5,8 +5,7 @@
 
 __metaclass__ = type
 
-import xmlrpclib
-
+from six.moves import xmlrpc_client
 from zope.component import getUtility
 from zope.security.proxy import removeSecurityProxy
 
@@ -77,7 +76,7 @@ class TestCodeImportSchedulerAPI(TestCaseWithFactory):
         # is no code import job with the given ID.
         fault = self.api.getImportDataForJobID(-1)
         self.assertTrue(
-            isinstance(fault, xmlrpclib.Fault),
+            isinstance(fault, xmlrpc_client.Fault),
             "getImportDataForJobID(-1) returned %r, not a Fault."
             % (fault,))
         self.assertEqual(NoSuchCodeImportJob, fault.__class__)
@@ -96,7 +95,7 @@ class TestCodeImportSchedulerAPI(TestCaseWithFactory):
         # code import job with the given ID.
         fault = self.api.updateHeartbeat(-1, '')
         self.assertTrue(
-            isinstance(fault, xmlrpclib.Fault),
+            isinstance(fault, xmlrpc_client.Fault),
             "updateHeartbeat(-1, '') returned %r, not a Fault."
             % (fault,))
         self.assertEqual(NoSuchCodeImportJob, fault.__class__)
@@ -131,7 +130,7 @@ class TestCodeImportSchedulerAPI(TestCaseWithFactory):
         fault = self.api.finishJobID(
             -1, CodeImportResultStatus.SUCCESS.name, '')
         self.assertTrue(
-            isinstance(fault, xmlrpclib.Fault),
+            isinstance(fault, xmlrpc_client.Fault),
             "finishJobID(-1, 'SUCCESS', 0) returned %r, not a Fault."
             % (fault,))
         self.assertEqual(NoSuchCodeImportJob, fault.__class__)
diff --git a/lib/lp/codehosting/inmemory.py b/lib/lp/codehosting/inmemory.py
index 2873314..a2a7103 100644
--- a/lib/lp/codehosting/inmemory.py
+++ b/lib/lp/codehosting/inmemory.py
@@ -10,7 +10,7 @@ __all__ = [
     ]
 
 import operator
-from xmlrpclib import Fault
+from six.moves.xmlrpc_client import Fault
 
 from breezy.urlutils import (
     escape,
diff --git a/lib/lp/codehosting/tests/test_acceptance.py b/lib/lp/codehosting/tests/test_acceptance.py
index 23ee03e..38cb7e9 100644
--- a/lib/lp/codehosting/tests/test_acceptance.py
+++ b/lib/lp/codehosting/tests/test_acceptance.py
@@ -11,13 +11,13 @@ import signal
 import subprocess
 import sys
 import time
-import xmlrpclib
 
 import breezy.branch
 from breezy.tests import TestCaseWithTransport
 from breezy.tests.per_repository import all_repository_format_scenarios
 from breezy.urlutils import local_path_from_url
 from breezy.workingtree import WorkingTree
+from six.moves import xmlrpc_client
 from six.moves.urllib.request import urlopen
 from testscenarios import (
     load_tests_apply_scenarios,
@@ -318,9 +318,9 @@ class SSHTestCase(TestCaseWithTransport, LoomTestMixin, TestCaseWithFactory):
         Used to create branches that the test user is not able to create, and
         might not even be able to view.
         """
-        authserver = xmlrpclib.ServerProxy(
+        authserver = xmlrpc_client.ServerProxy(
             config.codehosting.authentication_endpoint)
-        codehosting_api = xmlrpclib.ServerProxy(
+        codehosting_api = xmlrpc_client.ServerProxy(
             config.codehosting.codehosting_endpoint)
         if creator is None:
             creator_id = authserver.getUserAndSSHKeys(user)['id']
diff --git a/lib/lp/codehosting/vfs/branchfs.py b/lib/lp/codehosting/vfs/branchfs.py
index 92d4b3f..c984771 100644
--- a/lib/lp/codehosting/vfs/branchfs.py
+++ b/lib/lp/codehosting/vfs/branchfs.py
@@ -56,7 +56,6 @@ __all__ = [
 
 import os.path
 import sys
-import xmlrpclib
 
 from breezy import urlutils
 from breezy.bzr.bzrdir import BzrDir
@@ -72,6 +71,7 @@ from breezy.transport import get_transport
 from breezy.transport.memory import MemoryServer
 from lazr.uri import URI
 import six
+from six.moves import xmlrpc_client
 from twisted.internet import (
     defer,
     error,
@@ -171,7 +171,7 @@ def is_lock_directory(absolute_path):
 
 def get_ro_server():
     """Get a Launchpad internal server for scanning branches."""
-    proxy = xmlrpclib.ServerProxy(config.codehosting.codehosting_endpoint)
+    proxy = xmlrpc_client.ServerProxy(config.codehosting.codehosting_endpoint)
     codehosting_endpoint = DeferredBlockingProxy(proxy)
     branch_transport = get_readonly_transport(
         get_transport(config.codehosting.internal_branch_by_id_root))
@@ -194,7 +194,8 @@ def get_rw_server(direct_database=False):
     if direct_database:
         return DirectDatabaseLaunchpadServer('lp-internal:///', transport)
     else:
-        proxy = xmlrpclib.ServerProxy(config.codehosting.codehosting_endpoint)
+        proxy = xmlrpc_client.ServerProxy(
+            config.codehosting.codehosting_endpoint)
         codehosting_endpoint = DeferredBlockingProxy(proxy)
         return LaunchpadInternalServer(
             'lp-internal:///', codehosting_endpoint, transport)
@@ -749,7 +750,7 @@ def get_lp_server(user_id, codehosting_endpoint_url=None, branch_url=None,
             raise AssertionError(
                 "can't supply both branch_url and branch_transport!")
 
-    codehosting_client = xmlrpclib.ServerProxy(codehosting_endpoint_url)
+    codehosting_client = xmlrpc_client.ServerProxy(codehosting_endpoint_url)
     lp_server = LaunchpadServer(
         DeferredBlockingProxy(codehosting_client), user_id, branch_transport,
         seen_new_branch_hook)
diff --git a/lib/lp/codehosting/vfs/tests/test_branchfs.py b/lib/lp/codehosting/vfs/tests/test_branchfs.py
index eba8732..0aa7fe7 100644
--- a/lib/lp/codehosting/vfs/tests/test_branchfs.py
+++ b/lib/lp/codehosting/vfs/tests/test_branchfs.py
@@ -10,7 +10,6 @@ import os
 import re
 from StringIO import StringIO
 import sys
-import xmlrpclib
 
 from breezy import errors
 from breezy.bzr.bzrdir import BzrDir
@@ -36,6 +35,7 @@ from breezy.urlutils import (
     escape,
     local_path_to_url,
     )
+from six.moves import xmlrpc_client
 from testtools.twistedsupport import (
     assert_fails_with,
     AsynchronousDeferredRunTest,
@@ -1037,7 +1037,7 @@ class TestBranchChangedErrorHandling(TestCaseWithTransport, TestCase):
             report = errorlog.globalErrorUtility.raising(f, request)
             # Record the id for checking later.
             self.generated_oopsids.append(report['id'])
-            raise xmlrpclib.Fault(-1, report)
+            raise xmlrpc_client.Fault(-1, report)
 
     def get_server(self):
         if self._server is None:
diff --git a/lib/lp/registry/tests/mailinglists_helper.py b/lib/lp/registry/tests/mailinglists_helper.py
index 4a51736..bb7942a 100644
--- a/lib/lp/registry/tests/mailinglists_helper.py
+++ b/lib/lp/registry/tests/mailinglists_helper.py
@@ -11,9 +11,7 @@ __all__ = [
     'new_team',
     ]
 
-
-import xmlrpclib
-
+from six.moves import xmlrpc_client
 from zope.component import getUtility
 
 from lp.registry.enums import TeamMembershipPolicy
@@ -39,7 +37,7 @@ def fault_catcher(func):
 
     def caller(self, *args, **kws):
         result = func(self, *args, **kws)
-        if isinstance(result, xmlrpclib.Fault):
+        if isinstance(result, xmlrpc_client.Fault):
             raise result
         else:
             return result
diff --git a/lib/lp/registry/tests/test_mailinglistapi.py b/lib/lp/registry/tests/test_mailinglistapi.py
index 8b90ce2..e967e3e 100644
--- a/lib/lp/registry/tests/test_mailinglistapi.py
+++ b/lib/lp/registry/tests/test_mailinglistapi.py
@@ -8,13 +8,13 @@ __all__ = []
 
 from email import message_from_string
 from textwrap import dedent
-import xmlrpclib
 
 from testtools.matchers import (
     Equals,
     MatchesDict,
     MatchesSetwise,
     )
+from six.moves import xmlrpc_client
 import transaction
 from zope.component import getUtility
 from zope.security.proxy import removeSecurityProxy
@@ -496,7 +496,7 @@ class MailingListAPIMessageTestCase(TestCaseWithFactory):
                 I put \xa9 in the body.
                 """))
         info = self.mailinglist_api.holdMessage(
-            'team', xmlrpclib.Binary(message.as_string()))
+            'team', xmlrpc_client.Binary(message.as_string()))
         transaction.commit()
         found = self.message_approval_set.getMessageByMessageID('<\\xa9-me>')
         self.assertIs(True, info)
diff --git a/lib/lp/registry/tests/test_xmlrpc.py b/lib/lp/registry/tests/test_xmlrpc.py
index 1223cc3..5217f8c 100644
--- a/lib/lp/registry/tests/test_xmlrpc.py
+++ b/lib/lp/registry/tests/test_xmlrpc.py
@@ -5,8 +5,7 @@
 
 __metaclass__ = type
 
-import xmlrpclib
-
+from six.moves import xmlrpc_client
 from zope.security.proxy import removeSecurityProxy
 
 from lp.registry.enums import PersonVisibility
@@ -21,7 +20,7 @@ class TestCanonicalSSOApplication(TestCaseWithFactory):
 
     def setUp(self):
         super(TestCanonicalSSOApplication, self).setUp()
-        self.rpc_proxy = xmlrpclib.ServerProxy(
+        self.rpc_proxy = xmlrpc_client.ServerProxy(
             'http://xmlrpc-private.launchpad.test:8087/canonicalsso',
             transport=XMLRPCTestTransport())
 
@@ -50,12 +49,12 @@ class TestCanonicalSSOApplication(TestCaseWithFactory):
         person = self.factory.makePerson()
         openid_identifier = removeSecurityProxy(
             person.account).openid_identifiers.any().identifier
-        public_rpc_proxy = xmlrpclib.ServerProxy(
+        public_rpc_proxy = xmlrpc_client.ServerProxy(
             'http://test@xxxxxxxxxxxxx:test@'
             'xmlrpc.launchpad.test/canonicalsso',
             transport=XMLRPCTestTransport())
         e = self.assertRaises(
-            xmlrpclib.ProtocolError,
+            xmlrpc_client.ProtocolError,
             public_rpc_proxy.getPersonDetailsByOpenIDIdentifier,
             openid_identifier)
         self.assertEqual(404, e.errcode)
diff --git a/lib/lp/registry/xmlrpc/mailinglist.py b/lib/lp/registry/xmlrpc/mailinglist.py
index a8545db..9a16123 100644
--- a/lib/lp/registry/xmlrpc/mailinglist.py
+++ b/lib/lp/registry/xmlrpc/mailinglist.py
@@ -9,8 +9,8 @@ __all__ = [
     ]
 
 import re
-import xmlrpclib
 
+from six.moves import xmlrpc_client
 from zope.component import getUtility
 from zope.interface import implementer
 from zope.security.proxy import removeSecurityProxy
@@ -241,7 +241,7 @@ class MailingListAPIView(LaunchpadXMLRPCView):
         # non-ascii characters in the message can be safely passed across
         # XMLRPC. For most tests though it's much more convenient to just
         # pass 8-bit strings.
-        if isinstance(bytes, xmlrpclib.Binary):
+        if isinstance(bytes, xmlrpc_client.Binary):
             bytes = bytes.data
         # Although it is illegal for an email header to have unencoded
         # non-ascii characters, it is better to let the list owner
diff --git a/lib/lp/services/authserver/doc/xmlrpc-authserver.txt b/lib/lp/services/authserver/doc/xmlrpc-authserver.txt
index 95b44c0..7918087 100644
--- a/lib/lp/services/authserver/doc/xmlrpc-authserver.txt
+++ b/lib/lp/services/authserver/doc/xmlrpc-authserver.txt
@@ -28,9 +28,9 @@ The AuthServerAPIView provides the IAuthServer XML-RPC API:
 That interface allows the codehosting SSH server to find information
 about users.
 
-    >>> import xmlrpclib
+    >>> from six.moves import xmlrpc_client
     >>> from lp.testing.xmlrpc import XMLRPCTestTransport
-    >>> authserver= xmlrpclib.ServerProxy(
+    >>> authserver= xmlrpc_client.ServerProxy(
     ...     'http://xmlrpc-private.launchpad.test:8087/authserver',
     ...     transport=XMLRPCTestTransport())
 
diff --git a/lib/lp/services/features/__init__.py b/lib/lp/services/features/__init__.py
index 08fbeca..0c44375 100644
--- a/lib/lp/services/features/__init__.py
+++ b/lib/lp/services/features/__init__.py
@@ -131,7 +131,7 @@ Checking flags without access to the database
 Feature flags can also be checked without access to the database by making use
 of the 'getFeatureFlag' XML-RPC method.
 
-    server_proxy = xmlrpclib.ServerProxy(
+    server_proxy = xmlrpc_client.ServerProxy(
         config.launchpad.feature_flags_endpoint, allow_none=True)
     if server_proxy.getFeatureFlag(
         'codehosting.use_forking_server', ['user:' + user_name]):
diff --git a/lib/lp/services/features/tests/test_xmlrpc.py b/lib/lp/services/features/tests/test_xmlrpc.py
index 2e7b46c..9f72825 100644
--- a/lib/lp/services/features/tests/test_xmlrpc.py
+++ b/lib/lp/services/features/tests/test_xmlrpc.py
@@ -5,7 +5,7 @@
 
 __metaclass__ = type
 
-import xmlrpclib
+from six.moves import xmlrpc_client
 
 from lp.services import features
 from lp.services.config import config
@@ -84,13 +84,13 @@ class TestGetFeatureFlag(TestCaseWithFactory):
                     flag_name, ['user:' + person.name]))
 
     def test_xmlrpc_interface_unset(self):
-        sp = xmlrpclib.ServerProxy(
+        sp = xmlrpc_client.ServerProxy(
             config.launchpad.feature_flags_endpoint,
             transport=XMLRPCTestTransport(), allow_none=True)
         self.assertEqual(None, sp.getFeatureFlag(u'flag'))
 
     def test_xmlrpc_interface_set(self):
-        sp = xmlrpclib.ServerProxy(
+        sp = xmlrpc_client.ServerProxy(
             config.launchpad.feature_flags_endpoint,
             transport=XMLRPCTestTransport(), allow_none=True)
         flag_name = u'flag'
diff --git a/lib/lp/services/tests/test_timeout.py b/lib/lp/services/tests/test_timeout.py
index f811945..33cdcdf 100644
--- a/lib/lp/services/tests/test_timeout.py
+++ b/lib/lp/services/tests/test_timeout.py
@@ -13,7 +13,6 @@ from SimpleXMLRPCServer import (
 import socket
 from textwrap import dedent
 import threading
-import xmlrpclib
 
 from fixtures import (
     MonkeyPatch,
@@ -24,6 +23,7 @@ from requests.exceptions import (
     ConnectionError,
     InvalidSchema,
     )
+from six.moves import xmlrpc_client
 from testtools.matchers import (
     ContainsDict,
     Equals,
@@ -500,8 +500,8 @@ class TestTimeout(TestCase):
             logRequests=False)
         server_thread = threading.Thread(target=server.serve_2_requests)
         server_thread.start()
-        proxy = xmlrpclib.ServerProxy(http_server_url,
-                                      transport=TransportWithTimeout())
+        proxy = xmlrpc_client.ServerProxy(
+            http_server_url, transport=TransportWithTimeout())
         self.assertEqual('Successful test message.',
                          proxy.echo('Successful test message.'))
         self.assertRaises(TimeoutError,
diff --git a/lib/lp/services/tests/test_xmlrpc.py b/lib/lp/services/tests/test_xmlrpc.py
index bd75959..2d624b3 100644
--- a/lib/lp/services/tests/test_xmlrpc.py
+++ b/lib/lp/services/tests/test_xmlrpc.py
@@ -13,7 +13,7 @@ from lp.testing.layers import BaseLayer
 
 
 class TestTransport(TestCase):
-    """Test code that allows xmlrpclib.ServerProxy to have a socket timeout"""
+    """Test code that allows ServerProxy to have a socket timeout."""
 
     layer = BaseLayer
 
diff --git a/lib/lp/services/timeout.py b/lib/lp/services/timeout.py
index d96456f..c06a703 100644
--- a/lib/lp/services/timeout.py
+++ b/lib/lp/services/timeout.py
@@ -26,10 +26,6 @@ from threading import (
     Lock,
     Thread,
     )
-from xmlrpclib import (
-    SafeTransport,
-    Transport,
-    )
 
 from requests import (
     HTTPError,
@@ -42,6 +38,10 @@ from requests.adapters import (
 from requests_file import FileAdapter
 from requests_toolbelt.downloadutils import stream
 from six import reraise
+from six.moves.xmlrpc_client import (
+    SafeTransport,
+    Transport,
+    )
 from urllib3.connectionpool import (
     HTTPConnectionPool,
     HTTPSConnectionPool,
diff --git a/lib/lp/services/twistedsupport/xmlrpc.py b/lib/lp/services/twistedsupport/xmlrpc.py
index 13f82c5..3521641 100644
--- a/lib/lp/services/twistedsupport/xmlrpc.py
+++ b/lib/lp/services/twistedsupport/xmlrpc.py
@@ -17,7 +17,7 @@ from twisted.web import xmlrpc
 
 
 class BlockingProxy:
-    """Make an xmlrpclib.ServerProxy behave like a Twisted XML-RPC proxy.
+    """Make a ServerProxy behave like a Twisted XML-RPC proxy.
 
     This is useful for writing code that needs to work in both a synchronous
     and asynchronous fashion.
@@ -29,7 +29,7 @@ class BlockingProxy:
     def __init__(self, proxy):
         """Construct a `BlockingProxy`.
 
-        :param proxy: An xmlrpclib.ServerProxy.
+        :param proxy: An xmlrpc_client.ServerProxy.
         """
         self._proxy = proxy
 
@@ -38,12 +38,13 @@ class BlockingProxy:
 
 
 class DeferredBlockingProxy(BlockingProxy):
-    """Make an xmlrpclib.ServerProxy behave more like a Twisted XML-RPC proxy.
+    """Make a ServerProxy behave more like a Twisted XML-RPC proxy.
 
     This is almost exactly like 'BlockingProxy', except that this returns
     Deferreds. It is guaranteed to be exactly as synchronous as the passed-in
-    proxy. That means if you pass in a normal xmlrpclib proxy you ought to be
-    able to use `lp.services.twistedsupport.extract_result` to get the result.
+    proxy. That means if you pass in a normal xmlrpc_client proxy you ought to
+    be able to use `lp.services.twistedsupport.extract_result` to get the
+    result.
     """
 
     def callRemote(self, method_name, *args, **kwargs):
diff --git a/lib/lp/services/webapp/servers.py b/lib/lp/services/webapp/servers.py
index e99fb05..33cf173 100644
--- a/lib/lp/services/webapp/servers.py
+++ b/lib/lp/services/webapp/servers.py
@@ -6,7 +6,6 @@
 __metaclass__ = type
 
 import threading
-import xmlrpclib
 
 from lazr.restful.interfaces import (
     ICollectionResource,
@@ -20,6 +19,7 @@ from lazr.restful.publisher import (
 from lazr.restful.utils import get_current_browser_request
 from lazr.uri import URI
 import six
+from six.moves import xmlrpc_client
 from six.moves.urllib.parse import parse_qs
 import transaction
 from transaction.interfaces import ISynchronizer
@@ -1443,15 +1443,15 @@ class PublicXMLRPCResponse(XMLRPCResponse):
     """Response type for doing public XML-RPC in Launchpad."""
 
     def handleException(self, exc_info):
-        # If we don't have a proper xmlrpclib.Fault, and we have
+        # If we don't have a proper xmlrpc_client.Fault, and we have
         # logged an OOPS, create a Fault that reports the OOPS ID to
         # the user.
         exc_value = exc_info[1]
-        if not isinstance(exc_value, xmlrpclib.Fault):
+        if not isinstance(exc_value, xmlrpc_client.Fault):
             request = get_current_browser_request()
             if request is not None and request.oopsid is not None:
-                exc_info = (xmlrpclib.Fault,
-                            xmlrpclib.Fault(-1, request.oopsid),
+                exc_info = (xmlrpc_client.Fault,
+                            xmlrpc_client.Fault(-1, request.oopsid),
                             None)
         XMLRPCResponse.handleException(self, exc_info)
 
diff --git a/lib/lp/services/xmlrpc.py b/lib/lp/services/xmlrpc.py
index dde6103..9eff891 100644
--- a/lib/lp/services/xmlrpc.py
+++ b/lib/lp/services/xmlrpc.py
@@ -10,15 +10,15 @@ __all__ = [
     ]
 
 import socket
-import xmlrpclib
 
 from defusedxml.xmlrpc import monkey_patch
+from six.moves import xmlrpc_client
 
 # Protect against various XML parsing vulnerabilities.
 monkey_patch()
 
 
-class LaunchpadFault(xmlrpclib.Fault):
+class LaunchpadFault(xmlrpc_client.Fault):
     """Base class for a Launchpad XMLRPC fault.
 
     Subclasses should define a unique error_code and a msg_template,
@@ -34,7 +34,7 @@ class LaunchpadFault(xmlrpclib.Fault):
         assert self.msg_template is not None, (
             "Subclasses must define msg_template.")
         msg = self.msg_template % kw
-        xmlrpclib.Fault.__init__(self, self.error_code, msg)
+        xmlrpc_client.Fault.__init__(self, self.error_code, msg)
 
     def __eq__(self, other):
         if not isinstance(other, LaunchpadFault):
@@ -47,19 +47,19 @@ class LaunchpadFault(xmlrpclib.Fault):
         return not (self == other)
 
 
-class Transport(xmlrpclib.Transport):
-    """An xmlrpclib transport that supports a timeout argument.
+class Transport(xmlrpc_client.Transport):
+    """An xmlrpc_client transport that supports a timeout argument.
 
-    Use by passing into the "transport" argument of the xmlrpclib.ServerProxy
-    initialization.
+    Use by passing into the "transport" argument of the
+    xmlrpc_client.ServerProxy initialization.
     """
 
     def __init__(self,
                  use_datetime=0, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
-        xmlrpclib.Transport.__init__(self, use_datetime)
+        xmlrpc_client.Transport.__init__(self, use_datetime)
         self.timeout = timeout
 
     def make_connection(self, host):
-        conn = xmlrpclib.Transport.make_connection(self, host)
+        conn = xmlrpc_client.Transport.make_connection(self, host)
         conn.timeout = self.timeout
         return conn
diff --git a/lib/lp/soyuz/model/livefsbuildbehaviour.py b/lib/lp/soyuz/model/livefsbuildbehaviour.py
index bef72b0..4182c79 100644
--- a/lib/lp/soyuz/model/livefsbuildbehaviour.py
+++ b/lib/lp/soyuz/model/livefsbuildbehaviour.py
@@ -87,7 +87,7 @@ class LiveFSBuildBehaviour(BuildFarmJobBehaviourBase):
         base_args = yield super(LiveFSBuildBehaviour, self).extraBuildArgs(
             logger=logger)
         # Non-trivial metadata values may have been security-wrapped, which
-        # is pointless here and just gets in the way of xmlrpclib
+        # is pointless here and just gets in the way of xmlrpc_client
         # serialisation.
         args = dict(removeSecurityProxy(build.livefs.metadata))
         if build.metadata_override is not None:
diff --git a/lib/lp/testing/xmlrpc.py b/lib/lp/testing/xmlrpc.py
index 50a78c5..066297e 100644
--- a/lib/lp/testing/xmlrpc.py
+++ b/lib/lp/testing/xmlrpc.py
@@ -8,9 +8,11 @@ __all__ = [
     ]
 
 from cStringIO import StringIO
-import xmlrpclib
 
-from six.moves import http_client
+from six.moves import (
+    http_client,
+    xmlrpc_client,
+    )
 from zope.security.management import (
     endInteraction,
     queryInteraction,
@@ -38,7 +40,7 @@ class _FakeSocket(object):
 class TestHTTPConnection(http_client.HTTPConnection):
     """A HTTPConnection which talks to http() instead of a real server.
 
-    Only the methods called by xmlrpclib are overridden.
+    Only the methods called by xmlrpc_client are overridden.
     """
 
     _data_to_send = ''
@@ -76,7 +78,7 @@ class TestHTTPConnection(http_client.HTTPConnection):
         return response
 
 
-class XMLRPCTestTransport(xmlrpclib.Transport):
+class XMLRPCTestTransport(xmlrpc_client.Transport):
     """An XMLRPC Transport which sends the requests to http()."""
 
     def make_connection(self, host):
diff --git a/lib/lp/xmlrpc/application.py b/lib/lp/xmlrpc/application.py
index 0bd91b6..a84706b 100644
--- a/lib/lp/xmlrpc/application.py
+++ b/lib/lp/xmlrpc/application.py
@@ -11,8 +11,7 @@ __all__ = [
     'SelfTest',
     ]
 
-import xmlrpclib
-
+from six.moves import xmlrpc_client
 from zope.component import getUtility
 from zope.interface import (
     implementer,
@@ -101,7 +100,7 @@ class SelfTest(LaunchpadXMLRPCView):
 
     def make_fault(self):
         """Returns an xmlrpc fault."""
-        return xmlrpclib.Fault(666, "Yoghurt and spanners.")
+        return xmlrpc_client.Fault(666, "Yoghurt and spanners.")
 
     def concatenate(self, string1, string2):
         """Return the concatenation of the two given strings."""
diff --git a/lib/lp/xmlrpc/configure.zcml b/lib/lp/xmlrpc/configure.zcml
index 70e4bb6..47a3100 100644
--- a/lib/lp/xmlrpc/configure.zcml
+++ b/lib/lp/xmlrpc/configure.zcml
@@ -74,148 +74,148 @@
     />
 
   <class class="lp.xmlrpc.faults.BranchAlreadyRegistered">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.FileBugGotProductAndDistro">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class
       class="lp.xmlrpc.faults.FileBugMissingProductOrDistribution"
       >
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NoSuchDistribution">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NoSuchPackage">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NoSuchProduct">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NoSuchPerson">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NoSuchPersonWithName">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NoSuchBranch">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NoSuchBug">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.RequiredParameterMissing">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.BranchCreationForbidden">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.InvalidBranchUrl">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.BranchUniqueNameConflict">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NoSuchTeamMailingList">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.UnexpectedStatusReport">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.BadStatus">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NoLinkedBranch">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NoSuchProductSeries">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.InvalidBranchIdentifier">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.BranchNameInUse">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.CannotHaveLinkedBranch">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.InvalidProductName">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NotInTeam">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.InvalidBranchName">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NoBranchWithID">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NoUrlForBranch">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.PathTranslationError">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.InvalidPath">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.PermissionDenied">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NotFound">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.InvalidBranchUniqueName">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NoSuchDistroSeries">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.NoSuchSourcePackageName">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.InvalidSourcePackageName">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 
   <class class="lp.xmlrpc.faults.Unauthorized">
-    <require like_class="xmlrpclib.Fault" />
+    <require like_class="six.moves.xmlrpc_client.Fault" />
   </class>
 </configure>
diff --git a/lib/lp/xmlrpc/helpers.py b/lib/lp/xmlrpc/helpers.py
index d4d3cc4..194468f 100644
--- a/lib/lp/xmlrpc/helpers.py
+++ b/lib/lp/xmlrpc/helpers.py
@@ -8,8 +8,7 @@ __all__ = [
     'return_fault',
     ]
 
-from xmlrpclib import Fault
-
+from six.moves.xmlrpc_client import Fault
 from twisted.python.util import mergeFunctionMetadata
 
 
diff --git a/lib/lp/xmlrpc/tests/test_private_xmlrpc.py b/lib/lp/xmlrpc/tests/test_private_xmlrpc.py
index ed5fe51..c20d180 100644
--- a/lib/lp/xmlrpc/tests/test_private_xmlrpc.py
+++ b/lib/lp/xmlrpc/tests/test_private_xmlrpc.py
@@ -4,8 +4,7 @@
 """Private XMLRPC tests.
 """
 
-import xmlrpclib
-
+from six.moves import xmlrpc_client
 from zope.component import getUtility
 
 from lp.services.verification.interfaces.logintoken import ILoginTokenSet
@@ -31,14 +30,14 @@ class TestPrivateXMLRPC(TestCase):
     private_root = 'http://xmlrpc-private.launchpad.test:8087/'
 
     def get_public_proxy(self, path):
-        """Get an xmlrpclib.ServerProxy pointing at the public URL"""
-        return xmlrpclib.ServerProxy(
+        """Get an xmlrpc_client.ServerProxy pointing at the public URL"""
+        return xmlrpc_client.ServerProxy(
             self.public_root + path,
             transport=XMLRPCTestTransport())
 
     def get_private_proxy(self, path):
-        """Get an xmlrpclib.ServerProxy pointing at the private URL"""
-        return xmlrpclib.ServerProxy(
+        """Get an xmlrpc_client.ServerProxy pointing at the private URL"""
+        return xmlrpc_client.ServerProxy(
             self.private_root + path,
             transport=XMLRPCTestTransport())
 
@@ -48,7 +47,7 @@ class TestPrivateXMLRPC(TestCase):
         not available on the external XML-RPC port.
         """
         external_api = self.get_public_proxy('mailinglists/')
-        e = self.assertRaises(xmlrpclib.ProtocolError,
+        e = self.assertRaises(xmlrpc_client.ProtocolError,
                               external_api.getPendingActions)
         self.assertEqual(404, e.errcode)
 
@@ -78,7 +77,7 @@ class TestPrivateXMLRPC(TestCase):
         internal_api = self.get_private_proxy('bugs/')
         bug_dict = dict(
             product='firefox', summary='the summary', comment='the comment')
-        e = self.assertRaises(xmlrpclib.ProtocolError,
+        e = self.assertRaises(xmlrpc_client.ProtocolError,
                               internal_api.filebug, bug_dict)
         self.assertEqual(404, e.errcode)
 
diff --git a/lib/lp/xmlrpc/tests/test_xmlrpc_selftest.py b/lib/lp/xmlrpc/tests/test_xmlrpc_selftest.py
index 313fe1e..4c005eb 100644
--- a/lib/lp/xmlrpc/tests/test_xmlrpc_selftest.py
+++ b/lib/lp/xmlrpc/tests/test_xmlrpc_selftest.py
@@ -4,8 +4,7 @@
 """XMLRPC self-test api.
 """
 
-import xmlrpclib
-
+from six.moves import xmlrpc_client
 from zope.component import getUtility
 
 from lp.services.webapp.interfaces import ILaunchBag
@@ -28,11 +27,11 @@ class TestXMLRPCSelfTest(TestCaseWithFactory):
     layer = LaunchpadFunctionalLayer
 
     def make_proxy(self):
-        return xmlrpclib.ServerProxy(
+        return xmlrpc_client.ServerProxy(
             'http://xmlrpc.launchpad.test/', transport=XMLRPCTestTransport())
 
     def make_logged_in_proxy(self):
-        return xmlrpclib.ServerProxy(
+        return xmlrpc_client.ServerProxy(
             'http://test@xxxxxxxxxxxxx:test@xxxxxxxxxxxxxxxxxxxxx/',
             transport=XMLRPCTestTransport())
 
@@ -47,18 +46,18 @@ class TestXMLRPCSelfTest(TestCaseWithFactory):
         self.assertEqual("<Fault 666: 'Yoghurt and spanners.'>", str(fault))
 
     def test_custom_transport(self):
-        """We can test our XMLRPC APIs using xmlrpclib, using a custom
+        """We can test our XMLRPC APIs using xmlrpc_client, using a custom
         Transport which talks with the publisher directly.
         """
         selftest = self.make_proxy()
         self.assertEqual('foo bar', selftest.concatenate('foo', 'bar'))
-        fault = self.assertRaises(xmlrpclib.Fault, selftest.make_fault)
+        fault = self.assertRaises(xmlrpc_client.Fault, selftest.make_fault)
         self.assertEqual("<Fault 666: 'Yoghurt and spanners.'>", str(fault))
 
     def test_unexpected_exception(self):
         """Sometimes an XML-RPC method will be buggy, and raise an exception
-        other than xmlrpclib.Fault.  We have such a method on the self test
-        view.
+        other than xmlrpc_client.Fault.  We have such a method on the self
+        test view.
         """
         selftestview = SelfTest('somecontext', 'somerequest')
         self.assertRaises(RuntimeError, selftestview.raise_exception)
@@ -70,7 +69,7 @@ class TestXMLRPCSelfTest(TestCaseWithFactory):
         one was generated):
         """
         selftest = self.make_proxy()
-        e = self.assertRaises(xmlrpclib.Fault, selftest.raise_exception)
+        e = self.assertRaises(xmlrpc_client.Fault, selftest.raise_exception)
         self.assertStartsWith(str(e), "<Fault -1: 'OOPS-")
 
     def test_anonymous_authentication(self):