Unify the use of Store.internal_load for Store.load, Store.load_file and Store.load_data. Add some more additional tests

pull/227/head
Edmond 3 years ago
parent 9d2206f7fc
commit 913f3530d9
  1. 105
      python/src/store.rs
  2. 36
      python/tests/test_store.py

@ -1,5 +1,7 @@
#![allow(clippy::needless_option_as_deref)] #![allow(clippy::needless_option_as_deref)]
use std::io::Read;
use crate::io::{allow_threads_unsafe, map_io_err, map_parse_error, PyFileLike}; use crate::io::{allow_threads_unsafe, map_io_err, map_parse_error, PyFileLike};
use crate::model::*; use crate::model::*;
use crate::sparql::*; use crate::sparql::*;
@ -7,7 +9,7 @@ use oxigraph::io::{DatasetFormat, GraphFormat};
use oxigraph::model::{GraphName, GraphNameRef}; use oxigraph::model::{GraphName, GraphNameRef};
use oxigraph::sparql::Update; use oxigraph::sparql::Update;
use oxigraph::store::{self, LoaderError, SerializerError, StorageError, Store}; use oxigraph::store::{self, LoaderError, SerializerError, StorageError, Store};
use pyo3::exceptions::{self, PyIOError, PyRuntimeError, PyValueError}; use pyo3::exceptions::{self, PyIOError, PyNotImplementedError, PyRuntimeError, PyValueError};
use pyo3::types::{IntoPyDict, PyBytes, PyString, PyType}; use pyo3::types::{IntoPyDict, PyBytes, PyString, PyType};
use pyo3::{prelude::*, PyTypeInfo}; use pyo3::{prelude::*, PyTypeInfo};
use pyo3::{Py, PyRef}; use pyo3::{Py, PyRef};
@ -344,38 +346,12 @@ impl PyStore {
to_graph: Option<&PyAny>, to_graph: Option<&PyAny>,
py: Python<'_>, py: Python<'_>,
) -> PyResult<()> { ) -> PyResult<()> {
let to_graph_name = if let Some(graph_name) = to_graph { let mut input = PyFileLike::open(input, py).map_err(map_io_err)?;
Some(GraphName::from(&PyGraphNameRef::try_from(graph_name)?)) let mut buf = String::new();
} else { match input.read_to_string(&mut buf) {
None Ok(_) => self.internal_load(buf.as_bytes(), mime_type, base_iri, to_graph, py),
}; Err(err) => Err(PyNotImplementedError::new_err(err.to_string())),
let input = PyFileLike::open(input, py).map_err(map_io_err)?; }
py.allow_threads(|| {
if let Some(graph_format) = GraphFormat::from_media_type(mime_type) {
self.inner
.load_graph(
input,
graph_format,
to_graph_name.as_ref().unwrap_or(&GraphName::DefaultGraph),
base_iri,
)
.map_err(map_loader_error)
} else if let Some(dataset_format) = DatasetFormat::from_media_type(mime_type) {
if to_graph_name.is_some() {
return Err(PyValueError::new_err(
"The target graph name parameter is not available for dataset formats",
));
}
self.inner
.load_dataset(input, dataset_format, base_iri)
.map_err(map_loader_error)
} else {
Err(PyValueError::new_err(format!(
"Not supported MIME type: {}",
mime_type
)))
}
})
} }
/// Loads an RDF serialization into the store from a file. /// Loads an RDF serialization into the store from a file.
@ -423,38 +399,12 @@ impl PyStore {
to_graph: Option<&PyAny>, to_graph: Option<&PyAny>,
py: Python<'_>, py: Python<'_>,
) -> PyResult<()> { ) -> PyResult<()> {
let to_graph_name = if let Some(graph_name) = to_graph { let mut input = PyFileLike::open(input, py).map_err(map_io_err)?;
Some(GraphName::from(&PyGraphNameRef::try_from(graph_name)?)) let mut buf = String::new();
} else { match input.read_to_string(&mut buf) {
None Ok(_) => self.internal_load(buf.as_bytes(), mime_type, base_iri, to_graph, py),
}; Err(err) => Err(PyNotImplementedError::new_err(err.to_string())),
let input = PyFileLike::open(input, py).map_err(map_io_err)?; }
py.allow_threads(|| {
if let Some(graph_format) = GraphFormat::from_media_type(mime_type) {
self.inner
.load_graph(
input,
graph_format,
to_graph_name.as_ref().unwrap_or(&GraphName::DefaultGraph),
base_iri,
)
.map_err(map_loader_error)
} else if let Some(dataset_format) = DatasetFormat::from_media_type(mime_type) {
if to_graph_name.is_some() {
return Err(PyValueError::new_err(
"The target graph name parameter is not available for dataset formats",
));
}
self.inner
.load_dataset(input, dataset_format, base_iri)
.map_err(map_loader_error)
} else {
Err(PyValueError::new_err(format!(
"Not supported MIME type: {}",
mime_type
)))
}
})
} }
/// Loads an RDF serialization into the store from a buffer or a python I/O object. /// Loads an RDF serialization into the store from a buffer or a python I/O object.
@ -502,20 +452,29 @@ impl PyStore {
to_graph: Option<&PyAny>, to_graph: Option<&PyAny>,
py: Python<'_>, py: Python<'_>,
) -> PyResult<()> { ) -> PyResult<()> {
let to_graph_name = if let Some(graph_name) = to_graph {
Some(GraphName::from(&PyGraphNameRef::try_from(graph_name)?))
} else {
None
};
let InputValue(value) = input; let InputValue(value) = input;
self.internal_load(value.as_bytes(), mime_type, base_iri, to_graph, py)
}
// fn internal_load_data<File: BufRead + std::marker::Send>(
fn internal_load(
&self,
input: &[u8],
mime_type: &str,
base_iri: Option<&str>,
to_graph: Option<&PyAny>,
py: Python<'_>,
) -> PyResult<()> {
let to_graph_name = to_graph
.map(|graph_name| GraphName::from(&PyGraphNameRef::try_from(graph_name).unwrap()));
py.allow_threads(|| { py.allow_threads(|| {
if let Some(graph_format) = GraphFormat::from_media_type(mime_type) { if let Some(graph_format) = GraphFormat::from_media_type(mime_type) {
self.inner self.inner
.load_graph( .load_graph(
value.as_ref(), input,
graph_format, graph_format,
to_graph_name.as_ref().unwrap_or(&GraphName::DefaultGraph), &to_graph_name.unwrap_or(GraphName::DefaultGraph),
base_iri, base_iri,
) )
.map_err(map_loader_error) .map_err(map_loader_error)
@ -526,7 +485,7 @@ impl PyStore {
)); ));
} }
self.inner self.inner
.load_dataset(value.as_ref(), dataset_format, base_iri) .load_dataset(input, dataset_format, base_iri)
.map_err(map_loader_error) .map_err(map_loader_error)
} else { } else {
Err(PyValueError::new_err(format!( Err(PyValueError::new_err(format!(

@ -189,6 +189,14 @@ class TestStore(unittest.TestCase):
) )
self.assertEqual(set(store), {Quad(foo, bar, baz, DefaultGraph())}) self.assertEqual(set(store), {Quad(foo, bar, baz, DefaultGraph())})
def test_load_file_ntriples_to_default_graph(self):
store = Store()
store.load_file(
BytesIO(b"<http://foo> <http://bar> <http://baz> ."),
mime_type="application/n-triples",
)
self.assertEqual(set(store), {Quad(foo, bar, baz, DefaultGraph())})
def test_load_ntriples_to_named_graph(self): def test_load_ntriples_to_named_graph(self):
store = Store() store = Store()
store.load( store.load(
@ -198,26 +206,35 @@ class TestStore(unittest.TestCase):
) )
self.assertEqual(set(store), {Quad(foo, bar, baz, graph)}) self.assertEqual(set(store), {Quad(foo, bar, baz, graph)})
def test_load_turtle_with_base_iri(self): def test_load_file_ntriples_to_named_graph(self):
store = Store() store = Store()
store.load( store.load_file(
BytesIO(b"<http://foo> <http://bar> <http://baz> ."),
mime_type="application/n-triples",
to_graph=graph,
)
self.assertEqual(set(store), {Quad(foo, bar, baz, graph)})
def test_load_file_turtle_with_base_iri(self):
store = Store()
store.load_file(
BytesIO(b"<http://foo> <http://bar> <> ."), BytesIO(b"<http://foo> <http://bar> <> ."),
mime_type="text/turtle", mime_type="text/turtle",
base_iri="http://baz", base_iri="http://baz",
) )
self.assertEqual(set(store), {Quad(foo, bar, baz, DefaultGraph())}) self.assertEqual(set(store), {Quad(foo, bar, baz, DefaultGraph())})
def test_load_nquads(self): def test_load_file_nquads(self):
store = Store() store = Store()
store.load( store.load_file(
BytesIO(b"<http://foo> <http://bar> <http://baz> <http://graph>."), BytesIO(b"<http://foo> <http://bar> <http://baz> <http://graph>."),
mime_type="application/n-quads", mime_type="application/n-quads",
) )
self.assertEqual(set(store), {Quad(foo, bar, baz, graph)}) self.assertEqual(set(store), {Quad(foo, bar, baz, graph)})
def test_load_trig_with_base_iri(self): def test_load_file_trig_with_base_iri(self):
store = Store() store = Store()
store.load( store.load_file(
BytesIO(b"<http://graph> { <http://foo> <http://bar> <> . }"), BytesIO(b"<http://graph> { <http://foo> <http://bar> <> . }"),
mime_type="application/trig", mime_type="application/trig",
base_iri="http://baz", base_iri="http://baz",
@ -289,6 +306,13 @@ class TestStore(unittest.TestCase):
with self.assertRaises(NotImplementedError) as _: with self.assertRaises(NotImplementedError) as _:
Store().load(BadIO(), mime_type="application/n-triples") Store().load(BadIO(), mime_type="application/n-triples")
def test_load_file_with_io_error(self):
class BadIO(RawIOBase):
pass
with self.assertRaises(NotImplementedError) as _:
Store().load_file(BadIO(), mime_type="application/n-triples")
def test_dump_ntriples(self): def test_dump_ntriples(self):
store = Store() store = Store()
store.add(Quad(foo, bar, baz, graph)) store.add(Quad(foo, bar, baz, graph))

Loading…
Cancel
Save