Skip to content

Commit 448f364

Browse files
committed
Introduce a ValueConverterFactory.
Add a helper object to facilitate the creation of value converters and ensure we only create the value converters we need for a given type of object, based on the slot definitions for that object.
1 parent 2738ba9 commit 448f364

File tree

1 file changed

+56
-23
lines changed

1 file changed

+56
-23
lines changed

src/sssom/rdf_internal.py

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import logging
66
from datetime import date
7-
from typing import Any, Dict, List, Optional, Set, Union, cast
7+
from typing import Any, Dict, List, Optional, Set, Type, Union, cast
88

99
from curies import Converter
1010
from linkml_runtime.linkml_model.meta import SlotDefinition
@@ -284,6 +284,50 @@ def to_rdf(self, value: Any) -> Node:
284284
return Literal(value)
285285

286286

287+
class ValueConverterFactory(object):
288+
"""Helper object to create value converters."""
289+
290+
constructors: Dict[str, Type[ValueConverter]]
291+
292+
def __init__(self) -> None:
293+
"""Create a new instance."""
294+
self.constructors = {
295+
"date": DateValueConverter,
296+
"double": DoubleValueConverter,
297+
"string": StringValueConverter,
298+
"ncname": StringValueConverter,
299+
"EntityReference": EntityReferenceValueConverter,
300+
"uriorcurie": EntityReferenceValueConverter,
301+
"NonRelativeURI": NonRelativeURIValueConverter,
302+
}
303+
304+
def create(
305+
self, range_name: str, schema: SchemaView, curie_converter: Converter
306+
) -> ValueConverter:
307+
"""Create a new value converter.
308+
309+
:param range_name: The range for which a value converter is
310+
wanted.
311+
:param schema: The SSSOM LinkML schema.
312+
:param curie_converter: The CURIE converter to use, for the
313+
converters that need one.
314+
315+
:returns: A suitable value converter for the range.
316+
"""
317+
ctor = self.constructors.get(range_name)
318+
if ctor is not None:
319+
if ctor == EntityReferenceValueConverter:
320+
return EntityReferenceValueConverter(curie_converter)
321+
else:
322+
return ctor()
323+
elif range_name.endswith("_enum"):
324+
return EnumValueConverter(schema, range_name)
325+
else:
326+
# This should only happen if a brand new type of slot has
327+
# been introduced in the SSSOM schema
328+
raise NotImplementedError(f"Range {range_name} is not supported")
329+
330+
287331
class ObjectConverter(object):
288332
"""Base class for conversion of SSSOM objects to and from RDF.
289333
@@ -331,31 +375,20 @@ def __init__(self, class_name: str, curie_converter: Converter):
331375
self.schema = SSSOMSchemaView()
332376
self.curie_converter = curie_converter
333377

334-
str_value_converter = StringValueConverter()
335-
er_value_converter = EntityReferenceValueConverter(curie_converter)
336-
self.value_converters = {
337-
"string": str_value_converter,
338-
"ncname": str_value_converter,
339-
"EntityReference": er_value_converter,
340-
"uriorcurie": er_value_converter,
341-
"NonRelativeURI": NonRelativeURIValueConverter(),
342-
"date": DateValueConverter(),
343-
"double": DoubleValueConverter(),
344-
"entity_type_enum": EnumValueConverter(self.schema.view, "entity_type_enum"),
345-
"sssom_version_enum": EnumValueConverter(self.schema.view, "sssom_version_enum"),
346-
"mapping_cardinality_enum": EnumValueConverter(
347-
self.schema.view, "mapping_cardinality_enum"
348-
),
349-
"predicate_modifier_enum": EnumValueConverter(
350-
self.schema.view, "predicate_modifier_enum"
351-
),
352-
}
353-
354378
self.slots_by_name = {}
355379
self.slots_by_uri = {}
380+
ranges: List[SlotDefinition] = []
356381
for slot in self.schema.view.class_induced_slots(class_name):
357382
self.slots_by_name[slot.name] = slot
358383
self.slots_by_uri[self._get_slot_uri(slot)] = slot
384+
ranges.append(slot.range)
385+
386+
self.value_converters = {}
387+
factory = ValueConverterFactory()
388+
for rng in set(ranges):
389+
if self.schema.view.get_class(rng) is not None:
390+
continue
391+
self.value_converters[rng] = factory.create(rng, self.schema.view, curie_converter)
359392

360393
self.name = self._fix_class_name(class_name)
361394
object_class = self.schema.view.get_class(class_name)
@@ -583,8 +616,8 @@ def _get_value_converter(self, slot: SlotDefinition) -> ValueConverter:
583616
"""
584617
converter = self.value_converters.get(slot.range)
585618
if converter is None:
586-
# This should only happen if a brand new type of slot has
587-
# been introduced in the SSSOM schema
619+
# This should have been caught already at init time by the
620+
# ValueConverterFactory
588621
raise NotImplementedError(f"Unsupported range {slot.range} for {slot.name}")
589622
return converter
590623

0 commit comments

Comments
 (0)