-
Notifications
You must be signed in to change notification settings - Fork 41
Rewrite unique_ids.check() and enable for v3 #220
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| import sys | ||
| import json | ||
| from typing import List, Set, Tuple | ||
| from presentation_validator.model import ErrorDetail | ||
| from presentation_validator.v3.schemavalidator import create_snippet | ||
|
|
||
| IGNORE: Set[str] = { | ||
| "target", | ||
| "lookAt", | ||
| "range", | ||
| "structures", | ||
| "first", | ||
| "last", | ||
| "start", | ||
| "source", | ||
| "body", | ||
| "scope", | ||
| "thumbnail", | ||
| } | ||
| MAX_DEPTH: int = 1000 | ||
|
|
||
|
|
||
| class MaxDepthExceeded(Exception): | ||
| pass | ||
|
|
||
|
|
||
| def check(manifest) -> List[ErrorDetail]: | ||
| """ | ||
| Checks that all values associated with the key 'id' are globally unique. | ||
|
|
||
| Args: | ||
| manifest: the root JSON dict | ||
|
|
||
| Returns: | ||
| A generator of ErrorDetail objects for each duplicate ID found. | ||
| The generator is empty if no duplicates are found. | ||
|
|
||
| Raises: | ||
| MaxDepthExceeded: If MAX_DEPTH is exceeded in the search. | ||
| """ | ||
| seen_ids = [] | ||
| # stores tuples of (search depth, path, node) | ||
| stack: List[Tuple[int, str, dict]] = [(0, "", manifest)] | ||
| while stack: | ||
| depth, path, node = stack.pop() | ||
| if depth > MAX_DEPTH: | ||
| raise MaxDepthExceeded(f"Max search depth {MAX_DEPTH} exceeded at {node}") | ||
| for key, value in filter(lambda x: x[0] not in IGNORE, node.items()): | ||
| if key == "id" or key == "@id": | ||
| if value in seen_ids: | ||
| yield ErrorDetail( | ||
| f"Duplicate id found", | ||
| "The id field must be unique", | ||
| f"Duplicate id: {value}", | ||
| path + "/" + key, | ||
| create_snippet(node), | ||
| None, | ||
| ) | ||
| seen_ids.append(value) | ||
| elif isinstance(value, list): | ||
| for i, item in enumerate(value): | ||
| # only dicts can contain IDs | ||
| if isinstance(item, dict): | ||
| stack.append((depth + 1, f"{path}/{key}[{i}]", item)) | ||
|
|
||
|
|
||
| def main(): | ||
| # pass in manifest by command line argument | ||
| # load json from file | ||
| with open(sys.argv[1], "r") as f: | ||
| manifest = json.load(f) | ||
|
|
||
| errors = check(manifest) | ||
| for err in errors: | ||
| print(err) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,6 @@ | |
| import sys | ||
| from presentation_validator.model import ValidationResult | ||
| from presentation_validator.v3.schemavalidator import convertValidationError | ||
| from presentation_validator.v4.unique_ids import check | ||
|
|
||
| from jsonschema import Draft202012Validator | ||
| from jsonschema.exceptions import relevance | ||
|
|
@@ -51,18 +50,11 @@ def validate(instance): | |
| # Now create some useful messsages to pass on | ||
| for err in errors: | ||
| result.errorList.append(convertValidationError(err, errorCount, len(errors))) | ||
|
|
||
| errorCount += 1 | ||
| else: | ||
| result.passed = True | ||
|
|
||
| duplicate_ids = check(instance) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you mean to remove the check from v4? I think it should be in both v3 and v4
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I moved the callsite to |
||
| if duplicate_ids: | ||
| result.passed = False | ||
|
|
||
| # Add all of the examples of duplicated ids | ||
| result.errorList.extend(duplicate_ids) | ||
|
|
||
| return result | ||
|
|
||
| def main(): | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add thumbnail?