update-pandas-testing
Skill9.8k starsChanged 3 months agoApache-2.0View on GitHub
Use when updating pandas for cudf.pandas testing in CI, or when updating the skip and expected-failure lists in python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 1 is distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 92
Before running the pandas unit tests, remove dictionary entries whose node id no longer points to a test in the new pandas version, as …
- Very specific: line 146
Run the same run-pandas-tests.sh command that ci/cudf_pandas_scripts/pandas-tests/run.sh runs, from the fresh working directory, and pipe …
- Very specific: line 163
If a test is failing because of a bug in cudf.pandas, or a bug or bad assumption in pandas, add a key, value pair to the NODEIDS_THAT_FAIL …
- Very specific: line 164
If a test fails only on some runs, or only because of the installed version of an optional dependency, add a key, value pair to …
- Very specific: line 166
If a test in NODEIDS_THAT_FAIL reports [XPASS(strict)], it now passes.
- Very specific: line 167
If a test not in the plugin reports [XPASS(strict)] (pandas marks it xfail(strict=True) but it passes under cudf.pandas), it must go in …
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
pandas testing for cudf.pandas
This rule describes the procedure for updating the pandas unit testing of cudf.pandas in CI. A successful update involves verifying locally that the pandas unit tests run by ci/cudf_pandas_scripts/pandas-tests/run.sh all pass.
Prerequisites
- Prompt the user for a development environment. Assume that the provided environment already contains cudf, the target version of pandas, and the pandas test dependencies.
If the user does not provide an environment, create one from the file in
conda/environments/that matches the CUDA version and CPU architecture of the machine (all_cuda-<CUDA major><CUDA minor>_arch-<arch>.yaml), then add thetest_python_pandas_testsdependencies, which you generate withrapids-dependency-file-generatorfrom thepandas_testsfile key independencies.yaml. Neither file contains cudf. Build and install cudf into the new environment in editable mode.For example, to create a fictional conda development environment named "cudf-dev" on an x86_64 machine with CUDA 13
conda env create -n cudf-dev -f conda/environments/all_cuda-133_arch-x86_64.yaml rapids-dependency-file-generator --file-key pandas_tests --output conda --matrix "" > /tmp/pandas_tests.yaml conda env update -n cudf-dev -f /tmp/pandas_tests.yaml conda run -n cudf-dev ./build.sh libcudf pylibcudf cudf --pydevelop
Notes on the development environment:
- cudf must be installed in editable mode from this repository.
run-pandas-tests.shloads the plugin as-p cudf.pandas.scripts.pandas-testing-plugin, so the plugin is imported from the installed cudf package. If cudf is not an editable install, edits topython/cudf/cudf/pandas/scripts/pandas-testing-plugin.pyhave no effect. Verify withpython -c "import cudf; print(cudf.__file__)". - The environment may contain extra packages, or different versions of optional packages, than the
pandas-testsCI job installs. These can cause spurious local-only failures. Do not add these to the plugin; confirm a failure is reproducible in CI's dependency set before recording it. run-pandas-tests.shcreates apandas-testing/directory in the current working directory. It clones thev<installed pandas version>tag intopandas-testing/pandasand copies the tests intopandas-testing/pandas-tests, but only if those directories do not already exist. If they exist from an earlier pandas version, the old tests are silently reused. Always run the script from a fresh working directory (outside the cudf repository) for each pandas version.
The pandas-testing-plugin.py dictionaries
python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py marks tests to skip or as expected to fail before the tests are run. Each dictionary has keys that are pytest node ids of the form tests/<path>.py::<test>[<params>] and values that are a short reason. The node ids are relative to the pandas-testing/pandas-tests directory, which is where pytest runs. Keep the keys in each dictionary in alphabetical order.
| Dictionary | Marker applied | Use for |
NODEIDS_TO_SKIP | skip | Tests of behavior that cudf.pandas cannot support, for example tests of private pandas APIs |
NODEIDS_PATHS_TO_SKIP | skip | Keys are node id prefixes; skips a whole file, directory, or test name |
NODEIDS_TO_SKIP_WHEN_SHARDED | skip, only with --num-shards > 1 | Tests that fail only because sharding changes the test order |
NODEIDS_THAT_MAY_FAIL | xfail(strict=False) | Flaky or environment-sensitive tests |
NODEIDS_THAT_FAIL | xfail (strict) | Tests that fail because of a bug in cudf.pandas, or a bug or bad assumption in pandas |
pytest_collection_modifyitems checks the dictionaries in this order and applies only the first match: NODEIDS_TO_SKIP, NODEIDS_TO_SKIP_WHEN_SHARDED, NODEIDS_PATHS_TO_SKIP, NODEIDS_THAT_MAY_FAIL, NODEIDS_THAT_FAIL.
The vendored pyproject.toml in run-pandas-tests.sh sets xfail_strict = true. So a test in NODEIDS_THAT_FAIL that now passes is reported as [XPASS(strict)] and fails the run.
Skip tests of non-public pandas APIs
cudf.pandas only aims to support the public pandas API. A unit test that exercises a non-public pandas API belongs in NODEIDS_TO_SKIP or NODEIDS_PATHS_TO_SKIP with a reason that names one non-public API that the test uses, for example "Tests private pandas APIs, for example pandas.core.apply.reconstruct_func" or "Tests private pandas APIs, for example the _mgr attribute", regardless of whether it currently passes or fails. The public pandas API is the set of objects documented in the .rst files in doc/source/reference of the pandas repository.
The scripts in .agents/skills/update-pandas-testing/scripts/ make this determination. Run them with the plain python of the development environment, not with -m cudf.pandas.
- Clone the pandas repository at the tag of the installed pandas version into
pandas-testing/pandasof the fresh working directory.run-pandas-tests.shreuses this clone, so the analyzed tests and the run tests are the same.PANDAS_VERSION=$(python -c "import pandas; print(pandas.__version__)") git clone https://github.com/pandas-dev/pandas --depth=1 -b "v${PANDAS_VERSION}" pandas-testing/pandas - Collect the node ids of the tests. This also creates
pandas-testing/pandas-tests. The script exits with status 1 after a--collect-onlyrun because it finds no report log to move; this is expected.bash <cudf repo>/python/cudf/cudf/pandas/scripts/run-pandas-tests.sh --collect-only -q > collected.txt - Collect the public API into a text file with one fully qualified name per line, for example
pandas.DataFrame.groupby. Use this file to check by hand whether a name is public, for example withgrep -x "pandas.Series.str.lower" public_api.txt.python <cudf repo>/.agents/skills/update-pandas-testing/scripts/collect_public_api.py pandas-testing/pandas > public_api.txt Report the test functions that reference non-public pandas APIs. Pass test files or directories relative to
pandas-teststo limit the report.python <cudf repo>/.agents/skills/update-pandas-testing/scripts/find_private_api_tests.py \ public_api.txt pandas-testing/pandas-tests > private_api_report.txtThe script statically analyzes each test function, its decorators, and the fixtures and helpers that it uses from the same file. It flags two kinds of references:
- A pandas object, reached through an import or an attribute chain such as
pd.core.common.foo, that is not inpublic_api.txtand is not the same object as an entry in it. For example,pandas.core.arrays.DatetimeArrayis public because it ispandas.arrays.DatetimeArray. - An underscore attribute such as
df._mgroridx._datathat is not a documented member name (for exampleExtensionArray._from_sequence) and is not defined by the test code in the same directory.
It does not flag test infrastructure such as
pandas._testingandpandas.compat(TEST_INFRASTRUCTUREin the script), thepandas.apinamespace, or the IPython display methods such as_repr_html_. Each finding that comes from a fixture or helper is marked(via <name>).- A pandas object, reached through an import or an attribute chain such as
- Review every flagged test function in the report. Do not add a test only because the script flags it. Add it only if the non-public API is part of what the test checks, not only part of its setup. Findings marked
(via <name>)are often setup, for example a fixture that usespandas.core.computationto choose its parameters for tests of the publicpd.eval. If a flagged name is public but missing from the reference documentation, add it toUNDOCUMENTED_PUBLICin the script instead. - Print the candidate dictionary entries. Tests that the plugin already skips are omitted. Without
--include-indirect, only tests with direct findings are included.
If every test function in a file is flagged, the file is printed as apython <cudf repo>/.agents/skills/update-pandas-testing/scripts/find_private_api_tests.py \ public_api.txt pandas-testing/pandas-tests \ --format plugin \ --collected collected.txt \ --plugin <cudf repo>/python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py > private_api_entries.txtNODEIDS_PATHS_TO_SKIPcandidate. Otherwise, each collected node id of a flagged test function is printed as aNODEIDS_TO_SKIPcandidate. The reason of each entry names the first finding of the test function in the report, preferring a direct finding over one marked(via <name>); a file's reason names the first finding of its first test function. Add the entries that the review confirmed, and remove each of these tests fromNODEIDS_TO_SKIP_WHEN_SHARDED,NODEIDS_THAT_FAILandNODEIDS_THAT_MAY_FAIL.NODEIDS_TO_SKIPis checked first, so an entry for the same test in another dictionary never applies. If the review found that the named API is only setup, change the reason to name the non-public API that the test checks instead, in the same"Tests private pandas APIs, for example <API>"form. Write a fully qualified name such aspandas.core.dtypes.cast.dict_compatfor an object, andthe <name> attributefor an underscore attribute.
The static analysis does not see tests that a test class inherits from a base class in another file (for example the classes in tests/extension/base/), or fixtures defined in a conftest.py. Review these by hand if a failure in the next step points at a non-public API.
Iterate and classify test failures from run-pandas-tests.sh
Next, run the pandas unit tests with cudf.pandas until there are no test failures.
Remove stale entries
Before running the pandas unit tests, remove dictionary entries whose node id no longer points to a test in the new pandas version, as tests may have been renamed, re-parametrized, or removed. Use the collected.txt file from the previous step to list the stale keys:
import runpy
plugin = runpy.run_path(
"<cudf repo>/python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py"
)
collected = {
line.strip() for line in open("collected.txt") if "::" in line
}
for name in (
"NODEIDS_TO_SKIP",
"NODEIDS_TO_SKIP_WHEN_SHARDED",
"NODEIDS_THAT_MAY_FAIL",
"NODEIDS_THAT_FAIL",
):
for key in sorted(set(plugin[name]) - collected):
print(name, key)
for prefix in plugin["NODEIDS_PATHS_TO_SKIP"]:
if not any(nodeid.startswith(prefix) for nodeid in collected):
print("NODEIDS_PATHS_TO_SKIP", prefix)The -m "not slow and not single_cpu and not db and not network" filter in run-pandas-tests.sh deselects some tests. Before removing a key, confirm that it is truly gone from the new pandas test suite (for example with grep in pandas-testing/pandas-tests) and not only deselected by a marker.
Remove entries that never apply
pytest_collection_modifyitems applies only the first dictionary that matches a test, in the order given in "The pandas-testing-plugin.py dictionaries". List the entries that an earlier dictionary already covers:
import runpy
plugin = runpy.run_path(
"<cudf repo>/python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py"
)
skip = set(plugin["NODEIDS_TO_SKIP"])
paths = tuple(plugin["NODEIDS_PATHS_TO_SKIP"])
may_fail = set(plugin["NODEIDS_THAT_MAY_FAIL"])
for name in (
"NODEIDS_TO_SKIP_WHEN_SHARDED",
"NODEIDS_THAT_MAY_FAIL",
"NODEIDS_THAT_FAIL",
):
for key in sorted(set(plugin[name]) & skip):
print(name, key, "is in NODEIDS_TO_SKIP")
for name in ("NODEIDS_TO_SKIP", "NODEIDS_THAT_MAY_FAIL", "NODEIDS_THAT_FAIL"):
for key in sorted(plugin[name]):
if key.startswith(paths):
print(name, key, "is under a NODEIDS_PATHS_TO_SKIP prefix")
for key in sorted(set(plugin["NODEIDS_THAT_FAIL"]) & may_fail):
print("NODEIDS_THAT_FAIL", key, "is in NODEIDS_THAT_MAY_FAIL")Remove each listed entry from the dictionary named first on its line. The one exception is a NODEIDS_TO_SKIP entry under a NODEIDS_PATHS_TO_SKIP key that is the node id of that single test. In that case, keep the NODEIDS_TO_SKIP entry and remove the NODEIDS_PATHS_TO_SKIP entry. A test in both NODEIDS_TO_SKIP_WHEN_SHARDED and NODEIDS_THAT_MAY_FAIL is intended: it is skipped when sharded and allowed to fail otherwise. Run this check again before sorting the dictionaries.
Run the tests
- Run the same
run-pandas-tests.shcommand thatci/cudf_pandas_scripts/pandas-tests/run.shruns, from the fresh working directory, and pipe the output to a file. Omit--junitxmland the sharding arguments, so the full suite runs unsharded like the nightly job:
The full suite takes a long time. To iterate faster on a subset, pass test paths relative tobash <cudf repo>/python/cudf/cudf/pandas/scripts/run-pandas-tests.sh \ --numprocesses 8 \ --tb=line \ --max-worker-restart=3 \ --dist worksteal \ --report-log=pr.json > pandas-tests-output.txt 2>&1pandas-testsas extra arguments, for exampletests/groupby. - Review the test output and collect the failing tests. The script moves the report log to
pandas-testing/pr.json. Each line is a JSON test report, and thenodeidvalues are in the dictionary key format:jq -r 'select(.["$report_type"] == "TestReport" and .outcome == "failed") | .nodeid' pandas-testing/pr.json | sort -upython <cudf repo>/python/cudf/cudf/pandas/scripts/analyze-test-failures.py pandas-testing/pr.json "<file-or-pattern>"prints the most common failures for a group of tests. - For each failing test:
- If a test is failing because it exercises behavior that cannot be supported in cudf.pandas, add a key, value pair to the
NODEIDS_TO_SKIPdictionary where the key is the node id and the value is a short reason for skipping. If every test in a file or directory fails for the same reason, add the prefix toNODEIDS_PATHS_TO_SKIPinstead. - If a test is failing because of a bug in cudf.pandas, or a bug or bad assumption in pandas, add a key, value pair to the
NODEIDS_THAT_FAILdictionary where the key is the node id and the value is"TODO: Fails starting with pandas version <version>". - If a test fails only on some runs, or only because of the installed version of an optional dependency, add a key, value pair to
NODEIDS_THAT_MAY_FAILwhere the key is the node id and the value is"TODO: Fails starting with pandas version <version>". - In both reasons,
<version>is the pandas version installed in the development environment (python -c "import pandas; print(pandas.__version__)"), for example"TODO: Fails starting with pandas version 3.0.6". - If a test in
NODEIDS_THAT_FAILreports[XPASS(strict)], it now passes. Remove it fromNODEIDS_THAT_FAIL. - If a test not in the plugin reports
[XPASS(strict)](pandas marks itxfail(strict=True)but it passes under cudf.pandas), it must go inNODEIDS_TO_SKIP, notNODEIDS_THAT_FAIL. Adding anxfailmarker does not override pandas' own strict marker, so the strict XPASS would still fail.
- If a test is failing because it exercises behavior that cannot be supported in cudf.pandas, add a key, value pair to the
- Repeat the process until the test output reports no failures.
Run the tests with sharding
Pull request CI splits the suite across shards (see NUM_SHARDS in the pandas-tests-shards job in .github/workflows/pr.yaml). Sharding changes the order the tests run in, which exposes order-dependent behavior in cudf.pandas. After the unsharded run passes, run each shard by adding --shard-id <i> --num-shards <NUM_SHARDS> to the command above for every i from 0 to NUM_SHARDS - 1. Add tests that fail only in a sharded run to NODEIDS_TO_SKIP_WHEN_SHARDED, and repeat until every shard reports no failures.
Importantly when evaluating failing tests, do not attempt to fix cudf.pandas to solve the failures. This is out of scope.
Sort the dictionaries
Once the unsharded run and every shard pass, sort the keys of every dictionary in pandas-testing-plugin.py alphabetically:
python <cudf repo>/.agents/skills/update-pandas-testing/scripts/sort_plugin_dictionaries.py \
<cudf repo>/python/cudf/cudf/pandas/scripts/pandas-testing-plugin.pyThe script requires each entry to start on its own line, and exits with an error without changing the file if one does not. Comment lines directly above an entry move with that entry. If a comment describes several entries, check that it still reads correctly after the sort, and move or repeat it if it does not. Pass --check to only verify the order; the script then exits with status 1 if a dictionary is not sorted.
Finally, report the new test failures, the tests skipped as tests of non-public pandas APIs, and the removed stale entries for each dictionary.
Trending
More talk lately.about the whole repository
Who's talking about NVIDIA/cudf
- NVIDIA/cccl“[spike]: Speed-of-Light Fancy Iterators”GitHub · Oct 3, 2026 · 2 reactions
- NVIDIA/cudf-spark-jni“[submodule-sync] bot-submodule-sync-main to main [skip ci] [bot]”GitHub · Oct 30, 2026 · 1 reactions
- NVIDIA/cudf-spark-jni“[submodule-sync] bot-submodule-sync-main to main [skip ci] [bot]”GitHub · Oct 30, 2026 · 1 reactions
- NVIDIA/cudf-spark-jni“[submodule-sync] bot-submodule-sync-main to main [skip ci] [bot]”GitHub · Oct 30, 2026 · 1 reactions
- NVIDIA/cudf-spark-jni“[submodule-sync] bot-submodule-sync-main to main [skip ci] [bot]”GitHub · Oct 30, 2026 · 1 reactions
The biggest 5 of 17 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 17
Talked about on GitHub and the web (17 times).
On GitHub · 14
- Oct 3, 2026[spike]: Speed-of-Light Fancy Iterators — NVIDIA/cccl2 reactions
- Oct 30, 2026[submodule-sync] bot-submodule-sync-main to main [skip ci] [bot] — NVIDIA/cudf-spark-jni1 reaction · 3 comments
- Oct 30, 2026[submodule-sync] bot-submodule-sync-main to main [skip ci] [bot] — NVIDIA/cudf-spark-jni1 reaction · 3 comments
- Oct 30, 2026[submodule-sync] bot-submodule-sync-main to main [skip ci] [bot] — NVIDIA/cudf-spark-jni1 reaction · 3 comments
- Oct 30, 2026[submodule-sync] bot-submodule-sync-main to main [skip ci] [bot] — NVIDIA/cudf-spark-jni1 reaction · 3 comments
9 more on GitHub
- Oct 15, 2026Select appropriate conda compression levels — rapidsai/build-planning1 reaction · 1 comment
- Oct 6, 2026Drop Python 3.11 support — rapidsai/build-planning1 reaction
- Aug 4, 2026Updating & automating UCX versions — rapidsai/build-planning1 reaction · 3 comments
- Jul 23, 2026Add isolated load_library() smoke tests for library wheels — rapidsai/build-planning1 reaction · 1 comment
- Oct 27, 2026Tracking issues of upstream repo PR — algeon-dev/algeon0 reactions
- Oct 16, 2026[FEA]: Make `__resizable_buffer` public in some capacity — NVIDIA/cccl0 reactions
- Oct 15, 2026Use rapids-github-fetch to download files from GitHub in ci/check_style.sh — rapidsai/build-planning0 reactions · 1 comment
- Oct 1, 2026Shorthand YAML syntax for simple events — rapidsai/quent0 reactions
- Sep 9, 2026Properly leverage pre-commit cache — rapidsai/build-planning0 reactions · 4 comments
On the web · 3
- Oct 20, 2026libcudf - rapidsai — google.com
- Oct 10, 2026accelerated-computing-cudf - nvidia — google.com
- Feb 25, 2026Accelerated Computing Cudf by NVIDIA — AI Skill for Any ... — typingmind.com
In this repository13 other files it gives its agents.
- build-test-cudf-javaSkill
- build-test-cudfSkill
- debug-cudf-pandasSkill
- perf-compare-cudfSkill
- reproduce-ciSkill
- review-cudf-polars-expressionsSkill
- review-cudfSkill
- review-udf-mlir-migrationSkill
- update-cudf-polars-polars-tests-selectionSkill
- update-narwhals-testingSkill
- upgrade-polarsSkill
- accelerated-computing-cudfSkill
- cudf-query-engine-builderSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

