From d929b80dcd0139a41589a25d595ce8f5867a8d18 Mon Sep 17 00:00:00 2001 From: Simone Baffelli Date: Mon, 18 Aug 2025 15:35:24 +0200 Subject: [PATCH] Removed unused classes --- .../crate/metadata_entry.py | 17 +--- .../crate/owl_restriction.py | 25 ------ .../src/lib_ro_crate_schema/crate/rdf.py | 3 +- .../lib_ro_crate_schema/crate/rdfs_class.py | 39 ---------- .../lib_ro_crate_schema/crate/restriction.py | 13 +--- .../src/lib_ro_crate_schema/crate/ro.py | 69 ----------------- .../src/lib_ro_crate_schema/crate/type.py | 9 +-- .../crate/type_property.py | 36 +-------- .../lib_ro_crate_schema/example/examples.py | 77 ++----------------- .../lib_ro_crate_schema/utils/jsonld_utils.py | 62 +++++++++++++++ 10 files changed, 78 insertions(+), 272 deletions(-) delete mode 100644 0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/owl_restriction.py delete mode 100644 0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/rdfs_class.py delete mode 100644 0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/ro.py create mode 100644 0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/utils/jsonld_utils.py diff --git a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/metadata_entry.py b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/metadata_entry.py index d0dc799..bc82458 100644 --- a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/metadata_entry.py +++ b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/metadata_entry.py @@ -1,4 +1,3 @@ -from lib_ro_crate_schema.crate.ro import RO_ID_LITERAL from pydantic import BaseModel, Field from rdflib.graph import Node from rdflib import URIRef, RDF, Literal @@ -30,18 +29,4 @@ class MetadataEntry(BaseModel): yield is_type(self.id, URIRef(tid)) for prop_name, prop_value in self.props.items(): yield (subj, object_id(prop_name), Literal(prop_value)) - # # If you have a types field, emit type triples (optional, not in original fields) - # if hasattr(self, 'types') and self.types: - # for t in self.types: - # tid = t.id if hasattr(t, 'id') else t - # yield is_type(self.id, URIRef(tid)) - # if self.props: - # for p, v in self.props.items(): - # pid = p.id if hasattr(p, 'id') else p - # yield (subj, URIRef(pid), Literal(v)) - # if self.references: - # for p, vs in self.references.items(): - # pid = p.id if hasattr(p, 'id') else p - # for v in vs: - # vid = v.id if hasattr(v, 'id') else v - # yield (subj, URIRef(pid), URIRef(vid)) + diff --git a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/owl_restriction.py b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/owl_restriction.py deleted file mode 100644 index a2348c9..0000000 --- a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/owl_restriction.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Literal as TLiteral -from lib_ro_crate_schema.crate.ro import RO_ID_LITERAL, RoEntity, RO_TYPE_LITERAL -from lib_ro_crate_schema.crate.ro_constants import ( - OWL_RESTRICTION, - ON_PROPERTY, - OWL_MAX_CARDINALITY, - OWL_MIN_CARDINALITY, -) -from pydantic import BaseModel, Field -from rdflib import URIRef, RDF, OWL, Literal, URIRef -from lib_ro_crate_schema.crate.rdf import is_type, object_id - - -class OwlRestriction(BaseModel): - id: str - on_property: str - min_cardinality: TLiteral[0, 1] - max_cardinality: TLiteral[0, 1] - - def to_triples(self, subject=None): - subj = object_id(self.id) if subject is None else subject - yield is_type(self.id, URIRef(OWL_RESTRICTION)) - yield (subj, URIRef(ON_PROPERTY), URIRef(self.on_property)) - yield (subj, URIRef(OWL_MIN_CARDINALITY), Literal(self.min_cardinality)) - yield (subj, URIRef(OWL_MAX_CARDINALITY), Literal(self.max_cardinality)) diff --git a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/rdf.py b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/rdf.py index 661dbba..d08b395 100644 --- a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/rdf.py +++ b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/rdf.py @@ -1,9 +1,10 @@ from typing import Protocol from rdflib import Graph -from rdflib import Node, URIRef, RDF, Literal, IdentifiedNode +from rdflib import Node, URIRef, RDF, IdentifiedNode from rdflib import Namespace from rdflib.namespace import NamespaceManager + type Triple = tuple[IdentifiedNode, IdentifiedNode, Node] SCHEMA = Namespace("http://schema.org/") BASE = Namespace("http://example.com/") diff --git a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/rdfs_class.py b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/rdfs_class.py deleted file mode 100644 index f4b6a18..0000000 --- a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/rdfs_class.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import Generator, List, Literal -from lib_ro_crate_schema.crate.ro_constants import RDFS_SUBCLASS_OF -from lib_ro_crate_schema.crate.type_property import TypeProperty, RoTypeProperty -from lib_ro_crate_schema.crate.ro import ( - EQUIVALENT_CLASS, - RO_ID_LITERAL, - RO_TYPE_LITERAL, - RoEntity, - RoReference, -) -from pydantic import BaseModel, Field -from rdflib import URIRef, RDF, RDFS, Literal, Node -from lib_ro_crate_schema.crate.rdf import Triple, is_type - - -class RdfsClass(RoEntity): - id: str = Field(..., serialization_alias=RO_ID_LITERAL) - self_type: str = Field("rdfs:Class", serialization_alias=RO_TYPE_LITERAL) - subclass_of: RoReference | List[RoReference] | List[str] = Field( - ..., serialization_alias=RDFS_SUBCLASS_OF - ) - ontological_annotations: List[str] | None = Field( - ..., serialization_alias=EQUIVALENT_CLASS - ) - rdfs_properties: List[RoTypeProperty] | None = None - - def to_triples(self, subject=None) -> Generator[Triple]: - subj = URIRef(self.id) if subject is None else subject - yield is_type(self.id, RDFS.Class) - if self.subclass_of: - parents = self.subclass_of if isinstance(self.subclass_of, list) else [self.subclass_of] - for parent in parents: - yield (subj, RDFS.subClassOf, URIRef(str(parent))) - if self.ontological_annotations: - for eq in self.ontological_annotations: - yield (subj, URIRef(EQUIVALENT_CLASS), URIRef(str(eq))) - if self.rdfs_properties: - for prop in self.rdfs_properties: - yield from prop.to_triples(subject=subj) diff --git a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/restriction.py b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/restriction.py index 011127c..475f617 100644 --- a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/restriction.py +++ b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/restriction.py @@ -1,15 +1,8 @@ from typing import Literal as TLiteral -from lib_ro_crate_schema.crate.owl_restriction import OwlRestriction from lib_ro_crate_schema.crate.rdf import is_type, object_id -from lib_ro_crate_schema.crate.ro import ToRo -from lib_ro_crate_schema.crate.ro_constants import ( - OWL_MIN_CARDINALITY, - OWL_MAX_CARDINALITY, - OWL_RESTRICTION, -) -from pydantic import BaseModel, Field -from rdflib import URIRef, OWL, Literal, XSD -from .type_property import TypeProperty + +from pydantic import BaseModel +from rdflib import OWL, Literal, XSD from uuid import uuid4 diff --git a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/ro.py b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/ro.py deleted file mode 100644 index 57f0cae..0000000 --- a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/ro.py +++ /dev/null @@ -1,69 +0,0 @@ -from lib_ro_crate_schema.crate.ro_constants import OWL_RESTRICTION -from pydantic import BaseModel, Field -from typing import List, Literal, Protocol, TypeVar, Generic - -RO_TYPE_LITERAL = "@type" -RO_ID_LITERAL = "@id" - -ALLOWED_RO_SCHEMA_TYPES = ( - Literal["rdfs:Class"] | Literal["owl:Restriction"] | Literal["rdfs:Property"] -) - -# class RoId(BaseModel): -# """ -# This class is a wapper to represent the @id propery -# in JSON-LS -# """ -# id: str = Field(..., serialization_alias=RO_ID_LITERAL) - - -class RoReference(BaseModel): - """ - This class encodes the reference to another object through its @id - """ - - id: str = Field(..., serialization_alias=RO_ID_LITERAL) - - -class RoEntity(BaseModel): - """ - This is the base class to represent a RO-Crate graph entity - which as minimum members should offer id and its own type as - @id and @type - """ - - id: str = Field(..., serialization_alias=RO_ID_LITERAL) - self_type: str = Field(..., serialization_alias=RO_TYPE_LITERAL) - - -T = TypeVar("T") - - -class ToRo(Protocol[T]): - """ - This is a protocol (a static duck typed class) - that allows for each class to define what behavior it should implement. - In this way we can for example say that `Type` should implement ToRo[RdfsClass] - """ - - def to_ro(self) -> T: ... - - -type RoReferences = RoReference | List[RoReference] | None - - -def serialize_references(value: List[str] | str | None) -> RoReferences: - match value: - case None: - return None - case str(val) | [val]: - return RoReference(id=val) - case [vals] as ls: - return [RoReference(id=sc) for sc in ls] - - -RDFS_CLASS: Literal["rdfs:Class"] = "rdfs:Class" -RDFS_PROPERTY: Literal["rdfs:Property"] = "rdfs:Property" -EQUIVALENT_CLASS: Literal["owl:equivalentClass"] = "owl:equivalentClass" -EQUIVALENT_CONCEPT: Literal["owl:equivalentProperty"] = "owl:equivalentProperty" -TYPE_RESTRICTION: Literal["owl:restriction"] = "owl:restriction" diff --git a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/type.py b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/type.py index 58546b3..0779cd0 100644 --- a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/type.py +++ b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/type.py @@ -1,13 +1,10 @@ -from typing import List, Optional, Union, Generator +from typing import List, Generator from lib_ro_crate_schema.crate.rdf import is_type, object_id -from lib_ro_crate_schema.crate.rdfs_class import RdfsClass -from .literal_type import LiteralType from .restriction import Restriction -from .type_property import TypeProperty, RoTypeProperty -from .ro import RoReference, ToRo, serialize_references +from .type_property import TypeProperty from pydantic import BaseModel -from rdflib import Node, Literal, URIRef, RDF, RDFS, XSD, IdentifiedNode, OWL +from rdflib import Node, Literal, URIRef, RDFS, OWL class Type(BaseModel): diff --git a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/type_property.py b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/type_property.py index c66c37b..e65685b 100644 --- a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/type_property.py +++ b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/crate/type_property.py @@ -1,20 +1,12 @@ from typing import List, Optional, Union from lib_ro_crate_schema.crate.rdf import SCHEMA, is_type, object_id -from lib_ro_crate_schema.crate.ro import RDFS_PROPERTY from lib_ro_crate_schema.crate.ro_constants import DOMAIN_IDENTIFIER from .literal_type import LiteralType, to_rdf from pydantic import BaseModel, Field from rocrate.model import Person from rocrate.model.contextentity import ContextEntity -from .ro import ( - RO_ID_LITERAL, - RO_TYPE_LITERAL, - RoEntity, - RoReference, - RoReferences, - serialize_references, -) + from rdflib import URIRef, RDF, RDFS, Literal, OWL @@ -50,29 +42,3 @@ class TypeProperty(BaseModel): # Add more as needed for data types, annotations, etc. -class RoTypeProperty(BaseModel): - id: str - label: Optional[str] = None - comment: Optional[str] = None - domain_includes: Optional[List[str]] = None - range_includes: Optional[List[str]] = None - range_includes_data_type: Optional[List[LiteralType]] = None - ontological_annotations: Optional[List[str]] = None - - def to_triples(self, subject=None): - subj = object_id(self.id) if subject is None else subject - yield (subj, RDF.type, RDF.Property) - if self.label: - yield (subj, RDFS.label, Literal(self.label)) - if self.comment: - yield (subj, RDFS.comment, Literal(self.comment)) - # if self.domain_includes and self.domain_includes.domain_includes: - # doms = self.domain_includes.domain_includes - # doms = doms if isinstance(doms, list) else [doms] - # for d in doms: - # yield (subj, URIRef(DOMAIN_IDENTIFIER), URIRef(d.id if hasattr(d, 'id') else str(d))) - if self.range_includes: - for r in self.range_includes: - yield (subj, SCHEMA["rangeIncludes"], URIRef(r)) - # Add more as needed for data types, annotations, etc. - diff --git a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/example/examples.py b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/example/examples.py index 03e1fdd..6da4266 100644 --- a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/example/examples.py +++ b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/example/examples.py @@ -1,16 +1,14 @@ -from pathlib import Path -import tempfile + import json -from lib_ro_crate_schema.crate.rdf import BASE, SCHEMA, unbind -from lib_ro_crate_schema.crate.type import Type, RdfsClass -from lib_ro_crate_schema.crate.type_property import TypeProperty, RoTypeProperty +from lib_ro_crate_schema.crate.rdf import BASE +from lib_ro_crate_schema.crate.type import Type +from lib_ro_crate_schema.crate.type_property import TypeProperty from lib_ro_crate_schema.crate.literal_type import LiteralType from lib_ro_crate_schema.crate.metadata_entry import MetadataEntry from lib_ro_crate_schema.crate.schema_facade import SchemaFacade from rocrate.rocrate import ROCrate -from rocrate.model import ContextEntity -from rdflib import Graph, RDF -import pyld +from rdflib import Graph +from lib_ro_crate_schema.utils.jsonld_utils import emit_crate_with_context, update_jsonld_context, get_context RO_EXTRA_CTX = { @@ -18,73 +16,10 @@ RO_EXTRA_CTX = { "owl:maxCardinality": {"@type": "xsd:integer"}, } - -def update_jsonld_context(ld_obj: dict, new_context: dict[str, str]) -> dict: - """ - Use pyld to update the @context of a JSON-LD object. - Returns a new JSON-LD object with the updated context. - """ - return pyld.jsonld.compact(ld_obj, new_context) - - -def get_context(g: Graph) -> dict[str, str]: - """ - Extracts all used namespaces from the rdflib graph and returns a JSON-LD @context dict. - This can be used for JSON-LD compaction or as a base for RO-Crate @context. - """ - # Get all namespaces used in the graph - context = {} - for prefix, namespace in g.namespaces(): - # Avoid default empty prefix - if prefix: - context[prefix] = str(namespace) - # Optionally, add schema.org and other common ones if not present - if "schema" not in context: - context["schema"] = "https://schema.org/" - return context - - def emit_crate_with_context(crate: ROCrate, context: dict) -> dict: - """ - Emits the ROCrate to a temporary file, reads it back, updates the @context directly (no pyld), - and returns the updated JSON-LD dict. Uses the tempfile context manager for cleanup. - """ - with tempfile.TemporaryDirectory() as tmp: - crate.metadata.write(tmp) - ld = json.loads((Path(tmp) / Path("ro-crate-metadata.json")).read_text()) - # Only allow old context as string (RO-Crate style), else raise error - orig_ctx = ld.get("@context") - if isinstance(orig_ctx, str): - ld["@context"] = [orig_ctx, context] - else: - raise ValueError( - f"Unsupported original @context type: {type(orig_ctx)}. Only string is supported for RO-Crate compatibility." - ) - return ld return pyld.jsonld.compact(ld, context) -def add_schema_to_crate(schema: SchemaFacade, crate: ROCrate) -> dict: - """ - Emits triples from schema, builds a graph, compacts JSON-LD, adds objects to the crate, - writes to a tempfile, updates context using pyld, and returns the final JSON-LD dict. - """ - triples = schema.to_triples() - metadata_graph = Graph() - metadata_graph.bind("base", BASE) - for t in triples: - metadata_graph.add(t) - # Serialize and compact JSON-LD - ld_ser = metadata_graph.serialize(format="json-ld") - ld_obj = pyld.jsonld.json.loads(ld_ser) - - context = {**get_context(metadata_graph), **RO_EXTRA_CTX} - ld_obj_compact = update_jsonld_context(ld_obj, context) - # Add each object in the compacted graph to the crate - for obj in ld_obj_compact.get("@graph", []): - crate.add_jsonld(obj) - # Use the tempfile-based utility to update context and return - return emit_crate_with_context(crate, context) def main(): diff --git a/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/utils/jsonld_utils.py b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/utils/jsonld_utils.py new file mode 100644 index 0000000..da10e16 --- /dev/null +++ b/0.2.x/lib/python/lib-ro-crate-schema/src/lib_ro_crate_schema/utils/jsonld_utils.py @@ -0,0 +1,62 @@ +import tempfile +import json +from pathlib import Path +import pyld + +def emit_crate_with_context(crate, context): + """ + Emits the ROCrate to a temporary file, reads it back, updates the @context directly (no pyld), + and returns the updated JSON-LD dict. Uses the tempfile context manager for cleanup. + Only supports original @context as string (RO-Crate style). + """ + with tempfile.TemporaryDirectory() as tmp: + crate.metadata.write(tmp) + ld = json.loads((Path(tmp) / Path("ro-crate-metadata.json")).read_text()) + orig_ctx = ld.get("@context") + if isinstance(orig_ctx, str): + ld["@context"] = [orig_ctx, context] + else: + raise ValueError(f"Unsupported original @context type: {type(orig_ctx)}. Only string is supported for RO-Crate compatibility.") + return ld + +def update_jsonld_context(ld_obj, new_context): + """ + (Legacy) Use pyld to update the @context of a JSON-LD object. + Returns a new JSON-LD object with the updated context. + """ + return pyld.jsonld.compact(ld_obj, new_context) + +def get_context(g): + """ + Extracts all used namespaces from the rdflib graph and returns a JSON-LD @context dict. + This can be used for JSON-LD compaction or as a base for RO-Crate @context. + """ + context = {} + for prefix, namespace in g.namespaces(): + if prefix: + context[prefix] = str(namespace) + if "schema" not in context: + context["schema"] = "https://schema.org/" + return context + +def add_schema_to_crate(schema: SchemaFacade, crate: ROCrate) -> dict: + """ + Emits triples from schema, builds a graph, compacts JSON-LD, adds objects to the crate, + writes to a tempfile, updates context using pyld, and returns the final JSON-LD dict. + """ + triples = schema.to_triples() + metadata_graph = Graph() + metadata_graph.bind("base", BASE) + for t in triples: + metadata_graph.add(t) + # Serialize and compact JSON-LD + ld_ser = metadata_graph.serialize(format="json-ld") + ld_obj = pyld.jsonld.json.loads(ld_ser) + + context = {**get_context(metadata_graph), **RO_EXTRA_CTX} + ld_obj_compact = update_jsonld_context(ld_obj, context) + # Add each object in the compacted graph to the crate + for obj in ld_obj_compact.get("@graph", []): + crate.add_jsonld(obj) + # Use the tempfile-based utility to update context and return + return emit_crate_with_context(crate, context)