Skip to content

bpo-2897: Make PyMemberDef part of stable ABI; deprecate structmember.h #20462

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions Doc/extending/newtypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -275,28 +275,30 @@ be read-only or read-write. The structures in the table are defined as::
For each entry in the table, a :term:`descriptor` will be constructed and added to the
type which will be able to extract a value from the instance structure. The
:attr:`type` field should contain one of the type codes defined in the
:file:`structmember.h` header; the value will be used to determine how to
:file:`descrobject.h` header; the value will be used to determine how to
convert Python values to and from C values. The :attr:`flags` field is used to
store flags which control how the attribute can be accessed.

The following flag constants are defined in :file:`structmember.h`; they may be
combined using bitwise-OR.

+---------------------------+----------------------------------------------+
| Constant | Meaning |
+===========================+==============================================+
| :const:`READONLY` | Never writable. |
+---------------------------+----------------------------------------------+
| :const:`READ_RESTRICTED` | Not readable in restricted mode. |
+---------------------------+----------------------------------------------+
| :const:`WRITE_RESTRICTED` | Not writable in restricted mode. |
+---------------------------+----------------------------------------------+
| :const:`RESTRICTED` | Not readable or writable in restricted mode. |
+---------------------------+----------------------------------------------+
The following flag constants are provided; they may be combined using
bitwise-OR.

+-----------------------------+--------------------------------------------+
| Constant | Meaning |
+=============================+============================================+
| :const:`PY_READONLY` | Never writable. |
+-----------------------------+--------------------------------------------+
| :const:`PY_READ_RESTRICTED` | Reading raises an audit event. |
+-----------------------------+--------------------------------------------+

.. index::
single: PY_READONLY
single: PY_READ_RESTRICTED

The :const:`WRITE_RESTRICTED` and :const:`RESTRICTED` flags are deprecated. They
are provided in the deprecated header :file:`structmember.h` for backward
compatibility and ignored in Python 3.x.

.. index::
single: READONLY
single: READ_RESTRICTED
single: WRITE_RESTRICTED
single: RESTRICTED

Expand Down
7 changes: 0 additions & 7 deletions Doc/extending/newtypes_tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,6 @@ adds these capabilities:

This version of the module has a number of changes.

We've added an extra include::

#include <structmember.h>

This include provides declarations that we use to handle attributes, as
described a bit later.

The :class:`Custom` type now has three data attributes in its C struct,
*first*, *last*, and *number*. The *first* and *last* variables are Python
strings containing first and last names. The *number* attribute is a C integer.
Expand Down
1 change: 0 additions & 1 deletion Doc/includes/custom2.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "structmember.h"

typedef struct {
PyObject_HEAD
Expand Down
1 change: 0 additions & 1 deletion Doc/includes/custom3.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "structmember.h"

typedef struct {
PyObject_HEAD
Expand Down
1 change: 0 additions & 1 deletion Doc/includes/custom4.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "structmember.h"

typedef struct {
PyObject_HEAD
Expand Down
2 changes: 1 addition & 1 deletion Include/Python.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
#endif
#endif

/* For size_t? */
/* For size_t, offsetof */
#ifdef HAVE_STDDEF_H
#include <stddef.h>
#endif
Expand Down
58 changes: 58 additions & 0 deletions Include/descrobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,60 @@ typedef struct PyGetSetDef {
void *closure;
} PyGetSetDef;

/* Interface to map C struct members to Python object attributes */

/* An array of PyMemberDef structures defines the name, type and offset
of selected members of a C structure. These can be read by
PyMember_GetOne() and set by PyMember_SetOne() (except if their READONLY
flag is set). The array must be terminated with an entry whose name
pointer is NULL. */

typedef struct PyMemberDef {
const char *name;
int type;
Py_ssize_t offset;
int flags;
const char *doc;
} PyMemberDef;

/* PyMemberDef Types */
#define T_SHORT 0
#define T_INT 1
#define T_LONG 2
#define T_FLOAT 3
#define T_DOUBLE 4
#define T_STRING 5
#define T_OBJECT 6
/* XXX the ordering here is weird for binary compatibility */
#define T_CHAR 7 /* 1-character string */
#define T_BYTE 8 /* 8-bit signed int */
/* unsigned variants: */
#define T_UBYTE 9
#define T_USHORT 10
#define T_UINT 11
#define T_ULONG 12

/* Added by Jack: strings contained in the structure */
#define T_STRING_INPLACE 13

/* Added by Lillo: bools contained in the structure (assumed char) */
#define T_BOOL 14

#define T_OBJECT_EX 16 /* Like T_OBJECT, but raises AttributeError
when the value is NULL, instead of
converting to None. */
#define T_LONGLONG 17
#define T_ULONGLONG 18

#define T_PYSSIZET 19 /* Py_ssize_t */
#define T_NONE 20 /* Value is always None */


/* PyMemberDef Flags */
#define PY_READONLY 1
#define PY_READ_RESTRICTED 2


#ifndef Py_LIMITED_API
typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args,
void *wrapped);
Expand Down Expand Up @@ -99,6 +153,10 @@ PyAPI_FUNC(PyObject *) PyDescr_NewWrapper(PyTypeObject *,
PyAPI_FUNC(PyObject *) PyDictProxy_New(PyObject *);
PyAPI_FUNC(PyObject *) PyWrapper_New(PyObject *, PyObject *);

#ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject *) PyMember_GetOne(const char *, struct PyMemberDef *);
PyAPI_FUNC(int) PyMember_SetOne(char *, struct PyMemberDef *, PyObject *);
#endif

PyAPI_DATA(PyTypeObject) PyProperty_Type;
#ifdef __cplusplus
Expand Down
67 changes: 6 additions & 61 deletions Include/structmember.h
Original file line number Diff line number Diff line change
@@ -1,73 +1,18 @@
/* Deprecated header. `PyMemberDef`, `PyMember_GetOne` and `PyMember_SetOne`
* were moved to `descrobject.h`. */

#ifndef Py_STRUCTMEMBER_H
#define Py_STRUCTMEMBER_H
#ifdef __cplusplus
extern "C" {
#endif


/* Interface to map C struct members to Python object attributes */

#include <stddef.h> /* For offsetof */

/* An array of PyMemberDef structures defines the name, type and offset
of selected members of a C structure. These can be read by
PyMember_GetOne() and set by PyMember_SetOne() (except if their READONLY
flag is set). The array must be terminated with an entry whose name
pointer is NULL. */

typedef struct PyMemberDef {
const char *name;
int type;
Py_ssize_t offset;
int flags;
const char *doc;
} PyMemberDef;

/* Types */
#define T_SHORT 0
#define T_INT 1
#define T_LONG 2
#define T_FLOAT 3
#define T_DOUBLE 4
#define T_STRING 5
#define T_OBJECT 6
/* XXX the ordering here is weird for binary compatibility */
#define T_CHAR 7 /* 1-character string */
#define T_BYTE 8 /* 8-bit signed int */
/* unsigned variants: */
#define T_UBYTE 9
#define T_USHORT 10
#define T_UINT 11
#define T_ULONG 12

/* Added by Jack: strings contained in the structure */
#define T_STRING_INPLACE 13

/* Added by Lillo: bools contained in the structure (assumed char) */
#define T_BOOL 14

#define T_OBJECT_EX 16 /* Like T_OBJECT, but raises AttributeError
when the value is NULL, instead of
converting to None. */
#define T_LONGLONG 17
#define T_ULONGLONG 18

#define T_PYSSIZET 19 /* Py_ssize_t */
#define T_NONE 20 /* Value is always None */


/* Flags */
#define READONLY 1
#define READ_RESTRICTED 2
/* The following names are provided for backward compatibility. */
#define READONLY PY_READONLY
#define READ_RESTRICTED PY_READ_RESTRICTED
#define PY_WRITE_RESTRICTED 4
#define RESTRICTED (READ_RESTRICTED | PY_WRITE_RESTRICTED)


/* Current API, use this */
PyAPI_FUNC(PyObject *) PyMember_GetOne(const char *, struct PyMemberDef *);
PyAPI_FUNC(int) PyMember_SetOne(char *, struct PyMemberDef *, PyObject *);


#ifdef __cplusplus
}
#endif
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
PyMemberDef is available in Python.h and part of the stable ABI now.
READONLY was renamed to PY_READONLY and READ_RESTRICTED to
PY_READ_RESTRICTED. The structmember.h header was deprecated.
7 changes: 3 additions & 4 deletions Modules/_bz2module.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#define PY_SSIZE_T_CLEAN

#include "Python.h"
#include "structmember.h" // PyMemberDef

#include <bzlib.h>
#include <stdio.h>
Expand Down Expand Up @@ -674,10 +673,10 @@ PyDoc_STRVAR(BZ2Decompressor_needs_input_doc,

static PyMemberDef BZ2Decompressor_members[] = {
{"eof", T_BOOL, offsetof(BZ2Decompressor, eof),
READONLY, BZ2Decompressor_eof__doc__},
PY_READONLY, BZ2Decompressor_eof__doc__},
{"unused_data", T_OBJECT_EX, offsetof(BZ2Decompressor, unused_data),
READONLY, BZ2Decompressor_unused_data__doc__},
{"needs_input", T_BOOL, offsetof(BZ2Decompressor, needs_input), READONLY,
PY_READONLY, BZ2Decompressor_unused_data__doc__},
{"needs_input", T_BOOL, offsetof(BZ2Decompressor, needs_input), PY_READONLY,
BZ2Decompressor_needs_input_doc},
{NULL}
};
Expand Down
1 change: 0 additions & 1 deletion Modules/_collectionsmodule.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include "Python.h"
#include "structmember.h" // PyMemberDef

#ifdef STDC_HEADERS
#include <stddef.h>
Expand Down
13 changes: 6 additions & 7 deletions Modules/_csv.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ module instead.
#define MODULE_VERSION "1.0"

#include "Python.h"
#include "structmember.h" // PyMemberDef
#include <stdbool.h>


Expand Down Expand Up @@ -299,9 +298,9 @@ dialect_check_quoting(int quoting)
#define D_OFF(x) offsetof(DialectObj, x)

static struct PyMemberDef Dialect_memberlist[] = {
{ "skipinitialspace", T_BOOL, D_OFF(skipinitialspace), READONLY },
{ "doublequote", T_BOOL, D_OFF(doublequote), READONLY },
{ "strict", T_BOOL, D_OFF(strict), READONLY },
{ "skipinitialspace", T_BOOL, D_OFF(skipinitialspace), PY_READONLY },
{ "doublequote", T_BOOL, D_OFF(doublequote), PY_READONLY },
{ "strict", T_BOOL, D_OFF(strict), PY_READONLY },
{ NULL }
};

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

static struct PyMemberDef Reader_memberlist[] = {
{ "dialect", T_OBJECT, R_OFF(dialect), READONLY },
{ "line_num", T_ULONG, R_OFF(line_num), READONLY },
{ "dialect", T_OBJECT, R_OFF(dialect), PY_READONLY },
{ "line_num", T_ULONG, R_OFF(line_num), PY_READONLY },
{ NULL }
};

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

static struct PyMemberDef Writer_memberlist[] = {
{ "dialect", T_OBJECT, W_OFF(dialect), READONLY },
{ "dialect", T_OBJECT, W_OFF(dialect), PY_READONLY },
{ NULL }
};

Expand Down
7 changes: 3 additions & 4 deletions Modules/_ctypes/_ctypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ bytes(cdata)
#define PY_SSIZE_T_CLEAN

#include "Python.h"
#include "structmember.h" // PyMemberDef

#include <ffi.h>
#ifdef MS_WIN32
Expand Down Expand Up @@ -2787,13 +2786,13 @@ PyCData_dealloc(PyObject *self)

static PyMemberDef PyCData_members[] = {
{ "_b_base_", T_OBJECT,
offsetof(CDataObject, b_base), READONLY,
offsetof(CDataObject, b_base), PY_READONLY,
"the base object" },
{ "_b_needsfree_", T_INT,
offsetof(CDataObject, b_needsfree), READONLY,
offsetof(CDataObject, b_needsfree), PY_READONLY,
"whether the object owns the memory or not" },
{ "_objects", T_OBJECT,
offsetof(CDataObject, b_objects), READONLY,
offsetof(CDataObject, b_objects), PY_READONLY,
"internal objects tree (NEVER CHANGE THIS OBJECT!)"},
{ NULL },
};
Expand Down
3 changes: 1 addition & 2 deletions Modules/_ctypes/callproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
*/

#include "Python.h"
#include "structmember.h" // PyMemberDef

#ifdef MS_WIN32
#include <windows.h>
Expand Down Expand Up @@ -563,7 +562,7 @@ PyCArg_repr(PyCArgObject *self)

static PyMemberDef PyCArgType_members[] = {
{ "_obj", T_OBJECT,
offsetof(PyCArgObject, obj), READONLY,
offsetof(PyCArgObject, obj), PY_READONLY,
"the wrapped object" },
{ NULL },
};
Expand Down
7 changes: 3 additions & 4 deletions Modules/_datetimemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

#include "Python.h"
#include "datetime.h"
#include "structmember.h" // PyMemberDef

#include <time.h>

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

static PyMemberDef delta_members[] = {

{"days", T_INT, OFFSET(days), READONLY,
{"days", T_INT, OFFSET(days), PY_READONLY,
PyDoc_STR("Number of days.")},

{"seconds", T_INT, OFFSET(seconds), READONLY,
{"seconds", T_INT, OFFSET(seconds), PY_READONLY,
PyDoc_STR("Number of seconds (>= 0 and less than 1 day).")},

{"microseconds", T_INT, OFFSET(microseconds), READONLY,
{"microseconds", T_INT, OFFSET(microseconds), PY_READONLY,
PyDoc_STR("Number of microseconds (>= 0 and less than 1 second).")},
{NULL}
};
Expand Down
Loading