Skip to content

Conversation

@youknowone
Copy link
Member

@youknowone youknowone commented Nov 9, 2025

Summary by CodeRabbit

  • Refactor
    • Updated internal code to use direct type references instead of string literals for base class specifications across class and exception declarations, improving type safety and consistency in the codebase without affecting user-facing functionality.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 9, 2025

Walkthrough

The pull request refactors base class specification across PyO3 attribute macros from string literals to direct type paths. Core infrastructure in derive-impl converts base parameter handling from Option<String> to Option<syn::Path>, and this change propagates through exception, class, and type declarations throughout the codebase.

Changes

Cohort / File(s) Summary
Core derive infrastructure
derive-impl/src/pyclass.rs, derive-impl/src/util.rs
Modified generate_class_def() function signature to accept base: Option<syn::Path> instead of Option<String>. Added _optional_path() method to parse path values from metadata. Updated ClassItemMeta::base() to return Option<syn::Path> and delegate to _optional_path().
Documentation update
derive/src/lib.rs
Updated pyclass macro example documentation: changed base argument from string literal "BaseClass" to identifier BaseClass.
SSL exceptions
stdlib/src/ssl.rs
Converted seven exception declarations (PySslError, PySslCertVerificationError, PySslZeroReturnError, PySslWantReadError, PySslWantWriteError, PySslSyscallError, PySslEOFError) to use direct type references for base parameter instead of string literals.
Core exception definitions
vm/src/exceptions.rs
Systematically updated all ~50 exception type declarations across base exceptions, arithmetic errors, lookup errors, OS errors, connection errors, runtime errors, syntax errors, type errors, unicode errors, and warnings to specify base classes as type paths rather than strings.
Builtin type declarations
vm/src/builtins/bool.rs, vm/src/builtins/builtin_func.rs
Updated PyBool and PyNativeMethod pyclass declarations to use direct type references (PyInt, PyNativeFunction) for base parameter.
AST node definitions
vm/src/stdlib/ast/pyast.rs
Updated ~80+ AST node class declarations (Module, Expression, FunctionDef, ClassDef, and all statement/expression/operator/pattern/type-parameter variants) to use direct type references (NodeMod, NodeStmt, NodeExpr, NodePattern, etc.) instead of string literals.
ctypes class hierarchy
vm/src/stdlib/ctypes/array.rs, vm/src/stdlib/ctypes/base.rs, vm/src/stdlib/ctypes/function.rs, vm/src/stdlib/ctypes/structure.rs, vm/src/stdlib/ctypes/union.rs
Updated PyCArrayType, PyCArray, PyCSimpleType, _SimpleCData, PyCFuncPtr, PyCStructure, and PyCUnion declarations to use direct type references for base inheritance (PyType, PyCData).
IO type hierarchy
vm/src/stdlib/io.rs
Updated ~12 IO-related classes (_RawIOBase, _BufferedIOBase, _TextIOBase, BufferedReader, BufferedWriter, BufferedRandom, BufferedRWPair, TextIOWrapper, StringIO, BytesIO, FileIO) to specify base classes as direct type paths instead of strings.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Specific areas requiring attention:

  • derive-impl changes (critical path): Verify that _optional_path() correctly parses type paths from metadata and that the Path type is properly handled through macro expansion without string conversion artifacts.
  • Widespread attribute updates: Confirm that all base type references in macro invocations are valid identifiers in scope (e.g., PyBaseException, NodeStmt, _IOBase). Spot-check a few files from different cohorts to ensure consistency.
  • ctypes and IO hierarchies: The large count of changes in these files increases the risk of missed conversions or inconsistent type references—verify completeness in vm/src/stdlib/io.rs and vm/src/stdlib/ctypes/*.
  • AST node hierarchy: Given the large number of node types affected, ensure no base references were overlooked and that the macro invocation pattern is uniform across all node variants.

Suggested reviewers

  • coolreader18
  • ShaharNaveh
  • arihant2math

Poem

🐰 No more strings to quote and parse,
Type paths shine like morning glass,
Derive now speaks in native tongue,
Inheritance—a Rust-y song!
From base = "Foo" to base = Foo,
The macros dance the whole codebase through!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: converting #[pyclass(base=...)] attributes from string literals to direct type paths across the entire codebase.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@youknowone youknowone marked this pull request as ready for review November 9, 2025 12:51
Copy link
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: 1

📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ed9a61d and 41d497c.

📒 Files selected for processing (14)
  • derive-impl/src/pyclass.rs (1 hunks)
  • derive-impl/src/util.rs (2 hunks)
  • derive/src/lib.rs (1 hunks)
  • stdlib/src/ssl.rs (7 hunks)
  • vm/src/builtins/bool.rs (1 hunks)
  • vm/src/builtins/builtin_func.rs (1 hunks)
  • vm/src/exceptions.rs (13 hunks)
  • vm/src/stdlib/ast/pyast.rs (1 hunks)
  • vm/src/stdlib/ctypes/array.rs (2 hunks)
  • vm/src/stdlib/ctypes/base.rs (2 hunks)
  • vm/src/stdlib/ctypes/function.rs (1 hunks)
  • vm/src/stdlib/ctypes/structure.rs (1 hunks)
  • vm/src/stdlib/ctypes/union.rs (1 hunks)
  • vm/src/stdlib/io.rs (11 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.rs: Format Rust code with the default rustfmt style (run cargo fmt)
Run clippy and fix any warnings or lints introduced by your changes
Follow Rust best practices for error handling and memory management

Files:

  • vm/src/builtins/builtin_func.rs
  • vm/src/builtins/bool.rs
  • derive-impl/src/util.rs
  • vm/src/stdlib/ctypes/array.rs
  • vm/src/stdlib/ctypes/structure.rs
  • derive-impl/src/pyclass.rs
  • stdlib/src/ssl.rs
  • vm/src/stdlib/ctypes/function.rs
  • derive/src/lib.rs
  • vm/src/stdlib/ctypes/base.rs
  • vm/src/stdlib/ctypes/union.rs
  • vm/src/exceptions.rs
  • vm/src/stdlib/io.rs
  • vm/src/stdlib/ast/pyast.rs
{vm,stdlib}/**/*.rs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use RustPython macros (pyclass, pymodule, pyfunction, etc.) when implementing Python functionality in Rust

Files:

  • vm/src/builtins/builtin_func.rs
  • vm/src/builtins/bool.rs
  • vm/src/stdlib/ctypes/array.rs
  • vm/src/stdlib/ctypes/structure.rs
  • stdlib/src/ssl.rs
  • vm/src/stdlib/ctypes/function.rs
  • vm/src/stdlib/ctypes/base.rs
  • vm/src/stdlib/ctypes/union.rs
  • vm/src/exceptions.rs
  • vm/src/stdlib/io.rs
  • vm/src/stdlib/ast/pyast.rs
🧠 Learnings (3)
📚 Learning: 2025-09-11T05:06:59.971Z
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-11T05:06:59.971Z
Learning: Applies to {vm,stdlib}/**/*.rs : Use RustPython macros (`pyclass`, `pymodule`, `pyfunction`, etc.) when implementing Python functionality in Rust

Applied to files:

  • vm/src/builtins/builtin_func.rs
  • vm/src/builtins/bool.rs
  • vm/src/stdlib/ctypes/array.rs
  • vm/src/stdlib/ctypes/structure.rs
  • vm/src/stdlib/ctypes/function.rs
  • derive/src/lib.rs
  • vm/src/stdlib/ctypes/base.rs
  • vm/src/stdlib/ctypes/union.rs
  • vm/src/exceptions.rs
  • vm/src/stdlib/io.rs
  • vm/src/stdlib/ast/pyast.rs
📚 Learning: 2025-09-11T05:06:59.971Z
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-11T05:06:59.971Z
Learning: Applies to Lib/**/*.py : Minimize modifications to CPython standard library files; only make minimal changes to work around RustPython limitations

Applied to files:

  • vm/src/builtins/builtin_func.rs
  • vm/src/stdlib/ctypes/array.rs
  • vm/src/stdlib/ctypes/structure.rs
  • stdlib/src/ssl.rs
  • vm/src/stdlib/ctypes/function.rs
  • derive/src/lib.rs
  • vm/src/stdlib/ctypes/base.rs
  • vm/src/exceptions.rs
  • vm/src/stdlib/io.rs
📚 Learning: 2025-09-11T05:06:59.971Z
Learnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-11T05:06:59.971Z
Learning: In most cases, avoid editing Python code; prefer fixing bugs via Rust changes

Applied to files:

  • vm/src/exceptions.rs
🧬 Code graph analysis (12)
vm/src/builtins/builtin_func.rs (2)
derive/src/lib.rs (1)
  • pyclass (124-128)
derive-impl/src/util.rs (2)
  • module (428-457)
  • base (416-418)
vm/src/builtins/bool.rs (2)
derive/src/lib.rs (1)
  • pyclass (124-128)
derive-impl/src/util.rs (2)
  • module (428-457)
  • base (416-418)
vm/src/stdlib/ctypes/array.rs (2)
derive/src/lib.rs (1)
  • pyclass (124-128)
derive-impl/src/util.rs (2)
  • base (416-418)
  • module (428-457)
vm/src/stdlib/ctypes/structure.rs (2)
derive/src/lib.rs (1)
  • pyclass (124-128)
derive-impl/src/util.rs (2)
  • module (428-457)
  • base (416-418)
derive-impl/src/pyclass.rs (1)
derive-impl/src/util.rs (2)
  • base (416-418)
  • syn (202-202)
stdlib/src/ssl.rs (3)
derive/src/lib.rs (1)
  • pyexception (139-143)
derive-impl/src/lib.rs (1)
  • pyexception (50-56)
derive-impl/src/util.rs (1)
  • base (416-418)
vm/src/stdlib/ctypes/function.rs (2)
derive/src/lib.rs (1)
  • pyclass (124-128)
derive-impl/src/util.rs (2)
  • module (428-457)
  • base (416-418)
vm/src/stdlib/ctypes/base.rs (1)
derive-impl/src/util.rs (2)
  • module (428-457)
  • base (416-418)
vm/src/stdlib/ctypes/union.rs (1)
derive-impl/src/util.rs (1)
  • base (416-418)
vm/src/exceptions.rs (3)
derive/src/lib.rs (1)
  • pyexception (139-143)
derive-impl/src/lib.rs (1)
  • pyexception (50-56)
derive-impl/src/util.rs (1)
  • base (416-418)
vm/src/stdlib/io.rs (3)
derive/src/lib.rs (1)
  • pyclass (124-128)
derive-impl/src/lib.rs (1)
  • pyclass (42-48)
derive-impl/src/util.rs (2)
  • base (416-418)
  • module (428-457)
vm/src/stdlib/ast/pyast.rs (1)
derive-impl/src/util.rs (2)
  • module (428-457)
  • base (416-418)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Run rust tests (windows-latest)
  • GitHub Check: Run snippets and cpython tests (windows-latest)
  • GitHub Check: Run snippets and cpython tests (macos-latest)
  • GitHub Check: Ensure compilation on various targets
  • GitHub Check: Run snippets and cpython tests (ubuntu-latest)
  • GitHub Check: Run rust tests (macos-latest)
  • GitHub Check: Check Rust code with rustfmt and clippy
🔇 Additional comments (14)
derive/src/lib.rs (1)

37-37: Documentation example correctly reflects the refactored syntax.

The update to use base = BaseClass (type path) instead of the previous string literal syntax aligns with the PR's refactoring of base class specifications across the codebase. The documentation example now accurately guides users on the correct macro usage.

stdlib/src/ssl.rs (1)

249-249: LGTM! Clean refactoring from string literals to type paths.

The updated #[pyexception] attributes now use direct type paths (PyOSError, PySslError) instead of string literals. This improves type safety and aligns with the PR's objective to refactor base class specification across PyO3 macros. All referenced types are properly in scope, and the exception hierarchy is preserved correctly.

Also applies to: 272-272, 281-281, 290-290, 299-299, 308-308, 317-317

vm/src/stdlib/ctypes/function.rs (1)

125-125: LGTM! Base class reference correctly updated.

The change from string literal to direct type path aligns with the PR objective and macro infrastructure update. The PyCData type is properly imported at line 6.

vm/src/stdlib/ctypes/union.rs (1)

4-4: LGTM! Base class reference correctly updated.

The change from string literal to direct type path is correct. The PyCData type is properly imported at line 1.

vm/src/stdlib/ctypes/structure.rs (1)

11-11: LGTM! Base class reference correctly updated.

The change from string literal to direct type path is correct. The PyCData type is properly imported at line 1.

vm/src/stdlib/ctypes/array.rs (2)

13-13: LGTM! Base class reference correctly updated.

The change from string literal to direct type path is correct. The PyType type is properly imported at line 6.


50-55: LGTM! Base class reference correctly updated and typo fixed.

The change from base = "PyData" to base = PyCData not only updates to the new type-path format but also fixes what appears to be a typo ("PyData"PyCData). The PyCData type is properly imported at line 11. This demonstrates a benefit of the type-path approach: compile-time verification catches naming errors.

vm/src/stdlib/ctypes/base.rs (2)

160-160: LGTM! Base class reference correctly updated.

The change from string literal to direct type path is correct. The PyType type is properly imported at line 2.


176-181: LGTM! Base class reference correctly updated.

The change from string literal to direct type path is correct. The PyCData type is defined in this same file (lines 151-158), so the reference is valid.

derive-impl/src/pyclass.rs (4)

307-315: LGTM: Improved type safety with syn::Path

The function signature change from Option<String> to Option<syn::Path> for the base parameter improves type safety and aligns with the parsing logic in util.rs. This eliminates the need for intermediate string-to-Ident conversions.


357-387: LGTM: Clean direct usage of Path in code generation

The base class handling correctly uses the syn::Path directly in both quote_spanned! and quote! macros, eliminating the previous string-to-Ident conversion step. The span preservation in line 361 ensures good error reporting.


426-434: LGTM: Consistent usage of new Path type

The calls to class_meta.base() and subsequent usage in generate_class_def correctly handle the new Option<syn::Path> return type, maintaining consistency throughout the codebase.


539-570: LGTM: Exception base class handling updated correctly

The exception implementation correctly retrieves and uses the base class as Option<syn::Path>. The Path is properly interpolated into the #[pyclass(...)] attribute at line 570, where it will be correctly parsed by the macro.

derive-impl/src/util.rs (1)

190-217: LGTM! Well-structured path parsing implementation.

The new _optional_path method correctly mirrors the pattern of _optional_str and provides clear error messages. The use of to_token_stream() followed by syn::parse2 is the idiomatic approach for parsing syn types.

Comment on lines +416 to 418
pub fn base(&self) -> Result<Option<syn::Path>> {
self.inner()._optional_path("base")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify all call sites handle the new Path return type.

The change from String to syn::Path aligns with the PR objective. Ensure all consumers of base() have been updated to work with syn::Path instead of String.


🏁 Script executed:

#!/bin/bash
# Description: Find all usages of ClassItemMeta::base() and ExceptionItemMeta::base() to verify they handle syn::Path

# Search for calls to .base() method that might need updates
rg -nP --type=rust -C5 '\.base\s*\(\s*\)'

# Also search for ExceptionItemMeta usage since it derefs to ClassItemMeta
rg -nP --type=rust -C3 'ExceptionItemMeta|ClassItemMeta'

Length of output: 7276


🏁 Script executed:

#!/bin/bash
# Description: Get detailed context around base() usage to see how results are handled

# Show full context for line 426 usage in pyclass.rs
echo "=== Usage 1: Around line 426 in pyclass.rs ==="
sed -n '420,445p' derive-impl/src/pyclass.rs

echo ""
echo "=== Usage 2: Around line 539 in pyclass.rs ==="
sed -n '533,570p' derive-impl/src/pyclass.rs

Length of output: 2604


🏁 Script executed:

#!/bin/bash
# Description: Find generate_class_def signature and verify type expectations

# Find generate_class_def definition
echo "=== Searching for generate_class_def definition ==="
rg -nP --type=rust -B3 'fn generate_class_def' derive-impl/src/

echo ""
echo "=== Check the full signature of generate_class_def ==="
rg -nP --type=rust -A15 'fn generate_class_def'

Length of output: 1251


🏁 Script executed:

#!/bin/bash
# Description: Verify how base_class_name is used in the quote output and check for potential issues

echo "=== Full context of base_class_name usage in quote macro ==="
sed -n '539,600p' derive-impl/src/pyclass.rs

echo ""
echo "=== Search for how this generated code might be processed ==="
rg -nP --type=rust -C3 'base_class_name'

Length of output: 3041


🏁 Script executed:

#!/bin/bash
# Description: Verify how pyclass attribute expects base parameter and check for compilation

echo "=== Check if there are test cases for pyexception with base ==="
fd -e rs test -o example | xargs rg -l 'pyexception.*base|base.*pyexception' 2>/dev/null || echo "No tests found"

echo ""
echo "=== Search for how pyclass macro processes the base attribute ==="
rg -nP --type=rust 'base.*=' derive-impl/src/util.rs | head -20

Length of output: 303


🏁 Script executed:

#!/bin/bash
# Description: Search for similar base usage patterns and quote macro handling

echo "=== Search for all quote! blocks using base parameter ==="
rg -nP --type=rust -B5 -A5 'quote!.*base|base.*quote!' derive-impl/src/

echo ""
echo "=== Check util.rs for base handling patterns ==="
sed -n '410,425p' derive-impl/src/util.rs

Length of output: 1079


Fix pyexception code path to properly handle Option<syn::Path> return type from base().

The change from String to syn::Path at line 426 is correctly handled by generate_class_def(), which expects Option<syn::Path>. However, line 570 has a critical issue: it directly interpolates the Option type into the quote macro, which will generate invalid proc macro attribute syntax like base = Some(path) or base = None.

Line 570 must follow the pattern used at lines 383-387: match on the Option<syn::Path>, unwrap when present, and provide an appropriate default when absent. Either unwrap the option explicitly before quoting (if base is required for exceptions), or conditionally quote the attribute value.

🤖 Prompt for AI Agents
In derive-impl/src/util.rs around lines 416-418 (and the pyexception emit site
near line 570), the pyexception attribute code currently interpolates an
Option<syn::Path> directly into quote causing generated attributes like `base =
Some(path)` or `base = None`; change this to match the pattern at lines
~383-387: match on the Option, map Some(path) to a token/value you will inject
(e.g. build a `base = path` TokenStream or the path token itself) and map None
to either omit the base attribute or emit an appropriate default token stream,
then use that prepared token/value in the quote invocation so the generated
attribute contains either the unwrapped path or nothing/default rather than an
Option.

@youknowone youknowone merged commit d8a4a09 into RustPython:main Nov 10, 2025
12 checks passed
@youknowone youknowone deleted the pyclass-base branch November 10, 2025 00:47
This was referenced Nov 29, 2025
@coderabbitai coderabbitai bot mentioned this pull request Dec 9, 2025
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