Skip to content

Commit

Permalink
Merge pull request #291 from linkml/pv_descendants
Browse files Browse the repository at this point in the history
add schemaview method to return permissible_value descendants and children
  • Loading branch information
sierra-moxon authored Dec 14, 2023
2 parents bfec27d + 641c7b5 commit c9972b4
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 1 deletion.
51 changes: 50 additions & 1 deletion linkml_runtime/utils/schemaview.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,40 @@ def permissible_value_parent(self, permissible_value: str, enum_name: ENUM_NAME)
else:
return []

@lru_cache()
def permissible_value_children(self, permissible_value: str, enum_name: ENUM_NAME) -> Union[
str, PermissibleValueText, None, ValueError]:
"""
:param enum_name: parent enum name
:param permissible_value: permissible value
:return: all direct child permissible values (is_a)
CAT:
LION:
is_a: CAT
ANGRY_LION:
is_a: LION
TABBY:
is_a: CAT
BIRD:
EAGLE:
is_a: BIRD
"""

enum = self.get_enum(enum_name, strict=True)
children = []
if enum:
if permissible_value in enum.permissible_values:
pv = enum.permissible_values[permissible_value]
for isapv in enum.permissible_values:
isapv_entity = enum.permissible_values[isapv]
if isapv_entity.is_a and pv.text == isapv_entity.is_a:
children.append(isapv)
return children
else:
raise ValueError(f'No such enum as "{enum_name}"')

@lru_cache()
def slot_parents(self, slot_name: SLOT_NAME, imports=True, mixins=True, is_a=True) -> List[SlotDefinitionName]:
"""
Expand Down Expand Up @@ -719,6 +753,22 @@ def permissible_value_ancestors(self, permissible_value_text: str,
reflexive=reflexive,
depth_first=depth_first)

@lru_cache()
def permissible_value_descendants(self, permissible_value_text: str,
enum_name: ENUM_NAME,
reflexive=True,
depth_first=True) -> List[str]:
"""
Closure of permissible_value_children method
:enum
"""


return _closure(lambda x: self.permissible_value_children(x, enum_name),
permissible_value_text,
reflexive=reflexive,
depth_first=depth_first)

@lru_cache()
def enum_ancestors(self, enum_name: ENUM_NAME, imports=True, mixins=True, reflexive=True, is_a=True,
depth_first=True) -> List[EnumDefinitionName]:
Expand Down Expand Up @@ -931,7 +981,6 @@ def get_uri(self, element: Union[ElementName, Element], imports=True, expand=Fal
if schema == None:
raise ValueError(f'Cannot find {e.from_schema} in schema_map')
else:
logging.warning(f'from_schema not populated for element {e.name}')
schema = self.schema_map[self.in_schema(e.name)]
pfx = schema.default_prefix
uri = f'{pfx}:{e_name}'
Expand Down
2 changes: 2 additions & 0 deletions tests/test_utils/input/kitchen_sink_noimports.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,8 @@ enums:
is_a: OtherEnum
permissible_values:
CAT:
TABBY:
is_a: CAT
LION:
is_a: CAT
ANGRY_LION:
Expand Down
11 changes: 11 additions & 0 deletions tests/test_utils/test_schemaview.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,26 @@ def test_all_aliases(self):

def test_schemaview_enums(self):
view = SchemaView(SCHEMA_NO_IMPORTS)
with self.assertRaises(ValueError):
view.permissible_value_parent("not_a_pv", "not_an_enum")
for en, e in view.all_enums().items():
if e.name == "Animals":
for pv, v in e.permissible_values.items():
if pv == "CAT":
self.assertEqual(view.permissible_value_parent(pv, e.name), None)
self.assertEqual(view.permissible_value_ancestors(pv, e.name), ['CAT'])
self.assertIn("LION", view.permissible_value_descendants(pv, e.name))
self.assertIn("ANGRY_LION", view.permissible_value_descendants(pv, e.name))
self.assertIn("TABBY", view.permissible_value_descendants(pv, e.name))
self.assertIn("TABBY", view.permissible_value_children(pv, e.name))
self.assertIn("LION", view.permissible_value_children(pv, e.name))
self.assertNotIn("EAGLE", view.permissible_value_descendants(pv, e.name))
if pv == "LION":
self.assertIn("ANGRY_LION", view.permissible_value_children(pv, e.name))
if pv == "ANGRY_LION":
self.assertEqual(view.permissible_value_parent(pv, e.name), ['LION'])
self.assertEqual(view.permissible_value_ancestors(pv, e.name), ['ANGRY_LION', 'LION', 'CAT'])
self.assertEquals(["ANGRY_LION"], view.permissible_value_descendants(pv, e.name))
for cn, c in view.all_classes().items():
if c.name == "Adult":
self.assertEqual(view.class_ancestors(c.name), ['Adult', 'Person', 'HasAliases', 'Thing'])
Expand Down

0 comments on commit c9972b4

Please sign in to comment.