def test_as_dict_includes_expected_fields(self): schema = Schema( "term_name", properties={ 'mandatory': Property('mandatory', 'desc', required=True), 'whatever_man': Property('whatever_man', 'desc', required=False), }, skos_preflabel="preferred", exact_synonym=["splynonym"]) expected_fields = { '$id': 'term_name', 'type': 'object', 'additionalProperties': True, 'properties': { 'mandatory': { 'description': 'desc', 'type': 'string' }, 'whatever_man': { 'description': 'desc', 'type': 'string' }, }, 'required': ['mandatory'] } schema_dict = schema.as_dict() for expected_field, expected_value in expected_fields.items(): self.assertIn(expected_field, schema_dict) self.assertEqual(schema_dict[expected_field], expected_value)
def test_type_info_wraps_in_array_if_array(self): prop = Property("foo", "desc", min_cardinality=0) prop.add_type(RefType("reef")) self.assertEqual(prop.type_info(), { 'type': 'array', 'items': {'$ref': 'reef'}, })
def test_required_property_names_includes_only_required_properties(self): schema = Schema( "term_name", properties={ 'mandatory': Property('mandatory', 'desc', required=True), 'whatever_man': Property('whatever_man', 'desc', required=False), } ) self.assertEqual(schema.required_property_names(), ['mandatory'])
def test_base_type_info_returns_oneof_for_multiple_values(self): prop = Property("foo", "desc") prop.add_type(RefType("ref1")) prop.add_type(RefType("ref2")) self.assertEqual(prop.base_type_info(), { 'oneOf': [ {'$ref': 'ref1'}, {'$ref': 'ref2'}, ] })
def test_optional_fields_includes_only_defined_fields(self): prop = Property( "foo", "desc", comment="hey", skos_preflabel="jimbo" ) optional_fields = prop.optional_fields() self.assertIn("comment", optional_fields) self.assertIn("skos:prefLabel", optional_fields) self.assertNotIn("title", optional_fields) self.assertNotIn("oneOf", optional_fields)
def test_as_dict_includes_expected_fields(self): prop = Property("foo", "desc", max_cardinality=3) prop.add_enum_value("steve") prop.add_enum_value("stove") expected_fields = { 'description': 'desc', 'oneOf': ['steve', 'stove'], 'type': 'array', 'items': {'type': 'string'}, 'maxItems': 3, } dictified = prop.as_dict() for expected_field, expected_value in expected_fields.items(): self.assertIn(expected_field, dictified) self.assertEqual(dictified[expected_field], expected_value)
def test_add_type_allows_further_types_if_not_restrictive(self): prop = Property("foo", "desc") prop.add_type(PrimitiveType("string"), restrictive=False) # we just run this to see if it raises an exception, so there's no assertions in the test prop.add_type(RefType("argbl"))
def test_base_type_info_returns_type_for_single_value(self): prop = Property("foo", "desc") prop.add_type(RefType("reef")) self.assertEqual(prop.base_type_info(), {'$ref': 'reef'})
def test_is_array_type_true_if_either_cardinality(self): self.assertTrue(Property("foo", "desc", min_cardinality=1).is_array_type()) self.assertTrue(Property("foo", "desc", max_cardinality=3).is_array_type())
def test_base_type_info_defaults_to_string(self): prop = Property("foo", "desc") self.assertEqual(prop.base_type_info(), {'type': 'string'})
def test_add_enum_value_mutex_with_type_constraints(self): prop = Property("foo", "desc") prop.add_enum_value("steve") with self.assertRaises(ValueError): prop.add_type(PrimitiveType("string"))
def test_add_enum_value_adds_enum_value(self): prop = Property("foo", "desc") prop.add_enum_value("steve") self.assertEqual(prop.allowed_values, ["steve"])
def ensure_property_initialized(self, target_property: rdflib.term.Identifier) -> None: property_name = self.graph_manager.namespaced_name_for_node(target_property) if property_name not in self.schema.properties: self.schema.properties[property_name] = Property(property_name, str(target_property))
def test_type_info_generates_flat_type_info_if_not_array(self): prop = Property("foo", "desc") prop.add_type(RefType("reef")) self.assertEqual(prop.type_info(), {'$ref': 'reef'})
def test_add_type_blocks_further_types_if_restrictive(self): prop = Property("foo", "desc") prop.add_type(PrimitiveType("string"), restrictive=True) with self.assertRaises(ValueError): prop.add_type(RefType("argbl"))
def test_add_type_adds_type(self): prop = Property("foo", "desc") self.assertEqual(len(prop.allowed_types), 0) prop.add_type(PrimitiveType("string")) self.assertEqual(prop.allowed_types, [PrimitiveType("string")])
def test_as_dict_always_includes_description_even_if_blank(self): prop = Property("foo", "", max_cardinality=3) self.assertIn('description', prop.as_dict())
def test_is_array_type_false_if_neither_cardinality(self): self.assertFalse(Property("foo", "desc").is_array_type())
def test_add_type_ignores_duplicates(self): prop = Property("foo", "desc") prop.add_type(PrimitiveType("string")) prop.add_type(PrimitiveType("string")) self.assertEqual(prop.allowed_types, [PrimitiveType("string")])
from data_model_exporter.rdf_graph_manager import RdfGraphManager from data_model_exporter.schema import Schema from data_model_exporter.property import Property from data_model_exporter.property_types import RefType from data_model_exporter.typing import JsonSchema # we manually define this because the preinstalled PROV namespace in rdflib doesn't include some terms we use, # e.g. 'definition' PROV = Namespace("http://www.w3.org/ns/prov#") OBO_IN_OWL = Namespace("http://www.geneontology.org/formats/oboInOwl#") # properties that should appear in the json schema even if they aren't present in the ttl file UNIVERSAL_PROPERTIES = { 'rdfs:label': Property('rdfs:label', "A human-readable name for the entity."), 'id': Property('id', "UUID for this entity."), 'describedBy': Property('describedBy', "The URL reference to the JSON Schema that defines this object."), } SKIPPABLE_DOMAIN_PREDICATES = [ RDF.type, # this just indicates something is a property, which we already know RDFS.domain, # no point annotating domain, since it's how we get a list of props for a class to begin with ] SKIPPABLE_RESTRICTION_PREDICATES = [ RDF.type, # indicates that it's a restriction property. we check this explicitly before scanning. OWL.onProperty, # we grab this beforehand as well to see what property the restrictions apply to. ]