Skip to content

Implement negative zero coercion formatting - #8475

Merged
youknowone merged 2 commits into
RustPython:mainfrom
shAn-kor:implement-negative-zero-coercion-format
Aug 9, 2026
Merged

Implement negative zero coercion formatting#8475
youknowone merged 2 commits into
RustPython:mainfrom
shAn-kor:implement-negative-zero-coercion-format

Conversation

@shAn-kor

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

Copy link
Copy Markdown
Contributor

Related to #6839

What changed

RustPython did not support the z format option introduced by PEP 682, which removes the sign from a negative value when its formatted result rounds to zero.

The formatter now parses z after the sign option and applies it to floating point and complex formatting, including the locale-aware n path. The sign is removed only when the formatted magnitude is zero, so -0.0001 formatted with z.2f becomes 0.00 while nonzero negative results keep their sign.

Invalid uses with integer, boolean, and string formats follow CPython error behavior. Complex formatting also preserves explicit + and space signs for purely imaginary values.

The existing test_negative_zero CPython test is now enabled, with additional common-layer coverage for rounding, complex values, locale formatting, and invalid format specifications.

Tests

  • cargo test -p rustpython-common format_negative_zero_coercion
  • cargo run --release -- -m test test_format
  • cargo run --release -- -m test test_complex
  • prek run --all-files
  • repository pre-push checks, including full clippy, workspace tests, and 102 C-API tests

AI assistance

Codex (GPT-5) assisted with comparing CPython and RustPython behavior, drafting the implementation and regression tests, and writing this PR description. I reviewed the final diff and verified the behavior locally.

Summary by CodeRabbit

  • New Features
    • Added support for suppressing negative signs on zero-valued floating-point and complex-number output.
    • Added validation for character formatting options, including precision, signs, alternate form, coercion, and valid code points.
  • Bug Fixes
    • Standardized errors for unsupported formatting options and unknown boolean format types.
    • Added clear type-specific messages when negative-zero suppression is not supported.

@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: 645fc07f-c995-4f09-b024-1a1cfb5c2243

📥 Commits

Reviewing files that changed from the base of the PR and between 1819677 and 4939a3a.

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

📝 Walkthrough

Walkthrough

The formatting engine now parses the z negative-zero coercion flag. Float and complex formatting suppress negative signs for values formatted as zero. Unsupported types return a dedicated error that the VM converts to ValueError.

Changes

Negative-zero coercion

Layer / File(s) Summary
Parse and error contract
crates/common/src/format.rs
FormatSpec stores the z flag. FormatSpecError includes a type-specific rejection variant.
Formatting and validation behavior
crates/common/src/format.rs
Float and complex formatting apply negative-zero coercion. Integer, string, boolean, and character paths reject unsupported use.
Validation and exception mapping
crates/common/src/format.rs, crates/vm/src/format.rs
Tests cover parsing, coercion, locale formatting, complex values, and rejection cases. The VM converts the new error to ValueError.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PythonCode
  participant FormatSpec
  participant FloatOrComplexFormatter
  participant VMExceptionMapper

  PythonCode->>FormatSpec: parse format specification with z
  FormatSpec->>FloatOrComplexFormatter: provide no_neg_0
  FloatOrComplexFormatter-->>PythonCode: format zero without negative sign
  FormatSpec->>VMExceptionMapper: report unsupported coercion type
  VMExceptionMapper-->>PythonCode: raise ValueError
Loading

Possibly related PRs

Suggested labels: z-ca-2026

Suggested reviewers: joshuamegnauth54, youknowone

🚥 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 and concisely describes the implementation of negative-zero coercion formatting.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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] lib: cpython/Lib/reprlib.py
[x] test: cpython/Lib/test/test_reprlib.py (TODO: 1)

dependencies:

  • reprlib

dependent tests: (245 tests)

  • reprlib: test_reprlib
    • bdb: test_bdb test_pdb
    • collections: test_annotationlib test_array test_asyncio test_bisect test_builtin test_c_locale_coercion test_call test_collections test_configparser test_contains test_context test_copy test_csv test_ctypes test_defaultdict test_deque test_descr test_dict test_dictviews test_embed test_enum test_exception_group test_file test_fileinput test_fileio test_frame test_funcattrs test_functools test_genericalias test_hash test_httpservers test_inspect test_io test_ipaddress test_iter test_iterlen test_json test_logging test_math test_monitoring test_ordered_dict test_pathlib test_patma test_pickle test_plistlib test_pprint test_pydoc test_random test_richcmp test_set test_shelve test_sqlite3 test_statistics test_string test_struct test_sys test_traceback test_tuple test_types test_typing test_unittest test_urllib test_userdict test_userlist test_userstring test_weakref test_weakset test_with
      • ast: test_ast test_compile test_compiler_codegen test_dis test_fstring test_future_stmt test_peepholer test_peg_generator test_site test_ssl test_type_comments test_ucn test_unparse
      • concurrent.futures._base: test_concurrent_futures
      • dbm.dumb: test_dbm_dumb
      • dbm.sqlite3: test_dbm_sqlite3
      • difflib: test_difflib test_profile test_sys_settrace
      • dis: test__opcode test_code test_compiler_assemble test_dtrace test_opcache test_positional_only_arg test_type_cache
      • email.feedparser: test_email
      • http.client: test_docxmlrpc test_hashlib test_unicodedata test_urllib2 test_wsgiref test_xmlrpc
      • importlib.metadata: test_importlib test_zoneinfo
      • inspect: test_abc test_argparse test_asyncgen test_buffer test_clinic test_coroutines test_decimal test_generators test_grammar test_ntpath test_operator test_posixpath test_signal test_turtle test_type_annotations test_yield_from test_zipimport test_zipimport_support
      • logging: test_asyncio test_pkgutil test_support test_urllib2net
      • multiprocessing: test_asyncio test_compileall test_concurrent_futures test_fcntl test_memoryview test_multiprocessing_main_handling test_re test_socket
      • pkgutil: test_pyrepl test_runpy
      • platform: test__locale test__osx_support test_asyncio test_baseexception test_cmath test_ctypes test_mimetypes test_os test_platform test_posix test_regrtest test_shutil test_strptime test_sysconfig test_time test_winreg
      • pprint: test_htmlparser test_sys_setprofile
      • queue: test_android test_asyncio test_concurrent_futures test_dummy_thread test_sched
      • selectors: test_asyncio test_selectors test_subprocess
      • shlex: test_shlex test_venv test_webbrowser
      • shutil: test_bz2 test_ctypes test_filecmp test_glob test_importlib test_largefile test_launcher test_modulefinder test_peg_generator test_py_compile test_sax test_string_literals test_tarfile test_tempfile test_unicode_file
      • ssl: test_ftplib test_httplib test_imaplib test_poplib test_urllib2_localnet
      • string: test_email test_fnmatch test_grp test_importlib test_mmap test_pwd test_pyrepl test_secrets test_string test_tokenize test_zipfile
      • threading: test_asyncio test_bytes test_concurrent_futures test_contextlib test_ctypes test_external_inspection test_fork1 test_gc test_importlib test_ioctl test_itertools test_linecache test_pathlib test_poll test_pyrepl test_queue test_robotparser test_smtplib test_socketserver test_super test_syslog test_termios test_threadedtempfile test_threading test_threading_local test_zstd
      • tokenize: test_tabnanny
      • traceback: test_asyncio test_code_module test_contextlib_async test_dictcomps test_exceptions test_http_cookiejar test_importlib test_listcomps test_pyexpat test_setcomps test_unittest
      • tracemalloc: test_tracemalloc
      • urllib.parse: test_http_cookies test_urllibnet test_urlparse
      • wave: test_wave
      • xml.etree.ElementTree: test_doctest
    • dataclasses: test__colorize test_ctypes
      • pstats: test_pstats

[x] test: cpython/Lib/test/test_funcattrs.py (TODO: 2)

dependencies:

dependent tests: (no tests depend on funcattrs)

[x] test: cpython/Lib/test/test_format.py (TODO: 3)

dependencies:

dependent tests: (no tests depend on format)

Legend:

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

@youknowone youknowone added the z-ca-2026 Tag to track Contribution Academy 2026 label Aug 9, 2026

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

👍

@youknowone
youknowone merged commit 12a0a1e into RustPython:main Aug 9, 2026
28 checks passed
kyokuping pushed a commit to kyokuping/RustPython that referenced this pull request Aug 9, 2026
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.

2 participants