Merge remote-tracking branch 'origin/master' into docs

Manually merged updates to README.md across to docs

# Conflicts:
#	README.md
This commit is contained in:
Joe Rickerby
2019-11-03 19:38:18 +00:00
16 changed files with 389 additions and 95 deletions
+8 -2
View File
@@ -23,9 +23,15 @@ matrix:
# macOS Python 3 # macOS Python 3
- os: osx - os: osx
env: PYTHON=python3 env: PYTHON=python3
- os: windows
language: shell
before_install: before_install:
- brew update - choco install python3 --version 3.6.8 --no-progress -y
- brew outdated python || brew upgrade python install:
- C:\\Python36\\python -m pip install -r requirements-dev.txt
script:
- C:\\Python36\\python ./bin/run_tests.py
install: $PYTHON -m pip install -r requirements-dev.txt install: $PYTHON -m pip install -r requirements-dev.txt
+13 -4
View File
@@ -17,13 +17,15 @@ What does it do?
| | macOS 10.6+ | manylinux i686 | manylinux x86_64 | Windows 32bit | Windows 64bit | | | macOS 10.6+ | manylinux i686 | manylinux x86_64 | Windows 32bit | Windows 64bit |
|---|---|---|---|---|---| |---|---|---|---|---|---|
| Python 2.7 | ✅ | ✅ | ✅ | ✅ | ✅ | | Python 2.7 | ✅ | ✅ | ✅ | ✅² | ✅² |
| Python 3.4 | ✅ | ✅ | ✅ | ✅* | ✅* | | Python 3.4 | ✅ | ✅ | ✅ | ✅¹²| ✅¹²|
| Python 3.5 | ✅ | ✅ | ✅ | ✅ | ✅ | | Python 3.5 | ✅ | ✅ | ✅ | ✅ | ✅ |
| Python 3.6 | ✅ | ✅ | ✅ | ✅ | ✅ | | Python 3.6 | ✅ | ✅ | ✅ | ✅ | ✅ |
| Python 3.7 | ✅ | ✅ | ✅ | ✅ | ✅ | | Python 3.7 | ✅ | ✅ | ✅ | ✅ | ✅ |
> \* Not supported on Azure Pipelines > ¹ Not supported on Azure Pipelines
>
> ² Not supported on Travis
- Builds manylinux, macOS and Windows (32 and 64bit) wheels using Azure Pipelines, Travis CI, AppVeyor, and CircleCI - Builds manylinux, macOS and Windows (32 and 64bit) wheels using Azure Pipelines, Travis CI, AppVeyor, and CircleCI
- Bundles shared library dependencies on Linux and macOS through [auditwheel](https://github.com/pypa/auditwheel) and [delocate](https://github.com/matthew-brett/delocate) - Bundles shared library dependencies on Linux and macOS through [auditwheel](https://github.com/pypa/auditwheel) and [delocate](https://github.com/matthew-brett/delocate)
@@ -32,7 +34,14 @@ What does it do?
Usage Usage
----- -----
`cibuildwheel` currently works **Travis CI** and **CircleCI** to build Linux and Mac wheels, and **AppVeyor** to build Windows wheels. **Azure Pipelines** supports all three. `cibuildwheel` currently works on **Travis CI** and **Azure Pipelines** to build wheels for all three supported platforms (Linux, macOS, Windows). On **CircleCI** Linux and macOS wheels can be built, and on **AppVeyor** Windows is supported.
| | Linux | macOS | Windows |
|-----------------|-------|-------|---------|
| Azure Pipelines | ✅ | ✅ | ✅ |
| Travis CI | ✅ | ✅ | ✅ |
| AppVeyor | | | ✅ |
| CircleCI | ✅ | ✅ | |
`cibuildwheel` is not intended to run on your development machine. Because it uses system Python from Python.org it will try to install packages globally - not what you expect from a build tool! Instead, isolated CI services like Travis CI, CircleCI, Azure Pipelines and AppVeyor are ideal. `cibuildwheel` is not intended to run on your development machine. Because it uses system Python from Python.org it will try to install packages globally - not what you expect from a build tool! Instead, isolated CI services like Travis CI, CircleCI, Azure Pipelines and AppVeyor are ideal.
+33 -3
View File
@@ -54,6 +54,8 @@ def main():
args = parser.parse_args() args = parser.parse_args()
detect_obsolete_options()
if args.platform != 'auto': if args.platform != 'auto':
platform = args.platform platform = args.platform
else: else:
@@ -63,6 +65,8 @@ def main():
platform = 'linux' platform = 'linux'
elif os.environ.get('TRAVIS_OS_NAME') == 'osx': elif os.environ.get('TRAVIS_OS_NAME') == 'osx':
platform = 'macos' platform = 'macos'
elif os.environ.get('TRAVIS_OS_NAME') == 'windows':
platform = 'windows'
elif 'APPVEYOR' in os.environ: elif 'APPVEYOR' in os.environ:
platform = 'windows' platform = 'windows'
elif 'BITRISE_BUILD_NUMBER' in os.environ: elif 'BITRISE_BUILD_NUMBER' in os.environ:
@@ -141,11 +145,17 @@ def main():
) )
if platform == 'linux': if platform == 'linux':
manylinux1_x86_64_image = os.environ.get('CIBW_MANYLINUX1_X86_64_IMAGE', None) manylinux_x86_64_image = os.environ.get('CIBW_MANYLINUX_X86_64_IMAGE', 'manylinux2010')
manylinux1_i686_image = os.environ.get('CIBW_MANYLINUX1_I686_IMAGE', None) manylinux_i686_image = os.environ.get('CIBW_MANYLINUX_I686_IMAGE', 'manylinux2010')
default_manylinux_images_x86_64 = {'manylinux1': 'quay.io/pypa/manylinux1_x86_64',
'manylinux2010': 'quay.io/pypa/manylinux2010_x86_64'}
default_manylinux_images_i686 = {'manylinux1': 'quay.io/pypa/manylinux1_i686',
'manylinux2010': 'quay.io/pypa/manylinux2010_i686'}
build_options.update( build_options.update(
manylinux1_images={'x86_64': manylinux1_x86_64_image, 'i686': manylinux1_i686_image}, manylinux_images={'x86_64': default_manylinux_images_x86_64.get(manylinux_x86_64_image) or manylinux_x86_64_image,
'i686': default_manylinux_images_i686.get(manylinux_i686_image) or manylinux_i686_image},
) )
elif platform == 'macos': elif platform == 'macos':
pass pass
@@ -170,6 +180,26 @@ def main():
raise Exception('Unsupported platform') raise Exception('Unsupported platform')
def detect_obsolete_options():
# Check the old 'MANYLINUX1_*_IMAGE' options
for (deprecated, alternative) in [('CIBW_MANYLINUX1_X86_64_IMAGE', 'CIBW_MANYLINUX_X86_64_IMAGE'),
('CIBW_MANYLINUX1_I686_IMAGE', 'CIBW_MANYLINUX_I686_IMAGE')]:
if deprecated in os.environ:
print("'{}' has been deprecated, and will be removed in a future release. Use the option '{}' instead.".format(deprecated, alternative))
if alternative not in os.environ:
print("Using value of option '{}' as replacement for '{}'".format(deprecated, alternative))
os.environ[alternative] = os.environ[deprecated]
else:
print("Option '{}' is not empty. Please unset '{}'".format(alternative, deprecated))
exit(2)
# Check for 'manylinux1' in the 'CIBW_BUILD' and 'CIBW_SKIP' options
for deprecated in ['CIBW_BUILD', 'CIBW_SKIP']:
if deprecated in os.environ and 'manylinux1' in os.environ[deprecated]:
print("Build identifiers with 'manylinux1' been deprecated. Replacing all occurences of 'manylinux1' by 'manylinux' in the option '{}'".format(deprecated))
os.environ[deprecated] = os.environ[deprecated].replace('manylinux1', 'manylinux')
def print_preamble(platform, build_options): def print_preamble(platform, build_options):
print(textwrap.dedent(''' print(textwrap.dedent('''
_ _ _ _ _ _ _ _ _ _ _ _ _ _
+56 -34
View File
@@ -12,25 +12,25 @@ except ImportError:
def get_python_configurations(build_selector): def get_python_configurations(build_selector):
PythonConfiguration = namedtuple('PythonConfiguration', ['identifier', 'path']) PythonConfiguration = namedtuple('PythonConfiguration', ['identifier', 'path'])
python_configurations = [ python_configurations = [
PythonConfiguration(identifier='cp27-manylinux1_x86_64', path='/opt/python/cp27-cp27m'), PythonConfiguration(identifier='cp27-manylinux_x86_64', path='/opt/python/cp27-cp27m'),
PythonConfiguration(identifier='cp27-manylinux1_x86_64', path='/opt/python/cp27-cp27mu'), PythonConfiguration(identifier='cp27-manylinux_x86_64', path='/opt/python/cp27-cp27mu'),
PythonConfiguration(identifier='cp34-manylinux1_x86_64', path='/opt/python/cp34-cp34m'), PythonConfiguration(identifier='cp34-manylinux_x86_64', path='/opt/python/cp34-cp34m'),
PythonConfiguration(identifier='cp35-manylinux1_x86_64', path='/opt/python/cp35-cp35m'), PythonConfiguration(identifier='cp35-manylinux_x86_64', path='/opt/python/cp35-cp35m'),
PythonConfiguration(identifier='cp36-manylinux1_x86_64', path='/opt/python/cp36-cp36m'), PythonConfiguration(identifier='cp36-manylinux_x86_64', path='/opt/python/cp36-cp36m'),
PythonConfiguration(identifier='cp37-manylinux1_x86_64', path='/opt/python/cp37-cp37m'), PythonConfiguration(identifier='cp37-manylinux_x86_64', path='/opt/python/cp37-cp37m'),
PythonConfiguration(identifier='cp27-manylinux1_i686', path='/opt/python/cp27-cp27m'), PythonConfiguration(identifier='cp27-manylinux_i686', path='/opt/python/cp27-cp27m'),
PythonConfiguration(identifier='cp27-manylinux1_i686', path='/opt/python/cp27-cp27mu'), PythonConfiguration(identifier='cp27-manylinux_i686', path='/opt/python/cp27-cp27mu'),
PythonConfiguration(identifier='cp34-manylinux1_i686', path='/opt/python/cp34-cp34m'), PythonConfiguration(identifier='cp34-manylinux_i686', path='/opt/python/cp34-cp34m'),
PythonConfiguration(identifier='cp35-manylinux1_i686', path='/opt/python/cp35-cp35m'), PythonConfiguration(identifier='cp35-manylinux_i686', path='/opt/python/cp35-cp35m'),
PythonConfiguration(identifier='cp36-manylinux1_i686', path='/opt/python/cp36-cp36m'), PythonConfiguration(identifier='cp36-manylinux_i686', path='/opt/python/cp36-cp36m'),
PythonConfiguration(identifier='cp37-manylinux1_i686', path='/opt/python/cp37-cp37m'), PythonConfiguration(identifier='cp37-manylinux_i686', path='/opt/python/cp37-cp37m'),
] ]
# skip builds as required # skip builds as required
return [c for c in python_configurations if build_selector(c.identifier)] return [c for c in python_configurations if build_selector(c.identifier)]
def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, environment, manylinux1_images): def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, environment, manylinux_images):
try: try:
subprocess.check_call(['docker', '--version']) subprocess.check_call(['docker', '--version'])
except: except:
@@ -42,8 +42,8 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
python_configurations = get_python_configurations(build_selector) python_configurations = get_python_configurations(build_selector)
platforms = [ platforms = [
('manylinux1_x86_64', manylinux1_images.get('x86_64') or 'quay.io/pypa/manylinux1_x86_64'), ('manylinux_x86_64', manylinux_images['x86_64']),
('manylinux1_i686', manylinux1_images.get('i686') or 'quay.io/pypa/manylinux1_i686'), ('manylinux_i686', manylinux_images['i686']),
] ]
for platform_tag, docker_image in platforms: for platform_tag, docker_image in platforms:
@@ -62,9 +62,9 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
for PYBIN in {pybin_paths}; do for PYBIN in {pybin_paths}; do
# Setup # Setup
rm -rf /tmp/built_wheel rm -rf /tmp/built_wheel
rm -rf /tmp/delocated_wheel rm -rf /tmp/delocated_wheels
mkdir /tmp/built_wheel mkdir /tmp/built_wheel
mkdir /tmp/delocated_wheel mkdir /tmp/delocated_wheels
if [ ! -z {before_build} ]; then if [ ! -z {before_build} ]; then
PATH="$PYBIN:$PATH" sh -c {before_build} PATH="$PYBIN:$PATH" sh -c {before_build}
@@ -79,30 +79,52 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
# the first element # the first element
if [[ "$built_wheel" == *none-any.whl ]]; then if [[ "$built_wheel" == *none-any.whl ]]; then
# pure python wheel - just copy # pure python wheel - just copy
mv "$built_wheel" /tmp/delocated_wheel mv "$built_wheel" /tmp/delocated_wheels
else else
auditwheel repair "$built_wheel" -w /tmp/delocated_wheel auditwheel repair "$built_wheel" -w /tmp/delocated_wheels
fi fi
delocated_wheel=(/tmp/delocated_wheel/*.whl) delocated_wheels=(/tmp/delocated_wheels/*.whl)
# Install the wheel we just built
"$PYBIN/pip" install "$delocated_wheel"{test_extras}
# Install any requirements to run the tests
if [ ! -z "{test_requires}" ]; then
"$PYBIN/pip" install {test_requires}
fi
# Run the tests from a different directory
if [ ! -z {test_command} ]; then if [ ! -z {test_command} ]; then
pushd $HOME # Set up a virtual environment to install and test from, to make sure
PATH="$PYBIN:$PATH" sh -c {test_command} # there are no dependencies that were pulled in at build time.
popd "$PYBIN/pip" install virtualenv
venv_dir=`mktemp -d`/venv
"$PYBIN/python" -m virtualenv "$venv_dir"
# run the tests in a subshell to keep that `activate`
# script from polluting the env
(
source "$venv_dir/bin/activate"
echo "Running tests using `which python`"
# Install the wheel we just built
# Note: If auditwheel produced two wheels, it's because the earlier produced wheel
# conforms to multiple manylinux standards. These multiple versions of the wheel are
# functionally the same, differing only in name, wheel metadata, and possibly include
# different external shared libraries. so it doesn't matter which one we run the tests on.
# Let's just pick the first one.
pip install "${{delocated_wheels[0]}}"{test_extras}
# Install any requirements to run the tests
if [ ! -z "{test_requires}" ]; then
pip install {test_requires}
fi
# Run the tests from a different directory
pushd $HOME
sh -c {test_command}
popd
)
# clean up
rm -rf "$venv_dir"
fi fi
# we're all done here; move it to output # we're all done here; move it to output
mv "$delocated_wheel" /output mv "${{delocated_wheels[@]}}" /output
chown {uid}:{gid} "/output/$(basename "$delocated_wheel")" for delocated_wheel in "${{delocated_wheels[@]}}"; do chown {uid}:{gid} "/output/$(basename "$delocated_wheel")"; done
done done
'''.format( '''.format(
pybin_paths=' '.join(c.path+'/bin' for c in platform_configs), pybin_paths=' '.join(c.path+'/bin' for c in platform_configs),
+32 -9
View File
@@ -1,4 +1,5 @@
from __future__ import print_function from __future__ import print_function
import tempfile
import os, subprocess, shlex, sys, shutil import os, subprocess, shlex, sys, shutil
from collections import namedtuple from collections import namedtuple
from glob import glob from glob import glob
@@ -13,11 +14,11 @@ from .util import prepare_command, get_build_verbosity_extra_flags
def get_python_configurations(build_selector): def get_python_configurations(build_selector):
PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'identifier', 'url']) PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'identifier', 'url'])
python_configurations = [ python_configurations = [
PythonConfiguration(version='2.7', identifier='cp27-macosx_10_6_intel', url='https://www.python.org/ftp/python/2.7.16/python-2.7.16-macosx10.6.pkg'), PythonConfiguration(version='2.7', identifier='cp27-macosx_10_6_intel', url='https://www.python.org/ftp/python/2.7.17/python-2.7.17-macosx10.6.pkg'),
PythonConfiguration(version='3.4', identifier='cp34-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.4.4/python-3.4.4-macosx10.6.pkg'), PythonConfiguration(version='3.4', identifier='cp34-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.4.4/python-3.4.4-macosx10.6.pkg'),
PythonConfiguration(version='3.5', identifier='cp35-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg'), PythonConfiguration(version='3.5', identifier='cp35-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg'),
PythonConfiguration(version='3.6', identifier='cp36-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.6.pkg'), PythonConfiguration(version='3.6', identifier='cp36-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.6.pkg'),
PythonConfiguration(version='3.7', identifier='cp37-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.7.4/python-3.7.4-macosx10.6.pkg'), PythonConfiguration(version='3.7', identifier='cp37-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.7.5/python-3.7.5-macosx10.6.pkg'),
] ]
# skip builds as required # skip builds as required
@@ -120,18 +121,40 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
call(['delocate-wheel', '-w', '/tmp/delocated_wheel', built_wheel], env=env) call(['delocate-wheel', '-w', '/tmp/delocated_wheel', built_wheel], env=env)
delocated_wheel = glob('/tmp/delocated_wheel/*.whl')[0] delocated_wheel = glob('/tmp/delocated_wheel/*.whl')[0]
# install the wheel
call(['pip', 'install', delocated_wheel + test_extras], env=env)
# test the wheel
if test_requires:
call(['pip', 'install'] + test_requires, env=env)
if test_command: if test_command:
# set up a virtual environment to install and test from, to make sure
# there are no dependencies that were pulled in at build time.
call(['pip', 'install', 'virtualenv'], env=env)
venv_dir = tempfile.mkdtemp()
call(['python', '-m', 'virtualenv', venv_dir], env=env)
virtualenv_env = env.copy()
virtualenv_env['PATH'] = os.pathsep.join([
os.path.join(venv_dir, 'bin'),
virtualenv_env['PATH'],
])
# Fix some weird issue with the shebang of installed scripts
# See https://github.com/theacodes/nox/issues/44 and https://github.com/pypa/virtualenv/issues/620
virtualenv_env.pop('__PYVENV_LAUNCHER__', None)
# check that we are using the Python from the virtual environment
call(['which', 'python'], env=virtualenv_env)
# install the wheel
call(['pip', 'install', delocated_wheel + test_extras], env=virtualenv_env)
# test the wheel
if test_requires:
call(['pip', 'install'] + test_requires, env=virtualenv_env)
# run the tests from $HOME, with an absolute path in the command # run the tests from $HOME, with an absolute path in the command
# (this ensures that Python runs the tests against the installed wheel # (this ensures that Python runs the tests against the installed wheel
# and not the repo code) # and not the repo code)
test_command_prepared = prepare_command(test_command, project=abs_project_dir) test_command_prepared = prepare_command(test_command, project=abs_project_dir)
call(test_command_prepared, cwd=os.environ['HOME'], env=env, shell=True) call(test_command_prepared, cwd=os.environ['HOME'], env=virtualenv_env, shell=True)
# clean up
shutil.rmtree(venv_dir)
# we're all done here; move it to output (overwrite existing) # we're all done here; move it to output (overwrite existing)
dst = os.path.join(output_dir, os.path.basename(delocated_wheel)) dst = os.path.join(output_dir, os.path.basename(delocated_wheel))
+87 -24
View File
@@ -1,12 +1,18 @@
from __future__ import print_function from __future__ import print_function
import os, tempfile, subprocess, shutil import os, tempfile, subprocess, shutil, sys
from collections import namedtuple from collections import namedtuple
from glob import glob from glob import glob
try:
from shlex import quote as shlex_quote
except ImportError:
from pipes import quote as shlex_quote
from .util import prepare_command, get_build_verbosity_extra_flags from .util import prepare_command, get_build_verbosity_extra_flags
IS_RUNNING_ON_AZURE = os.path.exists('C:\\hostedtoolcache') IS_RUNNING_ON_AZURE = os.path.exists('C:\\hostedtoolcache')
IS_RUNNING_ON_TRAVIS = os.environ.get('TRAVIS_OS_NAME') == 'windows'
def get_python_path(config): def get_python_path(config):
if IS_RUNNING_ON_AZURE: if IS_RUNNING_ON_AZURE:
@@ -22,6 +28,12 @@ def get_python_path(config):
return glob(path_pattern)[0] return glob(path_pattern)[0]
except IndexError: except IndexError:
raise Exception('Could not find a Python install at ' + path_pattern) raise Exception('Could not find a Python install at ' + path_pattern)
elif IS_RUNNING_ON_TRAVIS:
if config.version == "3.4.x":
return config.path
else:
nuget_args = get_nuget_args(config)
return os.path.join(nuget_args[-1], nuget_args[0] + "." + config.nuget_version, "tools")
else: else:
# Assume we're running on AppVeyor # Assume we're running on AppVeyor
major, minor = config.version.split('.')[:2] major, minor = config.version.split('.')[:2]
@@ -32,32 +44,49 @@ def get_python_path(config):
) )
def get_nuget_args(configuration):
if configuration.nuget_version is None:
return None
python_name = "python" if configuration.version[0] == '3' else "python2"
if configuration.arch == "32":
python_name = python_name + "x86"
return [python_name, "-Version", configuration.nuget_version, "-OutputDirectory", "C:/python"]
def get_python_configurations(build_selector): def get_python_configurations(build_selector):
PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'arch', 'identifier', 'path']) PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'arch', 'identifier', 'path', "nuget_version"])
python_configurations = [ python_configurations = [
PythonConfiguration(version='2.7.x', arch="32", identifier='cp27-win32', path='C:\Python27'), PythonConfiguration(version='2.7.x', arch="32", identifier='cp27-win32', path='C:\\Python27', nuget_version="2.7.16"),
PythonConfiguration(version='2.7.x', arch="64", identifier='cp27-win_amd64', path='C:\Python27-x64'), PythonConfiguration(version='2.7.x', arch="64", identifier='cp27-win_amd64', path='C:\\Python27-x64', nuget_version="2.7.16"),
PythonConfiguration(version='3.4.x', arch="32", identifier='cp34-win32', path='C:\Python34'), PythonConfiguration(version='3.4.x', arch="32", identifier='cp34-win32', path='C:\\Python34', nuget_version=None),
PythonConfiguration(version='3.4.x', arch="64", identifier='cp34-win_amd64', path='C:\Python34-x64'), PythonConfiguration(version='3.4.x', arch="64", identifier='cp34-win_amd64', path='C:\\Python34-x64', nuget_version=None),
PythonConfiguration(version='3.5.x', arch="32", identifier='cp35-win32', path='C:\Python35'), PythonConfiguration(version='3.5.x', arch="32", identifier='cp35-win32', path='C:\\Python35', nuget_version="3.5.4"),
PythonConfiguration(version='3.5.x', arch="64", identifier='cp35-win_amd64', path='C:\Python35-x64'), PythonConfiguration(version='3.5.x', arch="64", identifier='cp35-win_amd64', path='C:\\Python35-x64', nuget_version="3.5.4"),
PythonConfiguration(version='3.6.x', arch="32", identifier='cp36-win32', path='C:\Python36'), PythonConfiguration(version='3.6.x', arch="32", identifier='cp36-win32', path='C:\\Python36', nuget_version="3.6.8"),
PythonConfiguration(version='3.6.x', arch="64", identifier='cp36-win_amd64', path='C:\Python36-x64'), PythonConfiguration(version='3.6.x', arch="64", identifier='cp36-win_amd64', path='C:\\Python36-x64', nuget_version="3.6.8"),
PythonConfiguration(version='3.7.x', arch="32", identifier='cp37-win32', path='C:\Python37'), PythonConfiguration(version='3.7.x', arch="32", identifier='cp37-win32', path='C:\\Python37', nuget_version="3.7.4"),
PythonConfiguration(version='3.7.x', arch="64", identifier='cp37-win_amd64', path='C:\Python37-x64'), PythonConfiguration(version='3.7.x', arch="64", identifier='cp37-win_amd64', path='C:\\Python37-x64', nuget_version="3.7.4")
] ]
if IS_RUNNING_ON_AZURE: if IS_RUNNING_ON_AZURE:
# Python 3.4 isn't supported on Azure. # Python 3.4 isn't supported on Azure.
# See https://github.com/Microsoft/azure-pipelines-tasks/issues/9674 # See https://github.com/Microsoft/azure-pipelines-tasks/issues/9674
python_configurations = [c for c in python_configurations if c.version != '3.4.x'] python_configurations = [c for c in python_configurations if c.version != '3.4.x']
if IS_RUNNING_ON_TRAVIS:
# cannot install VCForPython27.msi which is needed for compiling C software
# try with (and similar): msiexec /i VCForPython27.msi ALLUSERS=1 ACCEPT=YES /passive
# no easy and stable way fo installing python 3.4
python_configurations = [c for c in python_configurations if c.version != '2.7.x' and c.version != '3.4.x']
# skip builds as required
python_configurations = [c for c in python_configurations if build_selector(c.identifier)]
return python_configurations
# skip builds as required
return [c for c in python_configurations if build_selector(c.identifier)]
def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, environment): def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, environment):
if IS_RUNNING_ON_AZURE: if IS_RUNNING_ON_AZURE or IS_RUNNING_ON_TRAVIS:
def shell(args, env=None, cwd=None): def shell(args, env=None, cwd=None):
print('+ ' + ' '.join(args)) print('+ ' + ' '.join(args))
args = ['cmd', '/E:ON', '/V:ON', '/C'] + args args = ['cmd', '/E:ON', '/V:ON', '/C'] + args
@@ -77,10 +106,21 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
temp_dir = tempfile.mkdtemp(prefix='cibuildwheel') temp_dir = tempfile.mkdtemp(prefix='cibuildwheel')
built_wheel_dir = os.path.join(temp_dir, 'built_wheel') built_wheel_dir = os.path.join(temp_dir, 'built_wheel')
python_configurations = get_python_configurations(build_selector) if IS_RUNNING_ON_TRAVIS:
# instal nuget as best way for provide python
shell(["choco", "install", "nuget.commandline"])
# get pip fo this installation which not have.
get_pip_url = 'https://bootstrap.pypa.io/get-pip.py'
get_pip_script = 'C:\\get-pip.py'
shell(['curl', '-L', '-o', get_pip_script, get_pip_url])
python_configurations = get_python_configurations(build_selector)
for config in python_configurations: for config in python_configurations:
config_python_path = get_python_path(config) config_python_path = get_python_path(config)
if IS_RUNNING_ON_TRAVIS and config.nuget_version is not None and not os.path.exists(config_python_path):
shell(["nuget", "install"] + get_nuget_args(config))
if not os.path.exists(os.path.join(config_python_path, 'Scripts', 'pip.exe')):
shell([os.path.join(config_python_path, 'python.exe'), get_pip_script ])
# check python & pip exist for this configuration # check python & pip exist for this configuration
assert os.path.exists(os.path.join(config_python_path, 'python.exe')) assert os.path.exists(os.path.join(config_python_path, 'python.exe'))
@@ -107,8 +147,12 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
shell(['python', '-c', '"import struct; print(struct.calcsize(\'P\') * 8)\"'], env=env) shell(['python', '-c', '"import struct; print(struct.calcsize(\'P\') * 8)\"'], env=env)
# prepare the Python environment # prepare the Python environment
shell(['python', '-m', 'pip', 'install', '--upgrade', 'pip'], if config.version == "3.4.x":
shell(['python', '-m', 'pip', 'install', 'pip==19.1.1'],
env=env) env=env)
else:
shell(['python', '-m', 'pip', 'install', '--upgrade', 'pip'],
env=env)
shell(['pip', 'install', '--upgrade', 'setuptools'], env=env) shell(['pip', 'install', '--upgrade', 'setuptools'], env=env)
shell(['pip', 'install', 'wheel'], env=env) shell(['pip', 'install', 'wheel'], env=env)
@@ -121,18 +165,37 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef
shell(['pip', 'wheel', abs_project_dir, '-w', built_wheel_dir, '--no-deps'] + get_build_verbosity_extra_flags(build_verbosity), env=env) shell(['pip', 'wheel', abs_project_dir, '-w', built_wheel_dir, '--no-deps'] + get_build_verbosity_extra_flags(build_verbosity), env=env)
built_wheel = glob(built_wheel_dir+'/*.whl')[0] built_wheel = glob(built_wheel_dir+'/*.whl')[0]
# install the wheel
shell(['pip', 'install', built_wheel + test_extras], env=env)
# test the wheel
if test_requires:
shell(['pip', 'install'] + test_requires, env=env)
if test_command: if test_command:
# set up a virtual environment to install and test from, to make sure
# there are no dependencies that were pulled in at build time.
shell(['pip', 'install', 'virtualenv'], env=env)
venv_dir = tempfile.mkdtemp()
shell(['python', '-m', 'virtualenv', venv_dir], env=env)
virtualenv_env = env.copy()
virtualenv_env['PATH'] = os.pathsep.join([
os.path.join(venv_dir, 'Scripts'),
virtualenv_env['PATH'],
])
# check that we are using the Python from the virtual environment
shell(['which', 'python'], env=virtualenv_env)
# install the wheel
shell(['pip', 'install', built_wheel + test_extras], env=virtualenv_env)
# test the wheel
if test_requires:
shell(['pip', 'install'] + test_requires, env=virtualenv_env)
# run the tests from c:\, with an absolute path in the command # run the tests from c:\, with an absolute path in the command
# (this ensures that Python runs the tests against the installed wheel # (this ensures that Python runs the tests against the installed wheel
# and not the repo code) # and not the repo code)
test_command_prepared = prepare_command(test_command, project=abs_project_dir) test_command_prepared = prepare_command(test_command, project=abs_project_dir)
shell([test_command_prepared], cwd='c:\\', env=env) shell([test_command_prepared], cwd='c:\\', env=virtualenv_env)
# clean up
shutil.rmtree(venv_dir)
# we're all done here; move it to output (remove if already exists) # we're all done here; move it to output (remove if already exists)
dst = os.path.join(output_dir, os.path.basename(built_wheel)) dst = os.path.join(output_dir, os.path.basename(built_wheel))
+2 -2
View File
@@ -16,13 +16,13 @@ If your wheel didn't compile, check the list below for some debugging tips.
### Linux builds on Docker ### Linux builds on Docker
Linux wheels are built in the [`manylinux` docker images](https://github.com/pypa/manylinux) to provide binary compatible wheels on Linux, according to [PEP 513](https://www.python.org/dev/peps/pep-0513/). Because of this, when building with `cibuildwheel` on Linux, a few things should be taken into account: Linux wheels are built in the [`manylinux` docker images](https://github.com/pypa/manylinux) to provide binary compatible wheels on Linux, according to [PEP 571](https://www.python.org/dev/peps/pep-0571/). Because of this, when building with `cibuildwheel` on Linux, a few things should be taken into account:
- Programs and libraries cannot be installed on the Travis CI Ubuntu host with `apt-get`, but can be installed inside of the Docker image using `yum` or manually. The same goes for environment variables that are potentially needed to customize the wheel building. `cibuildwheel` supports this by providing the `CIBW_ENVIRONMENT` and `CIBW_BEFORE_BUILD` options to setup the build environment inside the running Docker image. See [the options docs](options.md#build-environment) for details on these options. - Programs and libraries cannot be installed on the Travis CI Ubuntu host with `apt-get`, but can be installed inside of the Docker image using `yum` or manually. The same goes for environment variables that are potentially needed to customize the wheel building. `cibuildwheel` supports this by providing the `CIBW_ENVIRONMENT` and `CIBW_BEFORE_BUILD` options to setup the build environment inside the running Docker image. See [the options docs](options.md#build-environment) for details on these options.
- The project directory is mounted in the running Docker instance as `/project`, the output directory for the wheels as `/output`. In general, this is handled transparently by `cibuildwheel`. For a more finegrained level of control however, the root of the host file system is mounted as `/host`, allowing for example to access shared files, caches, etc. on the host file system. Note that this is not available on CircleCI due to their Docker policies. - The project directory is mounted in the running Docker instance as `/project`, the output directory for the wheels as `/output`. In general, this is handled transparently by `cibuildwheel`. For a more finegrained level of control however, the root of the host file system is mounted as `/host`, allowing for example to access shared files, caches, etc. on the host file system. Note that this is not available on CircleCI due to their Docker policies.
- Alternative dockers images can be specified with the `CIBW_MANYLINUX1_X86_64_IMAGE` and `CIBW_MANYLINUX1_I686_IMAGE` options to allow for a custom, preconfigured build environment for the Linux builds. See [options](options.md#manylinux-image) for more details. - Alternative dockers images can be specified with the `CIBW_MANYLINUX_X86_64_IMAGE` and `CIBW_MANYLINUX_I686_IMAGE` options to allow for a custom, preconfigured build environment for the Linux builds. See [options](options.md#manylinux-image) for more details.
### Building packages with optional C extensions ### Building packages with optional C extensions
+16 -9
View File
@@ -59,17 +59,19 @@ For `linux` you need Docker running, on Mac or Linux. For `macos`, you need a Ma
> Choose the Python versions to build > Choose the Python versions to build
Space-separated list of builds to build and skip. Each build has an identifier like `cp27-manylinux1_x86_64` or `cp34-macosx_10_6_intel` - you can list specific ones to build and `cibuildwheel` will only build those, and/or list ones to skip and `cibuildwheel` won't try to build them. Space-separated list of builds to build and skip. Each build has an identifier like `cp27-manylinux_x86_64` or `cp34-macosx_10_6_intel` - you can list specific ones to build and `cibuildwheel` will only build those, and/or list ones to skip and `cibuildwheel` won't try to build them.
When both options are specified, both conditions are applied and only builds with a tag that matches `CIBW_BUILD` and does not match `CIBW_SKIP` will be built. When both options are specified, both conditions are applied and only builds with a tag that matches `CIBW_BUILD` and does not match `CIBW_SKIP` will be built.
The format is `python_tag-platform_tag`. The tags are as defined in [PEP 0425](https://www.python.org/dev/peps/pep-0425/#details). The format is `python_tag-platform_tag`. The tags are similar but not identical to the ones defined in [PEP 425](https://www.python.org/dev/peps/pep-0425/#details).
Python tags look like `cp27` `cp34` `cp35` `cp36` `cp37` Python tags look like `cp27` `cp34` `cp35` `cp36` `cp37`
Platform tags look like `macosx_10_6_intel` `manylinux1_x86_64` `manylinux1_i686` `win32` `win_amd64` Platform tags look like `macosx_10_6_intel` `manylinux_x86_64` `manylinux_i686` `win32` `win_amd64`
You can also use shell-style globbing syntax (as per `fnmatch`) You can also use shell-style globbing syntax (as per `fnmatch`).
The list of supported and currently selected build identifiers can be retrieved by passing the `--print-build-identifiers` flag to `cibuildwheel`.
Examples: Examples:
@@ -80,7 +82,7 @@ Examples:
- Skip Python 2.7 on 32-bit Windows: `CIBW_SKIP=cp27-win32` - Skip Python 2.7 on 32-bit Windows: `CIBW_SKIP=cp27-win32`
- Skip Python 3.4 and Python 3.5: `CIBW_SKIP=cp34-* cp35-*` - Skip Python 3.4 and Python 3.5: `CIBW_SKIP=cp34-* cp35-*`
- Skip Python 3.6 on Linux: `CIBW_SKIP=cp36-manylinux*` - Skip Python 3.6 on Linux: `CIBW_SKIP=cp36-manylinux*`
- Only build on Python 3 and skip 32-bit builds: `CIBW_BUILD=cp3?-*` and `CIBW_SKIP=*-win32 *-manylinux1_i686` - Only build on Python 3 and skip 32-bit builds: `CIBW_BUILD=cp3?-*` and `CIBW_SKIP=*-win32 *-manylinux_i686`
## Build environment ## Build environment
@@ -119,13 +121,18 @@ Example: `yum install -y libffi-dev && pip install .`
Platform-specific variants also available: Platform-specific variants also available:
`CIBW_BEFORE_BUILD_MACOS` | `CIBW_BEFORE_BUILD_WINDOWS` | `CIBW_BEFORE_BUILD_LINUX` `CIBW_BEFORE_BUILD_MACOS` | `CIBW_BEFORE_BUILD_WINDOWS` | `CIBW_BEFORE_BUILD_LINUX`
### CIBW_MANYLINUX1_X86_64_IMAGE, CIBW_MANYLINUX1_I686_IMAGE {: #manylinux-image} ### CIBW_MANYLINUX_X86_64_IMAGE, CIBW_MANYLINUX_I686_IMAGE {: #manylinux-image}
> Specify alternative manylinux1 x86_64 docker images > Specify alternative manylinux docker images
An alternative docker image to be used for building [`manylinux1`](https://github.com/pypa/manylinux) wheels. `cibuildwheel` will then pull these instead of the official images, [`quay.io/pypa/manylinux1_x86_64`](https://quay.io/pypa/manylinux1_i686) and [`quay.io/pypa/manylinux1_i686`](https://quay.io/pypa/manylinux1_i686). An alternative Docker image to be used for building [`manylinux`](https://github.com/pypa/manylinux) wheels. `cibuildwheel` will then pull these instead of the default images, [`quay.io/pypa/manylinux2010_x86_64`](https://quay.io/pypa/manylinux2010_x86_64) and [`quay.io/pypa/manylinux2010_i686`](https://quay.io/pypa/manylinux2010_i686).
Beware to specify a valid docker image that can be used the same as the official, default docker images: all necessary Python and pip versions need to be present in `/opt/python/`, and the `auditwheel` tool needs to be present for `cibuildwheel` to work. Apart from that, the architecture and relevant shared system libraries need to be manylinux1-compatible in order to produce valid `manylinux1` wheels (see https://github.com/pypa/manylinux and [PEP 513](https://www.python.org/dev/peps/pep-0513/) for more details). The value of this option can either be set to `manylinux1` or `manylinux2010` to use the [official `manylinux` images](https://github.com/pypa/manylinux), or any other valid Docker image name.
Beware to specify a valid Docker image that can be used in the same way as the official, default Docker images: all necessary Python and pip versions need to be present in `/opt/python/`, and the `auditwheel` tool needs to be present for `cibuildwheel` to work. Apart from that, the architecture and relevant shared system libraries need to be manylinux1- or manylinux2010-compatible in order to produce valid `manylinux1`/`manylinux2010` wheels (see https://github.com/pypa/manylinux, [PEP 513](https://www.python.org/dev/peps/pep-0513/), and [PEP 571](https://www.python.org/dev/peps/pep-0571/) for more details).
Note that `auditwheel` detects the version of the `manylinux` standard in the Docker image through the `AUDITWHEEL_PLAT` environment variable, as `cibuildwheel` has no way of detecting the correct `--plat` command line argument to pass to `auditwheel` for a custom image. If a Docker image does not correctly set this `AUDITWHEEL_PLAT` environment variable, the `CIBW_ENVIRONMENT` option can be used to do so (e.g., `CIBW_ENVIRONMENT="manylinux2010_$(uname -m)"`).
Example: `manylinux1`
Example: `dockcross/manylinux-x64` Example: `dockcross/manylinux-x64`
Example: `dockcross/manylinux-x86` Example: `dockcross/manylinux-x86`
+12
View File
@@ -73,6 +73,18 @@ script:
- cibuildwheel --output-dir wheelhouse - cibuildwheel --output-dir wheelhouse
``` ```
To build on Windows too, add this matrix entry:
```yaml
- os: windows
language: shell
before_install:
- choco install python3 --version 3.6.8 --no-progress -y
env:
- PATH=/c/Python36:/c/Python36/Scripts:$PATH
```
Note that building Windows Python 2.7 wheels on Travis is unsupported.
Commit this file, enable building of your repo on Travis CI, and push. Commit this file, enable building of your repo on Travis CI, and push.
Then setup a deployment method by following the [Travis CI deployment docs](https://docs.travis-ci.com/user/deployment/), or see [Delivering to PyPI](deliver-to-pypi.md). For more info on `.travis.yml`, check out the [docs](https://docs.travis-ci.com/). Then setup a deployment method by following the [Travis CI deployment docs](https://docs.travis-ci.com/user/deployment/), or see [Delivering to PyPI](deliver-to-pypi.md). For more info on `.travis.yml`, check out the [docs](https://docs.travis-ci.com/).
+5 -1
View File
@@ -17,6 +17,10 @@ def test():
def test_build_identifiers(): def test_build_identifiers():
# check that the number of expected wheels matches the number of build # check that the number of expected wheels matches the number of build
# identifiers # identifiers
expected_wheels = utils.expected_wheels('spam', '0.1.0') # after adding CIBW_MANYLINUX_IMAGE to support manylinux2010, there
# can be multiple wheels for each wheel, though, so we need to limit
# the expected wheels
expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0')
if not '-manylinux' in w or '-manylinux1' in w]
build_identifiers = utils.cibuildwheel_get_build_identifiers(project_dir) build_identifiers = utils.cibuildwheel_get_build_identifiers(project_dir)
assert len(expected_wheels) == len(build_identifiers) assert len(expected_wheels) == len(build_identifiers)
+15 -1
View File
@@ -1,4 +1,5 @@
import os import os, subprocess
import pytest
import utils import utils
def test(): def test():
@@ -35,3 +36,16 @@ def test_extras_require():
expected_wheels = utils.expected_wheels('spam', '0.1.0') expected_wheels = utils.expected_wheels('spam', '0.1.0')
actual_wheels = os.listdir('wheelhouse') actual_wheels = os.listdir('wheelhouse')
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_failing_test():
'''Ensure a failing test causes cibuildwheel to error out and exit'''
project_dir = os.path.dirname(__file__)
with pytest.raises(subprocess.CalledProcessError):
utils.cibuildwheel_run(project_dir, add_env={
'CIBW_TEST_COMMAND': 'false',
})
assert len(os.listdir('wheelhouse'))
+7 -4
View File
@@ -5,14 +5,17 @@ def test():
project_dir = os.path.dirname(__file__) project_dir = os.path.dirname(__file__)
if utils.platform != 'linux': if utils.platform != 'linux':
pytest.skip('the docker test is only relevant to the linux build') pytest.skip('the test is only relevant to the linux build')
utils.cibuildwheel_run(project_dir, add_env={ utils.cibuildwheel_run(project_dir, add_env={
'CIBW_MANYLINUX1_X86_64_IMAGE': 'dockcross/manylinux-x64', 'CIBW_MANYLINUX_X86_64_IMAGE': 'dockcross/manylinux2010-x64',
'CIBW_MANYLINUX1_I686_IMAGE': 'dockcross/manylinux-x86', 'CIBW_MANYLINUX_I686_IMAGE': 'dockcross/manylinux1-x86',
'CIBW_BEFORE_BUILD': '/opt/python/cp36-cp36m/bin/pip install -U auditwheel', # Currently necessary on dockcross images to get auditwheel 2.1 supporting AUDITWHEEL_PLAT
'CIBW_ENVIRONMENT': 'AUDITWHEEL_PLAT=`if [ $(uname -i) == "x86_64" ]; then echo "manylinux2010_x86_64"; else echo "manylinux1_i686"; fi`',
}) })
# also check that we got the right wheels built # also check that we got the right wheels built
expected_wheels = utils.expected_wheels('spam', '0.1.0') expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0')
if '-manylinux2010_i686' not in w]
actual_wheels = os.listdir('wheelhouse') actual_wheels = os.listdir('wheelhouse')
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
@@ -0,0 +1,21 @@
import os, pytest
import utils
def test():
project_dir = os.path.dirname(__file__)
if utils.platform != 'linux':
pytest.skip('the docker test is only relevant to the linux build')
# build the wheels
# CFLAGS environment veriable is ecessary to fail on 'malloc_info' (on manylinux1) during compilation/linking,
# rather than when dynamically loading the Python
utils.cibuildwheel_run(project_dir, add_env={
'CIBW_ENVIRONMENT': 'CFLAGS="$CFLAGS -Werror=implicit-function-declaration"',
})
# also check that we got the right wheels
expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0')
if not '-manylinux' in w or '-manylinux2010' in w]
actual_wheels = os.listdir('wheelhouse')
assert set(actual_wheels) == set(expected_wheels)
+7
View File
@@ -0,0 +1,7 @@
from setuptools import setup, Extension
setup(
name="spam",
ext_modules=[Extension('spam', sources=['spam.c'])],
version="0.1.0",
)
+57
View File
@@ -0,0 +1,57 @@
#include <Python.h>
#if defined(__linux__)
#include <malloc.h>
#endif
static PyObject *
spam_system(PyObject *self, PyObject *args)
{
const char *command;
int sts = 0;
if (!PyArg_ParseTuple(args, "s", &command))
return NULL;
#if defined(__linux__)
sts = malloc_info(0, stdout);
#endif
if (sts == 0) {
sts = system(command);
}
return PyLong_FromLong(sts);
}
/* Module initialization */
#if PY_MAJOR_VERSION >= 3
#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
#define MOD_DEF(m, name, doc, methods, module_state_size) \
static struct PyModuleDef moduledef = { \
PyModuleDef_HEAD_INIT, name, doc, module_state_size, methods, }; \
m = PyModule_Create(&moduledef);
#define MOD_RETURN(m) return m;
#else
#define MOD_INIT(name) PyMODINIT_FUNC init##name(void)
#define MOD_DEF(m, name, doc, methods, module_state_size) \
m = Py_InitModule3(name, methods, doc);
#define MOD_RETURN(m) return;
#endif
static PyMethodDef module_methods[] = {
{"system", (PyCFunction)spam_system, METH_VARARGS,
"Execute a shell command."},
{NULL} /* Sentinel */
};
MOD_INIT(spam)
{
PyObject* m;
MOD_DEF(m,
"spam",
"Example module",
module_methods,
-1)
MOD_RETURN(m)
}
+18 -2
View File
@@ -6,7 +6,8 @@ This file is added to the PYTHONPATH in the test runner at bin/run_test.py.
import subprocess, sys, os import subprocess, sys, os
IS_RUNNING_ON_AZURE = os.path.exists('C:\\hostedtoolcache') IS_WINDOWS_RUNNING_ON_AZURE = os.path.exists('C:\\hostedtoolcache')
IS_WINDOWS_RUNNING_ON_TRAVIS = os.environ.get('TRAVIS_OS_NAME') == 'windows'
def cibuildwheel_get_build_identifiers(project_path, env=None): def cibuildwheel_get_build_identifiers(project_path, env=None):
@@ -54,12 +55,24 @@ def expected_wheels(package_name, package_version):
'{package_name}-{package_version}-cp35-cp35m-manylinux1_x86_64.whl', '{package_name}-{package_version}-cp35-cp35m-manylinux1_x86_64.whl',
'{package_name}-{package_version}-cp36-cp36m-manylinux1_x86_64.whl', '{package_name}-{package_version}-cp36-cp36m-manylinux1_x86_64.whl',
'{package_name}-{package_version}-cp37-cp37m-manylinux1_x86_64.whl', '{package_name}-{package_version}-cp37-cp37m-manylinux1_x86_64.whl',
'{package_name}-{package_version}-cp27-cp27m-manylinux2010_x86_64.whl',
'{package_name}-{package_version}-cp27-cp27mu-manylinux2010_x86_64.whl',
'{package_name}-{package_version}-cp34-cp34m-manylinux2010_x86_64.whl',
'{package_name}-{package_version}-cp35-cp35m-manylinux2010_x86_64.whl',
'{package_name}-{package_version}-cp36-cp36m-manylinux2010_x86_64.whl',
'{package_name}-{package_version}-cp37-cp37m-manylinux2010_x86_64.whl',
'{package_name}-{package_version}-cp27-cp27m-manylinux1_i686.whl', '{package_name}-{package_version}-cp27-cp27m-manylinux1_i686.whl',
'{package_name}-{package_version}-cp27-cp27mu-manylinux1_i686.whl', '{package_name}-{package_version}-cp27-cp27mu-manylinux1_i686.whl',
'{package_name}-{package_version}-cp34-cp34m-manylinux1_i686.whl', '{package_name}-{package_version}-cp34-cp34m-manylinux1_i686.whl',
'{package_name}-{package_version}-cp35-cp35m-manylinux1_i686.whl', '{package_name}-{package_version}-cp35-cp35m-manylinux1_i686.whl',
'{package_name}-{package_version}-cp36-cp36m-manylinux1_i686.whl', '{package_name}-{package_version}-cp36-cp36m-manylinux1_i686.whl',
'{package_name}-{package_version}-cp37-cp37m-manylinux1_i686.whl', '{package_name}-{package_version}-cp37-cp37m-manylinux1_i686.whl',
'{package_name}-{package_version}-cp27-cp27m-manylinux2010_i686.whl',
'{package_name}-{package_version}-cp27-cp27mu-manylinux2010_i686.whl',
'{package_name}-{package_version}-cp34-cp34m-manylinux2010_i686.whl',
'{package_name}-{package_version}-cp35-cp35m-manylinux2010_i686.whl',
'{package_name}-{package_version}-cp36-cp36m-manylinux2010_i686.whl',
'{package_name}-{package_version}-cp37-cp37m-manylinux2010_i686.whl',
] ]
elif platform == 'windows': elif platform == 'windows':
templates = [ templates = [
@@ -85,9 +98,12 @@ def expected_wheels(package_name, package_version):
else: else:
raise Exception('unsupported platform') raise Exception('unsupported platform')
if IS_RUNNING_ON_AZURE: if IS_WINDOWS_RUNNING_ON_AZURE:
# Python 3.4 isn't supported on Azure. # Python 3.4 isn't supported on Azure.
templates = [t for t in templates if '-cp34-' not in t] templates = [t for t in templates if '-cp34-' not in t]
if IS_WINDOWS_RUNNING_ON_TRAVIS:
# Python 2.7 and 3.4 isn't supported on Travis.
templates = [t for t in templates if '-cp27-' not in t and '-cp34-' not in t]
return [filename.format(package_name=package_name, package_version=package_version) return [filename.format(package_name=package_name, package_version=package_version)
for filename in templates] for filename in templates]