Skip to content

Add map_unwrap_or clippy rule#7829

Merged
youknowone merged 12 commits into
RustPython:mainfrom
ShaharNaveh:clippy-map-unwrap-or
May 11, 2026
Merged

Add map_unwrap_or clippy rule#7829
youknowone merged 12 commits into
RustPython:mainfrom
ShaharNaveh:clippy-map-unwrap-or

Conversation

@ShaharNaveh
Copy link
Copy Markdown
Contributor

@ShaharNaveh ShaharNaveh commented May 11, 2026

Summary by CodeRabbit

  • Refactor
    • Modernized numerous internal option/result patterns across the codebase for clearer, more concise expressions; behavior preserved.
  • Chores
    • Updated lint configuration to enable an additional Clippy warning.

No public APIs or user-facing behavior changed.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

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: 7b4c8de6-08b5-4807-a6eb-b2f8ee954191

📥 Commits

Reviewing files that changed from the base of the PR and between 741204c and 4611245.

📒 Files selected for processing (1)
  • crates/stdlib/src/overlapped.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/stdlib/src/overlapped.rs

📝 Walkthrough

Walkthrough

This PR refactors many compiler, stdlib, and VM sites to replace map(...).unwrap_or(...) and similar patterns with idiomatic Rust combinators (map_or, map_or_else, is_ok_and, is_some_and, and_then), and updates workspace Clippy lints accordingly; behavior is preserved.

Changes

Option Handling Modernization

Layer / File(s) Summary
Workspace Lint Configuration
Cargo.toml, crates/codegen/src/compile.rs
Enable map_unwrap_or Clippy lint and add #[expect] where applicable.
Code Generation Pattern Matching
crates/codegen/src/compile.rs
Refactor wildcard-pattern detection to use is_some_and() for star/match_as wildcard name checks.
Code Generation IR Optimization
crates/codegen/src/ir.rs
Replace map(...).unwrap_or(true) with is_none_or() for fallthrough detection; simplify debug/index computations with map_or/map_or_else.
Symbol Table Scope Tracking
crates/codegen/src/symboltable.rs
Use is_some_and() to compute nested-scope status from parent scope properties.
Format Parsing and Class Derivation
crates/common/src/cformat.rs, crates/derive-impl/src/pyclass.rs
Simplify error-index computation and base-name derivation using map_or()/map_or_else().
String & Regex Character Classification
crates/sre_engine/src/string.rs
Modernize ASCII/Unicode classification and casing helpers using try_from(...).is_ok_and(...) and map_or(...).
AsyncIO Repr Fallback
crates/stdlib/src/_asyncio.rs
Use map_or_else() for future/task _state repr fallback.
Opcode Instruction Handling
crates/stdlib/src/_opcode.rs
Refactor stack_effect oparg defaulting and has_* predicates to map_or()/is_ok_and() patterns.
Bisect Index Handling
crates/stdlib/src/bisect.rs
Simplify lo/hi defaults and conversions using map_or().
CSV Reader Trimming
crates/stdlib/src/csv.rs
Update trimmed-end computation to `map_or(0,
Faulthandler Line/Handler Fallbacks
crates/stdlib/src/faulthandler.rs
Refactor line-number fallback and saved-signal-handler retrieval using map_or()/map_or_else().
JSON Scanner Fallback Index
crates/stdlib/src/json.rs
Use map_or() for end-byte fallback when char→byte mapping fails.
Math.prod Float Init
crates/stdlib/src/math.rs
Refactor float fast-path initialization using map_or(1.0, ...).
Mmap Range & Read Calculations
crates/stdlib/src/mmap.rs
Refactor get_find_range() and read() optional-parameter handling with map_or_else()/map_or().
SSL/TLS Option Handling
crates/stdlib/src/ssl.rs
Modernize session-resume detection, non-blocking checks, buffer sizing, digit detection, and default-verify-path construction using is_some_and() and map_or*.
SSL Compat Read Paths
crates/stdlib/src/ssl/compat.rs
Simplify optional bytes-length extraction to map_or(0, ...) (merged into SSL layer).
Float Parsing Error Path
crates/vm/src/builtins/float.rs
Use map_or_else() to choose between propagating repr() errors or raising ValueError with repr text.
Frame Line Number Fallbacks
crates/vm/src/builtins/frame.rs
Simplify f_lineno() / set_f_lineno() fallback derivation using map_or().
Function Docstring Default
crates/vm/src/builtins/function.rs
Use map_or_else() to extract docstring from constants or fallback to vm.ctx.none().
Sequence Iterator length_hint
crates/vm/src/builtins/iter.rs
Refactor length-resolution to map_or_else() returning NotImplemented on failure.
Module Shadowing Detection
crates/vm/src/builtins/module.rs
Use is_some_and() to test module origin for possible stdlib shadowing.
Object Reduction / Pickling
crates/vm/src/builtins/object.rs
Construct kwargs dict via map_or_else() when reducing new objects.
Singleton Comparison
crates/vm/src/builtins/singletons.rs
Use map_or() for PyNone identical-optimization mapping.
String Encoding & Lossy Conversion
crates/vm/src/builtins/str.rs
Refactor encoding default and lossy conversion fallback with map_or()/map_or_else().
Template Interpolation Values
crates/vm/src/builtins/template.rs
Simplify interpolation value extraction with map_or_else().
Type Slot Inheritance & Counts
crates/vm/src/builtins/type.rs
Use and_then() for inherited slots and map_or() for member-count defaults.
OS Error String Formatting
crates/vm/src/exceptions.rs
Use map_or_else() to supply "None" defaults for missing errno/strerror conversions.
Frame Execution & Instrumentation
crates/vm/src/frame.rs
Modernize traceback conversion, exception-info stacking, instrumented-read fallbacks, import shadowing checks, and panic-message formatting.
Virtualenv Path Config
crates/vm/src/getpath.rs
Refactor venv prefix assignment using map_or_else() fallback to calculated prefix.
Atomic Reference Pointer Conversions
crates/vm/src/object/ext.rs
Replace map(...).unwrap_or(null_mut()) with map_or(null_mut(), ...) in PyAtomicRef From/swap implementations.
AST Statement Serialization
crates/vm/src/stdlib/_ast/statement.rs
Use map_or_else() for optional AST fields to produce empty-list defaults.
Codec Argument Defaults
crates/vm/src/stdlib/_codecs.rs
Simplify optional encoding and Windows errors defaults via map_or().
Deque Repr & Errors
crates/vm/src/stdlib/_collections.rs
Refactor deque index error detail and repr maxlen closing via map_or_else().
ctypes Array & Wchar
crates/vm/src/stdlib/_ctypes/array.rs
Use nested map_or() for element-size defaults and wchar first-codepoint extraction.
ctypes Buffer→FFI Conversion
crates/vm/src/stdlib/_ctypes/base.rs
Refactor byte extraction and boolean conversion using map_or()/is_some_and().
ctypes Function Results & Formats
crates/vm/src/stdlib/_ctypes/function.rs
Modernize out-buffer result, buffer-format selection, flags defaulting, and callback repr fallback using map_or*/map_or_else().
ctypes Pointer & Simple Types
crates/vm/src/stdlib/_ctypes/pointer.rs, .../simple.rs
Produce format Cow via map_or(...) to select borrowed default or owned Cow.
functools.partial Dict & Repr
crates/vm/src/stdlib/_functools.rs
Refactor __dict__ getter and qualname wtf8 conversion with map_or_else().
I/O Size & Repr Fallback
crates/vm/src/stdlib/_io.rs
Simplify optional size conversion and file-repr fallback with map_or()/map_or_else().
re.Match Group Values
crates/vm/src/stdlib/_sre.rs
Refactor group, groups, and groupdict to use map_or_else() for missing slices.
TypeAlias Param Error Fallback
crates/vm/src/stdlib/_typing.rs
Use map_or_else() for param repr fallbacks in error messages.
Builtins build_class Metaclass
crates/vm/src/stdlib/builtins.rs
Refactor metaclass kwarg extraction via map_or_else() while preserving downcast/default behaviors.
Type Slot Hash Wrapper Fallback
crates/vm/src/types/slot.rs
Select fix_sentinel or hash_bigint fallback via map_or_else().
Warning Registry Version Matching
crates/vm/src/warn.rs
Use is_ok_and() to detect saved filters-version matching current filters_version.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested reviewers

  • youknowone
  • fanninpm

"I hopped through maps with nimble paws,
I fixed each unwrap with kinder laws.
map_or, is_some_and, map_or_else—what fun!
Sixty files polished; not a behavior undone.
A lint-approved hop, and now it's done."

🚥 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 accurately describes the main objective: adding the map_unwrap_or clippy lint rule to the codebase, which is reflected throughout the entire changeset across 40+ files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

Copy link
Copy Markdown
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/getpath.rs (1)

146-157: ⚡ Quick win

Simplify by using pattern matching instead of map_or_else within a guaranteed-Some context.

The code uses map_or_else inside an if venv_prefix.is_some() block, which means the None branch (|| calculated_prefix.clone()) is unreachable dead code. This makes the logic unnecessarily complex.

♻️ Proposed refactor using pattern matching
-    // Step 5: Set prefix and base_prefix
-    if venv_prefix.is_some() {
-        // In venv: prefix = venv directory, base_prefix = original Python's prefix
-        paths.prefix = venv_prefix.as_ref().map_or_else(
-            || calculated_prefix.clone(),
-            |p| p.to_string_lossy().into_owned(),
-        );
-        paths.base_prefix = calculated_prefix;
-    } else {
-        // Not in venv: prefix == base_prefix
-        paths.prefix = calculated_prefix.clone();
-        paths.base_prefix = calculated_prefix;
-    }
+    // Step 5: Set prefix and base_prefix
+    if let Some(venv) = venv_prefix.as_ref() {
+        // In venv: prefix = venv directory, base_prefix = original Python's prefix
+        paths.prefix = venv.to_string_lossy().into_owned();
+        paths.base_prefix = calculated_prefix;
+    } else {
+        // Not in venv: prefix == base_prefix
+        paths.prefix = calculated_prefix.clone();
+        paths.base_prefix = calculated_prefix;
+    }
🤖 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/getpath.rs` around lines 146 - 157, The current block uses
map_or_else inside an if venv_prefix.is_some() branch leaving the None closure
dead; replace that with pattern matching: use if let Some(p) =
venv_prefix.as_ref() (or match venv_prefix.as_ref()) and set paths.prefix =
p.to_string_lossy().into_owned() and paths.base_prefix = calculated_prefix in
that arm, keeping the existing else branch that sets paths.prefix =
calculated_prefix.clone() and paths.base_prefix = calculated_prefix.
🤖 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/stdlib/src/csv.rs`:
- Around line 965-968: The trim_spaces function can panic when input is all
spaces because trimmed_start becomes input.len() and trimmed_end becomes 0; fix
by detecting that case and returning an empty slice instead of slicing with
start > end: after computing trimmed_start and trimmed_end (variables in
trim_spaces), if trimmed_start >= trimmed_end return an empty slice (e.g.,
&input[0..0]) otherwise return &input[trimmed_start..trimmed_end]; this prevents
the panic for all-space fields.

---

Nitpick comments:
In `@crates/vm/src/getpath.rs`:
- Around line 146-157: The current block uses map_or_else inside an if
venv_prefix.is_some() branch leaving the None closure dead; replace that with
pattern matching: use if let Some(p) = venv_prefix.as_ref() (or match
venv_prefix.as_ref()) and set paths.prefix = p.to_string_lossy().into_owned()
and paths.base_prefix = calculated_prefix in that arm, keeping the existing else
branch that sets paths.prefix = calculated_prefix.clone() and paths.base_prefix
= calculated_prefix.
🪄 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: 6293fec9-0c76-4c43-9ada-76964c5b6190

📥 Commits

Reviewing files that changed from the base of the PR and between 320355f and fef6a35.

📒 Files selected for processing (46)
  • Cargo.toml
  • crates/codegen/src/compile.rs
  • crates/codegen/src/ir.rs
  • crates/codegen/src/symboltable.rs
  • crates/common/src/cformat.rs
  • crates/derive-impl/src/pyclass.rs
  • crates/sre_engine/src/string.rs
  • crates/stdlib/src/_asyncio.rs
  • crates/stdlib/src/_opcode.rs
  • crates/stdlib/src/bisect.rs
  • crates/stdlib/src/csv.rs
  • crates/stdlib/src/faulthandler.rs
  • crates/stdlib/src/json.rs
  • crates/stdlib/src/math.rs
  • crates/stdlib/src/mmap.rs
  • crates/stdlib/src/ssl.rs
  • crates/stdlib/src/ssl/compat.rs
  • crates/vm/src/builtins/float.rs
  • crates/vm/src/builtins/frame.rs
  • crates/vm/src/builtins/function.rs
  • crates/vm/src/builtins/iter.rs
  • crates/vm/src/builtins/module.rs
  • crates/vm/src/builtins/object.rs
  • crates/vm/src/builtins/singletons.rs
  • crates/vm/src/builtins/str.rs
  • crates/vm/src/builtins/template.rs
  • crates/vm/src/builtins/type.rs
  • crates/vm/src/exceptions.rs
  • crates/vm/src/frame.rs
  • crates/vm/src/getpath.rs
  • crates/vm/src/object/ext.rs
  • crates/vm/src/stdlib/_ast/statement.rs
  • crates/vm/src/stdlib/_codecs.rs
  • crates/vm/src/stdlib/_collections.rs
  • crates/vm/src/stdlib/_ctypes/array.rs
  • crates/vm/src/stdlib/_ctypes/base.rs
  • crates/vm/src/stdlib/_ctypes/function.rs
  • crates/vm/src/stdlib/_ctypes/pointer.rs
  • crates/vm/src/stdlib/_ctypes/simple.rs
  • crates/vm/src/stdlib/_functools.rs
  • crates/vm/src/stdlib/_io.rs
  • crates/vm/src/stdlib/_sre.rs
  • crates/vm/src/stdlib/_typing.rs
  • crates/vm/src/stdlib/builtins.rs
  • crates/vm/src/types/slot.rs
  • crates/vm/src/warn.rs

Comment thread crates/stdlib/src/csv.rs
Comment on lines 965 to 968
fn trim_spaces(input: &[u8]) -> &[u8] {
let trimmed_start = input.iter().position(|&x| x != b' ').unwrap_or(input.len());
let trimmed_end = input
.iter()
.rposition(|&x| x != b' ')
.map(|i| i + 1)
.unwrap_or(0);
let trimmed_end = input.iter().rposition(|&x| x != b' ').map_or(0, |i| i + 1);
&input[trimmed_start..trimmed_end]
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.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

trim_spaces can panic on all-space fields.

At Line 967, all-space input yields trimmed_start = input.len() and trimmed_end = 0, so &input[trimmed_start..trimmed_end] panics.

Suggested fix
 fn trim_spaces(input: &[u8]) -> &[u8] {
     let trimmed_start = input.iter().position(|&x| x != b' ').unwrap_or(input.len());
-    let trimmed_end = input.iter().rposition(|&x| x != b' ').map_or(0, |i| i + 1);
+    let trimmed_end = input
+        .iter()
+        .rposition(|&x| x != b' ')
+        .map_or(trimmed_start, |i| i + 1);
     &input[trimmed_start..trimmed_end]
 }
📝 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.

Suggested change
fn trim_spaces(input: &[u8]) -> &[u8] {
let trimmed_start = input.iter().position(|&x| x != b' ').unwrap_or(input.len());
let trimmed_end = input
.iter()
.rposition(|&x| x != b' ')
.map(|i| i + 1)
.unwrap_or(0);
let trimmed_end = input.iter().rposition(|&x| x != b' ').map_or(0, |i| i + 1);
&input[trimmed_start..trimmed_end]
fn trim_spaces(input: &[u8]) -> &[u8] {
let trimmed_start = input.iter().position(|&x| x != b' ').unwrap_or(input.len());
let trimmed_end = input
.iter()
.rposition(|&x| x != b' ')
.map_or(trimmed_start, |i| i + 1);
&input[trimmed_start..trimmed_end]
}
🤖 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/stdlib/src/csv.rs` around lines 965 - 968, The trim_spaces function
can panic when input is all spaces because trimmed_start becomes input.len() and
trimmed_end becomes 0; fix by detecting that case and returning an empty slice
instead of slicing with start > end: after computing trimmed_start and
trimmed_end (variables in trim_spaces), if trimmed_start >= trimmed_end return
an empty slice (e.g., &input[0..0]) otherwise return
&input[trimmed_start..trimmed_end]; this prevents the panic for all-space
fields.

@youknowone youknowone merged commit 4a46e84 into RustPython:main May 11, 2026
25 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request May 15, 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.

2 participants