diff --git a/Cargo.lock b/Cargo.lock
index 191f9136..07f2bc46 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -390,7 +390,7 @@ dependencies = [
  "autocfg",
  "cfg-if",
  "crossbeam-utils",
- "memoffset",
+ "memoffset 0.8.0",
  "scopeguard",
 ]
 
@@ -846,6 +846,15 @@ dependencies = [
  "autocfg",
 ]
 
+[[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"
@@ -1227,14 +1236,14 @@ dependencies = [
 
 [[package]]
 name = "pyo3"
-version = "0.18.3"
+version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3b1ac5b3731ba34fdaa9785f8d74d17448cd18f30cf19e0c7e7b1fdb5272109"
+checksum = "cffef52f74ec3b1a1baf295d9b8fcc3070327aefc39a6d00656b13c1d0b8885c"
 dependencies = [
  "cfg-if",
  "indoc",
  "libc",
- "memoffset",
+ "memoffset 0.9.0",
  "parking_lot",
  "pyo3-build-config",
  "pyo3-ffi",
@@ -1244,9 +1253,9 @@ dependencies = [
 
 [[package]]
 name = "pyo3-build-config"
-version = "0.18.3"
+version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cb946f5ac61bb61a5014924910d936ebd2b23b705f7a4a3c40b05c720b079a3"
+checksum = "713eccf888fb05f1a96eb78c0dbc51907fee42b3377272dc902eb38985f418d5"
 dependencies = [
  "once_cell",
  "target-lexicon",
@@ -1254,9 +1263,9 @@ dependencies = [
 
 [[package]]
 name = "pyo3-ffi"
-version = "0.18.3"
+version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd4d7c5337821916ea2a1d21d1092e8443cf34879e53a0ac653fbb98f44ff65c"
+checksum = "5b2ecbdcfb01cbbf56e179ce969a048fd7305a66d4cdf3303e0da09d69afe4c3"
 dependencies = [
  "libc",
  "pyo3-build-config",
@@ -1264,9 +1273,9 @@ dependencies = [
 
 [[package]]
 name = "pyo3-macros"
-version = "0.18.3"
+version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9d39c55dab3fc5a4b25bbd1ac10a2da452c4aca13bb450f22818a002e29648d"
+checksum = "b78fdc0899f2ea781c463679b20cb08af9247febc8d052de941951024cd8aea0"
 dependencies = [
  "proc-macro2",
  "pyo3-macros-backend",
@@ -1276,9 +1285,9 @@ dependencies = [
 
 [[package]]
 name = "pyo3-macros-backend"
-version = "0.18.3"
+version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97daff08a4c48320587b5224cc98d609e3c27b6d437315bd40b605c98eeb5918"
+checksum = "60da7b84f1227c3e2fe7593505de274dcf4c8928b4e0a1c23d551a14e4e80a0f"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/python/Cargo.toml b/python/Cargo.toml
index 20488c8c..32bf13f4 100644
--- a/python/Cargo.toml
+++ b/python/Cargo.toml
@@ -20,4 +20,4 @@ abi3 = ["pyo3/abi3-py37"]
 
 [dependencies]
 oxigraph = { version = "0.3.17-dev", path="../lib", features = ["http_client"] }
-pyo3 = { version = "0.18", features = ["extension-module"] }
+pyo3 = { version = "0.19", features = ["extension-module"] }
diff --git a/python/src/io.rs b/python/src/io.rs
index 681a25fa..53e53af4 100644
--- a/python/src/io.rs
+++ b/python/src/io.rs
@@ -48,7 +48,7 @@ pub fn add_to_module(module: &PyModule) -> PyResult<()> {
 /// >>> list(parse(input, "text/turtle", base_iri="http://example.com/"))
 /// [<Triple 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>>>]
 #[pyfunction]
-#[pyo3(text_signature = "(input, mime_type, *, base_iri = None)")]
+#[pyo3(signature = (input, mime_type, *, base_iri = None))]
 pub fn parse(
     input: PyObject,
     mime_type: &str,
diff --git a/python/src/lib.rs b/python/src/lib.rs
index d20f80be..170d78b8 100644
--- a/python/src/lib.rs
+++ b/python/src/lib.rs
@@ -1,9 +1,3 @@
-#![allow(
-    clippy::redundant_pub_crate,
-    clippy::used_underscore_binding,
-    clippy::unused_self,
-    clippy::trivially_copy_pass_by_ref
-)]
 mod io;
 mod model;
 mod sparql;
diff --git a/python/src/model.rs b/python/src/model.rs
index f92b862d..26791351 100644
--- a/python/src/model.rs
+++ b/python/src/model.rs
@@ -21,7 +21,6 @@ use std::vec::IntoIter;
 /// >>> str(NamedNode('http://example.com'))
 /// '<http://example.com>'
 #[pyclass(frozen, name = "NamedNode", module = "pyoxigraph")]
-#[pyo3(text_signature = "(value)")]
 #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)]
 pub struct PyNamedNode {
     inner: NamedNode,
@@ -145,7 +144,6 @@ impl PyNamedNode {
 /// >>> str(BlankNode('ex'))
 /// '_:ex'
 #[pyclass(frozen, name = "BlankNode", module = "pyoxigraph")]
-#[pyo3(text_signature = "(value = None)")]
 #[derive(Eq, PartialEq, Debug, Clone, Hash)]
 pub struct PyBlankNode {
     inner: BlankNode,
@@ -281,7 +279,6 @@ impl PyBlankNode {
 /// >>> str(Literal('11', datatype=NamedNode('http://www.w3.org/2001/XMLSchema#integer')))
 /// '"11"^^<http://www.w3.org/2001/XMLSchema#integer>'
 #[pyclass(frozen, name = "Literal", module = "pyoxigraph")]
-#[pyo3(text_signature = "(value, *, datatype = None, language = None)")]
 #[derive(Eq, PartialEq, Debug, Clone, Hash)]
 pub struct PyLiteral {
     inner: Literal,
@@ -428,7 +425,6 @@ impl PyLiteral {
 
 /// The RDF `default graph name <https://www.w3.org/TR/rdf11-concepts/#dfn-default-graph>`_.
 #[pyclass(frozen, name = "DefaultGraph", module = "pyoxigraph")]
-#[pyo3(text_signature = "()")]
 #[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
 pub struct PyDefaultGraph {}
 
@@ -627,7 +623,6 @@ impl IntoPy<PyObject> for PyTerm {
 /// >>> (s, p, o) = Triple(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'))
 #[pyclass(frozen, name = "Triple", module = "pyoxigraph")]
 #[derive(Eq, PartialEq, Debug, Clone, Hash)]
-#[pyo3(text_signature = "(subject, predicate, object)")]
 pub struct PyTriple {
     inner: Triple,
 }
@@ -825,7 +820,6 @@ impl IntoPy<PyObject> for PyGraphName {
 ///
 /// >>> (s, p, o, g) = Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g'))
 #[pyclass(frozen, name = "Quad", module = "pyoxigraph")]
-#[pyo3(text_signature = "(subject, predicate, object, graph_name = None)")]
 #[derive(Eq, PartialEq, Debug, Clone, Hash)]
 pub struct PyQuad {
     inner: Quad,
@@ -1013,7 +1007,6 @@ impl PyQuad {
 /// >>> str(Variable('foo'))
 /// '?foo'
 #[pyclass(frozen, name = "Variable", module = "pyoxigraph")]
-#[pyo3(text_signature = "(value)")]
 #[derive(Eq, PartialEq, Debug, Clone, Hash)]
 pub struct PyVariable {
     inner: Variable,
diff --git a/python/src/store.rs b/python/src/store.rs
index 49749c5b..9410aeed 100644
--- a/python/src/store.rs
+++ b/python/src/store.rs
@@ -35,8 +35,7 @@ use pyo3::prelude::*;
 /// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1'), NamedNode('http://example.com/g')))
 /// >>> str(store)
 /// '<http://example.com> <http://example.com/p> "1" <http://example.com/g> .\n'
-#[pyclass(name = "Store", module = "pyoxigraph")]
-#[pyo3(text_signature = "(path = None)")]
+#[pyclass(frozen, name = "Store", module = "pyoxigraph")]
 #[derive(Clone)]
 pub struct PyStore {
     inner: Store,
@@ -94,7 +93,7 @@ impl PyStore {
     /// :rtype: Store
     /// :raises IOError: if the target directories contain invalid data or could not be accessed.
     #[staticmethod]
-    #[pyo3(signature = (primary_path, secondary_path = None), text_signature = "(primary_path, secondary_path = None)")]
+    #[pyo3(signature = (primary_path, secondary_path = None))]
     fn secondary(
         primary_path: &str,
         secondary_path: Option<&str>,
@@ -216,7 +215,7 @@ impl PyStore {
     /// >>> 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))
     /// [<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>>]
-    #[pyo3(signature = (subject, predicate, object, graph_name = None), text_signature = "($self, subject, predicate, object, graph_name = None)")]
+    #[pyo3(signature = (subject, predicate, object, graph_name = None))]
     fn quads_for_pattern(
         &self,
         subject: &PyAny,
@@ -273,10 +272,7 @@ impl PyStore {
     /// >>> store.add(Quad(NamedNode('http://example.com'), NamedNode('http://example.com/p'), Literal('1')))
     /// >>> store.query('ASK { ?s ?p ?o }')
     /// True
-    #[pyo3(
-        signature = (query, *, base_iri = None, use_default_graph_as_union = false, default_graph = None, named_graphs = None),
-        text_signature = "($self, query, *, base_iri = None, use_default_graph_as_union = False, default_graph = None, named_graphs = None)"
-    )]
+    #[pyo3(signature = (query, *, base_iri = None, use_default_graph_as_union = false, default_graph = None, named_graphs = None))]
     fn query(
         &self,
         query: &str,
@@ -332,7 +328,7 @@ impl PyStore {
     /// >>> store.update('DELETE WHERE { <http://example.com> ?p ?o }')
     /// >>> list(store)
     /// []
-    #[pyo3(signature = (update, *, base_iri = None), text_signature = "($self, update, *, base_iri = None)")]
+    #[pyo3(signature = (update, *, base_iri = None))]
     fn update(&self, update: &str, base_iri: Option<&str>, py: Python<'_>) -> PyResult<()> {
         py.allow_threads(|| {
             let update =
@@ -377,7 +373,7 @@ impl PyStore {
     /// >>> store.load(io.BytesIO(b'<foo> <p> "1" .'), "text/turtle", base_iri="http://example.com/", to_graph=NamedNode("http://example.com/g"))
     /// >>> 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>>]
-    #[pyo3(signature = (input, mime_type, *, base_iri = None, to_graph = None), text_signature = "($self, input, mime_type, *, base_iri = None, to_graph = None)")]
+    #[pyo3(signature = (input, mime_type, *, base_iri = None, to_graph = None))]
     fn load(
         &self,
         input: PyObject,
@@ -459,7 +455,7 @@ impl PyStore {
     /// >>> store.bulk_load(io.BytesIO(b'<foo> <p> "1" .'), "text/turtle", base_iri="http://example.com/", to_graph=NamedNode("http://example.com/g"))
     /// >>> 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>>]
-    #[pyo3(signature = (input, mime_type, *, base_iri = None, to_graph = None), text_signature = "($self, input, mime_type, *, base_iri = None, to_graph = None)")]
+    #[pyo3(signature = (input, mime_type, *, base_iri = None, to_graph = None))]
     fn bulk_load(
         &self,
         input: PyObject,
@@ -537,7 +533,7 @@ impl PyStore {
     /// >>> store.dump(output, "text/turtle", from_graph=NamedNode("http://example.com/g"))
     /// >>> output.getvalue()
     /// b'<http://example.com> <http://example.com/p> "1" .\n'
-    #[pyo3(signature = (output, mime_type, *, from_graph = None), text_signature = "($self, output, mime_type, *, from_graph = None)")]
+    #[pyo3(signature = (output, mime_type, *, from_graph = None))]
     fn dump(
         &self,
         output: PyObject,