Skip to content
Merged
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
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
repos:
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.3
rev: 3.8.4
hooks:
- id: flake8
exclude: cibuildwheel/resources/
additional_dependencies: [flake8-bugbear]

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
rev: v3.4.0
hooks:
- id: check-case-conflict
- id: check-merge-conflict
Expand All @@ -18,8 +18,8 @@ repos:
- id: trailing-whitespace

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.782
rev: v0.790
hooks:
- id: mypy
files: ^(cibuildwheel/|test/|bin/projects.py)
files: ^(cibuildwheel/|test/|bin/projects.py|unit_test/)
pass_filenames: false
6 changes: 3 additions & 3 deletions cibuildwheel/bashlex_eval.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import subprocess
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
EnvironmentExecutor = Callable[[List[str], Dict[str, str]], str]
Expand Down Expand Up @@ -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:
value = node.word
value: str = node.word

for part in node.parts:
part_string = context.input[part.pos[0]:part.pos[1]]
Expand Down Expand Up @@ -95,7 +95,7 @@ def evaluate_nodes_as_compound_command(nodes: Sequence[bashlex.ast.node], contex
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]
return context.executor(command, context.environment)

Expand Down
31 changes: 23 additions & 8 deletions cibuildwheel/docker_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
import subprocess
import sys
import uuid
from os import PathLike
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:
Expand All @@ -23,14 +25,15 @@ class DockerContainer:
'''
UTILITY_PYTHON = '/opt/python/cp38-cp38/bin/python'

process: subprocess.Popen
process: PopenBytes
bash_stdin: 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.simulate_32_bit = simulate_32_bit
self.cwd = cwd
self.name: Optional[str] = None

def __enter__(self) -> 'DockerContainer':
self.name = f'cibuildwheel-{uuid.uuid4()}'
Expand Down Expand Up @@ -68,11 +71,18 @@ def __enter__(self) -> 'DockerContainer':

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.process.terminate()
self.process.wait()

assert isinstance(self.name, str)

subprocess.run(['docker', 'rm', '--force', '-v', self.name], stdout=subprocess.DEVNULL)
self.name = None

Expand Down Expand Up @@ -117,8 +127,12 @@ def glob(self, path: PurePath, pattern: str) -> List[PurePath]:

return [PurePath(p) for p in path_strs]

def call(self, args: Sequence[Union[str, PathLike]], env: Optional[Dict[str, str]] = None,
capture_output=False, cwd: Optional[Union[str, PathLike]] = None) -> str:
def call(
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 ''
env_assignments = ' '.join(f'{shlex.quote(k)}={shlex.quote(v)}'
Expand Down Expand Up @@ -178,11 +192,12 @@ def call(self, args: Sequence[Union[str, PathLike]], env: Optional[Dict[str, str
return output

def get_environment(self) -> Dict[str, str]:
return json.loads(self.call([
env = json.loads(self.call([
self.UTILITY_PYTHON,
'-c',
'import sys, json, os; json.dump(os.environ.copy(), sys.stdout)'
], capture_output=True))
return cast(Dict[str, str], env)

def environment_executor(self, command: List[str], environment: Dict[str, str]) -> str:
# used as an EnvironmentExecutor to evaluate commands and capture output
Expand Down
2 changes: 1 addition & 1 deletion cibuildwheel/environment.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import bashlex # type: ignore
import bashlex

from typing import Dict, List, Mapping, Optional

Expand Down
8 changes: 4 additions & 4 deletions cibuildwheel/linux.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import subprocess
import sys
import textwrap
from os import PathLike
from pathlib import Path, PurePath
from typing import List, NamedTuple, Union
from typing import List, NamedTuple

from .docker_container import DockerContainer
from .logger import log
from .util import (
Architecture, BuildOptions, BuildSelector, NonPlatformWheelError,
get_build_verbosity_extra_flags, prepare_command,
)
from .typing import PathOrStr


class PythonConfiguration(NamedTuple):
Expand All @@ -19,7 +19,7 @@ class PythonConfiguration(NamedTuple):
path_str: str

@property
def path(self):
def path(self) -> PurePath:
return PurePath(self.path_str)


Expand Down Expand Up @@ -125,7 +125,7 @@ def build(options: BuildOptions) -> None:
for config in platform_configs:
log.build_start(config.identifier)

dependency_constraint_flags: List[Union[str, PathLike]] = []
dependency_constraint_flags: List[PathOrStr] = []
if config.identifier.startswith("pp"):
# Patch PyPy to make sure headers get installed into a venv
patch_version = '_27' if config.version == '2.7' else ''
Expand Down
86 changes: 36 additions & 50 deletions cibuildwheel/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import re
import sys
import time
from typing import Optional, Union
from typing import Optional, Union, AnyStr, IO

from cibuildwheel.util import CIProvider, detect_ci_provider

Expand Down Expand Up @@ -35,7 +35,7 @@ class Logger:
step_start_time: Optional[float] = None
active_fold_group_name: Optional[str] = None

def __init__(self):
def __init__(self) -> None:
if sys.platform == 'win32' and hasattr(sys.stdout, 'reconfigure'):
# the encoding on Windows can be a 1-byte charmap, but all CIs
# support utf8, so we hardcode that
Expand Down Expand Up @@ -65,7 +65,7 @@ def __init__(self):
self.fold_mode = 'disabled'
self.colors_enabled = file_supports_color(sys.stdout)

def build_start(self, identifier: str):
def build_start(self, identifier: str) -> None:
self.step_end()
c = self.colors
description = build_description_from_identifier(identifier)
Expand All @@ -77,7 +77,7 @@ def build_start(self, identifier: str):
self.build_start_time = time.time()
self.active_build_identifier = identifier

def build_end(self):
def build_end(self) -> None:
assert self.build_start_time is not None
assert self.active_build_identifier is not None
self.step_end()
Expand All @@ -91,12 +91,12 @@ def build_end(self):
self.build_start_time = None
self.active_build_identifier = None

def step(self, step_description: str):
def step(self, step_description: str) -> None:
self.step_end()
self.step_start_time = time.time()
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:
self._end_fold_group()
c = self.colors
Expand All @@ -109,7 +109,7 @@ def step_end(self, success=True):

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)
print()

Expand All @@ -119,7 +119,7 @@ def error(self, error: Union[Exception, str]):
c = self.colors
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.active_fold_group_name = name
fold_start_pattern = FOLD_PATTERNS.get(self.fold_mode, DEFAULT_FOLD_PATTERN)[0]
Expand All @@ -129,15 +129,15 @@ def _start_fold_group(self, name: str):
print()
sys.stdout.flush()

def _end_fold_group(self):
def _end_fold_group(self) -> None:
if self.active_fold_group_name:
fold_start_pattern = FOLD_PATTERNS.get(self.fold_mode, DEFAULT_FOLD_PATTERN)[1]
identifier = self._fold_group_identifier(self.active_fold_group_name)
print(fold_start_pattern.format(name=self.active_fold_group_name, identifier=identifier))
sys.stdout.flush()
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
method converts them to ascii identifiers
Expand All @@ -152,21 +152,21 @@ def _fold_group_identifier(self, name: str):
return identifier.lower()[:20]

@property
def colors(self):
def colors(self) -> "Colors":
if self.colors_enabled:
return Colors.enabled
return Colors(enabled=True)
else:
return Colors.disabled
return Colors(enabled=False)

@property
def symbols(self):
def symbols(self) -> "Symbols":
if self.unicode_enabled:
return Symbols.unicode
return Symbols(unicode=True)
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('-')

build_description = ''
Expand All @@ -192,45 +192,31 @@ def build_description_from_identifier(identifier: str):


class Colors:
class Enabled:
red = '\033[31m'
green = '\033[32m'
yellow = '\033[33m'
blue = '\033[34m'
cyan = '\033[36m'
bright_red = '\033[91m'
bright_green = '\033[92m'
white = '\033[37m\033[97m'
def __init__(self, *, enabled: bool) -> None:
self.red = '\033[31m' if enabled else ''
self.green = '\033[32m' if enabled else ''
self.yellow = '\033[33m' if enabled else ''
self.blue = '\033[34m' if enabled else ''
self.cyan = '\033[36m' if enabled else ''
self.bright_red = '\033[91m' if enabled else ''
self.bright_green = '\033[92m' if enabled else ''
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'
faint = '\033[2m'
self.bold = '\033[1m' if enabled else ''
self.faint = '\033[2m' if enabled else ''

end = '\033[0m'

class Disabled:
def __getattr__(self, attr: str) -> str:
return ''

enabled = Enabled()
disabled = Disabled()
self.end = '\033[0m' if enabled else ''


class Symbols:
class Unicode:
done = '✓'
error = '✕'

class Ascii:
done = 'done'
error = 'failed'

unicode = Unicode()
ascii = Ascii()
def __init__(self, *, unicode: bool) -> None:
self.done = '✓' if unicode else 'done'
self.error = '✕' if unicode else 'failed'


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.
"""
Expand All @@ -242,11 +228,11 @@ def file_supports_color(file_obj):
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()


def file_supports_unicode(file_obj):
def file_supports_unicode(file_obj: IO[AnyStr]) -> bool:
encoding = getattr(file_obj, 'encoding', None)
if not encoding:
return False
Expand Down
Loading