diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -384,3 +384,7 @@ The calculated size of the struct (and hence of the bytes object produced by the :meth:`pack` method) corresponding to :attr:`format`. + .. attribute:: nmemb + + Number of members of the struct, corresponding to :attr:`format`. + diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -2,6 +2,7 @@ import unittest import struct import sys +import random from test.support import run_unittest @@ -556,6 +557,45 @@ s = struct.Struct('i') s.__init__('ii') + def test_Struct_nmemb(self): + fmtchars = "cbB?hHiIlLqQfdPsp" + nchars = len(fmtchars) + for _ in range(10): + n = random.randrange(1, nchars+1) + fmtlist = random.sample(fmtchars, n) + if 'P' in fmtlist: + # 'P' needs native mode, 'qQ' both need standard mode if 64-bit + # types are not available. + fmtlist[:] = [v for v in fmtlist if not v in 'qQ'] + n = len(fmtlist) + + for i, v in enumerate(fmtlist[:]): + if random.randrange(2): + # Insert repeat count. + x = random.randrange(1000000) + fmtlist[i] = str(x) + v + if v != 's' and v != 'p': + n += (x - 1) + + if random.randrange(2): + # Insert padding character. + i = random.randrange(len(fmtlist)) + fmtlist.insert(i, 'x') + + # Insert mode character. + if any('q' in v.lower() for v in fmtlist): + fmtlist.insert(0, random.choice("=<>!")) + elif random.randrange(2): + order = "@" + if not any('P' in v for v in fmtlist): + order += "=<>!" + fmtlist.insert(0, random.choice(order)) + + fmt = ''.join(fmtlist) + s = struct.Struct(fmt) + self.assertEqual(s.nmemb, n) + + def test_main(): run_unittest(StructTest) diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1665,6 +1665,12 @@ return PyLong_FromSsize_t(self->s_size); } +static PyObject * +s_get_nmemb(PyStructObject *self, void *unused) +{ + return PyLong_FromSsize_t(self->s_len); +} + /* List of functions */ static struct PyMethodDef s_methods[] = { @@ -1687,6 +1693,7 @@ static PyGetSetDef s_getsetlist[] = { {"format", (getter)s_get_format, (setter)NULL, "struct format string", NULL}, {"size", (getter)s_get_size, (setter)NULL, "struct size in bytes", NULL}, + {"nmemb", (getter)s_get_nmemb, (setter)NULL, "number of struct members", NULL}, {NULL} /* sentinel */ };