diff --git a/.travis.yml b/.travis.yml index 02b90836..4ad0022c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,8 @@ jobs: env: - PYTHON=C:\\Python35\\python - - name: Linux | s390x | Python 3.5 + - &linux_s390x_35 + name: Linux | s390x | Python 3.5 language: python python: 3.5 services: docker @@ -43,12 +44,7 @@ jobs: allow_failures: # must repeat the s390x job above exactly to match - - name: Linux | s390x | Python 3.5 - language: python - python: 3.5 - services: docker - arch: s390x - env: PYTHON=python + - *linux_s390x_35 install: $PYTHON -m pip install -r requirements-dev.txt diff --git a/README.md b/README.md index 7f5f0a8c..6a069aa3 100644 --- a/README.md +++ b/README.md @@ -18,14 +18,15 @@ What does it do? | | macOS x86_64 | Windows 64bit | Windows 32bit | manylinux x86_64 | manylinux i686 | manylinux aarch64 | manylinux ppc64le | manylinux s390x | |---|---|---|---|---|---|---|---|---| | CPython 2.7 | ✅ | ✅¹ | ✅¹ | ✅ | ✅ | | | | -| CPython 3.5 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| CPython 3.6 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| CPython 3.7 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| CPython 3.8 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| CPython 3.5 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | +| CPython 3.6 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | +| CPython 3.7 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | +| CPython 3.8 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | | PyPy 2.7 v7.3.0 | ✅ | | ✅ | ✅ | | | | | | PyPy 3.6 v7.3.0 | ✅ | | ✅ | ✅ | | | | | -¹ Not supported on Travis +¹ Not supported on Travis
+² Beta support until Travis CI fixes a bug - Builds manylinux, macOS and Windows wheels for CPython and PyPy 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) @@ -75,7 +76,7 @@ env: # Note: TWINE_PASSWORD is set to a PyPI API token in Travis settings install: - - python3 -m pip install cibuildwheel==1.1.0 + - python3 -m pip install cibuildwheel==1.2.0 script: # build the wheels, put them into './wheelhouse' @@ -104,6 +105,7 @@ Options | | [`CIBW_REPAIR_WHEEL_COMMAND`](https://cibuildwheel.readthedocs.io/en/stable/options/#repair-wheel-command) | Execute a shell command to repair each (non-pure Python) built wheel | | | [`CIBW_MANYLINUX_X86_64_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) [`CIBW_MANYLINUX_I686_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) [`CIBW_MANYLINUX_PYPY_X86_64_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#manylinux-image) | Specify alternative manylinux docker images | | **Testing** | [`CIBW_TEST_COMMAND`](https://cibuildwheel.readthedocs.io/en/stable/options/#test-command) | Execute a shell command to test each built wheel | +| | [`CIBW_BEFORE_TEST`](https://cibuildwheel.readthedocs.io/en/stable/options/#before-test) | Execute shell command to prepare test environment | | | [`CIBW_TEST_REQUIRES`](https://cibuildwheel.readthedocs.io/en/stable/options/#test-requires) | Install Python dependencies before running the tests | | | [`CIBW_TEST_EXTRAS`](https://cibuildwheel.readthedocs.io/en/stable/options/#test-extras) | Install your wheel for testing using extras_require | | **Other** | [`CIBW_BUILD_VERBOSITY`](https://cibuildwheel.readthedocs.io/en/stable/options/#build-verbosity) | Increase/decrease the output of pip wheel | @@ -123,6 +125,7 @@ Here are some repos that use cibuildwheel. - [apriltags2-ethz](https://github.com/safijari/apriltags2_ethz) - [TgCrypto](https://github.com/pyrogram/tgcrypto) - [Twisted](https://github.com/twisted/twisted) +- [gmic-py](https://github.com/dtschump/gmic-py) > Add your repo here! Send a PR. @@ -138,6 +141,29 @@ This is similar to static linking, so it might have some licence implications. C Changelog ========= +### 1.2.0 + +_8 March 2020_ + +- ✨ Add support for building PyPy wheels, across Manylinux, macOS, and + Windows. (#185) +- ✨ Added the ability to build ARM64 (aarch64), ppc64le, and s390x wheels, + using manylinux2014 and Travis CI. (#273) +- ✨ You can now build macOS wheels on Appveyor. (#230) +- 🛠 Changed default macOS minimum target to 10.9, from 10.6. This allows the + use of more modern C++ libraries, among other things. (#156) +- 🛠 Stop building universal binaries on macOS. We now only build x86_64 + wheels on macOS. (#220) +- ✨ Allow chaining of commands using `&&` and `||` on Windows inside + CIBW_BEFORE_BUILD and CIBW_TEST_COMMAND. (#293) +- 🛠 Improved error reporting for failed Cython builds due to stale .so files + (#263) +- 🛠 Update CPython from 3.7.5 to 3.7.6 and from 3.8.0 to 3.8.2 on Mac/Windows +- 🛠 Improved error messages when a bad config breaks cibuildwheel's PATH + variable. (#264) +- ⚠️ Removed support for *running* cibuildwheel on Python 2.7. cibuildwheel + will continue to build Python 2.7 wheels for a little while. (#265) + ### 1.1.0 _7 December 2019_ diff --git a/bin/bump_version.py b/bin/bump_version.py new file mode 100755 index 00000000..8ad630ac --- /dev/null +++ b/bin/bump_version.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 + +import click +from pathlib import Path +import os +import cibuildwheel +from packaging.version import Version, InvalidVersion +import subprocess +import glob + +config = [ + # file path, version find/replace format + ('cibuildwheel/__init__.py', "__version__ = '{}'"), + ('setup.py', "version='{}'"), + ('README.md', "cibuildwheel=={}"), + ('examples/*', "cibuildwheel=={}"), +] + + +@click.command() +def bump_version(): + git_changes_result = subprocess.run(['git diff-index --quiet HEAD --'], shell=True) + repo_has_uncommitted_changes = git_changes_result.returncode != 0 + + if repo_has_uncommitted_changes: + print('error: Uncommitted changes detected.') + exit(1) + + current_version = cibuildwheel.__version__ + print( 'Current version:', current_version) # noqa + new_version = input(' New version: ').strip() + + try: + Version(new_version) + except InvalidVersion: + print("error: This version doesn't conform to PEP440") + print(' https://www.python.org/dev/peps/pep-0440/') + exit(1) + + actions = [] + + for path_pattern, version_pattern in config: + paths = [Path(p) for p in glob.glob(path_pattern)] + + if not paths: + print(f'error: Pattern {path_pattern} didn’t match any files') + exit(1) + + find_pattern = version_pattern.format(current_version) + replace_pattern = version_pattern.format(new_version) + found_at_least_one_file_needing_update = False + + for path in paths: + contents = path.read_text(encoding='utf8') + if find_pattern in contents: + found_at_least_one_file_needing_update = True + actions.append( + (path, find_pattern, replace_pattern) + ) + + if not found_at_least_one_file_needing_update: + print('error: Didn’t find any occurences of “{}” in “{}”'.format(find_pattern, path_pattern)) + exit(1) + + print() + print("Here's the plan:") + print() + + for action in actions: + print('{} {red}{}{off} → {green}{}{off}'.format( + *action, + red="\u001b[31m", green="\u001b[32m", off="\u001b[0m" + )) + + print('Then commit, and tag as v{}'.format(new_version)) + + answer = input('Proceed? [y/N] ').strip() + + if answer != 'y': + print('Aborted') + exit(1) + + for path, find, replace in actions: + contents = path.read_text(encoding='utf8') + contents = contents.replace(find, replace) + path.write_text(contents, encoding='utf8') + + print('Files updated. If you want to update the changelog as part of this') + print('commit, do that now.') + + while input('Type "done" to continue: ').strip().lower() != 'done': + pass + + subprocess.run([ + 'git', 'commit', + '-a', + '-m', f'Bump version: v{new_version}' + ], check=True) + + subprocess.run([ + 'git', 'tag', + '-a', + '-m', f'v{new_version}', + f'v{new_version}' + ], check=True) + + print('Done.') + + +if __name__ == '__main__': + os.chdir(os.path.dirname(__file__)) + os.chdir('..') + bump_version() diff --git a/cibuildwheel/__init__.py b/cibuildwheel/__init__.py index 1a72d32e..58d478ab 100644 --- a/cibuildwheel/__init__.py +++ b/cibuildwheel/__init__.py @@ -1 +1 @@ -__version__ = '1.1.0' +__version__ = '1.2.0' diff --git a/cibuildwheel/__main__.py b/cibuildwheel/__main__.py index 6c3963ff..ad41c485 100644 --- a/cibuildwheel/__main__.py +++ b/cibuildwheel/__main__.py @@ -115,6 +115,7 @@ def main(): repair_command_default = '' repair_command = get_option_from_environment('CIBW_REPAIR_WHEEL_COMMAND', platform=platform, default=repair_command_default) environment_config = get_option_from_environment('CIBW_ENVIRONMENT', platform=platform, default='') + before_test = get_option_from_environment('CIBW_BEFORE_TEST', platform=platform, default='') dependency_versions = get_option_from_environment('CIBW_DEPENDENCY_VERSIONS', platform=platform, default='pinned') if dependency_versions == 'pinned': @@ -164,6 +165,7 @@ def main(): build_selector=build_selector, repair_command=repair_command, environment=environment, + before_test=before_test, dependency_constraints=dependency_constraints, ) diff --git a/cibuildwheel/linux.py b/cibuildwheel/linux.py index 5999c48d..d7ebfab2 100644 --- a/cibuildwheel/linux.py +++ b/cibuildwheel/linux.py @@ -68,7 +68,7 @@ def get_python_configurations(build_selector): return [c for c in python_configurations if matches_platform(c.identifier) and build_selector(c.identifier)] -def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, repair_command, environment, manylinux_images, dependency_constraints): +def build(project_dir, output_dir, test_command, before_test, test_requires, test_extras, before_build, build_verbosity, build_selector, repair_command, environment, manylinux_images, dependency_constraints): try: subprocess.check_call(['docker', '--version']) except Exception: @@ -175,6 +175,10 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef echo "Running tests using `which python`" + if [ ! -z {before_build} ]; then + sh -c {before_build} + fi + # 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 @@ -224,6 +228,9 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef environment_exports='\n'.join(environment.as_shell_commands()), uid=os.getuid(), gid=os.getgid(), + before_test=shlex.quote( + prepare_command(before_test, project='/project') if before_test else '' + ), dependency_install_flags='-c /constraints.txt' if dependency_constraints else '', ) ) diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index 349b398f..fabf8edf 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -106,7 +106,7 @@ def install_pypy(version, url): return installation_bin_path -def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, repair_command, environment, dependency_constraints): +def build(project_dir, output_dir, test_command, before_test, test_requires, test_extras, before_build, build_verbosity, build_selector, repair_command, environment, dependency_constraints): abs_project_dir = os.path.abspath(project_dir) temp_dir = tempfile.mkdtemp(prefix='cibuildwheel') built_wheel_dir = os.path.join(temp_dir, 'built_wheel') @@ -219,6 +219,10 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef # check that we are using the Python from the virtual environment call(['which', 'python'], env=virtualenv_env) + if before_test: + before_test_prepared = prepare_command(before_test, project=abs_project_dir) + call(before_test_prepared, env=virtualenv_env, shell=True) + # install the wheel call(['pip', 'install', repaired_wheel + test_extras], env=virtualenv_env) diff --git a/cibuildwheel/windows.py b/cibuildwheel/windows.py index ab7238bc..a9c56cf2 100644 --- a/cibuildwheel/windows.py +++ b/cibuildwheel/windows.py @@ -21,8 +21,7 @@ IS_RUNNING_ON_TRAVIS = os.environ.get('TRAVIS_OS_NAME') == 'windows' def shell(args, env=None, cwd=None): print('+ ' + ' '.join(args)) - args = ['cmd', '/E:ON', '/V:ON', '/C'] + args - return subprocess.check_call(' '.join(args), env=env, cwd=cwd) + return subprocess.check_call(' '.join(args), env=env, cwd=cwd, shell=True) def get_nuget_args(version, arch): @@ -88,7 +87,7 @@ def install_pypy(version, arch, url): return installation_path -def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, repair_command, environment, dependency_constraints): +def build(project_dir, output_dir, test_command, before_test, test_requires, test_extras, before_build, build_verbosity, build_selector, repair_command, environment, dependency_constraints): abs_project_dir = os.path.abspath(project_dir) temp_dir = tempfile.mkdtemp(prefix='cibuildwheel') built_wheel_dir = os.path.join(temp_dir, 'built_wheel') @@ -201,6 +200,10 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef # check that we are using the Python from the virtual environment shell(['which', 'python'], env=virtualenv_env) + if before_test: + before_test_prepared = prepare_command(before_test, project=abs_project_dir) + shell([before_test_prepared], env=virtualenv_env) + # install the wheel shell(['pip', 'install', repaired_wheel + test_extras], env=virtualenv_env) diff --git a/docs/options.md b/docs/options.md index 0d827274..1fd47118 100644 --- a/docs/options.md +++ b/docs/options.md @@ -194,7 +194,7 @@ If dependencies are required to build your wheel (for example if you include a h The active Python binary can be accessed using `python`, and pip with `pip`; `cibuildwheel` makes sure the right version of Python and pip will be executed. `{project}` can be used as a placeholder for the absolute path to the project's root and will be replaced by `cibuildwheel`. -On Linux and macOS, the command is run in a shell, so you can write things like `cmd1 && cmd2`. +The command is run in a shell, so you can write things like `cmd1 && cmd2`. Platform-specific variants also available:
`CIBW_BEFORE_BUILD_MACOS` | `CIBW_BEFORE_BUILD_WINDOWS` | `CIBW_BEFORE_BUILD_LINUX` @@ -209,6 +209,9 @@ CIBW_BEFORE_BUILD: pip install pybind11 # chain commands using && CIBW_BEFORE_BUILD: yum install -y libffi-dev && pip install . + +# run a script that's inside your repo +CIBW_BEFORE_BUILD: bash scripts/prepare_for_build.sh ``` @@ -229,7 +232,7 @@ The following placeholders must be used inside the command and will be replaced - `{wheel}` for the absolute path to the built wheel - `{dest_dir}` for the absolute path of the directory where to create the repaired wheel. -On Linux and macOS, the command is run in a shell, so you can write things like `cmd1 && cmd2`. +The command is run in a shell, so you can run multiple commands like `cmd1 && cmd2`. Platform-specific variants also available:
`CIBW_REPAIR_WHEEL_COMMAND_MACOS` | `CIBW_REPAIR_WHEEL_COMMAND_WINDOWS` | `CIBW_REPAIR_WHEEL_COMMAND_LINUX` @@ -340,7 +343,7 @@ CIBW_DEPENDENCY_VERSIONS: ./constraints.txt Shell command to run tests after the build. The wheel will be installed automatically and available for import from the tests. `{project}` can be used as a placeholder for the absolute path to the project's root and will be replaced by `cibuildwheel`. -On Linux and macOS, the command is run in a shell, so you can write things like `cmd1 && cmd2`. +The command is run in a shell, so you can write things like `cmd1 && cmd2`. Platform-specific variants also available:
`CIBW_TEST_COMMAND_MACOS` | `CIBW_TEST_COMMAND_WINDOWS` | `CIBW_TEST_COMMAND_LINUX` @@ -395,6 +398,33 @@ Platform-specific variants also available:
CIBW_TEST_EXTRAS: test,qt ``` +### `CIBW_BEFORE_TEST` {: #before-test} +> Execute a shell command before testing each wheel + +A shell command to run in **each** test virtual environment, before your wheel is installed and tested. This is useful if you need to install a non pip package, change values of environment variables +or perform multi step pip installation (e.g. installing `scikit-build` or `cython` before install test package) + +The active Python binary can be accessed using `python`, and pip with `pip`; `cibuildwheel` makes sure the right version of Python and pip will be executed. `{project}` can be used as a placeholder for the absolute path to the project's root and will be replaced by `cibuildwheel`. + +The command is run in a shell, so you can write things like `cmd1 && cmd2`. + +Platform-specific variants also available:
+ `CIBW_BEFORE_TEST_MACOS` | `CIBW_BEFORE_TEST_WINDOWS` | `CIBW_BEFORE_TEST_LINUX` + +#### Examples +```yaml +# install test dependencies with overwritten environment variables. +CIBW_BEFORE_TEST: CC=gcc CXX=g++ pip install -r requirements.txt + +# chain commands using && +CIBW_BEFORE_TEST: rm -rf ./data/cache && mkdir -p ./data/cache + +# install non pip python package +CIBW_BEFORE_TEST: cd some_dir; ./configure; make; make install + +# install python packages that are required to install test dependencies +CIBW_BEFORE_TEST: pip install cmake scikit-build +``` ## Other diff --git a/examples/appveyor-minimal.yml b/examples/appveyor-minimal.yml index a6d8654b..3b5625e1 100644 --- a/examples/appveyor-minimal.yml +++ b/examples/appveyor-minimal.yml @@ -12,7 +12,7 @@ stack: python 3.7 init: - cmd: set PATH=C:\Python37;C:\Python37\Scripts;%PATH% -install: python -m pip install cibuildwheel==1.1.0 +install: python -m pip install cibuildwheel==1.2.0 build_script: python -m cibuildwheel --output-dir wheelhouse diff --git a/examples/azure-pipelines-minimal.yml b/examples/azure-pipelines-minimal.yml index d5504b2d..d457e1b5 100644 --- a/examples/azure-pipelines-minimal.yml +++ b/examples/azure-pipelines-minimal.yml @@ -5,7 +5,7 @@ jobs: - task: UsePythonVersion@0 - bash: | python3 -m pip install --upgrade pip - pip3 install cibuildwheel==1.1.0 + pip3 install cibuildwheel==1.2.0 cibuildwheel --output-dir wheelhouse . - task: PublishBuildArtifacts@1 inputs: {pathtoPublish: 'wheelhouse'} @@ -16,7 +16,7 @@ jobs: - task: UsePythonVersion@0 - bash: | python3 -m pip install --upgrade pip - pip3 install cibuildwheel==1.1.0 + pip3 install cibuildwheel==1.2.0 cibuildwheel --output-dir wheelhouse . - task: PublishBuildArtifacts@1 inputs: {pathtoPublish: 'wheelhouse'} @@ -29,7 +29,7 @@ jobs: displayName: Install Visual C++ for Python 2.7 - bash: | python -m pip install --upgrade pip - pip install cibuildwheel==1.1.0 + pip install cibuildwheel==1.2.0 cibuildwheel --output-dir wheelhouse . - task: PublishBuildArtifacts@1 inputs: {pathtoPublish: 'wheelhouse'} diff --git a/examples/circleci-minimal.yml b/examples/circleci-minimal.yml index fd6c00e8..f76b011c 100644 --- a/examples/circleci-minimal.yml +++ b/examples/circleci-minimal.yml @@ -11,7 +11,7 @@ jobs: - run: name: Build the Linux wheels. command: | - pip3 install --user cibuildwheel==1.1.0 + pip3 install --user cibuildwheel==1.2.0 cibuildwheel --output-dir wheelhouse - store_artifacts: path: wheelhouse/ @@ -25,7 +25,7 @@ jobs: - run: name: Build the OS X wheels. command: | - pip3 install --user cibuildwheel==1.1.0 + pip3 install --user cibuildwheel==1.2.0 cibuildwheel --output-dir wheelhouse - store_artifacts: path: wheelhouse/ diff --git a/examples/travis-ci-deploy-only.yml b/examples/travis-ci-deploy-only.yml index 1e08893f..f205bc76 100644 --- a/examples/travis-ci-deploy-only.yml +++ b/examples/travis-ci-deploy-only.yml @@ -25,7 +25,7 @@ env: # Note: TWINE_PASSWORD is set to a PyPI API token in Travis settings install: - - python3 -m pip install cibuildwheel==1.1.0 + - python3 -m pip install cibuildwheel==1.2.0 script: # build the wheels, put them into './wheelhouse' diff --git a/examples/travis-ci-minimal.yml b/examples/travis-ci-minimal.yml index d3bb5a75..2060444e 100644 --- a/examples/travis-ci-minimal.yml +++ b/examples/travis-ci-minimal.yml @@ -26,7 +26,7 @@ jobs: - ln -s /c/Python38/python.exe /c/Python38/python3.exe install: - - python3 -m pip install cibuildwheel==1.1.0 + - python3 -m pip install cibuildwheel==1.2.0 script: # build the wheels, put them into './wheelhouse' diff --git a/examples/travis-ci-test-and-deploy.yml b/examples/travis-ci-test-and-deploy.yml index 2012a06f..5a92634a 100644 --- a/examples/travis-ci-test-and-deploy.yml +++ b/examples/travis-ci-test-and-deploy.yml @@ -56,7 +56,7 @@ jobs: - stage: deploy name: Build and deploy Linux wheels services: docker - install: python3 -m pip install cibuildwheel==1.1.0 + install: python3 -m pip install cibuildwheel==1.2.0 script: python3 -m cibuildwheel --output-dir wheelhouse after_success: | python3 -m pip install twine @@ -66,7 +66,7 @@ jobs: name: Build and deploy macOS wheels os: osx language: shell - install: python3 -m pip install cibuildwheel==1.1.0 + install: python3 -m pip install cibuildwheel==1.2.0 script: python3 -m cibuildwheel --output-dir wheelhouse after_success: | python3 -m pip install twine @@ -76,7 +76,7 @@ jobs: name: Build and deploy Windows wheels os: windows language: shell - install: python3 -m pip install cibuildwheel==1.1.0 + install: python3 -m pip install cibuildwheel==1.2.0 script: python3 -m cibuildwheel --output-dir wheelhouse after_success: | python3 -m pip install twine diff --git a/setup.cfg b/setup.cfg index 4346b720..b2c53158 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,24 +1,3 @@ -[bumpversion] -current_version = 1.1.0 -commit = True -tag = True -message = Bump version - -[bumpversion:file:setup.py] - -[bumpversion:file:cibuildwheel/__init__.py] - -[bumpversion:file:README.md] -search = cibuildwheel=={current_version} -replace = cibuildwheel=={new_version} - -[bumpversion:file:docs/setup.md] -search = cibuildwheel=={current_version} -replace = cibuildwheel=={new_version} - -[bdist_wheel] -universal = 1 - [flake8] ignore = E501,W503 application-import-names = cibuildwheel diff --git a/setup.py b/setup.py index 010d5621..e139d8fb 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ with io.open(os.path.join(this_directory, 'README.md'), encoding='utf-8') as f: setup( name='cibuildwheel', - version='1.1.0', + version='1.2.0', install_requires=['bashlex!=0.13'], description="Build Python wheels on CI with minimal configuration.", long_description=long_description, diff --git a/test/02_test/cibuildwheel_test.py b/test/02_test/cibuildwheel_test.py index ca084d65..21878d2c 100644 --- a/test/02_test/cibuildwheel_test.py +++ b/test/02_test/cibuildwheel_test.py @@ -15,7 +15,7 @@ def test(): # the 'false ||' bit is to ensure this command runs in a shell on # mac/linux. 'CIBW_TEST_COMMAND': 'false || nosetests {project}/test', - 'CIBW_TEST_COMMAND_WINDOWS': 'nosetests {project}/test', + 'CIBW_TEST_COMMAND_WINDOWS': 'COLOR 00 || nosetests {project}/test', }) # also check that we got the right wheels @@ -32,7 +32,7 @@ def test_extras_require(): # the 'false ||' bit is to ensure this command runs in a shell on # mac/linux. 'CIBW_TEST_COMMAND': 'false || nosetests {project}/test', - 'CIBW_TEST_COMMAND_WINDOWS': 'nosetests {project}/test', + 'CIBW_TEST_COMMAND_WINDOWS': 'COLOR 00 || nosetests {project}/test', }) # also check that we got the right wheels diff --git a/test/11_before_test/cibuildwheel_test.py b/test/11_before_test/cibuildwheel_test.py new file mode 100644 index 00000000..5aa1c4ca --- /dev/null +++ b/test/11_before_test/cibuildwheel_test.py @@ -0,0 +1,23 @@ +import os +import utils + + +def test(): + project_dir = os.path.dirname(__file__) + + # build the wheels + actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ + # write python version information to a temporary file, this is + # checked in setup.py + 'CIBW_BEFORE_TEST': '''python -c "import sys; open('/tmp/pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('/tmp/pythonprefix.txt', 'w').write(sys.prefix)"''', + 'CIBW_BEFORE_TEST_WINDOWS': '''python -c "import sys; open('c:\\pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('c:\\pythonprefix.txt', 'w').write(sys.prefix)"''', + 'CIBW_TEST_REQUIRES': 'nose', + # the 'false ||' bit is to ensure this command runs in a shell on + # mac/linux. + 'CIBW_TEST_COMMAND': 'false || nosetests {project}/test', + 'CIBW_TEST_COMMAND_WINDOWS': 'nosetests {project}/test', + }) + + # also check that we got the right wheels + expected_wheels = utils.expected_wheels('spam', '0.1.0') + assert set(actual_wheels) == set(expected_wheels) diff --git a/test/11_before_test/setup.py b/test/11_before_test/setup.py new file mode 100644 index 00000000..e3ea2938 --- /dev/null +++ b/test/11_before_test/setup.py @@ -0,0 +1,8 @@ +from setuptools import setup, Extension + + +setup( + name="spam", + ext_modules=[Extension('spam', sources=['spam.c'])], + version="0.1.0", +) diff --git a/test/11_before_test/spam.c b/test/11_before_test/spam.c new file mode 100644 index 00000000..d1ab0f22 --- /dev/null +++ b/test/11_before_test/spam.c @@ -0,0 +1,48 @@ +#include + +static PyObject * +spam_system(PyObject *self, PyObject *args) +{ + const char *command; + int sts; + + if (!PyArg_ParseTuple(args, "s", &command)) + return NULL; + 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) +} diff --git a/test/11_before_test/test/spam_test.py b/test/11_before_test/test/spam_test.py new file mode 100644 index 00000000..21bad8c2 --- /dev/null +++ b/test/11_before_test/test/spam_test.py @@ -0,0 +1,28 @@ +import sys +import os +from unittest import TestCase + + +class TestBeforeTest(TestCase): + def test_version(self): + # assert that the Python version as written to pythonversion.txt in the CIBW_BEFORE_TEST step + # is the same one as is currently running. + # because of use symlinks in MacOS run this test is also need + version_file = 'c:\\pythonversion.txt' if sys.platform == 'win32' else '/tmp/pythonversion.txt' + with open(version_file) as f: + stored_version = f.read() + print('stored_version', stored_version) + print('sys.version', sys.version) + assert stored_version == sys.version + + def test_prefix(self): + # check that the prefix also was written + prefix_file = 'c:\\pythonprefix.txt' if sys.platform == 'win32' else '/tmp/pythonprefix.txt' + with open(prefix_file) as f: + stored_prefix = f.read() + print('stored_prefix', stored_prefix) + print('sys.prefix', sys.prefix) + # Works around path-comparison bugs caused by short-paths on Windows e.g. + # vssadm~1 instead of vssadministrator + + assert os.stat(stored_prefix) == os.stat(sys.prefix)