Wheel包RECORD文件SHA256哈希生成逻辑及Python实现问询
Let's break down how the SHA256 hash values in a wheel's RECORD file are generated, including the exact Python implementation logic you're looking for.
Core Generation Steps
The hash format follows the PEP 427 specification (the standard for wheel packages). Here's the step-by-step process:
- Compute the binary SHA256 digest of the file's raw content (not the hexadecimal string output from
sha256sum). - Encode the digest with URL-safe Base64: This automatically replaces
+with-and/with_to avoid URL-unsafe characters. - Strip padding characters: Base64 encoding adds
=at the end for alignment; we remove these to get the final 43-character hash string. - Calculate file size: The total number of bytes in the file (equivalent to running
wc -c <file).
Python Implementation Logic
The actual code lives in the official wheel package (used by setuptools when building wheels). Here's a simplified version of the core logic from the wheel/wheelfile.py module:
import hashlib import base64 def generate_record_entry(file_obj): # Calculate SHA256 digest in chunks (memory-efficient for large files) sha256 = hashlib.sha256() chunk_size = 16384 # 16KB chunks while chunk := file_obj.read(chunk_size): sha256.update(chunk) digest = sha256.digest() # URL-safe Base64 encode, strip padding, convert to ASCII string hash_value = base64.urlsafe_b64encode(digest).rstrip(b'=').decode('ascii') # Get file size (position after reading the entire file) file_size = str(file_obj.tell()) return hash_value, file_size
Why Your Test Command Differed
When you ran:
python3 -c "import hashlib; import base64; print(base64.b64encode(hashlib.sha256(open('WHEEL', 'rb').read()).digest()))"
You got a result with a trailing = because you used standard Base64 encoding (base64.b64encode) instead of the URL-safe variant. The wheel implementation uses base64.urlsafe_b64encode (which handles the +/ → -/_ replacement automatically) and strips the trailing = padding, resulting in the exact 43-character string you see in RECORD.
Verifying the Match
If you adjust your test command to match the wheel logic, you'll get the exact hash from your RECORD line:
python3 -c "import hashlib; import base64; print(base64.urlsafe_b64encode(hashlib.sha256(open('WHEEL', 'rb').read()).digest()).rstrip(b'=').decode('ascii'))"
This will output X8kVdBCq85ICewwfaE6btv5qKsFQfVq8NYJIXUK0i1A—matching the value in your example perfectly.
Where to Find the Full Source
The official implementation is in the wheel package's wheelfile.py module, specifically in the _add_to_record method. When you use setuptools to build a wheel, it delegates the RECORD file generation to this wheel library code.
内容的提问来源于stack exchange,提问作者Mizux

