-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #289 from gaiaresources/BDRSPS-955
BDRSPS-955 Added siteVisitID -> siteID lookup check for the survey occurrence template
- Loading branch information
Showing
6 changed files
with
225 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
"""Provides extra frictionless lookup match checks for the package""" | ||
|
||
# Third-Party | ||
import frictionless | ||
import frictionless.errors | ||
import attrs | ||
|
||
# Typing | ||
from typing import Iterator, Mapping | ||
|
||
|
||
@attrs.define(kw_only=True, repr=False) | ||
class VLookupMatch(frictionless.Check): | ||
"""Takes the as a key, the value of one column to perform a VLOOKUP style check. | ||
Validation fails if the cell value for `key_field` does not match any keys of the provided | ||
map. If a null value for key is encountered then check is bypassed. | ||
Attributes: | ||
key_field: name of the column to use as the key for the lookup. | ||
value_field: name of the column to be compared against during lookup comparison. | ||
lu_map: map consisting of the valid combinations value for a given key. | ||
""" | ||
|
||
# Check Attributes | ||
type = "vlookup-match" | ||
Errors = [frictionless.errors.RowConstraintError] | ||
|
||
# Attributes specific to this check | ||
key_field: str | ||
value_field: str | ||
lu_map: Mapping | ||
|
||
def validate_row(self, row: frictionless.Row) -> Iterator[frictionless.Error]: | ||
"""Called to validate the given row (on every row). | ||
Args: | ||
row (frictionless.Row): The row to check the mutual inclusion of. | ||
Yields: | ||
frictionless.Error: For when the mutual inclusion is violated. | ||
""" | ||
# Check for null key | ||
if row[self.key_field] is None: | ||
# Bypass | ||
return | ||
|
||
# Confirm key column value exists in map | ||
if self.lu_map.get(row[self.key_field]) is not None: | ||
# Extract lookup values | ||
expected = self.lu_map[row[self.key_field]] | ||
actual = row[self.value_field] | ||
|
||
# Perform lookup check | ||
if actual == expected: | ||
# Valid | ||
return | ||
else: | ||
# Customise error note for the result | ||
note = ( | ||
f"Expected cell value `{expected}` for field `{self.value_field}` given key" | ||
f" `{row[self.key_field]}` for field `{self.key_field}; got `{actual}`" | ||
) | ||
else: | ||
# Customise note for error | ||
note = f"Index `{row[self.key_field]}` does not exist in the provided lookup map" | ||
|
||
# Yield Error | ||
yield frictionless.errors.RowConstraintError.from_row( | ||
row=row, | ||
note=note, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
"""Provides Unit Tests for the `abis_mapping.plugins.lookup_match` module""" | ||
|
||
# Third-Party | ||
import frictionless | ||
|
||
# Local | ||
from abis_mapping import plugins | ||
|
||
|
||
def test_checks_vlookup_match() -> None: | ||
"""Tests the VLookupMatch Checker""" | ||
# Construct Fake Resource | ||
resource = frictionless.Resource( | ||
source=[ | ||
# Valid | ||
{"a": "A", "b": "B", "c": "C"}, | ||
{"a": "A", "b": "B", "c": None}, | ||
{"a": "A1", "b": "B1", "c": None}, | ||
{"a": None, "b": "B", "c": "C"}, | ||
{"a": None, "b": "B", "c": None}, | ||
{"a": None, "b": None, "c": "C"}, | ||
# Invalid | ||
{"a": "A", "b": None, "c": None}, | ||
{"a": "A", "b": None, "c": "C"}, | ||
{"a": "A1", "b": "B2", "c": "C"}, | ||
{"a": "A", "b": "B1", "c": "C"}, | ||
{"a": "A2", "b": "B", "c": "C"}, | ||
], | ||
) | ||
|
||
lookup_map: dict[str, str] = {"A": "B", "A1": "B1"} | ||
|
||
# Validate | ||
report: frictionless.Report = resource.validate( | ||
checklist=frictionless.Checklist( | ||
checks=[ | ||
plugins.lookup_match.VLookupMatch( | ||
key_field="a", | ||
value_field="b", | ||
lu_map=lookup_map, | ||
), | ||
] | ||
) | ||
) | ||
|
||
# Check | ||
assert not report.valid | ||
row_numbers = report.flatten(["rowNumber"]) | ||
assert len(row_numbers) == 5 | ||
# Confirm that the rows in error are where we expect | ||
assert all([r[0] > 7 for r in row_numbers]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters