[Autotest][PY3] Migrating client/cros (debugd_util -> kernel_config)

Migrating client/cros from debugd_util.py -> kernel_config.py to python3.

BUG=chromium:990593
TEST= py_compile in py2 and py3. CQ. dummy_Pass. policy_ tests for httpd

Change-Id: I565e11a7d4e18fa9414928df2fd184be1786506e
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/2487216
Reviewed-by: Greg Edelston <gredelston@google.com>
Commit-Queue: Derek Beckett <dbeckett@chromium.org>
Tested-by: Derek Beckett <dbeckett@chromium.org>
diff --git a/client/cros/dhcp_packet.py b/client/cros/dhcp_packet.py
index bff9aa4..695fe1e 100644
--- a/client/cros/dhcp_packet.py
+++ b/client/cros/dhcp_packet.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -27,9 +28,14 @@
 file still pass.
 """
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
 import collections
 import logging
 import random
+from six.moves import range
 import socket
 import struct
 
@@ -717,7 +723,7 @@
 
         @returns The MessageType for this packet, or MESSAGE_TYPE_UNKNOWN.
         """
-        if (self._options.has_key(OPTION_DHCP_MESSAGE_TYPE) and
+        if (OPTION_DHCP_MESSAGE_TYPE in self._options and
             self._options[OPTION_DHCP_MESSAGE_TYPE] > 0 and
             self._options[OPTION_DHCP_MESSAGE_TYPE] < len(MESSAGE_TYPE_BY_NUM)):
             return MESSAGE_TYPE_BY_NUM[self._options[OPTION_DHCP_MESSAGE_TYPE]]
diff --git a/client/cros/dhcp_test_base.py b/client/cros/dhcp_test_base.py
index c2ccb81..0ca81e2 100644
--- a/client/cros/dhcp_test_base.py
+++ b/client/cros/dhcp_test_base.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -10,7 +11,13 @@
 logic of their test.  The plumbing of DhcpTestBase is accessible via properties.
 """
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
 import logging
+from six.moves import filter
+from six.moves import range
 import socket
 import struct
 import time
@@ -116,9 +123,9 @@
         proxy = self.shill_proxy
 
         ipconfig_object = proxy.DBUS_TYPE_IPCONFIG
-        return filter(bool,
+        return list(filter(bool,
                       [ proxy.get_dbus_object(ipconfig_object, property_path)
-                        for property_path in device_properties['IPConfigs'] ])
+                        for property_path in device_properties['IPConfigs'] ]))
 
 
     def get_interface_ipconfig(self, interface_name):
diff --git a/client/cros/dhcp_test_server.py b/client/cros/dhcp_test_server.py
index 3aa55d9..4b0ff9e 100644
--- a/client/cros/dhcp_test_server.py
+++ b/client/cros/dhcp_test_server.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -48,7 +49,12 @@
 still pass.
 """
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
 import logging
+from six.moves import range
 import socket
 import threading
 import time
@@ -134,7 +140,7 @@
             # Wait 100 ms for a packet, then return, thus keeping the thread
             # active but mostly idle.
             self._socket.settimeout(0.1)
-        except socket.error, socket_error:
+        except socket.error as socket_error:
             self._logger.error("Socket error: %s." % str(socket_error))
             self._logger.error(traceback.format_exc())
             if not self._socket is None:
diff --git a/client/cros/dhcp_unittest.py b/client/cros/dhcp_unittest.py
index 7a6812a..8d0fa02 100755
--- a/client/cros/dhcp_unittest.py
+++ b/client/cros/dhcp_unittest.py
@@ -4,7 +4,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
 import logging
+from six.moves import range
 import socket
 import sys
 import time
@@ -49,7 +54,7 @@
     """
     chars = ["x" + (hex(ord(c))[2:].zfill(2)) for c in byte_str]
     groups = []
-    for i in xrange(0, len(chars), justification):
+    for i in range(0, len(chars), justification):
         groups.append("".join(chars[i:i+justification]))
     return "\n".join(groups)
 
@@ -62,25 +67,25 @@
         return False
     generated_string = discovery_packet.to_binary_string()
     if generated_string is None:
-        print "Failed to generate string from packet object."
+        print("Failed to generate string from packet object.")
         return False
     if generated_string != binary_discovery_packet:
-        print "Packets didn't match: "
-        print "Generated: \n%s" % bin2hex(generated_string)
-        print "Expected: \n%s" % bin2hex(binary_discovery_packet)
+        print("Packets didn't match: ")
+        print("Generated: \n%s" % bin2hex(generated_string))
+        print("Expected: \n%s" % bin2hex(binary_discovery_packet))
         return False
-    print "test_packet_serialization PASSED"
+    print("test_packet_serialization PASSED")
     return True
 
 def test_classless_static_route_parsing():
     parsed_routes = dhcp_packet.ClasslessStaticRoutesOption.unpack(
             TEST_CLASSLESS_STATIC_ROUTE_DATA)
     if parsed_routes != TEST_CLASSLESS_STATIC_ROUTE_LIST_PARSED:
-        print ("Parsed binary domain list and got %s but expected %s" %
+        print("Parsed binary domain list and got %s but expected %s" %
                (repr(parsed_routes),
                 repr(TEST_CLASSLESS_STATIC_ROUTE_LIST_PARSED)))
         return False
-    print "test_classless_static_route_parsing PASSED"
+    print("test_classless_static_route_parsing PASSED")
     return True
 
 def test_classless_static_route_serialization():
@@ -90,11 +95,11 @@
         # Turn the strings into printable hex strings on a single line.
         pretty_actual = bin2hex(byte_string, 100)
         pretty_expected = bin2hex(TEST_CLASSLESS_STATIC_ROUTE_DATA, 100)
-        print ("Expected to serialize %s to %s but instead got %s." %
+        print("Expected to serialize %s to %s but instead got %s." %
                (repr(TEST_CLASSLESS_STATIC_ROUTE_LIST_PARSED), pretty_expected,
                      pretty_actual))
         return False
-    print "test_classless_static_route_serialization PASSED"
+    print("test_classless_static_route_serialization PASSED")
     return True
 
 def test_domain_search_list_parsing():
@@ -103,10 +108,10 @@
     # Order matters too.
     parsed_domains = tuple(parsed_domains)
     if parsed_domains != TEST_DOMAIN_SEARCH_LIST_PARSED:
-        print ("Parsed binary domain list and got %s but expected %s" %
+        print("Parsed binary domain list and got %s but expected %s" %
                (parsed_domains, TEST_DOMAIN_SEARCH_LIST_EXPECTED))
         return False
-    print "test_domain_search_list_parsing PASSED"
+    print("test_domain_search_list_parsing PASSED")
     return True
 
 def test_domain_search_list_serialization():
@@ -116,24 +121,24 @@
         # Turn the strings into printable hex strings on a single line.
         pretty_actual = bin2hex(byte_string, 100)
         pretty_expected = bin2hex(TEST_DOMAIN_SEARCH_LIST_EXPECTED, 100)
-        print ("Expected to serialize %s to %s but instead got %s." %
+        print("Expected to serialize %s to %s but instead got %s." %
                (TEST_DOMAIN_SEARCH_LIST_PARSED, pretty_expected, pretty_actual))
         return False
-    print "test_domain_search_list_serialization PASSED"
+    print("test_domain_search_list_serialization PASSED")
     return True
 
 def test_broken_domain_search_list_parsing():
     byte_string = '\x00' * 240 + TEST_DOMAIN_SEARCH_LIST1 + TEST_DOMAIN_SEARCH_LIST2 + '\xff'
     packet = dhcp_packet.DhcpPacket(byte_str=byte_string)
     if len(packet._options) != 1:
-        print "Expected domain list of length 1"
+        print("Expected domain list of length 1")
         return False
     for k, v in packet._options.items():
         if tuple(v) != TEST_DOMAIN_SEARCH_LIST_PARSED:
-            print ("Expected binary domain list and got %s but expected %s" %
+            print("Expected binary domain list and got %s but expected %s" %
                     (tuple(v), TEST_DOMAIN_SEARCH_LIST_PARSED))
             return False
-    print "test_broken_domain_search_list_parsing PASSED"
+    print("test_broken_domain_search_list_parsing PASSED")
     return True
 
 def receive_packet(a_socket, timeout_seconds=1.0):
@@ -145,13 +150,13 @@
         except socket.timeout:
             pass # We expect many timeouts.
     if data is None:
-        print "Timed out before we received a response from the server."
+        print("Timed out before we received a response from the server.")
         return None
 
-    print "Client received a packet of length %d from the server." % len(data)
+    print("Client received a packet of length %d from the server." % len(data))
     packet = dhcp_packet.DhcpPacket(byte_str=data)
     if not packet.is_valid:
-        print "Received an invalid response from DHCP server."
+        print("Received an invalid response from DHCP server.")
         return None
 
     return packet
@@ -211,14 +216,14 @@
         return False
 
     if (offer_packet.message_type != dhcp_packet.MESSAGE_TYPE_OFFER):
-        print "Type of DHCP response is not offer."
+        print("Type of DHCP response is not offer.")
         return False
 
     if offer_packet.get_field(dhcp_packet.FIELD_YOUR_IP) != intended_ip:
-        print "Server didn't offer the IP we expected."
+        print("Server didn't offer the IP we expected.")
         return False
 
-    print "Offer looks good to the client, sending request."
+    print("Offer looks good to the client, sending request.")
     # In real tests, dhcpcd formats all the DISCOVERY and REQUEST messages.  In
     # our unit test, we have to do this ourselves.
     request_message.set_option(
@@ -241,21 +246,21 @@
         return False
 
     if (ack_packet.message_type != dhcp_packet.MESSAGE_TYPE_ACK):
-        print "Type of DHCP response is not acknowledgement."
+        print("Type of DHCP response is not acknowledgement.")
         return False
 
     if ack_packet.get_field(dhcp_packet.FIELD_YOUR_IP) != intended_ip:
-        print "Server didn't give us the IP we expected."
+        print("Server didn't give us the IP we expected.")
         return False
 
-    print "Waiting for the server to finish."
+    print("Waiting for the server to finish.")
     server.wait_for_test_to_finish()
-    print "Server agrees that the test is over."
+    print("Server agrees that the test is over.")
     if not server.last_test_passed:
-        print "Server is unhappy with the test result."
+        print("Server is unhappy with the test result.")
         return False
 
-    print "test_simple_server_exchange PASSED."
+    print("test_simple_server_exchange PASSED.")
     return True
 
 def test_server_dialogue():
@@ -268,10 +273,10 @@
     if server.is_healthy:
         ret = test_simple_server_exchange(server)
     else:
-        print "Server isn't healthy, aborting."
-    print "Sending server stop() signal."
+        print("Server isn't healthy, aborting.")
+    print("Sending server stop() signal.")
     server.stop()
-    print "Stop signal sent."
+    print("Stop signal sent.")
     return ret
 
 def run_tests():
@@ -288,10 +293,10 @@
     retval &= test_broken_domain_search_list_parsing()
     retval &= test_server_dialogue()
     if retval:
-        print "All tests PASSED."
+        print("All tests PASSED.")
         return 0
     else:
-        print "Some tests FAILED"
+        print("Some tests FAILED")
         return -1
 
 if __name__ == "__main__":
diff --git a/client/cros/dhcpv6_test_base.py b/client/cros/dhcpv6_test_base.py
index e53ec88..990d255 100644
--- a/client/cros/dhcpv6_test_base.py
+++ b/client/cros/dhcpv6_test_base.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # Copyright 2015 The Chromium OS Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -10,7 +11,13 @@
 with the logic of their test.
 """
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
 import logging
+from six.moves import filter
+from six.moves import range
 import time
 import traceback
 
@@ -80,9 +87,9 @@
         proxy = self.shill_proxy
 
         ipconfig_object = proxy.DBUS_TYPE_IPCONFIG
-        return filter(bool,
+        return list(filter(bool,
                       [ proxy.get_dbus_object(ipconfig_object, property_path)
-                        for property_path in device_properties['IPConfigs'] ])
+                        for property_path in device_properties['IPConfigs'] ]))
 
 
     def get_interface_ipconfig(self, interface_name):
diff --git a/client/cros/dhcpv6_test_server.py b/client/cros/dhcpv6_test_server.py
index a011f05..84b4cf7 100644
--- a/client/cros/dhcpv6_test_server.py
+++ b/client/cros/dhcpv6_test_server.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # Copyright 2015 The Chromium OS Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -105,7 +106,8 @@
         associated process.
         """
         if os.path.exists(DHCPV6_SERVER_PID_FILE):
-            pid = int(file(DHCPV6_SERVER_PID_FILE).read())
+            with open(DHCPV6_SERVER_PID_FILE) as rf:
+                pid = int(rf.read())
             os.remove(DHCPV6_SERVER_PID_FILE)
             try:
                 os.kill(pid, signal.SIGTERM)
diff --git a/client/cros/ec.py b/client/cros/ec.py
index 64a8676..b350c7f 100644
--- a/client/cros/ec.py
+++ b/client/cros/ec.py
@@ -1,9 +1,15 @@
+# Lint as: python2, python3
 # Copyright 2015 The Chromium OS Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
 import logging
 import os
 import re
+from six.moves import range
 import time
 
 from autotest_lib.client.bin import utils
@@ -518,7 +524,7 @@
         if (self.get_num_ports() == 0):
             raise error.TestNAError("Device has no USB-PD ports")
 
-        for i in xrange(self._num_ports):
+        for i in range(self._num_ports):
             self.ports.append(EC_USBPD_Port(i))
 
     def get_num_ports(self):
diff --git a/client/cros/gpio.py b/client/cros/gpio.py
index 39c318a..b838516 100644
--- a/client/cros/gpio.py
+++ b/client/cros/gpio.py
@@ -11,6 +11,10 @@
 See help(Gpio) for more information.
 '''
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
 import os, shutil, sys, tempfile
 
 
@@ -112,10 +116,10 @@
     gpio = Gpio()
     try:
         gpio.setup()
-        print ("developer switch current status: %s" %
-               gpio.read(gpio.DEVELOPER_SWITCH_CURRENT))
-    except Exception, e:
-        print "GPIO failed. %s" % e
+        print("developer switch current status: %s" %
+              gpio.read(gpio.DEVELOPER_SWITCH_CURRENT))
+    except Exception as e:
+        print("GPIO failed. %s" % e)
         sys.exit(1)
 
 if __name__ == '__main__':
diff --git a/client/cros/http_speed.py b/client/cros/http_speed.py
index f9272e0..a283d6b 100644
--- a/client/cros/http_speed.py
+++ b/client/cros/http_speed.py
@@ -1,10 +1,12 @@
+# Lint as: python2, python3
 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
 """A tool to measure single-stream link bandwidth using HTTP connections."""
 
-import logging, random, time, urllib2
+import logging, random, time
+from six.moves import urllib
 
 import numpy.random
 
@@ -18,7 +20,7 @@
 def TimeTransfer(url, data):
     """Transfers data to/from url.  Returns (time, url contents)."""
     start_time = time.time()
-    result = urllib2.urlopen(url, data=data, timeout=TIMEOUT)
+    result = urllib.request.urlopen(url, data=data, timeout=TIMEOUT)
     got = result.read()
     transfer_time = time.time() - start_time
     if transfer_time <= 0:
diff --git a/client/cros/httpd.py b/client/cros/httpd.py
index 7525c6c..5a9f271 100644
--- a/client/cros/httpd.py
+++ b/client/cros/httpd.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -9,10 +10,11 @@
    http://localhost:nnnn/?status="Browser started!"
 """
 
-import cgi, errno, logging, os, posixpath, SimpleHTTPServer, socket, ssl, sys
-import threading, urllib, urlparse
-from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
-from SocketServer import BaseServer, ThreadingMixIn
+import cgi, errno, logging, os, posixpath, six.moves.SimpleHTTPServer, socket, ssl, sys
+import threading, six.moves.urllib.parse
+from six.moves import urllib
+from six.moves.BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+from six.moves.socketserver import BaseServer, ThreadingMixIn
 
 
 def _handle_http_errors(func):
@@ -20,7 +22,7 @@
     def wrapper(self):
         try:
             func(self)
-        except IOError, e:
+        except IOError as e:
             if e.errno == errno.EPIPE or e.errno == errno.ECONNRESET:
                 # Instead of dumping a stack trace, a single line is sufficient.
                 self.log_error(str(e))
@@ -30,7 +32,7 @@
     return wrapper
 
 
-class FormHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+class FormHandler(six.moves.SimpleHTTPServer.SimpleHTTPRequestHandler):
     """Implements a form handler (for POST requests only) which simply
     echoes the key=value parameters back in the response.
 
@@ -38,7 +40,7 @@
     to disk with the name contained in the 'filename' field.
     """
 
-    SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map.update({
+    six.moves.SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map.update({
         '.webm': 'video/webm',
     })
 
@@ -67,7 +69,7 @@
             for field in form.keys():
                 field_item = form[field]
                 self.server._form_entries[field] = field_item.value
-        path = urlparse.urlparse(self.path)[2]
+        path = six.moves.urllib.parse.urlparse(self.path)[2]
         if path in self.server._url_handlers:
             self.server._url_handlers[path](self, form)
         else:
@@ -84,10 +86,10 @@
         # Send response boilerplate
         self.send_response(200)
         self.end_headers()
-        self.wfile.write('Hello from Autotest!\nClient: %s\n' %
-                         str(self.client_address))
-        self.wfile.write('Request for path: %s\n' % self.path)
-        self.wfile.write('Got form data:\n')
+        self.wfile.write(('Hello from Autotest!\nClient: %s\n' %
+                         str(self.client_address)).encode('utf-8'))
+        self.wfile.write(('Request for path: %s\n' % self.path).encode('utf-8'))
+        self.wfile.write(b'Got form data:\n')
 
         # See the note in do_POST about form.keys().
         if form:
@@ -96,13 +98,13 @@
                 if field_item.filename:
                     # The field contains an uploaded file
                     upload = field_item.file.read()
-                    self.wfile.write('\tUploaded %s (%d bytes)<br>' %
-                                     (field, len(upload)))
+                    self.wfile.write(('\tUploaded %s (%d bytes)<br>' %
+                                     (field, len(upload))).encode('utf-8'))
                     # Write submitted file to specified filename.
-                    file(field_item.filename, 'w').write(upload)
+                    open(field_item.filename, 'w').write(upload)
                     del upload
                 else:
-                    self.wfile.write('\t%s=%s<br>' % (field, form[field].value))
+                    self.wfile.write(('\t%s=%s<br>' % (field, form[field].value)).encode('utf-8'))
 
 
     def translate_path(self, path):
@@ -110,10 +112,10 @@
         from arbitrary docroot
         """
         # abandon query parameters
-        path = urlparse.urlparse(path)[2]
-        path = posixpath.normpath(urllib.unquote(path))
+        path = six.moves.urllib.parse.urlparse(path)[2]
+        path = posixpath.normpath(urllib.parse.unquote(path))
         words = path.split('/')
-        words = filter(None, words)
+        words = [_f for _f in words if _f]
         path = self.server.docroot
         for word in words:
             drive, word = os.path.splitdrive(word)
@@ -143,22 +145,22 @@
             fp=self.rfile,
             headers=self.headers,
             environ={'REQUEST_METHOD': 'GET'})
-        split_url = urlparse.urlsplit(self.path)
+        split_url = six.moves.urllib.parse.urlsplit(self.path)
         path = split_url[2]
         # Strip off query parameters to ensure that the url path
         # matches any registered events.
         self.path = path
-        args = urlparse.parse_qs(split_url[3])
+        args = six.moves.urllib.parse.parse_qs(split_url[3])
         if path in self.server._url_handlers:
             self.server._url_handlers[path](self, args)
         else:
-            SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
+            six.moves.SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
         self._fire_event()
 
 
     @_handle_http_errors
     def do_HEAD(self):
-        SimpleHTTPServer.SimpleHTTPRequestHandler.do_HEAD(self)
+        six.moves.SimpleHTTPServer.SimpleHTTPRequestHandler.do_HEAD(self)
 
 
 class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
diff --git a/client/cros/httpd_unittest.py b/client/cros/httpd_unittest.py
index d36d03b..aa908bc 100755
--- a/client/cros/httpd_unittest.py
+++ b/client/cros/httpd_unittest.py
@@ -6,9 +6,14 @@
 
 """HTTPlistener unittest."""
 
-import logging, os, sys, threading, urllib, unittest
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
 
-from httpd import HTTPListener, SecureHTTPListener
+import logging, os, sys, threading, unittest
+from six.moves import urllib
+
+from autotest_lib.client.cros.httpd import HTTPListener, SecureHTTPListener
 
 GET_TEST_PATH = '/get_test'
 
@@ -17,13 +22,13 @@
     get_done = test_server.add_wait_url(GET_TEST_PATH)
     get_resp = ''
     try:
-        get_resp = urllib.urlopen(url).read()
-    except IOError, e:
+        get_resp = urllib.request.urlopen(url).read()
+    except IOError as e:
         pass
     if not (get_done.is_set() and get_resp):
-        print 'FAILED'
+        print('FAILED')
     else:
-        print 'PASSED'
+        print('PASSED')
         err = 0
     return err
 
@@ -34,26 +39,26 @@
                                          matchParams={'test': 'passed'})
     def _Spam():
         while not post_done.is_set():
-            print 'TEST: server running'
+            print('TEST: server running')
             post_done.wait()
         return
     test_server.run()
     t = threading.Thread(target=_Spam).start()
-    params = urllib.urlencode({'test': 'passed'})
+    params = urllib.parse.urlencode({'test': 'passed'})
     err = 1
 
     # TODO(seano): This test doesn't seem to pass.
     post_resp = ''
     try:
-        post_resp = urllib.urlopen('http://localhost:8000/post_test',
+        post_resp = urllib.request.urlopen('http://localhost:8000/post_test',
                                    params).read()
-    except IOError, e:
+    except IOError as e:
         pass
     if not (post_done.is_set() and
             test_server.get_form_entries()['test'] != 'passed'):
-        print 'FAILED'
+        print('FAILED')
     else:
-        print 'PASSED'
+        print('PASSED')
         err = 0
 
 
diff --git a/client/cros/kernel_config.py b/client/cros/kernel_config.py
index 8258dbc..6022c86 100644
--- a/client/cros/kernel_config.py
+++ b/client/cros/kernel_config.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # Copyright 2014 The Chromium OS Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -133,33 +134,35 @@
                 self._failed('"%s" found for "%s" when only "%s" allowed' %
                              (name, regex, "|".join(expected)))
 
-    def _open_config(self):
+    def _read_config(self):
         """Open the kernel's build config file. Attempt to use the built-in
         symbols from /proc first, then fall back to looking for a text file
         in /boot.
 
-        @return fileobj for open config file
+        @return readlines for fileobj
         """
         filename = '/proc/config.gz'
         if not os.path.exists(filename):
             utils.system("modprobe configs", ignore_status=True)
         if os.path.exists(filename):
-            return gzip.open(filename, "r")
+            with gzip.open(filename, "r").readlines() as rf:
+                return rf.readlines()
 
         filename = '/boot/config-%s' % utils.system_output('uname -r')
         if os.path.exists(filename):
             logging.info('Falling back to reading %s', filename)
-            return file(filename, "r")
+            with open(filename, "r") as rf:
+                return rf.readlines()
 
         self._fatal("Cannot locate suitable kernel config file")
 
     def initialize(self, missing_ok=None):
         """Load the kernel configuration and parse it.
         """
-        fileobj = self._open_config()
+        file_lines = self._read_config()
         # Import kernel config variables into a dictionary for each searching.
         config = dict()
-        for item in fileobj.readlines():
+        for item in file_lines:
             item = item.strip()
             if not '=' in item:
                 continue