Skip to content

Commit d0de21b

Browse files
committed
NRL-1165 reject whitespace-only strings in model, update tests for pydantic validation of codeable concept fields
1 parent ac08c83 commit d0de21b

File tree

12 files changed

+625
-291
lines changed

12 files changed

+625
-291
lines changed

api/producer/createDocumentReference/tests/test_create_document_reference.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,36 @@ def test_create_document_reference_invalid_body():
239239
"diagnostics": "Request body could not be parsed (status: Field required)",
240240
"expression": ["status"],
241241
},
242+
{
243+
"severity": "error",
244+
"code": "invalid",
245+
"details": {
246+
"coding": [
247+
{
248+
"code": "MESSAGE_NOT_WELL_FORMED",
249+
"display": "Message not well formed",
250+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
251+
}
252+
],
253+
},
254+
"diagnostics": "Request body could not be parsed (type: Field required)",
255+
"expression": ["type"],
256+
},
257+
{
258+
"severity": "error",
259+
"code": "invalid",
260+
"details": {
261+
"coding": [
262+
{
263+
"code": "MESSAGE_NOT_WELL_FORMED",
264+
"display": "Message not well formed",
265+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
266+
}
267+
],
268+
},
269+
"diagnostics": "Request body could not be parsed (category: Field required)",
270+
"expression": ["category"],
271+
},
242272
{
243273
"severity": "error",
244274
"code": "invalid",

api/producer/swagger.yaml

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,7 +1386,7 @@ components:
13861386
description: Relationships that this document has with other document references that already exist.
13871387
description:
13881388
type: string
1389-
pattern: "[ \\r\\n\\t\\S]+"
1389+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
13901390
description: Human–readable description of the source document.
13911391
securityLabel:
13921392
type: array
@@ -1408,6 +1408,8 @@ components:
14081408
- content
14091409
- author
14101410
- context
1411+
- type
1412+
- category
14111413
Bundle:
14121414
type: object
14131415
properties:
@@ -1693,7 +1695,7 @@ components:
16931695
description: The calculated hash of the data using SHA–1. Represented using base64.
16941696
title:
16951697
type: string
1696-
pattern: "[ \\r\\n\\t\\S]+"
1698+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
16971699
description: A label or set of text to display in place of the data.
16981700
creation:
16991701
type: string
@@ -1716,7 +1718,7 @@ components:
17161718
description: A reference to a code defined by a terminology system.
17171719
text:
17181720
type: string
1719-
pattern: "[ \\r\\n\\t\\S]+"
1721+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
17201722
description: A human language representation of the concept as seen/selected/uttered by the user who entered the data and/or which represents the intended meaning of the user.
17211723
NRLCodeableConcept:
17221724
type: object
@@ -1734,7 +1736,7 @@ components:
17341736
maxItems: 1
17351737
text:
17361738
type: string
1737-
pattern: "[ \\r\\n\\t\\S]+"
1739+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
17381740
description: A human language representation of the concept as seen/selected/uttered by the user who entered the data and/or which represents the intended meaning of the user.
17391741
required:
17401742
- coding
@@ -1752,15 +1754,15 @@ components:
17521754
description: The identification of the code system that defines the meaning of the symbol in the code.
17531755
version:
17541756
type: string
1755-
pattern: "[ \\r\\n\\t\\S]+"
1757+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
17561758
description: The version of the code system which was used when choosing this code. Note that a well–maintained code system does not need the version reported, because the meaning of codes is consistent across versions. However this cannot consistently be assured, and when the meaning is not guaranteed to be consistent, the version SHOULD be exchanged.
17571759
code:
17581760
type: string
17591761
pattern: "[^\\s]+(\\s[^\\s]+)*"
17601762
description: A symbol in syntax defined by the system. The symbol may be a predefined code or an expression in a syntax defined by the coding system (e.g. post–coordination).
17611763
display:
17621764
type: string
1763-
pattern: "[ \\r\\n\\t\\S]+"
1765+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
17641766
description: A representation of the meaning of the code in the system, following the rules of the system.
17651767
userSelected:
17661768
type: boolean
@@ -1778,15 +1780,15 @@ components:
17781780
description: The identification of the code system that defines the meaning of the symbol in the code.
17791781
version:
17801782
type: string
1781-
pattern: "[ \\r\\n\\t\\S]+"
1783+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
17821784
description: The version of the code system which was used when choosing this code. Note that a well–maintained code system does not need the version reported, because the meaning of codes is consistent across versions. However this cannot consistently be assured, and when the meaning is not guaranteed to be consistent, the version SHOULD be exchanged.
17831785
code:
17841786
type: string
17851787
pattern: "[^\\s]+(\\s[^\\s]+)*"
17861788
description: A symbol in syntax defined by the system. The symbol may be a predefined code or an expression in a syntax defined by the coding system (e.g. post–coordination).
17871789
display:
17881790
type: string
1789-
pattern: "[ \\r\\n\\t\\S]+"
1791+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
17901792
description: A representation of the meaning of the code in the system, following the rules of the system.
17911793
userSelected:
17921794
type: boolean
@@ -1893,11 +1895,11 @@ components:
18931895
description: A coded type for the identifier that can be used to determine which identifier to use for a specific purpose.
18941896
system:
18951897
type: string
1896-
pattern: \S*
1898+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
18971899
description: Establishes the namespace for the value – that is, a URL that describes a set values that are unique.
18981900
value:
18991901
type: string
1900-
pattern: "[ \\r\\n\\t\\S]+"
1902+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
19011903
description: The portion of the identifier typically relevant to the user and which is unique within the context of the system.
19021904
period:
19031905
$ref: "#/components/schemas/Period"
@@ -1936,11 +1938,11 @@ components:
19361938
description: How the value should be understood and represented &ndash; whether the actual value is greater or less than the stated value due to measurement issues; e.g. if the comparator is "<" , then the real value is < stated value.
19371939
unit:
19381940
type: string
1939-
pattern: "[ \\r\\n\\t\\S]+"
1941+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
19401942
description: A human&ndash;readable form of the unit.
19411943
system:
19421944
type: string
1943-
pattern: \S*
1945+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
19441946
description: The identification of the system that provides the coded form of the unit.
19451947
code:
19461948
type: string
@@ -1955,11 +1957,11 @@ components:
19551957
description: Unique id for the element within a resource (for internal references). This may be any string value that does not contain spaces.
19561958
reference:
19571959
type: string
1958-
pattern: "[ \\r\\n\\t\\S]+"
1960+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
19591961
description: A reference to a location at which the other resource is found. The reference may be a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources.
19601962
type:
19611963
type: string
1962-
pattern: \S*
1964+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
19631965
description: |-
19641966
The expected type of the target of the reference. If both Reference.type and Reference.reference are populated and Reference.reference is a FHIR URL, both SHALL be consistent.
19651967
The type is the Canonical URL of Resource Definition that is the type this reference refers to. References are URLs that are relative to http://hl7.org/fhir/StructureDefinition/ e.g. "Patient" is a reference to http://hl7.org/fhir/StructureDefinition/Patient. Absolute URLs are only allowed for logical models (and can only be used in references in logical models, not resources).
@@ -1968,7 +1970,7 @@ components:
19681970
description: An identifier for the target resource. This is used when there is no way to reference the other resource directly, either because the entity it represents is not available through a FHIR server, or because there is no way for the author of the resource to convert a known identifier to an actual location. There is no requirement that a Reference.identifier point to something that is actually exposed as a FHIR instance, but it SHALL point to a business concept that would be expected to be exposed as a FHIR instance, and that instance would need to be of a FHIR resource type allowed by the reference.
19691971
display:
19701972
type: string
1971-
pattern: "[ \\r\\n\\t\\S]+"
1973+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
19721974
description: Plain text narrative that identifies the resource in addition to the resource reference.
19731975
Signature:
19741976
type: object
@@ -2026,13 +2028,13 @@ components:
20262028
description: When the resource last changed &ndash; e.g. when the version changed.
20272029
source:
20282030
type: string
2029-
pattern: \S*
2031+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
20302032
description: A uri that identifies the source system of the resource. This provides a minimal amount of [Provenance](provenance.html#) information that can be used to track or differentiate the source of information in the resource. The source may identify another FHIR server, document, message, database, etc.
20312033
profile:
20322034
type: array
20332035
items:
20342036
type: string
2035-
pattern: \S*
2037+
pattern: "[\\S]+[ \\r\\n\\t\\S]*"
20362038
description: A list of profiles (references to [StructureDefinition](structuredefinition.html#) resources) that this resource claims to conform to. The URL is a reference to [StructureDefinition.url](structuredefinition&ndash;definitions.html#StructureDefinition.url).
20372039
security:
20382040
type: array

api/producer/updateDocumentReference/tests/test_update_document_reference.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ def test_create_document_reference_no_body():
195195
}
196196

197197

198-
def test_create_document_reference_invalid_body():
198+
def test_update_document_reference_invalid_body():
199199
event = create_test_api_gateway_event(
200200
headers=create_headers(),
201201
path_parameters={"id": "Y05868-99999-99999-999999"},
@@ -246,6 +246,36 @@ def test_create_document_reference_invalid_body():
246246
"diagnostics": "Request body could not be parsed (status: Field required)",
247247
"expression": ["status"],
248248
},
249+
{
250+
"severity": "error",
251+
"code": "invalid",
252+
"details": {
253+
"coding": [
254+
{
255+
"code": "MESSAGE_NOT_WELL_FORMED",
256+
"display": "Message not well formed",
257+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
258+
}
259+
],
260+
},
261+
"diagnostics": "Request body could not be parsed (type: Field required)",
262+
"expression": ["type"],
263+
},
264+
{
265+
"severity": "error",
266+
"code": "invalid",
267+
"details": {
268+
"coding": [
269+
{
270+
"code": "MESSAGE_NOT_WELL_FORMED",
271+
"display": "Message not well formed",
272+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
273+
}
274+
],
275+
},
276+
"diagnostics": "Request body could not be parsed (category: Field required)",
277+
"expression": ["category"],
278+
},
249279
{
250280
"severity": "error",
251281
"code": "invalid",

api/producer/upsertDocumentReference/tests/test_upsert_document_reference.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,36 @@ def test_upsert_document_reference_invalid_body():
324324
"diagnostics": "Request body could not be parsed (status: Field required)",
325325
"expression": ["status"],
326326
},
327+
{
328+
"severity": "error",
329+
"code": "invalid",
330+
"details": {
331+
"coding": [
332+
{
333+
"code": "MESSAGE_NOT_WELL_FORMED",
334+
"display": "Message not well formed",
335+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
336+
}
337+
],
338+
},
339+
"diagnostics": "Request body could not be parsed (type: Field required)",
340+
"expression": ["type"],
341+
},
342+
{
343+
"severity": "error",
344+
"code": "invalid",
345+
"details": {
346+
"coding": [
347+
{
348+
"code": "MESSAGE_NOT_WELL_FORMED",
349+
"display": "Message not well formed",
350+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
351+
}
352+
],
353+
},
354+
"diagnostics": "Request body could not be parsed (category: Field required)",
355+
"expression": ["category"],
356+
},
327357
{
328358
"severity": "error",
329359
"code": "invalid",

layer/nrlf/consumer/fhir/r4/model.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# generated by datamodel-codegen:
22
# filename: swagger.yaml
3-
# timestamp: 2024-12-13T11:19:30+00:00
3+
# timestamp: 2025-01-27T09:26:33+00:00
44

55
from __future__ import annotations
66

layer/nrlf/core/dynamodb/tests/test_model.py

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
from nrlf.core.constants import PointerTypes
77
from nrlf.core.dynamodb.model import DocumentPointer, DynamoDBModel
88
from nrlf.core.utils import create_fhir_instant
9-
from nrlf.producer.fhir.r4.model import DocumentReference
10-
from nrlf.tests.data import load_document_reference, load_document_reference_json
9+
from nrlf.tests.data import load_document_reference
1110

1211

1312
def test_dynamodb_model_init():
@@ -159,28 +158,6 @@ def test_document_pointer_from_document_reference_invalid():
159158
assert str(error.value) == "'NoneType' object has no attribute 'coding'"
160159

161160

162-
def test_document_pointer_from_document_reference_multiple_types():
163-
doc_ref_data = load_document_reference_json("Y05868-736253002-Valid")
164-
doc_ref = DocumentReference.model_validate(
165-
{
166-
**doc_ref_data,
167-
"type": {
168-
"coding": [
169-
{"system": "http://snomed.info/sct", "code": "123456789"},
170-
{"system": "http://snomed.info/sct", "code": "987654321"},
171-
]
172-
},
173-
}
174-
)
175-
176-
with pytest.raises(ValueError) as error:
177-
DocumentPointer.from_document_reference(doc_ref)
178-
179-
assert (
180-
str(error.value) == "DocumentReference.type.coding must have exactly one item"
181-
)
182-
183-
184161
def test_document_pointer_extract_custodian_suffix_no_suffix():
185162
values = {"custodian": "X26", "custodian_suffix": None}
186163

0 commit comments

Comments
 (0)