Skip to content

Commit

Permalink
refactor: Override options redesign
Browse files Browse the repository at this point in the history
* Add test for defaults, fix platform detection

* Improve correctness of reader.identifier with block

* Fix options test to be multiplatform

* 'Refactored by Sourcery'

docs: write a section on overrides

tests: test docker launches

feat: add identifiers to launches

test: add test for correct build step generation

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
  • Loading branch information
joerick authored and henryiii committed Oct 17, 2021
1 parent cd07697 commit 08a6944
Show file tree
Hide file tree
Showing 20 changed files with 1,200 additions and 794 deletions.
84 changes: 40 additions & 44 deletions cibuildwheel/__main__.py
Expand Up @@ -2,26 +2,20 @@
import os
import sys
import textwrap
from pathlib import Path
from typing import List, Set, Union
from typing import List, Optional, Set, Union

import cibuildwheel
import cibuildwheel.linux
import cibuildwheel.macos
import cibuildwheel.util
import cibuildwheel.windows
from cibuildwheel.architecture import Architecture, allowed_architectures_check
from cibuildwheel.options import compute_options
from cibuildwheel.options import CommandLineArguments, Options, compute_options
from cibuildwheel.typing import PLATFORMS, PlatformName, assert_never
from cibuildwheel.util import (
AllBuildOptions,
BuildSelector,
Unbuffered,
detect_ci_provider,
)
from cibuildwheel.util import BuildSelector, Unbuffered, detect_ci_provider


def main() -> None:
def main(sys_args: Optional[List[str]] = None) -> None:
platform: PlatformName

parser = argparse.ArgumentParser(
Expand Down Expand Up @@ -104,7 +98,7 @@ def main() -> None:
help="Enable pre-release Python versions if available.",
)

args = parser.parse_args()
args = parser.parse_args(args=sys_args, namespace=CommandLineArguments())

if args.platform != "auto":
platform = args.platform
Expand Down Expand Up @@ -141,68 +135,71 @@ def main() -> None:
print(f"cibuildwheel: Unsupported platform: {platform}", file=sys.stderr)
sys.exit(2)

package_dir = Path(args.package_dir)
output_dir = Path(
args.output_dir
if args.output_dir is not None
else os.environ.get("CIBW_OUTPUT_DIR", "wheelhouse")
)
options = compute_options(platform=platform, command_line_arguments=args)

all_build_options, build_options_by_selector = compute_options(
platform, package_dir, output_dir, args.config_file, args.archs, args.prerelease_pythons
)
package_dir = options.globals.package_dir
package_files = {"setup.py", "setup.cfg", "pyproject.toml"}

if not any(package_dir.joinpath(name).exists() for name in package_files):
names = ", ".join(sorted(package_files, reverse=True))
msg = f"cibuildwheel: Could not find any of {{{names}}} at root of package"
print(msg, file=sys.stderr)
sys.exit(2)

identifiers = get_build_identifiers(
platform, all_build_options.build_selector, all_build_options.architectures
platform=platform,
build_selector=options.globals.build_selector,
architectures=options.globals.architectures,
)

if args.print_build_identifiers:
for identifier in identifiers:
print(identifier)
sys.exit(0)

build_options = AllBuildOptions(all_build_options, build_options_by_selector, identifiers)

# Add CIBUILDWHEEL environment variable
# This needs to be passed on to the docker container in linux.py
os.environ["CIBUILDWHEEL"] = "1"

# 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) # type: ignore[no-untyped-call,assignment]

print_preamble(platform, build_options)
print_preamble(platform=platform, options=options, identifiers=identifiers)

try:
allowed_architectures_check(platform, build_options.architectures)
options.check_for_invalid_configuration(identifiers)
allowed_architectures_check(platform, options.globals.architectures)
except ValueError as err:
print("cibuildwheel:", *err.args, file=sys.stderr)
sys.exit(4)

if not identifiers:
print(
f"cibuildwheel: No build identifiers selected: {build_options.build_selector}",
f"cibuildwheel: No build identifiers selected: {options.globals.build_selector}",
file=sys.stderr,
)
if not args.allow_empty:
sys.exit(3)

output_dir = options.globals.output_dir

if not output_dir.exists():
output_dir.mkdir(parents=True)

with cibuildwheel.util.print_new_wheels(
"\n{n} wheels produced in {m:.0f} minutes:", output_dir
):
if platform == "linux":
cibuildwheel.linux.build(build_options)
cibuildwheel.linux.build(options)
elif platform == "windows":
cibuildwheel.windows.build(build_options)
cibuildwheel.windows.build(options)
elif platform == "macos":
cibuildwheel.macos.build(build_options)
cibuildwheel.macos.build(options)
else:
assert_never(platform)


def print_preamble(platform: str, build_options: AllBuildOptions) -> None:
def print_preamble(platform: str, options: Options, identifiers: List[str]) -> None:
print(
textwrap.dedent(
"""
Expand All @@ -218,9 +215,9 @@ def print_preamble(platform: str, build_options: AllBuildOptions) -> None:

print("Build options:")
print(f" platform: {platform!r}")
print(textwrap.indent(str(build_options), " "))
print(textwrap.indent(options.summary(identifiers), " "))

warnings = detect_warnings(platform, build_options)
warnings = detect_warnings(platform=platform, options=options, identifiers=identifiers)
if warnings:
print("\nWarnings:")
for warning in warnings:
Expand Down Expand Up @@ -256,21 +253,20 @@ def get_build_identifiers(
return [config.identifier for config in python_configurations]


def detect_warnings(platform: str, all_options: AllBuildOptions) -> List[str]:
def detect_warnings(platform: str, options: Options, identifiers: List[str]) -> List[str]:
warnings = []

# warn about deprecated {python} and {pip}
for build_options in all_options.values():
for option_name in ["test_command", "before_build"]:
option_value = getattr(build_options, option_name)

if option_value and ("{python}" in option_value or "{pip}" in option_value):
# Reminder: in an f-string, double braces means literal single brace
msg = (
f"{option_name}: '{{python}}' and '{{pip}}' are no longer needed, "
"and will be removed in a future release. Simply use 'python' or 'pip' instead."
)
warnings.append(msg)
for option_name in ["test_command", "before_build"]:
option_values = [getattr(options.build_options(i), option_name) for i in identifiers]

if any(o and ("{python}" in o or "{pip}" in o) for o in option_values):
# Reminder: in an f-string, double braces means literal single brace
msg = (
f"{option_name}: '{{python}}' and '{{pip}}' are no longer needed, "
"and will be removed in a future release. Simply use 'python' or 'pip' instead."
)
warnings.append(msg)

return warnings

Expand Down
4 changes: 2 additions & 2 deletions cibuildwheel/docker_container.py
Expand Up @@ -17,7 +17,7 @@ class DockerContainer:
An object that represents a running Docker container.
Intended for use as a context manager e.g.
`with DockerContainer('ubuntu') as docker:`
`with DockerContainer(docker_image = 'ubuntu') as docker:`
A bash shell is running in the remote container. When `call()` is invoked,
the command is relayed to the remote shell, and the results are streamed
Expand All @@ -31,7 +31,7 @@ class DockerContainer:
bash_stdout: IO[bytes]

def __init__(
self, docker_image: str, simulate_32_bit: bool = False, cwd: Optional[PathOrStr] = None
self, *, docker_image: str, simulate_32_bit: bool = False, cwd: Optional[PathOrStr] = None
):
if not docker_image:
raise ValueError("Must have a non-empty docker image to run.")
Expand Down

0 comments on commit 08a6944

Please sign in to comment.