Skip to content

Conversation

@terryluan12
Copy link
Contributor

@terryluan12 terryluan12 commented Jan 4, 2026

Summary by CodeRabbit

  • New Features
    • Enhanced bytes decoding with optional errors parameter supporting multiple error-handling strategies: strict, ignore, replace, backslashreplace, and surrogateescape modes.
    • Added time.altzone() function to retrieve alternative timezone offset information.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 4, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

Two files are modified: bytes_inner.rs expands the DecodeArgs struct with an errors parameter and refactors bytes_decode to handle more complex encoding resolution with branching error logic; time.rs adds a new altzone function to the time module.

Changes

Cohort / File(s) Summary
Bytes decoding parameter and error handling
crates/vm/src/bytes_inner.rs
DecodeArgs struct updated to derive Debug and introduce errors: Option<PyStrRef> field with #[pyarg(any, default)] decorator. Function bytes_decode signature restructured to accept zelf: PyObjectRef and args: DecodeArgs parameters. Encoding resolution logic substantially expanded with multiple error handling branches: "strict" mode emits Unicode encode error; "ignore"/"replace"/"backslashreplace" marked TODO; "surrogateescape" uses lossy conversion; other values emit surrogate-not-allowed error.
Time module altzone function
crates/vm/src/stdlib/time.rs
New public altzone function added to time module, exposed via #[pyattr], returning c_long. Guarded by cfgs excluding MSVC and wasm32 targets. Implements as c_timezone - 3600 with FIXME note for future C altzone integration.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hops of joy for error paths clear,
Bytes decode now knows what to steer,
Errors handled with surrogates bright,
Time counts altzone in system delight!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title mentions 'Update email library + test.support v3.13.11', but the actual changes are in bytes_inner.rs (decoding logic) and time.rs (altzone function). The title does not reflect the main changes in the changeset. Update the title to accurately reflect the primary changes, such as 'Add error handling to bytes.decode() and altzone() to time module' or similar.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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.

@terryluan12 terryluan12 changed the title Update email library Update email library v3.13.11 Jan 4, 2026
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

🧹 Nitpick comments (1)
crates/vm/src/stdlib/time.rs (1)

200-206: Hardcoded 3600-second DST offset may be incorrect for some timezones.

The calculation c_timezone - 3600 assumes DST offset is always 1 hour, but some regions use different DST offsets (e.g., Lord Howe Island uses 30 minutes). While the FIXME acknowledges this limitation, consider documenting which timezones may return incorrect values or adding a more prominent warning.

The implementation follows the existing pattern in this module and is acceptable as a placeholder until proper C altzone support is added.

📜 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 8bfe927 and 2773e69.

⛔ Files ignored due to path filters (93)
  • Lib/email/_header_value_parser.py is excluded by !Lib/**
  • Lib/email/_parseaddr.py is excluded by !Lib/**
  • Lib/email/_policybase.py is excluded by !Lib/**
  • Lib/email/contentmanager.py is excluded by !Lib/**
  • Lib/email/feedparser.py is excluded by !Lib/**
  • Lib/email/generator.py is excluded by !Lib/**
  • Lib/email/header.py is excluded by !Lib/**
  • Lib/email/message.py is excluded by !Lib/**
  • Lib/email/parser.py is excluded by !Lib/**
  • Lib/email/utils.py is excluded by !Lib/**
  • Lib/test/support/testresult.py is excluded by !Lib/**
  • Lib/test/test_email/__init__.py is excluded by !Lib/**
  • Lib/test/test_email/__main__.py is excluded by !Lib/**
  • Lib/test/test_email/data/msg_01.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_02.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_03.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_04.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_05.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_06.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_07.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_08.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_09.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_10.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_11.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_12.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_12a.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_13.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_14.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_15.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_16.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_17.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_18.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_19.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_20.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_21.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_22.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_23.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_24.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_25.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_26.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_27.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_28.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_29.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_30.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_31.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_32.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_33.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_34.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_35.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_36.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_37.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_38.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_39.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_40.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_41.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_42.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_43.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_44.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_45.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_46.txt is excluded by !Lib/**
  • Lib/test/test_email/data/msg_47.txt is excluded by !Lib/**
  • Lib/test/test_email/data/python.bmp is excluded by !**/*.bmp, !Lib/**
  • Lib/test/test_email/data/python.exr is excluded by !Lib/**
  • Lib/test/test_email/data/python.gif is excluded by !**/*.gif, !Lib/**
  • Lib/test/test_email/data/python.jpg is excluded by !**/*.jpg, !Lib/**
  • Lib/test/test_email/data/python.pbm is excluded by !Lib/**
  • Lib/test/test_email/data/python.pgm is excluded by !Lib/**
  • Lib/test/test_email/data/python.png is excluded by !**/*.png, !Lib/**
  • Lib/test/test_email/data/python.ppm is excluded by !Lib/**
  • Lib/test/test_email/data/python.ras is excluded by !Lib/**
  • Lib/test/test_email/data/python.sgi is excluded by !Lib/**
  • Lib/test/test_email/data/python.tiff is excluded by !**/*.tiff, !Lib/**
  • Lib/test/test_email/data/python.webp is excluded by !Lib/**
  • Lib/test/test_email/data/python.xbm is excluded by !Lib/**
  • Lib/test/test_email/data/sndhdr.aifc is excluded by !Lib/**
  • Lib/test/test_email/data/sndhdr.aiff is excluded by !Lib/**
  • Lib/test/test_email/data/sndhdr.au is excluded by !Lib/**
  • Lib/test/test_email/data/sndhdr.wav is excluded by !**/*.wav, !Lib/**
  • Lib/test/test_email/test__encoded_words.py is excluded by !Lib/**
  • Lib/test/test_email/test__header_value_parser.py is excluded by !Lib/**
  • Lib/test/test_email/test_asian_codecs.py is excluded by !Lib/**
  • Lib/test/test_email/test_contentmanager.py is excluded by !Lib/**
  • Lib/test/test_email/test_defect_handling.py is excluded by !Lib/**
  • Lib/test/test_email/test_email.py is excluded by !Lib/**
  • Lib/test/test_email/test_generator.py is excluded by !Lib/**
  • Lib/test/test_email/test_headerregistry.py is excluded by !Lib/**
  • Lib/test/test_email/test_inversion.py is excluded by !Lib/**
  • Lib/test/test_email/test_message.py is excluded by !Lib/**
  • Lib/test/test_email/test_parser.py is excluded by !Lib/**
  • Lib/test/test_email/test_pickleable.py is excluded by !Lib/**
  • Lib/test/test_email/test_policy.py is excluded by !Lib/**
  • Lib/test/test_email/test_utils.py is excluded by !Lib/**
  • Lib/test/test_email/torture_test.py is excluded by !Lib/**
📒 Files selected for processing (2)
  • crates/vm/src/bytes_inner.rs
  • crates/vm/src/stdlib/time.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 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/time.rs
  • crates/vm/src/bytes_inner.rs
⏰ 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). (11)
  • GitHub Check: Run rust tests (macos-latest)
  • GitHub Check: Run tests under miri
  • GitHub Check: Run rust tests (windows-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 (macos-latest)
  • GitHub Check: Run rust tests (ubuntu-latest)
  • GitHub Check: Check Rust code with clippy
  • GitHub Check: Run snippets and cpython tests on wasm-wasi
  • GitHub Check: Ensure compilation on various targets
  • GitHub Check: Check the WASM package and demo
🔇 Additional comments (1)
crates/vm/src/bytes_inner.rs (1)

1091-1097: LGTM!

Adding the Debug derive to DecodeArgs improves debuggability. The struct definition is clean and follows the existing patterns in this file.

Comment on lines 1106 to 1137
let encoding = match encoding.as_ref() {
Some(s) => match s.to_str() {
Some(valid_str) => valid_str,
None => {
let Some(errors) = &errors else {
return Err(vm.new_unicode_encode_error(format!(
"'{}' codec can't encode characters: surrogates not allowed",
s
)));
};

match errors.as_str() {
"strict" => {
return Err(
vm.new_unicode_encode_error("Struct format must be a UTF-8 string")
);
}
"ignore" => todo!("TODO"),
"replace" => todo!("TODO"),
"backslashreplace" => todo!("TODO"),
"surrogateescape" => &s.to_string_lossy(),
_ => {
return Err(vm.new_unicode_encode_error(format!(
"'{}' codec can't encode characters: surrogates not allowed",
s
)));
}
}
}
},
None => crate::codecs::DEFAULT_ENCODING,
};
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

Critical: Dangling reference and incomplete implementation.

Two significant issues:

  1. Dangling reference (Line 1126): &s.to_string_lossy() creates a temporary Cow<str> that is dropped at the end of the expression. The resulting &str reference would be invalid when used later. This should either fail to compile or cause undefined behavior.

  2. Unimplemented paths will panic (Lines 1123-1125): The todo!() macros for "ignore", "replace", and "backslashreplace" will panic at runtime if these error handlers are used.

🔎 Proposed fix

To fix the lifetime issue, you need to own the string. One approach:

 pub fn bytes_decode(
     zelf: PyObjectRef,
     args: DecodeArgs,
     vm: &VirtualMachine,
 ) -> PyResult<PyStrRef> {
     let DecodeArgs { encoding, errors } = args;
 
-    let encoding = match encoding.as_ref() {
-        Some(s) => match s.to_str() {
-            Some(valid_str) => valid_str,
+    let encoding_owned: Option<String>;
+    let encoding: &str = match encoding.as_ref() {
+        Some(s) => match s.to_str() {
+            Some(valid_str) => valid_str,
             None => {
                 let Some(errors) = &errors else {
                     return Err(vm.new_unicode_encode_error(format!(
                         "'{}' codec can't encode characters: surrogates not allowed",
                         s
                     )));
                 };
 
                 match errors.as_str() {
                     "strict" => {
                         return Err(
-                            vm.new_unicode_encode_error("Struct format must be a UTF-8 string")
+                            vm.new_unicode_encode_error("encoding must be a valid UTF-8 string")
                         );
                     }
-                    "ignore" => todo!("TODO"),
-                    "replace" => todo!("TODO"),
-                    "backslashreplace" => todo!("TODO"),
-                    "surrogateescape" => &s.to_string_lossy(),
+                    "ignore" | "replace" | "backslashreplace" => {
+                        return Err(vm.new_not_implemented_error(
+                            format!("error handler '{}' not yet implemented for encoding with surrogates", errors.as_str())
+                        ));
+                    }
+                    "surrogateescape" => {
+                        encoding_owned = Some(s.to_string_lossy().into_owned());
+                        encoding_owned.as_ref().unwrap()
+                    }
                     _ => {
                         return Err(vm.new_unicode_encode_error(format!(
                             "'{}' codec can't encode characters: surrogates not allowed",
                             s
                         )));
                     }
                 }
             }
         },
         None => crate::codecs::DEFAULT_ENCODING,
     };

Committable suggestion skipped: line range outside the PR's diff.

@terryluan12 terryluan12 changed the title Update email library v3.13.11 Update email library + test.support v3.13.11 Jan 5, 2026
@terryluan12 terryluan12 closed this Jan 5, 2026
@terryluan12 terryluan12 deleted the update_email branch January 5, 2026 19:06
@terryluan12 terryluan12 restored the update_email branch January 5, 2026 19:06
@youknowone youknowone reopened this Jan 6, 2026
@youknowone
Copy link
Member

@terryluan12 was there problem in this PR?

@terryluan12
Copy link
Contributor Author

terryluan12 commented Jan 6, 2026

I don't remember closing this, whoops. Yes, there are many lol. Please don't merge. I'm planning to keep the PR open while I work on it, if that's alright

@terryluan12 terryluan12 marked this pull request as draft January 6, 2026 04:39
…r parameter in bytes_decode function in `bytes_inner.rs`
@github-actions
Copy link
Contributor

Code has been automatically formatted

The code in this PR has been formatted using:

  • cargo fmt --all
    Please pull the latest changes before pushing again:
git pull origin update_email

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