From bc17f103f199366cfe2669b440e0ca4b01695362 Mon Sep 17 00:00:00 2001 From: mayeut Date: Thu, 14 Jul 2022 12:47:01 +0200 Subject: [PATCH 1/3] chore: drop python 3.6 for cibuildwheel driver This drops python 3.6 for cibuildwheel. Building python 3.6 packages is still supported. --- .circleci/config.yml | 10 +++++----- .pre-commit-config.yaml | 17 +++-------------- .travis.yml | 22 +++++++++++----------- CI.md | 12 ++++++------ azure-pipelines.yml | 11 ----------- bin/update_dependencies.py | 1 - cibuildwheel/bashlex_eval.py | 4 +--- docs/contributing.md | 2 -- examples/circleci-minimal.yml | 2 +- examples/travis-ci-test-and-deploy.yml | 1 - pyproject.toml | 4 ++-- setup.cfg | 4 +--- test/test_macos_archs.py | 2 +- test/utils.py | 2 +- unit_test/oci_container_test.py | 4 ++-- 15 files changed, 34 insertions(+), 64 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 62cefcab..3a657f7e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2 jobs: - osx-python3.6: + osx-python3.9: macos: xcode: 12.5.1 environment: @@ -17,9 +17,9 @@ jobs: command: venv/bin/python ./bin/run_tests.py no_output_timeout: 30m - linux-python3.6: + linux-python3.9: docker: - - image: circleci/python:3.6 + - image: circleci/python:3.9 environment: PYTHON: python3 # Temporarily restrict the tests that are run on CircleCI to prevent @@ -41,5 +41,5 @@ workflows: version: 2 all-tests: jobs: - - osx-python3.6 - - linux-python3.6 + - osx-python3.9 + - linux-python3.9 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fdd22536..38864019 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,12 +17,6 @@ repos: rev: v2.37.1 hooks: - id: pyupgrade - name: PyUpgrade 3.6+ - args: ["--py36-plus"] - exclude: ^bin/ - - id: pyupgrade - name: PyUpgrade 3.7+ on bin - exclude: ^(cibuildwheel|unit_test|test)/ args: ["--py37-plus"] # Autoremoves unused imports @@ -52,9 +46,9 @@ repos: rev: v0.961 hooks: - id: mypy - name: mypy 3.6 on cibuildwheel/ - exclude: ^(bin|cibuildwheel/resources|docs)/.*py$ - args: ["--python-version=3.6"] + name: mypy 3.7 on cibuildwheel/ + exclude: ^cibuildwheel/resources/.*py$ + args: ["--python-version=3.7"] additional_dependencies: &mypy-dependencies - nox - packaging>=21.0 @@ -70,11 +64,6 @@ repos: - types-requests - bracex - dataclasses - - id: mypy - name: mypy 3.7+ on bin/ - files: ^((bin|docs)/.*py)$ - args: ["--python-version=3.7"] - additional_dependencies: *mypy-dependencies - id: mypy name: mypy 3.10 args: ["--python-version=3.10"] diff --git a/.travis.yml b/.travis.yml index aad9e5a5..4256a69b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,21 +8,21 @@ branches: jobs: include: - - name: Linux | x86_64 + i686 | Python 3.6 - python: 3.6 + - name: Linux | x86_64 + i686 | Python 3.7 + python: 3.7 services: docker env: PYTHON=python - - name: Linux | arm64 | Python 3.6 - python: 3.6 + - name: Linux | arm64 | Python 3.7 + python: 3.7 services: docker arch: arm64-graviton2 group: edge virt: vm env: PYTHON=python - - name: Linux | ppc64le | Python 3.6 - python: 3.6 + - name: Linux | ppc64le | Python 3.7 + python: 3.7 services: docker arch: ppc64le allow_failure: True @@ -32,18 +32,18 @@ jobs: # c.f. https://travis-ci.community/t/running-out-of-disk-space-quota-when-using-docker-on-ppc64le/11634 - PYTEST_ADDOPTS='-k "not test_manylinuxXXXX_only"' - - name: Windows | x86_64 | Python 3.6 + - name: Windows | x86_64 | Python 3.7 os: windows language: shell before_install: - - choco upgrade python3 -y --version 3.6.8 --limit-output + - choco upgrade python3 -y --version 3.7.9 --limit-output # Update root certificates to fix SSL error; see http://www.chawn.com/RootCerts.htm - powershell "md C:\temp\certs; CertUtil -generateSSTFromWU C:\temp\certs\RootStore.sst; Get-ChildItem -Path C:\\temp\certs\Rootstore.sst | Import-Certificate -CertStoreLocation Cert:\\LocalMachine\\Root\\ | out-null" env: - - PYTHON=C:\\Python36\\python + - PYTHON=C:\\Python37\\python - - name: Linux | s390x | Python 3.6 - python: 3.6 + - name: Linux | s390x | Python 3.7 + python: 3.7 services: docker arch: s390x env: PYTHON=python diff --git a/CI.md b/CI.md index 8ac4ada5..76167c35 100644 --- a/CI.md +++ b/CI.md @@ -1,11 +1,11 @@ This is a summary of the Python versions and platforms covered by the different CI platforms: -| | 3.6 | 3.7 | 3.8 | -|----------|------------------------------|-----------------------------|------------------| -| Linux | Travis CI / CircleCI | AppVeyor¹ / GitHub Actions | Azure Pipelines | -| macOS | CircleCI | AppVeyor¹ / GitHub Actions | Azure Pipelines | -| Windows | Travis CI / Azure Pipelines | AppVeyor¹ / GitHub Actions | Azure Pipelines | +| | 3.7 | 3.8 | 3.9 | 3.10 | +|----------|-----------------------|---------------------------|----------|----------------| +| Linux | AppVeyor¹ / Travis CI | Azure Pipelines / GitLab | CircleCI | GitHub Actions | +| macOS | AppVeyor¹ / Travis CI | Azure Pipelines | CircleCI | GitHub Actions | +| Windows | AppVeyor¹ / Travis CI | Azure Pipelines | | GitHub Actions | > ¹ AppVeyor only runs the "basic" test to reduce load. -Non-x86 architectures are covered on Travis CI using Python 3.6. +Non-x86 architectures are covered on Travis CI using Python 3.7. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 56131899..f8142ce8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -20,17 +20,6 @@ jobs: python -m pip install -e ".[dev]" pytest-azurepipelines python ./bin/run_tests.py -- job: windows_36 - pool: {vmImage: 'windows-2019'} - timeoutInMinutes: 180 - steps: - - task: UsePythonVersion@0 - inputs: - versionSpec: '3.6' - - bash: | - python -m pip install -e ".[dev]" pytest-azurepipelines - python ./bin/run_tests.py - - job: windows_38 pool: {vmImage: 'windows-2019'} timeoutInMinutes: 180 diff --git a/bin/update_dependencies.py b/bin/update_dependencies.py index 69e62cfa..9dc9f536 100755 --- a/bin/update_dependencies.py +++ b/bin/update_dependencies.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# This file supports 3.6+ import os import shutil diff --git a/cibuildwheel/bashlex_eval.py b/cibuildwheel/bashlex_eval.py index a8b4691c..cd1fa563 100644 --- a/cibuildwheel/bashlex_eval.py +++ b/cibuildwheel/bashlex_eval.py @@ -9,9 +9,7 @@ EnvironmentExecutor = Callable[[List[str], Dict[str, str]], str] def local_environment_executor(command: List[str], env: Dict[str, str]) -> str: - return subprocess.run( - command, env=env, universal_newlines=True, stdout=subprocess.PIPE, check=True - ).stdout + return subprocess.run(command, env=env, text=True, stdout=subprocess.PIPE, check=True).stdout @dataclass(frozen=True) diff --git a/docs/contributing.md b/docs/contributing.md index c6a5b930..24566e4e 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -94,7 +94,6 @@ This has been moved to using docker, so you only need the following instructions The dependency update script in the next section requires multiple python versions installed. One way to do this is to use `pyenv`: ```bash -pyenv install 3.6.11 pyenv install 3.7.8 # Optionally add 3.8 and make it the local version; # otherwise assuming 3.8+ already is your current python version @@ -103,7 +102,6 @@ pyenv install 3.7.8 Then, you need to make the required virtual environments: ```bash -$(pyenv prefix 3.6.11)/bin/python -m venv env36 $(pyenv prefix 3.7.8)/bin/python -m venv env37 ``` diff --git a/examples/circleci-minimal.yml b/examples/circleci-minimal.yml index d8ebea72..3162ceb5 100644 --- a/examples/circleci-minimal.yml +++ b/examples/circleci-minimal.yml @@ -4,7 +4,7 @@ jobs: linux-wheels: working_directory: ~/linux-wheels docker: - - image: circleci/python:3.6 + - image: circleci/python:3.9 steps: - checkout - setup_remote_docker diff --git a/examples/travis-ci-test-and-deploy.yml b/examples/travis-ci-test-and-deploy.yml index 837db2eb..42a27954 100644 --- a/examples/travis-ci-test-and-deploy.yml +++ b/examples/travis-ci-test-and-deploy.yml @@ -9,7 +9,6 @@ os: linux dist: focal language: python python: - - 3.6 - 3.7 - 3.8 diff --git a/pyproject.toml b/pyproject.toml index 40f8dc5a..6c78cdb0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta" [tool.black] line-length = 100 -target-version = ['py36', 'py37', 'py38', 'py39', 'py310'] +target-version = ['py37', 'py38', 'py39', 'py310'] [tool.isort] @@ -88,7 +88,7 @@ ignore = [ ] [tool.pylint] -master.py-version = "3.6" +master.py-version = "3.7" master.jobs = "0" master.fail-on = ["E", "F"] master.fail-under = "9.8" diff --git a/setup.cfg b/setup.cfg index 2efc7c51..51718be9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -16,7 +16,6 @@ classifiers = Natural Language :: English Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 @@ -37,10 +36,9 @@ install_requires = filelock packaging>=20.9 platformdirs - dataclasses;python_version < '3.7' tomli;python_version < '3.11' typing-extensions>=3.10.0.0;python_version < '3.8' -python_requires = >=3.6 +python_requires = >=3.7 include_package_data = True zip_safe = False diff --git a/test/test_macos_archs.py b/test/test_macos_archs.py index a5db09f8..a85a6b24 100644 --- a/test/test_macos_archs.py +++ b/test/test_macos_archs.py @@ -17,7 +17,7 @@ ALL_MACOS_WHEELS = { def get_xcode_version() -> Tuple[int, int]: output = subprocess.run( ["xcodebuild", "-version"], - universal_newlines=True, + text=True, check=True, stdout=subprocess.PIPE, ).stdout diff --git a/test/utils.py b/test/utils.py index 22fe4c1a..ebe682e3 100644 --- a/test/utils.py +++ b/test/utils.py @@ -35,7 +35,7 @@ def cibuildwheel_get_build_identifiers(project_path, env=None, *, prerelease_pyt cmd_output = subprocess.run( cmd, - universal_newlines=True, + text=True, env=env, check=True, stdout=subprocess.PIPE, diff --git a/unit_test/oci_container_test.py b/unit_test/oci_container_test.py index 2f425daf..05ef24fd 100644 --- a/unit_test/oci_container_test.py +++ b/unit_test/oci_container_test.py @@ -83,7 +83,7 @@ def test_container_removed(container_engine): shell=True, check=True, stdout=subprocess.PIPE, - universal_newlines=True, + text=True, ).stdout assert container.name is not None assert container.name in docker_containers_listing @@ -94,7 +94,7 @@ def test_container_removed(container_engine): shell=True, check=True, stdout=subprocess.PIPE, - universal_newlines=True, + text=True, ).stdout assert old_container_name not in docker_containers_listing From 054230e01ba8d090357f90092eda0078448b0da3 Mon Sep 17 00:00:00 2001 From: mayeut Date: Thu, 14 Jul 2022 15:23:59 +0200 Subject: [PATCH 2/3] fix: test_build_default_launches to use an empty package dir test_build_default_launches was using cibuildwheel setup.cfg which led to the test failing once python 3.6 was dropped. Use an empty package, provided by fake_package_dir, to run the test. --- unit_test/conftest.py | 4 +++- unit_test/option_prepare_test.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/unit_test/conftest.py b/unit_test/conftest.py index cbfdbb72..3d98c30b 100644 --- a/unit_test/conftest.py +++ b/unit_test/conftest.py @@ -12,7 +12,7 @@ def pytest_addoption(parser): @pytest.fixture -def fake_package_dir(monkeypatch): +def fake_package_dir(tmp_path, monkeypatch): """ Monkey-patch enough for the main() function to run """ @@ -25,6 +25,8 @@ def fake_package_dir(monkeypatch): return real_path_exists(path) args = ["cibuildwheel", str(MOCK_PACKAGE_DIR)] + tmp_path.joinpath(MOCK_PACKAGE_DIR).mkdir() monkeypatch.setattr(Path, "exists", mock_path_exists) monkeypatch.setattr(sys, "argv", args) + monkeypatch.chdir(tmp_path) return args diff --git a/unit_test/option_prepare_test.py b/unit_test/option_prepare_test.py index 10bca432..3eef68a7 100644 --- a/unit_test/option_prepare_test.py +++ b/unit_test/option_prepare_test.py @@ -44,7 +44,7 @@ def mock_build_container(monkeypatch): def test_build_default_launches(mock_build_container, fake_package_dir, monkeypatch): - monkeypatch.setattr(sys, "argv", ["cibuildwheel", "--platform=linux"]) + monkeypatch.setattr(sys, "argv", sys.argv + ["--platform=linux"]) main() From 6d27f05c7cc57786febc4eb5894ef27ef078ee0e Mon Sep 17 00:00:00 2001 From: mayeut Date: Thu, 14 Jul 2022 13:36:57 +0200 Subject: [PATCH 3/3] chore: use `from __future__ import annotations` --- .pre-commit-config.yaml | 3 + bin/run_tests.py | 2 + bin/update_dependencies.py | 2 + bin/update_readme_changelog.py | 2 + cibuildwheel/__init__.py | 2 + cibuildwheel/__main__.py | 21 ++--- cibuildwheel/architecture.py | 15 ++-- cibuildwheel/bashlex_eval.py | 12 +-- cibuildwheel/environment.py | 20 ++--- cibuildwheel/extra.py | 5 +- cibuildwheel/functools_cached_property_38.py | 14 ++-- cibuildwheel/linux.py | 20 ++--- cibuildwheel/logger.py | 20 ++--- cibuildwheel/macos.py | 18 +++-- cibuildwheel/oci_container.py | 26 +++--- cibuildwheel/options.py | 81 +++++++++---------- cibuildwheel/projectfiles.py | 10 ++- cibuildwheel/typing.py | 4 +- cibuildwheel/util.py | 48 +++++------ cibuildwheel/windows.py | 16 ++-- docs/main.py | 2 + noxfile.py | 2 + setup.py | 2 + test/conftest.py | 4 +- test/test_0_basic.py | 2 + test/test_abi_variants.py | 2 + test/test_before_all.py | 2 + test/test_before_build.py | 2 + test/test_before_test.py | 2 + test/test_build_skip.py | 2 + test/test_container_images.py | 2 + test/test_cpp_standards.py | 2 + test/test_dependency_versions.py | 2 + test/test_emulation.py | 2 + test/test_environment.py | 2 + test/test_from_sdist.py | 2 + test/test_macos_archs.py | 5 +- test/test_manylinuxXXXX_only.py | 2 + test/test_pep518.py | 2 + test/test_podman.py | 2 + test/test_projects/__init__.py | 2 + test/test_projects/__main__.py | 2 + test/test_projects/base.py | 2 + test/test_projects/c.py | 2 + test/test_pure_wheel.py | 2 + test/test_same_wheel.py | 2 + test/test_ssl.py | 2 + test/test_subdir_package.py | 2 + test/test_testing.py | 2 + test/test_troubleshooting.py | 2 + test/test_wheel_tag.py | 2 + test/utils.py | 2 + unit_test/build_ids_test.py | 5 +- unit_test/build_selector_test.py | 2 + unit_test/conftest.py | 2 + unit_test/dependency_constraints_test.py | 2 + unit_test/download_test.py | 2 + unit_test/environment_test.py | 2 + unit_test/linux_build_steps_test.py | 2 + unit_test/main_tests/conftest.py | 2 + unit_test/main_tests/main_options_test.py | 2 + unit_test/main_tests/main_platform_test.py | 2 + .../main_tests/main_requires_python_test.py | 2 + unit_test/oci_container_test.py | 2 + unit_test/option_prepare_test.py | 2 + unit_test/options_test.py | 2 + unit_test/options_toml_test.py | 2 + unit_test/projectfiles_test.py | 2 + unit_test/utils.py | 2 + unit_test/utils_test.py | 2 + unit_test/wheel_print_test.py | 2 + 71 files changed, 285 insertions(+), 166 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 38864019..271c1019 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,6 +18,7 @@ repos: hooks: - id: pyupgrade args: ["--py37-plus"] + exclude: ^cibuildwheel/resources/.*py$ # Autoremoves unused imports - repo: https://github.com/hadialqattan/pycln @@ -31,6 +32,8 @@ repos: rev: 5.10.1 hooks: - id: isort + args: ["-a", "from __future__ import annotations"] + exclude: ^cibuildwheel/resources/.*py$ - repo: https://github.com/psf/black rev: 22.6.0 diff --git a/bin/run_tests.py b/bin/run_tests.py index 82e193c3..583d13c7 100755 --- a/bin/run_tests.py +++ b/bin/run_tests.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from __future__ import annotations + import argparse import os import subprocess diff --git a/bin/update_dependencies.py b/bin/update_dependencies.py index 9dc9f536..c0d7f200 100755 --- a/bin/update_dependencies.py +++ b/bin/update_dependencies.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from __future__ import annotations + import os import shutil import subprocess diff --git a/bin/update_readme_changelog.py b/bin/update_readme_changelog.py index 90b2ffd8..4a4625ff 100755 --- a/bin/update_readme_changelog.py +++ b/bin/update_readme_changelog.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from __future__ import annotations + import re import sys from pathlib import Path diff --git a/cibuildwheel/__init__.py b/cibuildwheel/__init__.py index b4066b65..b923f228 100644 --- a/cibuildwheel/__init__.py +++ b/cibuildwheel/__init__.py @@ -1 +1,3 @@ +from __future__ import annotations + __version__ = "2.8.1" diff --git a/cibuildwheel/__main__.py b/cibuildwheel/__main__.py index a3b7711f..034673a2 100644 --- a/cibuildwheel/__main__.py +++ b/cibuildwheel/__main__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import argparse import os import shutil @@ -7,7 +9,6 @@ import tempfile import textwrap from pathlib import Path from tempfile import mkdtemp -from typing import List, Set, Union import cibuildwheel import cibuildwheel.linux @@ -257,7 +258,7 @@ def build_in_directory(args: CommandLineArguments) -> None: log.warning(f"Can't delete temporary folder '{str(tmp_path)}'") -def print_preamble(platform: str, options: Options, identifiers: List[str]) -> None: +def print_preamble(platform: str, options: Options, identifiers: list[str]) -> None: print( textwrap.dedent( """ @@ -287,13 +288,13 @@ def print_preamble(platform: str, options: Options, identifiers: List[str]) -> N def get_build_identifiers( - platform: PlatformName, build_selector: BuildSelector, architectures: Set[Architecture] -) -> List[str]: - python_configurations: Union[ - List[cibuildwheel.linux.PythonConfiguration], - List[cibuildwheel.windows.PythonConfiguration], - List[cibuildwheel.macos.PythonConfiguration], - ] + platform: PlatformName, build_selector: BuildSelector, architectures: set[Architecture] +) -> list[str]: + python_configurations: ( + list[cibuildwheel.linux.PythonConfiguration] + | list[cibuildwheel.windows.PythonConfiguration] + | list[cibuildwheel.macos.PythonConfiguration] + ) if platform == "linux": python_configurations = cibuildwheel.linux.get_python_configurations( @@ -313,7 +314,7 @@ def get_build_identifiers( return [config.identifier for config in python_configurations] -def detect_warnings(*, options: Options, identifiers: List[str]) -> List[str]: +def detect_warnings(*, options: Options, identifiers: list[str]) -> list[str]: warnings = [] # warn about deprecated {python} and {pip} diff --git a/cibuildwheel/architecture.py b/cibuildwheel/architecture.py index be87f321..82a78b30 100644 --- a/cibuildwheel/architecture.py +++ b/cibuildwheel/architecture.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import functools import platform as platform_module import re from enum import Enum -from typing import Set from .typing import Final, Literal, PlatformName, assert_never @@ -32,11 +33,11 @@ class Architecture(Enum): ARM64 = "ARM64" # Allow this to be sorted - def __lt__(self, other: "Architecture") -> bool: + def __lt__(self, other: Architecture) -> bool: return self.value < other.value @staticmethod - def parse_config(config: str, platform: PlatformName) -> "Set[Architecture]": + def parse_config(config: str, platform: PlatformName) -> set[Architecture]: result = set() for arch_str in re.split(r"[\s,]+", config): if arch_str == "auto": @@ -54,7 +55,7 @@ class Architecture(Enum): return result @staticmethod - def auto_archs(platform: PlatformName) -> "Set[Architecture]": + def auto_archs(platform: PlatformName) -> set[Architecture]: native_architecture = Architecture(platform_module.machine()) result = {native_architecture} @@ -72,7 +73,7 @@ class Architecture(Enum): return result @staticmethod - def all_archs(platform: PlatformName) -> "Set[Architecture]": + def all_archs(platform: PlatformName) -> set[Architecture]: all_archs_map = { "linux": { Architecture.x86_64, @@ -87,7 +88,7 @@ class Architecture(Enum): return all_archs_map[platform] @staticmethod - def bitness_archs(platform: PlatformName, bitness: Literal["64", "32"]) -> "Set[Architecture]": + def bitness_archs(platform: PlatformName, bitness: Literal["64", "32"]) -> set[Architecture]: archs_32 = {Architecture.i686, Architecture.x86} auto_archs = Architecture.auto_archs(platform) @@ -101,7 +102,7 @@ class Architecture(Enum): def allowed_architectures_check( platform: PlatformName, - architectures: Set[Architecture], + architectures: set[Architecture], ) -> None: allowed_architectures = Architecture.all_archs(platform) diff --git a/cibuildwheel/bashlex_eval.py b/cibuildwheel/bashlex_eval.py index cd1fa563..47e4aea3 100644 --- a/cibuildwheel/bashlex_eval.py +++ b/cibuildwheel/bashlex_eval.py @@ -1,6 +1,8 @@ +from __future__ import annotations + import subprocess from dataclasses import dataclass -from typing import Callable, Dict, List, Optional, Sequence +from typing import Callable, Dict, List, Sequence import bashlex @@ -8,19 +10,19 @@ import bashlex EnvironmentExecutor = Callable[[List[str], Dict[str, str]], str] -def local_environment_executor(command: List[str], env: Dict[str, str]) -> str: +def local_environment_executor(command: list[str], env: dict[str, str]) -> str: return subprocess.run(command, env=env, text=True, stdout=subprocess.PIPE, check=True).stdout @dataclass(frozen=True) class NodeExecutionContext: - environment: Dict[str, str] + environment: dict[str, str] input: str executor: EnvironmentExecutor def evaluate( - value: str, environment: Dict[str, str], executor: Optional[EnvironmentExecutor] = None + value: str, environment: dict[str, str], executor: EnvironmentExecutor | None = None ) -> str: if not value: # empty string evaluates to empty string @@ -101,7 +103,7 @@ def evaluate_nodes_as_compound_command( def evaluate_nodes_as_simple_command( - nodes: List[bashlex.ast.node], context: NodeExecutionContext + nodes: list[bashlex.ast.node], context: NodeExecutionContext ) -> str: command = [evaluate_node(part, context=context) for part in nodes] return context.executor(command, context.environment) diff --git a/cibuildwheel/environment.py b/cibuildwheel/environment.py index 3bf982d2..a544852a 100644 --- a/cibuildwheel/environment.py +++ b/cibuildwheel/environment.py @@ -1,5 +1,7 @@ +from __future__ import annotations + import dataclasses -from typing import Any, Dict, List, Mapping, Optional, Sequence +from typing import Any, Mapping, Sequence import bashlex @@ -12,7 +14,7 @@ class EnvironmentParseError(Exception): pass -def split_env_items(env_string: str) -> List[str]: +def split_env_items(env_string: str) -> list[str]: """Splits space-separated variable assignments into a list of individual assignments. >>> split_env_items('VAR=abc') @@ -47,8 +49,8 @@ class EnvironmentAssignment(Protocol): def evaluated_value( self, *, - environment: Dict[str, str], - executor: Optional[bashlex_eval.EnvironmentExecutor] = None, + environment: dict[str, str], + executor: bashlex_eval.EnvironmentExecutor | None = None, ) -> str: """Returns the value of this assignment, as evaluated in the environment""" @@ -84,8 +86,8 @@ class EnvironmentAssignmentBash: def evaluated_value( self, - environment: Dict[str, str], - executor: Optional[bashlex_eval.EnvironmentExecutor] = None, + environment: dict[str, str], + executor: bashlex_eval.EnvironmentExecutor | None = None, ) -> str: return bashlex_eval.evaluate(self.value, environment=environment, executor=executor) @@ -100,7 +102,7 @@ class EnvironmentAssignmentBash: @dataclasses.dataclass class ParsedEnvironment: - assignments: List[EnvironmentAssignment] + assignments: list[EnvironmentAssignment] def __init__(self, assignments: Sequence[EnvironmentAssignment]) -> None: self.assignments = list(assignments) @@ -108,8 +110,8 @@ class ParsedEnvironment: def as_dictionary( self, prev_environment: Mapping[str, str], - executor: Optional[bashlex_eval.EnvironmentExecutor] = None, - ) -> Dict[str, str]: + executor: bashlex_eval.EnvironmentExecutor | None = None, + ) -> dict[str, str]: environment = dict(**prev_environment) for assignment in self.assignments: diff --git a/cibuildwheel/extra.py b/cibuildwheel/extra.py index 60eecbad..36389e6f 100644 --- a/cibuildwheel/extra.py +++ b/cibuildwheel/extra.py @@ -2,8 +2,9 @@ These are utilities for the `/bin` scripts, not for the `cibuildwheel` program. """ +from __future__ import annotations + from io import StringIO -from typing import Dict, List from .typing import Protocol @@ -15,7 +16,7 @@ class Printable(Protocol): ... -def dump_python_configurations(inp: Dict[str, Dict[str, List[Dict[str, Printable]]]]) -> str: +def dump_python_configurations(inp: dict[str, dict[str, list[dict[str, Printable]]]]) -> str: output = StringIO() for header, values in inp.items(): output.write(f"[{header}]\n") diff --git a/cibuildwheel/functools_cached_property_38.py b/cibuildwheel/functools_cached_property_38.py index e1c45ac2..cbe4537a 100644 --- a/cibuildwheel/functools_cached_property_38.py +++ b/cibuildwheel/functools_cached_property_38.py @@ -1,5 +1,7 @@ +from __future__ import annotations + from threading import RLock -from typing import Any, Callable, Generic, Optional, Type, TypeVar, overload +from typing import Any, Callable, Generic, TypeVar, overload __all__ = ["cached_property"] @@ -11,11 +13,11 @@ _T = TypeVar("_T") class cached_property(Generic[_T]): def __init__(self, func: Callable[[Any], _T]): self.func = func - self.attrname: Optional[str] = None + self.attrname: str | None = None self.__doc__ = func.__doc__ self.lock = RLock() - def __set_name__(self, owner: Type[Any], name: str) -> None: + def __set_name__(self, owner: type[Any], name: str) -> None: if self.attrname is None: self.attrname = name elif name != self.attrname: @@ -25,14 +27,14 @@ class cached_property(Generic[_T]): ) @overload - def __get__(self, instance: None, owner: Optional[Type[Any]] = ...) -> "cached_property[_T]": + def __get__(self, instance: None, owner: type[Any] | None = ...) -> cached_property[_T]: ... @overload - def __get__(self, instance: object, owner: Optional[Type[Any]] = ...) -> _T: + def __get__(self, instance: object, owner: type[Any] | None = ...) -> _T: ... - def __get__(self, instance: Optional[object], owner: Optional[Type[Any]] = None) -> Any: + def __get__(self, instance: object | None, owner: type[Any] | None = None) -> Any: if instance is None: return self if self.attrname is None: diff --git a/cibuildwheel/linux.py b/cibuildwheel/linux.py index 57a7deee..2a0ec43f 100644 --- a/cibuildwheel/linux.py +++ b/cibuildwheel/linux.py @@ -1,9 +1,11 @@ +from __future__ import annotations + import subprocess import sys import textwrap from dataclasses import dataclass from pathlib import Path, PurePath, PurePosixPath -from typing import Iterator, List, Set, Tuple +from typing import Iterator, Tuple from .architecture import Architecture from .logger import log @@ -35,15 +37,15 @@ class PythonConfiguration: @dataclass(frozen=True) class BuildStep: - platform_configs: List[PythonConfiguration] + platform_configs: list[PythonConfiguration] platform_tag: str container_image: str def get_python_configurations( build_selector: BuildSelector, - architectures: Set[Architecture], -) -> List[PythonConfiguration]: + architectures: set[Architecture], +) -> list[PythonConfiguration]: full_python_configs = read_python_configs("linux") @@ -79,7 +81,7 @@ def container_image_for_python_configuration(config: PythonConfiguration, option def get_build_steps( - options: Options, python_configurations: List[PythonConfiguration] + options: Options, python_configurations: list[PythonConfiguration] ) -> Iterator[BuildStep]: """ Groups PythonConfigurations into BuildSteps. Each BuildStep represents a @@ -110,7 +112,7 @@ def get_build_steps( def build_in_container( *, options: Options, - platform_configs: List[PythonConfiguration], + platform_configs: list[PythonConfiguration], container: OCIContainer, container_project_path: PurePath, container_package_dir: PurePath, @@ -140,13 +142,13 @@ def build_in_container( ) container.call(["sh", "-c", before_all_prepared], env=env) - built_wheels: List[PurePosixPath] = [] + built_wheels: list[PurePosixPath] = [] for config in platform_configs: log.build_start(config.identifier) build_options = options.build_options(config.identifier) - dependency_constraint_flags: List[PathOrStr] = [] + dependency_constraint_flags: list[PathOrStr] = [] if build_options.dependency_constraints: constraints_file = build_options.dependency_constraints.get_for_python_version( @@ -395,7 +397,7 @@ def build(options: Options, tmp_path: Path) -> None: # pylint: disable=unused-a sys.exit(1) -def _matches_prepared_command(error_cmd: List[str], command_template: str) -> bool: +def _matches_prepared_command(error_cmd: list[str], command_template: str) -> bool: if len(error_cmd) < 3 or error_cmd[0:2] != ["sh", "-c"]: return False command_prefix = command_template.split("{", maxsplit=1)[0].strip() diff --git a/cibuildwheel/logger.py b/cibuildwheel/logger.py index 0a4be14d..6f408b47 100644 --- a/cibuildwheel/logger.py +++ b/cibuildwheel/logger.py @@ -1,9 +1,11 @@ +from __future__ import annotations + import codecs import os import re import sys import time -from typing import IO, AnyStr, Optional, Union +from typing import IO, AnyStr from cibuildwheel.typing import Final from cibuildwheel.util import CIProvider, detect_ci_provider @@ -39,10 +41,10 @@ class Logger: fold_mode: str colors_enabled: bool unicode_enabled: bool - active_build_identifier: Optional[str] = None - build_start_time: Optional[float] = None - step_start_time: Optional[float] = None - active_fold_group_name: Optional[str] = None + active_build_identifier: str | None = None + build_start_time: float | None = None + step_start_time: float | None = None + active_fold_group_name: str | None = None def __init__(self) -> None: if sys.platform == "win32" and hasattr(sys.stdout, "reconfigure"): @@ -120,7 +122,7 @@ class Logger: self.step_start_time = None - def step_end_with_error(self, error: Union[BaseException, str]) -> None: + def step_end_with_error(self, error: BaseException | str) -> None: self.step_end(success=False) self.error(error) @@ -131,7 +133,7 @@ class Logger: c = self.colors print(f"{c.yellow}Warning{c.end}: {message}\n", file=sys.stderr) - def error(self, error: Union[BaseException, str]) -> None: + def error(self, error: BaseException | str) -> None: if self.fold_mode == "github": print(f"::error::{error}\n", file=sys.stderr) else: @@ -174,11 +176,11 @@ class Logger: return identifier.lower()[:20] @property - def colors(self) -> "Colors": + def colors(self) -> Colors: return Colors(enabled=self.colors_enabled) @property - def symbols(self) -> "Symbols": + def symbols(self) -> Symbols: return Symbols(unicode=self.unicode_enabled) diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index beb4d32e..6d56be20 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import functools import os import platform @@ -7,7 +9,7 @@ import subprocess import sys from dataclasses import dataclass from pathlib import Path -from typing import Dict, List, Sequence, Set, Tuple, cast +from typing import Sequence, Tuple, cast from filelock import FileLock @@ -37,7 +39,7 @@ from .util import ( ) -def get_macos_version() -> Tuple[int, int]: +def get_macos_version() -> tuple[int, int]: """ Returns the macOS major/minor version, as a tuple, e.g. (10, 15) or (11, 0) @@ -51,7 +53,7 @@ def get_macos_version() -> Tuple[int, int]: return cast(Tuple[int, int], version) -def get_macos_sdks() -> List[str]: +def get_macos_sdks() -> list[str]: output = call("xcodebuild", "-showsdks", capture_stdout=True) return [m.group(1) for m in re.finditer(r"-sdk (macosx\S+)", output)] @@ -64,8 +66,8 @@ class PythonConfiguration: def get_python_configurations( - build_selector: BuildSelector, architectures: Set[Architecture] -) -> List[PythonConfiguration]: + build_selector: BuildSelector, architectures: set[Architecture] +) -> list[PythonConfiguration]: full_python_configs = read_python_configs("macos") @@ -134,7 +136,7 @@ def setup_python( dependency_constraint_flags: Sequence[PathOrStr], environment: ParsedEnvironment, build_frontend: BuildFrontend, -) -> Dict[str, str]: +) -> dict[str, str]: tmp.mkdir() implementation_id = python_configuration.identifier.split("-")[0] log.step(f"Installing Python {implementation_id}...") @@ -295,7 +297,7 @@ def build(options: Options, tmp_path: Path) -> None: ) shell(before_all_prepared, env=env) - built_wheels: List[Path] = [] + built_wheels: list[Path] = [] for config in python_configurations: build_options = options.build_options(config.identifier) @@ -418,7 +420,7 @@ def build(options: Options, tmp_path: Path) -> None: if build_options.test_command and build_options.test_selector(config.identifier): machine_arch = platform.machine() - testing_archs: List[Literal["x86_64", "arm64"]] + testing_archs: list[Literal["x86_64", "arm64"]] if config_is_arm64: testing_archs = ["arm64"] diff --git a/cibuildwheel/oci_container.py b/cibuildwheel/oci_container.py index c02f7678..91714c7e 100644 --- a/cibuildwheel/oci_container.py +++ b/cibuildwheel/oci_container.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import io import json import os @@ -9,7 +11,7 @@ import sys import uuid from pathlib import Path, PurePath, PurePosixPath from types import TracebackType -from typing import IO, Dict, List, Optional, Sequence, Type, cast +from typing import IO, Dict, Sequence, cast from cibuildwheel.util import CIProvider, detect_ci_provider @@ -52,7 +54,7 @@ class OCIContainer: *, image: str, simulate_32_bit: bool = False, - cwd: Optional[PathOrStr] = None, + cwd: PathOrStr | None = None, engine: ContainerEngine = "docker", ): if not image: @@ -61,10 +63,10 @@ class OCIContainer: self.image = image self.simulate_32_bit = simulate_32_bit self.cwd = cwd - self.name: Optional[str] = None + self.name: str | None = None self.engine = engine - def __enter__(self) -> "OCIContainer": + def __enter__(self) -> OCIContainer: self.name = f"cibuildwheel-{uuid.uuid4()}" @@ -122,9 +124,9 @@ class OCIContainer: def __exit__( self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, ) -> None: self.bash_stdin.write(b"exit 0\n") @@ -217,7 +219,7 @@ class OCIContainer: else: raise KeyError(self.engine) - def glob(self, path: PurePosixPath, pattern: str) -> List[PurePosixPath]: + def glob(self, path: PurePosixPath, pattern: str) -> list[PurePosixPath]: glob_pattern = path.joinpath(pattern) path_strings = json.loads( @@ -236,9 +238,9 @@ class OCIContainer: def call( self, args: Sequence[PathOrStr], - env: Optional[Dict[str, str]] = None, + env: dict[str, str] | None = None, capture_output: bool = False, - cwd: Optional[PathOrStr] = None, + cwd: PathOrStr | None = None, ) -> str: if cwd is None: @@ -314,7 +316,7 @@ class OCIContainer: return output - def get_environment(self) -> Dict[str, str]: + def get_environment(self) -> dict[str, str]: env = json.loads( self.call( [ @@ -327,7 +329,7 @@ class OCIContainer: ) 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 return self.call(command, env=environment, capture_output=True) diff --git a/cibuildwheel/options.py b/cibuildwheel/options.py index 59ff1226..30803604 100644 --- a/cibuildwheel/options.py +++ b/cibuildwheel/options.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import functools import os import sys @@ -6,18 +8,7 @@ from configparser import ConfigParser from contextlib import contextmanager from dataclasses import asdict, dataclass from pathlib import Path -from typing import ( - Any, - Dict, - Generator, - List, - Mapping, - Optional, - Set, - Tuple, - Union, - cast, -) +from typing import Any, Dict, Generator, List, Mapping, Union, cast if sys.version_info >= (3, 11): import tomllib @@ -50,7 +41,7 @@ from .util import ( @dataclass class CommandLineArguments: platform: Literal["auto", "linux", "macos", "windows"] - archs: Optional[str] + archs: str | None output_dir: Path config_file: str package_dir: Path @@ -65,7 +56,7 @@ class GlobalOptions: output_dir: Path build_selector: BuildSelector test_selector: TestSelector - architectures: Set[Architecture] + architectures: set[Architecture] container_engine: ContainerEngine @@ -74,14 +65,14 @@ class BuildOptions: globals: GlobalOptions environment: ParsedEnvironment before_all: str - before_build: Optional[str] + before_build: str | None repair_command: str - manylinux_images: Optional[Dict[str, str]] - musllinux_images: Optional[Dict[str, str]] - dependency_constraints: Optional[DependencyConstraints] - test_command: Optional[str] - before_test: Optional[str] - test_requires: List[str] + manylinux_images: dict[str, str] | None + musllinux_images: dict[str, str] | None + dependency_constraints: DependencyConstraints | None + test_command: str | None + before_test: str | None + test_requires: list[str] test_extras: str build_verbosity: int build_frontend: BuildFrontend @@ -103,7 +94,7 @@ class BuildOptions: return self.globals.test_selector @property - def architectures(self) -> Set[Architecture]: + def architectures(self) -> set[Architecture]: return self.globals.architectures @@ -113,7 +104,7 @@ Setting = Union[Dict[str, str], List[str], str, int] @dataclass(frozen=True) class Override: select_pattern: str - options: Dict[str, Setting] + options: dict[str, Setting] MANYLINUX_OPTIONS = {f"manylinux-{build_platform}-image" for build_platform in MANYLINUX_ARCHS} @@ -134,7 +125,7 @@ class ConfigOptionError(KeyError): pass -def _dig_first(*pairs: Tuple[Mapping[str, Setting], str], ignore_empty: bool = False) -> Setting: +def _dig_first(*pairs: tuple[Mapping[str, Setting], str], ignore_empty: bool = False) -> Setting: """ Return the first dict item that matches from pairs of dicts and keys. Will throw a KeyError if missing. @@ -176,10 +167,10 @@ class OptionsReader: def __init__( self, - config_file_path: Optional[Path] = None, + config_file_path: Path | None = None, *, platform: PlatformName, - disallow: Optional[Dict[str, Set[str]]] = None, + disallow: dict[str, set[str]] | None = None, ) -> None: self.platform = platform self.disallow = disallow or {} @@ -189,8 +180,8 @@ class OptionsReader: self.default_options, self.default_platform_options = self._load_file(defaults_path) # Load the project config file - config_options: Dict[str, Any] = {} - config_platform_options: Dict[str, Any] = {} + config_options: dict[str, Any] = {} + config_platform_options: dict[str, Any] = {} if config_file_path is not None: config_options, config_platform_options = self._load_file(config_file_path) @@ -209,8 +200,8 @@ class OptionsReader: self.config_options = config_options self.config_platform_options = config_platform_options - self.overrides: List[Override] = [] - self.current_identifier: Optional[str] = None + self.overrides: list[Override] = [] + self.current_identifier: str | None = None config_overrides = self.config_options.get("overrides") @@ -251,7 +242,7 @@ class OptionsReader: return name in allowed_option_names - def _load_file(self, filename: Path) -> Tuple[Dict[str, Any], Dict[str, Any]]: + def _load_file(self, filename: Path) -> tuple[dict[str, Any], dict[str, Any]]: """ Load a toml file, returns global and platform as separate dicts. """ @@ -264,7 +255,7 @@ class OptionsReader: return global_options, platform_options @property - def active_config_overrides(self) -> List[Override]: + def active_config_overrides(self) -> list[Override]: if self.current_identifier is None: return [] return [ @@ -272,7 +263,7 @@ class OptionsReader: ] @contextmanager - def identifier(self, identifier: Optional[str]) -> Generator[None, None, None]: + def identifier(self, identifier: str | None) -> Generator[None, None, None]: self.current_identifier = identifier try: yield @@ -284,8 +275,8 @@ class OptionsReader: name: str, *, env_plat: bool = True, - sep: Optional[str] = None, - table: Optional[TableFmt] = None, + sep: str | None = None, + table: TableFmt | None = None, ignore_empty: bool = False, ) -> str: """ @@ -349,7 +340,7 @@ class Options: ) @property - def config_file_path(self) -> Optional[Path]: + def config_file_path(self) -> Path | None: args = self.command_line_arguments if args.config_file: @@ -363,7 +354,7 @@ class Options: return None @cached_property - def package_requires_python_str(self) -> Optional[str]: + def package_requires_python_str(self) -> str | None: args = self.command_line_arguments return get_requires_python_str(Path(args.package_dir)) @@ -383,7 +374,7 @@ class Options: # This is not supported in tool.cibuildwheel, as it comes from a standard location. # Passing this in as an environment variable will override pyproject.toml, setup.cfg, or setup.py - requires_python_str: Optional[str] = ( + requires_python_str: str | None = ( os.environ.get("CIBW_PROJECT_REQUIRES_PYTHON") or self.package_requires_python_str ) requires_python = None if requires_python_str is None else SpecifierSet(requires_python_str) @@ -417,7 +408,7 @@ class Options: container_engine=container_engine, ) - def build_options(self, identifier: Optional[str]) -> BuildOptions: + def build_options(self, identifier: str | None) -> BuildOptions: """ Compute BuildOptions for a single run configuration. """ @@ -469,9 +460,9 @@ class Options: pass if dependency_versions == "pinned": - dependency_constraints: Optional[ + dependency_constraints: None | ( DependencyConstraints - ] = DependencyConstraints.with_defaults() + ) = DependencyConstraints.with_defaults() elif dependency_versions == "latest": dependency_constraints = None else: @@ -486,8 +477,8 @@ class Options: except ValueError: build_verbosity = 0 - manylinux_images: Dict[str, str] = {} - musllinux_images: Dict[str, str] = {} + manylinux_images: dict[str, str] = {} + musllinux_images: dict[str, str] = {} if self.platform == "linux": all_pinned_container_images = _get_pinned_container_images() @@ -539,7 +530,7 @@ class Options: build_frontend=build_frontend, ) - def check_for_invalid_configuration(self, identifiers: List[str]) -> None: + def check_for_invalid_configuration(self, identifiers: list[str]) -> None: if self.platform in ["macos", "windows"]: before_all_values = {self.build_options(i).before_all for i in identifiers} @@ -562,7 +553,7 @@ class Options: deprecated_selectors("CIBW_SKIP", build_selector.skip_config) deprecated_selectors("CIBW_TEST_SKIP", test_selector.skip_config) - def summary(self, identifiers: List[str]) -> str: + def summary(self, identifiers: list[str]) -> str: lines = [ f"{option_name}: {option_value!r}" for option_name, option_value in sorted(asdict(self.globals).items()) diff --git a/cibuildwheel/projectfiles.py b/cibuildwheel/projectfiles.py index 90d388f6..b5c3cbdf 100644 --- a/cibuildwheel/projectfiles.py +++ b/cibuildwheel/projectfiles.py @@ -1,8 +1,10 @@ +from __future__ import annotations + import ast import sys from configparser import ConfigParser from pathlib import Path -from typing import Any, Optional +from typing import Any if sys.version_info >= (3, 11): import tomllib @@ -24,7 +26,7 @@ else: class Analyzer(ast.NodeVisitor): def __init__(self) -> None: - self.requires_python: Optional[str] = None + self.requires_python: str | None = None def visit(self, node: ast.AST) -> None: for inner_node in ast.walk(node): @@ -43,7 +45,7 @@ class Analyzer(ast.NodeVisitor): self.requires_python = get_constant(node.value) -def setup_py_python_requires(content: str) -> Optional[str]: +def setup_py_python_requires(content: str) -> str | None: try: tree = ast.parse(content) analyzer = Analyzer() @@ -53,7 +55,7 @@ def setup_py_python_requires(content: str) -> Optional[str]: return None -def get_requires_python_str(package_dir: Path) -> Optional[str]: +def get_requires_python_str(package_dir: Path) -> str | None: """Return the python requires string from the most canonical source available, or None""" # Read in from pyproject.toml:project.requires-python diff --git a/cibuildwheel/typing.py b/cibuildwheel/typing.py index 1e6e5787..a546d7bf 100644 --- a/cibuildwheel/typing.py +++ b/cibuildwheel/typing.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import subprocess import sys @@ -36,7 +38,7 @@ else: PlatformName = Literal["linux", "macos", "windows"] -PLATFORMS: Final[Set[PlatformName]] = {"linux", "macos", "windows"} +PLATFORMS: Final[set[PlatformName]] = {"linux", "macos", "windows"} def assert_never(value: NoReturn) -> NoReturn: diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index d2287a05..6a6a6e2a 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import contextlib import fnmatch import itertools @@ -18,15 +20,11 @@ from time import sleep from typing import ( Any, ClassVar, - Dict, Generator, Iterable, - List, - Optional, Sequence, TextIO, TypeVar, - Union, cast, overload, ) @@ -98,8 +96,8 @@ IS_WIN: Final = sys.platform.startswith("win") @overload def call( *args: PathOrStr, - env: Optional[Dict[str, str]] = None, - cwd: Optional[PathOrStr] = None, + env: dict[str, str] | None = None, + cwd: PathOrStr | None = None, capture_stdout: Literal[False] = ..., ) -> None: ... @@ -108,8 +106,8 @@ def call( @overload def call( *args: PathOrStr, - env: Optional[Dict[str, str]] = None, - cwd: Optional[PathOrStr] = None, + env: dict[str, str] | None = None, + cwd: PathOrStr | None = None, capture_stdout: Literal[True], ) -> str: ... @@ -117,10 +115,10 @@ def call( def call( *args: PathOrStr, - env: Optional[Dict[str, str]] = None, - cwd: Optional[PathOrStr] = None, + env: dict[str, str] | None = None, + cwd: PathOrStr | None = None, capture_stdout: bool = False, -) -> Optional[str]: +) -> str | None: """ Run subprocess.run, but print the commands first. Takes the commands as *args. Uses shell=True on Windows due to a bug. Also converts to @@ -130,7 +128,7 @@ def call( args_ = [str(arg) for arg in args] # print the command executing for the logs print("+ " + " ".join(shlex.quote(a) for a in args_)) - kwargs: Dict[str, Any] = {} + kwargs: dict[str, Any] = {} if capture_stdout: kwargs["universal_newlines"] = True kwargs["stdout"] = subprocess.PIPE @@ -140,9 +138,7 @@ def call( return cast(str, result.stdout) -def shell( - *commands: str, env: Optional[Dict[str, str]] = None, cwd: Optional[PathOrStr] = None -) -> None: +def shell(*commands: str, env: dict[str, str] | None = None, cwd: PathOrStr | None = None) -> None: command = " ".join(commands) print(f"+ {command}") subprocess.run(command, env=env, cwd=cwd, shell=True, check=True) @@ -200,7 +196,7 @@ def prepare_command(command: str, **kwargs: PathOrStr) -> str: return format_safe(command, python="python", pip="pip", **kwargs) -def get_build_verbosity_extra_flags(level: int) -> List[str]: +def get_build_verbosity_extra_flags(level: int) -> list[str]: if level > 0: return ["-" + level * "v"] elif level < 0: @@ -209,11 +205,11 @@ def get_build_verbosity_extra_flags(level: int) -> List[str]: return [] -def read_python_configs(config: PlatformName) -> List[Dict[str, str]]: +def read_python_configs(config: PlatformName) -> list[dict[str, str]]: input_file = resources_dir / "build-platforms.toml" with input_file.open("rb") as f: loaded_file = tomllib.load(f) - results: List[Dict[str, str]] = list(loaded_file[config]["python_configurations"]) + results: list[dict[str, str]] = list(loaded_file[config]["python_configurations"]) return results @@ -243,7 +239,7 @@ class BuildSelector: build_config: str skip_config: str - requires_python: Optional[SpecifierSet] = None + requires_python: SpecifierSet | None = None # a pattern that skips prerelease versions, when include_prereleases is False. PRERELEASE_SKIP: ClassVar[str] = "cp311-*" @@ -328,7 +324,7 @@ class DependencyConstraints: self.base_file_path = base_file_path.resolve() @staticmethod - def with_defaults() -> "DependencyConstraints": + def with_defaults() -> DependencyConstraints: return DependencyConstraints(base_file_path=resources_dir / "constraints.txt") def get_for_python_version(self, version: str) -> Path: @@ -400,7 +396,7 @@ class CIProvider(Enum): other = "other" -def detect_ci_provider() -> Optional[CIProvider]: +def detect_ci_provider() -> CIProvider | None: if "TRAVIS" in os.environ: return CIProvider.travis_ci elif "APPVEYOR" in os.environ: @@ -473,7 +469,7 @@ def print_new_wheels(msg: str, output_dir: Path) -> Generator[None, None, None]: ) -def get_pip_version(env: Dict[str, str]) -> str: +def get_pip_version(env: dict[str, str]) -> str: versions_output_text = call( "python", "-m", "pip", "freeze", "--all", capture_stdout=True, env=env ) @@ -501,7 +497,7 @@ def _ensure_virtualenv() -> Path: def _parse_constraints_for_virtualenv( dependency_constraint_flags: Sequence[PathOrStr], -) -> Dict[str, str]: +) -> dict[str, str]: """ Parses the constraints file referenced by `dependency_constraint_flags` and returns a dict where the key is the package name, and the value is the constraint version. @@ -547,7 +543,7 @@ def _parse_constraints_for_virtualenv( def virtualenv( python: Path, venv_path: Path, dependency_constraint_flags: Sequence[PathOrStr] -) -> Dict[str, str]: +) -> dict[str, str]: assert python.exists() virtualenv_app = _ensure_virtualenv() constraints = _parse_constraints_for_virtualenv(dependency_constraint_flags) @@ -589,7 +585,7 @@ def virtualenv( T = TypeVar("T", bound=PurePath) -def find_compatible_wheel(wheels: Sequence[T], identifier: str) -> Optional[T]: +def find_compatible_wheel(wheels: Sequence[T], identifier: str) -> T | None: """ Finds a wheel with an abi3 or a none ABI tag in `wheels` compatible with the Python interpreter specified by `identifier` that is previously built. @@ -641,7 +637,7 @@ else: # Can be replaced by contextlib.chdir in Python 3.11 @contextlib.contextmanager -def chdir(new_path: Union[Path, str]) -> Generator[None, None, None]: +def chdir(new_path: Path | str) -> Generator[None, None, None]: """Non thread-safe context manager to change the current working directory.""" cwd = os.getcwd() diff --git a/cibuildwheel/windows.py b/cibuildwheel/windows.py index 82309a23..b6e223ec 100644 --- a/cibuildwheel/windows.py +++ b/cibuildwheel/windows.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import shutil import subprocess @@ -5,7 +7,7 @@ import sys from dataclasses import dataclass from functools import lru_cache from pathlib import Path -from typing import Dict, List, Optional, Sequence, Set +from typing import Sequence from zipfile import ZipFile from filelock import FileLock @@ -34,7 +36,7 @@ from .util import ( ) -def get_nuget_args(version: str, arch: str, output_directory: Path) -> List[str]: +def get_nuget_args(version: str, arch: str, output_directory: Path) -> list[str]: platform_suffix = {"32": "x86", "64": "", "ARM64": "arm64"} python_name = "python" + platform_suffix[arch] return [ @@ -53,13 +55,13 @@ class PythonConfiguration: version: str arch: str identifier: str - url: Optional[str] = None + url: str | None = None def get_python_configurations( build_selector: BuildSelector, - architectures: Set[Architecture], -) -> List[PythonConfiguration]: + architectures: set[Architecture], +) -> list[PythonConfiguration]: full_python_configs = read_python_configs("windows") @@ -124,7 +126,7 @@ def setup_python( dependency_constraint_flags: Sequence[PathOrStr], environment: ParsedEnvironment, build_frontend: BuildFrontend, -) -> Dict[str, str]: +) -> dict[str, str]: tmp.mkdir() implementation_id = python_configuration.identifier.split("-")[0] log.step(f"Installing Python {implementation_id}...") @@ -253,7 +255,7 @@ def build(options: Options, tmp_path: Path) -> None: ) shell(before_all_prepared, env=env) - built_wheels: List[Path] = [] + built_wheels: list[Path] = [] for config in python_configurations: build_options = options.build_options(config.identifier) diff --git a/docs/main.py b/docs/main.py index b1798237..acb0d49c 100644 --- a/docs/main.py +++ b/docs/main.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import subprocess from typing import Any diff --git a/noxfile.py b/noxfile.py index f045e616..659e7ff5 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import shutil import sys diff --git a/setup.py b/setup.py index 6c08425d..0cb95028 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from setuptools import setup extras = { diff --git a/test/conftest.py b/test/conftest.py index e7c42112..872eeb17 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -1,4 +1,4 @@ -from typing import Dict +from __future__ import annotations import pytest @@ -13,5 +13,5 @@ def pytest_addoption(parser) -> None: @pytest.fixture( params=[{"CIBW_BUILD_FRONTEND": "pip"}, {"CIBW_BUILD_FRONTEND": "build"}], ids=["pip", "build"] ) -def build_frontend_env(request) -> Dict[str, str]: +def build_frontend_env(request) -> dict[str, str]: return request.param # type: ignore[no-any-return] diff --git a/test/test_0_basic.py b/test/test_0_basic.py index 2d2e8d97..5fb7a241 100644 --- a/test/test_0_basic.py +++ b/test/test_0_basic.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import textwrap import pytest diff --git a/test/test_abi_variants.py b/test/test_abi_variants.py index 932a2ec0..11473655 100644 --- a/test/test_abi_variants.py +++ b/test/test_abi_variants.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import textwrap from . import test_projects, utils diff --git a/test/test_before_all.py b/test/test_before_all.py index 9c8722d7..bad2d4c0 100644 --- a/test/test_before_all.py +++ b/test/test_before_all.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import subprocess import textwrap diff --git a/test/test_before_build.py b/test/test_before_build.py index 00906acc..1ee7757e 100644 --- a/test/test_before_build.py +++ b/test/test_before_build.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import subprocess import textwrap diff --git a/test/test_before_test.py b/test/test_before_test.py index 535131aa..5c3e09d2 100644 --- a/test/test_before_test.py +++ b/test/test_before_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from . import test_projects, utils before_test_project = test_projects.new_c_project() diff --git a/test/test_build_skip.py b/test/test_build_skip.py index 0d285d82..e29d14f1 100644 --- a/test/test_build_skip.py +++ b/test/test_build_skip.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import textwrap from . import test_projects, utils diff --git a/test/test_container_images.py b/test/test_container_images.py index 8318a64e..75b102e3 100644 --- a/test/test_container_images.py +++ b/test/test_container_images.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import platform import textwrap diff --git a/test/test_cpp_standards.py b/test/test_cpp_standards.py index a5385007..f09e7a53 100644 --- a/test/test_cpp_standards.py +++ b/test/test_cpp_standards.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import jinja2 diff --git a/test/test_dependency_versions.py b/test/test_dependency_versions.py index 90854a86..e1f20632 100644 --- a/test/test_dependency_versions.py +++ b/test/test_dependency_versions.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import re import textwrap diff --git a/test/test_emulation.py b/test/test_emulation.py index 95b574dd..6b29c019 100644 --- a/test/test_emulation.py +++ b/test/test_emulation.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import subprocess import pytest diff --git a/test/test_environment.py b/test/test_environment.py index 6ad8ff9f..4382df44 100644 --- a/test/test_environment.py +++ b/test/test_environment.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import subprocess import textwrap diff --git a/test/test_from_sdist.py b/test/test_from_sdist.py index d1d4ff11..f0b7e93e 100644 --- a/test/test_from_sdist.py +++ b/test/test_from_sdist.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import subprocess import sys diff --git a/test/test_macos_archs.py b/test/test_macos_archs.py index a85a6b24..d3a56fb7 100644 --- a/test/test_macos_archs.py +++ b/test/test_macos_archs.py @@ -1,6 +1,7 @@ +from __future__ import annotations + import platform import subprocess -from typing import Tuple import pytest @@ -14,7 +15,7 @@ ALL_MACOS_WHEELS = { } -def get_xcode_version() -> Tuple[int, int]: +def get_xcode_version() -> tuple[int, int]: output = subprocess.run( ["xcodebuild", "-version"], text=True, diff --git a/test/test_manylinuxXXXX_only.py b/test/test_manylinuxXXXX_only.py index 935aa592..6013e856 100644 --- a/test/test_manylinuxXXXX_only.py +++ b/test/test_manylinuxXXXX_only.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import platform import textwrap diff --git a/test/test_pep518.py b/test/test_pep518.py index 12883428..0f1bc0c5 100644 --- a/test/test_pep518.py +++ b/test/test_pep518.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import textwrap from . import test_projects, utils diff --git a/test/test_podman.py b/test/test_podman.py index dd07572b..ea3bd8a6 100644 --- a/test/test_podman.py +++ b/test/test_podman.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from . import test_projects, utils diff --git a/test/test_projects/__init__.py b/test/test_projects/__init__.py index d6bed818..2d8da665 100644 --- a/test/test_projects/__init__.py +++ b/test/test_projects/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from .base import TestProject from .c import new_c_project diff --git a/test/test_projects/__main__.py b/test/test_projects/__main__.py index a1e77c43..0d3cf252 100644 --- a/test/test_projects/__main__.py +++ b/test/test_projects/__main__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import importlib import subprocess import sys diff --git a/test/test_projects/base.py b/test/test_projects/base.py index 66d0006e..c4ea5403 100644 --- a/test/test_projects/base.py +++ b/test/test_projects/base.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pathlib import Path from typing import Any, Dict, Union diff --git a/test/test_projects/c.py b/test/test_projects/c.py index d4c37c69..62252a62 100644 --- a/test/test_projects/c.py +++ b/test/test_projects/c.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import jinja2 from .base import TestProject diff --git a/test/test_pure_wheel.py b/test/test_pure_wheel.py index 2ba33711..f7a4807b 100644 --- a/test/test_pure_wheel.py +++ b/test/test_pure_wheel.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import subprocess from test import test_projects diff --git a/test/test_same_wheel.py b/test/test_same_wheel.py index d89f28cb..f25cba5d 100644 --- a/test/test_same_wheel.py +++ b/test/test_same_wheel.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import subprocess from test import test_projects diff --git a/test/test_ssl.py b/test/test_ssl.py index 5283a59d..9c35650e 100644 --- a/test/test_ssl.py +++ b/test/test_ssl.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import textwrap from . import test_projects, utils diff --git a/test/test_subdir_package.py b/test/test_subdir_package.py index 9241ae30..c1d73df1 100644 --- a/test/test_subdir_package.py +++ b/test/test_subdir_package.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pathlib import Path import jinja2 diff --git a/test/test_testing.py b/test/test_testing.py index ef41f35a..c7264383 100644 --- a/test/test_testing.py +++ b/test/test_testing.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import subprocess import textwrap diff --git a/test/test_troubleshooting.py b/test/test_troubleshooting.py index 7039c268..e647bca6 100644 --- a/test/test_troubleshooting.py +++ b/test/test_troubleshooting.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import subprocess import pytest diff --git a/test/test_wheel_tag.py b/test/test_wheel_tag.py index a026b2d7..786eaa7a 100644 --- a/test/test_wheel_tag.py +++ b/test/test_wheel_tag.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from . import test_projects, utils diff --git a/test/utils.py b/test/utils.py index ebe682e3..947c8968 100644 --- a/test/utils.py +++ b/test/utils.py @@ -4,6 +4,8 @@ Utility functions used by the cibuildwheel tests. This file is added to the PYTHONPATH in the test runner at bin/run_test.py. """ +from __future__ import annotations + import os import platform as pm import subprocess diff --git a/unit_test/build_ids_test.py b/unit_test/build_ids_test.py index 60ac3874..0f62ba40 100644 --- a/unit_test/build_ids_test.py +++ b/unit_test/build_ids_test.py @@ -1,5 +1,6 @@ +from __future__ import annotations + import sys -from typing import Dict, List if sys.version_info >= (3, 11): import tomllib @@ -27,7 +28,7 @@ def test_compare_configs(): def test_dump_with_Version(): # MyPy doesn't understand deeply nested dicts correctly - example: Dict[str, Dict[str, List[Dict[str, Printable]]]] = { + example: dict[str, dict[str, list[dict[str, Printable]]]] = { "windows": { "python_configurations": [ {"identifier": "cp27-win32", "version": Version("2.7.18"), "arch": "32"}, diff --git a/unit_test/build_selector_test.py b/unit_test/build_selector_test.py index b71cb05f..14ff8da6 100644 --- a/unit_test/build_selector_test.py +++ b/unit_test/build_selector_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from packaging.specifiers import SpecifierSet from cibuildwheel.util import BuildSelector diff --git a/unit_test/conftest.py b/unit_test/conftest.py index 3d98c30b..7e1df1b2 100644 --- a/unit_test/conftest.py +++ b/unit_test/conftest.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys from pathlib import Path diff --git a/unit_test/dependency_constraints_test.py b/unit_test/dependency_constraints_test.py index 95215195..ce907d5e 100644 --- a/unit_test/dependency_constraints_test.py +++ b/unit_test/dependency_constraints_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pathlib import Path from cibuildwheel.util import DependencyConstraints diff --git a/unit_test/download_test.py b/unit_test/download_test.py index 0aac1430..efc5c4e5 100644 --- a/unit_test/download_test.py +++ b/unit_test/download_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import ssl import certifi diff --git a/unit_test/environment_test.py b/unit_test/environment_test.py index c1d0a4a1..38678771 100644 --- a/unit_test/environment_test.py +++ b/unit_test/environment_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os from cibuildwheel.environment import parse_environment diff --git a/unit_test/linux_build_steps_test.py b/unit_test/linux_build_steps_test.py index 36aaebb7..809cdf65 100644 --- a/unit_test/linux_build_steps_test.py +++ b/unit_test/linux_build_steps_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import textwrap from pathlib import Path from pprint import pprint diff --git a/unit_test/main_tests/conftest.py b/unit_test/main_tests/conftest.py index 973012cf..25732187 100644 --- a/unit_test/main_tests/conftest.py +++ b/unit_test/main_tests/conftest.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import contextlib import platform as platform_module import subprocess diff --git a/unit_test/main_tests/main_options_test.py b/unit_test/main_tests/main_options_test.py index 59368de5..813fd5c5 100644 --- a/unit_test/main_tests/main_options_test.py +++ b/unit_test/main_tests/main_options_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys from fnmatch import fnmatch from pathlib import Path diff --git a/unit_test/main_tests/main_platform_test.py b/unit_test/main_tests/main_platform_test.py index 8974a27e..61dd8e85 100644 --- a/unit_test/main_tests/main_platform_test.py +++ b/unit_test/main_tests/main_platform_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys import pytest diff --git a/unit_test/main_tests/main_requires_python_test.py b/unit_test/main_tests/main_requires_python_test.py index 0edb0937..e513f743 100644 --- a/unit_test/main_tests/main_requires_python_test.py +++ b/unit_test/main_tests/main_requires_python_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys import textwrap diff --git a/unit_test/oci_container_test.py b/unit_test/oci_container_test.py index 05ef24fd..30739db7 100644 --- a/unit_test/oci_container_test.py +++ b/unit_test/oci_container_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import platform import random diff --git a/unit_test/option_prepare_test.py b/unit_test/option_prepare_test.py index 3eef68a7..bc01317b 100644 --- a/unit_test/option_prepare_test.py +++ b/unit_test/option_prepare_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import platform as platform_module import subprocess import sys diff --git a/unit_test/options_test.py b/unit_test/options_test.py index 3ce8b214..a609bb49 100644 --- a/unit_test/options_test.py +++ b/unit_test/options_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import platform as platform_module import pytest diff --git a/unit_test/options_toml_test.py b/unit_test/options_toml_test.py index 1dcfdc21..a3fab2cc 100644 --- a/unit_test/options_toml_test.py +++ b/unit_test/options_toml_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pathlib import Path import pytest diff --git a/unit_test/projectfiles_test.py b/unit_test/projectfiles_test.py index 6c55d46a..e7e21ba5 100644 --- a/unit_test/projectfiles_test.py +++ b/unit_test/projectfiles_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from textwrap import dedent from cibuildwheel.projectfiles import get_requires_python_str, setup_py_python_requires diff --git a/unit_test/utils.py b/unit_test/utils.py index 2b312eca..0cd2fefb 100644 --- a/unit_test/utils.py +++ b/unit_test/utils.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pathlib import Path from cibuildwheel.options import CommandLineArguments diff --git a/unit_test/utils_test.py b/unit_test/utils_test.py index 7f949a73..adf21435 100644 --- a/unit_test/utils_test.py +++ b/unit_test/utils_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pathlib import PurePath import pytest diff --git a/unit_test/wheel_print_test.py b/unit_test/wheel_print_test.py index 02060060..fe68f718 100644 --- a/unit_test/wheel_print_test.py +++ b/unit_test/wheel_print_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from cibuildwheel.util import print_new_wheels