Skip to content

Commit

Permalink
rename '?' to 'b', and 'b' to 'r'
Browse files Browse the repository at this point in the history
Renaming of the boolean and the bytearray format string letters. This is a _non_ backwards compatile change.
  • Loading branch information
eerimoq committed Dec 10, 2015
1 parent 1b8b180 commit 82f89a6
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 35 deletions.
37 changes: 28 additions & 9 deletions bitstruct.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@


def _parse_format(fmt):
types = re.findall(r'[a-zA-Z?]+', fmt)
types = re.findall(r'[a-zA-Z]+', fmt)
sizes = map(lambda size: int(size),
re.findall(r'\d+', fmt))

return zip(types, sizes)


def _pack_integer(size, arg):
if arg < 0:
arg = ((1 << size) + arg)

return '{{:0{}b}}'.format(size).format(arg)


Expand All @@ -33,30 +35,36 @@ def _pack_float(size, arg):
def _pack_bytearray(size, arg):
bits = ''.join('{:08b}'.format(b)
for b in arg)

return bits[0:size]


def _unpack_integer(type, bits):
value = int(bits, 2)

if type == 's':
if bits[0] == '1':
value -= (1 << len(bits))

return value


def _unpack_boolean(bits):
value = _unpack_integer('u', bits)

return bool(value)


def _unpack_float(size, bits):
packed = _unpack_bytearray(size, bits)

if size == 32:
value = struct.unpack('>f', packed)[0]
elif size == 64:
value = struct.unpack('>d', packed)[0]
else:
raise ValueError('Bad float size {}. Must be 32 or 64 bits.'.format(size))

return value

def _unpack_bytearray(size, bits):
Expand All @@ -79,23 +87,25 @@ def pack(fmt, *args):
:param args: Variable argument list of values to pack.
:returns: Bytearray of packed values.
`fmt` is a string of type-length pairs. There are five
types; 'u', 's', 'f', 'b', '?' and 'p'. Length is the number of bits to pack
`fmt` is a string of type-length pairs. There are five types; 'u',
's', 'f', 'b', 'r' and 'p'. Length is the number of bits to pack
the value into.
- 'u' -- unsigned integer
- 's' -- signed integer
- 'f' -- floating point number of 32 or 64 bits
- 'b' -- bytearray
- '?' -- boolean
- 'b' -- boolean
- 'r' -- raw, bytearray
- 'p' -- padding, ignore
Example format string: 'u1u3p7s16'
"""

bits = ''
infos = _parse_format(fmt)
i = 0

for type, size in infos:
if type == 'p':
bits += size * '0'
Expand All @@ -105,9 +115,9 @@ def pack(fmt, *args):
elif type == 'f':
bits += _pack_float(size, args[i])
elif type == 'b':
bits += _pack_bytearray(size, args[i])
elif type == '?':
bits += _pack_boolean(size, args[i])
elif type == 'r':
bits += _pack_bytearray(size, args[i])
else:
raise ValueError("bad type '{}' in format".format(type))
i += 1
Expand All @@ -131,10 +141,12 @@ def unpack(fmt, data):
:returns: Tuple of unpacked values.
"""

bits = ''.join(['{:08b}'.format(b) for b in data])
infos = _parse_format(fmt)
res = []
i = 0

for type, size in infos:
if type == 'p':
pass
Expand All @@ -144,11 +156,14 @@ def unpack(fmt, data):
elif type == 'f':
value = _unpack_float(size, bits[i:i+size])
elif type == 'b':
value = _unpack_bytearray(size, bits[i:i+size])
elif type == '?':
value = _unpack_boolean(bits[i:i+size])
elif type == 'r':
value = _unpack_bytearray(size, bits[i:i+size])
else:
raise ValueError("bad type '{}' in format".format(type))
res.append(value)
i += size

return tuple(res)


Expand All @@ -160,6 +175,7 @@ def calcsize(fmt):
:returns: Number of bits in format string.
"""

return sum([size for _, size in _parse_format(fmt)])


Expand All @@ -176,11 +192,14 @@ def byteswap(fmt, data, offset = 0):
:returns: Bytearray of swapped bytes.
"""

i = offset

for f in fmt:
length = int(f)
value = data[i:i+length]
value.reverse()
data[i:i+length] = value
i += length

return data
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from setuptools import setup

setup(name='bitstruct',
version='1.1.0',
version='2.0.0',
description=('This module performs conversions between Python values '
'and C bit field structs represented as Python '
'bytearrays.'),
Expand Down
54 changes: 29 additions & 25 deletions tests/test_bitstruct.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
class BitStructTest(unittest.TestCase):

def test_pack(self):
'''
Pack values.
'''
"""Pack values.
"""

packed = pack('u1u1s6u7u9', 0, 0, -2, 65, 22)
self.assertEqual(packed, bytearray(b'\x3e\x82\x16'))

Expand All @@ -24,22 +24,22 @@ def test_pack(self):
packed = pack('p1u1s6p7u9', 0, -2, 22)
self.assertEqual(packed, bytearray(b'\x3e\x00\x16'))

packed = pack('u1s6f32b43', 0, -2, 3.75, bytearray(b'\x00\xff\x00\xff\x00\xff'))
packed = pack('u1s6f32r43', 0, -2, 3.75, bytearray(b'\x00\xff\x00\xff\x00\xff'))
self.assertEqual(packed, bytearray(b'\x7c\x80\xe0\x00\x00\x01\xfe\x01\xfe\x01\xc0'))

packed = pack('?1', True)
packed = pack('b1', True)
self.assertEqual(packed, bytearray(b'\x80'))

packed = pack('?1p6?1', True, True)
packed = pack('b1p6b1', True, True)
self.assertEqual(packed, bytearray(b'\x81'))

packed = pack('u5?2u1', -1, False, 1)
packed = pack('u5b2u1', -1, False, 1)
self.assertEqual(packed, bytearray(b'\xf9'))

def test_unpack(self):
'''
Unpack values.
'''
"""Unpack values.
"""

unpacked = unpack('u1u1s6u7u9', bytearray(b'\x3e\x82\x16'))
self.assertEqual(unpacked, (0, 0, -2, 65, 22))

Expand All @@ -59,23 +59,23 @@ def test_unpack(self):
self.assertEqual(unpacked, (0, -2, 22))

packed = bytearray(b'\x7c\x80\xe0\x00\x00\x01\xfe\x01\xfe\x01\xc0')
unpacked = unpack('u1s6f32b43', packed)
unpacked = unpack('u1s6f32r43', packed)
self.assertEqual(unpacked, (0, -2, 3.75, bytearray(b'\x00\xff\x00\xff\x00\xe0')))

packed = bytearray(b'\x80')
unpacked = unpack('?1', packed)
unpacked = unpack('b1', packed)
self.assertEqual(unpacked, (True,))

packed = bytearray(b'\x80')
unpacked = unpack('?1p6?1', packed)
unpacked = unpack('b1p6b1', packed)
self.assertEqual(unpacked, (True, False))

packed = bytearray(b'\x06')
unpacked = unpack('u5?2u1', packed)
unpacked = unpack('u5b2u1', packed)
self.assertEqual(unpacked, (0, True, 0))

packed = bytearray(b'\x04')
unpacked = unpack('u5?2u1', packed)
unpacked = unpack('u5b2u1', packed)
self.assertEqual(unpacked, (0, True, 0))

# bad float size
Expand All @@ -86,17 +86,21 @@ def test_unpack(self):
pass

def test_pack_unpack(self):
'''
Pack and unpack values.
'''
"""Pack and unpack values.
"""

packed = pack('u1u1s6u7u9', 0, 0, -2, 65, 22)
unpacked = unpack('u1u1s6u7u9', packed)
self.assertEqual(unpacked, (0, 0, -2, 65, 22))

packed = pack('f64', 1.0)
unpacked = unpack('f64', packed)
self.assertEqual(unpacked, (1.0, ))

def test_calcsize(self):
'''
Calculate size.
'''
"""Calculate size.
"""

size = calcsize('u1u1s6u7u9')
self.assertEqual(size, 24)

Expand All @@ -109,13 +113,13 @@ def test_calcsize(self):
size = calcsize('u1s6u7u9')
self.assertEqual(size, 23)

size = calcsize('?1s6u7u9')
size = calcsize('b1s6u7u9')
self.assertEqual(size, 23)

def test_byteswap(self):
'''
Byte swap.
'''
"""Byte swap.
"""

res = bytearray(b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a')
ref = bytearray(b'\x01\x03\x02\x04\x08\x07\x06\x05\x0a\x09')
self.assertEqual(byteswap('12142', ref), res)
Expand Down

0 comments on commit 82f89a6

Please sign in to comment.