|
@@ -19,7 +19,7 @@
|
|
typedef struct {
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
PyObject_HEAD
|
|
LSUP_CodecIterator *it;
|
|
LSUP_CodecIterator *it;
|
|
- char *line;
|
|
|
|
|
|
+ unsigned char *line;
|
|
} StringIteratorObject;
|
|
} StringIteratorObject;
|
|
|
|
|
|
|
|
|
|
@@ -31,8 +31,8 @@ StringIterator_dealloc (StringIteratorObject *it_obj)
|
|
static PyObject *
|
|
static PyObject *
|
|
StringIterator_next (StringIteratorObject *it_obj)
|
|
StringIterator_next (StringIteratorObject *it_obj)
|
|
{
|
|
{
|
|
- unsigned char *rdf_str;
|
|
|
|
- LSUP_rc rc = it_obj->it->codec->encode_graph_iter (it_obj->it, &rdf_str);
|
|
|
|
|
|
+ LSUP_rc rc = it_obj->it->codec->encode_graph_iter (
|
|
|
|
+ it_obj->it, &it_obj->line);
|
|
if (rc != LSUP_OK) {
|
|
if (rc != LSUP_OK) {
|
|
if (rc != LSUP_END)
|
|
if (rc != LSUP_END)
|
|
PyErr_SetString (PyExc_ValueError, "Error encoding graph.");
|
|
PyErr_SetString (PyExc_ValueError, "Error encoding graph.");
|
|
@@ -41,7 +41,7 @@ StringIterator_next (StringIteratorObject *it_obj)
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
- PyObject *rdf_obj = PyUnicode_FromString ((char*)rdf_str);
|
|
|
|
|
|
+ PyObject *rdf_obj = PyUnicode_FromString ((char*)it_obj->line);
|
|
if (UNLIKELY (!rdf_obj)) return NULL;
|
|
if (UNLIKELY (!rdf_obj)) return NULL;
|
|
|
|
|
|
Py_INCREF (rdf_obj);
|
|
Py_INCREF (rdf_obj);
|
|
@@ -152,38 +152,60 @@ Graph_copy (PyTypeObject *cls, PyObject *src)
|
|
static PyObject *
|
|
static PyObject *
|
|
Graph_new_from_rdf (PyTypeObject *cls, PyObject *args)
|
|
Graph_new_from_rdf (PyTypeObject *cls, PyObject *args)
|
|
{
|
|
{
|
|
-
|
|
|
|
- Py_buffer *buf;
|
|
|
|
|
|
+ PyObject *buf, *fileno_fn, *fileno_obj;
|
|
const char *type;
|
|
const char *type;
|
|
- if (! PyArg_ParseTuple (args, "s*s", &buf, &type)) return NULL;
|
|
|
|
|
|
+ if (! PyArg_ParseTuple (args, "Os", &buf, &type)) return NULL;
|
|
|
|
+
|
|
|
|
+ // Get the file descriptor from the Python BufferedIO object.
|
|
|
|
+ // FIXME This is not sure to be reliable. See
|
|
|
|
+ // https://docs.python.org/3/library/io.html?highlight=io%20bufferedreader#io.IOBase.fileno
|
|
|
|
+ if (! (fileno_fn = PyObject_GetAttrString (buf, "fileno"))) {
|
|
|
|
+ PyErr_SetString (PyExc_TypeError, "Object has no fileno function.");
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+ PyObject* fileno_args = PyTuple_New(0);
|
|
|
|
+ if (! (fileno_obj = PyObject_CallObject (fileno_fn, fileno_args))) {
|
|
|
|
+ PyErr_SetString (PyExc_SystemError, "Error calling fileno function.");
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+ int fd = PyLong_AsSize_t (fileno_obj);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * From the Linux man page:
|
|
|
|
+ *
|
|
|
|
+ * > The file descriptor is not dup'ed, and will be closed when the stream
|
|
|
|
+ * > created by fdopen() is closed. The result of applying fdopen() to a
|
|
|
|
+ * > shared memory object is undefined.
|
|
|
|
+ *
|
|
|
|
+ * This handle must not be closed. Leave open for the Python caller to
|
|
|
|
+ * handle it.
|
|
|
|
+ */
|
|
|
|
+ FILE *fh = fdopen (fd, "r");
|
|
|
|
|
|
GraphObject *res = (GraphObject *) cls->tp_alloc(cls, 0);
|
|
GraphObject *res = (GraphObject *) cls->tp_alloc(cls, 0);
|
|
- if (!res) goto fail;
|
|
|
|
|
|
+ if (!res) return PyErr_NoMemory();
|
|
|
|
|
|
const LSUP_Codec *codec;
|
|
const LSUP_Codec *codec;
|
|
if (strcmp(type, "nt") == 0) codec = &nt_codec;
|
|
if (strcmp(type, "nt") == 0) codec = &nt_codec;
|
|
// TODO other codecs here.
|
|
// TODO other codecs here.
|
|
else {
|
|
else {
|
|
PyErr_SetString (PyExc_ValueError, "Unsupported codec.");
|
|
PyErr_SetString (PyExc_ValueError, "Unsupported codec.");
|
|
- goto fail;
|
|
|
|
|
|
+ return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
size_t ct;
|
|
size_t ct;
|
|
char *err;
|
|
char *err;
|
|
- codec->decode_graph (buf->buf, &res->ob_struct, &ct, &err);
|
|
|
|
|
|
+ codec->decode_graph (fh, &res->ob_struct, &ct, &err);
|
|
|
|
|
|
TRACE ("Decoded %lu triples.\n", ct);
|
|
TRACE ("Decoded %lu triples.\n", ct);
|
|
- if (!UNLIKELY (err)) goto fail;
|
|
|
|
|
|
+ if (UNLIKELY (err)) {
|
|
|
|
+ PyErr_SetString (PyExc_IOError, err);
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
|
|
- PyBuffer_Release (buf);
|
|
|
|
Py_INCREF(res);
|
|
Py_INCREF(res);
|
|
|
|
|
|
return (PyObject *) res;
|
|
return (PyObject *) res;
|
|
-
|
|
|
|
-fail:
|
|
|
|
- PyBuffer_Release (buf);
|
|
|
|
-
|
|
|
|
- return NULL;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -306,12 +328,12 @@ Graph_encode (PyObject *self, PyObject *args)
|
|
((GraphObject *)self)->ob_struct);
|
|
((GraphObject *)self)->ob_struct);
|
|
|
|
|
|
// Initialize the generator object.
|
|
// Initialize the generator object.
|
|
- //StringIteratorType *it_type;
|
|
|
|
StringIteratorObject *it_obj = PyObject_New (
|
|
StringIteratorObject *it_obj = PyObject_New (
|
|
StringIteratorObject, &StringIteratorType);
|
|
StringIteratorObject, &StringIteratorType);
|
|
if (!it_obj) return NULL;
|
|
if (!it_obj) return NULL;
|
|
|
|
|
|
it_obj->it = it;
|
|
it_obj->it = it;
|
|
|
|
+ it_obj->line = NULL;
|
|
|
|
|
|
Py_INCREF (it_obj);
|
|
Py_INCREF (it_obj);
|
|
return (PyObject *)it_obj;
|
|
return (PyObject *)it_obj;
|
|
@@ -319,10 +341,13 @@ Graph_encode (PyObject *self, PyObject *args)
|
|
|
|
|
|
|
|
|
|
static PyMethodDef Graph_methods[] = {
|
|
static PyMethodDef Graph_methods[] = {
|
|
- {"copy", (PyCFunction) Graph_copy, METH_CLASS, "Copy a graph."},
|
|
|
|
{
|
|
{
|
|
- "from_rdf", (PyCFunction) Graph_new_from_rdf, METH_CLASS,
|
|
|
|
- "Create a graph from a RDF file."
|
|
|
|
|
|
+ "copy", (PyCFunction) Graph_copy,
|
|
|
|
+ METH_CLASS | METH_VARARGS, "Copy a graph."
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "from_rdf", (PyCFunction) Graph_new_from_rdf,
|
|
|
|
+ METH_CLASS | METH_VARARGS, "Create a graph from a RDF file."
|
|
},
|
|
},
|
|
{"add", (PyCFunction) Graph_add, METH_O, "Add triples to a graph."},
|
|
{"add", (PyCFunction) Graph_add, METH_O, "Add triples to a graph."},
|
|
{
|
|
{
|