8000 Fix f-string conversion flag ValueError when compiling AST by youknowone · Pull Request #6534 · RustPython/RustPython · GitHub
[go: up one dir, main page]

Skip to content

Conversation

@youknowone
Copy link
Member
@youknowone youknowone commented Dec 26, 2025

The ast_from_object for ConversionFlag was using bytecode::ConvertValueOparg::from_op_arg() which only accepts internal oparg values (0, 1, 2, 3, 255), but Python's AST uses ASCII codes ('s'=115, 'r'=114, 'a'=97, -1=None).

This caused compile() on parsed AST with conversion flags to fail with "invalid conversion flag".

@ShaharNaveh You probably knows better about ConvertValueOparg. Will this be okay? Do we need to handle ConvertValueOparg differently?

Fix #6533

Summary by CodeRabbit

  • Refactor

    • Improved internal deserialization logic for better code maintainability.
  • Chores

    • Removed unused import dependencies.

✏️ Tip: You can customize this high-level summary in your review settings.

…n#6533)

The ast_from_object for ConversionFlag was using bytecode::ConvertValueOparg::from_op_arg()
which only accepts internal oparg values (0, 1, 2, 3, 255), but Python's AST uses ASCII codes
('s'=115, 'r'=114, 'a'=97, -1=None).

This caused compile() on parsed AST with conversion flags to fail with "invalid conversion flag".
@coderabbitai
Copy link
Contributor
coderabbitai bot commented Dec 26, 2025
📝 Walkthrough

Walkthrough

This PR fixes conversion flag deserialization in f-strings by replacing bytecode-based mapping with direct ASCII-code matching. An unused import is removed, 8000 and the deserialization logic now maps -1 or 255 to None, 's' to Str, 'r' to Repr, and 'a' to Ascii, while preserving serialization behavior.

Changes

Cohort / File(s) Summary
Import cleanup
crates/vm/src/stdlib/ast.rs
Removed unused import of OpArgType from compiler::core::bytecode module
Conversion flag deserialization
crates/vm/src/stdlib/ast/other.rs
Replaced ToPrimitive-based deserialization with direct ASCII-code matching for ConversionFlag in ast_from_object; maps 's'→Str, 'r'→Repr, 'a'→Ascii, -1/255→None; removed bytecode dependency; ast_to_object unchanged

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Poem

🐰 String conversions dance with glee,
ASCII codes now match with spree!
No more flags that fail to parse,
F-strings shine with ASCII ars! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: fixing a ValueError related to f-string conversion flags in AST compilation.
Linked Issues check ✅ Passed The changes directly address the issue by replacing bytecode oparg handling with ASCII code mapping for ConversionFlag deserialization, allowing compile() to handle AST conversion flags correctly.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the ConversionFlag deserialization issue reported in #6533; the import removal in ast.rs is a necessary cleanup.
✨ 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 December 26, 2025 02:12
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 c9bf8df and ae63092.

📒 Files selected for processing (2)
  • crates/vm/src/stdlib/ast.rs
  • crates/vm/src/stdlib/ast/other.rs
💤 Files with no reviewable changes (1)
  • crates/vm/src/stdlib/ast.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

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

**/*.rs: Follow the default rustfmt code style by running cargo fmt to format Rust code
Always run clippy to lint Rust code (cargo clippy) before completing tasks and fix any warnings or lints introduced by changes
Follow Rust best practices for error handling and memory management
Use the macro system (pyclass, pymodule, pyfunction, etc.) when implementing Python functionality in Rust

Files:

  • crates/vm/src/stdlib/ast/other.rs
🔇 Additional comments (1)
crates/vm/src/stdlib/ast/other.rs (1)

2-2: LGTM!

The import cleanup correctly removes unused dependencies and retains only SourceFile, which is required for the updated AST conversion logic.

Comment on lines +14 to +22
// Python's AST uses ASCII codes: 's', 'r', 'a', -1=None
// Note: 255 is -1i8 as u8 (ruff's ConversionFlag::None)
match i32::try_from_object(vm, object)? {
-1 | 255 => Ok(Self::None),
x if x == b's' as i32 => Ok(Self::Str),
x if x == b'r' as i32 => Ok(Self::Repr),
x if x == b'a' as i32 => Ok(Self::Ascii),
_ => Err(vm.new_value_error("invalid conversion flag")),
}
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Search for ConversionFlag enum definition
rg -n "enum ConversionFlag" --type rust -A 10

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Search for ast_to_object implementation in the file
rg -n "fn ast_to_object" crates/vm/src/stdlib/ast/other.rs -A 5

Repository: RustPython/RustPython

Length of output: 1205


🏁 Script executed:

# Check if there are any tests for ConversionFlag round-trip conversion
rg -n "ConversionFlag" crates/vm/src/stdlib/ast/ --type rust -B 2 -A 2

Repository: RustPython/RustPython

Length of output: 1254


🏁 Script executed:

# Check cargo.toml for ruff dependency
rg -n "ruff" Cargo.toml -A 2 -B 2

Repository: RustPython/RustPython

Length of output: 1048


🏁 Script executed:

# Search for ConversionFlag in ruff-related files or comments
rg -n "ConversionFlag" --type rust -B 3 -A 3 | head -50

Repository: RustPython/RustPython

Length of output: 3179


🏁 Script executed:

# Check if there's any documentation or external reference about ConversionFlag values
find . -name "*.rs" -type f | xargs grep -l "ruff::ConversionFlag" | head -5

Repository: RustPython/RustPython

Length of output: 137


🏁 Script executed:

# Search for usage of ast_to_object to understand if it's used for Python round-trips
rg -n "ast_to_object" crates/vm/src/stdlib/ast/ --type rust -B 2 -A 2 | head -40

Repository: RustPython/RustPython

Length of output: 2701


🏁 Script executed:

# Check if there are tests for AST conversion
fd "test" crates/vm/src/stdlib/ast/ --type rust

Repository: RustPython/RustPython

Length of output: 236


🏁 Script executed:

# Look at the unparse.rs file since it imports ConversionFlag - check how it uses it
head -50 crates/codegen/src/unparse.rs

Repository: RustPython/RustPython

Length of output: 1461


🏁 Script executed:

# Search for where FormattedValue is used and how conversion field is accessed
rg -n "FormattedValue" crates/vm/src/stdlib/ast/ -B 2 -A 5

Repository: RustPython/RustPython

Length of output: 7673


🏁 Script executed:

# Check how conversion flag is used in string formatting code
rg -n "conversion" crates/vm/src/stdlib/ast/string.rs -B 2 -A 2

Repository: RustPython/RustPython

Length of output: 1670


🏁 Script executed:

# Search for any documentation about Python's ConversionFlag values
rg -n "conversion.*flag\|conversion.*-1\|conversion.*255" --ignore-case -i

Repository: RustPython/RustPython

Length of output: 47


Fix ast_to_object to output -1 for ConversionFlag::None to preserve round-trip compatibility.

The round-trip conversion is real: FormattedValue uses conversion.ast_to_object() to serialize to Python AST objects (line 318 in string.rs), and later deserializes via ast_from_object() (line 340). While ast_from_object correctly accepts both -1 and 255 for None, the reverse conversion breaks round-trip compatibility:

  • ast_to_object outputs 255 (via self as u8) for ConversionFlag::None
  • Python's _ast.FormattedValue expects -1 for no conversion
  • Result: Python AST objects get conversion=255 instead of -1, breaking compatibility

Fix by special-casing None to output -1 as a signed integer:

fn ast_to_object(self, vm: &VirtualMachine, _source_file: &SourceFile) -> PyObjectRef {
    let val = match self {
        Self::None => -1i32,
        _ => self as u8 as i32,
    };
    vm.ctx.new_int(val).into()
}
🤖 Prompt for AI Agents
In crates/vm/src/stdlib/ast/other.rs around lines 14 to 22, ast_to_object
currently emits 255 for ConversionFlag::None (via casting to u8) which breaks
round-trip with Python AST expecting -1; change ast_to_object to special-case
Self::None and produce -1i32, otherwise cast the enum to u8 then to i32, and
return vm.ctx.new_int(val).into() so the Python AST sees -1 for None and other
flags remain unchanged.

@ShaharNaveh
Copy link
Collaborator

@ShaharNaveh You probably knows better about ConvertValueOparg. Will this be okay? Do we need to handle ConvertValueOparg differently?

I don't think that we do

@youknowone youknowone merged commit 1856415 into RustPython:main Dec 26, 2025
13 checks passed
@youknowone youknowone deleted the convert-value branch December 26, 2025 12:38
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.

ValueError: invalid conversion flag

2 participants

0