diff --git a/.gitmodules b/.gitmodules
index fba23723..f9da0706 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -7,9 +7,6 @@
[submodule "bench/bsbm-tools"]
path = bench/bsbm-tools
url = https://github.com/Tpt/bsbm-tools.git
-[submodule "oxrocksdb-sys/rocksdb"]
- path = oxrocksdb-sys/rocksdb
- url = https://github.com/oxigraph/rocksdb.git
[submodule "oxrocksdb-sys/lz4"]
path = oxrocksdb-sys/lz4
url = https://github.com/lz4/lz4.git
diff --git a/Cargo.lock b/Cargo.lock
index 2b579b9a..1748576d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -154,17 +154,16 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "bindgen"
-version = "0.69.4"
+version = "0.65.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
+checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5"
dependencies = [
- "bitflags 2.5.0",
+ "bitflags 1.3.2",
"cexpr",
"clang-sys",
- "itertools 0.12.1",
"lazy_static",
"lazycell",
- "log",
+ "peeking_take_while",
"prettyplease",
"proc-macro2",
"quote",
@@ -172,7 +171,6 @@ dependencies = [
"rustc-hash",
"shlex",
"syn",
- "which",
]
[[package]]
@@ -219,6 +217,17 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
+[[package]]
+name = "bzip2-sys"
+version = "0.1.11+1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+]
+
[[package]]
name = "cast"
version = "0.3.0"
@@ -316,7 +325,7 @@ version = "4.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f"
dependencies = [
- "heck 0.5.0",
+ "heck",
"proc-macro2",
"quote",
"syn",
@@ -422,7 +431,7 @@ dependencies = [
"clap",
"criterion-plot",
"is-terminal",
- "itertools 0.10.5",
+ "itertools",
"num-traits",
"once_cell",
"oorandom",
@@ -443,7 +452,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
dependencies = [
"cast",
- "itertools 0.10.5",
+ "itertools",
]
[[package]]
@@ -672,12 +681,6 @@ dependencies = [
"crunchy",
]
-[[package]]
-name = "heck"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
-
[[package]]
name = "heck"
version = "0.5.0"
@@ -696,15 +699,6 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-[[package]]
-name = "home"
-version = "0.5.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
-dependencies = [
- "windows-sys 0.52.0",
-]
-
[[package]]
name = "httparse"
version = "1.8.0"
@@ -737,12 +731,6 @@ dependencies = [
"winapi-util",
]
-[[package]]
-name = "indoc"
-version = "2.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
-
[[package]]
name = "is-terminal"
version = "0.4.12"
@@ -763,15 +751,6 @@ dependencies = [
"either",
]
-[[package]]
-name = "itertools"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
-dependencies = [
- "either",
-]
-
[[package]]
name = "itoa"
version = "1.0.10"
@@ -844,21 +823,37 @@ dependencies = [
]
[[package]]
-name = "linux-raw-sys"
-version = "0.4.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+name = "librocksdb-sys"
+version = "0.11.0+8.3.2"
+source = "git+https://git.nextgraph.org/NextGraph/rust-rocksdb.git?branch=master#cedbf494b4ec11638f1e0b7446731e0b73573352"
+dependencies = [
+ "bindgen",
+ "bzip2-sys",
+ "cc",
+ "glob",
+ "libc",
+ "libz-sys",
+ "openssl",
+ "pkg-config",
+]
[[package]]
-name = "lock_api"
-version = "0.4.11"
+name = "libz-sys"
+version = "1.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
+checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9"
dependencies = [
- "autocfg",
- "scopeguard",
+ "cc",
+ "pkg-config",
+ "vcpkg",
]
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+
[[package]]
name = "log"
version = "0.4.21"
@@ -881,15 +876,6 @@ version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
-[[package]]
-name = "memoffset"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
-dependencies = [
- "autocfg",
-]
-
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@@ -1007,6 +993,15 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+[[package]]
+name = "openssl-src"
+version = "300.2.3+3.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5cff92b6f71555b61bb9315f7c64da3ca43d87531622120fea0195fc761b4843"
+dependencies = [
+ "cc",
+]
+
[[package]]
name = "openssl-sys"
version = "0.9.101"
@@ -1015,6 +1010,7 @@ checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff"
dependencies = [
"cc",
"libc",
+ "openssl-src",
"pkg-config",
"vcpkg",
]
@@ -1052,10 +1048,10 @@ dependencies = [
"oxiri",
"oxrdf",
"oxrdfio",
- "oxrocksdb-sys",
"oxsdatatypes",
"rand",
"regex",
+ "rocksdb",
"sha1",
"sha2",
"siphasher",
@@ -1158,16 +1154,6 @@ dependencies = [
"tokio",
]
-[[package]]
-name = "oxrocksdb-sys"
-version = "0.4.0-alpha.7-dev"
-dependencies = [
- "bindgen",
- "cc",
- "libc",
- "pkg-config",
-]
-
[[package]]
name = "oxsdatatypes"
version = "0.2.0-alpha.1"
@@ -1189,27 +1175,10 @@ dependencies = [
]
[[package]]
-name = "parking_lot"
-version = "0.12.1"
+name = "peeking_take_while"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
-dependencies = [
- "lock_api",
- "parking_lot_core",
-]
-
-[[package]]
-name = "parking_lot_core"
-version = "0.9.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
-dependencies = [
- "cfg-if",
- "libc",
- "redox_syscall",
- "smallvec",
- "windows-targets 0.48.5",
-]
+checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "peg"
@@ -1284,12 +1253,6 @@ dependencies = [
"plotters-backend",
]
-[[package]]
-name = "portable-atomic"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
-
[[package]]
name = "powerfmt"
version = "0.2.0"
@@ -1351,77 +1314,6 @@ dependencies = [
"unicode-ident",
]
-[[package]]
-name = "pyo3"
-version = "0.21.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a02a88a17e74cadbc8ce77855e1d6c8ad0ab82901a4a9b5046bd01c1c0bd95cd"
-dependencies = [
- "cfg-if",
- "indoc",
- "libc",
- "memoffset",
- "parking_lot",
- "portable-atomic",
- "pyo3-build-config",
- "pyo3-ffi",
- "pyo3-macros",
- "unindent",
-]
-
-[[package]]
-name = "pyo3-build-config"
-version = "0.21.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5eb0b6ecba38961f6f4bd6cd5906dfab3cd426ff37b2eed5771006aa31656f1"
-dependencies = [
- "once_cell",
- "target-lexicon",
-]
-
-[[package]]
-name = "pyo3-ffi"
-version = "0.21.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba8a6e48a29b5d22e4fdaf132d8ba8d3203ee9f06362d48f244346902a594ec3"
-dependencies = [
- "libc",
- "pyo3-build-config",
-]
-
-[[package]]
-name = "pyo3-macros"
-version = "0.21.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e80493c5965f94a747d0782a607b2328a4eea5391327b152b00e2f3b001cede"
-dependencies = [
- "proc-macro2",
- "pyo3-macros-backend",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "pyo3-macros-backend"
-version = "0.21.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcd7d86f42004025200e12a6a8119bd878329e6fddef8178eaafa4e4b5906c5b"
-dependencies = [
- "heck 0.4.1",
- "proc-macro2",
- "pyo3-build-config",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "pyoxigraph"
-version = "0.4.0-alpha.7-dev"
-dependencies = [
- "oxigraph",
- "pyo3",
-]
-
[[package]]
name = "quick-xml"
version = "0.31.0"
@@ -1491,15 +1383,6 @@ dependencies = [
"crossbeam-utils",
]
-[[package]]
-name = "redox_syscall"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
-dependencies = [
- "bitflags 1.3.2",
-]
-
[[package]]
name = "regex"
version = "1.10.4"
@@ -1544,6 +1427,15 @@ dependencies = [
"windows-sys 0.52.0",
]
+[[package]]
+name = "rocksdb"
+version = "0.21.0"
+source = "git+https://git.nextgraph.org/NextGraph/rust-rocksdb.git?branch=master#cedbf494b4ec11638f1e0b7446731e0b73573352"
+dependencies = [
+ "libc",
+ "librocksdb-sys",
+]
+
[[package]]
name = "rustc-demangle"
version = "0.1.23"
@@ -1647,12 +1539,6 @@ dependencies = [
"windows-sys 0.52.0",
]
-[[package]]
-name = "scopeguard"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
-
[[package]]
name = "security-framework"
version = "2.9.2"
@@ -1741,12 +1627,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
-[[package]]
-name = "smallvec"
-version = "1.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
-
[[package]]
name = "sparesults"
version = "0.2.0-alpha.4"
@@ -1816,12 +1696,6 @@ dependencies = [
"unicode-ident",
]
-[[package]]
-name = "target-lexicon"
-version = "0.12.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
-
[[package]]
name = "tempfile"
version = "3.10.1"
@@ -1992,12 +1866,6 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
-[[package]]
-name = "unindent"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
-
[[package]]
name = "untrusted"
version = "0.9.0"
@@ -2131,18 +1999,6 @@ dependencies = [
"rustls-pki-types",
]
-[[package]]
-name = "which"
-version = "4.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
-dependencies = [
- "either",
- "home",
- "once_cell",
- "rustix",
-]
-
[[package]]
name = "winapi"
version = "0.2.8"
diff --git a/Cargo.toml b/Cargo.toml
index 8e9e1205..a88c8e25 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,8 +12,6 @@ members = [
"lib/spargebra",
"lib/sparopt",
"lib/sparql-smith",
- "oxrocksdb-sys",
- "python",
"testsuite"
]
resolver = "2"
@@ -71,7 +69,6 @@ oxigraph = { version = "=0.4.0-alpha.7-dev", path = "lib/oxigraph" }
oxrdf = { version = "=0.2.0-alpha.4", path = "lib/oxrdf" }
oxrdfio = { version = "=0.1.0-alpha.5", path = "lib/oxrdfio" }
oxrdfxml = { version = "=0.1.0-alpha.5", path = "lib/oxrdfxml" }
-oxrocksdb-sys = { version = "=0.4.0-alpha.7-dev", path = "./oxrocksdb-sys" }
oxsdatatypes = { version = "=0.2.0-alpha.1", path = "lib/oxsdatatypes" }
oxttl = { version = "=0.1.0-alpha.5", path = "lib/oxttl" }
sparesults = { version = "=0.2.0-alpha.4", path = "lib/sparesults" }
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index c2ebf2ec..5560844f 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -20,9 +20,8 @@ path = "src/main.rs"
doc = false
[features]
-default = ["native-tls"]
+default = []
native-tls = ["oxigraph/http-client-native-tls"]
-rocksdb-pkg-config = ["oxigraph/rocksdb-pkg-config"]
rustls-native = ["oxigraph/http-client-rustls-native"]
rustls-webpki = ["oxigraph/http-client-rustls-webpki"]
diff --git a/lib/oxigraph/Cargo.toml b/lib/oxigraph/Cargo.toml
index 68b59dee..ac619163 100644
--- a/lib/oxigraph/Cargo.toml
+++ b/lib/oxigraph/Cargo.toml
@@ -17,13 +17,12 @@ rust-version.workspace = true
[features]
default = ["rocksdb"]
-rocksdb = ["oxrocksdb-sys"]
+rocksdb = ["dep:rocksdb"]
js = ["getrandom/js", "oxsdatatypes/js", "js-sys"]
http-client = ["oxhttp"]
http-client-native-tls = ["http-client", "oxhttp/native-tls"]
http-client-rustls-webpki = ["http-client", "oxhttp/rustls-ring-webpki"]
http-client-rustls-native = ["http-client", "oxhttp/rustls-ring-native"]
-rocksdb-pkg-config = ["oxrocksdb-sys/pkg-config"]
rocksdb-debug = []
[dependencies]
@@ -49,7 +48,7 @@ thiserror.workspace = true
[target.'cfg(not(target_family = "wasm"))'.dependencies]
libc.workspace = true
oxhttp = { workspace = true, optional = true }
-oxrocksdb-sys = { workspace = true, optional = true }
+rocksdb = {git = "https://git.nextgraph.org/NextGraph/rust-rocksdb.git", branch = "master", features = [ ], optional = true }
[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
getrandom.workspace = true
diff --git a/lib/oxigraph/src/model.rs b/lib/oxigraph/src/model.rs
index 3a9fd053..dbca934b 100644
--- a/lib/oxigraph/src/model.rs
+++ b/lib/oxigraph/src/model.rs
@@ -18,3 +18,5 @@
//! ```
pub use oxrdf::*;
+
+pub use spargebra::term::GroundQuad;
diff --git a/lib/oxigraph/src/storage/backend/mod.rs b/lib/oxigraph/src/storage/backend/mod.rs
index 0fc4f90f..db2ebd5f 100644
--- a/lib/oxigraph/src/storage/backend/mod.rs
+++ b/lib/oxigraph/src/storage/backend/mod.rs
@@ -4,9 +4,9 @@
#[cfg(any(target_family = "wasm", not(feature = "rocksdb")))]
pub use fallback::{ColumnFamily, ColumnFamilyDefinition, Db, Iter, Reader, Transaction};
#[cfg(all(not(target_family = "wasm"), feature = "rocksdb"))]
-pub use rocksdb::{ColumnFamily, ColumnFamilyDefinition, Db, Iter, Reader, Transaction};
+pub use oxi_rocksdb::{ColumnFamily, ColumnFamilyDefinition, Db, Iter, Reader, Transaction};
#[cfg(any(target_family = "wasm", not(feature = "rocksdb")))]
mod fallback;
#[cfg(all(not(target_family = "wasm"), feature = "rocksdb"))]
-mod rocksdb;
+mod oxi_rocksdb;
diff --git a/lib/oxigraph/src/storage/backend/rocksdb.rs b/lib/oxigraph/src/storage/backend/oxi_rocksdb.rs
similarity index 99%
rename from lib/oxigraph/src/storage/backend/rocksdb.rs
rename to lib/oxigraph/src/storage/backend/oxi_rocksdb.rs
index b665401b..0f194a6e 100644
--- a/lib/oxigraph/src/storage/backend/rocksdb.rs
+++ b/lib/oxigraph/src/storage/backend/oxi_rocksdb.rs
@@ -10,8 +10,8 @@
use crate::storage::error::{CorruptionError, StorageError};
use libc::c_void;
-use oxrocksdb_sys::*;
use rand::random;
+use rocksdb::ffi::*;
use std::borrow::Borrow;
#[cfg(unix)]
use std::cmp::min;
diff --git a/oxrocksdb-sys/rocksdb b/oxrocksdb-sys/rocksdb
deleted file mode 160000
index aecd720a..00000000
--- a/oxrocksdb-sys/rocksdb
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit aecd720a5fc2bf7eae9649265a017b68605a8c87
diff --git a/python/Cargo.toml b/python/Cargo.toml
deleted file mode 100644
index e1abf1be..00000000
--- a/python/Cargo.toml
+++ /dev/null
@@ -1,38 +0,0 @@
-[package]
-name = "pyoxigraph"
-version.workspace = true
-authors.workspace = true
-license.workspace = true
-readme = "README.md"
-keywords = ["RDF", "SPARQL", "graph-database", "database"]
-repository = "https://github.com/oxigraph/oxigraph/tree/main/python"
-homepage = "https://pyoxigraph.readthedocs.io/"
-description = "Python bindings of Oxigraph, a SPARQL database and RDF toolkit"
-edition.workspace = true
-rust-version.workspace = true
-publish = false
-
-[lib]
-crate-type = ["cdylib"]
-name = "pyoxigraph"
-doctest = false
-doc = false
-
-[features]
-abi3 = ["pyo3/abi3-py38"]
-rocksdb-pkg-config = ["oxigraph/rocksdb-pkg-config"]
-
-[dependencies]
-pyo3 = { workspace = true, features = ["extension-module"] }
-
-[target.'cfg(any(target_family = "windows", target_os = "macos", target_os = "ios"))'.dependencies]
-oxigraph = { workspace = true, features = ["http-client-native-tls"] }
-
-[target.'cfg(target_family = "wasm")'.dependencies]
-oxigraph.workspace = true
-
-[target.'cfg(not(any(target_family = "windows", target_os = "macos", target_os = "ios", target_family = "wasm")))'.dependencies]
-oxigraph = { workspace = true, features = ["http-client-rustls-native"] }
-
-[lints]
-workspace = true
diff --git a/python/README.md b/python/README.md
deleted file mode 100644
index d9fae275..00000000
--- a/python/README.md
+++ /dev/null
@@ -1,83 +0,0 @@
-# Pyoxigraph (Oxigraph for Python)
-
-[![PyPI](https://img.shields.io/pypi/v/pyoxigraph)](https://pypi.org/project/pyoxigraph/)
-[![Conda](https://img.shields.io/conda/vn/conda-forge/pyoxigraph)](https://anaconda.org/conda-forge/pyoxigraph)
-![PyPI - Implementation](https://img.shields.io/pypi/implementation/pyoxigraph)
-![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyoxigraph)
-[![actions status](https://github.com/oxigraph/oxigraph/workflows/build/badge.svg)](https://github.com/oxigraph/oxigraph/actions)
-[![Gitter](https://badges.gitter.im/oxigraph/community.svg)](https://gitter.im/oxigraph/community)
-
-Pyoxigraph is a graph database library implementing the [SPARQL](https://www.w3.org/TR/sparql11-overview/) standard.
-It is a Python library written on top of [Oxigraph](https://crates.io/crates/oxigraph).
-
-Pyoxigraph offers two stores with [SPARQL 1.1](https://www.w3.org/TR/sparql11-overview/) capabilities.
-One of the store is in-memory, and the other one is disk based.
-
-It also provides a set of utility functions for reading, writing and processing RDF files in
-[Turtle](https://www.w3.org/TR/turtle/),
-[TriG](https://www.w3.org/TR/trig/),
-[N-Triples](https://www.w3.org/TR/n-triples/),
-[N-Quads](https://www.w3.org/TR/n-quads/) and
-[RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/).
-
-Pyoxigraph is distributed [on Pypi](https://pypi.org/project/pyoxigraph/) and [on conda-forge](https://anaconda.org/conda-forge/pyoxigraph).
-Run `pip install pyoxigraph` to install it.
-
-There exists also a small library providing [rdflib](https://rdflib.readthedocs.io) stores using pyoxigraph: [oxrdflib](https://github.com/oxigraph/oxrdflib).
-
-Pyoxigraph documentation is [available on the Oxigraph website](https://pyoxigraph.readthedocs.io/).
-
-## Build the development version
-
-To build and install the development version of pyoxigraph you need to clone this git repository including submodules (`git clone --recursive https://github.com/oxigraph/oxigraph.git`)
-and to run `pip install .` in the `python` directory (the one this README is in).
-
-Note that by default the installation will not use [cpython stable ABI](https://docs.python.org/3/c-api/stable.html).
-Use `--features abi3` feature to use cpython stable ABI.
-
-## Help
-
-Feel free to use [GitHub discussions](https://github.com/oxigraph/oxigraph/discussions) or [the Gitter chat](https://gitter.im/oxigraph/community) to ask questions or talk about Oxigraph.
-[Bug reports](https://github.com/oxigraph/oxigraph/issues) are also very welcome.
-
-If you need advanced support or are willing to pay to get some extra features, feel free to reach out to [Tpt](https://github.com/Tpt).
-
-## How to contribute
-
-Pyoxigraph is written in Rust using [PyO3](https://github.com/PyO3/pyo3).
-
-Pyoxigraph is built using [Maturin](https://github.com/PyO3/maturin).
-Maturin could be installed using the `pip install 'maturin>=0.9,<0.10'`.
-To install a development version of Oxigraph just run `maturin develop` in this README directory.
-
-### Tests
-
-The Python bindings tests are written in Python.
-To run them use `python -m unittest` in the `tests` directory.
-
-### Docs
-
-The Sphinx documentation can be generated and viewed in the browser using the following command:
-
-```
-sphinx-autobuild docs docs/_build/html
-```
-
-Note that you will need to have [sphinx-autobuild](https://pypi.org/project/sphinx-autobuild/) installed.
-
-Alternatively, you can use `sphinx-build` with Python's `http.server` to achieve the same thing.
-
-## License
-
-This project is licensed under either of
-
-- Apache License, Version 2.0, ([LICENSE-APACHE](../LICENSE-APACHE) or
- http://www.apache.org/licenses/LICENSE-2.0)
-- MIT license ([LICENSE-MIT](../LICENSE-MIT) or
- http://opensource.org/licenses/MIT)
-
-at your option.
-
-### Contribution
-
-Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Oxigraph by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
diff --git a/python/docs/conf.py b/python/docs/conf.py
deleted file mode 100644
index 007e6426..00000000
--- a/python/docs/conf.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import datetime
-import sys
-from pathlib import Path
-
-import pyoxigraph
-
-sys.path.insert(0, str(Path(__file__).parent.parent.absolute()))
-
-# -- Project information -----------------------------------------------------
-
-project = "pyoxigraph"
-copyright = f"{datetime.date.today().year}, Oxigraph contributors"
-author = pyoxigraph.__author__
-version = pyoxigraph.__version__
-release = pyoxigraph.__version__
-
-# -- General configuration ---------------------------------------------------
-
-extensions = ["sphinx.ext.autodoc", "sphinx.ext.doctest", "sphinx.ext.intersphinx"]
-
-exclude_patterns = ["build", "Thumbs.db", ".DS_Store"]
-
-# -- Options for HTML output -------------------------------------------------
-
-html_theme = "furo"
-html_static_path = []
-html_logo = "../../logo.svg"
-html_favicon = "../../logo.svg"
-html_theme_options = {"body_max_width": None}
-html_baseurl = "https://pyoxigraph.readthedocs.io/en/stable/"
-
-# -- Options for doctests -------------------------------------------------
-
-doctest_global_setup = "from pyoxigraph import *\nimport io"
-
-# -- Options for intersphinx -------------------------------------------------
-
-intersphinx_mapping = {"python": ("https://docs.python.org/3", None)}
diff --git a/python/docs/index.rst b/python/docs/index.rst
deleted file mode 100644
index 47ba57d2..00000000
--- a/python/docs/index.rst
+++ /dev/null
@@ -1,79 +0,0 @@
-pyoxigraph |release|
-====================
-
-.. image:: https://img.shields.io/pypi/v/pyoxigraph
- :alt: PyPI
- :target: https://pypi.org/project/pyoxigraph/
-.. image:: https://img.shields.io/conda/vn/conda-forge/pyoxigraph
- :alt: conda-forge
- :target: https://anaconda.org/conda-forge/pyoxigraph
-.. image:: https://img.shields.io/pypi/implementation/pyoxigraph
- :alt: PyPI - Implementation
-.. image:: https://img.shields.io/pypi/pyversions/pyoxigraph
- :alt: PyPI - Python Version
-.. image:: https://img.shields.io/pypi/l/pyoxigraph
- :alt: PyPI - License
-
-
-Pyoxigraph is a Python graph database library implementing the `SPARQL `_ standard.
-
-It is built on top of `Oxigraph `_ using `PyO3 `_.
-
-It also provides a set of utility functions for reading, writing, and processing RDF files in
-`Turtle `_,
-`TriG `_,
-`N-Triples `_,
-`N-Quads `_ and
-`RDF/XML `_.
-
-Pyoxigraph is distributed `on Pypi `_ and `on conda-forge `_.
-
-There is also a small library providing a `rdflib `_ store using pyoxigraph: `oxrdflib `_.
-
-Oxigraph and pyoxigraph source code are on `GitHub `_.
-
-
-Installation
-""""""""""""
-
-Pyoxigraph is distributed on `Pypi `_.
-
-To install it, run the usual ``pip install pyoxigraph``
-
-
-Example
-"""""""
-
-Insert the triple `` "example"`` and print the name of ```` in SPARQL:
-
-::
-
- from pyoxigraph import *
-
- store = Store()
- ex = NamedNode('http://example/')
- schema_name = NamedNode('http://schema.org/name')
- store.add(Quad(ex, schema_name, Literal('example')))
- for binding in store.query('SELECT ?name WHERE { ?name }'):
- print(binding['name'].value)
-
-
-Table of contents
-"""""""""""""""""
-
-.. toctree::
-
- model
- io
- store
- sparql
- migration
-
-
-Help
-""""
-
-Feel free to use `GitHub discussions `_ or `the Gitter chat `_ to ask questions or talk about Oxigraph.
-`Bug reports `_ are also very welcome.
-
-If you need advanced support or are willing to pay to get some extra features, feel free to reach out to `Tpt `_.
diff --git a/python/docs/io.rst b/python/docs/io.rst
deleted file mode 100644
index edf3fba0..00000000
--- a/python/docs/io.rst
+++ /dev/null
@@ -1,21 +0,0 @@
-RDF Parsing and Serialization
-=============================
-.. py:currentmodule:: pyoxigraph
-
-Oxigraph provides functions to parse and serialize RDF files:
-
-
-Parsing
-"""""""
-.. autofunction:: parse
-
-
-Serialization
-"""""""""""""
-.. autofunction:: serialize
-
-
-Formats
-"""""""
-.. autoclass:: RdfFormat
- :members:
diff --git a/python/docs/migration.rst b/python/docs/migration.rst
deleted file mode 100644
index 3fe44d80..00000000
--- a/python/docs/migration.rst
+++ /dev/null
@@ -1,47 +0,0 @@
-Migration Guide
-===============
-
-From 0.3 to 0.4
-"""""""""""""""
-
-* Python 3.7 and ``musllinux_1_1`` support have been removed.
-* :py:class:`OSError` is now raised instead of :py:class:`IOError` on OS errors.
-* The ``mime_type`` parameter have been renamed to ``format`` in I/O functions.
- Using :py:class:`RdfFormat` is recommended to describe formats.
-* Boolean SPARQL results are now encoded with the :py:class:`QueryBoolean` class and not a simple :py:class:`bool`.
-* A `path` parameter has been added to all I/O method to read from a file.
- The existing ``input`` parameter now consider :py:class:`str` values to be a serialization to parse.
- For example, ``parse(path="foo.ttl")`` will parse the file ``foo.ttl`` whereas ``parse("foo", format=RdfFormat.N_TRIPLES)`` will parse a N-Triples file which content is ``foo``.
-
-
-From 0.2 to 0.3
-"""""""""""""""
-
-* Python 3.6 and ``manylinux2010`` (`PEP 571 `_) support have been removed. The new minimal versions are Python 3.7 and ``manylinux2014`` (`PEP 599 `_).
-* The on-disk storage system has been rebuilt on top of `RocksDB `_.
- It is now implemented by the :py:class:`.Store` class that keeps the same API as the late :py:class:`.SledStore` class.
-
- To migrate you have to dump the store content using pyoxigraph **0.2** and the following code:
-
- .. code-block:: python
-
- from pyoxigraph import SledStore
- store = SledStore('MY_STORAGE_PATH')
- with open('temp_file.nq', 'wb') as fp:
- store.dump(fp, "application/n-quads")
-
- And then upgrade to pyoxigraph **0.3** and run:
-
- .. code-block:: python
-
- from pyoxigraph import Store
- store = Store('MY_NEW_STORAGE_PATH')
- with open('temp_file.nq', 'rb') as fp:
- store.bulk_load(fp, "application/n-quads")
-
-* The in-memory storage class :py:class:`.MemoryStore` has been merged into the :py:class:`.Store` class that provides the exact same API as the late :py:class:`.MemoryStore`.
- On platforms other than Linux, a temporary directory is created when opening the :py:class:`.Store` and automatically removed when it is garbage collected. No data is written in this directory.
-* :py:class:`.Store` operations are now transactional using the "repeatable read" isolation level:
- the store only exposes changes that have been "committed" (i.e. no partial writes)
- and the exposed state does not change for the complete duration of a read operation (e.g. a SPARQL query) or a read/write operation (e.g. a SPARQL update).
-* `RDF-star `_ is now supported (including serialization formats and SPARQL-star). :py:class:`.Triple` can now be used in :py:attr:`.Triple.object`, :py:attr:`.Triple.object`, :py:attr:`.Quad.subject` and :py:attr:`.Quad.object`.
diff --git a/python/docs/model.rst b/python/docs/model.rst
deleted file mode 100644
index 99893190..00000000
--- a/python/docs/model.rst
+++ /dev/null
@@ -1,47 +0,0 @@
-RDF Model
-=========
-.. py:currentmodule:: pyoxigraph
-
-Oxigraph provides python classes to represents basic RDF concepts:
-
-
-`IRIs `_
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.. autoclass:: NamedNode
- :members:
-
-
-`Blank Nodes `_
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.. autoclass:: BlankNode
- :members:
-
-
-`Literals `_
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.. autoclass:: Literal
- :members:
-
-
-`Triples `_
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.. autoclass:: Triple
- :members:
-
-
-Quads (`triples `_ in a `RDF dataset `_)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.. autoclass:: Quad
- :members:
-
-.. autoclass:: DefaultGraph
- :members:
-
-
-`Datasets `_
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.. autoclass:: Dataset
- :members:
-
-.. autoclass:: CanonicalizationAlgorithm
- :members:
diff --git a/python/docs/sparql.rst b/python/docs/sparql.rst
deleted file mode 100644
index 824a42cb..00000000
--- a/python/docs/sparql.rst
+++ /dev/null
@@ -1,33 +0,0 @@
-SPARQL utility objects
-======================
-.. py:currentmodule:: pyoxigraph
-
-Oxigraph provides also some utilities related to SPARQL queries:
-
-Variable
-""""""""
-.. autoclass:: Variable
- :members:
-
-``SELECT`` solutions
-""""""""""""""""""""
-.. autoclass:: QuerySolutions
- :members:
-.. autoclass:: QuerySolution
- :members:
-
-``ASK`` results
-"""""""""""""""
-.. autoclass:: QueryBoolean
- :members:
-
-``CONSTRUCT`` results
-"""""""""""""""""""""
-.. autoclass:: QueryTriples
- :members:
-
-Query results parsing
-"""""""""""""""""""""
-.. autofunction:: parse_query_results
-.. autoclass:: QueryResultsFormat
- :members:
diff --git a/python/docs/store.rst b/python/docs/store.rst
deleted file mode 100644
index b6af6ef5..00000000
--- a/python/docs/store.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-RDF Store
-=========
-.. py:currentmodule:: pyoxigraph
-
-.. autoclass:: Store
- :members:
diff --git a/python/generate_stubs.py b/python/generate_stubs.py
deleted file mode 100644
index 5626c8de..00000000
--- a/python/generate_stubs.py
+++ /dev/null
@@ -1,438 +0,0 @@
-import argparse
-import ast
-import importlib
-import inspect
-import logging
-import re
-import subprocess
-from functools import reduce
-from typing import Any, Dict, List, Mapping, Optional, Set, Tuple, Union
-
-
-def path_to_type(*elements: str) -> ast.AST:
- base: ast.AST = ast.Name(id=elements[0], ctx=ast.Load())
- for e in elements[1:]:
- base = ast.Attribute(value=base, attr=e, ctx=ast.Load())
- return base
-
-
-OBJECT_MEMBERS = dict(inspect.getmembers(object))
-BUILTINS: Dict[str, Union[None, Tuple[List[ast.AST], ast.AST]]] = {
- "__annotations__": None,
- "__bool__": ([], path_to_type("bool")),
- "__bytes__": ([], path_to_type("bytes")),
- "__class__": None,
- "__contains__": ([path_to_type("typing", "Any")], path_to_type("bool")),
- "__del__": None,
- "__delattr__": ([path_to_type("str")], path_to_type("None")),
- "__delitem__": ([path_to_type("typing", "Any")], path_to_type("typing", "Any")),
- "__dict__": None,
- "__dir__": None,
- "__doc__": None,
- "__eq__": ([path_to_type("typing", "Any")], path_to_type("bool")),
- "__format__": ([path_to_type("str")], path_to_type("str")),
- "__ge__": ([path_to_type("typing", "Any")], path_to_type("bool")),
- "__getattribute__": ([path_to_type("str")], path_to_type("typing", "Any")),
- "__getitem__": ([path_to_type("typing", "Any")], path_to_type("typing", "Any")),
- "__gt__": ([path_to_type("typing", "Any")], path_to_type("bool")),
- "__hash__": ([], path_to_type("int")),
- "__init__": ([], path_to_type("None")),
- "__init_subclass__": None,
- "__iter__": ([], path_to_type("typing", "Any")),
- "__le__": ([path_to_type("typing", "Any")], path_to_type("bool")),
- "__len__": ([], path_to_type("int")),
- "__lt__": ([path_to_type("typing", "Any")], path_to_type("bool")),
- "__module__": None,
- "__ne__": ([path_to_type("typing", "Any")], path_to_type("bool")),
- "__new__": None,
- "__next__": ([], path_to_type("typing", "Any")),
- "__reduce__": None,
- "__reduce_ex__": None,
- "__repr__": ([], path_to_type("str")),
- "__setattr__": (
- [path_to_type("str"), path_to_type("typing", "Any")],
- path_to_type("None"),
- ),
- "__setitem__": (
- [path_to_type("typing", "Any"), path_to_type("typing", "Any")],
- path_to_type("typing", "Any"),
- ),
- "__sizeof__": None,
- "__str__": ([], path_to_type("str")),
- "__subclasshook__": None,
-}
-
-
-def module_stubs(module: Any) -> ast.Module:
- types_to_import = {"typing"}
- classes = []
- functions = []
- for member_name, member_value in inspect.getmembers(module):
- element_path = [module.__name__, member_name]
- if member_name.startswith("__"):
- pass
- elif inspect.isclass(member_value):
- classes.append(class_stubs(member_name, member_value, element_path, types_to_import))
- elif inspect.isbuiltin(member_value):
- functions.append(
- function_stub(
- member_name,
- member_value,
- element_path,
- types_to_import,
- in_class=False,
- )
- )
- else:
- logging.warning(f"Unsupported root construction {member_name}")
- return ast.Module(
- body=[ast.Import(names=[ast.alias(name=t)]) for t in sorted(types_to_import)] + classes + functions,
- type_ignores=[],
- )
-
-
-def class_stubs(cls_name: str, cls_def: Any, element_path: List[str], types_to_import: Set[str]) -> ast.ClassDef:
- attributes: List[ast.AST] = []
- methods: List[ast.AST] = []
- magic_methods: List[ast.AST] = []
- constants: List[ast.AST] = []
- for member_name, member_value in inspect.getmembers(cls_def):
- current_element_path = [*element_path, member_name]
- if member_name == "__init__":
- try:
- inspect.signature(cls_def) # we check it actually exists
- methods = [
- function_stub(
- member_name,
- cls_def,
- current_element_path,
- types_to_import,
- in_class=True,
- ),
- *methods,
- ]
- except ValueError as e:
- if "no signature found" not in str(e):
- raise ValueError(f"Error while parsing signature of {cls_name}.__init_") from e
- elif member_value == OBJECT_MEMBERS.get(member_name) or BUILTINS.get(member_name, ()) is None:
- pass
- elif inspect.isdatadescriptor(member_value):
- attributes.extend(data_descriptor_stub(member_name, member_value, current_element_path, types_to_import))
- elif inspect.isroutine(member_value):
- (magic_methods if member_name.startswith("__") else methods).append(
- function_stub(
- member_name,
- member_value,
- current_element_path,
- types_to_import,
- in_class=True,
- )
- )
- elif member_name == "__match_args__":
- constants.append(
- ast.AnnAssign(
- target=ast.Name(id=member_name, ctx=ast.Store()),
- annotation=ast.Subscript(
- value=path_to_type("tuple"),
- slice=ast.Tuple(elts=[path_to_type("str"), ast.Ellipsis()], ctx=ast.Load()),
- ctx=ast.Load(),
- ),
- value=ast.Constant(member_value),
- simple=1,
- )
- )
- elif member_value is not None:
- constants.append(
- ast.AnnAssign(
- target=ast.Name(id=member_name, ctx=ast.Store()),
- annotation=concatenated_path_to_type(
- member_value.__class__.__name__, element_path, types_to_import
- ),
- value=ast.Ellipsis(),
- simple=1,
- )
- )
- else:
- logging.warning(f"Unsupported member {member_name} of class {'.'.join(element_path)}")
-
- doc = inspect.getdoc(cls_def)
- doc_comment = build_doc_comment(doc) if doc else None
- return ast.ClassDef(
- cls_name,
- bases=[],
- keywords=[],
- body=(([doc_comment] if doc_comment else []) + attributes + methods + magic_methods + constants)
- or [ast.Ellipsis()],
- decorator_list=[path_to_type("typing", "final")],
- )
-
-
-def data_descriptor_stub(
- data_desc_name: str,
- data_desc_def: Any,
- element_path: List[str],
- types_to_import: Set[str],
-) -> Union[Tuple[ast.AnnAssign, ast.Expr], Tuple[ast.AnnAssign]]:
- annotation = None
- doc_comment = None
-
- doc = inspect.getdoc(data_desc_def)
- if doc is not None:
- annotation = returns_stub(data_desc_name, doc, element_path, types_to_import)
- m = re.findall(r"^ *:return: *(.*) *$", doc, re.MULTILINE)
- if len(m) == 1:
- doc_comment = m[0]
- elif len(m) > 1:
- raise ValueError(
- f"Multiple return annotations found with :return: in {'.'.join(element_path)} documentation"
- )
-
- assign = ast.AnnAssign(
- target=ast.Name(id=data_desc_name, ctx=ast.Store()),
- annotation=annotation or path_to_type("typing", "Any"),
- simple=1,
- )
- doc_comment = build_doc_comment(doc_comment) if doc_comment else None
- return (assign, doc_comment) if doc_comment else (assign,)
-
-
-def function_stub(
- fn_name: str,
- fn_def: Any,
- element_path: List[str],
- types_to_import: Set[str],
- *,
- in_class: bool,
-) -> ast.FunctionDef:
- body: List[ast.AST] = []
- doc = inspect.getdoc(fn_def)
- if doc is not None:
- doc_comment = build_doc_comment(doc)
- if doc_comment is not None:
- body.append(doc_comment)
-
- decorator_list = []
- if in_class and hasattr(fn_def, "__self__"):
- decorator_list.append(ast.Name("staticmethod"))
-
- return ast.FunctionDef(
- fn_name,
- arguments_stub(fn_name, fn_def, doc or "", element_path, types_to_import),
- body or [ast.Ellipsis()],
- decorator_list=decorator_list,
- returns=returns_stub(fn_name, doc, element_path, types_to_import) if doc else None,
- lineno=0,
- )
-
-
-def arguments_stub(
- callable_name: str,
- callable_def: Any,
- doc: str,
- element_path: List[str],
- types_to_import: Set[str],
-) -> ast.arguments:
- real_parameters: Mapping[str, inspect.Parameter] = inspect.signature(callable_def).parameters
- if callable_name == "__init__":
- real_parameters = {
- "self": inspect.Parameter("self", inspect.Parameter.POSITIONAL_ONLY),
- **real_parameters,
- }
-
- parsed_param_types = {}
- optional_params = set()
-
- # Types for magic functions types
- builtin = BUILTINS.get(callable_name)
- if isinstance(builtin, tuple):
- param_names = list(real_parameters.keys())
- if param_names and param_names[0] == "self":
- del param_names[0]
- for name, t in zip(param_names, builtin[0]):
- parsed_param_types[name] = t
-
- # Types from comment
- for match in re.findall(r"^ *:type *([a-z_]+): ([^\n]*) *$", doc, re.MULTILINE):
- if match[0] not in real_parameters:
- raise ValueError(
- f"The parameter {match[0]} of {'.'.join(element_path)} "
- "is defined in the documentation but not in the function signature"
- )
- type = match[1]
- if type.endswith(", optional"):
- optional_params.add(match[0])
- type = type[:-10]
- parsed_param_types[match[0]] = convert_type_from_doc(type, element_path, types_to_import)
-
- # we parse the parameters
- posonlyargs = []
- args = []
- vararg = None
- kwonlyargs = []
- kw_defaults = []
- kwarg = None
- defaults = []
- for param in real_parameters.values():
- if param.name != "self" and param.name not in parsed_param_types:
- raise ValueError(
- f"The parameter {param.name} of {'.'.join(element_path)} "
- "has no type definition in the function documentation"
- )
- param_ast = ast.arg(arg=param.name, annotation=parsed_param_types.get(param.name))
-
- default_ast = None
- if param.default != param.empty:
- default_ast = ast.Constant(param.default)
- if param.name not in optional_params:
- raise ValueError(
- f"Parameter {param.name} of {'.'.join(element_path)} "
- "is optional according to the type but not flagged as such in the doc"
- )
- elif param.name in optional_params:
- raise ValueError(
- f"Parameter {param.name} of {'.'.join(element_path)} "
- "is optional according to the documentation but has no default value"
- )
-
- if param.kind == param.POSITIONAL_ONLY:
- posonlyargs.append(param_ast)
- defaults.append(default_ast)
- elif param.kind == param.POSITIONAL_OR_KEYWORD:
- args.append(param_ast)
- defaults.append(default_ast)
- elif param.kind == param.VAR_POSITIONAL:
- vararg = param_ast
- elif param.kind == param.KEYWORD_ONLY:
- kwonlyargs.append(param_ast)
- kw_defaults.append(default_ast)
- elif param.kind == param.VAR_KEYWORD:
- kwarg = param_ast
-
- return ast.arguments(
- posonlyargs=posonlyargs,
- args=args,
- vararg=vararg,
- kwonlyargs=kwonlyargs,
- kw_defaults=kw_defaults,
- defaults=defaults,
- kwarg=kwarg,
- )
-
-
-def returns_stub(callable_name: str, doc: str, element_path: List[str], types_to_import: Set[str]) -> Optional[ast.AST]:
- m = re.findall(r"^ *:rtype: *([^\n]*) *$", doc, re.MULTILINE)
- if len(m) == 0:
- builtin = BUILTINS.get(callable_name)
- if isinstance(builtin, tuple) and builtin[1] is not None:
- return builtin[1]
- raise ValueError(
- f"The return type of {'.'.join(element_path)} "
- "has no type definition using :rtype: in the function documentation"
- )
- if len(m) > 1:
- raise ValueError(f"Multiple return type annotations found with :rtype: for {'.'.join(element_path)}")
- return convert_type_from_doc(m[0], element_path, types_to_import)
-
-
-def convert_type_from_doc(type_str: str, element_path: List[str], types_to_import: Set[str]) -> ast.AST:
- type_str = type_str.strip()
- return parse_type_to_ast(type_str, element_path, types_to_import)
-
-
-def parse_type_to_ast(type_str: str, element_path: List[str], types_to_import: Set[str]) -> ast.AST:
- # let's tokenize
- tokens = []
- current_token = ""
- for c in type_str:
- if "a" <= c <= "z" or "A" <= c <= "Z" or c == ".":
- current_token += c
- else:
- if current_token:
- tokens.append(current_token)
- current_token = ""
- if c != " ":
- tokens.append(c)
- if current_token:
- tokens.append(current_token)
-
- # let's first parse nested parenthesis
- stack: List[List[Any]] = [[]]
- for token in tokens:
- if token == "[":
- children: List[str] = []
- stack[-1].append(children)
- stack.append(children)
- elif token == "]":
- stack.pop()
- else:
- stack[-1].append(token)
-
- # then it's easy
- def parse_sequence(sequence: List[Any]) -> ast.AST:
- # we split based on "or"
- or_groups: List[List[str]] = [[]]
- for e in sequence:
- if e == "or":
- or_groups.append([])
- else:
- or_groups[-1].append(e)
- if any(not g for g in or_groups):
- raise ValueError(f"Not able to parse type '{type_str}' used by {'.'.join(element_path)}")
-
- new_elements: List[ast.AST] = []
- for group in or_groups:
- if len(group) == 1 and isinstance(group[0], str):
- new_elements.append(concatenated_path_to_type(group[0], element_path, types_to_import))
- elif len(group) == 2 and isinstance(group[0], str) and isinstance(group[1], list):
- new_elements.append(
- ast.Subscript(
- value=concatenated_path_to_type(group[0], element_path, types_to_import),
- slice=parse_sequence(group[1]),
- ctx=ast.Load(),
- )
- )
- else:
- raise ValueError(f"Not able to parse type '{type_str}' used by {'.'.join(element_path)}")
- return reduce(lambda left, right: ast.BinOp(left=left, op=ast.BitOr(), right=right), new_elements)
-
- return parse_sequence(stack[0])
-
-
-def concatenated_path_to_type(path: str, element_path: List[str], types_to_import: Set[str]) -> ast.AST:
- parts = path.split(".")
- if any(not p for p in parts):
- raise ValueError(f"Not able to parse type '{path}' used by {'.'.join(element_path)}")
- if len(parts) > 1:
- types_to_import.add(".".join(parts[:-1]))
- return path_to_type(*parts)
-
-
-def build_doc_comment(doc: str) -> Optional[ast.Expr]:
- lines = [line.strip() for line in doc.split("\n")]
- clean_lines = []
- for line in lines:
- if line.startswith((":type", ":rtype")):
- continue
- clean_lines.append(line)
- text = "\n".join(clean_lines).strip()
- return ast.Expr(value=ast.Constant(text)) if text else None
-
-
-def format_with_ruff(file: str) -> None:
- subprocess.check_call(["python", "-m", "ruff", "format", file])
-
-
-if __name__ == "__main__":
- parser = argparse.ArgumentParser(description="Extract Python type stub from a python module.")
- parser.add_argument("module_name", help="Name of the Python module for which generate stubs")
- parser.add_argument(
- "out",
- help="Name of the Python stub file to write to",
- type=argparse.FileType("wt"),
- )
- parser.add_argument("--ruff", help="Formats the generated stubs using Ruff", action="store_true")
- args = parser.parse_args()
- stub_content = ast.unparse(module_stubs(importlib.import_module(args.module_name)))
- args.out.write(stub_content)
- if args.ruff:
- format_with_ruff(args.out.name)
diff --git a/python/mypy_allowlist.txt b/python/mypy_allowlist.txt
deleted file mode 100644
index bae62500..00000000
--- a/python/mypy_allowlist.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-pyoxigraph.pyoxigraph
-pyoxigraph.DefaultGraph.__init__
\ No newline at end of file
diff --git a/python/pyproject.toml b/python/pyproject.toml
deleted file mode 100644
index e1003177..00000000
--- a/python/pyproject.toml
+++ /dev/null
@@ -1,59 +0,0 @@
-[build-system]
-requires = ["maturin~=1.0"]
-build-backend = "maturin"
-
-[project]
-# Most of the metadata are in Cargo.toml and injected by maturin
-name = "pyoxigraph"
-classifiers = [
- "Development Status :: 3 - Alpha",
- "Intended Audience :: Developers",
- "License :: OSI Approved :: Apache Software License",
- "License :: OSI Approved :: MIT License",
- "Programming Language :: Python :: 3 :: Only",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Rust",
- "Topic :: Database :: Database Engines/Servers",
- "Topic :: Software Development :: Libraries :: Python Modules",
-]
-requires-python = ">=3.8"
-
-[project.urls]
-Changelog = "https://github.com/oxigraph/oxigraph/blob/main/CHANGELOG.md"
-Documentation = "https://pyoxigraph.readthedocs.io/"
-Homepage = "https://pyoxigraph.readthedocs.io/"
-Source = "https://github.com/oxigraph/oxigraph/tree/main/python"
-Tracker = "https://github.com/oxigraph/oxigraph/issues"
-
-[tool.maturin]
-strip = true
-
-[tool.ruff]
-line-length = 120
-
-[tool.ruff.lint]
-select = [
- "ARG",
- "B",
- "C40",
- "E",
- "F",
- "FBT",
- "I",
- "ICN",
- "N",
- "PIE",
- "PTH",
- "RET",
- "RUF",
- "SIM",
- "T10",
- "TCH",
- "TID",
- "UP",
- "W",
- "YTT"
-]
diff --git a/python/requirements.dev.txt b/python/requirements.dev.txt
deleted file mode 100644
index f91877f3..00000000
--- a/python/requirements.dev.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-furo
-maturin~=1.0
-mypy~=1.0
-ruff~=0.3.0
-sphinx~=7.0
-sphinx-lint~=0.9.1
diff --git a/python/src/dataset.rs b/python/src/dataset.rs
deleted file mode 100644
index 25eb729e..00000000
--- a/python/src/dataset.rs
+++ /dev/null
@@ -1,327 +0,0 @@
-use crate::model::{hash, PyGraphNameRef, PyNamedNodeRef, PyQuad, PySubjectRef, PyTermRef};
-use oxigraph::model::dataset::{CanonicalizationAlgorithm, Dataset};
-use oxigraph::model::{Quad, QuadRef};
-use pyo3::exceptions::PyKeyError;
-use pyo3::prelude::*;
-
-/// An in-memory `RDF dataset `_.
-///
-/// It can accommodate a fairly large number of quads (in the few millions).
-///
-/// Use :py:class:`Store` if you need on-disk persistence or SPARQL.
-///
-/// Warning: It interns the strings and does not do any garbage collection yet:
-/// if you insert and remove a lot of different terms, memory will grow without any reduction.
-///
-/// :param quads: some quads to initialize the dataset with.
-/// :type quads: collections.abc.Iterable[Quad] or None, optional
-///
-/// The :py:class:`str` function provides an N-Quads serialization:
-///
-/// >>> str(Dataset([Quad(NamedNode('http://example.com/s'), NamedNode('http://example.com/p'), NamedNode('http://example.com/o'), NamedNode('http://example.com/g'))]))
-/// ' .\n'
-#[pyclass(name = "Dataset", module = "pyoxigraph")]
-#[derive(Eq, PartialEq, Debug, Clone)]
-pub struct PyDataset {
- inner: Dataset,
-}
-
-#[pymethods]
-impl PyDataset {
- #[new]
- #[pyo3(signature = (quads = None))]
- fn new(quads: Option<&Bound<'_, PyAny>>) -> PyResult {
- let mut inner = Dataset::new();
- if let Some(quads) = quads {
- for quad in quads.iter()? {
- inner.insert(&*quad?.extract::>()?);
- }
- }
- Ok(Self { inner })
- }
-
- /// Looks for the quads with the given subject.
- ///
- /// :param subject: the quad subject.
- /// :type subject: NamedNode or BlankNode or Triple
- /// :return: an iterator of the quads.
- /// :rtype: collections.abc.Iterator[Quad]
- ///
- /// >>> 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')))
- /// [ predicate= object=> graph_name=>]
- #[allow(clippy::needless_pass_by_value)]
- pub fn quads_for_subject(&self, subject: PySubjectRef<'_>) -> QuadIter {
- QuadIter {
- inner: self
- .inner
- .quads_for_subject(&subject)
- .map(QuadRef::into_owned)
- .collect::>()
- .into_iter(),
- }
- }
-
- /// Looks for the quads with the given predicate.
- ///
- /// :param predicate: the quad predicate.
- /// :type predicate: NamedNode
- /// :return: an iterator of the quads.
- /// :rtype: collections.abc.Iterator[Quad]
- ///
- /// >>> 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')))
- /// [ predicate= object=> graph_name=>]
- #[allow(clippy::needless_pass_by_value)]
- pub fn quads_for_predicate(&self, predicate: PyNamedNodeRef<'_>) -> QuadIter {
- QuadIter {
- inner: self
- .inner
- .quads_for_predicate(&predicate)
- .map(QuadRef::into_owned)
- .collect::>()
- .into_iter(),
- }
- }
-
- /// Looks for the quads with the given object.
- ///
- /// :param object: the quad object.
- /// :type object: NamedNode or BlankNode or Literal or Triple
- /// :return: an iterator of the quads.
- /// :rtype: collections.abc.Iterator[Quad]
- ///
- /// >>> 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')))
- /// [ predicate= object=> graph_name=>]
- #[allow(clippy::needless_pass_by_value)]
- pub fn quads_for_object(&self, object: PyTermRef<'_>) -> QuadIter {
- QuadIter {
- inner: self
- .inner
- .quads_for_object(&object)
- .map(QuadRef::into_owned)
- .collect::>()
- .into_iter(),
- }
- }
-
- /// Looks for the quads with the given graph name.
- ///
- /// :param graph_name: the quad graph name.
- /// :type graph_name: NamedNode or BlankNode or DefaultGraph
- /// :return: an iterator of the quads.
- /// :rtype: collections.abc.Iterator[Quad]
- ///
- /// >>> 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')))
- /// [ predicate= object=> graph_name=>]
- #[allow(clippy::needless_pass_by_value)]
- pub fn quads_for_graph_name(&self, graph_name: PyGraphNameRef<'_>) -> QuadIter {
- QuadIter {
- inner: self
- .inner
- .quads_for_graph_name(&graph_name)
- .map(QuadRef::into_owned)
- .collect::>()
- .into_iter(),
- }
- }
-
- /// Adds a quad to the dataset.
- ///
- /// :param quad: the quad to add.
- /// :type quad: Quad
- /// :rtype: None
- ///
- /// >>> quad = Quad(NamedNode('http://example.com/s'), NamedNode('http://example.com/p'), NamedNode('http://example.com/o'), NamedNode('http://example.com/g'))
- /// >>> dataset = Dataset()
- /// >>> dataset.add(quad)
- /// >>> quad in dataset
- /// True
- fn add(&mut self, quad: &PyQuad) {
- self.inner.insert(quad);
- }
-
- /// Removes a quad from the dataset and raises an exception if it is not in the set.
- ///
- /// :param quad: the quad to remove.
- /// :type quad: Quad
- /// :rtype: None
- /// :raises KeyError: if the element was not in the set.
- ///
- /// >>> quad = Quad(NamedNode('http://example.com/s'), NamedNode('http://example.com/p'), NamedNode('http://example.com/o'), NamedNode('http://example.com/g'))
- /// >>> dataset = Dataset([quad])
- /// >>> dataset.remove(quad)
- /// >>> quad in dataset
- /// False
- fn remove(&mut self, quad: &PyQuad) -> PyResult<()> {
- if self.inner.remove(quad) {
- Ok(())
- } else {
- Err(PyKeyError::new_err(format!(
- "{} is not in the Dataset",
- QuadRef::from(quad)
- )))
- }
- }
-
- /// Removes a quad from the dataset if it is present.
- ///
- /// :param quad: the quad to remove.
- /// :type quad: Quad
- /// :rtype: None
- ///
- /// >>> quad = Quad(NamedNode('http://example.com/s'), NamedNode('http://example.com/p'), NamedNode('http://example.com/o'), NamedNode('http://example.com/g'))
- /// >>> dataset = Dataset([quad])
- /// >>> dataset.discard(quad)
- /// >>> quad in dataset
- /// False
- fn discard(&mut self, quad: &PyQuad) {
- self.inner.remove(quad);
- }
-
- /// Removes all quads from the dataset.
- ///
- /// :rtype: None
- ///
- /// >>> quad = Quad(NamedNode('http://example.com/s'), NamedNode('http://example.com/p'), NamedNode('http://example.com/o'), NamedNode('http://example.com/g'))
- /// >>> dataset = Dataset([quad])
- /// >>> dataset.clear()
- /// >>> len(dataset)
- /// 0
- fn clear(&mut self) {
- self.inner.clear()
- }
-
- /// Canonicalizes the dataset by renaming blank nodes.
- ///
- /// Warning: Blank node ids depends on the current shape of the graph. Adding a new quad might change the ids of a lot of blank nodes.
- /// Hence, this canonization might not be suitable for diffs.
- ///
- /// Warning: This implementation worst-case complexity is in *O(b!)* with *b* the number of blank nodes in the input dataset.
- ///
- /// :param algorithm: the canonicalization algorithm to use.
- /// :type algorithm: CanonicalizationAlgorithm
- /// :rtype: None
- ///
- /// >>> d1 = Dataset([Quad(BlankNode(), NamedNode('http://example.com/p'), BlankNode())])
- /// >>> d2 = Dataset([Quad(BlankNode(), NamedNode('http://example.com/p'), BlankNode())])
- /// >>> d1 == d2
- /// False
- /// >>> d1.canonicalize(CanonicalizationAlgorithm.UNSTABLE)
- /// >>> d2.canonicalize(CanonicalizationAlgorithm.UNSTABLE)
- /// >>> d1 == d2
- /// True
- fn canonicalize(&mut self, algorithm: &PyCanonicalizationAlgorithm) {
- self.inner.canonicalize(algorithm.inner)
- }
-
- fn __str__(&self) -> String {
- self.inner.to_string()
- }
-
- fn __bool__(&self) -> bool {
- self.inner.is_empty()
- }
-
- fn __eq__(&self, other: &Self) -> bool {
- self.inner == other.inner
- }
-
- fn __ne__(&self, other: &Self) -> bool {
- self.inner != other.inner
- }
-
- fn __len__(&self) -> usize {
- self.inner.len()
- }
-
- fn __contains__(&self, quad: &PyQuad) -> bool {
- self.inner.contains(quad)
- }
-
- fn __iter__(&self) -> QuadIter {
- // TODO: very inefficient
- QuadIter {
- inner: self
- .inner
- .iter()
- .map(QuadRef::into_owned)
- .collect::>()
- .into_iter(),
- }
- }
-}
-
-#[pyclass(unsendable, module = "pyoxigraph")]
-pub struct QuadIter {
- inner: std::vec::IntoIter,
-}
-
-#[pymethods]
-impl QuadIter {
- fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
- slf
- }
-
- fn __next__(&mut self) -> Option {
- Some(self.inner.next()?.into())
- }
-}
-
-/// RDF canonicalization algorithms.
-///
-/// The following algorithms are supported:
-///
-/// * :py:attr:`CanonicalizationAlgorithm.UNSTABLE`: an unstable algorithm preferred by PyOxigraph.
-#[pyclass(name = "CanonicalizationAlgorithm", module = "pyoxigraph")]
-#[derive(Clone)]
-pub struct PyCanonicalizationAlgorithm {
- inner: CanonicalizationAlgorithm,
-}
-
-#[pymethods]
-impl PyCanonicalizationAlgorithm {
- /// The algorithm preferred by PyOxigraph.
- ///
- /// Warning: Might change between Oxigraph versions. No stability guaranties.
- #[classattr]
- const UNSTABLE: Self = Self {
- inner: CanonicalizationAlgorithm::Unstable,
- };
-
- fn __repr__(&self) -> String {
- format!(
- "",
- match self.inner {
- CanonicalizationAlgorithm::Unstable => "unstable",
- _ => "unknown",
- }
- )
- }
-
- fn __hash__(&self) -> u64 {
- hash(&self.inner)
- }
-
- fn __eq__(&self, other: &Self) -> bool {
- self.inner == other.inner
- }
-
- fn __ne__(&self, other: &Self) -> bool {
- self.inner != other.inner
- }
-
- /// :rtype: CanonicalizationAlgorithm
- fn __copy__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
- slf
- }
-
- /// :type memo: typing.Any
- /// :rtype: CanonicalizationAlgorithm
- #[allow(unused_variables)]
- fn __deepcopy__<'a>(slf: PyRef<'a, Self>, memo: &'_ Bound<'_, PyAny>) -> PyRef<'a, Self> {
- slf
- }
-}
diff --git a/python/src/io.rs b/python/src/io.rs
deleted file mode 100644
index d03adeb6..00000000
--- a/python/src/io.rs
+++ /dev/null
@@ -1,640 +0,0 @@
-#![allow(clippy::needless_option_as_deref)]
-
-use crate::model::{hash, PyQuad, PyTriple};
-use oxigraph::io::{FromReadQuadReader, RdfFormat, RdfParseError, RdfParser, RdfSerializer};
-use oxigraph::model::QuadRef;
-use pyo3::exceptions::{PyDeprecationWarning, PySyntaxError, PyValueError};
-use pyo3::intern;
-use pyo3::prelude::*;
-use pyo3::types::{PyBytes, PyString};
-use std::cmp::max;
-use std::ffi::OsStr;
-use std::fs::File;
-use std::io::{self, BufWriter, Cursor, Read, Write};
-use std::path::{Path, PathBuf};
-use std::sync::OnceLock;
-
-/// Parses RDF graph and dataset serialization formats.
-///
-/// It currently supports the following formats:
-///
-/// * `N-Triples `_ (:py:attr:`RdfFormat.N_TRIPLES`)
-/// * `N-Quads `_ (:py:attr:`RdfFormat.N_QUADS`)
-/// * `Turtle `_ (:py:attr:`RdfFormat.TURTLE`)
-/// * `TriG `_ (:py:attr:`RdfFormat.TRIG`)
-/// * `N3 `_ (:py:attr:`RdfFormat.N3`)
-/// * `RDF/XML `_ (:py:attr:`RdfFormat.RDF_XML`)
-///
-/// It supports also some media type and extension aliases.
-/// For example, ``application/turtle`` could also be used for `Turtle `_
-/// and ``application/xml`` or ``xml`` for `RDF/XML `_.
-///
-/// :param input: The :py:class:`str`, :py:class:`bytes` or I/O object to read from. For example, it could be the file content as a string or a file reader opened in binary mode with ``open('my_file.ttl', 'rb')``.
-/// :type input: bytes or str or typing.IO[bytes] or typing.IO[str] or None, optional
-/// :param format: the format of the RDF serialization. If :py:const:`None`, the format is guessed from the file name extension.
-/// :type format: RdfFormat or None, optional
-/// :param path: The file path to read from. Replaces the ``input`` parameter.
-/// :type path: str or os.PathLike[str] or None, optional
-/// :param base_iri: the base IRI used to resolve the relative IRIs in the file or :py:const:`None` if relative IRI resolution should not be done.
-/// :type base_iri: str or None, optional
-/// :param without_named_graphs: Sets that the parser must fail when parsing a named graph.
-/// :type without_named_graphs: bool, optional
-/// :param rename_blank_nodes: Renames the blank nodes identifiers from the ones set in the serialization to random ids. This allows to avoid identifier conflicts when merging graphs together.
-/// :type rename_blank_nodes: bool, optional
-/// :return: an iterator of RDF triples or quads depending on the format.
-/// :rtype: collections.abc.Iterator[Quad]
-/// :raises ValueError: if the format is not supported.
-/// :raises SyntaxError: if the provided data is invalid.
-/// :raises OSError: if a system error happens while reading the file.
-///
-/// >>> list(parse(input=b'
"1" .', format=RdfFormat.TURTLE, base_iri="http://example.com/"))
-/// [ predicate= object=> graph_name=>]
-#[pyfunction]
-#[pyo3(signature = (input = None, format = None, *, path = None, base_iri = None, without_named_graphs = false, rename_blank_nodes = false))]
-pub fn parse(
- input: Option,
- format: Option,
- path: Option,
- base_iri: Option<&str>,
- without_named_graphs: bool,
- rename_blank_nodes: bool,
- py: Python<'_>,
-) -> PyResult {
- let input = PyReadable::from_args(&path, input, py)?;
- let format = lookup_rdf_format(format, path.as_deref())?;
- let mut parser = RdfParser::from_format(format);
- if let Some(base_iri) = base_iri {
- parser = parser
- .with_base_iri(base_iri)
- .map_err(|e| PyValueError::new_err(e.to_string()))?;
- }
- if without_named_graphs {
- parser = parser.without_named_graphs();
- }
- if rename_blank_nodes {
- parser = parser.rename_blank_nodes();
- }
- Ok(PyQuadReader {
- inner: parser.parse_read(input),
- file_path: path,
- }
- .into_py(py))
-}
-
-/// Serializes an RDF graph or dataset.
-///
-/// It currently supports the following formats:
-///
-/// * `canonical `_ `N-Triples `_ (:py:attr:`RdfFormat.N_TRIPLES`)
-/// * `N-Quads `_ (:py:attr:`RdfFormat.N_QUADS`)
-/// * `Turtle `_ (:py:attr:`RdfFormat.TURTLE`)
-/// * `TriG `_ (:py:attr:`RdfFormat.TRIG`)
-/// * `N3 `_ (:py:attr:`RdfFormat.N3`)
-/// * `RDF/XML `_ (:py:attr:`RdfFormat.RDF_XML`)
-///
-/// It supports also some media type and extension aliases.
-/// For example, ``application/turtle`` could also be used for `Turtle `_
-/// and ``application/xml`` or ``xml`` for `RDF/XML `_.
-///
-/// :param input: the RDF triples and quads to serialize.
-/// :type input: collections.abc.Iterable[Triple] or collections.abc.Iterable[Quad]
-/// :param output: The binary I/O object or file path to write to. For example, it could be a file path as a string or a file writer opened in binary mode with ``open('my_file.ttl', 'wb')``. If :py:const:`None`, a :py:class:`bytes` buffer is returned with the serialized content.
-/// :type output: typing.IO[bytes] or str or os.PathLike[str] or None, optional
-/// :param format: the format of the RDF serialization. If :py:const:`None`, the format is guessed from the file name extension.
-/// :type format: RdfFormat or None, optional
-/// :return: :py:class:`bytes` with the serialization if the ``output`` parameter is :py:const:`None`, :py:const:`None` if ``output`` is set.
-/// :rtype: bytes or None
-/// :raises ValueError: if the format is not supported.
-/// :raises TypeError: if a triple is given during a quad format serialization or reverse.
-/// :raises OSError: if a system error happens while writing the file.
-///
-/// >>> serialize([Triple(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'))], format=RdfFormat.TURTLE)
-/// b' "1" .\n'
-///
-/// >>> import io
-/// >>> output = io.BytesIO()
-/// >>> serialize([Triple(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'))], output, RdfFormat.TURTLE)
-/// >>> output.getvalue()
-/// b' "1" .\n'
-#[pyfunction]
-#[pyo3(signature = (input, output = None, format = None))]
-pub fn serialize<'py>(
- input: &Bound<'py, PyAny>,
- output: Option,
- format: Option,
- py: Python<'py>,
-) -> PyResult