Skip to content

Match invalid format specifier error messages - #8477

Open
shAn-kor wants to merge 1488 commits into
RustPython:mainfrom
shAn-kor:fix-invalid-format-specifier-error-message
Open

shAn-kor wants to merge 1488 commits into
RustPython:mainfrom
shAn-kor:fix-invalid-format-specifier-error-message

Conversation

@shAn-kor

@shAn-kor shAn-kor commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Summary

This is a follow-up to #8475. RustPython still returned the generic Invalid format specifier message for malformed format specifications, while CPython includes both the original specifier and the runtime object type.

Add a VM-level format-spec parsing helper that maps only InvalidFormatSpecifier to CPython's detailed ValueError message. Integer, boolean, float, complex, and string formatting now use the helper, including subclasses whose runtime type names must appear in the error.

With the error text matching CPython, this enables the existing test_better_error_message_format, test_unicode_in_error_message, and test_specifier_z_error tests without changing their assertions or test data.

Tests

  • cargo run --release -- -m test test_format
  • cargo test --workspace --exclude rustpython_wasm --exclude rustpython-venvlauncher --exclude rustpython-capi
  • (cd crates/capi && cargo test) — 102 passed
  • cargo clippy --workspace --exclude rustpython_wasm --exclude rustpython-venvlauncher --all-targets
  • repository pre-commit and pre-push checks

AI assistance

Codex (GPT-5.6) assisted with comparing CPython and RustPython error behavior, implementing the shared parsing helper, enabling the existing regression tests, running validation, and drafting this PR description. I reviewed the final diff and verified the behavior locally on macOS.

Summary by CodeRabbit

  • Bug Fixes
    • Improved formatting support for booleans, integers, floating-point numbers, complex numbers, and strings.
    • Invalid format specifications now produce clearer, more consistent error messages that identify the affected value type and specification.
    • Preserved existing locale-aware and standard formatting behavior.

ShaharNaveh and others added 30 commits June 22, 2026 22:57
Bumps [https://github.com/astral-sh/ruff-pre-commit](https://github.com/astral-sh/ruff-pre-commit) from v0.15.16 to 0.15.17.
- [Release notes](https://github.com/astral-sh/ruff-pre-commit/releases)
- [Commits](astral-sh/ruff-pre-commit@v0.15.16...v0.15.17)

---
updated-dependencies:
- dependency-name: https://github.com/astral-sh/ruff-pre-commit
  dependency-version: 0.15.17
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [github/gh-aw](https://github.com/github/gh-aw) from 0.77.5 to 0.79.9.
- [Release notes](https://github.com/github/gh-aw/releases)
- [Changelog](https://github.com/github/gh-aw/blob/main/CHANGELOG.md)
- [Commits](github/gh-aw@f990bbb...54ad1f8)

---
updated-dependencies:
- dependency-name: github/gh-aw
  dependency-version: 0.79.9
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…RustPython#8145)

Bumps [https://github.com/rbubley/mirrors-prettier](https://github.com/rbubley/mirrors-prettier) from v3.8.3 to 3.8.4.
- [Commits](rbubley/mirrors-prettier@v3.8.3...v3.8.4)

---
updated-dependencies:
- dependency-name: https://github.com/rbubley/mirrors-prettier
  dependency-version: 3.8.4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…n#8146)

Bumps the malachite group with 2 updates in the / directory: [malachite-bigint](https://github.com/mhogrefe/malachite) and [malachite-q](https://github.com/mhogrefe/malachite).


Updates `malachite-bigint` from 0.9.1 to 0.9.2
- [Release notes](https://github.com/mhogrefe/malachite/releases)
- [Commits](mhogrefe/malachite@v0.9.1...v0.9.2)

Updates `malachite-q` from 0.9.1 to 0.9.2
- [Release notes](https://github.com/mhogrefe/malachite/releases)
- [Commits](mhogrefe/malachite@v0.9.1...v0.9.2)

Updates `malachite-base` from 0.9.1 to 0.9.2
- [Release notes](https://github.com/mhogrefe/malachite/releases)
- [Commits](mhogrefe/malachite@v0.9.1...v0.9.2)

---
updated-dependencies:
- dependency-name: malachite-bigint
  dependency-version: 0.9.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: malachite
- dependency-name: malachite-q
  dependency-version: 0.9.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: malachite
- dependency-name: malachite-base
  dependency-version: 0.9.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: malachite
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the random group with 1 update in the / directory: [getrandom](https://github.com/rust-random/getrandom).


Updates `getrandom` from 0.4.2 to 0.4.3
- [Changelog](https://github.com/rust-random/getrandom/blob/master/CHANGELOG.md)
- [Commits](rust-random/getrandom@v0.4.2...v0.4.3)

---
updated-dependencies:
- dependency-name: getrandom
  dependency-version: 0.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: random
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…thon#8150)

Bumps the webpki-root group with 1 update in the / directory: [webpki-roots](https://github.com/rustls/webpki-roots).


Updates `webpki-roots` from 1.0.7 to 1.0.8
- [Release notes](https://github.com/rustls/webpki-roots/releases)
- [Commits](rustls/webpki-roots@v/1.0.7...v/1.0.8)

---
updated-dependencies:
- dependency-name: webpki-roots
  dependency-version: 1.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: webpki-root
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [which](https://github.com/harryfei/which-rs) from 8.0.3 to 8.0.4.
- [Release notes](https://github.com/harryfei/which-rs/releases)
- [Changelog](https://github.com/harryfei/which-rs/blob/master/CHANGELOG.md)
- [Commits](harryfei/which-rs@8.0.3...8.0.4)

---
updated-dependencies:
- dependency-name: which
  dependency-version: 8.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.81.8 to 2.81.11.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](taiki-e/install-action@0631aa6...15449e3)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.81.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
RustPython#8155)

* mark_except_handlers

* mark_warm

* mark_cold

* push_cold_blocks_to_end

* check_cfg

* jump thread

* basicblock_add_jump

* convert_pseudo_conditional_jumps

* normalize_jumps_in_block

* basicblock_inline_small_or_no_lineno_blocks

* inline_small_or_no_lineno_blocks

* basicblock_remove_redundant_nops

* remove_redundant_nops

* no_redundant_nops

* remove_redundant_jumps

* no_redundant_jumps

* remove_redundant_nops_and_jumps

* blocks_new_block

* clippy
* Update `test_repl.py` to 3.14.6

* mark failing tests

* Mark failing test correctly
* Update `test_ssl.py` to 3.14.6

* Add `Lib/test/ssltests.py`

* Mark failing test correctly
* Add `test_fileutils.py` from 3.14.6

* Align patch for `test_zipimport_support.py`

* Update `test_bigmem.py` to 3.14.6

* Update `test_exception_group.py`

* Align patches for `test_baseexception.py`

* Update `test_exceptions.py`

* Update `test_dtrace.py`

* Remove patch from `string_tests.py`
* Align compiler and AST behavior with CPython

Update the compiler pipeline, AST module support, and related VM compile/eval paths toward CPython 3.14 behavior.

Use upstream Ruff parser crates directly and keep RustPython-specific syntax preflight handling in the compile path.

Refresh opcode metadata, snapshots, and targeted tests for the aligned bytecode and AST behavior.

* fix

* Fix PR 8138 CI failures

* Fix match mapping wildcard scan complexity

* fixes

* Use Ruff runtime AST fields

* Minimize residual patch diff

* refactor error handling

* Remove _ast conversion context wrappers

* Clean up _ast conversion glue and compiler warning escalation

Rename the Node conversion parameter `ctx` to `vm` throughout the _ast
module.

Remove the unused compile_program, compile_program_single,
compile_block_expression, and compile_expression forwarders; compile_top
stays as the entry point.

Stash an escalated compiler SyntaxWarning so a non-SyntaxWarning category
propagates unchanged instead of being rewritten to SyntaxError, matching
PyErr_ExceptionMatches(SyntaxWarning) in compiler_warn. Drop the now-unused
CompileWarningError::into_codegen_error.

Replace the PositionalArguments two-variant enum with a struct holding a
shared range and a PositionalArgumentsKind enum.

Assisted-by: Claude

* Represent compiler flags as a CompilerFlags bitflags

Replace the loose PY_CF_*/CO_* i32 constants in compile_mode with a
CompilerFlags bitflags covering the PyCF_* flags and __future__
CO_FUTURE_* bits. The Python-visible ast.PyCF_* attribute values are
derived from it via bits(); parser input modes stay plain consts.

builtins::compile and the compile_string flag handling test flags
through CompilerFlags::contains instead of raw bit math.

Assisted-by: Claude

* Fix PR 8138 test regressions

* Fix PR 8138 CI failures

* Avoid shell interpolation in Linux deps action

* Fix review findings in compiler/AST changes

- frame.rs: compute the MATCH_CLASS class name lazily so a successful
  match no longer takes the type name lock or allocates; the
  __match_args__-not-a-tuple branch reuses it instead of recomputing.
- _ast/constant.rs: add the missing leading space to the with_recursion
  label ("maximum recursion depth exceeded during compilation").
- sys.set_int_max_str_digits: restore the "maxdigits must be 0 or larger
  than {n}" error text.
- codegen: set CO_MAXBLOCKS to 20 in both ir.rs and compile.rs.
- _ast/exception.rs: extract the duplicated excepthandler node guard
  into ensure_excepthandler_node.
- codegen: correct the validate_keywords doc comment.
- Drop redundant "CPython" qualifiers from comments added in this branch.

Assisted-by: Claude
* Update `test/signalinterproctester.py` to 3.14.6

* Add `signalinterproctester.py` as a test dependency of `test_signal.py`
* Fix all clippy suggestions in `ir.rs`

* remove some `idx()` calls
* Add more int functions to the c-api

* Simplify as_mask logic

* Add `PyLong_FromNativeBytes` & `PyLong_FromUnsignedNativeBytes`
joshuamegnauth54 and others added 21 commits August 4, 2026 16:50
Assisted-by: WarpForgeAgent:DeepSeek-v4-flash
…tPython#8452)

Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.4 to 3.1.5.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](fastify/fast-uri@v3.1.4...v3.1.5)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Validate decimal integer literals from the parser token stream before
lowering the parsed AST. Reuse the validator for normal compilation and
the `_ast` parsing path so `PyCF_ONLY_AST`, `ast.parse()`, and
`ast.literal_eval()` honor `int_max_str_digits` consistently.

Remove the now-passing `test_literal_eval_str_int_limit` expected-failure
marker. The token-based validator excludes non-decimal integers, floats,
complex literals, strings, and comments without duplicating lexer logic.

Assisted-by: Codex:gpt-5.6-sol
…ustPython#8431)

* Factor with_iframe into enter_iframe/exit_iframe helpers

Extract the frame entry (recursion check, TLS link, exception save)
and exit (materialization sync, TLS restore, GC tracking) logic
from with_iframe into standalone enter_iframe/exit_iframe methods.
with_iframe now calls them, with no behavioral change.

This prepares for the trampoline loop where enter/exit are called
individually rather than wrapped around a closure.

Assisted-by: Claude

* Allocate InterpreterFrame and LocalsPlus together on the datastack

Add InterpreterFrame::new_on_datastack() that bump-allocates both the
InterpreterFrame struct and its LocalsPlus data array in a single
datastack push, eliminating one allocation per function call.

Update datastack_frame_size_bytes_for_code() to include InterpreterFrame
size. Convert invoke_prepared_exact_args() and the invoke() fast path to
use the combined allocation.

Add release_datastack_frame() method on InterpreterFrame that drops all
localsplus values, runs field destructors (trace, temporary_refs,
retained_back, etc.), and returns the datastack base pointer for pop.

Assisted-by: Claude

* Implement trampoline loop for Python-to-Python calls

Add ExecutionResult::TailCall variant and a trampoline in
run_frame_fast that flattens Python-to-Python calls into a single
Rust stack frame instead of recursing through the eval loop.

CallPyExactArgs now prepares the callee frame on the datastack and
returns TailCall when tailcall_enabled is set (run_iframe path only).
The trampoline dispatches via a state machine (EnterCallee / ReturnValue
/ Unwind) in a single loop, avoiding mutual recursion between helper
functions that would exhaust the C stack.

Exception propagation through suspended frames uses
trampoline_handle_exception which adds traceback entries and calls
unwind_blocks on each caller.

Assisted-by: Claude

* Optimize trampoline: skip recursion check, avoid temporary_refs mutex, add bound method TailCall

- Add enter_iframe_unchecked for trampoline callee entry (recursion
  already checked by specialization_call_recursion_guard)
- Move callable ownership from per-frame temporary_refs mutex to
  trampoline-local SuspendedFrame.owned_refs via VM side channel
- Add TailCall support for CallBoundMethodExactArgs
- Move args directly from caller stack to callee fastlocals
- Read materialized pointer once in exit_iframe

Incremental call overhead: ~55 ns -> ~35 ns

Assisted-by: Claude

* Use UnsafeCell for pending_tailcall_refs

The VM is per-thread so RefCell's runtime borrow checking is
unnecessary overhead. Replace with UnsafeCell for direct access.

Assisted-by: Claude

* Remove .claude/settings.json from tracking

Assisted-by: Claude

* Replace SendPtr with Option<SendNonNull> for type-safe pending tailcall

Use NonNull + Option instead of raw *mut T with manual null checks.
The compiler enforces non-null via the type system, and Option<NonNull>
has the same size as a raw pointer thanks to niche optimization.
Also extract take_pending_tailcall helper to deduplicate the pattern.

Assisted-by: Claude

* Restrict PendingFrame to private, expose only set/take methods

Rename SendNonNull to PendingFrame and make it fully private: the
struct, its field, and the pending_tailcall_frame Cell are all
non-pub. External code accesses the side channel only through
set_pending_tailcall (pub(crate)) and take_pending_tailcall (private).

This ensures the unsafe Send+Sync impl cannot be reused elsewhere
without justifying a new safety argument.

Assisted-by: Claude

* Restore C-stack overflow check in trampoline enter_iframe_unchecked

enter_iframe_unchecked was skipping C-stack checks under the
assumption that the trampoline stays in one Rust stack frame. But
each run_iframe call still consumes Rust stack, so deep Python
recursion through the trampoline can exhaust the C stack (observed
as STATUS_STACK_OVERFLOW on Windows CI).

Keep the C-stack check (every 8th call) while still skipping the
Python recursion depth check (already done by
specialization_call_recursion_guard).

Assisted-by: Claude

* Address code review: entry frame double-free, panic safety, cleanup

- Fix double-free: mark entry frame with is_entry flag in
  SuspendedFrame so the trampoline skips its datastack release
  (the caller owns that cleanup)
- Clear iframe.previous in exit_iframe before unlinking the chain,
  matching with_frame and resume_gen_frame behavior
- Add scopeguard in with_iframe for panic safety
- Use saturating_sub(1) for lasti in trampoline_handle_exception
- Extract datastack_iframe_localsplus_offset helper to avoid
  duplicated alignment computation

Assisted-by: Claude
I left one lint (a clippy deny) unfixed because it's a lot more
involved, so I'll work on it in a different patch.
The cell type filled neither the richcompare nor the repr slot, so
object's address-based defaults showed through: cell(1) == cell(1) was
False, ordering raised TypeError, and repr rendered
<cell object at 0x...> rather than <cell at 0x...: int object at 0x...>.

Compare cells by contents, with empty cells ordering before everything
else, and render CPython's repr for both the filled and empty cases.

The comparison fills the richcompare slot directly rather than going
through Comparable, whose cmp() can only answer with a bool. CPython
returns whatever PyObject_RichCompare produced, so a contained __eq__
that yields a non-bool must pass through untouched; coercing it would
also call __bool__ and surface exceptions CPython never raises. The
empty-cell branch still answers with a bool, so both arms are needed and
the slot returns Either.

The repr truncates the contained type name the way "%.80s" does: at most
80 bytes, dropping a character the cut would leave incomplete.

Mark the type unhashable. Content-based equality combined with the
inherited identity hash would break the hash/eq contract, and hashing the
contents is not possible either because cell_contents is writable.
CPython gets this implicitly, because defining tp_richcompare suppresses
tp_hash inheritance.

Reference: CPython Objects/cellobject.c, cell_richcompare and cell_repr.

Assisted-by: Claude Code:claude-opus-5
…8464)

* Use type-specialized comparators for homogeneous list sorts

Scan the sort keys once before sorting; when every element is exactly str, int, or float, compare wtf8 bytes / BigInt / f64 directly instead of going through rich_compare_bool dispatch, mirroring CPython's pre-sort check in listsort.c (unsafe_latin_compare and friends). Subclasses and mixed-type lists keep the generic __lt__ path.

* Add edge-case tests for specialized list sorts

* Cache the richcompare slot for homogeneous list sorts

* Specialize tuple sorts on their first elements

* Apply ruff formatting to the new list sort tests

* Deduplicate the reverse swap across sort dispatch arms
…tside function scope (RustPython#8467)

CPython's _PyFrame_GetLocals only syncs fastlocals/cells into locals()
for function scope; module/class scope just returns the namespace dict
as-is. sync_visible_locals_to_mapping did this for every scope, so the
implicit __conditional_annotations__ cell (used for PEP 649/749
deferred annotations) broke two ways: at module scope its cell is
always empty, so syncing overwrote the dict's real value with None,
causing NameError on the next annotated statement; at class scope its
cell is the only real value, so syncing leaked it into locals()/dir(),
unlike CPython.

Skip cell/free slots outside function scope to match CPython, and add
a regression snippet.

Closes RustPython#8379

Assisted-by: Claude Code:claude-sonnet-5
)

* Allow automated commits through pre-commit hooks

* Fix agent C-API test instructions

Exclude rustpython-capi from root workspace test commands and run its tests from the crate directory so its Cargo configuration applies. Document the project AI policy and required commit trailer.

Assisted-by: Codex:gpt-5
According to POSIX, `time_t` should be 64 bits. `musl` changed its
`time_t` to an `i64` over five years ago. `glibc` provides compatibility
features that declare `time_t` as either `i32` or `i64`. Rustix uses the
raw Linux syscall for stat which returns an `i64`. For our purposes, an
`i64` makes sense because it's modern and avoids the year 2038 problem.
It also reduces our dependency on what `libc` defines.

Sources:
* https://www.man7.org/linux/man-pages/man3/time_t.3type.html
* https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_types.h.html
…prefix (RustPython#8473)

`search_info_literal`'s len>1 arm reset the tail-match cursor by advancing one
character past the matched prefix. That position equals the INFO block's
prefix_skip boundary only when the prefix ends where the skip does; for a
pattern like `ab(cd)`, `_get_literal_prefix` reports prefix_len=4 with
prefix_skip=2, so the tail resumed two characters too far.

`state.cursor` already holds `req.start + skip`, which is what
`sre_lib.h` SRE(search) computes as `ptr - (prefix_len - prefix_skip - 1)`,
and which the len==1 arm above already uses. Take it unconditionally.

Searching "xabcdcd" for `ab(cd)` returned span (1, 7) instead of (1, 5);
over a 600-case corpus stamped with CPython's own answers, 94 cases disagreed
before this change and none after. The wrong resume also dropped matches
outright, not only widened them.

Assisted-by: Claude
* Fix EOF SyntaxError diagnostics

* Fix Scope EOF SyntaxError location conversion

* Fix Additional Unexpected Test

* Docs Add Annotation source_location_in_code_points()
code.replace() called as_interned_str().unwrap() on its string
arguments, which panics when the caller passes a string that has not
been interned. modulefinder's replace_paths_in_code() builds a fresh
co_filename, so any use of ModuleFinder(replace_paths=...) aborted the
interpreter.

Intern the incoming strings instead, and raise TypeError rather than
panicking when a non-string appears in co_names/co_varnames/
co_cellvars/co_freevars.

Unskips test_modulefinder.test_replace_paths.

Co-authored-by: Pablo Garcia <[email protected]>
Rust supports C string literals which automatically create a CStr with a
trailing NUL. `windows-sys` provides an analogous macro for wide
strings. Both of these avoid allocations which is nice for constants.
Part of: RustPython#4583

This will enable -m test for wasi preview 1

Signed-off-by: Jiwoo Ahn <[email protected]>
Assisted-by: Codex:gpt-5.6-sol
@coderabbitai

coderabbitai Bot commented Aug 9, 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 Plus

Run ID: cf056c51-a50e-4bb4-94e3-0cfc5d7d88d1

📥 Commits

Reviewing files that changed from the base of the PR and between dca9b09 and 6e4ba86.

⛔ Files ignored due to path filters (1)
  • Lib/test/test_format.py is excluded by !Lib/**
📒 Files selected for processing (6)
  • crates/vm/src/builtins/bool.rs
  • crates/vm/src/builtins/complex.rs
  • crates/vm/src/builtins/float.rs
  • crates/vm/src/builtins/int.rs
  • crates/vm/src/builtins/str.rs
  • crates/vm/src/format.rs

📝 Walkthrough

Walkthrough

The change adds a shared VM-aware format-spec parser. Boolean, complex, float, integer, and string formatting methods now use it for parsing and error conversion.

Changes

Format-spec parsing

Layer / File(s) Summary
Shared format-spec parser
crates/vm/src/format.rs
Adds parse_format_spec, which includes the object type and original specification in invalid-specifier errors.
Built-in formatting integration
crates/vm/src/builtins/bool.rs, crates/vm/src/builtins/complex.rs, crates/vm/src/builtins/float.rs, crates/vm/src/builtins/int.rs, crates/vm/src/builtins/str.rs
Built-in __format__ methods use the shared parser and remove direct FormatSpec imports.

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

Possibly related PRs

Suggested reviewers: kangdora, youknowone

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 summarizes the main change: matching invalid format specifier error messages with CPython.
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.
✨ 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 Aug 9, 2026

Copy link
Copy Markdown
Contributor

📦 Library Dependencies

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

[x] test: cpython/Lib/test/test_format.py

dependencies:

dependent tests: (no tests depend on format)

[x] lib: cpython/Lib/ssl.py
[ ] test: cpython/Lib/test/test_ssl.py (TODO: 10)

dependencies:

  • ssl

dependent tests: (53 tests)

  • ssl: test_asyncio test_ftplib test_httplib test_httpservers test_imaplib test_logging test_poplib test_ssl test_urllib test_urllib2_localnet test_venv test_xmlrpc
    • asyncio.selector_events: test_asyncio
    • ftplib: test_urllib2
      • urllib.request: test_http_cookiejar test_pathlib test_pydoc test_sax test_site test_urllib2net test_urllibnet
    • http.client: test_docxmlrpc test_hashlib test_ucn test_unicodedata test_wsgiref
      • logging.handlers: test_concurrent_futures test_pkgutil
    • http.server: test_robotparser
      • pydoc: test_enum
    • smtplib: test_smtplib test_smtpnet
    • urllib.request:
      • pathlib: test_ast test_dbm_sqlite3 test_ensurepip test_importlib test_json test_launcher test_pathlib test_peg_generator test_pyrepl test_runpy test_tarfile test_tempfile test_tomllib test_tools test_traceback test_unparse test_winapi test_zipapp test_zipfile test_zoneinfo test_zstd

Legend:

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

@moreal moreal added the z-ca-2026 Tag to track Contribution Academy 2026 label Aug 9, 2026
@shAn-kor
shAn-kor marked this pull request as ready for review August 9, 2026 23:11
youknowone
youknowone previously approved these changes Aug 11, 2026
@youknowone
youknowone dismissed their stale review August 11, 2026 12:22

let me think once again if this is the best way

@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.

Hi! I left a change request not to make confusion to old path.
Sorry for late review!

Comment thread crates/vm/src/format.rs
}
}

pub(crate) fn parse_format_spec(

@youknowone youknowone Aug 18, 2026

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.

due to this helper, FormatSpecError::InvalidFormatSpecifier arm in impl IntoPyException for FormatSpecError is now a trap. The error message will be diverged by its calling path.
if we go this direction, I prefer to remove impl IntoPyException for FormatSpecError and bring the implementation into this helper.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

z-ca-2026 Tag to track Contribution Academy 2026

Projects

None yet

Development

Successfully merging this pull request may close these issues.