Python: use OSError instead of IOError to map io::Error

pull/595/head
Tpt 1 year ago committed by Thomas Tanon
parent f183196859
commit 4a798ed3ea
  1. 13
      python/src/io.rs
  2. 50
      python/src/store.rs

@ -3,7 +3,7 @@
use crate::model::{PyQuad, PyTriple}; use crate::model::{PyQuad, PyTriple};
use oxigraph::io::{FromReadQuadReader, ParseError, RdfFormat, RdfParser, RdfSerializer}; use oxigraph::io::{FromReadQuadReader, ParseError, RdfFormat, RdfParser, RdfSerializer};
use oxigraph::model::QuadRef; use oxigraph::model::QuadRef;
use pyo3::exceptions::{PyIOError, PySyntaxError, PyValueError}; use pyo3::exceptions::{PySyntaxError, PyValueError};
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::types::PyBytes; use pyo3::types::PyBytes;
use pyo3::{intern, wrap_pyfunction}; use pyo3::{intern, wrap_pyfunction};
@ -272,14 +272,17 @@ impl Write for PyIo {
fn flush(&mut self) -> io::Result<()> { fn flush(&mut self) -> io::Result<()> {
Python::with_gil(|py| { Python::with_gil(|py| {
self.0.as_ref(py).call_method0(intern!(py, "flush"))?; self.0
.as_ref(py)
.call_method0(intern!(py, "flush"))
.map_err(to_io_err)?;
Ok(()) Ok(())
}) })
} }
} }
fn to_io_err(error: impl Into<PyErr>) -> io::Error { fn to_io_err(error: PyErr) -> io::Error {
io::Error::new(io::ErrorKind::Other, error.into()) io::Error::new(io::ErrorKind::Other, error)
} }
pub fn map_io_err(error: io::Error) -> PyErr { pub fn map_io_err(error: io::Error) -> PyErr {
@ -289,7 +292,7 @@ pub fn map_io_err(error: io::Error) -> PyErr {
{ {
*error.into_inner().unwrap().downcast().unwrap() *error.into_inner().unwrap().downcast().unwrap()
} else { } else {
PyIOError::new_err(error.to_string()) error.into()
} }
} }

@ -7,7 +7,7 @@ use oxigraph::io::RdfFormat;
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::{PyIOError, PyRuntimeError, PyValueError}; use pyo3::exceptions::{PyRuntimeError, PyValueError};
use pyo3::prelude::*; use pyo3::prelude::*;
use std::path::PathBuf; use std::path::PathBuf;
@ -28,7 +28,7 @@ use std::path::PathBuf;
/// If no directory is provided a temporary one is created and removed when the Python garbage collector removes the store. /// If no directory is provided a temporary one is created and removed when the Python garbage collector removes the store.
/// In this case, the store data are kept in memory and never written on disk. /// In this case, the store data are kept in memory and never written on disk.
/// :type path: str or pathlib.Path or None, optional /// :type path: str or pathlib.Path or None, optional
/// :raises IOError: if the target directory contains invalid data or could not be accessed. /// :raises OSError: if the target directory contains invalid data or could not be accessed.
/// ///
/// The :py:func:`str` function provides a serialization of the store in NQuads: /// The :py:func:`str` function provides a serialization of the store in NQuads:
/// ///
@ -68,7 +68,7 @@ impl PyStore {
/// :type path: str /// :type path: str
/// :return: the opened store. /// :return: the opened store.
/// :rtype: Store /// :rtype: Store
/// :raises IOError: if the target directory contains invalid data or could not be accessed. /// :raises OSError: if the target directory contains invalid data or could not be accessed.
#[staticmethod] #[staticmethod]
fn read_only(path: &str, py: Python<'_>) -> PyResult<Self> { fn read_only(path: &str, py: Python<'_>) -> PyResult<Self> {
py.allow_threads(|| { py.allow_threads(|| {
@ -92,7 +92,7 @@ impl PyStore {
/// :type secondary_path: str or None, optional /// :type secondary_path: str or None, optional
/// :return: the opened store. /// :return: the opened store.
/// :rtype: Store /// :rtype: Store
/// :raises IOError: if the target directories contain invalid data or could not be accessed. /// :raises OSError: if the target directories contain invalid data or could not be accessed.
#[staticmethod] #[staticmethod]
#[pyo3(signature = (primary_path, secondary_path = None))] #[pyo3(signature = (primary_path, secondary_path = None))]
fn secondary( fn secondary(
@ -117,7 +117,7 @@ impl PyStore {
/// :param quad: the quad to add. /// :param quad: the quad to add.
/// :type quad: Quad /// :type quad: Quad
/// :rtype: None /// :rtype: None
/// :raises IOError: if an I/O error happens during the quad insertion. /// :raises OSError: if an error happens during the quad insertion.
/// ///
/// >>> store = Store() /// >>> store = Store()
/// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))) /// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g')))
@ -138,7 +138,7 @@ impl PyStore {
/// :param quads: the quads to add. /// :param quads: the quads to add.
/// :type quads: iterable(Quad) /// :type quads: iterable(Quad)
/// :rtype: None /// :rtype: None
/// :raises IOError: if an I/O error happens during the quad insertion. /// :raises OSError: if an error happens during the quad insertion.
/// ///
/// >>> store = Store() /// >>> store = Store()
/// >>> store.extend([Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))]) /// >>> store.extend([Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))])
@ -163,7 +163,7 @@ impl PyStore {
/// :param quads: the quads to add. /// :param quads: the quads to add.
/// :type quads: iterable(Quad) /// :type quads: iterable(Quad)
/// :rtype: None /// :rtype: None
/// :raises IOError: if an I/O error happens during the quad insertion. /// :raises OSError: if an error happens during the quad insertion.
/// ///
/// >>> store = Store() /// >>> store = Store()
/// >>> store.bulk_extend([Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))]) /// >>> store.bulk_extend([Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))])
@ -183,7 +183,7 @@ impl PyStore {
/// :param quad: the quad to remove. /// :param quad: the quad to remove.
/// :type quad: Quad /// :type quad: Quad
/// :rtype: None /// :rtype: None
/// :raises IOError: if an I/O error happens during the quad removal. /// :raises OSError: if an error happens during the quad removal.
/// ///
/// >>> store = Store() /// >>> store = Store()
/// >>> quad = Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g')) /// >>> quad = Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))
@ -210,7 +210,7 @@ impl PyStore {
/// :type graph_name: NamedNode or BlankNode or DefaultGraph or None, optional /// :type graph_name: NamedNode or BlankNode or DefaultGraph or None, optional
/// :return: an iterator of the quads matching the pattern. /// :return: an iterator of the quads matching the pattern.
/// :rtype: iterator(Quad) /// :rtype: iterator(Quad)
/// :raises IOError: if an I/O error happens during the quads lookup. /// :raises OSError: if an error happens during the quads lookup.
/// ///
/// >>> store = Store() /// >>> store = Store()
/// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))) /// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g')))
@ -251,7 +251,7 @@ impl PyStore {
/// :return: a :py:class:`bool` for ``ASK`` queries, an iterator of :py:class:`Triple` for ``CONSTRUCT`` and ``DESCRIBE`` queries and an iterator of :py:class:`QuerySolution` for ``SELECT`` queries. /// :return: a :py:class:`bool` for ``ASK`` queries, an iterator of :py:class:`Triple` for ``CONSTRUCT`` and ``DESCRIBE`` queries and an iterator of :py:class:`QuerySolution` for ``SELECT`` queries.
/// :rtype: QuerySolutions or QueryTriples or bool /// :rtype: QuerySolutions or QueryTriples or bool
/// :raises SyntaxError: if the provided query is invalid. /// :raises SyntaxError: if the provided query is invalid.
/// :raises IOError: if an I/O error happens while reading the store. /// :raises OSError: if an error happens while reading the store.
/// ///
/// ``SELECT`` query: /// ``SELECT`` query:
/// ///
@ -305,7 +305,7 @@ impl PyStore {
/// :type base_iri: str or None, optional /// :type base_iri: str or None, optional
/// :rtype: None /// :rtype: None
/// :raises SyntaxError: if the provided update is invalid. /// :raises SyntaxError: if the provided update is invalid.
/// :raises IOError: if an I/O error happens while reading the store. /// :raises OSError: if an error happens while reading the store.
/// ///
/// ``INSERT DATA`` update: /// ``INSERT DATA`` update:
/// ///
@ -368,7 +368,7 @@ impl PyStore {
/// :rtype: None /// :rtype: None
/// :raises ValueError: if the MIME type is not supported. /// :raises ValueError: if the MIME type is not supported.
/// :raises SyntaxError: if the provided data is invalid. /// :raises SyntaxError: if the provided data is invalid.
/// :raises IOError: if an I/O error happens during a quad insertion. /// :raises OSError: if an error happens during a quad insertion.
/// ///
/// >>> store = Store() /// >>> store = Store()
/// >>> store.load(io.BytesIO(b'<foo> <p> "1" .'), "text/turtle", base_iri="http://example.com/", to_graph=NamedNode("http://example.com/g")) /// >>> store.load(io.BytesIO(b'<foo> <p> "1" .'), "text/turtle", base_iri="http://example.com/", to_graph=NamedNode("http://example.com/g"))
@ -439,7 +439,7 @@ impl PyStore {
/// :rtype: None /// :rtype: None
/// :raises ValueError: if the MIME type is not supported. /// :raises ValueError: if the MIME type is not supported.
/// :raises SyntaxError: if the provided data is invalid. /// :raises SyntaxError: if the provided data is invalid.
/// :raises IOError: if an I/O error happens during a quad insertion. /// :raises OSError: if an error happens during a quad insertion.
/// ///
/// >>> store = Store() /// >>> store = Store()
/// >>> store.bulk_load(io.BytesIO(b'<foo> <p> "1" .'), "text/turtle", base_iri="http://example.com/", to_graph=NamedNode("http://example.com/g")) /// >>> store.bulk_load(io.BytesIO(b'<foo> <p> "1" .'), "text/turtle", base_iri="http://example.com/", to_graph=NamedNode("http://example.com/g"))
@ -505,7 +505,7 @@ impl PyStore {
/// :type from_graph: NamedNode or BlankNode or DefaultGraph or None, optional /// :type from_graph: NamedNode or BlankNode or DefaultGraph or None, optional
/// :rtype: None /// :rtype: None
/// :raises ValueError: if the MIME type is not supported or the `from_graph` parameter is not given with a syntax not supporting named graphs. /// :raises ValueError: if the MIME type is not supported or the `from_graph` parameter is not given with a syntax not supporting named graphs.
/// :raises IOError: if an I/O error happens during a quad lookup /// :raises OSError: if an error happens during a quad lookup
/// ///
/// >>> store = Store() /// >>> store = Store()
/// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))) /// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g')))
@ -550,7 +550,7 @@ impl PyStore {
/// ///
/// :return: an iterator of the store graph names. /// :return: an iterator of the store graph names.
/// :rtype: iterator(NamedNode or BlankNode) /// :rtype: iterator(NamedNode or BlankNode)
/// :raises IOError: if an I/O error happens during the named graphs lookup. /// :raises OSError: if an error happens during the named graphs lookup.
/// ///
/// >>> store = Store() /// >>> store = Store()
/// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))) /// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g')))
@ -567,7 +567,7 @@ impl PyStore {
/// :param graph_name: the name of the named graph. /// :param graph_name: the name of the named graph.
/// :type graph_name: NamedNode or BlankNode or DefaultGraph /// :type graph_name: NamedNode or BlankNode or DefaultGraph
/// :rtype: bool /// :rtype: bool
/// :raises IOError: if an I/O error happens during the named graph lookup. /// :raises OSError: if an error happens during the named graph lookup.
/// ///
/// >>> store = Store() /// >>> store = Store()
/// >>> store.add_graph(NamedNode('http://example.com/g')) /// >>> store.add_graph(NamedNode('http://example.com/g'))
@ -588,7 +588,7 @@ impl PyStore {
/// :param graph_name: the name of the name graph to add. /// :param graph_name: the name of the name graph to add.
/// :type graph_name: NamedNode or BlankNode or DefaultGraph /// :type graph_name: NamedNode or BlankNode or DefaultGraph
/// :rtype: None /// :rtype: None
/// :raises IOError: if an I/O error happens during the named graph insertion. /// :raises OSError: if an error happens during the named graph insertion.
/// ///
/// >>> store = Store() /// >>> store = Store()
/// >>> store.add_graph(NamedNode('http://example.com/g')) /// >>> store.add_graph(NamedNode('http://example.com/g'))
@ -615,7 +615,7 @@ impl PyStore {
/// :param graph_name: the name of the name graph to clear. /// :param graph_name: the name of the name graph to clear.
/// :type graph_name: NamedNode or BlankNode or DefaultGraph /// :type graph_name: NamedNode or BlankNode or DefaultGraph
/// :rtype: None /// :rtype: None
/// :raises IOError: if an I/O error happens during the operation. /// :raises OSError: if an error happens during the operation.
/// ///
/// >>> store = Store() /// >>> store = Store()
/// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))) /// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g')))
@ -640,7 +640,7 @@ impl PyStore {
/// :param graph_name: the name of the name graph to remove. /// :param graph_name: the name of the name graph to remove.
/// :type graph_name: NamedNode or BlankNode or DefaultGraph /// :type graph_name: NamedNode or BlankNode or DefaultGraph
/// :rtype: None /// :rtype: None
/// :raises IOError: if an I/O error happens during the named graph removal. /// :raises OSError: if an error happens during the named graph removal.
/// ///
/// >>> store = Store() /// >>> store = Store()
/// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))) /// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g')))
@ -666,7 +666,7 @@ impl PyStore {
/// Clears the store by removing all its contents. /// Clears the store by removing all its contents.
/// ///
/// :rtype: None /// :rtype: None
/// :raises IOError: if an I/O error happens during the operation. /// :raises OSError: if an error happens during the operation.
/// ///
/// >>> store = Store() /// >>> store = Store()
/// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))) /// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g')))
@ -684,7 +684,7 @@ impl PyStore {
/// Flushes are automatically done using background threads but might lag a little bit. /// Flushes are automatically done using background threads but might lag a little bit.
/// ///
/// :rtype: None /// :rtype: None
/// :raises IOError: if an I/O error happens during the flush. /// :raises OSError: if an error happens during the flush.
fn flush(&self, py: Python<'_>) -> PyResult<()> { fn flush(&self, py: Python<'_>) -> PyResult<()> {
py.allow_threads(|| self.inner.flush().map_err(map_storage_error)) py.allow_threads(|| self.inner.flush().map_err(map_storage_error))
} }
@ -694,7 +694,7 @@ impl PyStore {
/// Useful to call after a batch upload or another similar operation. /// Useful to call after a batch upload or another similar operation.
/// ///
/// :rtype: None /// :rtype: None
/// :raises IOError: if an I/O error happens during the optimization. /// :raises OSError: if an error happens during the optimization.
fn optimize(&self, py: Python<'_>) -> PyResult<()> { fn optimize(&self, py: Python<'_>) -> PyResult<()> {
py.allow_threads(|| self.inner.optimize().map_err(map_storage_error)) py.allow_threads(|| self.inner.optimize().map_err(map_storage_error))
} }
@ -719,7 +719,7 @@ impl PyStore {
/// :param target_directory: the directory name to save the database to. /// :param target_directory: the directory name to save the database to.
/// :type target_directory: str /// :type target_directory: str
/// :rtype: None /// :rtype: None
/// :raises IOError: if an I/O error happens during the backup. /// :raises OSError: if an error happens during the backup.
fn backup(&self, target_directory: &str, py: Python<'_>) -> PyResult<()> { fn backup(&self, target_directory: &str, py: Python<'_>) -> PyResult<()> {
py.allow_threads(|| { py.allow_threads(|| {
self.inner self.inner
@ -830,7 +830,7 @@ pub fn extract_quads_pattern<'a>(
pub fn map_storage_error(error: StorageError) -> PyErr { pub fn map_storage_error(error: StorageError) -> PyErr {
match error { match error {
StorageError::Io(error) => PyIOError::new_err(error.to_string()), StorageError::Io(error) => error.into(),
_ => PyRuntimeError::new_err(error.to_string()), _ => PyRuntimeError::new_err(error.to_string()),
} }
} }
@ -846,7 +846,7 @@ pub fn map_loader_error(error: LoaderError) -> PyErr {
pub fn map_serializer_error(error: SerializerError) -> PyErr { pub fn map_serializer_error(error: SerializerError) -> PyErr {
match error { match error {
SerializerError::Storage(error) => map_storage_error(error), SerializerError::Storage(error) => map_storage_error(error),
SerializerError::Io(error) => PyIOError::new_err(error.to_string()), SerializerError::Io(error) => error.into(),
SerializerError::DatasetFormatExpected(_) => PyValueError::new_err(error.to_string()), SerializerError::DatasetFormatExpected(_) => PyValueError::new_err(error.to_string()),
} }
} }

Loading…
Cancel
Save