Python library for converting between Python values and C bit field structs represented as byte strings.
npx @tessl/cli install tessl/pypi-bitstruct@8.21.00
# Bitstruct
1
2
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.
3
4
## Package Information
5
6
- **Package Name**: bitstruct
7
- **Language**: Python
8
- **Installation**: `pip install bitstruct`
9
10
## Core Imports
11
12
```python
13
import bitstruct
14
```
15
16
Common usage patterns:
17
18
```python
19
from bitstruct import * # Import all functions
20
```
21
22
For better performance (C extension):
23
24
```python
25
import bitstruct.c as bitstruct # Optional C implementation
26
```
27
28
## Basic Usage
29
30
```python
31
import bitstruct
32
33
# Pack values into bytes using format string
34
packed = bitstruct.pack('u1u3u4s16', 1, 2, 3, -4)
35
print(packed) # b'\xa3\xff\xfc'
36
37
# Unpack bytes back to values
38
unpacked = bitstruct.unpack('u1u3u4s16', packed)
39
print(unpacked) # (1, 2, 3, -4)
40
41
# Calculate the size in bits for a format
42
size = bitstruct.calcsize('u1u3u4s16')
43
print(size) # 24 bits
44
45
# Use compiled format for repeated operations
46
cf = bitstruct.compile('u1u3u4s16')
47
packed = cf.pack(1, 2, 3, -4)
48
unpacked = cf.unpack(packed)
49
```
50
51
## Format String Specification
52
53
Format strings define the bit layout using type-length combinations:
54
55
- **Bit Order**: `>` (MSB first, default) or `<` (LSB first)
56
- **Byte Order**: `>` (big endian, default) or `<` (little endian) as suffix
57
- **Types**:
58
- `u` - unsigned integer
59
- `s` - signed integer
60
- `f` - floating point (16, 32, or 64 bits)
61
- `b` - boolean
62
- `t` - text (ASCII or UTF-8)
63
- `r` - raw bytes
64
- `p` - padding with zeros (ignored)
65
- `P` - padding with ones (ignored)
66
67
Example format strings:
68
- `'u1u3u4s16'` - 1-bit uint, 3-bit uint, 4-bit uint, 16-bit signed int
69
- `'<u1u3u4s16<'` - Same with LSB bit order and little endian byte order
70
- `'u5s5f32b1r13t40'` - Mixed types including float, boolean, raw, and text
71
72
## Capabilities
73
74
### Pack Functions
75
76
Convert Python values to bytes according to format strings.
77
78
```python { .api }
79
def pack(fmt: str, *args) -> bytes:
80
"""Pack values into bytes according to format string."""
81
82
def pack_into(fmt: str, buf: bytearray, offset: int, *args, **kwargs) -> None:
83
"""Pack values into existing buffer at bit offset."""
84
85
def pack_dict(fmt: str, names: list[str], data: dict) -> bytes:
86
"""Pack values from dictionary using field names."""
87
88
def pack_into_dict(fmt: str, names: list[str], buf: bytearray, offset: int, data: dict, **kwargs) -> None:
89
"""Pack dictionary values into buffer at bit offset."""
90
```
91
92
### Unpack Functions
93
94
Convert bytes to Python values according to format strings.
95
96
```python { .api }
97
def unpack(fmt: str, data: bytes, allow_truncated: bool = False, text_encoding: str = 'utf-8', text_errors: str = 'strict') -> tuple:
98
"""Unpack bytes according to format string."""
99
100
def unpack_from(fmt: str, data: bytes, offset: int = 0, allow_truncated: bool = False, text_encoding: str = 'utf-8', text_errors: str = 'strict') -> tuple:
101
"""Unpack from bytes starting at bit offset."""
102
103
def unpack_dict(fmt: str, names: list[str], data: bytes, allow_truncated: bool = False, text_encoding: str = 'utf-8', text_errors: str = 'strict') -> dict:
104
"""Unpack bytes to dictionary using field names."""
105
106
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:
107
"""Unpack from bytes to dictionary starting at bit offset."""
108
```
109
110
### Utility Functions
111
112
Additional operations for format analysis and byte manipulation.
113
114
```python { .api }
115
def calcsize(fmt: str) -> int:
116
"""Return the number of bits in given format string."""
117
118
def byteswap(fmt: str, data: bytes, offset: int = 0) -> bytes:
119
"""Swap bytes in data according to format."""
120
121
def compile(fmt: str, names: list[str] = None, text_encoding: str = 'utf-8', text_errors: str = 'strict') -> CompiledFormat | CompiledFormatDict:
122
"""Compile format string for repeated use."""
123
```
124
125
### Compiled Format Classes
126
127
Pre-compiled format objects for efficient repeated operations.
128
129
```python { .api }
130
class CompiledFormat:
131
"""Compiled format string for tuple-based pack/unpack operations."""
132
133
def __init__(self, fmt: str, text_encoding: str = 'utf-8', text_errors: str = 'strict'): ...
134
135
def pack(self, *args) -> bytes:
136
"""Pack values using compiled format."""
137
138
def unpack(self, data: bytes, allow_truncated: bool = False) -> tuple:
139
"""Unpack using compiled format."""
140
141
def pack_into(self, buf: bytearray, offset: int, *args, **kwargs) -> None:
142
"""Pack into buffer using compiled format."""
143
144
def unpack_from(self, data: bytes, offset: int = 0, allow_truncated: bool = False) -> tuple:
145
"""Unpack from offset using compiled format."""
146
147
def calcsize(self) -> int:
148
"""Return the number of bits in the compiled format."""
149
150
class CompiledFormatDict:
151
"""Compiled format string for dictionary-based pack/unpack operations."""
152
153
def pack(self, data: dict) -> bytes:
154
"""Pack from dictionary using compiled format."""
155
156
def unpack(self, data: bytes, allow_truncated: bool = False) -> dict:
157
"""Unpack to dictionary using compiled format."""
158
159
def pack_into(self, buf: bytearray, offset: int, data: dict, **kwargs) -> None:
160
"""Pack dictionary into buffer using compiled format."""
161
162
def unpack_from(self, data: bytes, offset: int = 0, allow_truncated: bool = False) -> dict:
163
"""Unpack to dictionary from offset using compiled format."""
164
```
165
166
### Exception Types
167
168
Package-specific exceptions for error handling.
169
170
```python { .api }
171
class Error(Exception):
172
"""Package-specific exception for bitstruct errors."""
173
```
174
175
## Usage Examples
176
177
### Working with Mixed Data Types
178
179
```python
180
import bitstruct
181
182
# Pack unsigned int, signed int, float, boolean, raw bytes, and text
183
packed = bitstruct.pack('u5s5f32b1r13t40', 1, -1, 3.75, True, b'\xff\xff', 'hello')
184
print(packed) # b'\x0f\xd0\x1c\x00\x00?\xffhello'
185
186
# Unpack the same data
187
unpacked = bitstruct.unpack('u5s5f32b1r13t40', packed)
188
print(unpacked) # (1, -1, 3.75, True, b'\xff\xf8', 'hello')
189
```
190
191
### Dictionary-based Packing
192
193
```python
194
import bitstruct
195
196
# Define field names
197
names = ['a', 'b', 'c', 'd']
198
data = {'a': 1, 'b': 2, 'c': 3, 'd': -4}
199
200
# Pack from dictionary
201
packed = bitstruct.pack_dict('u1u3u4s16', names, data)
202
print(packed) # b'\xa3\xff\xfc'
203
204
# Unpack to dictionary
205
unpacked = bitstruct.unpack_dict('u1u3u4s16', names, packed)
206
print(unpacked) # {'a': 1, 'b': 2, 'c': 3, 'd': -4}
207
```
208
209
### Bit Offset Operations
210
211
```python
212
import bitstruct
213
214
# Pack into existing buffer at bit offset
215
data = bytearray(b'\x00\x00\x00\x00')
216
bitstruct.pack_into('u1u3u4s16', data, 5, 1, 2, 3, -4)
217
print(data) # bytearray(b'\x05\x1f\xff\xe0')
218
219
# Unpack from bit offset
220
unpacked = bitstruct.unpack_from('u1u3u4s16', data, 5)
221
print(unpacked) # (1, 2, 3, -4)
222
```
223
224
### Compiled Format Usage
225
226
```python
227
import bitstruct
228
229
# Compile format for repeated use
230
cf = bitstruct.compile('u1u3u4s16')
231
232
# Use compiled format multiple times
233
packed1 = cf.pack(1, 2, 3, -4)
234
packed2 = cf.pack(0, 7, 15, 32767)
235
236
unpacked1 = cf.unpack(packed1)
237
unpacked2 = cf.unpack(packed2)
238
239
print(f"Size: {cf.calcsize()} bits") # Size: 24 bits
240
```
241
242
### Endianness Control
243
244
```python
245
import bitstruct
246
247
# Big endian (default)
248
packed_be = bitstruct.pack('u1u3u4s16', 1, 2, 3, 1)
249
250
# Little endian
251
packed_le = bitstruct.pack('<u1u3u4s16<', 1, 2, 3, 1)
252
253
# Change byte order with byteswap
254
swapped = bitstruct.byteswap('12', packed_be)
255
unpacked_swapped = bitstruct.unpack('u1u3u4s16', swapped)
256
print(unpacked_swapped) # (1, 2, 3, 256)
257
```
258
259
## Performance Notes
260
261
- **Pure Python**: Default implementation in main `bitstruct` module
262
- **C Extension**: Optional `bitstruct.c` module for better performance
263
- Import with `import bitstruct.c as bitstruct`
264
- Limitations: 64-bit max integers/booleans, text/raw must be multiples of 8 bits
265
- **Compiled Formats**: Use `compile()` for repeated operations to avoid re-parsing format strings
266
267
## Error Handling
268
269
The library raises `bitstruct.Error` for:
270
- Invalid format strings
271
- Value range errors (e.g., integer too large for specified bit width)
272
- Buffer size mismatches
273
- Text encoding/decoding errors (controlled by `text_encoding` and `text_errors` parameters)
274
275
## Constants
276
277
```python { .api }
278
__version__: str # Package version string (currently '8.21.0')
279
```