or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/pypi-bitstruct

Python library for converting between Python values and C bit field structs represented as byte strings.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/bitstruct@8.21.x

To install, run

npx @tessl/cli install tessl/pypi-bitstruct@8.21.0

index.mddocs/

Bitstruct

A Python library for converting between Python values and C bit field structs represented as byte strings. Bitstruct provides functionality similar to the built-in struct module but operates on individual bits instead of primitive data types, enabling precise bit-level data manipulation for binary protocols, embedded systems, and specialized data formats.

Package Information

  • Package Name: bitstruct
  • Language: Python
  • Installation: pip install bitstruct

Core Imports

import bitstruct

Common usage patterns:

from bitstruct import *  # Import all functions

For better performance (C extension):

import bitstruct.c as bitstruct  # Optional C implementation

Basic Usage

import bitstruct

# Pack values into bytes using format string
packed = bitstruct.pack('u1u3u4s16', 1, 2, 3, -4)
print(packed)  # b'\xa3\xff\xfc'

# Unpack bytes back to values
unpacked = bitstruct.unpack('u1u3u4s16', packed)
print(unpacked)  # (1, 2, 3, -4)

# Calculate the size in bits for a format
size = bitstruct.calcsize('u1u3u4s16')
print(size)  # 24 bits

# Use compiled format for repeated operations
cf = bitstruct.compile('u1u3u4s16')
packed = cf.pack(1, 2, 3, -4)
unpacked = cf.unpack(packed)

Format String Specification

Format strings define the bit layout using type-length combinations:

  • Bit Order: > (MSB first, default) or < (LSB first)
  • Byte Order: > (big endian, default) or < (little endian) as suffix
  • Types:
    • u - unsigned integer
    • s - signed integer
    • f - floating point (16, 32, or 64 bits)
    • b - boolean
    • t - text (ASCII or UTF-8)
    • r - raw bytes
    • p - padding with zeros (ignored)
    • P - padding with ones (ignored)

Example format strings:

  • 'u1u3u4s16' - 1-bit uint, 3-bit uint, 4-bit uint, 16-bit signed int
  • '<u1u3u4s16<' - Same with LSB bit order and little endian byte order
  • 'u5s5f32b1r13t40' - Mixed types including float, boolean, raw, and text

Capabilities

Pack Functions

Convert Python values to bytes according to format strings.

def pack(fmt: str, *args) -> bytes:
    """Pack values into bytes according to format string."""

def pack_into(fmt: str, buf: bytearray, offset: int, *args, **kwargs) -> None:
    """Pack values into existing buffer at bit offset."""

def pack_dict(fmt: str, names: list[str], data: dict) -> bytes:
    """Pack values from dictionary using field names."""

def pack_into_dict(fmt: str, names: list[str], buf: bytearray, offset: int, data: dict, **kwargs) -> None:
    """Pack dictionary values into buffer at bit offset."""

Unpack Functions

Convert bytes to Python values according to format strings.

def unpack(fmt: str, data: bytes, allow_truncated: bool = False, text_encoding: str = 'utf-8', text_errors: str = 'strict') -> tuple:
    """Unpack bytes according to format string."""

def unpack_from(fmt: str, data: bytes, offset: int = 0, allow_truncated: bool = False, text_encoding: str = 'utf-8', text_errors: str = 'strict') -> tuple:
    """Unpack from bytes starting at bit offset."""

def unpack_dict(fmt: str, names: list[str], data: bytes, allow_truncated: bool = False, text_encoding: str = 'utf-8', text_errors: str = 'strict') -> dict:
    """Unpack bytes to dictionary using field names."""

def unpack_from_dict(fmt: str, names: list[str], data: bytes, offset: int = 0, allow_truncated: bool = False, text_encoding: str = 'utf-8', text_errors: str = 'strict') -> dict:
    """Unpack from bytes to dictionary starting at bit offset."""

Utility Functions

Additional operations for format analysis and byte manipulation.

def calcsize(fmt: str) -> int:
    """Return the number of bits in given format string."""

def byteswap(fmt: str, data: bytes, offset: int = 0) -> bytes:
    """Swap bytes in data according to format."""

def compile(fmt: str, names: list[str] = None, text_encoding: str = 'utf-8', text_errors: str = 'strict') -> CompiledFormat | CompiledFormatDict:
    """Compile format string for repeated use."""

Compiled Format Classes

Pre-compiled format objects for efficient repeated operations.

class CompiledFormat:
    """Compiled format string for tuple-based pack/unpack operations."""
    
    def __init__(self, fmt: str, text_encoding: str = 'utf-8', text_errors: str = 'strict'): ...
    
    def pack(self, *args) -> bytes:
        """Pack values using compiled format."""
    
    def unpack(self, data: bytes, allow_truncated: bool = False) -> tuple:
        """Unpack using compiled format."""
    
    def pack_into(self, buf: bytearray, offset: int, *args, **kwargs) -> None:
        """Pack into buffer using compiled format."""
    
    def unpack_from(self, data: bytes, offset: int = 0, allow_truncated: bool = False) -> tuple:
        """Unpack from offset using compiled format."""
    
    def calcsize(self) -> int:
        """Return the number of bits in the compiled format."""

class CompiledFormatDict:
    """Compiled format string for dictionary-based pack/unpack operations."""
    
    def pack(self, data: dict) -> bytes:
        """Pack from dictionary using compiled format."""
    
    def unpack(self, data: bytes, allow_truncated: bool = False) -> dict:
        """Unpack to dictionary using compiled format."""
    
    def pack_into(self, buf: bytearray, offset: int, data: dict, **kwargs) -> None:
        """Pack dictionary into buffer using compiled format."""
    
    def unpack_from(self, data: bytes, offset: int = 0, allow_truncated: bool = False) -> dict:
        """Unpack to dictionary from offset using compiled format."""

Exception Types

Package-specific exceptions for error handling.

class Error(Exception):
    """Package-specific exception for bitstruct errors."""

Usage Examples

Working with Mixed Data Types

import bitstruct

# Pack unsigned int, signed int, float, boolean, raw bytes, and text
packed = bitstruct.pack('u5s5f32b1r13t40', 1, -1, 3.75, True, b'\xff\xff', 'hello')
print(packed)  # b'\x0f\xd0\x1c\x00\x00?\xffhello'

# Unpack the same data
unpacked = bitstruct.unpack('u5s5f32b1r13t40', packed)
print(unpacked)  # (1, -1, 3.75, True, b'\xff\xf8', 'hello')

Dictionary-based Packing

import bitstruct

# Define field names
names = ['a', 'b', 'c', 'd']
data = {'a': 1, 'b': 2, 'c': 3, 'd': -4}

# Pack from dictionary
packed = bitstruct.pack_dict('u1u3u4s16', names, data)
print(packed)  # b'\xa3\xff\xfc'

# Unpack to dictionary
unpacked = bitstruct.unpack_dict('u1u3u4s16', names, packed)
print(unpacked)  # {'a': 1, 'b': 2, 'c': 3, 'd': -4}

Bit Offset Operations

import bitstruct

# Pack into existing buffer at bit offset
data = bytearray(b'\x00\x00\x00\x00')
bitstruct.pack_into('u1u3u4s16', data, 5, 1, 2, 3, -4)
print(data)  # bytearray(b'\x05\x1f\xff\xe0')

# Unpack from bit offset
unpacked = bitstruct.unpack_from('u1u3u4s16', data, 5)
print(unpacked)  # (1, 2, 3, -4)

Compiled Format Usage

import bitstruct

# Compile format for repeated use
cf = bitstruct.compile('u1u3u4s16')

# Use compiled format multiple times
packed1 = cf.pack(1, 2, 3, -4)
packed2 = cf.pack(0, 7, 15, 32767)

unpacked1 = cf.unpack(packed1)
unpacked2 = cf.unpack(packed2)

print(f"Size: {cf.calcsize()} bits")  # Size: 24 bits

Endianness Control

import bitstruct

# Big endian (default)
packed_be = bitstruct.pack('u1u3u4s16', 1, 2, 3, 1)

# Little endian
packed_le = bitstruct.pack('<u1u3u4s16<', 1, 2, 3, 1)

# Change byte order with byteswap
swapped = bitstruct.byteswap('12', packed_be)
unpacked_swapped = bitstruct.unpack('u1u3u4s16', swapped)
print(unpacked_swapped)  # (1, 2, 3, 256)

Performance Notes

  • Pure Python: Default implementation in main bitstruct module
  • C Extension: Optional bitstruct.c module for better performance
    • Import with import bitstruct.c as bitstruct
    • Limitations: 64-bit max integers/booleans, text/raw must be multiples of 8 bits
  • Compiled Formats: Use compile() for repeated operations to avoid re-parsing format strings

Error Handling

The library raises bitstruct.Error for:

  • Invalid format strings
  • Value range errors (e.g., integer too large for specified bit width)
  • Buffer size mismatches
  • Text encoding/decoding errors (controlled by text_encoding and text_errors parameters)

Constants

__version__: str  # Package version string (currently '8.21.0')