2019-04-12 22:46:21 -03:00
|
|
|
#define PY_SSIZE_T_CLEAN
|
2018-04-07 13:14:03 -03:00
|
|
|
#include <Python.h>
|
gh-47146: Soft-deprecate structmember.h, expose its contents via Python.h (GH-99014)
The ``structmember.h`` header is deprecated, though it continues to be available
and there are no plans to remove it. There are no deprecation warnings. Old code
can stay unchanged (unless the extra include and non-namespaced macros bother
you greatly). Specifically, no uses in CPython are updated -- that would just be
unnecessary churn.
The ``structmember.h`` header is deprecated, though it continues to be
available and there are no plans to remove it.
Its contents are now available just by including ``Python.h``,
with a ``Py`` prefix added if it was missing:
- `PyMemberDef`, `PyMember_GetOne` and`PyMember_SetOne`
- Type macros like `Py_T_INT`, `Py_T_DOUBLE`, etc.
(previously ``T_INT``, ``T_DOUBLE``, etc.)
- The flags `Py_READONLY` (previously ``READONLY``) and
`Py_AUDIT_READ` (previously all uppercase)
Several items are not exposed from ``Python.h``:
- `T_OBJECT` (use `Py_T_OBJECT_EX`)
- `T_NONE` (previously undocumented, and pretty quirky)
- The macro ``WRITE_RESTRICTED`` which does nothing.
- The macros ``RESTRICTED`` and ``READ_RESTRICTED``, equivalents of
`Py_AUDIT_READ`.
- In some configurations, ``<stddef.h>`` is not included from ``Python.h``.
It should be included manually when using ``offsetof()``.
The deprecated header continues to provide its original
contents under the original names.
Your old code can stay unchanged, unless the extra include and non-namespaced
macros bother you greatly.
There is discussion on the issue to rename `T_PYSSIZET` to `PY_T_SSIZE` or
similar. I chose not to do that -- users will probably copy/paste that with any
spelling, and not renaming it makes migration docs simpler.
Co-Authored-By: Alexander Belopolsky <abalkin@users.noreply.github.com>
Co-Authored-By: Matthias Braun <MatzeB@users.noreply.github.com>
2022-11-22 03:25:43 -04:00
|
|
|
#include <stddef.h> /* for offsetof() */
|
2018-04-07 13:14:03 -03:00
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
PyObject_HEAD
|
|
|
|
PyObject *first; /* first name */
|
|
|
|
PyObject *last; /* last name */
|
|
|
|
int number;
|
|
|
|
} CustomObject;
|
|
|
|
|
|
|
|
static int
|
|
|
|
Custom_traverse(CustomObject *self, visitproc visit, void *arg)
|
|
|
|
{
|
|
|
|
Py_VISIT(self->first);
|
|
|
|
Py_VISIT(self->last);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
Custom_clear(CustomObject *self)
|
|
|
|
{
|
|
|
|
Py_CLEAR(self->first);
|
|
|
|
Py_CLEAR(self->last);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
Custom_dealloc(CustomObject *self)
|
|
|
|
{
|
|
|
|
PyObject_GC_UnTrack(self);
|
|
|
|
Custom_clear(self);
|
|
|
|
Py_TYPE(self)->tp_free((PyObject *) self);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
|
|
{
|
|
|
|
CustomObject *self;
|
|
|
|
self = (CustomObject *) type->tp_alloc(type, 0);
|
|
|
|
if (self != NULL) {
|
|
|
|
self->first = PyUnicode_FromString("");
|
|
|
|
if (self->first == NULL) {
|
|
|
|
Py_DECREF(self);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
self->last = PyUnicode_FromString("");
|
|
|
|
if (self->last == NULL) {
|
|
|
|
Py_DECREF(self);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
self->number = 0;
|
|
|
|
}
|
|
|
|
return (PyObject *) self;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
|
|
|
|
{
|
|
|
|
static char *kwlist[] = {"first", "last", "number", NULL};
|
2022-11-22 09:22:22 -04:00
|
|
|
PyObject *first = NULL, *last = NULL;
|
2018-04-07 13:14:03 -03:00
|
|
|
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
|
|
|
|
&first, &last,
|
|
|
|
&self->number))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (first) {
|
2022-11-22 09:22:22 -04:00
|
|
|
Py_SETREF(self->first, Py_NewRef(first));
|
2018-04-07 13:14:03 -03:00
|
|
|
}
|
|
|
|
if (last) {
|
2022-11-22 09:22:22 -04:00
|
|
|
Py_SETREF(self->last, Py_NewRef(last));
|
2018-04-07 13:14:03 -03:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyMemberDef Custom_members[] = {
|
gh-47146: Soft-deprecate structmember.h, expose its contents via Python.h (GH-99014)
The ``structmember.h`` header is deprecated, though it continues to be available
and there are no plans to remove it. There are no deprecation warnings. Old code
can stay unchanged (unless the extra include and non-namespaced macros bother
you greatly). Specifically, no uses in CPython are updated -- that would just be
unnecessary churn.
The ``structmember.h`` header is deprecated, though it continues to be
available and there are no plans to remove it.
Its contents are now available just by including ``Python.h``,
with a ``Py`` prefix added if it was missing:
- `PyMemberDef`, `PyMember_GetOne` and`PyMember_SetOne`
- Type macros like `Py_T_INT`, `Py_T_DOUBLE`, etc.
(previously ``T_INT``, ``T_DOUBLE``, etc.)
- The flags `Py_READONLY` (previously ``READONLY``) and
`Py_AUDIT_READ` (previously all uppercase)
Several items are not exposed from ``Python.h``:
- `T_OBJECT` (use `Py_T_OBJECT_EX`)
- `T_NONE` (previously undocumented, and pretty quirky)
- The macro ``WRITE_RESTRICTED`` which does nothing.
- The macros ``RESTRICTED`` and ``READ_RESTRICTED``, equivalents of
`Py_AUDIT_READ`.
- In some configurations, ``<stddef.h>`` is not included from ``Python.h``.
It should be included manually when using ``offsetof()``.
The deprecated header continues to provide its original
contents under the original names.
Your old code can stay unchanged, unless the extra include and non-namespaced
macros bother you greatly.
There is discussion on the issue to rename `T_PYSSIZET` to `PY_T_SSIZE` or
similar. I chose not to do that -- users will probably copy/paste that with any
spelling, and not renaming it makes migration docs simpler.
Co-Authored-By: Alexander Belopolsky <abalkin@users.noreply.github.com>
Co-Authored-By: Matthias Braun <MatzeB@users.noreply.github.com>
2022-11-22 03:25:43 -04:00
|
|
|
{"number", Py_T_INT, offsetof(CustomObject, number), 0,
|
2018-04-07 13:14:03 -03:00
|
|
|
"custom number"},
|
|
|
|
{NULL} /* Sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
Custom_getfirst(CustomObject *self, void *closure)
|
|
|
|
{
|
2022-11-14 13:49:14 -04:00
|
|
|
return Py_NewRef(self->first);
|
2018-04-07 13:14:03 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
Custom_setfirst(CustomObject *self, PyObject *value, void *closure)
|
|
|
|
{
|
|
|
|
if (value == NULL) {
|
|
|
|
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!PyUnicode_Check(value)) {
|
|
|
|
PyErr_SetString(PyExc_TypeError,
|
|
|
|
"The first attribute value must be a string");
|
|
|
|
return -1;
|
|
|
|
}
|
2022-11-22 09:22:22 -04:00
|
|
|
Py_XSETREF(self->first, Py_NewRef(value));
|
2018-04-07 13:14:03 -03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
Custom_getlast(CustomObject *self, void *closure)
|
|
|
|
{
|
2022-11-14 13:49:14 -04:00
|
|
|
return Py_NewRef(self->last);
|
2018-04-07 13:14:03 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
Custom_setlast(CustomObject *self, PyObject *value, void *closure)
|
|
|
|
{
|
|
|
|
if (value == NULL) {
|
|
|
|
PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!PyUnicode_Check(value)) {
|
|
|
|
PyErr_SetString(PyExc_TypeError,
|
|
|
|
"The last attribute value must be a string");
|
|
|
|
return -1;
|
|
|
|
}
|
2022-11-22 09:22:22 -04:00
|
|
|
Py_XSETREF(self->last, Py_NewRef(value));
|
2018-04-07 13:14:03 -03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyGetSetDef Custom_getsetters[] = {
|
|
|
|
{"first", (getter) Custom_getfirst, (setter) Custom_setfirst,
|
|
|
|
"first name", NULL},
|
|
|
|
{"last", (getter) Custom_getlast, (setter) Custom_setlast,
|
|
|
|
"last name", NULL},
|
|
|
|
{NULL} /* Sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
|
|
|
|
{
|
|
|
|
return PyUnicode_FromFormat("%S %S", self->first, self->last);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyMethodDef Custom_methods[] = {
|
|
|
|
{"name", (PyCFunction) Custom_name, METH_NOARGS,
|
|
|
|
"Return the name, combining the first and last name"
|
|
|
|
},
|
|
|
|
{NULL} /* Sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
static PyTypeObject CustomType = {
|
2023-04-06 12:59:36 -03:00
|
|
|
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
|
2018-04-07 13:14:03 -03:00
|
|
|
.tp_name = "custom4.Custom",
|
2022-04-18 00:39:32 -03:00
|
|
|
.tp_doc = PyDoc_STR("Custom objects"),
|
2018-04-07 13:14:03 -03:00
|
|
|
.tp_basicsize = sizeof(CustomObject),
|
|
|
|
.tp_itemsize = 0,
|
|
|
|
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
|
|
|
|
.tp_new = Custom_new,
|
|
|
|
.tp_init = (initproc) Custom_init,
|
|
|
|
.tp_dealloc = (destructor) Custom_dealloc,
|
|
|
|
.tp_traverse = (traverseproc) Custom_traverse,
|
|
|
|
.tp_clear = (inquiry) Custom_clear,
|
|
|
|
.tp_members = Custom_members,
|
|
|
|
.tp_methods = Custom_methods,
|
|
|
|
.tp_getset = Custom_getsetters,
|
|
|
|
};
|
|
|
|
|
|
|
|
static PyModuleDef custommodule = {
|
2023-04-06 12:59:36 -03:00
|
|
|
.m_base = PyModuleDef_HEAD_INIT,
|
2018-04-07 13:14:03 -03:00
|
|
|
.m_name = "custom4",
|
|
|
|
.m_doc = "Example module that creates an extension type.",
|
|
|
|
.m_size = -1,
|
|
|
|
};
|
|
|
|
|
|
|
|
PyMODINIT_FUNC
|
|
|
|
PyInit_custom4(void)
|
|
|
|
{
|
|
|
|
PyObject *m;
|
|
|
|
if (PyType_Ready(&CustomType) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
m = PyModule_Create(&custommodule);
|
|
|
|
if (m == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2022-11-14 13:49:14 -04:00
|
|
|
if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
|
2019-09-12 09:11:20 -03:00
|
|
|
Py_DECREF(m);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-04-07 13:14:03 -03:00
|
|
|
return m;
|
|
|
|
}
|