2 Python wrappers for TDB module
4 Copyright (C) Tim Potter, 2002-2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 NOTE: Since tdb is licenced under the GPL any program that uses these bindings
23 must be distributed under the GPL license terms since this is what
26 http://www.gnu.org/licenses/gpl-faq.html#IfInterpreterIsGPL
31 /* This symbol is used in both includes.h and Python.h which causes an
32 annoying compiler warning. */
42 PyObject
*py_tdb_error
;
44 /* tdb handle object */
51 PyTypeObject tdb_hnd_type
;
53 PyObject
*new_tdb_hnd_object(TDB_CONTEXT
*tdb
)
57 obj
= PyObject_New(tdb_hnd_object
, &tdb_hnd_type
);
60 return (PyObject
*)obj
;
63 PyObject
*py_tdb_close(PyObject
*self
, PyObject
*args
)
67 if (!PyArg_ParseTuple(args
, "O!", &tdb_hnd_type
, &obj
))
70 if (tdb_close(obj
->tdb
) == -1) {
72 PyErr_SetString(py_tdb_error
, strerror(errno
));
82 PyObject
*py_tdb_open(PyObject
*self
, PyObject
*args
, PyObject
*kw
)
84 static char *kwlist
[] = { "name", "hash_size", "tdb_flags",
85 "open_flags", "mode", NULL
};
87 int hash_size
= 0, flags
= TDB_DEFAULT
, open_flags
= -1, open_mode
= 0600;
90 if (!PyArg_ParseTupleAndKeywords(
91 args
, kw
, "s|iiii", kwlist
, &name
, &hash_size
, &flags
,
92 &open_flags
, &open_mode
))
95 /* Default open_flags to read/write */
97 if (open_flags
== -1) {
98 if (access(name
, W_OK
) == -1)
99 open_flags
= O_RDONLY
;
104 if (!(tdb
= tdb_open(name
, hash_size
, flags
, open_flags
, open_mode
))) {
105 PyErr_SetString(py_tdb_error
, strerror(errno
));
109 return new_tdb_hnd_object(tdb
);
113 * Allow a tdb to act as a python mapping (dictionary)
116 static int tdb_traverse_count(TDB_CONTEXT
*tdb
, TDB_DATA key
, TDB_DATA value
,
119 /* Do nothing - tdb_traverse will return the number of records
125 static int tdb_hnd_length(tdb_hnd_object
*obj
)
129 result
= tdb_traverse(obj
->tdb
, tdb_traverse_count
, NULL
);
134 static PyObject
*tdb_hnd_subscript(tdb_hnd_object
*obj
, PyObject
*key
)
139 if (!PyArg_Parse(key
, "s#", &krec
.dptr
, &krec
.dsize
))
142 drec
= tdb_fetch(obj
->tdb
, krec
);
145 PyErr_SetString(PyExc_KeyError
,
146 PyString_AsString(key
));
150 result
= PyString_FromStringAndSize(drec
.dptr
, drec
.dsize
);
156 static int tdb_ass_subscript(tdb_hnd_object
*obj
, PyObject
*key
, PyObject
*value
)
160 if (!PyArg_Parse(key
, "s#", &krec
.dptr
, &krec
.dsize
)) {
161 PyErr_SetString(PyExc_TypeError
,
162 "tdb mappings have string indices only");
168 py_tdb_error
, "tdb object has been closed");
176 if (tdb_delete(obj
->tdb
, krec
) == -1) {
177 PyErr_SetString(PyExc_KeyError
,
178 PyString_AsString(value
));
186 if (!PyArg_Parse(value
, "s#", &drec
.dptr
, &drec
.dsize
)) {
187 PyErr_SetString(PyExc_TypeError
,
188 "tdb mappings have string elements only");
194 if (tdb_store(obj
->tdb
, krec
, drec
, 0) < 0 ) {
196 PyErr_SetFromErrno(py_tdb_error
);
200 (char *)tdb_errorstr(obj
->tdb
));
209 static PyMappingMethods tdb_mapping
= {
210 (inquiry
) tdb_hnd_length
,
211 (binaryfunc
) tdb_hnd_subscript
,
212 (objobjargproc
) tdb_ass_subscript
219 /* Return non-zero if a given key exists in the tdb */
221 PyObject
*py_tdb_hnd_has_key(PyObject
*self
, PyObject
*args
)
223 tdb_hnd_object
*obj
= (tdb_hnd_object
*)self
;
226 if (!PyArg_ParseTuple(args
, "s#", &key
.dptr
, &key
.dsize
))
231 py_tdb_error
, "tdb object has been closed");
235 return PyInt_FromLong(tdb_exists(obj
->tdb
, key
));
238 /* Return a list of keys in the tdb */
240 static int tdb_traverse_keys(TDB_CONTEXT
*tdb
, TDB_DATA key
, TDB_DATA value
,
243 PyObject
*key_list
= (PyObject
*)state
;
245 PyList_Append(key_list
,
246 PyString_FromStringAndSize(key
.dptr
, key
.dsize
));
251 PyObject
*py_tdb_hnd_keys(PyObject
*self
, PyObject
*args
)
253 tdb_hnd_object
*obj
= (tdb_hnd_object
*)self
;
254 PyObject
*key_list
= PyList_New(0);
257 PyErr_SetString(py_tdb_error
, "tdb object has been closed");
261 if (tdb_traverse(obj
->tdb
, tdb_traverse_keys
, key_list
) == -1) {
262 PyErr_SetString(py_tdb_error
, "error traversing tdb");
270 PyObject
*py_tdb_hnd_first_key(PyObject
*self
, PyObject
*args
)
272 tdb_hnd_object
*obj
= (tdb_hnd_object
*)self
;
276 PyErr_SetString(py_tdb_error
, "tdb object has been closed");
280 key
= tdb_firstkey(obj
->tdb
);
282 return Py_BuildValue("s#", key
.dptr
, key
.dsize
);
285 PyObject
*py_tdb_hnd_next_key(PyObject
*self
, PyObject
*py_oldkey
)
287 tdb_hnd_object
*obj
= (tdb_hnd_object
*)self
;
288 TDB_DATA key
, oldkey
;
291 PyErr_SetString(py_tdb_error
, "tdb object has been closed");
295 if (!PyArg_Parse(py_oldkey
, "s#", &oldkey
.dptr
, &oldkey
.dsize
))
298 key
= tdb_nextkey(obj
->tdb
, oldkey
);
300 return Py_BuildValue("s#", key
.dptr
, key
.dsize
);
307 PyObject
*py_tdb_hnd_lock_all(PyObject
*self
, PyObject
*args
)
309 tdb_hnd_object
*obj
= (tdb_hnd_object
*)self
;
313 PyErr_SetString(py_tdb_error
, "tdb object has been closed");
317 result
= tdb_lockall(obj
->tdb
);
319 return PyInt_FromLong(result
!= -1);
322 PyObject
*py_tdb_hnd_unlock_all(PyObject
*self
, PyObject
*args
)
324 tdb_hnd_object
*obj
= (tdb_hnd_object
*)self
;
327 PyErr_SetString(py_tdb_error
, "tdb object has been closed");
331 tdb_unlockall(obj
->tdb
);
337 /* Return an array of keys from a python object which must be a string or a
340 static BOOL
make_lock_list(PyObject
*py_keys
, TDB_DATA
**keys
, int *num_keys
)
342 /* Are we a list or a string? */
344 if (!PyList_Check(py_keys
) && !PyString_Check(py_keys
)) {
345 PyErr_SetString(PyExc_TypeError
, "arg must be list of string");
349 if (PyList_Check(py_keys
)) {
352 /* Turn python list into array of keys */
354 *num_keys
= PyList_Size(py_keys
);
355 *keys
= (TDB_DATA
*)malloc(sizeof(TDB_DATA
) * (*num_keys
));
357 for (i
= 0; i
< *num_keys
; i
++) {
358 PyObject
*key
= PyList_GetItem(py_keys
, i
);
360 if (!PyString_Check(key
)) {
363 "list elements must be strings");
367 PyArg_Parse(key
, "s#", &(*keys
)[i
].dptr
,
373 /* Turn python string into a single key */
375 *keys
= (TDB_DATA
*)malloc(sizeof(TDB_DATA
));
377 PyArg_Parse(py_keys
, "s#", &(*keys
)->dptr
, &(*keys
)->dsize
);
383 PyObject
*py_tdb_hnd_lock(PyObject
*self
, PyObject
*args
)
385 tdb_hnd_object
*obj
= (tdb_hnd_object
*)self
;
388 int num_keys
, result
;
391 PyErr_SetString(py_tdb_error
, "tdb object has been closed");
395 if (!PyArg_ParseTuple(args
, "O", &py_keys
))
398 if (!make_lock_list(py_keys
, &keys
, &num_keys
))
401 result
= tdb_lockkeys(obj
->tdb
, num_keys
, keys
);
405 return PyInt_FromLong(result
!= -1);
408 PyObject
*py_tdb_hnd_unlock(PyObject
*self
, PyObject
*args
)
410 tdb_hnd_object
*obj
= (tdb_hnd_object
*)self
;
413 PyErr_SetString(py_tdb_error
, "tdb object has been closed");
417 if (!PyArg_ParseTuple(args
, ""))
420 tdb_unlockkeys(obj
->tdb
);
430 struct traverse_info
{
435 static int tdb_traverse_traverse(TDB_CONTEXT
*tdb
, TDB_DATA key
, TDB_DATA value
,
438 struct traverse_info
*info
= state
;
439 PyObject
*arglist
, *py_result
;
442 arglist
= Py_BuildValue("(s#s#O)", key
.dptr
, key
.dsize
, value
.dptr
,
443 value
.dsize
, info
->state
);
445 py_result
= PyEval_CallObject(info
->callback
, arglist
);
449 if (!PyInt_Check(py_result
)) {
450 result
= 1; /* Hmm - non-integer object returned by callback */
454 result
= PyInt_AsLong(py_result
);
457 Py_DECREF(py_result
);
461 PyObject
*py_tdb_hnd_traverse(PyObject
*self
, PyObject
*args
, PyObject
*kw
)
463 tdb_hnd_object
*obj
= (tdb_hnd_object
*)self
;
464 static char *kwlist
[] = { "traverse_fn", "state", NULL
};
465 PyObject
*state
= Py_None
, *callback
;
466 struct traverse_info info
;
469 if (!PyArg_ParseTupleAndKeywords(
470 args
, kw
, "O|O", kwlist
, &callback
, &state
))
473 if (!PyCallable_Check(callback
)) {
474 PyErr_SetString(PyExc_TypeError
, "parameter must be callable");
481 info
.callback
= callback
;
484 result
= tdb_traverse(obj
->tdb
, tdb_traverse_traverse
, &info
);
489 return PyInt_FromLong(result
);
492 PyObject
*py_tdb_hnd_chainlock(PyObject
*self
, PyObject
*args
)
494 tdb_hnd_object
*obj
= (tdb_hnd_object
*)self
;
499 PyErr_SetString(py_tdb_error
, "tdb object has been closed");
503 if (!PyArg_ParseTuple(args
, "s#", &key
.dptr
, &key
.dsize
))
506 result
= tdb_chainlock(obj
->tdb
, key
);
508 return PyInt_FromLong(result
!= -1);
511 PyObject
*py_tdb_hnd_chainunlock(PyObject
*self
, PyObject
*args
)
513 tdb_hnd_object
*obj
= (tdb_hnd_object
*)self
;
518 PyErr_SetString(py_tdb_error
, "tdb object has been closed");
522 if (!PyArg_ParseTuple(args
, "s#", &key
.dptr
, &key
.dsize
))
525 result
= tdb_chainunlock(obj
->tdb
, key
);
527 return PyInt_FromLong(result
!= -1);
530 PyObject
*py_tdb_hnd_lock_bystring(PyObject
*self
, PyObject
*args
)
532 tdb_hnd_object
*obj
= (tdb_hnd_object
*)self
;
533 int result
, timeout
= 30;
537 PyErr_SetString(py_tdb_error
, "tdb object has been closed");
541 if (!PyArg_ParseTuple(args
, "s|i", &s
, &timeout
))
544 result
= tdb_lock_bystring(obj
->tdb
, s
, timeout
);
546 return PyInt_FromLong(result
!= -1);
549 PyObject
*py_tdb_hnd_unlock_bystring(PyObject
*self
, PyObject
*args
)
551 tdb_hnd_object
*obj
= (tdb_hnd_object
*)self
;
555 PyErr_SetString(py_tdb_error
, "tdb object has been closed");
559 if (!PyArg_ParseTuple(args
, "s", &s
))
562 tdb_unlock_bystring(obj
->tdb
, s
);
569 * Method dispatch table for this module
572 static PyMethodDef tdb_methods
[] = {
573 { "open", (PyCFunction
)py_tdb_open
, METH_VARARGS
| METH_KEYWORDS
},
574 { "close", (PyCFunction
)py_tdb_close
, METH_VARARGS
},
579 * Methods on a tdb object
582 static PyMethodDef tdb_hnd_methods
[] = {
583 { "keys", (PyCFunction
)py_tdb_hnd_keys
, METH_VARARGS
},
584 { "has_key", (PyCFunction
)py_tdb_hnd_has_key
, METH_VARARGS
},
585 { "first_key", (PyCFunction
)py_tdb_hnd_first_key
, METH_VARARGS
},
586 { "next_key", (PyCFunction
)py_tdb_hnd_next_key
, METH_VARARGS
},
587 { "lock_all", (PyCFunction
)py_tdb_hnd_lock_all
, METH_VARARGS
},
588 { "unlock_all", (PyCFunction
)py_tdb_hnd_unlock_all
, METH_VARARGS
},
589 { "lock", (PyCFunction
)py_tdb_hnd_lock
, METH_VARARGS
},
590 { "unlock", (PyCFunction
)py_tdb_hnd_unlock
, METH_VARARGS
},
591 { "traverse", (PyCFunction
)py_tdb_hnd_traverse
, METH_VARARGS
| METH_KEYWORDS
},
592 { "chainlock", (PyCFunction
)py_tdb_hnd_chainlock
, METH_VARARGS
| METH_KEYWORDS
},
593 { "chainunlock", (PyCFunction
)py_tdb_hnd_chainunlock
, METH_VARARGS
| METH_KEYWORDS
},
594 { "lock_bystring", (PyCFunction
)py_tdb_hnd_lock_bystring
, METH_VARARGS
| METH_KEYWORDS
},
595 { "unlock_bystring", (PyCFunction
)py_tdb_hnd_unlock_bystring
, METH_VARARGS
| METH_KEYWORDS
},
599 /* Deallocate a tdb handle object */
601 static void tdb_hnd_dealloc(PyObject
* self
)
603 tdb_hnd_object
*hnd
= (tdb_hnd_object
*)self
;
611 /* Return tdb handle attributes */
613 static PyObject
*tdb_hnd_getattr(PyObject
*self
, char *attrname
)
615 return Py_FindMethod(tdb_hnd_methods
, self
, attrname
);
618 static char tdb_hnd_type_doc
[] =
619 "Python wrapper for tdb.";
621 PyTypeObject tdb_hnd_type
= {
622 PyObject_HEAD_INIT(NULL
)
625 sizeof(tdb_hnd_object
),
627 tdb_hnd_dealloc
, /* tp_dealloc*/
629 tdb_hnd_getattr
, /* tp_getattr*/
634 0, /* tp_as_sequence*/
635 &tdb_mapping
, /* tp_as_mapping*/
642 Py_TPFLAGS_DEFAULT
, /* tp_flags */
643 tdb_hnd_type_doc
, /* tp_doc */
648 static struct const_vals
{
651 } module_const_vals
[] = {
653 /* Flags for tdb_open() */
655 { "TDB_DEFAULT", TDB_DEFAULT
},
656 { "TDB_CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST
},
657 { "TDB_INTERNAL", TDB_INTERNAL
},
658 { "TDB_NOLOCK", TDB_NOLOCK
},
659 { "TDB_NOMMAP", TDB_NOMMAP
},
660 { "TDB_CONVERT", TDB_CONVERT
},
661 { "TDB_BIGENDIAN", TDB_BIGENDIAN
},
666 static void const_init(PyObject
*dict
)
668 struct const_vals
*tmp
;
671 for (tmp
= module_const_vals
; tmp
->name
; tmp
++) {
672 obj
= PyInt_FromLong(tmp
->value
);
673 PyDict_SetItemString(dict
, tmp
->name
, obj
);
678 /* Module initialisation */
682 PyObject
*module
, *dict
;
684 /* Initialise module */
686 module
= Py_InitModule("tdb", tdb_methods
);
687 dict
= PyModule_GetDict(module
);
689 py_tdb_error
= PyErr_NewException("tdb.error", NULL
, NULL
);
690 PyDict_SetItemString(dict
, "error", py_tdb_error
);
692 /* Initialise policy handle object */
694 tdb_hnd_type
.ob_type
= &PyType_Type
;
696 PyDict_SetItemString(dict
, "tdb.hnd",
697 (PyObject
*)&tdb_hnd_type
);
699 /* Initialise constants */