Skip to content

Add SHA3 private attribute parity to hashlib hash objects#7134

Merged
youknowone merged 1 commit intoRustPython:mainfrom
moreal:fix/fail-hashlib-test_extra_sha3
Feb 14, 2026
Merged

Add SHA3 private attribute parity to hashlib hash objects#7134
youknowone merged 1 commit intoRustPython:mainfrom
moreal:fix/fail-hashlib-test_extra_sha3

Conversation

@moreal
Copy link
Contributor

@moreal moreal commented Feb 14, 2026

Summary by CodeRabbit

  • New Features
    • HASH and HASHXOF objects now expose additional metadata properties: capacity bits, rate bits, and suffix information for Keccak-based hash algorithms.

@moreal moreal self-assigned this Feb 14, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 14, 2026

📝 Walkthrough

Walkthrough

This PR introduces Keccak-related helper functions and constants to the hashlib module, then exposes Keccak metadata properties (capacity bits, rate bits, suffix byte) on PyHasher and PyHasherXof classes.

Changes

Cohort / File(s) Summary
Keccak Constants and Helpers
crates/stdlib/src/hashlib.rs
Added KECCAK_WIDTH_BITS constant and four private helper functions: keccak_suffix(), keccak_rate_bits(), keccak_capacity_bits(), and missing_hash_attribute() for Keccak metadata computation.
PyHasher and PyHasherXof Enhancements
crates/stdlib/src/hashlib.rs
Added three new Python-facing computed properties to PyHasher and PyHasherXof: _capacity_bits(), _rate_bits(), and _suffix() to expose Keccak metadata with fallback error handling.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • youknowone

Poem

🐰 A hasher's delight, so crisp and clean,
Keccak secrets now are seen,
Capacity, rate, and suffix too—
Python's metadata dreams come true! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (8 files):

⚔️ Lib/test/test_class.py (content)
⚔️ Lib/test/test_codecs.py (content)
⚔️ Lib/test/test_descr.py (content)
⚔️ Lib/test/test_hashlib.py (content)
⚔️ Lib/test/test_itertools.py (content)
⚔️ Lib/test/test_pickle.py (content)
⚔️ crates/stdlib/src/hashlib.rs (content)
⚔️ crates/vm/src/builtins/object.rs (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (2 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 change: adding private attributes (_capacity_bits, _rate_bits, _suffix) to PyHasher and PyHasherXof classes for SHA3/Keccak parity.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch fix/fail-hashlib-test_extra_sha3
  • Post resolved changes as copyable diffs in a comment

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
crates/stdlib/src/hashlib.rs (2)

157-181: Properties are correct; consider .ok_or_else() for conciseness.

Minor style nit: the match + Some/None pattern could be slightly more concise with .ok_or_else().

fn _capacity_bits(&self, vm: &VirtualMachine) -> PyResult<usize> {
    let block_size = self.ctx.read().block_size();
    keccak_capacity_bits(&self.name, block_size)
        .ok_or_else(|| vm.new_attribute_error(format!("'HASH' object has no attribute '_capacity_bits'")))
}

This is purely stylistic — the current form is clear too.


256-280: Duplicated property bodies between PyHasher and PyHasherXof.

These three properties are identical to their PyHasher counterparts (lines 157–181), differing only in the "HASHXOF" vs "HASH" class name string. Given the #[pyclass] macro constraints, full dedup is awkward, but you could extract thin helpers that accept the class name:

♻️ Example dedup
fn get_capacity_bits(name: &str, block_size: usize, class_name: &str, vm: &VirtualMachine) -> PyResult<usize> {
    keccak_capacity_bits(name, block_size)
        .ok_or_else(|| vm.new_attribute_error(format!("'{class_name}' object has no attribute '_capacity_bits'")))
}

fn get_rate_bits(name: &str, block_size: usize, class_name: &str, vm: &VirtualMachine) -> PyResult<usize> {
    keccak_rate_bits(name, block_size)
        .ok_or_else(|| vm.new_attribute_error(format!("'{class_name}' object has no attribute '_rate_bits'")))
}

fn get_suffix(name: &str, class_name: &str, vm: &VirtualMachine) -> PyResult<PyBytes> {
    keccak_suffix(name)
        .map(|s| vec![s].into())
        .ok_or_else(|| vm.new_attribute_error(format!("'{class_name}' object has no attribute '_suffix'")))
}

Then each #[pygetset] becomes a one-liner delegating to the shared helper.

As per coding guidelines, "When branches differ only in a value but share common logic, extract the differing value first, then call the common logic once to avoid duplicate code."


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.

@github-actions
Copy link
Contributor

📦 Library Dependencies

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

[ ] test: cpython/Lib/test/test_class.py (TODO: 16)
[x] test: cpython/Lib/test/test_genericclass.py
[x] test: cpython/Lib/test/test_subclassinit.py

dependencies:

dependent tests: (no tests depend on class)

[x] lib: cpython/Lib/codecs.py
[ ] test: cpython/Lib/test/test_codecs.py (TODO: 11)
[ ] test: cpython/Lib/test/test_codeccallbacks.py (TODO: 9)
[ ] test: cpython/Lib/test/test_codecencodings_cn.py
[ ] test: cpython/Lib/test/test_codecencodings_hk.py
[ ] test: cpython/Lib/test/test_codecencodings_iso2022.py
[ ] test: cpython/Lib/test/test_codecencodings_jp.py
[ ] test: cpython/Lib/test/test_codecencodings_kr.py
[ ] test: cpython/Lib/test/test_codecencodings_tw.py
[ ] test: cpython/Lib/test/test_codecmaps_cn.py
[ ] test: cpython/Lib/test/test_codecmaps_hk.py
[ ] test: cpython/Lib/test/test_codecmaps_jp.py
[ ] test: cpython/Lib/test/test_codecmaps_kr.py
[ ] test: cpython/Lib/test/test_codecmaps_tw.py
[ ] test: cpython/Lib/test/test_charmapcodec.py
[ ] test: cpython/Lib/test/test_multibytecodec.py

dependencies:

  • codecs

dependent tests: (124 tests)

  • codecs: test_charmapcodec test_codeccallbacks test_codecs test_eof test_exceptions test_importlib test_io test_json test_locale test_logging test_os test_plistlib test_str test_sys
    • encodings:
      • locale: test__locale test_builtin test_c_locale_coercion test_calendar test_decimal test_format test_re test_regrtest test_types test_utf8_mode
    • json: test_subprocess test_sysconfig test_tomllib test_tools test_traceback test_zoneinfo
      • importlib.metadata: test_importlib
    • pickle: test_annotationlib test_array test_asyncio test_bytes test_bz2 test_collections test_concurrent_futures test_coroutines test_csv test_ctypes test_defaultdict test_deque test_descr test_dict test_dictviews test_email test_enum test_enumerate test_fractions test_functools test_generators test_genericalias test_http_cookies test_inspect test_ipaddress test_iter test_itertools test_list test_lzma test_memoryio test_memoryview test_opcache test_operator test_ordered_dict test_pathlib test_pickle test_pickletools test_platform test_positional_only_arg test_posix test_random test_range test_set test_shelve test_slice test_socket test_statistics test_string test_trace test_tuple test_type_aliases test_type_params test_typing test_unittest test_uuid test_xml_dom_minicompat test_xml_etree test_zipfile test_zlib test_zoneinfo
      • logging.handlers: test_concurrent_futures
    • tokenize: test_linecache test_tabnanny test_tokenize test_unparse
      • inspect: test_abc test_argparse test_asyncgen test_buffer test_code test_grammar test_ntpath test_patma test_posixpath test_pydoc test_signal test_type_annotations test_yield_from test_zipimport
      • traceback: test_asyncio test_code_module test_contextlib test_contextlib_async test_dictcomps test_importlib test_listcomps test_pyexpat test_setcomps test_ssl test_threadedtempfile test_threading test_unittest test_with

[ ] test: cpython/Lib/test/test_descr.py (TODO: 49)
[ ] test: cpython/Lib/test/test_descrtut.py (TODO: 1)

dependencies:

dependent tests: (no tests depend on descr)

[ ] lib: cpython/Lib/hashlib.py
[ ] test: cpython/Lib/test/test_hashlib.py (TODO: 9)

dependencies:

  • hashlib

dependent tests: (15 tests)

  • hashlib: test_hashlib test_hmac test_smtplib test_tarfile test_unicodedata test_urllib2_localnet
    • urllib.request: test_http_cookiejar test_pathlib test_pydoc test_site test_ssl test_urllib test_urllib2 test_urllib2net test_urllibnet

[ ] test: cpython/Lib/test/test_itertools.py (TODO: 27)

dependencies:

dependent tests: (46 tests)

  • itertools: test_annotationlib test_ast test_asyncio test_bdb test_buffer test_builtin test_call test_codeccallbacks test_collections test_concurrent_futures test_csv test_descr test_dis test_email test_exceptions test_functools test_genericalias test_hashlib test_heapq test_httplib test_importlib test_io test_iterlen test_itertools test_logging test_math test_memoryview test_mmap test_os test_peepholer test_pprint test_queue test_range test_set test_shlex test_slice test_socket test_statistics test_str test_struct test_subprocess test_typing test_unittest test_uuid test_xml_etree test_zipfile

[x] lib: cpython/Lib/pickle.py
[ ] lib: cpython/Lib/_compat_pickle.py
[ ] test: cpython/Lib/test/test_pickle.py (TODO: 21)
[ ] test: cpython/Lib/test/test_picklebuffer.py (TODO: 12)
[ ] test: cpython/Lib/test/test_pickletools.py (TODO: 8)

dependencies:

  • pickle (native: itertools, sys)
    • _compat_pickle
    • _compat_pickle
    • types
    • codecs, copyreg, functools, io, struct

dependent tests: (72 tests)

  • pickle: test_annotationlib test_array test_asyncio test_builtin test_bytes test_bz2 test_codecs test_collections test_concurrent_futures test_coroutines test_csv test_ctypes test_decimal test_defaultdict test_deque test_descr test_dict test_dictviews test_email test_enum test_enumerate test_exceptions test_fractions test_functools test_generators test_genericalias test_http_cookies test_importlib test_inspect test_io test_ipaddress test_iter test_itertools test_list test_logging test_lzma test_memoryio test_memoryview test_opcache test_operator test_ordered_dict test_os test_pathlib test_pickle test_pickletools test_platform test_plistlib test_positional_only_arg test_posix test_random test_range test_set test_shelve test_slice test_socket test_statistics test_str test_string test_trace test_tuple test_type_aliases test_type_params test_types test_typing test_unittest test_uuid test_xml_dom_minicompat test_xml_etree test_zipfile test_zlib test_zoneinfo
    • logging.handlers: test_concurrent_futures

Legend:

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

@moreal moreal marked this pull request as ready for review February 14, 2026 12:20
@youknowone youknowone merged commit 16c7439 into RustPython:main Feb 14, 2026
14 checks passed
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