Python module: python3 compatibility

This commit is contained in:
Jean-Francois Dockes 2013-10-30 10:38:02 +01:00
parent 3e8989e096
commit 33833c5b22
6 changed files with 255 additions and 110 deletions

View File

@ -81,6 +81,7 @@ src/index/alldeps.stamp
src/index/recollindex src/index/recollindex
src/internfile/alldeps src/internfile/alldeps
src/kde/kioslave/kio_recoll/builddir src/kde/kioslave/kio_recoll/builddir
src/lib/Makefile
src/lib/alldeps src/lib/alldeps
src/lib/librecoll.a src/lib/librecoll.a
src/lib/librecoll.so* src/lib/librecoll.so*

View File

@ -51,7 +51,7 @@ Extractor_dealloc(rclx_ExtractorObject *self)
{ {
LOGDEB(("Extractor_dealloc\n")); LOGDEB(("Extractor_dealloc\n"));
delete self->xtr; delete self->xtr;
self->ob_type->tp_free((PyObject*)self); Py_TYPE(self)->tp_free((PyObject*)self);
} }
static PyObject * static PyObject *
@ -191,8 +191,8 @@ Extractor_idoctofile(rclx_ExtractorObject* self, PyObject *args,
} }
if (outfile.empty()) if (outfile.empty())
temp->setnoremove(1); temp->setnoremove(1);
PyObject *result = outfile.empty() ? PyString_FromString(temp->filename()) : PyObject *result = outfile.empty() ? PyBytes_FromString(temp->filename()) :
PyString_FromString(outfile.c_str()); PyBytes_FromString(outfile.c_str());
return (PyObject *)result; return (PyObject *)result;
} }
@ -211,8 +211,7 @@ PyDoc_STRVAR(doc_ExtractorObject,
"object.\n" "object.\n"
); );
static PyTypeObject rclx_ExtractorType = { static PyTypeObject rclx_ExtractorType = {
PyObject_HEAD_INIT(NULL) PyVarObject_HEAD_INIT(NULL, 0)
0, /*ob_size*/
"rclextract.Extractor", /*tp_name*/ "rclextract.Extractor", /*tp_name*/
sizeof(rclx_ExtractorObject), /*tp_basicsize*/ sizeof(rclx_ExtractorObject), /*tp_basicsize*/
0, /*tp_itemsize*/ 0, /*tp_itemsize*/
@ -253,17 +252,56 @@ static PyTypeObject rclx_ExtractorType = {
}; };
///////////////////////////////////// Module-level stuff ///////////////////////////////////// Module-level stuff
static PyMethodDef rclxMethods[] = { static PyMethodDef rclextract_methods[] = {
{NULL, NULL, 0, NULL} /* Sentinel */ {NULL, NULL, 0, NULL} /* Sentinel */
}; };
PyDoc_STRVAR(rclx_doc_string, PyDoc_STRVAR(rclx_doc_string,
"This is an interface to the Recoll text extraction features."); "This is an interface to the Recoll text extraction features.");
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ struct module_state {
#define PyMODINIT_FUNC void PyObject *error;
};
#if PY_MAJOR_VERSION >= 3
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
#else
#define GETSTATE(m) (&_state)
static struct module_state _state;
#endif #endif
#if PY_MAJOR_VERSION >= 3
static int rclextract_traverse(PyObject *m, visitproc visit, void *arg) {
Py_VISIT(GETSTATE(m)->error);
return 0;
}
static int rclextract_clear(PyObject *m) {
Py_CLEAR(GETSTATE(m)->error);
return 0;
}
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"rclextract",
NULL,
sizeof(struct module_state),
rclextract_methods,
NULL,
rclextract_traverse,
rclextract_clear,
NULL
};
#define INITERROR return NULL
extern "C" PyObject *
PyInit_rclextract(void)
#else
#define INITERROR return
PyMODINIT_FUNC PyMODINIT_FUNC
initrclextract(void) initrclextract(void)
#endif
{ {
// We run recollinit. It's responsible for initializing some static data // We run recollinit. It's responsible for initializing some static data
// which is distinct from pyrecoll's as we're separately dlopened // which is distinct from pyrecoll's as we're separately dlopened
@ -271,33 +309,53 @@ initrclextract(void)
rclconfig = recollinit(0, 0, reason, 0); rclconfig = recollinit(0, 0, reason, 0);
if (rclconfig == 0) { if (rclconfig == 0) {
PyErr_SetString(PyExc_EnvironmentError, reason.c_str()); PyErr_SetString(PyExc_EnvironmentError, reason.c_str());
return; INITERROR;
} }
if (!rclconfig->ok()) { if (!rclconfig->ok()) {
PyErr_SetString(PyExc_EnvironmentError, PyErr_SetString(PyExc_EnvironmentError,
"Recoll init error: bad environment ?"); "Recoll init error: bad environment ?");
return; INITERROR;
} }
PyObject* m = Py_InitModule("rclextract", rclxMethods); #if PY_MAJOR_VERSION >= 3
PyModule_AddStringConstant(m, "__doc__", rclx_doc_string); PyObject *module = PyModule_Create(&moduledef);
#else
PyObject *module = Py_InitModule("rclextract", rclextract_methods);
#endif
if (module == NULL)
INITERROR;
struct module_state *st = GETSTATE(module);
// The first parameter is a char *. Hopefully we don't initialize
// modules too often...
st->error = PyErr_NewException(strdup("rclextract.Error"), NULL, NULL);
if (st->error == NULL) {
Py_DECREF(module);
INITERROR;
}
PyModule_AddStringConstant(module, "__doc__", rclx_doc_string);
if (PyType_Ready(&rclx_ExtractorType) < 0) if (PyType_Ready(&rclx_ExtractorType) < 0)
return; INITERROR;
Py_INCREF(&rclx_ExtractorType); Py_INCREF(&rclx_ExtractorType);
PyModule_AddObject(m, "Extractor", (PyObject *)&rclx_ExtractorType); PyModule_AddObject(module, "Extractor", (PyObject *)&rclx_ExtractorType);
#if PY_MAJOR_VERSION >= 2 && PY_MINOR_VERSION >= 7 #if PY_MAJOR_VERSION >= 3 || (PY_MAJOR_VERSION >= 2 && PY_MINOR_VERSION >= 7)
recoll_DocType = (PyObject*)PyCapsule_Import(PYRECOLL_PACKAGE "recoll.doctypeptr", 0); recoll_DocType = (PyObject*)PyCapsule_Import(PYRECOLL_PACKAGE "recoll.doctypeptr", 0);
#else #else
PyObject *module = PyImport_ImportModule(PYRECOLL_PACKAGE "recoll"); PyObject *module = PyImport_ImportModule(PYRECOLL_PACKAGE "recoll");
if (module != NULL) { if (module != NULL) {
PyObject *cobject = PyObject_GetAttrString(module, "_C_API"); PyObject *cobject = PyObject_GetAttrString(module, "_C_API");
if (cobject == NULL) if (cobject == NULL)
return; INITERROR;
if (PyCObject_Check(cobject)) if (PyCObject_Check(cobject))
recoll_DocType = (PyObject*)PyCObject_AsVoidPtr(cobject); recoll_DocType = (PyObject*)PyCObject_AsVoidPtr(cobject);
Py_DECREF(cobject); Py_DECREF(cobject);
} }
#endif #endif
#if PY_MAJOR_VERSION >= 3
return module;
#endif
} }

View File

@ -47,6 +47,10 @@ static set<Rcl::Doc *> the_docs;
static RclConfig *rclconfig; static RclConfig *rclconfig;
#if PY_MAJOR_VERSION >=3
# define Py_TPFLAGS_HAVE_ITER 0
#endif
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
/// SEARCHDATA SearchData code /// SEARCHDATA SearchData code
typedef struct { typedef struct {
@ -59,7 +63,7 @@ static void
SearchData_dealloc(recoll_SearchDataObject *self) SearchData_dealloc(recoll_SearchDataObject *self)
{ {
LOGDEB(("SearchData_dealloc\n")); LOGDEB(("SearchData_dealloc\n"));
self->ob_type->tp_free((PyObject*)self); Py_TYPE(self)->tp_free((PyObject*)self);
} }
static PyObject * static PyObject *
@ -130,8 +134,7 @@ static PyMethodDef SearchData_methods[] = {
}; };
static PyTypeObject recoll_SearchDataType = { static PyTypeObject recoll_SearchDataType = {
PyObject_HEAD_INIT(NULL) PyVarObject_HEAD_INIT(NULL, 0)
0, /*ob_size*/
"recoll.SearchData", /*tp_name*/ "recoll.SearchData", /*tp_name*/
sizeof(recoll_SearchDataObject), /*tp_basicsize*/ sizeof(recoll_SearchDataObject), /*tp_basicsize*/
0, /*tp_itemsize*/ 0, /*tp_itemsize*/
@ -293,7 +296,7 @@ Doc_dealloc(recoll_DocObject *self)
if (self->doc) if (self->doc)
the_docs.erase(self->doc); the_docs.erase(self->doc);
deleteZ(self->doc); deleteZ(self->doc);
self->ob_type->tp_free((PyObject*)self); Py_TYPE(self)->tp_free((PyObject*)self);
} }
static PyObject * static PyObject *
@ -463,22 +466,41 @@ static PyMethodDef Doc_methods[] = {
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
// Note that this returns None if the attribute is not found instead of raising
// an exception as would be standard. We don't change it to keep existing code
// working.
static PyObject * static PyObject *
Doc_getattr(recoll_DocObject *self, char *name) Doc_getattro(recoll_DocObject *self, PyObject *nameobj)
{ {
LOGDEB1(("Doc_getattr: name [%s]\n", name)); if (self->doc == 0 || the_docs.find(self->doc) == the_docs.end()) {
if (self->doc == 0 ||
the_docs.find(self->doc) == the_docs.end()) {
PyErr_SetString(PyExc_AttributeError, "doc"); PyErr_SetString(PyExc_AttributeError, "doc");
return 0; return 0;
} }
string key = rclconfig->fieldCanon(string(name));
// Handle special cases, then check this is not a method then
// try retrieving key value from the meta array
string value;
bool found = false; bool found = false;
string value;
string key;
char *name = 0;
PyObject* utf8o = 0;
if (PyUnicode_Check(nameobj)) {
utf8o = PyUnicode_AsUTF8String(nameobj);
if (utf8o == 0) {
LOGERR(("Doc_getattro: encoding name to utf8 failed\n"));
PyErr_SetString(PyExc_AttributeError, "name??");
Py_RETURN_NONE;
}
name = PyBytes_AsString(utf8o);
Py_DECREF(utf8o);
} else if (PyBytes_Check(nameobj)) {
name = PyBytes_AsString(nameobj);
} else {
PyErr_SetString(PyExc_AttributeError, "name not unicode nor string??");
Py_RETURN_NONE;
}
key = rclconfig->fieldCanon(string(name));
switch (key.at(0)) { switch (key.at(0)) {
case 'u': case 'u':
if (!key.compare(Rcl::Doc::keyurl)) { if (!key.compare(Rcl::Doc::keyurl)) {
@ -533,48 +555,46 @@ Doc_getattr(recoll_DocObject *self, char *name)
} }
if (!found) { if (!found) {
PyObject *meth = Py_FindMethod(Doc_methods, (PyObject*)self, // This will look up a method name (we have no other standard
key.c_str()); // attributes)
PyObject *meth = PyObject_GenericGetAttr((PyObject*)self, nameobj);
if (meth) { if (meth) {
return meth; return meth;
} else {
PyErr_Clear();
} }
PyErr_Clear();
// Else look for another attribute
if (self->doc->getmeta(key, 0)) { if (self->doc->getmeta(key, 0)) {
value = self->doc->meta[key]; value = self->doc->meta[key];
found = true; found = true;
} }
} }
if (!found) { if (found) {
LOGDEB(("Doc_getattr: name [%s] key [%s] Not found\n", LOGDEB1(("Doc_getattro: [%s] -> [%s]\n", key.c_str(), value.c_str()));
name, key.c_str())); // Return a python unicode object
Py_RETURN_NONE; return PyUnicode_Decode(value.c_str(), value.size(), "utf-8",
"replace");
} }
LOGDEB1(("Doc_getattr: [%s] (%s) -> [%s]\n", Py_RETURN_NONE;
name, key.c_str(), value.c_str()));
// Return a python unicode object
PyObject* res = PyUnicode_Decode(value.c_str(), value.size(), "utf-8",
"replace");
return res;
} }
static int static int
Doc_setattr(recoll_DocObject *self, char *name, PyObject *value) Doc_setattr(recoll_DocObject *self, char *name, PyObject *value)
{ {
if (self->doc == 0 || if (self->doc == 0 || the_docs.find(self->doc) == the_docs.end()) {
the_docs.find(self->doc) == the_docs.end()) {
PyErr_SetString(PyExc_AttributeError, "doc??"); PyErr_SetString(PyExc_AttributeError, "doc??");
return -1; return -1;
} }
LOGDEB1(("Doc_setmeta: doc %p\n", self->doc)); LOGDEB1(("Doc_setmeta: doc %p\n", self->doc));
#if PY_MAJOR_VERSION < 3
if (PyString_Check(value)) { if (PyString_Check(value)) {
value = PyUnicode_FromObject(value); value = PyUnicode_FromObject(value);
if (value == 0) if (value == 0)
return -1; return -1;
} }
#endif
if (!PyUnicode_Check(value)) { if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_AttributeError, "value not str/unicode??"); PyErr_SetString(PyExc_AttributeError, "value not str/unicode??");
@ -591,8 +611,8 @@ Doc_setattr(recoll_DocObject *self, char *name, PyObject *value)
PyErr_SetString(PyExc_AttributeError, "value??"); PyErr_SetString(PyExc_AttributeError, "value??");
return -1; return -1;
} }
char* uvalue = PyBytes_AsString(putf8);
char* uvalue = PyString_AsString(putf8); Py_DECREF(putf8);
string key = rclconfig->fieldCanon(string(name)); string key = rclconfig->fieldCanon(string(name));
LOGDEB0(("Doc_setattr: [%s] (%s) -> [%s]\n", key.c_str(), name, uvalue)); LOGDEB0(("Doc_setattr: [%s] (%s) -> [%s]\n", key.c_str(), name, uvalue));
@ -690,14 +710,13 @@ PyDoc_STRVAR(doc_DocObject,
" keywords (both)\n" " keywords (both)\n"
); );
static PyTypeObject recoll_DocType = { static PyTypeObject recoll_DocType = {
PyObject_HEAD_INIT(NULL) PyVarObject_HEAD_INIT(NULL, 0)
0, /*ob_size*/
"recoll.Doc", /*tp_name*/ "recoll.Doc", /*tp_name*/
sizeof(recoll_DocObject), /*tp_basicsize*/ sizeof(recoll_DocObject), /*tp_basicsize*/
0, /*tp_itemsize*/ 0, /*tp_itemsize*/
(destructor)Doc_dealloc, /*tp_dealloc*/ (destructor)Doc_dealloc, /*tp_dealloc*/
0, /*tp_print*/ 0, /*tp_print*/
(getattrfunc)Doc_getattr, /*tp_getattr*/ 0, /*tp_getattr*/
(setattrfunc)Doc_setattr, /*tp_setattr*/ (setattrfunc)Doc_setattr, /*tp_setattr*/
0, /*tp_compare*/ 0, /*tp_compare*/
0, /*tp_repr*/ 0, /*tp_repr*/
@ -707,7 +726,7 @@ static PyTypeObject recoll_DocType = {
0, /*tp_hash */ 0, /*tp_hash */
0, /*tp_call*/ 0, /*tp_call*/
0, /*tp_str*/ 0, /*tp_str*/
0, /*tp_getattro*/ (getattrofunc)Doc_getattro,/*tp_getattro*/
0, /*tp_setattro*/ 0, /*tp_setattro*/
0, /*tp_as_buffer*/ 0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
@ -768,7 +787,7 @@ Query_dealloc(recoll_QueryObject *self)
{ {
LOGDEB(("Query_dealloc\n")); LOGDEB(("Query_dealloc\n"));
Query_close(self); Query_close(self);
self->ob_type->tp_free((PyObject*)self); Py_TYPE(self)->tp_free((PyObject*)self);
} }
static PyObject * static PyObject *
@ -1118,7 +1137,7 @@ public:
PyObject *res1 = res; PyObject *res1 = res;
if (PyUnicode_Check(res)) if (PyUnicode_Check(res))
res1 = PyUnicode_AsUTF8String(res); res1 = PyUnicode_AsUTF8String(res);
return PyString_AsString(res1); return PyBytes_AsString(res1);
} }
virtual string endMatch() virtual string endMatch()
@ -1131,7 +1150,7 @@ public:
PyObject *res1 = res; PyObject *res1 = res;
if (PyUnicode_Check(res)) if (PyUnicode_Check(res))
res1 = PyUnicode_AsUTF8String(res); res1 = PyUnicode_AsUTF8String(res);
return PyString_AsString(res1); return PyBytes_AsString(res1);
} }
PyObject *m_methods; PyObject *m_methods;
@ -1393,8 +1412,7 @@ PyDoc_STRVAR(doc_QueryObject,
"They must be created by the Db.query() method.\n" "They must be created by the Db.query() method.\n"
); );
static PyTypeObject recoll_QueryType = { static PyTypeObject recoll_QueryType = {
PyObject_HEAD_INIT(NULL) PyVarObject_HEAD_INIT(NULL, 0)
0, /*ob_size*/
"recoll.Query", /*tp_name*/ "recoll.Query", /*tp_name*/
sizeof(recoll_QueryObject), /*tp_basicsize*/ sizeof(recoll_QueryObject), /*tp_basicsize*/
0, /*tp_itemsize*/ 0, /*tp_itemsize*/
@ -1458,7 +1476,7 @@ Db_dealloc(recoll_DbObject *self)
{ {
LOGDEB(("Db_dealloc\n")); LOGDEB(("Db_dealloc\n"));
Db_close(self); Db_close(self);
self->ob_type->tp_free((PyObject*)self); Py_TYPE(self)->tp_free((PyObject*)self);
} }
static PyObject * static PyObject *
@ -1530,7 +1548,7 @@ Db_init(recoll_DbObject *self, PyObject *args, PyObject *kwargs)
} }
for (int i = 0; i < dbcnt; i++) { for (int i = 0; i < dbcnt; i++) {
PyObject *item = PySequence_GetItem(extradbs, i); PyObject *item = PySequence_GetItem(extradbs, i);
char *s = PyString_AsString(item); char *s = PyBytes_AsString(item);
Py_DECREF(item); Py_DECREF(item);
if (!s) { if (!s) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
@ -1857,8 +1875,7 @@ PyDoc_STRVAR(doc_DbObject,
"writable decides if we can index new data through this connection\n" "writable decides if we can index new data through this connection\n"
); );
static PyTypeObject recoll_DbType = { static PyTypeObject recoll_DbType = {
PyObject_HEAD_INIT(NULL) PyVarObject_HEAD_INIT(NULL, 0)
0, /*ob_size*/
"recoll.Db", /*tp_name*/ "recoll.Db", /*tp_name*/
sizeof(recoll_DbObject), /*tp_basicsize*/ sizeof(recoll_DbObject), /*tp_basicsize*/
0, /*tp_itemsize*/ 0, /*tp_itemsize*/
@ -1920,7 +1937,7 @@ PyDoc_STRVAR(doc_connect,
"writable decides if we can index new data through this connection\n" "writable decides if we can index new data through this connection\n"
); );
static PyMethodDef recollMethods[] = { static PyMethodDef recoll_methods[] = {
{"connect", (PyCFunction)recoll_connect, METH_VARARGS|METH_KEYWORDS, {"connect", (PyCFunction)recoll_connect, METH_VARARGS|METH_KEYWORDS,
doc_connect}, doc_connect},
@ -1931,50 +1948,110 @@ static PyMethodDef recollMethods[] = {
PyDoc_STRVAR(pyrecoll_doc_string, PyDoc_STRVAR(pyrecoll_doc_string,
"This is an interface to the Recoll full text indexer."); "This is an interface to the Recoll full text indexer.");
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ struct module_state {
#define PyMODINIT_FUNC void PyObject *error;
};
#if PY_MAJOR_VERSION >= 3
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
#else
#define GETSTATE(m) (&_state)
static struct module_state _state;
#endif #endif
#if PY_MAJOR_VERSION >= 3
static int recoll_traverse(PyObject *m, visitproc visit, void *arg) {
Py_VISIT(GETSTATE(m)->error);
return 0;
}
static int recoll_clear(PyObject *m) {
Py_CLEAR(GETSTATE(m)->error);
return 0;
}
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"recoll",
NULL,
sizeof(struct module_state),
recoll_methods,
NULL,
recoll_traverse,
recoll_clear,
NULL
};
#define INITERROR return NULL
extern "C" PyObject *
PyInit_recoll(void)
#else
#define INITERROR return
PyMODINIT_FUNC PyMODINIT_FUNC
initrecoll(void) initrecoll(void)
#endif
{ {
// Note: we can't call recollinit here, because the confdir is only really // Note: we can't call recollinit here, because the confdir is only really
// known when the first db object is created (it is an optional parameter). // known when the first db object is created (it is an optional parameter).
// Using a default here may end up with variables such as stripchars being // Using a default here may end up with variables such as stripchars being
// wrong // wrong
PyObject* m; #if PY_MAJOR_VERSION >= 3
m = Py_InitModule3("recoll", recollMethods, "Recoll extension module."); PyObject *module = PyModule_Create(&moduledef);
#else
PyObject *module = Py_InitModule("recoll", recoll_methods);
#endif
if (module == NULL)
INITERROR;
struct module_state *st = GETSTATE(module);
// The first parameter is a char *. Hopefully we don't initialize
// modules too often...
st->error = PyErr_NewException(strdup("recoll.Error"), NULL, NULL);
if (st->error == NULL) {
Py_DECREF(module);
INITERROR;
}
if (PyType_Ready(&recoll_DbType) < 0) if (PyType_Ready(&recoll_DbType) < 0)
return; INITERROR;
Py_INCREF((PyObject*)&recoll_DbType); Py_INCREF((PyObject*)&recoll_DbType);
PyModule_AddObject(m, "Db", (PyObject *)&recoll_DbType); PyModule_AddObject(module, "Db", (PyObject *)&recoll_DbType);
if (PyType_Ready(&recoll_QueryType) < 0) if (PyType_Ready(&recoll_QueryType) < 0)
return; INITERROR;
Py_INCREF((PyObject*)&recoll_QueryType); Py_INCREF((PyObject*)&recoll_QueryType);
PyModule_AddObject(m, "Query", (PyObject *)&recoll_QueryType); PyModule_AddObject(module, "Query", (PyObject *)&recoll_QueryType);
if (PyType_Ready(&recoll_DocType) < 0) if (PyType_Ready(&recoll_DocType) < 0)
return; INITERROR;
Py_INCREF((PyObject*)&recoll_DocType); Py_INCREF((PyObject*)&recoll_DocType);
PyModule_AddObject(m, "Doc", (PyObject *)&recoll_DocType); PyModule_AddObject(module, "Doc", (PyObject *)&recoll_DocType);
if (PyType_Ready(&recoll_SearchDataType) < 0) if (PyType_Ready(&recoll_SearchDataType) < 0)
return; INITERROR;
Py_INCREF((PyObject*)&recoll_SearchDataType); Py_INCREF((PyObject*)&recoll_SearchDataType);
PyModule_AddObject(m, "SearchData", (PyObject *)&recoll_SearchDataType); PyModule_AddObject(module, "SearchData",
PyModule_AddStringConstant(m, "__doc__", (PyObject *)&recoll_SearchDataType);
PyModule_AddStringConstant(module, "__doc__",
pyrecoll_doc_string); pyrecoll_doc_string);
PyObject *doctypecobject; PyObject *doctypecobject;
#if PY_MAJOR_VERSION >= 2 && PY_MINOR_VERSION >= 7 #if PY_MAJOR_VERSION >= 3 || (PY_MAJOR_VERSION >= 2 && PY_MINOR_VERSION >= 7)
// Export a few pointers for the benefit of other recoll python modules // Export a few pointers for the benefit of other recoll python modules
doctypecobject= doctypecobject=
PyCapsule_New(&recoll_DocType, PYRECOLL_PACKAGE "recoll.doctypeptr", 0); PyCapsule_New(&recoll_DocType, PYRECOLL_PACKAGE "recoll.doctypeptr", 0);
#else #else
doctypecobject = PyCObject_FromVoidPtr(&recoll_DocType, NULL); doctypecobject = PyCObject_FromVoidPtr(&recoll_DocType, NULL);
#endif #endif
PyModule_AddObject(m, "doctypeptr", doctypecobject);
PyModule_AddObject(module, "doctypeptr", doctypecobject);
#if PY_MAJOR_VERSION >= 3
return module;
#endif
} }

View File

@ -53,20 +53,20 @@ class ConfSimple:
value = value.strip() value = value.strip()
#print "Name:", nm, "Value:", value #print "Name:", nm, "Value:", value
if not self.submaps.has_key(submapkey): if not submapkey in self.submaps:
self.submaps[submapkey] = {} self.submaps[submapkey] = {}
self.submaps[submapkey][nm] = value self.submaps[submapkey][nm] = value
def get(self, nm, sk = ''): def get(self, nm, sk = ''):
'''Returns None if not found, empty string if found empty''' '''Returns None if not found, empty string if found empty'''
if not self.submaps.has_key(sk): if not sk in self.submaps:
return None return None
if not self.submaps[sk].has_key(nm): if not nm in self.submaps[sk]:
return None return None
return self.submaps[sk][nm] return self.submaps[sk][nm]
def getNames(self, sk = ''): def getNames(self, sk = ''):
if not self.submaps.has_key(sk): if not sk in self.submaps:
return None return None
return self.submaps[sk].keys() return self.submaps[sk].keys()
@ -141,7 +141,7 @@ class RclConfig:
# Find configuration directory # Find configuration directory
if argcnf is not None: if argcnf is not None:
self.confdir = os.path.abspath(argcnf) self.confdir = os.path.abspath(argcnf)
elif os.environ.has_key("RECOLL_CONFDIR"): elif "RECOLL_CONFDIR" in os.environ:
self.confdir = os.environ["RECOLL_CONFDIR"] self.confdir = os.environ["RECOLL_CONFDIR"]
else: else:
self.confdir = os.path.expanduser("~/.recoll") self.confdir = os.path.expanduser("~/.recoll")
@ -150,7 +150,7 @@ class RclConfig:
# "configure" in the C code. We can only do our best. Have to # "configure" in the C code. We can only do our best. Have to
# choose a preference order. Use RECOLL_DATADIR if the order is wrong # choose a preference order. Use RECOLL_DATADIR if the order is wrong
self.datadir = None self.datadir = None
if os.environ.has_key("RECOLL_DATADIR"): if "RECOLL_DATADIR" in os.environ:
self.datadir = os.environ["RECOLL_DATADIR"] self.datadir = os.environ["RECOLL_DATADIR"]
else: else:
dirs = ("/opt/local", "/usr", "/usr/local") dirs = ("/opt/local", "/usr", "/usr/local")
@ -164,11 +164,11 @@ class RclConfig:
self.cdirs = [] self.cdirs = []
# Additional config directory, values override user ones # Additional config directory, values override user ones
if os.environ.has_key("RECOLL_CONFTOP"): if "RECOLL_CONFTOP" in os.environ:
self.cdirs.append(os.environ["RECOLL_CONFTOP"]) self.cdirs.append(os.environ["RECOLL_CONFTOP"])
self.cdirs.append(self.confdir) self.cdirs.append(self.confdir)
# Additional config directory, overrides system's, overridden by user's # Additional config directory, overrides system's, overridden by user's
if os.environ.has_key("RECOLL_CONFMID"): if "RECOLL_CONFMID" in os.environ:
self.cdirs.append(os.environ["RECOLL_CONFMID"]) self.cdirs.append(os.environ["RECOLL_CONFMID"])
self.cdirs.append(os.path.join(self.datadir, "examples")) self.cdirs.append(os.path.join(self.datadir, "examples"))
@ -195,4 +195,4 @@ class RclExtraDbs:
if __name__ == '__main__': if __name__ == '__main__':
config = RclConfig() config = RclConfig()
print config.getConfParam("topdirs") print(config.getConfParam("topdirs"))

View File

@ -8,7 +8,7 @@ top = os.path.join('..', '..')
library_dirs = [os.path.join(top, 'lib')] library_dirs = [os.path.join(top, 'lib')]
libraries = ['recoll'] libraries = ['recoll']
if os.environ.has_key('libdir') and os.environ['libdir'] != "": if 'libdir' in os.environ and os.environ['libdir'] != "":
runtime_library_dirs = [os.path.join(os.environ['libdir'], 'recoll')] runtime_library_dirs = [os.path.join(os.environ['libdir'], 'recoll')]
else: else:
runtime_library_dirs = [os.path.join('@prefix@', 'lib', 'recoll')] runtime_library_dirs = [os.path.join('@prefix@', 'lib', 'recoll')]
@ -18,7 +18,7 @@ localdefs = os.path.join(top, 'mk', 'localdefs')
try: try:
lines = open(localdefs, 'r').readlines() lines = open(localdefs, 'r').readlines()
except: except:
print 'You need to build recoll first. Use configure --enable-pic' print('You need to build recoll first. Use configure --enable-pic')
sys.exit(1) sys.exit(1)
picok = False picok = False
for line in lines: for line in lines:
@ -26,7 +26,7 @@ for line in lines:
picok = True picok = True
break break
if not picok: if not picok:
print 'You need to rebuild recoll with PIC enabled. Use configure --enable-pic and make clean' print('You need to rebuild recoll with PIC enabled. Use configure --enable-pic and make clean')
sys.exit(1) sys.exit(1)

View File

@ -9,6 +9,11 @@ import sys
import locale import locale
from getopt import getopt from getopt import getopt
if sys.version_info[0] >= 3:
ISP3 = True
else:
ISP3 = False
try: try:
from recoll import recoll from recoll import recoll
from recoll import rclextract from recoll import rclextract
@ -21,7 +26,7 @@ allmeta = ("title", "keywords", "abstract", "url", "mimetype", "mtime",
"ipath", "fbytes", "dbytes", "relevancyrating") "ipath", "fbytes", "dbytes", "relevancyrating")
def Usage(): def Usage():
print >> sys.stderr, "Usage: recollq.py [-c conf] [-i extra_index] <recoll query>" print("Usage: recollq.py [-c conf] [-i extra_index] <recoll query>")
sys.exit(1); sys.exit(1);
class ptrmeths: class ptrmeths:
@ -44,6 +49,12 @@ def extractofile(doc, outfilename=""):
ofilename=outfilename) ofilename=outfilename)
return outfilename return outfilename
def utf8string(s):
if ISP3:
return s
else:
return s.encode('utf8')
def doquery(db, q): def doquery(db, q):
# Get query object # Get query object
query = db.query() query = db.query()
@ -51,14 +62,13 @@ def doquery(db, q):
# Parse/run input query string # Parse/run input query string
nres = query.execute(q, stemming = 0, stemlang="english") nres = query.execute(q, stemming = 0, stemlang="english")
qs = u"Xapian query: [%s]" % query.getxquery() qs = "Xapian query: [%s]" % query.getxquery()
print(qs.encode("utf-8")) print(utf8string(qs))
groups = query.getgroups() groups = query.getgroups()
print "Groups:", groups
m = ptrmeths(groups) m = ptrmeths(groups)
# Print results: # Print results:
print "Result count: ", nres, query.rowcount print("Result count: %d %d" % (nres, query.rowcount))
if nres > 20: if nres > 20:
nres = 20 nres = 20
#results = query.fetchmany(nres) #results = query.fetchmany(nres)
@ -68,24 +78,24 @@ def doquery(db, q):
doc = query.fetchone() doc = query.fetchone()
rownum = query.next if type(query.next) == int else \ rownum = query.next if type(query.next) == int else \
query.rownumber query.rownumber
print rownum, ":", print("%d:"%(rownum,))
#for k,v in doc.items().items(): #for k,v in doc.items().items():
#print "KEY:", k.encode('utf-8'), "VALUE", v.encode('utf-8') #print "KEY:", utf8string(k), "VALUE", utf8string(v)
#continue #continue
#outfile = extractofile(doc) #outfile = extractofile(doc)
#print "outfile:", outfile, "url", doc.url.encode("utf-8") #print "outfile:", outfile, "url", utf8string(doc.url)
for k in ("title", "mtime", "author"): for k in ("title", "mtime", "author"):
value = getattr(doc, k) value = getattr(doc, k)
# value = doc.get(k) # value = doc.get(k)
if value is None: if value is None:
print k, ":", "(None)" print("%s: (None)"%(k,))
else: else:
print k, ":", value.encode('utf-8') print("%s : %s"%(k, utf8string(value)))
#doc.setbinurl(bytearray("toto")) #doc.setbinurl(bytearray("toto"))
#burl = doc.getbinurl(); print "Bin URL :", doc.getbinurl() #burl = doc.getbinurl(); print("Bin URL : [%s]"%(doc.getbinurl(),))
abs = query.makedocabstract(doc, methods=m) abs = query.makedocabstract(doc, methods=m)
print abs.encode('utf-8') print(utf8string(abs))
print print('')
# fulldoc = extract(doc) # fulldoc = extract(doc)
# print "FULLDOC MIMETYPE", fulldoc.mimetype, "TEXT:", fulldoc.text.encode("utf-8") # print "FULLDOC MIMETYPE", fulldoc.mimetype, "TEXT:", fulldoc.text.encode("utf-8")
@ -109,20 +119,19 @@ for opt,val in options:
elif opt == "-i": elif opt == "-i":
extra_dbs.append(val) extra_dbs.append(val)
else: else:
print >> sys.stderr, "Bad opt: ", opt print("Bad opt: %s"%(opt,))
Usage() Usage()
# The query should be in the remaining arg(s) # The query should be in the remaining arg(s)
if len(args) == 0: if len(args) == 0:
print >> sys.stderr, "No query found in command line" print("No query found in command line")
Usage() Usage()
q = u'' q = ''
for word in args: for word in args:
q += word.decode(localecharset) + u' ' q += word + ' '
print "QUERY: [", q, "]" print("QUERY: [%s]"%(q,))
db = recoll.connect(confdir=confdir, db = recoll.connect(confdir=confdir, extra_dbs=extra_dbs)
extra_dbs=extra_dbs)
db.setAbstractParams(maxchars=maxchars, contextwords=contextwords) db.setAbstractParams(maxchars=maxchars, contextwords=contextwords)
doquery(db, q) doquery(db, q)