Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a test-sources configuration option. #2062

Merged
merged 8 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from 5 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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ Options
| | [`CIBW_DEPENDENCY_VERSIONS`](https://cibuildwheel.pypa.io/en/stable/options/#dependency-versions) | Specify how cibuildwheel controls the versions of the tools it uses |
| **Testing** | [`CIBW_TEST_COMMAND`](https://cibuildwheel.pypa.io/en/stable/options/#test-command) | Execute a shell command to test each built wheel |
| | [`CIBW_BEFORE_TEST`](https://cibuildwheel.pypa.io/en/stable/options/#before-test) | Execute a shell command before testing each wheel |
| | [`CIBW_TEST_SOURCES`](https://cibuildwheel.pypa.io/en/stable/options/#test-sources) | Files and folders from the source tree that must be copied into the test environment before running the tests. |
freakboy3742 marked this conversation as resolved.
Show resolved Hide resolved
| | [`CIBW_TEST_REQUIRES`](https://cibuildwheel.pypa.io/en/stable/options/#test-requires) | Install Python dependencies before running the tests |
| | [`CIBW_TEST_EXTRAS`](https://cibuildwheel.pypa.io/en/stable/options/#test-extras) | Install your wheel for testing using extras_require |
| | [`CIBW_TEST_SKIP`](https://cibuildwheel.pypa.io/en/stable/options/#test-skip) | Skip running tests on some builds |
Expand Down
18 changes: 14 additions & 4 deletions cibuildwheel/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
from .util import (
BuildFrontendConfig,
BuildSelector,
copy_test_sources,
find_compatible_wheel,
get_build_verbosity_extra_flags,
prepare_command,
read_python_configs,
split_config_settings,
test_fail_cwd_file,
unwrap,
)

Expand Down Expand Up @@ -401,9 +401,19 @@ def build_in_container(
package=container_package_dir,
wheel=wheel_to_test,
)
test_cwd = testing_temp_dir / "test_cwd"
container.call(["mkdir", "-p", test_cwd])
container.copy_into(test_fail_cwd_file, test_cwd / "test_fail.py")

if build_options.test_sources:
test_cwd = testing_temp_dir / "test_cwd"
container.call(["mkdir", "-p", test_cwd])
copy_test_sources(
build_options.test_sources,
build_options.package_dir,
test_cwd,
copy_into=container.copy_into,
)
else:
# There are no test sources. Run the tests in the project directory.
test_cwd = PurePosixPath(container_project_path)

container.call(["sh", "-c", test_command_prepared], cwd=test_cwd, env=virtualenv_env)

Expand Down
16 changes: 12 additions & 4 deletions cibuildwheel/macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
BuildSelector,
call,
combine_constraints,
copy_test_sources,
detect_ci_provider,
download,
find_compatible_wheel,
Expand All @@ -44,7 +45,6 @@
read_python_configs,
shell,
split_config_settings,
test_fail_cwd_file,
unwrap,
virtualenv,
)
Expand Down Expand Up @@ -736,9 +736,17 @@ def build(options: Options, tmp_path: Path) -> None:
wheel=repaired_wheel,
)

test_cwd = identifier_tmp_dir / "test_cwd"
test_cwd.mkdir(exist_ok=True)
(test_cwd / "test_fail.py").write_text(test_fail_cwd_file.read_text())
if build_options.test_sources:
test_cwd = identifier_tmp_dir / "test_cwd"
test_cwd.mkdir(exist_ok=True)
copy_test_sources(
build_options.test_sources,
build_options.package_dir,
test_cwd,
)
else:
# There are no test sources. Run the tests in the project directory.
test_cwd = Path(".").resolve()

shell_with_arch(test_command_prepared, cwd=test_cwd, env=virtualenv_env)

Expand Down
5 changes: 5 additions & 0 deletions cibuildwheel/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class BuildOptions:
dependency_constraints: DependencyConstraints | None
test_command: str | None
before_test: str | None
test_sources: list[str]
test_requires: list[str]
test_extras: str
test_groups: list[str]
Expand Down Expand Up @@ -677,6 +678,9 @@ def build_options(self, identifier: str | None) -> BuildOptions:
dependency_versions = self.reader.get("dependency-versions")
test_command = self.reader.get("test-command", option_format=ListFormat(sep=" && "))
before_test = self.reader.get("before-test", option_format=ListFormat(sep=" && "))
test_sources = self.reader.get(
"test-sources", option_format=ListFormat(sep=" ")
).split()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't handle filenames/directories with a space in it. Should we care about such things? I suppose it can't really hurt! so... the solution here would be to add an optional quote param to ListFormat, use it here like ListFormat(sep=" ", quote=shlex.quote), and then use shlex.split() rather than split() here.

I'm happy to make that change if the above isn't clear!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense - I'll add this to my todo list.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just pushed an update that does shlex quote handling; not sure if there's any additional testing that you'd like to see - I couldn't find an obvious trove of explicit ListOption tests.

I'm still looking into the Pyodide test that failed on the previous CI run.

test_requires = self.reader.get(
"test-requires", option_format=ListFormat(sep=" ")
).split()
Expand Down Expand Up @@ -785,6 +789,7 @@ def build_options(self, identifier: str | None) -> BuildOptions:
return BuildOptions(
globals=self.globals,
test_command=test_command,
test_sources=test_sources,
test_requires=[*test_requires, *test_requirements_from_groups],
test_extras=test_extras,
test_groups=test_groups,
Expand Down
16 changes: 12 additions & 4 deletions cibuildwheel/pyodide.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
BuildSelector,
call,
combine_constraints,
copy_test_sources,
download,
ensure_node,
extract_zip,
Expand All @@ -31,7 +32,6 @@
read_python_configs,
shell,
split_config_settings,
test_fail_cwd_file,
virtualenv,
)

Expand Down Expand Up @@ -379,9 +379,17 @@ def build(options: Options, tmp_path: Path) -> None:
package=build_options.package_dir.resolve(),
)

test_cwd = identifier_tmp_dir / "test_cwd"
test_cwd.mkdir(exist_ok=True)
(test_cwd / "test_fail.py").write_text(test_fail_cwd_file.read_text())
if build_options.test_sources:
test_cwd = identifier_tmp_dir / "test_cwd"
test_cwd.mkdir(exist_ok=True)
copy_test_sources(
build_options.test_sources,
build_options.package_dir,
test_cwd,
)
else:
# There are no test sources. Run the tests in the project directory.
test_cwd = Path(".").resolve()

shell(test_command_prepared, cwd=test_cwd, env=virtualenv_env)

Expand Down
33 changes: 33 additions & 0 deletions cibuildwheel/resources/cibuildwheel.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,21 @@
],
"title": "CIBW_TEST_EXTRAS"
},
"test-sources": {
"description": "Test files that are required by the test environment",
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
],
"title": "CIBW_TEST_SOURCES"
},
"test-groups": {
"description": "Install extra groups when testing",
"oneOf": [
Expand Down Expand Up @@ -500,6 +515,9 @@
"test-extras": {
"$ref": "#/$defs/inherit"
},
"test-sources": {
"$ref": "#/$defs/inherit"
},
"test-requires": {
"$ref": "#/$defs/inherit"
}
Expand Down Expand Up @@ -586,6 +604,9 @@
"test-extras": {
"$ref": "#/properties/test-extras"
},
"test-sources": {
"$ref": "#/properties/test-sources"
},
"test-groups": {
"$ref": "#/properties/test-groups"
},
Expand Down Expand Up @@ -693,6 +714,9 @@
"test-extras": {
"$ref": "#/properties/test-extras"
},
"test-sources": {
"$ref": "#/properties/test-sources"
},
"test-groups": {
"$ref": "#/properties/test-groups"
},
Expand Down Expand Up @@ -741,6 +765,9 @@
"test-extras": {
"$ref": "#/properties/test-extras"
},
"test-sources": {
"$ref": "#/properties/test-sources"
},
"test-groups": {
"$ref": "#/properties/test-groups"
},
Expand Down Expand Up @@ -802,6 +829,9 @@
"test-extras": {
"$ref": "#/properties/test-extras"
},
"test-sources": {
"$ref": "#/properties/test-sources"
},
"test-groups": {
"$ref": "#/properties/test-groups"
},
Expand Down Expand Up @@ -850,6 +880,9 @@
"test-extras": {
"$ref": "#/properties/test-extras"
},
"test-sources": {
"$ref": "#/properties/test-sources"
},
"test-groups": {
"$ref": "#/properties/test-groups"
},
Expand Down
1 change: 1 addition & 0 deletions cibuildwheel/resources/defaults.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ repair-wheel-command = ""

test-command = ""
before-test = ""
test-sources = []
test-requires = []
test-extras = []
test-groups = []
Expand Down
17 changes: 0 additions & 17 deletions cibuildwheel/resources/testing_temp_dir_file.py

This file was deleted.

41 changes: 38 additions & 3 deletions cibuildwheel/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import typing
import urllib.request
from collections import defaultdict
from collections.abc import Generator, Iterable, Mapping, MutableMapping, Sequence
from collections.abc import Callable, Generator, Iterable, Mapping, MutableMapping, Sequence
from dataclasses import dataclass
from enum import Enum
from functools import lru_cache, total_ordering
Expand All @@ -35,6 +35,7 @@
from packaging.version import Version
from platformdirs import user_cache_path

from . import errors
from ._compat import tomllib
from .architecture import Architecture
from .typing import PathOrStr, PlatformName
Expand Down Expand Up @@ -63,8 +64,6 @@

free_thread_enable_313: Final[Path] = resources_dir / "free-threaded-enable-313.xml"

test_fail_cwd_file: Final[Path] = resources_dir / "testing_temp_dir_file.py"


MANYLINUX_ARCHS: Final[tuple[str, ...]] = (
"x86_64",
Expand Down Expand Up @@ -394,6 +393,42 @@
return Path(resulting_file).resolve(strict=True)


def copy_into(src: Path, dst: PurePath) -> None:
"""Copy a path from src to dst, regardless of whether it's a file or a directory."""
# Ensure the target folder location exists
Path(dst.parent).mkdir(exist_ok=True, parents=True)

if src.is_dir():
shutil.copytree(src, dst)
else:
shutil.copy(src, dst)


def copy_test_sources(
test_sources: list[str],
package_dir: Path,
test_dir: PurePath,
copy_into: Callable[[Path, PurePath], None] = copy_into,

Check warning on line 411 in cibuildwheel/util.py

View workflow job for this annotation

GitHub Actions / Linters (mypy, flake8, etc.)

W0621

Redefining name 'copy_into' from outer scope (line 396)
freakboy3742 marked this conversation as resolved.
Show resolved Hide resolved
) -> None:
"""Copy the list of test sources from the package to the test directory.

:param test_sources: A list of test paths, relative to the package_dir.
:param package_dir: The root of the package directory.
:param test_dir: The folder where test sources should be placed.
:param copy_info: The copy function to use. By default, does a local
filesystem copy; but an OCIContainer.copy_info method (or equivalent)
can be provided.
"""
for test_path in test_sources:
source = package_dir.resolve() / test_path

if not source.exists():
msg = f"Test source {test_path} does not exist."
raise errors.FatalError(msg)

copy_into(source, test_dir / test_path)


class DependencyConstraints:
def __init__(self, base_file_path: Path):
assert base_file_path.exists()
Expand Down
16 changes: 12 additions & 4 deletions cibuildwheel/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
BuildSelector,
call,
combine_constraints,
copy_test_sources,
download,
extract_zip,
find_compatible_wheel,
Expand All @@ -38,7 +39,6 @@
read_python_configs,
shell,
split_config_settings,
test_fail_cwd_file,
unwrap,
virtualenv,
)
Expand Down Expand Up @@ -572,9 +572,17 @@ def build(options: Options, tmp_path: Path) -> None:
package=options.globals.package_dir.resolve(),
wheel=repaired_wheel,
)
test_cwd = identifier_tmp_dir / "test_cwd"
test_cwd.mkdir()
(test_cwd / "test_fail.py").write_text(test_fail_cwd_file.read_text())
if build_options.test_sources:
test_cwd = identifier_tmp_dir / "test_cwd"
test_cwd.mkdir()
copy_test_sources(
build_options.test_sources,
build_options.package_dir,
test_cwd,
)
else:
# There are no test sources. Run the tests in the project directory.
test_cwd = Path(".").resolve()

shell(test_command_prepared, cwd=test_cwd, env=virtualenv_env)

Expand Down
Loading
Loading