CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-bitstruct

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

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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')

docs

index.md

tile.json