| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
📝 Walkthrough
WalkthroughThis PR adds the Clippy lint unnecessary_wraps = "warn" to the workspace and systematically removes PyResult wrapping from hundreds of helper functions, internal methods, and stdlib functions across codegen, VM builtins, and stdlib modules. Functions now return direct values (bool, usize, String, PyObjectRef, etc.) instead of Result-wrapped equivalents, simplifying call sites by eliminating ? operators and Ok(...) wrappers where applicable. Several module-level module_exec functions and similar required-signature spots gain #[expect] annotations. ChangesInfallibility refactor across codegen, VM, and stdlib
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
✨ Finishing Touches 🧪 Generate unit tests (beta)
|
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)crates/vm/src/stdlib/_ctypes.rs (1)crates/vm/src/stdlib/_ctypes/base.rs (2)546-557: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win
Preserve Python error propagation in LoadLibrary (avoid panic).
Line 555 uses unwrap() inside a Python-callable function. On library load failure this can panic the VM instead of raising an exception.
Proposed fix🤖 Prompt for AI Agents- fn load_library_windows( + fn load_library_windows( name: String, _load_flags: OptionalArg<i32>, vm: &VirtualMachine, -) -> usize { +) -> PyResult<usize> { let cache = library::libcache(); let mut cache_write = cache.write(); - let (id, _) = cache_write.get_or_insert_lib(&name, vm).unwrap(); - id + let (id, _) = cache_write + .get_or_insert_lib(&name, vm) + .map_err(|e| vm.new_os_error(e.to_string()))?; + Ok(id) }Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/vm/src/stdlib/_ctypes.rs` around lines 546 - 557, The function load_library_windows currently calls cache.write().get_or_insert_lib(&name, vm).unwrap() which can panic; change load_library_windows to return PyResult<usize> (instead of usize) and propagate the error instead of unwrapping: call get_or_insert_lib(&name, vm) and map or match its Err to a Python exception via the VirtualMachine (e.g. vm.new_os_error or an appropriate vm.new_exception with a descriptive message), returning Err(...) on failure, or use the ? operator after converting the error into a PyResult to return the id on success; keep references to library::libcache(), cache.write(), and get_or_insert_lib to locate the code.2465-2495: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift
Avoid pointer-size fallback for unknown field types.
Line 2494 defaults to size_of::<usize>() when size resolution fails. That can let invalid _fields_ entries pass with a bogus size instead of failing fast with TypeError.
Suggested direction-pub(super) fn get_field_size(field_type: &PyObject, vm: &VirtualMachine) -> usize { +pub(super) fn get_field_size(field_type: &PyObject, vm: &VirtualMachine) -> PyResult<usize> { ... - core::mem::size_of::<usize>() + Err(vm.new_type_error("field type has no determinable ctypes size")) }Update callers in structure/union/CField initialization to propagate this error.
🤖 Prompt for AI AgentsVerify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/vm/src/stdlib/_ctypes/base.rs` around lines 2465 - 2495, Replace the pointer-size fallback in get_field_size by returning a failure instead: change get_field_size to return Option<usize> (or Result<usize, PyErr>) instead of usize, remove the final core::mem::size_of::<usize>() default and return None/Error when no size could be resolved, and then update all callers (e.g., the structure/union initialization paths and CField construction sites that currently call get_field_size) to check the Option/Result and propagate a TypeError via the VM (e.g., vm.new_type_error or equivalent) when size resolution fails so invalid _fields_ entries fail fast.
1590-1643: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift
Do not silently zero-fill failed ctypes conversions.
Line 1642 (and unwrap_or(0) at Lines 1624, 1628, 1632, 1636) turns invalid/out-of-range assignments into zero bytes instead of raising, which can silently corrupt structure/union field data.
Suggested direction-fn value_to_bytes(value: &PyObject, size: usize, vm: &VirtualMachine) -> Vec<u8> { +fn value_to_bytes(value: &PyObject, size: usize, vm: &VirtualMachine) -> PyResult<Vec<u8>> { ... - _ => vec![0u8; size], + _ => { + return Err(vm.new_type_error(format!( + "cannot convert {} to ctypes field value", + value.class().name() + ))); + } }Then propagate ? at call sites where assignment must fail on invalid conversion.
🤖 Prompt for AI AgentsVerify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/vm/src/stdlib/_ctypes/base.rs` around lines 1590 - 1643, The helper value_to_bytes currently silently zero-fills on failed numeric conversions (uses unwrap_or(0) and returns zero bytes), which hides errors; change value_to_bytes to return a PyResult<Vec<u8>> (or Result) and propagate conversion failures instead of substituting zeros: replace the unwrap_or(0) calls in value_to_bytes and the final fallback path so that when int conversions via value.try_int(vm) or bigint->to_i8/to_i16/to_i32/to_i64 fail you return an appropriate Python error (e.g. OverflowError/TypeError via the VirtualMachine) instead of producing zero bytes, and likewise make float/int size-mismatch cases return an error rather than unreachable/zero-fill so callers of value_to_bytes (e.g. code using PyCData) can handle the failure.
crates/stdlib/src/unicodedata.rs (1)🤖 Prompt for all review comments with AI agentscrates/vm/src/exceptions.rs (1)194-217: ⚡ Quick win
Extract shared normalization logic to avoid duplicated match branches.
Line 194 and Line 223 implement the same match form normalization pipeline in two places. Please extract this into one helper (e.g., fn normalize_text(form, text) -> Wtf8Buf) and reuse it from both methods to keep behavior aligned and reduce drift risk.
As per coding guidelines, "When branches differ only in a value but share common logic, extract the differing value first, then call the common logic once to avoid duplicate code".
Also applies to: 221-245
🤖 Prompt for AI AgentsVerify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/stdlib/src/unicodedata.rs` around lines 194 - 217, Extract the duplicated normalization pipeline into a single helper (e.g., fn normalize_text(form: super::NormalizeForm, text: &Wtf8Str) -> Wtf8Buf) that first maps the form to the correct normalizer instance (ComposingNormalizerBorrowed::new_nfc(), ::new_nfkc(), DecomposingNormalizerBorrowed::new_nfd(), ::new_nfkd()) and then performs text.map_utf8(|s| normalizer.normalize_iter(s.chars())).collect(); replace the duplicated match blocks in normalize(...) and the other location (the branch around lines 221–245) to call this helper so only the normalizer selection differs while the mapping/collect logic is centralized.1102-1113: 💤 Low value
Minor: consider a flatter form to avoid the Some(match ...) with early return None.
The current form works correctly but mixes a wrapping Some(...) with an inner return None, which is slightly awkward to read. A direct match returning Option per-arm is more idiomatic.
♻️ Proposed refactor🤖 Prompt for AI Agentslet args = exc.args.read(); - Some(match args.len() { - 0 => return None, - 1 => args.first().unwrap().clone(), - _ => args.as_object().to_owned(), - }) + match args.len() { + 0 => None, + 1 => Some(args.first().unwrap().clone()), + _ => Some(args.as_object().to_owned()), + }Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/vm/src/exceptions.rs` around lines 1102 - 1113, Refactor system_exit_code to return an Option directly from a match instead of wrapping a match in Some(...) and using an early return; replace the current Some(match args.len() { 0 => return None, 1 => ..., _ => ... }) with match args.len() { 0 => None, 1 => Some(args.first().unwrap().clone()), _ => Some(args.as_object().to_owned()) } so the function returns Option<PyObjectRef> idiomatically and removes the inner return; keep the same uses of args.read(), args.first(), and args.as_object() from the existing function.
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/vm/src/stdlib/_ctypes/function.rs`:
- Around line 1906-1913: Change set_argtypes back to return PyResult<()> and
perform the same input validation pattern used by set_restype and set_errcheck:
if vm.is_none(&value) set self.argtypes to None and return Ok(()); otherwise
ensure value is an iterable (reject non-iterable with vm.new_type_error) and
iterate its items validating each is either None or an acceptable ctypes
type/callable (reject invalid items with a descriptive Err). Update assignments
to set self.argtypes = Some(value) only after validation succeeds and return
Ok(()).
In `@crates/vm/src/stdlib/sys.rs`:
- Around line 88-92: The write method in sys.rs currently ignores
std::io::stderr().write_all(bytes) errors but always returns bytes.len(), which
violates the write contract; change write to check the Result from write_all on
the PyStrRef bytes and return bytes.len() only on Ok(()), otherwise return 0
(i.e., treat a write failure as zero bytes written). Update the function named
write to capture the result (match or if let Err(_)) and return 0 on error while
preserving the existing successful return value.
---
Outside diff comments:
In `@crates/vm/src/stdlib/_ctypes.rs`:
- Around line 546-557: The function load_library_windows currently calls
cache.write().get_or_insert_lib(&name, vm).unwrap() which can panic; change
load_library_windows to return PyResult<usize> (instead of usize) and propagate
the error instead of unwrapping: call get_or_insert_lib(&name, vm) and map or
match its Err to a Python exception via the VirtualMachine (e.g. vm.new_os_error
or an appropriate vm.new_exception with a descriptive message), returning
Err(...) on failure, or use the ? operator after converting the error into a
PyResult to return the id on success; keep references to library::libcache(),
cache.write(), and get_or_insert_lib to locate the code.
In `@crates/vm/src/stdlib/_ctypes/base.rs`:
- Around line 2465-2495: Replace the pointer-size fallback in get_field_size by
returning a failure instead: change get_field_size to return Option<usize> (or
Result<usize, PyErr>) instead of usize, remove the final
core::mem::size_of::<usize>() default and return None/Error when no size could
be resolved, and then update all callers (e.g., the structure/union
initialization paths and CField construction sites that currently call
get_field_size) to check the Option/Result and propagate a TypeError via the VM
(e.g., vm.new_type_error or equivalent) when size resolution fails so invalid
_fields_ entries fail fast.
- Around line 1590-1643: The helper value_to_bytes currently silently zero-fills
on failed numeric conversions (uses unwrap_or(0) and returns zero bytes), which
hides errors; change value_to_bytes to return a PyResult<Vec<u8>> (or Result)
and propagate conversion failures instead of substituting zeros: replace the
unwrap_or(0) calls in value_to_bytes and the final fallback path so that when
int conversions via value.try_int(vm) or bigint->to_i8/to_i16/to_i32/to_i64 fail
you return an appropriate Python error (e.g. OverflowError/TypeError via the
VirtualMachine) instead of producing zero bytes, and likewise make float/int
size-mismatch cases return an error rather than unreachable/zero-fill so callers
of value_to_bytes (e.g. code using PyCData) can handle the failure.
---
Nitpick comments:
In `@crates/stdlib/src/unicodedata.rs`:
- Around line 194-217: Extract the duplicated normalization pipeline into a
single helper (e.g., fn normalize_text(form: super::NormalizeForm, text:
&Wtf8Str) -> Wtf8Buf) that first maps the form to the correct normalizer
instance (ComposingNormalizerBorrowed::new_nfc(), ::new_nfkc(),
DecomposingNormalizerBorrowed::new_nfd(), ::new_nfkd()) and then performs
text.map_utf8(|s| normalizer.normalize_iter(s.chars())).collect(); replace the
duplicated match blocks in normalize(...) and the other location (the branch
around lines 221–245) to call this helper so only the normalizer selection
differs while the mapping/collect logic is centralized.
In `@crates/vm/src/exceptions.rs`:
- Around line 1102-1113: Refactor system_exit_code to return an Option directly
from a match instead of wrapping a match in Some(...) and using an early return;
replace the current Some(match args.len() { 0 => return None, 1 => ..., _ => ...
}) with match args.len() { 0 => None, 1 => Some(args.first().unwrap().clone()),
_ => Some(args.as_object().to_owned()) } so the function returns
Option<PyObjectRef> idiomatically and removes the inner return; keep the same
uses of args.read(), args.first(), and args.as_object() from the existing
function.
Fix all unresolved CodeRabbit comments on this PR:
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: ea378332-1b44-40ac-b3c9-66ff36dae5e8
📥 CommitsReviewing files that changed from the base of the PR and between 7ebffd0 and fc58a80.
📒 Files selected for processing (72)
Sorry, something went wrong.
| fn set_argtypes(&self, value: PyObjectRef, vm: &VirtualMachine) { | ||
| if vm.is_none(&value) { | ||
| *self.argtypes.write() = None; | ||
| } else { | ||
| // Store the argtypes object directly as it is | ||
| *self.argtypes.write() = Some(value); | ||
| } | ||
| Ok(()) | ||
| } |
There was a problem hiding this comment.
⚠️ Potential issue | 🟠 Major | ⚡ Quick win
Restore validation and PyResult<()> return type for consistency.
The removal of PyResult<()> from set_argtypes creates an inconsistency with other setters in this impl block. Both set_restype (line 1884) and set_errcheck (line 1922) return PyResult<()> and validate their inputs, rejecting invalid values at set time. However, set_argtypes now accepts any value without validation, deferring errors until call time.
This degrades user experience by producing less clear error messages and breaks consistency with CPython's ctypes behavior.
🔧 Proposed fix to restore validation #[pygetset(name = "argtypes", setter)]
- fn set_argtypes(&self, value: PyObjectRef, vm: &VirtualMachine) {
+ fn set_argtypes(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
if vm.is_none(&value) {
*self.argtypes.write() = None;
+ } else if value.try_to_value::<Vec<PyObjectRef>>(vm).is_ok() {
+ // Validate it's a sequence; detailed type checking happens at call time
+ *self.argtypes.write() = Some(value);
} else {
- // Store the argtypes object directly as it is
- *self.argtypes.write() = Some(value);
+ return Err(vm.new_type_error("argtypes must be a sequence or None"));
}
+ Ok(())
}Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/vm/src/stdlib/_ctypes/function.rs` around lines 1906 - 1913, Change set_argtypes back to return PyResult<()> and perform the same input validation pattern used by set_restype and set_errcheck: if vm.is_none(&value) set self.argtypes to None and return Ok(()); otherwise ensure value is an iterable (reject non-iterable with vm.new_type_error) and iterate its items validating each is either None or an acceptable ctypes type/callable (reject invalid items with a descriptive Err). Update assignments to set self.argtypes = Some(value) only after validation succeeds and return Ok(()).
Sorry, something went wrong.
| fn write(&self, s: PyStrRef) -> usize { | ||
| let bytes = s.as_bytes(); | ||
| let _ = std::io::stderr().write_all(bytes); | ||
| Ok(bytes.len()) | ||
| bytes.len() | ||
| } |
There was a problem hiding this comment.
⚠️ Potential issue | 🟡 Minor | ⚡ Quick win
Return value is incorrect when write fails.
The method ignores write errors (line 90) but still returns bytes.len() (line 91), misleading callers into thinking all bytes were successfully written. While ignoring errors during bootstrap may be acceptable, returning an incorrect length violates the write method contract.
Proposed fix: return 0 on write failure #[pymethod]
fn write(&self, s: PyStrRef) -> usize {
let bytes = s.as_bytes();
- let _ = std::io::stderr().write_all(bytes);
- bytes.len()
+ std::io::stderr()
+ .write_all(bytes)
+ .map(|_| bytes.len())
+ .unwrap_or(0)
}‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| fn write(&self, s: PyStrRef) -> usize { | |
| let bytes = s.as_bytes(); | |
| let _ = std::io::stderr().write_all(bytes); | |
| Ok(bytes.len()) | |
| bytes.len() | |
| } | |
| #[pymethod] | |
| fn write(&self, s: PyStrRef) -> usize { | |
| let bytes = s.as_bytes(); | |
| std::io::stderr() | |
| .write_all(bytes) | |
| .map(|_| bytes.len()) | |
| .unwrap_or(0) | |
| } |
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/vm/src/stdlib/sys.rs` around lines 88 - 92, The write method in sys.rs currently ignores std::io::stderr().write_all(bytes) errors but always returns bytes.len(), which violates the write contract; change write to check the Result from write_all on the PyStrRef bytes and return bytes.len() only on Ok(()), otherwise return 0 (i.e., treat a write failure as zero bytes written). Update the function named write to capture the result (match or if let Err(_)) and return 0 on error while preserving the existing successful return value.
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Summary by CodeRabbit