Skip to content

Commit

Permalink
Merge pull request #315 from YannickJadoul/type-annotations
Browse files Browse the repository at this point in the history
Add type annotations and drop Python 3.5 host support
  • Loading branch information
YannickJadoul authored May 9, 2020
2 parents 7927836 + 0368d58 commit ac0012e
Show file tree
Hide file tree
Showing 15 changed files with 178 additions and 165 deletions.
32 changes: 9 additions & 23 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
version: 2

jobs:
flake8:
flake8-mypy:
docker:
- image: circleci/python:3.6
steps:
- checkout

- run:
name: Install flake8
command: sudo python -m pip install flake8
name: Install flake8 & mypy
command: sudo python -m pip install flake8 mypy
- run:
name: Test.
command: flake8 .
name: flake8
command: flake8
- run:
name: mypy
command: mypy

osx-python3.6:
macos:
Expand All @@ -30,22 +33,6 @@ jobs:
command: venv/bin/python ./bin/run_tests.py
no_output_timeout: 30m

osx-python3.7:
macos:
xcode: "10.0.0"
environment:
PYTHON: python3
steps:
- checkout

- run:
name: Prepare the environment.
command: bash .circleci/prepare.sh
- run:
name: Test.
command: venv/bin/python ./bin/run_tests.py
no_output_timeout: 30m

linux-python3.6:
docker:
- image: circleci/python:3.6
Expand All @@ -67,7 +54,6 @@ workflows:
version: 2
all-tests:
jobs:
- flake8
- flake8-mypy
- osx-python3.6
- osx-python3.7
- linux-python3.6
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,6 @@ env3?/

# VSCode project settings
/.vscode

# MyPy cache
.mypy_cache/
26 changes: 13 additions & 13 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ branches:

jobs:
include:
- name: Linux | x86_64 + i686 | Python 3.5
- name: Linux | x86_64 + i686 | Python 3.6
language: python
python: 3.5
python: 3.6
services: docker
env: PYTHON=python

- name: Linux | arm64 | Python 3.5
- name: Linux | arm64 | Python 3.6
language: python
python: 3.5
python: 3.6
services: docker
arch: arm64
env: PYTHON=python

- name: Linux | ppc64le | Python 3.5
- name: Linux | ppc64le | Python 3.6
language: python
python: 3.5
python: 3.6
services: docker
arch: ppc64le
env: PYTHON=python
Expand All @@ -30,25 +30,25 @@ jobs:
os: osx
env: PYTHON=python3

- name: Windows | x86_64 | Python 3.5
- name: Windows | x86_64 | Python 3.6
os: windows
language: shell
before_install:
- choco install python3 --version 3.5.4 --no-progress -y
- choco install python3 --version 3.6.8 --no-progress -y
env:
- PYTHON=C:\\Python35\\python
- PYTHON=C:\\Python36\\python

- &linux_s390x_35
name: Linux | s390x | Python 3.5
- &linux_s390x_36
name: Linux | s390x | Python 3.6
language: python
python: 3.5
python: 3.6
services: docker
arch: s390x
env: PYTHON=python

allow_failures:
# must repeat the s390x job above exactly to match
- *linux_s390x_35
- *linux_s390x_36

install: $PYTHON -m pip install -r requirements-dev.txt

Expand Down
12 changes: 6 additions & 6 deletions CI.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
This is a summary of the Python versions and platforms covered by the different CI platforms:

| | 3.5 | 3.6 | 3.7 | 3.8 |
|----------|------------------|------------------|----------------------------------------------------|------------------|
| Linux | Travis CI | CircleCI | AppVeyor² / GitHub Actions | Azure Pipelines |
| macOS | Azure Pipelines | CircleCI | AppVeyor² / Travis CI¹ / CircleCI / GitHub Actions | Azure Pipelines |
| Windows | TravisCI | Azure Pipelines | AppVeyor² / GitHub Actions | Azure Pipelines |
| | 3.6 | 3.7 | 3.8 |
|----------|------------------------------|------------------------------------------|------------------|
| Linux | Travis CI / CircleCI | AppVeyor² / GitHub Actions | Azure Pipelines |
| macOS | CircleCI | AppVeyor² / Travis CI¹ / GitHub Actions | Azure Pipelines |
| Windows | Travis CI / Azure Pipelines | AppVeyor² / GitHub Actions | Azure Pipelines |

> ¹ Python version not really pinned, but dependent on the (default) version of image used.
> ² AppVeyor only runs the "basic" test to reduce load.
Non-x86 architectures are covered on Travis CI using Python 3.5.
Non-x86 architectures are covered on Travis CI using Python 3.6.
10 changes: 0 additions & 10 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,6 @@ jobs:
python -m pip install -r requirements-dev.txt
python ./bin/run_tests.py
- job: macos_35
pool: {vmImage: 'macOS-10.15'}
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.5'
- bash: |
python -m pip install -r requirements-dev.txt
python ./bin/run_tests.py
- job: macos_38
pool: {vmImage: 'macOS-10.15'}
steps:
Expand Down
37 changes: 20 additions & 17 deletions cibuildwheel/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import traceback
from configparser import ConfigParser

from typing import Any, Dict, List, Optional, overload

import cibuildwheel
import cibuildwheel.linux
import cibuildwheel.macos
Expand All @@ -14,14 +16,18 @@
parse_environment,
)
from cibuildwheel.util import (
BuildOptions,
BuildSelector,
DependencyConstraints,
Unbuffered,
BuildOptions
)


def get_option_from_environment(option_name, platform=None, default=None):
@overload
def get_option_from_environment(option_name: str, platform: Optional[str], default: str) -> str: ... # noqa: E704
@overload
def get_option_from_environment(option_name: str, platform: Optional[str] = None, default: None = None) -> Optional[str]: ... # noqa: E704 E302
def get_option_from_environment(option_name: str, platform: Optional[str] = None, default: Optional[str] = None) -> Optional[str]: # noqa: E302
'''
Returns an option from the environment, optionally scoped by the platform.
Expand All @@ -39,13 +45,13 @@ def get_option_from_environment(option_name, platform=None, default=None):
return os.environ.get(option_name, default)


def strtobool(val):
def strtobool(val: str) -> bool:
if val.lower() in ('y', 'yes', 't', 'true', 'on', '1'):
return True
return False


def main():
def main() -> None:
parser = argparse.ArgumentParser(
description='Build wheels for all the platforms.',
epilog='''
Expand Down Expand Up @@ -114,7 +120,7 @@ def main():
test_extras = get_option_from_environment('CIBW_TEST_EXTRAS', platform=platform, default='')
package_dir = args.package_dir
before_build = get_option_from_environment('CIBW_BEFORE_BUILD', platform=platform)
build_verbosity = get_option_from_environment('CIBW_BUILD_VERBOSITY', platform=platform, default='')
build_verbosity_str = get_option_from_environment('CIBW_BUILD_VERBOSITY', platform=platform, default='')
build_config, skip_config = os.environ.get('CIBW_BUILD', '*'), os.environ.get('CIBW_SKIP', '')
if platform == 'linux':
repair_command_default = 'auditwheel repair -w {dest_dir} {wheel}'
Expand All @@ -128,7 +134,7 @@ def main():

dependency_versions = get_option_from_environment('CIBW_DEPENDENCY_VERSIONS', platform=platform, default='pinned')
if dependency_versions == 'pinned':
dependency_constraints = DependencyConstraints.with_defaults()
dependency_constraints: Optional[DependencyConstraints] = DependencyConstraints.with_defaults()
elif dependency_versions == 'latest':
dependency_constraints = None
else:
Expand All @@ -138,7 +144,7 @@ def main():
test_extras = '[{0}]'.format(test_extras)

try:
build_verbosity = min(3, max(-3, int(build_verbosity)))
build_verbosity = min(3, max(-3, int(build_verbosity_str)))
except ValueError:
build_verbosity = 0

Expand All @@ -163,6 +169,7 @@ def main():
print_build_identifiers(platform, build_selector)
exit(0)

manylinux_images: Optional[Dict[str, str]] = None
if platform == 'linux':
pinned_docker_images_file = os.path.join(
os.path.dirname(__file__), 'resources', 'pinned_docker_images.cfg'
Expand Down Expand Up @@ -193,9 +200,6 @@ def main():

manylinux_images[build_platform] = image

else:
manylinux_images = None

build_options = BuildOptions(
package_dir=package_dir,
output_dir=output_dir,
Expand All @@ -213,7 +217,7 @@ def main():
)

# Python is buffering by default when running on the CI platforms, giving problems interleaving subprocess call output with unflushed calls to 'print'
sys.stdout = Unbuffered(sys.stdout)
sys.stdout = Unbuffered(sys.stdout) # type: ignore

print_preamble(platform, build_options)

Expand All @@ -231,7 +235,7 @@ def main():
exit(2)


def detect_obsolete_options():
def detect_obsolete_options() -> None:
# 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')]:
Expand All @@ -258,7 +262,7 @@ def detect_obsolete_options():
os.environ[option] = os.environ[option].replace(deprecated, alternative)


def print_preamble(platform, build_options):
def print_preamble(platform: str, build_options: BuildOptions) -> None:
print(textwrap.dedent('''
_ _ _ _ _ _ _
___|_| |_ _ _|_| |_| |_ _ _| |_ ___ ___| |
Expand All @@ -282,21 +286,20 @@ def print_preamble(platform, build_options):
print('\nHere we go!\n')


def print_build_identifiers(platform, build_selector):
def print_build_identifiers(platform: str, build_selector: BuildSelector) -> None:
python_configurations: List[Any] = []
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):
def detect_warnings(platform: str, build_options: BuildOptions) -> List[str]:
warnings = []

# warn about deprecated {python} and {pip}
Expand Down
24 changes: 14 additions & 10 deletions cibuildwheel/bashlex_eval.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import shlex
import subprocess
from collections import namedtuple

import bashlex
from typing import Dict, NamedTuple

NodeExecutionContext = namedtuple('NodeExecutionContext', ['environment', 'input'])
import bashlex # type: ignore


def evaluate(value, environment):
class NodeExecutionContext(NamedTuple):
environment: Dict[str, str]
input: str


def evaluate(value: str, environment: Dict[str, str]) -> str:
if not value:
# empty string evaluates to empty string
# (but trips up bashlex)
Expand All @@ -26,7 +30,7 @@ def evaluate(value, environment):
)


def evaluate_node(node, context):
def evaluate_node(node: bashlex.ast.node, context: NodeExecutionContext) -> str:
if node.kind == 'word':
return evaluate_word_node(node, context=context)
elif node.kind == 'commandsubstitution':
Expand All @@ -37,7 +41,7 @@ def evaluate_node(node, context):
raise ValueError('Unsupported bash construct: "%s"' % node.word)


def evaluate_word_node(node, context):
def evaluate_word_node(node: bashlex.ast.node, context: NodeExecutionContext) -> str:
word_start = node.pos[0]
word_end = node.pos[1]
word_string = context.input[word_start:word_end]
Expand All @@ -49,22 +53,22 @@ def evaluate_word_node(node, context):

# Set all the characters in the part to None
for i in range(part_start, part_end):
letters[i] = None
letters[i] = ''

letters[part_start] = evaluate_node(part, context=context)

# remove the None letters and concat
value = ''.join(l for l in letters if l is not None)
value = ''.join(letters)

# apply bash-like quotes/whitespace treatment
return ' '.join(word.strip() for word in shlex.split(value))


def evaluate_command_node(node, context):
def evaluate_command_node(node: bashlex.ast.node, context: NodeExecutionContext) -> str:
words = [evaluate_node(part, context=context) for part in node.parts]
command = ' '.join(words)
return subprocess.check_output(shlex.split(command), env=context.environment, universal_newlines=True)


def evaluate_parameter_node(node, context):
def evaluate_parameter_node(node: bashlex.ast.node, context: NodeExecutionContext) -> str:
return context.environment.get(node.value, '')
Loading

0 comments on commit ac0012e

Please sign in to comment.