Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add schemaview method to return permissible_value descendants and children #291

Merged
merged 4 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
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}"')

Check warning on line 653 in linkml_runtime/utils/schemaview.py

View check run for this annotation

Codecov / codecov/patch

linkml_runtime/utils/schemaview.py#L653

Added line #L653 was not covered by tests

@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 @@
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 @@
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