From 923beb6300aab1271b8fe6acb91affefbf8b4e00 Mon Sep 17 00:00:00 2001 From: Tpt Date: Wed, 29 Jul 2020 22:15:02 +0200 Subject: [PATCH] Use io::Error in load_graph and load_dataset errors It is possible to find the kind of error (parsing, loading...) using the std::io::ErrorKind enumeration --- lib/src/store/memory.rs | 20 ++++++-- lib/src/store/mod.rs | 96 +++++++++++++++++++++++++------------- lib/src/store/rocksdb.rs | 18 ++++++- lib/src/store/sled.rs | 22 +++++++-- python/src/memory_store.rs | 6 +-- python/src/sled_store.rs | 29 ++++-------- python/src/store_utils.rs | 16 +++++-- 7 files changed, 139 insertions(+), 68 deletions(-) diff --git a/lib/src/store/memory.rs b/lib/src/store/memory.rs index 0665950f..6f671253 100644 --- a/lib/src/store/memory.rs +++ b/lib/src/store/memory.rs @@ -266,13 +266,16 @@ impl MemoryStore { /// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), None)], results); /// # oxigraph::Result::Ok(()) /// ``` + /// + /// Errors related to parameter validation like the base IRI use the `INVALID_INPUT` error kind. + /// Errors related to a bad syntax in the loaded file use the `INVALID_DATA` error kind. pub fn load_graph( &self, reader: impl BufRead, syntax: GraphSyntax, to_graph_name: &GraphName, base_iri: Option<&str>, - ) -> crate::Result<()> { + ) -> Result<(), io::Error> { let mut store = self; load_graph(&mut store, reader, syntax, to_graph_name, base_iri) } @@ -296,12 +299,15 @@ impl MemoryStore { /// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), Some(ex.into()))], results); /// # oxigraph::Result::Ok(()) /// ``` + /// + /// Errors related to parameter validation like the base IRI use the `INVALID_INPUT` error kind. + /// Errors related to a bad syntax in the loaded file use the `INVALID_DATA` error kind. pub fn load_dataset( &self, reader: impl BufRead, syntax: DatasetSyntax, base_iri: Option<&str>, - ) -> crate::Result<()> { + ) -> Result<(), io::Error> { let mut store = self; load_dataset(&mut store, reader, syntax, base_iri) } @@ -348,6 +354,9 @@ impl MemoryStore { /// assert_eq!(file, buffer.as_slice()); /// # oxigraph::Result::Ok(()) /// ``` + /// + /// Errors related to parameter validation like the base IRI use the `INVALID_INPUT` error kind. + /// Errors related to a bad syntax in the loaded file use the `INVALID_DATA` error kind. pub fn dump_graph( &self, writer: &mut impl Write, @@ -378,6 +387,9 @@ impl MemoryStore { /// assert_eq!(file, buffer.as_slice()); /// # oxigraph::Result::Ok(()) /// ``` + /// + /// Errors related to parameter validation like the base IRI use the `INVALID_INPUT` error kind. + /// Errors related to a bad syntax in the loaded file use the `INVALID_DATA` error kind. pub fn dump_dataset( &self, writer: &mut impl Write, @@ -986,7 +998,7 @@ impl<'a> MemoryTransaction<'a> { syntax: GraphSyntax, to_graph_name: &GraphName, base_iri: Option<&str>, - ) -> crate::Result<()> { + ) -> Result<(), io::Error> { load_graph(self, reader, syntax, to_graph_name, base_iri) } @@ -1014,7 +1026,7 @@ impl<'a> MemoryTransaction<'a> { reader: impl BufRead, syntax: DatasetSyntax, base_iri: Option<&str>, - ) -> crate::Result<()> { + ) -> Result<(), io::Error> { load_dataset(self, reader, syntax, base_iri) } diff --git a/lib/src/store/mod.rs b/lib/src/store/mod.rs index 8eef6096..c1625217 100644 --- a/lib/src/store/mod.rs +++ b/lib/src/store/mod.rs @@ -23,7 +23,7 @@ use rio_api::formatter::{QuadsFormatter, TriplesFormatter}; use rio_api::parser::{QuadsParser, TriplesParser}; use rio_turtle::{ NQuadsFormatter, NQuadsParser, NTriplesFormatter, NTriplesParser, TriGFormatter, TriGParser, - TurtleFormatter, TurtleParser, + TurtleError, TurtleFormatter, TurtleParser, }; use rio_xml::{RdfXmlError, RdfXmlFormatter, RdfXmlParser}; use std::collections::HashMap; @@ -66,45 +66,45 @@ fn load_graph( syntax: GraphSyntax, to_graph_name: &GraphName, base_iri: Option<&str>, -) -> Result<(), crate::Error> -where - crate::Error: From<::Error> + From<::Error>, -{ +) -> Result<(), io::Error> { let base_iri = base_iri.unwrap_or(""); match syntax { GraphSyntax::NTriples => { - load_from_triple_parser(store, NTriplesParser::new(reader)?, to_graph_name) + load_from_triple_parser(store, NTriplesParser::new(reader), to_graph_name) } GraphSyntax::Turtle => { - load_from_triple_parser(store, TurtleParser::new(reader, base_iri)?, to_graph_name) + load_from_triple_parser(store, TurtleParser::new(reader, base_iri), to_graph_name) } GraphSyntax::RdfXml => { - load_from_triple_parser(store, RdfXmlParser::new(reader, base_iri)?, to_graph_name) + load_from_triple_parser(store, RdfXmlParser::new(reader, base_iri), to_graph_name) } } } fn load_from_triple_parser( store: &mut S, - mut parser: P, + parser: Result, to_graph_name: &GraphName, -) -> Result<(), crate::Error> +) -> Result<(), io::Error> where - crate::Error: From - + From<::Error> - + From<::Error>, + IoOrParseError: From, + P::Error: Send + Sync + 'static, { + let mut parser = parser.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; let mut bnode_map = HashMap::default(); let to_graph_name = store .encode_graph_name(to_graph_name) .map_err(|e| e.into())?; - parser.parse_all(&mut move |t| { + let result: Result<(), IoOrParseError<_>> = parser.parse_all(&mut move |t| { let quad = store .encode_rio_triple_in_graph(t, to_graph_name, &mut bnode_map) - .map_err(crate::Error::from)?; - store.insert_encoded(&quad).map_err(crate::Error::from)?; + .map_err(|e| IoOrParseError::Io(e.into()))?; + store + .insert_encoded(&quad) + .map_err(|e| IoOrParseError::Io(e.into()))?; Ok(()) - }) + }); + Ok(result?) } fn dump_graph( @@ -147,34 +147,34 @@ fn load_dataset( reader: impl BufRead, syntax: DatasetSyntax, base_iri: Option<&str>, -) -> Result<(), crate::Error> -where - crate::Error: From<::Error> + From<::Error>, -{ +) -> Result<(), io::Error> { let base_iri = base_iri.unwrap_or(""); match syntax { - DatasetSyntax::NQuads => load_from_quad_parser(store, NQuadsParser::new(reader)?), - DatasetSyntax::TriG => load_from_quad_parser(store, TriGParser::new(reader, base_iri)?), + DatasetSyntax::NQuads => load_from_quad_parser(store, NQuadsParser::new(reader)), + DatasetSyntax::TriG => load_from_quad_parser(store, TriGParser::new(reader, base_iri)), } } fn load_from_quad_parser( store: &mut S, - mut parser: P, -) -> Result<(), crate::Error> + parser: Result, +) -> Result<(), io::Error> where - crate::Error: From - + From<::Error> - + From<::Error>, + IoOrParseError: From, + P::Error: Send + Sync + 'static, { + let mut parser = parser.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; let mut bnode_map = HashMap::default(); - parser.parse_all(&mut move |q| { + let result: Result<(), IoOrParseError<_>> = parser.parse_all(&mut move |q| { let quad = store .encode_rio_quad(q, &mut bnode_map) - .map_err(crate::Error::from)?; - store.insert_encoded(&quad).map_err(crate::Error::from)?; + .map_err(|e| IoOrParseError::Io(e.into()))?; + store + .insert_encoded(&quad) + .map_err(|e| IoOrParseError::Io(e.into()))?; Ok(()) - }) + }); + Ok(result?) } fn dump_dataset( @@ -200,3 +200,35 @@ fn dump_dataset( } Ok(()) } + +enum IoOrParseError { + Io(io::Error), + Parse(E), +} + +impl From for IoOrParseError { + fn from(error: io::Error) -> Self { + Self::Io(error) + } +} + +impl From for IoOrParseError { + fn from(error: TurtleError) -> Self { + Self::Parse(error) + } +} + +impl From for IoOrParseError { + fn from(error: RdfXmlError) -> Self { + Self::Parse(error) + } +} + +impl From> for io::Error { + fn from(error: IoOrParseError) -> Self { + match error { + IoOrParseError::Io(error) => error, + IoOrParseError::Parse(error) => io::Error::new(io::ErrorKind::InvalidData, error), + } + } +} diff --git a/lib/src/store/rocksdb.rs b/lib/src/store/rocksdb.rs index 7952f86e..2b09541b 100644 --- a/lib/src/store/rocksdb.rs +++ b/lib/src/store/rocksdb.rs @@ -184,6 +184,10 @@ impl RocksDbStore { /// only a part of it may be written. Use a (memory greedy) transaction if you do not want that. /// /// See `MemoryStore` for a usage example. + /// + /// Errors related to parameter validation like the base IRI use the `INVALID_INPUT` error kind. + /// Errors related to a bad syntax in the loaded file use the `INVALID_DATA` error kind. + /// Errors related to data loading into the store use the other error kinds. pub fn load_graph( &self, reader: impl BufRead, @@ -202,6 +206,10 @@ impl RocksDbStore { /// only a part of it may be written. Use a (memory greedy) transaction if you do not want that. /// /// See `MemoryStore` for a usage example. + /// + /// Errors related to parameter validation like the base IRI use the `INVALID_INPUT` error kind. + /// Errors related to a bad syntax in the loaded file use the `INVALID_DATA` error kind. + /// Errors related to data loading into the store use the other error kinds. pub fn load_dataset( &self, reader: impl BufRead, @@ -567,13 +575,16 @@ impl RocksDbTransaction<'_> { /// Do not use for big files. /// /// See `MemoryTransaction` for a usage example. + /// + /// Errors related to parameter validation like the base IRI use the `INVALID_INPUT` error kind. + /// Errors related to a bad syntax in the loaded file use the `INVALID_DATA` error kind. pub fn load_graph( &mut self, reader: impl BufRead, syntax: GraphSyntax, to_graph_name: &GraphName, base_iri: Option<&str>, - ) -> Result<(), crate::Error> { + ) -> Result<(), io::Error> { load_graph(&mut self.inner, reader, syntax, to_graph_name, base_iri) } @@ -584,12 +595,15 @@ impl RocksDbTransaction<'_> { /// Do not use for big files. /// /// See `MemoryTransaction` for a usage example. + /// + /// Errors related to parameter validation like the base IRI use the `INVALID_INPUT` error kind. + /// Errors related to a bad syntax in the loaded file use the `INVALID_DATA` error kind. pub fn load_dataset( &mut self, reader: impl BufRead, syntax: DatasetSyntax, base_iri: Option<&str>, - ) -> Result<(), crate::Error> { + ) -> Result<(), io::Error> { load_dataset(&mut self.inner, reader, syntax, base_iri) } diff --git a/lib/src/store/sled.rs b/lib/src/store/sled.rs index dd45a3df..0ad80c0e 100644 --- a/lib/src/store/sled.rs +++ b/lib/src/store/sled.rs @@ -169,13 +169,17 @@ impl SledStore { /// only a part of it may be written. Use a (memory greedy) transaction if you do not want that. /// /// See `MemoryStore` for a usage example. + /// + /// Errors related to parameter validation like the base IRI use the `INVALID_INPUT` error kind. + /// Errors related to a bad syntax in the loaded file use the `INVALID_DATA` error kind. + /// Errors related to data loading into the store use the other error kinds. pub fn load_graph( &self, reader: impl BufRead, syntax: GraphSyntax, to_graph_name: &GraphName, base_iri: Option<&str>, - ) -> Result<(), crate::Error> { + ) -> Result<(), io::Error> { load_graph( &mut DirectWriter::new(self), reader, @@ -191,12 +195,16 @@ impl SledStore { /// only a part of it may be written. Use a (memory greedy) transaction if you do not want that. /// /// See `MemoryStore` for a usage example. + /// + /// Errors related to parameter validation like the base IRI use the `INVALID_INPUT` error kind. + /// Errors related to a bad syntax in the loaded file use the `INVALID_DATA` error kind. + /// Errors related to data loading into the store use the other error kinds. pub fn load_dataset( &self, reader: impl BufRead, syntax: DatasetSyntax, base_iri: Option<&str>, - ) -> Result<(), crate::Error> { + ) -> Result<(), io::Error> { load_dataset(&mut DirectWriter::new(self), reader, syntax, base_iri) } @@ -658,13 +666,16 @@ impl SledTransaction<'_> { /// Do not use for big files. /// /// See `MemoryTransaction` for a usage example. + /// + /// Errors related to parameter validation like the base IRI use the `INVALID_INPUT` error kind. + /// Errors related to a bad syntax in the loaded file use the `INVALID_DATA` error kind. pub fn load_graph( &mut self, reader: impl BufRead, syntax: GraphSyntax, to_graph_name: &GraphName, base_iri: Option<&str>, - ) -> Result<(), crate::Error> { + ) -> Result<(), io::Error> { load_graph(&mut self.inner, reader, syntax, to_graph_name, base_iri) } @@ -675,12 +686,15 @@ impl SledTransaction<'_> { /// Do not use for big files. /// /// See `MemoryTransaction` for a usage example. + /// + /// Errors related to parameter validation like the base IRI use the `INVALID_INPUT` error kind. + /// Errors related to a bad syntax in the loaded file use the `INVALID_DATA` error kind. pub fn load_dataset( &mut self, reader: impl BufRead, syntax: DatasetSyntax, base_iri: Option<&str>, - ) -> Result<(), crate::Error> { + ) -> Result<(), io::Error> { load_dataset(&mut self.inner, reader, syntax, base_iri) } diff --git a/python/src/memory_store.rs b/python/src/memory_store.rs index 9f097e50..cae216b1 100644 --- a/python/src/memory_store.rs +++ b/python/src/memory_store.rs @@ -58,7 +58,7 @@ impl PyMemoryStore { let results = self .inner .query(query, QueryOptions::default()) - .map_err(|e| ParseError::py_err(e.to_string()))?; + .map_err(|e| ValueError::py_err(e.to_string()))?; query_results_to_python(py, results) } @@ -89,7 +89,7 @@ impl PyMemoryStore { &to_graph_name.unwrap_or(GraphName::DefaultGraph), base_iri, ) - .map_err(|e| ParseError::py_err(e.to_string())) + .map_err(map_io_err) } else if let Some(dataset_syntax) = DatasetSyntax::from_media_type(mime_type) { if to_graph_name.is_some() { return Err(ValueError::py_err( @@ -98,7 +98,7 @@ impl PyMemoryStore { } self.inner .load_dataset(Cursor::new(data), dataset_syntax, base_iri) - .map_err(|e| ParseError::py_err(e.to_string())) + .map_err(map_io_err) } else { Err(ValueError::py_err(format!( "Not supported MIME type: {}", diff --git a/python/src/sled_store.rs b/python/src/sled_store.rs index b3b2c2ee..a4061b44 100644 --- a/python/src/sled_store.rs +++ b/python/src/sled_store.rs @@ -3,7 +3,7 @@ use crate::store_utils::*; use oxigraph::model::*; use oxigraph::sparql::QueryOptions; use oxigraph::{DatasetSyntax, GraphSyntax, SledStore}; -use pyo3::exceptions::{IOError, ValueError}; +use pyo3::exceptions::ValueError; use pyo3::prelude::*; use pyo3::types::PyTuple; use pyo3::{PyIterProtocol, PyObjectProtocol, PySequenceProtocol}; @@ -22,23 +22,19 @@ impl PySledStore { fn new(path: Option<&str>) -> PyResult { Ok(Self { inner: if let Some(path) = path { - SledStore::open(path).map_err(|e| IOError::py_err(e.to_string()))? + SledStore::open(path).map_err(map_io_err)? } else { - SledStore::new().map_err(|e| IOError::py_err(e.to_string()))? + SledStore::new().map_err(map_io_err)? }, }) } fn add(&self, quad: &PyTuple) -> PyResult<()> { - self.inner - .insert(&extract_quad(quad)?) - .map_err(|e| IOError::py_err(e.to_string())) + self.inner.insert(&extract_quad(quad)?).map_err(map_io_err) } fn remove(&self, quad: &PyTuple) -> PyResult<()> { - self.inner - .remove(&extract_quad(quad)?) - .map_err(|e| IOError::py_err(e.to_string())) + self.inner.remove(&extract_quad(quad)?).map_err(map_io_err) } fn r#match( @@ -64,7 +60,7 @@ impl PySledStore { let results = self .inner .query(query, QueryOptions::default()) - .map_err(|e| ParseError::py_err(e.to_string()))?; + .map_err(|e| ValueError::py_err(e.to_string()))?; query_results_to_python(py, results) } @@ -95,7 +91,7 @@ impl PySledStore { &to_graph_name.unwrap_or(GraphName::DefaultGraph), base_iri, ) - .map_err(|e| ParseError::py_err(e.to_string())) + .map_err(map_io_err) } else if let Some(dataset_syntax) = DatasetSyntax::from_media_type(mime_type) { if to_graph_name.is_some() { return Err(ValueError::py_err( @@ -104,7 +100,7 @@ impl PySledStore { } self.inner .load_dataset(Cursor::new(data), dataset_syntax, base_iri) - .map_err(|e| ParseError::py_err(e.to_string())) + .map_err(map_io_err) } else { Err(ValueError::py_err(format!( "Not supported MIME type: {}", @@ -134,7 +130,7 @@ impl PySequenceProtocol for PySledStore { fn __contains__(&self, quad: &PyTuple) -> PyResult { self.inner .contains(&extract_quad(quad)?) - .map_err(|e| IOError::py_err(e.to_string())) + .map_err(map_io_err) } } @@ -163,12 +159,7 @@ impl PyIterProtocol for QuadIter { ) -> PyResult> { slf.inner .next() - .map(move |q| { - Ok(quad_to_python( - slf.py(), - q.map_err(|e| IOError::py_err(e.to_string()))?, - )) - }) + .map(move |q| Ok(quad_to_python(slf.py(), q.map_err(map_io_err)?))) .transpose() } } diff --git a/python/src/store_utils.rs b/python/src/store_utils.rs index f93ebb88..9f896950 100644 --- a/python/src/store_utils.rs +++ b/python/src/store_utils.rs @@ -2,12 +2,11 @@ use crate::model::*; use oxigraph::model::*; use oxigraph::sparql::{QueryResult, QuerySolution, QuerySolutionsIterator}; use oxigraph::Result; -use pyo3::exceptions::{IOError, TypeError}; +use pyo3::exceptions::{IOError, TypeError, ValueError}; use pyo3::prelude::*; -use pyo3::{create_exception, PyIterProtocol, PyMappingProtocol, PyNativeType, PyObjectProtocol}; +use pyo3::{PyIterProtocol, PyMappingProtocol, PyNativeType, PyObjectProtocol}; use std::fmt::Write; - -create_exception!(oxigraph, ParseError, pyo3::exceptions::Exception); +use std::io; pub fn extract_quads_pattern( subject: &PyAny, @@ -140,3 +139,12 @@ impl PyIterProtocol for TripleResultIter { .map(move |t| triple_to_python(slf.py(), t))) } } + +pub fn map_io_err(error: io::Error) -> PyErr { + match error.kind() { + io::ErrorKind::InvalidInput | io::ErrorKind::InvalidData => { + ValueError::py_err(error.to_string()) + } + _ => IOError::py_err(error.to_string()), + } +}