|
3 | 3 | from pydantic import ValidationError |
4 | 4 | from pydantic_core import ErrorDetails |
5 | 5 |
|
6 | | -from nrlf.core.constants import ( |
7 | | - CONTENT_FORMAT_CODE_URL, |
8 | | - CONTENT_RETRIEVAL_SYSTEM_URL, |
9 | | - CONTENT_STABILITY_SYSTEM_URL, |
10 | | -) |
11 | 6 | from nrlf.core.response import Response |
12 | 7 | from nrlf.core.types import CodeableConcept |
13 | 8 | from nrlf.producer.fhir.r4 import model as producer_model |
14 | 9 | from nrlf.producer.fhir.r4.model import OperationOutcome, OperationOutcomeIssue |
15 | 10 |
|
16 | 11 |
|
17 | 12 | def format_error_location(loc: List) -> str: |
18 | | - # List of extension class names to exclude from error paths |
19 | | - exclude_classes = {"ContentStabilityExtension", "RetrievalMechanismExtension"} |
20 | | - filtered_loc = [each for each in loc if each not in exclude_classes] |
21 | | - |
22 | 13 | formatted_loc = "" |
23 | | - for each in filtered_loc: |
| 14 | + for each in loc: |
24 | 15 | if isinstance(each, int): |
25 | 16 | formatted_loc = f"{formatted_loc}[{each}]" |
26 | 17 | else: |
27 | 18 | formatted_loc = f"{formatted_loc}.{each}" if formatted_loc else str(each) |
28 | 19 | return formatted_loc |
29 | 20 |
|
30 | 21 |
|
31 | | -def append_value_set_url(loc_string: str) -> str: |
32 | | - if loc_string.endswith(("url", "system")): |
33 | | - return "" |
34 | | - |
35 | | - if "content" in loc_string: |
36 | | - if "extension" in loc_string: |
37 | | - return f". See ValueSets: {CONTENT_STABILITY_SYSTEM_URL} & {CONTENT_RETRIEVAL_SYSTEM_URL}" |
38 | | - if "format" in loc_string: |
39 | | - return f". See ValueSet: {CONTENT_FORMAT_CODE_URL}" |
40 | | - |
41 | | - return "" |
42 | | - |
43 | | - |
44 | | -def diag_for_error(error: ErrorDetails) -> str: |
| 22 | +def diag_for_error(error: ErrorDetails, value_set: str, root_location: tuple) -> str: |
45 | 23 | loc_string = format_error_location(error["loc"]) |
| 24 | + if root_location: |
| 25 | + loc_string = format_error_location(root_location) + "." + loc_string |
| 26 | + |
46 | 27 | msg = f"{loc_string or 'DocumentReference'}: {error['msg']}" |
47 | | - msg += append_value_set_url(loc_string) |
| 28 | + msg += f", see: {value_set}" if value_set else "" |
48 | 29 | return msg |
49 | 30 |
|
50 | 31 |
|
51 | | -def expression_for_error(error: ErrorDetails) -> Optional[str]: |
52 | | - return format_error_location(error["loc"]) or "DocumentReference" |
| 32 | +def expression_for_error(error: ErrorDetails, root_location: tuple) -> Optional[str]: |
| 33 | + loc_string = format_error_location(error["loc"]) or "DocumentReference" |
| 34 | + if root_location and error["loc"]: |
| 35 | + loc_string = ( |
| 36 | + format_error_location(root_location) |
| 37 | + + "." |
| 38 | + + format_error_location(error["loc"]) |
| 39 | + ) |
| 40 | + return loc_string |
53 | 41 |
|
54 | 42 |
|
55 | 43 | class OperationOutcomeError(Exception): |
@@ -99,15 +87,20 @@ def __init__(self, issues: List[OperationOutcomeIssue]): |
99 | 87 |
|
100 | 88 | @classmethod |
101 | 89 | def from_validation_error( |
102 | | - cls, exc: ValidationError, details: CodeableConcept, msg: str = "" |
| 90 | + cls, |
| 91 | + exc: ValidationError, |
| 92 | + details: CodeableConcept, |
| 93 | + msg: str = "", |
| 94 | + value_set: str = "", |
| 95 | + root_location: tuple = None, |
103 | 96 | ): |
104 | 97 | issues = [ |
105 | 98 | producer_model.OperationOutcomeIssue( |
106 | 99 | severity="error", |
107 | 100 | code="invalid", |
108 | 101 | details=details, # type: ignore |
109 | | - diagnostics=f"{msg} ({diag_for_error(error)})", |
110 | | - expression=[expression_for_error(error)], # type: ignore |
| 102 | + diagnostics=f"{msg} ({diag_for_error(error, value_set, root_location)})", |
| 103 | + expression=[expression_for_error(error, root_location)], # type: ignore |
111 | 104 | ) |
112 | 105 | for error in exc.errors() |
113 | 106 | ] |
|
0 commit comments