Refactor cudf-polars test suite onto pytest fixtures - #22212
Conversation
5e26c86 to
5f9913e
Compare
1a38c35 to
a464a61
Compare
14fbfb3 to
15e9f36
Compare
Replaces module-level test configuration (`DEFAULT_EXECUTOR`, `DEFAULT_RUNTIME`, `DEFAULT_CLUSTER`, `DEFAULT_BLOCKSIZE_MODE`) with per-test pytest fixtures, and removes the `--blocksize-mode` CLI option. **Note:** The diff is largely mechanical fixture refactoring. The meaningful review surface is limited to: * `tests/conftest.py` * `cudf_polars/testing/asserts.py` * CI scripts
gforsyth
left a comment
There was a problem hiding this comment.
Small changes requested in the logging in the CI scripts
mroeschke
left a comment
There was a problem hiding this comment.
Some optional suggestions and a question.
Also agreed with #22212 (comment)
| _ENGINE_PARAMS = ["in-memory"] | ||
| if importlib.util.find_spec("rapidsmpf") is not None: | ||
| _ENGINE_PARAMS.append("spmd") | ||
|
|
||
|
|
||
| @pytest.fixture(params=_ENGINE_PARAMS) |
There was a problem hiding this comment.
| _ENGINE_PARAMS = ["in-memory"] | |
| if importlib.util.find_spec("rapidsmpf") is not None: | |
| _ENGINE_PARAMS.append("spmd") | |
| @pytest.fixture(params=_ENGINE_PARAMS) | |
| @pytest.fixture(params=["in-memory", pytest.param("spmd", marks=pytest.mark.skipif(importlib.util.find_spec("rapidsmpf") is not None, reason="rapidsmpf not installed") |
There was a problem hiding this comment.
Let’s defer this until rapidsmpf is always available in CI. Right now, this would produce a lot of extra skipped: rapidsmpf not installed lines per run.
| --runtime rapidsmpf \ | ||
| --blocksize-mode small | ||
| echo "Running tests" | ||
| timeout 10m python -m pytest --cache-clear "$@" tests --ignore=tests/experimental/legacy |
There was a problem hiding this comment.
How close are we to collapsing these two pytest calls into ci/run_cudf_polars_pytests.sh?
There was a problem hiding this comment.
I suppose a final state of these existing runs should be
- With the in-memory executor
- With the streaming executor, single cluster with rapidsmpf
- With the streaming executor, distributed dask cluster with rapidsmpf
There was a problem hiding this comment.
Hopefully we can remove all the legacy code next week.
At that point, we’ll be left with the in-memory engine alongside RayEngine, DaskEngine, and SPMDEngine.
Co-authored-by: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com>
TomAugspurger
left a comment
There was a problem hiding this comment.
The update CI scripts and conftest files look good.
| return cudf_polars.testing.asserts.DEFAULT_RUNTIME == "rapidsmpf" | ||
| def using_streaming_engine(engine: pl.GPUEngine) -> bool: | ||
| """True when the active ``engine`` fixture is an :class:`StreamingEngine`.""" | ||
| try: |
There was a problem hiding this comment.
I guess this try/except is unavoidable for now, but once it's the default and we depend on rapidsmpf I'd be more comfortable if this errors loudly if there's an import issue.
pentschev
left a comment
There was a problem hiding this comment.
Minor typo suggestion and a couple of comments. LGTM.
| """Session-scoped communicator — bootstrapped once and shared across all tests. | ||
|
|
||
| Sharing a single communicator avoids the file-based bootstrap race that can | ||
| cause hangs when ``create_ucxx_comm()`` is called repeatedly in the same | ||
| ``rrun`` session (stale barrier files / stale ``ucxx_root_address`` KV entry). | ||
| """ |
There was a problem hiding this comment.
This is fine here, but I wonder if we should change something in rrun or there's nothing we should do there. We will probably be bitten by the same type of issue in every new pytest job that includes rrun. One thing that could be done differently (although that's also on the client/user side) would be to add a barrier at the end of each test, probably not worth the extra cost here though. On rrun's side I can't immediately think of a solution to that, perhaps it would need some care on permitting proper destruction/respawning of the worker being used, this is definitely something that wasn't prioritized.
| # Ray's internal subprocess management leaks `/dev/null` file handles, and | ||
| # distributed's shutdown leaves unclosed sockets. Under Python 3.14 + | ||
| # pytest 9, these surface as unraisable `ResourceWarning`s and — combined | ||
| # with `filterwarnings = ["error", ...]` in pyproject.toml — fail | ||
| # otherwise-unrelated tests when the GC finalizer happens to fire during | ||
| # them. With `pytest-xdist --dist=worksteal`, the leak can land in any | ||
| # test that shares a worker with a ray/dask test, so the suppression must | ||
| # apply globally rather than per-module. | ||
| config.addinivalue_line("filterwarnings", "ignore::ResourceWarning") |
There was a problem hiding this comment.
The only downside of this is that any legit non-Ray/non-Distributed leaks will be swallowed too.
Co-authored-by: Peter Andreas Entschev <peter@entschev.com>
|
/merge |
1 similar comment
|
/merge |
Replaces module-level test configuration (`DEFAULT_*`) with per-test pytest fixtures, and removes the `--blocksize-mode` CLI option. **Note:** The diff is largely mechanical fixture refactoring. The meaningful review surface is limited to: * `tests/conftest.py` * `cudf_polars/testing/asserts.py` * CI scripts --- ### Motivation The test suite currently relies on custom pytest CLI flags (`--executor`, `--cluster`, `--runtime`, `--blocksize-mode`) that are parsed into module-level globals. Covering multiple configurations requires running pytest multiple times in CI with different flag combinations. This does not scale with the new frontend model (`SPMDEngine`, `RayEngine`, `DaskEngine`). CLI flags can only express a single configuration per run, and module-level globals make per-test resource setup and teardown awkward (e.g. communicator, RMM, thread pool). Each new engine also expands the CI matrix. Pytest fixtures map naturally to this. Engines become fixtures with proper lifecycle and scoping, and tests can parametrize over available engines. This removes global state, collapses CI to a single pytest run, and makes it easy to add new engines without touching CI or test configuration. Authors: - Mads R. B. Kristensen (https://github.com/madsbk) - Peter Andreas Entschev (https://github.com/pentschev) Approvers: - Gil Forsyth (https://github.com/gforsyth) - Tom Augspurger (https://github.com/TomAugspurger) - Peter Andreas Entschev (https://github.com/pentschev) - Lawrence Mitchell (https://github.com/wence-) URL: NVIDIA#22212
…#22281) closes #21466 closes #21767 Waiting for #22212 * Makes rapidsmpf a required dependency of cudf_polars * Removes the following `StreamingExecutor` options as they were "experimental" with associated code paths * `StreamingExecutor.runtime` * `StreamingExecutor.shuffle_method` * `StreamingExecutor.unique_fraction` * `StreamingExecutor.groupby_n_ary` * `StreamingExecutor.rapidsmpf_spill` * Removes the task runtime and associated tests * Some tests we modified to only test 1 specific test configuration because of #22346 to pass these tests for now. Planning on revisiting this once rapidsmpf becomes the default Ops-Bot-Merge-Barrier: true Authors: - Matthew Roeschke (https://github.com/mroeschke) Approvers: - Mads R. B. Kristensen (https://github.com/madsbk) - Bradley Dice (https://github.com/bdice) - Matthew Murray (https://github.com/Matt711) - Lawrence Mitchell (https://github.com/wence-) URL: #22281
…NVIDIA#22281) closes NVIDIA#21466 closes NVIDIA#21767 Waiting for NVIDIA#22212 * Makes rapidsmpf a required dependency of cudf_polars * Removes the following `StreamingExecutor` options as they were "experimental" with associated code paths * `StreamingExecutor.runtime` * `StreamingExecutor.shuffle_method` * `StreamingExecutor.unique_fraction` * `StreamingExecutor.groupby_n_ary` * `StreamingExecutor.rapidsmpf_spill` * Removes the task runtime and associated tests * Some tests we modified to only test 1 specific test configuration because of NVIDIA#22346 to pass these tests for now. Planning on revisiting this once rapidsmpf becomes the default Ops-Bot-Merge-Barrier: true Authors: - Matthew Roeschke (https://github.com/mroeschke) Approvers: - Mads R. B. Kristensen (https://github.com/madsbk) - Bradley Dice (https://github.com/bdice) - Matthew Murray (https://github.com/Matt711) - Lawrence Mitchell (https://github.com/wence-) URL: NVIDIA#22281
Replaces module-level test configuration (`DEFAULT_*`) with per-test pytest fixtures, and removes the `--blocksize-mode` CLI option. **Note:** The diff is largely mechanical fixture refactoring. The meaningful review surface is limited to: * `tests/conftest.py` * `cudf_polars/testing/asserts.py` * CI scripts --- ### Motivation The test suite currently relies on custom pytest CLI flags (`--executor`, `--cluster`, `--runtime`, `--blocksize-mode`) that are parsed into module-level globals. Covering multiple configurations requires running pytest multiple times in CI with different flag combinations. This does not scale with the new frontend model (`SPMDEngine`, `RayEngine`, `DaskEngine`). CLI flags can only express a single configuration per run, and module-level globals make per-test resource setup and teardown awkward (e.g. communicator, RMM, thread pool). Each new engine also expands the CI matrix. Pytest fixtures map naturally to this. Engines become fixtures with proper lifecycle and scoping, and tests can parametrize over available engines. This removes global state, collapses CI to a single pytest run, and makes it easy to add new engines without touching CI or test configuration. Authors: - Mads R. B. Kristensen (https://github.com/madsbk) - Peter Andreas Entschev (https://github.com/pentschev) Approvers: - Gil Forsyth (https://github.com/gforsyth) - Tom Augspurger (https://github.com/TomAugspurger) - Peter Andreas Entschev (https://github.com/pentschev) - Lawrence Mitchell (https://github.com/wence-) URL: NVIDIA#22212
…NVIDIA#22281) closes NVIDIA#21466 closes NVIDIA#21767 Waiting for NVIDIA#22212 * Makes rapidsmpf a required dependency of cudf_polars * Removes the following `StreamingExecutor` options as they were "experimental" with associated code paths * `StreamingExecutor.runtime` * `StreamingExecutor.shuffle_method` * `StreamingExecutor.unique_fraction` * `StreamingExecutor.groupby_n_ary` * `StreamingExecutor.rapidsmpf_spill` * Removes the task runtime and associated tests * Some tests we modified to only test 1 specific test configuration because of NVIDIA#22346 to pass these tests for now. Planning on revisiting this once rapidsmpf becomes the default Ops-Bot-Merge-Barrier: true Authors: - Matthew Roeschke (https://github.com/mroeschke) Approvers: - Mads R. B. Kristensen (https://github.com/madsbk) - Bradley Dice (https://github.com/bdice) - Matthew Murray (https://github.com/Matt711) - Lawrence Mitchell (https://github.com/wence-) URL: NVIDIA#22281
Replaces module-level test configuration (
DEFAULT_*) with per-test pytest fixtures, and removes the--blocksize-modeCLI option.Note: The diff is largely mechanical fixture refactoring. The meaningful review surface is limited to:
tests/conftest.pycudf_polars/testing/asserts.pyMotivation
The test suite currently relies on custom pytest CLI flags (
--executor,--cluster,--runtime,--blocksize-mode) that are parsed into module-level globals. Covering multiple configurations requires running pytest multiple times in CI with different flag combinations.This does not scale with the new frontend model (
SPMDEngine,RayEngine,DaskEngine). CLI flags can only express a single configuration per run, and module-level globals make per-test resource setup and teardown awkward (e.g. communicator, RMM, thread pool). Each new engine also expands the CI matrix.Pytest fixtures map naturally to this. Engines become fixtures with proper lifecycle and scoping, and tests can parametrize over available engines. This removes global state, collapses CI to a single pytest run, and makes it easy to add new engines without touching CI or test configuration.