From 0cadc3aebecdaf3f7200a9c7f067b374e48399ed Mon Sep 17 00:00:00 2001 From: Vincent Emonet Date: Mon, 20 Nov 2023 08:42:23 +0100 Subject: [PATCH] improve python bindings --- docs/use_python.md | 61 ++++++++++---------- lib/src/nanopub.rs | 2 + lib/src/profile.rs | 2 +- python/pyproject.toml | 2 - python/src/lib.rs | 11 ++-- python/src/nanopub.rs | 130 ++++++++++++++++++++++++------------------ python/try.py | 62 ++++++++++---------- 7 files changed, 143 insertions(+), 127 deletions(-) diff --git a/docs/use_python.md b/docs/use_python.md index 2e6cfd6..5b71bf4 100644 --- a/docs/use_python.md +++ b/docs/use_python.md @@ -19,59 +19,56 @@ pip install nanopub-sign Create a `sign.py` file with: ```python -from nanopub_sign import Nanopub +from nanopub_sign import Nanopub, NpProfile rdf_str = """@prefix : . -@prefix drugbank: . -@prefix np: . -@prefix pav: . -@prefix rdf: . -@prefix infores: . @prefix xsd: . -@prefix dcterms: . -@prefix orcid: . -@prefix biolink: . -@prefix pmid: . +@prefix dc: . +@prefix pav: . @prefix prov: . +@prefix np: . @prefix npx: . +@prefix ex: . :Head { - : a np:Nanopublication ; - np:hasAssertion :assertion; - np:hasProvenance :provenance; - np:hasPublicationInfo :pubInfo . + : np:hasAssertion :assertion ; + np:hasProvenance :provenance ; + np:hasPublicationInfo :pubinfo ; + a np:Nanopublication . } :assertion { - drugbank:DB10771 a biolink:Drug . - - a biolink:Disease . - - :association rdf:object ; - rdf:predicate biolink:treats; - rdf:subject drugbank:DB10771; - a biolink:ChemicalToDiseaseOrPhenotypicFeatureAssociation . + ex:mosquito ex:transmits ex:malaria . } :provenance { - :assertion dcterms:created "2020-09-21T00:00:00"^^xsd:dateTime . + :assertion prov:hadPrimarySource . } -:pubInfo { - : prov:wasAttributedTo orcid:0000-0000-0000-0000 . +:pubinfo { + : dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime ; + pav:createdBy ; + a npx:ExampleNanopub . }""" private_key = """MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCjY1gsFxmak6SOCouJPuEzHNForkqFhgfHE3aAIAx+Y5q6UDEDM9Q0EksheNffJB4iPqsAfiFpY0ARQY92K5r8P4+a78eu9reYrb2WxZb1qPJmvR7XZ6sN1oHD7dd/EyQoJmQsmOKdrqaLRbzR7tZrf52yvKkwNWXcIVhW8uxe7iUgxiojZpW9srKoK/qFRpaUZSKn7Z/zgtDH9FJkYbBsGPDMqp78Kzt+sJb+U2W+wCSSy34jIUxx6QRbzvn6uexc/emFw/1DU5y7zBudhgC7mVk8vX1gUNKyjZBzlOmRcretrANgffqs5fx/TMHN1xtkA/H1u1IKBfKoyk/xThMLAgMBAAECggEAECuG0GZA3HF8OaqFgMG+W+agOvH04h4Pqv4cHjYNxnxpFcNV9nEssTKWSOvCwYy7hrwZBGV3PQzbjFmmrxVFs20+8yCD7KbyKKQZPVC0zf84bj6NTNgvr6DpGtDxINxuGaMjCt7enqhoRyRRuZ0fj2gD3Wqae/Ds8cpDCefkyMg0TvauHSUj244vGq5nt93txUv1Sa+/8tWZ77Dm0s5a3wUYB2IeAMl5WrO2GMvgzwH+zT+4kvNWg5S0Ze4KE+dG3lSIYZjo99h14LcQS9eALC/VBcAJ6pRXaCTT/TULtcLNeOpoc9Fu25f0yTsDt6Ga5ApliYkb7rDhV+OFrw1sYQKBgQDCE9so+dPg7qbp0cV+lbb7rrV43m5s9Klq0riS7u8m71oTwhmvm6gSLfjzqb8GLrmflCK4lKPDSTdwyvd+2SSmOXySw94zr1Pvc7sHdmMRyA7mH3m+zSOOgyCTTKyhDRCNcRIkysoL+DecDhNo4Fumf71tsqDYogfxpAQhn0re8wKBgQDXhMmmT2oXiMnYHhi2k7CJe3HUqkZgmW4W44SWqKHp0V6sjcHm0N0RT5Hz1BFFUd5Y0ZB3JLcah19myD1kKYCj7xz6oVLb8O7LeAZNlb0FsrtD7NU+Hciywo8qESiA7UYDkU6+hsmxaI01DsttMIdG4lSBbEjA7t4IQC5lyr7xiQKBgQCN87YGJ40Y5ZXCSgOZDepz9hqX2KGOIfnUv2HvXsIfiUwqTXs6HbD18xg3KL4myIBOvywSM+4ABYp+foY+Cpcq2btLIeZhiWjsKIrw71+Q/vIe0YDb1PGf6DsoYhmWBpdHzR9HN+hGjvwlsYny2L9Qbfhgxxmsuf7zeFLpQLijjwKBgH7TD28k8IOk5VKec2CNjKd600OYaA3UfCpP/OhDl/RmVtYoHWDcrBrRvkvEEd2/DZ8qw165Zl7gJs3vK+FTYvYVcfIzGPWA1KU7nkntwewmf3i7V8lT8ZTwVRsmObWU60ySJ8qKuwoBQodki2VX12NpMN1wgWe3qUUlr6gLJU4xAoGAet6nD3QKwk6TTmcGVfSWOzvpaDEzGkXjCLaxLKh9GreM/OE+h5aN2gUoFeQapG5rUwI/7Qq0xiLbRXw+OmfAoV2XKv7iI8DjdIh0F06mlEAwQ/B0CpbqkuuxphIbchtdcz/5ra233r3BMNIqBl3VDDVoJlgHPg9msOTRy13lFqc=""" -np = Nanopub( - rdf=rdf_str, +# Check +np = Nanopub.check(rdf_str) +print(np.get_rdf()) + +# Publish +profile = NpProfile( + name="", private_key=private_key, - orcid="https://orcid.org/0000-0000-0000-0000", - server_url='', - publish=False, + orcid_id="https://orcid.org/0000-0000-0000-0000", + introduction_nanopub_uri="" +) +np = Nanopub.publish( + rdf=rdf_str, + profile=profile, + server_url=None, ) - -print(np.get_rdf()) ``` Run it: diff --git a/lib/src/nanopub.rs b/lib/src/nanopub.rs index 2f38579..df9e503 100644 --- a/lib/src/nanopub.rs +++ b/lib/src/nanopub.rs @@ -20,6 +20,7 @@ use std::collections::HashSet; use std::{fmt, str}; /// Infos extracted from a nanopublication: graphs URLs, signature, trusty hash... +#[derive(Clone)] pub struct NpInfo { pub uri: Iri, pub ns: Namespace, @@ -50,6 +51,7 @@ impl fmt::Display for NpInfo { } /// A nanopublication object +#[derive(Clone)] pub struct Nanopub { pub uri: String, pub ns: String, diff --git a/lib/src/profile.rs b/lib/src/profile.rs index 8cb7443..b35712b 100644 --- a/lib/src/profile.rs +++ b/lib/src/profile.rs @@ -10,7 +10,7 @@ use crate::constants::DEFAULT_NP_PROFILE; use crate::constants::{BOLD, END}; use crate::error::NpError; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct NpProfile { pub orcid_id: String, pub name: String, diff --git a/python/pyproject.toml b/python/pyproject.toml index c587822..218d8f6 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -9,7 +9,6 @@ version = "0.0.0" 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.7", @@ -18,7 +17,6 @@ classifiers = [ "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.7" diff --git a/python/src/lib.rs b/python/src/lib.rs index 5ba37a2..bf13076 100644 --- a/python/src/lib.rs +++ b/python/src/lib.rs @@ -15,12 +15,13 @@ use pyo3::prelude::*; /// Nanopub Python bindings #[pymodule] -fn nanopub_sign(_py: Python<'_>, module: &PyModule) -> PyResult<()> { - module.add("__package__", "nanopub-sign")?; - module.add("__version__", env!("CARGO_PKG_VERSION"))?; - module.add("__author__", env!("CARGO_PKG_AUTHORS").replace(':', "\n"))?; +fn nanopub_sign(_py: Python<'_>, m: &PyModule) -> PyResult<()> { + m.add("__package__", "nanopub-sign")?; + m.add("__version__", env!("CARGO_PKG_VERSION"))?; + m.add("__author__", env!("CARGO_PKG_AUTHORS").replace(':', "\n"))?; - module.add_class::() + m.add_class::()?; + m.add_class::() // io::add_to_module(module) } diff --git a/python/src/nanopub.rs b/python/src/nanopub.rs index 9f57069..ff4cd80 100644 --- a/python/src/nanopub.rs +++ b/python/src/nanopub.rs @@ -2,68 +2,67 @@ use nanopub::{Nanopub, NpProfile}; use pyo3::prelude::*; #[pyclass(name = "Nanopub", module = "nanopub_sign")] -#[pyo3(text_signature = "(rdf, private_key, orcid, server_url=None, publish=False)")] -// #[derive(Clone)] +#[derive(Clone)] pub struct NanopubPy { np: Nanopub, } #[pymethods] impl NanopubPy { - #[new] - fn new( + // #[new] + #[staticmethod] + #[pyo3(text_signature = "(rdf)")] + fn check(rdf: &str) -> PyResult { + let np = Nanopub::check(rdf).unwrap(); + Ok(Self { np }) + } + + #[staticmethod] + #[pyo3(text_signature = "(rdf, private_key, orcid, server_url=None)")] + fn publish( rdf: &str, - private_key: &str, - orcid: &str, - server_url: &str, - publish: bool, - py: Python<'_>, + profile: &NpProfilePy, + // private_key: &str, + // orcid: &str, + server_url: Option<&str>, + // py: Python<'_>, ) -> PyResult { - py.allow_threads(|| { - let profile = NpProfile::new(orcid, "", private_key, None).unwrap(); - let np = if publish { - Nanopub::publish( - // &rdf.unwrap_or("default in py").to_string(), - rdf, - &profile, - Some(server_url), - ) - .unwrap() - } else { - Nanopub::sign(rdf, &profile).unwrap() - }; - Ok(Self { np }) + // py.allow_threads(|| { // Put code in this block to enable true parallel https://pyo3.rs/v0.20.0/parallelism + // let profile = NpProfile::new(orcid, "", private_key, None).unwrap(); + + let np = Nanopub::publish(rdf, &profile.profile, server_url).unwrap(); + // Nanopub::sign(rdf, &profile).unwrap() + Ok(Self { np }) - // Ok( Self { - // rdf: nq_stringifier.serialize_dataset(&mut dataset)?.to_string(), - // dataset: dataset, - // public_key: public_key.to_string(), - // private_key: private_key.to_string(), - // orcid: orcid.to_string(), - // server_url: if let Some(server_url) = server_url { - // server_url.to_string() - // } else{ - // TEST_SERVER.to_string() - // }, - // publish: if let Some(publish) = publish { - // publish.clone() - // } else { - // false - // } - // }) + // Ok( Self { + // rdf: nq_stringifier.serialize_dataset(&mut dataset)?.to_string(), + // dataset: dataset, + // public_key: public_key.to_string(), + // private_key: private_key.to_string(), + // orcid: orcid.to_string(), + // server_url: if let Some(server_url) = server_url { + // server_url.to_string() + // } else{ + // TEST_SERVER.to_string() + // }, + // publish: if let Some(publish) = publish { + // publish.clone() + // } else { + // false + // } + // }) - // Ok(Self { - // np: Nanopub::new(&rdf.unwrap_or("default in py").to_string()), - // }) - // Ok(Self { - // np: if let Some(rdf) = rdf { - // Nanopub::new(rdf.unwrap_or("default in py")) - // } else { - // Nanopub::new() - // } - // .map_err(map_storage_error)?, - // }) - }) + // Ok(Self { + // np: Nanopub::new(&rdf.unwrap_or("default in py").to_string()), + // }) + // Ok(Self { + // np: if let Some(rdf) = rdf { + // Nanopub::new(rdf.unwrap_or("default in py")) + // } else { + // Nanopub::new() + // } + // .map_err(map_storage_error)?, + // }) } // #[new] @@ -84,8 +83,9 @@ impl NanopubPy { // } #[pyo3(text_signature = "($self)")] - fn get_rdf(&self, py: Python<'_>) -> PyResult { - py.allow_threads(|| Ok(self.np.get_rdf())) + fn get_rdf(&self, _py: Python<'_>) -> PyResult { + // py.allow_threads(|| Ok(self.np.get_rdf())) + Ok(self.np.get_rdf()) } // /// >>> store.update('DELETE WHERE { ?p ?o }') @@ -100,6 +100,28 @@ impl NanopubPy { // } } +#[pyclass(name = "NpProfile", module = "nanopub_sign")] +#[derive(Clone)] +pub struct NpProfilePy { + profile: NpProfile, +} + +#[pymethods] +impl NpProfilePy { + #[new] + #[pyo3(text_signature = "(orcid_id, name, private_key, introduction_nanopub_uri)")] + fn new( + orcid_id: &str, + name: &str, + private_key: &str, + introduction_nanopub_uri: Option<&str>, + ) -> PyResult { + let profile = + NpProfile::new(orcid_id, name, private_key, introduction_nanopub_uri).unwrap(); + Ok(Self { profile }) + } +} + // /// Formats the sum of two numbers as string. // #[pyfunction] // fn sum_as_string(a: usize, b: usize) -> PyResult { diff --git a/python/try.py b/python/try.py index 652348c..c8f2461 100644 --- a/python/try.py +++ b/python/try.py @@ -1,54 +1,50 @@ -from nanopub_sign import Nanopub +from nanopub_sign import Nanopub, NpProfile rdf_str = """@prefix : . -@prefix drugbank: . -@prefix np: . -@prefix pav: . -@prefix rdf: . -@prefix infores: . @prefix xsd: . -@prefix dcterms: . -@prefix orcid: . -@prefix biolink: . -@prefix pmid: . +@prefix dc: . +@prefix pav: . @prefix prov: . +@prefix np: . @prefix npx: . +@prefix ex: . :Head { - : a np:Nanopublication ; - np:hasAssertion :assertion; - np:hasProvenance :provenance; - np:hasPublicationInfo :pubInfo . + : np:hasAssertion :assertion ; + np:hasProvenance :provenance ; + np:hasPublicationInfo :pubinfo ; + a np:Nanopublication . } :assertion { - drugbank:DB10771 a biolink:Drug . - - a biolink:Disease . - - :association rdf:object ; - rdf:predicate biolink:treats; - rdf:subject drugbank:DB10771; - a biolink:ChemicalToDiseaseOrPhenotypicFeatureAssociation . + ex:mosquito ex:transmits ex:malaria . } :provenance { - :assertion dcterms:created "2020-09-21T00:00:00"^^xsd:dateTime . + :assertion prov:hadPrimarySource . } -:pubInfo { - : prov:wasAttributedTo orcid:0000-0000-0000-0000 . +:pubinfo { + : dc:created "2014-07-24T18:05:11+01:00"^^xsd:dateTime ; + pav:createdBy ; + a npx:ExampleNanopub . }""" private_key = """MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCjY1gsFxmak6SOCouJPuEzHNForkqFhgfHE3aAIAx+Y5q6UDEDM9Q0EksheNffJB4iPqsAfiFpY0ARQY92K5r8P4+a78eu9reYrb2WxZb1qPJmvR7XZ6sN1oHD7dd/EyQoJmQsmOKdrqaLRbzR7tZrf52yvKkwNWXcIVhW8uxe7iUgxiojZpW9srKoK/qFRpaUZSKn7Z/zgtDH9FJkYbBsGPDMqp78Kzt+sJb+U2W+wCSSy34jIUxx6QRbzvn6uexc/emFw/1DU5y7zBudhgC7mVk8vX1gUNKyjZBzlOmRcretrANgffqs5fx/TMHN1xtkA/H1u1IKBfKoyk/xThMLAgMBAAECggEAECuG0GZA3HF8OaqFgMG+W+agOvH04h4Pqv4cHjYNxnxpFcNV9nEssTKWSOvCwYy7hrwZBGV3PQzbjFmmrxVFs20+8yCD7KbyKKQZPVC0zf84bj6NTNgvr6DpGtDxINxuGaMjCt7enqhoRyRRuZ0fj2gD3Wqae/Ds8cpDCefkyMg0TvauHSUj244vGq5nt93txUv1Sa+/8tWZ77Dm0s5a3wUYB2IeAMl5WrO2GMvgzwH+zT+4kvNWg5S0Ze4KE+dG3lSIYZjo99h14LcQS9eALC/VBcAJ6pRXaCTT/TULtcLNeOpoc9Fu25f0yTsDt6Ga5ApliYkb7rDhV+OFrw1sYQKBgQDCE9so+dPg7qbp0cV+lbb7rrV43m5s9Klq0riS7u8m71oTwhmvm6gSLfjzqb8GLrmflCK4lKPDSTdwyvd+2SSmOXySw94zr1Pvc7sHdmMRyA7mH3m+zSOOgyCTTKyhDRCNcRIkysoL+DecDhNo4Fumf71tsqDYogfxpAQhn0re8wKBgQDXhMmmT2oXiMnYHhi2k7CJe3HUqkZgmW4W44SWqKHp0V6sjcHm0N0RT5Hz1BFFUd5Y0ZB3JLcah19myD1kKYCj7xz6oVLb8O7LeAZNlb0FsrtD7NU+Hciywo8qESiA7UYDkU6+hsmxaI01DsttMIdG4lSBbEjA7t4IQC5lyr7xiQKBgQCN87YGJ40Y5ZXCSgOZDepz9hqX2KGOIfnUv2HvXsIfiUwqTXs6HbD18xg3KL4myIBOvywSM+4ABYp+foY+Cpcq2btLIeZhiWjsKIrw71+Q/vIe0YDb1PGf6DsoYhmWBpdHzR9HN+hGjvwlsYny2L9Qbfhgxxmsuf7zeFLpQLijjwKBgH7TD28k8IOk5VKec2CNjKd600OYaA3UfCpP/OhDl/RmVtYoHWDcrBrRvkvEEd2/DZ8qw165Zl7gJs3vK+FTYvYVcfIzGPWA1KU7nkntwewmf3i7V8lT8ZTwVRsmObWU60ySJ8qKuwoBQodki2VX12NpMN1wgWe3qUUlr6gLJU4xAoGAet6nD3QKwk6TTmcGVfSWOzvpaDEzGkXjCLaxLKh9GreM/OE+h5aN2gUoFeQapG5rUwI/7Qq0xiLbRXw+OmfAoV2XKv7iI8DjdIh0F06mlEAwQ/B0CpbqkuuxphIbchtdcz/5ra233r3BMNIqBl3VDDVoJlgHPg9msOTRy13lFqc=""" -np = Nanopub( - rdf=rdf_str, +# Check +np = Nanopub.check(rdf_str) +print(np.get_rdf()) + +# Publish +profile = NpProfile( + name="", private_key=private_key, - orcid="https://orcid.org/0000-0000-0000-0000", - # TODO: Defaults don't work - server_url='', - publish=False, + orcid_id="https://orcid.org/0000-0000-0000-0000", + introduction_nanopub_uri="" +) +np = Nanopub.publish( + rdf=rdf_str, + profile=profile, + server_url=None, ) - -print(np.get_rdf())