Make various Python scripts more compatible with Python 3.
- Switch to print() in many places.
- Pick between itertools.imap() and map().
- Convert bytes to strings in a few places.
Bug: pdfium:1674
Change-Id: I46136989311c8b714f4a58f3621c34c50e32b67c
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/79490
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/testing/tools/api_check.py b/testing/tools/api_check.py
index 66b3077..f340243 100755
--- a/testing/tools/api_check.py
+++ b/testing/tools/api_check.py
@@ -12,6 +12,8 @@
"""
+from __future__ import print_function
+
import os
import re
import sys
@@ -106,9 +108,9 @@
if not failure_list:
return True
- print '%s:' % failure_message
+ print('%s:' % failure_message)
for f in sorted(failure_list):
- print f
+ print(f)
return False
diff --git a/testing/tools/common.py b/testing/tools/common.py
index 108fcfd..f086b13 100755
--- a/testing/tools/common.py
+++ b/testing/tools/common.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 datetime
import glob
import os
@@ -139,20 +141,21 @@
cwd = os.getcwd()
os.chdir(build_dir)
gn_args_output = subprocess.check_output(
- ['gn', 'args', '.', '--list=%s' % arg_name, '--short'])
+ ['gn', 'args', '.', '--list=%s' % arg_name, '--short']).decode('utf8')
os.chdir(cwd)
arg_match_output = re.search('%s = (.*)' % arg_name, gn_args_output).group(1)
if verbose:
- print >> sys.stderr, "Found '%s' for value of %s" % (arg_match_output,
- arg_name)
+ print(
+ "Found '%s' for value of %s" % (arg_match_output, arg_name),
+ file=sys.stderr)
return arg_match_output == 'true'
def PrintWithTime(s):
"""Prints s prepended by a timestamp."""
- print '[%s] %s' % (datetime.datetime.now().strftime("%Y%m%d %H:%M:%S"), s)
+ print('[%s] %s' % (datetime.datetime.now().strftime("%Y%m%d %H:%M:%S"), s))
def PrintErr(s):
"""Prints s to stderr."""
- print >> sys.stderr, s
+ print(s, file=sys.stderr)
diff --git a/testing/tools/coverage/coverage_report.py b/testing/tools/coverage/coverage_report.py
index 7261390..71ab401 100755
--- a/testing/tools/coverage/coverage_report.py
+++ b/testing/tools/coverage/coverage_report.py
@@ -8,6 +8,8 @@
Prefers that 'is_component_build = false' is set in args.gn.
"""
+from __future__ import print_function
+
import argparse
from collections import namedtuple
import fnmatch
@@ -115,38 +117,38 @@
def check_output(self, args, dry_run=False, env=None):
"""Dry run aware wrapper of subprocess.check_output()"""
if dry_run:
- print "Would have run '%s'" % ' '.join(args)
+ print("Would have run '%s'" % ' '.join(args))
return ''
output = subprocess.check_output(args, env=env)
if self.verbose:
- print "check_output(%s) returned '%s'" % (args, output)
+ print("check_output(%s) returned '%s'" % (args, output))
return output
def call(self, args, dry_run=False, env=None):
"""Dry run aware wrapper of subprocess.call()"""
if dry_run:
- print "Would have run '%s'" % ' '.join(args)
+ print("Would have run '%s'" % ' '.join(args))
return 0
output = subprocess.call(args, env=env)
if self.verbose:
- print 'call(%s) returned %s' % (args, output)
+ print('call(%s) returned %s' % (args, output))
return output
def call_silent(self, args, dry_run=False, env=None):
"""Dry run aware wrapper of subprocess.call() that eats output from call"""
if dry_run:
- print "Would have run '%s'" % ' '.join(args)
+ print("Would have run '%s'" % ' '.join(args))
return 0
with open(os.devnull, 'w') as f:
output = subprocess.call(args, env=env, stdout=f)
if self.verbose:
- print 'call_silent(%s) returned %s' % (args, output)
+ print('call_silent(%s) returned %s' % (args, output))
return output
def calculate_coverage_tests(self, args):
@@ -192,10 +194,10 @@
spec: Tuple containing the TestSpec.
"""
if self.verbose:
- print "Generating coverage for test '%s', using data '%s'" % (name, spec)
+ print("Generating coverage for test '%s', using data '%s'" % (name, spec))
if not os.path.exists(spec.binary):
print('Unable to generate coverage for %s, since it appears to not exist'
- ' @ %s') % (name, spec.binary)
+ ' @ %s' % (name, spec.binary))
return False
binary_args = [spec.binary]
@@ -218,7 +220,7 @@
binary_args.extend(['-j', '8', '--build-dir', self.build_directory])
if self.call(binary_args, dry_run=self.dry_run, env=env) and self.verbose:
print('Running %s appears to have failed, which might affect '
- 'results') % spec.binary
+ 'results' % spec.binary)
return True
@@ -267,24 +269,24 @@
def run(self):
"""Setup environment, execute the tests and generate coverage report"""
if not self.fetch_profiling_tools():
- print 'Unable to fetch profiling tools'
+ print('Unable to fetch profiling tools')
return False
if not self.build_binaries():
- print 'Failed to successfully build binaries'
+ print('Failed to successfully build binaries')
return False
for name in self.coverage_tests.keys():
if not self.generate_coverage(name, self.coverage_tests[name]):
- print 'Failed to successfully generate coverage data'
+ print('Failed to successfully generate coverage data')
return False
if not self.merge_raw_coverage_results():
- print 'Failed to successfully merge raw coverage results'
+ print('Failed to successfully merge raw coverage results')
return False
if not self.generate_html_report():
- print 'Failed to successfully generate HTML report'
+ print('Failed to successfully generate HTML report')
return False
return True
diff --git a/testing/tools/fixup_pdf_template.py b/testing/tools/fixup_pdf_template.py
index 808c0bb..91d9cf0 100755
--- a/testing/tools/fixup_pdf_template.py
+++ b/testing/tools/fixup_pdf_template.py
@@ -17,6 +17,9 @@
{{streamlen}} - expands to |/Length n|.
"""
+from __future__ import print_function
+
+# TODO(thestig): Figure out what to do with cStringIO.
import cStringIO
import optparse
import os
@@ -146,13 +149,13 @@
for line in preprocessed:
outfile.write(processor.process_line(line))
except IOError:
- print >> sys.stderr, 'failed to process %s' % input_path
+ print('failed to process %s' % input_path, file=sys.stderr)
def insert_includes(input_path, output_file, visited_set):
input_path = os.path.normpath(input_path)
if input_path in visited_set:
- print >> sys.stderr, 'Circular inclusion %s, ignoring' % input_path
+ print('Circular inclusion %s, ignoring' % input_path, file=sys.stderr)
return
visited_set.add(input_path)
try:
@@ -170,7 +173,7 @@
line = line.replace(WINDOWS_LINE_ENDING, UNIX_LINE_ENDING)
output_file.write(line)
except IOError:
- print >> sys.stderr, 'failed to include %s' % input_path
+ print('failed to include %s' % input_path, file=sys.stderr)
raise
visited_set.discard(input_path)
diff --git a/testing/tools/pngdiffer.py b/testing/tools/pngdiffer.py
index 63315c9..911da10 100755
--- a/testing/tools/pngdiffer.py
+++ b/testing/tools/pngdiffer.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 distutils.spawn
import itertools
import os
@@ -56,6 +58,16 @@
else:
self.max_path_mode = PathMode.DEFAULT
+ @staticmethod
+ def _GetMapFunc():
+ try:
+ # Only exists in Python 2.
+ func = itertools.imap
+ except AttributeError:
+ # Python 3's map returns an iterator.
+ func = map
+ return func
+
def CheckMissingTools(self, regenerate_expected):
if (regenerate_expected and self.os_name == 'linux' and
not distutils.spawn.find_executable('optipng')):
@@ -70,7 +82,7 @@
for page in itertools.count():
actual_path = path_templates.GetActualPath(page)
expected_paths = path_templates.GetExpectedPaths(page)
- if any(itertools.imap(os.path.exists, expected_paths)):
+ if any(self._GetMapFunc()(os.path.exists, expected_paths)):
actual_paths.append(actual_path)
else:
break
@@ -92,15 +104,15 @@
for page in itertools.count():
actual_path = path_templates.GetActualPath(page)
expected_paths = path_templates.GetExpectedPaths(page)
- if not any(itertools.imap(os.path.exists, expected_paths)):
+ if not any(self._GetMapFunc()(os.path.exists, expected_paths)):
if page == 0:
- print "WARNING: no expected results files for " + input_filename
+ print("WARNING: no expected results files for " + input_filename)
if os.path.exists(actual_path):
print('FAILURE: Missing expected result for 0-based page %d of %s' %
(page, input_filename))
return True
break
- print "Checking " + actual_path
+ print("Checking " + actual_path)
sys.stdout.flush()
error = None
@@ -115,7 +127,7 @@
break
if error:
- print "FAILURE: " + input_filename + "; " + str(error)
+ print("FAILURE: " + input_filename + "; " + str(error))
return True
return False
diff --git a/testing/tools/safetynet_compare.py b/testing/tools/safetynet_compare.py
index c76ce44..8a5942d 100755
--- a/testing/tools/safetynet_compare.py
+++ b/testing/tools/safetynet_compare.py
@@ -4,6 +4,8 @@
# found in the LICENSE file.
"""Compares the performance of two versions of the pdfium code."""
+from __future__ import print_function
+
import argparse
import functools
import glob
@@ -564,7 +566,7 @@
ComparisonConclusions.GetOutputDict().
"""
if self.args.machine_readable:
- print json.dumps(conclusions_dict)
+ print(json.dumps(conclusions_dict))
else:
PrintConclusionsDictHumanReadable(
conclusions_dict, colored=True, key=self.args.case_order)
diff --git a/testing/tools/safetynet_conclusions.py b/testing/tools/safetynet_conclusions.py
index 8f0b28c..dc6e3dd 100644
--- a/testing/tools/safetynet_conclusions.py
+++ b/testing/tools/safetynet_conclusions.py
@@ -3,6 +3,8 @@
# found in the LICENSE file.
"""Classes that draw conclusions out of a comparison and represent them."""
+from __future__ import print_function
+
from collections import Counter
FORMAT_RED = '\033[01;31m{0}\033[00m'
@@ -245,9 +247,9 @@
key: String with the CaseResult dictionary key to sort the cases.
"""
# Print header
- print '=' * 80
- print '{0:>11s} {1:>15s} {2}'.format('% Change', 'Time after', 'Test case')
- print '-' * 80
+ print('=' * 80)
+ print('{0:>11s} {1:>15s} {2}'.format('% Change', 'Time after', 'Test case'))
+ print('-' * 80)
color = FORMAT_NORMAL
@@ -264,18 +266,18 @@
color = RATING_TO_COLOR[case_dict['rating']]
if case_dict['rating'] == RATING_FAILURE:
- print u'{} to measure time for {}'.format(
- color.format('Failed'), case_name).encode('utf-8')
+ print(u'{} to measure time for {}'.format(
+ color.format('Failed'), case_name).encode('utf-8'))
continue
- print u'{0} {1:15,d} {2}'.format(
+ print(u'{0} {1:15,d} {2}'.format(
color.format('{:+11.4%}'.format(case_dict['ratio'])),
- case_dict['after'], case_name).encode('utf-8')
+ case_dict['after'], case_name).encode('utf-8'))
# Print totals
totals = conclusions_dict['summary']
- print '=' * 80
- print 'Test cases run: %d' % totals['total']
+ print('=' * 80)
+ print('Test cases run: %d' % totals['total'])
if colored:
color = FORMAT_MAGENTA if totals[RATING_FAILURE] else FORMAT_GREEN
diff --git a/testing/tools/safetynet_image.py b/testing/tools/safetynet_image.py
index f300615..3161178 100644
--- a/testing/tools/safetynet_image.py
+++ b/testing/tools/safetynet_image.py
@@ -4,6 +4,8 @@
"""Compares pairs of page images and generates an HTML to look at differences.
"""
+from __future__ import print_function
+
import functools
import glob
import multiprocessing
@@ -63,7 +65,7 @@
# pylint: disable=attribute-defined-outside-init
if len(self.two_labels) != 2:
- print >> sys.stderr, 'two_labels must be a tuple of length 2'
+ print('two_labels must be a tuple of length 2', file=sys.stderr)
return 1
finder = DirectoryFinder(self.build_dir)
@@ -88,7 +90,7 @@
for image in self.image_locations.Images():
diff = difference[image]
if diff is None:
- print >> sys.stderr, 'Failed to compare image %s' % image
+ print('Failed to compare image %s' % image, file=sys.stderr)
elif diff > self.threshold:
self._WriteImageRows(f, image, diff)
else:
@@ -170,7 +172,7 @@
except subprocess.CalledProcessError as e:
return image, percentage_change
else:
- print >> sys.stderr, 'Warning: Should have failed the previous diff.'
+ print('Warning: Should have failed the previous diff.', file=sys.stderr)
return image, 0
def _GetRelativePath(self, absolute_path):
diff --git a/testing/tools/safetynet_measure.py b/testing/tools/safetynet_measure.py
index 3577189..35f1832 100755
--- a/testing/tools/safetynet_measure.py
+++ b/testing/tools/safetynet_measure.py
@@ -7,6 +7,8 @@
The output is a number that is a metric which depends on the profiler specified.
"""
+from __future__ import print_function
+
import argparse
import os
import re
@@ -65,7 +67,7 @@
if time is None:
return 1
- print time
+ print(time)
return 0
def _RunCallgrind(self):
diff --git a/testing/tools/suppressor.py b/testing/tools/suppressor.py
index 38351b5..2464289 100755
--- a/testing/tools/suppressor.py
+++ b/testing/tools/suppressor.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
# pylint: disable=relative-import
@@ -49,18 +51,18 @@
def IsResultSuppressed(self, input_filename):
if input_filename in self.suppression_set:
- print "%s result is suppressed" % input_filename
+ print("%s result is suppressed" % input_filename)
return True
return False
def IsExecutionSuppressed(self, input_filepath):
if "xfa_specific" in input_filepath and not self.has_xfa:
- print "%s execution is suppressed" % input_filepath
+ print("%s execution is suppressed" % input_filepath)
return True
return False
def IsImageDiffSuppressed(self, input_filename):
if input_filename in self.image_suppression_set:
- print "%s image diff comparison is suppressed" % input_filename
+ print("%s image diff comparison is suppressed" % input_filename)
return True
return False
diff --git a/testing/tools/test_runner.py b/testing/tools/test_runner.py
index 4a34938..a7198cc 100644
--- a/testing/tools/test_runner.py
+++ b/testing/tools/test_runner.py
@@ -379,7 +379,8 @@
os.makedirs(self.working_dir)
self.features = subprocess.check_output(
- [self.pdfium_test_path, '--show-config']).strip().split(',')
+ [self.pdfium_test_path,
+ '--show-config']).decode('utf-8').strip().split(',')
self.test_suppressor = suppressor.Suppressor(
finder, self.features, self.options.disable_javascript,
self.options.disable_xfa)
diff --git a/testing/tools/text_diff.py b/testing/tools/text_diff.py
index fdf45a0..b408e6e 100755
--- a/testing/tools/text_diff.py
+++ b/testing/tools/text_diff.py
@@ -3,13 +3,15 @@
# 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 difflib
import sys
def main(argv):
if len(argv) != 3:
- print '%s: invalid arguments' % argv[0]
+ print('%s: invalid arguments' % argv[0])
return 2
filename1 = argv[1]
filename2 = argv[2]
@@ -21,7 +23,7 @@
diffs = difflib.unified_diff(
str1, str2, fromfile=filename1, tofile=filename2)
except Exception as e:
- print "something went astray: %s" % e
+ print("something went astray: %s" % e)
return 1
status_code = 0
for diff in diffs: