Skip to content

Commit

Permalink
Add runtime validation that no extra parameters are provided
Browse files Browse the repository at this point in the history
I'd assumed that pydantic did this, but it turns out it doesn't.  Feels
like it's worth checking for, as extra parameters are likely to be a
mistake.
  • Loading branch information
inglesp committed Sep 26, 2024
1 parent 547c1dd commit 9f15198
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 0 deletions.
6 changes: 6 additions & 0 deletions pipeline/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
validate_cohortextractor_outputs,
validate_databuilder_outputs,
validate_glob_pattern,
validate_no_kwargs,
validate_type,
)

Expand Down Expand Up @@ -58,6 +59,7 @@ def build(
population_size: Any = None,
**kwargs: Any,
) -> Expectations:
validate_no_kwargs(kwargs, "project `expectations` section")
try:
population_size = int(population_size)
except (TypeError, ValueError):
Expand Down Expand Up @@ -91,6 +93,8 @@ def build(
f"must specify at least one output of: {', '.join(['highly_sensitive', 'moderately_sensitive', 'minimally_sensitive'])}"
)

validate_no_kwargs(kwargs, f"`outputs` section for action {action_id}")

cls.validate_output_filenames_are_valid(
action_id, "highly_sensitive", highly_sensitive
)
Expand Down Expand Up @@ -175,6 +179,7 @@ def build(
dummy_data_file: Any = None,
**kwargs: Any,
) -> Action:
validate_no_kwargs(kwargs, f"action {action_id}")
validate_type(outputs, dict, f"`outputs` section for action {action_id}")
validate_type(run, str, f"`run` section for action {action_id}")
validate_type(
Expand Down Expand Up @@ -243,6 +248,7 @@ def build(
expectations: Any = None,
**kwargs: Any,
) -> Pipeline:
validate_no_kwargs(kwargs, "project")
if version is None:
raise ValidationError(
f"Project file must have a `version` attribute specifying which "
Expand Down
5 changes: 5 additions & 0 deletions pipeline/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ def validate_type(val: Any, exp_type: type, loc: str, optional: bool = False) ->
raise ValidationError(f"{loc} must be a {type_lookup[exp_type]}")


def validate_no_kwargs(kwargs: dict[str, Any], loc: str) -> None:
if kwargs:
raise ValidationError(f"Unexpected parameters ({', '.join(kwargs)}) in {loc}")


def validate_glob_pattern(pattern: str, privacy_level: str) -> None:
"""
These patterns get converted into regular expressions and matched
Expand Down
60 changes: 60 additions & 0 deletions tests/test_type_validation.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import re

import pytest

from pipeline.exceptions import ValidationError
Expand Down Expand Up @@ -114,3 +116,61 @@ def test_output_filename_incorrect_type():
},
expectations={"population_size": 10},
)


def test_project_extra_parameters():
with pytest.raises(
ValidationError, match=re.escape("Unexpected parameters (extra) in project")
):
Pipeline.build(extra=123)


def test_action_extra_parameters():
with pytest.raises(
ValidationError,
match=re.escape("Unexpected parameters (extra) in action action1"),
):
Pipeline.build(
version=3,
actions={
"action1": {
"outputs": {},
"run": "test:v1",
"extra": 123,
}
},
expectations={"population_size": 10},
)


def test_outputs_extra_parameters():
with pytest.raises(
ValidationError,
match=re.escape(
"Unexpected parameters (extra) in `outputs` section for action action1"
),
):
Pipeline.build(
version=3,
actions={
"action1": {
"outputs": {"highly_sensitive": {"dataset": {}}, "extra": 123},
"run": "test:v1",
}
},
expectations={"population_size": 10},
)


def test_expectations_extra_parameters():
with pytest.raises(
ValidationError,
match=re.escape(
"Unexpected parameters (extra) in project `expectations` section"
),
):
Pipeline.build(
version=3,
actions={},
expectations={"population_size": 10, "extra": 123},
)

0 comments on commit 9f15198

Please sign in to comment.