Skip to content

Commit 9436bbd

Browse files
authored
bpo-29165: doc: make extending/newtypes more Python 3 friendly (GH-211)
* Use PyVarObject_HEAD_INIT instead of PyObject_HEAD_INIT on type struct header. * Backport many minor fixes from Python 3 doc to minimize diff.
1 parent d9a7574 commit 9436bbd

File tree

7 files changed

+206
-219
lines changed

7 files changed

+206
-219
lines changed

Doc/extending/newtypes.rst

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -79,27 +79,26 @@ Python integers::
7979
Moving on, we come to the crunch --- the type object. ::
8080

8181
static PyTypeObject noddy_NoddyType = {
82-
PyObject_HEAD_INIT(NULL)
83-
0, /*ob_size*/
84-
"noddy.Noddy", /*tp_name*/
85-
sizeof(noddy_NoddyObject), /*tp_basicsize*/
86-
0, /*tp_itemsize*/
87-
0, /*tp_dealloc*/
88-
0, /*tp_print*/
89-
0, /*tp_getattr*/
90-
0, /*tp_setattr*/
91-
0, /*tp_compare*/
92-
0, /*tp_repr*/
93-
0, /*tp_as_number*/
94-
0, /*tp_as_sequence*/
95-
0, /*tp_as_mapping*/
96-
0, /*tp_hash */
97-
0, /*tp_call*/
98-
0, /*tp_str*/
99-
0, /*tp_getattro*/
100-
0, /*tp_setattro*/
101-
0, /*tp_as_buffer*/
102-
Py_TPFLAGS_DEFAULT, /*tp_flags*/
82+
PyVarObject_HEAD_INIT(NULL, 0)
83+
"noddy.Noddy", /* tp_name */
84+
sizeof(noddy_NoddyObject), /* tp_basicsize */
85+
0, /* tp_itemsize */
86+
0, /* tp_dealloc */
87+
0, /* tp_print */
88+
0, /* tp_getattr */
89+
0, /* tp_setattr */
90+
0, /* tp_compare */
91+
0, /* tp_repr */
92+
0, /* tp_as_number */
93+
0, /* tp_as_sequence */
94+
0, /* tp_as_mapping */
95+
0, /* tp_hash */
96+
0, /* tp_call */
97+
0, /* tp_str */
98+
0, /* tp_getattro */
99+
0, /* tp_setattro */
100+
0, /* tp_as_buffer */
101+
Py_TPFLAGS_DEFAULT, /* tp_flags */
103102
"Noddy objects", /* tp_doc */
104103
};
105104

@@ -111,23 +110,16 @@ it's common practice to not specify them explicitly unless you need them.
111110
This is so important that we're going to pick the top of it apart still
112111
further::
113112

114-
PyObject_HEAD_INIT(NULL)
113+
PyVarObject_HEAD_INIT(NULL, 0)
115114

116115
This line is a bit of a wart; what we'd like to write is::
117116

118-
PyObject_HEAD_INIT(&PyType_Type)
117+
PyVarObject_HEAD_INIT(&PyType_Type, 0)
119118

120119
as the type of a type object is "type", but this isn't strictly conforming C and
121120
some compilers complain. Fortunately, this member will be filled in for us by
122121
:c:func:`PyType_Ready`. ::
123122

124-
0, /* ob_size */
125-
126-
The :attr:`ob_size` field of the header is not used; its presence in the type
127-
structure is a historical artifact that is maintained for binary compatibility
128-
with extension modules compiled for older versions of Python. Always set this
129-
field to zero. ::
130-
131123
"noddy.Noddy", /* tp_name */
132124

133125
The name of our type. This will appear in the default textual representation of
@@ -171,7 +163,7 @@ for now.
171163
Skipping a number of type methods that we don't provide, we set the class flags
172164
to :const:`Py_TPFLAGS_DEFAULT`. ::
173165

174-
Py_TPFLAGS_DEFAULT, /*tp_flags*/
166+
Py_TPFLAGS_DEFAULT, /* tp_flags */
175167

176168
All types should include this constant in their flags. It enables all of the
177169
members defined by the current version of Python.
@@ -244,7 +236,7 @@ doesn't do anything. It can't even be subclassed.
244236
Adding data and methods to the Basic example
245237
--------------------------------------------
246238

247-
Let's expend the basic example to add some data and methods. Let's also make
239+
Let's extend the basic example to add some data and methods. Let's also make
248240
the type usable as a base class. We'll create a new module, :mod:`noddy2` that
249241
adds these capabilities:
250242

@@ -284,7 +276,7 @@ allocation and deallocation. At a minimum, we need a deallocation method::
284276
{
285277
Py_XDECREF(self->first);
286278
Py_XDECREF(self->last);
287-
self->ob_type->tp_free((PyObject*)self);
279+
Py_TYPE(self)->tp_free((PyObject*)self);
288280
}
289281

290282
which is assigned to the :c:member:`~PyTypeObject.tp_dealloc` member::
@@ -497,7 +489,7 @@ concatenation of the first and last names. ::
497489
The method is implemented as a C function that takes a :class:`Noddy` (or
498490
:class:`Noddy` subclass) instance as the first argument. Methods always take an
499491
instance as the first argument. Methods often take positional and keyword
500-
arguments as well, but in this cased we don't take any and don't need to accept
492+
arguments as well, but in this case we don't take any and don't need to accept
501493
a positional argument tuple or keyword argument dictionary. This method is
502494
equivalent to the Python method::
503495

@@ -806,7 +798,7 @@ decrementing of reference counts. With :c:func:`Py_CLEAR`, the
806798

807799
Finally, we add the :const:`Py_TPFLAGS_HAVE_GC` flag to the class flags::
808800

809-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
801+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
810802

811803
That's pretty much it. If we had written custom :c:member:`~PyTypeObject.tp_alloc` or
812804
:c:member:`~PyTypeObject.tp_free` slots, we'd need to modify them for cyclic-garbage collection.
@@ -965,14 +957,15 @@ Finalization and De-allocation
965957

966958
This function is called when the reference count of the instance of your type is
967959
reduced to zero and the Python interpreter wants to reclaim it. If your type
968-
has memory to free or other clean-up to perform, put it here. The object itself
969-
needs to be freed here as well. Here is an example of this function::
960+
has memory to free or other clean-up to perform, you can put it here. The
961+
object itself needs to be freed here as well. Here is an example of this
962+
function::
970963

971964
static void
972965
newdatatype_dealloc(newdatatypeobject * obj)
973966
{
974967
free(obj->obj_UnderlyingDatatypePtr);
975-
obj->ob_type->tp_free(obj);
968+
Py_TYPE(obj)->tp_free(obj);
976969
}
977970

978971
.. index::
@@ -1015,7 +1008,7 @@ done. This can be done using the :c:func:`PyErr_Fetch` and
10151008

10161009
Py_DECREF(self->my_callback);
10171010
}
1018-
obj->ob_type->tp_free((PyObject*)self);
1011+
Py_TYPE(obj)->tp_free((PyObject*)self);
10191012
}
10201013

10211014

Doc/includes/noddy.c

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,26 @@ typedef struct {
66
} noddy_NoddyObject;
77

88
static PyTypeObject noddy_NoddyType = {
9-
PyObject_HEAD_INIT(NULL)
10-
0, /*ob_size*/
11-
"noddy.Noddy", /*tp_name*/
12-
sizeof(noddy_NoddyObject), /*tp_basicsize*/
13-
0, /*tp_itemsize*/
14-
0, /*tp_dealloc*/
15-
0, /*tp_print*/
16-
0, /*tp_getattr*/
17-
0, /*tp_setattr*/
18-
0, /*tp_compare*/
19-
0, /*tp_repr*/
20-
0, /*tp_as_number*/
21-
0, /*tp_as_sequence*/
22-
0, /*tp_as_mapping*/
23-
0, /*tp_hash */
24-
0, /*tp_call*/
25-
0, /*tp_str*/
26-
0, /*tp_getattro*/
27-
0, /*tp_setattro*/
28-
0, /*tp_as_buffer*/
29-
Py_TPFLAGS_DEFAULT, /*tp_flags*/
9+
PyVarObject_HEAD_INIT(NULL, 0)
10+
"noddy.Noddy", /* tp_name */
11+
sizeof(noddy_NoddyObject), /* tp_basicsize */
12+
0, /* tp_itemsize */
13+
0, /* tp_dealloc */
14+
0, /* tp_print */
15+
0, /* tp_getattr */
16+
0, /* tp_setattr */
17+
0, /* tp_compare */
18+
0, /* tp_repr */
19+
0, /* tp_as_number */
20+
0, /* tp_as_sequence */
21+
0, /* tp_as_mapping */
22+
0, /* tp_hash */
23+
0, /* tp_call */
24+
0, /* tp_str */
25+
0, /* tp_getattro */
26+
0, /* tp_setattro */
27+
0, /* tp_as_buffer */
28+
Py_TPFLAGS_DEFAULT, /* tp_flags */
3029
"Noddy objects", /* tp_doc */
3130
};
3231

Doc/includes/noddy2.c

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Noddy_dealloc(Noddy* self)
1313
{
1414
Py_XDECREF(self->first);
1515
Py_XDECREF(self->last);
16-
self->ob_type->tp_free((PyObject*)self);
16+
Py_TYPE(self)->tp_free((PyObject*)self);
1717
}
1818

1919
static PyObject *
@@ -24,18 +24,16 @@ Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
2424
self = (Noddy *)type->tp_alloc(type, 0);
2525
if (self != NULL) {
2626
self->first = PyString_FromString("");
27-
if (self->first == NULL)
28-
{
27+
if (self->first == NULL) {
2928
Py_DECREF(self);
3029
return NULL;
31-
}
32-
30+
}
31+
3332
self->last = PyString_FromString("");
34-
if (self->last == NULL)
35-
{
33+
if (self->last == NULL) {
3634
Py_DECREF(self);
3735
return NULL;
38-
}
36+
}
3937

4038
self->number = 0;
4139
}
@@ -50,10 +48,10 @@ Noddy_init(Noddy *self, PyObject *args, PyObject *kwds)
5048

5149
static char *kwlist[] = {"first", "last", "number", NULL};
5250

53-
if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
54-
&first, &last,
51+
if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
52+
&first, &last,
5553
&self->number))
56-
return -1;
54+
return -1;
5755

5856
if (first) {
5957
tmp = self->first;
@@ -111,7 +109,7 @@ Noddy_name(Noddy* self)
111109

112110
result = PyString_Format(format, args);
113111
Py_DECREF(args);
114-
112+
115113
return result;
116114
}
117115

@@ -123,34 +121,34 @@ static PyMethodDef Noddy_methods[] = {
123121
};
124122

125123
static PyTypeObject NoddyType = {
126-
PyObject_HEAD_INIT(NULL)
127-
0, /*ob_size*/
128-
"noddy.Noddy", /*tp_name*/
129-
sizeof(Noddy), /*tp_basicsize*/
130-
0, /*tp_itemsize*/
131-
(destructor)Noddy_dealloc, /*tp_dealloc*/
132-
0, /*tp_print*/
133-
0, /*tp_getattr*/
134-
0, /*tp_setattr*/
135-
0, /*tp_compare*/
136-
0, /*tp_repr*/
137-
0, /*tp_as_number*/
138-
0, /*tp_as_sequence*/
139-
0, /*tp_as_mapping*/
140-
0, /*tp_hash */
141-
0, /*tp_call*/
142-
0, /*tp_str*/
143-
0, /*tp_getattro*/
144-
0, /*tp_setattro*/
145-
0, /*tp_as_buffer*/
146-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
124+
PyVarObject_HEAD_INIT(NULL, 0)
125+
"noddy.Noddy", /* tp_name */
126+
sizeof(Noddy), /* tp_basicsize */
127+
0, /* tp_itemsize */
128+
(destructor)Noddy_dealloc, /* tp_dealloc */
129+
0, /* tp_print */
130+
0, /* tp_getattr */
131+
0, /* tp_setattr */
132+
0, /* tp_compare */
133+
0, /* tp_repr */
134+
0, /* tp_as_number */
135+
0, /* tp_as_sequence */
136+
0, /* tp_as_mapping */
137+
0, /* tp_hash */
138+
0, /* tp_call */
139+
0, /* tp_str */
140+
0, /* tp_getattro */
141+
0, /* tp_setattro */
142+
0, /* tp_as_buffer */
143+
Py_TPFLAGS_DEFAULT |
144+
Py_TPFLAGS_BASETYPE, /* tp_flags */
147145
"Noddy objects", /* tp_doc */
148-
0, /* tp_traverse */
149-
0, /* tp_clear */
150-
0, /* tp_richcompare */
151-
0, /* tp_weaklistoffset */
152-
0, /* tp_iter */
153-
0, /* tp_iternext */
146+
0, /* tp_traverse */
147+
0, /* tp_clear */
148+
0, /* tp_richcompare */
149+
0, /* tp_weaklistoffset */
150+
0, /* tp_iter */
151+
0, /* tp_iternext */
154152
Noddy_methods, /* tp_methods */
155153
Noddy_members, /* tp_members */
156154
0, /* tp_getset */
@@ -172,7 +170,7 @@ static PyMethodDef module_methods[] = {
172170
#define PyMODINIT_FUNC void
173171
#endif
174172
PyMODINIT_FUNC
175-
initnoddy2(void)
173+
initnoddy2(void)
176174
{
177175
PyObject* m;
178176

@@ -183,7 +181,7 @@ initnoddy2(void)
183181
"Example module that creates an extension type.");
184182

185183
if (m == NULL)
186-
return;
184+
return;
187185

188186
Py_INCREF(&NoddyType);
189187
PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType);

0 commit comments

Comments
 (0)