Removed unused classes

This commit is contained in:
Simone Baffelli
2025-08-18 15:35:24 +02:00
parent ec2a182aca
commit d929b80dcd
10 changed files with 78 additions and 272 deletions
@@ -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,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)