Skip to content

Commit 56276cd

Browse files
committed
bpo-2897: Make PyMemberDef part of stable ABI; deprecate structmember.h
Move PyMemberDef and related flags from structmember.h to descrobject.h. Rename READONLY to PY_READONLY and READ_RESTRICTED to PY_READ_RESTRICTED. This makes the structure part of the stable ABI. Move PyMember_GetOne and PyMemberSetOne as well but do not make them part of the stable ABI yet. Document that structmember.h is deprecated, change examples and documentation and add definitions for READONLY, READ_RESTRICTED, PY_WRITE_RESTRICTED and RESTRICTED to it for backwards compatibility. Add check for stddef.h to configure.ac because we need to include it for offsetof and Python.h does not pass the HAVE_STDDEF_H check without it.
1 parent 526e23f commit 56276cd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+284
-337
lines changed

Doc/extending/newtypes.rst

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -275,28 +275,30 @@ be read-only or read-write. The structures in the table are defined as::
275275
For each entry in the table, a :term:`descriptor` will be constructed and added to the
276276
type which will be able to extract a value from the instance structure. The
277277
:attr:`type` field should contain one of the type codes defined in the
278-
:file:`structmember.h` header; the value will be used to determine how to
278+
:file:`descrobject.h` header; the value will be used to determine how to
279279
convert Python values to and from C values. The :attr:`flags` field is used to
280280
store flags which control how the attribute can be accessed.
281281

282-
The following flag constants are defined in :file:`structmember.h`; they may be
283-
combined using bitwise-OR.
284-
285-
+---------------------------+----------------------------------------------+
286-
| Constant | Meaning |
287-
+===========================+==============================================+
288-
| :const:`READONLY` | Never writable. |
289-
+---------------------------+----------------------------------------------+
290-
| :const:`READ_RESTRICTED` | Not readable in restricted mode. |
291-
+---------------------------+----------------------------------------------+
292-
| :const:`WRITE_RESTRICTED` | Not writable in restricted mode. |
293-
+---------------------------+----------------------------------------------+
294-
| :const:`RESTRICTED` | Not readable or writable in restricted mode. |
295-
+---------------------------+----------------------------------------------+
282+
The following flag constants are provided; they may be combined using
283+
bitwise-OR.
284+
285+
+-----------------------------+--------------------------------------------+
286+
| Constant | Meaning |
287+
+=============================+============================================+
288+
| :const:`PY_READONLY` | Never writable. |
289+
+-----------------------------+--------------------------------------------+
290+
| :const:`PY_READ_RESTRICTED` | Reading raises an audit event. |
291+
+-----------------------------+--------------------------------------------+
292+
293+
.. index::
294+
single: PY_READONLY
295+
single: PY_READ_RESTRICTED
296+
297+
The :const:`WRITE_RESTRICTED` and :const:`RESTRICTED` flags are deprecated. They
298+
are provided in the deprecated header :file:`structmember.h` for backward
299+
compatibility and ignored in Python 3.x.
296300

297301
.. index::
298-
single: READONLY
299-
single: READ_RESTRICTED
300302
single: WRITE_RESTRICTED
301303
single: RESTRICTED
302304

Doc/extending/newtypes_tutorial.rst

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -238,13 +238,6 @@ adds these capabilities:
238238

239239
This version of the module has a number of changes.
240240

241-
We've added an extra include::
242-
243-
#include <structmember.h>
244-
245-
This include provides declarations that we use to handle attributes, as
246-
described a bit later.
247-
248241
The :class:`Custom` type now has three data attributes in its C struct,
249242
*first*, *last*, and *number*. The *first* and *last* variables are Python
250243
strings containing first and last names. The *number* attribute is a C integer.

Doc/includes/custom2.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#define PY_SSIZE_T_CLEAN
22
#include <Python.h>
3-
#include "structmember.h"
43

54
typedef struct {
65
PyObject_HEAD

Doc/includes/custom3.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#define PY_SSIZE_T_CLEAN
22
#include <Python.h>
3-
#include "structmember.h"
43

54
typedef struct {
65
PyObject_HEAD

Doc/includes/custom4.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#define PY_SSIZE_T_CLEAN
22
#include <Python.h>
3-
#include "structmember.h"
43

54
typedef struct {
65
PyObject_HEAD

Include/Python.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
#endif
5050
#endif
5151

52-
/* For size_t? */
52+
/* For size_t, offsetof */
5353
#ifdef HAVE_STDDEF_H
5454
#include <stddef.h>
5555
#endif

Include/descrobject.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,60 @@ typedef struct PyGetSetDef {
1616
void *closure;
1717
} PyGetSetDef;
1818

19+
/* Interface to map C struct members to Python object attributes */
20+
21+
/* An array of PyMemberDef structures defines the name, type and offset
22+
of selected members of a C structure. These can be read by
23+
PyMember_GetOne() and set by PyMember_SetOne() (except if their READONLY
24+
flag is set). The array must be terminated with an entry whose name
25+
pointer is NULL. */
26+
27+
typedef struct PyMemberDef {
28+
const char *name;
29+
int type;
30+
Py_ssize_t offset;
31+
int flags;
32+
const char *doc;
33+
} PyMemberDef;
34+
35+
/* PyMemberDef Types */
36+
#define T_SHORT 0
37+
#define T_INT 1
38+
#define T_LONG 2
39+
#define T_FLOAT 3
40+
#define T_DOUBLE 4
41+
#define T_STRING 5
42+
#define T_OBJECT 6
43+
/* XXX the ordering here is weird for binary compatibility */
44+
#define T_CHAR 7 /* 1-character string */
45+
#define T_BYTE 8 /* 8-bit signed int */
46+
/* unsigned variants: */
47+
#define T_UBYTE 9
48+
#define T_USHORT 10
49+
#define T_UINT 11
50+
#define T_ULONG 12
51+
52+
/* Added by Jack: strings contained in the structure */
53+
#define T_STRING_INPLACE 13
54+
55+
/* Added by Lillo: bools contained in the structure (assumed char) */
56+
#define T_BOOL 14
57+
58+
#define T_OBJECT_EX 16 /* Like T_OBJECT, but raises AttributeError
59+
when the value is NULL, instead of
60+
converting to None. */
61+
#define T_LONGLONG 17
62+
#define T_ULONGLONG 18
63+
64+
#define T_PYSSIZET 19 /* Py_ssize_t */
65+
#define T_NONE 20 /* Value is always None */
66+
67+
68+
/* PyMemberDef Flags */
69+
#define PY_READONLY 1
70+
#define PY_READ_RESTRICTED 2
71+
72+
1973
#ifndef Py_LIMITED_API
2074
typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args,
2175
void *wrapped);
@@ -99,6 +153,10 @@ PyAPI_FUNC(PyObject *) PyDescr_NewWrapper(PyTypeObject *,
99153
PyAPI_FUNC(PyObject *) PyDictProxy_New(PyObject *);
100154
PyAPI_FUNC(PyObject *) PyWrapper_New(PyObject *, PyObject *);
101155

156+
#ifndef Py_LIMITED_API
157+
PyAPI_FUNC(PyObject *) PyMember_GetOne(const char *, struct PyMemberDef *);
158+
PyAPI_FUNC(int) PyMember_SetOne(char *, struct PyMemberDef *, PyObject *);
159+
#endif
102160

103161
PyAPI_DATA(PyTypeObject) PyProperty_Type;
104162
#ifdef __cplusplus

Include/structmember.h

Lines changed: 6 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,18 @@
1+
/* Deprecated header. `PyMemberDef`, `PyMember_GetOne` and `PyMember_SetOne`
2+
* were moved to `descrobject.h`. */
3+
14
#ifndef Py_STRUCTMEMBER_H
25
#define Py_STRUCTMEMBER_H
36
#ifdef __cplusplus
47
extern "C" {
58
#endif
69

7-
8-
/* Interface to map C struct members to Python object attributes */
9-
10-
#include <stddef.h> /* For offsetof */
11-
12-
/* An array of PyMemberDef structures defines the name, type and offset
13-
of selected members of a C structure. These can be read by
14-
PyMember_GetOne() and set by PyMember_SetOne() (except if their READONLY
15-
flag is set). The array must be terminated with an entry whose name
16-
pointer is NULL. */
17-
18-
typedef struct PyMemberDef {
19-
const char *name;
20-
int type;
21-
Py_ssize_t offset;
22-
int flags;
23-
const char *doc;
24-
} PyMemberDef;
25-
26-
/* Types */
27-
#define T_SHORT 0
28-
#define T_INT 1
29-
#define T_LONG 2
30-
#define T_FLOAT 3
31-
#define T_DOUBLE 4
32-
#define T_STRING 5
33-
#define T_OBJECT 6
34-
/* XXX the ordering here is weird for binary compatibility */
35-
#define T_CHAR 7 /* 1-character string */
36-
#define T_BYTE 8 /* 8-bit signed int */
37-
/* unsigned variants: */
38-
#define T_UBYTE 9
39-
#define T_USHORT 10
40-
#define T_UINT 11
41-
#define T_ULONG 12
42-
43-
/* Added by Jack: strings contained in the structure */
44-
#define T_STRING_INPLACE 13
45-
46-
/* Added by Lillo: bools contained in the structure (assumed char) */
47-
#define T_BOOL 14
48-
49-
#define T_OBJECT_EX 16 /* Like T_OBJECT, but raises AttributeError
50-
when the value is NULL, instead of
51-
converting to None. */
52-
#define T_LONGLONG 17
53-
#define T_ULONGLONG 18
54-
55-
#define T_PYSSIZET 19 /* Py_ssize_t */
56-
#define T_NONE 20 /* Value is always None */
57-
58-
59-
/* Flags */
60-
#define READONLY 1
61-
#define READ_RESTRICTED 2
10+
/* The following names are provided for backward compatibility. */
11+
#define READONLY PY_READONLY
12+
#define READ_RESTRICTED PY_READ_RESTRICTED
6213
#define PY_WRITE_RESTRICTED 4
6314
#define RESTRICTED (READ_RESTRICTED | PY_WRITE_RESTRICTED)
6415

65-
66-
/* Current API, use this */
67-
PyAPI_FUNC(PyObject *) PyMember_GetOne(const char *, struct PyMemberDef *);
68-
PyAPI_FUNC(int) PyMember_SetOne(char *, struct PyMemberDef *, PyObject *);
69-
70-
7116
#ifdef __cplusplus
7217
}
7318
#endif
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
PyMemberDef is available in Python.h and part of the stable ABI now.
2+
READONLY was renamed to PY_READONLY and READ_RESTRICTED to
3+
PY_READ_RESTRICTED. The structmember.h header was deprecated.

Modules/_bz2module.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#define PY_SSIZE_T_CLEAN
44

55
#include "Python.h"
6-
#include "structmember.h" // PyMemberDef
76

87
#include <bzlib.h>
98
#include <stdio.h>
@@ -674,10 +673,10 @@ PyDoc_STRVAR(BZ2Decompressor_needs_input_doc,
674673

675674
static PyMemberDef BZ2Decompressor_members[] = {
676675
{"eof", T_BOOL, offsetof(BZ2Decompressor, eof),
677-
READONLY, BZ2Decompressor_eof__doc__},
676+
PY_READONLY, BZ2Decompressor_eof__doc__},
678677
{"unused_data", T_OBJECT_EX, offsetof(BZ2Decompressor, unused_data),
679-
READONLY, BZ2Decompressor_unused_data__doc__},
680-
{"needs_input", T_BOOL, offsetof(BZ2Decompressor, needs_input), READONLY,
678+
PY_READONLY, BZ2Decompressor_unused_data__doc__},
679+
{"needs_input", T_BOOL, offsetof(BZ2Decompressor, needs_input), PY_READONLY,
681680
BZ2Decompressor_needs_input_doc},
682681
{NULL}
683682
};

Modules/_collectionsmodule.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#include "Python.h"
2-
#include "structmember.h" // PyMemberDef
32

43
#ifdef STDC_HEADERS
54
#include <stddef.h>

Modules/_csv.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ module instead.
1111
#define MODULE_VERSION "1.0"
1212

1313
#include "Python.h"
14-
#include "structmember.h" // PyMemberDef
1514
#include <stdbool.h>
1615

1716

@@ -299,9 +298,9 @@ dialect_check_quoting(int quoting)
299298
#define D_OFF(x) offsetof(DialectObj, x)
300299

301300
static struct PyMemberDef Dialect_memberlist[] = {
302-
{ "skipinitialspace", T_BOOL, D_OFF(skipinitialspace), READONLY },
303-
{ "doublequote", T_BOOL, D_OFF(doublequote), READONLY },
304-
{ "strict", T_BOOL, D_OFF(strict), READONLY },
301+
{ "skipinitialspace", T_BOOL, D_OFF(skipinitialspace), PY_READONLY },
302+
{ "doublequote", T_BOOL, D_OFF(doublequote), PY_READONLY },
303+
{ "strict", T_BOOL, D_OFF(strict), PY_READONLY },
305304
{ NULL }
306305
};
307306

@@ -895,8 +894,8 @@ static struct PyMethodDef Reader_methods[] = {
895894
#define R_OFF(x) offsetof(ReaderObj, x)
896895

897896
static struct PyMemberDef Reader_memberlist[] = {
898-
{ "dialect", T_OBJECT, R_OFF(dialect), READONLY },
899-
{ "line_num", T_ULONG, R_OFF(line_num), READONLY },
897+
{ "dialect", T_OBJECT, R_OFF(dialect), PY_READONLY },
898+
{ "line_num", T_ULONG, R_OFF(line_num), PY_READONLY },
900899
{ NULL }
901900
};
902901

@@ -1293,7 +1292,7 @@ static struct PyMethodDef Writer_methods[] = {
12931292
#define W_OFF(x) offsetof(WriterObj, x)
12941293

12951294
static struct PyMemberDef Writer_memberlist[] = {
1296-
{ "dialect", T_OBJECT, W_OFF(dialect), READONLY },
1295+
{ "dialect", T_OBJECT, W_OFF(dialect), PY_READONLY },
12971296
{ NULL }
12981297
};
12991298

Modules/_ctypes/_ctypes.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ bytes(cdata)
102102
#define PY_SSIZE_T_CLEAN
103103

104104
#include "Python.h"
105-
#include "structmember.h" // PyMemberDef
106105

107106
#include <ffi.h>
108107
#ifdef MS_WIN32
@@ -2787,13 +2786,13 @@ PyCData_dealloc(PyObject *self)
27872786

27882787
static PyMemberDef PyCData_members[] = {
27892788
{ "_b_base_", T_OBJECT,
2790-
offsetof(CDataObject, b_base), READONLY,
2789+
offsetof(CDataObject, b_base), PY_READONLY,
27912790
"the base object" },
27922791
{ "_b_needsfree_", T_INT,
2793-
offsetof(CDataObject, b_needsfree), READONLY,
2792+
offsetof(CDataObject, b_needsfree), PY_READONLY,
27942793
"whether the object owns the memory or not" },
27952794
{ "_objects", T_OBJECT,
2796-
offsetof(CDataObject, b_objects), READONLY,
2795+
offsetof(CDataObject, b_objects), PY_READONLY,
27972796
"internal objects tree (NEVER CHANGE THIS OBJECT!)"},
27982797
{ NULL },
27992798
};

Modules/_ctypes/callproc.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
*/
5656

5757
#include "Python.h"
58-
#include "structmember.h" // PyMemberDef
5958

6059
#ifdef MS_WIN32
6160
#include <windows.h>
@@ -563,7 +562,7 @@ PyCArg_repr(PyCArgObject *self)
563562

564563
static PyMemberDef PyCArgType_members[] = {
565564
{ "_obj", T_OBJECT,
566-
offsetof(PyCArgObject, obj), READONLY,
565+
offsetof(PyCArgObject, obj), PY_READONLY,
567566
"the wrapped object" },
568567
{ NULL },
569568
};

Modules/_datetimemodule.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
#include "Python.h"
1111
#include "datetime.h"
12-
#include "structmember.h" // PyMemberDef
1312

1413
#include <time.h>
1514

@@ -2653,13 +2652,13 @@ delta_reduce(PyDateTime_Delta* self, PyObject *Py_UNUSED(ignored))
26532652

26542653
static PyMemberDef delta_members[] = {
26552654

2656-
{"days", T_INT, OFFSET(days), READONLY,
2655+
{"days", T_INT, OFFSET(days), PY_READONLY,
26572656
PyDoc_STR("Number of days.")},
26582657

2659-
{"seconds", T_INT, OFFSET(seconds), READONLY,
2658+
{"seconds", T_INT, OFFSET(seconds), PY_READONLY,
26602659
PyDoc_STR("Number of seconds (>= 0 and less than 1 day).")},
26612660

2662-
{"microseconds", T_INT, OFFSET(microseconds), READONLY,
2661+
{"microseconds", T_INT, OFFSET(microseconds), PY_READONLY,
26632662
PyDoc_STR("Number of microseconds (>= 0 and less than 1 second).")},
26642663
{NULL}
26652664
};

0 commit comments

Comments
 (0)