Skip to content

Custom test checks #136

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,8 @@ Options
-------

```
usage: cibuildwheel [-h]
[--output-dir OUTPUT_DIR]
[--platform PLATFORM]
usage: cibuildwheel [-h] [--platform {auto,linux,macos,windows}]
[--output-dir OUTPUT_DIR] [--print-build-identifiers]
[project_dir]

Build wheels for all the platforms.
Expand All @@ -174,7 +173,10 @@ optional arguments:
you need to run in Windows, and it will build and test
for all versions of Python at C:\PythonXX[-x64].
--output-dir OUTPUT_DIR
Destination folder for the wheels.
Destination folder for the wheels.
--print-build-identifiers
Print the build identifiers matched by the current
invocation and exit.

```

Expand Down
2 changes: 1 addition & 1 deletion bin/run_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def single_run(test_project):
print('%s built successfully. %i wheels built.' % (test_project, len(wheels)))

# check some wheels were actually built
assert len(wheels) >= 3
subprocess.check_call([sys.executable, os.path.join(test_project, 'check.py')])

# clean up
shutil.rmtree('wheelhouse')
Expand Down
2 changes: 1 addition & 1 deletion bin/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

### run the integration tests

test_projects = glob('test/??_*')
test_projects = sorted(glob('test/??_*'))

if len(test_projects) == 0:
print('No test projects found. Aborting.', file=sys.stderr)
Expand Down
24 changes: 24 additions & 0 deletions cibuildwheel/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ def main():
help=('Path to the project that you want wheels for. Default: the current '
'directory.'))

parser.add_argument('--print-build-identifiers',
action='store_true',
help='Print the build identifiers matched by the current invocation and exit.')

args = parser.parse_args()

if args.platform != 'auto':
Expand Down Expand Up @@ -109,6 +113,10 @@ def main():
print('cibuildwheel: Could not find setup.py at root of project', file=sys.stderr)
exit(2)

if args.print_build_identifiers:
print_build_identifiers(platform, build_selector)
exit(0)

build_options = dict(
project_dir=project_dir,
output_dir=output_dir,
Expand Down Expand Up @@ -149,6 +157,7 @@ def main():
else:
raise Exception('Unsupported platform')


def print_preamble(platform, build_options):
print(textwrap.dedent('''
_ _ _ _ _ _ _
Expand All @@ -173,6 +182,21 @@ def print_preamble(platform, build_options):

print('\nHere we go!\n')


def print_build_identifiers(platform, build_selector):
if platform == 'linux':
python_configurations = cibuildwheel.linux.get_python_configurations(build_selector)
elif platform == 'windows':
python_configurations = cibuildwheel.windows.get_python_configurations(build_selector)
elif platform == 'macos':
python_configurations = cibuildwheel.macos.get_python_configurations(build_selector)
else:
python_configurations = []

for config in python_configurations:
print(config.identifier)


def detect_warnings(platform, build_options):
warnings = []

Expand Down
25 changes: 14 additions & 11 deletions cibuildwheel/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,7 @@
from pipes import quote as shlex_quote


def build(project_dir, output_dir, test_command, test_requires, before_build, build_verbosity, build_selector, environment, manylinux1_images):
try:
subprocess.check_call(['docker', '--version'])
except:
print('cibuildwheel: Docker not found. Docker is required to run Linux builds. '
'If you\'re building on Travis CI, add `services: [docker]` to your .travis.yml.'
'If you\'re building on Circle CI in Linux, add a `setup_remote_docker` step to your .circleci/config.yml',
file=sys.stderr)
exit(2)

def get_python_configurations(build_selector):
PythonConfiguration = namedtuple('PythonConfiguration', ['identifier', 'path'])
python_configurations = [
PythonConfiguration(identifier='cp27-manylinux1_x86_64', path='/opt/python/cp27-cp27m'),
Expand All @@ -36,8 +27,20 @@ def build(project_dir, output_dir, test_command, test_requires, before_build, bu
]

# skip builds as required
python_configurations = [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, before_build, build_verbosity, build_selector, environment, manylinux1_images):
try:
subprocess.check_call(['docker', '--version'])
except:
print('cibuildwheel: Docker not found. Docker is required to run Linux builds. '
'If you\'re building on Travis CI, add `services: [docker]` to your .travis.yml.'
'If you\'re building on Circle CI in Linux, add a `setup_remote_docker` step to your .circleci/config.yml',
file=sys.stderr)
exit(2)

python_configurations = get_python_configurations(build_selector)
platforms = [
('manylinux1_x86_64', manylinux1_images.get('x86_64') or 'quay.io/pypa/manylinux1_x86_64'),
('manylinux1_i686', manylinux1_images.get('i686') or 'quay.io/pypa/manylinux1_i686'),
Expand Down
13 changes: 8 additions & 5 deletions cibuildwheel/macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from .util import prepare_command, get_build_verbosity_extra_flags


def build(project_dir, output_dir, test_command, test_requires, before_build, build_verbosity, build_selector, environment):
def get_python_configurations(build_selector):
PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'identifier', 'url'])
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'),
Expand All @@ -19,6 +19,13 @@ def build(project_dir, output_dir, test_command, test_requires, before_build, bu
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.2/python-3.7.2-macosx10.6.pkg'),
]

# 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, before_build, build_verbosity, build_selector, environment):
python_configurations = get_python_configurations(build_selector)
get_pip_url = 'https://bootstrap.pypa.io/get-pip.py'
get_pip_script = '/tmp/get-pip.py'

Expand All @@ -42,10 +49,6 @@ def call(args, env=None, cwd=None, shell=False):
call(['curl', '-L', '-o', get_pip_script, get_pip_url])

for config in python_configurations:
if not build_selector(config.identifier):
print('cibuildwheel: Skipping build %s' % config.identifier, file=sys.stderr)
continue

# if this version of python isn't installed, get it from python.org and install
python_package_identifier = 'org.python.Python.PythonFramework-%s' % config.version
if python_package_identifier not in installed_system_packages:
Expand Down
37 changes: 20 additions & 17 deletions cibuildwheel/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,25 @@
from .util import prepare_command, get_build_verbosity_extra_flags


def get_python_configurations(build_selector):
PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'arch', 'identifier', 'path'])
python_configurations = [
PythonConfiguration(version='2.7.x', arch="32", identifier='cp27-win32', path='C:\Python27'),
PythonConfiguration(version='2.7.x', arch="64", identifier='cp27-win_amd64', path='C:\Python27-x64'),
PythonConfiguration(version='3.4.x', arch="32", identifier='cp34-win32', path='C:\Python34'),
PythonConfiguration(version='3.4.x', arch="64", identifier='cp34-win_amd64', path='C:\Python34-x64'),
PythonConfiguration(version='3.5.x', arch="32", identifier='cp35-win32', path='C:\Python35'),
PythonConfiguration(version='3.5.x', arch="64", identifier='cp35-win_amd64', path='C:\Python35-x64'),
PythonConfiguration(version='3.6.x', arch="32", identifier='cp36-win32', path='C:\Python36'),
PythonConfiguration(version='3.6.x', arch="64", identifier='cp36-win_amd64', path='C:\Python36-x64'),
PythonConfiguration(version='3.7.x', arch="32", identifier='cp37-win32', path='C:\Python37'),
PythonConfiguration(version='3.7.x', arch="64", identifier='cp37-win_amd64', path='C:\Python37-x64'),
]

# 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, before_build, build_verbosity, build_selector, environment):
# run_with_env is a cmd file that sets the right environment variables to
run_with_env = os.path.join(tempfile.gettempdir(), 'appveyor_run_with_env.cmd')
Expand All @@ -24,29 +43,13 @@ def shell(args, env=None, cwd=None):
args = ['cmd', '/E:ON', '/V:ON', '/C', run_with_env] + args
return subprocess.check_call(' '.join(args), env=env, cwd=cwd)

PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'arch', 'identifier', 'path'])
python_configurations = [
PythonConfiguration(version='2.7.x', arch="32", identifier='cp27-win32', path='C:\Python27'),
PythonConfiguration(version='2.7.x', arch="64", identifier='cp27-win_amd64', path='C:\Python27-x64'),
PythonConfiguration(version='3.4.x', arch="32", identifier='cp34-win32', path='C:\Python34'),
PythonConfiguration(version='3.4.x', arch="64", identifier='cp34-win_amd64', path='C:\Python34-x64'),
PythonConfiguration(version='3.5.x', arch="32", identifier='cp35-win32', path='C:\Python35'),
PythonConfiguration(version='3.5.x', arch="64", identifier='cp35-win_amd64', path='C:\Python35-x64'),
PythonConfiguration(version='3.6.x', arch="32", identifier='cp36-win32', path='C:\Python36'),
PythonConfiguration(version='3.6.x', arch="64", identifier='cp36-win_amd64', path='C:\Python36-x64'),
PythonConfiguration(version='3.7.x', arch="32", identifier='cp37-win32', path='C:\Python37'),
PythonConfiguration(version='3.7.x', arch="64", identifier='cp37-win_amd64', path='C:\Python37-x64'),
]
python_configurations = get_python_configurations(build_selector)

abs_project_dir = os.path.abspath(project_dir)
temp_dir = tempfile.mkdtemp(prefix='cibuildwheel')
built_wheel_dir = os.path.join(temp_dir, 'built_wheel')

for config in python_configurations:
if not build_selector(config.identifier):
print('cibuildwheel: Skipping build %s' % config.identifier, file=sys.stderr)
continue

# check python & pip exist for this configuration
assert os.path.exists(os.path.join(config.path, 'python.exe'))
assert os.path.exists(os.path.join(config.path, 'Scripts', 'pip.exe'))
Expand Down
9 changes: 9 additions & 0 deletions test/01_basic/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import glob
import subprocess
import sys

build_identifiers = subprocess.check_output([sys.executable, '-m', 'cibuildwheel', '--print-build-identifiers'], universal_newlines=True).strip().split('\n')
Copy link
Contributor

@joerick joerick Apr 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure on getting cibuildwheel to tell us what it should be producing... a mistake in the python configurations would then not be caught by the tests. Also, I'm happy for the tests to contain extra, redundant information, as long as that is checked by the machine! So I think I'd prefer the tests to assert all the wheels that they expect to see on each platform.

The --print-build-identifiers arg will be useful regardless :).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. Maybe on reflection, just one test needs to check that the build identifiers match the produced wheels. Then we can trust it after that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure on getting cibuildwheel to tell us what it should be producing... a mistake in the python configurations would then not be caught by the tests.

Good point; the using this --print-build-identifiers still has turned out to be more code duplication than expected. It would be good if we could make some utilities Python code to be shared by the different tests.

The --print-build-identifiers arg will be useful regardless :).

If we can do the previous, should I then split up this PR into two separate ones? One for the tests, and one for --print-build-identifiers?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe on reflection, just one test needs to check that the build identifiers match the produced wheels. Then we can trust it after that.

Problem here is that there's no unambiguous mapping from build identifier to wheel name. Particularly in the cp27-cp27m and cp27-cp27mu cases, which both have cp27-... identifiers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Problem here is that there's no unambiguous mapping from build identifier to wheel name. Particularly in the cp27-cp27m and cp27-cp27mu cases, which both have cp27-... identifiers

argh, good point. maybe just statically writing out expected wheels in the test will be better then.

If we can do the previous, should I then split up this PR into two separate ones? One for the tests, and one for --print-build-identifiers?

I think for the later tests might find the build_identifiers useful, let's keep it in for now

expected_identifiers = build_identifiers
built_wheels = glob.glob('wheelhouse/*.whl')

assert len(built_wheels) == len(expected_identifiers)
9 changes: 9 additions & 0 deletions test/02_test/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import glob
import subprocess
import sys

build_identifiers = subprocess.check_output([sys.executable, '-m', 'cibuildwheel', '--print-build-identifiers'], universal_newlines=True).strip().split('\n')
expected_identifiers = build_identifiers
built_wheels = glob.glob('wheelhouse/*.whl')

assert len(built_wheels) == len(expected_identifiers)
9 changes: 9 additions & 0 deletions test/03_before_build/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import glob
import subprocess
import sys

build_identifiers = subprocess.check_output([sys.executable, '-m', 'cibuildwheel', '--print-build-identifiers'], universal_newlines=True).strip().split('\n')
expected_identifiers = build_identifiers
built_wheels = glob.glob('wheelhouse/*.whl')

assert len(built_wheels) == len(expected_identifiers)
9 changes: 9 additions & 0 deletions test/04_build_skip/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import glob
import subprocess
import sys

build_identifiers = subprocess.check_output([sys.executable, '-m', 'cibuildwheel', '--print-build-identifiers'], universal_newlines=True).strip().split('\n')
expected_identifiers = [identifier for identifier in build_identifiers if "cp3" in identifier and "cp34" not in identifier]
built_wheels = glob.glob('wheelhouse/*.whl')

assert len(built_wheels) == len(expected_identifiers)
9 changes: 9 additions & 0 deletions test/05_environment/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import glob
import subprocess
import sys

build_identifiers = subprocess.check_output([sys.executable, '-m', 'cibuildwheel', '--print-build-identifiers'], universal_newlines=True).strip().split('\n')
expected_identifiers = build_identifiers
built_wheels = glob.glob('wheelhouse/*.whl')

assert len(built_wheels) == len(expected_identifiers)
9 changes: 9 additions & 0 deletions test/06_docker_images/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import glob
import subprocess
import sys

build_identifiers = subprocess.check_output([sys.executable, '-m', 'cibuildwheel', '--print-build-identifiers'], universal_newlines=True).strip().split('\n')
expected_identifiers = [identifier for identifier in build_identifiers if 'macos' not in identifier and 'win' not in identifier]
built_wheels = glob.glob('wheelhouse/*.whl')

assert len(built_wheels) == len(expected_identifiers)
2 changes: 1 addition & 1 deletion test/06_docker_images/environment.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"CIBW_MANYLINUX1_X86_64_IMAGE": "dockcross/manylinux-x64",
"CIBW_MANYLINUX1_I686_IMAGE": "dockcross/manylinux-x86",
"CIBW_SKIP": "cp37-manylinux*"
"CIBW_SKIP": "*macos* *win*"
}
9 changes: 9 additions & 0 deletions test/07_ssl/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import glob
import subprocess
import sys

build_identifiers = subprocess.check_output([sys.executable, '-m', 'cibuildwheel', '--print-build-identifiers'], universal_newlines=True).strip().split('\n')
expected_identifiers = build_identifiers
built_wheels = glob.glob('wheelhouse/*.whl')

assert len(built_wheels) == len(expected_identifiers)