Merge remote-tracking branch 'origin/master' into macos-universal2

This commit is contained in:
Joe Rickerby
2021-01-05 13:35:39 +00:00
36 changed files with 251 additions and 194 deletions
+1 -1
View File
@@ -4,6 +4,6 @@ set -o xtrace
$PYTHON --version $PYTHON --version
$PYTHON -m pip --version $PYTHON -m pip --version
$PYTHON -m virtualenv -p $PYTHON venv $PYTHON -m virtualenv -p $PYTHON venv
venv/bin/python -m pip install -r requirements-dev.txt venv/bin/python -m pip install -e ".[dev]"
venv/bin/python -m pip freeze venv/bin/python -m pip freeze
venv/bin/python --version venv/bin/python --version
+1 -1
View File
@@ -37,7 +37,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
python -m pip install -r requirements-dev.txt python -m pip install -e ".[dev]"
- name: Install Visual C++ for Python 2.7 - name: Install Visual C++ for Python 2.7
if: runner.os == 'Windows' if: runner.os == 'Windows'
+1 -1
View File
@@ -11,5 +11,5 @@ linux:
DOCKER_TLS_CERTDIR: "" DOCKER_TLS_CERTDIR: ""
script: script:
- curl -sSL https://get.docker.com/ | sh - curl -sSL https://get.docker.com/ | sh
- python -m pip install -r requirements-dev.txt - python -m pip install -e ".[dev]"
- python ./bin/run_tests.py - python ./bin/run_tests.py
+16 -9
View File
@@ -1,13 +1,7 @@
repos: repos:
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.3
hooks:
- id: flake8
exclude: cibuildwheel/resources/
additional_dependencies: [flake8-bugbear]
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0 rev: v3.4.0
hooks: hooks:
- id: check-case-conflict - id: check-case-conflict
- id: check-merge-conflict - id: check-merge-conflict
@@ -18,8 +12,21 @@ repos:
- id: trailing-whitespace - id: trailing-whitespace
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.782 rev: v0.790
hooks: hooks:
- id: mypy - id: mypy
files: ^(cibuildwheel/|test/|bin/projects.py) files: ^(cibuildwheel/|test/|bin/projects.py|unit_test/)
pass_filenames: false pass_filenames: false
- repo: https://github.com/asottile/pyupgrade
rev: v2.7.4
hooks:
- id: pyupgrade
args: ["--py36-plus"]
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.4
hooks:
- id: flake8
exclude: cibuildwheel/resources/
additional_dependencies: [flake8-bugbear]
+4 -1
View File
@@ -8,4 +8,7 @@ mkdocs:
python: python:
version: 3.7 version: 3.7
install: install:
- requirements: requirements-dev.txt - method: pip
path: .
extra_requirements:
- dev
+1 -1
View File
@@ -54,6 +54,6 @@ jobs:
# must repeat the s390x job above exactly to match # must repeat the s390x job above exactly to match
- *linux_s390x_36 - *linux_s390x_36
install: $PYTHON -m pip install -r requirements-dev.txt pytest-custom-exit-code install: $PYTHON -m pip install -e ".[dev]" pytest-custom-exit-code
script: $PYTHON ./bin/run_tests.py script: $PYTHON ./bin/run_tests.py
+7 -1
View File
@@ -80,7 +80,7 @@ jobs:
name: Install Python name: Install Python
- name: Install cibuildwheel - name: Install cibuildwheel
run: python -m pip install cibuildwheel==1.7.3 run: python -m pip install cibuildwheel==1.7.4
- name: Build wheels - name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse run: python -m cibuildwheel --output-dir wheelhouse
@@ -270,6 +270,12 @@ Changelog
<!--changelog-start--> <!--changelog-start-->
### 1.7.4
_2 January 2021_
- 🐛 Fix the PyPy virtualenv patch to work on macOS 10.14 (#506)
### 1.7.3 ### 1.7.3
_1 January 2021_ _1 January 2021_
+1 -1
View File
@@ -19,7 +19,7 @@ init:
$env:PYTEST_ADDOPTS='-k "unit_test or test_0_basic" --suppress-no-test-exit-code' $env:PYTEST_ADDOPTS='-k "unit_test or test_0_basic" --suppress-no-test-exit-code'
} }
install: python -m pip install -r requirements-dev.txt pytest-custom-exit-code install: python -m pip install -e ".[dev]" pytest-custom-exit-code
# the '-u' flag is required so the output is in the correct order. # the '-u' flag is required so the output is in the correct order.
# See https://github.com/joerick/cibuildwheel/pull/24 for more info. # See https://github.com/joerick/cibuildwheel/pull/24 for more info.
+4 -4
View File
@@ -6,7 +6,7 @@ jobs:
inputs: inputs:
versionSpec: '3.8' versionSpec: '3.8'
- bash: | - bash: |
python -m pip install -r requirements-dev.txt pytest-azurepipelines python -m pip install -e ".[dev]" pytest-azurepipelines
python ./bin/run_tests.py python ./bin/run_tests.py
- job: macos_38 - job: macos_38
@@ -16,7 +16,7 @@ jobs:
inputs: inputs:
versionSpec: '3.8' versionSpec: '3.8'
- bash: | - bash: |
python -m pip install -r requirements-dev.txt pytest-azurepipelines python -m pip install -e ".[dev]" pytest-azurepipelines
python ./bin/run_tests.py python ./bin/run_tests.py
- job: windows_36 - job: windows_36
@@ -29,7 +29,7 @@ jobs:
- script: choco install vcpython27 -f -y - script: choco install vcpython27 -f -y
displayName: Install Visual C++ for Python 2.7 displayName: Install Visual C++ for Python 2.7
- bash: | - bash: |
python -m pip install -r requirements-dev.txt pytest-azurepipelines python -m pip install -e ".[dev]" pytest-azurepipelines
python ./bin/run_tests.py python ./bin/run_tests.py
- job: windows_38 - job: windows_38
@@ -42,5 +42,5 @@ jobs:
- script: choco install vcpython27 -f -y - script: choco install vcpython27 -f -y
displayName: Install Visual C++ for Python 2.7 displayName: Install Visual C++ for Python 2.7
- bash: | - bash: |
python -m pip install -r requirements-dev.txt pytest-azurepipelines python -m pip install -e ".[dev]" pytest-azurepipelines
python ./bin/run_tests.py python ./bin/run_tests.py
+3 -3
View File
@@ -17,7 +17,7 @@ config = [
('docs/faq.md', "cibuildwheel@v{}"), ('docs/faq.md', "cibuildwheel@v{}"),
('docs/setup.md', "cibuildwheel@v{}"), ('docs/setup.md', "cibuildwheel@v{}"),
('examples/*', "cibuildwheel=={}"), ('examples/*', "cibuildwheel=={}"),
('setup.py', "version='{}'"), ('setup.cfg', "version = {}"),
] ]
@@ -81,7 +81,7 @@ def bump_version():
) )
if not found_at_least_one_file_needing_update: if not found_at_least_one_file_needing_update:
print('error: Didnt find any occurences of “{}” in “{}'.format(find_pattern, path_pattern)) print(f'error: Didnt find any occurences of “{find_pattern}” in “{path_pattern}')
exit(1) exit(1)
print() print()
@@ -94,7 +94,7 @@ def bump_version():
red="\u001b[31m", green="\u001b[32m", off="\u001b[0m" red="\u001b[31m", green="\u001b[32m", off="\u001b[0m"
)) ))
print('Then commit, and tag as v{}'.format(new_version)) print(f'Then commit, and tag as v{new_version}')
answer = input('Proceed? [y/N] ').strip() answer = input('Proceed? [y/N] ').strip()
+1 -1
View File
@@ -1 +1 @@
__version__ = '1.7.3' __version__ = '1.7.4'
+3 -3
View File
@@ -1,7 +1,7 @@
import subprocess import subprocess
from typing import Callable, Dict, List, NamedTuple, Optional, Sequence from typing import Callable, Dict, List, NamedTuple, Optional, Sequence
import bashlex # type: ignore import bashlex
# a function that takes a command and the environment, and returns the result # a function that takes a command and the environment, and returns the result
EnvironmentExecutor = Callable[[List[str], Dict[str, str]], str] EnvironmentExecutor = Callable[[List[str], Dict[str, str]], str]
@@ -50,7 +50,7 @@ def evaluate_node(node: bashlex.ast.node, context: NodeExecutionContext) -> str:
def evaluate_word_node(node: bashlex.ast.node, context: NodeExecutionContext) -> str: def evaluate_word_node(node: bashlex.ast.node, context: NodeExecutionContext) -> str:
value = node.word value: str = node.word
for part in node.parts: for part in node.parts:
part_string = context.input[part.pos[0]:part.pos[1]] part_string = context.input[part.pos[0]:part.pos[1]]
@@ -95,7 +95,7 @@ def evaluate_nodes_as_compound_command(nodes: Sequence[bashlex.ast.node], contex
return result return result
def evaluate_nodes_as_simple_command(nodes: List[bashlex.ast.node], context: NodeExecutionContext): def evaluate_nodes_as_simple_command(nodes: List[bashlex.ast.node], context: NodeExecutionContext) -> str:
command = [evaluate_node(part, context=context) for part in nodes] command = [evaluate_node(part, context=context) for part in nodes]
return context.executor(command, context.environment) return context.executor(command, context.environment)
+23 -8
View File
@@ -5,9 +5,11 @@ import shlex
import subprocess import subprocess
import sys import sys
import uuid import uuid
from os import PathLike
from pathlib import Path, PurePath from pathlib import Path, PurePath
from typing import IO, Dict, List, Optional, Sequence, Union from typing import cast, IO, Dict, List, Optional, Sequence, Type
from types import TracebackType
from .typing import PathOrStr, PopenBytes
class DockerContainer: class DockerContainer:
@@ -23,14 +25,15 @@ class DockerContainer:
''' '''
UTILITY_PYTHON = '/opt/python/cp38-cp38/bin/python' UTILITY_PYTHON = '/opt/python/cp38-cp38/bin/python'
process: subprocess.Popen process: PopenBytes
bash_stdin: IO[bytes] bash_stdin: IO[bytes]
bash_stdout: IO[bytes] bash_stdout: IO[bytes]
def __init__(self, docker_image: str, simulate_32_bit: bool = False, cwd: Optional[Union[str, PathLike]] = None): def __init__(self, docker_image: str, simulate_32_bit: bool = False, cwd: Optional[PathOrStr] = None):
self.docker_image = docker_image self.docker_image = docker_image
self.simulate_32_bit = simulate_32_bit self.simulate_32_bit = simulate_32_bit
self.cwd = cwd self.cwd = cwd
self.name: Optional[str] = None
def __enter__(self) -> 'DockerContainer': def __enter__(self) -> 'DockerContainer':
self.name = f'cibuildwheel-{uuid.uuid4()}' self.name = f'cibuildwheel-{uuid.uuid4()}'
@@ -68,11 +71,18 @@ class DockerContainer:
return self return self
def __exit__(self, exc_type, exc_val, exc_tb): def __exit__(
self,
exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType]) -> None:
self.bash_stdin.close() self.bash_stdin.close()
self.process.terminate() self.process.terminate()
self.process.wait() self.process.wait()
assert isinstance(self.name, str)
subprocess.run(['docker', 'rm', '--force', '-v', self.name], stdout=subprocess.DEVNULL) subprocess.run(['docker', 'rm', '--force', '-v', self.name], stdout=subprocess.DEVNULL)
self.name = None self.name = None
@@ -117,8 +127,12 @@ class DockerContainer:
return [PurePath(p) for p in path_strs] return [PurePath(p) for p in path_strs]
def call(self, args: Sequence[Union[str, PathLike]], env: Optional[Dict[str, str]] = None, def call(
capture_output=False, cwd: Optional[Union[str, PathLike]] = None) -> str: self,
args: Sequence[PathOrStr],
env: Optional[Dict[str, str]] = None,
capture_output: bool = False,
cwd: Optional[PathOrStr] = None) -> str:
chdir = f'cd {cwd}' if cwd else '' chdir = f'cd {cwd}' if cwd else ''
env_assignments = ' '.join(f'{shlex.quote(k)}={shlex.quote(v)}' env_assignments = ' '.join(f'{shlex.quote(k)}={shlex.quote(v)}'
@@ -178,11 +192,12 @@ class DockerContainer:
return output return output
def get_environment(self) -> Dict[str, str]: def get_environment(self) -> Dict[str, str]:
return json.loads(self.call([ env = json.loads(self.call([
self.UTILITY_PYTHON, self.UTILITY_PYTHON,
'-c', '-c',
'import sys, json, os; json.dump(os.environ.copy(), sys.stdout)' 'import sys, json, os; json.dump(os.environ.copy(), sys.stdout)'
], capture_output=True)) ], capture_output=True))
return cast(Dict[str, str], env)
def environment_executor(self, command: List[str], environment: Dict[str, str]) -> str: def environment_executor(self, command: List[str], environment: Dict[str, str]) -> str:
# used as an EnvironmentExecutor to evaluate commands and capture output # used as an EnvironmentExecutor to evaluate commands and capture output
+1 -1
View File
@@ -1,4 +1,4 @@
import bashlex # type: ignore import bashlex
from typing import Dict, List, Mapping, Optional from typing import Dict, List, Mapping, Optional
+4 -4
View File
@@ -1,9 +1,8 @@
import subprocess import subprocess
import sys import sys
import textwrap import textwrap
from os import PathLike
from pathlib import Path, PurePath from pathlib import Path, PurePath
from typing import List, NamedTuple, Union from typing import List, NamedTuple
from .docker_container import DockerContainer from .docker_container import DockerContainer
from .logger import log from .logger import log
@@ -11,6 +10,7 @@ from .util import (
Architecture, BuildOptions, BuildSelector, NonPlatformWheelError, Architecture, BuildOptions, BuildSelector, NonPlatformWheelError,
get_build_verbosity_extra_flags, prepare_command, get_build_verbosity_extra_flags, prepare_command,
) )
from .typing import PathOrStr
class PythonConfiguration(NamedTuple): class PythonConfiguration(NamedTuple):
@@ -19,7 +19,7 @@ class PythonConfiguration(NamedTuple):
path_str: str path_str: str
@property @property
def path(self): def path(self) -> PurePath:
return PurePath(self.path_str) return PurePath(self.path_str)
@@ -125,7 +125,7 @@ def build(options: BuildOptions) -> None:
for config in platform_configs: for config in platform_configs:
log.build_start(config.identifier) log.build_start(config.identifier)
dependency_constraint_flags: List[Union[str, PathLike]] = [] dependency_constraint_flags: List[PathOrStr] = []
if config.identifier.startswith("pp"): if config.identifier.startswith("pp"):
# Patch PyPy to make sure headers get installed into a venv # Patch PyPy to make sure headers get installed into a venv
patch_version = '_27' if config.version == '2.7' else '' patch_version = '_27' if config.version == '2.7' else ''
+36 -50
View File
@@ -3,7 +3,7 @@ import os
import re import re
import sys import sys
import time import time
from typing import Optional, Union from typing import Optional, Union, AnyStr, IO
from cibuildwheel.util import CIProvider, detect_ci_provider from cibuildwheel.util import CIProvider, detect_ci_provider
@@ -37,7 +37,7 @@ class Logger:
step_start_time: Optional[float] = None step_start_time: Optional[float] = None
active_fold_group_name: Optional[str] = None active_fold_group_name: Optional[str] = None
def __init__(self): def __init__(self) -> None:
if sys.platform == 'win32' and hasattr(sys.stdout, 'reconfigure'): if sys.platform == 'win32' and hasattr(sys.stdout, 'reconfigure'):
# the encoding on Windows can be a 1-byte charmap, but all CIs # the encoding on Windows can be a 1-byte charmap, but all CIs
# support utf8, so we hardcode that # support utf8, so we hardcode that
@@ -67,7 +67,7 @@ class Logger:
self.fold_mode = 'disabled' self.fold_mode = 'disabled'
self.colors_enabled = file_supports_color(sys.stdout) self.colors_enabled = file_supports_color(sys.stdout)
def build_start(self, identifier: str): def build_start(self, identifier: str) -> None:
self.step_end() self.step_end()
c = self.colors c = self.colors
description = build_description_from_identifier(identifier) description = build_description_from_identifier(identifier)
@@ -79,7 +79,7 @@ class Logger:
self.build_start_time = time.time() self.build_start_time = time.time()
self.active_build_identifier = identifier self.active_build_identifier = identifier
def build_end(self): def build_end(self) -> None:
assert self.build_start_time is not None assert self.build_start_time is not None
assert self.active_build_identifier is not None assert self.active_build_identifier is not None
self.step_end() self.step_end()
@@ -93,12 +93,12 @@ class Logger:
self.build_start_time = None self.build_start_time = None
self.active_build_identifier = None self.active_build_identifier = None
def step(self, step_description: str): def step(self, step_description: str) -> None:
self.step_end() self.step_end()
self.step_start_time = time.time() self.step_start_time = time.time()
self._start_fold_group(step_description) self._start_fold_group(step_description)
def step_end(self, success=True): def step_end(self, success: bool = True) -> None:
if self.step_start_time is not None: if self.step_start_time is not None:
self._end_fold_group() self._end_fold_group()
c = self.colors c = self.colors
@@ -111,7 +111,7 @@ class Logger:
self.step_start_time = None self.step_start_time = None
def error(self, error: Union[Exception, str]): def error(self, error: Union[BaseException, str]) -> None:
self.step_end(success=False) self.step_end(success=False)
print() print()
@@ -121,7 +121,7 @@ class Logger:
c = self.colors c = self.colors
print(f'{c.bright_red}Error{c.end} {error}') print(f'{c.bright_red}Error{c.end} {error}')
def _start_fold_group(self, name: str): def _start_fold_group(self, name: str) -> None:
self._end_fold_group() self._end_fold_group()
self.active_fold_group_name = name self.active_fold_group_name = name
fold_start_pattern = FOLD_PATTERNS.get(self.fold_mode, DEFAULT_FOLD_PATTERN)[0] fold_start_pattern = FOLD_PATTERNS.get(self.fold_mode, DEFAULT_FOLD_PATTERN)[0]
@@ -131,7 +131,7 @@ class Logger:
print() print()
sys.stdout.flush() sys.stdout.flush()
def _end_fold_group(self): def _end_fold_group(self) -> None:
if self.active_fold_group_name: if self.active_fold_group_name:
fold_start_pattern = FOLD_PATTERNS.get(self.fold_mode, DEFAULT_FOLD_PATTERN)[1] fold_start_pattern = FOLD_PATTERNS.get(self.fold_mode, DEFAULT_FOLD_PATTERN)[1]
identifier = self._fold_group_identifier(self.active_fold_group_name) identifier = self._fold_group_identifier(self.active_fold_group_name)
@@ -139,7 +139,7 @@ class Logger:
sys.stdout.flush() sys.stdout.flush()
self.active_fold_group_name = None self.active_fold_group_name = None
def _fold_group_identifier(self, name: str): def _fold_group_identifier(self, name: str) -> str:
''' '''
Travis doesn't like fold groups identifiers that have spaces in. This Travis doesn't like fold groups identifiers that have spaces in. This
method converts them to ascii identifiers method converts them to ascii identifiers
@@ -154,21 +154,21 @@ class Logger:
return identifier.lower()[:20] return identifier.lower()[:20]
@property @property
def colors(self): def colors(self) -> "Colors":
if self.colors_enabled: if self.colors_enabled:
return Colors.enabled return Colors(enabled=True)
else: else:
return Colors.disabled return Colors(enabled=False)
@property @property
def symbols(self): def symbols(self) -> "Symbols":
if self.unicode_enabled: if self.unicode_enabled:
return Symbols.unicode return Symbols(unicode=True)
else: else:
return Symbols.ascii return Symbols(unicode=False)
def build_description_from_identifier(identifier: str): def build_description_from_identifier(identifier: str) -> str:
python_identifier, _, platform_identifier = identifier.partition('-') python_identifier, _, platform_identifier = identifier.partition('-')
build_description = '' build_description = ''
@@ -194,45 +194,31 @@ def build_description_from_identifier(identifier: str):
class Colors: class Colors:
class Enabled: def __init__(self, *, enabled: bool) -> None:
red = '\033[31m' self.red = '\033[31m' if enabled else ''
green = '\033[32m' self.green = '\033[32m' if enabled else ''
yellow = '\033[33m' self.yellow = '\033[33m' if enabled else ''
blue = '\033[34m' self.blue = '\033[34m' if enabled else ''
cyan = '\033[36m' self.cyan = '\033[36m' if enabled else ''
bright_red = '\033[91m' self.bright_red = '\033[91m' if enabled else ''
bright_green = '\033[92m' self.bright_green = '\033[92m' if enabled else ''
white = '\033[37m\033[97m' self.white = '\033[37m\033[97m' if enabled else ''
bg_grey = '\033[48;5;235m' self.bg_grey = '\033[48;5;235m' if enabled else ''
bold = '\033[1m' self.bold = '\033[1m' if enabled else ''
faint = '\033[2m' self.faint = '\033[2m' if enabled else ''
end = '\033[0m' self.end = '\033[0m' if enabled else ''
class Disabled:
def __getattr__(self, attr: str) -> str:
return ''
enabled = Enabled()
disabled = Disabled()
class Symbols: class Symbols:
class Unicode: def __init__(self, *, unicode: bool) -> None:
done = '' self.done = '' if unicode else 'done'
error = '' self.error = '' if unicode else 'failed'
class Ascii:
done = 'done'
error = 'failed'
unicode = Unicode()
ascii = Ascii()
def file_supports_color(file_obj): def file_supports_color(file_obj: IO[AnyStr]) -> bool:
""" """
Returns True if the running system's terminal supports color. Returns True if the running system's terminal supports color.
""" """
@@ -244,11 +230,11 @@ def file_supports_color(file_obj):
return (supported_platform and is_a_tty) return (supported_platform and is_a_tty)
def file_is_a_tty(file_obj): def file_is_a_tty(file_obj: IO[AnyStr]) -> bool:
return hasattr(file_obj, 'isatty') and file_obj.isatty() return hasattr(file_obj, 'isatty') and file_obj.isatty()
def file_supports_unicode(file_obj): def file_supports_unicode(file_obj: IO[AnyStr]) -> bool:
encoding = getattr(file_obj, 'encoding', None) encoding = getattr(file_obj, 'encoding', None)
if not encoding: if not encoding:
return False return False
+6 -6
View File
@@ -6,18 +6,18 @@ import subprocess
import sys import sys
import tempfile import tempfile
import textwrap import textwrap
from os import PathLike
from pathlib import Path from pathlib import Path
from typing import Dict, List, NamedTuple, Optional, Sequence, Tuple, Union, cast from typing import Dict, List, NamedTuple, Optional, Sequence, Tuple, cast
from .environment import ParsedEnvironment from .environment import ParsedEnvironment
from .logger import log from .logger import log
from .util import (Architecture, BuildOptions, BuildSelector, NonPlatformWheelError, from .util import (Architecture, BuildOptions, BuildSelector, NonPlatformWheelError,
download, get_build_verbosity_extra_flags, get_pip_script, download, get_build_verbosity_extra_flags, get_pip_script,
install_certifi_script, prepare_command) install_certifi_script, prepare_command)
from .typing import PathOrStr
def call(args: Union[str, Sequence[Union[str, PathLike]]], env: Optional[Dict[str, str]] = None, cwd: Optional[str] = None, shell: bool = False) -> int: def call(args: Sequence[PathOrStr], env: Optional[Dict[str, str]] = None, cwd: Optional[str] = None, shell: bool = False) -> int:
# print the command executing for the logs # print the command executing for the logs
if shell: if shell:
print(f'+ {args}') print(f'+ {args}')
@@ -134,7 +134,7 @@ def install_pypy(version: str, url: str) -> Path:
# Patch PyPy to make sure headers get installed into a venv # Patch PyPy to make sure headers get installed into a venv
patch_version = '_27' if version == '2.7' else '' patch_version = '_27' if version == '2.7' else ''
patch_path = Path(__file__).absolute().parent / 'resources' / f'pypy_venv{patch_version}.patch' patch_path = Path(__file__).absolute().parent / 'resources' / f'pypy_venv{patch_version}.patch'
call(['patch', '--force', '-d', installation_path, patch_path]) call(['patch', '--force', '-p1', '-d', installation_path, '-i', patch_path])
installation_bin_path = installation_path / 'bin' installation_bin_path = installation_path / 'bin'
python_executable = 'pypy3' if version[0] == '3' else 'pypy' python_executable = 'pypy3' if version[0] == '3' else 'pypy'
@@ -145,7 +145,7 @@ def install_pypy(version: str, url: str) -> Path:
def setup_python(python_configuration: PythonConfiguration, def setup_python(python_configuration: PythonConfiguration,
dependency_constraint_flags: Sequence[Union[str, PathLike]], dependency_constraint_flags: Sequence[PathOrStr],
environment: ParsedEnvironment) -> Dict[str, str]: environment: ParsedEnvironment) -> Dict[str, str]:
implementation_id = python_configuration.identifier.split("-")[0] implementation_id = python_configuration.identifier.split("-")[0]
log.step(f'Installing Python {implementation_id}...') log.step(f'Installing Python {implementation_id}...')
@@ -242,7 +242,7 @@ def build(options: BuildOptions) -> None:
for config in python_configurations: for config in python_configurations:
log.build_start(config.identifier) log.build_start(config.identifier)
dependency_constraint_flags: Sequence[Union[str, PathLike]] = [] dependency_constraint_flags: Sequence[PathOrStr] = []
if options.dependency_constraints: if options.dependency_constraints:
dependency_constraint_flags = [ dependency_constraint_flags = [
'-c', options.dependency_constraints.get_for_python_version(config.version) '-c', options.dependency_constraints.get_for_python_version(config.version)
View File
@@ -1,22 +1,22 @@
[x86_64] [x86_64]
manylinux1 = quay.io/pypa/manylinux1_x86_64:2020-12-30-e2b3664 manylinux1 = quay.io/pypa/manylinux1_x86_64:2020-12-31-84e1e23
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2020-12-30-3161d69 manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2020-12-31-4928808
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2020-12-30-68d3257 manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2020-12-31-56195b3
[i686] [i686]
manylinux1 = quay.io/pypa/manylinux1_i686:2020-12-30-e2b3664 manylinux1 = quay.io/pypa/manylinux1_i686:2020-12-31-84e1e23
manylinux2010 = quay.io/pypa/manylinux2010_i686:2020-12-30-3161d69 manylinux2010 = quay.io/pypa/manylinux2010_i686:2020-12-31-4928808
manylinux2014 = quay.io/pypa/manylinux2014_i686:2020-12-30-68d3257 manylinux2014 = quay.io/pypa/manylinux2014_i686:2020-12-31-56195b3
[pypy_x86_64] [pypy_x86_64]
manylinux2010 = pypywheels/manylinux2010-pypy_x86_64:2020-12-11-f1e0e80 manylinux2010 = pypywheels/manylinux2010-pypy_x86_64:2020-12-11-f1e0e80
[aarch64] [aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2020-12-30-68d3257 manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2020-12-31-56195b3
[ppc64le] [ppc64le]
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2020-12-30-68d3257 manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2020-12-31-56195b3
[s390x] [s390x]
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2020-12-30-68d3257 manylinux2014 = quay.io/pypa/manylinux2014_s390x:2020-12-31-56195b3
+11
View File
@@ -0,0 +1,11 @@
from typing import Union, TYPE_CHECKING
import os
import subprocess
if TYPE_CHECKING:
PopenBytes = subprocess.Popen[bytes]
PathOrStr = Union[str, os.PathLike[str]]
else:
PopenBytes = subprocess.Popen
PathOrStr = Union[str, "os.PathLike[str]"]
+4 -3
View File
@@ -8,14 +8,15 @@ from enum import Enum
from fnmatch import fnmatch from fnmatch import fnmatch
from pathlib import Path from pathlib import Path
from time import sleep from time import sleep
from typing import Dict, List, NamedTuple, Optional, Union from typing import Dict, List, NamedTuple, Optional
import certifi import certifi
from .environment import ParsedEnvironment from .environment import ParsedEnvironment
from .typing import PathOrStr
def prepare_command(command: str, **kwargs: Union[str, os.PathLike]) -> str: def prepare_command(command: str, **kwargs: PathOrStr) -> str:
''' '''
Preprocesses a command by expanding variables like {python}. Preprocesses a command by expanding variables like {python}.
@@ -119,7 +120,7 @@ class DependencyConstraints:
else: else:
return self.base_file_path return self.base_file_path
def __repr__(self): def __repr__(self) -> str:
return f'{self.__class__.__name__}{self.base_file_path!r})' return f'{self.__class__.__name__}{self.base_file_path!r})'
+5 -5
View File
@@ -4,9 +4,8 @@ import subprocess
import sys import sys
import tempfile import tempfile
import textwrap import textwrap
from os import PathLike
from pathlib import Path from pathlib import Path
from typing import Dict, List, NamedTuple, Optional, Sequence, Union from typing import Dict, List, NamedTuple, Optional, Sequence
from zipfile import ZipFile from zipfile import ZipFile
import toml import toml
@@ -16,12 +15,13 @@ from .logger import log
from .util import (Architecture, BuildOptions, BuildSelector, NonPlatformWheelError, from .util import (Architecture, BuildOptions, BuildSelector, NonPlatformWheelError,
download, get_build_verbosity_extra_flags, get_pip_script, download, get_build_verbosity_extra_flags, get_pip_script,
prepare_command) prepare_command)
from .typing import PathOrStr
IS_RUNNING_ON_AZURE = Path('C:\\hostedtoolcache').exists() IS_RUNNING_ON_AZURE = Path('C:\\hostedtoolcache').exists()
IS_RUNNING_ON_TRAVIS = os.environ.get('TRAVIS_OS_NAME') == 'windows' IS_RUNNING_ON_TRAVIS = os.environ.get('TRAVIS_OS_NAME') == 'windows'
def call(args: Sequence[Union[str, PathLike]], env: Optional[Dict[str, str]] = None, def call(args: Sequence[PathOrStr], env: Optional[Dict[str, str]] = None,
cwd: Optional[str] = None) -> None: cwd: Optional[str] = None) -> None:
print('+ ' + ' '.join(str(a) for a in args)) print('+ ' + ' '.join(str(a) for a in args))
# we use shell=True here, even though we don't need a shell due to a bug # we use shell=True here, even though we don't need a shell due to a bug
@@ -109,7 +109,7 @@ def install_pypy(version: str, arch: str, url: str) -> Path:
return installation_path return installation_path
def setup_python(python_configuration: PythonConfiguration, dependency_constraint_flags: Sequence[Union[str, PathLike]], environment: ParsedEnvironment) -> Dict[str, str]: def setup_python(python_configuration: PythonConfiguration, dependency_constraint_flags: Sequence[PathOrStr], environment: ParsedEnvironment) -> Dict[str, str]:
nuget = Path('C:\\cibw\\nuget.exe') nuget = Path('C:\\cibw\\nuget.exe')
if not nuget.exists(): if not nuget.exists():
log.step('Downloading nuget...') log.step('Downloading nuget...')
@@ -225,7 +225,7 @@ def build(options: BuildOptions) -> None:
for config in python_configurations: for config in python_configurations:
log.build_start(config.identifier) log.build_start(config.identifier)
dependency_constraint_flags: Sequence[Union[str, PathLike]] = [] dependency_constraint_flags: Sequence[PathOrStr] = []
if options.dependency_constraints: if options.dependency_constraints:
dependency_constraint_flags = [ dependency_constraint_flags = [
'-c', options.dependency_constraints.get_for_python_version(config.version) '-c', options.dependency_constraints.get_for_python_version(config.version)
+15
View File
@@ -32,8 +32,21 @@ So, if we can, I'd like to improve the experience on errors as well. In [this](h
Maintainer notes Maintainer notes
---------------- ----------------
## Local testing
You should run:
```python
python3 -m venv venv
. venv/bin/activate
pip install -e .[dev]
```
To prepare a development environment.
## Testing minimal configs ## Testing minimal configs
cibuildwheel's _minimal_ example configs can be tested on a simple project on cibuildwheel's existing CI. These should be run whenever the minimal configs change. cibuildwheel's _minimal_ example configs can be tested on a simple project on cibuildwheel's existing CI. These should be run whenever the minimal configs change.
To test minimal configs, make sure you have a clean git repo, then run the script: To test minimal configs, make sure you have a clean git repo, then run the script:
@@ -48,6 +61,8 @@ The script then outputs a Markdown table that can be copy/pasted into a PR to mo
## Preparing environments ## Preparing environments
This has been moved to using docker, so you only need the following instructions if you add `--no-docker` to avoid using docker.
The dependency update script in the next section requires multiple python versions installed. One way to do this is to use `pyenv`: The dependency update script in the next section requires multiple python versions installed. One way to do this is to use `pyenv`:
```bash ```bash
+2 -2
View File
@@ -113,7 +113,7 @@ There are two suggested methods for keeping cibuildwheel up to date that instead
If you use GitHub Actions for builds, you can use cibuildwheel as an action: If you use GitHub Actions for builds, you can use cibuildwheel as an action:
```yaml ```yaml
uses: joerick/cibuildwheel@v1.7.3 uses: joerick/cibuildwheel@v1.7.4
``` ```
This is a composite step that just installs and runs cibuildwheel. You can set command-line options as `with:` parameters, and use `env:` as normal. This is a composite step that just installs and runs cibuildwheel. You can set command-line options as `with:` parameters, and use `env:` as normal.
@@ -139,7 +139,7 @@ The second option, and the only one that supports other CI systems, is using a `
```bash ```bash
# requirements-cibw.txt # requirements-cibw.txt
cibuildwheel==1.7.3 cibuildwheel==1.7.4
``` ```
Then your install step would have `python -m pip install -r requirements-cibw.txt` in it. Your `dependabot.yml` file could look like this: Then your install step would have `python -m pip install -r requirements-cibw.txt` in it. Your `dependabot.yml` file could look like this:
+1 -1
View File
@@ -17,7 +17,7 @@ For more info on this file, check out the [docs](https://help.github.com/en/acti
[`examples/github-deploy.yml`](https://github.com/joerick/cibuildwheel/blob/master/examples/github-deploy.yml) extends this minimal example with a demonstration of how to automatically upload the built wheels to PyPI. [`examples/github-deploy.yml`](https://github.com/joerick/cibuildwheel/blob/master/examples/github-deploy.yml) extends this minimal example with a demonstration of how to automatically upload the built wheels to PyPI.
You can also use cibuildwheel directly as an action with `uses: joerick/cibuildwheel@v1.7.3`; this combines the download and run steps into a single action, and command line arguments are available via `with:`. This makes it easy to manage cibuildwheel updates via normal actions update mechanisms like dependabot, see [Automatic updates](faq.md#automatic-updates). You can also use cibuildwheel directly as an action with `uses: joerick/cibuildwheel@v1.7.4`; this combines the download and run steps into a single action, and command line arguments are available via `with:`. This makes it easy to manage cibuildwheel updates via normal actions update mechanisms like dependabot, see [Automatic updates](faq.md#automatic-updates).
# Azure Pipelines [linux/mac/windows] {: #azure-pipelines} # Azure Pipelines [linux/mac/windows] {: #azure-pipelines}
+1 -1
View File
@@ -12,7 +12,7 @@ stack: python 3.7
init: init:
- cmd: set PATH=C:\Python37;C:\Python37\Scripts;%PATH% - cmd: set PATH=C:\Python37;C:\Python37\Scripts;%PATH%
install: python -m pip install cibuildwheel==1.7.3 install: python -m pip install cibuildwheel==1.7.4
build_script: python -m cibuildwheel --output-dir wheelhouse build_script: python -m cibuildwheel --output-dir wheelhouse
+3 -3
View File
@@ -6,7 +6,7 @@ jobs:
- bash: | - bash: |
set -o errexit set -o errexit
python3 -m pip install --upgrade pip python3 -m pip install --upgrade pip
pip3 install cibuildwheel==1.7.3 pip3 install cibuildwheel==1.7.4
displayName: Install dependencies displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse . - bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels displayName: Build wheels
@@ -20,7 +20,7 @@ jobs:
- bash: | - bash: |
set -o errexit set -o errexit
python3 -m pip install --upgrade pip python3 -m pip install --upgrade pip
python3 -m pip install cibuildwheel==1.7.3 python3 -m pip install cibuildwheel==1.7.4
displayName: Install dependencies displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse . - bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels displayName: Build wheels
@@ -36,7 +36,7 @@ jobs:
- bash: | - bash: |
set -o errexit set -o errexit
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install cibuildwheel==1.7.3 pip install cibuildwheel==1.7.4
displayName: Install dependencies displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse . - bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels displayName: Build wheels
+2 -2
View File
@@ -11,7 +11,7 @@ jobs:
- run: - run:
name: Build the Linux wheels. name: Build the Linux wheels.
command: | command: |
pip3 install --user cibuildwheel==1.7.3 pip3 install --user cibuildwheel==1.7.4
cibuildwheel --output-dir wheelhouse cibuildwheel --output-dir wheelhouse
- store_artifacts: - store_artifacts:
path: wheelhouse/ path: wheelhouse/
@@ -25,7 +25,7 @@ jobs:
- run: - run:
name: Build the OS X wheels. name: Build the OS X wheels.
command: | command: |
pip3 install cibuildwheel==1.7.3 pip3 install cibuildwheel==1.7.4
cibuildwheel --output-dir wheelhouse cibuildwheel --output-dir wheelhouse
- store_artifacts: - store_artifacts:
path: wheelhouse/ path: wheelhouse/
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
- name: Install cibuildwheel - name: Install cibuildwheel
run: | run: |
python -m pip install cibuildwheel==1.7.3 python -m pip install cibuildwheel==1.7.4
- name: Install Visual C++ for Python 2.7 - name: Install Visual C++ for Python 2.7
if: runner.os == 'Windows' if: runner.os == 'Windows'
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- name: Install cibuildwheel - name: Install cibuildwheel
run: | run: |
python -m pip install cibuildwheel==1.7.3 python -m pip install cibuildwheel==1.7.4
- name: Install Visual C++ for Python 2.7 - name: Install Visual C++ for Python 2.7
if: runner.os == 'Windows' if: runner.os == 'Windows'
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- ln -s /c/Python38/python.exe /c/Python38/python3.exe - ln -s /c/Python38/python.exe /c/Python38/python3.exe
install: install:
- python3 -m pip install cibuildwheel==1.7.3 - python3 -m pip install cibuildwheel==1.7.4
script: script:
# build the wheels, put them into './wheelhouse' # build the wheels, put them into './wheelhouse'
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
- ln -s /c/Python38/python.exe /c/Python38/python3.exe - ln -s /c/Python38/python.exe /c/Python38/python3.exe
install: install:
- python3 -m pip install cibuildwheel==1.7.3 - python3 -m pip install cibuildwheel==1.7.4
script: script:
# build the wheels, put them into './wheelhouse' # build the wheels, put them into './wheelhouse'
+3 -3
View File
@@ -55,7 +55,7 @@ jobs:
- stage: deploy - stage: deploy
name: Build and deploy Linux wheels name: Build and deploy Linux wheels
services: docker services: docker
install: python3 -m pip install cibuildwheel==1.7.3 install: python3 -m pip install cibuildwheel==1.7.4
script: python3 -m cibuildwheel --output-dir wheelhouse script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: | after_success: |
python3 -m pip install twine python3 -m pip install twine
@@ -65,7 +65,7 @@ jobs:
name: Build and deploy macOS wheels name: Build and deploy macOS wheels
os: osx os: osx
language: shell language: shell
install: python3 -m pip install cibuildwheel==1.7.3 install: python3 -m pip install cibuildwheel==1.7.4
script: python3 -m cibuildwheel --output-dir wheelhouse script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: | after_success: |
python3 -m pip install twine python3 -m pip install twine
@@ -75,7 +75,7 @@ jobs:
name: Build and deploy Windows wheels name: Build and deploy Windows wheels
os: windows os: windows
language: shell language: shell
install: python3 -m pip install cibuildwheel==1.7.3 install: python3 -m pip install cibuildwheel==1.7.4
script: python3 -m cibuildwheel --output-dir wheelhouse script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: | after_success: |
python3 -m pip install twine python3 -m pip install twine
+1 -13
View File
@@ -1,13 +1 @@
-e . -e .[dev]
pytest
pytest-timeout
mkdocs==1.0.4
mkdocs-include-markdown-plugin==2.1.1
pymdown-extensions
pip-tools
requests
click
mypy
pyyaml
pygithub
typing-extensions
+75 -4
View File
@@ -1,3 +1,64 @@
[metadata]
name = cibuildwheel
version = 1.7.4
description = Build Python wheels on CI with minimal configuration.
long_description = file: README.md
long_description_content_type = text/markdown
author = Joe Rickerby
author_email = joerick@mac.com
url = https://github.com/joerick/cibuildwheel
license = BSD
classifiers =
Intended Audience :: Developers
Natural Language :: English
Programming Language :: Python :: 3
Development Status :: 5 - Production/Stable
License :: OSI Approved :: BSD License
Programming Language :: Python :: Implementation :: CPython
Topic :: Software Development :: Build Tools
project_urls =
Changelog=https://github.com/joerick/cibuildwheel#changelog
Documentation=https://cibuildwheel.readthedocs.io/
keywords = ci,wheel,packaging,pypi,travis,appveyor,macos,linux,windows
[options]
packages = find:
zip_safe = False
include_package_data = True
python_requires = >=3.6
install_requires =
bashlex!=0.13
toml
certifi
[options.package_data]
cibuildwheel = resources/*
[options.extras_require]
dev =
click
mkdocs-include-markdown-plugin==2.1.1
mkdocs==1.0.4
mypy
pip-tools
pygithub
pymdown-extensions
pytest
pytest-timeout
pyyaml
requests
typing-extensions
[options.packages.find]
include =
cibuildwheel
[options.entry_points]
console_scripts =
cibuildwheel = cibuildwheel.__main__:main
[flake8] [flake8]
ignore = E501,W503,E741,E226,B950 ignore = E501,W503,E741,E226,B950
select = C,E,F,W,B,B9 select = C,E,F,W,B,B9
@@ -18,12 +79,14 @@ junit_family=xunit2
[mypy] [mypy]
python_version = 3.6 python_version = 3.6
files = cibuildwheel,test files = cibuildwheel,test,unit_test
warn_unused_configs = True warn_unused_configs = True
warn_redundant_casts = True warn_redundant_casts = True
[mypy-cibuildwheel] [mypy-test.*]
check_untyped_defs = True
[mypy-cibuildwheel.*,unit_test.*]
disallow_any_generics = True disallow_any_generics = True
disallow_subclassing_any = True disallow_subclassing_any = True
disallow_untyped_calls = True disallow_untyped_calls = True
@@ -37,5 +100,13 @@ warn_return_any = True
no_implicit_reexport = True no_implicit_reexport = True
strict_equality = True strict_equality = True
[mypy-pytest,setuptools] [mypy-setuptools.*]
ignore_missing_imports = True
# Ignored for pre-commit to speed up check
# Not ignored if manually running and pytest installed
[mypy-pytest.*]
ignore_missing_imports = True
[mypy-bashlex.*]
ignore_missing_imports = True ignore_missing_imports = True
+2 -48
View File
@@ -1,49 +1,3 @@
# -*- coding: utf-8 -*- from setuptools import setup
from pathlib import Path
try: setup()
from setuptools import setup
except ImportError:
from distutils.core import setup
this_directory = Path(__file__).parent
long_description = (this_directory / 'README.md').read_text(encoding='utf-8')
setup(
name='cibuildwheel',
version='1.7.3',
install_requires=['bashlex!=0.13', 'toml', 'certifi'],
description="Build Python wheels on CI with minimal configuration.",
long_description=long_description,
long_description_content_type='text/markdown',
author="Joe Rickerby",
author_email='joerick@mac.com',
url='https://github.com/joerick/cibuildwheel',
project_urls={
'Changelog': 'https://github.com/joerick/cibuildwheel#changelog',
'Documentation': 'https://cibuildwheel.readthedocs.io/',
},
packages=['cibuildwheel', ],
license="BSD",
zip_safe=False,
package_data={
'cibuildwheel': ['resources/*'],
},
# Supported python versions
python_requires='>=3.6',
keywords='ci wheel packaging pypi travis appveyor macos linux windows',
classifiers=[
'Intended Audience :: Developers',
'Natural Language :: English',
'Programming Language :: Python :: 3',
'Development Status :: 5 - Production/Stable',
'License :: OSI Approved :: BSD License',
'Programming Language :: Python :: Implementation :: CPython',
'Topic :: Software Development :: Build Tools',
],
entry_points={
'console_scripts': [
'cibuildwheel = cibuildwheel.__main__:main',
],
},
)