Skip to content

Commit 6f79937

Browse files
committed
Add optional docstrings to member descriptors. For backwards
compatibility, this required all places where an array of "struct memberlist" structures was declared that is referenced from a type's tp_members slot to change the type of the structure to PyMemberDef; "struct memberlist" is now only used by old code that still calls PyMember_Get/Set. The code in PyObject_GenericGetAttr/SetAttr now calls the new APIs PyMember_GetOne/SetOne, which take a PyMemberDef argument. As examples, I added actual docstrings to the attributes of a few types: file, complex, instance method, super, and xxsubtype.spamlist. Also converted the symtable to new style getattr.
1 parent e0af35e commit 6f79937

17 files changed

Lines changed: 313 additions & 251 deletions

Include/descrobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ struct wrapperbase {
2121

2222
extern DL_IMPORT(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *);
2323
extern DL_IMPORT(PyObject *) PyDescr_NewMember(PyTypeObject *,
24-
struct memberlist *);
24+
struct PyMemberDef *);
2525
extern DL_IMPORT(PyObject *) PyDescr_NewGetSet(PyTypeObject *,
2626
struct getsetlist *);
2727
extern DL_IMPORT(PyObject *) PyDescr_NewWrapper(PyTypeObject *,

Include/object.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ typedef struct _typeobject {
274274

275275
/* Attribute descriptor and subclassing stuff */
276276
struct PyMethodDef *tp_methods;
277-
struct memberlist *tp_members;
277+
struct PyMemberDef *tp_members;
278278
struct getsetlist *tp_getset;
279279
struct _typeobject *tp_base;
280280
PyObject *tp_dict;

Include/structmember.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,22 @@ extern "C" {
2828
pointer is NULL. */
2929

3030
struct memberlist {
31+
/* Obsolete version, for binary backwards compatibility */
3132
char *name;
3233
int type;
3334
int offset;
3435
int flags;
3536
};
3637

38+
typedef struct PyMemberDef {
39+
/* Current version, use this */
40+
char *name;
41+
int type;
42+
int offset;
43+
int flags;
44+
char *doc;
45+
} PyMemberDef;
46+
3747
/* Types */
3848
#define T_SHORT 0
3949
#define T_INT 1
@@ -66,9 +76,15 @@ struct memberlist {
6676
#define RESTRICTED (READ_RESTRICTED | WRITE_RESTRICTED)
6777

6878

79+
/* Obsolete API, for binary backwards compatibility */
6980
DL_IMPORT(PyObject *) PyMember_Get(char *, struct memberlist *, char *);
7081
DL_IMPORT(int) PyMember_Set(char *, struct memberlist *, char *, PyObject *);
7182

83+
/* Current API, use this */
84+
DL_IMPORT(PyObject *) PyMember_GetOne(char *, struct PyMemberDef *);
85+
DL_IMPORT(int) PyMember_SetOne(char *, struct PyMemberDef *, PyObject *);
86+
87+
7288
#ifdef __cplusplus
7389
}
7490
#endif

Modules/xxsubtype.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,9 @@ spamdict_init(spamdictobject *self, PyObject *args, PyObject *kwds)
148148
return 0;
149149
}
150150

151-
static struct memberlist spamdict_members[] = {
152-
{"state", T_INT, offsetof(spamdictobject, state), READONLY},
151+
static PyMemberDef spamdict_members[] = {
152+
{"state", T_INT, offsetof(spamdictobject, state), READONLY,
153+
"an int variable for demonstration purposes"},
153154
{0}
154155
};
155156

Objects/classobject.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,10 +2006,13 @@ PyMethod_New(PyObject *func, PyObject *self, PyObject *class)
20062006

20072007
#define OFF(x) offsetof(PyMethodObject, x)
20082008

2009-
static struct memberlist instancemethod_memberlist[] = {
2010-
{"im_class", T_OBJECT, OFF(im_class), READONLY|RESTRICTED},
2011-
{"im_func", T_OBJECT, OFF(im_func), READONLY|RESTRICTED},
2012-
{"im_self", T_OBJECT, OFF(im_self), READONLY|RESTRICTED},
2009+
static PyMemberDef instancemethod_memberlist[] = {
2010+
{"im_class", T_OBJECT, OFF(im_class), READONLY|RESTRICTED,
2011+
"the class associated with a method"},
2012+
{"im_func", T_OBJECT, OFF(im_func), READONLY|RESTRICTED,
2013+
"the function (or other callable) implementing a method"},
2014+
{"im_self", T_OBJECT, OFF(im_self), READONLY|RESTRICTED,
2015+
"the instance to which a method is bound; None for unbound methods"},
20132016
{NULL} /* Sentinel */
20142017
};
20152018

Objects/complexobject.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -625,9 +625,11 @@ static PyMethodDef complex_methods[] = {
625625
{NULL, NULL} /* sentinel */
626626
};
627627

628-
static struct memberlist complex_members[] = {
629-
{"real", T_DOUBLE, offsetof(PyComplexObject, cval.real), 0},
630-
{"imag", T_DOUBLE, offsetof(PyComplexObject, cval.imag), 0},
628+
static PyMemberDef complex_members[] = {
629+
{"real", T_DOUBLE, offsetof(PyComplexObject, cval.real), 0,
630+
"the real part of a complex number"},
631+
{"imag", T_DOUBLE, offsetof(PyComplexObject, cval.imag), 0,
632+
"the imaginary part of a complex number"},
631633
{0},
632634
};
633635

Objects/descrobject.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ typedef struct {
2121

2222
typedef struct {
2323
COMMON;
24-
struct memberlist *d_member;
24+
PyMemberDef *d_member;
2525
} PyMemberDescrObject;
2626

2727
typedef struct {
@@ -126,8 +126,7 @@ member_get(PyMemberDescrObject *descr, PyObject *obj, PyTypeObject *type)
126126

127127
if (descr_check((PyDescrObject *)descr, obj, type, &res))
128128
return res;
129-
return PyMember_Get((char *)obj, descr->d_member,
130-
descr->d_member->name);
129+
return PyMember_GetOne((char *)obj, descr->d_member);
131130
}
132131

133132
static PyObject *
@@ -181,8 +180,7 @@ member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value)
181180

182181
if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
183182
return res;
184-
return PyMember_Set((char *)obj, descr->d_member,
185-
descr->d_member->name, value);
183+
return PyMember_SetOne((char *)obj, descr->d_member, value);
186184
}
187185

188186
static int
@@ -289,7 +287,7 @@ wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)
289287
}
290288

291289
static PyObject *
292-
member_get_doc(PyMethodDescrObject *descr, void *closure)
290+
method_get_doc(PyMethodDescrObject *descr, void *closure)
293291
{
294292
if (descr->d_method->ml_doc == NULL) {
295293
Py_INCREF(Py_None);
@@ -298,12 +296,27 @@ member_get_doc(PyMethodDescrObject *descr, void *closure)
298296
return PyString_FromString(descr->d_method->ml_doc);
299297
}
300298

301-
static struct memberlist descr_members[] = {
299+
static PyMemberDef descr_members[] = {
302300
{"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},
303301
{"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},
304302
{0}
305303
};
306304

305+
static struct getsetlist method_getset[] = {
306+
{"__doc__", (getter)method_get_doc},
307+
{0}
308+
};
309+
310+
static PyObject *
311+
member_get_doc(PyMemberDescrObject *descr, void *closure)
312+
{
313+
if (descr->d_member->doc == NULL) {
314+
Py_INCREF(Py_None);
315+
return Py_None;
316+
}
317+
return PyString_FromString(descr->d_member->doc);
318+
}
319+
307320
static struct getsetlist member_getset[] = {
308321
{"__doc__", (getter)member_get_doc},
309322
{0}
@@ -355,7 +368,7 @@ static PyTypeObject PyMethodDescr_Type = {
355368
0, /* tp_iternext */
356369
0, /* tp_methods */
357370
descr_members, /* tp_members */
358-
member_getset, /* tp_getset */
371+
method_getset, /* tp_getset */
359372
0, /* tp_base */
360373
0, /* tp_dict */
361374
(descrgetfunc)method_get, /* tp_descr_get */
@@ -393,7 +406,7 @@ static PyTypeObject PyMemberDescr_Type = {
393406
0, /* tp_iternext */
394407
0, /* tp_methods */
395408
descr_members, /* tp_members */
396-
0, /* tp_getset */
409+
member_getset, /* tp_getset */
397410
0, /* tp_base */
398411
0, /* tp_dict */
399412
(descrgetfunc)member_get, /* tp_descr_get */
@@ -507,7 +520,7 @@ PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
507520
}
508521

509522
PyObject *
510-
PyDescr_NewMember(PyTypeObject *type, struct memberlist *member)
523+
PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member)
511524
{
512525
PyMemberDescrObject *descr;
513526

Objects/fileobject.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,10 +1383,13 @@ static PyMethodDef file_methods[] = {
13831383

13841384
#define OFF(x) offsetof(PyFileObject, x)
13851385

1386-
static struct memberlist file_memberlist[] = {
1387-
{"softspace", T_INT, OFF(f_softspace)},
1388-
{"mode", T_OBJECT, OFF(f_mode), RO},
1389-
{"name", T_OBJECT, OFF(f_name), RO},
1386+
static PyMemberDef file_memberlist[] = {
1387+
{"softspace", T_INT, OFF(f_softspace), 0,
1388+
"flag indicating that a space needs to be printed; used by print"},
1389+
{"mode", T_OBJECT, OFF(f_mode), RO,
1390+
"file mode ('r', 'w', 'a', possibly with 'b' or '+' added)"},
1391+
{"name", T_OBJECT, OFF(f_name), RO,
1392+
"file name"},
13901393
/* getattr(f, "closed") is implemented without this table */
13911394
{NULL} /* Sentinel */
13921395
};

Objects/frameobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
#define OFF(x) offsetof(PyFrameObject, x)
1212

13-
static struct memberlist frame_memberlist[] = {
13+
static PyMemberDef frame_memberlist[] = {
1414
{"f_back", T_OBJECT, OFF(f_back), RO},
1515
{"f_code", T_OBJECT, OFF(f_code), RO},
1616
{"f_builtins", T_OBJECT, OFF(f_builtins),RO},

Objects/funcobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ PyFunction_SetClosure(PyObject *op, PyObject *closure)
129129

130130
#define RR ()
131131

132-
static struct memberlist func_memberlist[] = {
132+
static PyMemberDef func_memberlist[] = {
133133
{"func_closure", T_OBJECT, OFF(func_closure),
134134
RESTRICTED|READONLY},
135135
{"func_doc", T_OBJECT, OFF(func_doc), WRITE_RESTRICTED},

0 commit comments

Comments
 (0)