From 69bfd20d89b00d6a217b5356f3cf3af35abe3d1e Mon Sep 17 00:00:00 2001 From: Nico Matentzoglu Date: Sat, 4 Oct 2025 12:17:13 +0300 Subject: [PATCH 01/11] Add valid and invalid MappingSpecification YAML test data Introduces new YAML files under tests/data/valid and tests/data/invalid to provide examples of both valid and invalid MappingSpecification objects. These files can be used for testing schema validation and error handling. --- .../invalid/MappingSpecification-001.yaml | 12 +++++++++ .../invalid/MappingSpecification-002.yaml | 11 ++++++++ .../invalid/MappingSpecification-003.yaml | 17 +++++++++++++ .../data/valid/MappingSpecification-001.yaml | 24 ++++++++++++++++++ .../data/valid/MappingSpecification-002.yaml | 25 +++++++++++++++++++ .../data/valid/MappingSpecification-003.yaml | 11 ++++++++ 6 files changed, 100 insertions(+) create mode 100644 tests/data/invalid/MappingSpecification-001.yaml create mode 100644 tests/data/invalid/MappingSpecification-002.yaml create mode 100644 tests/data/invalid/MappingSpecification-003.yaml create mode 100644 tests/data/valid/MappingSpecification-001.yaml create mode 100644 tests/data/valid/MappingSpecification-002.yaml create mode 100644 tests/data/valid/MappingSpecification-003.yaml diff --git a/tests/data/invalid/MappingSpecification-001.yaml b/tests/data/invalid/MappingSpecification-001.yaml new file mode 100644 index 0000000..c6435c1 --- /dev/null +++ b/tests/data/invalid/MappingSpecification-001.yaml @@ -0,0 +1,12 @@ +# Invalid MappingSpecification - author is a string instead of Agent object +--- +author: "Jane Smith" +content: https://example.org/mappings/invalid.sssom.tsv +subject_source: + name: Source X + content: https://example.org/source-x + content_type: text/plain +object_source: + name: Source Y + content: https://example.org/source-y + content_type: text/plain diff --git a/tests/data/invalid/MappingSpecification-002.yaml b/tests/data/invalid/MappingSpecification-002.yaml new file mode 100644 index 0000000..6772da0 --- /dev/null +++ b/tests/data/invalid/MappingSpecification-002.yaml @@ -0,0 +1,11 @@ +# Invalid MappingSpecification - subject_source is a string instead of Source object +--- +author: + id: example:author456 + name: Test Author +content: https://example.org/mapping.txt +subject_source: "Source A" +object_source: + name: Source B + content: https://example.org/source-b + content_type: text/plain diff --git a/tests/data/invalid/MappingSpecification-003.yaml b/tests/data/invalid/MappingSpecification-003.yaml new file mode 100644 index 0000000..a2e7ba0 --- /dev/null +++ b/tests/data/invalid/MappingSpecification-003.yaml @@ -0,0 +1,17 @@ +# Invalid MappingSpecification - creator is a list instead of Agent object +--- +author: + id: example:author789 + name: Another Author +creator: + - John Doe + - Jane Smith +content: https://example.org/mapping.txt +subject_source: + name: Valid Source + content: https://example.org/source-valid + content_type: text/plain +object_source: + name: Another Source + content: https://example.org/source-invalid + content_type: text/plain diff --git a/tests/data/valid/MappingSpecification-001.yaml b/tests/data/valid/MappingSpecification-001.yaml new file mode 100644 index 0000000..4e08ca9 --- /dev/null +++ b/tests/data/valid/MappingSpecification-001.yaml @@ -0,0 +1,24 @@ +# Valid MappingSpecification example - SSSOM mapping between two ontologies +--- +publication_date: "2024-01-15" +license: CC-BY-4.0 +version: "1.0.0" +description: Mappings between disease ontologies DO and MONDO +type: SSSOM +mapping_method: manual curation +documentation: https://example.org/do-mondo-mappings/docs +content: https://example.org/mappings/do-mondo.sssom.tsv +subject_source: + name: Disease Ontology + version: "2024-01-01" + type: owl ontology + documentation: https://disease-ontology.org/ + content: http://purl.obolibrary.org/obo/doid.owl + content_type: application/rdf+xml +object_source: + name: Mondo Disease Ontology + version: "2024-01-10" + type: owl ontology + documentation: https://mondo.monarchinitiative.org/ + content: http://purl.obolibrary.org/obo/mondo.owl + content_type: application/rdf+xml diff --git a/tests/data/valid/MappingSpecification-002.yaml b/tests/data/valid/MappingSpecification-002.yaml new file mode 100644 index 0000000..447d841 --- /dev/null +++ b/tests/data/valid/MappingSpecification-002.yaml @@ -0,0 +1,25 @@ +# Valid MappingSpecification example - R2RML mapping between database and RDF +--- + +publication_date: "2023-11-20" +license: Apache-2.0 +version: "2.1.0" +description: R2RML mapping from legacy patient database to FHIR RDF +type: R2RML +mapping_method: automated generation with manual review +documentation: https://example.org/patient-fhir-mapping +content: https://example.org/mappings/patient-db-to-fhir.r2rml.ttl +subject_source: + name: Patient Database + version: "v5.2" + type: relational database + documentation: https://example.org/db-schema + content: postgresql://example.org:5432/patients + content_type: application/sql +object_source: + name: FHIR RDF Ontology + version: "4.0.1" + type: rdf vocabulary + documentation: http://hl7.org/fhir/ + content: http://hl7.org/fhir/fhir.ttl + content_type: text/turtle diff --git a/tests/data/valid/MappingSpecification-003.yaml b/tests/data/valid/MappingSpecification-003.yaml new file mode 100644 index 0000000..c428187 --- /dev/null +++ b/tests/data/valid/MappingSpecification-003.yaml @@ -0,0 +1,11 @@ +# Valid MappingSpecification example - minimal required fields only +--- +content: https://example.org/minimal-mapping.txt +subject_source: + name: Source A + content: https://example.org/source-a + content_type: text/plain +object_source: + name: Source B + content: https://example.org/source-b + content_type: text/plain From 8db1a3a575de02e4425a0990b6dce8cc35eed650 Mon Sep 17 00:00:00 2001 From: Nico Matentzoglu Date: Sat, 4 Oct 2025 12:17:45 +0300 Subject: [PATCH 02/11] Add Agent, Source, and MappingSpecification classes to schema Introduces new classes (Agent, Source, MappingSpecification) and associated slots to the fair_mappings_schema.yaml. --- .../schema/fair_mappings_schema.yaml | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/src/fair_mappings_schema/schema/fair_mappings_schema.yaml b/src/fair_mappings_schema/schema/fair_mappings_schema.yaml index 917eba0..2bb1160 100644 --- a/src/fair_mappings_schema/schema/fair_mappings_schema.yaml +++ b/src/fair_mappings_schema/schema/fair_mappings_schema.yaml @@ -21,3 +21,89 @@ default_range: string imports: - linkml:types +classes: + + Agent: + description: An entity that can create or contribute to a digital object, such as an author or creator. + slots: + - id + - name + + Source: + description: >- + A data source from which entities are drawn, such as a database, ontology, or vocabulary. + slots: + - name + - version + - type + - documentation + - content + - content_type + MappingSpecification: + description: >- + A formal description of correspondences between entities in a source and a target, expressed as rules, functions, or mapping statements. + slots: + - author + - creator + - publication_date + - license + - version + - description + - type + - mapping_method + - documentation + - content + - subject_source + - object_source + +slots: + id: + description: Identifier for the information entity + identifier: true + range: string + name: + description: Name of the information entity + range: string + creator: + description: Creator of the mapping specification + range: Agent + inlined: true + author: + description: Author of the mapping specification + range: Agent + inlined: true + publication_date: + description: Date of publication of the mapping specification + range: string + license: + description: License under which the mapping specification is released + range: string + version: + description: Version of the digital object + range: string + description: + description: A brief description of the mapping specification + range: string + type: + description: Type of the information entity + range: string + mapping_method: + description: Method used to create the mapping specification + range: string + documentation: + description: URL or reference to documentation for the mapping specification + range: string + content: + description: Reference to the actual content of the digital object + range: string + content_type: + description: The type of the content of the digital object + range: string + subject_source: + description: The source from which the subject entities are drawn + range: Source + inlined: true + object_source: + description: The source from which the object entities are drawn + range: Source + inlined: true From fb758c0266a9c485e112a189f715194dbc5b4dfc Mon Sep 17 00:00:00 2001 From: Nico Matentzoglu Date: Sat, 4 Oct 2025 12:18:03 +0300 Subject: [PATCH 03/11] Generated schema (from gen-doc) --- .../datamodel/fair_mappings_schema.py | 212 +++++++++++------- .../fair_mappings_schema_pydantic.py | 97 +++----- 2 files changed, 161 insertions(+), 148 deletions(-) diff --git a/src/fair_mappings_schema/datamodel/fair_mappings_schema.py b/src/fair_mappings_schema/datamodel/fair_mappings_schema.py index 6342772..30b54b2 100644 --- a/src/fair_mappings_schema/datamodel/fair_mappings_schema.py +++ b/src/fair_mappings_schema/datamodel/fair_mappings_schema.py @@ -1,9 +1,9 @@ # Auto generated from fair_mappings_schema.yaml by pythongen.py version: 0.0.1 -# Generation date: 2025-10-04T08:59:50 +# Generation date: 2025-10-04T12:17:23 # Schema: fair-mappings-schema # # id: https://w3id.org/mapping-commons/fair-mappings-schema -# description: A basic metadata schema for FAIR mapping specifications +# description: A minimal metadata schema for FAIR mapping specifications # license: Apache-2.0 import dataclasses @@ -56,8 +56,7 @@ URIRef ) -from linkml_runtime.linkml_model.types import Date, Integer, String, Uriorcurie -from linkml_runtime.utils.metamodelcore import URIorCURIE, XSDDate +from linkml_runtime.linkml_model.types import String metamodel_version = "1.7.0" version = None @@ -75,151 +74,192 @@ # Types # Class references -class NamedThingId(URIorCURIE): - pass - - -class PersonId(NamedThingId): +class AgentId(extended_str): pass @dataclass(repr=False) -class NamedThing(YAMLRoot): +class Agent(YAMLRoot): """ - A generic grouping for any identifiable entity + An entity that can create or contribute to a digital object, such as an author or creator. """ _inherited_slots: ClassVar[list[str]] = [] - class_class_uri: ClassVar[URIRef] = SCHEMA["Thing"] - class_class_curie: ClassVar[str] = "schema:Thing" - class_name: ClassVar[str] = "NamedThing" - class_model_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA.NamedThing + class_class_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA["Agent"] + class_class_curie: ClassVar[str] = "fair_mappings_schema:Agent" + class_name: ClassVar[str] = "Agent" + class_model_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA.Agent - id: Union[str, NamedThingId] = None + id: Union[str, AgentId] = None name: Optional[str] = None - description: Optional[str] = None def __post_init__(self, *_: str, **kwargs: Any): if self._is_empty(self.id): self.MissingRequiredField("id") - if not isinstance(self.id, NamedThingId): - self.id = NamedThingId(self.id) + if not isinstance(self.id, AgentId): + self.id = AgentId(self.id) if self.name is not None and not isinstance(self.name, str): self.name = str(self.name) - if self.description is not None and not isinstance(self.description, str): - self.description = str(self.description) - super().__post_init__(**kwargs) @dataclass(repr=False) -class Person(NamedThing): +class Source(YAMLRoot): """ - Represents a Person + A data source from which entities are drawn, such as a database, ontology, or vocabulary. """ _inherited_slots: ClassVar[list[str]] = [] - class_class_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA["Person"] - class_class_curie: ClassVar[str] = "fair_mappings_schema:Person" - class_name: ClassVar[str] = "Person" - class_model_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA.Person + class_class_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA["Source"] + class_class_curie: ClassVar[str] = "fair_mappings_schema:Source" + class_name: ClassVar[str] = "Source" + class_model_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA.Source - id: Union[str, PersonId] = None - primary_email: Optional[str] = None - birth_date: Optional[Union[str, XSDDate]] = None - age_in_years: Optional[int] = None - vital_status: Optional[Union[str, "PersonStatus"]] = None + name: Optional[str] = None + version: Optional[str] = None + type: Optional[str] = None + documentation: Optional[str] = None + content: Optional[str] = None + content_type: Optional[str] = None def __post_init__(self, *_: str, **kwargs: Any): - if self._is_empty(self.id): - self.MissingRequiredField("id") - if not isinstance(self.id, PersonId): - self.id = PersonId(self.id) + if self.name is not None and not isinstance(self.name, str): + self.name = str(self.name) + + if self.version is not None and not isinstance(self.version, str): + self.version = str(self.version) - if self.primary_email is not None and not isinstance(self.primary_email, str): - self.primary_email = str(self.primary_email) + if self.type is not None and not isinstance(self.type, str): + self.type = str(self.type) - if self.birth_date is not None and not isinstance(self.birth_date, XSDDate): - self.birth_date = XSDDate(self.birth_date) + if self.documentation is not None and not isinstance(self.documentation, str): + self.documentation = str(self.documentation) - if self.age_in_years is not None and not isinstance(self.age_in_years, int): - self.age_in_years = int(self.age_in_years) + if self.content is not None and not isinstance(self.content, str): + self.content = str(self.content) - if self.vital_status is not None and not isinstance(self.vital_status, PersonStatus): - self.vital_status = PersonStatus(self.vital_status) + if self.content_type is not None and not isinstance(self.content_type, str): + self.content_type = str(self.content_type) super().__post_init__(**kwargs) @dataclass(repr=False) -class PersonCollection(YAMLRoot): +class MappingSpecification(YAMLRoot): """ - A holder for Person objects + A formal description of correspondences between entities in a source and a target, expressed as rules, functions, + or mapping statements. """ _inherited_slots: ClassVar[list[str]] = [] - class_class_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA["PersonCollection"] - class_class_curie: ClassVar[str] = "fair_mappings_schema:PersonCollection" - class_name: ClassVar[str] = "PersonCollection" - class_model_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA.PersonCollection + class_class_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA["MappingSpecification"] + class_class_curie: ClassVar[str] = "fair_mappings_schema:MappingSpecification" + class_name: ClassVar[str] = "MappingSpecification" + class_model_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA.MappingSpecification - entries: Optional[Union[dict[Union[str, PersonId], Union[dict, Person]], list[Union[dict, Person]]]] = empty_dict() + author: Optional[Union[dict, Agent]] = None + creator: Optional[Union[dict, Agent]] = None + publication_date: Optional[str] = None + license: Optional[str] = None + version: Optional[str] = None + description: Optional[str] = None + type: Optional[str] = None + mapping_method: Optional[str] = None + documentation: Optional[str] = None + content: Optional[str] = None + subject_source: Optional[Union[dict, Source]] = None + object_source: Optional[Union[dict, Source]] = None def __post_init__(self, *_: str, **kwargs: Any): - self._normalize_inlined_as_list(slot_name="entries", slot_type=Person, key_name="id", keyed=True) + if self.author is not None and not isinstance(self.author, Agent): + self.author = Agent(**as_dict(self.author)) + + if self.creator is not None and not isinstance(self.creator, Agent): + self.creator = Agent(**as_dict(self.creator)) + + if self.publication_date is not None and not isinstance(self.publication_date, str): + self.publication_date = str(self.publication_date) + + if self.license is not None and not isinstance(self.license, str): + self.license = str(self.license) + + if self.version is not None and not isinstance(self.version, str): + self.version = str(self.version) + + if self.description is not None and not isinstance(self.description, str): + self.description = str(self.description) + + if self.type is not None and not isinstance(self.type, str): + self.type = str(self.type) + + if self.mapping_method is not None and not isinstance(self.mapping_method, str): + self.mapping_method = str(self.mapping_method) + + if self.documentation is not None and not isinstance(self.documentation, str): + self.documentation = str(self.documentation) + + if self.content is not None and not isinstance(self.content, str): + self.content = str(self.content) + + if self.subject_source is not None and not isinstance(self.subject_source, Source): + self.subject_source = Source(**as_dict(self.subject_source)) + + if self.object_source is not None and not isinstance(self.object_source, Source): + self.object_source = Source(**as_dict(self.object_source)) super().__post_init__(**kwargs) # Enumerations -class PersonStatus(EnumDefinitionImpl): - - ALIVE = PermissibleValue( - text="ALIVE", - description="the person is living", - meaning=PATO["0001421"]) - DEAD = PermissibleValue( - text="DEAD", - description="the person is deceased", - meaning=PATO["0001422"]) - UNKNOWN = PermissibleValue( - text="UNKNOWN", - description="the vital status is not known") - - _defn = EnumDefinition( - name="PersonStatus", - ) + # Slots class slots: pass -slots.id = Slot(uri=SCHEMA.identifier, name="id", curie=SCHEMA.curie('identifier'), +slots.id = Slot(uri=FAIR_MAPPINGS_SCHEMA.id, name="id", curie=FAIR_MAPPINGS_SCHEMA.curie('id'), model_uri=FAIR_MAPPINGS_SCHEMA.id, domain=None, range=URIRef) -slots.name = Slot(uri=SCHEMA.name, name="name", curie=SCHEMA.curie('name'), +slots.name = Slot(uri=FAIR_MAPPINGS_SCHEMA.name, name="name", curie=FAIR_MAPPINGS_SCHEMA.curie('name'), model_uri=FAIR_MAPPINGS_SCHEMA.name, domain=None, range=Optional[str]) -slots.description = Slot(uri=SCHEMA.description, name="description", curie=SCHEMA.curie('description'), +slots.creator = Slot(uri=FAIR_MAPPINGS_SCHEMA.creator, name="creator", curie=FAIR_MAPPINGS_SCHEMA.curie('creator'), + model_uri=FAIR_MAPPINGS_SCHEMA.creator, domain=None, range=Optional[Union[dict, Agent]]) + +slots.author = Slot(uri=FAIR_MAPPINGS_SCHEMA.author, name="author", curie=FAIR_MAPPINGS_SCHEMA.curie('author'), + model_uri=FAIR_MAPPINGS_SCHEMA.author, domain=None, range=Optional[Union[dict, Agent]]) + +slots.publication_date = Slot(uri=FAIR_MAPPINGS_SCHEMA.publication_date, name="publication_date", curie=FAIR_MAPPINGS_SCHEMA.curie('publication_date'), + model_uri=FAIR_MAPPINGS_SCHEMA.publication_date, domain=None, range=Optional[str]) + +slots.license = Slot(uri=FAIR_MAPPINGS_SCHEMA.license, name="license", curie=FAIR_MAPPINGS_SCHEMA.curie('license'), + model_uri=FAIR_MAPPINGS_SCHEMA.license, domain=None, range=Optional[str]) + +slots.version = Slot(uri=FAIR_MAPPINGS_SCHEMA.version, name="version", curie=FAIR_MAPPINGS_SCHEMA.curie('version'), + model_uri=FAIR_MAPPINGS_SCHEMA.version, domain=None, range=Optional[str]) + +slots.description = Slot(uri=FAIR_MAPPINGS_SCHEMA.description, name="description", curie=FAIR_MAPPINGS_SCHEMA.curie('description'), model_uri=FAIR_MAPPINGS_SCHEMA.description, domain=None, range=Optional[str]) -slots.primary_email = Slot(uri=SCHEMA.email, name="primary_email", curie=SCHEMA.curie('email'), - model_uri=FAIR_MAPPINGS_SCHEMA.primary_email, domain=None, range=Optional[str]) +slots.type = Slot(uri=FAIR_MAPPINGS_SCHEMA.type, name="type", curie=FAIR_MAPPINGS_SCHEMA.curie('type'), + model_uri=FAIR_MAPPINGS_SCHEMA.type, domain=None, range=Optional[str]) + +slots.mapping_method = Slot(uri=FAIR_MAPPINGS_SCHEMA.mapping_method, name="mapping_method", curie=FAIR_MAPPINGS_SCHEMA.curie('mapping_method'), + model_uri=FAIR_MAPPINGS_SCHEMA.mapping_method, domain=None, range=Optional[str]) -slots.birth_date = Slot(uri=SCHEMA.birthDate, name="birth_date", curie=SCHEMA.curie('birthDate'), - model_uri=FAIR_MAPPINGS_SCHEMA.birth_date, domain=None, range=Optional[Union[str, XSDDate]]) +slots.documentation = Slot(uri=FAIR_MAPPINGS_SCHEMA.documentation, name="documentation", curie=FAIR_MAPPINGS_SCHEMA.curie('documentation'), + model_uri=FAIR_MAPPINGS_SCHEMA.documentation, domain=None, range=Optional[str]) -slots.age_in_years = Slot(uri=FAIR_MAPPINGS_SCHEMA.age_in_years, name="age_in_years", curie=FAIR_MAPPINGS_SCHEMA.curie('age_in_years'), - model_uri=FAIR_MAPPINGS_SCHEMA.age_in_years, domain=None, range=Optional[int]) +slots.content = Slot(uri=FAIR_MAPPINGS_SCHEMA.content, name="content", curie=FAIR_MAPPINGS_SCHEMA.curie('content'), + model_uri=FAIR_MAPPINGS_SCHEMA.content, domain=None, range=Optional[str]) -slots.vital_status = Slot(uri=FAIR_MAPPINGS_SCHEMA.vital_status, name="vital_status", curie=FAIR_MAPPINGS_SCHEMA.curie('vital_status'), - model_uri=FAIR_MAPPINGS_SCHEMA.vital_status, domain=None, range=Optional[Union[str, "PersonStatus"]]) +slots.content_type = Slot(uri=FAIR_MAPPINGS_SCHEMA.content_type, name="content_type", curie=FAIR_MAPPINGS_SCHEMA.curie('content_type'), + model_uri=FAIR_MAPPINGS_SCHEMA.content_type, domain=None, range=Optional[str]) -slots.personCollection__entries = Slot(uri=FAIR_MAPPINGS_SCHEMA.entries, name="personCollection__entries", curie=FAIR_MAPPINGS_SCHEMA.curie('entries'), - model_uri=FAIR_MAPPINGS_SCHEMA.personCollection__entries, domain=None, range=Optional[Union[dict[Union[str, PersonId], Union[dict, Person]], list[Union[dict, Person]]]]) +slots.subject_source = Slot(uri=FAIR_MAPPINGS_SCHEMA.subject_source, name="subject_source", curie=FAIR_MAPPINGS_SCHEMA.curie('subject_source'), + model_uri=FAIR_MAPPINGS_SCHEMA.subject_source, domain=None, range=Optional[Union[dict, Source]]) -slots.Person_primary_email = Slot(uri=SCHEMA.email, name="Person_primary_email", curie=SCHEMA.curie('email'), - model_uri=FAIR_MAPPINGS_SCHEMA.Person_primary_email, domain=Person, range=Optional[str], - pattern=re.compile(r'^\S+@[\S+\.]+\S+')) +slots.object_source = Slot(uri=FAIR_MAPPINGS_SCHEMA.object_source, name="object_source", curie=FAIR_MAPPINGS_SCHEMA.curie('object_source'), + model_uri=FAIR_MAPPINGS_SCHEMA.object_source, domain=None, range=Optional[Union[dict, Source]]) diff --git a/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py b/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py index 0d662cb..348f58d 100644 --- a/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py +++ b/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py @@ -63,7 +63,7 @@ def __contains__(self, key:str) -> bool: linkml_meta = LinkMLMeta({'default_prefix': 'fair_mappings_schema', 'default_range': 'string', - 'description': 'A basic metadata schema for FAIR mapping specifications', + 'description': 'A minimal metadata schema for FAIR mapping specifications', 'id': 'https://w3id.org/mapping-commons/fair-mappings-schema', 'imports': ['linkml:types'], 'license': 'Apache-2.0', @@ -84,81 +84,54 @@ def __contains__(self, key:str) -> bool: 'source_file': 'src/fair_mappings_schema/schema/fair_mappings_schema.yaml', 'title': 'fair-mappings-schema'} ) -class PersonStatus(str, Enum): - ALIVE = "ALIVE" - """ - the person is living - """ - DEAD = "DEAD" - """ - the person is deceased - """ - UNKNOWN = "UNKNOWN" + +class Agent(ConfiguredBaseModel): """ - the vital status is not known + An entity that can create or contribute to a digital object, such as an author or creator. """ + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema'}) + id: str = Field(default=..., description="""Identifier for the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'id', 'domain_of': ['Agent']} }) + name: Optional[str] = Field(default=None, description="""Name of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['Agent', 'Source']} }) -class NamedThing(ConfiguredBaseModel): +class Source(ConfiguredBaseModel): """ - A generic grouping for any identifiable entity + A data source from which entities are drawn, such as a database, ontology, or vocabulary. """ - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'class_uri': 'schema:Thing', - 'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema'}) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema'}) - id: str = Field(default=..., description="""A unique identifier for a thing""", json_schema_extra = { "linkml_meta": {'alias': 'id', 'domain_of': ['NamedThing'], 'slot_uri': 'schema:identifier'} }) - name: Optional[str] = Field(default=None, description="""A human-readable name for a thing""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['NamedThing'], 'slot_uri': 'schema:name'} }) - description: Optional[str] = Field(default=None, description="""A human-readable description for a thing""", json_schema_extra = { "linkml_meta": {'alias': 'description', - 'domain_of': ['NamedThing'], - 'slot_uri': 'schema:description'} }) + name: Optional[str] = Field(default=None, description="""Name of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['Agent', 'Source']} }) + version: Optional[str] = Field(default=None, description="""Version of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'version', 'domain_of': ['Source', 'MappingSpecification']} }) + type: Optional[str] = Field(default=None, description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', 'domain_of': ['Source', 'MappingSpecification']} }) + documentation: Optional[str] = Field(default=None, description="""URL or reference to documentation for the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'documentation', 'domain_of': ['Source', 'MappingSpecification']} }) + content: Optional[str] = Field(default=None, description="""Reference to the actual content of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'content', 'domain_of': ['Source', 'MappingSpecification']} }) + content_type: Optional[str] = Field(default=None, description="""The type of the content of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'content_type', 'domain_of': ['Source']} }) -class Person(NamedThing): - """ - Represents a Person +class MappingSpecification(ConfiguredBaseModel): """ - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema', - 'slot_usage': {'primary_email': {'name': 'primary_email', - 'pattern': '^\\S+@[\\S+\\.]+\\S+'}}}) - - primary_email: Optional[str] = Field(default=None, description="""The main email address of a person""", json_schema_extra = { "linkml_meta": {'alias': 'primary_email', 'domain_of': ['Person'], 'slot_uri': 'schema:email'} }) - birth_date: Optional[date] = Field(default=None, description="""Date on which a person is born""", json_schema_extra = { "linkml_meta": {'alias': 'birth_date', 'domain_of': ['Person'], 'slot_uri': 'schema:birthDate'} }) - age_in_years: Optional[int] = Field(default=None, description="""Number of years since birth""", json_schema_extra = { "linkml_meta": {'alias': 'age_in_years', 'domain_of': ['Person']} }) - vital_status: Optional[PersonStatus] = Field(default=None, description="""living or dead status""", json_schema_extra = { "linkml_meta": {'alias': 'vital_status', 'domain_of': ['Person']} }) - id: str = Field(default=..., description="""A unique identifier for a thing""", json_schema_extra = { "linkml_meta": {'alias': 'id', 'domain_of': ['NamedThing'], 'slot_uri': 'schema:identifier'} }) - name: Optional[str] = Field(default=None, description="""A human-readable name for a thing""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['NamedThing'], 'slot_uri': 'schema:name'} }) - description: Optional[str] = Field(default=None, description="""A human-readable description for a thing""", json_schema_extra = { "linkml_meta": {'alias': 'description', - 'domain_of': ['NamedThing'], - 'slot_uri': 'schema:description'} }) - - @field_validator('primary_email') - def pattern_primary_email(cls, v): - pattern=re.compile(r"^\S+@[\S+\.]+\S+") - if isinstance(v, list): - for element in v: - if isinstance(element, str) and not pattern.match(element): - err_msg = f"Invalid primary_email format: {element}" - raise ValueError(err_msg) - elif isinstance(v, str) and not pattern.match(v): - err_msg = f"Invalid primary_email format: {v}" - raise ValueError(err_msg) - return v - - -class PersonCollection(ConfiguredBaseModel): + A formal description of correspondences between entities in a source and a target, expressed as rules, functions, or mapping statements. """ - A holder for Person objects - """ - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema', - 'tree_root': True}) - - entries: Optional[list[Person]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'entries', 'domain_of': ['PersonCollection']} }) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema'}) + + author: Optional[Agent] = Field(default=None, description="""Author of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'author', 'domain_of': ['MappingSpecification']} }) + creator: Optional[Agent] = Field(default=None, description="""Creator of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'creator', 'domain_of': ['MappingSpecification']} }) + publication_date: Optional[str] = Field(default=None, description="""Date of publication of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'publication_date', 'domain_of': ['MappingSpecification']} }) + license: Optional[str] = Field(default=None, description="""License under which the mapping specification is released""", json_schema_extra = { "linkml_meta": {'alias': 'license', 'domain_of': ['MappingSpecification']} }) + version: Optional[str] = Field(default=None, description="""Version of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'version', 'domain_of': ['Source', 'MappingSpecification']} }) + description: Optional[str] = Field(default=None, description="""A brief description of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'description', 'domain_of': ['MappingSpecification']} }) + type: Optional[str] = Field(default=None, description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', 'domain_of': ['Source', 'MappingSpecification']} }) + mapping_method: Optional[str] = Field(default=None, description="""Method used to create the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'mapping_method', 'domain_of': ['MappingSpecification']} }) + documentation: Optional[str] = Field(default=None, description="""URL or reference to documentation for the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'documentation', 'domain_of': ['Source', 'MappingSpecification']} }) + content: Optional[str] = Field(default=None, description="""Reference to the actual content of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'content', 'domain_of': ['Source', 'MappingSpecification']} }) + subject_source: Optional[Source] = Field(default=None, description="""The source from which the subject entities are drawn""", json_schema_extra = { "linkml_meta": {'alias': 'subject_source', 'domain_of': ['MappingSpecification']} }) + object_source: Optional[Source] = Field(default=None, description="""The source from which the object entities are drawn""", json_schema_extra = { "linkml_meta": {'alias': 'object_source', 'domain_of': ['MappingSpecification']} }) # Model rebuild # see https://pydantic-docs.helpmanual.io/usage/models/#rebuilding-a-model -NamedThing.model_rebuild() -Person.model_rebuild() -PersonCollection.model_rebuild() +Agent.model_rebuild() +Source.model_rebuild() +MappingSpecification.model_rebuild() From 06ca205330f9cdcef03e875b2fee8f8f203f5735 Mon Sep 17 00:00:00 2001 From: Nico Matentzoglu Date: Mon, 6 Oct 2025 00:31:41 +0300 Subject: [PATCH 04/11] Add enums and slot usages for agent, source, and mapping types Introduced AgentTypeEnum, SourceTypeEnum, and MappingSpecificationTypeEnum to define permissible values for agent, source, and mapping specification types. Updated the Agent, Source, and MappingSpecification classes to use these enums via slot_usage. Added new slots for version, type, and reviewer to relevant classes to enhance schema expressiveness. --- .../schema/fair_mappings_schema.yaml | 70 ++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/src/fair_mappings_schema/schema/fair_mappings_schema.yaml b/src/fair_mappings_schema/schema/fair_mappings_schema.yaml index 2bb1160..6964f62 100644 --- a/src/fair_mappings_schema/schema/fair_mappings_schema.yaml +++ b/src/fair_mappings_schema/schema/fair_mappings_schema.yaml @@ -21,6 +21,49 @@ default_range: string imports: - linkml:types +enums: + AgentTypeEnum: + description: Types of agents that can contribute to a mapping specification + permissible_values: + person: + description: An individual person + organization: + description: An organization or institution + software: + description: A software tool or system + + SourceTypeEnum: + description: Types of data sources + permissible_values: + owl_ontology: + description: An ontology in OWL format + database: + description: A relational or other database + skos_vocabulary: + description: A SKOS vocabulary or terminology + rdf_vocabulary: + description: An RDF vocabulary or schema + schema: + description: A data schema or model + api: + description: An API or web service + other: + description: Other type of source + + MappingSpecificationTypeEnum: + description: Types of mapping specifications + permissible_values: + sssom: + description: Simple Standard for Sharing Ontological Mappings + r2rml: + description: RDB to RDF Mapping Language + rml: + description: RDF Mapping Language + sparql: + description: SPARQL-based mapping + other: + description: Other type of mapping specification + classes: Agent: @@ -28,38 +71,53 @@ classes: slots: - id - name + - version + - type + slot_usage: + type: + range: AgentTypeEnum Source: description: >- A data source from which entities are drawn, such as a database, ontology, or vocabulary. slots: + - id - name - version - type - documentation - content - content_type + slot_usage: + type: + range: SourceTypeEnum MappingSpecification: description: >- A formal description of correspondences between entities in a source and a target, expressed as rules, functions, or mapping statements. + tree_root: true slots: + - id + - name + - description - author - creator + - reviewer - publication_date - license - version - - description - type - mapping_method - documentation - content - subject_source - object_source + slot_usage: + type: + range: MappingSpecificationTypeEnum slots: id: description: Identifier for the information entity - identifier: true range: string name: description: Name of the information entity @@ -72,6 +130,14 @@ slots: description: Author of the mapping specification range: Agent inlined: true + reviewer: + description: Reviewer of the mapping specification + range: Agent + inlined: true + mapping_tool: + description: The tool used to create the mapping specification + range: Agent + inlined: true publication_date: description: Date of publication of the mapping specification range: string From b45695f8bbc3000c187180faab0cdfcb22b00c8f Mon Sep 17 00:00:00 2001 From: Nico Matentzoglu Date: Mon, 6 Oct 2025 00:31:59 +0300 Subject: [PATCH 05/11] Updated downstream schema files --- .../datamodel/fair_mappings_schema.py | 149 +++++++++++++++--- .../fair_mappings_schema_pydantic.py | 111 +++++++++++-- 2 files changed, 229 insertions(+), 31 deletions(-) diff --git a/src/fair_mappings_schema/datamodel/fair_mappings_schema.py b/src/fair_mappings_schema/datamodel/fair_mappings_schema.py index 30b54b2..4743270 100644 --- a/src/fair_mappings_schema/datamodel/fair_mappings_schema.py +++ b/src/fair_mappings_schema/datamodel/fair_mappings_schema.py @@ -1,5 +1,5 @@ # Auto generated from fair_mappings_schema.yaml by pythongen.py version: 0.0.1 -# Generation date: 2025-10-04T12:17:23 +# Generation date: 2025-10-06T00:29:50 # Schema: fair-mappings-schema # # id: https://w3id.org/mapping-commons/fair-mappings-schema @@ -74,8 +74,7 @@ # Types # Class references -class AgentId(extended_str): - pass + @dataclass(repr=False) @@ -90,18 +89,24 @@ class Agent(YAMLRoot): class_name: ClassVar[str] = "Agent" class_model_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA.Agent - id: Union[str, AgentId] = None + id: Optional[str] = None name: Optional[str] = None + version: Optional[str] = None + type: Optional[Union[str, "AgentTypeEnum"]] = None def __post_init__(self, *_: str, **kwargs: Any): - if self._is_empty(self.id): - self.MissingRequiredField("id") - if not isinstance(self.id, AgentId): - self.id = AgentId(self.id) + if self.id is not None and not isinstance(self.id, str): + self.id = str(self.id) if self.name is not None and not isinstance(self.name, str): self.name = str(self.name) + if self.version is not None and not isinstance(self.version, str): + self.version = str(self.version) + + if self.type is not None and not isinstance(self.type, AgentTypeEnum): + self.type = AgentTypeEnum(self.type) + super().__post_init__(**kwargs) @@ -117,22 +122,26 @@ class Source(YAMLRoot): class_name: ClassVar[str] = "Source" class_model_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA.Source + id: Optional[str] = None name: Optional[str] = None version: Optional[str] = None - type: Optional[str] = None + type: Optional[Union[str, "SourceTypeEnum"]] = None documentation: Optional[str] = None content: Optional[str] = None content_type: Optional[str] = None def __post_init__(self, *_: str, **kwargs: Any): + if self.id is not None and not isinstance(self.id, str): + self.id = str(self.id) + if self.name is not None and not isinstance(self.name, str): self.name = str(self.name) if self.version is not None and not isinstance(self.version, str): self.version = str(self.version) - if self.type is not None and not isinstance(self.type, str): - self.type = str(self.type) + if self.type is not None and not isinstance(self.type, SourceTypeEnum): + self.type = SourceTypeEnum(self.type) if self.documentation is not None and not isinstance(self.documentation, str): self.documentation = str(self.documentation) @@ -159,13 +168,16 @@ class MappingSpecification(YAMLRoot): class_name: ClassVar[str] = "MappingSpecification" class_model_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA.MappingSpecification + id: Optional[str] = None + name: Optional[str] = None + description: Optional[str] = None author: Optional[Union[dict, Agent]] = None creator: Optional[Union[dict, Agent]] = None + reviewer: Optional[Union[dict, Agent]] = None publication_date: Optional[str] = None license: Optional[str] = None version: Optional[str] = None - description: Optional[str] = None - type: Optional[str] = None + type: Optional[Union[str, "MappingSpecificationTypeEnum"]] = None mapping_method: Optional[str] = None documentation: Optional[str] = None content: Optional[str] = None @@ -173,12 +185,24 @@ class MappingSpecification(YAMLRoot): object_source: Optional[Union[dict, Source]] = None def __post_init__(self, *_: str, **kwargs: Any): + if self.id is not None and not isinstance(self.id, str): + self.id = str(self.id) + + if self.name is not None and not isinstance(self.name, str): + self.name = str(self.name) + + if self.description is not None and not isinstance(self.description, str): + self.description = str(self.description) + if self.author is not None and not isinstance(self.author, Agent): self.author = Agent(**as_dict(self.author)) if self.creator is not None and not isinstance(self.creator, Agent): self.creator = Agent(**as_dict(self.creator)) + if self.reviewer is not None and not isinstance(self.reviewer, Agent): + self.reviewer = Agent(**as_dict(self.reviewer)) + if self.publication_date is not None and not isinstance(self.publication_date, str): self.publication_date = str(self.publication_date) @@ -188,11 +212,8 @@ def __post_init__(self, *_: str, **kwargs: Any): if self.version is not None and not isinstance(self.version, str): self.version = str(self.version) - if self.description is not None and not isinstance(self.description, str): - self.description = str(self.description) - - if self.type is not None and not isinstance(self.type, str): - self.type = str(self.type) + if self.type is not None and not isinstance(self.type, MappingSpecificationTypeEnum): + self.type = MappingSpecificationTypeEnum(self.type) if self.mapping_method is not None and not isinstance(self.mapping_method, str): self.mapping_method = str(self.mapping_method) @@ -213,14 +234,87 @@ def __post_init__(self, *_: str, **kwargs: Any): # Enumerations - +class AgentTypeEnum(EnumDefinitionImpl): + """ + Types of agents that can contribute to a mapping specification + """ + person = PermissibleValue( + text="person", + description="An individual person") + organization = PermissibleValue( + text="organization", + description="An organization or institution") + software = PermissibleValue( + text="software", + description="A software tool or system") + + _defn = EnumDefinition( + name="AgentTypeEnum", + description="Types of agents that can contribute to a mapping specification", + ) + +class SourceTypeEnum(EnumDefinitionImpl): + """ + Types of data sources + """ + owl_ontology = PermissibleValue( + text="owl_ontology", + description="An ontology in OWL format") + database = PermissibleValue( + text="database", + description="A relational or other database") + skos_vocabulary = PermissibleValue( + text="skos_vocabulary", + description="A SKOS vocabulary or terminology") + rdf_vocabulary = PermissibleValue( + text="rdf_vocabulary", + description="An RDF vocabulary or schema") + schema = PermissibleValue( + text="schema", + description="A data schema or model") + api = PermissibleValue( + text="api", + description="An API or web service") + other = PermissibleValue( + text="other", + description="Other type of source") + + _defn = EnumDefinition( + name="SourceTypeEnum", + description="Types of data sources", + ) + +class MappingSpecificationTypeEnum(EnumDefinitionImpl): + """ + Types of mapping specifications + """ + sssom = PermissibleValue( + text="sssom", + description="Simple Standard for Sharing Ontological Mappings") + r2rml = PermissibleValue( + text="r2rml", + description="RDB to RDF Mapping Language") + rml = PermissibleValue( + text="rml", + description="RDF Mapping Language") + sparql = PermissibleValue( + text="sparql", + description="SPARQL-based mapping") + custom = PermissibleValue( + text="custom", + description="Custom mapping format") + + _defn = EnumDefinition( + name="MappingSpecificationTypeEnum", + description="Types of mapping specifications", + ) # Slots class slots: pass slots.id = Slot(uri=FAIR_MAPPINGS_SCHEMA.id, name="id", curie=FAIR_MAPPINGS_SCHEMA.curie('id'), - model_uri=FAIR_MAPPINGS_SCHEMA.id, domain=None, range=URIRef) + model_uri=FAIR_MAPPINGS_SCHEMA.id, domain=None, range=Optional[str]) slots.name = Slot(uri=FAIR_MAPPINGS_SCHEMA.name, name="name", curie=FAIR_MAPPINGS_SCHEMA.curie('name'), model_uri=FAIR_MAPPINGS_SCHEMA.name, domain=None, range=Optional[str]) @@ -231,6 +325,12 @@ class slots: slots.author = Slot(uri=FAIR_MAPPINGS_SCHEMA.author, name="author", curie=FAIR_MAPPINGS_SCHEMA.curie('author'), model_uri=FAIR_MAPPINGS_SCHEMA.author, domain=None, range=Optional[Union[dict, Agent]]) +slots.reviewer = Slot(uri=FAIR_MAPPINGS_SCHEMA.reviewer, name="reviewer", curie=FAIR_MAPPINGS_SCHEMA.curie('reviewer'), + model_uri=FAIR_MAPPINGS_SCHEMA.reviewer, domain=None, range=Optional[Union[dict, Agent]]) + +slots.mapping_tool = Slot(uri=FAIR_MAPPINGS_SCHEMA.mapping_tool, name="mapping_tool", curie=FAIR_MAPPINGS_SCHEMA.curie('mapping_tool'), + model_uri=FAIR_MAPPINGS_SCHEMA.mapping_tool, domain=None, range=Optional[Union[dict, Agent]]) + slots.publication_date = Slot(uri=FAIR_MAPPINGS_SCHEMA.publication_date, name="publication_date", curie=FAIR_MAPPINGS_SCHEMA.curie('publication_date'), model_uri=FAIR_MAPPINGS_SCHEMA.publication_date, domain=None, range=Optional[str]) @@ -263,3 +363,12 @@ class slots: slots.object_source = Slot(uri=FAIR_MAPPINGS_SCHEMA.object_source, name="object_source", curie=FAIR_MAPPINGS_SCHEMA.curie('object_source'), model_uri=FAIR_MAPPINGS_SCHEMA.object_source, domain=None, range=Optional[Union[dict, Source]]) + +slots.Agent_type = Slot(uri=FAIR_MAPPINGS_SCHEMA.type, name="Agent_type", curie=FAIR_MAPPINGS_SCHEMA.curie('type'), + model_uri=FAIR_MAPPINGS_SCHEMA.Agent_type, domain=Agent, range=Optional[Union[str, "AgentTypeEnum"]]) + +slots.Source_type = Slot(uri=FAIR_MAPPINGS_SCHEMA.type, name="Source_type", curie=FAIR_MAPPINGS_SCHEMA.curie('type'), + model_uri=FAIR_MAPPINGS_SCHEMA.Source_type, domain=Source, range=Optional[Union[str, "SourceTypeEnum"]]) + +slots.MappingSpecification_type = Slot(uri=FAIR_MAPPINGS_SCHEMA.type, name="MappingSpecification_type", curie=FAIR_MAPPINGS_SCHEMA.curie('type'), + model_uri=FAIR_MAPPINGS_SCHEMA.MappingSpecification_type, domain=MappingSpecification, range=Optional[Union[str, "MappingSpecificationTypeEnum"]]) diff --git a/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py b/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py index 348f58d..14a8a57 100644 --- a/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py +++ b/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py @@ -84,26 +84,109 @@ def __contains__(self, key:str) -> bool: 'source_file': 'src/fair_mappings_schema/schema/fair_mappings_schema.yaml', 'title': 'fair-mappings-schema'} ) +class AgentTypeEnum(str, Enum): + """ + Types of agents that can contribute to a mapping specification + """ + person = "person" + """ + An individual person + """ + organization = "organization" + """ + An organization or institution + """ + software = "software" + """ + A software tool or system + """ + + +class SourceTypeEnum(str, Enum): + """ + Types of data sources + """ + owl_ontology = "owl_ontology" + """ + An ontology in OWL format + """ + database = "database" + """ + A relational or other database + """ + skos_vocabulary = "skos_vocabulary" + """ + A SKOS vocabulary or terminology + """ + rdf_vocabulary = "rdf_vocabulary" + """ + An RDF vocabulary or schema + """ + schema = "schema" + """ + A data schema or model + """ + api = "api" + """ + An API or web service + """ + other = "other" + """ + Other type of source + """ + + +class MappingSpecificationTypeEnum(str, Enum): + """ + Types of mapping specifications + """ + sssom = "sssom" + """ + Simple Standard for Sharing Ontological Mappings + """ + r2rml = "r2rml" + """ + RDB to RDF Mapping Language + """ + rml = "rml" + """ + RDF Mapping Language + """ + sparql = "sparql" + """ + SPARQL-based mapping + """ + custom = "custom" + """ + Custom mapping format + """ + + class Agent(ConfiguredBaseModel): """ An entity that can create or contribute to a digital object, such as an author or creator. """ - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema'}) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema', + 'slot_usage': {'type': {'name': 'type', 'range': 'AgentTypeEnum'}}}) - id: str = Field(default=..., description="""Identifier for the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'id', 'domain_of': ['Agent']} }) - name: Optional[str] = Field(default=None, description="""Name of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['Agent', 'Source']} }) + id: Optional[str] = Field(default=None, description="""Identifier for the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'id', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + name: Optional[str] = Field(default=None, description="""Name of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + version: Optional[str] = Field(default=None, description="""Version of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'version', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + type: Optional[AgentTypeEnum] = Field(default=None, description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) class Source(ConfiguredBaseModel): """ A data source from which entities are drawn, such as a database, ontology, or vocabulary. """ - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema'}) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema', + 'slot_usage': {'type': {'name': 'type', 'range': 'SourceTypeEnum'}}}) - name: Optional[str] = Field(default=None, description="""Name of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['Agent', 'Source']} }) - version: Optional[str] = Field(default=None, description="""Version of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'version', 'domain_of': ['Source', 'MappingSpecification']} }) - type: Optional[str] = Field(default=None, description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', 'domain_of': ['Source', 'MappingSpecification']} }) + id: Optional[str] = Field(default=None, description="""Identifier for the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'id', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + name: Optional[str] = Field(default=None, description="""Name of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + version: Optional[str] = Field(default=None, description="""Version of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'version', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + type: Optional[SourceTypeEnum] = Field(default=None, description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) documentation: Optional[str] = Field(default=None, description="""URL or reference to documentation for the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'documentation', 'domain_of': ['Source', 'MappingSpecification']} }) content: Optional[str] = Field(default=None, description="""Reference to the actual content of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'content', 'domain_of': ['Source', 'MappingSpecification']} }) content_type: Optional[str] = Field(default=None, description="""The type of the content of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'content_type', 'domain_of': ['Source']} }) @@ -113,15 +196,21 @@ class MappingSpecification(ConfiguredBaseModel): """ A formal description of correspondences between entities in a source and a target, expressed as rules, functions, or mapping statements. """ - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema'}) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema', + 'slot_usage': {'type': {'name': 'type', + 'range': 'MappingSpecificationTypeEnum'}}, + 'tree_root': True}) + id: Optional[str] = Field(default=None, description="""Identifier for the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'id', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + name: Optional[str] = Field(default=None, description="""Name of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + description: Optional[str] = Field(default=None, description="""A brief description of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'description', 'domain_of': ['MappingSpecification']} }) author: Optional[Agent] = Field(default=None, description="""Author of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'author', 'domain_of': ['MappingSpecification']} }) creator: Optional[Agent] = Field(default=None, description="""Creator of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'creator', 'domain_of': ['MappingSpecification']} }) + reviewer: Optional[Agent] = Field(default=None, description="""Reviewer of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'reviewer', 'domain_of': ['MappingSpecification']} }) publication_date: Optional[str] = Field(default=None, description="""Date of publication of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'publication_date', 'domain_of': ['MappingSpecification']} }) license: Optional[str] = Field(default=None, description="""License under which the mapping specification is released""", json_schema_extra = { "linkml_meta": {'alias': 'license', 'domain_of': ['MappingSpecification']} }) - version: Optional[str] = Field(default=None, description="""Version of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'version', 'domain_of': ['Source', 'MappingSpecification']} }) - description: Optional[str] = Field(default=None, description="""A brief description of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'description', 'domain_of': ['MappingSpecification']} }) - type: Optional[str] = Field(default=None, description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', 'domain_of': ['Source', 'MappingSpecification']} }) + version: Optional[str] = Field(default=None, description="""Version of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'version', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + type: Optional[MappingSpecificationTypeEnum] = Field(default=None, description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) mapping_method: Optional[str] = Field(default=None, description="""Method used to create the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'mapping_method', 'domain_of': ['MappingSpecification']} }) documentation: Optional[str] = Field(default=None, description="""URL or reference to documentation for the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'documentation', 'domain_of': ['Source', 'MappingSpecification']} }) content: Optional[str] = Field(default=None, description="""Reference to the actual content of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'content', 'domain_of': ['Source', 'MappingSpecification']} }) From 483974eb496790015d3673368c17249b996a936f Mon Sep 17 00:00:00 2001 From: Nico Matentzoglu Date: Mon, 6 Oct 2025 00:32:38 +0300 Subject: [PATCH 06/11] Update test files to be schema conformant --- tests/data/valid/MappingSpecification-001.yaml | 2 +- tests/data/valid/MappingSpecification-002.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/data/valid/MappingSpecification-001.yaml b/tests/data/valid/MappingSpecification-001.yaml index 4e08ca9..1dff7ac 100644 --- a/tests/data/valid/MappingSpecification-001.yaml +++ b/tests/data/valid/MappingSpecification-001.yaml @@ -4,7 +4,7 @@ publication_date: "2024-01-15" license: CC-BY-4.0 version: "1.0.0" description: Mappings between disease ontologies DO and MONDO -type: SSSOM +type: sssom mapping_method: manual curation documentation: https://example.org/do-mondo-mappings/docs content: https://example.org/mappings/do-mondo.sssom.tsv diff --git a/tests/data/valid/MappingSpecification-002.yaml b/tests/data/valid/MappingSpecification-002.yaml index 447d841..e52167a 100644 --- a/tests/data/valid/MappingSpecification-002.yaml +++ b/tests/data/valid/MappingSpecification-002.yaml @@ -5,14 +5,14 @@ publication_date: "2023-11-20" license: Apache-2.0 version: "2.1.0" description: R2RML mapping from legacy patient database to FHIR RDF -type: R2RML +type: r2rml mapping_method: automated generation with manual review documentation: https://example.org/patient-fhir-mapping content: https://example.org/mappings/patient-db-to-fhir.r2rml.ttl subject_source: name: Patient Database version: "v5.2" - type: relational database + type: database documentation: https://example.org/db-schema content: postgresql://example.org:5432/patients content_type: application/sql From 32671009d05ae47aea5437bf96bfc1a5d087e990 Mon Sep 17 00:00:00 2001 From: Nico Matentzoglu Date: Mon, 6 Oct 2025 00:36:11 +0300 Subject: [PATCH 07/11] Fix test files --- tests/data/valid/MappingSpecification-001.yaml | 4 ++-- tests/data/valid/MappingSpecification-002.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/data/valid/MappingSpecification-001.yaml b/tests/data/valid/MappingSpecification-001.yaml index 1dff7ac..be057e4 100644 --- a/tests/data/valid/MappingSpecification-001.yaml +++ b/tests/data/valid/MappingSpecification-001.yaml @@ -11,14 +11,14 @@ content: https://example.org/mappings/do-mondo.sssom.tsv subject_source: name: Disease Ontology version: "2024-01-01" - type: owl ontology + type: owl_ontology documentation: https://disease-ontology.org/ content: http://purl.obolibrary.org/obo/doid.owl content_type: application/rdf+xml object_source: name: Mondo Disease Ontology version: "2024-01-10" - type: owl ontology + type: owl_ontology documentation: https://mondo.monarchinitiative.org/ content: http://purl.obolibrary.org/obo/mondo.owl content_type: application/rdf+xml diff --git a/tests/data/valid/MappingSpecification-002.yaml b/tests/data/valid/MappingSpecification-002.yaml index e52167a..6ca996c 100644 --- a/tests/data/valid/MappingSpecification-002.yaml +++ b/tests/data/valid/MappingSpecification-002.yaml @@ -19,7 +19,7 @@ subject_source: object_source: name: FHIR RDF Ontology version: "4.0.1" - type: rdf vocabulary + type: rdf_vocabulary documentation: http://hl7.org/fhir/ content: http://hl7.org/fhir/fhir.ttl content_type: text/turtle From 7e15efe4d53ad45c81706e8d7ab46323984f8210 Mon Sep 17 00:00:00 2001 From: Nico Matentzoglu Date: Mon, 6 Oct 2025 00:36:21 +0300 Subject: [PATCH 08/11] Update downstream schema files --- .../datamodel/fair_mappings_schema.py | 8 ++++---- .../datamodel/fair_mappings_schema_pydantic.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/fair_mappings_schema/datamodel/fair_mappings_schema.py b/src/fair_mappings_schema/datamodel/fair_mappings_schema.py index 4743270..925d148 100644 --- a/src/fair_mappings_schema/datamodel/fair_mappings_schema.py +++ b/src/fair_mappings_schema/datamodel/fair_mappings_schema.py @@ -1,5 +1,5 @@ # Auto generated from fair_mappings_schema.yaml by pythongen.py version: 0.0.1 -# Generation date: 2025-10-06T00:29:50 +# Generation date: 2025-10-06T00:35:53 # Schema: fair-mappings-schema # # id: https://w3id.org/mapping-commons/fair-mappings-schema @@ -300,9 +300,9 @@ class MappingSpecificationTypeEnum(EnumDefinitionImpl): sparql = PermissibleValue( text="sparql", description="SPARQL-based mapping") - custom = PermissibleValue( - text="custom", - description="Custom mapping format") + other = PermissibleValue( + text="other", + description="Other type of mapping specification") _defn = EnumDefinition( name="MappingSpecificationTypeEnum", diff --git a/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py b/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py index 14a8a57..a54d340 100644 --- a/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py +++ b/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py @@ -156,9 +156,9 @@ class MappingSpecificationTypeEnum(str, Enum): """ SPARQL-based mapping """ - custom = "custom" + other = "other" """ - Custom mapping format + Other type of mapping specification """ From 7a8a88b9ed67cd21dccd3620e2de5cd6df129f36 Mon Sep 17 00:00:00 2001 From: Nico Matentzoglu Date: Mon, 6 Oct 2025 23:13:59 +0300 Subject: [PATCH 09/11] Refactor agent classes and extend mapping enums Removed AgentTypeEnum and refactored Agent into abstract class with Person, Organization, and Software subclasses. Added new slots for agent subclasses and extended MappingTypeEnum with yarrrml and xslt options. --- .../schema/fair_mappings_schema.yaml | 58 ++++++++++++++----- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/src/fair_mappings_schema/schema/fair_mappings_schema.yaml b/src/fair_mappings_schema/schema/fair_mappings_schema.yaml index 6964f62..e407b9a 100644 --- a/src/fair_mappings_schema/schema/fair_mappings_schema.yaml +++ b/src/fair_mappings_schema/schema/fair_mappings_schema.yaml @@ -1,7 +1,7 @@ --- id: https://w3id.org/mapping-commons/fair-mappings-schema name: fair-mappings-schema -title: fair-mappings-schema +title: FAIR Mappings Schema description: |- A minimal metadata schema for FAIR mapping specifications license: Apache-2.0 @@ -22,16 +22,6 @@ imports: - linkml:types enums: - AgentTypeEnum: - description: Types of agents that can contribute to a mapping specification - permissible_values: - person: - description: An individual person - organization: - description: An organization or institution - software: - description: A software tool or system - SourceTypeEnum: description: Types of data sources permissible_values: @@ -61,6 +51,10 @@ enums: description: RDF Mapping Language sparql: description: SPARQL-based mapping + yarrrml: + description: YARRRML mapping file + xslt: + description: XSLT-based mapping other: description: Other type of mapping specification @@ -68,14 +62,36 @@ classes: Agent: description: An entity that can create or contribute to a digital object, such as an author or creator. + abstract: true slots: - id - name - - version - type slot_usage: type: - range: AgentTypeEnum + designates_type: true + range: string + + Person: + description: An individual person who contributes to a mapping specification + is_a: Agent + slots: + - orcid + - affiliation + + Organization: + description: An organization or institution that contributes to a mapping specification + is_a: Agent + slots: + - ror_id + - url + + Software: + description: A software tool or system used in creating mappings + is_a: Agent + slots: + - version + - repository_url Source: description: >- @@ -91,6 +107,7 @@ classes: slot_usage: type: range: SourceTypeEnum + MappingSpecification: description: >- A formal description of correspondences between entities in a source and a target, expressed as rules, functions, or mapping statements. @@ -173,3 +190,18 @@ slots: description: The source from which the object entities are drawn range: Source inlined: true + orcid: + description: ORCID identifier for a person + range: string + affiliation: + description: Institutional affiliation of a person + range: string + ror_id: + description: ROR (Research Organization Registry) identifier + range: string + url: + description: URL or web address + range: string + repository_url: + description: URL to a code repository + range: string From f2ccaa28e54b315e5d911ad3a77e5cac92a426f5 Mon Sep 17 00:00:00 2001 From: Nico Matentzoglu Date: Mon, 6 Oct 2025 23:14:07 +0300 Subject: [PATCH 10/11] Regenerate schema files --- .../datamodel/fair_mappings_schema.py | 137 ++++++++++++++---- .../fair_mappings_schema_pydantic.py | 91 ++++++++---- 2 files changed, 176 insertions(+), 52 deletions(-) diff --git a/src/fair_mappings_schema/datamodel/fair_mappings_schema.py b/src/fair_mappings_schema/datamodel/fair_mappings_schema.py index 925d148..f41504f 100644 --- a/src/fair_mappings_schema/datamodel/fair_mappings_schema.py +++ b/src/fair_mappings_schema/datamodel/fair_mappings_schema.py @@ -1,5 +1,5 @@ # Auto generated from fair_mappings_schema.yaml by pythongen.py version: 0.0.1 -# Generation date: 2025-10-06T00:35:53 +# Generation date: 2025-10-06T23:07:21 # Schema: fair-mappings-schema # # id: https://w3id.org/mapping-commons/fair-mappings-schema @@ -91,8 +91,7 @@ class Agent(YAMLRoot): id: Optional[str] = None name: Optional[str] = None - version: Optional[str] = None - type: Optional[Union[str, "AgentTypeEnum"]] = None + type: Optional[str] = None def __post_init__(self, *_: str, **kwargs: Any): if self.id is not None and not isinstance(self.id, str): @@ -101,13 +100,105 @@ def __post_init__(self, *_: str, **kwargs: Any): if self.name is not None and not isinstance(self.name, str): self.name = str(self.name) + self.type = str(self.class_name) + + super().__post_init__(**kwargs) + self.type = str(self.class_name) + + + def __new__(cls, *args, **kwargs): + + type_designator = "type" + if not type_designator in kwargs: + return super().__new__(cls,*args,**kwargs) + else: + type_designator_value = kwargs[type_designator] + target_cls = cls._class_for("class_name", type_designator_value) + + + if target_cls is None: + raise ValueError(f"Wrong type designator value: class {cls.__name__} " + f"has no subclass with ['class_name']='{kwargs[type_designator]}'") + return super().__new__(target_cls,*args,**kwargs) + + + +@dataclass(repr=False) +class Person(Agent): + """ + An individual person who contributes to a mapping specification + """ + _inherited_slots: ClassVar[list[str]] = [] + + class_class_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA["Person"] + class_class_curie: ClassVar[str] = "fair_mappings_schema:Person" + class_name: ClassVar[str] = "Person" + class_model_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA.Person + + orcid: Optional[str] = None + affiliation: Optional[str] = None + + def __post_init__(self, *_: str, **kwargs: Any): + if self.orcid is not None and not isinstance(self.orcid, str): + self.orcid = str(self.orcid) + + if self.affiliation is not None and not isinstance(self.affiliation, str): + self.affiliation = str(self.affiliation) + + super().__post_init__(**kwargs) + self.type = str(self.class_name) + + +@dataclass(repr=False) +class Organization(Agent): + """ + An organization or institution that contributes to a mapping specification + """ + _inherited_slots: ClassVar[list[str]] = [] + + class_class_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA["Organization"] + class_class_curie: ClassVar[str] = "fair_mappings_schema:Organization" + class_name: ClassVar[str] = "Organization" + class_model_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA.Organization + + ror_id: Optional[str] = None + url: Optional[str] = None + + def __post_init__(self, *_: str, **kwargs: Any): + if self.ror_id is not None and not isinstance(self.ror_id, str): + self.ror_id = str(self.ror_id) + + if self.url is not None and not isinstance(self.url, str): + self.url = str(self.url) + + super().__post_init__(**kwargs) + self.type = str(self.class_name) + + +@dataclass(repr=False) +class Software(Agent): + """ + A software tool or system used in creating mappings + """ + _inherited_slots: ClassVar[list[str]] = [] + + class_class_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA["Software"] + class_class_curie: ClassVar[str] = "fair_mappings_schema:Software" + class_name: ClassVar[str] = "Software" + class_model_uri: ClassVar[URIRef] = FAIR_MAPPINGS_SCHEMA.Software + + version: Optional[str] = None + repository_url: Optional[str] = None + + def __post_init__(self, *_: str, **kwargs: Any): if self.version is not None and not isinstance(self.version, str): self.version = str(self.version) - if self.type is not None and not isinstance(self.type, AgentTypeEnum): - self.type = AgentTypeEnum(self.type) + if self.repository_url is not None and not isinstance(self.repository_url, str): + self.repository_url = str(self.repository_url) super().__post_init__(**kwargs) + self.type = str(self.class_name) @dataclass(repr=False) @@ -234,25 +325,6 @@ def __post_init__(self, *_: str, **kwargs: Any): # Enumerations -class AgentTypeEnum(EnumDefinitionImpl): - """ - Types of agents that can contribute to a mapping specification - """ - person = PermissibleValue( - text="person", - description="An individual person") - organization = PermissibleValue( - text="organization", - description="An organization or institution") - software = PermissibleValue( - text="software", - description="A software tool or system") - - _defn = EnumDefinition( - name="AgentTypeEnum", - description="Types of agents that can contribute to a mapping specification", - ) - class SourceTypeEnum(EnumDefinitionImpl): """ Types of data sources @@ -364,8 +436,23 @@ class slots: slots.object_source = Slot(uri=FAIR_MAPPINGS_SCHEMA.object_source, name="object_source", curie=FAIR_MAPPINGS_SCHEMA.curie('object_source'), model_uri=FAIR_MAPPINGS_SCHEMA.object_source, domain=None, range=Optional[Union[dict, Source]]) +slots.orcid = Slot(uri=FAIR_MAPPINGS_SCHEMA.orcid, name="orcid", curie=FAIR_MAPPINGS_SCHEMA.curie('orcid'), + model_uri=FAIR_MAPPINGS_SCHEMA.orcid, domain=None, range=Optional[str]) + +slots.affiliation = Slot(uri=FAIR_MAPPINGS_SCHEMA.affiliation, name="affiliation", curie=FAIR_MAPPINGS_SCHEMA.curie('affiliation'), + model_uri=FAIR_MAPPINGS_SCHEMA.affiliation, domain=None, range=Optional[str]) + +slots.ror_id = Slot(uri=FAIR_MAPPINGS_SCHEMA.ror_id, name="ror_id", curie=FAIR_MAPPINGS_SCHEMA.curie('ror_id'), + model_uri=FAIR_MAPPINGS_SCHEMA.ror_id, domain=None, range=Optional[str]) + +slots.url = Slot(uri=FAIR_MAPPINGS_SCHEMA.url, name="url", curie=FAIR_MAPPINGS_SCHEMA.curie('url'), + model_uri=FAIR_MAPPINGS_SCHEMA.url, domain=None, range=Optional[str]) + +slots.repository_url = Slot(uri=FAIR_MAPPINGS_SCHEMA.repository_url, name="repository_url", curie=FAIR_MAPPINGS_SCHEMA.curie('repository_url'), + model_uri=FAIR_MAPPINGS_SCHEMA.repository_url, domain=None, range=Optional[str]) + slots.Agent_type = Slot(uri=FAIR_MAPPINGS_SCHEMA.type, name="Agent_type", curie=FAIR_MAPPINGS_SCHEMA.curie('type'), - model_uri=FAIR_MAPPINGS_SCHEMA.Agent_type, domain=Agent, range=Optional[Union[str, "AgentTypeEnum"]]) + model_uri=FAIR_MAPPINGS_SCHEMA.Agent_type, domain=Agent, range=Optional[str]) slots.Source_type = Slot(uri=FAIR_MAPPINGS_SCHEMA.type, name="Source_type", curie=FAIR_MAPPINGS_SCHEMA.curie('type'), model_uri=FAIR_MAPPINGS_SCHEMA.Source_type, domain=Source, range=Optional[Union[str, "SourceTypeEnum"]]) diff --git a/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py b/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py index a54d340..08a756d 100644 --- a/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py +++ b/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py @@ -84,24 +84,6 @@ def __contains__(self, key:str) -> bool: 'source_file': 'src/fair_mappings_schema/schema/fair_mappings_schema.yaml', 'title': 'fair-mappings-schema'} ) -class AgentTypeEnum(str, Enum): - """ - Types of agents that can contribute to a mapping specification - """ - person = "person" - """ - An individual person - """ - organization = "organization" - """ - An organization or institution - """ - software = "software" - """ - A software tool or system - """ - - class SourceTypeEnum(str, Enum): """ Types of data sources @@ -167,13 +149,63 @@ class Agent(ConfiguredBaseModel): """ An entity that can create or contribute to a digital object, such as an author or creator. """ - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema', - 'slot_usage': {'type': {'name': 'type', 'range': 'AgentTypeEnum'}}}) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'abstract': True, + 'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema', + 'slot_usage': {'type': {'designates_type': True, + 'name': 'type', + 'range': 'string'}}}) + + id: Optional[str] = Field(default=None, description="""Identifier for the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'id', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + name: Optional[str] = Field(default=None, description="""Name of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + type: Literal["Agent"] = Field(default="Agent", description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', + 'designates_type': True, + 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + + +class Person(Agent): + """ + An individual person who contributes to a mapping specification + """ + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema'}) + + orcid: Optional[str] = Field(default=None, description="""ORCID identifier for a person""", json_schema_extra = { "linkml_meta": {'alias': 'orcid', 'domain_of': ['Person']} }) + affiliation: Optional[str] = Field(default=None, description="""Institutional affiliation of a person""", json_schema_extra = { "linkml_meta": {'alias': 'affiliation', 'domain_of': ['Person']} }) + id: Optional[str] = Field(default=None, description="""Identifier for the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'id', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + name: Optional[str] = Field(default=None, description="""Name of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + type: Literal["Person"] = Field(default="Person", description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', + 'designates_type': True, + 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + + +class Organization(Agent): + """ + An organization or institution that contributes to a mapping specification + """ + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema'}) + + ror_id: Optional[str] = Field(default=None, description="""ROR (Research Organization Registry) identifier""", json_schema_extra = { "linkml_meta": {'alias': 'ror_id', 'domain_of': ['Organization']} }) + url: Optional[str] = Field(default=None, description="""URL or web address""", json_schema_extra = { "linkml_meta": {'alias': 'url', 'domain_of': ['Organization']} }) + id: Optional[str] = Field(default=None, description="""Identifier for the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'id', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + name: Optional[str] = Field(default=None, description="""Name of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + type: Literal["Organization"] = Field(default="Organization", description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', + 'designates_type': True, + 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + + +class Software(Agent): + """ + A software tool or system used in creating mappings + """ + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/mapping-commons/fair-mappings-schema'}) + version: Optional[str] = Field(default=None, description="""Version of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'version', + 'domain_of': ['Software', 'Source', 'MappingSpecification']} }) + repository_url: Optional[str] = Field(default=None, description="""URL to a code repository""", json_schema_extra = { "linkml_meta": {'alias': 'repository_url', 'domain_of': ['Software']} }) id: Optional[str] = Field(default=None, description="""Identifier for the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'id', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) name: Optional[str] = Field(default=None, description="""Name of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) - version: Optional[str] = Field(default=None, description="""Version of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'version', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) - type: Optional[AgentTypeEnum] = Field(default=None, description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + type: Literal["Software"] = Field(default="Software", description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', + 'designates_type': True, + 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) class Source(ConfiguredBaseModel): @@ -185,7 +217,8 @@ class Source(ConfiguredBaseModel): id: Optional[str] = Field(default=None, description="""Identifier for the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'id', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) name: Optional[str] = Field(default=None, description="""Name of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) - version: Optional[str] = Field(default=None, description="""Version of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'version', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + version: Optional[str] = Field(default=None, description="""Version of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'version', + 'domain_of': ['Software', 'Source', 'MappingSpecification']} }) type: Optional[SourceTypeEnum] = Field(default=None, description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) documentation: Optional[str] = Field(default=None, description="""URL or reference to documentation for the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'documentation', 'domain_of': ['Source', 'MappingSpecification']} }) content: Optional[str] = Field(default=None, description="""Reference to the actual content of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'content', 'domain_of': ['Source', 'MappingSpecification']} }) @@ -204,12 +237,13 @@ class MappingSpecification(ConfiguredBaseModel): id: Optional[str] = Field(default=None, description="""Identifier for the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'id', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) name: Optional[str] = Field(default=None, description="""Name of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'name', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) description: Optional[str] = Field(default=None, description="""A brief description of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'description', 'domain_of': ['MappingSpecification']} }) - author: Optional[Agent] = Field(default=None, description="""Author of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'author', 'domain_of': ['MappingSpecification']} }) - creator: Optional[Agent] = Field(default=None, description="""Creator of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'creator', 'domain_of': ['MappingSpecification']} }) - reviewer: Optional[Agent] = Field(default=None, description="""Reviewer of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'reviewer', 'domain_of': ['MappingSpecification']} }) + author: Optional[Union[Agent,Person,Organization,Software]] = Field(default=None, description="""Author of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'author', 'domain_of': ['MappingSpecification']} }) + creator: Optional[Union[Agent,Person,Organization,Software]] = Field(default=None, description="""Creator of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'creator', 'domain_of': ['MappingSpecification']} }) + reviewer: Optional[Union[Agent,Person,Organization,Software]] = Field(default=None, description="""Reviewer of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'reviewer', 'domain_of': ['MappingSpecification']} }) publication_date: Optional[str] = Field(default=None, description="""Date of publication of the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'publication_date', 'domain_of': ['MappingSpecification']} }) license: Optional[str] = Field(default=None, description="""License under which the mapping specification is released""", json_schema_extra = { "linkml_meta": {'alias': 'license', 'domain_of': ['MappingSpecification']} }) - version: Optional[str] = Field(default=None, description="""Version of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'version', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) + version: Optional[str] = Field(default=None, description="""Version of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'version', + 'domain_of': ['Software', 'Source', 'MappingSpecification']} }) type: Optional[MappingSpecificationTypeEnum] = Field(default=None, description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) mapping_method: Optional[str] = Field(default=None, description="""Method used to create the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'mapping_method', 'domain_of': ['MappingSpecification']} }) documentation: Optional[str] = Field(default=None, description="""URL or reference to documentation for the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'documentation', 'domain_of': ['Source', 'MappingSpecification']} }) @@ -221,6 +255,9 @@ class MappingSpecification(ConfiguredBaseModel): # Model rebuild # see https://pydantic-docs.helpmanual.io/usage/models/#rebuilding-a-model Agent.model_rebuild() +Person.model_rebuild() +Organization.model_rebuild() +Software.model_rebuild() Source.model_rebuild() MappingSpecification.model_rebuild() From 20bf0f5754ada890d8759e0eb5f6f46ffea8612f Mon Sep 17 00:00:00 2001 From: Nico Matentzoglu Date: Mon, 6 Oct 2025 23:30:22 +0300 Subject: [PATCH 11/11] Refactor content fields to content_url and add metadata fields Replaces 'content' with 'content_url' in Source and MappingSpecification classes and updates all related YAML and test files. Adds 'metadata_url' and 'metadata_type' fields to Source for improved metadata handling. --- .../datamodel/fair_mappings_schema.py | 38 ++++++++++++++----- .../fair_mappings_schema_pydantic.py | 16 ++++++-- .../schema/fair_mappings_schema.yaml | 14 +++++-- .../data/valid/MappingSpecification-001.yaml | 6 +-- .../data/valid/MappingSpecification-002.yaml | 6 +-- .../data/valid/MappingSpecification-003.yaml | 6 +-- 6 files changed, 62 insertions(+), 24 deletions(-) diff --git a/src/fair_mappings_schema/datamodel/fair_mappings_schema.py b/src/fair_mappings_schema/datamodel/fair_mappings_schema.py index f41504f..46e1381 100644 --- a/src/fair_mappings_schema/datamodel/fair_mappings_schema.py +++ b/src/fair_mappings_schema/datamodel/fair_mappings_schema.py @@ -1,5 +1,5 @@ # Auto generated from fair_mappings_schema.yaml by pythongen.py version: 0.0.1 -# Generation date: 2025-10-06T23:07:21 +# Generation date: 2025-10-06T23:29:58 # Schema: fair-mappings-schema # # id: https://w3id.org/mapping-commons/fair-mappings-schema @@ -218,8 +218,10 @@ class Source(YAMLRoot): version: Optional[str] = None type: Optional[Union[str, "SourceTypeEnum"]] = None documentation: Optional[str] = None - content: Optional[str] = None + content_url: Optional[str] = None content_type: Optional[str] = None + metadata_url: Optional[str] = None + metadata_type: Optional[str] = None def __post_init__(self, *_: str, **kwargs: Any): if self.id is not None and not isinstance(self.id, str): @@ -237,12 +239,18 @@ def __post_init__(self, *_: str, **kwargs: Any): if self.documentation is not None and not isinstance(self.documentation, str): self.documentation = str(self.documentation) - if self.content is not None and not isinstance(self.content, str): - self.content = str(self.content) + if self.content_url is not None and not isinstance(self.content_url, str): + self.content_url = str(self.content_url) if self.content_type is not None and not isinstance(self.content_type, str): self.content_type = str(self.content_type) + if self.metadata_url is not None and not isinstance(self.metadata_url, str): + self.metadata_url = str(self.metadata_url) + + if self.metadata_type is not None and not isinstance(self.metadata_type, str): + self.metadata_type = str(self.metadata_type) + super().__post_init__(**kwargs) @@ -271,7 +279,7 @@ class MappingSpecification(YAMLRoot): type: Optional[Union[str, "MappingSpecificationTypeEnum"]] = None mapping_method: Optional[str] = None documentation: Optional[str] = None - content: Optional[str] = None + content_url: Optional[str] = None subject_source: Optional[Union[dict, Source]] = None object_source: Optional[Union[dict, Source]] = None @@ -312,8 +320,8 @@ def __post_init__(self, *_: str, **kwargs: Any): if self.documentation is not None and not isinstance(self.documentation, str): self.documentation = str(self.documentation) - if self.content is not None and not isinstance(self.content, str): - self.content = str(self.content) + if self.content_url is not None and not isinstance(self.content_url, str): + self.content_url = str(self.content_url) if self.subject_source is not None and not isinstance(self.subject_source, Source): self.subject_source = Source(**as_dict(self.subject_source)) @@ -372,6 +380,12 @@ class MappingSpecificationTypeEnum(EnumDefinitionImpl): sparql = PermissibleValue( text="sparql", description="SPARQL-based mapping") + yarrrml = PermissibleValue( + text="yarrrml", + description="YARRRML mapping file") + xslt = PermissibleValue( + text="xslt", + description="XSLT-based mapping") other = PermissibleValue( text="other", description="Other type of mapping specification") @@ -424,12 +438,18 @@ class slots: slots.documentation = Slot(uri=FAIR_MAPPINGS_SCHEMA.documentation, name="documentation", curie=FAIR_MAPPINGS_SCHEMA.curie('documentation'), model_uri=FAIR_MAPPINGS_SCHEMA.documentation, domain=None, range=Optional[str]) -slots.content = Slot(uri=FAIR_MAPPINGS_SCHEMA.content, name="content", curie=FAIR_MAPPINGS_SCHEMA.curie('content'), - model_uri=FAIR_MAPPINGS_SCHEMA.content, domain=None, range=Optional[str]) +slots.content_url = Slot(uri=FAIR_MAPPINGS_SCHEMA.content_url, name="content_url", curie=FAIR_MAPPINGS_SCHEMA.curie('content_url'), + model_uri=FAIR_MAPPINGS_SCHEMA.content_url, domain=None, range=Optional[str]) slots.content_type = Slot(uri=FAIR_MAPPINGS_SCHEMA.content_type, name="content_type", curie=FAIR_MAPPINGS_SCHEMA.curie('content_type'), model_uri=FAIR_MAPPINGS_SCHEMA.content_type, domain=None, range=Optional[str]) +slots.metadata_url = Slot(uri=FAIR_MAPPINGS_SCHEMA.metadata_url, name="metadata_url", curie=FAIR_MAPPINGS_SCHEMA.curie('metadata_url'), + model_uri=FAIR_MAPPINGS_SCHEMA.metadata_url, domain=None, range=Optional[str]) + +slots.metadata_type = Slot(uri=FAIR_MAPPINGS_SCHEMA.metadata_type, name="metadata_type", curie=FAIR_MAPPINGS_SCHEMA.curie('metadata_type'), + model_uri=FAIR_MAPPINGS_SCHEMA.metadata_type, domain=None, range=Optional[str]) + slots.subject_source = Slot(uri=FAIR_MAPPINGS_SCHEMA.subject_source, name="subject_source", curie=FAIR_MAPPINGS_SCHEMA.curie('subject_source'), model_uri=FAIR_MAPPINGS_SCHEMA.subject_source, domain=None, range=Optional[Union[dict, Source]]) diff --git a/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py b/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py index 08a756d..d33fda9 100644 --- a/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py +++ b/src/fair_mappings_schema/datamodel/fair_mappings_schema_pydantic.py @@ -82,7 +82,7 @@ def __contains__(self, key:str) -> bool: 'prefix_reference': 'http://schema.org/'}}, 'see_also': ['https://mapping-commons.github.io/fair-mappings-schema'], 'source_file': 'src/fair_mappings_schema/schema/fair_mappings_schema.yaml', - 'title': 'fair-mappings-schema'} ) + 'title': 'FAIR Mappings Schema'} ) class SourceTypeEnum(str, Enum): """ @@ -138,6 +138,14 @@ class MappingSpecificationTypeEnum(str, Enum): """ SPARQL-based mapping """ + yarrrml = "yarrrml" + """ + YARRRML mapping file + """ + xslt = "xslt" + """ + XSLT-based mapping + """ other = "other" """ Other type of mapping specification @@ -221,8 +229,10 @@ class Source(ConfiguredBaseModel): 'domain_of': ['Software', 'Source', 'MappingSpecification']} }) type: Optional[SourceTypeEnum] = Field(default=None, description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) documentation: Optional[str] = Field(default=None, description="""URL or reference to documentation for the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'documentation', 'domain_of': ['Source', 'MappingSpecification']} }) - content: Optional[str] = Field(default=None, description="""Reference to the actual content of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'content', 'domain_of': ['Source', 'MappingSpecification']} }) + content_url: Optional[str] = Field(default=None, description="""Reference to the actual content of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'content_url', 'domain_of': ['Source', 'MappingSpecification']} }) content_type: Optional[str] = Field(default=None, description="""The type of the content of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'content_type', 'domain_of': ['Source']} }) + metadata_url: Optional[str] = Field(default=None, description="""Reference to metadata about the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'metadata_url', 'domain_of': ['Source']} }) + metadata_type: Optional[str] = Field(default=None, description="""The type of the metadata about the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'metadata_type', 'domain_of': ['Source']} }) class MappingSpecification(ConfiguredBaseModel): @@ -247,7 +257,7 @@ class MappingSpecification(ConfiguredBaseModel): type: Optional[MappingSpecificationTypeEnum] = Field(default=None, description="""Type of the information entity""", json_schema_extra = { "linkml_meta": {'alias': 'type', 'domain_of': ['Agent', 'Source', 'MappingSpecification']} }) mapping_method: Optional[str] = Field(default=None, description="""Method used to create the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'mapping_method', 'domain_of': ['MappingSpecification']} }) documentation: Optional[str] = Field(default=None, description="""URL or reference to documentation for the mapping specification""", json_schema_extra = { "linkml_meta": {'alias': 'documentation', 'domain_of': ['Source', 'MappingSpecification']} }) - content: Optional[str] = Field(default=None, description="""Reference to the actual content of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'content', 'domain_of': ['Source', 'MappingSpecification']} }) + content_url: Optional[str] = Field(default=None, description="""Reference to the actual content of the digital object""", json_schema_extra = { "linkml_meta": {'alias': 'content_url', 'domain_of': ['Source', 'MappingSpecification']} }) subject_source: Optional[Source] = Field(default=None, description="""The source from which the subject entities are drawn""", json_schema_extra = { "linkml_meta": {'alias': 'subject_source', 'domain_of': ['MappingSpecification']} }) object_source: Optional[Source] = Field(default=None, description="""The source from which the object entities are drawn""", json_schema_extra = { "linkml_meta": {'alias': 'object_source', 'domain_of': ['MappingSpecification']} }) diff --git a/src/fair_mappings_schema/schema/fair_mappings_schema.yaml b/src/fair_mappings_schema/schema/fair_mappings_schema.yaml index e407b9a..cfaeaca 100644 --- a/src/fair_mappings_schema/schema/fair_mappings_schema.yaml +++ b/src/fair_mappings_schema/schema/fair_mappings_schema.yaml @@ -102,8 +102,10 @@ classes: - version - type - documentation - - content + - content_url - content_type + - metadata_url + - metadata_type slot_usage: type: range: SourceTypeEnum @@ -125,7 +127,7 @@ classes: - type - mapping_method - documentation - - content + - content_url - subject_source - object_source slot_usage: @@ -176,12 +178,18 @@ slots: documentation: description: URL or reference to documentation for the mapping specification range: string - content: + content_url: description: Reference to the actual content of the digital object range: string content_type: description: The type of the content of the digital object range: string + metadata_url: + description: Reference to metadata about the digital object + range: string + metadata_type: + description: The type of the metadata about the digital object + range: string subject_source: description: The source from which the subject entities are drawn range: Source diff --git a/tests/data/valid/MappingSpecification-001.yaml b/tests/data/valid/MappingSpecification-001.yaml index be057e4..3c551ec 100644 --- a/tests/data/valid/MappingSpecification-001.yaml +++ b/tests/data/valid/MappingSpecification-001.yaml @@ -7,18 +7,18 @@ description: Mappings between disease ontologies DO and MONDO type: sssom mapping_method: manual curation documentation: https://example.org/do-mondo-mappings/docs -content: https://example.org/mappings/do-mondo.sssom.tsv +content_url: https://example.org/mappings/do-mondo.sssom.tsv subject_source: name: Disease Ontology version: "2024-01-01" type: owl_ontology documentation: https://disease-ontology.org/ - content: http://purl.obolibrary.org/obo/doid.owl + content_url: http://purl.obolibrary.org/obo/doid.owl content_type: application/rdf+xml object_source: name: Mondo Disease Ontology version: "2024-01-10" type: owl_ontology documentation: https://mondo.monarchinitiative.org/ - content: http://purl.obolibrary.org/obo/mondo.owl + content_url: http://purl.obolibrary.org/obo/mondo.owl content_type: application/rdf+xml diff --git a/tests/data/valid/MappingSpecification-002.yaml b/tests/data/valid/MappingSpecification-002.yaml index 6ca996c..afe4c0c 100644 --- a/tests/data/valid/MappingSpecification-002.yaml +++ b/tests/data/valid/MappingSpecification-002.yaml @@ -8,18 +8,18 @@ description: R2RML mapping from legacy patient database to FHIR RDF type: r2rml mapping_method: automated generation with manual review documentation: https://example.org/patient-fhir-mapping -content: https://example.org/mappings/patient-db-to-fhir.r2rml.ttl +content_url: https://example.org/mappings/patient-db-to-fhir.r2rml.ttl subject_source: name: Patient Database version: "v5.2" type: database documentation: https://example.org/db-schema - content: postgresql://example.org:5432/patients + content_url: postgresql://example.org:5432/patients content_type: application/sql object_source: name: FHIR RDF Ontology version: "4.0.1" type: rdf_vocabulary documentation: http://hl7.org/fhir/ - content: http://hl7.org/fhir/fhir.ttl + content_url: http://hl7.org/fhir/fhir.ttl content_type: text/turtle diff --git a/tests/data/valid/MappingSpecification-003.yaml b/tests/data/valid/MappingSpecification-003.yaml index c428187..4868423 100644 --- a/tests/data/valid/MappingSpecification-003.yaml +++ b/tests/data/valid/MappingSpecification-003.yaml @@ -1,11 +1,11 @@ # Valid MappingSpecification example - minimal required fields only --- -content: https://example.org/minimal-mapping.txt +content_url: https://example.org/minimal-mapping.txt subject_source: name: Source A - content: https://example.org/source-a + content_url: https://example.org/source-a content_type: text/plain object_source: name: Source B - content: https://example.org/source-b + content_url: https://example.org/source-b content_type: text/plain