CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-wheel

Command line tool for manipulating wheel files

Overview
Eval results
Files

wheelfile-ops.mddocs/

WheelFile Operations

Core functionality for reading, writing, and manipulating wheel archives. The WheelFile class extends Python's ZipFile with wheel-specific features including hash verification, reproducible builds, and wheel format compliance.

Capabilities

WheelFile Class

A ZipFile derivative that reads SHA-256 hashes from .dist-info/RECORD and verifies file integrity during read operations.

class WheelFile(ZipFile):
    """
    A ZipFile derivative class that also reads SHA-256 hashes from
    .dist-info/RECORD and checks any read files against those.
    """
    
    def __init__(
        self,
        file: str | os.PathLike[str],
        mode: Literal["r", "w", "x", "a"] = "r",
        compression: int = ZIP_DEFLATED,
    ):
        """
        Initialize wheel file.
        
        Parameters:
        - file: Path to wheel file
        - mode: File mode ('r', 'w', 'x', 'a')
        - compression: Compression method (ZIP_DEFLATED default)
        
        Raises:
        - WheelError: If filename doesn't match wheel naming convention
        """
    
    parsed_filename: re.Match[str]
    """Regex match object containing parsed wheel filename components."""
    
    dist_info_path: str
    """Path to .dist-info directory within wheel."""
    
    record_path: str
    """Path to RECORD file within wheel."""

File Operations

Read and write files within wheel archives with automatic hash verification and generation.

def open(
    self,
    name_or_info: str | ZipInfo,
    mode: Literal["r", "w"] = "r",
    pwd: bytes | None = None,
) -> IO[bytes]:
    """
    Open file in wheel with hash verification.
    
    Parameters:
    - name_or_info: Filename or ZipInfo object
    - mode: File mode ('r' or 'w')
    - pwd: Password for encrypted files
    
    Returns:
    File-like object
    
    Raises:
    - WheelError: If file hash doesn't match RECORD or file not in RECORD
    """

def write(
    self,
    filename: str,
    arcname: str | None = None,
    compress_type: int | None = None,
) -> None:
    """
    Write file to wheel archive.
    
    Parameters:
    - filename: Path to source file
    - arcname: Archive name (uses filename if None)
    - compress_type: Compression method override
    """

def writestr(
    self,
    zinfo_or_arcname: str | ZipInfo,
    data: bytes | str,
    compress_type: int | None = None,
) -> None:
    """
    Write string or bytes data to wheel archive.
    
    Parameters:
    - zinfo_or_arcname: Archive filename or ZipInfo object
    - data: Data to write (str will be UTF-8 encoded)
    - compress_type: Compression method override
    """

def write_files(self, base_dir: str) -> None:
    """
    Write entire directory tree to wheel.
    
    Parameters:
    - base_dir: Base directory to add to wheel
    
    Note: Defers .dist-info files to write last, skips RECORD file
    """

def close(self) -> None:
    """
    Close wheel file, automatically generating RECORD file for write mode.
    """

Hash Utilities

URL-safe base64 encoding/decoding functions used for hash storage in RECORD files.

def urlsafe_b64encode(data: bytes) -> bytes:
    """
    URL-safe base64 encoding without padding.
    
    Parameters:
    - data: Bytes to encode
    
    Returns:
    Encoded bytes without '=' padding
    """

def urlsafe_b64decode(data: bytes) -> bytes:
    """
    URL-safe base64 decoding without padding.
    
    Parameters:
    - data: Encoded bytes (padding added automatically)
    
    Returns:
    Decoded bytes
    """

Reproducible Builds

Support for reproducible wheel builds using SOURCE_DATE_EPOCH environment variable.

def get_zipinfo_datetime(
    timestamp: float | None = None,
) -> tuple[int, int, int, int, int]:
    """
    Get datetime tuple for ZipInfo, supporting reproducible builds.
    
    Parameters:
    - timestamp: Unix timestamp (uses SOURCE_DATE_EPOCH env var or current time)
    
    Returns:
    Datetime tuple (year, month, day, hour, minute) for ZipInfo
    
    Note: Minimum timestamp is 1980-01-01 00:00:00 UTC (315532800)
    """

Usage Examples

Reading Wheel Contents

from wheel.wheelfile import WheelFile

with WheelFile('package-1.0-py3-none-any.whl', 'r') as wf:
    # Access parsed filename components
    name = wf.parsed_filename.group('name')
    version = wf.parsed_filename.group('ver')
    
    # List all files
    for info in wf.filelist:
        print(f"{info.filename} ({info.file_size} bytes)")
    
    # Read specific file with hash verification
    with wf.open('package/__init__.py') as f:
        content = f.read().decode('utf-8')
        print(content)

Creating New Wheel

from wheel.wheelfile import WheelFile
import os

with WheelFile('new_package-1.0-py3-none-any.whl', 'w') as wf:
    # Write files from directory (automatically generates hashes)
    wf.write_files('build/lib/')
    
    # Write individual files
    wf.write('README.txt', 'new_package-1.0.dist-info/README.txt')
    
    # Write string data
    metadata = """Name: new-package
Version: 1.0
"""
    wf.writestr('new_package-1.0.dist-info/METADATA', metadata)
    
    # RECORD file is automatically generated on close()

Reproducible Builds

import os
from wheel.wheelfile import WheelFile

# Set reproducible timestamp
os.environ['SOURCE_DATE_EPOCH'] = '1640995200'  # 2022-01-01

with WheelFile('reproducible-1.0-py3-none-any.whl', 'w') as wf:
    wf.write_files('src/')
    # All files will have the same timestamp for reproducible builds

Types

from typing import IO, Literal
from zipfile import ZipInfo
import re

class WheelError(Exception):
    """Exception raised for wheel-related errors."""
    pass

WHEEL_INFO_RE: re.Pattern[str]
"""
Regex pattern for parsing wheel filenames.
Matches: name-version(-build)?-python-abi-platform.whl
Groups: namever, name, ver, build, pyver, abi, plat
"""

MINIMUM_TIMESTAMP: int
"""Minimum timestamp for wheel files (315532800 = 1980-01-01 00:00:00 UTC)"""

Install with Tessl CLI

npx tessl i tessl/pypi-wheel

docs

cli-commands.md

index.md

package-conversion.md

tag-management.md

wheelfile-ops.md

tile.json