[SCons] Only build the Python package for Python 3.x

This commit is contained in:
Ray Speth 2018-09-09 22:19:34 -04:00
parent dcb7f34b4a
commit d6da006e3e
15 changed files with 294 additions and 565 deletions

View file

@ -65,10 +65,8 @@ if 'clean' in COMMAND_LINE_TARGETS:
removeDirectory('include/cantera/ext')
removeFile('interfaces/cython/cantera/_cantera.cpp')
removeFile('interfaces/cython/cantera/_cantera.h')
removeFile('interfaces/cython/setup2.py')
removeFile('interfaces/cython/setup3.py')
removeFile('interfaces/python_minimal/setup2.py')
removeFile('interfaces/python_minimal/setup3.py')
removeFile('interfaces/cython/setup.py')
removeFile('interfaces/python_minimal/setup.py')
removeFile('config.log')
removeDirectory('doc/sphinx/matlab/examples')
removeFile('doc/sphinx/matlab/examples.rst')
@ -348,7 +346,7 @@ config_options = [
sys.executable),
PathVariable(
'python_prefix',
"""Use this option if you want to install the Cantera Python 2 package to
"""Use this option if you want to install the Cantera Python package to
an alternate location. On Unix-like systems, the default is the same
as the 'prefix' option. If the 'python_prefix' option is set to
the empty string or the 'prefix' option is not set, then the package
@ -356,53 +354,20 @@ config_options = [
To install to the current user's 'site-packages' directory, use
'python_prefix=USER'.""",
defaults.python_prefix, PathVariable.PathAccept),
EnumVariable(
'python2_package',
"""Controls whether or not the Python 2 module will be built. By
default, the module will be built if the Python 2 interpreter
and the required dependencies (NumPy for Python 2 and Cython
for the version of Python for which SCons is installed) can be
found.""",
'default', ('full', 'minimal', 'y', 'n', 'none', 'default')),
PathVariable(
'python2_cmd',
"""The path to the Python 2 interpreter. The default is
'python2'; if this executable cannot be found, this
value must be specified to build the Python 2 module.""",
'python2', PathVariable.PathAccept),
PathVariable(
'python2_prefix',
"""Use this option if you want to install the Cantera Python 2 package to
an alternate location. On Unix-like systems, the default is the same
as the 'prefix' option. If the 'python_prefix' option is set to
the empty string or the 'prefix' option is not set, then the package
will be installed to the system default 'site-packages' directory.
To install to the current user's 'site-packages' directory, use
'python2_prefix=USER'.""",
defaults.python_prefix, PathVariable.PathAccept),
EnumVariable(
'python3_package',
"""Controls whether or not the Python 3 module will be built. By
default, the module will be built if the Python 3 interpreter
and the required dependencies (NumPy for Python 3 and Cython
for the version of Python for which SCons is installed) can be
found.""",
"""Deprecated synonym for the 'python_package' option. Will be overridden
if 'python_package' is set.""",
'default', ('full', 'minimal', 'y', 'n', 'none', 'default')),
PathVariable(
'python3_cmd',
"""The path to the Python 3 interpreter. The default is
'python3'; if this executable cannot be found, this
value must be specified to build the Python 3 module.""",
'python3', PathVariable.PathAccept),
"""Deprecated synonym for the 'python_cmd' option. Will be overridden
if 'python_cmd' is set.""",
sys.executable, PathVariable.PathAccept),
PathVariable(
'python3_prefix',
"""Use this option if you want to install the Cantera Python 3 package to
an alternate location. On Unix-like systems, the default is the same
as the 'prefix' option. If the 'python_prefix' option is set to
the empty string or the 'prefix' option is not set, then the package
will be installed to the system default 'site-packages' directory.
To install to the current user's 'site-packages' directory, use
'python3_prefix=USER'.""",
"""Deprecated synonym for the 'python_prefix' option. Will be overridden
if 'python_prefix' is set.""",
defaults.python_prefix, PathVariable.PathAccept),
EnumVariable(
'matlab_toolbox',
@ -1148,13 +1113,19 @@ env['python_cmd_esc'] = quoted(env['python_cmd'])
cython_min_version = LooseVersion('0.23')
numpy_min_test_version = LooseVersion('1.8.1')
# If both python2_package and python3_package are set to something
# other than the default ignore the python_package option
if all([env['python{}_package'.format(p)] != 'default' for p in ['2', '3']]):
if env['python_package'] != 'default':
print("WARNING: Both version-specific pythonX_package options are set. Ignoring "
"non-version specific python_package options")
env['python_package'] = 'none'
# Handle the version-specific Python package options
python_options = (('package', 'default'),
('cmd', sys.executable),
('prefix', defaults.python_prefix))
for option, default in python_options:
if env['python3_' + option] != default:
print("WARNING: Option 'python3_{0}' is deprecated."
" Use 'python_{0}' instead.".format(option))
if env['python_' + option] == default:
env['python_' + option] = env['python3_' + option]
else:
print("WARNING: Ignoring option 'python3_{0}'"
" because 'python_{0}' was also set.".format(option))
if env['python_package'] == 'new':
print("WARNING: The 'new' option for the Python package is "
@ -1163,73 +1134,13 @@ if env['python_package'] == 'new':
env['python_package'] = 'full' # Allow 'new' as a synonym for 'full'
elif env['python_package'] == 'y':
env['python_package'] = 'full' # Allow 'y' as a synonym for 'full'
elif env['python_package'] in ['none', 'n']:
if env['python2_package'] == 'default':
env['python2_package'] = 'none'
if env['python3_package'] == 'default':
env['python3_package'] = 'none'
elif env['python_package'] == 'n':
env['python_package'] = 'none' # Allow 'n' as a synonym for 'none'
for py_pkg in ['python2_package', 'python3_package']:
if env[py_pkg] == 'y':
env[py_pkg] = 'full' # Allow 'y' as a synonym for 'full'
elif env[py_pkg] == 'n':
env[py_pkg] = 'none' # Allow 'n' as a synonym for 'none'
env['install_python_action'] = ''
env['python_module_loc'] = ''
if env['python_package'] in ('full', 'minimal', 'default'):
# If the non-specific python_package option is not none, check
# the version of the Python package we want to build using
# python_cmd
script = '\n'.join(["from __future__ import print_function",
"import sys",
"print('{v.major}.{v.minor}'.format(v=sys.version_info))"])
try:
env['python_version'] = getCommandOutput(env['python_cmd'], '-c', script)
except (OSError, subprocess.CalledProcessError) as err:
if env['python_package'] in ['full', 'minimal']:
print('ERROR: Problem checking for Python:')
print(err)
sys.exit(1)
else:
print('WARNING: Problem checking for Python:')
print(err)
print('Continuing with default parameters.')
else:
major = env['python_version'][0]
py_pkg = 'python{}_package'.format(major)
if env[py_pkg] != 'default':
if env['python_package'] != 'default':
# If python_package is default don't print a warning. If python_package has been
# set, warn the user that we're ignoring that option.
print("WARNING: The python{v}_package option has been set to {option}. All "
"non-version-specific Python options (including python_cmd) have been "
"ignored.".format(v=major, option=env[py_pkg]))
else: # pythonX_package is 'default'
# This dictionary has the default values for the Python related variables
default_py_vars = {'python{}_cmd': 'python{}'.format(major),
'python{}_prefix': '$prefix'}
env[py_pkg] = env['python_package']
# Check whether any Python related variables are different from the default
for key, value in default_py_vars.items():
if env[key.format(major)] != value:
print("WARNING: The value for {0} has been set and will be used instead "
"of {1}".format(key.format(major), key.format('')))
else:
env[key.format(major)] = env[key.format('')]
del env['python_version']
# Make sure everything gets converted to properly versioned variables by deleting
# these so they don't get used accidentally
del env['python_package']
del env['python_cmd']
del env['python_prefix']
require_python = any([env['python{}_package'.format(p)] == 'full' for p in ['2', '3']])
want_python = any([env['python{}_package'.format(p)] == 'default' for p in ['2', '3']])
if require_python or want_python:
if env['python_package'] in ('full', 'default'):
# Check for Cython:
try:
import Cython
@ -1247,63 +1158,18 @@ if require_python or want_python:
have_cython = True
finally:
if not have_cython:
if require_python:
if env['python_package'] == 'full':
print('ERROR: ' + message)
sys.exit(1)
elif want_python:
elif env['python_package'] == 'default':
print('WARNING: ' + message)
for py_pkg in ['python{}_package'.format(p) for p in ['2', '3']]:
if env[py_pkg] == 'default':
env[py_pkg] = 'minimal-default'
env['python_package'] = 'minimal'
else:
print('INFO: Using Cython version {0}.'.format(cython_version))
def configure_minimal_python(py_ver):
# Test to see if we can run Python if the minimal interface is to be built
warn_no_python = False
script = textwrap.dedent("""\
from __future__ import print_function
import sys
print('{v.major}.{v.minor}'.format(v=sys.version_info))
""")
try:
info = getCommandOutput(env['python{}_cmd'.format(py_ver)], '-c', script)
except OSError as err:
if env['VERBOSE']:
print('Error checking for Python {}:'.format(py_ver))
print(err)
warn_no_python = True
except subprocess.CalledProcessError as err:
if env['VERBOSE']:
print('Error checking for Python {}:'.format(py_ver))
print(err, err.output)
warn_no_python = True
else:
(env['python{}_version'.format(py_ver)],) = info.splitlines()[-1:]
if warn_no_python:
if 'default' in env['python{}_package'.format(py_ver)]:
print('WARNING: Not building the minimal Python {py_ver} package because the Python '
'{py_ver} interpreter {interp!r} could not be '
'found.'.format(py_ver=py_ver, interp=env['python{}_cmd'.format(py_ver)]))
env['python{}_package'.format(py_ver)] = 'none'
else:
print('ERROR: Could not execute the Python {py_ver} interpreter {interp!r}.'.format(
py_ver=py_ver, interp=env['python{}_cmd'.format(py_ver)]
))
sys.exit(1)
else:
print('INFO: Building the minimal Python package for Python {0}'.format(env['python{}_version'.format(py_ver)]))
env['python{}_package'.format(py_ver)] = 'minimal'
def configure_full_python(py_ver):
# Test to see if we can import numpy
warn_no_python = False
script = textwrap.dedent("""\
from __future__ import print_function
import sys
print('{v.major}.{v.minor}'.format(v=sys.version_info))
try:
@ -1315,106 +1181,91 @@ def configure_full_python(py_ver):
""")
try:
info = getCommandOutput(env['python{}_cmd'.format(py_ver)], '-c', script).splitlines()
info = getCommandOutput(env['python_cmd'], '-c', script).splitlines()
except OSError as err:
if env['VERBOSE']:
print('Error checking for Python {}:'.format(py_ver))
print('Error checking for Python:')
print(err)
warn_no_python = True
except subprocess.CalledProcessError as err:
if env['VERBOSE']:
print('Error checking for Python {}:'.format(py_ver))
print('Error checking for Python:')
print(err, err.output)
warn_no_python = True
else:
env['python{}_version'.format(py_ver)] = info[0]
env['python_version'] = info[0]
numpy_version = LooseVersion(info[1])
if len(info) > 2:
print("WARNING: Unexpected output while checking Python & Numpy versions:")
print('| ' + '\n|'.join(info[2:]))
if numpy_version == LooseVersion('0.0.0'):
print("NumPy for Python {0} not found.".format(env['python{}_version'.format(py_ver)]))
print("NumPy not found.")
warn_no_python = True
elif numpy_version < numpy_min_test_version:
print("WARNING: The installed version of Numpy for Python {0} is not tested and "
"support is not guaranteed. Found {1} but {2} or newer is preferred".format(
env['python{}_version'.format(py_ver)], numpy_version, numpy_min_test_version))
print("WARNING: The installed version of Numpy is not tested and "
"support is not guaranteed. Found {0} but {1} or newer is preferred".format(
numpy_version, numpy_min_test_version))
else:
print('INFO: Using NumPy version {0} for Python {1}.'.format(
numpy_version, env['python{}_version'.format(py_ver)]))
print('INFO: Using NumPy version {0}.'.format(numpy_version))
if warn_no_python:
if env['python{}_package'.format(py_ver)] == 'default':
print('WARNING: Not building the full Python {py_ver} package because the Python '
'{py_ver} interpreter {interp!r} could not be found or a required dependency '
'(e.g. numpy) was not found.'.format(py_ver=py_ver, interp=env['python{}_cmd'.format(py_ver)]))
if env['python_package'] == 'default':
print('WARNING: Not building the full Python package because the Python '
'interpreter {!r} could not be found or a required dependency '
'(e.g. numpy) was not found.'.format(env['python_cmd']))
env['python{}_package'.format(py_ver)] = 'minimal-default'
env['python_package'] = 'minimal-default'
else:
print('ERROR: Could not execute the Python {py_ver} interpreter {interp!r} or a required '
'dependency (e.g. numpy) could not be found.'.format(py_ver=py_ver, interp=env['python{}_cmd'.format(py_ver)]))
print('ERROR: Could not execute the Python interpreter {!r} or a required '
'dependency (e.g. numpy) could not be found.'.format(env['python_cmd']))
sys.exit(1)
else:
print('INFO: Building the full Python package for Python {0}'.format(env['python{}_version'.format(py_ver)]))
env['python{}_package'.format(py_ver)] = 'full'
print('INFO: Building the full Python package for Python {0}'.format(env['python_version']))
env['python_package'] = 'full'
for py_ver in [2, 3]:
env['install_python{}_action'.format(py_ver)] = ''
if env['python{}_package'.format(py_ver)] in ['full', 'default']:
configure_full_python(py_ver)
elif env['python{}_package'.format(py_ver)] == 'minimal':
configure_minimal_python(py_ver)
env['python{}_module_loc'.format(py_ver)] = ''
else:
env['python{}_module_loc'.format(py_ver)] = ''
# If we're building the full Python interface for one version of Python,
# we probably don't want the minimal interface of the other version
if env['python2_package'] == 'minimal-default' and env['python3_package'] == 'full':
env['python2_package'] = 'none'
elif env['python3_package'] == 'minimal-default' and env['python2_package'] == 'full':
env['python3_package'] = 'none'
# 'minimal-default' means that something was wrong with Python or NumPy
# such that the full interface for that version of Python can't be built
# and the pythonX_package option wasn't supplied by the user. Check to see
# if the minimal package should be built
if env['python2_package'] == 'minimal-default':
configure_minimal_python(2)
if env['python3_package'] == 'minimal-default':
configure_minimal_python(3)
for py_ver in [2, 3]:
if env['python{}_package'.format(py_ver)] != 'none':
# The directory within the source tree which will contain the Python module
env['pythonpath_build{}'.format(py_ver)] = Dir('build/python{}'.format(py_ver)).abspath
if 'PYTHONPATH' in env['ENV']:
env['pythonpath_build{}'.format(py_ver)] += os.path.pathsep + env['ENV']['PYTHONPATH']
# Check for 3to2. See http://pypi.python.org/pypi/3to2
# Only needed for Python 2 package
if env['python2_package'] == 'full':
if env['python_package'] in ('minimal', 'minimal-default'):
# Test to see if we can run Python if the minimal interface is to be built
warn_no_python = False
script = textwrap.dedent("""\
from lib3to2.main import main
print(main('lib3to2.fixes', ['-l']))
import sys
print('{v.major}.{v.minor}'.format(v=sys.version_info))
""")
try:
ret = getCommandOutput(env['python2_cmd'], '-c', script)
except (OSError, subprocess.CalledProcessError) as err:
info = getCommandOutput(env['python_cmd'], '-c', script)
except OSError as err:
if env['VERBOSE']:
print('Error checking for 3to2:')
print('Error checking for Python:')
print(err)
ret = ''
if 'print' in ret:
env['python_convert_examples'] = True
warn_no_python = True
except subprocess.CalledProcessError as err:
if env['VERBOSE']:
print('Error checking for Python:')
print(err, err.output)
warn_no_python = True
else:
env['python_convert_examples'] = False
print("WARNING: Couldn't find the 3to2 package. "
"Python 2 examples will not work correctly.")
(env['python_version'],) = info.splitlines()[-1:]
if warn_no_python:
if env['python_package'] == 'minimal-default':
print('WARNING: Not building the minimal Python package because the Python '
'interpreter {!r} could not be found.'.format(env['python_cmd']))
env['python_package'] = 'none'
else:
env['python_convert_examples'] = False
print('ERROR: Could not execute the Python interpreter {!r}.'.format(env['python_cmd']))
sys.exit(1)
else:
print('INFO: Building the minimal Python package for Python {0}'.format(env['python_version']))
env['python_package'] = 'minimal'
if env['python_package'] != 'none':
# The directory within the source tree which will contain the Python module
env['pythonpath_build'] = Dir('build/python').abspath
if 'PYTHONPATH' in env['ENV']:
env['pythonpath_build'] += os.path.pathsep + env['ENV']['PYTHONPATH']
# Matlab Toolbox settings
if env['matlab_path'] != '' and env['matlab_toolbox'] == 'default':
@ -1506,12 +1357,11 @@ addInstallActions = ('install' in COMMAND_LINE_TARGETS or
if env['stage_dir']:
instRoot = pjoin(os.getcwd(), env['stage_dir'],
stripDrive(env['prefix']).strip('/\\'))
for k in ('python2_prefix', 'python3_prefix'):
if env[k]:
env[k] = pjoin(os.getcwd(), env['stage_dir'],
stripDrive(env[k]).strip('/\\'))
if env['python_prefix']:
env['python_prefix'] = pjoin(os.getcwd(), env['stage_dir'],
stripDrive(env['python_prefix']).strip('/\\'))
else:
env[k] = pjoin(os.getcwd(), env['stage_dir'])
env['python_prefix'] = pjoin(os.getcwd(), env['stage_dir'])
else:
instRoot = env['prefix']
@ -1532,8 +1382,7 @@ if env['layout'] == 'debian':
env['libdirname'], 'cantera', 'matlab', 'toolbox')
env['inst_python_bindir'] = pjoin(base, 'cantera-python', 'usr', 'bin')
env['python2_prefix'] = pjoin(base, 'cantera-python')
env['python3_prefix'] = pjoin(base, 'cantera-python3')
env['python_prefix'] = pjoin(base, 'cantera-python3')
else:
env['inst_libdir'] = pjoin(instRoot, env['libdirname'])
env['inst_bindir'] = pjoin(instRoot, 'bin')
@ -1720,10 +1569,9 @@ if env['f90_interface'] == 'y':
VariantDir('build/src', 'src', duplicate=0)
SConscript('build/src/SConscript')
if env['python3_package'] == 'full' or env['python2_package'] == 'full':
if env['python_package'] == 'full':
SConscript('interfaces/cython/SConscript')
if env['python3_package'] == 'minimal' or env['python2_package'] == 'minimal':
elif env['python_package'] == 'minimal':
SConscript('interfaces/python_minimal/SConscript')
if env['CC'] != 'cl':
@ -1794,17 +1642,11 @@ def postInstallMessage(target, source, env):
samples {ct_sampledir!s}
data files {ct_datadir!s}""".format(**env_dict))
if env['python2_package'] == 'full':
env['python2_example_loc'] = pjoin(env['python2_module_loc'], 'cantera', 'examples')
if env['python_package'] == 'full':
env['python_example_loc'] = pjoin(env['python_module_loc'], 'cantera', 'examples')
install_message += indent(textwrap.dedent("""
Python 2 package (cantera) {python2_module_loc!s}
Python 2 samples {python2_example_loc!s}""".format(**env_dict)), ' ')
if env['python3_package'] == 'full':
env['python3_example_loc'] = pjoin(env['python3_module_loc'], 'cantera', 'examples')
install_message += indent(textwrap.dedent("""
Python 3 package (cantera) {python3_module_loc!s}
Python 3 samples {python3_example_loc!s}""".format(**env_dict)), ' ')
Python package (cantera) {python_module_loc!s}
Python samples {python_example_loc!s}""".format(**env_dict)), ' ')
if env['matlab_toolbox'] == 'y':
env['matlab_sample_loc'] = pjoin(env['ct_sampledir'], 'matlab')
@ -1856,13 +1698,9 @@ def getParentDirs(path, top=True):
# Files installed by SCons
allfiles = FindInstalledFiles()
# Files installed by the Python installer(s)
pyFiles = ['build/python2-installed-files.txt',
'build/python3-installed-files.txt']
for filename in pyFiles:
if os.path.exists(filename):
with open(filename, 'r') as f:
# Files installed by the Python installer
if os.path.exists('build/python-installed-files.txt'):
with open('build/python-installed-files.txt', 'r') as f:
file_list = f.readlines()
install_base = os.path.dirname(file_list[0].strip())
@ -1928,7 +1766,7 @@ if any(target.startswith('test') for target in COMMAND_LINE_TARGETS):
env['testNames'] = []
env['test_results'] = env.Command('test_results', [], testResults.printReport)
if env['python2_package'] == 'none' and env['python3_package'] == 'none':
if env['python_package'] == 'none':
# copy scripts from the full Cython module
test_py_int = env.Command('#build/python_minimal/cantera/__init__.py',
'#interfaces/python_minimal/cantera/__init__.py',

View file

@ -16,10 +16,7 @@ import sys, os, re
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
if sys.version_info[0] == 3:
sys.path.insert(0, os.path.abspath('../../build/python3'))
else:
sys.path.insert(0, os.path.abspath('../../build/python2'))
sys.path.insert(0, os.path.abspath('../../build/python'))
sys.path.append(os.path.abspath('.'))
sys.path.append(os.path.abspath('./exts'))
@ -99,9 +96,6 @@ release = re.search('CANTERA_VERSION "(.*?)"', configh).group(1)
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []
if sys.version_info[0] == 3:
exclude_patterns.append('python/*')
# The reST default role (used for this markup: `text`) to use for all documents.
default_role = 'py:obj'

View file

@ -7,8 +7,7 @@ cantera/test/data/*.xml
cantera/test/data/*.inp
cantera/test/data/*.dat
cantera/test/data/*.csv
setup2.py
setup3.py
setup.py
scripts/ctml_writer.py
scripts/ctml_writer
scripts/ck2cti.py

View file

@ -6,8 +6,32 @@ Import('env', 'build', 'install')
localenv = env.Clone()
def cythonize(target, source, env):
Cython.Build.cythonize([f.abspath for f in source])
def configure_python(env, python_command):
cythonized = localenv.Command('cantera/_cantera.cpp', ['cantera/_cantera.pyx'],
cythonize)
for f in mglob(localenv, 'cantera', 'pyx', 'pxd'):
localenv.Depends(cythonized, f)
for line in open('cantera/_cantera.pxd'):
m = re.search(r'from "(cantera.*?)"', line)
if m:
localenv.Depends('cantera/_cantera.cpp', '#include/' + m.group(1))
dataFiles = localenv.RecursiveInstall('#interfaces/cython/cantera/data',
'#build/data')
build(dataFiles)
testFiles = localenv.RecursiveInstall('#interfaces/cython/cantera/test/data',
'#test/data')
build(testFiles)
for f in ['inputs/h2o2.inp', 'inputs/gri30.inp', 'transport/gri30_tran.dat']:
inp = build(localenv.Install('#interfaces/cython/cantera/test/data/', '#data/' + f))
testFiles.append(inp)
# Get information needed to build the Python module
script = '\n'.join(("from distutils.sysconfig import *",
"import numpy",
"print(get_config_var('EXT_SUFFIX') or get_config_var('SO'))",
@ -16,27 +40,39 @@ def configure_python(env, python_command):
"print(get_config_var('prefix'))",
"print(get_python_version())",
"print(numpy.get_include())"))
info = getCommandOutput(python_command, '-c', script)
info = getCommandOutput(localenv['python_cmd'], '-c', script)
module_ext, inc, pylib, prefix, py_version, numpy_include = info.splitlines()[-6:]
env.Prepend(CPPPATH=[Dir('#include'), inc, numpy_include])
env.Prepend(LIBS=env['cantera_libs'])
if env['OS'] == 'Darwin':
env.Append(LINKFLAGS='-undefined dynamic_lookup')
elif env['OS'] == 'Windows':
env.Append(LIBPATH=prefix+'/libs')
if env['toolchain'] == 'mingw':
env.Append(LIBS='python%s' % py_version.replace('.',''))
if env['OS_BITS'] == 64:
env.Append(CPPDEFINES='MS_WIN64')
localenv.Prepend(CPPPATH=[Dir('#include'), inc, numpy_include])
localenv.Prepend(LIBS=localenv['cantera_libs'])
if localenv['OS'] == 'Darwin':
localenv.Append(LINKFLAGS='-undefined dynamic_lookup')
elif localenv['OS'] == 'Windows':
localenv.Append(LIBPATH=prefix+'/libs')
if localenv['toolchain'] == 'mingw':
localenv.Append(LIBS='python{}'.format(py_version.replace('.','')))
if localenv['OS_BITS'] == 64:
localenv.Append(CPPDEFINES='MS_WIN64')
# fix for http://bugs.python.org/issue11566
env.Append(CPPDEFINES={'_hypot':'hypot'})
elif env['OS'] == 'Cygwin':
localenv.Append(CPPDEFINES={'_hypot':'hypot'})
elif localenv['OS'] == 'Cygwin':
# extract 'pythonX.Y' from 'libpythonX.Y.dll.a'
env.Append(LIBS=pylib[3:-6])
return module_ext, py_version
localenv.Append(LIBS=pylib[3:-6])
# Build the Python module
obj = localenv.SharedObject('#build/temp-py/_cantera', 'cantera/_cantera.cpp')
ext = localenv.LoadableModule('#build/python/cantera/_cantera{}'.format(module_ext),
obj, LIBPREFIX='', SHLIBSUFFIX=module_ext,
SHLIBPREFIX='', LIBSUFFIXES=[module_ext])
localenv['py_extension'] = ext[0].name
localenv.SubstFile('setup.py', 'setup.py.in')
build_cmd = ('cd interfaces/cython &&'
' $python_cmd_esc setup.py build --build-lib=../../build/python')
mod = build(localenv.Command('#build/python/cantera/__init__.py', 'setup.py',
build_cmd))
env['python_module'] = mod
env['python_extension'] = ext
def add_dependencies(mod, ext):
localenv.Depends(mod, ext)
localenv.Depends(mod, dataFiles + testFiles)
localenv.Depends(ext, localenv['cantera_staticlib'])
@ -53,146 +89,55 @@ def add_dependencies(mod, ext):
mglob(localenv, 'cantera/examples/misc', 'py')):
localenv.Depends(mod, f)
def cythonize(target, source, env):
Cython.Build.cythonize([f.abspath for f in source])
cythonized = localenv.Command('cantera/_cantera.cpp', ['cantera/_cantera.pyx'],
cythonize)
for f in mglob(localenv, 'cantera', 'pyx', 'pxd'):
localenv.Depends(cythonized, f)
for line in open('cantera/_cantera.pxd'):
m = re.search(r'from "(cantera.*?)"', line)
if m:
localenv.Depends('cantera/_cantera.cpp', '#include/' + m.group(1))
def install_module(prefix, python_version):
major = python_version[0]
minor = python_version.split('.')[1]
dummy = 'dummy' + major
if prefix == 'USER':
# Determine installation path and install the Python module
if localenv['python_prefix'] == 'USER':
# Install to the OS-dependent user site-packages directory
extra = '--user'
if localenv['OS'] == 'Darwin':
extra += ' --prefix=""'
elif prefix:
elif localenv['python_prefix']:
# A specific location for the Cantera python module has been given
if localenv['debian'] and localenv.subst(prefix) == '/usr/local':
if localenv['debian'] and localenv.subst('${python_prefix}') == '/usr/local':
# Installation to /usr/local is the default on Debian-based distributions
extra = ''
elif localenv['OS'] == 'Darwin':
extra = localenv.subst(' --prefix=${python%s_prefix}' % major)
extra = localenv.subst(' --prefix=${python_prefix}')
elif localenv['libdirname'] == 'lib64':
# 64-bit RHEL / Fedora
extra = localenv.subst(
' --prefix=${python%s_prefix} --install-lib=${python%s_prefix}/lib64/python%s.%s/site-packages' % (major, major, major, minor))
' --prefix=${python_prefix}'
' --install-lib=${python_prefix}/lib64/python{}/site-packages'.format(py_version))
else:
extra = '--user'
localenv.AppendENVPath(
'PYTHONUSERBASE',
normpath(localenv.subst('$python%s_prefix' % major)))
normpath(localenv.subst('$python_prefix')))
else:
# Install Python module in the default location
extra = ''
env['python%s_module_loc' % major] = '<unspecified>'
env['python_module_loc'] = '<unspecified>'
if localenv['PYTHON_INSTALLER'] == 'direct':
mod_inst = install(localenv.Command, dummy, mod,
build_cmd + ' install %s' % extra +
' --record=../../build/python%s-installed-files.txt' % major +
mod_inst = install(localenv.Command, 'dummy', mod,
build_cmd + ' install ' + extra +
' --record=../../build/python-installed-files.txt' +
' --single-version-externally-managed')
global_env = env
def find_module_dir(target, source, env):
check = pjoin('cantera', '__init__.py')
for filename in open('build/python%s-installed-files.txt' % major).readlines():
for filename in open('build/python-installed-files.txt').readlines():
filename = filename.strip()
if filename.endswith(check):
filename = filename.replace(check, '')
global_env['python%s_module_loc' % major] = normpath(filename)
global_env['python_module_loc'] = normpath(filename)
break
localenv.AlwaysBuild(localenv.AddPostAction(mod_inst, find_module_dir))
env['install_python{}_action'.format(major)] = mod_inst
env['install_python_action'] = mod_inst
elif localenv['PYTHON_INSTALLER'] == 'debian':
extra = localenv.subst(' --root=${python%s_prefix}' % major)
install(localenv.Command, dummy, mod,
build_cmd + ' install --install-layout=deb --no-compile %s' % extra)
extra = localenv.subst(' --root=${python_prefix}')
install(localenv.Command, 'dummy', mod,
build_cmd + ' install --install-layout=deb --no-compile ' + extra)
elif localenv['PYTHON_INSTALLER'] == 'binary':
install(localenv.Command, dummy, mod,
install(localenv.Command, 'dummy', mod,
build_cmd + ' bdist_msi --dist-dir=../..' +
' --target-version=%s' % python_version)
dataFiles = localenv.RecursiveInstall('#interfaces/cython/cantera/data',
'#build/data')
build(dataFiles)
testFiles = localenv.RecursiveInstall('#interfaces/cython/cantera/test/data',
'#test/data')
build(testFiles)
for f in ['inputs/h2o2.inp', 'inputs/gri30.inp', 'transport/gri30_tran.dat']:
inp = build(localenv.Install('#interfaces/cython/cantera/test/data/', '#data/' + f))
testFiles.append(inp)
# Cython module for Python 3.x
if localenv['python3_package'] == 'full':
localenv['python3_cmd_esc'] = quoted(localenv['python3_cmd'])
py3env = localenv.Clone()
module_ext, py3_version = configure_python(py3env, py3env['python3_cmd'])
obj = py3env.SharedObject('#build/temp-py/_cantera3', 'cantera/_cantera.cpp')
ext = py3env.LoadableModule('#build/python3/cantera/_cantera%s' % module_ext,
obj, LIBPREFIX='', SHLIBSUFFIX=module_ext,
SHLIBPREFIX='', LIBSUFFIXES=[module_ext])
py3env['py_extension'] = ext[0].name
py3env.SubstFile('setup3.py', 'setup.py.in')
build_cmd = ('cd interfaces/cython &&'
' $python3_cmd_esc setup3.py build --build-lib=../../build/python3')
mod = build(py3env.Command('#build/python3/cantera/__init__.py', 'setup3.py',
build_cmd))
env['python3_module'] = mod
env['python3_extension'] = ext
add_dependencies(mod, ext)
install_module(py3env['python3_prefix'], py3_version)
# Cython module for Python 2.x
if localenv['python2_package'] == 'full':
localenv['python2_cmd_esc'] = quoted(localenv['python2_cmd'])
py2env = localenv.Clone()
module_ext, py2_version = configure_python(py2env, py2env['python2_cmd'])
obj = py2env.SharedObject('#build/temp-py/_cantera2', 'cantera/_cantera.cpp')
ext = py2env.LoadableModule('#build/python2/cantera/_cantera%s' % module_ext,
obj, LIBPREFIX='', SHLIBSUFFIX=module_ext,
SHLIBPREFIX='', LIBSUFFIXES=[module_ext])
py2env['py_extension'] = ext[0].name
py2env.SubstFile('setup2.py', 'setup.py.in')
build_cmd = ('cd interfaces/cython &&'
' $python2_cmd_esc setup2.py build --build-lib=../../build/python2')
mod = build(py2env.Command('#build/python2/cantera/__init__.py',
'setup2.py',
build_cmd))
env['python2_module'] = mod
env['python2_extension'] = ext
# Use 3to2 to convert examples from Python 3 syntax
if env['python_convert_examples']:
a = build(py2env.Command('#build/python2/cantera/examples', 'cantera/examples',
Copy("$TARGET", "$SOURCE")))
# In these next few things, the double quotes are necessary
# so the command line is processed properly
threetotwo_options = ['--no-diff', '-n', '-w', '-x', 'str', '-x', 'print', '-x', 'open',
'-f', 'all', '-f', 'printfunction']
threetotwo_options = ', '.join(["'{}'"]*len(threetotwo_options)).format(*threetotwo_options)
ex_loc = "'build/python2/cantera/examples'"
convert_script = textwrap.dedent("""\
$python2_cmd_esc -c "from lib3to2.main import main; main('lib3to2.fixes', [{opts}, {loc}])"
""".format(opts=threetotwo_options, loc=ex_loc))
b = build(py2env.AddPostAction(a, convert_script))
py2env.Depends(mod, b)
add_dependencies(mod, ext)
install_module(py2env['python2_prefix'], py2_version)
' --target-version=' + py_version)

View file

@ -375,7 +375,7 @@ class TestFreeFlame(utilities.CanteraTest):
self.create_sim(p, Tin, reactants)
self.solve_fixed_T()
filename = pjoin(self.test_work_dir, 'onedim-fixed-T{0}.xml'.format(utilities.python_version))
filename = pjoin(self.test_work_dir, 'onedim-fixed-T.xml')
if os.path.exists(filename):
os.remove(filename)
@ -436,7 +436,7 @@ class TestFreeFlame(utilities.CanteraTest):
p = 2 * ct.one_atm
Tin = 400
filename = pjoin(self.test_work_dir, 'onedim-add-species{0}.xml'.format(utilities.python_version))
filename = pjoin(self.test_work_dir, 'onedim-add-species.xml')
if os.path.exists(filename):
os.remove(filename)
@ -464,7 +464,7 @@ class TestFreeFlame(utilities.CanteraTest):
p = 2 * ct.one_atm
Tin = 400
filename = pjoin(self.test_work_dir, 'onedim-add-species{0}.xml'.format(utilities.python_version))
filename = pjoin(self.test_work_dir, 'onedim-add-species.xml')
if os.path.exists(filename):
os.remove(filename)
@ -488,7 +488,7 @@ class TestFreeFlame(utilities.CanteraTest):
self.assertArrayNear(Y1[k1], Y2[k2])
def test_write_csv(self):
filename = pjoin(self.test_work_dir, 'onedim-write_csv{0}.csv'.format(utilities.python_version))
filename = pjoin(self.test_work_dir, 'onedim-write_csv.csv')
if os.path.exists(filename):
os.remove(filename)
@ -551,7 +551,7 @@ class TestFreeFlame(utilities.CanteraTest):
class TestDiffusionFlame(utilities.CanteraTest):
# Note: to re-create the reference file:
# (1) set PYTHONPATH to build/python2 or build/python3.
# (1) set PYTHONPATH to build/python.
# (2) Start Python in the test/work directory and run:
# >>> import cantera.test
# >>> t = cantera.test.test_onedim.TestDiffusionFlame("test_mixture_averaged")
@ -753,7 +753,7 @@ class TestDiffusionFlame(utilities.CanteraTest):
class TestCounterflowPremixedFlame(utilities.CanteraTest):
# Note: to re-create the reference file:
# (1) set PYTHONPATH to build/python2 or build/python3.
# (1) set PYTHONPATH to build/python.
# (2) Start Python in the test/work directory and run:
# >>> import cantera.test
# >>> t = cantera.test.test_onedim.TestCounterflowPremixedFlame("test_mixture_averaged")

View file

@ -1455,7 +1455,7 @@ class TestSolutionArray(utilities.CanteraTest):
states.TPX = np.linspace(300, 1000, 7), 2e5, 'H2:0.5, O2:0.4'
states.equilibrate('HP')
outfile = pjoin(self.test_work_dir, 'solutionarray{}.csv'.format(utilities.python_version))
outfile = pjoin(self.test_work_dir, 'solutionarray.csv')
states.write_csv(outfile)
data = np.genfromtxt(outfile, names=True, delimiter=',')

View file

@ -30,8 +30,7 @@ class CanteraTest(unittest.TestCase):
root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..', '..', '..', '..'))
if os.path.exists(os.path.join(root_dir, 'SConstruct')):
cls.test_work_dir = os.path.join(root_dir, 'test', 'work',
'python{}'.format(python_version))
cls.test_work_dir = os.path.join(root_dir, 'test', 'work', 'python')
try:
os.makedirs(cls.test_work_dir)
except OSError as e:

View file

@ -37,7 +37,7 @@ end
% Set path to Python module
if strcmp(getenv('PYTHONPATH'), '')
setenv('PYTHONPATH', fullfile(cantera_root, 'build', 'python2'))
setenv('PYTHONPATH', fullfile(cantera_root, 'build', 'python'))
end
% A simple test to make sure that the ctmethods.mex file is present and working

View file

@ -5,58 +5,53 @@ Import('env', 'build', 'install')
localenv = env.Clone()
for py_ver in [2, 3]:
if env['python{}_package'.format(py_ver)] == 'minimal':
make_setup = build(localenv.SubstFile('setup{}.py'.format(py_ver), 'setup.py.in'))
make_setup = build(localenv.SubstFile('setup.py', 'setup.py.in'))
# copy scripts from the full Cython module
for script in ['ctml_writer', 'ck2cti']:
# The actual script
s = build(env.Command('cantera/%s.py' % script,
'#interfaces/cython/cantera/%s.py' % script,
s = build(env.Command('cantera/{}.py'.format(script),
'#interfaces/cython/cantera/{}.py'.format(script),
Copy('$TARGET', '$SOURCE')))
localenv.Depends(make_setup, s)
localenv['python{}_cmd_esc'.format(py_ver)] = quoted(localenv['python{}_cmd'.format(py_ver)])
build_cmd = ('cd interfaces/python_minimal &&'
' $python{py_ver}_cmd_esc setup{py_ver}.py build --build-lib=../../build/python{py_ver}'.format(py_ver=py_ver))
' $python_cmd_esc setup.py build --build-lib=../../build/python')
mod = build(localenv.Command('#build/python{}/cantera/__init__.py'.format(py_ver),
'setup{}.py'.format(py_ver),
mod = build(localenv.Command('#build/python/cantera/__init__.py', 'setup.py',
build_cmd))
env['python{}_module'.format(py_ver)] = mod
env['python_module'] = mod
if localenv['PYTHON_INSTALLER'] == 'direct':
if localenv['python{}_prefix'.format(py_ver)] == 'USER':
if localenv['python_prefix'] == 'USER':
# Install to the OS-dependent user site-packages directory
extra = '--user'
if localenv['OS'] == 'Darwin':
extra += ' --prefix=""'
elif localenv['python{}_prefix'.format(py_ver)]:
elif localenv['python_prefix']:
# A specific location for the Cantera python module has been given
extra = '--user'
if localenv['OS'] == 'Darwin':
extra += ' --prefix=""'
localenv.AppendENVPath(
'PYTHONUSERBASE',
normpath(localenv.subst('$python{}_prefix'.format(py_ver)))
normpath(localenv.subst('$python_prefix'))
)
else:
# Install Python module in the default location
extra = ''
mod_inst = install(localenv.Command, 'dummy{}'.format(py_ver), mod,
build_cmd + ' install %s' % extra +
' --record=../../build/python{}-installed-files.txt'.format(py_ver) +
mod_inst = install(localenv.Command, 'dummy', mod,
build_cmd + ' install ' + extra +
' --record=../../build/python-installed-files.txt' +
' --single-version-externally-managed')
global_env = env
def find_module_dir(target, source, env):
check = pjoin('cantera', '__init__.py')
py_ver = str(source[0]).split('/')[1][-1]
for filename in open('build/python{}-installed-files.txt'.format(py_ver)).readlines():
for filename in open('build/python-installed-files.txt').readlines():
filename = filename.strip()
if filename.endswith(check):
filename = filename.replace(check, '')
global_env['python{}_module_loc'.format(py_ver)] = normpath(filename)
global_env['python_module_loc'] = normpath(filename)
break
localenv.AlwaysBuild(localenv.AddPostAction(mod_inst, find_module_dir))
env['install_python{}_action'.format(py_ver)] = mod_inst
env['install_python_action'] = mod_inst

View file

@ -11,31 +11,19 @@ if env['INSTALL_MANPAGES']:
### Generate customized scripts ###
# If any Python 3 package is built, prefer that one. If not,
# and if any Python 2 package is built, prefer that one.
# In all other cases, use the Python 3 location variables,
# which should all be empty strings
if env['python3_package'] in ['full', 'minimal']:
major = '3'
elif env['python2_package'] in ['full', 'minimal']:
major = '2'
else:
major = '3'
# 'setup_cantera'
if localenv['layout'] != 'debian' and env['OS'] != 'Windows':
def copy_var(target, source, env):
if env['python{}_prefix'.format(major)] == 'USER':
if env['python_prefix'] == 'USER':
env['python_module_loc_sc'] = ''
else:
env['python_module_loc_sc'] = env['python{}_module_loc'.format(major)]
env['python_cmd'] = env['python{}_cmd'.format(major)]
env['python_module_loc_sc'] = env['python_module_loc']
for script in ['setup_cantera', 'setup_cantera.csh']:
target = env.SubstFile(script, script + '.in')
localenv.AddPreAction(target, copy_var)
localenv.Depends(target, env['install_python{}_action'.format(major)])
localenv.Depends(target, env['install_python_action'])
install('$inst_bindir', target)
# Cantera.mak include file for Makefile projects

View file

@ -4,7 +4,6 @@
Collect test coverage data and generate an html report.
"""
from __future__ import print_function
import os
import subprocess
import shutil

View file

@ -80,28 +80,16 @@ env['matlab_extension'] = ctmethods
# 'ctpath.m'
globalenv = env
# If any Python 3 package is built, prefer that one. If not,
# and if any Python 2 package is built, prefer that one.
# In all other cases, use the Python 3 location variables,
# which should all be empty strings
if env['python3_package'] in ['full', 'minimal']:
major = '3'
elif env['python2_package'] in ['full', 'minimal']:
major = '2'
else:
major = '3'
def copy_var(target, source, env):
if env['python{}_prefix'.format(major)] == 'USER':
if env['python_prefix'] == 'USER':
env['python_module_loc_sc'] = ''
else:
env['python_module_loc_sc'] = globalenv['python{}_module_loc'.format(major)]
env['python_cmd'] = env['python{}_cmd'.format(major)]
env['python_module_loc_sc'] = globalenv['python_module_loc']
target = localenv.SubstFile('#interfaces/matlab/ctpath.m',
'#interfaces/matlab/ctpath.m.in')
localenv.AddPreAction(target, copy_var)
localenv.Depends(target, env['install_python{}_action'.format(major)])
localenv.Depends(target, env['install_python_action'])
install('$inst_matlab_dir', target)
# 'Contents.m'

View file

@ -238,12 +238,9 @@ def addMatlabTest(script, testName, dependencies=None, env_vars=()):
return run_program
if localenv['python2_package'] in ('full', 'minimal'):
python_env_vars = {'PYTHONPATH': localenv['pythonpath_build2'],
'PYTHON_CMD': localenv.subst('$python2_cmd')}
elif localenv['python3_package'] in ('full', 'minimal'):
python_env_vars = {'PYTHONPATH': localenv['pythonpath_build3'],
'PYTHON_CMD': localenv.subst('$python3_cmd')}
if localenv['python_package'] in ('full', 'minimal'):
python_env_vars = {'PYTHONPATH': localenv['pythonpath_build'],
'PYTHON_CMD': localenv.subst('$python_cmd')}
else:
python_env_vars = {'PYTHONPATH': '../../build/python_minimal',
'PYTHON_CMD': localenv.subst('$python_cmd')}
@ -261,31 +258,24 @@ test_root = '#interfaces/cython/cantera/test'
for f in mglob(localenv, test_root, '^test_*.py'):
python_subtests.append(f.name[5:-3])
def make_python_tests(version):
# Create test aliases for individual test modules (e.g. test-python2-thermo;
if localenv['python_package'] == 'full':
# Create test aliases for individual test modules (e.g. test-python-thermo;
# not run as part of the main suite) and a single test runner with all the
# tests (test-python2) for the main suite.
# tests (test-python) for the main suite.
for subset in python_subtests:
name = 'python%i-' %version + subset if subset else 'python%i' % version
name = 'python-' + subset if subset else 'python'
pyTest = addPythonTest(
name, 'python', 'runCythonTests.py',
args=subset,
interpreter='$python{}_cmd'.format(version),
outfile=File('#test/work/python%d-results.txt' % version).abspath,
dependencies=(localenv['python%i_module' % version] +
localenv['python%i_extension' % version] +
interpreter='$python_cmd',
outfile=File('#test/work/python-results.txt').abspath,
dependencies=(localenv['python_module'] + localenv['python_extension'] +
mglob(localenv, test_root, 'py')),
env_vars={'PYTHONPATH': localenv['pythonpath_build%s' % version]},
env_vars={'PYTHONPATH': localenv['pythonpath_build']},
optional=bool(subset))
localenv.Alias('test-' + name, pyTest)
env['testNames'].append(name)
if localenv['python2_package'] == 'full':
make_python_tests(2)
if localenv['python3_package'] == 'full':
make_python_tests(3)
if localenv['matlab_toolbox'] == 'y':
matlabTest = addMatlabTest('runCanteraTests.m', 'matlab',
dependencies=mglob(localenv, 'matlab', 'm'),

View file

@ -17,7 +17,6 @@ a single test:
python runCythonTests.py onedim.TestDiffusionFlame.test_mixture_averaged
"""
from __future__ import print_function
import sys
import os
@ -25,8 +24,7 @@ import warnings
warnings.simplefilter('default')
cantera_root = os.path.relpath(__file__).split(os.sep)[:-1] + ['..', '..']
py_version = 'python3' if sys.version_info[0] == 3 else 'python2'
module_path = os.path.abspath(os.sep.join(cantera_root + ['build', py_version]))
module_path = os.path.abspath(os.sep.join(cantera_root + ['build']))
if 'PYTHONPATH' in os.environ:
os.environ['PYTHONPATH'] = module_path + os.path.pathsep + os.environ['PYTHONPATH']
@ -45,7 +43,7 @@ cantera.make_deprecation_warnings_fatal()
class TestResult(unittest.TextTestResult):
def __init__(self, *args, **kwargs):
unittest.TextTestResult.__init__(self, *args, **kwargs)
self.outName = 'python%d-results.txt' % sys.version_info[0]
self.outName = 'python-results.txt'
with open(self.outName, 'w') as f:
pass # just create an empty output file

View file

@ -19,13 +19,9 @@ if localenv['OS'] == 'Linux':
else:
cantera_libs = localenv['cantera_libs']
if localenv['python2_package'] in ('full', 'minimal'):
localenv['ENV']['PYTHONPATH'] = localenv['pythonpath_build2']
localenv['ENV']['PYTHON_CMD'] = localenv.subst('$python2_cmd')
haveConverters = True
elif localenv['python3_package'] in ('full', 'minimal'):
localenv['ENV']['PYTHONPATH'] = localenv['pythonpath_build3']
localenv['ENV']['PYTHON_CMD'] = localenv.subst('$python3_cmd')
if localenv['python_package'] in ('full', 'minimal'):
localenv['ENV']['PYTHONPATH'] = localenv['pythonpath_build']
localenv['ENV']['PYTHON_CMD'] = localenv.subst('$python_cmd')
haveConverters = True
else:
localenv['ENV']['PYTHONPATH'] = '../../build/python_minimal'