mirror of
https://github.com/researchobjectschema/ro-crate-interoperability-profile.git
synced 2026-08-03 12:28:12 +02:00
Trying to use Pydantic to do the heavy work - defined utility classes to serialize into
This commit is contained in:
+4
-3
@@ -1,8 +1,9 @@
|
||||
from pydantic import BaseModel
|
||||
from lib_ro_crate_schema.crate.ro import RO_ID_LITERAL
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
class MetadataEntry(BaseModel):
|
||||
id: str
|
||||
types: set[str] | None = None
|
||||
id: str = Field(..., serialization_alias=RO_ID_LITERAL)
|
||||
types: set[str] | None = Field(..., alias="@types")
|
||||
props: dict[str, str] | None = None
|
||||
references : dict[str, list[str]] | None = None
|
||||
children_identifiers: list[str] | None = None
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
from typing import Literal
|
||||
from lib_ro_crate_schema.crate.ro import RO_ID_LITERAL, RoEntity, RO_TYPE_LITERAL
|
||||
from lib_ro_crate_schema.crate.schema_facade import OWL_RESTRICTION, ON_PROPERTY, OWL_MAX_CARDINALITY, OWL_MIN_CARDINALITY
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
|
||||
class OwlRestriction(RoEntity):
|
||||
id: str = Field(..., serialization_alias=RO_ID_LITERAL)
|
||||
self_type: str = Field(..., serialization_alias=RO_TYPE_LITERAL)
|
||||
on_property: str = Field(..., serialization_alias=ON_PROPERTY)
|
||||
min_cardinality: Literal[0, 1] = Field(...,serialization_alias= OWL_MIN_CARDINALITY)
|
||||
max_cardinality: Literal[0, 1] = Field(...,serialization_alias= OWL_MAX_CARDINALITY)
|
||||
@@ -1,13 +1,17 @@
|
||||
from typing import List
|
||||
from typing import List, Literal
|
||||
from lib_ro_crate_schema.crate.schema_facade import EQUIVALENT_CLASS, RDFS_SUBCLASS_OF
|
||||
from lib_ro_crate_schema.crate.type_property import TypeProperty
|
||||
from pydantic import BaseModel
|
||||
from lib_ro_crate_schema.crate.ro import RO_ID_LITERAL, RO_TYPE_LITERAL, RoEntity, RoReference
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class RdfsClass(BaseModel):
|
||||
id: str
|
||||
type: str
|
||||
subclass_of: List[str] | None = None
|
||||
ontological_annotations: List[str] | None = None
|
||||
|
||||
|
||||
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] | None = Field(..., serialization_alias=RDFS_SUBCLASS_OF)
|
||||
ontological_annotations: List[str] | None = Field(..., serialization_alias=EQUIVALENT_CLASS)
|
||||
rdfs_properties: List[TypeProperty] | None = None
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import Literal
|
||||
from lib_ro_crate_schema.crate.owl_restriction import OwlRestriction
|
||||
from lib_ro_crate_schema.crate.ro import ToRo
|
||||
from lib_ro_crate_schema.crate.schema_facade import OWL_MIN_CARDINALITY, OWL_MAX_CARDINALITY, OWL_RESTRICTION
|
||||
from pydantic import BaseModel, Field
|
||||
from .type_property import TypeProperty
|
||||
|
||||
|
||||
|
||||
class Restriction(BaseModel):
|
||||
id: str
|
||||
property_type: TypeProperty
|
||||
min_cardinality: int
|
||||
max_cardinality: int
|
||||
property_type: str
|
||||
min_cardinality: Literal[0, 1]
|
||||
max_cardinality: Literal[0, 1]
|
||||
|
||||
class Config:
|
||||
validate_by_name = True
|
||||
populate_by_name = True
|
||||
|
||||
def to_ro(self):
|
||||
return OwlRestriction(
|
||||
id = self.id,
|
||||
self_type=OWL_RESTRICTION,
|
||||
on_property=self.property_type,
|
||||
min_cardinality=self.min_cardinality,
|
||||
max_cardinality=self.max_cardinality
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
from lib_ro_crate_schema.crate.schema_facade import RDFS_CLASS, OWL_RESTRICTION
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import 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:
|
||||
...
|
||||
@@ -0,0 +1,55 @@
|
||||
# Constants from Java SchemaFacade
|
||||
from typing import Literal
|
||||
|
||||
|
||||
|
||||
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"
|
||||
RANGE_IDENTIFIER: Literal["schema:rangeIncludes"] = "schema:rangeIncludes"
|
||||
DOMAIN_IDENTIFIER: Literal["schema:domainIncludes"] = "schema:domainIncludes"
|
||||
OWL_MIN_CARDINALITY: Literal["owl:minCardinality"] = "owl:minCardinality"
|
||||
OWL_MAX_CARDINALITY: Literal["owl:maxCardinality"] = "owl:maxCardinality"
|
||||
OWL_RESTRICTION: Literal["owl:restriction"] = "owl:restriction"
|
||||
ON_PROPERTY: Literal["owl:onProperty"] = "owl:onProperty"
|
||||
RDFS_LABEL: Literal["rdfs:label"] = "rdfs:label"
|
||||
RDFS_COMMENT: Literal["rdfs:comment"] = "rdfs:comment"
|
||||
RDFS_SUBCLASS_OF: Literal["rdfs:subClassOf"] = "rdfs:subClassOf"
|
||||
|
||||
# Cardinality and other integer literals
|
||||
MIN_CARDINALITY_MANDATORY: Literal[1] = 1
|
||||
MAX_CARDINALITY_SINGLE: Literal[1] = 1
|
||||
MAX_CARDINALITY_UNLIMITED: Literal[0] = 0
|
||||
|
||||
class SchemaFacade:
|
||||
def __init__(self):
|
||||
self.types = {}
|
||||
self.property_types = {}
|
||||
self.metadata_entries = {}
|
||||
|
||||
def add_type(self, type_obj):
|
||||
self.types[type_obj.id] = type_obj
|
||||
|
||||
def add_property_type(self, property_obj):
|
||||
self.property_types[property_obj.id] = property_obj
|
||||
|
||||
def add_metadata_entry(self, entry_obj):
|
||||
self.metadata_entries[entry_obj.id] = entry_obj
|
||||
|
||||
def serialize_ro_crate_graph(self):
|
||||
"""
|
||||
Serialize all types, property types, and metadata entries as RO-Crate @graph list.
|
||||
"""
|
||||
graph = []
|
||||
# Serialize types
|
||||
for t in self.types.values():
|
||||
graph.append(t.model_dump())
|
||||
# Serialize property types
|
||||
for p in self.property_types.values():
|
||||
graph.append(p.model_dump())
|
||||
# Serialize metadata entries
|
||||
for m in self.metadata_entries.values():
|
||||
graph.append(m.model_dump())
|
||||
return graph
|
||||
@@ -1,12 +1,24 @@
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from lib_ro_crate_schema.crate.rdfs_class import RdfsClass
|
||||
from .literal_type import LiteralType
|
||||
from .restriction import Restriction
|
||||
from .type_property import TypeProperty
|
||||
from .ro import RoReference, ToRo
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
def serialize_subclass_of(value: List[str] | str | None):
|
||||
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]
|
||||
|
||||
class Type(BaseModel):
|
||||
id: str
|
||||
id: str
|
||||
type: str
|
||||
subclass_of: List[str] | None
|
||||
ontological_annotations: List[str] | None
|
||||
@@ -14,3 +26,19 @@ class Type(BaseModel):
|
||||
comment: str
|
||||
label: str
|
||||
restrictions: List[Restriction] | None
|
||||
|
||||
def to_ro(self) -> RdfsClass:
|
||||
return RdfsClass(id=self.id,
|
||||
self_type="rdfs:Class",
|
||||
subclass_of=serialize_subclass_of(self.subclass_of),
|
||||
ontological_annotations=None, rdfs_properties=None)
|
||||
|
||||
|
||||
|
||||
# def to_ro(self):
|
||||
# return RdfsClass(
|
||||
# id=RoId(id=self.id),
|
||||
# subclass_of=[RoId(id=i) for i in self.subclass_of if i] if self.subclass_of else [],
|
||||
# ontological_annotations=
|
||||
# equivalent_class=
|
||||
# )
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
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
|
||||
|
||||
rdfs_type = Type(
|
||||
id="Creator",
|
||||
type="Type",
|
||||
subclass_of=["https://schema.org/Thing"],
|
||||
ontological_annotations=["https://www.dublincore.org/specifications/dublin-core/dcmi-terms/terms/creator//"],
|
||||
rdfs_property=None,
|
||||
comment="",
|
||||
label="",
|
||||
restrictions=None
|
||||
)
|
||||
|
||||
serialized = rdfs_type.to_ro()
|
||||
print(serialized.model_dump_json(by_alias=True))
|
||||
|
||||
# # Define properties for Creator
|
||||
# has_name = TypeProperty(
|
||||
# id="hasName",
|
||||
# range_includes_data_type=[LiteralType.STRING]
|
||||
# )
|
||||
|
||||
# has_identifier = TypeProperty(
|
||||
# id="hasIdentifier",
|
||||
# range_includes_data_type=[LiteralType.STRING],
|
||||
# ontological_annotations=["https://www.dublincore.org/specifications/dublin-core/dcmi-terms/elements11/identifier/"]
|
||||
# )
|
||||
|
||||
# # Define the Creator type with its properties
|
||||
# creator_type = Type(
|
||||
# id="Creator",
|
||||
# type="Type",
|
||||
# subclass_of=["https://schema.org/Thing"],
|
||||
# ontological_annotations=["https://www.dublincore.org/specifications/dublin-core/dcmi-terms/terms/creator//"],
|
||||
# rdfs_property=[has_name, has_identifier],
|
||||
# comment="",
|
||||
# label="",
|
||||
# restrictions=None
|
||||
# )
|
||||
|
||||
# # Define properties for TextResource
|
||||
# has_date_submitted = TypeProperty(
|
||||
# id="hasDateSubmitted",
|
||||
# range_includes_data_type=[LiteralType.DATETIME],
|
||||
# ontological_annotations=["https://www.dublincore.org/specifications/dublin-core/dcmi-terms/terms/dateSubmitted/"]
|
||||
# )
|
||||
|
||||
# has_creator = TypeProperty(
|
||||
# id="hasCreator",
|
||||
# range_includes=[creator_type.id]
|
||||
# )
|
||||
|
||||
# # Define the TextResource type with its properties
|
||||
# text_resource_type = Type(
|
||||
# id="TextResource",
|
||||
# type="Type",
|
||||
# subclass_of=["https://schema.org/Thing"],
|
||||
# ontological_annotations=["https://www.dublincore.org/specifications/dublin-core/dcmi-terms/dcmitype/Text/"],
|
||||
# rdfs_property=[has_date_submitted, has_creator],
|
||||
# comment="",
|
||||
# label="",
|
||||
# restrictions=None
|
||||
# )
|
||||
|
||||
# # Create metadata entries
|
||||
# creator_entry = MetadataEntry(
|
||||
# id="creator1",
|
||||
# types={creator_type.id},
|
||||
# props={"hasName": "John Author", "hasIdentifier": "https://orcid.org/0000-0000-0000-0000"},
|
||||
# references={}
|
||||
# )
|
||||
|
||||
# text_resource_entry = MetadataEntry(
|
||||
# id="TextResource1",
|
||||
# types={text_resource_type.id},
|
||||
# props={"hasDate": "2025-01-21T07:12:20Z"},
|
||||
# references={"hasCreator": ["creator1"]}
|
||||
# )
|
||||
|
||||
# print(creator_entry.model_dump_json())
|
||||
Reference in New Issue
Block a user