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

[FDS-2506] Fix type Validation #1526

Merged
merged 5 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
16 changes: 9 additions & 7 deletions schematic/models/validate_attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,7 @@ def type_validation(
) -> tuple[list[list[str]], list[list[str]]]:
"""
Purpose:
Check if values for a given manifest attribue are the same type
Check if values for a given manifest attribute are the same type
specified in val_rule.
Input:
- val_rule: str, Validation rule, specifying input type, either
Expand All @@ -1121,6 +1121,10 @@ def type_validation(
TODO:
Convert all inputs to .lower() just to prevent any entry errors.
"""

val_rule_components = val_rule.split(" ")
val_rule_type = val_rule_components[0]

specified_type = {
"num": (int, np.int64, float),
"int": (int, np.int64),
Expand All @@ -1132,15 +1136,15 @@ def type_validation(
warnings: list[list[str]] = []

# num indicates either a float or int.
if val_rule == "num":
if val_rule_type == "num":
for i, value in enumerate(manifest_col):
entry_has_value = self.get_entry_has_value(
entry=value,
node_display_name=manifest_col.name,
)
if (
bool(value)
and not isinstance(value, specified_type[val_rule])
and not isinstance(value, specified_type[val_rule_type])
and entry_has_value
):
vr_errors, vr_warnings = GenerateError.generate_type_error(
Expand All @@ -1152,18 +1156,17 @@ def type_validation(
)
if vr_errors:
errors.append(vr_errors)
# It seems impossible to get warnings with type rules
if vr_warnings:
warnings.append(vr_warnings)
elif val_rule in ["int", "float", "str"]:
elif val_rule_type in ["int", "float", "str"]:
for i, value in enumerate(manifest_col):
entry_has_value = self.get_entry_has_value(
entry=value,
node_display_name=manifest_col.name,
)
if (
bool(value)
and not isinstance(value, specified_type[val_rule])
and not isinstance(value, specified_type[val_rule_type])
and entry_has_value
):
vr_errors, vr_warnings = GenerateError.generate_type_error(
Expand All @@ -1175,7 +1178,6 @@ def type_validation(
)
if vr_errors:
errors.append(vr_errors)
# It seems impossible to get warnings with type rules
if vr_warnings:
warnings.append(vr_warnings)
return errors, warnings
Expand Down
8 changes: 4 additions & 4 deletions tests/data/example.model.csv
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ Check Regex List Like,,,,,TRUE,DataProperty,,,list like::regex match [a-f]
Check Regex Single,,,,,TRUE,DataProperty,,,regex search [a-f]
Check Regex Format,,,,,TRUE,DataProperty,,,regex match [a-f]
Check Regex Integer,,,,,TRUE,DataProperty,,,regex search ^\d+$
Check Num,,,,,TRUE,DataProperty,,,num
Check Float,,,,,TRUE,DataProperty,,,float
Check Int,,,,,TRUE,DataProperty,,,int
Check String,,,,,TRUE,DataProperty,,,str
Check Num,,,,,TRUE,DataProperty,,,num error
Check Float,,,,,TRUE,DataProperty,,,float error
Check Int,,,,,TRUE,DataProperty,,,int error
Check String,,,,,TRUE,DataProperty,,,str error
Check URL,,,,,TRUE,DataProperty,,,url
Check Match at Least,,,,,TRUE,DataProperty,,,matchAtLeastOne Patient.PatientID set
Check Match Exactly,,,,,TRUE,DataProperty,,,matchExactlyOne MockComponent.checkMatchExactly set
Expand Down
8 changes: 4 additions & 4 deletions tests/data/example.model.jsonld
Original file line number Diff line number Diff line change
Expand Up @@ -1258,7 +1258,7 @@
"sms:displayName": "Check Num",
"sms:required": "sms:true",
"sms:validationRules": [
"num"
"num error"
]
},
{
Expand All @@ -1277,7 +1277,7 @@
"sms:displayName": "Check Float",
"sms:required": "sms:true",
"sms:validationRules": [
"float"
"float error"
]
},
{
Expand All @@ -1296,7 +1296,7 @@
"sms:displayName": "Check Int",
"sms:required": "sms:true",
"sms:validationRules": [
"int"
"int error"
]
},
{
Expand All @@ -1315,7 +1315,7 @@
"sms:displayName": "Check String",
"sms:required": "sms:true",
"sms:validationRules": [
"str"
"str error"
]
},
{
Expand Down
114 changes: 109 additions & 5 deletions tests/unit/test_validate_attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,104 @@ def test_generate_filename_error_unsupported_error_type(
error_type="unsupported error type",
)

@pytest.mark.parametrize(
"input_rule, input_num, input_name, input_entry, expected_error, expected_warning",
[
(
"x",
0,
"Patient",
"y",
[],
[
0,
"Patient",
"On row 0 the attribute Patient does not contain the proper value type x.",
"y",
],
),
(
"x warning",
0,
"Patient",
"y",
[],
[
0,
"Patient",
"On row 0 the attribute Patient does not contain the proper value type x.",
"y",
],
),
(
"x error",
0,
"Patient",
"y",
[
0,
"Patient",
"On row 0 the attribute Patient does not contain the proper value type x.",
"y",
],
[],
),
],
)
def test_generate_type_error(
self,
dmge: DataModelGraphExplorer,
input_rule: str,
input_num: int,
input_name: str,
input_entry: str,
expected_error: list[str],
expected_warning: list[str],
) -> None:
"""Testing for GenerateError.generate_type_error"""
error, warning = GenerateError.generate_type_error(
val_rule=input_rule,
row_num=input_num,
attribute_name=input_name,
invalid_entry=input_entry,
dmge=dmge,
)
import logging

logging.warning(error)
logging.warning(warning)
assert error == expected_error
assert warning == expected_warning

@pytest.mark.parametrize(
"input_rule, input_num, input_name, input_entry, exception",
[
# Empty rule or entry causes a key error
("", 0, "x", "x", KeyError),
("x", 0, "x", "", KeyError),
# Empty attribute causes an index error
("x", 0, "", "x", IndexError),
],
)
def test_generate_type_error_exceptions(
self,
dmge: DataModelGraphExplorer,
input_rule: str,
input_num: int,
input_name: str,
input_entry: str,
exception: Exception,
) -> None:
"""Testing for GenerateError.generate_type_error"""
with pytest.raises(exception):
GenerateError.generate_type_error(
val_rule=input_rule,
row_num=input_num,
attribute_name=input_name,
invalid_entry=input_entry,
dmge=dmge,
)


class TestValidateAttributeObject:
"""Testing for ValidateAttribute class with all Synapse calls mocked"""
Expand Down Expand Up @@ -1792,15 +1890,19 @@ def test_type_validation_passing(
"input_column, rule",
[
(Series([1], name="Check String"), "str"),
(Series([1], name="Check String"), "str error"),
(Series(["a"], name="Check Num"), "num"),
(Series(["a"], name="Check Num"), "num error"),
(Series(["20"], name="Check Num"), "num"),
(Series([1.1], name="Check Int"), "int"),
(Series(["a"], name="Check Int"), "int"),
(Series(["a"], name="Check Int"), "int error"),
(Series([1], name="Check Float"), "float"),
(Series(["a"], name="Check Float"), "float"),
(Series(["a"], name="Check Float"), "float error"),
],
)
def test_type_validation_failing(
def test_type_validation_errors(
self, va_obj: ValidateAttribute, input_column: Series, rule: str
) -> None:
"""
Expand All @@ -1814,20 +1916,22 @@ def test_type_validation_failing(
@pytest.mark.parametrize(
"input_column, rule",
[
(Series([1], name="Check String"), "str error"),
(Series([1], name="Check String"), "str warning"),
(Series(["a"], name="Check Num"), "num warning"),
(Series(["a"], name="Check Int"), "int warning"),
(Series(["a"], name="Check Float"), "float warning"),
],
)
def test_type_validation_does_not_work(
def test_type_validation_warnings(
self, va_obj: ValidateAttribute, input_column: Series, rule: str
) -> None:
"""
This tests ValidateAttribute.type_validation
This test shows that the msg level parameter doesn't work
This test shows failing examples using the type rule
"""
errors, warnings = va_obj.type_validation(rule, input_column)
assert len(errors) == 0
assert len(warnings) == 0
assert len(warnings) == 1

################
# url_validation
Expand Down
Loading