Skip to content

Commit 6379772

Browse files
joerickhenryiii
andauthored
Revert to running tests from from a temp dir when test-sources is unset (#2420)
* Revert to running tests from from a temp dir when test-sources is unset * Fix placeholders error message, add test for it * Add back {project} placeholders to CIBW_TEST_COMMAND in tests & docs * Update test/test_before_test.py --------- Co-authored-by: Henry Schreiner <[email protected]>
1 parent 7298563 commit 6379772

File tree

16 files changed

+209
-107
lines changed

16 files changed

+209
-107
lines changed

cibuildwheel/platforms/ios.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -559,19 +559,19 @@ def build(options: Options, tmp_path: Path) -> None:
559559
env=test_env,
560560
)
561561

562-
if not build_options.test_sources:
563-
# iOS requires an explicit test-sources, as the project directory
564-
# isn't visible on the simulator.
565-
566-
msg = "Testing on iOS requires a definition of test-sources."
567-
raise errors.FatalError(msg)
562+
testbed_app_path = testbed_path / "iOSTestbed" / "app"
568563

569564
# Copy the test sources to the testbed app
570-
copy_test_sources(
571-
build_options.test_sources,
572-
build_options.package_dir,
573-
testbed_path / "iOSTestbed" / "app",
574-
)
565+
if build_options.test_sources:
566+
copy_test_sources(
567+
build_options.test_sources,
568+
build_options.package_dir,
569+
testbed_app_path,
570+
)
571+
else:
572+
(testbed_app_path / "test_fail.py").write_text(
573+
resources.TEST_FAIL_CWD_FILE.read_text()
574+
)
575575

576576
log.step("Installing test requirements...")
577577
# Install the compiled wheel (with any test extras), plus
@@ -598,6 +598,26 @@ def build(options: Options, tmp_path: Path) -> None:
598598

599599
log.step("Running test suite...")
600600

601+
# iOS doesn't support placeholders in the test command,
602+
# because the source dir isn't visible on the simulator.
603+
if (
604+
"{project}" in build_options.test_command
605+
or "{package}" in build_options.test_command
606+
):
607+
msg = unwrap_preserving_paragraphs(
608+
f"""
609+
iOS tests configured with a test command that uses the "{{project}}" or
610+
"{{package}}" placeholder. iOS tests cannot use placeholders, because the
611+
source directory is not visible on the simulator.
612+
613+
In addition, iOS tests must run as a Python module, so the test command
614+
must begin with 'python -m'.
615+
616+
Test command: {build_options.test_command!r}
617+
"""
618+
)
619+
raise errors.FatalError(msg)
620+
601621
test_command_parts = shlex.split(build_options.test_command)
602622
if test_command_parts[0:2] != ["python", "-m"]:
603623
first_part = test_command_parts[0]

cibuildwheel/platforms/linux.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -398,18 +398,20 @@ def build_in_container(
398398
wheel=wheel_to_test,
399399
)
400400

401+
test_cwd = testing_temp_dir / "test_cwd"
402+
container.call(["mkdir", "-p", test_cwd])
403+
401404
if build_options.test_sources:
402-
test_cwd = testing_temp_dir / "test_cwd"
403-
container.call(["mkdir", "-p", test_cwd])
404405
copy_test_sources(
405406
build_options.test_sources,
406407
build_options.package_dir,
407408
test_cwd,
408409
copy_into=container.copy_into,
409410
)
410411
else:
411-
# There are no test sources. Run the tests in the project directory.
412-
test_cwd = PurePosixPath(container_project_path)
412+
# Use the test_fail.py file to raise a nice error if the user
413+
# tries to run tests in the cwd
414+
container.copy_into(resources.TEST_FAIL_CWD_FILE, test_cwd / "test_fail.py")
413415

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

cibuildwheel/platforms/macos.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -706,8 +706,9 @@ def build(options: Options, tmp_path: Path) -> None:
706706
wheel=repaired_wheel,
707707
)
708708

709+
test_cwd = identifier_tmp_dir / "test_cwd"
710+
709711
if build_options.test_sources:
710-
test_cwd = identifier_tmp_dir / "test_cwd"
711712
# only create test_cwd if it doesn't already exist - it
712713
# may have been created during a previous `testing_arch`
713714
if not test_cwd.exists():
@@ -718,8 +719,12 @@ def build(options: Options, tmp_path: Path) -> None:
718719
test_cwd,
719720
)
720721
else:
721-
# There are no test sources. Run the tests in the project directory.
722-
test_cwd = Path.cwd()
722+
# Use the test_fail.py file to raise a nice error if the user
723+
# tries to run tests in the cwd
724+
test_cwd.mkdir(exist_ok=True)
725+
(test_cwd / "test_fail.py").write_text(
726+
resources.TEST_FAIL_CWD_FILE.read_text()
727+
)
723728

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

cibuildwheel/platforms/pyodide.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -523,17 +523,19 @@ def build(options: Options, tmp_path: Path) -> None:
523523
package=build_options.package_dir.resolve(),
524524
)
525525

526+
test_cwd = identifier_tmp_dir / "test_cwd"
527+
test_cwd.mkdir(exist_ok=True)
528+
526529
if build_options.test_sources:
527-
test_cwd = identifier_tmp_dir / "test_cwd"
528-
test_cwd.mkdir(exist_ok=True)
529530
copy_test_sources(
530531
build_options.test_sources,
531532
build_options.package_dir,
532533
test_cwd,
533534
)
534535
else:
535-
# There are no test sources. Run the tests in the project directory.
536-
test_cwd = Path.cwd()
536+
# Use the test_fail.py file to raise a nice error if the user
537+
# tries to run tests in the cwd
538+
(test_cwd / "test_fail.py").write_text(resources.TEST_FAIL_CWD_FILE.read_text())
537539

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

cibuildwheel/platforms/windows.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -588,24 +588,26 @@ def build(options: Options, tmp_path: Path) -> None:
588588
# run the tests from a temp dir, with an absolute path in the command
589589
# (this ensures that Python runs the tests against the installed wheel
590590
# and not the repo code)
591-
test_command_prepared = prepare_command(
592-
build_options.test_command,
593-
project=Path.cwd(),
594-
package=options.globals.package_dir.resolve(),
595-
wheel=repaired_wheel,
596-
)
591+
test_cwd = identifier_tmp_dir / "test_cwd"
592+
test_cwd.mkdir()
593+
597594
if build_options.test_sources:
598-
test_cwd = identifier_tmp_dir / "test_cwd"
599-
test_cwd.mkdir()
600595
copy_test_sources(
601596
build_options.test_sources,
602597
build_options.package_dir,
603598
test_cwd,
604599
)
605600
else:
606-
# There are no test sources. Run the tests in the project directory.
607-
test_cwd = Path.cwd()
601+
# Use the test_fail.py file to raise a nice error if the user
602+
# tries to run tests in the cwd
603+
(test_cwd / "test_fail.py").write_text(resources.TEST_FAIL_CWD_FILE.read_text())
608604

605+
test_command_prepared = prepare_command(
606+
build_options.test_command,
607+
project=Path.cwd(),
608+
package=options.globals.package_dir.resolve(),
609+
wheel=repaired_wheel,
610+
)
609611
shell(test_command_prepared, cwd=test_cwd, env=virtualenv_env)
610612

611613
# we're all done here; move it to output (remove if already exists)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# this file is copied to the testing cwd, to raise the below error message if
2+
# pytest/unittest is run from there.
3+
4+
import sys
5+
import unittest
6+
from typing import NoReturn
7+
8+
9+
class TestStringMethods(unittest.TestCase):
10+
def test_fail(self) -> NoReturn:
11+
if sys.platform == "ios":
12+
msg = (
13+
"You tried to run tests from the testbed app's working "
14+
"directory, without specifying `test-sources`. "
15+
"On iOS, you must copy your test files to the testbed app by "
16+
"setting the `test-sources` option in your cibuildwheel "
17+
"configuration."
18+
)
19+
else:
20+
msg = (
21+
"cibuildwheel executes tests from a different working directory to "
22+
"your project. This ensures only your wheel is imported, preventing "
23+
"Python from accessing files that haven't been packaged into the "
24+
"wheel. "
25+
"\n\n"
26+
"Please specify a path to your tests when invoking pytest "
27+
"using the {project} placeholder, e.g. `pytest {project}` or "
28+
"`pytest {project}/tests`. cibuildwheel will replace {project} with "
29+
"the path to your project. "
30+
"\n\n"
31+
"Alternatively, you can specify your test files using the "
32+
"`test-sources` option, and cibuildwheel will copy them to the "
33+
"working directory for testing."
34+
)
35+
36+
self.fail(msg)

cibuildwheel/util/resources.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
VIRTUALENV: Final[Path] = PATH / "virtualenv.toml"
1818
CIBUILDWHEEL_SCHEMA: Final[Path] = PATH / "cibuildwheel.schema.json"
1919
PYTHON_BUILD_STANDALONE_RELEASES: Final[Path] = PATH / "python-build-standalone-releases.json"
20+
TEST_FAIL_CWD_FILE: Final[Path] = PATH / "testing_temp_dir_file.py"
2021

2122

2223
# this value is cached because it's used a lot in unit tests

docs/configuration.md

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ cibuildwheel to run tests, add the following YAML to your CI config file:
1717
```yaml
1818
env:
1919
CIBW_TEST_REQUIRES: pytest
20-
CIBW_TEST_COMMAND: "pytest ./tests"
20+
CIBW_TEST_COMMAND: "pytest {project}/tests"
2121
```
2222

2323
!!! tab "Azure Pipelines"
@@ -27,7 +27,7 @@ cibuildwheel to run tests, add the following YAML to your CI config file:
2727
```yaml
2828
variables:
2929
CIBW_TEST_REQUIRES: pytest
30-
CIBW_TEST_COMMAND: "pytest ./tests"
30+
CIBW_TEST_COMMAND: "pytest {project}/tests"
3131
```
3232

3333
!!! tab "Travis CI"
@@ -38,18 +38,7 @@ cibuildwheel to run tests, add the following YAML to your CI config file:
3838
env:
3939
global:
4040
- CIBW_TEST_REQUIRES=pytest
41-
- CIBW_TEST_COMMAND="pytest ./tests"
42-
```
43-
44-
!!! tab "AppVeyor"
45-
46-
> appveyor.yml ([docs](https://www.appveyor.com/docs/build-configuration/#environment-variables))
47-
48-
```yaml
49-
environment:
50-
global:
51-
CIBW_TEST_REQUIRES: pytest
52-
CIBW_TEST_COMMAND: "pytest {project}\\tests"
41+
- CIBW_TEST_COMMAND="pytest {project}/tests"
5342
```
5443

5544
!!! tab "CircleCI"
@@ -61,7 +50,7 @@ cibuildwheel to run tests, add the following YAML to your CI config file:
6150
job_name:
6251
environment:
6352
CIBW_TEST_REQUIRES: pytest
64-
CIBW_TEST_COMMAND: "pytest ./tests"
53+
CIBW_TEST_COMMAND: "pytest {project}/tests"
6554
```
6655

6756
!!! tab "Gitlab CI"
@@ -72,7 +61,7 @@ cibuildwheel to run tests, add the following YAML to your CI config file:
7261
linux:
7362
variables:
7463
CIBW_TEST_REQUIRES: pytest
75-
CIBW_TEST_COMMAND: "pytest ./tests"
64+
CIBW_TEST_COMMAND: "pytest {project}/tests"
7665
```
7766

7867
!!! tab "Cirrus CI"
@@ -82,7 +71,7 @@ cibuildwheel to run tests, add the following YAML to your CI config file:
8271
```yaml
8372
env:
8473
CIBW_TEST_REQUIRES: pytest
85-
CIBW_TEST_COMMAND: "pytest ./tests"
74+
CIBW_TEST_COMMAND: "pytest {project}/tests"
8675
```
8776

8877
## Configuration file {: #configuration-file}

docs/options.md

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ This option can also be set using the [command-line option](#command-line) `--pl
2828

2929
```bash
3030
export CIBW_BUILD='cp37-*'
31-
export CIBW_TEST_COMMAND='pytest ./tests'
31+
export CIBW_TEST_COMMAND='pytest {project}/tests'
3232
cibuildwheel --platform linux .
3333
```
3434

@@ -1284,23 +1284,23 @@ Shell command to run tests after the build. The wheel will be installed
12841284
automatically and available for import from the tests. If this variable is not
12851285
set, your wheel will not be installed after building.
12861286

1287-
By default, tests are executed from your project directory. When specifying
1288-
`test-command`, you can optionally use the placeholders `{package}` and
1289-
`{project}` to pass in the location of your test code:
1287+
To ensure the wheel is imported by your tests (instead of your source copy),
1288+
**Tests are executed from a temporary directory**, outside of your source
1289+
tree. To access your test code, you have a couple of options:
12901290

1291-
- `{package}` is the path to the package being built - the `package_dir`
1292-
argument supplied to cibuildwheel on the command line.
1293-
- `{project}` is an absolute path to the project root - the working directory
1294-
where cibuildwheel was called.
1291+
- You can use the [`test-sources`](#test-sources) setting to copy specific
1292+
files from your source tree into the temporary directory. When using
1293+
test-sources, use relative paths in your test command, as if they were
1294+
relative to the project root.
12951295

1296-
Using `{package}` or `{project}` used to be required, but since cibuildwheel
1297-
3.0, tests are run from the project root by default. This means that you can
1298-
use relative paths in your test command, and they will be relative to the
1299-
project root.
1296+
- You can use the `{package}` or `{project}` placeholders in your
1297+
`test-command` to refer to the package being built or the project root,
1298+
respectively.
13001299

1301-
Alternatively, you can use the [`test-sources`](#test-sources) setting to
1302-
create a temporary folder populated with a specific subset of project files to
1303-
run your test suite.
1300+
- `{package}` is the path to the package being built - the `package_dir`
1301+
argument supplied to cibuildwheel on the command line.
1302+
- `{project}` is an absolute path to the project root - the working
1303+
directory where cibuildwheel was called.
13041304

13051305
On all platforms other than iOS, the command is run in a shell, so you can write things like `cmd1 && cmd2`.
13061306

@@ -1318,18 +1318,18 @@ Platform-specific environment variables are also available:<br/>
13181318
```toml
13191319
[tool.cibuildwheel]
13201320
# Run the package tests using `pytest`
1321-
test-command = "pytest ./tests"
1321+
test-command = "pytest {project}/tests"
13221322

13231323
# Trigger an install of the package, but run nothing of note
13241324
test-command = "echo Wheel installed"
13251325

13261326
# Multiline example
13271327
test-command = [
1328-
"pytest ./tests",
1329-
"python ./test.py",
1328+
"pytest {project}/tests",
1329+
"python {project}/test.py",
13301330
]
13311331

1332-
# run tests on ios
1332+
# run tests on ios - when test-sources is set, use relative paths, not {project} or {package}
13331333
[tool.cibuildwheel.ios]
13341334
test-sources = ["tests"]
13351335
test-command = "python -m pytest ./tests"
@@ -1341,17 +1341,17 @@ Platform-specific environment variables are also available:<br/>
13411341

13421342
```yaml
13431343
# Run the package tests using `pytest`
1344-
CIBW_TEST_COMMAND: pytest ./tests
1344+
CIBW_TEST_COMMAND: pytest {project}/tests
13451345

13461346
# Trigger an install of the package, but run nothing of note
13471347
CIBW_TEST_COMMAND: "echo Wheel installed"
13481348

13491349
# Multi-line example - join with && on all platforms
13501350
CIBW_TEST_COMMAND: >
1351-
pytest ./tests &&
1352-
python ./test.py
1351+
pytest {project}/tests &&
1352+
python {project}/test.py
13531353

1354-
# run tests on ios
1354+
# run tests on ios - when test-sources is set, use relative paths, not {project} or {package}
13551355
CIBW_TEST_SOURCES_IOS: tests
13561356
CIBW_TEST_COMMAND_IOS: python -m pytest ./tests
13571357
```

test/test_abi_variants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def test_abi_none(tmp_path, capfd):
187187
project_dir,
188188
add_env={
189189
"CIBW_TEST_REQUIRES": "pytest",
190-
"CIBW_TEST_COMMAND": f"{utils.invoke_pytest()} ./test",
190+
"CIBW_TEST_COMMAND": f"{utils.invoke_pytest()} {{project}}/test",
191191
# limit the number of builds for test performance reasons
192192
"CIBW_BUILD": "cp38-* cp{}{}-* cp313t-* pp310-*".format(*utils.SINGLE_PYTHON_VERSION),
193193
"CIBW_ENABLE": "all",

0 commit comments

Comments
 (0)