Validate compile() filename type and dont_inherit __bool__ protocol#7768
Conversation
Two CPython parity gaps in `compile()` argument handling:
1. **filename rejects only non-buffer-protocol types.** CPython's
`PyUnicode_FSDecoder` accepts `str`, `bytes`, and objects with
`__fspath__` only — `bytearray` / `memoryview` / `array.array` raise
TypeError. RustPython's `FsPath::TryFromObject` impl falls back to
any buffer-protocol object and silently converts to bytes, accepting
them.
```python
>>> compile('pass', bytearray(b'file.py'), 'exec')
# CPython 3.14.4: TypeError
# RustPython main: <code object> ❌
```
Change `CompileArgs::filename` from `FsPath` (which uses the
permissive `TryFromObject` impl) to `PyObjectRef`, then call the
strict `FsPath::try_from_path_like` at the top of `compile()`. Other
`FsPath` consumers are unchanged.
2. **dont_inherit strict-checks the `bool` type.** CPython routes
`dont_inherit` through `PyObject_IsTrue`, calling `__bool__` on
arbitrary objects and propagating exceptions raised there. RustPython
typed it `OptionalArg<bool>`, which rejects subclass-less objects at
binding time before `__bool__` runs.
```python
>>> class EvilBool:
... def __bool__(self): raise ValueError('hi')
>>> compile('pass', 'f', 'exec', dont_inherit=EvilBool())
# CPython 3.14.4: ValueError('hi')
# RustPython main: TypeError('Expected type bool, not EvilBool') ❌
```
Switch to `OptionalArg<ArgIntoBool>` — already used elsewhere in
`builtins` (`all`, `any`, `print(..., flush=...)`).
Verified byte-identical with CPython 3.14.4 across:
- 6 filename types (str, bytes, bytearray, memoryview, list, int)
- 7 dont_inherit values (True/False/1/0/""/"yes"/None) plus the
`__bool__`-raises-ValueError case
Unmasks `Lib/test/test_compile.py`:
- `test_compile_filename`
- `test_compile_filename_refleak`
`cargo run --release -- -m test test_compile test_builtin test_compileall
test_codeop test_ast` — 703 tests pass, 0 regressions. All 188
`extra_tests/snippets/*.py` pass under the CI feature set.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe ChangesArgument & Filename Handling
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.Comment |
📦 Library DependenciesThe following Lib/ modules were modified. Here are their dependencies: [x] test: cpython/Lib/test/test_compile.py (TODO: 16) dependencies: dependent tests: (no tests depend on compile) Legend:
|
Summary
Two CPython parity gaps in
compile()argument handling.1. filename — buffer-protocol types should be rejected
CPython's
PyUnicode_FSDecoderacceptsstr,bytes, and objects with__fspath__only —bytearray/memoryview/array.arrayraise TypeError. RustPython'sFsPath::TryFromObjectimpl falls back to any buffer-protocol object and silently converts to bytes.Change
CompileArgs::filenamefromFsPath(which uses the permissiveTryFromObjectimpl) toPyObjectRef, then call the strictFsPath::try_from_path_likeat the top ofcompile(). OtherFsPathconsumers are unchanged.2. dont_inherit — should call
__bool__, not strict-check the bool typeCPython routes
dont_inheritthroughPyObject_IsTrue, calling__bool__on arbitrary objects and propagating any exception raised there. Switch fromOptionalArg<bool>toOptionalArg<ArgIntoBool>(already used elsewhere inbuiltinsforall,any,print(..., flush=...)).Verification (CPython 3.14.4)
pathlib.Path, custom__fspath__, bad__fspath__, str/bytes subclass)__bool__, plain object)Tests unmasked
Lib/test/test_compile.py:test_compile_filenametest_compile_filename_refleakTest runs
cargo run --release -- -m test test_compile test_builtin test_compileall test_codeop test_ast— 703 tests pass, 0 regressions. All 188extra_tests/snippets/*.pypass under the CI feature set.Summary by CodeRabbit
compile()function for enhanced CPython compatibility with stricter parameter validation and better truthiness evaluation.