Skip to content

Commit

Permalink
Merge pull request #9 from linkml/issue_8
Browse files Browse the repository at this point in the history
Issue 8
  • Loading branch information
hsolbrig authored Jun 11, 2021
2 parents 2538644 + dc98b0f commit 21dafa6
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 17 deletions.
4 changes: 2 additions & 2 deletions linkml_runtime/linkml_model/extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ class Extension(YAMLRoot):

def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
if self._is_empty(self.tag):
raise ValueError("tag must be supplied")
self.MissingRequiredField("tag")
if not isinstance(self.tag, URIorCURIE):
self.tag = URIorCURIE(self.tag)

if self._is_empty(self.value):
raise ValueError("value must be supplied")
self.MissingRequiredField("value")
if not isinstance(self.value, str):
self.value = str(self.value)

Expand Down
30 changes: 15 additions & 15 deletions linkml_runtime/linkml_model/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class Element(YAMLRoot):

def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
if self._is_empty(self.name):
raise ValueError("name must be supplied")
self.MissingRequiredField("name")
if not isinstance(self.name, ElementName):
self.name = ElementName(self.name)

Expand Down Expand Up @@ -269,12 +269,12 @@ def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
if self.default_prefix is None:
self.default_prefix = sfx(str(self.id))
if self._is_empty(self.name):
raise ValueError("name must be supplied")
self.MissingRequiredField("name")
if not isinstance(self.name, SchemaDefinitionName):
self.name = SchemaDefinitionName(self.name)

if self._is_empty(self.id):
raise ValueError("id must be supplied")
self.MissingRequiredField("id")
if not isinstance(self.id, URI):
self.id = URI(self.id)

Expand Down Expand Up @@ -355,7 +355,7 @@ class TypeDefinition(Element):

def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
if self._is_empty(self.name):
raise ValueError("name must be supplied")
self.MissingRequiredField("name")
if not isinstance(self.name, TypeDefinitionName):
self.name = TypeDefinitionName(self.name)

Expand Down Expand Up @@ -390,7 +390,7 @@ class SubsetDefinition(Element):

def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
if self._is_empty(self.name):
raise ValueError("name must be supplied")
self.MissingRequiredField("name")
if not isinstance(self.name, SubsetDefinitionName):
self.name = SubsetDefinitionName(self.name)

Expand Down Expand Up @@ -483,7 +483,7 @@ class EnumDefinition(Element):

def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
if self._is_empty(self.name):
raise ValueError("name must be supplied")
self.MissingRequiredField("name")
if not isinstance(self.name, EnumDefinitionName):
self.name = EnumDefinitionName(self.name)

Expand Down Expand Up @@ -550,7 +550,7 @@ class SlotDefinition(Definition):

def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
if self._is_empty(self.name):
raise ValueError("name must be supplied")
self.MissingRequiredField("name")
if not isinstance(self.name, SlotDefinitionName):
self.name = SlotDefinitionName(self.name)

Expand Down Expand Up @@ -677,7 +677,7 @@ class ClassDefinition(Definition):

def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
if self._is_empty(self.name):
raise ValueError("name must be supplied")
self.MissingRequiredField("name")
if not isinstance(self.name, ClassDefinitionName):
self.name = ClassDefinitionName(self.name)

Expand Down Expand Up @@ -737,12 +737,12 @@ class Prefix(YAMLRoot):

def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
if self._is_empty(self.prefix_prefix):
raise ValueError("prefix_prefix must be supplied")
self.MissingRequiredField("prefix_prefix")
if not isinstance(self.prefix_prefix, PrefixPrefixPrefix):
self.prefix_prefix = PrefixPrefixPrefix(self.prefix_prefix)

if self._is_empty(self.prefix_reference):
raise ValueError("prefix_reference must be supplied")
self.MissingRequiredField("prefix_reference")
if not isinstance(self.prefix_reference, URI):
self.prefix_reference = URI(self.prefix_reference)

Expand All @@ -766,12 +766,12 @@ class LocalName(YAMLRoot):

def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
if self._is_empty(self.local_name_source):
raise ValueError("local_name_source must be supplied")
self.MissingRequiredField("local_name_source")
if not isinstance(self.local_name_source, LocalNameLocalNameSource):
self.local_name_source = LocalNameLocalNameSource(self.local_name_source)

if self._is_empty(self.local_name_value):
raise ValueError("local_name_value must be supplied")
self.MissingRequiredField("local_name_value")
if not isinstance(self.local_name_value, str):
self.local_name_value = str(self.local_name_value)

Expand Down Expand Up @@ -820,12 +820,12 @@ class AltDescription(YAMLRoot):

def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
if self._is_empty(self.source):
raise ValueError("source must be supplied")
self.MissingRequiredField("source")
if not isinstance(self.source, AltDescriptionSource):
self.source = AltDescriptionSource(self.source)

if self._is_empty(self.description):
raise ValueError("description must be supplied")
self.MissingRequiredField("description")
if not isinstance(self.description, str):
self.description = str(self.description)

Expand Down Expand Up @@ -866,7 +866,7 @@ class PermissibleValue(YAMLRoot):

def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
if self._is_empty(self.text):
raise ValueError("text must be supplied")
self.MissingRequiredField("text")
if not isinstance(self.text, PermissibleValueText):
self.text = PermissibleValueText(self.text)

Expand Down
7 changes: 7 additions & 0 deletions linkml_runtime/utils/yamlutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,13 @@ def _normalize_inlined_slot(self, slot_name: str, slot_type: Type, key_name: Opt
self[slot_name] = dict_slot[0]
self._normalize_inlined_as_dict(slot_name, slot_type, key_name, keyed)

# ==================
# Error intercepts
# ==================
def MissingRequiredField(self, field_name: str) -> None:
""" Generic loader error handler """
raise ValueError(f"{field_name} must be supplied")


def root_representer(dumper: yaml.Dumper, data: YAMLRoot):
""" YAML callback -- used to filter out empty values (None, {}, [] and false)
Expand Down
23 changes: 23 additions & 0 deletions tests/test_issues/input/issue_8.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
id: https://w3id.org/include_core
# Name is omitted
description: >-
This is an example of an imported module
imports:
- linkml:types
prefixes:
linkml: https://w3id.org/linkml/
include_core: https://w3id.org/mixs/include_core/
default_prefix: include_core

slots:
# Slot name ("id") is missing
- identifier: true
required: true

classes:
# Class name (root) is missing
- description: >-
root class
slots:
- id
65 changes: 65 additions & 0 deletions tests/test_issues/test_issue_8.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import unittest
from typing import Type

from linkml_runtime.linkml_model import SchemaDefinition, SlotDefinition, ClassDefinition
from linkml_runtime.loaders import yaml_loader
from linkml_runtime.utils.yamlutils import YAMLRoot
from tests.test_issues.environment import env


def override(cls: Type[YAMLRoot]):
def mrf(self, field_name: str) -> None:
if isinstance(self, SchemaDefinition) and field_name == "name":
self.name = self.id.rsplit('/', 1)[1]
elif isinstance(self, SlotDefinition) and field_name == "name":
self.name = "id"
elif isinstance(self, ClassDefinition) and field_name == "name":
self.name = "core"
else:
cls.MissingRequiredField(f"{self.__class__.__name}.{field_name}")
orig = cls.MissingRequiredField
cls.MissingRequiredField = mrf
return orig


msgs = set()


def override2():
def mrf(self, field_name: str) -> None:
msgs.add(f"{self.__class__.__name__}.{field_name} is not supplied")
orig = YAMLRoot.MissingRequiredField
YAMLRoot.MissingRequiredField = mrf
return orig


class TestErrorIntercept(unittest.TestCase):

def test_missing_intercept(self):
test_file = env.input_path('issue_8.yaml')
with self.assertRaises(ValueError) as e:
yaml_loader.load(test_file, SchemaDefinition)
self.assertEqual('name must be supplied', str(e.exception), "ValueError should be raised")

try:
orig = override2()
yaml_loader.load(test_file, SchemaDefinition)
finally:
YAMLRoot.MissingRequiredField = orig
self.assertEqual({'ClassDefinition.name is not supplied',
'SlotDefinition.name is not supplied',
'SchemaDefinition.name is not supplied'}, msgs)

try:
origschd = override(SchemaDefinition)
origslotd = override(SlotDefinition)
origcd = override(ClassDefinition)
yaml_loader.load(test_file, SchemaDefinition)
finally:
SchemaDefinition.MissingRequiredField = origschd
SlotDefinition.MissingRequiredField = origslotd
ClassDefinition.MissingRequiredField = origcd


if __name__ == '__main__':
unittest.main()

0 comments on commit 21dafa6

Please sign in to comment.