Skip to content

Commit

Permalink
feat: requires-python
Browse files Browse the repository at this point in the history
  • Loading branch information
henryiii committed Jan 15, 2021
1 parent d394386 commit b0f500a
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 13 deletions.
32 changes: 26 additions & 6 deletions cibuildwheel/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
from pathlib import Path
from typing import Any, Dict, List, Optional, Set, overload

import toml
from packaging.specifiers import SpecifierSet

import cibuildwheel
import cibuildwheel.linux
import cibuildwheel.macos
Expand All @@ -25,10 +28,10 @@


@overload
def get_option_from_environment(option_name: str, platform: Optional[str], default: str) -> str: ... # noqa: E704
def get_option_from_environment(option_name: str, *, platform: Optional[str] = None, 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
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 Down Expand Up @@ -151,7 +154,23 @@ def main() -> None:
test_extras = get_option_from_environment('CIBW_TEST_EXTRAS', platform=platform, default='')
build_verbosity_str = get_option_from_environment('CIBW_BUILD_VERBOSITY', platform=platform, default='')

build_selector = BuildSelector(build_config, skip_config)
# Default if not specified (may be increased in a later version)
requires_python = '>=2.7'

# Read in from metadata.requires-python if it exists
pyproject_toml = package_dir / 'pyproject.toml'
try:
info = toml.load(pyproject_toml)
requires_python = info["metadata"]["requires-python"]
except FileNotFoundError:
pass
except KeyError:
pass

# Passing this in as an environment variable will override default or pyproject.toml
requires_python = get_option_from_environment('CIBW_REQUIRES_PYTHON', platform=platform, default=requires_python)

build_selector = BuildSelector(build_config, skip_config, requires_python=SpecifierSet(requires_python))

try:
environment = parse_environment(environment_config)
Expand Down Expand Up @@ -181,14 +200,15 @@ def main() -> None:
os.environ['CIBUILDWHEEL'] = '1'

if not any((package_dir / name).exists()
for name in ["setup.py", "setup.cfg", "pyproject.toml"]):
for name in ['setup.py', 'setup.cfg', 'pyproject.toml']):
print('cibuildwheel: Could not find setup.py, setup.cfg or pyproject.toml at root of package', file=sys.stderr)
exit(2)

if args.archs is not None:
archs_config_str = args.archs
else:
archs_config_str = get_option_from_environment('CIBW_ARCHS', platform=platform, default='auto')

archs = Architecture.parse_config(archs_config_str, platform=platform)

if args.print_build_identifiers:
Expand Down Expand Up @@ -308,7 +328,7 @@ def print_preamble(platform: str, build_options: BuildOptions) -> None:


def print_build_identifiers(
platform: str, build_selector: BuildSelector, architectures: Set[Architecture]
platform: str, build_selector: BuildSelector, architectures: Set[Architecture]
) -> None:

python_configurations: List[Any] = []
Expand Down
18 changes: 17 additions & 1 deletion cibuildwheel/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

import certifi
import toml
from packaging.specifiers import SpecifierSet
from packaging.version import Version

from .environment import ParsedEnvironment
from .typing import PathOrStr, PlatformName, assert_never
Expand Down Expand Up @@ -56,11 +58,25 @@ def read_python_configs(config: PlatformName) -> List[Dict[str, str]]:


class BuildSelector:
def __init__(self, build_config: str, skip_config: str):
def __init__(self, build_config: str, skip_config: str, *, requires_python: Optional[SpecifierSet] = None):
self.build_patterns = build_config.split()
self.skip_patterns = skip_config.split()
self.requires_python = requires_python

def __call__(self, build_id: str) -> bool:
# Filter build selectors by python_requires if set
if self.requires_python is not None and '-' in build_id:
py_ver_str = build_id.split('-')[0]
try:
major = int(py_ver_str[2])
minor = int(py_ver_str[3:])
except ValueError:
pass
else:
version = Version(f"{major}.{minor}")
if not self.requires_python.contains(version):
return False

def match_any(patterns: List[str]) -> bool:
return any(fnmatch(build_id, pattern) for pattern in patterns)
return match_any(self.build_patterns) and not match_any(self.skip_patterns)
Expand Down
25 changes: 25 additions & 0 deletions docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,31 @@ to limit builds for each job; this list could grow in the future.
CIBW_ARCHS_LINUX: "auto aarch64"
```


### `pyproject.toml:metadata.requires-python` / `CIBW_REQUIRES_PYTHON` {: #requires-python}
> Limit the Python versions to build

The provisionally accepted [PEP 621](https://www.python.org/dev/peps/pep-0621/)
setting in `pyproject.toml` for `metadata.requires-python` is respected by
cibuildwheel. You can override this if needed using an environment variable.
You do not have to manually avoid versions that cibuildwheel does not support;
`>=2.7` and `>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*,` are
equivalent, as far as cibuildwheel is concerned.

Default: `>=2.7`, all supported versions are built. In the future, this will match
the EOL of Python, so setting this is recommended if you want to support past-EOL
Python versions.

Example `pyproject.toml`:

```toml
[metadata]
requires-python: ">=3.6"
```

Remember to always set `build-system.requires` and `build-system.build-backend`
if you add a `pyproject.toml` file.

## Build customization

### `CIBW_ENVIRONMENT` {: #environment}
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ install_requires =
bashlex!=0.13
toml
certifi
packaging
typing_extensions; python_version < '3.8'
importlib_resources>=1.4; python_version < '3.9'

Expand All @@ -51,7 +52,6 @@ dev =
pyyaml
requests
typing-extensions
packaging>=20.8
rich>=9.6

[options.packages.find]
Expand Down
7 changes: 2 additions & 5 deletions unit_test/build_ids_test.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import pytest
import toml

from cibuildwheel.util import resources_dir

Version = pytest.importorskip("packaging.version").Version
from packaging.version import Version

from cibuildwheel.extra import InlineArrayDictEncoder # noqa: E402
from cibuildwheel.util import resources_dir


def test_compare_configs():
Expand Down
19 changes: 19 additions & 0 deletions unit_test/build_selector_test.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from packaging.specifiers import SpecifierSet

from cibuildwheel.util import BuildSelector


Expand Down Expand Up @@ -59,3 +61,20 @@ def test_build_and_skip():
assert not build_selector('cp27-win_amd64')
assert build_selector('cp36-win_amd64')
assert not build_selector('cp37-win_amd64')


def test_build_limited_python():
build_selector = BuildSelector(build_config="*", skip_config="", requires_python=SpecifierSet(">=3.6"))

assert not build_selector('cp27-manylinux1_x86_64')
assert build_selector('cp36-manylinux1_x86_64')
assert build_selector('cp37-manylinux1_x86_64')
assert not build_selector('cp27-manylinux1_i686')
assert build_selector('cp36-manylinux1_i686')
assert build_selector('cp37-manylinux1_i686')
assert not build_selector('cp27-win32')
assert build_selector('cp36-win32')
assert build_selector('cp37-win32')
assert not build_selector('pp27-win32')
assert build_selector('pp36-win32')
assert build_selector('pp37-win32')

0 comments on commit b0f500a

Please sign in to comment.