From 913f3530d9fa594ef0e4ad2a055d10a5890e7a41 Mon Sep 17 00:00:00 2001 From: Edmond Date: Thu, 4 Aug 2022 03:48:16 +0000 Subject: [PATCH] Unify the use of Store.internal_load for Store.load, Store.load_file and Store.load_data. Add some more additional tests --- python/src/store.rs | 105 +++++++++++-------------------------- python/tests/test_store.py | 36 ++++++++++--- 2 files changed, 62 insertions(+), 79 deletions(-) diff --git a/python/src/store.rs b/python/src/store.rs index 9cc5bdae..888f3bfa 100644 --- a/python/src/store.rs +++ b/python/src/store.rs @@ -1,5 +1,7 @@ #![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::model::*; use crate::sparql::*; @@ -7,7 +9,7 @@ use oxigraph::io::{DatasetFormat, GraphFormat}; use oxigraph::model::{GraphName, GraphNameRef}; use oxigraph::sparql::Update; 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::{prelude::*, PyTypeInfo}; use pyo3::{Py, PyRef}; @@ -344,38 +346,12 @@ impl PyStore { to_graph: Option<&PyAny>, py: Python<'_>, ) -> PyResult<()> { - let to_graph_name = if let Some(graph_name) = to_graph { - Some(GraphName::from(&PyGraphNameRef::try_from(graph_name)?)) - } else { - None - }; - 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 - ))) - } - }) + let mut input = PyFileLike::open(input, py).map_err(map_io_err)?; + let mut buf = String::new(); + match input.read_to_string(&mut buf) { + Ok(_) => self.internal_load(buf.as_bytes(), mime_type, base_iri, to_graph, py), + Err(err) => Err(PyNotImplementedError::new_err(err.to_string())), + } } /// Loads an RDF serialization into the store from a file. @@ -423,38 +399,12 @@ impl PyStore { to_graph: Option<&PyAny>, py: Python<'_>, ) -> PyResult<()> { - let to_graph_name = if let Some(graph_name) = to_graph { - Some(GraphName::from(&PyGraphNameRef::try_from(graph_name)?)) - } else { - None - }; - 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 - ))) - } - }) + let mut input = PyFileLike::open(input, py).map_err(map_io_err)?; + let mut buf = String::new(); + match input.read_to_string(&mut buf) { + Ok(_) => self.internal_load(buf.as_bytes(), mime_type, base_iri, to_graph, py), + Err(err) => Err(PyNotImplementedError::new_err(err.to_string())), + } } /// 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>, py: Python<'_>, ) -> 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; + self.internal_load(value.as_bytes(), mime_type, base_iri, to_graph, py) + } + + // fn internal_load_data( + 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(|| { if let Some(graph_format) = GraphFormat::from_media_type(mime_type) { self.inner .load_graph( - value.as_ref(), + input, graph_format, - to_graph_name.as_ref().unwrap_or(&GraphName::DefaultGraph), + &to_graph_name.unwrap_or(GraphName::DefaultGraph), base_iri, ) .map_err(map_loader_error) @@ -526,7 +485,7 @@ impl PyStore { )); } self.inner - .load_dataset(value.as_ref(), dataset_format, base_iri) + .load_dataset(input, dataset_format, base_iri) .map_err(map_loader_error) } else { Err(PyValueError::new_err(format!( diff --git a/python/tests/test_store.py b/python/tests/test_store.py index d30f4bcc..21aa4a61 100644 --- a/python/tests/test_store.py +++ b/python/tests/test_store.py @@ -189,6 +189,14 @@ class TestStore(unittest.TestCase): ) 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" ."), + mime_type="application/n-triples", + ) + self.assertEqual(set(store), {Quad(foo, bar, baz, DefaultGraph())}) + def test_load_ntriples_to_named_graph(self): store = Store() store.load( @@ -198,26 +206,35 @@ class TestStore(unittest.TestCase): ) 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.load( + store.load_file( + BytesIO(b" ."), + 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" <> ."), mime_type="text/turtle", base_iri="http://baz", ) self.assertEqual(set(store), {Quad(foo, bar, baz, DefaultGraph())}) - def test_load_nquads(self): + def test_load_file_nquads(self): store = Store() - store.load( + store.load_file( BytesIO(b" ."), mime_type="application/n-quads", ) 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.load( + store.load_file( BytesIO(b" { <> . }"), mime_type="application/trig", base_iri="http://baz", @@ -289,6 +306,13 @@ class TestStore(unittest.TestCase): with self.assertRaises(NotImplementedError) as _: 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): store = Store() store.add(Quad(foo, bar, baz, graph))