Upgrades to PyO3 0.21

pull/839/head
Tpt 9 months ago committed by Thomas Tanon
parent 0f0c1d2742
commit 1d5843fddc
  1. 20
      Cargo.lock
  2. 2
      Cargo.toml
  3. 40
      python/src/dataset.rs
  4. 45
      python/src/io.rs
  5. 2
      python/src/lib.rs
  6. 163
      python/src/model.rs
  7. 36
      python/src/sparql.rs
  8. 161
      python/src/store.rs

20
Cargo.lock generated

@ -1366,9 +1366,9 @@ dependencies = [
[[package]] [[package]]
name = "pyo3" name = "pyo3"
version = "0.20.3" version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53bdbb96d49157e65d45cc287af5f32ffadd5f4761438b527b055fb0d4bb8233" checksum = "a02a88a17e74cadbc8ce77855e1d6c8ad0ab82901a4a9b5046bd01c1c0bd95cd"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"indoc", "indoc",
@ -1384,9 +1384,9 @@ dependencies = [
[[package]] [[package]]
name = "pyo3-build-config" name = "pyo3-build-config"
version = "0.20.3" version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "deaa5745de3f5231ce10517a1f5dd97d53e5a2fd77aa6b5842292085831d48d7" checksum = "a5eb0b6ecba38961f6f4bd6cd5906dfab3cd426ff37b2eed5771006aa31656f1"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"target-lexicon", "target-lexicon",
@ -1394,9 +1394,9 @@ dependencies = [
[[package]] [[package]]
name = "pyo3-ffi" name = "pyo3-ffi"
version = "0.20.3" version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b42531d03e08d4ef1f6e85a2ed422eb678b8cd62b762e53891c05faf0d4afa" checksum = "ba8a6e48a29b5d22e4fdaf132d8ba8d3203ee9f06362d48f244346902a594ec3"
dependencies = [ dependencies = [
"libc", "libc",
"pyo3-build-config", "pyo3-build-config",
@ -1404,9 +1404,9 @@ dependencies = [
[[package]] [[package]]
name = "pyo3-macros" name = "pyo3-macros"
version = "0.20.3" version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7305c720fa01b8055ec95e484a6eca7a83c841267f0dd5280f0c8b8551d2c158" checksum = "4e80493c5965f94a747d0782a607b2328a4eea5391327b152b00e2f3b001cede"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"pyo3-macros-backend", "pyo3-macros-backend",
@ -1416,9 +1416,9 @@ dependencies = [
[[package]] [[package]]
name = "pyo3-macros-backend" name = "pyo3-macros-backend"
version = "0.20.3" version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c7e9b68bb9c3149c5b0cade5d07f953d6d125eb4337723c4ccdb665f1f96185" checksum = "fcd7d86f42004025200e12a6a8119bd878329e6fddef8178eaafa4e4b5906c5b"
dependencies = [ dependencies = [
"heck 0.4.1", "heck 0.4.1",
"proc-macro2", "proc-macro2",

@ -51,7 +51,7 @@ oxiri = "0.2.3"
peg = "0.8" peg = "0.8"
pkg-config = "0.3.25" pkg-config = "0.3.25"
predicates = ">=2.0, <4.0" predicates = ">=2.0, <4.0"
pyo3 = "0.20.1" pyo3 = "0.21.0"
quick-xml = ">=0.29, <0.32" quick-xml = ">=0.29, <0.32"
rand = "0.8" rand = "0.8"
rayon-core = "1.11" rayon-core = "1.11"

@ -30,7 +30,7 @@ pub struct PyDataset {
impl PyDataset { impl PyDataset {
#[new] #[new]
#[pyo3(signature = (quads = None))] #[pyo3(signature = (quads = None))]
fn new(quads: Option<&PyAny>) -> PyResult<Self> { fn new(quads: Option<&Bound<'_, PyAny>>) -> PyResult<Self> {
let mut inner = Dataset::new(); let mut inner = Dataset::new();
if let Some(quads) = quads { if let Some(quads) = quads {
for quad in quads.iter()? { for quad in quads.iter()? {
@ -50,15 +50,16 @@ impl PyDataset {
/// >>> store = Dataset([Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))]) /// >>> store = Dataset([Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))])
/// >>> list(store.quads_for_subject(NamedNode('http://example.com'))) /// >>> list(store.quads_for_subject(NamedNode('http://example.com')))
/// [<Quad subject=<NamedNode value=http://example.com> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>] /// [<Quad subject=<NamedNode value=http://example.com> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>]
pub fn quads_for_subject(&self, subject: &PyAny) -> PyResult<QuadIter> { #[allow(clippy::needless_pass_by_value)]
Ok(QuadIter { pub fn quads_for_subject(&self, subject: PySubjectRef<'_>) -> QuadIter {
QuadIter {
inner: self inner: self
.inner .inner
.quads_for_subject(&PySubjectRef::try_from(subject)?) .quads_for_subject(&subject)
.map(QuadRef::into_owned) .map(QuadRef::into_owned)
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_iter(), .into_iter(),
}) }
} }
/// Looks for the quads with the given predicate. /// Looks for the quads with the given predicate.
@ -71,15 +72,16 @@ impl PyDataset {
/// >>> store = Dataset([Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))]) /// >>> store = Dataset([Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))])
/// >>> list(store.quads_for_predicate(NamedNode('http://example.com/p'))) /// >>> list(store.quads_for_predicate(NamedNode('http://example.com/p')))
/// [<Quad subject=<NamedNode value=http://example.com> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>] /// [<Quad subject=<NamedNode value=http://example.com> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>]
pub fn quads_for_predicate(&self, predicate: &PyAny) -> PyResult<QuadIter> { #[allow(clippy::needless_pass_by_value)]
Ok(QuadIter { pub fn quads_for_predicate(&self, predicate: PyNamedNodeRef<'_>) -> QuadIter {
QuadIter {
inner: self inner: self
.inner .inner
.quads_for_predicate(&PyNamedNodeRef::try_from(predicate)?) .quads_for_predicate(&predicate)
.map(QuadRef::into_owned) .map(QuadRef::into_owned)
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_iter(), .into_iter(),
}) }
} }
/// Looks for the quads with the given object. /// Looks for the quads with the given object.
@ -92,15 +94,16 @@ impl PyDataset {
/// >>> store = Dataset([Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))]) /// >>> store = Dataset([Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))])
/// >>> list(store.quads_for_object(Literal('1'))) /// >>> list(store.quads_for_object(Literal('1')))
/// [<Quad subject=<NamedNode value=http://example.com> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>] /// [<Quad subject=<NamedNode value=http://example.com> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>]
pub fn quads_for_object(&self, object: &PyAny) -> PyResult<QuadIter> { #[allow(clippy::needless_pass_by_value)]
Ok(QuadIter { pub fn quads_for_object(&self, object: PyTermRef<'_>) -> QuadIter {
QuadIter {
inner: self inner: self
.inner .inner
.quads_for_object(&PyTermRef::try_from(object)?) .quads_for_object(&object)
.map(QuadRef::into_owned) .map(QuadRef::into_owned)
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_iter(), .into_iter(),
}) }
} }
/// Looks for the quads with the given graph name. /// Looks for the quads with the given graph name.
@ -113,15 +116,16 @@ impl PyDataset {
/// >>> store = Dataset([Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))]) /// >>> store = Dataset([Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))])
/// >>> list(store.quads_for_graph_name(NamedNode('http://example.com/g'))) /// >>> list(store.quads_for_graph_name(NamedNode('http://example.com/g')))
/// [<Quad subject=<NamedNode value=http://example.com> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>] /// [<Quad subject=<NamedNode value=http://example.com> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>]
pub fn quads_for_graph_name(&self, graph_name: &PyAny) -> PyResult<QuadIter> { #[allow(clippy::needless_pass_by_value)]
Ok(QuadIter { pub fn quads_for_graph_name(&self, graph_name: PyGraphNameRef<'_>) -> QuadIter {
QuadIter {
inner: self inner: self
.inner .inner
.quads_for_graph_name(&PyGraphNameRef::try_from(graph_name)?) .quads_for_graph_name(&graph_name)
.map(QuadRef::into_owned) .map(QuadRef::into_owned)
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_iter(), .into_iter(),
}) }
} }
/// Adds a quad to the dataset. /// Adds a quad to the dataset.
@ -317,7 +321,7 @@ impl PyCanonicalizationAlgorithm {
/// :type memo: typing.Any /// :type memo: typing.Any
/// :rtype: CanonicalizationAlgorithm /// :rtype: CanonicalizationAlgorithm
#[allow(unused_variables)] #[allow(unused_variables)]
fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ PyAny) -> PyRef<'a, Self> { fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ Bound<'_, PyAny>) -> PyRef<'a, Self> {
slf slf
} }
} }

@ -6,7 +6,7 @@ use oxigraph::model::QuadRef;
use pyo3::exceptions::{PyDeprecationWarning, PySyntaxError, PyValueError}; use pyo3::exceptions::{PyDeprecationWarning, PySyntaxError, PyValueError};
use pyo3::intern; use pyo3::intern;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::types::PyBytes; use pyo3::types::{PyBytes, PyString};
use std::cmp::max; use std::cmp::max;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::fs::File; use std::fs::File;
@ -118,12 +118,12 @@ pub fn parse(
/// b'<http://example.com> <http://example.com/p> "1" .\n' /// b'<http://example.com> <http://example.com/p> "1" .\n'
#[pyfunction] #[pyfunction]
#[pyo3(signature = (input, output = None, format = None))] #[pyo3(signature = (input, output = None, format = None))]
pub fn serialize<'a>( pub fn serialize<'py>(
input: &PyAny, input: &Bound<'py, PyAny>,
output: Option<PyWritableOutput>, output: Option<PyWritableOutput>,
format: Option<PyRdfFormatInput>, format: Option<PyRdfFormatInput>,
py: Python<'a>, py: Python<'py>,
) -> PyResult<Option<&'a PyBytes>> { ) -> PyResult<Option<Bound<'py, PyBytes>>> {
PyWritable::do_write( PyWritable::do_write(
|output, file_path| { |output, file_path| {
let format = lookup_rdf_format(format, file_path.as_deref())?; let format = lookup_rdf_format(format, file_path.as_deref())?;
@ -355,7 +355,7 @@ impl PyRdfFormat {
/// :type memo: typing.Any /// :type memo: typing.Any
/// :rtype: RdfFormat /// :rtype: RdfFormat
#[allow(unused_variables)] #[allow(unused_variables)]
fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ PyAny) -> PyRef<'a, Self> { fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ Bound<'_, PyAny>) -> PyRef<'a, Self> {
slf slf
} }
} }
@ -423,7 +423,7 @@ impl PyWritable {
write: impl FnOnce(BufWriter<Self>, Option<PathBuf>) -> PyResult<BufWriter<Self>>, write: impl FnOnce(BufWriter<Self>, Option<PathBuf>) -> PyResult<BufWriter<Self>>,
output: Option<PyWritableOutput>, output: Option<PyWritableOutput>,
py: Python<'_>, py: Python<'_>,
) -> PyResult<Option<&PyBytes>> { ) -> PyResult<Option<Bound<'_, PyBytes>>> {
let (output, file_path) = match output { let (output, file_path) = match output {
Some(PyWritableOutput::Path(file_path)) => ( Some(PyWritableOutput::Path(file_path)) => (
Self::File(py.allow_threads(|| File::create(&file_path))?), Self::File(py.allow_threads(|| File::create(&file_path))?),
@ -436,9 +436,9 @@ impl PyWritable {
py.allow_threads(|| writer.into_inner())?.close(py) py.allow_threads(|| writer.into_inner())?.close(py)
} }
fn close(self, py: Python<'_>) -> PyResult<Option<&PyBytes>> { fn close(self, py: Python<'_>) -> PyResult<Option<Bound<'_, PyBytes>>> {
match self { match self {
Self::Bytes(bytes) => Ok(Some(PyBytes::new(py, &bytes))), Self::Bytes(bytes) => Ok(Some(PyBytes::new_bound(py, &bytes))),
Self::File(mut file) => { Self::File(mut file) => {
py.allow_threads(|| { py.allow_threads(|| {
file.flush()?; file.flush()?;
@ -489,13 +489,18 @@ impl Read for PyIo {
let to_read = max(1, buf.len() / 4); // We divide by 4 because TextIO works with number of characters and not with number of bytes let to_read = max(1, buf.len() / 4); // We divide by 4 because TextIO works with number of characters and not with number of bytes
let read = self let read = self
.0 .0
.as_ref(py) .bind(py)
.call_method1(intern!(py, "read"), (to_read,))?; .call_method1(intern!(py, "read"), (to_read,))?;
let bytes = read Ok(if let Ok(bytes) = read.extract::<&[u8]>() {
.extract::<&[u8]>() buf[..bytes.len()].copy_from_slice(bytes);
.or_else(|_| read.extract::<&str>().map(str::as_bytes))?; bytes.len()
buf[..bytes.len()].copy_from_slice(bytes); } else {
Ok(bytes.len()) // TODO: Python 3.10+ use directly .extract<&str>
let string = read.extract::<Bound<'_, PyString>>()?;
let str = string.to_cow()?;
buf[..str.len()].copy_from_slice(str.as_bytes());
str.len()
})
}) })
} }
} }
@ -505,15 +510,15 @@ impl Write for PyIo {
Python::with_gil(|py| { Python::with_gil(|py| {
Ok(self Ok(self
.0 .0
.as_ref(py) .bind(py)
.call_method1(intern!(py, "write"), (PyBytes::new(py, buf),))? .call_method1(intern!(py, "write"), (PyBytes::new_bound(py, buf),))?
.extract::<usize>()?) .extract::<usize>()?)
}) })
} }
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.bind(py).call_method0(intern!(py, "flush"))?;
Ok(()) Ok(())
}) })
} }
@ -629,5 +634,7 @@ pub fn python_version() -> (u8, u8) {
} }
pub fn deprecation_warning(message: &str) -> PyResult<()> { pub fn deprecation_warning(message: &str) -> PyResult<()> {
Python::with_gil(|py| PyErr::warn(py, py.get_type::<PyDeprecationWarning>(), message, 0)) Python::with_gil(|py| {
PyErr::warn_bound(py, &py.get_type_bound::<PyDeprecationWarning>(), message, 0)
})
} }

@ -19,7 +19,7 @@ use pyo3::prelude::*;
/// Oxigraph Python bindings /// Oxigraph Python bindings
#[pymodule] #[pymodule]
fn pyoxigraph(_py: Python<'_>, module: &PyModule) -> PyResult<()> { fn pyoxigraph(_py: Python<'_>, module: &Bound<'_, PyModule>) -> PyResult<()> {
module.add("__package__", "pyoxigraph")?; module.add("__package__", "pyoxigraph")?;
module.add("__version__", env!("CARGO_PKG_VERSION"))?; module.add("__version__", env!("CARGO_PKG_VERSION"))?;
module.add("__author__", env!("CARGO_PKG_AUTHORS").replace(':', "\n"))?; module.add("__author__", env!("CARGO_PKG_AUTHORS").replace(':', "\n"))?;

@ -93,12 +93,12 @@ impl PyNamedNode {
hash(&self.inner) hash(&self.inner)
} }
fn __richcmp__(&self, other: &PyAny, op: CompareOp) -> PyResult<bool> { fn __richcmp__(&self, other: &Bound<'_, PyAny>, op: CompareOp) -> PyResult<bool> {
if let Ok(other) = other.extract::<PyRef<'_, Self>>() { if let Ok(other) = other.extract::<PyRef<'_, Self>>() {
Ok(op.matches(self.cmp(&other))) Ok(op.matches(self.cmp(&other)))
} else if PyBlankNode::is_type_of(other) } else if PyBlankNode::is_type_of_bound(other)
|| PyLiteral::is_type_of(other) || PyLiteral::is_type_of_bound(other)
|| PyDefaultGraph::is_type_of(other) || PyDefaultGraph::is_type_of_bound(other)
{ {
eq_compare_other_type(op) eq_compare_other_type(op)
} else { } else {
@ -121,7 +121,7 @@ impl PyNamedNode {
/// :type memo: typing.Any /// :type memo: typing.Any
/// :rtype: NamedNode /// :rtype: NamedNode
#[allow(unused_variables)] #[allow(unused_variables)]
fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ PyAny) -> PyRef<'a, Self> { fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ Bound<'_, PyAny>) -> PyRef<'a, Self> {
slf slf
} }
@ -220,12 +220,12 @@ impl PyBlankNode {
hash(&self.inner) hash(&self.inner)
} }
fn __richcmp__(&self, other: &PyAny, op: CompareOp) -> PyResult<bool> { fn __richcmp__(&self, other: &Bound<'_, PyAny>, op: CompareOp) -> PyResult<bool> {
if let Ok(other) = other.extract::<PyRef<'_, Self>>() { if let Ok(other) = other.extract::<PyRef<'_, Self>>() {
eq_compare(self, &other, op) eq_compare(self, &other, op)
} else if PyNamedNode::is_type_of(other) } else if PyNamedNode::is_type_of_bound(other)
|| PyLiteral::is_type_of(other) || PyLiteral::is_type_of_bound(other)
|| PyDefaultGraph::is_type_of(other) || PyDefaultGraph::is_type_of_bound(other)
{ {
eq_compare_other_type(op) eq_compare_other_type(op)
} else { } else {
@ -248,7 +248,7 @@ impl PyBlankNode {
/// :type memo: typing.Any /// :type memo: typing.Any
/// :rtype: BlankNode /// :rtype: BlankNode
#[allow(unused_variables)] #[allow(unused_variables)]
fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ PyAny) -> PyRef<'a, Self> { fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ Bound<'_, PyAny>) -> PyRef<'a, Self> {
slf slf
} }
@ -376,12 +376,12 @@ impl PyLiteral {
hash(&self.inner) hash(&self.inner)
} }
fn __richcmp__(&self, other: &PyAny, op: CompareOp) -> PyResult<bool> { fn __richcmp__(&self, other: &Bound<'_, PyAny>, op: CompareOp) -> PyResult<bool> {
if let Ok(other) = other.extract::<PyRef<'_, Self>>() { if let Ok(other) = other.extract::<PyRef<'_, Self>>() {
eq_compare(self, &other, op) eq_compare(self, &other, op)
} else if PyNamedNode::is_type_of(other) } else if PyNamedNode::is_type_of_bound(other)
|| PyBlankNode::is_type_of(other) || PyBlankNode::is_type_of_bound(other)
|| PyDefaultGraph::is_type_of(other) || PyDefaultGraph::is_type_of_bound(other)
{ {
eq_compare_other_type(op) eq_compare_other_type(op)
} else { } else {
@ -392,8 +392,11 @@ impl PyLiteral {
} }
/// :rtype: typing.Any /// :rtype: typing.Any
fn __getnewargs_ex__<'a>(&'a self, py: Python<'a>) -> PyResult<((&'a str,), &'a PyDict)> { fn __getnewargs_ex__<'a, 'py>(
let kwargs = PyDict::new(py); &'a self,
py: Python<'py>,
) -> PyResult<((&'a str,), Bound<'py, PyDict>)> {
let kwargs = PyDict::new_bound(py);
if let Some(language) = self.language() { if let Some(language) = self.language() {
kwargs.set_item("language", language)?; kwargs.set_item("language", language)?;
} else { } else {
@ -410,7 +413,7 @@ impl PyLiteral {
/// :type memo: typing.Any /// :type memo: typing.Any
/// :rtype: Literal /// :rtype: Literal
#[allow(unused_variables)] #[allow(unused_variables)]
fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ PyAny) -> PyRef<'a, Self> { fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ Bound<'_, PyAny>) -> PyRef<'a, Self> {
slf slf
} }
@ -450,12 +453,12 @@ impl PyDefaultGraph {
0 0
} }
fn __richcmp__(&self, other: &PyAny, op: CompareOp) -> PyResult<bool> { fn __richcmp__(&self, other: &Bound<'_, PyAny>, op: CompareOp) -> PyResult<bool> {
if let Ok(other) = other.extract::<PyRef<'_, Self>>() { if let Ok(other) = other.extract::<PyRef<'_, Self>>() {
eq_compare(self, &other, op) eq_compare(self, &other, op)
} else if PyNamedNode::is_type_of(other) } else if PyNamedNode::is_type_of_bound(other)
|| PyBlankNode::is_type_of(other) || PyBlankNode::is_type_of_bound(other)
|| PyLiteral::is_type_of(other) || PyLiteral::is_type_of_bound(other)
{ {
eq_compare_other_type(op) eq_compare_other_type(op)
} else { } else {
@ -466,8 +469,8 @@ impl PyDefaultGraph {
} }
/// :rtype: typing.Any /// :rtype: typing.Any
fn __getnewargs__<'a>(&self, py: Python<'a>) -> &'a PyTuple { fn __getnewargs__<'py>(&self, py: Python<'py>) -> Bound<'py, PyTuple> {
PyTuple::empty(py) PyTuple::empty_bound(py)
} }
/// :rtype: DefaultGraph /// :rtype: DefaultGraph
@ -478,7 +481,7 @@ impl PyDefaultGraph {
/// :type memo: typing.Any /// :type memo: typing.Any
/// :rtype: DefaultGraph /// :rtype: DefaultGraph
#[allow(unused_variables)] #[allow(unused_variables)]
fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ PyAny) -> PyRef<'a, Self> { fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ Bound<'_, PyAny>) -> PyRef<'a, Self> {
slf slf
} }
} }
@ -739,7 +742,7 @@ impl PyTriple {
/// :type memo: typing.Any /// :type memo: typing.Any
/// :rtype: Triple /// :rtype: Triple
#[allow(unused_variables)] #[allow(unused_variables)]
fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ PyAny) -> PyRef<'a, Self> { fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ Bound<'_, PyAny>) -> PyRef<'a, Self> {
slf slf
} }
@ -976,7 +979,7 @@ impl PyQuad {
/// :type memo: typing.Any /// :type memo: typing.Any
/// :rtype: Quad /// :rtype: Quad
#[allow(unused_variables)] #[allow(unused_variables)]
fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ PyAny) -> PyRef<'a, Self> { fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ Bound<'_, PyAny>) -> PyRef<'a, Self> {
slf slf
} }
@ -1068,7 +1071,7 @@ impl PyVariable {
/// :type memo: typing.Any /// :type memo: typing.Any
/// :rtype: Variable /// :rtype: Variable
#[allow(unused_variables)] #[allow(unused_variables)]
fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ PyAny) -> PyRef<'a, Self> { fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ Bound<'_, PyAny>) -> PyRef<'a, Self> {
slf slf
} }
@ -1078,6 +1081,7 @@ impl PyVariable {
} }
} }
#[derive(FromPyObject)]
pub struct PyNamedNodeRef<'a>(PyRef<'a, PyNamedNode>); pub struct PyNamedNodeRef<'a>(PyRef<'a, PyNamedNode>);
impl<'a> From<&'a PyNamedNodeRef<'a>> for NamedNodeRef<'a> { impl<'a> From<&'a PyNamedNodeRef<'a>> for NamedNodeRef<'a> {
@ -1086,21 +1090,7 @@ impl<'a> From<&'a PyNamedNodeRef<'a>> for NamedNodeRef<'a> {
} }
} }
impl<'a> TryFrom<&'a PyAny> for PyNamedNodeRef<'a> { #[derive(FromPyObject)]
type Error = PyErr;
fn try_from(value: &'a PyAny) -> PyResult<Self> {
if let Ok(node) = value.extract::<PyRef<'_, PyNamedNode>>() {
Ok(Self(node))
} else {
Err(PyTypeError::new_err(format!(
"{} is not an RDF named node",
value.get_type().name()?,
)))
}
}
}
pub enum PyNamedOrBlankNodeRef<'a> { pub enum PyNamedOrBlankNodeRef<'a> {
NamedNode(PyRef<'a, PyNamedNode>), NamedNode(PyRef<'a, PyNamedNode>),
BlankNode(PyRef<'a, PyBlankNode>), BlankNode(PyRef<'a, PyBlankNode>),
@ -1115,23 +1105,7 @@ impl<'a> From<&'a PyNamedOrBlankNodeRef<'a>> for NamedOrBlankNodeRef<'a> {
} }
} }
impl<'a> TryFrom<&'a PyAny> for PyNamedOrBlankNodeRef<'a> { #[derive(FromPyObject)]
type Error = PyErr;
fn try_from(value: &'a PyAny) -> PyResult<Self> {
if let Ok(node) = value.extract::<PyRef<'_, PyNamedNode>>() {
Ok(Self::NamedNode(node))
} else if let Ok(node) = value.extract::<PyRef<'_, PyBlankNode>>() {
Ok(Self::BlankNode(node))
} else {
Err(PyTypeError::new_err(format!(
"{} is not an RDF named or blank node",
value.get_type().name()?,
)))
}
}
}
pub enum PySubjectRef<'a> { pub enum PySubjectRef<'a> {
NamedNode(PyRef<'a, PyNamedNode>), NamedNode(PyRef<'a, PyNamedNode>),
BlankNode(PyRef<'a, PyBlankNode>), BlankNode(PyRef<'a, PyBlankNode>),
@ -1148,25 +1122,7 @@ impl<'a> From<&'a PySubjectRef<'a>> for SubjectRef<'a> {
} }
} }
impl<'a> TryFrom<&'a PyAny> for PySubjectRef<'a> { #[derive(FromPyObject)]
type Error = PyErr;
fn try_from(value: &'a PyAny) -> PyResult<Self> {
if let Ok(node) = value.extract::<PyRef<'_, PyNamedNode>>() {
Ok(Self::NamedNode(node))
} else if let Ok(node) = value.extract::<PyRef<'_, PyBlankNode>>() {
Ok(Self::BlankNode(node))
} else if let Ok(node) = value.extract::<PyRef<'_, PyTriple>>() {
Ok(Self::Triple(node))
} else {
Err(PyTypeError::new_err(format!(
"{} is not an RDF named or blank node",
value.get_type().name()?,
)))
}
}
}
pub enum PyTermRef<'a> { pub enum PyTermRef<'a> {
NamedNode(PyRef<'a, PyNamedNode>), NamedNode(PyRef<'a, PyNamedNode>),
BlankNode(PyRef<'a, PyBlankNode>), BlankNode(PyRef<'a, PyBlankNode>),
@ -1191,31 +1147,11 @@ impl<'a> From<&'a PyTermRef<'a>> for Term {
} }
} }
impl<'a> TryFrom<&'a PyAny> for PyTermRef<'a> { #[derive(FromPyObject)]
type Error = PyErr;
fn try_from(value: &'a PyAny) -> PyResult<Self> {
if let Ok(node) = value.extract::<PyRef<'_, PyNamedNode>>() {
Ok(Self::NamedNode(node))
} else if let Ok(node) = value.extract::<PyRef<'_, PyBlankNode>>() {
Ok(Self::BlankNode(node))
} else if let Ok(node) = value.extract::<PyRef<'_, PyLiteral>>() {
Ok(Self::Literal(node))
} else if let Ok(node) = value.extract::<PyRef<'_, PyTriple>>() {
Ok(Self::Triple(node))
} else {
Err(PyTypeError::new_err(format!(
"{} is not an RDF term",
value.get_type().name()?,
)))
}
}
}
pub enum PyGraphNameRef<'a> { pub enum PyGraphNameRef<'a> {
NamedNode(PyRef<'a, PyNamedNode>), NamedNode(PyRef<'a, PyNamedNode>),
BlankNode(PyRef<'a, PyBlankNode>), BlankNode(PyRef<'a, PyBlankNode>),
DefaultGraph, DefaultGraph(PyRef<'a, PyDefaultGraph>),
} }
impl<'a> From<&'a PyGraphNameRef<'a>> for GraphNameRef<'a> { impl<'a> From<&'a PyGraphNameRef<'a>> for GraphNameRef<'a> {
@ -1223,32 +1159,7 @@ impl<'a> From<&'a PyGraphNameRef<'a>> for GraphNameRef<'a> {
match value { match value {
PyGraphNameRef::NamedNode(value) => value.inner.as_ref().into(), PyGraphNameRef::NamedNode(value) => value.inner.as_ref().into(),
PyGraphNameRef::BlankNode(value) => value.inner.as_ref().into(), PyGraphNameRef::BlankNode(value) => value.inner.as_ref().into(),
PyGraphNameRef::DefaultGraph => Self::DefaultGraph, PyGraphNameRef::DefaultGraph(_) => Self::DefaultGraph,
}
}
}
impl<'a> From<&'a PyGraphNameRef<'a>> for GraphName {
fn from(value: &'a PyGraphNameRef<'a>) -> Self {
GraphNameRef::from(value).into()
}
}
impl<'a> TryFrom<&'a PyAny> for PyGraphNameRef<'a> {
type Error = PyErr;
fn try_from(value: &'a PyAny) -> PyResult<Self> {
if let Ok(node) = value.extract::<PyRef<'_, PyNamedNode>>() {
Ok(Self::NamedNode(node))
} else if let Ok(node) = value.extract::<PyRef<'_, PyBlankNode>>() {
Ok(Self::BlankNode(node))
} else if value.extract::<PyRef<'_, PyDefaultGraph>>().is_ok() {
Ok(Self::DefaultGraph)
} else {
Err(PyTypeError::new_err(format!(
"{} is not an RDF graph name",
value.get_type().name()?,
)))
} }
} }
} }

@ -14,7 +14,7 @@ use oxigraph::sparql::{
use pyo3::basic::CompareOp; use pyo3::basic::CompareOp;
use pyo3::exceptions::{PyRuntimeError, PySyntaxError, PyValueError}; use pyo3::exceptions::{PyRuntimeError, PySyntaxError, PyValueError};
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::types::PyBytes; use pyo3::types::{PyBytes, PyString};
use std::ffi::OsStr; use std::ffi::OsStr;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -24,8 +24,8 @@ pub fn parse_query(
query: &str, query: &str,
base_iri: Option<&str>, base_iri: Option<&str>,
use_default_graph_as_union: bool, use_default_graph_as_union: bool,
default_graph: Option<&PyAny>, default_graph: Option<&Bound<'_, PyAny>>,
named_graphs: Option<&PyAny>, named_graphs: Option<&Bound<'_, PyAny>>,
py: Python<'_>, py: Python<'_>,
) -> PyResult<Query> { ) -> PyResult<Query> {
let mut query = allow_threads_unsafe(py, || Query::parse(query, base_iri)) let mut query = allow_threads_unsafe(py, || Query::parse(query, base_iri))
@ -133,13 +133,13 @@ impl PyQuerySolution {
self.inner.len() self.inner.len()
} }
fn __getitem__(&self, key: PySolutionKey<'_>) -> Option<PyTerm> { fn __getitem__(&self, key: PySolutionKey<'_>) -> PyResult<Option<PyTerm>> {
match key { Ok(match key {
PySolutionKey::Usize(key) => self.inner.get(key), PySolutionKey::Usize(key) => self.inner.get(key),
PySolutionKey::Str(key) => self.inner.get(key), PySolutionKey::Str(key) => self.inner.get(key.to_cow()?.as_ref()),
PySolutionKey::Variable(key) => self.inner.get(<&Variable>::from(&*key)), PySolutionKey::Variable(key) => self.inner.get(<&Variable>::from(&*key)),
} }
.map(|term| PyTerm::from(term.clone())) .map(|term| PyTerm::from(term.clone())))
} }
#[allow(clippy::unnecessary_to_owned)] #[allow(clippy::unnecessary_to_owned)]
@ -153,7 +153,7 @@ impl PyQuerySolution {
#[derive(FromPyObject)] #[derive(FromPyObject)]
pub enum PySolutionKey<'a> { pub enum PySolutionKey<'a> {
Usize(usize), Usize(usize),
Str(&'a str), Str(Bound<'a, PyString>), // TODO: Python 3.10+: use &str
Variable(PyRef<'a, PyVariable>), Variable(PyRef<'a, PyVariable>),
} }
@ -237,12 +237,12 @@ impl PyQuerySolutions {
/// >>> results.serialize(format=QueryResultsFormat.JSON) /// >>> results.serialize(format=QueryResultsFormat.JSON)
/// b'{"head":{"vars":["s","p","o"]},"results":{"bindings":[{"s":{"type":"uri","value":"http://example.com"},"p":{"type":"uri","value":"http://example.com/p"},"o":{"type":"literal","value":"1"}}]}}' /// b'{"head":{"vars":["s","p","o"]},"results":{"bindings":[{"s":{"type":"uri","value":"http://example.com"},"p":{"type":"uri","value":"http://example.com/p"},"o":{"type":"literal","value":"1"}}]}}'
#[pyo3(signature = (output = None, format = None))] #[pyo3(signature = (output = None, format = None))]
fn serialize<'a>( fn serialize<'py>(
&mut self, &mut self,
output: Option<PyWritableOutput>, output: Option<PyWritableOutput>,
format: Option<PyQueryResultsFormatInput>, format: Option<PyQueryResultsFormatInput>,
py: Python<'a>, py: Python<'py>,
) -> PyResult<Option<&'a PyBytes>> { ) -> PyResult<Option<Bound<'py, PyBytes>>> {
PyWritable::do_write( PyWritable::do_write(
|output, file_path| { |output, file_path| {
let format = lookup_query_results_format(format, file_path.as_deref())?; let format = lookup_query_results_format(format, file_path.as_deref())?;
@ -337,12 +337,12 @@ impl PyQueryBoolean {
/// >>> results.serialize(format=QueryResultsFormat.JSON) /// >>> results.serialize(format=QueryResultsFormat.JSON)
/// b'{"head":{},"boolean":true}' /// b'{"head":{},"boolean":true}'
#[pyo3(signature = (output = None, format = None))] #[pyo3(signature = (output = None, format = None))]
fn serialize<'a>( fn serialize<'py>(
&mut self, &mut self,
output: Option<PyWritableOutput>, output: Option<PyWritableOutput>,
format: Option<PyQueryResultsFormatInput>, format: Option<PyQueryResultsFormatInput>,
py: Python<'a>, py: Python<'py>,
) -> PyResult<Option<&'a PyBytes>> { ) -> PyResult<Option<Bound<'py, PyBytes>>> {
PyWritable::do_write( PyWritable::do_write(
|output, file_path| { |output, file_path| {
let format = lookup_query_results_format(format, file_path.as_deref())?; let format = lookup_query_results_format(format, file_path.as_deref())?;
@ -415,12 +415,12 @@ impl PyQueryTriples {
/// >>> results.serialize(format=RdfFormat.N_TRIPLES) /// >>> results.serialize(format=RdfFormat.N_TRIPLES)
/// b'<http://example.com> <http://example.com/p> "1" .\n' /// b'<http://example.com> <http://example.com/p> "1" .\n'
#[pyo3(signature = (output = None, format = None))] #[pyo3(signature = (output = None, format = None))]
fn serialize<'a>( fn serialize<'py>(
&mut self, &mut self,
output: Option<PyWritableOutput>, output: Option<PyWritableOutput>,
format: Option<PyRdfFormatInput>, format: Option<PyRdfFormatInput>,
py: Python<'a>, py: Python<'py>,
) -> PyResult<Option<&'a PyBytes>> { ) -> PyResult<Option<Bound<'py, PyBytes>>> {
PyWritable::do_write( PyWritable::do_write(
|output, file_path| { |output, file_path| {
let format = lookup_rdf_format(format, file_path.as_deref())?; let format = lookup_rdf_format(format, file_path.as_deref())?;
@ -642,7 +642,7 @@ impl PyQueryResultsFormat {
/// :type memo: typing.Any /// :type memo: typing.Any
/// :rtype: QueryResultsFormat /// :rtype: QueryResultsFormat
#[allow(unused_variables)] #[allow(unused_variables)]
fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ PyAny) -> PyRef<'a, Self> { fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ Bound<'_, PyAny>) -> PyRef<'a, Self> {
slf slf
} }
} }

@ -7,7 +7,7 @@ use crate::io::{
use crate::model::*; use crate::model::*;
use crate::sparql::*; use crate::sparql::*;
use oxigraph::io::RdfParser; use oxigraph::io::RdfParser;
use oxigraph::model::{GraphName, GraphNameRef}; use oxigraph::model::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::{PyRuntimeError, PyValueError}; use pyo3::exceptions::{PyRuntimeError, PyValueError};
@ -161,7 +161,7 @@ impl PyStore {
/// >>> 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'))])
/// >>> list(store) /// >>> list(store)
/// [<Quad subject=<NamedNode value=http://example.com> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>] /// [<Quad subject=<NamedNode value=http://example.com> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>]
fn extend(&self, quads: &PyAny, py: Python<'_>) -> PyResult<()> { fn extend(&self, quads: &Bound<'_, PyAny>, py: Python<'_>) -> PyResult<()> {
let quads = quads let quads = quads
.iter()? .iter()?
.map(|q| q?.extract()) .map(|q| q?.extract())
@ -187,7 +187,7 @@ impl PyStore {
/// >>> list(store) /// >>> list(store)
/// [<Quad subject=<NamedNode value=http://example.com> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>] /// [<Quad subject=<NamedNode value=http://example.com> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>]
#[cfg(not(target_family = "wasm"))] #[cfg(not(target_family = "wasm"))]
fn bulk_extend(&self, quads: &PyAny) -> PyResult<()> { fn bulk_extend(&self, quads: &Bound<'_, PyAny>) -> PyResult<()> {
self.inner self.inner
.bulk_loader() .bulk_loader()
.load_ok_quads::<PyErr, PythonOrStorageError>( .load_ok_quads::<PyErr, PythonOrStorageError>(
@ -234,24 +234,23 @@ impl PyStore {
/// >>> 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')))
/// >>> list(store.quads_for_pattern(NamedNode('http://example.com'), None, None, None)) /// >>> list(store.quads_for_pattern(NamedNode('http://example.com'), None, None, None))
/// [<Quad subject=<NamedNode value=http://example.com> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>] /// [<Quad subject=<NamedNode value=http://example.com> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>]
#[allow(clippy::needless_pass_by_value)]
#[pyo3(signature = (subject, predicate, object, graph_name = None))] #[pyo3(signature = (subject, predicate, object, graph_name = None))]
fn quads_for_pattern( fn quads_for_pattern(
&self, &self,
subject: &PyAny, subject: Option<PySubjectRef<'_>>,
predicate: &PyAny, predicate: Option<PyNamedNodeRef<'_>>,
object: &PyAny, object: Option<PyTermRef<'_>>,
graph_name: Option<&PyAny>, graph_name: Option<PyGraphNameRef<'_>>,
) -> PyResult<QuadIter> { ) -> QuadIter {
let (subject, predicate, object, graph_name) = QuadIter {
extract_quads_pattern(subject, predicate, object, graph_name)?;
Ok(QuadIter {
inner: self.inner.quads_for_pattern( inner: self.inner.quads_for_pattern(
subject.as_ref().map(Into::into), subject.as_ref().map(Into::into),
predicate.as_ref().map(Into::into), predicate.as_ref().map(Into::into),
object.as_ref().map(Into::into), object.as_ref().map(Into::into),
graph_name.as_ref().map(Into::into), graph_name.as_ref().map(Into::into),
), ),
}) }
} }
/// Executes a `SPARQL 1.1 query <https://www.w3.org/TR/sparql11-query/>`_. /// Executes a `SPARQL 1.1 query <https://www.w3.org/TR/sparql11-query/>`_.
@ -297,8 +296,8 @@ impl PyStore {
query: &str, query: &str,
base_iri: Option<&str>, base_iri: Option<&str>,
use_default_graph_as_union: bool, use_default_graph_as_union: bool,
default_graph: Option<&PyAny>, default_graph: Option<&Bound<'_, PyAny>>,
named_graphs: Option<&PyAny>, named_graphs: Option<&Bound<'_, PyAny>>,
py: Python<'_>, py: Python<'_>,
) -> PyResult<PyObject> { ) -> PyResult<PyObject> {
let query = parse_query( let query = parse_query(
@ -396,6 +395,7 @@ impl PyStore {
/// >>> store.load(input='<foo> <p> "1" .', format=RdfFormat.TURTLE, base_iri="http://example.com/", to_graph=NamedNode("http://example.com/g")) /// >>> store.load(input='<foo> <p> "1" .', format=RdfFormat.TURTLE, base_iri="http://example.com/", to_graph=NamedNode("http://example.com/g"))
/// >>> list(store) /// >>> list(store)
/// [<Quad subject=<NamedNode value=http://example.com/foo> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>] /// [<Quad subject=<NamedNode value=http://example.com/foo> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>]
#[allow(clippy::needless_pass_by_value)]
#[pyo3(signature = (input = None, format = None, *, path = None, base_iri = None, to_graph = None))] #[pyo3(signature = (input = None, format = None, *, path = None, base_iri = None, to_graph = None))]
fn load( fn load(
&self, &self,
@ -403,14 +403,10 @@ impl PyStore {
format: Option<PyRdfFormatInput>, format: Option<PyRdfFormatInput>,
path: Option<PathBuf>, path: Option<PathBuf>,
base_iri: Option<&str>, base_iri: Option<&str>,
to_graph: Option<&PyAny>, to_graph: Option<PyGraphNameRef<'_>>,
py: Python<'_>, py: Python<'_>,
) -> PyResult<()> { ) -> PyResult<()> {
let to_graph_name = if let Some(graph_name) = to_graph { let to_graph_name = to_graph.as_ref().map(GraphNameRef::from);
Some(GraphName::from(&PyGraphNameRef::try_from(graph_name)?))
} else {
None
};
let input = PyReadable::from_args(&path, input, py)?; let input = PyReadable::from_args(&path, input, py)?;
let format = lookup_rdf_format(format, path.as_deref())?; let format = lookup_rdf_format(format, path.as_deref())?;
py.allow_threads(|| { py.allow_threads(|| {
@ -468,6 +464,7 @@ impl PyStore {
/// >>> store.bulk_load(input=b'<foo> <p> "1" .', format=RdfFormat.TURTLE, base_iri="http://example.com/", to_graph=NamedNode("http://example.com/g")) /// >>> store.bulk_load(input=b'<foo> <p> "1" .', format=RdfFormat.TURTLE, base_iri="http://example.com/", to_graph=NamedNode("http://example.com/g"))
/// >>> list(store) /// >>> list(store)
/// [<Quad subject=<NamedNode value=http://example.com/foo> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>] /// [<Quad subject=<NamedNode value=http://example.com/foo> predicate=<NamedNode value=http://example.com/p> object=<Literal value=1 datatype=<NamedNode value=http://www.w3.org/2001/XMLSchema#string>> graph_name=<NamedNode value=http://example.com/g>>]
#[allow(clippy::needless_pass_by_value)]
#[pyo3(signature = (input = None, format = None, *, path = None, base_iri = None, to_graph = None))] #[pyo3(signature = (input = None, format = None, *, path = None, base_iri = None, to_graph = None))]
fn bulk_load( fn bulk_load(
&self, &self,
@ -475,14 +472,10 @@ impl PyStore {
format: Option<PyRdfFormatInput>, format: Option<PyRdfFormatInput>,
path: Option<PathBuf>, path: Option<PathBuf>,
base_iri: Option<&str>, base_iri: Option<&str>,
to_graph: Option<&PyAny>, to_graph: Option<PyGraphNameRef<'_>>,
py: Python<'_>, py: Python<'_>,
) -> PyResult<()> { ) -> PyResult<()> {
let to_graph_name = if let Some(graph_name) = to_graph { let to_graph_name = to_graph.as_ref().map(GraphNameRef::from);
Some(GraphName::from(&PyGraphNameRef::try_from(graph_name)?))
} else {
None
};
let input = PyReadable::from_args(&path, input, py)?; let input = PyReadable::from_args(&path, input, py)?;
let format = lookup_rdf_format(format, path.as_deref())?; let format = lookup_rdf_format(format, path.as_deref())?;
py.allow_threads(|| { py.allow_threads(|| {
@ -539,24 +532,21 @@ impl PyStore {
/// >>> store.dump(output, RdfFormat.TURTLE, from_graph=NamedNode("http://example.com/g")) /// >>> store.dump(output, RdfFormat.TURTLE, from_graph=NamedNode("http://example.com/g"))
/// >>> output.getvalue() /// >>> output.getvalue()
/// b'<http://example.com> <http://example.com/p> "1" .\n' /// b'<http://example.com> <http://example.com/p> "1" .\n'
#[allow(clippy::needless_pass_by_value)]
#[pyo3(signature = (output = None, format = None, *, from_graph = None))] #[pyo3(signature = (output = None, format = None, *, from_graph = None))]
fn dump<'a>( fn dump<'py>(
&self, &self,
output: Option<PyWritableOutput>, output: Option<PyWritableOutput>,
format: Option<PyRdfFormatInput>, format: Option<PyRdfFormatInput>,
from_graph: Option<&PyAny>, from_graph: Option<PyGraphNameRef<'_>>,
py: Python<'a>, py: Python<'py>,
) -> PyResult<Option<&'a PyBytes>> { ) -> PyResult<Option<Bound<'py, PyBytes>>> {
let from_graph_name = if let Some(graph_name) = from_graph { let from_graph_name = from_graph.as_ref().map(GraphNameRef::from);
Some(GraphName::from(&PyGraphNameRef::try_from(graph_name)?))
} else {
None
};
PyWritable::do_write( PyWritable::do_write(
|output, file_path| { |output, file_path| {
py.allow_threads(|| { py.allow_threads(|| {
let format = lookup_rdf_format(format, file_path.as_deref())?; let format = lookup_rdf_format(format, file_path.as_deref())?;
if let Some(from_graph_name) = &from_graph_name { if let Some(from_graph_name) = from_graph_name {
self.inner self.inner
.dump_graph_to_write(from_graph_name, format, output) .dump_graph_to_write(from_graph_name, format, output)
} else { } else {
@ -597,14 +587,21 @@ impl PyStore {
/// >>> store.add_graph(NamedNode('http://example.com/g')) /// >>> store.add_graph(NamedNode('http://example.com/g'))
/// >>> store.contains_named_graph(NamedNode('http://example.com/g')) /// >>> store.contains_named_graph(NamedNode('http://example.com/g'))
/// True /// True
fn contains_named_graph(&self, graph_name: &PyAny) -> PyResult<bool> { #[allow(clippy::needless_pass_by_value)]
let graph_name = GraphName::from(&PyGraphNameRef::try_from(graph_name)?); fn contains_named_graph(
match graph_name { &self,
GraphName::DefaultGraph => Ok(true), graph_name: PyGraphNameRef<'_>,
GraphName::NamedNode(graph_name) => self.inner.contains_named_graph(&graph_name), py: Python<'_>,
GraphName::BlankNode(graph_name) => self.inner.contains_named_graph(&graph_name), ) -> PyResult<bool> {
} let graph_name = GraphNameRef::from(&graph_name);
.map_err(map_storage_error) py.allow_threads(|| {
match graph_name {
GraphNameRef::DefaultGraph => Ok(true),
GraphNameRef::NamedNode(graph_name) => self.inner.contains_named_graph(graph_name),
GraphNameRef::BlankNode(graph_name) => self.inner.contains_named_graph(graph_name),
}
.map_err(map_storage_error)
})
} }
/// Adds a named graph to the store. /// Adds a named graph to the store.
@ -618,16 +615,17 @@ impl PyStore {
/// >>> store.add_graph(NamedNode('http://example.com/g')) /// >>> store.add_graph(NamedNode('http://example.com/g'))
/// >>> list(store.named_graphs()) /// >>> list(store.named_graphs())
/// [<NamedNode value=http://example.com/g>] /// [<NamedNode value=http://example.com/g>]
fn add_graph(&self, graph_name: &PyAny, py: Python<'_>) -> PyResult<()> { #[allow(clippy::needless_pass_by_value)]
let graph_name = GraphName::from(&PyGraphNameRef::try_from(graph_name)?); fn add_graph(&self, graph_name: PyGraphNameRef<'_>, py: Python<'_>) -> PyResult<()> {
let graph_name = GraphNameRef::from(&graph_name);
py.allow_threads(|| { py.allow_threads(|| {
match graph_name { match graph_name {
GraphName::DefaultGraph => Ok(()), GraphNameRef::DefaultGraph => Ok(()),
GraphName::NamedNode(graph_name) => { GraphNameRef::NamedNode(graph_name) => {
self.inner.insert_named_graph(&graph_name).map(|_| ()) self.inner.insert_named_graph(graph_name).map(|_| ())
} }
GraphName::BlankNode(graph_name) => { GraphNameRef::BlankNode(graph_name) => {
self.inner.insert_named_graph(&graph_name).map(|_| ()) self.inner.insert_named_graph(graph_name).map(|_| ())
} }
} }
.map_err(map_storage_error) .map_err(map_storage_error)
@ -648,11 +646,12 @@ impl PyStore {
/// [] /// []
/// >>> list(store.named_graphs()) /// >>> list(store.named_graphs())
/// [<NamedNode value=http://example.com/g>] /// [<NamedNode value=http://example.com/g>]
fn clear_graph(&self, graph_name: &PyAny, py: Python<'_>) -> PyResult<()> { #[allow(clippy::needless_pass_by_value)]
let graph_name = GraphName::from(&PyGraphNameRef::try_from(graph_name)?); fn clear_graph(&self, graph_name: PyGraphNameRef<'_>, py: Python<'_>) -> PyResult<()> {
let graph_name = GraphNameRef::from(&graph_name);
py.allow_threads(|| { py.allow_threads(|| {
self.inner self.inner
.clear_graph(&graph_name) .clear_graph(graph_name)
.map_err(map_storage_error) .map_err(map_storage_error)
}) })
} }
@ -671,16 +670,17 @@ impl PyStore {
/// >>> store.remove_graph(NamedNode('http://example.com/g')) /// >>> store.remove_graph(NamedNode('http://example.com/g'))
/// >>> list(store.named_graphs()) /// >>> list(store.named_graphs())
/// [] /// []
fn remove_graph(&self, graph_name: &PyAny, py: Python<'_>) -> PyResult<()> { #[allow(clippy::needless_pass_by_value)]
let graph_name = GraphName::from(&PyGraphNameRef::try_from(graph_name)?); fn remove_graph(&self, graph_name: PyGraphNameRef<'_>, py: Python<'_>) -> PyResult<()> {
let graph_name = GraphNameRef::from(&graph_name);
py.allow_threads(|| { py.allow_threads(|| {
match graph_name { match graph_name {
GraphName::DefaultGraph => self.inner.clear_graph(GraphNameRef::DefaultGraph), GraphNameRef::DefaultGraph => self.inner.clear_graph(GraphNameRef::DefaultGraph),
GraphName::NamedNode(graph_name) => { GraphNameRef::NamedNode(graph_name) => {
self.inner.remove_named_graph(&graph_name).map(|_| ()) self.inner.remove_named_graph(graph_name).map(|_| ())
} }
GraphName::BlankNode(graph_name) => { GraphNameRef::BlankNode(graph_name) => {
self.inner.remove_named_graph(&graph_name).map(|_| ()) self.inner.remove_named_graph(graph_name).map(|_| ())
} }
} }
.map_err(map_storage_error) .map_err(map_storage_error)
@ -816,45 +816,6 @@ impl GraphNameIter {
} }
} }
pub fn extract_quads_pattern<'a>(
subject: &'a PyAny,
predicate: &'a PyAny,
object: &'a PyAny,
graph_name: Option<&'a PyAny>,
) -> PyResult<(
Option<PySubjectRef<'a>>,
Option<PyNamedNodeRef<'a>>,
Option<PyTermRef<'a>>,
Option<PyGraphNameRef<'a>>,
)> {
Ok((
if subject.is_none() {
None
} else {
Some(TryFrom::try_from(subject)?)
},
if predicate.is_none() {
None
} else {
Some(TryFrom::try_from(predicate)?)
},
if object.is_none() {
None
} else {
Some(TryFrom::try_from(object)?)
},
if let Some(graph_name) = graph_name {
if graph_name.is_none() {
None
} else {
Some(TryFrom::try_from(graph_name)?)
}
} else {
None
},
))
}
pub fn map_storage_error(error: StorageError) -> PyErr { pub fn map_storage_error(error: StorageError) -> PyErr {
match error { match error {
StorageError::Io(error) => error.into(), StorageError::Io(error) => error.into(),

Loading…
Cancel
Save