Index: Lib/struct.py =================================================================== --- Lib/struct.py (revision 63457) +++ Lib/struct.py (working copy) @@ -1,2 +1,28 @@ +import collections +import re from _struct import * from _struct import _clearcache + +_fmt_regex = re.compile(r'([a-zA-Z_][a-zA-Z_0-9]*)?\((\S+)\)') + +class NamedStruct(Struct): + def __init__(self, format, name=None): + try: + attr_names, attr_formats = zip(*( + m.groups() for m in _fmt_regex.finditer(format))) + except ValueError: + raise ValueError('bad NamedStruct format: %r' % format) + Struct.__init__(self, ''.join(attr_formats)) + + if name is None: + name = self.__class__.__name__ + self._namedtuple = collections.namedtuple(name, + ' '.join(attr for attr in attr_names if attr)) + + def unpack(self, data): + return self._namedtuple(*Struct.unpack(self, data)) + +__all__ = [ + 'Struct', 'NamedStruct', + 'calcsize', 'error', 'pack', 'pack_into', 'unpack', 'unpack_from' +] Index: Lib/test/test_namedstruct.py =================================================================== --- Lib/test/test_namedstruct.py (revision 0) +++ Lib/test/test_namedstruct.py (revision 0) @@ -0,0 +1,41 @@ +import unittest +from test import test_support + +import struct + +class NamedStructTest(unittest.TestCase): + + def test_constructor(self): + ns = struct.NamedStruct + self.assertRaises(ValueError, ns, '') + self.assertRaises(ValueError, ns, 'bad-format()') + self.assertRaises(struct.error, ns, 'attr(/)') + self.assertRaises(ValueError, ns, '_attr(h)') + + def test_unpack(self): + ns1 = struct.NamedStruct('(!) x1(h) y1(h) (2x) x2(h) y2(h)') + data = '\x00\x01\x00\x02\x00\x00\x00\x03\x00\x04' + nt = ns1.unpack(data) + self.assertEqual(nt.x1, 1) + self.assertEqual(nt.y1, 2) + self.assertEqual(nt.x2, 3) + self.assertEqual(nt.y2, 4) + self.assertEqual(nt, (1, 2, 3, 4)) + self.assertRaises(AttributeError, getattr, nt, 'x3') + self.assertRaises(struct.error, ns1.unpack, data + '\x00') + self.assertRaises(struct.error, ns1.unpack, '') + + def test_pack(self): + ns1 = struct.NamedStruct('(!) x1(h) y1(h) (2x) x2(h) y2(h)') + data = '\x00\x01\x00\x02\x00\x00\x00\x03\x00\x04' + nt = ns1.unpack(data) + self.assertEqual(data, ns1.pack(*nt)) + self.assertEqual(data, ns1.pack(1, 2, 3, 4)) + self.assertRaises(struct.error, ns1.pack, 1, 2, 3) + self.assertRaises(struct.error, ns1.pack, 1, 2, 3, 4, 5) + +def test_main(): + test_support.run_unittest(NamedStructTest) + +if __name__ == "__main__": + test_main()