Skip to content

Commit 29fa17e

Browse files
authored
Merge pull request #102 from biolink/support_predicate_maps
add test for and fixes #93, fixes #86
2 parents cf2d672 + 68f848d commit 29fa17e

File tree

2 files changed

+111
-71
lines changed

2 files changed

+111
-71
lines changed

bmt/toolkit.py

Lines changed: 87 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
from bmt.utils import format_element, parse_name
2020

21-
2221
Url = str
2322
Path = str
2423

@@ -30,7 +29,6 @@
3029
ASSOCIATION_SLOT = "association slot"
3130
RELATED_TO = "related to"
3231

33-
3432
CACHE_SIZE = 1024
3533

3634
logger = logging.getLogger(__name__)
@@ -48,7 +46,7 @@ class Toolkit(object):
4846
"""
4947

5048
def __init__(
51-
self, schema: Union[Url, Path, TextIO, SchemaDefinition] = REMOTE_PATH,
49+
self, schema: Union[Url, Path, TextIO, SchemaDefinition] = REMOTE_PATH,
5250
predicate_map: Url = PREDICATE_MAP,
5351
infores_map: Url = INFORES_MAP
5452
) -> None:
@@ -292,7 +290,8 @@ def _filter_secondary(self, elements: List[str]) -> List[str]:
292290
return filtered_elements
293291

294292
@lru_cache(CACHE_SIZE)
295-
def get_permissible_value_ancestors(self, permissible_value: str, enum_name: str, formatted: bool = False) -> List[str]:
293+
def get_permissible_value_ancestors(self, permissible_value: str, enum_name: str, formatted: bool = False) -> List[
294+
str]:
296295
"""
297296
Get ancestors of a permissible value.
298297
@@ -394,11 +393,11 @@ def get_permissible_value_parent(self, permissible_value: str, enum_name: str) -
394393

395394
@lru_cache(CACHE_SIZE)
396395
def get_ancestors(
397-
self,
398-
name: str,
399-
reflexive: bool = True,
400-
formatted: bool = False,
401-
mixin: bool = True,
396+
self,
397+
name: str,
398+
reflexive: bool = True,
399+
formatted: bool = False,
400+
mixin: bool = True,
402401
) -> List[str]:
403402
"""
404403
Gets a list of names of ancestors.
@@ -444,11 +443,11 @@ def _get_mixin_descendants(self, ancestors: List[ElementName]) -> List[ElementNa
444443

445444
@lru_cache(CACHE_SIZE)
446445
def get_descendants(
447-
self,
448-
name: str,
449-
reflexive: bool = True,
450-
formatted: bool = False,
451-
mixin: bool = True,
446+
self,
447+
name: str,
448+
reflexive: bool = True,
449+
formatted: bool = False,
450+
mixin: bool = True,
452451
) -> List[str]:
453452
"""
454453
Gets a list of names of descendants.
@@ -487,9 +486,27 @@ def get_descendants(
487486

488487
return self._format_all_elements(filtered_desc, formatted)
489488

489+
@lru_cache(CACHE_SIZE)
490+
def get_all_multivalued_slots(self) -> List[str]:
491+
"""
492+
Gets a list of names of all multivalued slots.
493+
494+
Returns
495+
-------
496+
List[str]
497+
The names of all multivalued slots
498+
499+
"""
500+
multivalued_slots = []
501+
slots = self.view.all_slots()
502+
for slot_name, slot_def in slots.items():
503+
if self.view.is_multivalued(slot_name):
504+
multivalued_slots.append(slot_name)
505+
return multivalued_slots
506+
490507
@lru_cache(CACHE_SIZE)
491508
def get_children(
492-
self, name: str, formatted: bool = False, mixin: bool = True
509+
self, name: str, formatted: bool = False, mixin: bool = True
493510
) -> List[str]:
494511
"""
495512
Gets a list of names of children.
@@ -568,7 +585,6 @@ def get_element(self, name: str) -> Optional[Element]:
568585
if name in self.view.all_aliases()[e]:
569586
element = self.view.get_element(e)
570587
if element is None and "_" in name:
571-
print("has a _")
572588
element = self.get_element(name.replace("_", " "))
573589
if element is None:
574590
for e, el in self.view.all_elements().items():
@@ -577,11 +593,11 @@ def get_element(self, name: str) -> Optional[Element]:
577593
return element
578594

579595
def get_slot_domain(
580-
self,
581-
slot_name,
582-
include_ancestors: bool = False,
583-
formatted: bool = False,
584-
mixin: bool = True,
596+
self,
597+
slot_name,
598+
include_ancestors: bool = False,
599+
formatted: bool = False,
600+
mixin: bool = True,
585601
) -> List[str]:
586602
"""
587603
Get the domain for a given slot.
@@ -625,11 +641,11 @@ def get_slot_domain(
625641
return self._format_all_elements(slot_domain, formatted)
626642

627643
def get_slot_range(
628-
self,
629-
slot_name,
630-
include_ancestors: bool = False,
631-
formatted: bool = False,
632-
mixin: bool = True,
644+
self,
645+
slot_name,
646+
include_ancestors: bool = False,
647+
formatted: bool = False,
648+
mixin: bool = True,
633649
) -> List[str]:
634650
"""
635651
Get the range for a given slot.
@@ -662,11 +678,11 @@ def get_slot_range(
662678
return self._format_all_elements(slot_range, formatted)
663679

664680
def get_all_slots_with_class_domain(
665-
self,
666-
class_name,
667-
check_ancestors: bool = False,
668-
formatted: bool = False,
669-
mixin: bool = True,
681+
self,
682+
class_name,
683+
check_ancestors: bool = False,
684+
formatted: bool = False,
685+
mixin: bool = True,
670686
) -> List[str]:
671687
"""
672688
Given a class, get all the slots where the class is the domain.
@@ -694,11 +710,11 @@ def get_all_slots_with_class_domain(
694710
return self._format_all_elements(slot_names, formatted)
695711

696712
def get_all_slots_with_class_range(
697-
self,
698-
class_name,
699-
check_ancestors: bool = False,
700-
formatted: bool = False,
701-
mixin: bool = True,
713+
self,
714+
class_name,
715+
check_ancestors: bool = False,
716+
formatted: bool = False,
717+
mixin: bool = True,
702718
) -> List[str]:
703719
"""
704720
Given a class, get all the slots where the class is the range.
@@ -726,11 +742,11 @@ def get_all_slots_with_class_range(
726742
return self._format_all_elements(slot_names, formatted)
727743

728744
def get_all_predicates_with_class_domain(
729-
self,
730-
class_name,
731-
check_ancestors: bool = False,
732-
formatted: bool = False,
733-
mixin: bool = True,
745+
self,
746+
class_name,
747+
check_ancestors: bool = False,
748+
formatted: bool = False,
749+
mixin: bool = True,
734750
) -> List[str]:
735751
"""
736752
Given a class, get all Biolink predicates where the class is the domain.
@@ -764,11 +780,11 @@ def get_all_predicates_with_class_domain(
764780
return self._format_all_elements(filtered_slots, formatted)
765781

766782
def get_all_predicates_with_class_range(
767-
self,
768-
class_name,
769-
check_ancestors: bool = False,
770-
formatted: bool = False,
771-
mixin: bool = True,
783+
self,
784+
class_name,
785+
check_ancestors: bool = False,
786+
formatted: bool = False,
787+
mixin: bool = True,
772788
):
773789
"""
774790
Given a class, get all Biolink predicates where the class is the range.
@@ -802,11 +818,11 @@ def get_all_predicates_with_class_range(
802818
return self._format_all_elements(filtered_slots, formatted)
803819

804820
def get_all_properties_with_class_domain(
805-
self,
806-
class_name,
807-
check_ancestors: bool = False,
808-
formatted: bool = False,
809-
mixin: bool = True,
821+
self,
822+
class_name,
823+
check_ancestors: bool = False,
824+
formatted: bool = False,
825+
mixin: bool = True,
810826
) -> List[str]:
811827
"""
812828
Given a class, get all Biolink properties where the class is the domain.
@@ -840,11 +856,11 @@ def get_all_properties_with_class_domain(
840856
return self._format_all_elements(filtered_slots, formatted)
841857

842858
def get_all_properties_with_class_range(
843-
self,
844-
class_name,
845-
check_ancestors: bool = False,
846-
formatted: bool = False,
847-
mixin: bool = True,
859+
self,
860+
class_name,
861+
check_ancestors: bool = False,
862+
formatted: bool = False,
863+
mixin: bool = True,
848864
) -> List[str]:
849865
"""
850866
Given a class, get all Biolink properties where the class is the range.
@@ -911,7 +927,7 @@ def get_value_type_for_slot(self, slot_name, formatted: bool = False) -> str:
911927
return element_type
912928

913929
def _get_all_slots_with_class_domain(
914-
self, element: Element, check_ancestors: bool, mixin: bool = True
930+
self, element: Element, check_ancestors: bool, mixin: bool = True
915931
) -> List[Element]:
916932
"""
917933
Given a class, get all the slots where the class is the domain.
@@ -944,7 +960,7 @@ def _get_all_slots_with_class_domain(
944960
return slots
945961

946962
def _get_all_slots_with_class_range(
947-
self, element: Element, check_ancestors: bool, mixin: bool = True
963+
self, element: Element, check_ancestors: bool, mixin: bool = True
948964
) -> List[Element]:
949965
"""
950966
Given a class, get all the slots where the class is the range.
@@ -968,7 +984,7 @@ def _get_all_slots_with_class_range(
968984
for k, v in self.view.schema.slots.items():
969985
if check_ancestors:
970986
if v.range == element.name or v.range in self.get_ancestors(
971-
element.name, mixin
987+
element.name, mixin
972988
):
973989
slots.append(v)
974990
else:
@@ -1200,11 +1216,11 @@ def get_element_by_prefix(
12001216

12011217
@lru_cache(CACHE_SIZE)
12021218
def get_element_by_mapping(
1203-
self,
1204-
identifier: str,
1205-
most_specific: bool = False,
1206-
formatted: bool = False,
1207-
mixin: bool = True,
1219+
self,
1220+
identifier: str,
1221+
most_specific: bool = False,
1222+
formatted: bool = False,
1223+
mixin: bool = True,
12081224
) -> Optional[str]:
12091225
"""
12101226
Get a Biolink Model element by mapping.
@@ -1297,7 +1313,7 @@ def _get_element_by_mapping(self, identifier: str) -> List[str]:
12971313

12981314
@lru_cache(CACHE_SIZE)
12991315
def get_element_by_exact_mapping(
1300-
self, identifier: str, formatted: bool = False
1316+
self, identifier: str, formatted: bool = False
13011317
) -> List[str]:
13021318
"""
13031319
Given an identifier as IRI/CURIE, find a Biolink element that corresponds
@@ -1324,7 +1340,7 @@ def get_element_by_exact_mapping(
13241340

13251341
@lru_cache(CACHE_SIZE)
13261342
def get_element_by_close_mapping(
1327-
self, identifier: str, formatted: bool = False
1343+
self, identifier: str, formatted: bool = False
13281344
) -> List[str]:
13291345
"""
13301346
Given an identifier as IRI/CURIE, find a Biolink element that corresponds
@@ -1350,7 +1366,7 @@ def get_element_by_close_mapping(
13501366

13511367
@lru_cache(CACHE_SIZE)
13521368
def get_element_by_related_mapping(
1353-
self, identifier: str, formatted: bool = False
1369+
self, identifier: str, formatted: bool = False
13541370
) -> List[str]:
13551371
"""
13561372
Given an identifier as IRI/CURIE, find a Biolink element that corresponds
@@ -1376,7 +1392,7 @@ def get_element_by_related_mapping(
13761392

13771393
@lru_cache(CACHE_SIZE)
13781394
def get_element_by_narrow_mapping(
1379-
self, identifier: str, formatted: bool = False
1395+
self, identifier: str, formatted: bool = False
13801396
) -> List[str]:
13811397
"""
13821398
Given an identifier as IRI/CURIE, find a Biolink element that corresponds
@@ -1402,7 +1418,7 @@ def get_element_by_narrow_mapping(
14021418

14031419
@lru_cache(CACHE_SIZE)
14041420
def get_element_by_broad_mapping(
1405-
self, identifier: str, formatted: bool = False
1421+
self, identifier: str, formatted: bool = False
14061422
) -> List[str]:
14071423
"""
14081424
Given an identifier as IRI/CURIE, find a Biolink element that corresponds
@@ -1428,7 +1444,7 @@ def get_element_by_broad_mapping(
14281444

14291445
@lru_cache(CACHE_SIZE)
14301446
def get_all_elements_by_mapping(
1431-
self, identifier: str, formatted: bool = False
1447+
self, identifier: str, formatted: bool = False
14321448
) -> List[str]:
14331449
"""
14341450
Given an identifier as IRI/CURIE, find all Biolink elements that correspond
@@ -1451,7 +1467,7 @@ def get_all_elements_by_mapping(
14511467
return self._format_all_elements(mappings, formatted)
14521468

14531469
def _format_all_elements(
1454-
self, elements: List[str], formatted: bool = False
1470+
self, elements: List[str], formatted: bool = False
14551471
) -> List[str]:
14561472
"""
14571473
Format all the elements in a given list.

tests/unit/test_toolkit.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,3 +460,27 @@ def test_get_value_type_for_slot(toolkit):
460460
assert "biolink:CategoryType" in toolkit.get_value_type_for_slot(
461461
"category", formatted=True
462462
)
463+
464+
465+
def test_get_all_types(toolkit):
466+
basic_descendants = {}
467+
468+
# get_all_types()
469+
types = toolkit.get_all_types()
470+
471+
for element in types:
472+
try:
473+
basic_descendants.update({
474+
element: toolkit.get_descendants(
475+
element,
476+
reflexive=False,
477+
mixin=False,
478+
)
479+
})
480+
except Exception as e:
481+
assert False, f"Error getting descendants for {element}: {e}"
482+
483+
484+
def test_get_all_multivalued_slots(toolkit):
485+
assert "synonym" in toolkit.get_all_multivalued_slots()
486+
assert "id" not in toolkit.get_all_multivalued_slots()

0 commit comments

Comments
 (0)