Improve PPAPI scripts' Python 3 support

This mostly includes low-hanging fruit.

The scripts still work with Python 2.
There are no intended behaviour changes.

Bug: 941669
Change-Id: Ie950398b967b749f8136b4aea19592b6b50083ed
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1556774
Reviewed-by: Bill Budge <bbudge@chromium.org>
Commit-Queue: Bill Budge <bbudge@chromium.org>
Auto-Submit: Raul Tambre <raul@tambre.ee>
Cr-Original-Commit-Position: refs/heads/master@{#648792}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: a4895d8a40bb7d8566d0c2df81a54a5e35bfb295
diff --git a/c/documentation/doxy_cleanup.py b/c/documentation/doxy_cleanup.py
index 01b1ca0..be94342 100755
--- a/c/documentation/doxy_cleanup.py
+++ b/c/documentation/doxy_cleanup.py
@@ -8,6 +8,8 @@
 that they are suitable for publication on a Google documentation site.
 '''
 
+from __future__ import print_function
+
 import optparse
 import os
 import re
@@ -17,10 +19,10 @@
 try:
   from BeautifulSoup import BeautifulSoup, Tag
 except (ImportError, NotImplementedError):
-  print ("This tool requires the BeautifulSoup package "
-         "(see http://www.crummy.com/software/BeautifulSoup/).\n"
-         "Make sure that the file BeautifulSoup.py is either in this directory "
-         "or is available in your PYTHON_PATH")
+  print("This tool requires the BeautifulSoup package "
+        "(see http://www.crummy.com/software/BeautifulSoup/).\n"
+        "Make sure that the file BeautifulSoup.py is either in this directory "
+        "or is available in your PYTHON_PATH")
   raise
 
 
@@ -66,10 +68,10 @@
     table_headers.reverse()
     # Split up tables that have multiple table header (th) rows
     for tag in table_headers:
-      print "Header tag: %s is %s" % (tag.name, tag.string.strip())
+      print("Header tag: %s is %s" % (tag.name, tag.string.strip()))
       # Is this a heading in the middle of a table?
       if tag.findPreviousSibling('tr') and tag.parent.name == 'table':
-        print "Splitting Table named %s" % tag.string.strip()
+        print("Splitting Table named %s" % tag.string.strip())
         table = tag.parent
         table_parent = table.parent
         table_index = table_parent.contents.index(table)
@@ -121,7 +123,7 @@
       with open(filename, 'r') as file:
         html = file.read()
 
-      print "Processing %s" % filename
+      print("Processing %s" % filename)
       fixer = HTMLFixer(html)
       fixer.FixAll()
       with open(filename, 'w') as file:
@@ -133,7 +135,7 @@
           os.mkdir(new_directory)
         shutil.move(filename, new_directory)
     except:
-      print "Error while processing %s" % filename
+      print("Error while processing %s" % filename)
       raise
 
   return 0
diff --git a/cpp/documentation/doxy_cleanup.py b/cpp/documentation/doxy_cleanup.py
index 24ddb3c..fbbc2f6 100755
--- a/cpp/documentation/doxy_cleanup.py
+++ b/cpp/documentation/doxy_cleanup.py
@@ -7,6 +7,8 @@
 that they are suitable for publication on a Google documentation site.
 '''
 
+from __future__ import print_function
+
 import optparse
 import os
 import re
@@ -16,10 +18,10 @@
 try:
   from BeautifulSoup import BeautifulSoup, Tag
 except (ImportError, NotImplementedError):
-  print ("This tool requires the BeautifulSoup package "
-         "(see http://www.crummy.com/software/BeautifulSoup/).\n"
-         "Make sure that the file BeautifulSoup.py is either in this directory "
-         "or is available in your PYTHON_PATH")
+  print("This tool requires the BeautifulSoup package "
+        "(see http://www.crummy.com/software/BeautifulSoup/).\n"
+        "Make sure that the file BeautifulSoup.py is either in this directory "
+        "or is available in your PYTHON_PATH")
   raise
 
 
@@ -65,10 +67,10 @@
     table_headers.reverse()
     # Split up tables that have multiple table header (th) rows
     for tag in table_headers:
-      print "Header tag: %s is %s" % (tag.name, tag.string.strip())
+      print("Header tag: %s is %s" % (tag.name, tag.string.strip()))
       # Is this a heading in the middle of a table?
       if tag.findPreviousSibling('tr') and tag.parent.name == 'table':
-        print "Splitting Table named %s" % tag.string.strip()
+        print("Splitting Table named %s" % tag.string.strip())
         table = tag.parent
         table_parent = table.parent
         table_index = table_parent.contents.index(table)
@@ -120,7 +122,7 @@
       with open(filename, 'r') as file:
         html = file.read()
 
-      print "Processing %s" % filename
+      print("Processing %s" % filename)
       fixer = HTMLFixer(html)
       fixer.FixAll()
       with open(filename, 'w') as file:
@@ -132,7 +134,7 @@
           os.mkdir(new_directory)
         shutil.move(filename, new_directory)
     except:
-      print "Error while processing %s" % filename
+      print("Error while processing %s" % filename)
       raise
 
   return 0
diff --git a/generate_ppapi_include_tests.py b/generate_ppapi_include_tests.py
index 97daf24..f690f3e 100755
--- a/generate_ppapi_include_tests.py
+++ b/generate_ppapi_include_tests.py
@@ -17,6 +17,8 @@
 #                  tests to some 'generated' area, and remove them from version
 #                  control.
 
+from __future__ import print_function
+
 import re
 import os
 import sys
@@ -75,11 +77,11 @@
   in_gyp_not_file = gyp_sources - file_sources
   in_file_not_gyp = file_sources - gyp_sources
   if len(in_gyp_not_file):
-    print 'Found source file(s) in ppapi.gyp but not in the directory:', \
-      in_gyp_not_file
+    print('Found source file(s) in ppapi.gyp but not in the directory:', \
+      in_gyp_not_file)
   if len(in_file_not_gyp):
-    print 'Found source file(s) in the directory but not in ppapi.gyp:', \
-      in_file_not_gyp
+    print('Found source file(s) in the directory but not in ppapi.gyp:', \
+      in_file_not_gyp)
   error_count = len(in_gyp_not_file) + len(in_file_not_gyp)
   if error_count:
     sys.exit(error_count)
@@ -122,7 +124,7 @@
       sources = target[GYP_SOURCES_KEY]
       sources.sort()
       return sources
-  print 'Warning: no target named ', target, ' found.'
+  print('Warning: no target named ', target, ' found.')
   return []
 
 
@@ -168,4 +170,4 @@
 
 
 if __name__ == '__main__':
-    sys.exit(main())
+  sys.exit(main())
diff --git a/generate_ppapi_size_checks.py b/generate_ppapi_size_checks.py
index 11b4d98..a2b8e7d 100755
--- a/generate_ppapi_size_checks.py
+++ b/generate_ppapi_size_checks.py
@@ -7,6 +7,8 @@
 have appropriate size checking.
 """
 
+from __future__ import print_function
+
 import optparse
 import os
 import subprocess
@@ -166,12 +168,12 @@
     return
   elif typeinfo.name in typeinfo_map:
     if typeinfo.size != typeinfo_map[typeinfo.name].size:
-      print "Error: '" + typeinfo.name + "' is", \
+      print("Error: '" + typeinfo.name + "' is", \
           typeinfo_map[typeinfo.name].size, \
           "bytes on target '" + typeinfo_map[typeinfo.name].target + \
-          "', but", typeinfo.size, "on target '" + typeinfo.target + "'"
-      print typeinfo_map[typeinfo.name].parsed_line
-      print typeinfo.parsed_line
+          "', but", typeinfo.size, "on target '" + typeinfo.target + "'")
+      print(typeinfo_map[typeinfo.name].parsed_line)
+      print(typeinfo.parsed_line)
       sys.exit(1)
     else:
       # It's already in the map and the sizes match.
@@ -286,7 +288,7 @@
   options, args = parser.parse_args(argv)
   if args:
     parser.print_help()
-    print 'ERROR: invalid argument'
+    print('ERROR: invalid argument')
     sys.exit(1)
 
   clang_executable = os.path.join(options.clang_path, 'clang')
@@ -347,15 +349,15 @@
         # The sizes don't match, but there's no reason they couldn't.  It's
         # probably due to an alignment mismatch between Win32/NaCl vs Linux32/
         # Mac32.
-        print "Error: '" + typename + "' is", typeinfo32.size, \
+        print("Error: '" + typename + "' is", typeinfo32.size, \
             "bytes on target '" + typeinfo32.target + \
-            "', but", typeinfo64.size, "on target '" + typeinfo64.target + "'"
-        print typeinfo32.parsed_line
-        print typeinfo64.parsed_line
+            "', but", typeinfo64.size, "on target '" + typeinfo64.target + "'")
+        print(typeinfo32.parsed_line)
+        print(typeinfo64.parsed_line)
         sys.exit(1)
     else:
-      print "WARNING:  Type '", typename, "' was defined for target '",
-      print typeinfo32.target, ", but not for any 64-bit targets."
+      print("WARNING:  Type '", typename, "' was defined for target '")
+      print(typeinfo32.target, ", but not for any 64-bit targets.")
 
   # Now we have all the information we need to generate our static assertions.
   # Types that have consistent size across architectures will have the static
@@ -421,4 +423,4 @@
 
 
 if __name__ == '__main__':
-    sys.exit(main(sys.argv[1:]))
+  sys.exit(main(sys.argv[1:]))
diff --git a/generators/generator.py b/generators/generator.py
index a71893c..702bc1b 100755
--- a/generators/generator.py
+++ b/generators/generator.py
@@ -3,6 +3,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import os
 import sys
 import traceback
@@ -31,27 +33,28 @@
       current_dir = os.path.abspath(os.getcwd())
       script_dir = os.path.abspath(os.path.dirname(__file__))
       if current_dir != script_dir:
-        print '\nIncorrect CWD, default run skipped.'
-        print 'When running with no arguments set CWD to the scripts directory:'
-        print '\t' + script_dir + '\n'
-        print 'This ensures correct default paths and behavior.\n'
+        print('\nIncorrect CWD, default run skipped.')
+        print(
+            'When running with no arguments set CWD to the scripts directory:')
+        print('\t' + script_dir + '\n')
+        print('This ensures correct default paths and behavior.\n')
         return 1
 
     filenames = ParseOptions(args)
     ast = ParseFiles(filenames)
     if ast.errors:
-      print 'Found %d errors.  Aborting build.\n' % ast.errors
+      print('Found %d errors.  Aborting build.\n' % ast.errors)
       return 1
     return Generator.Run(ast)
-  except SystemExit, ec:
-    print 'Exiting with %d' % ec.code
+  except SystemExit as ec:
+    print('Exiting with %d' % ec.code)
     sys.exit(ec.code)
 
   except:
     typeinfo, value, tb = sys.exc_info()
     traceback.print_exception(typeinfo, value, tb)
-    print 'Called with: ' + ' '.join(sys.argv)
+    print('Called with: ' + ' '.join(sys.argv))
 
 
 if __name__ == '__main__':
-    sys.exit(Main(sys.argv[1:]))
+  sys.exit(Main(sys.argv[1:]))
diff --git a/generators/idl_ast.py b/generators/idl_ast.py
index e95e94e..19be3d4 100644
--- a/generators/idl_ast.py
+++ b/generators/idl_ast.py
@@ -4,6 +4,8 @@
 
 """Nodes for PPAPI IDL AST."""
 
+from __future__ import print_function
+
 from idl_namespace import IDLNamespace
 from idl_node import IDLNode
 from idl_option import GetOption
@@ -71,7 +73,7 @@
     if node.cls not in self.NamespaceSet:
       node.namespace = parent_namespace
     else:
-    # otherwise create one.
+      # otherwise create one.
       node.namespace = IDLNamespace(parent_namespace)
 
     # If this node is named, place it in its parent's namespace
@@ -116,7 +118,7 @@
     if not node.IsA('AST'):
       file_min, _ = filenode.release_map.GetReleaseRange()
       if not file_min:
-        print 'Resetting min on %s to %s' % (node, file_min)
+        print('Resetting min on %s to %s' % (node, file_min))
         node.SetMinRange(file_min)
 
     # If this node has a TYPEREF, resolve it to a version list
diff --git a/generators/idl_c_header.py b/generators/idl_c_header.py
index 7577682..d597f71 100755
--- a/generators/idl_c_header.py
+++ b/generators/idl_c_header.py
@@ -5,6 +5,8 @@
 
 """ Generator for C style prototypes and definitions """
 
+from __future__ import print_function
+
 import glob
 import os
 import re
@@ -96,7 +98,7 @@
   for node in filenode.GetListOf(*top_types):
     # Skip if this node is not in this release
     if not node.InReleases(releases):
-      print "Skiping %s" % node
+      print("Skiping %s" % node)
       continue
 
     # End/Start group marker
@@ -199,7 +201,7 @@
     my_min, my_max = filenode.GetMinMax(releases)
     if my_min > releases[-1] or my_max < releases[0]:
       if os.path.isfile(savename):
-        print "Removing stale %s for this range." % filenode.GetName()
+        print("Removing stale %s for this range." % filenode.GetName())
         os.remove(os.path.realpath(savename))
       return False
 
@@ -350,10 +352,10 @@
   filenames = glob.glob(idldir)
   ast = ParseFiles(filenames)
   if hgen.GenerateRelease(ast, 'M14', {}):
-    print "Golden file for M14 failed."
+    print("Golden file for M14 failed.")
     failed = 1
   else:
-    print "Golden file for M14 passed."
+    print("Golden file for M14 passed.")
 
 
   idldir = os.path.split(sys.argv[0])[0]
@@ -362,10 +364,10 @@
 
   ast = ParseFiles(filenames)
   if hgen.GenerateRange(ast, ['M13', 'M14', 'M15', 'M16', 'M17'], {}):
-    print "Golden file for M13-M17 failed."
+    print("Golden file for M13-M17 failed.")
     failed =1
   else:
-    print "Golden file for M13-M17 passed."
+    print("Golden file for M13-M17 passed.")
 
   return failed
 
diff --git a/generators/idl_c_proto.py b/generators/idl_c_proto.py
index d5c99a7..8404b79 100755
--- a/generators/idl_c_proto.py
+++ b/generators/idl_c_proto.py
@@ -5,6 +5,8 @@
 
 """ Generator for C style prototypes and definitions """
 
+from __future__ import print_function
+
 import glob
 import os
 import sys
@@ -199,7 +201,7 @@
   def Log(self, txt):
     if not GetOption('cgen_debug'): return
     tabs = '  ' * self.dbg_depth
-    print '%s%s' % (tabs, txt)
+    print('%s%s' % (tabs, txt))
 
   def LogEnter(self, txt):
     if txt: self.Log(txt)
@@ -766,7 +768,7 @@
 
     outstr = cgen.Define(node, releases=['M14'])
     if GetOption('verbose'):
-      print outstr + '\n'
+      print(outstr + '\n')
     outstr = CleanString(outstr)
 
     if instr != outstr:
@@ -809,10 +811,10 @@
   cgen = CGen()
   for f in ast.GetListOf('File'):
     if f.GetProperty('ERRORS') > 0:
-      print 'Skipping %s' % f.GetName()
+      print('Skipping %s' % f.GetName())
       continue
     for node in f.GetChildren()[2:]:
-      print cgen.Define(node, ast.releases, comment=True, prefix='tst_')
+      print(cgen.Define(node, ast.releases, comment=True, prefix='tst_'))
 
 
 if __name__ == '__main__':
diff --git a/generators/idl_diff.py b/generators/idl_diff.py
index 0d15fe8..7fd83cb 100755
--- a/generators/idl_diff.py
+++ b/generators/idl_diff.py
@@ -3,6 +3,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import glob
 import os
 import subprocess
@@ -37,16 +39,16 @@
 
   def Dump(self):
     if not self.was:
-      print 'Adding %s' % self.mode
+      print('Adding %s' % self.mode)
     elif not self.now:
-      print 'Missing %s' % self.mode
+      print('Missing %s' % self.mode)
     else:
-      print 'Modifying %s' % self.mode
+      print('Modifying %s' % self.mode)
 
     for line in self.was:
-      print 'src: >>%s<<' % line
+      print('src: >>%s<<' % line)
     for line in self.now:
-      print 'gen: >>%s<<' % line
+      print('gen: >>%s<<' % line)
     print
 
 #
@@ -234,7 +236,7 @@
         filter[nindex] = True
         filter[windex] = True
         if GetOption('verbose'):
-          print "Found %d, %d >>%s<<" % (windex + 1, nindex + 1, wline)
+          print("Found %d, %d >>%s<<" % (windex + 1, nindex + 1, wline))
   out = []
   for index in range(len(output)):
     if not filter[index]:
@@ -259,7 +261,7 @@
   last = None
 
   for line in lines:
-#    print "LINE=%s" % line
+    #print("LINE=%s" % line)
     if not line: continue
 
     elif line[0] == '<':
@@ -282,7 +284,7 @@
       was = []
       now = []
       if ValidChange(change):
-          changes.append(change)
+        changes.append(change)
       if line == 'END':
         break
 
@@ -315,7 +317,7 @@
       name = os.path.split(name)[1]
       name = os.path.join(GetOption('gen'), name)
       if name not in filenames:
-        print 'Missing: %s' % name
+        print('Missing: %s' % name)
 
   for filename in filenames:
     gen = filename
@@ -336,18 +338,19 @@
       changes = []
 
     if changes:
-      print "\n\nDelta between:\n  src=%s\n  gen=%s\n" % (src, gen)
+      print("\n\nDelta between:\n  src=%s\n  gen=%s\n" % (src, gen))
       for change in changes:
         change.Dump()
-      print 'Done with %s\n\n' % src
+      print('Done with %s\n\n' % src)
       if GetOption('ok'):
         open(diff, 'wt').write(output)
       if GetOption('halt'):
         return 1
     else:
-      print "\nSAME:\n  src=%s\n  gen=%s" % (src, gen)
-      if input: print '  ** Matched expected diff. **'
-      print '\n'
+      print("\nSAME:\n  src=%s\n  gen=%s" % (src, gen))
+      if input:
+        print('  ** Matched expected diff. **')
+      print('\n')
 
 
 if __name__ == '__main__':
diff --git a/generators/idl_generator.py b/generators/idl_generator.py
index 028a233..0477100 100755
--- a/generators/idl_generator.py
+++ b/generators/idl_generator.py
@@ -3,6 +3,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import sys
 
 from idl_log import ErrOut, InfoOut, WarnOut
@@ -66,7 +68,7 @@
     rangestr = GetOption('range')
     releasestr = GetOption('release')
 
-    print "Found releases: %s" % ast.releases
+    print("Found releases: %s" % ast.releases)
 
     # Generate list of files to ignore due to errors
     for filenode in ast.GetListOf('File'):
@@ -87,9 +89,9 @@
 
         # Generate 'start' and 'end' represent first and last found.
         if vmin == 'start':
-            vmin = ast.releases[0]
+          vmin = ast.releases[0]
         if vmax == 'end':
-            vmax = ast.releases[-1]
+          vmax = ast.releases[-1]
 
         vmin = ast.releases.index(vmin)
         vmax = ast.releases.index(vmax) + 1
@@ -223,7 +225,7 @@
       check_item = check_map[item]
       option_item = options.get(item, None)
       if check_item != option_item:
-        print 'Option %s is %s, expecting %s' % (item, option_item, check_item)
+        print('Option %s is %s, expecting %s' % (item, option_item, check_item))
         check_release = 0
 
     if release != 'M14':
@@ -243,24 +245,24 @@
 
   ParseOptions(['--testgen_opt=so_long,MyOpt=XYZ,goodbye'])
   if Generator.Run('AST') != 0:
-    print 'Generate release: Failed.\n'
+    print('Generate release: Failed.\n')
     return -1
 
   if check_release != 1 or check_range != 0:
-    print 'Gererate release: Failed to run.\n'
+    print('Gererate release: Failed to run.\n')
     return -1
 
   check_release = 0
   ParseOptions(['--testgen_opt="HELLO"', '--range=M14,M16'])
   if Generator.Run('AST') != 0:
-    print 'Generate range: Failed.\n'
+    print('Generate range: Failed.\n')
     return -1
 
   if check_release != 0 or check_range != 1:
-    print 'Gererate range: Failed to run.\n'
+    print('Gererate range: Failed to run.\n')
     return -1
 
-  print 'Generator test: Pass'
+  print('Generator test: Pass')
   return 0
 
 
diff --git a/generators/idl_lexer.py b/generators/idl_lexer.py
index 47d64a2..1c9492e 100755
--- a/generators/idl_lexer.py
+++ b/generators/idl_lexer.py
@@ -16,6 +16,8 @@
 # PLY can be found at:
 #   http://www.dabeaz.com/ply/
 
+from __future__ import print_function
+
 import os.path
 import re
 import sys
@@ -277,23 +279,23 @@
   count1 = len(values1)
   count2 = len(values2)
   if count1 != count2:
-    print "Size mismatch original %d vs %d\n" % (count1, count2)
+    print("Size mismatch original %d vs %d\n" % (count1, count2))
     if count1 > count2: count1 = count2
 
   for i in range(count1):
     if values1[i] != values2[i]:
-      print "%d >>%s<< >>%s<<" % (i, values1[i], values2[i])
+      print("%d >>%s<< >>%s<<" % (i, values1[i], values2[i]))
 
   if GetOption('output'):
     sys.stdout.write('Generating original.txt and tokenized.txt\n')
-    open('original.txt', 'w').write(src1)
-    open('tokenized.txt', 'w').write(src2)
+    open('original.txt', 'w').write(values1)
+    open('tokenized.txt', 'w').write(values2)
 
   if values1 == values2:
     sys.stdout.write('Same: Pass\n')
     return 0
 
-  print "****************\n%s\n%s***************\n" % (src1, src2)
+  print("****************\n%s\n%s***************\n" % (values1, values2))
   sys.stdout.write('Same: Failed\n')
   return -1
 
diff --git a/generators/idl_namespace.py b/generators/idl_namespace.py
index 21a643c..5630ae2 100755
--- a/generators/idl_namespace.py
+++ b/generators/idl_namespace.py
@@ -10,6 +10,8 @@
 a symbol as one or more AST nodes given a release or range of releases.
 """
 
+from __future__ import print_function
+
 import sys
 
 from idl_option import GetOption, Option, ParseOptions
@@ -68,7 +70,7 @@
     name = node.GetName()
     verlist = self._name_to_releases.setdefault(name,IDLReleaseList())
     if GetOption('namespace_debug'):
-        print "Adding to namespace: %s" % node
+      print("Adding to namespace: %s" % node)
     return verlist.AddNode(node)
 
 
@@ -101,11 +103,13 @@
     return self.name
 
   def Error(self, msg):
-    if GetOption('release_debug'): print 'Error: %s' % msg
+    if GetOption('release_debug'):
+      print('Error: %s' % msg)
     self.errors.append(msg)
 
   def Warn(self, msg):
-    if GetOption('release_debug'): print 'Warn: %s' % msg
+    if GetOption('release_debug'):
+      print('Warn: %s' % msg)
     self.warns.append(msg)
 
   def GetProperty(self, name):
@@ -118,15 +122,15 @@
 # Dumps all the information relevant  to an add failure.
 def DumpFailure(namespace, node, msg):
   global errors
-  print '\n******************************'
-  print 'Failure: %s %s' % (node, msg)
+  print('\n******************************')
+  print('Failure: %s %s' % (node, msg))
   for warn in node.warns:
-    print '  WARN: %s' % warn
+    print('  WARN: %s' % warn)
   for err in node.errors:
-    print '  ERROR: %s' % err
-  print '\n'
+    print('  ERROR: %s' % err)
+  print('\n')
   namespace.Dump()
-  print '******************************\n'
+  print('******************************\n')
   errors += 1
 
 # Add expecting no errors or warnings
@@ -150,15 +154,15 @@
     DumpFailure(namespace, node, 'Expected errors')
   if msg not in node.errors:
     DumpFailure(namespace, node, 'Expected error: %s' % msg)
-    print ">>%s<<\n>>%s<<\n" % (node.errors[0], msg)
+    print(">>%s<<\n>>%s<<\n" % (node.errors[0], msg))
 
 # Verify that a FindRelease call on the namespace returns the expected node.
 def VerifyFindOne(namespace, name, release, node):
   global errors
   if (namespace.FindRelease(name, release) != node):
-    print "Failed to find %s as release %f of %s" % (node, release, name)
+    print("Failed to find %s as release %f of %s" % (node, release, name))
     namespace.Dump()
-    print "\n"
+    print("\n")
     errors += 1
 
 # Verify that a FindRage call on the namespace returns a set of expected nodes.
@@ -166,14 +170,11 @@
   global errors
   out = namespace.FindRange(name, rmin, rmax)
   if (out != nodes):
-    print "Found [%s] instead of[%s] for releases %f to %f of %s" % (
-        ' '.join([str(x) for x in out]),
-        ' '.join([str(x) for x in nodes]),
-        rmin,
-        rmax,
-        name)
+    print("Found [%s] instead of[%s] for releases %f to %f of %s" % (' '.join([
+        str(x) for x in out
+    ]), ' '.join([str(x) for x in nodes]), rmin, rmax, name))
     namespace.Dump()
-    print "\n"
+    print("\n")
     errors += 1
 
 def Main(args):
@@ -238,9 +239,9 @@
   AddOkay(namespace, FooBar)
 
   if errors:
-    print 'Test failed with %d errors.' % errors
+    print('Test failed with %d errors.' % errors)
   else:
-    print 'Passed.'
+    print('Passed.')
   return errors
 
 
diff --git a/generators/idl_option.py b/generators/idl_option.py
index 54ac4cf..c1a2509 100644
--- a/generators/idl_option.py
+++ b/generators/idl_option.py
@@ -100,7 +100,7 @@
       if opt[0:2] == '--': opt = opt[2:]
       OptionMap[opt].Set(val)
 
-  except getopt.error, e:
+  except getopt.error as e:
     ErrOut.Log('Illegal option: %s\n' % str(e))
     DumpHelp()
     sys.exit(-1)
diff --git a/generators/idl_outfile.py b/generators/idl_outfile.py
index f6a1627..9b830ad 100755
--- a/generators/idl_outfile.py
+++ b/generators/idl_outfile.py
@@ -140,8 +140,8 @@
         InfoOut.Log('Output %s written.' % self.filename)
       return True
 
-    except IOError as (errno, strerror):
-      ErrOut.Log("I/O error(%d): %s" % (errno, strerror))
+    except IOError as e:
+      ErrOut.Log("I/O error(%d): %s" % (e.errno, e.strerror))
     except:
       ErrOut.Log("Unexpected error: %s" % sys.exc_info()[0])
       raise
diff --git a/generators/idl_release.py b/generators/idl_release.py
index 4406854..ce95ec8 100755
--- a/generators/idl_release.py
+++ b/generators/idl_release.py
@@ -10,6 +10,8 @@
 a symbol as one or more AST nodes given a Release or range of Releases.
 """
 
+from __future__ import print_function
+
 import sys
 
 from idl_log import ErrOut, InfoOut, WarnOut
@@ -272,7 +274,7 @@
   assert Foo23.InRange('M14', 'M15A')
   assert Foo23.InRange('M15B', 'M17')
   assert not Foo23.InRange('M16', 'M17')
-  print "TestReleaseNode - Passed"
+  print("TestReleaseNode - Passed")
 
 
 def TestReleaseListWarning():
@@ -287,7 +289,7 @@
   assert releases.AddNode(Foo23)
   assert releases.AddNode(Foo45)
   assert warning
-  print "TestReleaseListWarning - Passed"
+  print("TestReleaseListWarning - Passed")
 
 
 def TestReleaseListError():
@@ -303,7 +305,7 @@
   assert releases.AddNode(Foo23)
   assert not releases.AddNode(Foo1X)
   assert error
-  print "TestReleaseListError - Passed"
+  print("TestReleaseListError - Passed")
 
 
 def TestReleaseListOK():
@@ -335,11 +337,11 @@
   assert releases.FindRange(None, None) == [FooXX, Foo1X, Foo23, Foo45]
 
   # Verify we can find the correct versions
-  print "TestReleaseListOK - Passed"
+  print("TestReleaseListOK - Passed")
 
 
 def TestReleaseMap():
-  print "TestReleaseMap- Passed"
+  print("TestReleaseMap- Passed")
 
 
 def Main(args):
@@ -347,7 +349,7 @@
   TestReleaseListWarning()
   TestReleaseListError()
   TestReleaseListOK()
-  print "Passed"
+  print("Passed")
   return 0
 
 
diff --git a/generators/idl_tests.py b/generators/idl_tests.py
index b41bb0f..7b732bc 100755
--- a/generators/idl_tests.py
+++ b/generators/idl_tests.py
@@ -5,17 +5,19 @@
 
 """ Test runner for IDL Generator changes """
 
+from __future__ import print_function
+
 import subprocess
 import sys
 
 def TestIDL(testname, args):
-  print '\nRunning unit tests for %s.' % testname
+  print('\nRunning unit tests for %s.' % testname)
   try:
     args = [sys.executable, testname] + args
     subprocess.check_call(args)
     return 0
   except subprocess.CalledProcessError as err:
-    print 'Failed with %s.' % str(err)
+    print('Failed with %s.' % str(err))
     return 1
 
 def main(args):
@@ -36,7 +38,7 @@
   assert errors == 0
 
   if errors:
-    print '\nFailed tests.'
+    print('\nFailed tests.')
   return errors
 
 
diff --git a/generators/idl_thunk.py b/generators/idl_thunk.py
index 75117d2..ff7bdfd 100755
--- a/generators/idl_thunk.py
+++ b/generators/idl_thunk.py
@@ -5,6 +5,8 @@
 
 """ Generator for C++ style thunks """
 
+from __future__ import print_function
+
 import glob
 import os
 import re
@@ -423,7 +425,7 @@
     my_min, my_max = filenode.GetMinMax(releases)
     if my_min > releases[-1] or my_max < releases[0]:
       if os.path.isfile(savename):
-        print "Removing stale %s for this range." % filenode.GetName()
+        print("Removing stale %s for this range." % filenode.GetName())
         os.remove(os.path.realpath(savename))
       return False
     do_generate = filenode.GetProperty('generate_thunk')
@@ -493,7 +495,7 @@
     for node in filenode.GetListOf('Interface'):
       # Skip if this node is not in this release
       if not node.InReleases(releases):
-        print "Skipping %s" % node
+        print("Skipping %s" % node)
         continue
 
       # Generate Member functions
@@ -572,10 +574,10 @@
   filenames = glob.glob(idldir)
   ast = ParseFiles(filenames)
   if tgen.GenerateRange(ast, ['M13', 'M14', 'M15'], {}):
-    print "Golden file for M13-M15 failed."
+    print("Golden file for M13-M15 failed.")
     failed = 1
   else:
-    print "Golden file for M13-M15 passed."
+    print("Golden file for M13-M15 passed.")
 
   return failed
 
diff --git a/native_client/tools/browser_tester/browser_tester.py b/native_client/tools/browser_tester/browser_tester.py
index 87cafe4..c9b7ce6 100755
--- a/native_client/tools/browser_tester/browser_tester.py
+++ b/native_client/tools/browser_tester/browser_tester.py
@@ -3,6 +3,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import glob
 import optparse
 import os.path
@@ -226,7 +228,7 @@
   file_mapping = dict(options.map_files)
   for filename in options.files:
     file_mapping[os.path.basename(filename)] = filename
-  for server_path, real_path in file_mapping.iteritems():
+  for _, real_path in file_mapping.items():
     if not os.path.exists(real_path):
       raise AssertionError('\'%s\' does not exist.' % real_path)
   mime_types = {}
@@ -385,7 +387,7 @@
   options, args = parser.parse_args()
 
   if len(args) != 0:
-    print args
+    print(args)
     parser.error('Invalid arguments')
 
   # Validate the URL
diff --git a/native_client/tools/browser_tester/browsertester/browserlauncher.py b/native_client/tools/browser_tester/browsertester/browserlauncher.py
index d6b29ce..497cb94 100755
--- a/native_client/tools/browser_tester/browsertester/browserlauncher.py
+++ b/native_client/tools/browser_tester/browsertester/browserlauncher.py
@@ -3,6 +3,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import os.path
 import re
 import shutil
@@ -193,8 +195,8 @@
                            self.options.nacl_exe_stdout, True)
     self.SetStandardStream(env, 'NACL_EXE_STDERR',
                            self.options.nacl_exe_stderr, True)
-    print 'ENV:', ' '.join(['='.join(pair) for pair in env.iteritems()])
-    print 'LAUNCHING: %s' % ' '.join(cmd)
+    print('ENV:', ' '.join(['='.join(pair) for pair in env.items()]))
+    print('LAUNCHING: %s' % ' '.join(cmd))
     sys.stdout.flush()
     self.browser_process = RunCommand(cmd, env=env)
 
diff --git a/native_client/tools/browser_tester/browsertester/browserprocess.py b/native_client/tools/browser_tester/browsertester/browserprocess.py
index e10e6b5..d012eb2 100755
--- a/native_client/tools/browser_tester/browsertester/browserprocess.py
+++ b/native_client/tools/browser_tester/browsertester/browserprocess.py
@@ -3,6 +3,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import os
 import signal
 import subprocess
@@ -12,7 +14,7 @@
 
   def __init__(self, handle):
     self.handle = handle
-    print 'PID', self.handle.pid
+    print('PID', self.handle.pid)
 
   def GetReturnCode(self):
     return self.handle.returncode
@@ -36,7 +38,7 @@
 
   def Kill(self):
     if self.IsRunning():
-      print 'KILLING the browser'
+      print('KILLING the browser')
       try:
         self.kill()
         # If it doesn't die, we hang.  Oh well.
@@ -76,7 +78,7 @@
 def RunCommandInProcessGroup(cmd, env=None):
   def SetPGrp():
     os.setpgrp()
-    print 'I\'M THE SESSION LEADER!'
+    print('I\'M THE SESSION LEADER!')
+
   handle = subprocess.Popen(cmd, env=env, preexec_fn=SetPGrp)
   return BrowserProcessPosix(handle)
-
diff --git a/native_client/tools/browser_tester/browsertester/server.py b/native_client/tools/browser_tester/browsertester/server.py
index 971d0d6..454f6ee 100644
--- a/native_client/tools/browser_tester/browsertester/server.py
+++ b/native_client/tools/browser_tester/browsertester/server.py
@@ -59,17 +59,17 @@
     return path
 
   def guess_type(self, path):
-      # We store the extension -> MIME type mapping in the server instead of the
-      # request handler so we that can add additional mapping entries via the
-      # command line.
-      base, ext = posixpath.splitext(path)
-      if ext in self.server.extensions_mapping:
-          return self.server.extensions_mapping[ext]
-      ext = ext.lower()
-      if ext in self.server.extensions_mapping:
-          return self.server.extensions_mapping[ext]
-      else:
-          return self.server.extensions_mapping['']
+    # We store the extension -> MIME type mapping in the server instead of the
+    # request handler so we that can add additional mapping entries via the
+    # command line.
+    _, ext = posixpath.splitext(path)
+    if ext in self.server.extensions_mapping:
+      return self.server.extensions_mapping[ext]
+    ext = ext.lower()
+    if ext in self.server.extensions_mapping:
+      return self.server.extensions_mapping[ext]
+    else:
+      return self.server.extensions_mapping['']
 
   def SendRPCResponse(self, response):
     self.send_response(200)
@@ -84,14 +84,14 @@
 
   def HandleRPC(self, name, query):
     kargs = {}
-    for k, v in query.iteritems():
+    for k, v in query.items():
       assert len(v) == 1, k
       kargs[k] = v[0]
 
     l = self.server.listener
     try:
       response = getattr(l, name)(**kargs)
-    except Exception, e:
+    except Exception as e:
       self.SendRPCResponse('%r' % (e,))
       raise
     else:
@@ -139,7 +139,7 @@
       try:
         data = self.rfile.read(int(self.headers.getheader('content-length')))
         outfile.write(data)
-      except IOError, e:
+      except IOError as e:
         outfile.close()
         try:
           os.remove(output_path)