mirror of
https://github.com/researchobjectschema/ro-crate-interoperability-profile.git
synced 2026-06-08 10:18:42 +02:00
Removed unused classes
This commit is contained in:
+1
-16
@@ -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))
|
||||
|
||||
|
||||
@@ -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))
|
||||
@@ -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/")
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -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):
|
||||
|
||||
+1
-35
@@ -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.
|
||||
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user