From 26d62db3a616659c518619a2fd607555973b6447 Mon Sep 17 00:00:00 2001 From: wangshuo Date: Tue, 3 Mar 2020 16:17:59 +0800 Subject: [PATCH] boost: change py2 to py3 --- boost.spec | 32 +- change-scripts-from-py2-to-py3.patch | 7086 ++++++++++++++++++++++++++ 2 files changed, 7113 insertions(+), 5 deletions(-) create mode 100644 change-scripts-from-py2-to-py3.patch diff --git a/boost.spec b/boost.spec index a5d7253..6c8b921 100644 --- a/boost.spec +++ b/boost.spec @@ -21,7 +21,7 @@ Name: boost Version: 1.66.0 -Release: 16 +Release: 18 Summary: The free peer-reviewed portable C++ source libraries License: Boost and MIT and Python URL: http://www.boost.org @@ -72,6 +72,7 @@ Patch86: boost-1.66.0-python37.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1596468 # https://github.com/boostorg/python/pull/218 Patch87: boost-1.66.0-numpy3.patch +Patch88: change-scripts-from-py2-to-py3.patch Requires: boost-atomic%{?_isa} = %{version}-%{release} Requires: boost-chrono%{?_isa} = %{version}-%{release} @@ -442,7 +443,7 @@ configurable implementation of the mandated C99/C++ preprocessor functionality packed behind an easy to use iterator interface. %package devel -Summary: The Boost C++ headers, shared and static development libraries and examples +Summary: The Boost C++ headers, shared and static development libraries Requires: boost%{?_isa} = %{version}-%{release} Requires: libicu-devel%{?_isa} %if %{with quadmath} @@ -450,12 +451,10 @@ Requires: libquadmath-devel%{?_isa} %endif Provides: boost-static Obsoletes: boost-static -Provides: boost-examples -Obsoletes: boost-examples %description devel Headers shared object symbolic links for the Boost C++ libraries and static -Boost C++ libraries, example source files distributed with boost. +Boost C++ libraries distributed with boost. %package help Summary: HTML documentation for the Boost C++ libraries @@ -466,6 +465,14 @@ This package contains the documentation in the HTML format of the Boost C++ libraries. The documentation provides the same content as that on the Boost web page (http://www.boost.org/doc/libs/%{version_enc}). +%package examples +Summary: Source examples for the Boost C++ libraries +BuildArch: noarch +Requires: boost-devel = %{version}-%{release} + +%description examples +This package contains example source files distributed with boost. + %if 0%{with openmpi} %package openmpi Summary: Run-time component of Boost.MPI library @@ -684,6 +691,7 @@ find ./boost -name '*.hpp' -perm /111 | xargs chmod a-x %patch85 -p2 %patch86 -p1 %patch87 -p1 +%patch88 -p1 %build : PYTHON2_VERSION=%{python2_version} @@ -1120,6 +1128,8 @@ fi %if 0%{with openmpi} %{_libdir}/openmpi/lib/*.a %endif + +%files examples %doc %{boost_examplesdir}/* %if 0%{with openmpi} @@ -1205,6 +1215,18 @@ fi %{_mandir}/man1/bjam.1* %changelog +* Tue May 3 2020 Wang Shuo - 1.66.0-18 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: change scripts from py2 to py3 + +* Wed Feb 26 2020 Wang Shuo - 1.66.0-17 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: move examples files to examples package + * Mon Oct 28 2019 caomeng - 1.66.0-16 - Type:NA - ID:NA diff --git a/change-scripts-from-py2-to-py3.patch b/change-scripts-from-py2-to-py3.patch new file mode 100644 index 0000000..2960ad3 --- /dev/null +++ b/change-scripts-from-py2-to-py3.patch @@ -0,0 +1,7086 @@ +From 948b56e07d4c5d642c49f44223bf8f868cca0184 Mon Sep 17 00:00:00 2001 +From: wangshuo +Date: Tue, 3 Mar 2020 15:49:10 +0800 +Subject: [PATCH] boost: change scripts from py2 to py3 + +--- + libs/callable_traits/scripts/wandbox_deploy.py | 10 +- + libs/compatibility/generate_cpp_c_headers.py | 36 ++-- + libs/compute/perf/perf.py | 12 +- + libs/compute/perf/perfdoc.py | 4 +- + libs/geometry/doc/index/make_qbk.py | 2 +- + libs/geometry/doc/make_qbk.py | 6 +- + libs/iterator/doc/generate.py | 4 +- + libs/iterator/doc/scanrst.py | 2 +- + libs/iterator/doc/syscmd.py | 6 +- + libs/local_function/example/chrono.py | 6 +- + libs/metaparse/tools/benchmark/benchmark.py | 30 ++-- + libs/metaparse/tools/benchmark/generate.py | 15 +- + libs/metaparse/tools/build_environment.py | 10 +- + libs/metaparse/tools/string_headers.py | 17 +- + libs/mpi/example/python/hello_world.py | 4 +- + libs/mpi/test/python/all_gather_test.py | 4 +- + libs/mpi/test/python/all_reduce_test.py | 4 +- + libs/mpi/test/python/all_to_all_test.py | 4 +- + libs/mpi/test/python/broadcast_test.py | 4 +- + libs/mpi/test/python/gather_test.py | 4 +- + libs/mpi/test/python/nonblocking_test.py | 18 +- + libs/mpi/test/python/reduce_test.py | 4 +- + libs/mpi/test/python/ring_test.py | 6 +- + libs/mpi/test/python/scan_test.py | 4 +- + libs/mpi/test/python/scatter_test.py | 4 +- + libs/mpi/test/python/skeleton_content_test.py | 12 +- + .../src/docutils/writers/html4_refdoc/__init__.py | 6 +- + libs/mpl/doc/src/refmanual/refmanual.py | 9 +- + libs/mpl/preprocessed/boost_mpl_preprocess.py | 48 +++--- + libs/mpl/preprocessed/fix_boost_mpl_preprocess.py | 34 ++-- + libs/mpl/preprocessed/pp.py | 2 +- + libs/mpl/preprocessed/preprocess.py | 8 +- + libs/numeric/odeint/fix-copyright.py | 18 +- + libs/numeric/odeint/performance/plot_result.py | 2 +- + .../test/program_options_size_test.py | 10 +- + libs/program_options/test/winmain.py | 8 +- + libs/python/config/__init__.py | 6 +- + libs/python/config/toolchains/__init__.py | 2 +- + libs/python/config/tools/libs.py | 2 +- + libs/python/config/tools/sphinx4scons.py | 18 +- + libs/python/config/tools/tests.py | 4 +- + libs/python/config/ui.py | 2 +- + libs/python/doc/numpy/conf.py | 12 +- + libs/python/example/numpy/demo_gaussian.py | 12 +- + libs/python/example/tutorial/hello.py | 2 +- + libs/python/test/args.py | 2 +- + libs/python/test/dict.py | 2 +- + libs/python/test/docstring.py | 2 +- + libs/python/test/iterator.py | 2 +- + libs/python/test/list.py | 2 +- + libs/python/test/map_indexing_suite.py | 2 +- + libs/python/test/numpy/dtype.py | 8 +- + libs/python/test/numpy/ndarray.py | 4 +- + libs/python/test/numpy/ufunc.py | 4 +- + libs/python/test/object.py | 2 +- + libs/python/test/pickle2.py | 2 +- + libs/python/test/pickle3.py | 2 +- + libs/python/test/str.py | 2 +- + libs/python/test/test_cltree.py | 10 +- + libs/python/test/tuple.py | 2 +- + status/boost_check_library.py | 22 +-- + tools/boostbook/setup_boostbook.py | 88 +++++----- + tools/boostbook/test/more/run-tests.py | 22 +-- + tools/boostdep/depinst/depinst.py | 12 +- + tools/build/example/customization/inline_file.py | 4 +- + tools/build/src/build/alias.py | 16 +- + tools/build/src/build/build_request.py | 6 +- + tools/build/src/build/configure.py | 26 +-- + tools/build/src/build/engine.py | 32 ++-- + tools/build/src/build/errors.py | 26 +-- + tools/build/src/build/feature.py | 70 ++++---- + tools/build/src/build/generators.py | 100 +++++------ + tools/build/src/build/project.py | 189 +++++++++++---------- + tools/build/src/build/property.py | 47 +++-- + tools/build/src/build/property_set.py | 18 +- + tools/build/src/build/scanner.py | 12 +- + tools/build/src/build/targets.py | 113 ++++++------ + tools/build/src/build/toolset.py | 54 +++--- + tools/build/src/build/type.py | 78 ++++----- + tools/build/src/build/version.py | 6 +- + tools/build/src/build/virtual_target.py | 45 ++--- + tools/build/src/build_system.py | 56 +++--- + tools/build/src/contrib/boost.py | 8 +- + tools/build/src/engine/bump_version.py | 6 +- + tools/build/src/manager.py | 12 +- + tools/build/src/tools/builtin.py | 28 +-- + tools/build/src/tools/cast.py | 2 +- + tools/build/src/tools/common.py | 98 +++++------ + tools/build/src/tools/darwin.py | 2 +- + tools/build/src/tools/doxproc.py | 24 +-- + tools/build/src/tools/gcc.py | 34 ++-- + tools/build/src/tools/message.py | 2 +- + tools/build/src/tools/msvc.py | 17 +- + tools/build/src/tools/rc.py | 2 +- + tools/build/src/tools/stage.py | 4 +- + tools/build/src/tools/testing.py | 22 +-- + tools/build/src/tools/unix.py | 2 +- + tools/build/src/util/__init__.py | 15 +- + tools/build/src/util/path.py | 2 +- + tools/build/src/util/sequence.py | 3 +- + tools/build/src/util/utility.py | 20 +-- + tools/build/test/BoostBuild.py | 93 +++++----- + tools/build/test/TestCmd.py | 25 +-- + tools/build/test/builtin_glob_archive.py | 10 +- + tools/build/test/collect_debug_info.py | 4 +- + tools/build/test/core_arguments.py | 4 +- + tools/build/test/core_nt_cmd_line.py | 4 +- + tools/build/test/load_dir.py | 20 +-- + tools/build/test/notfile.py | 4 +- + tools/build/test/sort_rule.py | 12 +- + tools/build/test/symlink.py | 4 +- + tools/build/test/test_all.py | 16 +- + tools/build/test/tree.py | 16 +- + tools/litre/cplusplus.py | 89 +++++----- + tools/litre/litre.py | 8 +- + tools/quickbook/test/python/run_tests.py | 42 ++--- + tools/quickbook/test/stub.py | 2 +- + 117 files changed, 1091 insertions(+), 1092 deletions(-) + +diff --git a/libs/callable_traits/scripts/wandbox_deploy.py b/libs/callable_traits/scripts/wandbox_deploy.py +index 00af8eb..9bc1a94 100755 +--- a/libs/callable_traits/scripts/wandbox_deploy.py ++++ b/libs/callable_traits/scripts/wandbox_deploy.py +@@ -19,7 +19,7 @@ import fnmatch + import json + import os + import re +-import urllib2 ++import urllib.request, urllib.error, urllib.parse + + + # Strips C and C++ comments from the given string. +@@ -42,9 +42,9 @@ def strip_comments(text): + # Post the given JSON data to Wandbox's API, and return the result + # as a JSON object. + def upload(options): +- request = urllib2.Request('https://wandbox.org/api/compile.json') ++ request = urllib.request.Request('https://wandbox.org/api/compile.json') + request.add_header('Content-Type', 'application/json') +- response = urllib2.urlopen(request, json.dumps(options)) ++ response = urllib.request.urlopen(request, json.dumps(options)) + return json.loads(response.read()) + + +@@ -109,10 +109,10 @@ def main(): + }) + + if response['status'] == '0': +- print response['url'] ++ print(response['url']) + return 0 + else: +- print response ++ print(response) + return 1 + + +diff --git a/libs/compatibility/generate_cpp_c_headers.py b/libs/compatibility/generate_cpp_c_headers.py +index 189f4d5..0a99b09 100644 +--- a/libs/compatibility/generate_cpp_c_headers.py ++++ b/libs/compatibility/generate_cpp_c_headers.py +@@ -238,30 +238,30 @@ if (__name__ == "__main__"): + + now = time.asctime(time.localtime(time.time())) + ' ' + str(time.tzname) + +- for hfile in hfiles.keys(): ++ for hfile in list(hfiles.keys()): + HFILE = string.upper(hfile) + f = open(hfile, 'w') + sys.stdout = f +- print '// This file is automatically generated. Do not edit.' +- print '//', sys.argv +- print '//', now +- print +- print '#ifndef __' + HFILE + '_HEADER' +- print '#define __' + HFILE + '_HEADER' +- print '' +- print '#include <' + hfile[1:] + '.h>' +- print '' ++ print('// This file is automatically generated. Do not edit.') ++ print('//', sys.argv) ++ print('//', now) ++ print() ++ print('#ifndef __' + HFILE + '_HEADER') ++ print('#define __' + HFILE + '_HEADER') ++ print('') ++ print('#include <' + hfile[1:] + '.h>') ++ print('') + if (len(hfiles[hfile]) > 0): +- print 'namespace std {' ++ print('namespace std {') + for s in hfiles[hfile]: + n_endif = 0 +- for d in defines.keys(): ++ for d in list(defines.keys()): + if (s in defines[d]): +- print '#if !(' + d + ')' ++ print('#if !(' + d + ')') + n_endif = n_endif + 1 +- print ' using ::' + s + ';' +- for i in xrange(n_endif): print '#endif' +- print '}' +- print '' +- print '#endif // ' + HFILE + '_HEADER' ++ print(' using ::' + s + ';') ++ for i in range(n_endif): print('#endif') ++ print('}') ++ print('') ++ print('#endif // ' + HFILE + '_HEADER') + sys.stdout = sys.__stdout__ +diff --git a/libs/compute/perf/perf.py b/libs/compute/perf/perf.py +index c7b33f6..8049385 100755 +--- a/libs/compute/perf/perf.py ++++ b/libs/compute/perf/perf.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # Copyright (c) 2014 Kyle Lutz + # Distributed under the Boost Software License, Version 1.0 +@@ -29,7 +29,7 @@ def run_perf_process(name, size, backend = ""): + filename = "./perf/" + proc + + if not os.path.isfile(filename): +- print("Error: failed to find ", filename, " for running") ++ print(("Error: failed to find ", filename, " for running")) + return 0 + try: + output = subprocess.check_output([filename, str(int(size))]) +@@ -55,12 +55,12 @@ class Report: + self.samples[name].append((size, time)) + + def display(self): +- for name in self.samples.keys(): +- print('=== %s with %s ===' % (self.name, name)) ++ for name in list(self.samples.keys()): ++ print(('=== %s with %s ===' % (self.name, name))) + print('size,time (ms)') + + for sample in self.samples[name]: +- print('%d,%f' % sample) ++ print(('%d,%f' % sample)) + + def plot_time(self, name): + if not name in self.samples: +@@ -206,7 +206,7 @@ if __name__ == '__main__': + test = "sort" + if len(sys.argv) >= 2: + test = sys.argv[1] +- print('running %s perf test' % test) ++ print(('running %s perf test' % test)) + + sizes = [ pow(2, x) for x in range(1, 26) ] + +diff --git a/libs/compute/perf/perfdoc.py b/libs/compute/perf/perfdoc.py +index e9c6036..5c6b2c8 100755 +--- a/libs/compute/perf/perfdoc.py ++++ b/libs/compute/perf/perfdoc.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # Copyright (c) 2014 Kyle Lutz + # Distributed under the Boost Software License, Version 1.0 +@@ -64,7 +64,7 @@ if __name__ == '__main__': + pass + + for algorithm in algorithms: +- print("running '%s'" % (algorithm)) ++ print(("running '%s'" % (algorithm))) + report = run_benchmark(algorithm, sizes, ["stl", "thrust", "bolt"]) + plot_to_file(report, "perf_plots/%s_time_plot.png" % algorithm) + +diff --git a/libs/geometry/doc/index/make_qbk.py b/libs/geometry/doc/index/make_qbk.py +index 64775b1..70e15b5 100755 +--- a/libs/geometry/doc/index/make_qbk.py ++++ b/libs/geometry/doc/index/make_qbk.py +@@ -24,7 +24,7 @@ def run_command(command): + def remove_all_files(dir_relpath): + if os.path.exists(dir_relpath): + dir_abspath = os.path.join(os.getcwd(), dir_relpath) +- print("Boost.Geometry is cleaning Doxygen files in %s" % dir_abspath) ++ print(("Boost.Geometry is cleaning Doxygen files in %s" % dir_abspath)) + shutil.rmtree(dir_abspath, ignore_errors=True) + + remove_all_files("xml/") +diff --git a/libs/geometry/doc/make_qbk.py b/libs/geometry/doc/make_qbk.py +index cace58f..46fc174 100755 +--- a/libs/geometry/doc/make_qbk.py ++++ b/libs/geometry/doc/make_qbk.py +@@ -15,7 +15,7 @@ import os, sys, shutil + + script_dir = os.path.dirname(__file__) + os.chdir(os.path.abspath(script_dir)) +-print("Boost.Geometry is making .qbk files in %s" % os.getcwd()) ++print(("Boost.Geometry is making .qbk files in %s" % os.getcwd())) + + if 'DOXYGEN' in os.environ: + doxygen_cmd = os.environ['DOXYGEN'] +@@ -48,7 +48,7 @@ def run_command(command): + def remove_all_files(dir_relpath): + if os.path.exists(dir_relpath): + dir_abspath = os.path.join(os.getcwd(), dir_relpath) +- print("Boost.Geometry is cleaning Doxygen files in %s" % dir_abspath) ++ print(("Boost.Geometry is cleaning Doxygen files in %s" % dir_abspath)) + shutil.rmtree(dir_abspath, ignore_errors=True) + + def call_doxygen(): +@@ -188,7 +188,7 @@ class_to_quickbook2("de9im_1_1mask", "de9im_mask") + class_to_quickbook2("de9im_1_1static__mask", "de9im_static_mask") + + os.chdir("index") +-execfile("make_qbk.py") ++exec(compile(open("make_qbk.py").read(), "make_qbk.py", 'exec')) + os.chdir("..") + + # Clean up generated intermediate files +diff --git a/libs/iterator/doc/generate.py b/libs/iterator/doc/generate.py +index f5d0de8..87b8777 100644 +--- a/libs/iterator/doc/generate.py ++++ b/libs/iterator/doc/generate.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # Copyright David Abrahams 2004. Use, modification and distribution is + # subject to the Boost Software License, Version 1.0. (See accompanying + # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +@@ -26,7 +26,7 @@ else: + for s in sources + ] + +- print 'make %s' % ' '.join(all) ++ print('make %s' % ' '.join(all)) + syscmd('make %s' % ' '.join(all)) + + +diff --git a/libs/iterator/doc/scanrst.py b/libs/iterator/doc/scanrst.py +index 484d879..b16fbcf 100644 +--- a/libs/iterator/doc/scanrst.py ++++ b/libs/iterator/doc/scanrst.py +@@ -26,4 +26,4 @@ for file in sys.argv[1:]: + found = deps(file, {}) + if found: + base = os.path.splitext(os.path.basename(file))[0] +- print '%s.tex %s.html: %s' % (base, base, ' '.join(found.keys())) ++ print('%s.tex %s.html: %s' % (base, base, ' '.join(list(found.keys())))) +diff --git a/libs/iterator/doc/syscmd.py b/libs/iterator/doc/syscmd.py +index e6a8dca..01860ad 100644 +--- a/libs/iterator/doc/syscmd.py ++++ b/libs/iterator/doc/syscmd.py +@@ -6,9 +6,9 @@ import os + import sys + + def syscmd(s): +- print 'executing: ', repr(s) ++ print('executing: ', repr(s)) + sys.stdout.flush() + err = os.system(s) + if err: +- raise SystemError, 'command: %s returned %s' % ( +- repr(s), err) ++ raise SystemError('command: %s returned %s' % ( ++ repr(s), err)) +diff --git a/libs/local_function/example/chrono.py b/libs/local_function/example/chrono.py +index 84d6dfb..e31e179 100755 +--- a/libs/local_function/example/chrono.py ++++ b/libs/local_function/example/chrono.py +@@ -10,8 +10,8 @@ import time + import os + + if len(sys.argv) < 2: +- print "Usage: python " + sys.argv[0] + " COMMAND [COMMAND_OPTIONS]" +- print "Measure run-time of executing the specified command." ++ print("Usage: python " + sys.argv[0] + " COMMAND [COMMAND_OPTIONS]") ++ print("Measure run-time of executing the specified command.") + exit(1) + + cmd = "" +@@ -21,5 +21,5 @@ start = time.time() + ret = os.system(cmd) + sec = time.time() - start + +-if (ret == 0): print "\n" + str(sec) + "s" ++if (ret == 0): print("\n" + str(sec) + "s") + +diff --git a/libs/metaparse/tools/benchmark/benchmark.py b/libs/metaparse/tools/benchmark/benchmark.py +index 46d3ef9..f33d310 100755 +--- a/libs/metaparse/tools/benchmark/benchmark.py ++++ b/libs/metaparse/tools/benchmark/benchmark.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + """Utility to benchmark the generated source files""" + + # Copyright Abel Sinkovics (abel@sinkovics.hu) 2016. +@@ -26,7 +26,7 @@ import matplotlib.pyplot # pylint:disable=I0011,C0411,C0412,C0413 + def benchmark_command(cmd, progress): + """Benchmark one command execution""" + full_cmd = '/usr/bin/time --format="%U %M" {0}'.format(cmd) +- print '{0:6.2f}% Running {1}'.format(100.0 * progress, full_cmd) ++ print('{0:6.2f}% Running {1}'.format(100.0 * progress, full_cmd)) + (_, err) = subprocess.Popen( + ['/bin/sh', '-c', full_cmd], + stdin=subprocess.PIPE, +@@ -41,17 +41,18 @@ def benchmark_command(cmd, progress): + except: # pylint:disable=I0011,W0702 + pass # Handled by the code after the "if" + +- print err ++ print(err) + raise Exception('Error during benchmarking') + + + def benchmark_file( +- filename, compiler, include_dirs, (progress_from, progress_to), ++ filename, compiler, include_dirs, xxx_todo_changeme, + iter_count, extra_flags = ''): + """Benchmark one file""" ++ (progress_from, progress_to) = xxx_todo_changeme + time_sum = 0 + mem_sum = 0 +- for nth_run in xrange(0, iter_count): ++ for nth_run in range(0, iter_count): + (time_spent, mem_used) = benchmark_command( + '{0} -std=c++11 {1} -c {2} {3}'.format( + compiler, +@@ -163,21 +164,22 @@ def benchmark(src_dir, compiler, include_dirs, iter_count): + except: + has_string_templates = False + file_count -= string_template_file_cnt +- print 'Stopping the benchmarking of string literal templates' ++ print('Stopping the benchmarking of string literal templates') + + elapsed = time.time() - started_at + total = float(file_count * elapsed) / len(result) +- print 'Elapsed time: {0}, Remaining time: {1}'.format( ++ print('Elapsed time: {0}, Remaining time: {1}'.format( + format_time(elapsed), + format_time(total - elapsed) +- ) ++ )) + return result + + +-def plot(values, mode_names, title, (xlabel, ylabel), out_file): ++def plot(values, mode_names, title, xxx_todo_changeme1, out_file): + """Plot a diagram""" ++ (xlabel, ylabel) = xxx_todo_changeme1 + matplotlib.pyplot.clf() +- for mode, mode_name in mode_names.iteritems(): ++ for mode, mode_name in mode_names.items(): + vals = values[mode] + matplotlib.pyplot.plot( + [x for x, _ in vals], +@@ -236,18 +238,18 @@ def plot_temp_diagrams(config, results, temp_dir): + files = config['files'] + img_files = [] + +- if any('slt' in result for result in results) and 'bmp' in files.values()[0]: ++ if any('slt' in result for result in results) and 'bmp' in list(files.values())[0]: + config['modes']['slt'] = 'Using BOOST_METAPARSE_STRING with string literal templates' +- for f in files.values(): ++ for f in list(files.values()): + f['slt'] = f['bmp'].replace('bmp', 'slt') + + for measured in ['time', 'memory']: +- mpts = sorted(int(k) for k in files.keys()) ++ mpts = sorted(int(k) for k in list(files.keys())) + img_files.append(os.path.join(temp_dir, '_{0}.png'.format(measured))) + plot( + { + m: [(x, results[files[str(x)][m]][measured]) for x in mpts] +- for m in config['modes'].keys() ++ for m in list(config['modes'].keys()) + }, + config['modes'], + display_name[measured], +diff --git a/libs/metaparse/tools/benchmark/generate.py b/libs/metaparse/tools/benchmark/generate.py +index 52526c8..b9ac975 100755 +--- a/libs/metaparse/tools/benchmark/generate.py ++++ b/libs/metaparse/tools/benchmark/generate.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + """Utility to generate files to benchmark""" + + # Copyright Abel Sinkovics (abel@sinkovics.hu) 2016. +@@ -50,14 +50,14 @@ def in_comment(regex): + def random_chars(number): + """Generate random characters""" + char_map = { +- k: v for k, v in chars.CHARS.iteritems() ++ k: v for k, v in chars.CHARS.items() + if not format_character(k).startswith('\\x') + } + + char_num = sum(char_map.values()) + return ( + format_character(nth_char(char_map, random.randint(0, char_num - 1))) +- for _ in xrange(0, number) ++ for _ in range(0, number) + ) + + +@@ -105,7 +105,7 @@ class Mode(object): + new_base = '' + was_backslash = False + comma = '' +- for i in xrange(bmp_at + len(prefix), len(base)): ++ for i in range(bmp_at + len(prefix), len(base)): + if was_backslash: + result.append( + '{0}\'\\{1}\''.format(comma, base[i]) +@@ -146,11 +146,10 @@ class Template(object): + 'n[ \t]+in[ \t]*\\[([0-9]+)\\.\\.([0-9]+)\\),[ \t]+' + 'step[ \t]+([0-9]+)' + )) +- return range( ++ return list(range( + int(match.group(1)), + int(match.group(2)), +- int(match.group(3)) +- ) ++ int(match.group(3)))) + + def property(self, name): + """Parses and returns a property""" +@@ -225,7 +224,7 @@ def format_character(char): + + def write_file(filename, content): + """Create the file with the given content""" +- print 'Generating {0}'.format(filename) ++ print('Generating {0}'.format(filename)) + with open(filename, 'wb') as out_f: + out_f.write(content) + +diff --git a/libs/metaparse/tools/build_environment.py b/libs/metaparse/tools/build_environment.py +index b104fb3..9c47341 100755 +--- a/libs/metaparse/tools/build_environment.py ++++ b/libs/metaparse/tools/build_environment.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # Copyright Abel Sinkovics (abel@sinkovics.hu) 2016. + # Distributed under the Boost Software License, Version 1.0. +@@ -23,7 +23,7 @@ class ChildProcess: + + def run(self, cmd): + cmd_string = ' '.join(cmd) +- print 'Running {0}'.format(cmd_string) ++ print('Running {0}'.format(cmd_string)) + proc = subprocess.Popen( + self.cmd + cmd, + cwd = self.cwd, +@@ -58,7 +58,7 @@ def build_environment(submodules_file, out_dir, git, repo, action, ref): + git_in_boost = git.in_dir(out_dir) + + git_in_boost.run( +- ['submodule', 'init', '--'] + [k for k in submodules.keys() if k != ''] ++ ['submodule', 'init', '--'] + [k for k in list(submodules.keys()) if k != ''] + ) + git_in_boost.run(['submodule', 'update']) + if action == 'update': +@@ -66,13 +66,13 @@ def build_environment(submodules_file, out_dir, git, repo, action, ref): + f.write(json.dumps( + dict([ + (k, head_of_master(k, git_in_boost.in_subdir(k), ref)) +- for k, v in submodules.iteritems() ++ for k, v in submodules.items() + ]), + sort_keys=True, + indent=2 + )) + elif action == 'checkout': +- for name, commit in submodules.iteritems(): ++ for name, commit in submodules.items(): + git_in_boost.in_subdir(name).run(['checkout', commit]) + else: + raise Exception('Invalid action {0}'.format(action)) +diff --git a/libs/metaparse/tools/string_headers.py b/libs/metaparse/tools/string_headers.py +index 43ef052..6f4723e 100755 +--- a/libs/metaparse/tools/string_headers.py ++++ b/libs/metaparse/tools/string_headers.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + """Utility to generate the header files for BOOST_METAPARSE_STRING""" + + # Copyright Abel Sinkovics (abel@sinkovics.hu) 2016. +@@ -32,7 +32,7 @@ class Namespace(object): + + def end(self): + """Generate the closing part""" +- for depth in xrange(len(self.names) - 1, -1, -1): ++ for depth in range(len(self.names) - 1, -1, -1): + self.out_f.write('{0}}}\n'.format(self.prefix(depth))) + + def prefix(self, depth=None): +@@ -89,8 +89,9 @@ def macro_name(name): + return 'BOOST_METAPARSE_V{0}_{1}'.format(VERSION, name) + + +-def define_macro(out_f, (name, args, body), undefine=False, check=True): ++def define_macro(out_f, xxx_todo_changeme, undefine=False, check=True): + """Generate a macro definition or undefinition""" ++ (name, args, body) = xxx_todo_changeme + if undefine: + out_f.write( + '#undef {0}\n' +@@ -129,7 +130,7 @@ def length_limits(max_length_limit, length_limit_step): + string_len = len(str(max_length_limit)) + return [ + str(i).zfill(string_len) for i in +- xrange( ++ range( + length_limit_step, + max_length_limit + length_limit_step - 1, + length_limit_step +@@ -139,7 +140,7 @@ def length_limits(max_length_limit, length_limit_step): + + def unique_names(count): + """Generate count unique variable name""" +- return ('C{0}'.format(i) for i in xrange(0, count)) ++ return ('C{0}'.format(i) for i in range(0, count)) + + + def generate_take(out_f, steps, line_prefix): +@@ -159,7 +160,7 @@ def generate_take(out_f, steps, line_prefix): + + def generate_make_string(out_f, max_step): + """Generate the make_string template""" +- steps = [2 ** n for n in xrange(int(math.log(max_step, 2)), -1, -1)] ++ steps = [2 ** n for n in range(int(math.log(max_step, 2)), -1, -1)] + + with Namespace( + out_f, +@@ -243,7 +244,7 @@ def generate_string(out_dir, limits): + )) + + out_f.write('\n') +- for limit in xrange(0, max_limit + 1): ++ for limit in range(0, max_limit + 1): + out_f.write( + '#define {0} {1}\n' + .format( +@@ -267,7 +268,7 @@ def generate_string(out_dir, limits): + ','.join( + '{0}((s), {1})' + .format(macro_name('STRING_AT'), i) +- for i in xrange(prev_limit, length_limit) ++ for i in range(prev_limit, length_limit) + ) + ) + ) +diff --git a/libs/mpi/example/python/hello_world.py b/libs/mpi/example/python/hello_world.py +index 7331248..e5fecc0 100644 +--- a/libs/mpi/example/python/hello_world.py ++++ b/libs/mpi/example/python/hello_world.py +@@ -9,8 +9,8 @@ import boost.parallel.mpi as mpi + if mpi.world.rank == 0: + mpi.world.send(1, 0, 'Hello') + msg = mpi.world.recv(1, 1) +- print msg,'!' ++ print(msg,'!') + else: + msg = mpi.world.recv(0, 0) +- print msg,', ', ++ print(msg,', ', end=' ') + mpi.world.send(0, 1, 'world') +diff --git a/libs/mpi/test/python/all_gather_test.py b/libs/mpi/test/python/all_gather_test.py +index 824dc89..5b7e18f 100644 +--- a/libs/mpi/test/python/all_gather_test.py ++++ b/libs/mpi/test/python/all_gather_test.py +@@ -10,12 +10,12 @@ import boost.parallel.mpi as mpi + from generators import * + + def all_gather_test(comm, generator, kind): +- if comm.rank == 0: print ("Gathering %s..." % (kind,)), ++ if comm.rank == 0: print(("Gathering %s..." % (kind,)), end=' ') + my_value = generator(comm.rank) + result = mpi.all_gather(comm, my_value) + for p in range(0, comm.size): + assert result[p] == generator(p) +- if comm.rank == 0: print "OK." ++ if comm.rank == 0: print("OK.") + + return + +diff --git a/libs/mpi/test/python/all_reduce_test.py b/libs/mpi/test/python/all_reduce_test.py +index c3285e6..5068b3a 100644 +--- a/libs/mpi/test/python/all_reduce_test.py ++++ b/libs/mpi/test/python/all_reduce_test.py +@@ -11,7 +11,7 @@ from generators import * + + def all_reduce_test(comm, generator, kind, op, op_kind): + if comm.rank == 0: +- print ("Reducing to %s of %s..." % (op_kind, kind)), ++ print(("Reducing to %s of %s..." % (op_kind, kind)), end=' ') + my_value = generator(comm.rank) + result = mpi.all_reduce(comm, my_value, op) + expected_result = generator(0); +@@ -20,7 +20,7 @@ def all_reduce_test(comm, generator, kind, op, op_kind): + + assert result == expected_result + if comm.rank == 0: +- print "OK." ++ print("OK.") + return + + all_reduce_test(mpi.world, int_generator, "integers", lambda x,y:x + y, "sum") +diff --git a/libs/mpi/test/python/all_to_all_test.py b/libs/mpi/test/python/all_to_all_test.py +index b149bf0..228c188 100644 +--- a/libs/mpi/test/python/all_to_all_test.py ++++ b/libs/mpi/test/python/all_to_all_test.py +@@ -11,7 +11,7 @@ from generators import * + + def all_to_all_test(comm, generator, kind): + if comm.rank == 0: +- print ("All-to-all transmission of %s..." % (kind,)), ++ print(("All-to-all transmission of %s..." % (kind,)), end=' ') + + values = list() + for p in range(0, comm.size): +@@ -21,7 +21,7 @@ def all_to_all_test(comm, generator, kind): + for p in range(0, comm.size): + assert result[p] == generator(comm.rank) + +- if comm.rank == 0: print "OK." ++ if comm.rank == 0: print("OK.") + return + + all_to_all_test(mpi.world, int_generator, "integers") +diff --git a/libs/mpi/test/python/broadcast_test.py b/libs/mpi/test/python/broadcast_test.py +index dbd53d1..f41dd2d 100644 +--- a/libs/mpi/test/python/broadcast_test.py ++++ b/libs/mpi/test/python/broadcast_test.py +@@ -10,12 +10,12 @@ import boost.parallel.mpi as mpi + + def broadcast_test(comm, value, kind, root): + if comm.rank == root: +- print ("Broadcasting %s from root %d..." % (kind, root)), ++ print(("Broadcasting %s from root %d..." % (kind, root)), end=' ') + + got_value = mpi.broadcast(comm, value, root) + assert got_value == value + if comm.rank == root: +- print "OK." ++ print("OK.") + return + + broadcast_test(mpi.world, 17, 'integer', 0) +diff --git a/libs/mpi/test/python/gather_test.py b/libs/mpi/test/python/gather_test.py +index d56b3a4..10c27b9 100644 +--- a/libs/mpi/test/python/gather_test.py ++++ b/libs/mpi/test/python/gather_test.py +@@ -11,13 +11,13 @@ from generators import * + + def gather_test(comm, generator, kind, root): + if comm.rank == root: +- print ("Gathering %s to root %d..." % (kind, root)), ++ print(("Gathering %s to root %d..." % (kind, root)), end=' ') + my_value = generator(comm.rank) + result = mpi.gather(comm, my_value, root) + if comm.rank == root: + for p in range(0, comm.size): + assert result[p] == generator(p) +- print "OK." ++ print("OK.") + else: + assert result == None + return +diff --git a/libs/mpi/test/python/nonblocking_test.py b/libs/mpi/test/python/nonblocking_test.py +index 73b451c..3d57d8a 100644 +--- a/libs/mpi/test/python/nonblocking_test.py ++++ b/libs/mpi/test/python/nonblocking_test.py +@@ -37,13 +37,13 @@ class TagGroupListener: + for tag in self.tags: + if tag not in self.active_requests: + self.active_requests[tag] = self.comm.irecv(tag=tag) +- requests = mpi.RequestList(self.active_requests.values()) ++ requests = mpi.RequestList(list(self.active_requests.values())) + data, status, index = mpi.wait_any(requests) + del self.active_requests[status.tag] + return status, data + + def cancel(self): +- for r in self.active_requests.itervalues(): ++ for r in self.active_requests.values(): + r.cancel() + #r.wait() + self.active_requests = {} +@@ -52,7 +52,7 @@ class TagGroupListener: + + def rank0(): + sent_histories = (mpi.size-1)*15 +- print "sending %d packets on their way" % sent_histories ++ print("sending %d packets on their way" % sent_histories) + send_reqs = mpi.RequestList() + for i in range(sent_histories): + dest = random.randrange(1, mpi.size) +@@ -68,7 +68,7 @@ def rank0(): + [TAG_DATA, TAG_DEBUG, TAG_PROGRESS_REPORT, TAG_TERMINATE]) + + def is_complete(): +- for i in progress_reports.values(): ++ for i in list(progress_reports.values()): + if i != sent_histories: + return False + return len(dead_kids) == mpi.size-1 +@@ -80,22 +80,22 @@ def rank0(): + #print "received completed history %s from %d" % (data, status.source) + completed_histories.append(data) + if len(completed_histories) == sent_histories: +- print "all histories received, exiting" ++ print("all histories received, exiting") + for rank in range(1, mpi.size): + mpi.world.send(rank, TAG_TERMINATE, None) + elif status.tag == TAG_PROGRESS_REPORT: + progress_reports[len(data)] = progress_reports.get(len(data), 0) + 1 + elif status.tag == TAG_DEBUG: +- print "[DBG %d] %s" % (status.source, data) ++ print("[DBG %d] %s" % (status.source, data)) + elif status.tag == TAG_TERMINATE: + dead_kids.append(status.source) + else: +- print "unexpected tag %d from %d" % (status.tag, status.source) ++ print("unexpected tag %d from %d" % (status.tag, status.source)) + + if is_complete(): + break + +- print "OK" ++ print("OK") + + def comm_rank(): + while True: +@@ -113,7 +113,7 @@ def comm_rank(): + mpi.world.send(0, TAG_TERMINATE, 0) + break + else: +- print "[DIRECTDBG %d] unexpected tag %d from %d" % (mpi.rank, status.tag, status.source) ++ print("[DIRECTDBG %d] unexpected tag %d from %d" % (mpi.rank, status.tag, status.source)) + + + def main(): +diff --git a/libs/mpi/test/python/reduce_test.py b/libs/mpi/test/python/reduce_test.py +index 65f09f5..a5bf01c 100644 +--- a/libs/mpi/test/python/reduce_test.py ++++ b/libs/mpi/test/python/reduce_test.py +@@ -11,7 +11,7 @@ from generators import * + + def reduce_test(comm, generator, kind, op, op_kind, root): + if comm.rank == root: +- print ("Reducing to %s of %s at root %d..." % (op_kind, kind, root)), ++ print(("Reducing to %s of %s at root %d..." % (op_kind, kind, root)), end=' ') + my_value = generator(comm.rank) + result = mpi.reduce(comm, my_value, op, root) + if comm.rank == root: +@@ -19,7 +19,7 @@ def reduce_test(comm, generator, kind, op, op_kind, root): + for p in range(1, comm.size): + expected_result = op(expected_result, generator(p)) + assert result == expected_result +- print "OK." ++ print("OK.") + else: + assert result == None + return +diff --git a/libs/mpi/test/python/ring_test.py b/libs/mpi/test/python/ring_test.py +index 3c8b5b9..94802b6 100644 +--- a/libs/mpi/test/python/ring_test.py ++++ b/libs/mpi/test/python/ring_test.py +@@ -13,7 +13,7 @@ def ring_test(comm, value, kind, root): + prior_peer = (comm.rank + comm.size - 1) % comm.size; + + if comm.rank == root: +- print ("Passing %s around a ring from root %d..." % (kind, root)), ++ print(("Passing %s around a ring from root %d..." % (kind, root)), end=' ') + comm.send(next_peer, 0, value) + (other_value, stat) = comm.recv(return_status = True) + assert value == other_value +@@ -27,11 +27,11 @@ def ring_test(comm, value, kind, root): + + comm.barrier() + if comm.rank == root: +- print "OK" ++ print("OK") + pass + + if mpi.world.size < 2: +- print "ERROR: ring_test.py must be executed with more than one process" ++ print("ERROR: ring_test.py must be executed with more than one process") + mpi.world.abort(-1); + + ring_test(mpi.world, 17, 'integers', 0) +diff --git a/libs/mpi/test/python/scan_test.py b/libs/mpi/test/python/scan_test.py +index 193a6a4..034c76d 100644 +--- a/libs/mpi/test/python/scan_test.py ++++ b/libs/mpi/test/python/scan_test.py +@@ -11,7 +11,7 @@ from generators import * + + def scan_test(comm, generator, kind, op, op_kind): + if comm.rank == 0: +- print ("Prefix reduction to %s of %s..." % (op_kind, kind)), ++ print(("Prefix reduction to %s of %s..." % (op_kind, kind)), end=' ') + my_value = generator(comm.rank) + result = mpi.scan(comm, my_value, op) + expected_result = generator(0); +@@ -20,7 +20,7 @@ def scan_test(comm, generator, kind, op, op_kind): + + assert result == expected_result + if comm.rank == 0: +- print "OK." ++ print("OK.") + return + + scan_test(mpi.world, int_generator, "integers", lambda x,y:x + y, "sum") +diff --git a/libs/mpi/test/python/scatter_test.py b/libs/mpi/test/python/scatter_test.py +index e0bad96..84bc06d 100644 +--- a/libs/mpi/test/python/scatter_test.py ++++ b/libs/mpi/test/python/scatter_test.py +@@ -11,7 +11,7 @@ from generators import * + + def scatter_test(comm, generator, kind, root): + if comm.rank == root: +- print ("Scattering %s from root %d..." % (kind, root)), ++ print(("Scattering %s from root %d..." % (kind, root)), end=' ') + + if comm.rank == root: + values = list() +@@ -23,7 +23,7 @@ def scatter_test(comm, generator, kind, root): + + assert result == generator(comm.rank) + +- if comm.rank == root: print "OK." ++ if comm.rank == root: print("OK.") + return + + scatter_test(mpi.world, int_generator, "integers", 0) +diff --git a/libs/mpi/test/python/skeleton_content_test.py b/libs/mpi/test/python/skeleton_content_test.py +index 1dfde3c..ecc13dc 100644 +--- a/libs/mpi/test/python/skeleton_content_test.py ++++ b/libs/mpi/test/python/skeleton_content_test.py +@@ -20,31 +20,31 @@ def test_skeleton_and_content(comm, root, manual_broadcast = True): + + if comm.rank == root: + # Broadcast skeleton +- print ("Broadcasting integer list skeleton from root %d..." % (root)), ++ print(("Broadcasting integer list skeleton from root %d..." % (root)), end=' ') + if manual_broadcast: + for p in range(0,comm.size): + if p != comm.rank: + comm.send(p, 0, value = mpi.skeleton(original_list)) +- print "OK." ++ print("OK.") + + # Broadcast content +- print ("Broadcasting integer list content from root %d..." % (root)), ++ print(("Broadcasting integer list content from root %d..." % (root)), end=' ') + if manual_broadcast: + for p in range(0,comm.size): + if p != comm.rank: + comm.send(p, 0, value = mpi.get_content(original_list)) + +- print "OK." ++ print("OK.") + + # Broadcast reversed content + original_list.reverse() +- print ("Broadcasting reversed integer list content from root %d..." % (root)), ++ print(("Broadcasting reversed integer list content from root %d..." % (root)), end=' ') + if manual_broadcast: + for p in range(0,comm.size): + if p != comm.rank: + comm.send(p, 0, value = mpi.get_content(original_list)) + +- print "OK." ++ print("OK.") + else: + # Allocate some useless data, to try to get the addresses of + # the underlying lists used later to be different across +diff --git a/libs/mpl/doc/src/docutils/writers/html4_refdoc/__init__.py b/libs/mpl/doc/src/docutils/writers/html4_refdoc/__init__.py +index 19e7b65..c61968c 100755 +--- a/libs/mpl/doc/src/docutils/writers/html4_refdoc/__init__.py ++++ b/libs/mpl/doc/src/docutils/writers/html4_refdoc/__init__.py +@@ -77,8 +77,8 @@ class refdoc_translator(html4_frames.frame_pages_translator): + + def visit_reference(self, node): + self.in_reference = 1 +- if len(node) == 1 and isinstance(node[0], nodes.literal) and node[0].has_key('class'): +- if node.has_key('class') and node['class'].find(node[0]['class']) == -1: ++ if len(node) == 1 and isinstance(node[0], nodes.literal) and 'class' in node[0]: ++ if 'class' in node and node['class'].find(node[0]['class']) == -1: + node['class'] += ' %s' % node[0]['class'] + else: + node['class'] = node[0]['class'] +@@ -169,7 +169,7 @@ class refdoc_translator(html4_frames.frame_pages_translator): + + def visit_substitution_reference(self, node): + # debug help +- print 'Unresolved substitution_reference:', node.astext() ++ print('Unresolved substitution_reference:', node.astext()) + raise nodes.SkipNode + + +diff --git a/libs/mpl/doc/src/refmanual/refmanual.py b/libs/mpl/doc/src/refmanual/refmanual.py +index cda0c22..708b840 100644 +--- a/libs/mpl/doc/src/refmanual/refmanual.py ++++ b/libs/mpl/doc/src/refmanual/refmanual.py +@@ -43,7 +43,7 @@ def __include_page( output, src_dir, page, name = None ): + ) + else: + if ref.find( '/' ) == -1: +- ref = ' '.join( filter( lambda x: len( x.strip() ) > 0, re.split( '([A-Z][a-z]+)', ref ) ) ) ++ ref = ' '.join( [x for x in re.split( '([A-Z][a-z]+)', ref ) if len( x.strip() ) > 0] ) + output.write( '.. |%(ref)s| replace:: `%(ref)s`_\n' % { 'ref': ref } ) + + output.write( '\n' ) +@@ -59,10 +59,7 @@ def __write_index( filename, index ): + + + def main( filename, src_dir, build_dir ): +- sources = filter( +- lambda x: fnmatch.fnmatch(x,"*.rst") and x != filename +- , os.listdir( src_dir ) +- ) ++ sources = [x for x in os.listdir( src_dir ) if fnmatch.fnmatch(x,"*.rst") and x != filename] + + toc = [ t.strip() for t in open( os.path.join( src_dir, '%s.toc' % filename) ).readlines() ] + topics = {} +@@ -88,7 +85,7 @@ def main( filename, src_dir, build_dir ): + if match.group(3): + order = int(match.group(4)) + +- if not topics.has_key(topic): ++ if topic not in topics: + topics[topic] = [] + + topics[topic].append((src, order, name)) +diff --git a/libs/mpl/preprocessed/boost_mpl_preprocess.py b/libs/mpl/preprocessed/boost_mpl_preprocess.py +index b497391..60d4b2f 100755 +--- a/libs/mpl/preprocessed/boost_mpl_preprocess.py ++++ b/libs/mpl/preprocessed/boost_mpl_preprocess.py +@@ -150,19 +150,19 @@ def main(): + + # Some verbose debug output. + if args.verbose: +- print "Arguments extracted from command-line:" +- print " verbose = ", args.verbose +- print " source directory = ", args.sourceDir +- print " num elements = ", args.numElements +- print " sequence type = ", args.seqType +- print " want: vector = ", args.want_vector +- print " want: list = ", args.want_list +- print " want: set = ", args.want_set +- print " want: map = ", args.want_map ++ print("Arguments extracted from command-line:") ++ print(" verbose = ", args.verbose) ++ print(" source directory = ", args.sourceDir) ++ print(" num elements = ", args.numElements) ++ print(" sequence type = ", args.seqType) ++ print(" want: vector = ", args.want_vector) ++ print(" want: list = ", args.want_list) ++ print(" want: set = ", args.want_set) ++ print(" want: map = ", args.want_map) + + # Verify that we received any source-directory. + if args.sourceDir == None: +- print "You should specify a valid path to the Boost source-directory." ++ print("You should specify a valid path to the Boost source-directory.") + sys.exit(0) + + # The directories for header- and source files of Boost.MPL. +@@ -177,13 +177,13 @@ def main(): + sourceDir = os.path.join( args.sourceDir, "preprocessed" ) + if not os.path.exists( headerDir ) or not os.path.exists( sourceDir ): + cmdlineParser.print_usage() +- print "error: Cannot find Boost.MPL header/source files in given Boost source-directory!" ++ print("error: Cannot find Boost.MPL header/source files in given Boost source-directory!") + sys.exit(0) + + # Some verbose debug output. + if args.verbose: +- print "Chosen header-directory: ", headerDir +- print "Chosen source-directory: ", sourceDir ++ print("Chosen header-directory: ", headerDir) ++ print("Chosen source-directory: ", sourceDir) + + # Create list of containers for which files shall be pre-processed. + containers = [] +@@ -196,23 +196,23 @@ def main(): + if args.want_map: + containers.append('map') + if containers == []: +- print "Nothing to do." +- print "(Why did you prevent generating pre-processed headers for all Boost.MPL container types?)" ++ print("Nothing to do.") ++ print("(Why did you prevent generating pre-processed headers for all Boost.MPL container types?)") + sys.exit(0) + + # Possibly fix the header-comments of input-files needed for pre-processing. + if args.verbose: +- print "Checking if prior to pre-processing some input-files need fixing." ++ print("Checking if prior to pre-processing some input-files need fixing.") + needFixing = fixmpl.check_input_files(headerDir, sourceDir, containers, args.seqType, args.verbose) + if needFixing: + if args.verbose: +- print "Fixing of some input-files prior to pre-processing is needed." +- print "Will fix them now!" ++ print("Fixing of some input-files prior to pre-processing is needed.") ++ print("Will fix them now!") + fixmpl.fix_input_files(headerDir, sourceDir, containers, args.seqType, args.verbose) + + # Some verbose debug output. + if args.verbose: +- print "Containers for which to pre-process headers: ", containers ++ print("Containers for which to pre-process headers: ", containers) + + # Create (additional) input files for generating pre-processed headers of numbered sequence MPL containers. + if args.seqType == "both" or args.seqType == "numbered": +@@ -226,23 +226,23 @@ def main(): + if args.seqType == "both" or args.seqType == "numbered": + if args.want_vector: + if args.verbose: +- print "Pre-process headers for Boost.MPL numbered vectors." ++ print("Pre-process headers for Boost.MPL numbered vectors.") + os.system( "python " + os.path.join( sourceDir, "preprocess_vector.py" ) + " all " + args.sourceDir ) + if args.want_list: + if args.verbose: +- print "Pre-process headers for Boost.MPL numbered lists." ++ print("Pre-process headers for Boost.MPL numbered lists.") + os.system( "python " + os.path.join( sourceDir, "preprocess_list.py" ) + " all " + args.sourceDir ) + if args.want_set: + if args.verbose: +- print "Pre-process headers for Boost.MPL numbered sets." ++ print("Pre-process headers for Boost.MPL numbered sets.") + os.system( "python " + os.path.join( sourceDir, "preprocess_set.py" ) + " all " + args.sourceDir ) + if args.want_map: + if args.verbose: +- print "Pre-process headers for Boost.MPL numbered maps." ++ print("Pre-process headers for Boost.MPL numbered maps.") + os.system( "python " + os.path.join( sourceDir, "preprocess_map.py" ) + " all " + args.sourceDir ) + if args.seqType == "both" or args.seqType == "variadic": + if args.verbose: +- print "Pre-process headers for Boost.MPL variadic containers." ++ print("Pre-process headers for Boost.MPL variadic containers.") + os.system( "python " + os.path.join( sourceDir, "preprocess.py" ) + " all " + args.sourceDir ) + + +diff --git a/libs/mpl/preprocessed/fix_boost_mpl_preprocess.py b/libs/mpl/preprocessed/fix_boost_mpl_preprocess.py +index 3b92d25..ab1857c 100755 +--- a/libs/mpl/preprocessed/fix_boost_mpl_preprocess.py ++++ b/libs/mpl/preprocessed/fix_boost_mpl_preprocess.py +@@ -66,26 +66,26 @@ def check_input_files(headerDir, sourceDir, containers=['vector', 'list', 'set', + result1 = False + if seqType == "both" or seqType == "variadic": + if verbose: +- print "Check if input files for pre-processing Boost.MPL variadic containers need fixing." ++ print("Check if input files for pre-processing Boost.MPL variadic containers need fixing.") + result1 = check_input_files_for_variadic_seq(headerDir, sourceDir) + if verbose: + if result1: +- print " At least one input file needs fixing!" ++ print(" At least one input file needs fixing!") + else: +- print " No input file needs fixing!" ++ print(" No input file needs fixing!") + # Check the input files for containers in their numbered form. + result2 = False + result3 = False + if seqType == "both" or seqType == "numbered": + if verbose: +- print "Check input files for pre-processing Boost.MPL numbered containers." ++ print("Check input files for pre-processing Boost.MPL numbered containers.") + result2 = check_input_files_for_numbered_seq(headerDir, ".hpp", containers) + result3 = check_input_files_for_numbered_seq(sourceDir, ".cpp", containers) + if verbose: + if result2 or result3: +- print " At least one input file needs fixing!" ++ print(" At least one input file needs fixing!") + else: +- print " No input file needs fixing!" ++ print(" No input file needs fixing!") + # Return result. + return result1 or result2 or result3 + +@@ -128,12 +128,12 @@ def fix_input_files(headerDir, sourceDir, containers=['vector', 'list', 'set', ' + # Fix the input files for containers in their variadic form. + if seqType == "both" or seqType == "variadic": + if verbose: +- print "Fix input files for pre-processing Boost.MPL variadic containers." ++ print("Fix input files for pre-processing Boost.MPL variadic containers.") + fix_input_files_for_variadic_seq(headerDir, sourceDir, timestamp) + # Fix the input files for containers in their numbered form. + if seqType == "both" or seqType == "numbered": + if verbose: +- print "Fix input files for pre-processing Boost.MPL numbered containers." ++ print("Fix input files for pre-processing Boost.MPL numbered containers.") + fix_input_files_for_numbered_seq(headerDir, ".hpp", timestamp, containers) + fix_input_files_for_numbered_seq(sourceDir, ".cpp", timestamp, containers) + +@@ -164,10 +164,10 @@ def main(): + + # Some verbose debug output. + if args.verbose: +- print "Arguments extracted from command-line:" +- print " verbose = ", args.verbose +- print " check-only = ", args.checkonly +- print " source directory = ", args.sourceDir ++ print("Arguments extracted from command-line:") ++ print(" verbose = ", args.verbose) ++ print(" check-only = ", args.checkonly) ++ print(" source directory = ", args.sourceDir) + + # The directories for header- and source files of Boost.MPL. + # NOTE: Assuming 'args.sourceDir' is the source-directory of the entire boost project. +@@ -181,21 +181,21 @@ def main(): + sourceDir = os.path.join( args.sourceDir, "preprocessed" ) + if not os.path.exists( headerDir ) or not os.path.exists( sourceDir ): + cmdlineParser.print_usage() +- print "error: Cannot find Boost.MPL header/source files in given Boost source-directory!" ++ print("error: Cannot find Boost.MPL header/source files in given Boost source-directory!") + sys.exit(0) + + # Some verbose debug output. + if args.verbose: +- print "Chosen header-directory: ", headerDir +- print "Chosen source-directory: ", sourceDir ++ print("Chosen header-directory: ", headerDir) ++ print("Chosen source-directory: ", sourceDir) + + if args.checkonly: + # Check input files for generating pre-processed headers. + result = check_input_files(headerDir, sourceDir, verbose = args.verbose) + if result: +- print "Fixing the input-files used for pre-processing of Boost.MPL headers IS required." ++ print("Fixing the input-files used for pre-processing of Boost.MPL headers IS required.") + else: +- print "Fixing the input-files used for pre-processing of Boost.MPL headers is NOT required." ++ print("Fixing the input-files used for pre-processing of Boost.MPL headers is NOT required.") + else: + # Fix input files for generating pre-processed headers. + fix_input_files(headerDir, sourceDir, verbose = args.verbose) +diff --git a/libs/mpl/preprocessed/pp.py b/libs/mpl/preprocessed/pp.py +index 24bfd27..79c8dcd 100644 +--- a/libs/mpl/preprocessed/pp.py ++++ b/libs/mpl/preprocessed/pp.py +@@ -128,7 +128,7 @@ def handle_typedefs(match): + return '%s%s\n' \ + % ( + match.group(1) +- , string.join(map(string.strip, string.split(match.group(2), ';')), join_sep) ++ , string.join(list(map(string.strip, string.split(match.group(2), ';'))), join_sep) + ) + + def fix_angle_brackets( match ): +diff --git a/libs/mpl/preprocessed/preprocess.py b/libs/mpl/preprocessed/preprocess.py +index 0c38eb0..6c87352 100644 +--- a/libs/mpl/preprocessed/preprocess.py ++++ b/libs/mpl/preprocessed/preprocess.py +@@ -57,10 +57,10 @@ def process_all( root, boost_root, dst_dir, mode ): + + def main( all_modes, src_dir, dst_dir ): + if len( sys.argv ) < 2: +- print "\nUsage:\n\t %s []" % os.path.basename( sys.argv[0] ) +- print "\nPurpose:\n\t updates preprocessed version(s) of the header(s) in \"%s\" directory" % dst_dir +- print "\nExample:\n\t the following command will re-generate and update all 'apply.hpp' headers:" +- print "\n\t\t %s all f:\\cvs\\boost apply.cpp" % os.path.basename( sys.argv[0] ) ++ print("\nUsage:\n\t %s []" % os.path.basename( sys.argv[0] )) ++ print("\nPurpose:\n\t updates preprocessed version(s) of the header(s) in \"%s\" directory" % dst_dir) ++ print("\nExample:\n\t the following command will re-generate and update all 'apply.hpp' headers:") ++ print("\n\t\t %s all f:\\cvs\\boost apply.cpp" % os.path.basename( sys.argv[0] )) + sys.exit( -1 ) + + if sys.argv[1] == "all": +diff --git a/libs/numeric/odeint/fix-copyright.py b/libs/numeric/odeint/fix-copyright.py +index f484822..8179f64 100755 +--- a/libs/numeric/odeint/fix-copyright.py ++++ b/libs/numeric/odeint/fix-copyright.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/env python ++#!/usr/bin/env python3 + from subprocess import check_output as run + from datetime import datetime + from itertools import groupby +@@ -18,10 +18,10 @@ def authors(filename): + def new_copyright(filename, previous): + def f(): + au = list(authors(filename)) +- alldates = map(itemgetter(1), au) +- aup = sorted(au + map(lambda a: (a, None), previous), key=itemgetter(0)) ++ alldates = list(map(itemgetter(1), au)) ++ aup = sorted(au + [(a, None) for a in previous], key=itemgetter(0)) + for author, records in groupby(aup, itemgetter(0)): +- dates = filter(None, map(itemgetter(1), records)) ++ dates = [_f for _f in map(itemgetter(1), records) if _f] + if not dates: dates = alldates + start = min(dates) + end = max(dates) +@@ -29,7 +29,7 @@ def new_copyright(filename, previous): + line = 'Copyright ' + fmt.format(start.year, end.year) + ' ' + author + key = (start, author) + yield key, line +- return map(itemgetter(1), sorted(f())) ++ return list(map(itemgetter(1), sorted(f()))) + + def fix_copyright(filename): + # Find copyright block in original file +@@ -46,19 +46,19 @@ def fix_copyright(filename): + lines.append(i) + names.append(d['name'].strip()) + if len(prefix) != 1: +- print 'Not found:', filename ++ print('Not found:', filename) + return + prefix = list(prefix)[0] + +- print filename ++ print(filename) + new = iter(new_copyright(filename, names)) + with open(filename, 'w') as f: + for i, line in enumerate(content): + if i in lines: + for repl in new: +- print >>f, prefix + repl ++ print(prefix + repl, file=f) + else: +- print >>f, line, ++ print(line, end=' ', file=f) + pass + + def all_files(): +diff --git a/libs/numeric/odeint/performance/plot_result.py b/libs/numeric/odeint/performance/plot_result.py +index f39e49f..c3d7119 100644 +--- a/libs/numeric/odeint/performance/plot_result.py ++++ b/libs/numeric/odeint/performance/plot_result.py +@@ -36,7 +36,7 @@ t_c_intel = [get_runtime_from_file("perf_workbook/rk4_c_intel.perf"), + get_runtime_from_file("perf_ariel/rk4_c_intel.perf"), + get_runtime_from_file("perf_lyra/rk4_c_intel.perf")] + +-print t_c_intel ++print(t_c_intel) + + + ind = np.arange(3) # the x locations for the groups +diff --git a/libs/program_options/test/program_options_size_test.py b/libs/program_options/test/program_options_size_test.py +index 25ca2f7..e4cc6e9 100644 +--- a/libs/program_options/test/program_options_size_test.py ++++ b/libs/program_options/test/program_options_size_test.py +@@ -37,17 +37,17 @@ def run_tests(range, compiler_command): + for num in range: + size = run_test(num, compiler_command) + if last_size: +- print "%2d calls: %5d bytes (+ %d)" % (num, size, size-last_size) ++ print("%2d calls: %5d bytes (+ %d)" % (num, size, size-last_size)) + else: +- print "%2d calls: %5d bytes" % (num, size) ++ print("%2d calls: %5d bytes" % (num, size)) + first_size = size + last_size = size +- print "Avarage: ", (last_size-first_size)/(range[-1]-range[0]) ++ print("Avarage: ", (last_size-first_size)/(range[-1]-range[0])) + + if __name__ == '__main__': + for compiler in [ "g++ -Os", "g++ -O3"]: +- print "****", compiler, "****" +- run_tests(range(1, 20), compiler) ++ print("****", compiler, "****") ++ run_tests(list(range(1, 20)), compiler) + + + +diff --git a/libs/program_options/test/winmain.py b/libs/program_options/test/winmain.py +index 5c43242..ae5007f 100644 +--- a/libs/program_options/test/winmain.py ++++ b/libs/program_options/test/winmain.py +@@ -1,5 +1,5 @@ + +-from StringIO import StringIO ++from io import StringIO + import string + + testcases = r"""1 -> 1 +@@ -34,6 +34,6 @@ for s in t: + # print value, result + tokens = string.split(result, ",") + value = quote(value) +- tokens = map(string.strip, tokens) +- tokens = map(quote, tokens) +- print "TEST(%s, {%s});" % (value, string.join(tokens, ",")) ++ tokens = list(map(string.strip, tokens)) ++ tokens = list(map(quote, tokens)) ++ print("TEST(%s, {%s});" % (value, string.join(tokens, ","))) +diff --git a/libs/python/config/__init__.py b/libs/python/config/__init__.py +index 704124b..e217901 100644 +--- a/libs/python/config/__init__.py ++++ b/libs/python/config/__init__.py +@@ -61,14 +61,14 @@ def get_checks(env): + + def set_property(env, **kw): + +- from toolchains.gcc import features as gcc_features +- from toolchains.msvc import features as msvc_features ++ from .toolchains.gcc import features as gcc_features ++ from .toolchains.msvc import features as msvc_features + + if 'gcc' in env['TOOLS']: features = gcc_features + elif 'msvc' in env['TOOLS']: features = msvc_features + else: raise Error('unknown toolchain') + features.init_once(env) +- for (prop,value) in kw.items(): ++ for (prop,value) in list(kw.items()): + getattr(features, prop, lambda x, y : None)(env, value) + env[prop.upper()] = value + +diff --git a/libs/python/config/toolchains/__init__.py b/libs/python/config/toolchains/__init__.py +index af38285..f54cd7c 100644 +--- a/libs/python/config/toolchains/__init__.py ++++ b/libs/python/config/toolchains/__init__.py +@@ -11,7 +11,7 @@ import traceback + def append_feature_flag(env, **kw): + stack = traceback.extract_stack(limit = 3) + feature = stack[0][2].upper() +- for (key, val) in kw.items(): ++ for (key, val) in list(kw.items()): + feature_var = feature + "_" + key + env.AppendUnique(**{ key : "$" + feature_var }) + env[feature_var] = val +diff --git a/libs/python/config/tools/libs.py b/libs/python/config/tools/libs.py +index da8119d..97daa95 100644 +--- a/libs/python/config/tools/libs.py ++++ b/libs/python/config/tools/libs.py +@@ -53,7 +53,7 @@ def boost_copy_func(dest, source, env): + if os.path.isdir(source): + if os.path.exists(dest): + if not os.path.isdir(dest): +- raise SCons.Errors.UserError, "cannot overwrite non-directory `%s' with a directory `%s'" % (str(dest), str(source)) ++ raise SCons.Errors.UserError("cannot overwrite non-directory `%s' with a directory `%s'" % (str(dest), str(source))) + else: + os.makedirs(dest) + for file in os.listdir(source): +diff --git a/libs/python/config/tools/sphinx4scons.py b/libs/python/config/tools/sphinx4scons.py +index dda88d2..41ccd0e 100644 +--- a/libs/python/config/tools/sphinx4scons.py ++++ b/libs/python/config/tools/sphinx4scons.py +@@ -162,7 +162,7 @@ def _get_sphinxoptions(env, target, source): + if settings is not None: + if not SCons.SCons.Util.is_Dict(settings): + raise TypeError('SPHINXSETTINGS and/or settings argument must be a dictionary') +- for key, value in settings.iteritems(): ++ for key, value in settings.items(): + if value != '': + value = env.subst(value, target=target, source=source) + options.append('-D "%s=%s"' % (key, value)) +@@ -246,7 +246,7 @@ class SourceInfo(object): + + def _get_config(self, confignode, env): + config = {} +- execfile(confignode.File('conf.py').rfile().get_abspath(), config) ++ exec(compile(open(confignode.File('conf.py').rfile().get_abspath()).read(), confignode.File('conf.py').rfile().get_abspath(), 'exec'), config) + return config + + +@@ -321,7 +321,7 @@ class SourceInfo(object): + def _exclude(self, matchers, items): + result = items + for matcher in matchers: +- result = filter(lambda x: not matcher(x), result) ++ result = [x for x in result if not matcher(x)] + return result + + +@@ -505,8 +505,7 @@ def _get_latex_emissions(env, target, srcinfo): + sources = [] + sources.extend(srcinfo.sources) + +- targets = map(lambda x: target[0].File(os_path(x[1])), +- srcinfo.config.get('latex_documents')) ++ targets = [target[0].File(os_path(x[1])) for x in srcinfo.config.get('latex_documents')] + + return targets, sources + +@@ -521,8 +520,7 @@ def _get_linkcheck_emissions(env, target, srcinfo): + def _get_man_emissions(env, target, srcinfo): + sources = [] + sources.extend(srcinfo.sources) +- targets = map(lambda x: target[0].File(os_path("%s.%s" % (x[1], x[4]))), +- srcinfo.config.get('man_pages')) ++ targets = [target[0].File(os_path("%s.%s" % (x[1], x[4]))) for x in srcinfo.config.get('man_pages')] + return targets, sources + + +@@ -570,11 +568,9 @@ def _get_texinfo_emissions(env, target, srcinfo): + + sources = [] + sources.extend(srcinfo.sources) +- sources.extend(map(lambda x: source[0].File(os_path(x + suffix)), +- srcinfo.config.get('texinfo_appendices', []))) ++ sources.extend([source[0].File(os_path(x + suffix)) for x in srcinfo.config.get('texinfo_appendices', [])]) + +- targets = map(lambda x: target[0].File(os_path("%s.texi" % x[1])), +- srcinfo.config.get('texinfo_documents')) ++ targets = [target[0].File(os_path("%s.texi" % x[1])) for x in srcinfo.config.get('texinfo_documents')] + + return targets, sources + +diff --git a/libs/python/config/tools/tests.py b/libs/python/config/tools/tests.py +index a2e8e08..09f0dc1 100644 +--- a/libs/python/config/tools/tests.py ++++ b/libs/python/config/tools/tests.py +@@ -91,11 +91,11 @@ def BoostTestSummary(env, tests, **kw): + results = tests + failures = [r for r in results + if r.get_path().endswith('.result') and not 'Result: pass' in r.get_contents()] +- print('%s tests; %s pass; %s fails'%(len(results), len(results)-len(failures), len(failures))) ++ print(('%s tests; %s pass; %s fails'%(len(results), len(results)-len(failures), len(failures)))) + if failures: + print('For detailed failure reports, see:') + for f in failures: +- print(f.get_path()) ++ print((f.get_path())) + + testsumcomstr = env.get('TESTSUMCOMSTR') + if testsumcomstr: +diff --git a/libs/python/config/ui.py b/libs/python/config/ui.py +index e6e4f24..4f83567 100644 +--- a/libs/python/config/ui.py ++++ b/libs/python/config/ui.py +@@ -72,7 +72,7 @@ def pretty_output(env): + + #If the output is not a terminal, remove the colors + if not sys.stdout.isatty(): +- for key, value in colors.iteritems(): ++ for key, value in colors.items(): + colors[key] = '' + + compile_source_message = '{green}Compiling $TARGET{end}'.format(**colors) +diff --git a/libs/python/doc/numpy/conf.py b/libs/python/doc/numpy/conf.py +index 2f5d5e8..23ab678 100644 +--- a/libs/python/doc/numpy/conf.py ++++ b/libs/python/doc/numpy/conf.py +@@ -40,8 +40,8 @@ source_suffix = '.rst' + master_doc = 'index' + + # General information about the project. +-project = u'Boost.Python NumPy extension' +-copyright = u'2011, Stefan Seefeld' ++project = 'Boost.Python NumPy extension' ++copyright = '2011, Stefan Seefeld' + + # The version info for the project you're documenting, acts as replacement for + # |version| and |release|, also used in various other places throughout the +@@ -181,8 +181,8 @@ html_add_permalinks = False + # Grouping the document tree into LaTeX files. List of tuples + # (source start file, target name, title, author, documentclass [howto/manual]). + latex_documents = [ +- ('index', 'BoostPythonNumPy.tex', u'Boost.Python NumPy Documentation', +- u'Stefan Seefeld', 'manual'), ++ ('index', 'BoostPythonNumPy.tex', 'Boost.Python NumPy Documentation', ++ 'Stefan Seefeld', 'manual'), + ] + + # The name of an image file (relative to this directory) to place at the top of +@@ -214,6 +214,6 @@ latex_documents = [ + # One entry per manual page. List of tuples + # (source start file, name, description, authors, manual section). + man_pages = [ +- ('index', 'boostnumpy', u'Boost.Python NumPy Documentation', +- [u'Stefan Seefeld'], 1) ++ ('index', 'boostnumpy', 'Boost.Python NumPy Documentation', ++ ['Stefan Seefeld'], 1) + ] +diff --git a/libs/python/example/numpy/demo_gaussian.py b/libs/python/example/numpy/demo_gaussian.py +index 0b1c789..16b8193 100644 +--- a/libs/python/example/numpy/demo_gaussian.py ++++ b/libs/python/example/numpy/demo_gaussian.py +@@ -19,19 +19,19 @@ x, y = numpy.meshgrid(r, r) + z = g(x, y) + + s = z.sum() * (r[1] - r[0])**2 +-print "sum (should be ~ 1):", s ++print("sum (should be ~ 1):", s) + + xc = (z * x).sum() / z.sum() +-print "x centroid (should be ~ %f): %f" % (mu[0], xc) ++print("x centroid (should be ~ %f): %f" % (mu[0], xc)) + + yc = (z * y).sum() / z.sum() +-print "y centroid (should be ~ %f): %f" % (mu[1], yc) ++print("y centroid (should be ~ %f): %f" % (mu[1], yc)) + + xx = (z * (x - xc)**2).sum() / z.sum() +-print "xx moment (should be ~ %f): %f" % (sigma[0,0], xx) ++print("xx moment (should be ~ %f): %f" % (sigma[0,0], xx)) + + yy = (z * (y - yc)**2).sum() / z.sum() +-print "yy moment (should be ~ %f): %f" % (sigma[1,1], yy) ++print("yy moment (should be ~ %f): %f" % (sigma[1,1], yy)) + + xy = 0.5 * (z * (x - xc) * (y - yc)).sum() / z.sum() +-print "xy moment (should be ~ %f): %f" % (sigma[0,1], xy) ++print("xy moment (should be ~ %f): %f" % (sigma[0,1], xy)) +diff --git a/libs/python/example/tutorial/hello.py b/libs/python/example/tutorial/hello.py +index 31f7556..9fd58e7 100755 +--- a/libs/python/example/tutorial/hello.py ++++ b/libs/python/example/tutorial/hello.py +@@ -5,4 +5,4 @@ + # Hello World Example from the tutorial + + import hello_ext +-print(hello_ext.greet()) ++print((hello_ext.greet())) +diff --git a/libs/python/test/args.py b/libs/python/test/args.py +index e884c06..b6986af 100644 +--- a/libs/python/test/args.py ++++ b/libs/python/test/args.py +@@ -1,7 +1,7 @@ + # Copyright David Abrahams 2004. Distributed under the Boost + # Software License, Version 1.0. (See accompanying + # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +-from __future__ import print_function ++ + """ + >>> from args_ext import * + +diff --git a/libs/python/test/dict.py b/libs/python/test/dict.py +index 72c37d9..961c498 100644 +--- a/libs/python/test/dict.py ++++ b/libs/python/test/dict.py +@@ -1,7 +1,7 @@ + # Copyright David Abrahams 2004. Distributed under the Boost + # Software License, Version 1.0. (See accompanying + # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +-from __future__ import print_function ++ + """ + >>> from dict_ext import * + >>> def printer(*args): +diff --git a/libs/python/test/docstring.py b/libs/python/test/docstring.py +index 2727bd6..1b04dcd 100644 +--- a/libs/python/test/docstring.py ++++ b/libs/python/test/docstring.py +@@ -135,7 +135,7 @@ def run(args = None): + docmodule = lambda m: re.sub(".\10", "", pydoc.text.docmodule(m)) + try: + print('printing module help:') +- print(docmodule(docstring_ext)) ++ print((docmodule(docstring_ext))) + except object as x: + print('********* failed **********') + print(x) +diff --git a/libs/python/test/iterator.py b/libs/python/test/iterator.py +index 314a356..d16c833 100644 +--- a/libs/python/test/iterator.py ++++ b/libs/python/test/iterator.py +@@ -1,7 +1,7 @@ + # Copyright David Abrahams 2004. Distributed under the Boost + # Software License, Version 1.0. (See accompanying + # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +-from __future__ import print_function ++ + ''' + >>> from iterator_ext import * + >>> from input_iterator import * +diff --git a/libs/python/test/list.py b/libs/python/test/list.py +index 913032d..05e6221 100644 +--- a/libs/python/test/list.py ++++ b/libs/python/test/list.py +@@ -1,7 +1,7 @@ + # Copyright David Abrahams 2004. Distributed under the Boost + # Software License, Version 1.0. (See accompanying + # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +-from __future__ import print_function ++ + ''' + >>> from list_ext import * + +diff --git a/libs/python/test/map_indexing_suite.py b/libs/python/test/map_indexing_suite.py +index a5750a8..6d40569 100644 +--- a/libs/python/test/map_indexing_suite.py ++++ b/libs/python/test/map_indexing_suite.py +@@ -1,7 +1,7 @@ + # Copyright Joel de Guzman 2004. Distributed under the Boost + # Software License, Version 1.0. (See accompanying + # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +-from __future__ import print_function ++ + ''' + + ##################################################################### +diff --git a/libs/python/test/numpy/dtype.py b/libs/python/test/numpy/dtype.py +index a27ee0f..c27f809 100644 +--- a/libs/python/test/numpy/dtype.py ++++ b/libs/python/test/numpy/dtype.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/env python ++#!/usr/bin/env python3 + + # Copyright Jim Bosch & Ankit Daftery 2010-2012. + # Distributed under the Boost Software License, Version 1.0. +@@ -30,8 +30,8 @@ class DtypeTestCase(unittest.TestCase): + self.assertEquivalent(fu(True), numpy.dtype(u)) + self.assertEquivalent(fs(int(1)), numpy.dtype(s)) + self.assertEquivalent(fu(int(1)), numpy.dtype(u)) +- self.assertEquivalent(fs(long(1)), numpy.dtype(s)) +- self.assertEquivalent(fu(long(1)), numpy.dtype(u)) ++ self.assertEquivalent(fs(int(1)), numpy.dtype(s)) ++ self.assertEquivalent(fu(int(1)), numpy.dtype(u)) + for name in ("bool_", "byte", "ubyte", "short", "ushort", "intc", "uintc"): + t = getattr(numpy, name) + ft = getattr(dtype_ext, "accept_%s" % name) +@@ -40,7 +40,7 @@ class DtypeTestCase(unittest.TestCase): + self.assertEquivalent(ft(True), numpy.dtype(t)) + if name != "bool_": + self.assertEquivalent(ft(int(1)), numpy.dtype(t)) +- self.assertEquivalent(ft(long(1)), numpy.dtype(t)) ++ self.assertEquivalent(ft(int(1)), numpy.dtype(t)) + + + def testFloats(self): +diff --git a/libs/python/test/numpy/ndarray.py b/libs/python/test/numpy/ndarray.py +index 2acc384..0259a90 100644 +--- a/libs/python/test/numpy/ndarray.py ++++ b/libs/python/test/numpy/ndarray.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/env python ++#!/usr/bin/env python3 + + # Copyright Jim Bosch & Ankit Daftery 2010-2012. + # Distributed under the Boost Software License, Version 1.0. +@@ -32,7 +32,7 @@ class TestNdarray(unittest.TestCase): + self.assertEqual(type(a1), type(a2)) + + def testNdarray(self): +- a = range(0,60) ++ a = list(range(0,60)) + for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128): + v = numpy.array(a, dtype=dtp) + dt = numpy.dtype(dtp) +diff --git a/libs/python/test/numpy/ufunc.py b/libs/python/test/numpy/ufunc.py +index e820121..c23d08b 100755 +--- a/libs/python/test/numpy/ufunc.py ++++ b/libs/python/test/numpy/ufunc.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/env python ++#!/usr/bin/env python3 + + # Copyright Jim Bosch & Ankit Daftery 2010-2012. + # Distributed under the Boost Software License, Version 1.0. +@@ -29,7 +29,7 @@ class TestUnary(unittest.TestCase): + + def testList(self): + f = ufunc_ext.UnaryCallable() +- a = range(5) ++ a = list(range(5)) + b = f(a) + assert_array_almost_equal(b/2.0, a) + +diff --git a/libs/python/test/object.py b/libs/python/test/object.py +index 67a46d9..9bf0989 100644 +--- a/libs/python/test/object.py ++++ b/libs/python/test/object.py +@@ -1,7 +1,7 @@ + # Copyright David Abrahams 2004. Distributed under the Boost + # Software License, Version 1.0. (See accompanying + # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +-from __future__ import print_function ++ + ''' + >>> from object_ext import * + +diff --git a/libs/python/test/pickle2.py b/libs/python/test/pickle2.py +index f4788d3..ded5f99 100644 +--- a/libs/python/test/pickle2.py ++++ b/libs/python/test/pickle2.py +@@ -1,7 +1,7 @@ + # Copyright David Abrahams 2004. Distributed under the Boost + # Software License, Version 1.0. (See accompanying + # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +-from __future__ import print_function ++ + r'''>>> import pickle2_ext + >>> import pickle + >>> pickle2_ext.world.__module__ +diff --git a/libs/python/test/pickle3.py b/libs/python/test/pickle3.py +index 932e30f..f3cc479 100644 +--- a/libs/python/test/pickle3.py ++++ b/libs/python/test/pickle3.py +@@ -1,7 +1,7 @@ + # Copyright David Abrahams 2004. Distributed under the Boost + # Software License, Version 1.0. (See accompanying + # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +-from __future__ import print_function ++ + r'''>>> import pickle3_ext + >>> import pickle + >>> pickle3_ext.world.__module__ +diff --git a/libs/python/test/str.py b/libs/python/test/str.py +index 4eba0e8..72bddb2 100644 +--- a/libs/python/test/str.py ++++ b/libs/python/test/str.py +@@ -1,7 +1,7 @@ + # Copyright David Abrahams 2004. Distributed under the Boost + # Software License, Version 1.0. (See accompanying + # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +-from __future__ import print_function ++ + """ + >>> from str_ext import * + >>> def printer(*args): +diff --git a/libs/python/test/test_cltree.py b/libs/python/test/test_cltree.py +index 2127b7c..22a46df 100644 +--- a/libs/python/test/test_cltree.py ++++ b/libs/python/test/test_cltree.py +@@ -1,4 +1,4 @@ +-# Copyright David Abrahams 2004. Distributed under the Boost ++# Copyright David Abrahams 2004. Distributed under the Boost3 + # Software License, Version 1.0. (See accompanying + # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + #!/usr/bin/env python +@@ -30,13 +30,13 @@ assert not isinstance(v,symbol) + assert not isinstance(v,constant) + assert isinstance(v,variable) + +-print('b=',b) ++print(('b=',b)) + assert repr(b)=='cltree.basic()' +-print('s=',s) ++print(('s=',s)) + assert repr(s)!='cltree.wrapped_symbol()' # because not isinstance(s,basic) +-print('c=',c) ++print(('c=',c)) + assert repr(c)=='cltree.constant()' +-print('v=',v) ++print(('v=',v)) + assert repr(v)=='cltree.wrapped_variable()' + + +diff --git a/libs/python/test/tuple.py b/libs/python/test/tuple.py +index 1aec5fd..d748264 100644 +--- a/libs/python/test/tuple.py ++++ b/libs/python/test/tuple.py +@@ -1,7 +1,7 @@ + # Copyright David Abrahams 2004. Distributed under the Boost + # Software License, Version 1.0. (See accompanying + # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +-from __future__ import print_function ++ + """ + >>> from tuple_ext import * + >>> def printer(*args): +diff --git a/status/boost_check_library.py b/status/boost_check_library.py +index e755639..61dbc01 100644 +--- a/status/boost_check_library.py ++++ b/status/boost_check_library.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/env python ++#!/usr/bin/env python3 + + # Copyright Rene Rivera 2016 + # +@@ -163,11 +163,11 @@ class check_library(): + self.library_key = self.library.split('/',1)[1] + + if self.debug: +- print ">>> cwd: %s"%(os.getcwd()) +- print ">>> actions: %s"%(self.actions) +- print ">>> boost_root: %s"%(self.boost_root) +- print ">>> library: %s"%(self.library) +- print ">>> jamfile: %s"%(self.jamfile) ++ print(">>> cwd: %s"%(os.getcwd())) ++ print(">>> actions: %s"%(self.actions)) ++ print(">>> boost_root: %s"%(self.boost_root)) ++ print(">>> library: %s"%(self.library)) ++ print(">>> jamfile: %s"%(self.jamfile)) + + for action in self.actions: + action_m = "check_"+action.replace('-','_') +@@ -206,24 +206,24 @@ class check_library(): + + def error(self, reason, message, key): + self.error_count += 1 +- print("%s: error: %s; %s <<%s>>"%( ++ print(("%s: error: %s; %s <<%s>>"%( + self.library, + self.clean_message(reason), + self.clean_message(message), + key, +- )) ++ ))) + + def warn(self, reason, message, key): +- print("%s: warning: %s; %s <<%s>>"%( ++ print(("%s: warning: %s; %s <<%s>>"%( + self.library, + self.clean_message(reason), + self.clean_message(message), + key, +- )) ++ ))) + + def info(self, message): + if self.debug: +- print("%s: info: %s"%(self.library, self.clean_message(message))) ++ print(("%s: info: %s"%(self.library, self.clean_message(message)))) + + def clean_message(self, message): + return " ".join(message.strip().split()) +diff --git a/tools/boostbook/setup_boostbook.py b/tools/boostbook/setup_boostbook.py +index 032587d..08e9424 100644 +--- a/tools/boostbook/setup_boostbook.py ++++ b/tools/boostbook/setup_boostbook.py +@@ -31,7 +31,7 @@ sys.path.append( os.path.join( os.path.dirname( sys.modules[ __name__ ].__file__ + , "../regression/xsl_reports/utils" ) ) + + import checked_system +-import urllib2 ++import urllib.request, urllib.error, urllib.parse + import tarfile + import zipfile + +@@ -53,7 +53,7 @@ def to_posix( path ): + def unzip( archive_path, result_dir ): + z = zipfile.ZipFile( archive_path, 'r', zipfile.ZIP_DEFLATED ) + for f in z.infolist(): +- print f.filename ++ print(f.filename) + if not os.path.exists( os.path.join( result_dir, os.path.dirname( f.filename ) ) ): + os.makedirs( os.path.join( result_dir, os.path.dirname( f.filename ) ) ) + result = open( os.path.join( result_dir, f.filename ), 'wb' ) +@@ -70,23 +70,23 @@ def gunzip( archive_path, result_dir ): + + def http_get( file, url ): + f = open( file, "wb" ) +- f.write( urllib2.urlopen( url ).read() ) ++ f.write( urllib.request.urlopen( url ).read() ) + f.close() + + def find_executable( executable_name, env_variable, test_args, error_message ): +- print "Looking for %s ..." % executable_name +- if os.environ.has_key( env_variable ): ++ print("Looking for %s ..." % executable_name) ++ if env_variable in os.environ: + specified = os.environ[ env_variable ] +- print " Trying %s specified in env. variable %s" % ( specified, env_variable ) ++ print(" Trying %s specified in env. variable %s" % ( specified, env_variable )) + if os.path.exists( specified ): + return specified.replace( "\\", "/" ) + else: +- print "Cannot find %s specified in env. variable %s" % ( specified, env_variable ) ++ print("Cannot find %s specified in env. variable %s" % ( specified, env_variable )) + + rc = checked_system.system( [ "%s %s" % ( executable_name, test_args ) ] ) +- print "" ++ print("") + if rc != 0: +- print error_message ++ print(error_message) + return None + else: + return executable_name.replace( "\\", "/" ) +@@ -99,7 +99,7 @@ def adjust_user_config( config_file + , fop + , java + ): +- print "Modifying user-config.jam ..." ++ print("Modifying user-config.jam ...") + r = [] + using_boostbook = 0 + eaten=0 +@@ -138,52 +138,52 @@ def adjust_user_config( config_file + if doxygen is not None: + r.append( "using doxygen : %s ;\n" % doxygen ) + if fop is not None: +- print r.append( "using fop : %s : : %s ;\n" % ( fop, java ) ) ++ print(r.append( "using fop : %s : : %s ;\n" % ( fop, java ) )) + + open( config_file + ".tmp", "w" ).writelines( r ) + try: + os.rename( config_file + ".tmp", config_file ) +- except OSError, e: ++ except OSError as e: + os.unlink( config_file ) + os.rename( config_file + ".tmp", config_file ) + + + def setup_docbook_xsl( tools_directory ): +- print "DocBook XSLT Stylesheets ..." ++ print("DocBook XSLT Stylesheets ...") + DOCBOOK_XSL_TARBALL = os.path.join( tools_directory, "docbook-xsl-%s.tar.gz" % DOCBOOK_XSL_VERSION ) + DOCBOOK_XSL_URL = "%s/docbook-xsl/%s/%s/download" % (SOURCEFORGE_DOWNLOAD, DOCBOOK_XSL_VERSION, os.path.basename( DOCBOOK_XSL_TARBALL ) ) + + if os.path.exists( DOCBOOK_XSL_TARBALL ): +- print " Using existing DocBook XSLT Stylesheets (version %s)." % DOCBOOK_XSL_VERSION ++ print(" Using existing DocBook XSLT Stylesheets (version %s)." % DOCBOOK_XSL_VERSION) + else: +- print " Downloading DocBook XSLT Stylesheets version %s..." % DOCBOOK_XSL_VERSION +- print " from %s" % DOCBOOK_XSL_URL ++ print(" Downloading DocBook XSLT Stylesheets version %s..." % DOCBOOK_XSL_VERSION) ++ print(" from %s" % DOCBOOK_XSL_URL) + http_get( DOCBOOK_XSL_TARBALL, DOCBOOK_XSL_URL ) + + DOCBOOK_XSL_DIR = to_posix( os.path.join( tools_directory, "docbook-xsl-%s" % DOCBOOK_XSL_VERSION ) ) + + if not os.path.exists( DOCBOOK_XSL_DIR ): +- print " Expanding DocBook XSLT Stylesheets into %s..." % DOCBOOK_XSL_DIR ++ print(" Expanding DocBook XSLT Stylesheets into %s..." % DOCBOOK_XSL_DIR) + gunzip( DOCBOOK_XSL_TARBALL, tools_directory ) +- print " done." ++ print(" done.") + + return DOCBOOK_XSL_DIR + + def setup_docbook_dtd( tools_directory ): +- print "DocBook DTD ..." ++ print("DocBook DTD ...") + DOCBOOK_DTD_ZIP = to_posix( os.path.join( tools_directory, "docbook-xml-%s.zip" % DOCBOOK_DTD_VERSION ) ) + DOCBOOK_DTD_URL = "http://www.oasis-open.org/docbook/xml/%s/%s" % ( DOCBOOK_DTD_VERSION, os.path.basename( DOCBOOK_DTD_ZIP ) ) + if os.path.exists( DOCBOOK_DTD_ZIP ): +- print " Using existing DocBook XML DTD (version %s)." % DOCBOOK_DTD_VERSION ++ print(" Using existing DocBook XML DTD (version %s)." % DOCBOOK_DTD_VERSION) + else: +- print " Downloading DocBook XML DTD version %s..." % DOCBOOK_DTD_VERSION ++ print(" Downloading DocBook XML DTD version %s..." % DOCBOOK_DTD_VERSION) + http_get( DOCBOOK_DTD_ZIP, DOCBOOK_DTD_URL ) + + DOCBOOK_DTD_DIR = to_posix( os.path.join( tools_directory, "docbook-dtd-%s" % DOCBOOK_DTD_VERSION ) ) + if not os.path.exists( DOCBOOK_DTD_DIR ): +- print "Expanding DocBook XML DTD into %s... " % DOCBOOK_DTD_DIR ++ print("Expanding DocBook XML DTD into %s... " % DOCBOOK_DTD_DIR) + unzip( DOCBOOK_DTD_ZIP, DOCBOOK_DTD_DIR ) +- print "done." ++ print("done.") + + return DOCBOOK_DTD_DIR + +@@ -208,7 +208,7 @@ def find_java(): + + " environment variable to the path of the java executable." ) ) + + def setup_fop( tools_directory ): +- print "FOP ..." ++ print("FOP ...") + FOP_TARBALL = os.path.join( tools_directory, "fop-%s-bin-jdk%s.tar.gz" % ( FOP_VERSION, FOP_JDK_VERSION ) ) + FOP_URL = "%s/%s" % ( FOP_MIRROR, os.path.basename( FOP_TARBALL ) ) + FOP_DIR = to_posix( "%s/fop-%s" % ( tools_directory, FOP_VERSION ) ) +@@ -220,40 +220,40 @@ def setup_fop( tools_directory ): + FOP = to_posix( os.path.join( FOP_DIR, fop_driver ) ) + + if os.path.exists( FOP_TARBALL ) : +- print " Using existing FOP distribution (version %s)." % FOP_VERSION ++ print(" Using existing FOP distribution (version %s)." % FOP_VERSION) + else: +- print " Downloading FOP distribution version %s..." % FOP_VERSION ++ print(" Downloading FOP distribution version %s..." % FOP_VERSION) + http_get( FOP_TARBALL, FOP_URL ) + + if not os.path.exists( FOP_DIR ): +- print " Expanding FOP distribution into %s... " % FOP_DIR ++ print(" Expanding FOP distribution into %s... " % FOP_DIR) + gunzip( FOP_TARBALL, tools_directory ) +- print " done." ++ print(" done.") + + return FOP + + def find_user_config(): +- print "Looking for user-config.jam ..." ++ print("Looking for user-config.jam ...") + JAM_CONFIG_OUT = os.path.join( os.environ[ "HOME" ], "user-config.jam" ) + if os.path.exists( JAM_CONFIG_OUT ): + JAM_CONFIG_IN ="user-config-backup.jam" +- print " Found user-config.jam in HOME directory (%s)" % JAM_CONFIG_IN ++ print(" Found user-config.jam in HOME directory (%s)" % JAM_CONFIG_IN) + shutil.copyfile( JAM_CONFIG_OUT, os.path.join( os.environ[ "HOME" ], "user-config-backup.jam" ) ) + JAM_CONFIG_IN_TEMP="yes" +- print " Updating Boost.Jam configuration in %s... " % JAM_CONFIG_OUT ++ print(" Updating Boost.Jam configuration in %s... " % JAM_CONFIG_OUT) + return JAM_CONFIG_OUT +- elif os.environ.has_key( "BOOST_ROOT" ) and os.path.exists( os.path.join( os.environ[ "BOOST_ROOT" ], "tools/build/user-config.jam" ) ): ++ elif "BOOST_ROOT" in os.environ and os.path.exists( os.path.join( os.environ[ "BOOST_ROOT" ], "tools/build/user-config.jam" ) ): + JAM_CONFIG_IN=os.path.join( os.environ[ "BOOST_ROOT" ], "tools/build/user-config.jam" ) +- print " Found user-config.jam in BOOST_ROOT directory (%s)" % JAM_CONFIG_IN ++ print(" Found user-config.jam in BOOST_ROOT directory (%s)" % JAM_CONFIG_IN) + JAM_CONFIG_IN_TEMP="no" +- print " Writing Boost.Jam configuration to %s... " % JAM_CONFIG_OUT ++ print(" Writing Boost.Jam configuration to %s... " % JAM_CONFIG_OUT) + return JAM_CONFIG_IN + return None + + def setup_boostbook( tools_directory ): +- print "Setting up boostbook tools..." +- print "-----------------------------" +- print "" ++ print("Setting up boostbook tools...") ++ print("-----------------------------") ++ print("") + + DOCBOOK_XSL_DIR = setup_docbook_xsl( tools_directory ) + DOCBOOK_DTD_DIR = setup_docbook_dtd( tools_directory ) +@@ -263,7 +263,7 @@ def setup_boostbook( tools_directory ): + + FOP = None + if JAVA is not None: +- print "Java is present." ++ print("Java is present.") + FOP = setup_fop( tools_directory ) + + user_config = find_user_config() +@@ -271,8 +271,8 @@ def setup_boostbook( tools_directory ): + # Find the input jamfile to configure + + if user_config is None: +- print "ERROR: Please set the BOOST_ROOT environment variable to refer to your" +- print "Boost installation or copy user-config.jam into your home directory." ++ print("ERROR: Please set the BOOST_ROOT environment variable to refer to your") ++ print("Boost installation or copy user-config.jam into your home directory.") + sys.exit() + + adjust_user_config( config_file = user_config +@@ -284,11 +284,11 @@ def setup_boostbook( tools_directory ): + , java = JAVA + ) + +- print "done." ++ print("done.") + +- print "Done! Execute \"b2\" in a documentation directory to generate" +- print "documentation with BoostBook. If you have not already, you will need" +- print "to compile Boost.Jam." ++ print("Done! Execute \"b2\" in a documentation directory to generate") ++ print("documentation with BoostBook. If you have not already, you will need") ++ print("to compile Boost.Jam.") + + def main(): + ( tools_directory ) = accept_args( sys.argv[ 1: ] ) +diff --git a/tools/boostbook/test/more/run-tests.py b/tools/boostbook/test/more/run-tests.py +index 33fb855..1a5eb9b 100755 +--- a/tools/boostbook/test/more/run-tests.py ++++ b/tools/boostbook/test/more/run-tests.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/env python ++#!/usr/bin/env python3 + + # Copyright 2010 Daniel James. + # Distributed under the Boost Software License, Version 1.0. (See accompanying +@@ -17,7 +17,7 @@ from collections import defaultdict + # Globals + + def usage_and_exit(): +- print __doc__ ++ print(__doc__) + sys.exit(2) + + def main(argv): +@@ -45,9 +45,9 @@ def main(argv): + boostbook_xsl = etree.XSLT( + etree.parse(os.path.join(boostbook_directory, "docbook.xsl"), parser) + ) +- except lxml.etree.XMLSyntaxError, error: +- print "Error parsing boostbook xsl:" +- print error ++ except lxml.etree.XMLSyntaxError as error: ++ print("Error parsing boostbook xsl:") ++ print(error) + sys.exit(1) + + for root, dirs, files in os.walk(os.path.join(script_directory, 'tests')): +@@ -69,7 +69,7 @@ def main(argv): + doc_text = run_boostbook(parser, boostbook_xsl, src_path) + except: + # TODO: Need better error reporting here: +- print "Error running boostbook for " + src_path ++ print("Error running boostbook for " + src_path) + success = False + continue + +@@ -109,7 +109,7 @@ def normalize_boostbook_ids(doc): + id = node.get('id') + + if(id in ids): +- print 'Duplicate id: ' + id ++ print('Duplicate id: ' + id) + + match = re.match("(.+_id|id)([-mp]?[\d_]+)((?:-bb)?)", id) + if(match): +@@ -131,16 +131,16 @@ def compare_xml(file, doc_text, gold_text): + # So instead just do a text diff. + + if (doc_text != gold_text): +- print "Error: " + file +- print ++ print("Error: " + file) ++ print() + sys.stdout.writelines( + difflib.unified_diff( + gold_text.splitlines(True), + doc_text.splitlines(True) + ) + ) +- print +- print ++ print() ++ print() + return False + else: + return True +diff --git a/tools/boostdep/depinst/depinst.py b/tools/boostdep/depinst/depinst.py +index ce7f060..901bfc3 100644 +--- a/tools/boostdep/depinst/depinst.py ++++ b/tools/boostdep/depinst/depinst.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/env python ++#!/usr/bin/env python3 + + # depinst.py - installs the dependencies needed to test + # a Boost library +@@ -54,7 +54,7 @@ def module_for_header( h, x, gm ): + + return m.group( 1 ) + +- print 'Cannot determine module for header', h ++ print('Cannot determine module for header', h) + + return None + +@@ -149,11 +149,11 @@ def install_modules( deps, x, gm ): + + r = 0 + +- for m, i in deps.items(): ++ for m, i in list(deps.items()): + + if not i: + +- print 'Installing module', m ++ print('Installing module', m) + os.system( 'git submodule -q update --init libs/' + m ) + + r += 1 +@@ -178,8 +178,8 @@ if( __name__ == "__main__" ): + + def vprint( *args ): + for arg in args: +- print arg, +- print ++ print(arg, end=' ') ++ print() + + else: + +diff --git a/tools/build/example/customization/inline_file.py b/tools/build/example/customization/inline_file.py +index 9f13acd..beae3a8 100644 +--- a/tools/build/example/customization/inline_file.py ++++ b/tools/build/example/customization/inline_file.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # Copyright 2003 Vladimir Prus + # Distributed under the Boost Software License, Version 1.0. +@@ -30,7 +30,7 @@ def quote_file(file): + return result + + if len(sys.argv) < 3: +- print "Usage: inline_file.py output_c_file file_to_include" ++ print("Usage: inline_file.py output_c_file file_to_include") + else: + output_c_file = sys.argv[1] + out_file = open(output_c_file, "w"); +diff --git a/tools/build/src/build/alias.py b/tools/build/src/build/alias.py +index e9078c7..6241d20 100755 +--- a/tools/build/src/build/alias.py ++++ b/tools/build/src/build/alias.py +@@ -25,8 +25,8 @@ + # alias big_lib : : @/external_project/big_lib/static ; + # + +-import targets +-import property_set ++from . import targets ++from . import property_set + from b2.manager import get_manager + + from b2.util import metatarget, is_iterable_typed +@@ -39,7 +39,7 @@ class AliasTarget(targets.BasicTarget): + def construct(self, name, source_targets, properties): + if __debug__: + from .virtual_target import VirtualTarget +- assert isinstance(name, basestring) ++ assert isinstance(name, str) + assert is_iterable_typed(source_targets, VirtualTarget) + assert isinstance(properties, property_set.PropertySet) + return [property_set.empty(), source_targets] +@@ -55,11 +55,11 @@ class AliasTarget(targets.BasicTarget): + + @metatarget + def alias(name, sources=[], requirements=[], default_build=[], usage_requirements=[]): +- assert isinstance(name, basestring) +- assert is_iterable_typed(sources, basestring) +- assert is_iterable_typed(requirements, basestring) +- assert is_iterable_typed(default_build, basestring) +- assert is_iterable_typed(usage_requirements, basestring) ++ assert isinstance(name, str) ++ assert is_iterable_typed(sources, str) ++ assert is_iterable_typed(requirements, str) ++ assert is_iterable_typed(default_build, str) ++ assert is_iterable_typed(usage_requirements, str) + project = get_manager().projects().current() + targets = get_manager().targets() + +diff --git a/tools/build/src/build/build_request.py b/tools/build/src/build/build_request.py +index 4fa5407..57293ba 100644 +--- a/tools/build/src/build/build_request.py ++++ b/tools/build/src/build/build_request.py +@@ -95,7 +95,7 @@ def __x_product_aux (property_sets, seen_features): + def looks_like_implicit_value(v): + """Returns true if 'v' is either implicit value, or + the part before the first '-' symbol is implicit value.""" +- assert isinstance(v, basestring) ++ assert isinstance(v, str) + if feature.is_implicit_value(v): + return 1 + else: +@@ -110,7 +110,7 @@ def from_command_line(command_line): + and constructs build request from it. Returns a list of two + lists. First is the set of targets specified in the command line, + and second is the set of requested build properties.""" +- assert is_iterable_typed(command_line, basestring) ++ assert is_iterable_typed(command_line, str) + targets = [] + properties = [] + +@@ -128,7 +128,7 @@ def from_command_line(command_line): + # Converts one element of command line build request specification into + # internal form. + def convert_command_line_element(e): +- assert isinstance(e, basestring) ++ assert isinstance(e, str) + result = None + parts = e.split("/") + for p in parts: +diff --git a/tools/build/src/build/configure.py b/tools/build/src/build/configure.py +index 10afb82..735c7ca 100644 +--- a/tools/build/src/build/configure.py ++++ b/tools/build/src/build/configure.py +@@ -51,28 +51,28 @@ def components_building(components): + + def log_component_configuration(component, message): + """Report something about component configuration that the user should better know.""" +- assert isinstance(component, basestring) +- assert isinstance(message, basestring) ++ assert isinstance(component, str) ++ assert isinstance(message, str) + __component_logs.setdefault(component, []).append(message) + + def log_check_result(result): +- assert isinstance(result, basestring) ++ assert isinstance(result, str) + global __announced_checks + if not __announced_checks: +- print "Performing configuration checks" ++ print("Performing configuration checks") + __announced_checks = True + +- print result ++ print(result) + + def log_library_search_result(library, result): +- assert isinstance(library, basestring) +- assert isinstance(result, basestring) ++ assert isinstance(library, str) ++ assert isinstance(result, str) + log_check_result((" - %(library)s : %(result)s" % locals()).rjust(__width)) + + + def print_component_configuration(): + +- print "\nComponent configuration:" ++ print("\nComponent configuration:") + for c in __components: + if c in __built_components: + s = "building" +@@ -82,8 +82,8 @@ def print_component_configuration(): + message = message.rjust(__width) + message += " : " + s + for m in __component_logs.get(c, []): +- print " -" + m +- print "" ++ print(" -" + m) ++ print("") + + __builds_cache = {} + +@@ -91,10 +91,10 @@ def builds(metatarget_reference, project, ps, what): + # Attempt to build a metatarget named by 'metatarget-reference' + # in context of 'project' with properties 'ps'. + # Returns non-empty value if build is OK. +- assert isinstance(metatarget_reference, basestring) ++ assert isinstance(metatarget_reference, str) + assert isinstance(project, targets_.ProjectTarget) + assert isinstance(ps, property_set.PropertySet) +- assert isinstance(what, basestring) ++ assert isinstance(what, str) + + result = [] + +@@ -123,7 +123,7 @@ def builds(metatarget_reference, project, ps, what): + return existing + + def set_log_file(log_file_name): +- assert isinstance(log_file_name, basestring) ++ assert isinstance(log_file_name, str) + # Called by Boost.Build startup code to specify name of a file + # that will receive results of configure checks. This + # should never be called by users. +diff --git a/tools/build/src/build/engine.py b/tools/build/src/build/engine.py +index 6e49a8b..f70f9ba 100644 +--- a/tools/build/src/build/engine.py ++++ b/tools/build/src/build/engine.py +@@ -12,13 +12,15 @@ import re + import b2.build.property_set as property_set + + from b2.util import set_jam_action, is_iterable ++import collections ++from functools import reduce + + class BjamAction(object): + """Class representing bjam action defined from Python.""" + + def __init__(self, action_name, function, has_command=False): +- assert isinstance(action_name, basestring) +- assert callable(function) or function is None ++ assert isinstance(action_name, str) ++ assert isinstance(function, collections.Callable) or function is None + self.action_name = action_name + self.function = function + self.has_command = has_command +@@ -116,7 +118,7 @@ class Engine: + if isinstance(targets, str): + targets = [targets] + assert is_iterable(targets) +- assert isinstance(variable, basestring) ++ assert isinstance(variable, str) + + return bjam_interface.call('get-target-variable', targets, variable) + +@@ -133,7 +135,7 @@ class Engine: + value = [value] + + assert is_iterable(targets) +- assert isinstance(variable, basestring) ++ assert isinstance(variable, str) + assert is_iterable(value) + + if targets: +@@ -156,7 +158,7 @@ class Engine: + sources = [sources] + if properties is None: + properties = property_set.empty() +- assert isinstance(action_name, basestring) ++ assert isinstance(action_name, str) + assert is_iterable(targets) + assert is_iterable(sources) + assert(isinstance(properties, property_set.PropertySet)) +@@ -179,11 +181,11 @@ class Engine: + This function will be called by set_update_action, and can + set additional target variables. + """ +- assert isinstance(action_name, basestring) +- assert isinstance(command, basestring) ++ assert isinstance(action_name, str) ++ assert isinstance(command, str) + assert is_iterable(bound_list) + assert is_iterable(flags) +- assert function is None or callable(function) ++ assert function is None or isinstance(function, collections.Callable) + + bjam_flags = reduce(operator.or_, + (action_modifiers[flag] for flag in flags), 0) +@@ -210,8 +212,8 @@ class Engine: + # action name. This way, jamfile rules that take action names + # can just register them without specially checking if + # action is already registered. +- assert isinstance(action_name, basestring) +- assert function is None or callable(function) ++ assert isinstance(action_name, str) ++ assert function is None or isinstance(function, collections.Callable) + if action_name not in self.actions: + self.actions[action_name] = BjamNativeAction(action_name, function) + +@@ -219,7 +221,7 @@ class Engine: + + + def do_set_update_action (self, action_name, targets, sources, property_set_): +- assert isinstance(action_name, basestring) ++ assert isinstance(action_name, str) + assert is_iterable(targets) + assert is_iterable(sources) + assert isinstance(property_set_, property_set.PropertySet) +@@ -229,8 +231,8 @@ class Engine: + action(targets, sources, property_set_) + + def do_set_target_variable (self, target, variable, value, append): +- assert isinstance(target, basestring) +- assert isinstance(variable, basestring) ++ assert isinstance(target, str) ++ assert isinstance(variable, str) + assert is_iterable(value) + assert isinstance(append, int) # matches bools + if append: +@@ -239,8 +241,8 @@ class Engine: + bjam_interface.call("set-target-variable", target, variable, value) + + def do_add_dependency (self, target, source): +- assert isinstance(target, basestring) +- assert isinstance(source, basestring) ++ assert isinstance(target, str) ++ assert isinstance(source, str) + bjam_interface.call("DEPENDS", target, source) + + +diff --git a/tools/build/src/build/errors.py b/tools/build/src/build/errors.py +index dd51739..9565952 100644 +--- a/tools/build/src/build/errors.py ++++ b/tools/build/src/build/errors.py +@@ -31,9 +31,9 @@ class Context: + self.nested_ = nested + + def report(self, indent=""): +- print indent + " -", self.message_ ++ print(indent + " -", self.message_) + if self.nested_: +- print indent + " declared at:" ++ print(indent + " declared at:") + for n in self.nested_: + n.report(indent + " ") + +@@ -45,7 +45,7 @@ class JamfileContext: + + def report(self, indent=""): + for r in self.raw_: +- print indent + " - %s:%s" % (r[0], r[1]) ++ print(indent + " - %s:%s" % (r[0], r[1])) + + class ExceptionWithUserContext(Exception): + +@@ -58,32 +58,32 @@ class ExceptionWithUserContext(Exception): + self.stack_ = stack + + def report(self): +- print "error:", self.args[0] ++ print("error:", self.args[0]) + if self.original_exception_: +- print format(str(self.original_exception_), " ") +- print +- print " error context (most recent first):" ++ print(format(str(self.original_exception_), " ")) ++ print() ++ print(" error context (most recent first):") + for c in self.context_[::-1]: + c.report() +- print ++ print() + if "--stacktrace" in bjam.variable("ARGV"): + if self.original_tb_: + traceback.print_tb(self.original_tb_) + elif self.stack_: + for l in traceback.format_list(self.stack_): +- print l, ++ print(l, end=' ') + else: +- print " use the '--stacktrace' option to get Python stacktrace" +- print ++ print(" use the '--stacktrace' option to get Python stacktrace") ++ print() + + def user_error_checkpoint(callable): + def wrapper(self, *args): + errors = self.manager().errors() + try: + return callable(self, *args) +- except ExceptionWithUserContext, e: ++ except ExceptionWithUserContext as e: + raise +- except Exception, e: ++ except Exception as e: + errors.handle_stray_exception(e) + finally: + errors.pop_user_context() +diff --git a/tools/build/src/build/feature.py b/tools/build/src/build/feature.py +index 85f6579..1fe799e 100644 +--- a/tools/build/src/build/feature.py ++++ b/tools/build/src/build/feature.py +@@ -37,9 +37,9 @@ VALID_ATTRIBUTES = { + + class Feature(object): + def __init__(self, name, values, attributes): +- assert isinstance(name, basestring) +- assert is_iterable_typed(values, basestring) +- assert is_iterable_typed(attributes, basestring) ++ assert isinstance(name, str) ++ assert is_iterable_typed(values, str) ++ assert is_iterable_typed(attributes, str) + self.name = name + self.values = values + self.default = None +@@ -54,11 +54,11 @@ class Feature(object): + setattr(self, attr, True) + + def add_values(self, values): +- assert is_iterable_typed(values, basestring) ++ assert is_iterable_typed(values, str) + self.values.extend(values) + + def set_default(self, value): +- assert isinstance(value, basestring) ++ assert isinstance(value, str) + for attr in ('free', 'optional'): + if getattr(self, attr): + get_manager().errors()('"{}" feature "<{}>" cannot have a default value.' +@@ -72,7 +72,7 @@ class Feature(object): + + def set_parent(self, feature, value): + assert isinstance(feature, Feature) +- assert isinstance(value, basestring) ++ assert isinstance(value, str) + self.parent = (feature, value) + + def __hash__(self): +@@ -120,14 +120,14 @@ reset () + def enumerate (): + """ Returns an iterator to the features map. + """ +- return __all_features.iteritems () ++ return iter(__all_features.items ()) + + def get(name): + """Return the Feature instance for the specified name. + + Throws if no feature by such name exists + """ +- assert isinstance(name, basestring) ++ assert isinstance(name, str) + return __all_features[name] + + # FIXME: prepare-test/finish-test? +@@ -202,20 +202,20 @@ def valid (names): + """ + if isinstance(names, str): + names = [names] +- assert is_iterable_typed(names, basestring) ++ assert is_iterable_typed(names, str) + + return all(name in __all_features for name in names) + + def attributes (feature): + """ Returns the attributes of the given feature. + """ +- assert isinstance(feature, basestring) ++ assert isinstance(feature, str) + return __all_features[feature].attributes_string_list + + def values (feature): + """ Return the values of the given feature. + """ +- assert isinstance(feature, basestring) ++ assert isinstance(feature, str) + validate_feature (feature) + return __all_features[feature].values + +@@ -223,7 +223,7 @@ def is_implicit_value (value_string): + """ Returns true iff 'value_string' is a value_string + of an implicit feature. + """ +- assert isinstance(value_string, basestring) ++ assert isinstance(value_string, str) + if value_string in __implicit_features: + return __implicit_features[value_string] + +@@ -243,7 +243,7 @@ def is_implicit_value (value_string): + def implied_feature (implicit_value): + """ Returns the implicit feature associated with the given implicit value. + """ +- assert isinstance(implicit_value, basestring) ++ assert isinstance(implicit_value, str) + components = implicit_value.split('-') + + if components[0] not in __implicit_features: +@@ -253,8 +253,8 @@ def implied_feature (implicit_value): + + def __find_implied_subfeature (feature, subvalue, value_string): + assert isinstance(feature, Feature) +- assert isinstance(subvalue, basestring) +- assert isinstance(value_string, basestring) ++ assert isinstance(subvalue, str) ++ assert isinstance(value_string, str) + + try: + return __subfeature_from_value[feature][value_string][subvalue] +@@ -270,8 +270,8 @@ def __find_implied_subfeature (feature, subvalue, value_string): + + def implied_subfeature (feature, subvalue, value_string): + assert isinstance(feature, Feature) +- assert isinstance(subvalue, basestring) +- assert isinstance(value_string, basestring) ++ assert isinstance(subvalue, str) ++ assert isinstance(value_string, str) + result = __find_implied_subfeature (feature, subvalue, value_string) + if not result: + raise InvalidValue ("'%s' is not a known subfeature value of '%s%s'" % (subvalue, feature, value_string)) +@@ -281,7 +281,7 @@ def implied_subfeature (feature, subvalue, value_string): + def validate_feature (name): + """ Checks if all name is a valid feature. Otherwise, raises an exception. + """ +- assert isinstance(name, basestring) ++ assert isinstance(name, str) + if name not in __all_features: + raise InvalidFeature ("'%s' is not a valid feature name" % name) + else: +@@ -389,8 +389,8 @@ def expand_subfeatures(properties, dont_validate = False): + def extend (name, values): + """ Adds the given values to the given feature. + """ +- assert isinstance(name, basestring) +- assert is_iterable_typed(values, basestring) ++ assert isinstance(name, str) ++ assert is_iterable_typed(values, str) + name = add_grist (name) + __validate_feature (name) + feature = __all_features [name] +@@ -413,7 +413,7 @@ def validate_value_string (f, value_string): + """ Checks that value-string is a valid value-string for the given feature. + """ + assert isinstance(f, Feature) +- assert isinstance(value_string, basestring) ++ assert isinstance(value_string, str) + if f.free or value_string in f.values: + return + +@@ -452,10 +452,10 @@ def validate_value_string (f, value_string): + subvalues: The additional values of the subfeature being defined. + """ + def extend_subfeature (feature_name, value_string, subfeature_name, subvalues): +- assert isinstance(feature_name, basestring) +- assert isinstance(value_string, basestring) +- assert isinstance(subfeature_name, basestring) +- assert is_iterable_typed(subvalues, basestring) ++ assert isinstance(feature_name, str) ++ assert isinstance(value_string, str) ++ assert isinstance(subfeature_name, str) ++ assert is_iterable_typed(subvalues, str) + feature = validate_feature(feature_name) + + if value_string: +@@ -648,10 +648,10 @@ def __is_subproperty_of (parent_property, p): + # optional value-string is provided, returns true iff the subvalues + # are valid for the given value of the feature. + def is_subvalue(feature, value_string, subfeature, subvalue): +- assert isinstance(feature, basestring) +- assert isinstance(value_string, basestring) +- assert isinstance(subfeature, basestring) +- assert isinstance(subvalue, basestring) ++ assert isinstance(feature, str) ++ assert isinstance(value_string, str) ++ assert isinstance(subfeature, str) ++ assert isinstance(subvalue, str) + if not value_string: + value_string = '' + try: +@@ -794,7 +794,7 @@ def split (properties): + substitution of backslashes for slashes, since Jam, unbidden, + sometimes swaps slash direction on NT. + """ +- assert isinstance(properties, basestring) ++ assert isinstance(properties, str) + def split_one (properties): + pieces = re.split (__re_slash_or_backslash, properties) + result = [] +@@ -866,8 +866,8 @@ def __select_subproperties (parent_property, properties): + return [ x for x in properties if __is_subproperty_of (parent_property, x) ] + + def __get_subfeature_name (subfeature, value_string): +- assert isinstance(subfeature, basestring) +- assert isinstance(value_string, basestring) or value_string is None ++ assert isinstance(subfeature, str) ++ assert isinstance(value_string, str) or value_string is None + if value_string == None: + prefix = '' + else: +@@ -877,8 +877,8 @@ def __get_subfeature_name (subfeature, value_string): + + + def __validate_feature_attributes (name, attributes): +- assert isinstance(name, basestring) +- assert is_iterable_typed(attributes, basestring) ++ assert isinstance(name, str) ++ assert is_iterable_typed(attributes, str) + for attribute in attributes: + if attribute not in VALID_ATTRIBUTES: + raise InvalidAttribute ("unknown attributes: '%s' in feature declaration: '%s'" % (str (b2.util.set.difference (attributes, __all_attributes)), name)) +@@ -894,7 +894,7 @@ def __validate_feature_attributes (name, attributes): + def __validate_feature (feature): + """ Generates an error if the feature is unknown. + """ +- assert isinstance(feature, basestring) ++ assert isinstance(feature, str) + if feature not in __all_features: + raise BaseException ('unknown feature "%s"' % feature) + +diff --git a/tools/build/src/build/generators.py b/tools/build/src/build/generators.py +index a4a39d9..8eb926a 100644 +--- a/tools/build/src/build/generators.py ++++ b/tools/build/src/build/generators.py +@@ -48,10 +48,10 @@ + + + import re +-import cStringIO ++import io + import os.path + +-from virtual_target import Subvariant ++from .virtual_target import Subvariant + from . import virtual_target, type, property_set, property + from b2.exceptions import BaseBoostBuildException + from b2.util.logger import * +@@ -115,7 +115,7 @@ def decrease_indent(): + # same generator. Does nothing if a non-derived target type is passed to it. + # + def update_cached_information_with_a_new_type(type): +- assert isinstance(type, basestring) ++ assert isinstance(type, str) + base_type = b2.build.type.base(type) + + if base_type: +@@ -157,7 +157,7 @@ def invalidate_extendable_viable_source_target_type_cache(): + + def dout(message): + if debug(): +- print __indent + message ++ print(__indent + message) + + + class InvalidTargetSource(BaseBoostBuildException): +@@ -192,11 +192,11 @@ class Generator: + NOTE: all subclasses must have a similar signature for clone to work! + """ + def __init__ (self, id, composing, source_types, target_types_and_names, requirements = []): +- assert isinstance(id, basestring) ++ assert isinstance(id, str) + assert isinstance(composing, bool) +- assert is_iterable_typed(source_types, basestring) +- assert is_iterable_typed(target_types_and_names, basestring) +- assert is_iterable_typed(requirements, basestring) ++ assert is_iterable_typed(source_types, str) ++ assert is_iterable_typed(target_types_and_names, str) ++ assert is_iterable_typed(requirements, str) + self.id_ = id + self.composing_ = composing + self.source_types_ = source_types +@@ -240,8 +240,8 @@ class Generator: + - id + - value to feature in properties + """ +- assert isinstance(new_id, basestring) +- assert is_iterable_typed(new_toolset_properties, basestring) ++ assert isinstance(new_id, str) ++ assert is_iterable_typed(new_toolset_properties, str) + return self.__class__ (new_id, + self.composing_, + self.source_types_, +@@ -254,8 +254,8 @@ class Generator: + """Creates another generator that is the same as $(self), except that + if 'base' is in target types of $(self), 'type' will in target types + of the new generator.""" +- assert isinstance(base, basestring) +- assert isinstance(type, basestring) ++ assert isinstance(base, str) ++ assert isinstance(type, str) + target_types = [] + for t in self.target_types_and_names_: + m = _re_match_type.match(t) +@@ -341,7 +341,7 @@ class Generator: + from .targets import ProjectTarget + assert isinstance(project, ProjectTarget) + # intermediary targets don't have names, so None is possible +- assert isinstance(name, basestring) or name is None ++ assert isinstance(name, str) or name is None + assert isinstance(prop_set, property_set.PropertySet) + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + if project.manager ().logger ().on (): +@@ -377,7 +377,7 @@ class Generator: + from .targets import ProjectTarget + assert isinstance(project, ProjectTarget) + # intermediary targets don't have names, so None is possible +- assert isinstance(name, basestring) or name is None ++ assert isinstance(name, str) or name is None + assert isinstance(prop_set, property_set.PropertySet) + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + # consumed: Targets that this generator will consume directly. +@@ -416,7 +416,7 @@ class Generator: + from .targets import ProjectTarget + assert is_iterable_typed(consumed, virtual_target.VirtualTarget) + assert isinstance(project, ProjectTarget) +- assert isinstance(name, basestring) or name is None ++ assert isinstance(name, str) or name is None + assert isinstance(prop_set, property_set.PropertySet) + result = [] + # If this is 1->1 transformation, apply it to all consumed targets in order. +@@ -430,7 +430,7 @@ class Generator: + return result + + def determine_target_name(self, fullname): +- assert isinstance(fullname, basestring) ++ assert isinstance(fullname, str) + # Determine target name from fullname (maybe including path components) + # Place optional prefix and postfix around basename + +@@ -502,7 +502,7 @@ class Generator: + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + assert isinstance(prop_set, property_set.PropertySet) + assert isinstance(project, ProjectTarget) +- assert isinstance(name, basestring) or name is None ++ assert isinstance(name, str) or name is None + if not name: + name = self.determine_output_name(sources) + +@@ -538,7 +538,7 @@ class Generator: + """ + if __debug__: + from .targets import ProjectTarget +- assert isinstance(name, basestring) or name is None ++ assert isinstance(name, str) or name is None + assert isinstance(project, ProjectTarget) + assert isinstance(prop_set, property_set.PropertySet) + assert is_iterable_typed(sources, virtual_target.VirtualTarget) +@@ -651,7 +651,7 @@ class Generator: + def find (id): + """ Finds the generator with id. Returns None if not found. + """ +- assert isinstance(id, basestring) ++ assert isinstance(id, str) + return __generators.get (id, None) + + def register (g): +@@ -708,10 +708,10 @@ def register (g): + + def check_register_types(fn): + def wrapper(id, source_types, target_types, requirements=[]): +- assert isinstance(id, basestring) +- assert is_iterable_typed(source_types, basestring) +- assert is_iterable_typed(target_types, basestring) +- assert is_iterable_typed(requirements, basestring) ++ assert isinstance(id, str) ++ assert is_iterable_typed(source_types, str) ++ assert is_iterable_typed(target_types, str) ++ assert is_iterable_typed(requirements, str) + return fn(id, source_types, target_types, requirements=requirements) + wrapper.__name__ = fn.__name__ + wrapper.__doc__ = fn.__doc__ +@@ -741,7 +741,7 @@ def register_composing (id, source_types, target_types, requirements = []): + def generators_for_toolset (toolset): + """ Returns all generators which belong to 'toolset'. + """ +- assert isinstance(toolset, basestring) ++ assert isinstance(toolset, str) + return __generators_for_toolset.get(toolset, []) + + def override (overrider_id, overridee_id): +@@ -754,8 +754,8 @@ def override (overrider_id, overridee_id): + The overridden generators are discarded immediately + after computing the list of viable generators, before + running any of them.""" +- assert isinstance(overrider_id, basestring) +- assert isinstance(overridee_id, basestring) ++ assert isinstance(overrider_id, str) ++ assert isinstance(overridee_id, str) + + __overrides.setdefault(overrider_id, []).append(overridee_id) + +@@ -767,7 +767,7 @@ def __viable_source_types_real (target_type): + returns union of source types for those generators and result + of calling itself recusrively on source types. + """ +- assert isinstance(target_type, basestring) ++ assert isinstance(target_type, str) + generators = [] + + # 't0' is the initial list of target types we need to process to get a list +@@ -823,7 +823,7 @@ def __viable_source_types_real (target_type): + def viable_source_types (target_type): + """ Helper rule, caches the result of '__viable_source_types_real'. + """ +- assert isinstance(target_type, basestring) ++ assert isinstance(target_type, str) + if target_type not in __viable_source_types_cache: + __vst_cached_types.append(target_type) + __viable_source_types_cache [target_type] = __viable_source_types_real (target_type) +@@ -872,9 +872,9 @@ def try_one_generator_really (project, name, generator, target_type, properties, + if __debug__: + from .targets import ProjectTarget + assert isinstance(project, ProjectTarget) +- assert isinstance(name, basestring) or name is None ++ assert isinstance(name, str) or name is None + assert isinstance(generator, Generator) +- assert isinstance(target_type, basestring) ++ assert isinstance(target_type, str) + assert isinstance(properties, property_set.PropertySet) + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + targets = generator.run (project, name, properties, sources) +@@ -914,9 +914,9 @@ def try_one_generator (project, name, generator, target_type, properties, source + if __debug__: + from .targets import ProjectTarget + assert isinstance(project, ProjectTarget) +- assert isinstance(name, basestring) or name is None ++ assert isinstance(name, str) or name is None + assert isinstance(generator, Generator) +- assert isinstance(target_type, basestring) ++ assert isinstance(target_type, str) + assert isinstance(properties, property_set.PropertySet) + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + source_types = [] +@@ -945,8 +945,8 @@ def construct_types (project, name, target_types, prop_set, sources): + if __debug__: + from .targets import ProjectTarget + assert isinstance(project, ProjectTarget) +- assert isinstance(name, basestring) or name is None +- assert is_iterable_typed(target_types, basestring) ++ assert isinstance(name, str) or name is None ++ assert is_iterable_typed(target_types, str) + assert isinstance(prop_set, property_set.PropertySet) + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + +@@ -996,7 +996,7 @@ def find_viable_generators_aux (target_type, prop_set): + Note: this algorithm explicitly ignores generators for base classes if there's + at least one generator for requested target_type. + """ +- assert isinstance(target_type, basestring) ++ assert isinstance(target_type, str) + assert isinstance(prop_set, property_set.PropertySet) + # Select generators that can create the required target type. + viable_generators = [] +@@ -1045,7 +1045,7 @@ def find_viable_generators_aux (target_type, prop_set): + return viable_generators + + def find_viable_generators (target_type, prop_set): +- assert isinstance(target_type, basestring) ++ assert isinstance(target_type, str) + assert isinstance(prop_set, property_set.PropertySet) + key = target_type + '.' + str (prop_set) + +@@ -1095,8 +1095,8 @@ def __construct_really (project, name, target_type, prop_set, sources): + if __debug__: + from .targets import ProjectTarget + assert isinstance(project, ProjectTarget) +- assert isinstance(name, basestring) or name is None +- assert isinstance(target_type, basestring) ++ assert isinstance(name, str) or name is None ++ assert isinstance(target_type, str) + assert isinstance(prop_set, property_set.PropertySet) + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + viable_generators = find_viable_generators (target_type, prop_set) +@@ -1115,20 +1115,20 @@ def __construct_really (project, name, target_type, prop_set, sources): + if r: + generators_that_succeeded.append(g) + if result: +- output = cStringIO.StringIO() +- print >>output, "ambiguity found when searching for best transformation" +- print >>output, "Trying to produce type '%s' from: " % (target_type) ++ output = io.StringIO() ++ print("ambiguity found when searching for best transformation", file=output) ++ print("Trying to produce type '%s' from: " % (target_type), file=output) + for s in sources: +- print >>output, " - " + s.str() +- print >>output, "Generators that succeeded:" ++ print(" - " + s.str(), file=output) ++ print("Generators that succeeded:", file=output) + for g in generators_that_succeeded: +- print >>output, " - " + g.id() +- print >>output, "First generator produced: " ++ print(" - " + g.id(), file=output) ++ print("First generator produced: ", file=output) + for t in result[1:]: +- print >>output, " - " + str(t) +- print >>output, "Second generator produced:" ++ print(" - " + str(t), file=output) ++ print("Second generator produced:", file=output) + for t in r[1:]: +- print >>output, " - " + str(t) ++ print(" - " + str(t), file=output) + get_manager().errors()(output.getvalue()) + else: + result = r; +@@ -1156,8 +1156,8 @@ def construct (project, name, target_type, prop_set, sources, top_level=False): + if __debug__: + from .targets import ProjectTarget + assert isinstance(project, ProjectTarget) +- assert isinstance(name, basestring) or name is None +- assert isinstance(target_type, basestring) ++ assert isinstance(name, str) or name is None ++ assert isinstance(target_type, str) + assert isinstance(prop_set, property_set.PropertySet) + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + assert isinstance(top_level, bool) +diff --git a/tools/build/src/build/project.py b/tools/build/src/build/project.py +index 9ec2ccb..810581a 100644 +--- a/tools/build/src/build/project.py ++++ b/tools/build/src/build/project.py +@@ -60,6 +60,7 @@ import b2.util.option as option + from b2.util import ( + record_jam_to_value_mapping, qualify_jam_action, is_iterable_typed, bjam_signature, + is_iterable) ++import collections + + + class ProjectRegistry: +@@ -134,7 +135,7 @@ class ProjectRegistry: + file and jamfile needed by the loaded one will be loaded recursively. + If the jamfile at that location is loaded already, does nothing. + Returns the project module for the Jamfile.""" +- assert isinstance(jamfile_location, basestring) ++ assert isinstance(jamfile_location, str) + + absolute = os.path.join(os.getcwd(), jamfile_location) + absolute = os.path.normpath(absolute) +@@ -145,7 +146,7 @@ class ProjectRegistry: + if not mname in self.jamfile_modules: + + if "--debug-loading" in self.manager.argv(): +- print "Loading Jamfile at '%s'" % jamfile_location ++ print("Loading Jamfile at '%s'" % jamfile_location) + + self.load_jamfile(jamfile_location, mname) + +@@ -164,7 +165,7 @@ class ProjectRegistry: + return mname + + def load_used_projects(self, module_name): +- assert isinstance(module_name, basestring) ++ assert isinstance(module_name, str) + # local used = [ modules.peek $(module-name) : .used-projects ] ; + used = self.used_projects[module_name] + +@@ -178,13 +179,13 @@ class ProjectRegistry: + def load_parent(self, location): + """Loads parent of Jamfile at 'location'. + Issues an error if nothing is found.""" +- assert isinstance(location, basestring) ++ assert isinstance(location, str) + found = b2.util.path.glob_in_parents( + location, self.JAMROOT + self.JAMFILE) + + if not found: +- print "error: Could not find parent for project at '%s'" % location +- print "error: Did not find Jamfile.jam or Jamroot.jam in any parent directory." ++ print("error: Could not find parent for project at '%s'" % location) ++ print("error: Did not find Jamfile.jam or Jamroot.jam in any parent directory.") + sys.exit(1) + + return self.load(os.path.dirname(found[0])) +@@ -193,8 +194,8 @@ class ProjectRegistry: + """Given 'name' which can be project-id or plain directory name, + return project module corresponding to that id or directory. + Returns nothing of project is not found.""" +- assert isinstance(name, basestring) +- assert isinstance(current_location, basestring) ++ assert isinstance(name, str) ++ assert isinstance(current_location, str) + + project_module = None + +@@ -222,7 +223,7 @@ class ProjectRegistry: + """Returns the name of module corresponding to 'jamfile-location'. + If no module corresponds to location yet, associates default + module name with that location.""" +- assert isinstance(jamfile_location, basestring) ++ assert isinstance(jamfile_location, str) + module = self.location2module.get(jamfile_location) + if not module: + # Root the path, so that locations are always umbiguious. +@@ -239,7 +240,7 @@ class ProjectRegistry: + exact names of all the Jamfiles in the given directory. The optional + parent-root argument causes this to search not the given directory + but the ones above it up to the directory given in it.""" +- assert isinstance(dir, basestring) ++ assert isinstance(dir, str) + assert isinstance(parent_root, (int, bool)) + assert isinstance(no_errors, (int, bool)) + +@@ -271,10 +272,10 @@ class ProjectRegistry: + if len(v2_jamfiles) == 1: + jamfile_glob = v2_jamfiles + else: +- print """warning: Found multiple Jamfiles at '%s'!""" % (dir) ++ print("""warning: Found multiple Jamfiles at '%s'!""" % (dir)) + for j in jamfile_glob: +- print " -", j +- print "Loading the first one" ++ print(" -", j) ++ print("Loading the first one") + + # Could not find it, error. + if not no_errors and not jamfile_glob: +@@ -292,8 +293,8 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" + """Load a Jamfile at the given directory. Returns nothing. + Will attempt to load the file as indicated by the JAMFILE patterns. + Effect of calling this rule twice with the same 'dir' is underfined.""" +- assert isinstance(dir, basestring) +- assert isinstance(jamfile_module, basestring) ++ assert isinstance(dir, str) ++ assert isinstance(jamfile_module, str) + + # See if the Jamfile is where it should be. + is_jamroot = False +@@ -364,10 +365,10 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" + if not id: + # FIXME: go via errors module, so that contexts are + # shown? +- print "warning: the --build-dir option was specified" +- print "warning: but Jamroot at '%s'" % dir +- print "warning: specified no project id" +- print "warning: the --build-dir option will be ignored" ++ print("warning: the --build-dir option was specified") ++ print("warning: but Jamroot at '%s'" % dir) ++ print("warning: specified no project id") ++ print("warning: the --build-dir option will be ignored") + + def end_load(self, previous_project=None): + if not self.current_project: +@@ -394,15 +395,15 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" + The caller is required to never call this method twice on + the same file. + """ +- assert isinstance(jamfile_module, basestring) +- assert isinstance(file, basestring) ++ assert isinstance(jamfile_module, str) ++ assert isinstance(file, str) + + self.used_projects[jamfile_module] = [] + bjam.call("load", jamfile_module, file) + self.load_used_projects(jamfile_module) + + def is_jamroot(self, basename): +- assert isinstance(basename, basestring) ++ assert isinstance(basename, str) + match = [ pat for pat in self.JAMROOT if re.match(pat, basename)] + if match: + return 1 +@@ -418,9 +419,9 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" + standalone_path is the path to the source-location. + this should only be called from the python side. + """ +- assert isinstance(module_name, basestring) +- assert isinstance(location, basestring) or location is None +- assert isinstance(basename, basestring) or basename is None ++ assert isinstance(module_name, str) ++ assert isinstance(location, str) or location is None ++ assert isinstance(basename, str) or basename is None + jamroot = False + parent_module = None + if module_name == "test-config": +@@ -456,7 +457,7 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" + # make sure we don't reinitialize the module's attributes + if module_name not in self.module2attributes: + if "--debug-loading" in self.manager.argv(): +- print "Initializing project '%s'" % module_name ++ print("Initializing project '%s'" % module_name) + attributes = ProjectAttributes(self.manager, location, module_name) + self.module2attributes[module_name] = attributes + +@@ -511,8 +512,8 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" + def inherit_attributes(self, project_module, parent_module): + """Make 'project-module' inherit attributes of project + root and parent module.""" +- assert isinstance(project_module, basestring) +- assert isinstance(parent_module, basestring) ++ assert isinstance(project_module, str) ++ assert isinstance(parent_module, str) + + attributes = self.module2attributes[project_module] + pattributes = self.module2attributes[parent_module] +@@ -550,8 +551,8 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" + + def register_id(self, id, module): + """Associate the given id with the given project module.""" +- assert isinstance(id, basestring) +- assert isinstance(module, basestring) ++ assert isinstance(id, str) ++ assert isinstance(module, str) + self.id2module[id] = module + + def current(self): +@@ -587,14 +588,14 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" + def attributes(self, project): + """Returns the project-attribute instance for the + specified jamfile module.""" +- assert isinstance(project, basestring) ++ assert isinstance(project, str) + return self.module2attributes[project] + + def attribute(self, project, attribute): + """Returns the value of the specified attribute in the + specified jamfile module.""" +- assert isinstance(project, basestring) +- assert isinstance(attribute, basestring) ++ assert isinstance(project, str) ++ assert isinstance(attribute, str) + try: + return self.module2attributes[project].get(attribute) + except: +@@ -603,14 +604,14 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" + def attributeDefault(self, project, attribute, default): + """Returns the value of the specified attribute in the + specified jamfile module.""" +- assert isinstance(project, basestring) +- assert isinstance(attribute, basestring) +- assert isinstance(default, basestring) or default is None ++ assert isinstance(project, str) ++ assert isinstance(attribute, str) ++ assert isinstance(default, str) or default is None + return self.module2attributes[project].getDefault(attribute, default) + + def target(self, project_module): + """Returns the project target corresponding to the 'project-module'.""" +- assert isinstance(project_module, basestring) ++ assert isinstance(project_module, str) + if project_module not in self.module2target: + self.module2target[project_module] = \ + b2.build.targets.ProjectTarget(project_module, project_module, +@@ -620,8 +621,8 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" + + def use(self, id, location): + # Use/load a project. +- assert isinstance(id, basestring) +- assert isinstance(location, basestring) ++ assert isinstance(id, str) ++ assert isinstance(location, str) + saved_project = self.current_project + project_module = self.load(location) + declared_id = self.attributeDefault(project_module, "id", "") +@@ -640,8 +641,8 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" + """Makes rule 'name' available to all subsequently loaded Jamfiles. + + Calling that rule wil relay to 'callable'.""" +- assert isinstance(name, basestring) +- assert callable(callable_) ++ assert isinstance(name, str) ++ assert isinstance(callable_, collections.Callable) + self.project_rules_.add_rule(name, callable_) + + def project_rules(self): +@@ -651,9 +652,9 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" + if __debug__: + from .targets import ProjectTarget + assert isinstance(project, ProjectTarget) +- assert is_iterable_typed(wildcards, basestring) +- assert is_iterable_typed(excludes, basestring) or excludes is None +- assert isinstance(rule_name, basestring) ++ assert is_iterable_typed(wildcards, str) ++ assert is_iterable_typed(excludes, str) or excludes is None ++ assert isinstance(rule_name, str) + location = project.get("source-location")[0] + + result = [] +@@ -736,8 +737,8 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" + since then we might get naming conflicts between standard + Python modules and those. + """ +- assert isinstance(name, basestring) +- assert is_iterable_typed(extra_path, basestring) or extra_path is None ++ assert isinstance(name, str) ++ assert is_iterable_typed(extra_path, str) or extra_path is None + # See if we loaded module of this name already + existing = self.loaded_tool_modules_.get(name) + if existing: +@@ -867,19 +868,19 @@ class ProjectAttributes: + def set(self, attribute, specification, exact=False): + """Set the named attribute from the specification given by the user. + The value actually set may be different.""" +- assert isinstance(attribute, basestring) ++ assert isinstance(attribute, str) + assert isinstance(exact, (int, bool)) + if __debug__ and not exact: + if attribute == 'requirements': + assert (isinstance(specification, property_set.PropertySet) +- or all(isinstance(s, basestring) for s in specification)) ++ or all(isinstance(s, str) for s in specification)) + elif attribute in ( + 'usage-requirements', 'default-build', 'source-location', 'build-dir', 'id'): +- assert is_iterable_typed(specification, basestring) ++ assert is_iterable_typed(specification, str) + elif __debug__: + assert ( +- isinstance(specification, (property_set.PropertySet, type(None), basestring)) +- or all(isinstance(s, basestring) for s in specification) ++ isinstance(specification, (property_set.PropertySet, type(None), str)) ++ or all(isinstance(s, str) for s in specification) + ) + if exact: + self.__dict__[attribute] = specification +@@ -944,11 +945,11 @@ for project at '%s'""" % (attribute, self.location)) + self.__dict__[attribute] = specification + + def get(self, attribute): +- assert isinstance(attribute, basestring) ++ assert isinstance(attribute, str) + return self.__dict__[attribute] + + def getDefault(self, attribute, default): +- assert isinstance(attribute, basestring) ++ assert isinstance(attribute, str) + return self.__dict__.get(attribute, default) + + def dump(self): +@@ -965,12 +966,12 @@ for project at '%s'""" % (attribute, self.location)) + else: + parent = parent[0] + +- print "'%s'" % id +- print "Parent project:%s", parent +- print "Requirements:%s", self.get("requirements") +- print "Default build:%s", string.join(self.get("debuild-build")) +- print "Source location:%s", string.join(self.get("source-location")) +- print "Projects to build:%s", string.join(self.get("projects-to-build").sort()); ++ print("'%s'" % id) ++ print("Parent project:%s", parent) ++ print("Requirements:%s", self.get("requirements")) ++ print("Default build:%s", string.join(self.get("debuild-build"))) ++ print("Source location:%s", string.join(self.get("source-location"))) ++ print("Projects to build:%s", string.join(self.get("projects-to-build").sort())); + + class ProjectRules: + """Class keeping all rules that are made available to Jamfile.""" +@@ -985,9 +986,9 @@ class ProjectRules: + self.all_names_ = [x for x in self.local_names] + + def _import_rule(self, bjam_module, name, callable_): +- assert isinstance(bjam_module, basestring) +- assert isinstance(name, basestring) +- assert callable(callable_) ++ assert isinstance(bjam_module, str) ++ assert isinstance(name, str) ++ assert isinstance(callable_, collections.Callable) + if hasattr(callable_, "bjam_signature"): + bjam.import_rule(bjam_module, name, self.make_wrapper(callable_), callable_.bjam_signature) + else: +@@ -995,7 +996,7 @@ class ProjectRules: + + + def add_rule_for_type(self, type): +- assert isinstance(type, basestring) ++ assert isinstance(type, str) + rule_name = type.lower().replace("_", "-") + + @bjam_signature([['name'], ['sources', '*'], ['requirements', '*'], +@@ -1009,8 +1010,8 @@ class ProjectRules: + self.add_rule(rule_name, xpto) + + def add_rule(self, name, callable_): +- assert isinstance(name, basestring) +- assert callable(callable_) ++ assert isinstance(name, str) ++ assert isinstance(callable_, collections.Callable) + self.rules[name] = callable_ + self.all_names_.append(name) + +@@ -1024,17 +1025,17 @@ class ProjectRules: + return self.all_names_ + + def call_and_report_errors(self, callable_, *args, **kw): +- assert callable(callable_) ++ assert isinstance(callable_, collections.Callable) + result = None + try: + self.manager_.errors().push_jamfile_context() + result = callable_(*args, **kw) +- except ExceptionWithUserContext, e: ++ except ExceptionWithUserContext as e: + e.report() +- except Exception, e: ++ except Exception as e: + try: + self.manager_.errors().handle_stray_exception (e) +- except ExceptionWithUserContext, e: ++ except ExceptionWithUserContext as e: + e.report() + finally: + self.manager_.errors().pop_jamfile_context() +@@ -1045,13 +1046,13 @@ class ProjectRules: + """Given a free-standing function 'callable', return a new + callable that will call 'callable' and report all exceptins, + using 'call_and_report_errors'.""" +- assert callable(callable_) ++ assert isinstance(callable_, collections.Callable) + def wrapper(*args, **kw): + return self.call_and_report_errors(callable_, *args, **kw) + return wrapper + + def init_project(self, project_module, python_standalone=False): +- assert isinstance(project_module, basestring) ++ assert isinstance(project_module, str) + assert isinstance(python_standalone, bool) + if python_standalone: + m = sys.modules[project_module] +@@ -1069,7 +1070,7 @@ class ProjectRules: + # Using 'getattr' here gives us a bound method, + # while using self.__dict__[r] would give unbound one. + v = getattr(self, n) +- if callable(v): ++ if isinstance(v, collections.Callable): + if n == "import_": + n = "import" + else: +@@ -1137,8 +1138,8 @@ attribute is allowed only for top-level 'project' invocations""") + """Declare and set a project global constant. + Project global constants are normal variables but should + not be changed. They are applied to every child Jamfile.""" +- assert is_iterable_typed(name, basestring) +- assert is_iterable_typed(value, basestring) ++ assert is_iterable_typed(name, str) ++ assert is_iterable_typed(value, str) + self.registry.current().add_constant(name[0], value) + + def path_constant(self, name, value): +@@ -1146,8 +1147,8 @@ attribute is allowed only for top-level 'project' invocations""") + path is adjusted to be relative to the invocation directory. The given + value path is taken to be either absolute, or relative to this project + root.""" +- assert is_iterable_typed(name, basestring) +- assert is_iterable_typed(value, basestring) ++ assert is_iterable_typed(name, str) ++ assert is_iterable_typed(value, str) + if len(value) > 1: + self.registry.manager.errors()("path constant should have one element") + self.registry.current().add_constant(name[0], value, path=1) +@@ -1155,35 +1156,35 @@ attribute is allowed only for top-level 'project' invocations""") + def use_project(self, id, where): + # See comment in 'load' for explanation why we record the + # parameters as opposed to loading the project now. +- assert is_iterable_typed(id, basestring) +- assert is_iterable_typed(where, basestring) ++ assert is_iterable_typed(id, str) ++ assert is_iterable_typed(where, str) + m = self.registry.current().project_module() + self.registry.used_projects[m].append((id[0], where[0])) + + def build_project(self, dir): +- assert is_iterable_typed(dir, basestring) ++ assert is_iterable_typed(dir, str) + jamfile_module = self.registry.current().project_module() + attributes = self.registry.attributes(jamfile_module) + now = attributes.get("projects-to-build") + attributes.set("projects-to-build", now + dir, exact=True) + + def explicit(self, target_names): +- assert is_iterable_typed(target_names, basestring) ++ assert is_iterable_typed(target_names, str) + self.registry.current().mark_targets_as_explicit(target_names) + + def always(self, target_names): +- assert is_iterable_typed(target_names, basestring) ++ assert is_iterable_typed(target_names, str) + self.registry.current().mark_targets_as_always(target_names) + + def glob(self, wildcards, excludes=None): +- assert is_iterable_typed(wildcards, basestring) +- assert is_iterable_typed(excludes, basestring)or excludes is None ++ assert is_iterable_typed(wildcards, str) ++ assert is_iterable_typed(excludes, str)or excludes is None + return self.registry.glob_internal(self.registry.current(), + wildcards, excludes, "glob") + + def glob_tree(self, wildcards, excludes=None): +- assert is_iterable_typed(wildcards, basestring) +- assert is_iterable_typed(excludes, basestring) or excludes is None ++ assert is_iterable_typed(wildcards, str) ++ assert is_iterable_typed(excludes, str) or excludes is None + bad = 0 + for p in wildcards: + if os.path.dirname(p): +@@ -1207,7 +1208,7 @@ attribute is allowed only for top-level 'project' invocations""") + # will expect the module to be found even though + # the directory is not in BOOST_BUILD_PATH. + # So temporary change the search path. +- assert is_iterable_typed(toolset, basestring) ++ assert is_iterable_typed(toolset, str) + current = self.registry.current() + location = current.get('location') + +@@ -1222,9 +1223,9 @@ attribute is allowed only for top-level 'project' invocations""") + self.registry.set_current(current) + + def import_(self, name, names_to_import=None, local_names=None): +- assert is_iterable_typed(name, basestring) +- assert is_iterable_typed(names_to_import, basestring) or names_to_import is None +- assert is_iterable_typed(local_names, basestring)or local_names is None ++ assert is_iterable_typed(name, str) ++ assert is_iterable_typed(names_to_import, str) or names_to_import is None ++ assert is_iterable_typed(local_names, str)or local_names is None + name = name[0] + py_name = name + if py_name == "os": +@@ -1240,7 +1241,7 @@ attribute is allowed only for top-level 'project' invocations""") + for f in m.__dict__: + v = m.__dict__[f] + f = f.replace("_", "-") +- if callable(v): ++ if isinstance(v, collections.Callable): + qn = name + "." + f + self._import_rule(jamfile_module, qn, v) + record_jam_to_value_mapping(qualify_jam_action(qn, jamfile_module), v) +@@ -1267,8 +1268,8 @@ attribute is allowed only for top-level 'project' invocations""") + lib x : x.cpp : [ conditional gcc debug : + DEBUG_EXCEPTION DEBUG_TRACE ] ; + """ +- assert is_iterable_typed(condition, basestring) +- assert is_iterable_typed(requirements, basestring) ++ assert is_iterable_typed(condition, str) ++ assert is_iterable_typed(requirements, str) + c = string.join(condition, ",") + if c.find(":") != -1: + return [c + r for r in requirements] +@@ -1276,8 +1277,8 @@ attribute is allowed only for top-level 'project' invocations""") + return [c + ":" + r for r in requirements] + + def option(self, name, value): +- assert is_iterable(name) and isinstance(name[0], basestring) +- assert is_iterable(value) and isinstance(value[0], basestring) ++ assert is_iterable(name) and isinstance(name[0], str) ++ assert is_iterable(value) and isinstance(value[0], str) + name = name[0] + if not name in ["site-config", "user-config", "project-config"]: + get_manager().errors()("The 'option' rule may be used only in site-config or user-config") +diff --git a/tools/build/src/build/property.py b/tools/build/src/build/property.py +index dff8286..fee4b93 100644 +--- a/tools/build/src/build/property.py ++++ b/tools/build/src/build/property.py +@@ -80,10 +80,9 @@ class PropertyMeta(type): + + + @total_ordering +-class Property(object): ++class Property(object, metaclass=PropertyMeta): + + __slots__ = ('feature', 'value', 'condition', '_to_raw', '_hash', 'id') +- __metaclass__ = PropertyMeta + + def __init__(self, f, value, condition=None): + assert(f.free or ':' not in value) +@@ -161,13 +160,13 @@ class LazyProperty(object): + + + def create_from_string(s, allow_condition=False,allow_missing_value=False): +- assert isinstance(s, basestring) ++ assert isinstance(s, str) + assert isinstance(allow_condition, bool) + assert isinstance(allow_missing_value, bool) + condition = [] + import types +- if not isinstance(s, types.StringType): +- print type(s) ++ if not isinstance(s, bytes): ++ print(type(s)) + if __re_has_condition.search(s): + + if not allow_condition: +@@ -215,7 +214,7 @@ def create_from_string(s, allow_condition=False,allow_missing_value=False): + return p + + def create_from_strings(string_list, allow_condition=False): +- assert is_iterable_typed(string_list, basestring) ++ assert is_iterable_typed(string_list, str) + return [create_from_string(s, allow_condition) for s in string_list] + + def reset (): +@@ -341,7 +340,7 @@ def translate_indirect(properties, context_module): + either local to the module or global. Qualified local rules + with the name of the module.""" + assert is_iterable_typed(properties, Property) +- assert isinstance(context_module, basestring) ++ assert isinstance(context_module, str) + result = [] + for p in properties: + if p.value[0] == '@': +@@ -398,7 +397,7 @@ def split_conditional (property): + debug,gcc full. + Otherwise, returns empty string. + """ +- assert isinstance(property, basestring) ++ assert isinstance(property, str) + m = __re_split_conditional.match (property) + + if m: +@@ -410,7 +409,7 @@ def split_conditional (property): + def select (features, properties): + """ Selects properties which correspond to any of the given features. + """ +- assert is_iterable_typed(properties, basestring) ++ assert is_iterable_typed(properties, str) + result = [] + + # add any missing angle brackets +@@ -459,9 +458,9 @@ def change (properties, feature, value = None): + given feature replaced by the given value. + If 'value' is None the feature will be removed. + """ +- assert is_iterable_typed(properties, basestring) +- assert isinstance(feature, basestring) +- assert isinstance(value, (basestring, type(None))) ++ assert is_iterable_typed(properties, str) ++ assert isinstance(feature, str) ++ assert isinstance(value, (str, type(None))) + result = [] + + feature = add_grist (feature) +@@ -520,10 +519,10 @@ def __validate1 (property): + def remove(attributes, properties): + """Returns a property sets which include all the elements + in 'properties' that do not have attributes listed in 'attributes'.""" +- if isinstance(attributes, basestring): ++ if isinstance(attributes, str): + attributes = [attributes] +- assert is_iterable_typed(attributes, basestring) +- assert is_iterable_typed(properties, basestring) ++ assert is_iterable_typed(attributes, str) ++ assert is_iterable_typed(properties, str) + result = [] + for e in properties: + attributes_new = feature.attributes(get_grist(e)) +@@ -542,8 +541,8 @@ def remove(attributes, properties): + def take(attributes, properties): + """Returns a property set which include all + properties in 'properties' that have any of 'attributes'.""" +- assert is_iterable_typed(attributes, basestring) +- assert is_iterable_typed(properties, basestring) ++ assert is_iterable_typed(attributes, str) ++ assert is_iterable_typed(properties, str) + result = [] + for e in properties: + if b2.util.set.intersection(attributes, feature.attributes(get_grist(e))): +@@ -552,8 +551,8 @@ def take(attributes, properties): + + def translate_dependencies(properties, project_id, location): + assert is_iterable_typed(properties, Property) +- assert isinstance(project_id, basestring) +- assert isinstance(location, basestring) ++ assert isinstance(project_id, str) ++ assert isinstance(location, str) + result = [] + for p in properties: + +@@ -590,8 +589,8 @@ class PropertyMap: + def insert (self, properties, value): + """ Associate value with properties. + """ +- assert is_iterable_typed(properties, basestring) +- assert isinstance(value, basestring) ++ assert is_iterable_typed(properties, str) ++ assert isinstance(value, str) + self.__properties.append(properties) + self.__values.append(value) + +@@ -601,12 +600,12 @@ class PropertyMap: + subset has value assigned to it, return the + value for the longest subset, if it's unique. + """ +- assert is_iterable_typed(properties, basestring) ++ assert is_iterable_typed(properties, str) + return self.find_replace (properties) + + def find_replace(self, properties, value=None): +- assert is_iterable_typed(properties, basestring) +- assert isinstance(value, (basestring, type(None))) ++ assert is_iterable_typed(properties, str) ++ assert isinstance(value, (str, type(None))) + matches = [] + match_ranks = [] + +diff --git a/tools/build/src/build/property_set.py b/tools/build/src/build/property_set.py +index 3fc86de..093ecef 100644 +--- a/tools/build/src/build/property_set.py ++++ b/tools/build/src/build/property_set.py +@@ -10,7 +10,7 @@ import hashlib + + import bjam + from b2.util.utility import * +-import property, feature ++from . import property, feature + import b2.build.feature + from b2.exceptions import * + from b2.build.property import get_abbreviated_paths +@@ -38,7 +38,7 @@ def create (raw_properties = []): + or returns an already existing one. + """ + assert (is_iterable_typed(raw_properties, property.Property) +- or is_iterable_typed(raw_properties, basestring)) ++ or is_iterable_typed(raw_properties, str)) + # FIXME: propagate to callers. + if len(raw_properties) > 0 and isinstance(raw_properties[0], property.Property): + x = raw_properties +@@ -65,7 +65,7 @@ def create_with_validation (raw_properties): + that all properties are valid and converting implicit + properties into gristed form. + """ +- assert is_iterable_typed(raw_properties, basestring) ++ assert is_iterable_typed(raw_properties, str) + properties = [property.create_from_string(s) for s in raw_properties] + property.validate(properties) + +@@ -79,9 +79,9 @@ def empty (): + def create_from_user_input(raw_properties, jamfile_module, location): + """Creates a property-set from the input given by the user, in the + context of 'jamfile-module' at 'location'""" +- assert is_iterable_typed(raw_properties, basestring) +- assert isinstance(jamfile_module, basestring) +- assert isinstance(location, basestring) ++ assert is_iterable_typed(raw_properties, str) ++ assert isinstance(jamfile_module, str) ++ assert isinstance(location, str) + properties = property.create_from_strings(raw_properties, True) + properties = property.translate_paths(properties, location) + properties = property.translate_indirect(properties, jamfile_module) +@@ -106,9 +106,9 @@ def refine_from_user_input(parent_requirements, specification, jamfile_module, + will be bound. + - location -- the path to which path features are relative.""" + assert isinstance(parent_requirements, PropertySet) +- assert is_iterable_typed(specification, basestring) +- assert isinstance(jamfile_module, basestring) +- assert isinstance(location, basestring) ++ assert is_iterable_typed(specification, str) ++ assert isinstance(jamfile_module, str) ++ assert isinstance(location, str) + + if not specification: + return parent_requirements +diff --git a/tools/build/src/build/scanner.py b/tools/build/src/build/scanner.py +index ec3b31b..85c0274 100644 +--- a/tools/build/src/build/scanner.py ++++ b/tools/build/src/build/scanner.py +@@ -28,7 +28,7 @@ + # but different instances, and lead in unneeded duplication of + # actual targets. However, actions can also create scanners in a special + # way, instead of relying on just target type. +-import property ++from . import property + import bjam + import os + from b2.manager import get_manager +@@ -57,7 +57,7 @@ def register(scanner_class, relevant_properties): + should have one parameter: list of properties. + """ + assert issubclass(scanner_class, Scanner) +- assert isinstance(relevant_properties, basestring) ++ assert isinstance(relevant_properties, str) + __scanners[str(scanner_class)] = relevant_properties + + def registered(scanner_class): +@@ -70,7 +70,7 @@ def get(scanner_class, properties): + with the specified properties. + """ + assert issubclass(scanner_class, Scanner) +- assert is_iterable_typed(properties, basestring) ++ assert is_iterable_typed(properties, str) + scanner_name = str(scanner_class) + + if not registered(scanner_name): +@@ -135,8 +135,8 @@ class ScannerRegistry: + vtarget: virtual target from which 'target' was actualized. + """ + assert isinstance(scanner, Scanner) +- assert isinstance(target, basestring) +- assert isinstance(vtarget, basestring) ++ assert isinstance(target, str) ++ assert isinstance(vtarget, str) + engine = self.manager_.engine() + engine.set_target_variable(target, "HDRSCAN", scanner.pattern()) + if scanner not in self.exported_scanners_: +@@ -158,7 +158,7 @@ class ScannerRegistry: + + def propagate(self, scanner, targets): + assert isinstance(scanner, Scanner) +- assert is_iterable_typed(targets, basestring) or isinstance(targets, basestring) ++ assert is_iterable_typed(targets, str) or isinstance(targets, str) + engine = self.manager_.engine() + engine.set_target_variable(targets, "HDRSCAN", scanner.pattern()) + engine.set_target_variable(targets, "HDRRULE", +diff --git a/tools/build/src/build/targets.py b/tools/build/src/build/targets.py +index 6f71177..c7fdb46 100644 +--- a/tools/build/src/build/targets.py ++++ b/tools/build/src/build/targets.py +@@ -77,8 +77,8 @@ import sys + from b2.manager import get_manager + + from b2.util.utility import * +-import property, project, virtual_target, property_set, feature, generators, toolset +-from virtual_target import Subvariant ++from . import property, project, virtual_target, property_set, feature, generators, toolset ++from .virtual_target import Subvariant + from b2.exceptions import * + from b2.util.sequence import unique + from b2.util import path, bjam_signature, safe_isinstance, is_iterable_typed +@@ -88,6 +88,7 @@ from b2.build.errors import user_error_checkpoint + import b2.build.build_request as build_request + + import b2.util.set ++import collections + _re_separate_target_from_properties = re.compile (r'^([^<]*)(/(<.*))?$') + + class TargetRegistry: +@@ -118,8 +119,8 @@ class TargetRegistry: + as main target instances, and the name of such targets are adjusted to + be '__'. Such renaming + is disabled is non-empty value is passed for 'no-renaming' parameter.""" +- assert is_iterable_typed(sources, basestring) +- assert isinstance(main_target_name, basestring) ++ assert is_iterable_typed(sources, str) ++ assert isinstance(main_target_name, str) + assert isinstance(no_renaming, (int, bool)) + result = [] + +@@ -154,7 +155,7 @@ class TargetRegistry: + 'specification' are the properties xplicitly specified for a + main target + 'project' is the project where the main taret is to be declared.""" +- assert is_iterable_typed(specification, basestring) ++ assert is_iterable_typed(specification, str) + assert isinstance(project, ProjectTarget) + # create a copy since the list is being modified + specification = list(specification) +@@ -174,7 +175,7 @@ class TargetRegistry: + specification: Use-properties explicitly specified for a main target + project: Project where the main target is to be declared + """ +- assert is_iterable_typed(specification, basestring) ++ assert is_iterable_typed(specification, str) + assert isinstance(project, ProjectTarget) + project_usage_requirements = project.get ('usage-requirements') + +@@ -194,7 +195,7 @@ class TargetRegistry: + specification: Default build explicitly specified for a main target + project: Project where the main target is to be declared + """ +- assert is_iterable_typed(specification, basestring) ++ assert is_iterable_typed(specification, str) + assert isinstance(project, ProjectTarget) + if specification: + return property_set.create_with_validation(specification) +@@ -207,7 +208,7 @@ class TargetRegistry: + assert isinstance(main_target_instance, MainTarget) + if id(main_target_instance) in self.targets_being_built_: + names = [] +- for t in self.targets_being_built_.values() + [main_target_instance]: ++ for t in list(self.targets_being_built_.values()) + [main_target_instance]: + names.append (t.full_name()) + + get_manager().errors()("Recursion in main target references\n") +@@ -225,11 +226,11 @@ class TargetRegistry: + 'usage_requirements' are assumed to be in the form specified + by the user in Jamfile corresponding to 'project'. + """ +- assert isinstance(type, basestring) ++ assert isinstance(type, str) + assert isinstance(project, ProjectTarget) +- assert is_iterable_typed(sources, basestring) +- assert is_iterable_typed(requirements, basestring) +- assert is_iterable_typed(default_build, basestring) ++ assert is_iterable_typed(sources, str) ++ assert is_iterable_typed(requirements, str) ++ assert is_iterable_typed(default_build, str) + return self.main_target_alternative (TypedTarget (name, project, type, + self.main_target_sources (sources, name), + self.main_target_requirements (requirements, project), +@@ -247,7 +248,7 @@ class TargetRegistry: + + def log(self, message): + if self.debug_building_: +- print self.indent_ + message ++ print(self.indent_ + message) + + def push_target(self, target): + assert isinstance(target, AbstractTarget) +@@ -295,7 +296,7 @@ class AbstractTarget: + project: the project target to which this one belongs + manager:the manager object. If none, uses project.manager () + """ +- assert isinstance(name, basestring) ++ assert isinstance(name, str) + assert (isinstance (project, ProjectTarget)) + # Note: it might seem that we don't need either name or project at all. + # However, there are places where we really need it. One example is error +@@ -352,7 +353,7 @@ class AbstractTarget: + raise BaseException ("method should be defined in derived classes") + + def rename (self, new_name): +- assert isinstance(new_name, basestring) ++ assert isinstance(new_name, str) + self.name_ = new_name + + class ProjectTarget (AbstractTarget): +@@ -370,7 +371,7 @@ class ProjectTarget (AbstractTarget): + all alternatives are enumerated an main targets are created. + """ + def __init__ (self, manager, name, project_module, parent_project, requirements, default_build): +- assert isinstance(project_module, basestring) ++ assert isinstance(project_module, str) + assert isinstance(parent_project, (ProjectTarget, type(None))) + assert isinstance(requirements, (type(None), property_set.PropertySet)) + assert isinstance(default_build, (type(None), property_set.PropertySet)) +@@ -418,7 +419,7 @@ class ProjectTarget (AbstractTarget): + return self.project_module_ + + def get (self, attribute): +- assert isinstance(attribute, basestring) ++ assert isinstance(attribute, str) + return self.manager().projects().attribute( + self.project_module_, attribute) + +@@ -457,7 +458,7 @@ class ProjectTarget (AbstractTarget): + self.build_main_targets () + + # Collect all main targets here, except for "explicit" ones. +- for n, t in self.main_target_.iteritems (): ++ for n, t in self.main_target_.items (): + if not t.name () in self.explicit_targets_: + result.append (t) + +@@ -474,11 +475,11 @@ class ProjectTarget (AbstractTarget): + + # Record the name of the target, not instance, since this + # rule is called before main target instaces are created. +- assert is_iterable_typed(target_names, basestring) ++ assert is_iterable_typed(target_names, str) + self.explicit_targets_.update(target_names) + + def mark_targets_as_always(self, target_names): +- assert is_iterable_typed(target_names, basestring) ++ assert is_iterable_typed(target_names, str) + self.always_targets_.update(target_names) + + def add_alternative (self, target_instance): +@@ -491,7 +492,7 @@ class ProjectTarget (AbstractTarget): + self.alternatives_.append (target_instance) + + def main_target (self, name): +- assert isinstance(name, basestring) ++ assert isinstance(name, str) + if not self.built_main_targets_: + self.build_main_targets() + +@@ -499,7 +500,7 @@ class ProjectTarget (AbstractTarget): + + def has_main_target (self, name): + """Tells if a main target with the specified name exists.""" +- assert isinstance(name, basestring) ++ assert isinstance(name, str) + if not self.built_main_targets_: + self.build_main_targets() + +@@ -508,7 +509,7 @@ class ProjectTarget (AbstractTarget): + def create_main_target (self, name): + """ Returns a 'MainTarget' class instance corresponding to the 'name'. + """ +- assert isinstance(name, basestring) ++ assert isinstance(name, str) + if not self.built_main_targets_: + self.build_main_targets () + +@@ -519,7 +520,7 @@ class ProjectTarget (AbstractTarget): + """ Find and return the target with the specified id, treated + relative to self. + """ +- assert isinstance(id, basestring) ++ assert isinstance(id, str) + + result = None + current_location = self.get ('location') +@@ -588,7 +589,7 @@ class ProjectTarget (AbstractTarget): + return result + + def find (self, id, no_error = False): +- assert isinstance(id, basestring) ++ assert isinstance(id, str) + assert isinstance(no_error, int) # also matches bools + v = self.ids_cache_.get (id, None) + +@@ -624,8 +625,8 @@ class ProjectTarget (AbstractTarget): + the constant will be interpreted relatively + to the location of project. + """ +- assert isinstance(name, basestring) +- assert is_iterable_typed(value, basestring) ++ assert isinstance(name, str) ++ assert is_iterable_typed(value, str) + assert isinstance(path, int) # will also match bools + if path: + l = self.location_ +@@ -718,7 +719,7 @@ class MainTarget (AbstractTarget): + return self.alternatives_ [0] + + if debug: +- print "Property set for selection:", property_set_ ++ print("Property set for selection:", property_set_) + + for v in self.alternatives_: + properties = v.match (property_set_, debug) +@@ -797,7 +798,7 @@ class MainTarget (AbstractTarget): + return result + + def rename(self, new_name): +- assert isinstance(new_name, basestring) ++ assert isinstance(new_name, str) + AbstractTarget.rename(self, new_name) + for a in self.alternatives_: + a.rename(new_name) +@@ -844,7 +845,7 @@ def resolve_reference(target_reference, project): + as properties explicitly specified for this reference. + """ + # Separate target name from properties override +- assert isinstance(target_reference, basestring) ++ assert isinstance(target_reference, str) + assert isinstance(project, ProjectTarget) + split = _re_separate_target_from_properties.match (target_reference) + if not split: +@@ -873,7 +874,7 @@ def generate_from_reference(target_reference, project, property_set_): + project: Project where the reference is made + property_set: Properties of the main target that makes the reference + """ +- assert isinstance(target_reference, basestring) ++ assert isinstance(target_reference, str) + assert isinstance(project, ProjectTarget) + assert isinstance(property_set_, property_set.PropertySet) + target, sproperties = resolve_reference(target_reference, project) +@@ -894,7 +895,7 @@ class BasicTarget (AbstractTarget): + targets. + """ + def __init__ (self, name, project, sources, requirements = None, default_build = None, usage_requirements = None): +- assert is_iterable_typed(sources, basestring) ++ assert is_iterable_typed(sources, str) + assert isinstance(requirements, property_set.PropertySet) or requirements is None + assert isinstance(default_build, property_set.PropertySet) or default_build is None + assert isinstance(usage_requirements, property_set.PropertySet) or usage_requirements is None +@@ -1008,7 +1009,7 @@ class BasicTarget (AbstractTarget): + # might come from project's requirements. + assert isinstance(requirements, property_set.PropertySet) + assert isinstance(context, property_set.PropertySet) +- assert isinstance(what, basestring) ++ assert isinstance(what, str) + unconditional = feature.expand(requirements.non_conditional()) + + context = context.refine(property_set.create(unconditional)) +@@ -1044,7 +1045,7 @@ class BasicTarget (AbstractTarget): + for i in indirect: + new = None + i = b2.util.jam_to_value_maybe(i) +- if callable(i): ++ if isinstance(i, collections.Callable): + # This is Python callable, yeah. + new = i(current) + else: +@@ -1118,12 +1119,12 @@ class BasicTarget (AbstractTarget): + condition = b2.util.set.difference (bcondition, ccondition) + + if debug: +- print " next alternative: required properties:", [str(p) for p in condition] ++ print(" next alternative: required properties:", [str(p) for p in condition]) + + if b2.util.set.contains (condition, property_set_.all()): + + if debug: +- print " matched" ++ print(" matched") + + return condition + +@@ -1132,7 +1133,7 @@ class BasicTarget (AbstractTarget): + + + def generate_dependency_targets (self, target_ids, property_set_): +- assert is_iterable_typed(target_ids, basestring) ++ assert is_iterable_typed(target_ids, str) + assert isinstance(property_set_, property_set.PropertySet) + targets = [] + usage_requirements = [] +@@ -1378,10 +1379,10 @@ class BasicTarget (AbstractTarget): + + + class TypedTarget (BasicTarget): +- import generators ++ from . import generators + + def __init__ (self, name, project, type, sources, requirements, default_build, usage_requirements): +- assert isinstance(type, basestring) ++ assert isinstance(type, str) + BasicTarget.__init__ (self, name, project, sources, requirements, default_build, usage_requirements) + self.type_ = type + +@@ -1392,7 +1393,7 @@ class TypedTarget (BasicTarget): + return self.type_ + + def construct (self, name, source_targets, prop_set): +- assert isinstance(name, basestring) ++ assert isinstance(name, str) + assert is_iterable_typed(source_targets, virtual_target.VirtualTarget) + assert isinstance(prop_set, property_set.PropertySet) + r = generators.construct (self.project_, os.path.splitext(name)[0], +@@ -1401,16 +1402,16 @@ class TypedTarget (BasicTarget): + source_targets, True) + + if not r: +- print "warning: Unable to construct '%s'" % self.full_name () ++ print("warning: Unable to construct '%s'" % self.full_name ()) + + # Are there any top-level generators for this type/property set. + if not generators.find_viable_generators (self.type_, prop_set): +- print "error: no generators were found for type '" + self.type_ + "'" +- print "error: and the requested properties" +- print "error: make sure you've configured the needed tools" +- print "See http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html" ++ print("error: no generators were found for type '" + self.type_ + "'") ++ print("error: and the requested properties") ++ print("error: make sure you've configured the needed tools") ++ print("See http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html") + +- print "To debug this problem, try the --debug-generators option." ++ print("To debug this problem, try the --debug-generators option.") + sys.exit(1) + + return r +@@ -1465,11 +1466,11 @@ def apply_default_build(property_set_, default_build): + + + def create_typed_metatarget(name, type, sources, requirements, default_build, usage_requirements): +- assert isinstance(name, basestring) +- assert isinstance(type, basestring) +- assert is_iterable_typed(requirements, basestring) +- assert is_iterable_typed(default_build, basestring) +- assert is_iterable_typed(usage_requirements, basestring) ++ assert isinstance(name, str) ++ assert isinstance(type, str) ++ assert is_iterable_typed(requirements, str) ++ assert is_iterable_typed(default_build, str) ++ assert is_iterable_typed(usage_requirements, str) + + from b2.manager import get_manager + t = get_manager().targets() +@@ -1485,11 +1486,11 @@ def create_typed_metatarget(name, type, sources, requirements, default_build, us + + + def create_metatarget(klass, name, sources, requirements=[], default_build=[], usage_requirements=[]): +- assert isinstance(name, basestring) +- assert is_iterable_typed(sources, basestring) +- assert is_iterable_typed(requirements, basestring) +- assert is_iterable_typed(default_build, basestring) +- assert is_iterable_typed(usage_requirements, basestring) ++ assert isinstance(name, str) ++ assert is_iterable_typed(sources, str) ++ assert is_iterable_typed(requirements, str) ++ assert is_iterable_typed(default_build, str) ++ assert is_iterable_typed(usage_requirements, str) + from b2.manager import get_manager + t = get_manager().targets() + +diff --git a/tools/build/src/build/toolset.py b/tools/build/src/build/toolset.py +index cf2b24b..4929ab9 100644 +--- a/tools/build/src/build/toolset.py ++++ b/tools/build/src/build/toolset.py +@@ -11,7 +11,7 @@ + """ + import sys + +-import feature, property, generators, property_set ++from . import feature, property, generators, property_set + import b2.util.set + import bjam + +@@ -38,11 +38,11 @@ _ignore_toolset_requirements = '--ignore-toolset-requirements' not in sys.argv + class Flag: + + def __init__(self, variable_name, values, condition, rule = None): +- assert isinstance(variable_name, basestring) ++ assert isinstance(variable_name, str) + assert is_iterable(values) and all( +- isinstance(v, (basestring, type(None))) for v in values) ++ isinstance(v, (str, type(None))) for v in values) + assert is_iterable_typed(condition, property_set.PropertySet) +- assert isinstance(rule, (basestring, type(None))) ++ assert isinstance(rule, (str, type(None))) + self.variable_name = variable_name + self.values = values + self.condition = condition +@@ -128,10 +128,10 @@ def flags(rule_or_module, variable_name, condition, values = []): + is specified, then the value of 'feature' + will be added. + """ +- assert isinstance(rule_or_module, basestring) +- assert isinstance(variable_name, basestring) +- assert is_iterable_typed(condition, basestring) +- assert is_iterable(values) and all(isinstance(v, (basestring, type(None))) for v in values) ++ assert isinstance(rule_or_module, str) ++ assert isinstance(variable_name, str) ++ assert is_iterable_typed(condition, str) ++ assert is_iterable(values) and all(isinstance(v, (str, type(None))) for v in values) + caller = bjam.caller() + if not '.' in rule_or_module and caller and caller[:-1].startswith("Jamfile"): + # Unqualified rule name, used inside Jamfile. Most likely used with +@@ -171,8 +171,8 @@ def flags(rule_or_module, variable_name, condition, values = []): + def set_target_variables (manager, rule_or_module, targets, ps): + """ + """ +- assert isinstance(rule_or_module, basestring) +- assert is_iterable_typed(targets, basestring) ++ assert isinstance(rule_or_module, str) ++ assert is_iterable_typed(targets, str) + assert isinstance(ps, property_set.PropertySet) + settings = __set_target_variables_aux(manager, rule_or_module, ps) + +@@ -219,14 +219,14 @@ def find_satisfied_condition(conditions, ps): + def register (toolset): + """ Registers a new toolset. + """ +- assert isinstance(toolset, basestring) ++ assert isinstance(toolset, str) + feature.extend('toolset', [toolset]) + + def inherit_generators (toolset, properties, base, generators_to_ignore = []): +- assert isinstance(toolset, basestring) +- assert is_iterable_typed(properties, basestring) +- assert isinstance(base, basestring) +- assert is_iterable_typed(generators_to_ignore, basestring) ++ assert isinstance(toolset, str) ++ assert is_iterable_typed(properties, str) ++ assert isinstance(base, str) ++ assert is_iterable_typed(generators_to_ignore, str) + if not properties: + properties = [replace_grist (toolset, '')] + +@@ -259,9 +259,9 @@ def inherit_flags(toolset, base, prohibited_properties = []): + or version of a base toolset, it won't ever match the inheriting toolset. When + such flag settings must be inherited, define a rule in base toolset module and + call it as needed.""" +- assert isinstance(toolset, basestring) +- assert isinstance(base, basestring) +- assert is_iterable_typed(prohibited_properties, basestring) ++ assert isinstance(toolset, str) ++ assert isinstance(base, str) ++ assert is_iterable_typed(prohibited_properties, str) + for f in __module_flags.get(base, []): + + if not f.condition or b2.util.set.difference(f.condition, prohibited_properties): +@@ -283,7 +283,7 @@ def inherit_flags(toolset, base, prohibited_properties = []): + def inherit_rules(toolset, base): + engine = get_manager().engine() + new_actions = {} +- for action_name, action in engine.actions.iteritems(): ++ for action_name, action in engine.actions.items(): + module, id = split_action_id(action_name) + if module == base: + new_action_name = toolset + '.' + id +@@ -303,7 +303,7 @@ def __set_target_variables_aux (manager, rule_or_module, ps): + variables names and values, which must be set on targets for that + rule/properties combination. + """ +- assert isinstance(rule_or_module, basestring) ++ assert isinstance(rule_or_module, str) + assert isinstance(ps, property_set.PropertySet) + result = [] + +@@ -329,7 +329,7 @@ def __set_target_variables_aux (manager, rule_or_module, ps): + return result + + def __handle_flag_value (manager, value, ps): +- assert isinstance(value, basestring) ++ assert isinstance(value, str) + assert isinstance(ps, property_set.PropertySet) + result = [] + +@@ -366,11 +366,11 @@ def __add_flag (rule_or_module, variable_name, condition, values): + """ Adds a new flag setting with the specified values. + Does no checking. + """ +- assert isinstance(rule_or_module, basestring) +- assert isinstance(variable_name, basestring) ++ assert isinstance(rule_or_module, str) ++ assert isinstance(variable_name, str) + assert is_iterable_typed(condition, property_set.PropertySet) + assert is_iterable(values) and all( +- isinstance(v, (basestring, type(None))) for v in values) ++ isinstance(v, (str, type(None))) for v in values) + f = Flag(variable_name, values, condition, rule_or_module) + + # Grab the name of the module +@@ -393,7 +393,7 @@ def add_requirements(requirements): + will be automatically added to the requirements for all main targets, as if + they were specified literally. For best results, all requirements added should + be conditional or indirect conditional.""" +- assert is_iterable_typed(requirements, basestring) ++ assert is_iterable_typed(requirements, str) + + if _ignore_toolset_requirements: + __requirements.extend(requirements) +@@ -408,8 +408,8 @@ def add_requirements(requirements): + # 3. All flags are inherited + # 4. All rules are imported. + def inherit(toolset, base): +- assert isinstance(toolset, basestring) +- assert isinstance(base, basestring) ++ assert isinstance(toolset, str) ++ assert isinstance(base, str) + get_manager().projects().load_module(base, ['.']); + + inherit_generators(toolset, [], base) +diff --git a/tools/build/src/build/type.py b/tools/build/src/build/type.py +index 3d9b7c1..f8ca799 100644 +--- a/tools/build/src/build/type.py ++++ b/tools/build/src/build/type.py +@@ -116,7 +116,7 @@ def register (type, suffixes = [], base_type = None): + + # FIXME: quick hack. + def type_from_rule_name(rule_name): +- assert isinstance(rule_name, basestring) ++ assert isinstance(rule_name, str) + return rule_name.upper().replace("-", "_") + + +@@ -124,8 +124,8 @@ def register_suffixes (suffixes, type): + """ Specifies that targets with suffix from 'suffixes' have the type 'type'. + If a different type is already specified for any of syffixes, issues an error. + """ +- assert is_iterable_typed(suffixes, basestring) +- assert isinstance(type, basestring) ++ assert is_iterable_typed(suffixes, str) ++ assert isinstance(type, str) + for s in suffixes: + if s in __suffixes_to_types: + old_type = __suffixes_to_types [s] +@@ -137,13 +137,13 @@ def register_suffixes (suffixes, type): + def registered (type): + """ Returns true iff type has been registered. + """ +- assert isinstance(type, basestring) ++ assert isinstance(type, str) + return type in __types + + def validate (type): + """ Issues an error if 'type' is unknown. + """ +- assert isinstance(type, basestring) ++ assert isinstance(type, str) + if not registered (type): + raise BaseException ("Unknown target type '%s'" % type) + +@@ -152,7 +152,7 @@ def set_scanner (type, scanner): + """ + if __debug__: + from .scanner import Scanner +- assert isinstance(type, basestring) ++ assert isinstance(type, str) + assert issubclass(scanner, Scanner) + validate (type) + __types [type]['scanner'] = scanner +@@ -162,7 +162,7 @@ def get_scanner (type, prop_set): + """ + if __debug__: + from .property_set import PropertySet +- assert isinstance(type, basestring) ++ assert isinstance(type, str) + assert isinstance(prop_set, PropertySet) + if registered (type): + scanner_type = __types [type]['scanner'] +@@ -175,13 +175,13 @@ def get_scanner (type, prop_set): + def base(type): + """Returns a base type for the given type or nothing in case the given type is + not derived.""" +- assert isinstance(type, basestring) ++ assert isinstance(type, str) + return __types[type]['base'] + + def all_bases (type): + """ Returns type and all of its bases, in the order of their distance from type. + """ +- assert isinstance(type, basestring) ++ assert isinstance(type, str) + result = [] + while type: + result.append (type) +@@ -192,7 +192,7 @@ def all_bases (type): + def all_derived (type): + """ Returns type and all classes that derive from it, in the order of their distance from type. + """ +- assert isinstance(type, basestring) ++ assert isinstance(type, str) + result = [type] + for d in __types [type]['derived']: + result.extend (all_derived (d)) +@@ -202,8 +202,8 @@ def all_derived (type): + def is_derived (type, base): + """ Returns true if 'type' is 'base' or has 'base' as its direct or indirect base. + """ +- assert isinstance(type, basestring) +- assert isinstance(base, basestring) ++ assert isinstance(type, str) ++ assert isinstance(base, str) + # TODO: this isn't very efficient, especially for bases close to type + if base in all_bases (type): + return True +@@ -213,8 +213,8 @@ def is_derived (type, base): + def is_subtype (type, base): + """ Same as is_derived. Should be removed. + """ +- assert isinstance(type, basestring) +- assert isinstance(base, basestring) ++ assert isinstance(type, str) ++ assert isinstance(base, str) + # TODO: remove this method + return is_derived (type, base) + +@@ -232,9 +232,9 @@ def set_generated_target_suffix (type, properties, suffix): + The 'suffix' parameter can be empty string ("") to indicate that + no suffix should be used. + """ +- assert isinstance(type, basestring) +- assert is_iterable_typed(properties, basestring) +- assert isinstance(suffix, basestring) ++ assert isinstance(type, str) ++ assert is_iterable_typed(properties, str) ++ assert isinstance(suffix, str) + set_generated_target_ps(1, type, properties, suffix) + + +@@ -243,15 +243,15 @@ def change_generated_target_suffix (type, properties, suffix): + """ Change the suffix previously registered for this type/properties + combination. If suffix is not yet specified, sets it. + """ +- assert isinstance(type, basestring) +- assert is_iterable_typed(properties, basestring) +- assert isinstance(suffix, basestring) ++ assert isinstance(type, str) ++ assert is_iterable_typed(properties, str) ++ assert isinstance(suffix, str) + change_generated_target_ps(1, type, properties, suffix) + + def generated_target_suffix(type, properties): + if __debug__: + from .property_set import PropertySet +- assert isinstance(type, basestring) ++ assert isinstance(type, str) + assert isinstance(properties, PropertySet) + return generated_target_ps(1, type, properties) + +@@ -277,31 +277,31 @@ def set_generated_target_prefix(type, properties, prefix): + # Change the prefix previously registered for this type/properties combination. + # If prefix is not yet specified, sets it. + def change_generated_target_prefix(type, properties, prefix): +- assert isinstance(type, basestring) +- assert is_iterable_typed(properties, basestring) +- assert isinstance(prefix, basestring) ++ assert isinstance(type, str) ++ assert is_iterable_typed(properties, str) ++ assert isinstance(prefix, str) + change_generated_target_ps(0, type, properties, prefix) + + def generated_target_prefix(type, properties): + if __debug__: + from .property_set import PropertySet +- assert isinstance(type, basestring) ++ assert isinstance(type, str) + assert isinstance(properties, PropertySet) + return generated_target_ps(0, type, properties) + + def set_generated_target_ps(is_suffix, type, properties, val): + assert isinstance(is_suffix, (int, bool)) +- assert isinstance(type, basestring) +- assert is_iterable_typed(properties, basestring) +- assert isinstance(val, basestring) ++ assert isinstance(type, str) ++ assert is_iterable_typed(properties, str) ++ assert isinstance(val, str) + properties.append ('' + type) + __prefixes_suffixes[is_suffix].insert (properties, val) + + def change_generated_target_ps(is_suffix, type, properties, val): + assert isinstance(is_suffix, (int, bool)) +- assert isinstance(type, basestring) +- assert is_iterable_typed(properties, basestring) +- assert isinstance(val, basestring) ++ assert isinstance(type, str) ++ assert is_iterable_typed(properties, str) ++ assert isinstance(val, str) + properties.append ('' + type) + prev = __prefixes_suffixes[is_suffix].find_replace(properties, val) + if not prev: +@@ -313,8 +313,8 @@ def change_generated_target_ps(is_suffix, type, properties, val): + # base type, if any. + def generated_target_ps_real(is_suffix, type, properties): + assert isinstance(is_suffix, (int, bool)) +- assert isinstance(type, basestring) +- assert is_iterable_typed(properties, basestring) ++ assert isinstance(type, str) ++ assert is_iterable_typed(properties, str) + result = '' + found = False + while type and not found: +@@ -339,7 +339,7 @@ def generated_target_ps(is_suffix, type, prop_set): + if __debug__: + from .property_set import PropertySet + assert isinstance(is_suffix, (int, bool)) +- assert isinstance(type, basestring) ++ assert isinstance(type, str) + assert isinstance(prop_set, PropertySet) + key = (is_suffix, type, prop_set) + v = __target_suffixes_cache.get(key, None) +@@ -355,7 +355,7 @@ def type(filename): + tries each suffix. E.g. for name of "file.so.1.2" suffixes "2", "1", and + "so" will be tried. + """ +- assert isinstance(filename, basestring) ++ assert isinstance(filename, str) + while 1: + filename, suffix = os.path.splitext (filename) + if not suffix: return None +@@ -370,10 +370,10 @@ def register_type (type, suffixes, base_type = None, os = []): + if os is not specified. This rule is injected into each of the type + modules for the sake of convenience. + """ +- assert isinstance(type, basestring) +- assert is_iterable_typed(suffixes, basestring) +- assert isinstance(base_type, basestring) or base_type is None +- assert is_iterable_typed(os, basestring) ++ assert isinstance(type, str) ++ assert is_iterable_typed(suffixes, str) ++ assert isinstance(base_type, str) or base_type is None ++ assert is_iterable_typed(os, str) + if registered (type): + return + +diff --git a/tools/build/src/build/version.py b/tools/build/src/build/version.py +index 8829906..3ba7dbb 100644 +--- a/tools/build/src/build/version.py ++++ b/tools/build/src/build/version.py +@@ -24,15 +24,15 @@ def verify_engine_version(): + from textwrap import dedent + engine = sys.argv[0] + core = os.path.dirname(os.path.dirname(__file__)) +- print dedent("""\ ++ print(dedent("""\ + warning: mismatched version of Boost.Build engine core + warning: Boost.Build engine "{}" is "{}" + warning: Boost.Build core at {} is {} +- """.format(engine, '.'.join(v), core, boost_build())) ++ """.format(engine, '.'.join(v), core, boost_build()))) + return False + return True + + + def report(): + if verify_engine_version(): +- print "Boost.Build " + boost_build() ++ print("Boost.Build " + boost_build()) +diff --git a/tools/build/src/build/virtual_target.py b/tools/build/src/build/virtual_target.py +index e5a1304..f0f0819 100644 +--- a/tools/build/src/build/virtual_target.py ++++ b/tools/build/src/build/virtual_target.py +@@ -79,6 +79,7 @@ import b2.build.property as property + + from b2.manager import get_manager + from b2.util import bjam_signature ++import collections + + __re_starts_with_at = re.compile ('^@(.*)') + +@@ -159,8 +160,8 @@ class VirtualTargetRegistry: + """ + if __debug__: + from .targets import ProjectTarget +- assert isinstance(file, basestring) +- assert isinstance(file_location, basestring) ++ assert isinstance(file, str) ++ assert isinstance(file_location, str) + assert isinstance(project, ProjectTarget) + # Check if we've created a target corresponding to this file. + path = os.path.join(os.getcwd(), file_location, file) +@@ -198,7 +199,7 @@ class VirtualTargetRegistry: + return [t for t in targets if b2.build.type.is_sybtype(t.type(), type)] + + def register_actual_name (self, actual_name, virtual_target): +- assert isinstance(actual_name, basestring) ++ assert isinstance(actual_name, str) + assert isinstance(virtual_target, VirtualTarget) + if actual_name in self.actual_: + cs1 = self.actual_ [actual_name].creating_subvariant () +@@ -249,8 +250,8 @@ class VirtualTargetRegistry: + """ Appends the suffix appropriate to 'type/property_set' combination + to the specified name and returns the result. + """ +- assert isinstance(specified_name, basestring) +- assert isinstance(file_type, basestring) ++ assert isinstance(specified_name, str) ++ assert isinstance(file_type, str) + assert isinstance(prop_set, property_set.PropertySet) + suffix = b2.build.type.generated_target_suffix (file_type, prop_set) + +@@ -270,7 +271,7 @@ class VirtualTarget: + def __init__ (self, name, project): + if __debug__: + from .targets import ProjectTarget +- assert isinstance(name, basestring) ++ assert isinstance(name, str) + assert isinstance(project, ProjectTarget) + self.name_ = name + self.project_ = project +@@ -394,7 +395,7 @@ class AbstractFileTarget (VirtualTarget): + type: optional type of this target. + """ + def __init__ (self, name, type, project, action = None, exact=False): +- assert isinstance(type, basestring) or type is None ++ assert isinstance(type, str) or type is None + assert action is None or isinstance(action, Action) + assert isinstance(exact, (int, bool)) + VirtualTarget.__init__ (self, name, project) +@@ -426,7 +427,7 @@ class AbstractFileTarget (VirtualTarget): + """ Sets the path. When generating target name, it will override any path + computation from properties. + """ +- assert isinstance(path, basestring) ++ assert isinstance(path, str) + self.path_ = os.path.normpath(path) + + def action (self): +@@ -462,7 +463,7 @@ class AbstractFileTarget (VirtualTarget): + return self.creating_subvariant_ + + def actualize_action (self, target): +- assert isinstance(target, basestring) ++ assert isinstance(target, str) + if self.action_: + self.action_.actualize () + +@@ -541,7 +542,7 @@ class AbstractFileTarget (VirtualTarget): + If not property is specified, or the rule specified by + returns nothing, returns the result of calling + virtual-target.add-suffix""" +- assert isinstance(specified_name, basestring) ++ assert isinstance(specified_name, str) + if self.action_: + ps = self.action_.properties() + else: +@@ -567,7 +568,7 @@ class AbstractFileTarget (VirtualTarget): + """@rulename is present but is not the only feature""") + + tag = tag[0] +- if callable(tag): ++ if isinstance(tag, collections.Callable): + self.name_ = tag(specified_name, self.type_, ps) + else: + if not tag[0] == '@': +@@ -655,7 +656,7 @@ class FileTarget (AbstractFileTarget): + - the suffix which correspond to the target's type. + """ + def __init__ (self, name, type, project, action = None, path=None, exact=False): +- assert isinstance(type, basestring) or type is None ++ assert isinstance(type, str) or type is None + assert action is None or isinstance(action, Action) + assert isinstance(exact, (int, bool)) + AbstractFileTarget.__init__ (self, name, type, project, action, exact) +@@ -669,12 +670,12 @@ class FileTarget (AbstractFileTarget): + return self.name_ + + def clone_with_different_type(self, new_type): +- assert isinstance(new_type, basestring) ++ assert isinstance(new_type, str) + return FileTarget(self.name_, new_type, self.project_, + self.action_, self.path_, exact=True) + + def actualize_location (self, target): +- assert isinstance(target, basestring) ++ assert isinstance(target, str) + engine = self.project_.manager_.engine () + + if self.action_: +@@ -755,7 +756,7 @@ class NotFileTarget(AbstractFileTarget): + return None + + def actualize_location(self, target): +- assert isinstance(target, basestring) ++ assert isinstance(target, str) + bjam.call("NOTFILE", target) + bjam.call("ALWAYS", target) + bjam.call("NOUPDATE", target) +@@ -771,7 +772,7 @@ class Action: + """ + def __init__ (self, manager, sources, action_name, prop_set): + assert is_iterable_typed(sources, VirtualTarget) +- assert isinstance(action_name, basestring) or action_name is None ++ assert isinstance(action_name, str) or action_name is None + assert(isinstance(prop_set, property_set.PropertySet)) + self.sources_ = sources + self.action_name_ = action_name +@@ -840,7 +841,7 @@ class Action: + # Action name can include additional rule arguments, which should not + # be passed to 'set-target-variables'. + # FIXME: breaking circular dependency +- import toolset ++ from . import toolset + toolset.set_target_variables (self.manager_, self.action_name_, actual_targets, properties) + + engine = self.manager_.engine () +@@ -1004,7 +1005,7 @@ def clone_action (action, new_project, new_action_name, new_properties): + from .targets import ProjectTarget + assert isinstance(action, Action) + assert isinstance(new_project, ProjectTarget) +- assert isinstance(new_action_name, basestring) ++ assert isinstance(new_action_name, str) + assert isinstance(new_properties, property_set.PropertySet) + if not new_action_name: + new_action_name = action.action_name() +@@ -1136,8 +1137,8 @@ class Subvariant: + if 'target_type' is not specified), the result will contain + <$(feature)>path-to-that-target. + """ +- assert isinstance(feature, basestring) +- assert isinstance(target_type, basestring) ++ assert isinstance(feature, str) ++ assert isinstance(target_type, str) + if not target_type: + key = feature + else: +@@ -1154,7 +1155,7 @@ class Subvariant: + return result + + def all_target_directories(self, target_type = None): +- assert isinstance(target_type, (basestring, type(None))) ++ assert isinstance(target_type, (str, type(None))) + # TODO: does not appear to use target_type in deciding + # if we've computed this already. + if not self.target_directories_: +@@ -1162,7 +1163,7 @@ class Subvariant: + return self.target_directories_ + + def compute_target_directories(self, target_type=None): +- assert isinstance(target_type, (basestring, type(None))) ++ assert isinstance(target_type, (str, type(None))) + result = [] + for t in self.created_targets(): + if not target_type or b2.build.type.is_derived(t.type(), target_type): +diff --git a/tools/build/src/build_system.py b/tools/build/src/build_system.py +index 6e78ced..5fe4ebe 100644 +--- a/tools/build/src/build_system.py ++++ b/tools/build/src/build_system.py +@@ -176,8 +176,8 @@ def initialize_config_module(module_name, location=None): + def load_config(module_name, filename, paths, must_find=False): + + if debug_config: +- print "notice: Searching '%s' for '%s' configuration file '%s." \ +- % (paths, module_name, filename) ++ print("notice: Searching '%s' for '%s' configuration file '%s." \ ++ % (paths, module_name, filename)) + + where = None + for path in paths: +@@ -190,8 +190,8 @@ def load_config(module_name, filename, paths, must_find=False): + where = os.path.realpath(where) + + if debug_config: +- print "notice: Loading '%s' configuration file '%s' from '%s'." \ +- % (module_name, filename, where) ++ print("notice: Loading '%s' configuration file '%s' from '%s'." \ ++ % (module_name, filename, where)) + + # Set source location so that path-constant in config files + # with relative paths work. This is of most importance +@@ -207,7 +207,7 @@ def load_config(module_name, filename, paths, must_find=False): + get_manager().errors()(msg) + + elif debug_config: +- print msg ++ print(msg) + + return where + +@@ -256,8 +256,8 @@ def load_configuration_files(): + where = load_config("test-config", os.path.basename(test_config), [os.path.dirname(test_config)]) + if where: + if debug_config: +- print "notice: Regular site and user configuration files will" +- print "notice: be ignored due to the test configuration being loaded." ++ print("notice: Regular site and user configuration files will") ++ print("notice: be ignored due to the test configuration being loaded.") + + user_path = [os.path.expanduser("~")] + bjam.variable("BOOST_BUILD_PATH") + site_path = ["/etc"] + user_path +@@ -265,8 +265,8 @@ def load_configuration_files(): + site_path = [os.getenv("SystemRoot")] + user_path + + if debug_config and not test_config and ignore_site_config: +- print "notice: Site configuration files will be ignored due to the" +- print "notice: --ignore-site-config command-line option." ++ print("notice: Site configuration files will be ignored due to the") ++ print("notice: --ignore-site-config command-line option.") + + initialize_config_module("site-config") + if not test_config and not ignore_site_config: +@@ -302,15 +302,15 @@ def load_configuration_files(): + user_config = os.path.abspath(user_config) + + if debug_config: +- print "notice: Loading explicitly specified user configuration file:" +- print " " + user_config ++ print("notice: Loading explicitly specified user configuration file:") ++ print(" " + user_config) + + load_config('user-config', os.path.basename(user_config), [os.path.dirname(user_config)], True) + else: + load_config('user-config', os.path.basename(user_config), user_path) + else: + if debug_config: +- print "notice: User configuration file loading explicitly disabled." ++ print("notice: User configuration file loading explicitly disabled.") + + # We look for project-config.jam from "." upward. I am not sure this is + # 100% right decision, we might as well check for it only alongside the +@@ -349,8 +349,8 @@ def process_explicit_toolset_requests(): + (toolset_version, toolset, version) = re.match("(([^-/]+)-?([^/]+)?)/?.*", t).groups() + + if debug_config: +- print "notice: [cmdline-cfg] Detected command-line request for '%s': toolset= %s version=%s" \ +- % (toolset_version, toolset, version) ++ print("notice: [cmdline-cfg] Detected command-line request for '%s': toolset= %s version=%s" \ ++ % (toolset_version, toolset, version)) + + # If the toolset is not known, configure it now. + known = False +@@ -371,7 +371,7 @@ def process_explicit_toolset_requests(): + if not known: + + if debug_config: +- print "notice: [cmdline-cfg] toolset '%s' not previously configured; attempting to auto-configure now" % toolset_version ++ print("notice: [cmdline-cfg] toolset '%s' not previously configured; attempting to auto-configure now" % toolset_version) + if version is not None: + using(toolset, version) + else: +@@ -381,7 +381,7 @@ def process_explicit_toolset_requests(): + + if debug_config: + +- print "notice: [cmdline-cfg] toolset '%s' already configured" % toolset_version ++ print("notice: [cmdline-cfg] toolset '%s' already configured" % toolset_version) + + # Make sure we get an appropriate property into the build request in + # case toolset has been specified using the "--toolset=..." command-line +@@ -389,7 +389,7 @@ def process_explicit_toolset_requests(): + if not t in sys.argv and not t in feature_toolsets: + + if debug_config: +- print "notice: [cmdline-cfg] adding toolset=%s) to the build request." % t ; ++ print("notice: [cmdline-cfg] adding toolset=%s) to the build request." % t) ; + extra_properties += "toolset=%s" % t + + return extra_properties +@@ -437,7 +437,7 @@ def main(): + else: + try: + return main_real() +- except ExceptionWithUserContext, e: ++ except ExceptionWithUserContext as e: + e.report() + + def main_real(): +@@ -496,12 +496,12 @@ def main_real(): + # default-toolset = darwin ; + #} + +- print "warning: No toolsets are configured." +- print "warning: Configuring default toolset '%s'." % dt +- print "warning: If the default is wrong, your build may not work correctly." +- print "warning: Use the \"toolset=xxxxx\" option to override our guess." +- print "warning: For more configuration options, please consult" +- print "warning: http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html" ++ print("warning: No toolsets are configured.") ++ print("warning: Configuring default toolset '%s'." % dt) ++ print("warning: If the default is wrong, your build may not work correctly.") ++ print("warning: Use the \"toolset=xxxxx\" option to override our guess.") ++ print("warning: For more configuration options, please consult") ++ print("warning: http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html") + + using(dt, dtv) + +@@ -554,8 +554,8 @@ def main_real(): + t = find_target(id) + + if not t: +- print "notice: could not find main target '%s'" % id +- print "notice: assuming it's a name of file to create " ; ++ print("notice: could not find main target '%s'" % id) ++ print("notice: assuming it's a name of file to create ") ; + explicitly_requested_files.append(id) + else: + targets.append(t) +@@ -615,7 +615,7 @@ def main_real(): + if not isinstance(t, ProjectTarget): + results_of_main_targets.extend(g.targets()) + virtual_targets.extend(g.targets()) +- except ExceptionWithUserContext, e: ++ except ExceptionWithUserContext as e: + e.report() + except Exception: + raise +@@ -634,7 +634,7 @@ def main_real(): + elif k in ["off", "no", "false"]: + bjam.call("set-variable", "KEEP_GOING", "0") + else: +- print "error: Invalid value for the --keep-going option" ++ print("error: Invalid value for the --keep-going option") + sys.exit() + + # The 'all' pseudo target is not strictly needed expect in the case when we +diff --git a/tools/build/src/contrib/boost.py b/tools/build/src/contrib/boost.py +index 7d1f6b4..c94c821 100644 +--- a/tools/build/src/contrib/boost.py ++++ b/tools/build/src/contrib/boost.py +@@ -109,8 +109,8 @@ def init(version, options = None): + global __boost_default + if debug(): + if not __boost_default: +- print "notice: configuring default boost library {}".format(version) +- print "notice: configuring boost library {}".format(version) ++ print("notice: configuring default boost library {}".format(version)) ++ print("notice: configuring boost library {}".format(version)) + + if not __boost_default: + __boost_default = version +@@ -151,7 +151,7 @@ def use_project(version = None): + lib = opts.get('') + + if debug(): +- print "notice: using boost library {} {}".format( version, opt.raw() ) ++ print("notice: using boost library {} {}".format( version, opt.raw() )) + + global __layout + global __version_tag +@@ -239,7 +239,7 @@ def boost_std(inc = None, lib = None): + boost_lib('wave' , 'BOOST_WAVE_DYN_LINK' ) + + def boost_0_0_1( inc, lib ): +- print "You are trying to use an example placeholder for boost libs." ; ++ print("You are trying to use an example placeholder for boost libs.") ; + # Copy this template to another place (in the file boost.jam) + # and define a project and libraries modelled after the + # boost_std rule. Please note that it is also possible to have +diff --git a/tools/build/src/engine/bump_version.py b/tools/build/src/engine/bump_version.py +index 1771422..3b23a91 100644 +--- a/tools/build/src/engine/bump_version.py ++++ b/tools/build/src/engine/bump_version.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # This script is used to bump the bjam version. It takes a single argument, e.g + # +@@ -23,7 +23,7 @@ docdir = os.path.abspath(os.path.join(srcdir, "..", "doc")) + + + def edit(file, *replacements): +- print(" '%s'..." % file) ++ print((" '%s'..." % file)) + f = open(file, 'r') + text = f.read() + f.close() +@@ -42,7 +42,7 @@ def make_edits(ver): + join = lambda v, s : s.join(str(x) for x in v) + dotJoin = lambda v : join(v, ".") + +- print("Setting version to %s" % str(ver03)) ++ print(("Setting version to %s" % str(ver03))) + + edit(os.path.join(srcdir, "boost-jam.spec"), + ('^(Version:) .*$', '\\1 %s' % dotJoin(ver03))) +diff --git a/tools/build/src/manager.py b/tools/build/src/manager.py +index 9c1e057..7e53175 100644 +--- a/tools/build/src/manager.py ++++ b/tools/build/src/manager.py +@@ -19,13 +19,13 @@ class Manager: + """ Constructor. + engine: the build engine that will actually construct the targets. + """ +- from build.virtual_target import VirtualTargetRegistry +- from build.targets import TargetRegistry +- from build.project import ProjectRegistry +- from build.scanner import ScannerRegistry +- from build.errors import Errors ++ from .build.virtual_target import VirtualTargetRegistry ++ from .build.targets import TargetRegistry ++ from .build.project import ProjectRegistry ++ from .build.scanner import ScannerRegistry ++ from .build.errors import Errors + from b2.util.logger import NullLogger +- from build import build_request, property_set, feature ++ from .build import build_request, property_set, feature + + self.engine_ = engine + self.virtual_targets_ = VirtualTargetRegistry (self) +diff --git a/tools/build/src/tools/builtin.py b/tools/build/src/tools/builtin.py +index ee6474b..0984e0f 100644 +--- a/tools/build/src/tools/builtin.py ++++ b/tools/build/src/tools/builtin.py +@@ -437,7 +437,7 @@ class LibGenerator (generators.Generator): + + def run(self, project, name, prop_set, sources): + assert isinstance(project, targets.ProjectTarget) +- assert isinstance(name, basestring) or name is None ++ assert isinstance(name, str) or name is None + assert isinstance(prop_set, property_set.PropertySet) + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + # The lib generator is composing, and can be only invoked with +@@ -475,11 +475,11 @@ generators.override("builtin.prebuilt", "builtin.lib-generator") + def lib(names, sources=[], requirements=[], default_build=[], usage_requirements=[]): + """The implementation of the 'lib' rule. Beyond standard syntax that rule allows + simplified: 'lib a b c ;'.""" +- assert is_iterable_typed(names, basestring) +- assert is_iterable_typed(sources, basestring) +- assert is_iterable_typed(requirements, basestring) +- assert is_iterable_typed(default_build, basestring) +- assert is_iterable_typed(usage_requirements, basestring) ++ assert is_iterable_typed(names, str) ++ assert is_iterable_typed(sources, str) ++ assert is_iterable_typed(requirements, str) ++ assert is_iterable_typed(default_build, str) ++ assert is_iterable_typed(usage_requirements, str) + if len(names) > 1: + if any(r.startswith('') for r in requirements): + get_manager().errors()("When several names are given to the 'lib' rule\n" + +@@ -521,7 +521,7 @@ class SearchedLibGenerator (generators.Generator): + + def run(self, project, name, prop_set, sources): + assert isinstance(project, targets.ProjectTarget) +- assert isinstance(name, basestring) or name is None ++ assert isinstance(name, str) or name is None + assert isinstance(prop_set, property_set.PropertySet) + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + +@@ -561,7 +561,7 @@ class PrebuiltLibGenerator(generators.Generator): + + def run(self, project, name, properties, sources): + assert isinstance(project, targets.ProjectTarget) +- assert isinstance(name, basestring) ++ assert isinstance(name, str) + assert isinstance(properties, property_set.PropertySet) + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + +@@ -615,7 +615,7 @@ class LinkingGenerator (generators.Generator): + + def run (self, project, name, prop_set, sources): + assert isinstance(project, targets.ProjectTarget) +- assert isinstance(name, basestring) or name is None ++ assert isinstance(name, str) or name is None + assert isinstance(prop_set, property_set.PropertySet) + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + +@@ -708,7 +708,7 @@ class LinkingGenerator (generators.Generator): + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + assert isinstance(prop_set, property_set.PropertySet) + assert isinstance(project, targets.ProjectTarget) +- assert isinstance(name, basestring) ++ assert isinstance(name, str) + # sources to pass to inherited rule + sources2 = [] + # sources which are libraries +@@ -753,7 +753,7 @@ class ArchiveGenerator (generators.Generator): + + def run (self, project, name, prop_set, sources): + assert isinstance(project, targets.ProjectTarget) +- assert isinstance(name, basestring) or name is None ++ assert isinstance(name, str) or name is None + assert isinstance(prop_set, property_set.PropertySet) + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + +@@ -789,6 +789,6 @@ class DummyGenerator(generators.Generator): + + get_manager().projects().add_rule("variant", variant) + +-import stage +-import symlink +-import message ++from . import stage ++from . import symlink ++from . import message +diff --git a/tools/build/src/tools/cast.py b/tools/build/src/tools/cast.py +index cf1a876..ebc4ee1 100644 +--- a/tools/build/src/tools/cast.py ++++ b/tools/build/src/tools/cast.py +@@ -34,7 +34,7 @@ from b2.util import bjam_signature, is_iterable_typed + class CastTargetClass(targets.TypedTarget): + + def construct(self, name, source_targets, ps): +- assert isinstance(name, basestring) ++ assert isinstance(name, str) + assert is_iterable_typed(source_targets, virtual_target.VirtualTarget) + assert isinstance(ps, property_set.PropertySet) + +diff --git a/tools/build/src/tools/common.py b/tools/build/src/tools/common.py +index 87b942c..c03a7c8 100644 +--- a/tools/build/src/tools/common.py ++++ b/tools/build/src/tools/common.py +@@ -112,7 +112,7 @@ class Configurations(object): + Returns True if the configuration has been added and False if + it already exists. Reports an error if the configuration is 'used'. + """ +- assert isinstance(id, basestring) ++ assert isinstance(id, str) + if id in self.used_: + #FIXME + errors.error("common: the configuration '$(id)' is in use") +@@ -133,7 +133,7 @@ class Configurations(object): + 'used' and False if it the state wasn't changed. Reports an error + if the configuration isn't known. + """ +- assert isinstance(id, basestring) ++ assert isinstance(id, str) + if id not in self.all_: + #FIXME: + errors.error("common: the configuration '$(id)' is not known") +@@ -156,15 +156,15 @@ class Configurations(object): + + def get(self, id, param): + """ Returns the value of a configuration parameter. """ +- assert isinstance(id, basestring) +- assert isinstance(param, basestring) ++ assert isinstance(id, str) ++ assert isinstance(param, str) + return self.params_.get(param, {}).get(id) + + def set (self, id, param, value): + """ Sets the value of a configuration parameter. """ +- assert isinstance(id, basestring) +- assert isinstance(param, basestring) +- assert is_iterable_typed(value, basestring) ++ assert isinstance(id, str) ++ assert isinstance(param, str) ++ assert is_iterable_typed(value, str) + self.params_.setdefault(param, {})[id] = value + + # Ported from trunk@47174 +@@ -181,8 +181,8 @@ def check_init_parameters(toolset, requirement, *args): + + The return value from this rule is a condition to be used for flags settings. + """ +- assert isinstance(toolset, basestring) +- assert is_iterable_typed(requirement, basestring) or requirement is None ++ assert isinstance(toolset, str) ++ assert is_iterable_typed(requirement, str) or requirement is None + from b2.build import toolset as b2_toolset + if requirement is None: + requirement = [] +@@ -278,7 +278,7 @@ def check_init_parameters(toolset, requirement, *args): + condition += requirement + + if __show_configuration: +- print "notice:", condition ++ print("notice:", condition) + return ['/'.join(condition)] + + # Ported from trunk@47077 +@@ -294,23 +294,23 @@ def get_invocation_command_nodefault( + find the tool, a warning is issued. If 'path-last' is specified, PATH is + checked after 'additional-paths' when searching for 'tool'. + """ +- assert isinstance(toolset, basestring) +- assert isinstance(tool, basestring) +- assert is_iterable_typed(user_provided_command, basestring) +- assert is_iterable_typed(additional_paths, basestring) or additional_paths is None ++ assert isinstance(toolset, str) ++ assert isinstance(tool, str) ++ assert is_iterable_typed(user_provided_command, str) ++ assert is_iterable_typed(additional_paths, str) or additional_paths is None + assert isinstance(path_last, (int, bool)) + + if not user_provided_command: + command = find_tool(tool, additional_paths, path_last) + if not command and __debug_configuration: +- print "warning: toolset", toolset, "initialization: can't find tool, tool" ++ print("warning: toolset", toolset, "initialization: can't find tool, tool") + #FIXME + #print "warning: initialized from" [ errors.nearest-user-location ] ; + else: + command = check_tool(user_provided_command) + if not command and __debug_configuration: +- print "warning: toolset", toolset, "initialization:" +- print "warning: can't find user-provided command", user_provided_command ++ print("warning: toolset", toolset, "initialization:") ++ print("warning: can't find user-provided command", user_provided_command) + #FIXME + #ECHO "warning: initialized from" [ errors.nearest-user-location ] + command = [] +@@ -325,10 +325,10 @@ def get_invocation_command(toolset, tool, user_provided_command = [], + """ Same as get_invocation_command_nodefault, except that if no tool is found, + returns either the user-provided-command, if present, or the 'tool' parameter. + """ +- assert isinstance(toolset, basestring) +- assert isinstance(tool, basestring) +- assert is_iterable_typed(user_provided_command, basestring) +- assert is_iterable_typed(additional_paths, basestring) or additional_paths is None ++ assert isinstance(toolset, str) ++ assert isinstance(tool, str) ++ assert is_iterable_typed(user_provided_command, str) ++ assert is_iterable_typed(additional_paths, str) or additional_paths is None + assert isinstance(path_last, (int, bool)) + + result = get_invocation_command_nodefault(toolset, tool, +@@ -353,7 +353,7 @@ def get_absolute_tool_path(command): + return the absolute path to the command. This works even if commnad + has not path element and is present in PATH. + """ +- assert isinstance(command, basestring) ++ assert isinstance(command, str) + if os.path.dirname(command): + return os.path.dirname(command) + else: +@@ -361,7 +361,7 @@ def get_absolute_tool_path(command): + m = path.glob(programs, [command, command + '.exe' ]) + if not len(m): + if __debug_configuration: +- print "Could not find:", command, "in", programs ++ print("Could not find:", command, "in", programs) + return None + return os.path.dirname(m[0]) + +@@ -374,8 +374,8 @@ def find_tool(name, additional_paths = [], path_last = False): + Otherwise, returns the empty string. If 'path_last' is specified, + path is checked after 'additional_paths'. + """ +- assert isinstance(name, basestring) +- assert is_iterable_typed(additional_paths, basestring) ++ assert isinstance(name, str) ++ assert is_iterable_typed(additional_paths, str) + assert isinstance(path_last, (int, bool)) + + programs = path.programs_path() +@@ -405,7 +405,7 @@ def check_tool_aux(command): + """ Checks if 'command' can be found either in path + or is a full name to an existing file. + """ +- assert isinstance(command, basestring) ++ assert isinstance(command, str) + dirname = os.path.dirname(command) + if dirname: + if os.path.exists(command): +@@ -428,7 +428,7 @@ def check_tool(command): + If comand is absolute path, check that it exists. Returns 'command' + if ok and empty string otherwise. + """ +- assert is_iterable_typed(command, basestring) ++ assert is_iterable_typed(command, str) + #FIXME: why do we check the first and last elements???? + if check_tool_aux(command[0]) or check_tool_aux(command[-1]): + return command +@@ -446,10 +446,10 @@ def handle_options(tool, condition, command, options): + """ + from b2.build import toolset + +- assert isinstance(tool, basestring) +- assert is_iterable_typed(condition, basestring) +- assert command and isinstance(command, basestring) +- assert is_iterable_typed(options, basestring) ++ assert isinstance(tool, str) ++ assert is_iterable_typed(condition, str) ++ assert command and isinstance(command, str) ++ assert is_iterable_typed(options, str) + toolset.flags(tool, 'CONFIG_COMMAND', condition, [command]) + toolset.flags(tool + '.compile', 'OPTIONS', condition, feature.get_values('', options)) + toolset.flags(tool + '.compile.c', 'OPTIONS', condition, feature.get_values('', options)) +@@ -486,8 +486,8 @@ def variable_setting_command(variable, value): + words, on Unix systems, the variable is exported, which is consistent with the + only possible behavior on Windows systems. + """ +- assert isinstance(variable, basestring) +- assert isinstance(value, basestring) ++ assert isinstance(variable, str) ++ assert isinstance(value, str) + + if os_name() == 'NT': + return "set " + variable + "=" + value + os.linesep +@@ -529,8 +529,8 @@ def path_variable_setting_command(variable, paths): + Returns a command to sets a named shell path variable to the given NATIVE + paths on the current platform. + """ +- assert isinstance(variable, basestring) +- assert is_iterable_typed(paths, basestring) ++ assert isinstance(variable, str) ++ assert is_iterable_typed(paths, str) + sep = os.path.pathsep + return variable_setting_command(variable, sep.join(paths)) + +@@ -539,8 +539,8 @@ def prepend_path_variable_command(variable, paths): + Returns a command that prepends the given paths to the named path variable on + the current platform. + """ +- assert isinstance(variable, basestring) +- assert is_iterable_typed(paths, basestring) ++ assert isinstance(variable, str) ++ assert is_iterable_typed(paths, str) + return path_variable_setting_command( + variable, paths + [expand_variable(variable)]) + +@@ -568,7 +568,7 @@ __mkdir_set = set() + __re_windows_drive = re.compile(r'^.*:\$') + + def mkdir(engine, target): +- assert isinstance(target, basestring) ++ assert isinstance(target, str) + # If dir exists, do not update it. Do this even for $(DOT). + bjam.call('NOUPDATE', target) + +@@ -648,9 +648,9 @@ def format_name(format, name, target_type, prop_set): + """ + if __debug__: + from ..build.property_set import PropertySet +- assert is_iterable_typed(format, basestring) +- assert isinstance(name, basestring) +- assert isinstance(target_type, basestring) ++ assert is_iterable_typed(format, str) ++ assert isinstance(name, str) ++ assert isinstance(target_type, str) + assert isinstance(prop_set, PropertySet) + # assert(isinstance(prop_set, property_set.PropertySet)) + if type.is_derived(target_type, 'LIB'): +@@ -697,8 +697,8 @@ def format_name(format, name, target_type, prop_set): + return result + + def join_tag(joiner, tag): +- assert isinstance(joiner, basestring) +- assert isinstance(tag, basestring) ++ assert isinstance(joiner, str) ++ assert isinstance(tag, str) + if tag: + if not joiner: joiner = '-' + return joiner + tag +@@ -709,8 +709,8 @@ __re_toolset_version = re.compile(r"(\d+)[.](\d*)") + def toolset_tag(name, target_type, prop_set): + if __debug__: + from ..build.property_set import PropertySet +- assert isinstance(name, basestring) +- assert isinstance(target_type, basestring) ++ assert isinstance(name, str) ++ assert isinstance(target_type, str) + assert isinstance(prop_set, PropertySet) + tag = '' + +@@ -780,8 +780,8 @@ def toolset_tag(name, target_type, prop_set): + def threading_tag(name, target_type, prop_set): + if __debug__: + from ..build.property_set import PropertySet +- assert isinstance(name, basestring) +- assert isinstance(target_type, basestring) ++ assert isinstance(name, str) ++ assert isinstance(target_type, str) + assert isinstance(prop_set, PropertySet) + tag = '' + properties = prop_set.raw() +@@ -793,8 +793,8 @@ def threading_tag(name, target_type, prop_set): + def runtime_tag(name, target_type, prop_set ): + if __debug__: + from ..build.property_set import PropertySet +- assert isinstance(name, basestring) +- assert isinstance(target_type, basestring) ++ assert isinstance(name, str) ++ assert isinstance(target_type, str) + assert isinstance(prop_set, PropertySet) + tag = '' + +diff --git a/tools/build/src/tools/darwin.py b/tools/build/src/tools/darwin.py +index f03d63f..b3f088e 100644 +--- a/tools/build/src/tools/darwin.py ++++ b/tools/build/src/tools/darwin.py +@@ -7,7 +7,7 @@ + # Please see http://article.gmane.org/gmane.comp.lib.boost.build/3389/ + # for explanation why it's a separate toolset. + +-import common, gcc, builtin ++from . import common, gcc, builtin + from b2.build import feature, toolset, type, action, generators + from b2.util.utility import * + +diff --git a/tools/build/src/tools/doxproc.py b/tools/build/src/tools/doxproc.py +index d415133..c6aaac0 100644 +--- a/tools/build/src/tools/doxproc.py ++++ b/tools/build/src/tools/doxproc.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # Copyright 2006 Rene Rivera + # Distributed under the Boost Software License, Version 1.0. + # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +@@ -19,7 +19,7 @@ import xml.dom.minidom + + + def usage(): +- print ''' ++ print(''' + Usage: + %s options + +@@ -30,7 +30,7 @@ Options: + --title The title of the top level BoostBook section. + --enable-index Generate additional index sections for classes and + types. +-''' % ( sys.argv[0] ) ++''' % ( sys.argv[0] )) + + + def get_args( argv = sys.argv[1:] ): +@@ -48,7 +48,7 @@ def get_args( argv = sys.argv[1:] ): + '--title' : 'Doxygen' + } + ( option_pairs, other ) = getopt.getopt( argv, '', spec ) +- map( lambda x: options.__setitem__( x[0], x[1] ), option_pairs ) ++ list(map( lambda x: options.__setitem__( x[0], x[1] ), option_pairs )) + + if '--help' in options: + usage() +@@ -129,7 +129,7 @@ class Doxygen2BoostBook: + def _generate( self ): + if not self.generated: + self.generated = True +- symbols = self.symbols.keys() ++ symbols = list(self.symbols.keys()) + symbols.sort() + #~ Populate the header section. + for symbol in symbols: +@@ -202,7 +202,7 @@ class Doxygen2BoostBook: + suffix = '_'+c.nodeName.replace('-','_') + node = c + names.append('_translate') +- names = map(lambda x: x+suffix,names) ++ names = [x+suffix for x in names] + if node: + for name in names: + if hasattr(self,name): +@@ -809,7 +809,7 @@ class Doxygen2BoostBook: + + def _createNode( self, tag, **kwargs ): + result = self.boostbook.createElement(tag) +- for k in kwargs.keys(): ++ for k in list(kwargs.keys()): + if kwargs[k] != '': + if k == 'id': + result.setAttribute('id',kwargs[k]) +@@ -833,14 +833,8 @@ def main( xmldir=None, output=None, id=None, title=None, index=False ): + translator = Doxygen2BoostBook(id=id, title=title, index=index) + #~ Feed in the namespaces first to build up the set of namespaces + #~ and definitions so that lookup is unambiguous when reading in the definitions. +- namespace_files = filter( +- lambda x: +- os.path.basename(x).startswith('namespace'), +- input) +- decl_files = filter( +- lambda x: +- not os.path.basename(x).startswith('namespace') and not os.path.basename(x).startswith('_'), +- input) ++ namespace_files = [x for x in input if os.path.basename(x).startswith('namespace')] ++ decl_files = [x for x in input if not os.path.basename(x).startswith('namespace') and not os.path.basename(x).startswith('_')] + for dox in namespace_files: + #~ print '--|',os.path.basename(dox) + translator.addDox(xml.dom.minidom.parse(dox)) +diff --git a/tools/build/src/tools/gcc.py b/tools/build/src/tools/gcc.py +index 270ca97..a0067d2 100644 +--- a/tools/build/src/tools/gcc.py ++++ b/tools/build/src/tools/gcc.py +@@ -164,7 +164,7 @@ def init(version = None, command = None, options = None): + os.path.join(root, 'lib32'), + os.path.join(root, 'lib64')] + if debug(): +- print 'notice: using gcc libraries ::', condition, '::', lib_path ++ print('notice: using gcc libraries ::', condition, '::', lib_path) + toolset.flags('gcc.link', 'RUN_PATH', condition, lib_path) + + # If it's not a system gcc install we should adjust the various programs as +@@ -176,14 +176,14 @@ def init(version = None, command = None, options = None): + 'ar', feature.get_values('', options), [bin], path_last=True) + toolset.flags('gcc.archive', '.AR', condition, [archiver]) + if debug(): +- print 'notice: using gcc archiver ::', condition, '::', archiver ++ print('notice: using gcc archiver ::', condition, '::', archiver) + + # - Ranlib + ranlib = common.get_invocation_command('gcc', + 'ranlib', feature.get_values('', options), [bin], path_last=True) + toolset.flags('gcc.archive', '.RANLIB', condition, [ranlib]) + if debug(): +- print 'notice: using gcc archiver ::', condition, '::', ranlib ++ print('notice: using gcc archiver ::', condition, '::', ranlib) + + # - The resource compiler. + rc_command = common.get_invocation_command_nodefault('gcc', +@@ -438,10 +438,10 @@ class GccLinkingGenerator(unix.UnixLinkingGenerator): + reason = "On gcc, using DLLS together with the " +\ + "static options is not possible " + if reason: +- print 'warning:', reason +- print 'warning:',\ ++ print('warning:', reason) ++ print('warning:',\ + "It is suggested to use 'static' together",\ +- "with 'static'." ; ++ "with 'static'.") ; + return + else: + generated_targets = unix.UnixLinkingGenerator.run(self, project, +@@ -504,7 +504,7 @@ def init_link_flags(toolset, linker, condition): + # support -s. + + # FIXME: what does unchecked translate to? +- flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,--strip-all']) # : unchecked ; ++ flags(toolset_link, 'OPTIONS', [x + '/off' for x in condition], ['-Wl,--strip-all']) # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + flags(toolset_link, 'RPATH_LINK', condition, ['']) # : unchecked ; + flags(toolset_link, 'START-GROUP', condition, ['-Wl,--start-group'])# : unchecked ; +@@ -543,22 +543,22 @@ def init_link_flags(toolset, linker, condition): + + # On *nix mixing shared libs with static runtime is not a good idea. + flags(toolset_link, 'FINDLIBS-ST-PFX', +- map(lambda x: x + '/shared', condition), ++ [x + '/shared' for x in condition], + ['-Wl,-Bstatic']) # : unchecked ; + flags(toolset_link, 'FINDLIBS-SA-PFX', +- map(lambda x: x + '/shared', condition), ++ [x + '/shared' for x in condition], + ['-Wl,-Bdynamic']) # : unchecked ; + + # On windows allow mixing of static and dynamic libs with static + # runtime. + flags(toolset_link, 'FINDLIBS-ST-PFX', +- map(lambda x: x + '/static/windows', condition), ++ [x + '/static/windows' for x in condition], + ['-Wl,-Bstatic']) # : unchecked ; + flags(toolset_link, 'FINDLIBS-SA-PFX', +- map(lambda x: x + '/static/windows', condition), ++ [x + '/static/windows' for x in condition], + ['-Wl,-Bdynamic']) # : unchecked ; + flags(toolset_link, 'OPTIONS', +- map(lambda x: x + '/static/windows', condition), ++ [x + '/static/windows' for x in condition], + ['-Wl,-Bstatic']) # : unchecked ; + + elif linker == 'darwin': +@@ -570,7 +570,7 @@ def init_link_flags(toolset, linker, condition): + + elif linker == 'osf': + # No --strip-all, just -s. +- flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,-s']) ++ flags(toolset_link, 'OPTIONS', [x + '/off' for x in condition], ['-Wl,-s']) + # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + # This does not supports -R. +@@ -578,7 +578,7 @@ def init_link_flags(toolset, linker, condition): + # -rpath-link is not supported at all. + + elif linker == 'sun': +- flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,-s']) ++ flags(toolset_link, 'OPTIONS', [x + '/off' for x in condition], ['-Wl,-s']) + # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + # Solaris linker does not have a separate -rpath-link, but allows to use +@@ -591,13 +591,13 @@ def init_link_flags(toolset, linker, condition): + # separate question. + # AH, 2004/10/16: it is still necessary because some tests link against + # static libraries that were compiled without PIC. +- flags(toolset_link, 'OPTIONS', map(lambda x: x + '/shared', condition), ['-mimpure-text']) ++ flags(toolset_link, 'OPTIONS', [x + '/shared' for x in condition], ['-mimpure-text']) + # : unchecked ; + + elif linker == 'hpux': +- flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ++ flags(toolset_link, 'OPTIONS', [x + '/off' for x in condition], + ['-Wl,-s']) # : unchecked ; +- flags(toolset_link, 'OPTIONS', map(lambda x: x + '/shared', condition), ++ flags(toolset_link, 'OPTIONS', [x + '/shared' for x in condition], + ['-fPIC']) # : unchecked ; + + else: +diff --git a/tools/build/src/tools/message.py b/tools/build/src/tools/message.py +index 3f276f9..0182003 100644 +--- a/tools/build/src/tools/message.py ++++ b/tools/build/src/tools/message.py +@@ -28,7 +28,7 @@ class MessageTargetClass(targets.BasicTarget): + for arg in self.args: + if type(arg) == type([]): + arg = " ".join(arg) +- print arg ++ print(arg) + self.built = True + + return (property_set.empty(), []) +diff --git a/tools/build/src/tools/msvc.py b/tools/build/src/tools/msvc.py +index efd3a90..ebfb716 100644 +--- a/tools/build/src/tools/msvc.py ++++ b/tools/build/src/tools/msvc.py +@@ -25,7 +25,7 @@ + from os import environ + import os.path + import re +-import _winreg ++import winreg + + import bjam + +@@ -38,6 +38,7 @@ from b2.build.generators import Generator + from b2.build.toolset import flags + from b2.util.utility import to_seq, on_windows + from b2.tools.common import Configurations ++import collections + + __debug = None + +@@ -127,9 +128,9 @@ def configure(version=None, options=None): + all_versions = __versions.all() + if not all_versions: + if debug(): +- print "notice: [msvc-cfg] Asked to configure all registered" \ ++ print("notice: [msvc-cfg] Asked to configure all registered" \ + "msvc toolset versions when there are none currently" \ +- "registered." ; ++ "registered.") ; + else: + for v in all_versions: + # Note that there is no need to skip already configured +@@ -332,7 +333,7 @@ class SetupAction: + self.function = function + + def __call__(self, targets, sources, property_set): +- assert(callable(self.setup_func)) ++ assert(isinstance(self.setup_func, collections.Callable)) + # This can modify sources. + action_name = self.setup_func(targets, sources, property_set) + # Bjam actions defined from Python have only the command +@@ -610,8 +611,8 @@ def auto_detect_toolset_versions(): + vc_path = None + for x64elt in [ '', 'Wow6432Node\\' ]: + try: +- with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\{}Microsoft\\{}'.format(x64elt, globals()[versionVarName])) as reg_key: +- vc_path = _winreg.QueryValueEx(reg_key, "ProductDir")[0] ++ with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\{}Microsoft\\{}'.format(x64elt, globals()[versionVarName])) as reg_key: ++ vc_path = winreg.QueryValueEx(reg_key, "ProductDir")[0] + except: + pass + if vc_path: +@@ -930,7 +931,7 @@ def configure_really(version=None, options=[]): + + if debug(): + for cpu_condition in cpu_conditions: +- print "notice: [msvc-cfg] condition: '{}', setup: '{}'".format(cpu_condition,setup_script) ++ print("notice: [msvc-cfg] condition: '{}', setup: '{}'".format(cpu_condition,setup_script)) + + cpu_assembler = assembler + if not cpu_assembler: +@@ -1201,7 +1202,7 @@ def register_configuration(version, path=None): + command = os.path.join(path, 'cl.exe') + if os.path.exists(command): + if debug(): +- print "notice: [msvc-cfg] msvc-$(version) detected, command: ''".format(version,command) ++ print("notice: [msvc-cfg] msvc-$(version) detected, command: ''".format(version,command)) + __versions.register(version) + __versions.set(version,'options',['{}'.format(command)]) + +diff --git a/tools/build/src/tools/rc.py b/tools/build/src/tools/rc.py +index c7a02db..fb61839 100644 +--- a/tools/build/src/tools/rc.py ++++ b/tools/build/src/tools/rc.py +@@ -72,7 +72,7 @@ def configure (command = None, condition = None, options = None): + flags('rc.compile.resource', 'DEFINES', [], ['']) + flags('rc.compile.resource', 'INCLUDES', [], ['']) + if debug(): +- print 'notice: using rc compiler ::', condition, '::', command ++ print('notice: using rc compiler ::', condition, '::', command) + + engine = get_manager().engine() + +diff --git a/tools/build/src/tools/stage.py b/tools/build/src/tools/stage.py +index 2a15dd1..8c997dd 100644 +--- a/tools/build/src/tools/stage.py ++++ b/tools/build/src/tools/stage.py +@@ -25,7 +25,7 @@ import b2.build.type + + import os.path + import re +-import types ++from . import types + + feature.feature('install-dependencies', ['off', 'on'], ['incidental']) + feature.feature('install-type', [], ['free', 'incidental']) +@@ -170,7 +170,7 @@ class InstallTargetClass(targets.BasicTarget): + def collect_targets(self, targets): + + s = [t.creating_subvariant() for t in targets] +- s = unique(filter(lambda l: l != None,s)) ++ s = unique([l for l in s if l != None]) + + result = set(targets) + for i in s: +diff --git a/tools/build/src/tools/testing.py b/tools/build/src/tools/testing.py +index b634bea..7f33438 100644 +--- a/tools/build/src/tools/testing.py ++++ b/tools/build/src/tools/testing.py +@@ -88,10 +88,10 @@ __all_tests = [] + # Helper rule. Create a test target, using basename of first source if no target + # name is explicitly passed. Remembers the created target in a global variable. + def make_test(target_type, sources, requirements, target_name=None): +- assert isinstance(target_type, basestring) +- assert is_iterable_typed(sources, basestring) +- assert is_iterable_typed(requirements, basestring) +- assert isinstance(target_type, basestring) or target_type is None ++ assert isinstance(target_type, str) ++ assert is_iterable_typed(sources, str) ++ assert is_iterable_typed(requirements, str) ++ assert isinstance(target_type, str) or target_type is None + if not target_name: + target_name = stem(os.path.basename(sources[0])) + +@@ -192,7 +192,7 @@ __ln1 = re.compile("/(tools|libs)/(.*)/(test|example)") + __ln2 = re.compile("/(tools|libs)/(.*)$") + __ln3 = re.compile("(/status$)") + def get_library_name(path): +- assert isinstance(path, basestring) ++ assert isinstance(path, str) + + path = path.replace("\\", "/") + match1 = __ln1.match(path) +@@ -260,9 +260,9 @@ def dump_test(target): + + source_files = " ".join('"' + s + '"' for s in source_files) + if test_info: +- print 'boost-test(%s) "%s" [%s] : %s' % (type, name, test_info, source_files) ++ print('boost-test(%s) "%s" [%s] : %s' % (type, name, test_info, source_files)) + else: +- print 'boost-test(%s) "%s" : %s' % (type, name, source_files) ++ print('boost-test(%s) "%s" : %s' % (type, name, source_files)) + + # Register generators. Depending on target type, either 'expect-success' or + # 'expect-failure' rule will be used. +@@ -305,8 +305,8 @@ generators.register_composing("testing.time", [], ["TIME"]) + def run_path_setup(target, sources, ps): + if __debug__: + from ..build.property_set import PropertySet +- assert is_iterable_typed(target, basestring) or isinstance(target, basestring) +- assert is_iterable_typed(sources, basestring) ++ assert is_iterable_typed(target, str) or isinstance(target, str) ++ assert is_iterable_typed(sources, str) + assert isinstance(ps, PropertySet) + # For testing, we need to make sure that all dynamic libraries needed by the + # test are found. So, we collect all paths from dependency libraries (via +@@ -324,8 +324,8 @@ def run_path_setup(target, sources, ps): + def capture_output_setup(target, sources, ps): + if __debug__: + from ..build.property_set import PropertySet +- assert is_iterable_typed(target, basestring) +- assert is_iterable_typed(sources, basestring) ++ assert is_iterable_typed(target, str) ++ assert is_iterable_typed(sources, str) + assert isinstance(ps, PropertySet) + run_path_setup(target[0], sources, ps) + +diff --git a/tools/build/src/tools/unix.py b/tools/build/src/tools/unix.py +index 298fc1d..377be63 100644 +--- a/tools/build/src/tools/unix.py ++++ b/tools/build/src/tools/unix.py +@@ -9,7 +9,7 @@ + declared there store information about the order and use it properly. + """ + +-import builtin ++from . import builtin + from b2.build import generators, type + from b2.util.utility import * + from b2.util import set, sequence +diff --git a/tools/build/src/util/__init__.py b/tools/build/src/util/__init__.py +index 7c847cb..470034b 100644 +--- a/tools/build/src/util/__init__.py ++++ b/tools/build/src/util/__init__.py +@@ -4,6 +4,7 @@ import re + import types + + from itertools import groupby ++import collections + + + def safe_isinstance(value, types=None, class_names=None): +@@ -23,7 +24,7 @@ def safe_isinstance(value, types=None, class_names=None): + # this doesn't work with inheritance, but normally + # either the class will already be imported within the module, + # or the class doesn't have any subclasses. For example: PropertySet +- if isinstance(class_names, basestring): ++ if isinstance(class_names, str): + class_names = [class_names] + # this is the part that makes it "safe". + try: +@@ -42,7 +43,7 @@ def is_iterable_typed(values, type_): + + def is_iterable(value): + """Returns whether value is iterable and not a string.""" +- return not isinstance(value, basestring) and hasattr(value, '__iter__') ++ return not isinstance(value, str) and hasattr(value, '__iter__') + + + def is_iterable_or_none(value): +@@ -53,7 +54,7 @@ def is_single_value(value): + # some functions may specify a bjam signature + # that is a string type, but still allow a + # PropertySet to be passed in +- return safe_isinstance(value, (basestring, type(None)), 'PropertySet') ++ return safe_isinstance(value, (str, type(None)), 'PropertySet') + + + if __debug__: +@@ -86,14 +87,14 @@ if __debug__: + + def get_next_var(field): + it = iter(field) +- var = it.next() ++ var = next(it) + type_ = None + yield_var = False + while type_ not in bjam_types: + try: + # the first value has already + # been consumed outside of the loop +- type_ = it.next() ++ type_ = next(it) + except StopIteration: + # if there are no more values, then + # var still needs to be returned +@@ -110,7 +111,7 @@ if __debug__: + yield var, type_ + try: + # the next value should be a var +- var = it.next() ++ var = next(it) + except StopIteration: + # if not, then we're done with + # this field +@@ -255,7 +256,7 @@ def value_to_jam(value, methods=False): + if methods and type(value) == types.InstanceType: + for field_name in dir(value): + field = getattr(value, field_name) +- if callable(field) and not field_name.startswith("__"): ++ if isinstance(field, collections.Callable) and not field_name.startswith("__"): + bjam.import_rule("", exported_name + "." + field_name, field) + + return exported_name +diff --git a/tools/build/src/util/path.py b/tools/build/src/util/path.py +index e451c2c..1e44bb2 100644 +--- a/tools/build/src/util/path.py ++++ b/tools/build/src/util/path.py +@@ -19,7 +19,7 @@ + # of slash only. + + import os.path +-from utility import to_seq ++from .utility import to_seq + from glob import glob as builtin_glob + + from b2.util import bjam_signature +diff --git a/tools/build/src/util/sequence.py b/tools/build/src/util/sequence.py +index b5dddba..4fd7830 100644 +--- a/tools/build/src/util/sequence.py ++++ b/tools/build/src/util/sequence.py +@@ -6,6 +6,7 @@ + import operator + + from b2.util import is_iterable ++import collections + + + def unique (values, stable=False): +@@ -26,7 +27,7 @@ def max_element (elements, ordered = None): + or '<' is none is provided. + """ + assert is_iterable(elements) +- assert callable(ordered) or ordered is None ++ assert isinstance(ordered, collections.Callable) or ordered is None + if not ordered: ordered = operator.lt + + max = elements [0] +diff --git a/tools/build/src/util/utility.py b/tools/build/src/util/utility.py +index ded3e5b..3bc3537 100644 +--- a/tools/build/src/util/utility.py ++++ b/tools/build/src/util/utility.py +@@ -41,7 +41,7 @@ def add_grist (features): + features: one string or a sequence of strings + return: the gristed string, if features is a string, or a sequence of gristed strings, if features is a sequence + """ +- assert is_iterable_typed(features, basestring) or isinstance(features, basestring) ++ assert is_iterable_typed(features, str) or isinstance(features, str) + def grist_one (feature): + if feature [0] != '<' and feature [len (feature) - 1] != '>': + return '<' + feature + '>' +@@ -57,8 +57,8 @@ def replace_grist (features, new_grist): + """ Replaces the grist of a string by a new one. + Returns the string with the new grist. + """ +- assert is_iterable_typed(features, basestring) or isinstance(features, basestring) +- assert isinstance(new_grist, basestring) ++ assert is_iterable_typed(features, str) or isinstance(features, str) ++ assert isinstance(new_grist, str) + # this function is used a lot in the build phase and the original implementation + # was extremely slow; thus some of the weird-looking optimizations for this function. + single_item = False +@@ -85,14 +85,14 @@ def replace_grist (features, new_grist): + def get_value (property): + """ Gets the value of a property, that is, the part following the grist, if any. + """ +- assert is_iterable_typed(property, basestring) or isinstance(property, basestring) ++ assert is_iterable_typed(property, str) or isinstance(property, str) + return replace_grist (property, '') + + def get_grist (value): + """ Returns the grist of a string. + If value is a sequence, does it for every value and returns the result as a sequence. + """ +- assert is_iterable_typed(value, basestring) or isinstance(value, basestring) ++ assert is_iterable_typed(value, str) or isinstance(value, str) + def get_grist_one (name): + split = __re_grist_and_value.match (name) + if not split: +@@ -109,7 +109,7 @@ def ungrist (value): + """ Returns the value without grist. + If value is a sequence, does it for every value and returns the result as a sequence. + """ +- assert is_iterable_typed(value, basestring) or isinstance(value, basestring) ++ assert is_iterable_typed(value, str) or isinstance(value, str) + def ungrist_one (value): + stripped = __re_grist_content.match (value) + if not stripped: +@@ -126,15 +126,15 @@ def replace_suffix (name, new_suffix): + """ Replaces the suffix of name by new_suffix. + If no suffix exists, the new one is added. + """ +- assert isinstance(name, basestring) +- assert isinstance(new_suffix, basestring) ++ assert isinstance(name, str) ++ assert isinstance(new_suffix, str) + split = os.path.splitext (name) + return split [0] + new_suffix + + def forward_slashes (s): + """ Converts all backslashes to forward slashes. + """ +- assert isinstance(s, basestring) ++ assert isinstance(s, str) + return s.replace('\\', '/') + + +@@ -142,7 +142,7 @@ def split_action_id (id): + """ Splits an id in the toolset and specific rule parts. E.g. + 'gcc.compile.c++' returns ('gcc', 'compile.c++') + """ +- assert isinstance(id, basestring) ++ assert isinstance(id, str) + split = id.split ('.', 1) + toolset = split [0] + name = '' +diff --git a/tools/build/test/BoostBuild.py b/tools/build/test/BoostBuild.py +index a6872dc..a75f523 100644 +--- a/tools/build/test/BoostBuild.py ++++ b/tools/build/test/BoostBuild.py +@@ -15,7 +15,7 @@ import os + import os.path + import re + import shutil +-import StringIO ++import io + import subprocess + import sys + import tempfile +@@ -25,6 +25,7 @@ import tree + import types + + from xml.sax.saxutils import escape ++from functools import reduce + + + class TestEnvironmentError(Exception): +@@ -37,13 +38,13 @@ annotations = [] + def print_annotation(name, value, xml): + """Writes some named bits of information about the current test run.""" + if xml: +- print escape(name) + " {{{" +- print escape(value) +- print "}}}" ++ print(escape(name) + " {{{") ++ print(escape(value)) ++ print("}}}") + else: +- print name + " {{{" +- print value +- print "}}}" ++ print(name + " {{{") ++ print(value) ++ print("}}}") + + + def flush_annotations(xml=0): +@@ -146,7 +147,7 @@ def prepare_library_prefix(toolset): + + def re_remove(sequence, regex): + me = re.compile(regex) +- result = filter(lambda x: me.match(x), sequence) ++ result = [x for x in sequence if me.match(x)] + if not result: + raise ValueError() + for r in result: +@@ -215,8 +216,8 @@ class Tester(TestCmd.TestCmd): + assert arguments.__class__ is not str + self.original_workdir = os.getcwd() + if workdir and not os.path.isabs(workdir): +- raise ("Parameter workdir <%s> must point to an absolute " +- "directory: " % workdir) ++ raise "Parameter workdir <%s> must point to an absolute " ++ "directory: " + + self.last_build_timestamp = 0 + self.translate_suffixes = translate_suffixes +@@ -234,7 +235,7 @@ class Tester(TestCmd.TestCmd): + jam_build_dir = "" + if os.name == "nt": + jam_build_dir = "bin.ntx86" +- elif (os.name == "posix") and os.__dict__.has_key("uname"): ++ elif (os.name == "posix") and "uname" in os.__dict__: + if os.uname()[0].lower().startswith("cygwin"): + jam_build_dir = "bin.cygwinx86" + if ("TMP" in os.environ and +@@ -266,11 +267,11 @@ class Tester(TestCmd.TestCmd): + elif os.uname()[0] == "OSF1": + jam_build_dir = "bin.osf" + else: +- raise ("Do not know directory where Jam is built for this " +- "system: %s/%s" % (os.name, os.uname()[0])) ++ raise "Do not know directory where Jam is built for this " ++ "system: %s/%s" + else: +- raise ("Do not know directory where Jam is built for this " +- "system: %s" % os.name) ++ raise "Do not know directory where Jam is built for this " ++ "system: %s" + + # Find where jam_src is located. Try for the debug version if it is + # lying around. +@@ -337,7 +338,7 @@ class Tester(TestCmd.TestCmd): + def make_writable(unused, dir, entries): + for e in entries: + name = os.path.join(dir, e) +- os.chmod(name, os.stat(name).st_mode | 0222) ++ os.chmod(name, os.stat(name).st_mode | 0o222) + os.path.walk(".", make_writable, None) + + def write(self, file, content, wait=True): +@@ -374,7 +375,7 @@ class Tester(TestCmd.TestCmd): + os.utime(path, None) + + def rm(self, names): +- if not type(names) == types.ListType: ++ if not type(names) == list: + names = [names] + + if names == ["."]: +@@ -421,8 +422,8 @@ class Tester(TestCmd.TestCmd): + assert extra_args.__class__ is not str + + if os.path.isabs(subdir): +- print("You must pass a relative directory to subdir <%s>." % subdir +- ) ++ print(("You must pass a relative directory to subdir <%s>." % subdir ++ )) + return + + self.previous_tree, dummy = tree.build_tree(self.workdir) +@@ -461,7 +462,7 @@ class Tester(TestCmd.TestCmd): + kw["chdir"] = subdir + self.last_program_invocation = kw["program"] + build_time_start = time.time() +- apply(TestCmd.TestCmd.run, [self], kw) ++ TestCmd.TestCmd.run(*[self], **kw) + build_time_finish = time.time() + except: + self.dump_stdio() +@@ -518,9 +519,9 @@ class Tester(TestCmd.TestCmd): + if expected_duration is not None: + actual_duration = build_time_finish - build_time_start + if actual_duration > expected_duration: +- print("Test run lasted %f seconds while it was expected to " ++ print(("Test run lasted %f seconds while it was expected to " + "finish in under %f seconds." % (actual_duration, +- expected_duration)) ++ expected_duration))) + self.fail_test(1, dump_stdio=False) + + self.__ignore_junk() +@@ -578,7 +579,7 @@ class Tester(TestCmd.TestCmd): + return + + if dump_difference and hasattr(self, "difference"): +- f = StringIO.StringIO() ++ f = io.StringIO() + self.difference.pprint(f) + annotation("changes caused by the last build command", + f.getvalue()) +@@ -587,17 +588,17 @@ class Tester(TestCmd.TestCmd): + self.dump_stdio() + + if "--preserve" in sys.argv: +- print +- print "*** Copying the state of working dir into 'failed_test' ***" +- print ++ print() ++ print("*** Copying the state of working dir into 'failed_test' ***") ++ print() + path = os.path.join(self.original_workdir, "failed_test") + if os.path.isdir(path): + shutil.rmtree(path, ignore_errors=False) + elif os.path.exists(path): + raise "Path " + path + " already exists and is not a directory" + shutil.copytree(self.workdir, path) +- print "The failed command was:" +- print " ".join(self.last_program_invocation) ++ print("The failed command was:") ++ print(" ".join(self.last_program_invocation)) + + if dump_stack: + annotate_stack_trace() +@@ -726,7 +727,7 @@ class Tester(TestCmd.TestCmd): + def expect_nothing_more(self): + if not self.unexpected_difference.empty(): + annotation("failure", "Unexpected changes found") +- output = StringIO.StringIO() ++ output = io.StringIO() + self.unexpected_difference.pprint(output) + annotation("unexpected changes", output.getvalue()) + self.fail_test(1) +@@ -748,12 +749,12 @@ class Tester(TestCmd.TestCmd): + def sorted_(x): + x.sort(lambda x, y: cmp(x.lower().replace("\\","/"), y.lower().replace("\\","/"))) + return x +- actual_ = map(lambda x: sorted_(x.split()), actual.splitlines()) +- content_ = map(lambda x: sorted_(x.split()), content.splitlines()) ++ actual_ = [sorted_(x.split()) for x in actual.splitlines()] ++ content_ = [sorted_(x.split()) for x in content.splitlines()] + if len(actual_) == len(content_): +- matched = map( +- lambda x, y: map(lambda n, p: fnmatch.fnmatch(n, p), x, y), +- actual_, content_) ++ matched = list(map( ++ lambda x, y: list(map(lambda n, p: fnmatch.fnmatch(n, p), x, y)), ++ actual_, content_)) + matched = reduce( + lambda x, y: x and reduce( + lambda a, b: a and b, +@@ -761,10 +762,10 @@ class Tester(TestCmd.TestCmd): + matched) + + if not matched: +- print "Expected:\n" +- print content +- print "Got:\n" +- print actual ++ print("Expected:\n") ++ print(content) ++ print("Got:\n") ++ print(actual) + self.fail_test(1) + + def maybe_do_diff(self, actual, expected, result=None): +@@ -783,12 +784,12 @@ class Tester(TestCmd.TestCmd): + # exact Python/OS platform version, os.system() call may gobble up + # the external process's return code and return 0 itself. + if os.system('diff -u "%s" "%s"' % (e, a)) not in [0, 1]: +- print('Unable to compute difference: diff -u "%s" "%s"' % (e, a +- )) ++ print(('Unable to compute difference: diff -u "%s" "%s"' % (e, a ++ ))) + os.unlink(e) + os.unlink(a) + elif type(result) is TestCmd.MatchError: +- print(result.message) ++ print((result.message)) + else: + print("Set environmental variable 'DO_DIFF' to examine the " + "difference.") +@@ -831,9 +832,9 @@ class Tester(TestCmd.TestCmd): + def adjust_names(self, names): + if names.__class__ is str: + names = [names] +- r = map(self.adjust_lib_name, names) +- r = map(self.adjust_suffix, r) +- r = map(lambda x, t=self.toolset: x.replace("$toolset", t + "*"), r) ++ r = list(map(self.adjust_lib_name, names)) ++ r = list(map(self.adjust_suffix, r)) ++ r = list(map(lambda x, t=self.toolset: x.replace("$toolset", t + "*"), r)) + return r + + def adjust_name(self, name): +@@ -977,7 +978,7 @@ class Tester(TestCmd.TestCmd): + + def __ignore_elements(self, list, wildcard): + """Removes in-place 'list' elements matching the given 'wildcard'.""" +- list[:] = filter(lambda x, w=wildcard: not fnmatch.fnmatch(x, w), list) ++ list[:] = list(filter(lambda x, w=wildcard: not fnmatch.fnmatch(x, w), list)) + + def __makedirs(self, path, wait): + """ +@@ -1230,7 +1231,7 @@ def _contains_lines(data, lines): + def _match_line_sequence(data, start, end, lines): + if not lines: + return start +- for index in xrange(start, end - len(lines) + 1): ++ for index in range(start, end - len(lines) + 1): + data_index = index + for expected in lines: + if not fnmatch.fnmatch(data[data_index], expected): +diff --git a/tools/build/test/TestCmd.py b/tools/build/test/TestCmd.py +index b6bd531..1e0f874 100644 +--- a/tools/build/test/TestCmd.py ++++ b/tools/build/test/TestCmd.py +@@ -63,6 +63,7 @@ import shutil + import stat + import subprocess + import sys ++import atexit + import tempfile + import traceback + +@@ -79,7 +80,7 @@ def _clean(): + for test in list: + test.cleanup() + +-sys.exitfunc = _clean ++atexit.register(_clean) + + + def caller(tblist, skip): +@@ -176,7 +177,7 @@ def pass_test(self=None, condition=True, function=None): + class MatchError(object): + def __init__(self, message): + self.message = message +- def __nonzero__(self): ++ def __bool__(self): + return False + def __bool__(self): + return False +@@ -295,7 +296,7 @@ class TestCmd: + condition = self.condition + if self._preserve[condition]: + for dir in self._dirlist: +- print("Preserved directory %s" % dir) ++ print(("Preserved directory %s" % dir)) + else: + list = self._dirlist[:] + list.reverse() +@@ -385,11 +386,11 @@ class TestCmd: + + """ + if type(file) is ListType: +- file = apply(os.path.join, tuple(file)) ++ file = os.path.join(*tuple(file)) + if not os.path.isabs(file): + file = os.path.join(self.workdir, file) + if mode[0] != 'r': +- raise ValueError, "mode must begin with 'r'" ++ raise ValueError("mode must begin with 'r'") + return open(file, mode).read() + + def run(self, program=None, arguments=None, chdir=None, stdin=None, +@@ -491,7 +492,7 @@ class TestCmd: + if sub is None: + continue + if type(sub) is ListType: +- sub = apply(os.path.join, tuple(sub)) ++ sub = os.path.join(*tuple(sub)) + new = os.path.join(self.workdir, sub) + try: + os.mkdir(new) +@@ -510,7 +511,7 @@ class TestCmd: + + """ + if type(file) is ListType: +- file = apply(os.path.join, tuple(file)) ++ file = os.path.join(*tuple(file)) + if not os.path.isabs(file): + file = os.path.join(self.workdir, file) + os.unlink(file) +@@ -558,7 +559,7 @@ class TestCmd: + directory name with the specified arguments using os.path.join(). + + """ +- return apply(os.path.join, (self.workdir,) + tuple(args)) ++ return os.path.join(*(self.workdir,) + tuple(args)) + + def writable(self, top, write): + """ +@@ -574,8 +575,8 @@ class TestCmd: + st = os.stat(fullname) + os.chmod(fullname, arg(st[stat.ST_MODE])) + +- _mode_writable = lambda mode: stat.S_IMODE(mode|0200) +- _mode_non_writable = lambda mode: stat.S_IMODE(mode&~0200) ++ _mode_writable = lambda mode: stat.S_IMODE(mode|0o200) ++ _mode_non_writable = lambda mode: stat.S_IMODE(mode&~0o200) + + if write: + f = _mode_writable +@@ -597,9 +598,9 @@ class TestCmd: + + """ + if type(file) is ListType: +- file = apply(os.path.join, tuple(file)) ++ file = os.path.join(*tuple(file)) + if not os.path.isabs(file): + file = os.path.join(self.workdir, file) + if mode[0] != 'w': +- raise ValueError, "mode must begin with 'w'" ++ raise ValueError("mode must begin with 'w'") + open(file, mode).write(content) +diff --git a/tools/build/test/builtin_glob_archive.py b/tools/build/test/builtin_glob_archive.py +index 847b14a..06cbd7e 100644 +--- a/tools/build/test/builtin_glob_archive.py ++++ b/tools/build/test/builtin_glob_archive.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # Copyright 2014 Steven Watanabe + # Copyright 2015 Artur Shepilko +@@ -9,7 +9,7 @@ + + import os + import sys +-import StringIO ++import io + import BoostBuild + + vms = ( os.name == 'posix' and sys.platform == 'OpenVMS') +@@ -37,7 +37,7 @@ def create_sources(path, sources): + for s in sources : + f = os.path.join(path, s) + t.write(f, "") +- output = StringIO.StringIO() ++ output = io.StringIO() + for sym in sources[s] : + output.write("int %s() { return 0; }\n" % sym) + t.write(f, output.getvalue()) +@@ -48,7 +48,7 @@ def setup_archive(name, sources): + global obj_suffix + archive = t.adjust_names(name)[0] + obj_suffix = t.adjust_names(".obj")[0] +- output = StringIO.StringIO() ++ output = io.StringIO() + t.write("jamroot.jam","") + output.write("""\ + static-lib %s : +@@ -71,7 +71,7 @@ static-lib %s : + + + def test_glob_archive(archives, glob, expected, sort_results = False): +- output = StringIO.StringIO() ++ output = io.StringIO() + ## replace placeholders + glob = glob.replace("$archive1", archives[0]).replace("$obj", obj_suffix) + expected = [ m.replace("$archive1", +diff --git a/tools/build/test/collect_debug_info.py b/tools/build/test/collect_debug_info.py +index b25c15c..b213c94 100755 +--- a/tools/build/test/collect_debug_info.py ++++ b/tools/build/test/collect_debug_info.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # Copyright 2012 Jurko Gospodnetic + # Distributed under the Boost Software License, Version 1.0. +@@ -69,7 +69,7 @@ def _collect(results, prefix, name, t): + + + def _collectDebugInfo_environ(t): +- dummyVars = ["WOOF_WOOFIE_%d" % x for x in xrange(4)] ++ dummyVars = ["WOOF_WOOFIE_%d" % x for x in range(4)] + global tag + + tag = "XXX in os.environ" +diff --git a/tools/build/test/core_arguments.py b/tools/build/test/core_arguments.py +index a6e886f..5251f62 100755 +--- a/tools/build/test/core_arguments.py ++++ b/tools/build/test/core_arguments.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # Copyright 2001 Dave Abrahams + # Copyright 2011 Steven Watanabe +@@ -10,7 +10,7 @@ import BoostBuild + + + def simple_args(start, finish): +- return " : ".join("%d" % x for x in xrange(start, finish + 1)) ++ return " : ".join("%d" % x for x in range(start, finish + 1)) + + + def test(t, type, input, output, status=0): +diff --git a/tools/build/test/core_nt_cmd_line.py b/tools/build/test/core_nt_cmd_line.py +index 579242d..f077fe4 100755 +--- a/tools/build/test/core_nt_cmd_line.py ++++ b/tools/build/test/core_nt_cmd_line.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # Copyright 2001 Dave Abrahams + # Copyright 2011 Steven Watanabe +@@ -28,7 +28,7 @@ def string_of_length(n): + n -= 1 + y = ['', '$(1x10-1)', '$(10x10-1)', '$(100x10-1)', '$(1000x10-1)'] + result = [] +- for i in reversed(xrange(5)): ++ for i in reversed(range(5)): + x, n = divmod(n, 10 ** i) + result += [y[i]] * x + result.append('x') +diff --git a/tools/build/test/load_dir.py b/tools/build/test/load_dir.py +index faa47d2..ef51c84 100644 +--- a/tools/build/test/load_dir.py ++++ b/tools/build/test/load_dir.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + """ + Traverses a directory and output the code that would create the same directory +@@ -11,7 +11,7 @@ import stat + import string + + def usage(): +- print "usage: load_dir.py directory" ++ print("usage: load_dir.py directory") + + + def remove_first_component(path): +@@ -21,18 +21,18 @@ def remove_first_component(path): + if not s[0]: + break + result[:1] = list(s) +- return apply(os.path.join, result[1:]) ++ return os.path.join(*result[1:]) + + + def create_file(arg, dirname, fnames): + for n in fnames: + path = os.path.join(dirname, n) + if not os.path.isdir(path): +- print "t.write(\"%s\", \"\"\"" % (remove_first_component(path),), ++ print("t.write(\"%s\", \"\"\"" % (remove_first_component(path),), end=' ') + f = open(path, "r") + for l in f: +- print l, +- print '\n""")\n' ++ print(l, end=' ') ++ print('\n""")\n') + + + header = """#!/usr/bin/python +@@ -64,17 +64,17 @@ def main(): + path = sys.argv[1] + + if not os.access(path, os.F_OK): +- print "Path '%s' does not exist" % (path,) ++ print("Path '%s' does not exist" % (path,)) + sys.exit(1) + + if not os.path.isdir(path): +- print "Path '%s' is not a directory" % (path,) ++ print("Path '%s' is not a directory" % (path,)) + +- print header ++ print(header) + + os.path.walk(path, create_file, None) + +- print footer ++ print(footer) + + + if __name__ == '__main__': +diff --git a/tools/build/test/notfile.py b/tools/build/test/notfile.py +index 602415a..5d975c3 100644 +--- a/tools/build/test/notfile.py ++++ b/tools/build/test/notfile.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # Copyright (C) Vladimir Prus 2005. + # Distributed under the Boost Software License, Version 1.0. +@@ -30,7 +30,7 @@ t.run_build_system(["-n", "-d+2"]) + t.fail_test(t.stdout().find("echo hi") == -1) + + name = t.adjust_names("bin/$toolset/debug*/hello.exe")[0] +-name = apply(os.path.join, name.split("/")); ++name = os.path.join(*name.split("/")); + t.expect_output_lines(" valgrind *%s " % name) + + t.cleanup() +diff --git a/tools/build/test/sort_rule.py b/tools/build/test/sort_rule.py +index 31db771..21841a6 100755 +--- a/tools/build/test/sort_rule.py ++++ b/tools/build/test/sort_rule.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # Copyright (C) 2008. Jurko Gospodnetic + # Distributed under the Boost Software License, Version 1.0. +@@ -63,19 +63,19 @@ def testSORTDuration(): + use_test_config=False) + + f = open(t.workpath("test.jam"), "w") +- print >> f, "data = " ++ print("data = ", file=f) + for i in range(0, 20000): + if i % 2: +- print >> f, '"aaa"' ++ print('"aaa"', file=f) + else: +- print >> f, '"bbb"' +- print >> f, """; ++ print('"bbb"', file=f) ++ print("""; + + ECHO "starting up" ; + sorted = [ SORT $(data) ] ; + ECHO "done" ; + NOCARE all ; +-""" ++""", file=f) + f.close() + + t.run_build_system(expected_duration=1) +diff --git a/tools/build/test/symlink.py b/tools/build/test/symlink.py +index a4a7f34..74dd1e9 100644 +--- a/tools/build/test/symlink.py ++++ b/tools/build/test/symlink.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # Copyright 2003 Dave Abrahams + # Copyright 2003 Vladimir Prus +@@ -12,7 +12,7 @@ import BoostBuild + + + if os.name != 'posix': +- print "The symlink tests can be run on posix only." ++ print("The symlink tests can be run on posix only.") + import sys + sys.exit(1) + +diff --git a/tools/build/test/test_all.py b/tools/build/test/test_all.py +index fe97acd..38ec69b 100644 +--- a/tools/build/test/test_all.py ++++ b/tools/build/test/test_all.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # Copyright 2002-2005 Dave Abrahams. + # Copyright 2002-2006 Vladimir Prus. +@@ -52,7 +52,7 @@ def run_tests(critical_tests, other_tests): + + for test in all_tests: + if not xml: +- print("%%-%ds :" % max_test_name_len % test), ++ print(("%%-%ds :" % max_test_name_len % test), end=' ') + + passed = 0 + try: +@@ -100,16 +100,16 @@ def run_tests(critical_tests, other_tests): + rs = "succeed" + if not passed: + rs = "fail" +- print """ ++ print(""" + + """ % (test, toolset, "tools/build/v2/test/" + test + ".py", +- "boost/bin.v2/boost.build.tests/" + toolset + "/" + test, rs) ++ "boost/bin.v2/boost.build.tests/" + toolset + "/" + test, rs)) + if not passed: + BoostBuild.flush_annotations(1) +- print """ ++ print(""" + + +-""" ++""") + sys.stdout.flush() # Makes testing under emacs more entertaining. + BoostBuild.clear_annotations() + +@@ -118,11 +118,11 @@ def run_tests(critical_tests, other_tests): + open("test_results.txt", "w").close() + + if not xml: +- print """ ++ print(""" + === Test summary === + PASS: %d + FAIL: %d +- """ % (pass_count, failures_count) ++ """ % (pass_count, failures_count)) + + # exit with failure with failures + if failures_count > 0: +diff --git a/tools/build/test/tree.py b/tools/build/test/tree.py +index 70c66a3..e39b03b 100644 +--- a/tools/build/test/tree.py ++++ b/tools/build/test/tree.py +@@ -75,13 +75,13 @@ class TreeNode: + return self.children is None + + def pprint(self): +- print(" * Node name: %s" % self.name) +- print(" Path: %s" % self.path) +- print(" Contents: %s" % self.contents) ++ print((" * Node name: %s" % self.name)) ++ print((" Path: %s" % self.path)) ++ print((" Contents: %s" % self.contents)) + if self.is_file(): + print(" Children: is a file.") + else: +- print(" Children: %d" % len(self.children)) ++ print((" Children: %d" % len(self.children))) + + + class TreeDifference: +@@ -100,10 +100,10 @@ class TreeDifference: + def ignore_directories(self): + """Removes directories from our lists of found differences.""" + not_dir = lambda x : x[-1] != "/" +- self.added_files = filter(not_dir, self.added_files) +- self.removed_files = filter(not_dir, self.removed_files) +- self.modified_files = filter(not_dir, self.modified_files) +- self.touched_files = filter(not_dir, self.touched_files) ++ self.added_files = list(filter(not_dir, self.added_files)) ++ self.removed_files = list(filter(not_dir, self.removed_files)) ++ self.modified_files = list(filter(not_dir, self.modified_files)) ++ self.touched_files = list(filter(not_dir, self.touched_files)) + + def pprint(self, file=sys.stdout): + file.write("Added files : %s\n" % self.added_files) +diff --git a/tools/litre/cplusplus.py b/tools/litre/cplusplus.py +index c48e067..d258574 100644 +--- a/tools/litre/cplusplus.py ++++ b/tools/litre/cplusplus.py +@@ -10,6 +10,7 @@ import litre + import re + import sys + import traceback ++from functools import reduce + + # Thanks to Jean Brouwers for this snippet + def _caller(up=0): +@@ -174,16 +175,16 @@ def syscmd( + status = not status + + if status: +- print +- print '========== offending command ===========' +- print cmd +- print '------------ stdout/stderr -------------' +- print expect_error and 'Error expected, but none seen' or out ++ print() ++ print('========== offending command ===========') ++ print(cmd) ++ print('------------ stdout/stderr -------------') ++ print(expect_error and 'Error expected, but none seen' or out) + elif expect_error > 1: +- print +- print '------ Output of Expected Error --------' +- print out +- print '----------------------------------------' ++ print() ++ print('------ Output of Expected Error --------') ++ print(out) ++ print('----------------------------------------') + + sys.stdout.flush() + +@@ -336,12 +337,12 @@ class CPlusPlusTranslator(litre.LitreTranslator): + + if not re.search(expected, self.last_run_output, re.MULTILINE): + #if self.last_run_output.strip('\n') != expected.strip('\n'): +- print 'output failed to match example' +- print '-------- Actual Output -------------' +- print repr(self.last_run_output) +- print '-------- Expected Output -----------' +- print repr(expected) +- print '------------------------------------' ++ print('output failed to match example') ++ print('-------- Actual Output -------------') ++ print(repr(self.last_run_output)) ++ print('-------- Expected Output -----------') ++ print(repr(expected)) ++ print('------------------------------------') + sys.stdout.flush() + + def ignore(self, n = 1): +@@ -461,21 +462,21 @@ class CPlusPlusTranslator(litre.LitreTranslator): + status, output = syscmd(cmd, expect_error) + + if status or expect_error > 1: +- print ++ print() + if expect_error and expect_error < 2: +- print 'Compilation failure expected, but none seen' +- print '------------ begin offending source ------------' +- print open(cpp).read() +- print '------------ end offending source ------------' ++ print('Compilation failure expected, but none seen') ++ print('------------ begin offending source ------------') ++ print(open(cpp).read()) ++ print('------------ end offending source ------------') + + if self.config.save_cpp: +- print 'saved in', repr(cpp) ++ print('saved in', repr(cpp)) + else: + self._remove_source(cpp) + + sys.stdout.flush() + else: +- print '.', ++ print('.', end=' ') + sys.stdout.flush() + built_handler(built_file) + +@@ -485,7 +486,7 @@ class CPlusPlusTranslator(litre.LitreTranslator): + self._unlink(built_file) + except: + if not expect_error: +- print 'failed to unlink', built_file ++ print('failed to unlink', built_file) + + return status + +@@ -514,7 +515,7 @@ class CPlusPlusTranslator(litre.LitreTranslator): + if not id: + id = 'top-level' + +- if not self.examples.has_key(self.example.section): ++ if self.example.section not in self.examples: + self.examples[id] = [(rule, source)] + else: + self.examples[id].append((rule, source)) +@@ -535,23 +536,23 @@ import testing ; + + ''') + +- for id,examples in self.examples.items(): ++ for id,examples in list(self.examples.items()): + for i in range(len(examples)): + cpp = '%s%d.cpp' % (id, i) + + jam.write('%s %s ;\n' % (examples[i][0], cpp)) + + outfile = os.path.join(self.config.dump_dir, cpp) +- print cpp, ++ print(cpp, end=' ') + try: + if open(outfile, 'r').read() == examples[i][1]: +- print ' .. skip' ++ print(' .. skip') + continue + except: + pass + + open(outfile, 'w').write(examples[i][1]) +- print ' .. written' ++ print(' .. written') + + jam.close() + +@@ -605,18 +606,18 @@ import testing ; + status, output = syscmd(cmd, expect_error) + + if status or expect_error > 1: +- print ++ print() + if expect_error and expect_error < 2: +- print 'Compilation failure expected, but none seen' +- print '------------ begin offending source ------------' +- print open(cpp).read() +- print '------------ begin offending Jamfile -----------' +- print open(os.path.join(dir, 'Jamroot')).read() +- print '------------ end offending Jamfile -------------' ++ print('Compilation failure expected, but none seen') ++ print('------------ begin offending source ------------') ++ print(open(cpp).read()) ++ print('------------ begin offending Jamfile -----------') ++ print(open(os.path.join(dir, 'Jamroot')).read()) ++ print('------------ end offending Jamfile -------------') + + sys.stdout.flush() + else: +- print '.', ++ print('.', end=' ') + sys.stdout.flush() + + if status: return None +@@ -665,7 +666,7 @@ use-project /boost : $(BOOST_ROOT) ; + if isinstance(module_path, BuildResult) or type(module_path) == str: + module_path = [module_path] + +- module_path = map(lambda p: str(p), module_path) ++ module_path = [str(p) for p in module_path] + + source = '\n'.join( + self.prefix +@@ -696,16 +697,16 @@ use-project /boost : $(BOOST_ROOT) ; + status, output = syscmd('python %s' % py) + + if status or expect_error > 1: +- print ++ print() + if expect_error and expect_error < 2: +- print 'Compilation failure expected, but none seen' +- print '------------ begin offending source ------------' +- print open(py).read() +- print '------------ end offending Jamfile -------------' ++ print('Compilation failure expected, but none seen') ++ print('------------ begin offending source ------------') ++ print(open(py).read()) ++ print('------------ end offending Jamfile -------------') + + sys.stdout.flush() + else: +- print '.', ++ print('.', end=' ') + sys.stdout.flush() + + self.last_run_output = output +@@ -751,7 +752,7 @@ use-project /boost : $(BOOST_ROOT) ; + return "" + return '\n\n ---------------- Unhandled Fragment ------------ \n\n'.join( + [''] # generates a leading announcement +- + [ unicode(s) for s in self.stack] ++ + [ str(s) for s in self.stack] + ) + + class DumpTranslator(CPlusPlusTranslator): +diff --git a/tools/litre/litre.py b/tools/litre/litre.py +index c0ac67e..b6d3c50 100644 +--- a/tools/litre/litre.py ++++ b/tools/litre/litre.py +@@ -16,7 +16,7 @@ class LitreTranslator(nodes.GenericNodeVisitor): + # print '**departing:', repr(node) + + def visit_raw(self, node): +- if node.has_key('format'): ++ if 'format' in node: + key = node['format'].lower() + if key == 'litre': + # This is probably very evil ;-) +@@ -38,9 +38,9 @@ class LitreTranslator(nodes.GenericNodeVisitor): + try: + self._execute(compile( start_line*'\n' + code, str(node.source), 'exec')) + except: +- print '\n------- begin offending Python source -------' +- print code +- print '------- end offending Python source -------' ++ print('\n------- begin offending Python source -------') ++ print(code) ++ print('------- end offending Python source -------') + raise + + def _execute(self, code): +diff --git a/tools/quickbook/test/python/run_tests.py b/tools/quickbook/test/python/run_tests.py +index 955f52c..c3f1208 100644 +--- a/tools/quickbook/test/python/run_tests.py ++++ b/tools/quickbook/test/python/run_tests.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/env python ++#!/usr/bin/env python3 + + # Copyright 2012-2013 Daniel James + # Distributed under the Boost Software License, Version 1.0. +@@ -8,7 +8,7 @@ import sys, os, subprocess, tempfile, re + + def main(args, directory): + if len(args) != 1: +- print "Usage: output-deps.py quickbook-command" ++ print("Usage: output-deps.py quickbook-command") + exit(1) + quickbook_command = args[0] + +@@ -47,9 +47,9 @@ def main(args, directory): + output_gold = 'simple_custom_pretty_print.xml') + + if failures == 0: +- print "Success" ++ print("Success") + else: +- print "Failures:",failures ++ print("Failures:",failures) + exit(failures) + + def run_quickbook(quickbook_command, filename, output_gold = None, +@@ -81,10 +81,10 @@ def run_quickbook(quickbook_command, filename, output_gold = None, + command.extend(extra_flags) + + try: +- print 'Running: ' + ' '.join(command) +- print ++ print('Running: ' + ' '.join(command)) ++ print() + exit_code = subprocess.call(command) +- print ++ print() + success = not exit_code + + if output_filename: +@@ -109,30 +109,30 @@ def run_quickbook(quickbook_command, filename, output_gold = None, + gold = load_dependencies(deps_gold) + if deps != gold: + failures = failures + 1 +- print "Dependencies don't match:" +- print "Gold:", gold +- print "Result:", deps +- print ++ print("Dependencies don't match:") ++ print("Gold:", gold) ++ print("Result:", deps) ++ print() + + if locations_gold: + gold = load_locations(locations_gold) + if locations != gold: + failures = failures + 1 +- print "Dependencies don't match:" +- print "Gold:", gold +- print "Result:", locations +- print ++ print("Dependencies don't match:") ++ print("Gold:", gold) ++ print("Result:", locations) ++ print() + + if output_gold: + gold = load_file(output_gold) + if gold != output: + failures = failures + 1 +- print "Output doesn't match:" +- print +- print gold +- print +- print output +- print ++ print("Output doesn't match:") ++ print() ++ print(gold) ++ print() ++ print(output) ++ print() + + return failures + +diff --git a/tools/quickbook/test/stub.py b/tools/quickbook/test/stub.py +index 48ba87e..5148474 100644 +--- a/tools/quickbook/test/stub.py ++++ b/tools/quickbook/test/stub.py +@@ -24,4 +24,4 @@ def foo(): + + #] + +-print foo() +\ No newline at end of file ++print(foo()) +\ No newline at end of file +-- +1.8.3.1 + -- Gitee