Skip to content

Accept a negative or __index__ default in operator.length_hint() - #9515

Merged
youknowone merged 1 commit into
RustPython:mainfrom
jseop-lim:fix/operator-length-hint
Nov 1, 2026
Merged

youknowone merged 1 commit into
RustPython:mainfrom
jseop-lim:fix/operator-length-hint

Conversation

@jseop-lim

@jseop-lim jseop-lim commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

length_hint accepts default only as an int instance and converts it to usize, so a negative default raises ValueError and a default with __index__ raises TypeError. CPython converts default to Py_ssize_t with _PyNumber_Index (Modules/clinic/_operator.c.h) and returns it unchanged when the object gives no hint.

AS-IS

>>> import operator
>>> operator.length_hint(object(), -1)
ValueError: can't convert negative number to unsigned
>>> operator.length_hint(object(), Index())  # __index__ returns 5
TypeError: 'Index' object cannot be interpreted as an integer

TO-BE

>>> operator.length_hint(object(), -1)
-1
>>> operator.length_hint(object(), Index())
5

(matching CPython)

Changes

  • Bind default as isize in crates/vm/src/stdlib/_operator.rs, so it goes through __index__, and return vm.length_hint_opt(obj)?.map_or(default, …). The exact-int check and the now unused PyInt import go away.
  • Extend extra_tests/snippets/stdlib_operator.py with an __index__ default, an __index__ that raises, a negative default with and without a hint, a __length_hint__ returning a non-int, and an out-of-range default.

Test plan

Built and run on macOS aarch64 against upstream/main 713e14c, using the CI feature set --no-default-features --features stdlib,importlib,stdio,encodings,sqlite,ssl-rustls-aws-lc,host_env,doc,ucd_3_2_0, plus threading, compared with CPython 3.15.2.

  • The extended extra_tests/snippets/stdlib_operator.py fails on an unpatched build of that commit (at the __index__ default) and passes with the patch and under CPython 3.15.2.
  • rustpython -m test test_operator test_iter test_list test_bytes: 569 run, 17 skipped, all pass.
  • pytest -k rustpython in extra_tests: 248 pass.
  • cargo fmt --check clean, cargo clippy -p rustpython-vm -- -Dwarnings reports nothing, and the pre-commit hooks pass on both changed files.

I used Claude Code (claude-opus-5-5) to draft the analysis, the patch and this description; I reviewed the change and ran every command above myself.

Summary by CodeRabbit

  • Bug Fixes
    • Improved length_hint behavior to correctly accept integer-like length hints, return the supplied default when no hint is available, and preserve valid hints such as zero.
    • Invalid hints and defaults outside the supported range now raise the appropriate errors.

length_hint() required its default to be an exact int and converted it
to usize, so a default with __index__ raised TypeError and a negative
default raised ValueError. Bind the default as isize, which goes through
__index__, and return it unchanged when the object has no length hint.

Assisted-by: Claude Code:claude-opus-5-5
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-01T04:31:10.382706Z cbe6197 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 88f3733 and cbe6197.

Files selected for processing: 2
  • crates/vm/src/stdlib/_operator.rs
  • extra_tests/snippets/stdlib_operator.py

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.

Walkthrough

operator.length_hint now accepts a signed default converted to isize. It uses the optional length hint when available and returns the default otherwise. Tests cover valid hints, default handling, and error cases.

Changes: Operator length hint

Layer / File(s) Summary
Length hint conversion and checks
crates/vm/src/stdlib/_operator.rs, extra_tests/snippets/stdlib_operator.py
length_hint now accepts an isize default and returns PyResult<isize>. Tests check valid and invalid hints, exceptions, and default values.

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

Change: Bug fix · Severity of issue fixed: Low

Suggested reviewers: youknowone

Merge Risk: Minimal · up to cbe61

The change supports negative and index-convertible defaults while preserving available length hints. No concrete merge-blocking issue was identified; merge after normal checks pass.

Pre-merge checks: Passed 4 · Failed 1

Failed 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%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed 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: supporting negative defaults and index defaults in operator.length_hint().
Linked Issues check Passed The changes satisfy the coding requirements in [#9509]. LengthHintArgs.default now uses isize, so argument conversion uses __index__ and preserves signed values. vm.length_hint_opt(obj)? propa…
Out of Scope Changes check Passed The pull request changes only operator.length_hint() and its focused snippet tests. Removing the unused PyInt import supports the implementation change. The added tests directly verify the behavio…
Full details: Linked Issues check

Explanation

The changes satisfy the coding requirements in [#9509]. LengthHintArgs.default now uses isize, so argument conversion uses __index__ and preserves signed values. vm.length_hint_opt(obj)? propagates errors from __length_hint__ and from default conversion. The function returns the signed default when no hint exists. The added tests cover an __index__ default, an exception from __index__, negative defaults with and without a hint, invalid length hints, and an out-of-range default.

Full details: Out of Scope Changes check

Explanation

The pull request changes only operator.length_hint() and its focused snippet tests. Removing the unused PyInt import supports the implementation change. The added tests directly verify the behaviors requested by [#9509]. No unrelated change is present in the reviewed diff.

Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 1 functions across 2 files.

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cbe6197b34

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

return ()


assert _operator.length_hint(object(), Index()) == 5

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep test-file edits within the permitted changes

The root AGENTS.md explicitly limits test-file modifications to adding/removing @unittest.expectedFailure decorators and removing associated TODO comments. These new assertions and supporting classes fall outside that allowance. Keep the Rust fix, but remove the added snippet changes unless an explicit exception to the repository policy is approved.

AGENTS.md reference: AGENTS.md:L280-L282

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That section covers the CPython tests in Lib/test. For extra_tests/snippets, AGENTS.md asks for new tests in the most closely related existing file (L119-L120), which is what this does.

@youknowone
youknowone merged commit 1ad9beb into RustPython:main Nov 1, 2026
20 checks passed
@jseop-lim
jseop-lim deleted the fix/operator-length-hint branch November 1, 2026 16:25
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.

operator.length_hint() rejects a negative default and a default that defines __index__

2 participants