Conversation
|
|
There was a problem hiding this comment.
🟢 Approval recommended
The change is minimal, directly addresses a crash, and includes a focused regression test validating the new behavior.
Pull request overview
This PR fixes a hard crash in the PyArrow Dataset Python API by rejecting a None partition expression at the Cython boundary, converting an interpreter “bus error” into a normal Python TypeError and adding a regression test.
Changes:
- Mark
get_partition_keys’spartition_expressionparameter asnot Noneinpython/pyarrow/_dataset.pyxsoNoneis rejected before dereferencing. - Add a regression test ensuring
ds.get_partition_keys(None)raisesTypeError.
File summaries
| File | Description |
|---|---|
| python/pyarrow/_dataset.pyx | Adds not None to the typed Expression parameter to prevent null from reaching Cython internals. |
| python/pyarrow/tests/test_dataset.py | Adds a regression test asserting TypeError is raised for None input. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🟡 Changes recommended
The new subprocess-based sweep test can hang indefinitely and may miss post-“DONE” crashes unless it asserts returncode == 0 and uses a timeout.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 2
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
The new subprocess-based sweep tests need a timeout (to avoid hanging CI) and a couple of small documentation/comment fixes for correctness and debuggability.
Review details
Suppressed comments (4)
Previously missed (1) — in code that hasn't changed since the last review.
python/pyarrow/tests/test_misc.py:319
- This subprocess sweep has no timeout, so a single blocking callable can hang the entire test run. Consider adding a reasonable timeout (and include stderr in the failure) to make CI failures deterministic and easier to debug.
This issue also appears on line 377 of the same file.
python/pyarrow/tests/test_misc.py:280
- The comment says passing None to any public callable must produce a Python exception, but the test intentionally allows callables to accept None (it only asserts the subprocess doesn't crash). Please update the comment to match the actual contract (no crash).
# GH-51293: a typed Cython parameter that is not declared "not None"
# lets None reach code that dereferences it, killing the interpreter
# instead of raising. Passing None to any public callable must produce
# a Python exception, never a fatal signal.
python/pyarrow/tests/test_misc.py:381
- Same issue as the callable sweep above: this subprocess.run has no timeout and the failure message drops stderr, which can lead to hung CI jobs and harder debugging when something goes wrong.
res = subprocess.run([sys.executable, "-c", code],
capture_output=True, text=True)
lines = res.stdout.splitlines()
if not lines or lines[-1] != "DONE":
culprit = lines[-1] if lines else "<no output>"
python/pyarrow/_compute.pyx:2687
- The equals() docstring parameter type references pyarrow.dataset.Expression, but this is pyarrow.compute.Expression (and the method signature enforces that). This mismatch can confuse users reading the docs/help().
Parameters
----------
other : pyarrow.dataset.Expression
- Files reviewed: 4/4 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🟢 Approval recommended
The functional changes directly address the reported interpreter-crash bug and are covered by targeted and guard-style tests; remaining feedback is limited to minor doc/test robustness improvements.
Review details
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
python/pyarrow/_compute.pyx:2687
- The
Expression.equalsdocstring referencespyarrow.dataset.Expression, but this type lives inpyarrow.compute(and this method is defined inpyarrow/_compute.pyx). Updating the docstring avoids confusing API users.
def equals(self, Expression other not None):
"""
Parameters
----------
other : pyarrow.dataset.Expression
python/pyarrow/tests/test_misc.py:363
- The subprocess method sweep uses
inspect._empty, which is a privateinspectimplementation detail. Prefer the publicinspect.Parameter.emptyto reduce risk of breakage across Python versions.
- Files reviewed: 4/4 changed files
- Comments generated: 0 new
- Review effort level: Lite
|
Thanks for the PR.
I am not sure this is needed. @raul what do you think? I would rather see a missing test for the |
|
Done in 4415d41. This adds the focused Expression.equals(None) regression. |
There was a problem hiding this comment.
🟡 Changes recommended
The subprocess guard can exercise unrelated crashing methods and may skip the intended Cython methods, so it does not reliably validate the fix.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (1)
python/pyarrow/tests/test_misc.py:360
- This method guard is effectively vacuous for the Cython methods it is meant to cover. The child process uses stdlib
inspect, but this repository's Cython build does not reliably expose__text_signature__;dev/archery/archery/lang/python.py:169-184adds a docstring parser specifically becauseinspect.signaturefails. Thisexcepttherefore skipsExpression.equalsand similar methods, so the test can pass without exercising the regression; use the repository's Cython signature parser or explicitly include the methods under test.
sig = inspect.signature(attr)
except BaseException:
continue
- Files reviewed: 5/5 changed files
- Comments generated: 1
- Review effort level: Lite
get_partition_keys took an Expression without rejecting None, so passing None dereferenced a null pointer and terminated the interpreter. Signed-off-by: 1fanwang <1fannnw@gmail.com>
…lables Sweeps public module-level callables with None in a child process and fails with the offending name if the interpreter dies by signal, so a typed Cython parameter missing "not None" is caught as a test failure rather than a segfault in someone else's code. Signed-off-by: 1fanwang <1fannnw@gmail.com>
The sweep in the previous commit only covered module-level functions. Extending it to methods reached from a live object found Expression.equals taking a typed Expression without rejecting None, which segfaulted. Signed-off-by: 1fanwang <1fannnw@gmail.com>
…cisely Add a timeout so a blocking callable cannot hang CI, fail on a non-zero returncode so a crash during interpreter shutdown is caught, and correct the comment: some public APIs accept None, so the invariant is only that none of them terminate the interpreter. Signed-off-by: 1fanwang <1fannnw@gmail.com>
Signed-off-by: 1fanwang <1fannnw@gmail.com>
The two Expression guards should not depend on unrelated APIs accepting None. Signed-off-by: 1fanwang <1fannnw@gmail.com>
c048968 to
e96bab5
Compare

Rationale for this change
Passing None to partition-key extraction or expression equality terminates Python instead of raising an exception. Applications cannot catch that failure.
Fixes #51293.
What changes are included in this PR?
Both expression parameters reject None at the Cython boundary. Direct and subprocess regressions cover these two entry points.
Are these changes tested?
Built from source on macOS arm64 with Python 3.12.14. Both calls crash on upstream main and raise TypeError on the rebased branch. Valid equality and partition-key extraction retain their results.
Raw logs
Are there any user-facing changes?
Null expressions raise TypeError instead of terminating Python. Valid calls keep their existing behavior.
Was AI used for this PR?
In accordance to the AI generation guidelines, please disclose below whether and how AI was used in this PR.
PR code and description written by:
Reviewed before submission by: