Skip to content

Fix bytearray repr escaping for apostrophes - #8316

Merged
youknowone merged 2 commits into
RustPython:mainfrom
cuishuang:main
Jul 22, 2026
Merged

youknowone merged 2 commits into
RustPython:mainfrom
cuishuang:main

Conversation

@cuishuang

@cuishuang cuishuang commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Fix bytearray.__repr__ to match CPython when the underlying bytes contain apostrophes.

Previously, RustPython reused the generic bytes repr escaping logic for bytearray, which produced bytearray(b"'") for repr(bytearray(b"'")).

CPython escapes apostrophes inside bytearray repr output, including when the bytes literal uses double quotes. This PR adds bytearray-specific repr escaping while keeping bytes repr behavior unchanged.

Fixes #8311.

Tests

  • Re-enabled the existing test_bytearray_repr CPython test by removing the RustPython expected failure.
  • Ran cargo fmt --check.

Summary by CodeRabbit

  • Bug Fixes
    • Improved byte array/bytearray rendering to produce consistent, correctly escaped output.
    • Correctly selects quoting based on contained characters and handles escaping for quotes, backslashes, and common control characters (tab, newline, carriage return).
    • Printable ASCII is preserved, while non-printable bytes are represented using hexadecimal escapes for accurate, stable display.

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: b827ab96-67b1-4a1e-81a1-c770f6c6910f

📥 Commits

Reviewing files that changed from the base of the PR and between fb9aaa1 and e6a766e.

⛔ Files ignored due to path filters (1)
  • Lib/test/test_bytes.py is excluded by !Lib/**
📒 Files selected for processing (1)
  • crates/vm/src/bytes_inner.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/vm/src/bytes_inner.rs

📝 Walkthrough

Walkthrough

PyBytesInner::repr_with_name now manually selects quotes, calculates escaped output capacity, and emits bytearray representations using explicit per-byte escaping.

Changes

Bytearray representation escaping

Layer / File(s) Summary
Manual bytearray repr generation
crates/vm/src/bytes_inner.rs
Adds per-byte escaping helpers and rewrites repr_with_name to select quotes, calculate output capacity, and emit special or hexadecimal escapes.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 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 to bytearray repr escaping for apostrophes.
Linked Issues check ✅ Passed The code change directly addresses #8311 by escaping apostrophes in bytearray repr output while preserving bytes repr behavior.
Out of Scope Changes check ✅ Passed The changes stay focused on repr escaping logic in bytes_inner.rs with no obvious unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

📦 Library Dependencies

The following Lib/ modules were modified. Here are their dependencies:

[ ] test: cpython/Lib/test/test_bytes.py (TODO: 20)

dependencies:

dependent tests: (no tests depend on bytes)

Legend:

  • [+] path exists in CPython
  • [x] up-to-date, [ ] outdated

@ShaharNaveh ShaharNaveh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

tysm!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/vm/src/bytes_inner.rs`:
- Around line 231-255: Update bytearray_repr_char_len and
write_bytearray_repr_char in crates/vm/src/bytes_inner.rs (231-255) to accept
the selected quote and escape quote bytes only when ch matches that quote, while
always escaping backslashes; then update the callers in
crates/vm/src/bytes_inner.rs (279-305) to pass quote as u8 to both helpers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 4555f649-61e9-4353-a86f-ba148d6288e5

📥 Commits

Reviewing files that changed from the base of the PR and between 0bc109d and be525fe.

⛔ Files ignored due to path filters (1)
  • Lib/test/test_bytes.py is excluded by !Lib/**
📒 Files selected for processing (1)
  • crates/vm/src/bytes_inner.rs

Comment thread crates/vm/src/bytes_inner.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
crates/vm/src/bytes_inner.rs (1)

231-255: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Conditionally escape the selected quote character.

The current implementation unconditionally escapes b'\'' even when " is chosen as the enclosing quote (which produces bytearray(b"\'")). Python's _Py_bytes_repr logic dynamically checks if a byte matches the chosen quote character, successfully avoiding escaping the single quote if double quotes are selected (producing bytearray(b"'")).

  • crates/vm/src/bytes_inner.rs#L231-L255: Update the helper functions to accept the quote parameter and only escape ch if it matches quote (or b'\\').
  • crates/vm/src/bytes_inner.rs#L279-L305: Pass quote as u8 when calling bytearray_repr_char_len and write_bytearray_repr_char.
🐛 Proposed fixes

crates/vm/src/bytes_inner.rs#L231-L255

-fn bytearray_repr_char_len(ch: u8) -> usize {
+fn bytearray_repr_char_len(ch: u8, quote: u8) -> usize {
     match ch {
-        b'\'' | b'\\' | b'\t' | b'\r' | b'\n' => 2,
+        b'\\' | b'\t' | b'\r' | b'\n' => 2,
+        c if c == quote => 2,
         0x20..=0x7e => 1,
         _ => 4, // \xHH
     }
 }

-fn write_bytearray_repr_char(ch: u8, buf: &mut String) {
+fn write_bytearray_repr_char(ch: u8, quote: u8, buf: &mut String) {
     match ch {
-        b'\'' => buf.push_str("\\'"),
         b'\\' => buf.push_str("\\\\"),
         b'\t' => buf.push_str("\\t"),
         b'\n' => buf.push_str("\\n"),
         b'\r' => buf.push_str("\\r"),
+        c if c == quote => {
+            buf.push('\\');
+            buf.push(c as char);
+        }
         0x20..=0x7e => buf.push(ch as char),
         ch => {

crates/vm/src/bytes_inner.rs#L279-L305

         let body_len = self
             .elements
             .iter()
             .try_fold(0usize, |len, &ch| {
-                len.checked_add(bytearray_repr_char_len(ch))
+                len.checked_add(bytearray_repr_char_len(ch, quote as u8))
             })
             .ok_or_else(|| Self::new_repr_overflow_error(vm))?;
         let len = class_name
             .len()
             .checked_add(DECORATION_LEN)
             .and_then(|len| len.checked_add(body_len))
             .ok_or_else(|| Self::new_repr_overflow_error(vm))?;
         let mut buf = String::with_capacity(len);
         buf.push_str(class_name);
         buf.push('(');
         buf.push('b');
         buf.push(quote);
         for &ch in &self.elements {
-            write_bytearray_repr_char(ch, &mut buf);
+            write_bytearray_repr_char(ch, quote as u8, &mut buf);
         }

Run the following script to verify CPython's behavior for bytearray representations when apostrophes are present:

#!/bin/bash
# Description: Check CPython's bytearray representations to verify conditional escaping.

python3 -c "print(repr(bytearray(b\"'\")))"
python3 -c "print(repr(bytearray(b'\"')))"
python3 -c "print(repr(bytearray(b\"'\\\"\")))"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/vm/src/bytes_inner.rs` around lines 231 - 255, Update
bytearray_repr_char_len and write_bytearray_repr_char in
crates/vm/src/bytes_inner.rs:231-255 to accept the selected quote and escape it
only when ch matches that quote or is a backslash; update the callers in
crates/vm/src/bytes_inner.rs:279-305 to pass quote as u8 to both helpers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@crates/vm/src/bytes_inner.rs`:
- Around line 231-255: Update bytearray_repr_char_len and
write_bytearray_repr_char in crates/vm/src/bytes_inner.rs:231-255 to accept the
selected quote and escape it only when ch matches that quote or is a backslash;
update the callers in crates/vm/src/bytes_inner.rs:279-305 to pass quote as u8
to both helpers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 8af9828d-b2e7-45f8-8aef-53c611a1c7d7

📥 Commits

Reviewing files that changed from the base of the PR and between be525fe and fb9aaa1.

⛔ Files ignored due to path filters (1)
  • Lib/test/test_bytes.py is excluded by !Lib/**
📒 Files selected for processing (1)
  • crates/vm/src/bytes_inner.rs

@youknowone youknowone left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you so much! and welcome to RustPython project.

You actually fixed more than test_bytearray_repr. Could you please also remove expectedFailure markers from other tests?

UNEXPECTED SUCCESS: test_bytearray_str (test.test_bytes.AssortedBytesTest.test_bytearray_str)

You can check it yourself by opening CI result

Comment thread crates/vm/src/bytes_inner.rs Outdated

@youknowone youknowone left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you!

@youknowone
youknowone merged commit d2da5a2 into RustPython:main Jul 22, 2026
27 checks passed
youknowone pushed a commit that referenced this pull request Sep 16, 2026
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.

Incompatibility with CPython for bytearray.__repr__

3 participants