Skip to content

Add basic pyobject c-api functions#7872

Merged
youknowone merged 1 commit into
RustPython:mainfrom
bschoenmaeckers:c-api-object
May 14, 2026
Merged

Add basic pyobject c-api functions#7872
youknowone merged 1 commit into
RustPython:mainfrom
bschoenmaeckers:c-api-object

Conversation

@bschoenmaeckers
Copy link
Copy Markdown
Contributor

@bschoenmaeckers bschoenmaeckers commented May 13, 2026

Summary by CodeRabbit

  • New Features
    • Extended C-API compatibility layer with support for object attribute access and manipulation.
    • Added object introspection and string representation capabilities.
    • Enhanced support for Python C extensions interoperability.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

📝 Walkthrough

Walkthrough

This PR expands RustPython's C-API surface with seven new extern "C" functions. It adds attribute getters and setters (PyObject_GetAttr, PyObject_GetAttrString, PyObject_SetAttr, PyObject_SetAttrString), and object conversion helpers (PyObject_Repr, PyObject_Str, PyObject_IsTrue). These functions handle null pointers and type conversions transparently while delegating to the VM's existing object methods.

Changes

Object C-API Functions

Layer / File(s) Summary
Import and dependency setup
crates/capi/src/object.rs (lines 3–5)
Updated imports add C-interop helpers (CStr, c_char) and pointer utilities (NonNull), and expand rustpython_vm::builtins to support the new C-API functions.
Attribute access and mutation functions
crates/capi/src/object.rs (lines 50–107)
PyObject_GetAttr / PyObject_GetAttrString fetch attributes from objects; PyObject_SetAttr / PyObject_SetAttrString set attributes. Name conversion from PyStr or UTF-8 CStr and value cloning precede delegation to the VM's get_attr / set_attr methods.
Object conversion and truthiness helpers
crates/capi/src/object.rs (lines 109–137)
PyObject_Repr and PyObject_Str produce string representations (returning "<NULL>" for null pointers); PyObject_IsTrue tests object truthiness. All use with_vm and null handling for safety.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • ShaharNaveh

Poem

A rabbit hops through code so bright, 🐰
Adding GetAttr, SetAttr with might,
Repr, Str, and IsTrue all fine,
C-API surface now does shine,
Seven functions intertwine!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding C-API functions for PyObject operations like GetAttr, SetAttr, Repr, Str, and IsTrue.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
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/capi/src/object.rs`:
- Around line 87-89: The code currently uses
CStr::from_ptr(attr_name).to_str().expect(...) which will panic on invalid
UTF-8; instead decode the C string and handle errors by converting the UTF-8
error into a Python exception and returning the appropriate error indicator
(e.g., null pointer or error code) from the surrounding FFI function. Replace
the .expect() on to_str() with a match or map_err that calls the Python C-API to
set an exception (e.g., PyErr_SetString(PyExc_UnicodeDecodeError, ... ) or the
project's helper for raising Python errors), include the invalid data/error
message, and then return early from the function using the function's error
return convention; update uses of the local variable name accordingly after
successful decoding.
- Around line 70-74: The code currently calls
CStr::from_ptr(attr_name).to_str().expect(...), which will panic on invalid
UTF-8; replace the expect with explicit error handling by matching the Result
from to_str(): on Ok(s) assign s to name, on Err(e) set a Python exception (e.g.
PyErr_SetString(PyExc_ValueError, format!("invalid UTF-8 in attribute name: {}",
e).as_ptr()) or using pyo3::exceptions::PyValueError::new_err(...)) and return
the function's error sentinel (NULL for pointer returns or -1 for int returns).
Update the block around CStr::from_ptr(attr_name) / to_str() to use match or
map_err so attr_name decoding never panics and the function returns a
Python-level error instead; reference the variables/functions attr_name, name,
CStr::from_ptr and to_str when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: f82b4ad9-daf1-4860-9a13-70f1be3e791c

📥 Commits

Reviewing files that changed from the base of the PR and between ef375be and 683e008.

📒 Files selected for processing (1)
  • crates/capi/src/object.rs

Comment thread crates/capi/src/object.rs
Comment on lines +70 to +74
let name = unsafe {
CStr::from_ptr(attr_name)
.to_str()
.expect("attribute name must be valid UTF-8")
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace .expect() with proper error handling to avoid panics.

The .expect() call will panic if attr_name contains invalid UTF-8, crashing the entire process. In C APIs, panics cannot be caught by C callers. Instead, convert UTF-8 errors to Python exceptions.

🛡️ Proposed fix to handle UTF-8 decode errors gracefully
         let obj = unsafe { &*obj };
-        let name = unsafe {
-            CStr::from_ptr(attr_name)
-                .to_str()
-                .expect("attribute name must be valid UTF-8")
-        };
+        let name = unsafe { CStr::from_ptr(attr_name) }
+            .to_str()
+            .map_err(|_| vm.new_unicode_decode_error("attribute name must be valid UTF-8".to_owned()))?;
         obj.get_attr(name, vm)
🤖 Prompt for AI Agents
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/capi/src/object.rs` around lines 70 - 74, The code currently calls
CStr::from_ptr(attr_name).to_str().expect(...), which will panic on invalid
UTF-8; replace the expect with explicit error handling by matching the Result
from to_str(): on Ok(s) assign s to name, on Err(e) set a Python exception (e.g.
PyErr_SetString(PyExc_ValueError, format!("invalid UTF-8 in attribute name: {}",
e).as_ptr()) or using pyo3::exceptions::PyValueError::new_err(...)) and return
the function's error sentinel (NULL for pointer returns or -1 for int returns).
Update the block around CStr::from_ptr(attr_name) / to_str() to use match or
map_err so attr_name decoding never panics and the function returns a
Python-level error instead; reference the variables/functions attr_name, name,
CStr::from_ptr and to_str when making the change.

Comment thread crates/capi/src/object.rs
Comment on lines +87 to +89
let name = unsafe { CStr::from_ptr(attr_name) }
.to_str()
.expect("attribute name must be valid UTF-8");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace .expect() with proper error handling to avoid panics.

Same issue as in PyObject_GetAttrString: the .expect() call will panic on invalid UTF-8, crashing the process. Convert UTF-8 errors to Python exceptions instead.

🛡️ Proposed fix to handle UTF-8 decode errors gracefully
         let obj = unsafe { &*obj };
-        let name = unsafe { CStr::from_ptr(attr_name) }
-            .to_str()
-            .expect("attribute name must be valid UTF-8");
+        let name = unsafe { CStr::from_ptr(attr_name) }
+            .to_str()
+            .map_err(|_| vm.new_unicode_decode_error("attribute name must be valid UTF-8".to_owned()))?;
         let value = unsafe { &*value }.to_owned();
🤖 Prompt for AI Agents
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/capi/src/object.rs` around lines 87 - 89, The code currently uses
CStr::from_ptr(attr_name).to_str().expect(...) which will panic on invalid
UTF-8; instead decode the C string and handle errors by converting the UTF-8
error into a Python exception and returning the appropriate error indicator
(e.g., null pointer or error code) from the surrounding FFI function. Replace
the .expect() on to_str() with a match or map_err that calls the Python C-API to
set an exception (e.g., PyErr_SetString(PyExc_UnicodeDecodeError, ... ) or the
project's helper for raising Python errors), include the invalid data/error
message, and then return early from the function using the function's error
return convention; update uses of the local variable name accordingly after
successful decoding.

Copy link
Copy Markdown
Member

@youknowone youknowone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@youknowone youknowone merged commit 11e991f into RustPython:main May 14, 2026
25 checks passed
@bschoenmaeckers bschoenmaeckers deleted the c-api-object branch May 16, 2026 12:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants