4.5 KiB
Binding Return Value Checker
Overview
The check_binding_retval.py script is a static analysis tool that validates Python binding functions in the pocketpy codebase. It ensures that all functions bound to Python properly set return values before returning true.
Purpose
In pocketpy's C API, when a binding function returns true, it indicates successful execution. According to the API conventions, the function MUST set a return value through one of these methods:
-
Direct assignment using
py_new*functions:py_newint(py_retval(), 42); return true; -
Setting None explicitly:
py_newnone(py_retval()); return true; -
Using assignment:
py_assign(py_retval(), some_value); return true; -
Calling functions that set
py_retval()internally:bool ok = py_import("module_name"); // Sets py_retval() on success if(ok) return true;
Usage
Basic Usage
Run the checker on default directories (src/bindings and src/modules):
python scripts/check_binding_retval.py
Verbose Mode
Enable verbose output for debugging:
python scripts/check_binding_retval.py --verbose
Custom Directories
Check specific directories:
python scripts/check_binding_retval.py --dirs src/bindings src/modules src/custom
Exit Codes
0: No issues found (success)1: Issues found (binding functions missing return value assignment)2: Script error (e.g., file access error)
Integration
The checker is integrated into the CI/CD pipeline through the GitHub Actions workflow. It runs automatically on:
- Push events
- Pull request events
The check is part of the "Run Script Check" step in .github/workflows/main.yml.
What It Checks
The tool analyzes all functions that are bound to Python through:
py_bindfunc()py_bind()py_bindmagic()py_bindmethod()py_bindproperty()
For each bound function, it verifies that:
- If the function contains
return truestatements - There are corresponding assignments to
py_retval() - Comments are excluded from analysis (to avoid false positives)
Functions That Set py_retval() Internally
The checker recognizes these functions that internally set py_retval():
py_import()- Sets py_retval() to the imported module on successpy_call()- Sets py_retval() to the call resultpy_iter()- Sets py_retval() to the iteratorpy_str()- Sets py_retval() to string representationpy_repr()- Sets py_retval() to repr stringpy_getattr()- Sets py_retval() to attribute valuepy_next()- Sets py_retval() to next valuepy_getitem()- Sets py_retval() to the itempy_vectorcall()- Sets py_retval() to call result
Example Issues
Issue: Missing Return Value
static bool my_function(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
// Do some work...
return true; // BUG: Should set py_retval() before returning!
}
Fix:
static bool my_function(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
// Do some work...
py_newnone(py_retval()); // Set return value to None
return true;
}
Correct: Using py_new* Functions
static bool add_numbers(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
py_i64 a = py_toint(py_arg(0));
py_i64 b = py_toint(py_arg(1));
py_newint(py_retval(), a + b); // Sets return value
return true;
}
Correct: Calling Functions That Set py_retval()
static bool import_module(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
int res = py_import(py_tostr(py_arg(0))); // Sets py_retval() on success
if(res == -1) return false;
if(res) return true; // py_retval() already set by py_import
return ImportError("module not found");
}
False Positives
The checker may occasionally report false positives for:
- Helper functions that are bound but shouldn't set return values (rare)
- Complex control flow where the return value is set conditionally
If you encounter a false positive, verify that:
- The function is actually a Python-bound callable
- The return value is properly set in all code paths leading to
return true
Maintenance
When adding new patterns or functions that set py_retval() internally:
- Update the
RETVAL_SETTING_FUNCTIONSset incheck_binding_retval.py - Add corresponding test cases
- Update this documentation