Repository navigation
Conversation
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthroughC-API method definitions now select keyword dispatch from method flags. Native function and method descriptor call paths reject unsupported keyword arguments. Method descriptors require a valid positional receiver. Tests cover these checks and keyword handling across built-in functions and methods. ChangesNative keyword and receiver validation
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to No merge-blocking issue is established by the supplied evidence; normal checks can proceed. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The checked call paths reject unsupported keywords before argument conversion or native execution while preserving receiver checks. However, the implementation applies signature-derived policy more broadly than the described audited annotations, and compatibility with external registrations remains unverified. Retained concerns Security review detailsSecurity Blast Radius
Security Findings and Attack Paths
Trust Boundaries and Controls
Resilience and Maintainability Implications
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ 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. Comment |
📦 Library DependenciesThe following Lib/ modules were modified. Here are their dependencies: [ ] test: cpython/Lib/test/test_extcall.py (TODO: 7) dependencies: dependent tests: (no tests depend on extcall) Legend:
|
| )] | ||
| impl Py<PyList> { | ||
| #[pymethod] | ||
| #[pymethod(no_keywords)] |
There was a problem hiding this comment.
Does no_keyword need to be an explicit marker? when a function take only positional arguments, it is automatically no_keyword. Does CPython distinguish explicit no keyword function and others?
There was a problem hiding this comment.
Thank you for the comment. I found no_keyword marker is not necessary. CPython uses ml_flags to distinguish keyword-capable and non-keyword function. CPython rejects keyword arguments with function with ml_flags with METH_O, METH_NOARGS, and METH_FASTCALL without METH_KEYWORDS. So, I agree no_keywords marker is redundant. We can drive the keyword dispatch policy from FromArgs::PARAMS.
I will patch it.
youknowone
left a comment
There was a problem hiding this comment.
Thank you! I left a few comments; though I didn't fully reviewed the design yet.
There was a problem hiding this comment.
please merge tests into single test not to sprawl out.
my recommendation is putting both of them into syntax_funcion_args.py
There was a problem hiding this comment.
Sure, I’ll merge the tests into syntax_function_args.py.
| } | ||
| } | ||
|
|
||
| struct FunctionItemMeta(ItemMetaInner); |
There was a problem hiding this comment.
FunctionItemMeta was introduced to support the no_keywords marker. Now that the marker is gone, it is equivalent to SimpleItemMeta, so I’ll remove it.
| pub name: &'static str, | ||
| pub flags: PyMethodFlags, | ||
| pub doc: super::ItemDoc, | ||
| pub keyword_dispatch: KeywordDispatch, |
There was a problem hiding this comment.
while all fields are public, it means keyword_dispatch is decidable regardless how its parameters looks like. I don't have a good picture how this is expected to be, but I don't agree to this design.
There was a problem hiding this comment.
I introduced MethodDefSpec to simplify the function signature and accommodate future metadata changes, but it isn’t necessary here. Since such changes seem rare, the original new_method_def signature with an additional keyword_dispatch argument should be sufficient.
There was a problem hiding this comment.
MethodSpecDef itself might be useful, but at least keyword_dispatch must not be pub
There was a problem hiding this comment.
I see. I choose not to make MethodSpecDef this time.
b7bf32d to
aa4904b
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
|
@codspeedbot explain why performance improved |
The +11% on
|
| Function (inclusive time) | Base | Head | Δ |
|---|---|---|---|
| Whole benchmark | 936.6 µs | 842.7 µs | −93.9 µs |
PyMapping::_ass_subscript (STORE_NAME) |
419.3 µs | 326.1 µs | −93.2 µs |
↳ Dict::insert |
240.3 µs | 147.0 µs | −93.3 µs |
↳ Dict::lookup |
178.7 µs | 85.3 µs | −93.4 µs |
execute_for_iter / PyStrIterator::next |
174.8 / 74.3 µs | 175.2 / 74.4 µs | ≈0 |
PyDict::hash_or_unhashable |
73.8 µs | 73.8 µs | 0 |
Nearly all of the 94 µs is in Dict::lookup. The string iterator, hashing, and the interpreter loop cost the same in both runs, to within 1 µs.
Why Dict::lookup changed
- The benchmark is
for char in string: pass. Each iteration storescharinto the module globals dict, which goes throughDict::insert→Dict::lookup. benches/microbenchmarks.rsbuildsSettings::default(), which setshash_seed: None. Each benchmark process therefore picks a random string-hash secret.- That secret decides how many slots
Dict::lookupprobes before it findscharin the globals table. Some seeds find it right away and some need extra probes, so the benchmark tends to land on one of two levels, about 843 µs or about 937 µs. mainshows the same pattern with no related code changes. Dependency-only bumps (build(deps): bump which from 8.0.5 to 8.0.6 #8978, build(deps): bump bitflags from 2.13.1 to 2.13.2 #8979) movedloop_string.pyby about ±11% in the same function. This PR's head simply drew the faster seed.
Why the PR can't cause it
The PR changes the native call path: builtin_func.rs, descriptor.rs, function/signature.rs, and the derive macros. This loop never calls a native function or method descriptor, and none of the changed code appears in either flame graph. Nothing in dict_inner.rs, str.rs, or frame.rs was touched.
Bottom line: the PR has no performance effect on loop_string.py; the improvement can be ignored. To stop these flips, you could set settings.hash_seed = Some(0) in bench_rustpython_code so every run hashes strings the same way. I haven't made that change, since it is outside this PR's scope.
Summary
- Warming up the performance wizard...
- Investigate the loop_string.py improvement — The whole delta is in the globals-dict lookup, which the hash seed controls. It is not caused by this PR.
- Reply with explanation — Reply with explanation
- Handling comment — Comment handling finished successfully
Learnings updated. See what CodSpeed remembers about this repository.
Was this response helpful? React with 👍 or 👎 to help us improve CodSpeedBot.
aa4904b to
3624faf
Compare
3624faf to
a0c0223
Compare
Add explicit keyword dispatch metadata independently of inferred Rust calling flags. Reject nonempty keywords before binding and conversion, while preserving descriptor self checks and keyword-capable calls. Annotate 31 builtins and list.append/list.clear, derive C-API policies from ml_flags, and group dynamic registration metadata in MethodDefSpec. Add regression coverage and remove the id doctest expected-failure marker. Validation: workspace and C-API tests/clippy, VM without doc, keyword regressions, and test_call/test_extcall/test_builtin/test_list passed. The full snippet suite had 475 passes and 7 failures: six CPython-side expectation mismatches and one missing optional SQLite module. Assisted-by: Codex:GPT-6
Replace no_keywords annotations with registration-time inference from FromArgs::PARAMS, including nested parameter metadata. Forward arguments with keyword-capable parameters to the binder, preserving min/max body validation and descriptor self checks. Add regressions for raw arguments, keyword argument structs, and list.sort. Tested: C-API tests, workspace and C-API Clippy, VM without doc, both keyword regression snippets, and test_call/test_extcall/test_builtin/test_list. Workspace tests reported eight _opcode snapshot failures. The full snippet suite reported 477 passes and seven failures: six CPython-side failures and one RustPython failure due to the missing optional SQLite module. Assisted-by: Codex:GPT-6
Reuse SimpleItemMeta for pyfunction attributes and remove FunctionItemMeta. Remove MethodDefSpec and restore the original new_method_def arguments with an additional keyword_dispatch parameter, updating its callers. Consolidate keyword dispatch regressions in syntax_function_args.py, preserving their assertions and placing them before builtin shadowing. Validation: workspace and C-API tests/clippy, VM without doc, the combined snippet, and test_extcall/test_builtin/test_list/test_call passed. The full snippet suite reported 477 passes and seven existing failures: six CPython-side failures and one missing optional SQLite module. Assisted-by: Codex:GPT-6
Remove `KeywordDispatch`, the `keyword_dispatch` field of `PyMethodDef`, `PyMethodDef::with_keyword_dispatch`, `function::keyword_dispatch` and the derive macros' `keyword_dispatch_tokens`. Native functions and method descriptors reject nonempty keywords when `flags` lacks `KEYWORDS`, and report the unqualified name when `flags` contains `VARARGS`. `Context::new_method_def` takes `(name, f, flags, doc)` again. Add a snippet for `int.__new__` called with a keyword argument. Assisted-by: Claude Code:claude-opus-5-5
a0c0223 to
d8469d3
Compare
Summary
Reject unsupported keyword arguments before native argument binding and
conversion, matching CPython's dispatch order. For example,
id(obj=1)nowraises
TypeError: id() takes no keyword argumentsinstead of a positionalargument binding error.
The existing
id(1, **{'foo': 1})doctest intest_extcallnow passes, soremove its TODO and EXPECTED_FAILURE marker without changing the call or
expected output.
Details
KeywordDispatchpolicies at registration time fromFromArgs::PARAMSfor macro-registered functions and methods, includingnested parameter metadata, without explicit
no_keywordsannotations.This policy is independent of flags inferred from Rust signatures.
FuncArgsfunctionssuch as
minandmaxretain validation in their function bodies.method descriptors first validate positional self presence and type.
Empty keyword dictionaries remain accepted.
ml_flags, including the unqualifieddiagnostic name used by legacy
METH_VARARGSfunctions.keyword_dispatchargument toContext::new_method_def.SimpleItemMetafor function attributes and remove the redundantFunctionItemMetatype.extra_tests/snippets/syntax_function_args.py, plus a C-API regressionfor keyword rejection before NOARGS arity validation.
Automatic keyword dispatch applies to macro-registered functions and
methods. Constructors, slot wrappers, and keyword-capable parsers are not
rewritten. Positional-only arity diagnostics are outside this change.
Context::new_method_defnow takes(name, callable, flags, doc, keyword_dispatch); embedding callers usingthe previous signature need to supply the new policy argument. Direct
PyMethodDefstruct initializers also need the new
keyword_dispatchfield.Testing
Latest validation:
temp/extcall/validation/inference-20261006-072918/.Passed:
cargo testfromcrates/capi).cargo check -p rustpython-vm --no-default-features.syntax_function_args.pyonRustPython and through the CPython/RustPython snippet harness.
test_call,test_extcall,test_builtin, andtest_listvia the releaseinterpreter: 402 tests run, 198 skipped; all four modules passed.
cargo fmt --all --checkandgit diff --check.The full
extra_testspytest run reported 477 passed, 7 failed. Sixfailures were on CPython (
builtin_memoryview,builtin_signature,stdlib_atexit,stdlib_gc,stdlib_struct, andstdlib_unicode_shared).The RustPython failure was
stdlib_sqlite:_sqlite3was unavailable inthe default build. The consolidated keyword regressions passed on both interpreters.
AI assistance: Codex:GPT-6
Summary by CodeRabbit
self.