comparison _mysql_results.c @ 2:c0d1fc0429ce MySQLdb

Smashed _mysql.c with a great big hammer and got some smaller, more managable pieces.
author adustman
date Fri, 07 Apr 2006 05:06:01 +0000
parents _mysql.c@e51bc565a529
children d55bfb1a4701
comparison
equal deleted inserted replaced
1:e51bc565a529 2:c0d1fc0429ce
1 #include "_mysql.h"
2
3 static char _mysql_ResultObject__doc__[] =
4 "result(connection, use=0, converter={}) -- Result set from a query.\n\
5 \n\
6 Creating instances of this class directly is an excellent way to\n\
7 shoot yourself in the foot. If using _mysql.connection directly,\n\
8 use connection.store_result() or connection.use_result() instead.\n\
9 If using MySQLdb.Connection, this is done by the cursor class.\n\
10 Just forget you ever saw this. Forget... FOR-GET...";
11
12 int
13 _mysql_ResultObject_Initialize(
14 _mysql_ResultObject *self,
15 PyObject *args,
16 PyObject *kwargs)
17 {
18 static char *kwlist[] = {"connection", "use", "converter", NULL};
19 MYSQL_RES *result;
20 _mysql_ConnectionObject *conn=NULL;
21 int use=0;
22 PyObject *conv=NULL;
23 int n, i;
24 MYSQL_FIELD *fields;
25
26 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iO", kwlist,
27 &conn, &use, &conv))
28 return -1;
29 if (!conv) conv = PyDict_New();
30 if (!conv) return -1;
31 self->conn = (PyObject *) conn;
32 Py_INCREF(conn);
33 self->use = use;
34 Py_BEGIN_ALLOW_THREADS ;
35 if (use)
36 result = mysql_use_result(&(conn->connection));
37 else
38 result = mysql_store_result(&(conn->connection));
39 self->result = result;
40 Py_END_ALLOW_THREADS ;
41 if (!result) {
42 self->converter = PyTuple_New(0);
43 return 0;
44 }
45 n = mysql_num_fields(result);
46 self->nfields = n;
47 if (!(self->converter = PyTuple_New(n))) return -1;
48 fields = mysql_fetch_fields(result);
49 for (i=0; i<n; i++) {
50 PyObject *tmp, *fun;
51 tmp = PyInt_FromLong((long) fields[i].type);
52 if (!tmp) return -1;
53 fun = PyObject_GetItem(conv, tmp);
54 Py_DECREF(tmp);
55 if (!fun) {
56 PyErr_Clear();
57 fun = Py_None;
58 Py_INCREF(Py_None);
59 }
60 if (PySequence_Check(fun)) {
61 int j, n2=PySequence_Size(fun);
62 PyObject *fun2=NULL;
63 for (j=0; j<n2; j++) {
64 PyObject *t = PySequence_GetItem(fun, j);
65 if (!t) continue;
66 if (!PyTuple_Check(t)) goto cleanup;
67 if (PyTuple_GET_SIZE(t) == 2) {
68 long mask;
69 PyObject *pmask=NULL;
70 pmask = PyTuple_GET_ITEM(t, 0);
71 fun2 = PyTuple_GET_ITEM(t, 1);
72 if (PyInt_Check(pmask)) {
73 mask = PyInt_AS_LONG(pmask);
74 if (mask & fields[i].flags) {
75 break;
76 }
77 else {
78 continue;
79 }
80 } else {
81 break;
82 }
83 }
84 cleanup:
85 Py_DECREF(t);
86 }
87 if (!fun2) fun2 = Py_None;
88 Py_INCREF(fun2);
89 Py_DECREF(fun);
90 fun = fun2;
91 }
92 PyTuple_SET_ITEM(self->converter, i, fun);
93 }
94 return 0;
95 }
96
97 #if PY_VERSION_HEX >= 0x02020000
98 static int _mysql_ResultObject_traverse(
99 _mysql_ResultObject *self,
100 visitproc visit,
101 void *arg)
102 {
103 int r;
104 if (self->converter) {
105 if (!(r = visit(self->converter, arg))) return r;
106 }
107 if (self->conn)
108 return visit(self->conn, arg);
109 return 0;
110 }
111 #endif
112
113 static int _mysql_ResultObject_clear(
114 _mysql_ResultObject *self)
115 {
116 Py_XDECREF(self->converter);
117 self->converter = NULL;
118 Py_XDECREF(self->conn);
119 self->conn = NULL;
120 return 0;
121 }
122
123 static char _mysql_ResultObject_describe__doc__[] =
124 "Returns the sequence of 7-tuples required by the DB-API for\n\
125 the Cursor.description attribute.\n\
126 ";
127
128 static PyObject *
129 _mysql_ResultObject_describe(
130 _mysql_ResultObject *self,
131 PyObject *args)
132 {
133 PyObject *d;
134 MYSQL_FIELD *fields;
135 unsigned int i, n;
136 if (!PyArg_ParseTuple(args, "")) return NULL;
137 check_result_connection(self);
138 n = mysql_num_fields(self->result);
139 fields = mysql_fetch_fields(self->result);
140 if (!(d = PyTuple_New(n))) return NULL;
141 for (i=0; i<n; i++) {
142 PyObject *t;
143 t = Py_BuildValue("(siiiiii)",
144 fields[i].name,
145 (long) fields[i].type,
146 (long) fields[i].max_length,
147 (long) fields[i].length,
148 (long) fields[i].length,
149 (long) fields[i].decimals,
150 (long) !(IS_NOT_NULL(fields[i].flags)));
151 if (!t) goto error;
152 PyTuple_SET_ITEM(d, i, t);
153 }
154 return d;
155 error:
156 Py_XDECREF(d);
157 return NULL;
158 }
159
160 static char _mysql_ResultObject_field_flags__doc__[] =
161 "Returns a tuple of field flags, one for each column in the result.\n\
162 " ;
163
164 static PyObject *
165 _mysql_ResultObject_field_flags(
166 _mysql_ResultObject *self,
167 PyObject *args)
168 {
169 PyObject *d;
170 MYSQL_FIELD *fields;
171 unsigned int i, n;
172 if (!PyArg_ParseTuple(args, "")) return NULL;
173 check_result_connection(self);
174 n = mysql_num_fields(self->result);
175 fields = mysql_fetch_fields(self->result);
176 if (!(d = PyTuple_New(n))) return NULL;
177 for (i=0; i<n; i++) {
178 PyObject *f;
179 if (!(f = PyInt_FromLong((long)fields[i].flags))) goto error;
180 PyTuple_SET_ITEM(d, i, f);
181 }
182 return d;
183 error:
184 Py_XDECREF(d);
185 return NULL;
186 }
187
188 static PyObject *
189 _mysql_field_to_python(
190 PyObject *converter,
191 char *rowitem,
192 unsigned long length)
193 {
194 PyObject *v;
195 if (rowitem) {
196 if (converter != Py_None)
197 v = PyObject_CallFunction(converter,
198 "s#",
199 rowitem,
200 (int)length);
201 else
202 v = PyString_FromStringAndSize(rowitem,
203 (int)length);
204 if (!v)
205 return NULL;
206 } else {
207 Py_INCREF(Py_None);
208 v = Py_None;
209 }
210 return v;
211 }
212
213 static PyObject *
214 _mysql_row_to_tuple(
215 _mysql_ResultObject *self,
216 MYSQL_ROW row)
217 {
218 unsigned int n, i;
219 unsigned long *length;
220 PyObject *r, *c;
221
222 n = mysql_num_fields(self->result);
223 if (!(r = PyTuple_New(n))) return NULL;
224 length = mysql_fetch_lengths(self->result);
225 for (i=0; i<n; i++) {
226 PyObject *v;
227 c = PyTuple_GET_ITEM(self->converter, i);
228 v = _mysql_field_to_python(c, row[i], length[i]);
229 if (!v) goto error;
230 PyTuple_SET_ITEM(r, i, v);
231 }
232 return r;
233 error:
234 Py_XDECREF(r);
235 return NULL;
236 }
237
238 static PyObject *
239 _mysql_row_to_dict(
240 _mysql_ResultObject *self,
241 MYSQL_ROW row)
242 {
243 unsigned int n, i;
244 unsigned long *length;
245 PyObject *r, *c;
246 MYSQL_FIELD *fields;
247
248 n = mysql_num_fields(self->result);
249 if (!(r = PyDict_New())) return NULL;
250 length = mysql_fetch_lengths(self->result);
251 fields = mysql_fetch_fields(self->result);
252 for (i=0; i<n; i++) {
253 PyObject *v;
254 c = PyTuple_GET_ITEM(self->converter, i);
255 v = _mysql_field_to_python(c, row[i], length[i]);
256 if (!v) goto error;
257 if (!PyMapping_HasKeyString(r, fields[i].name)) {
258 PyMapping_SetItemString(r, fields[i].name, v);
259 } else {
260 int len;
261 char buf[256];
262 strncpy(buf, fields[i].table, 256);
263 len = strlen(buf);
264 strncat(buf, ".", 256-len);
265 len = strlen(buf);
266 strncat(buf, fields[i].name, 256-len);
267 PyMapping_SetItemString(r, buf, v);
268 }
269 Py_DECREF(v);
270 }
271 return r;
272 error:
273 Py_XDECREF(r);
274 return NULL;
275 }
276
277 static PyObject *
278 _mysql_row_to_dict_old(
279 _mysql_ResultObject *self,
280 MYSQL_ROW row)
281 {
282 unsigned int n, i;
283 unsigned long *length;
284 PyObject *r, *c;
285 MYSQL_FIELD *fields;
286
287 n = mysql_num_fields(self->result);
288 if (!(r = PyDict_New())) return NULL;
289 length = mysql_fetch_lengths(self->result);
290 fields = mysql_fetch_fields(self->result);
291 for (i=0; i<n; i++) {
292 PyObject *v;
293 c = PyTuple_GET_ITEM(self->converter, i);
294 v = _mysql_field_to_python(c, row[i], length[i]);
295 if (!v) goto error;
296 {
297 int len=0;
298 char buf[256]="";
299 if (strlen(fields[i].table)) {
300 strncpy(buf, fields[i].table, 256);
301 len = strlen(buf);
302 strncat(buf, ".", 256-len);
303 len = strlen(buf);
304 }
305 strncat(buf, fields[i].name, 256-len);
306 PyMapping_SetItemString(r, buf, v);
307 }
308 Py_DECREF(v);
309 }
310 return r;
311 error:
312 Py_XDECREF(r);
313 return NULL;
314 }
315
316 typedef PyObject *_PYFUNC(_mysql_ResultObject *, MYSQL_ROW);
317
318 int
319 _mysql__fetch_row(
320 _mysql_ResultObject *self,
321 PyObject **r,
322 int skiprows,
323 int maxrows,
324 _PYFUNC *convert_row)
325 {
326 unsigned int i;
327 MYSQL_ROW row;
328
329 for (i = skiprows; i<(skiprows+maxrows); i++) {
330 PyObject *v;
331 if (!self->use)
332 row = mysql_fetch_row(self->result);
333 else {
334 Py_BEGIN_ALLOW_THREADS;
335 row = mysql_fetch_row(self->result);
336 Py_END_ALLOW_THREADS;
337 }
338 if (!row && mysql_errno(&(((_mysql_ConnectionObject *)(self->conn))->connection))) {
339 _mysql_Exception((_mysql_ConnectionObject *)self->conn);
340 goto error;
341 }
342 if (!row) {
343 if (MyTuple_Resize(r, i, 0) == -1) goto error;
344 break;
345 }
346 v = convert_row(self, row);
347 if (!v) goto error;
348 PyTuple_SET_ITEM(*r, i, v);
349 }
350 return i-skiprows;
351 error:
352 return -1;
353 }
354
355 static char _mysql_ResultObject_fetch_row__doc__[] =
356 "fetch_row([maxrows, how]) -- Fetches up to maxrows as a tuple.\n\
357 The rows are formatted according to how:\n\
358 \n\
359 0 -- tuples (default)\n\
360 1 -- dictionaries, key=column or table.column if duplicated\n\
361 2 -- dictionaries, key=table.column\n\
362 ";
363
364 static PyObject *
365 _mysql_ResultObject_fetch_row(
366 _mysql_ResultObject *self,
367 PyObject *args,
368 PyObject *kwargs)
369 {
370 typedef PyObject *_PYFUNC(_mysql_ResultObject *, MYSQL_ROW);
371 static char *kwlist[] = { "maxrows", "how", NULL };
372 static _PYFUNC *row_converters[] =
373 {
374 _mysql_row_to_tuple,
375 _mysql_row_to_dict,
376 _mysql_row_to_dict_old
377 };
378 _PYFUNC *convert_row;
379 unsigned int maxrows=1, how=0, skiprows=0, rowsadded;
380 PyObject *r=NULL;
381
382 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:fetch_row", kwlist,
383 &maxrows, &how))
384 return NULL;
385 check_result_connection(self);
386 if (how < 0 || how >= sizeof(row_converters)) {
387 PyErr_SetString(PyExc_ValueError, "how out of range");
388 return NULL;
389 }
390 convert_row = row_converters[how];
391 if (maxrows) {
392 if (!(r = PyTuple_New(maxrows))) goto error;
393 rowsadded = _mysql__fetch_row(self, &r, skiprows, maxrows,
394 convert_row);
395 if (rowsadded == -1) goto error;
396 } else {
397 if (self->use) {
398 maxrows = 1000;
399 if (!(r = PyTuple_New(maxrows))) goto error;
400 while (1) {
401 rowsadded = _mysql__fetch_row(self, &r, skiprows,
402 maxrows, convert_row);
403 if (rowsadded == -1) goto error;
404 skiprows += rowsadded;
405 if (rowsadded < maxrows) break;
406 if (MyTuple_Resize(&r, skiprows+maxrows, 0) == -1)
407 goto error;
408 }
409 } else {
410 /* XXX if overflow, maxrows<0? */
411 maxrows = (int) mysql_num_rows(self->result);
412 if (!(r = PyTuple_New(maxrows))) goto error;
413 rowsadded = _mysql__fetch_row(self, &r, 0,
414 maxrows, convert_row);
415 if (rowsadded == -1) goto error;
416 }
417 }
418 return r;
419 error:
420 Py_XDECREF(r);
421 return NULL;
422 }
423
424
425 static char _mysql_ResultObject_num_fields__doc__[] =
426 "Returns the number of fields (column) in the result." ;
427
428 static PyObject *
429 _mysql_ResultObject_num_fields(
430 _mysql_ResultObject *self,
431 PyObject *args)
432 {
433 if (!PyArg_ParseTuple(args, "")) return NULL;
434 check_result_connection(self);
435 return PyInt_FromLong((long)mysql_num_fields(self->result));
436 }
437
438 static char _mysql_ResultObject_num_rows__doc__[] =
439 "Returns the number of rows in the result set. Note that if\n\
440 use=1, this will not return a valid value until the entire result\n\
441 set has been read.\n\
442 ";
443
444 static PyObject *
445 _mysql_ResultObject_num_rows(
446 _mysql_ResultObject *self,
447 PyObject *args)
448 {
449 if (!PyArg_ParseTuple(args, "")) return NULL;
450 check_result_connection(self);
451 return PyLong_FromUnsignedLongLong(mysql_num_rows(self->result));
452 }
453
454
455 static char _mysql_ResultObject_data_seek__doc__[] =
456 "data_seek(n) -- seek to row n of result set";
457 static PyObject *
458 _mysql_ResultObject_data_seek(
459 _mysql_ResultObject *self,
460 PyObject *args)
461 {
462 unsigned int row;
463 if (!PyArg_ParseTuple(args, "i:data_seek", &row)) return NULL;
464 check_result_connection(self);
465 mysql_data_seek(self->result, row);
466 Py_INCREF(Py_None);
467 return Py_None;
468 }
469
470 static char _mysql_ResultObject_row_seek__doc__[] =
471 "row_seek(n) -- seek by offset n rows of result set";
472 static PyObject *
473 _mysql_ResultObject_row_seek(
474 _mysql_ResultObject *self,
475 PyObject *args)
476 {
477 int offset;
478 MYSQL_ROW_OFFSET r;
479 if (!PyArg_ParseTuple(args, "i:row_seek", &offset)) return NULL;
480 check_result_connection(self);
481 if (self->use) {
482 PyErr_SetString(_mysql_ProgrammingError,
483 "cannot be used with connection.use_result()");
484 return NULL;
485 }
486 r = mysql_row_tell(self->result);
487 mysql_row_seek(self->result, r+offset);
488 Py_INCREF(Py_None);
489 return Py_None;
490 }
491
492 static char _mysql_ResultObject_row_tell__doc__[] =
493 "row_tell() -- return the current row number of the result set.";
494 static PyObject *
495 _mysql_ResultObject_row_tell(
496 _mysql_ResultObject *self,
497 PyObject *args)
498 {
499 MYSQL_ROW_OFFSET r;
500 if (!PyArg_ParseTuple(args, "")) return NULL;
501 check_result_connection(self);
502 if (self->use) {
503 PyErr_SetString(_mysql_ProgrammingError,
504 "cannot be used with connection.use_result()");
505 return NULL;
506 }
507 r = mysql_row_tell(self->result);
508 return PyInt_FromLong(r-self->result->data->data);
509 }
510
511 static void
512 _mysql_ResultObject_dealloc(
513 _mysql_ResultObject *self)
514 {
515 PyObject_GC_UnTrack((PyObject *)self);
516 mysql_free_result(self->result);
517 _mysql_ResultObject_clear(self);
518 MyFree(self);
519 }
520
521 static PyObject *
522 _mysql_ResultObject_repr(
523 _mysql_ResultObject *self)
524 {
525 char buf[300];
526 sprintf(buf, "<_mysql.result object at %lx>",
527 (long)self);
528 return PyString_FromString(buf);
529 }
530
531 static PyMethodDef _mysql_ResultObject_methods[] = {
532 {
533 "data_seek",
534 (PyCFunction)_mysql_ResultObject_data_seek,
535 METH_VARARGS,
536 _mysql_ResultObject_data_seek__doc__
537 },
538 {
539 "row_seek",
540 (PyCFunction)_mysql_ResultObject_row_seek,
541 METH_VARARGS,
542 _mysql_ResultObject_row_seek__doc__
543 },
544 {
545 "row_tell",
546 (PyCFunction)_mysql_ResultObject_row_tell,
547 METH_VARARGS,
548 _mysql_ResultObject_row_tell__doc__
549 },
550 {
551 "describe",
552 (PyCFunction)_mysql_ResultObject_describe,
553 METH_VARARGS,
554 _mysql_ResultObject_describe__doc__
555 },
556 {
557 "fetch_row",
558 (PyCFunction)_mysql_ResultObject_fetch_row,
559 METH_VARARGS | METH_KEYWORDS,
560 _mysql_ResultObject_fetch_row__doc__
561 },
562 {
563 "field_flags",
564 (PyCFunction)_mysql_ResultObject_field_flags,
565 METH_VARARGS,
566 _mysql_ResultObject_field_flags__doc__
567 },
568 {
569 "num_fields",
570 (PyCFunction)_mysql_ResultObject_num_fields,
571 METH_VARARGS,
572 _mysql_ResultObject_num_fields__doc__
573 },
574 {
575 "num_rows",
576 (PyCFunction)_mysql_ResultObject_num_rows,
577 METH_VARARGS,
578 _mysql_ResultObject_num_rows__doc__
579 },
580 {NULL, NULL} /* sentinel */
581 };
582
583 static MyMemberlist(_mysql_ResultObject_memberlist)[] = {
584 MyMember(
585 "converter",
586 T_OBJECT,
587 offsetof(_mysql_ResultObject,converter),
588 RO,
589 "Type conversion mapping"
590 ),
591 {NULL} /* Sentinel */
592 };
593
594 static PyObject *
595 _mysql_ResultObject_getattr(
596 _mysql_ResultObject *self,
597 char *name)
598 {
599 PyObject *res;
600
601 res = Py_FindMethod(_mysql_ResultObject_methods, (PyObject *)self, name);
602 if (res != NULL)
603 return res;
604 PyErr_Clear();
605 #if PY_VERSION_HEX < 0x02020000
606 return PyMember_Get((char *)self, _mysql_ResultObject_memberlist, name);
607 #else
608 {
609 MyMemberlist(*l);
610 for (l = _mysql_ResultObject_memberlist; l->name != NULL; l++) {
611 if (strcmp(l->name, name) == 0)
612 return PyMember_GetOne((char *)self, l);
613 }
614 PyErr_SetString(PyExc_AttributeError, name);
615 return NULL;
616 }
617 #endif
618 }
619
620 static int
621 _mysql_ResultObject_setattr(
622 _mysql_ResultObject *self,
623 char *name,
624 PyObject *v)
625 {
626 if (v == NULL) {
627 PyErr_SetString(PyExc_AttributeError,
628 "can't delete connection attributes");
629 return -1;
630 }
631 #if PY_VERSION_HEX < 0x02020000
632 return PyMember_Set((char *)self, _mysql_ResultObject_memberlist, name, v);
633 #else
634 {
635 MyMemberlist(*l);
636 for (l = _mysql_ResultObject_memberlist; l->name != NULL; l++)
637 if (strcmp(l->name, name) == 0)
638 return PyMember_SetOne((char *)self, l, v);
639 }
640 PyErr_SetString(PyExc_AttributeError, name);
641 return -1;
642 #endif
643 }
644
645 PyTypeObject _mysql_ResultObject_Type = {
646 PyObject_HEAD_INIT(NULL)
647 0,
648 "_mysql.result",
649 sizeof(_mysql_ResultObject),
650 0,
651 (destructor)_mysql_ResultObject_dealloc, /* tp_dealloc */
652 0, /*tp_print*/
653 (getattrfunc)_mysql_ResultObject_getattr, /* tp_getattr */
654 (setattrfunc)_mysql_ResultObject_setattr, /* tp_setattr */
655 0, /*tp_compare*/
656 (reprfunc)_mysql_ResultObject_repr, /* tp_repr */
657
658 /* Method suites for standard classes */
659
660 0, /* (PyNumberMethods *) tp_as_number */
661 0, /* (PySequenceMethods *) tp_as_sequence */
662 0, /* (PyMappingMethods *) tp_as_mapping */
663
664 /* More standard operations (here for binary compatibility) */
665
666 0, /* (hashfunc) tp_hash */
667 0, /* (ternaryfunc) tp_call */
668 0, /* (reprfunc) tp_str */
669 0, /* (getattrofunc) tp_getattro */
670 0, /* (setattrofunc) tp_setattro */
671
672 /* Functions to access object as input/output buffer */
673 0, /* (PyBufferProcs *) tp_as_buffer */
674
675 /* Flags to define presence of optional/expanded features */
676 #if PY_VERSION_HEX < 0x02020000
677 Py_TPFLAGS_DEFAULT, /* (long) tp_flags */
678 #else
679 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE,
680 #endif
681
682 _mysql_ResultObject__doc__, /* (char *) tp_doc Documentation string */
683 #if PY_VERSION_HEX >= 0x02000000
684 /* Assigned meaning in release 2.0 */
685 #if PY_VERSION_HEX >= 0x02020000
686 /* call function for all accessible objects */
687 (traverseproc) _mysql_ResultObject_traverse, /* tp_traverse */
688
689 /* delete references to contained objects */
690 (inquiry) _mysql_ResultObject_clear, /* tp_clear */
691 #else
692 /* not supporting pre-2.2 GC */
693 0,
694 0,
695 #endif
696 #if PY_VERSION_HEX >= 0x02010000
697 /* Assigned meaning in release 2.1 */
698 /* rich comparisons */
699 0, /* (richcmpfunc) tp_richcompare */
700
701 /* weak reference enabler */
702 0, /* (long) tp_weaklistoffset */
703 #if PY_VERSION_HEX >= 0x02020000
704 /* Added in release 2.2 */
705 /* Iterators */
706 0, /* (getiterfunc) tp_iter */
707 0, /* (iternextfunc) tp_iternext */
708
709 /* Attribute descriptor and subclassing stuff */
710 (struct PyMethodDef *) _mysql_ResultObject_methods, /* tp_methods */
711 (MyMemberlist(*)) _mysql_ResultObject_memberlist, /*tp_members */
712 0, /* (struct getsetlist *) tp_getset; */
713 0, /* (struct _typeobject *) tp_base; */
714 0, /* (PyObject *) tp_dict */
715 0, /* (descrgetfunc) tp_descr_get */
716 0, /* (descrsetfunc) tp_descr_set */
717 0, /* (long) tp_dictoffset */
718 (initproc)_mysql_ResultObject_Initialize, /* tp_init */
719 NULL, /* tp_alloc */
720 NULL, /* tp_new */
721 NULL, /* tp_free Low-level free-memory routine */
722 0, /* (PyObject *) tp_bases */
723 0, /* (PyObject *) tp_mro method resolution order */
724 0, /* (PyObject *) tp_defined */
725 #endif /* python 2.2 */
726 #endif /* python 2.1 */
727 #endif /* python 2.0 */
728 };