-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Fix genericalias parameters #5841
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Warning Rate limit exceeded@youknowone has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 18 minutes and 5 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (5)
""" WalkthroughThis update removes expected failure decorators from several Python test methods, rewrites generic alias parameter handling in Rust to support default parameters and tuple expansion, and adds a new constant for Changes
Sequence Diagram(s)sequenceDiagram
participant PythonTest as Python Test
participant RustVM as Rust VM (genericalias.rs)
participant Context as VM Context
PythonTest->>RustVM: Substitute generic alias parameters
RustVM->>RustVM: Check for __typing_subst__ attribute
alt Has __typing_subst__
RustVM->>RustVM: Call __typing_subst__ on argument
else No __typing_subst__
RustVM->>RustVM: Use subs_tvars (with tuple expansion if needed)
end
RustVM->>Context: Access __typing_subst__ constant
RustVM-->>PythonTest: Return substituted parameters tuple
Suggested reviewers
Poem
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
vm/src/builtins/genericalias.rs (3)
217-257
: Consider optimizing vector resizing for better performance.The current implementation resizes the vector multiple times during execution, which could lead to unnecessary allocations. Consider collecting parameters into a temporary structure first or using a more efficient growth strategy.
You could optimize by first collecting all parameters and then creating the final vector:
pub(crate) fn make_parameters(args: &Py<PyTuple>, vm: &VirtualMachine) -> PyTupleRef { - let mut parameters: Vec<PyObjectRef> = Vec::with_capacity(args.len()); - let mut iparam = 0; + let mut seen = std::collections::HashSet::new(); + let mut parameters = Vec::new(); for arg in args { // We don't want __parameters__ descriptor of a bare Python class. if arg.class().is(vm.ctx.types.type_type) { continue; } // Check for __typing_subst__ attribute (like CPython) if arg.get_attr(identifier!(vm, __typing_subst__), vm).is_ok() { - // Use tuple_add equivalent logic - if tuple_index_vec(¶meters, arg).is_none() { - if iparam >= parameters.len() { - parameters.resize(iparam + 1, vm.ctx.none()); - } - parameters[iparam] = arg.clone(); - iparam += 1; + if seen.insert(arg.as_object().id()) { + parameters.push(arg.clone()); } } else if let Ok(subparams) = arg.get_attr(identifier!(vm, __parameters__), vm) { if let Ok(sub_params) = subparams.try_to_ref::<PyTuple>(vm) { - let len2 = sub_params.len(); - // Resize if needed - if iparam + len2 > parameters.len() { - parameters.resize(iparam + len2, vm.ctx.none()); - } for sub_param in sub_params { - // Use tuple_add equivalent logic - if tuple_index_vec(¶meters[..iparam], sub_param).is_none() { - if iparam >= parameters.len() { - parameters.resize(iparam + 1, vm.ctx.none()); - } - parameters[iparam] = sub_param.clone(); - iparam += 1; + if seen.insert(sub_param.as_object().id()) { + parameters.push(sub_param.clone()); } } } } } - // Resize to actual size - parameters.truncate(iparam); PyTuple::new_ref(parameters, &vm.ctx) }
261-269
: Refactor to avoid code duplication betweentuple_index
andtuple_index_vec
.Both functions perform the same operation of finding an item by identity. Consider creating a generic helper function.
#[inline] -fn tuple_index(tuple: &PyTupleRef, item: &PyObjectRef) -> Option<usize> { - tuple.iter().position(|element| element.is(item)) +fn find_by_identity<'a>(iter: impl Iterator<Item = &'a PyObjectRef>, item: &PyObjectRef) -> Option<usize> { + iter.position(|element| element.is(item)) } #[inline] -fn tuple_index_vec(vec: &[PyObjectRef], item: &PyObjectRef) -> Option<usize> { - vec.iter().position(|element| element.is(item)) +fn tuple_index(tuple: &PyTupleRef, item: &PyObjectRef) -> Option<usize> { + find_by_identity(tuple.iter(), item) +} + +#[inline] +fn tuple_index_vec(vec: &[PyObjectRef], item: &PyObjectRef) -> Option<usize> { + find_by_identity(vec.iter(), item) }
375-392
: Clarify error message for unsupported default values.The comment indicates that CPython doesn't support default values in this context, but the error message doesn't make this clear to users.
} else { // CPython doesn't support default values in this context return Err(vm.new_type_error(format!( - "No argument provided for parameter at index {}", - idx + "No argument provided for parameter '{}' at index {} (default values not supported with __typing_subst__)", + arg.repr(vm).unwrap_or_else(|_| "?".to_string()), + idx ))); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
Lib/test/test_genericalias.py
(0 hunks)vm/src/builtins/genericalias.rs
(4 hunks)vm/src/vm/context.rs
(1 hunks)
💤 Files with no reviewable changes (1)
- Lib/test/test_genericalias.py
🧰 Additional context used
🧠 Learnings (1)
vm/src/builtins/genericalias.rs (2)
Learnt from: CR
PR: RustPython/RustPython#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-06-26T12:52:11.109Z
Learning: Use the macro system (such as 'pyclass', 'pymodule', 'pyfunction') when implementing Python functionality in Rust for RustPython.
Learnt from: CR
PR: RustPython/RustPython#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-06-26T12:52:11.109Z
Learning: When implementing a Python module in Rust for RustPython, use the #[pymodule] attribute and expose functions and classes using #[pyfunction], #[pyclass], and #[pymethod] as appropriate.
⏰ Context from checks skipped due to timeout of 90000ms (11)
- GitHub Check: Run tests under miri
- GitHub Check: Check Rust code with rustfmt and clippy
- GitHub Check: Check the WASM package and demo
- GitHub Check: Run snippets and cpython tests (macos-latest)
- GitHub Check: Run snippets and cpython tests (windows-latest)
- GitHub Check: Run snippets and cpython tests (ubuntu-latest)
- GitHub Check: Run snippets and cpython tests on wasm-wasi
- GitHub Check: Run rust tests (ubuntu-latest)
- GitHub Check: Run rust tests (windows-latest)
- GitHub Check: Run rust tests (macos-latest)
- GitHub Check: Ensure compilation on various targets
🔇 Additional comments (2)
vm/src/vm/context.rs (1)
226-226
: LGTM!The addition of
__typing_subst__
constant follows the established pattern and is necessary for the enhanced generic alias parameter handling.vm/src/builtins/genericalias.rs (1)
284-309
: TypeVarTuple handling looks correct!The implementation properly handles TypeVarTuple expansion by checking for the iterator slot and expanding tuple elements when appropriate. This aligns with CPython's behavior for type parameter substitution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
vm/src/builtins/genericalias.rs (1)
217-234
: Consider simplifying the vector management logic.The index-based insertion with
resize
calls could be simplified. The current approach works but may be harder to maintain.Consider this cleaner approach:
- let mut parameters: Vec<PyObjectRef> = Vec::with_capacity(args.len()); - let mut iparam = 0; - for arg in args { // We don't want __parameters__ descriptor of a bare Python class. if arg.class().is(vm.ctx.types.type_type) { continue; } // Check for __typing_subst__ attribute (like CPython) if arg.get_attr(identifier!(vm, __typing_subst__), vm).is_ok() { - // Use tuple_add equivalent logic - if tuple_index_vec(¶meters, arg).is_none() { - if iparam >= parameters.len() { - parameters.resize(iparam + 1, vm.ctx.none()); - } - parameters[iparam] = arg.clone(); - iparam += 1; + if !parameters.contains(arg) { + parameters.push(arg.clone()); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
Lib/test/test_dataclasses.py
(0 hunks)Lib/test/test_genericalias.py
(0 hunks)Lib/test/test_types.py
(0 hunks)vm/src/builtins/genericalias.rs
(4 hunks)vm/src/vm/context.rs
(1 hunks)
💤 Files with no reviewable changes (3)
- Lib/test/test_genericalias.py
- Lib/test/test_types.py
- Lib/test/test_dataclasses.py
🚧 Files skipped from review as they are similar to previous changes (1)
- vm/src/vm/context.rs
🧰 Additional context used
🧠 Learnings (1)
vm/src/builtins/genericalias.rs (2)
Learnt from: CR
PR: RustPython/RustPython#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-06-26T12:52:11.109Z
Learning: Use the macro system (such as 'pyclass', 'pymodule', 'pyfunction') when implementing Python functionality in Rust for RustPython.
Learnt from: CR
PR: RustPython/RustPython#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-06-26T12:52:11.109Z
Learning: When implementing a Python module in Rust for RustPython, use the #[pymodule] attribute and expose functions and classes using #[pyfunction], #[pyclass], and #[pymethod] as appropriate.
⏰ Context from checks skipped due to timeout of 90000ms (11)
- GitHub Check: Run rust tests (ubuntu-latest)
- GitHub Check: Run tests under miri
- GitHub Check: Run snippets and cpython tests on wasm-wasi
- GitHub Check: Run snippets and cpython tests (macos-latest)
- GitHub Check: Run rust tests (macos-latest)
- GitHub Check: Check the WASM package and demo
- GitHub Check: Check Rust code with rustfmt and clippy
- GitHub Check: Run snippets and cpython tests (ubuntu-latest)
- GitHub Check: Run rust tests (windows-latest)
- GitHub Check: Ensure compilation on various targets
- GitHub Check: Run snippets and cpython tests (windows-latest)
🔇 Additional comments (5)
vm/src/builtins/genericalias.rs (5)
266-269
: LGTM! Clean helper function implementation.The
tuple_index_vec
function correctly uses identity comparison withis()
which is appropriate for Python object references.
256-258
: Good optimization with truncate.Using
truncate
instead ofshrink_to_fit
is more appropriate here since we know the exact final size needed.
235-254
: Verify the nested parameter expansion logic.The recursive parameter expansion with index management is complex and could be error-prone. The logic appears correct but warrants careful testing.
#!/bin/bash # Search for tests that cover nested parameter expansion scenarios rg -A 10 -B 5 "__parameters__.*__parameters__" --type py
284-314
: Verify TypeVarTuple detection mechanism.The TypeVarTuple detection using
param.class().slots.iter.load().is_some()
is interesting but may not be the most reliable way to identify TypeVarTuple objects.#!/bin/bash # Search for TypeVarTuple usage patterns and tests rg -A 5 -B 5 "TypeVarTuple" --type py ast-grep --pattern 'class TypeVarTuple($_) { $$$ }'
338-370
: ```shell
#!/bin/bash
sed -n '330,370p' vm/src/builtins/genericalias.rs</details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
vm/src/builtins/genericalias.rs
Outdated
for arg in args.iter() { | ||
// Check for __typing_subst__ attribute directly (like CPython) | ||
if let Ok(subst) = arg.get_attr(identifier!(vm, __typing_subst__), vm) { | ||
let idx = tuple_index(¶meters, arg).unwrap(); | ||
if idx < num_items { | ||
// Call __typing_subst__ with the argument | ||
let substituted = subst.call((arg_items[idx].clone(),), vm)?; | ||
new_args.push(substituted); | ||
} else { | ||
subs_tvars(arg.clone(), ¶meters, arg_items, vm) | ||
// CPython doesn't support default values in this context | ||
return Err(vm.new_type_error(format!( | ||
"No argument provided for parameter at index {}", | ||
idx | ||
))); | ||
} | ||
}) | ||
.collect::<PyResult<Vec<_>>>()?; | ||
} else { | ||
new_args.push(subs_tvars(arg.clone(), ¶meters, arg_items, vm)?); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential issue with missing parameter handling.
The error handling for missing parameters when using __typing_subst__
may be too strict. CPython might handle this case differently, particularly with default values.
} else {
- // CPython doesn't support default values in this context
- return Err(vm.new_type_error(format!(
- "No argument provided for parameter at index {}",
- idx
- )));
+ // Use the parameter itself as default (CPython behavior)
+ new_args.push(arg.clone());
}
This needs verification against CPython's actual behavior in similar scenarios.
📝 Committable suggestion
‼️ 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.
for arg in args.iter() { | |
// Check for __typing_subst__ attribute directly (like CPython) | |
if let Ok(subst) = arg.get_attr(identifier!(vm, __typing_subst__), vm) { | |
let idx = tuple_index(¶meters, arg).unwrap(); | |
if idx < num_items { | |
// Call __typing_subst__ with the argument | |
let substituted = subst.call((arg_items[idx].clone(),), vm)?; | |
new_args.push(substituted); | |
} else { | |
subs_tvars(arg.clone(), ¶meters, arg_items, vm) | |
// CPython doesn't support default values in this context | |
return Err(vm.new_type_error(format!( | |
"No argument provided for parameter at index {}", | |
idx | |
))); | |
} | |
}) | |
.collect::<PyResult<Vec<_>>>()?; | |
} else { | |
new_args.push(subs_tvars(arg.clone(), ¶meters, arg_items, vm)?); | |
} | |
} | |
for arg in args.iter() { | |
// Check for __typing_subst__ attribute directly (like CPython) | |
if let Ok(subst) = arg.get_attr(identifier!(vm, __typing_subst__), vm) { | |
let idx = tuple_index(¶meters, arg).unwrap(); | |
if idx < num_items { | |
// Call __typing_subst__ with the argument | |
let substituted = subst.call((arg_items[idx].clone(),), vm)?; | |
new_args.push(substituted); | |
} else { | |
// Use the parameter itself as default (CPython behavior) | |
new_args.push(arg.clone()); | |
} | |
} else { | |
new_args.push(subs_tvars(arg.clone(), ¶meters, arg_items, vm)?); | |
} | |
} |
🤖 Prompt for AI Agents
In vm/src/builtins/genericalias.rs between lines 374 and 392, the current code
returns a type error if an argument index exceeds the number of items, assuming
no default values are supported like CPython. To address the potential issue,
verify CPython's behavior regarding default parameters with __typing_subst__ and
adjust the error handling accordingly. If CPython allows default values or
handles missing parameters differently, modify the code to support default
values or skip substitution for those parameters instead of returning an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
python3.13 -c "
import typing
from typing import TypeVar, Generic
# Create a test case that would trigger the missing parameter scenario
T = TypeVar('T')
U = TypeVar('U', bound=str)
class MyGeneric(Generic[T, U]):
pass
# Test various substitution scenarios
try:
# This should help us understand how CPython handles missing parameters
result = MyGeneric[int] # Missing second parameter
print('CPython allows partial substitution:', result)
except Exception as e:
print('CPython error:', e)
"
CPython error: Too few arguments for <class '__main__.MyGeneric'>; actual 1, expected at least 2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@youknowone Thank you for providing that test! Your output clearly shows that CPython raises an error with the format "Too few arguments for...; actual X, expected at least Y" when there are insufficient arguments for a generic type.
Looking at the current implementation in the diff, I can see that the RustPython code actually handles this correctly:
if num_items < min_required {
return Err(vm.new_type_error(format!(
"Too few arguments for {}; actual {}, expected at least {}",
repr(vm)?,
num_items,
min_required
)));
}
This matches CPython's behavior exactly. My original suggestion was incorrect - I was concerned that the error handling for the __typing_subst__
case might be too strict, but your test demonstrates that CPython does indeed raise errors for insufficient arguments.
The current implementation correctly:
- Validates argument counts upfront, considering parameters with defaults
- Uses error messages that match CPython's format
- Only reaches the "No argument provided for parameter at index" error in cases that should be unreachable if the earlier validation works properly
I retract my original suggestion. The current implementation appears to align properly with CPython's behavior.
🐰💭
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
vm/src/builtins/genericalias.rs (1)
374-392
: This still needs verification against CPython behavior.The error handling for missing parameters when using
__typing_subst__
may still be too strict compared to CPython's actual behavior, as noted in the previous review.The previous review comment about this exact issue remains valid. Please verify CPython's behavior for this scenario:
#!/bin/bash # Verify CPython's behavior with __typing_subst__ and missing parameters python3 -c " import typing from typing import TypeVar, Generic # Create a test case that would trigger the missing parameter scenario T = TypeVar('T') U = TypeVar('U', bound=str) class MyGeneric(Generic[T, U]): pass # Test various substitution scenarios try: # This should help us understand how CPython handles missing parameters result = MyGeneric[int] # Missing second parameter print('CPython allows partial substitution:', result) except Exception as e: print('CPython error:', e) "
🧹 Nitpick comments (2)
vm/src/builtins/genericalias.rs (2)
220-264
: Consider simplifying the complex parameter handling logic.The rewritten
make_parameters
function introduces significant complexity with vector resizing, index tracking, and deduplication logic. While the approach appears to align with CPython's behavior, the implementation could be error-prone.Consider these potential improvements:
- Simplify vector management: Instead of frequent resizing, use a
Vec
that grows naturally and truncate at the end.- Optimize deduplication: Consider using a
HashSet
for O(1) duplicate detection instead of linear search viatuple_index
.- Add comprehensive comments: The complex logic would benefit from detailed comments explaining the CPython behavior being mimicked.
pub(crate) fn make_parameters(args: &Py<PyTuple>, vm: &VirtualMachine) -> PyTupleRef { - let mut parameters: Vec<PyObjectRef> = Vec::with_capacity(args.len()); - let mut iparam = 0; + let mut parameters: Vec<PyObjectRef> = Vec::new(); + let mut seen: std::collections::HashSet<*const PyObject> = std::collections::HashSet::new(); for arg in args { // We don't want __parameters__ descriptor of a bare Python class. if arg.class().is(vm.ctx.types.type_type) { continue; } // Check for __typing_subst__ attribute (like CPython) if arg.get_attr(identifier!(vm, __typing_subst__), vm).is_ok() { - // Use tuple_add equivalent logic - if tuple_index(¶meters, arg).is_none() { - if iparam >= parameters.len() { - parameters.resize(iparam + 1, vm.ctx.none()); - } - parameters[iparam] = arg.clone(); - iparam += 1; - } + if seen.insert(arg.as_ptr()) { + parameters.push(arg.clone()); + } } else if let Ok(subparams) = arg.get_attr(identifier!(vm, __parameters__), vm) { // ... similar simplification for sub_params handling } } - // Resize to actual size - parameters.truncate(iparam); PyTuple::new_ref(parameters, &vm.ctx) }
284-308
: Good TypeVarTuple handling, but add clarifying comments.The logic for handling TypeVarTuple expansion is correct, but the implementation would benefit from clearer comments explaining the behavior.
for arg in sub_params.iter() { if let Some(idx) = tuple_index(params.as_slice(), arg) { let param = ¶ms[idx]; let substituted_arg = &arg_items[idx]; - // Check if this is a TypeVarTuple (has tp_iter) + // TypeVarTuple handling: Check if this parameter has iteration support + // and the substituted argument is a tuple that should be expanded if param.class().slots.iter.load().is_some() && substituted_arg.try_to_ref::<PyTuple>(vm).is_ok() { - // TypeVarTuple case - extend with tuple elements + // Expand tuple elements for TypeVarTuple substitution if let Ok(tuple) = substituted_arg.try_to_ref::<PyTuple>(vm) { for elem in tuple.iter() { sub_args.push(elem.clone()); } continue; } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
Lib/test/test_typing.py
(1 hunks)vm/src/builtins/genericalias.rs
(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- Lib/test/test_typing.py
🧰 Additional context used
🧠 Learnings (1)
vm/src/builtins/genericalias.rs (1)
Learnt from: CR
PR: RustPython/RustPython#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-06-26T12:52:11.109Z
Learning: Use the macro system (such as 'pyclass', 'pymodule', 'pyfunction') when implementing Python functionality in Rust for RustPython.
⏰ Context from checks skipped due to timeout of 90000ms (11)
- GitHub Check: Run rust tests (windows-latest)
- GitHub Check: Run rust tests (macos-latest)
- GitHub Check: Run rust tests (ubuntu-latest)
- GitHub Check: Run snippets and cpython tests on wasm-wasi
- GitHub Check: Run snippets and cpython tests (macos-latest)
- GitHub Check: Run snippets and cpython tests (ubuntu-latest)
- GitHub Check: Run snippets and cpython tests (windows-latest)
- GitHub Check: Ensure compilation on various targets
- GitHub Check: Check the WASM package and demo
- GitHub Check: Check Rust code with rustfmt and clippy
- GitHub Check: Run tests under miri
🔇 Additional comments (3)
vm/src/builtins/genericalias.rs (3)
20-34
: LGTM: Appropriate expansion of special attributes.The addition of
__class__
,__bases__
,__unpacked__
, and__typing_unpacked_tuple_args__
to the attribute exceptions list is appropriate for comprehensive generic alias support.
266-269
: LGTM: Clean utility function.The
tuple_index
function is a straightforward utility that correctly uses identity comparison for Python objects.
338-370
: Excellent default parameter handling implementation.The logic for handling default parameters is well-implemented with proper validation and informative error messages. The approach of counting defaults from the end backwards aligns with Python's parameter handling conventions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
vm/src/stdlib/typing.rs (1)
937-959
: Consider caching the typing module import for performance.The helper function is well-structured and follows good practices for calling typing module functions. However, it imports the typing module on every call.
Consider caching the typing module reference if this function is called frequently:
fn call_typing_args_kwargs( name: &'static str, cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine, ) -> PyResult { - let typing = vm.import("typing", 0)?; + // Consider caching if performance becomes an issue + let typing = vm.import("typing", 0)?; let func = typing.get_attr(name, vm)?; // Prepare arguments: (cls, *args) let mut call_args = vec![cls.into()]; call_args.extend(args.args); // Call with prepared args and original kwargs let func_args = FuncArgs { args: call_args, kwargs: args.kwargs, }; func.call(func_args, vm) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
Lib/test/test_functools.py
(0 hunks)Lib/test/test_genericalias.py
(0 hunks)Lib/test/test_typing.py
(2 hunks)vm/src/protocol/object.rs
(1 hunks)vm/src/stdlib/typing.rs
(5 hunks)
💤 Files with no reviewable changes (2)
- Lib/test/test_functools.py
- Lib/test/test_genericalias.py
✅ Files skipped from review due to trivial changes (2)
- vm/src/protocol/object.rs
- Lib/test/test_typing.py
🧰 Additional context used
🧠 Learnings (1)
vm/src/stdlib/typing.rs (2)
Learnt from: CR
PR: RustPython/RustPython#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-06-26T12:52:11.109Z
Learning: Use the macro system (such as 'pyclass', 'pymodule', 'pyfunction') when implementing Python functionality in Rust for RustPython.
Learnt from: CR
PR: RustPython/RustPython#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-06-26T12:52:11.109Z
Learning: When implementing a Python module in Rust for RustPython, use the #[pymodule] attribute and expose functions and classes using #[pyfunction], #[pyclass], and #[pymethod] as appropriate.
⏰ Context from checks skipped due to timeout of 90000ms (11)
- GitHub Check: Run rust tests (windows-latest)
- GitHub Check: Check the WASM package and demo
- GitHub Check: Run snippets and cpython tests (windows-latest)
- GitHub Check: Run rust tests (macos-latest)
- GitHub Check: Run rust tests (ubuntu-latest)
- GitHub Check: Run snippets and cpython tests on wasm-wasi
- GitHub Check: Run tests under miri
- GitHub Check: Check Rust code with rustfmt and clippy
- GitHub Check: Run snippets and cpython tests (ubuntu-latest)
- GitHub Check: Ensure compilation on various targets
- GitHub Check: Run snippets and cpython tests (macos-latest)
🔇 Additional comments (5)
vm/src/stdlib/typing.rs (5)
16-17
: LGTM! Clean import additions for new functionality.The added imports (
PyObjectRef
,PyRef
,PyTupleRef
, andIterable
) are necessary for the newIterable
trait implementation and properly follow the existing import organization.Also applies to: 20-20
610-610
: Good addition of Iterable trait to TypeVarTuple.Adding
Iterable
to the trait list enables iteration support forTypeVarTuple
, which aligns with CPython's behavior for handling variadic generics.
670-682
: Well-implemented Iterable trait for TypeVarTuple.The implementation correctly handles the unpacking behavior by:
- Importing the typing module to access
Unpack
- Creating
Unpack[self]
to represent the unpacked tuple- Returning a list iterator containing the unpacked element
This aligns with CPython's behavior for
Generic[*Ts]
as mentioned in the comment.
971-978
: Excellent refactor to delegate to Python typing module.The change from directly creating
PyGenericAlias
to calling_generic_class_getitem
via the helper function aligns with CPython's behavior and centralizes the logic in the Python typing module.
980-983
: Good delegation to Python typing module for subclass initialization.The refactor to use
call_typing_args_kwargs
for_generic_init_subclass
is consistent with theclass_getitem
changes and properly delegates complex logic to the Python side.
Summary by CodeRabbit
Bug Fixes
TypeVarTuple
to match standard Python unpacking behavior.Tests
Callable
andParamSpec
.functools.singledispatch
to pass as expected.Chores
__typing_subst__
attribute to align substitution logic with standard Python behavior.__typing_subst__
for improved VM attribute handling.