diff --git a/README.md b/README.md index 39536c8..20b94ca 100644 --- a/README.md +++ b/README.md @@ -2,21 +2,53 @@ Working in Alpha # Overview -ro-crate-rs is a rust library, python library and CLI tool for interfacing with Reserach Object Crates. -It's aim is to provide a robust, portable and scalable solution to dealing -RO-Crates within the varying software environments that are present across a Synthetic Biology -Laboratory stack. It enforces minimal RO-Crate structure adherence through it's +ro-crate-rs is a rust library, python library and CLI tool for interfacing with [Reserach Object Crates](https://www.researchobject.org/ro-crate/). +This implementation was specifically created to address the challenges of data +handling on automated robotic systems within an automated synthetic biology lab, +however it's noted that this could have more general applicability to other environments. +It's aim is to provide a robust, portable and scalable solution to dealing with +RO-Crates within the varying software environments of a synthetic biology lab stack. + +It enforces minimal RO-Crate structure adherence through it's defined data types, but equally allows the crate to be as expansive as needed. +## Why a rust library +Rust is an increasingly popular systems programming language that is useful for systems +that require performance, robustness and the ability to run in a myriad of different +computing environments; be it Windows, Linux or MacOS, or x86, ARM or any other +embedded/IOT system. It is a compiled, statically typed language with a strong +emphasis on type safety and has started to form the performant core of data libraries, +such as Polars and DeltaLake. + +In this library, the rust type system and the serde library have been leveraged to +provide a structured core for handling RO-Crates with robust data handling, built in +constraints as per the RO-Crate specification (v1.1) and sufficient flexibilty to add any +metadata required. + +The aim is that for regular, automated and ***consistent*** robotic experiements, this +library can be relied upon to create RO-Crates for years to come. + + +## Why a CLI tool The CLI tool can be used to immediately interface with RO-Crates within a somewhat constrained and structured environment, however an understanding of RO-Crate -is a realistic requirement to conform with schema.org specifications. +is a realistic requirement to conform with schema.org specifications. The CLI tool +should not be relied upon as your primary interface to RO-crates, however it does +allow the tool to be used on any system with some form of terminal. + -The python library (pycrate) allows the primary rust library to be leveraged in python. +## Why a python library wrapper +The python library (rocraters) allows the primary rust library to be leveraged in python. It's designed to be maximally flexible with minimal onboarding, allowing you to -incorprate it into scrpits/ data pipelines as easily as possible. This also -relies on you to have an understanding of the structure of an RO-Crate, but -focuses more on the fact that some metadata is better than no metadata. +incorprate it into scrpits/ data pipelines as easily as possible. Python is a +ubquitous language among scientists, so this provides an accessible tool to use +ro-crate-rs within already developed/new Python based environments. +This library relies on you to have an understanding of the structure of an RO-Crate, +but focuses more on the fact that some metadata is better than no metadata. + +This is not the go-to python libary for RO-Crate interfacing, +please see [ro-crate-py](https://github.com/ResearchObject/ro-crate-py) for a +full python implementation. # Libraries diff --git a/examples/create_and_write.py b/examples/create_and_write.py index 5a5315c..d66c53f 100644 --- a/examples/create_and_write.py +++ b/examples/create_and_write.py @@ -1,7 +1,7 @@ from rocraters import PyRoCrateContext, PyRoCrate, read, zip # Define context -context = PyRoCrateContext.from_string(" https://w3id.org/ro/crate/1.1/context") +context = PyRoCrateContext.from_string("https://w3id.org/ro/crate/1.1/context") # Initialise empty crate crate = PyRoCrate(context) diff --git a/python/README.md b/python/README.md index 052c580..98fedba 100644 --- a/python/README.md +++ b/python/README.md @@ -1,11 +1,31 @@ # Overview -rocraters is a python library that is built upon a rust backend for interfacing with [RO-Crates](https://www.researchobject.org/ro-crate/1.1/). It's designed to be maximally flexible with minimal onboarding, allowing you to incorprate it into scrpits/ data pipelines as easily as possible. This also relies on you to have an understanding of the structure of an RO-Crate, but focuses more on the fact that some metadata is better than no metadata. +rocraters is a python library that is built upon a rust backend for interfacing with [RO-Crates](https://www.researchobject.org/ro-crate/1.1/). +This implementation was specifically created to address the challenges of data +handling on automated robotic systems within an automated synthetic biology lab, +however it's noted that this could have more general applicability to other environments. + +It's aim is to provide a robust, portable and scalable solution to dealing with +RO-Crates within the varying software environments of a synthetic biology lab stack. +It's designed to be maximally flexible with minimal onboarding, allowing you to +incorprate it into scrpits/ data pipelines as easily as possible. +This also relies on you to have an understanding of the structure of an RO-Crate, but focuses more on the fact that some metadata is better than no metadata. + + +*This is not the go-to python libary for RO-Crate interfacing, +please see [ro-crate-py](https://github.com/ResearchObject/ro-crate-py) for a +full python implementation.* # Build Built using PyO3 and maturin. Recommended to setup python venv, then install maturin (and remember maturin[patchelf]) +# Installation + +```bash +pip install -i https://test.pypi.org/simple/ rocraters +``` + # Basic usage The RO-Crate specification defines an RO-Crate as a JSON-LD file, consisting of a context and a graph. As such, in python it is a dictionary containing a "context" key, with some form of vocab context (default is the RO-Crate context) and a "graph" key, which contains a list of json objects (dictionaries). diff --git a/python/example.py b/python/example.py new file mode 100644 index 0000000..19170a4 --- /dev/null +++ b/python/example.py @@ -0,0 +1,99 @@ + +from rocraters import PyRoCrateContext, PyRoCrate, read, zip + +# Define context +context = PyRoCrateContext.from_string("https://w3id.org/ro/crate/1.1/context") + +# Initialise empty crate +crate = PyRoCrate(context) + +# For an easy start, you can make a default crate! +default_crate = PyRoCrate.new_default() + +print(f"Example of a default crate \n {default_crate}") + +# Metadata descriptor +descriptor = { + "type": "CreativeWork", + "id": "ro-crate-metadata.json", + "conformsTo": {"id": "https://w3id.org/ro/crate/1.1"}, + "about": {"id": "./"} +} + +# Root data entity +root = { + "id": "./", + "type": "Dataset", + "datePublished": "2017", + "license": {"id": "https://creativecommons.org/licenses/by-nc-sa/3.0/au/"}, + "author": {"id": "#johndoe"} +} +# Data entity +data = { + "id": "output/data_file.txt", + "type": "Dataset", + "name": "Data file name" +} +# Contextual entity +contextual = { + "id": "#JohnDoe", + "type": "Person", +} + +failed_data = { + "id": "this_is_not_a_file.txt", + "type": "Dataset" +} + +# Update the RO-Crate object +crate.update_descriptor(descriptor) +crate.update_root(root) +crate.update_data(data) +crate.update_contextual(contextual) + +# This acts as an example of how if the file/ URI isn't valid as a potentially +# accessible data entity, it loads as a contextual entity +crate.update_data(failed_data) + +# Write crate +crate.write() + + +# Now that a new crate is written, we can open it again! +crate = read("ro-crate-metadata.json", True) + +# Update the data entity and make modification +data_target = crate.get_entity("output/data_file.txt") +data_target["description"] = "A text file dataset containing information" + +print(f"This is the loaded and modified data_file entity \n {data_target}") + +crate.update_data(data_target) + +print(f"This is now the updated, in memory, crate: \n {crate}") + +# Update the contextual entity and make modification +contextual_target = crate.get_entity("#JohnDoe") +contextual_target.update({"id" : "#JaneDoe"}) + +crate.update_contextual(contextual_target) +print(f"Example of a modified entity id that will save as a new entity: \n {crate}") + +# To delete a key:value +data_target.pop("description") + +# We then update the crate the same way we make it +# The ID will be used to serach the crate and overwrites the object with an indentical "id" key +crate.update_data(data_target) + +# To delete an entity - this immediately updates the crate object +crate.delete_entity("#JaneDoe", True) + +crate.write() + +# Final example of modified crate +crate = read("ro-crate-metadata.json", True) +print(crate) + +# Zip the crate to get all data +zip("ro-crate-metadata.json", True)