From 6fa34b168d1cb3873c7349211963eeee4c0db392 Mon Sep 17 00:00:00 2001 From: cmungall Date: Mon, 7 Mar 2022 12:23:39 -0800 Subject: [PATCH] Tests for RO --- linkml_owl/util/loader_wrapper.py | 2 - tests/inputs/expected_ro.ofn | 60 +++++++++++++++++++ tests/inputs/ro-data.yaml | 86 ++++++++++++++++++++++++++-- tests/inputs/ro-metamodel.yaml | 92 ++++++++++++++++++++++++++---- tests/output/chromo.schema.owl.ttl | 82 +++++++++++++------------- tests/test_ro_metamodel.py | 2 +- 6 files changed, 264 insertions(+), 60 deletions(-) diff --git a/linkml_owl/util/loader_wrapper.py b/linkml_owl/util/loader_wrapper.py index 801669f..d457768 100644 --- a/linkml_owl/util/loader_wrapper.py +++ b/linkml_owl/util/loader_wrapper.py @@ -72,8 +72,6 @@ def load_structured_file(source: Union[str, dict, TextIO], target_class: Union[s - if the schema specified a tree_root, this is used - if the objects contain a type designator, this is used - TODO: add tests - :param source: path or data or stream :param target_class: class to be instantiated, either name or the python class :param fmt: Any of yaml, json, csv, ttl. inferred if None and source is a file path diff --git a/tests/inputs/expected_ro.ofn b/tests/inputs/expected_ro.ofn index 8740c01..d83836d 100644 --- a/tests/inputs/expected_ro.ofn +++ b/tests/inputs/expected_ro.ofn @@ -19,6 +19,34 @@ Prefix( skos: = ) Prefix( dcterms: = ) Ontology( + AnnotationAssertion( "Inverse of BFO:0000050 part of" ) + Declaration( ObjectProperty( ) ) + AnnotationAssertion( rdfs:label "part of" ) + AnnotationAssertion( "a core relation that holds between a part and its whole" ) + AnnotationAssertion( dcterms:conformsTo rometa:ObjectProperty ) + SubObjectPropertyOf( ) + Declaration( ObjectProperty( ) ) + AnnotationAssertion( rdfs:label "has part" ) + InverseObjectProperties( ) + TransitiveObjectProperty( ) + SubObjectPropertyOf( ObjectPropertyChain( + + + ) ) + Declaration( ObjectProperty( ) ) + AnnotationAssertion( rdfs:label "overlaps" ) + AnnotationAssertion( "a core relation that holds between a part and its whole" ) + AnnotationAssertion( dcterms:conformsTo rometa:DefinedObjectPropertyByChain ) + SubObjectPropertyOf( ) + SymmetricObjectProperty( ) + SubObjectPropertyOf( ObjectPropertyChain( + + + ) ) + Declaration( ObjectProperty( ) ) + AnnotationAssertion( rdfs:label "characteristic of part of" ) + AnnotationAssertion( "A relationship between a characteristic and an entity where the characteristic is of either the entity itself or a part of the entity" ) + AnnotationAssertion( dcterms:conformsTo rometa:DefinedObjectPropertyByChain ) AnnotationAssertion( "Inverse of RO:0002202 develops from" ) Declaration( ObjectProperty( ) ) AnnotationAssertion( rdfs:label "develops from" ) @@ -31,16 +59,48 @@ Ontology( AnnotationAssertion( rdfs:label "develops into" ) InverseObjectProperties( ) TransitiveObjectProperty( ) + AnnotationAssertion( "Inverse of RO:0002012 occurrent part of" ) + Declaration( ObjectProperty( ) ) + AnnotationAssertion( rdfs:label "occurrent part of" ) + AnnotationAssertion( dcterms:conformsTo rometa:DefinedObjectPropertyByDomainAndRange ) + SubObjectPropertyOf( ) + ObjectPropertyDomain( ) + ObjectPropertyRange( ) + Declaration( ObjectProperty( ) ) + AnnotationAssertion( rdfs:label "has occurrent part" ) + InverseObjectProperties( ) SubObjectPropertyOf( ObjectPropertyChain( ) ) + AnnotationAssertion( "Inverse of RO:0002447 phosphorylates" ) Declaration( ObjectProperty( ) ) AnnotationAssertion( rdfs:label "phosphorylates" ) + AnnotationAssertion( "A molecularly-interacts-with relationship between two entities, where the subject catalyzes a kinase activity that takes the object as input" ) AnnotationAssertion( dcterms:conformsTo rometa:ObjectPropertyDefinedByInteractionProcess ) SubObjectPropertyOf( ) + Declaration( ObjectProperty( ) ) + AnnotationAssertion( rdfs:label "phosphorylated by" ) + InverseObjectProperties( ) SubClassOf( ObjectHasSelf( ) ) Declaration( ObjectProperty( ) ) AnnotationAssertion( rdfs:label "is kinase activity" ) + SubObjectPropertyOf( ObjectPropertyChain( + + + + ) ) + AnnotationAssertion( "Inverse of RO:0018002 myristoylates" ) + Declaration( ObjectProperty( ) ) + AnnotationAssertion( rdfs:label "myristoylates" ) + AnnotationAssertion( "A molecularly-interacts-with relationship between two entities, where the subject catalyzes a myristoylation activity that takes the object as input" ) + AnnotationAssertion( dcterms:conformsTo rometa:ObjectPropertyDefinedByInteractionProcess ) + SubObjectPropertyOf( ) + Declaration( ObjectProperty( ) ) + AnnotationAssertion( rdfs:label "myristoylated by" ) + InverseObjectProperties( ) + SubClassOf( ObjectHasSelf( ) ) + Declaration( ObjectProperty( ) ) + AnnotationAssertion( rdfs:label "is myristoyltransferase activity" ) ) \ No newline at end of file diff --git a/tests/inputs/ro-data.yaml b/tests/inputs/ro-data.yaml index 7c71853..9d724f1 100644 --- a/tests/inputs/ro-data.yaml +++ b/tests/inputs/ro-data.yaml @@ -1,3 +1,41 @@ +## basic example + +- id: BFO:0000050 + conforms_to: ObjectProperty + label: part of + inverse_of: + id: BFO:0000051 + label: has part + subproperty_of: RO:0002131 ## overlaps + definition: a core relation that holds between a part and its whole + transitive: true + locally_reflexive: true + +## chains + +- id: RO:0002131 + conforms_to: DefinedObjectPropertyByChain + label: overlaps + subproperty_of: RO:0002323 + definition: a core relation that holds between a part and its whole + symmetric: true + subproperty_of_pairwise_chain: + - first_member: BFO:0000051 + last_member: BFO:0000050 + +## chains to reflexive, see https://oborel.github.io/obo-relations/reflexivity/ + +- id: RO:0002314 + conforms_to: DefinedObjectPropertyByChain + #conforms_to: DefinedObjectPropertyByChainToReflexive ### TODO + label: characteristic of part of + definition: A relationship between a characteristic and an entity where the characteristic is of either the entity itself or a part of the entity + subproperty_of_pairwise_chain: + - first_member: RO:0000052 + last_member: BFO:0000050 + +## test for transitive form, e.g. develops-from is transitive form of directly-develops-from + - id: RO:0002202 conforms_to: TransitiveForm label: develops from @@ -12,17 +50,55 @@ domain: BFO:0000004 range: BFO:0000004 transitive: true + +## See https://github.com/oborel/obo-relations/pull/522 + +- id: RO:0002012 + conforms_to: DefinedObjectPropertyByDomainAndRange + label: occurrent part of + subproperty_of: BFO:0000050 + inverse_of: + id: RO:9999998 + label: has occurrent part + domain: BFO:0000003 + range: BFO:0000003 + + +## https://github.com/oborel/obo-relations/pull/522 + +# this one exists in RO - id: RO:0002447 conforms_to: ObjectPropertyDefinedByInteractionProcess label: phosphorylates - subproperty_of: RO:0002436 - #inverse_of: - # id: TODO - # label: phosphorylated by + definition: >- + A molecularly-interacts-with relationship between two entities, + where the subject catalyzes a kinase activity that takes the object as input + subproperty_of: RO:0002436 ## molecularly interacts with + inverse_of: + id: RO:9999999 + label: phosphorylated by subject_to_process_property: RO:0002215 ## capable of uses_rolified_property: id: RO:0002481 label: is kinase activity rolification_of: GO:0016301 - object_to_process_property: RO:0002400 ## has direct input + process_to_object_property: RO:0002400 ## has direct input + +# new one proposed in https://github.com/oborel/obo-relations/pull/522 +- id: RO:0018002 + conforms_to: ObjectPropertyDefinedByInteractionProcess + label: myristoylates + definition: >- + A molecularly-interacts-with relationship between two entities, + where the subject catalyzes a myristoylation activity that takes the object as input + subproperty_of: RO:0002436 ## molecularly interacts with + inverse_of: + id: RO:0018003 + label: myristoylated by + subject_to_process_property: RO:0002215 ## capable of + uses_rolified_property: + id: RO:0018001 + label: is myristoyltransferase activity + rolification_of: GO:0019107 + process_to_object_property: RO:0002400 ## has direct input diff --git a/tests/inputs/ro-metamodel.yaml b/tests/inputs/ro-metamodel.yaml index f941f48..e2d9cc6 100644 --- a/tests/inputs/ro-metamodel.yaml +++ b/tests/inputs/ro-metamodel.yaml @@ -24,14 +24,6 @@ default_prefix: rometa default_curi_maps: - semweb_context -enums: - ActivationStateEnum: - permissible_values: - ACTIVATED: - meaning: PATO:0002354 - INACTIVATED: - meaning: PATO:0002355 - types: label type: typeof: string @@ -121,6 +113,9 @@ slots: slot_uri: rdfs:range multivalued: false range: Class + subproperty_of_pairwise_chain: + multivalued: true + range: PairwisePropertyChain operands: range: NamedThing multivalued: true @@ -209,6 +204,24 @@ slots: classes: + Expression: + abstract: true + + PropertyChain: + abstract: true + todos: + - implement for more than pairwise + + PairwisePropertyChain: + description: a property chain of length 2 + attributes: + first_member: + range: ObjectProperty + #required: true + last_member: + range: ObjectProperty + #required: true + NamedThing: slots: - id @@ -254,6 +267,7 @@ classes: - reflexive - locally_reflexive - has_transitive_form + - subproperty_of_pairwise_chain slot_usage: genus: range: ObjectProperty @@ -277,6 +291,13 @@ classes: {% if inverse_of and not inverse_of.definition %} AnnotationAssertion( IAO:00000115 {{inverse_of.id}} "Inverse of {{id}} {{label}}") {% endif %} + {% for chain in subproperty_of_pairwise_chain %} + SubObjectPropertyOf( + ObjectPropertyChain({{chain.first_member}} + {{chain.last_member}}) + {{id}}) + {% endfor %} + GroupingObjectProperty: is_a: ObjectProperty description: An ObjectProperty that has is used for grouping purposes and should not be instantiated @@ -305,36 +326,78 @@ classes: DefinedObjectPropertyByDomain: is_a: DefinedObjectProperty description: An ObjectProperty that is defined by a parent property and a domain + slot_usage: + definition: + string_serialization: "A {genus} that holds between a {domain} and something" comments: - hidden GCI analogs not supported (i.e. adding a more specific domain that is used for classification) todos: - rolification + see_also: + - https://oborel.github.io/obo-relations/domain-or-range-specific-relation/ annotations: swrl: |- {{genus}}(?s, ?o), {{domain}}(?s) -> {{id}}(?s, ?o) DefinedObjectPropertyByRange: is_a: DefinedObjectProperty description: An ObjectProperty that is defined by a parent property and a range + slot_usage: + definition: + string_serialization: "A {genus} that holds between something and a {range}" comments: - hidden GCI analogs not supported (i.e. adding a more specific domain that is used for classification) todos: - rolification + see_also: + - https://oborel.github.io/obo-relations/domain-or-range-specific-relation/ annotations: swrl: |- {{genus}}(?s, ?o), {{range}}(?o) -> {{id}}(?s, ?o) DefinedObjectPropertyByDomainAndRange: is_a: DefinedObjectProperty description: An ObjectProperty that is defined by a parent property and a domain and a range + slot_usage: + definition: + string_serialization: "A {genus} that holds between a {domain} and a {range}" comments: - hidden GCI analogs not supported (i.e. adding a more specific domain that is used for classification) todos: - SWRL rule - rolification + see_also: + - https://oborel.github.io/obo-relations/domain-or-range-specific-relation/ + annotations: + swrl: |- + {{genus}}(?s, ?o), {{range}}(?o), {{domain}}(?s) -> {{id}}(?s, ?o) DefinedObjectPropertyByChain: is_a: DefinedObjectProperty - description: An ObjectProperty that is defined by a chain of relations + description: An ObjectProperty that is defined by a chain of two properties + slot_usage: + subproperty_of_pairwise_chain: + required: true + examples: + - value: overlaps + description: overlaps is defined as the chain of has-part followed by part-of + todos: + - this currently assumes chains of length 2 + - swrl + DefinedObjectPropertyByChainToReflexive: + is_a: DefinedObjectPropertyByChain + description: |- + An ObjectProperty that is defined by a chain of two properties where the second/final member + is used in a reflexive sense (regardless of whether it is actually reflexive). This has + the effect of making the chain relation a subproperty of the first member of the chain + slot_usage: + subproperty_of_pairwise_chain: + required: true examples: - value: characteristic of part of + todos: + - this currently assumes chains of length 2 + - swrl + #annotations: + # owl.template: |- + # SubObjectPropertyOf( {{subproperty_of_pairwise_chain.last_member}} {{id}} ) TransitiveForm: is_a: DefinedObjectProperty description: An ObjectProperty that is defined as the transitive form of another relation @@ -363,7 +426,7 @@ classes: attributes: subject_to_process_property: range: ObjectProperty - object_to_process_property: + process_to_object_property: range: ObjectProperty uses_rolified_property: range: RolifiedObjectProperty @@ -371,13 +434,20 @@ classes: see_also: - https://oborel.github.io/obo-relations/interaction-relations/ - http://ontologydesignpatterns.org/wiki/Submissions:N-Ary_Relation_Pattern_%28OWL_2%29 + - https://github.com/oborel/obo-relations/pull/522 + - https://github.com/oborel/obo-relations/issues/521 annotations: owl.template: |- SubObjectPropertyOf( ObjectPropertyChain({{subject_to_process_property}} {{uses_rolified_property.id}} - {{object_to_process_property}}) + {{process_to_object_property}}) {{id}}) + swrl: |- + {{subject_to_process_property}}(?s, ?proc), + {{uses_rolified_property.rolification_of}}(?proc), + {{process_to_object_property}}(?o, ?proc) + -> {{id}}(?s, ?o) diff --git a/tests/output/chromo.schema.owl.ttl b/tests/output/chromo.schema.owl.ttl index fb5df78..f61a509 100644 --- a/tests/output/chromo.schema.owl.ttl +++ b/tests/output/chromo.schema.owl.ttl @@ -27,7 +27,7 @@ Objects created using this schema can be directly worked with in YAML/Python, Additionally they can be translated to OWL""" ; - linkml:generation_date "2022-02-23T18:49:17" ; + linkml:generation_date "2022-03-07T12:19:20" ; linkml:metamodel_version "1.7.0" ; linkml:source_file "chromo.yaml" ; linkml:source_file_date "2022-01-12T21:11:50" ; @@ -49,17 +49,17 @@ chromoschema:ChromosomePartCollection a owl:Class, linkml:ClassDefinition ; rdfs:label "ChromosomePartCollection" ; rdfs:subClassOf [ a owl:Restriction ; + owl:allValuesFrom chromoschema:OrganismTaxon ; + owl:onProperty dcterms:hasPart ], + [ a owl:Restriction ; owl:maxQualifiedCardinality 1 ; owl:onClass linkml:String ; owl:onProperty chromoschema:name ], [ a owl:Restriction ; - owl:allValuesFrom chromoschema:Genome ; - owl:onProperty dcterms:hasPart ], - [ a owl:Restriction ; - owl:allValuesFrom chromoschema:OrganismTaxon ; + owl:allValuesFrom chromoschema:ChromosomePart ; owl:onProperty dcterms:hasPart ], [ a owl:Restriction ; - owl:allValuesFrom chromoschema:ChromosomePart ; + owl:allValuesFrom chromoschema:Genome ; owl:onProperty dcterms:hasPart ] . chromoschema:StrandType a owl:Class, @@ -214,13 +214,6 @@ chromoschema:Genome a owl:Class, linkml:ClassDefinition ; rdfs:label "Genome" ; rdfs:subClassOf [ a owl:Restriction ; - owl:onClass chromoschema:LabelType ; - owl:onProperty rdfs:label ; - owl:qualifiedCardinality 1 ], - [ a owl:Restriction ; - owl:allValuesFrom chromoschema:GenomeBuild ; - owl:onProperty chromoschema:previous_builds ], - [ a owl:Restriction ; owl:maxQualifiedCardinality 1 ; owl:onClass chromoschema:GenomeBuild ; owl:onProperty biolink:genome_build ], @@ -231,6 +224,13 @@ chromoschema:Genome a owl:Class, [ a owl:Restriction ; owl:onClass linkml:String ; owl:onProperty chromoschema:id ; + owl:qualifiedCardinality 1 ], + [ a owl:Restriction ; + owl:allValuesFrom chromoschema:GenomeBuild ; + owl:onProperty chromoschema:previous_builds ], + [ a owl:Restriction ; + owl:onClass chromoschema:LabelType ; + owl:onProperty rdfs:label ; owl:qualifiedCardinality 1 ] ; skos:definition """Represents a sequenced genome, one per species. Each genome can be associated with one or more builds""" . @@ -241,11 +241,11 @@ chromoschema:OrganismTaxon a owl:Class, rdfs:subClassOf [ a owl:Restriction ; owl:maxQualifiedCardinality 1 ; owl:onClass chromoschema:LabelType ; - owl:onProperty rdfs:label ], + owl:onProperty OIO:hasExactSynonym ], [ a owl:Restriction ; owl:maxQualifiedCardinality 1 ; owl:onClass chromoschema:LabelType ; - owl:onProperty OIO:hasExactSynonym ], + owl:onProperty rdfs:label ], [ a owl:Restriction ; owl:onClass linkml:String ; owl:onProperty chromoschema:id ; @@ -325,39 +325,51 @@ chromoschema:ChromosomePart a owl:Class, owl:onProperty chromoschema:somal_type ], [ a owl:Restriction ; owl:maxQualifiedCardinality 1 ; - owl:onClass linkml:Integer ; - owl:onProperty gff:end ], + owl:onClass chromoschema:ChromosomeNameType ; + owl:onProperty chromoschema:chromosome_name ], + [ a owl:Restriction ; + owl:maxQualifiedCardinality 1 ; + owl:onClass chromoschema:EntityType ; + owl:onProperty rdf:type ], [ a owl:Restriction ; owl:maxQualifiedCardinality 1 ; owl:onClass chromoschema:LabelType ; owl:onProperty rdfs:label ], [ a owl:Restriction ; owl:maxQualifiedCardinality 1 ; - owl:onClass chromoschema:ChromosomeNameType ; - owl:onProperty chromoschema:chromosome_name ], + owl:onClass linkml:Integer ; + owl:onProperty gff:start ], [ a owl:Restriction ; owl:maxQualifiedCardinality 1 ; - owl:onClass chromoschema:ChromosomePart ; + owl:onClass chromoschema:TaxonIdentifier ; + owl:onProperty RO:0002162 ], + [ a owl:Restriction ; + owl:maxQualifiedCardinality 1 ; + owl:onClass chromoschema:LocationType ; owl:onProperty BFO:0000050 ], [ a owl:Restriction ; owl:maxQualifiedCardinality 1 ; owl:onClass chromoschema:BandDescriptor ; owl:onProperty chromoschema:band_descriptor ], + [ a owl:Restriction ; + owl:maxQualifiedCardinality 1 ; + owl:onClass chromoschema:SexChromosomeType ; + owl:onProperty chromoschema:sex_chromosome_type ], [ a owl:Restriction ; owl:maxQualifiedCardinality 1 ; owl:onClass chromoschema:GenomeBuild ; owl:onProperty biolink:genome_build ], [ a owl:Restriction ; - owl:allValuesFrom linkml:String ; - owl:onProperty OIO:hasExactSynonym ], + owl:allValuesFrom chromoschema:ChromosomePart ; + owl:onProperty BFO:0000051 ], [ a owl:Restriction ; owl:maxQualifiedCardinality 1 ; - owl:onClass chromoschema:TaxonIdentifier ; - owl:onProperty RO:0002162 ], + owl:onClass linkml:Integer ; + owl:onProperty gff:end ], [ a owl:Restriction ; owl:maxQualifiedCardinality 1 ; - owl:onClass chromoschema:SexChromosomeType ; - owl:onProperty chromoschema:sex_chromosome_type ], + owl:onClass chromoschema:ChromosomePart ; + owl:onProperty BFO:0000050 ], [ a owl:Restriction ; owl:onClass linkml:String ; owl:onProperty chromoschema:id ; @@ -365,24 +377,12 @@ chromoschema:ChromosomePart a owl:Class, [ a owl:Restriction ; owl:allValuesFrom linkml:Uriorcurie ; owl:onProperty skos:exactMatch ], - [ a owl:Restriction ; - owl:maxQualifiedCardinality 1 ; - owl:onClass chromoschema:EntityType ; - owl:onProperty rdf:type ], - [ a owl:Restriction ; - owl:maxQualifiedCardinality 1 ; - owl:onClass linkml:Integer ; - owl:onProperty gff:start ], [ a owl:Restriction ; owl:allValuesFrom linkml:String ; - owl:onProperty OIO:hasBroadSynonym ], - [ a owl:Restriction ; - owl:allValuesFrom chromoschema:ChromosomePart ; - owl:onProperty BFO:0000051 ], + owl:onProperty OIO:hasExactSynonym ], [ a owl:Restriction ; - owl:maxQualifiedCardinality 1 ; - owl:onClass chromoschema:LocationType ; - owl:onProperty BFO:0000050 ] ; + owl:allValuesFrom linkml:String ; + owl:onProperty OIO:hasBroadSynonym ] ; skos:definition "A Chromosome or a part of a chromosome (includes whole chromosomes, arms, and bands)" ; skos:note """OWL Notes: when translated to OWL, instances of this class will be treated as OWL classes, with the superclass determined by the type field""", diff --git a/tests/test_ro_metamodel.py b/tests/test_ro_metamodel.py index 7e5737b..a57077e 100644 --- a/tests/test_ro_metamodel.py +++ b/tests/test_ro_metamodel.py @@ -33,7 +33,7 @@ -class TestROMetamodeel(unittest.TestCase): +class TestROMetamodel(unittest.TestCase): """Relation Ontology test case.""" def test_build_relation_ontology(self):