Skip to content

Commit 248b25c

Browse files
Merge pull request #643 from NHSDigital/feature/eema1-NRL-746-addContentExtensionToModel
NRL-746 add extension to model
2 parents 7f36bd5 + 3afd966 commit 248b25c

File tree

6 files changed

+453
-46
lines changed

6 files changed

+453
-46
lines changed

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

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -424,42 +424,60 @@ class RequestHeaderCorrelationId(BaseModel):
424424
__root__: Annotated[str, Field(example="11C46F5F-CDEF-4865-94B2-0EE0EDCC26DA")]
425425

426426

427-
class DocumentReferenceContent(BaseModel):
427+
class CodeableConcept(BaseModel):
428428
id: Annotated[
429429
str | None,
430430
Field(
431431
description="Unique id for the element within a resource (for internal references). This may be any string value that does not contain spaces.",
432432
regex="[A-Za-z0-9\\-\\.]{1,64}",
433433
),
434434
] = None
435-
attachment: Annotated[
436-
Attachment,
435+
coding: list[Coding] | None = None
436+
text: Annotated[
437+
str | None,
437438
Field(
438-
description="The document or URL of the document along with critical metadata to prove content has integrity."
439+
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.",
440+
regex="[ \\r\\n\\t\\S]+",
439441
),
440-
]
441-
format: Annotated[
442-
Coding | None,
442+
] = None
443+
444+
445+
class Extension(BaseModel):
446+
valueCodeableConcept: Annotated[
447+
CodeableConcept,
443448
Field(
444-
description="An identifier of the document encoding, structure, and template that the document conforms to beyond the base format indicated in the mimeType."
449+
description="Details about the extension.",
445450
),
446-
] = None
451+
]
452+
url: Annotated[
453+
str, Field(description="The reference link for the details.", regex="\\S*")
454+
]
447455

448456

449-
class CodeableConcept(BaseModel):
457+
class DocumentReferenceContent(BaseModel):
450458
id: Annotated[
451459
str | None,
452460
Field(
453461
description="Unique id for the element within a resource (for internal references). This may be any string value that does not contain spaces.",
454462
regex="[A-Za-z0-9\\-\\.]{1,64}",
455463
),
456464
] = None
457-
coding: list[Coding] | None = None
458-
text: Annotated[
459-
str | None,
465+
attachment: Annotated[
466+
Attachment,
460467
Field(
461-
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.",
462-
regex="[ \\r\\n\\t\\S]+",
468+
description="The document or URL of the document along with critical metadata to prove content has integrity."
469+
),
470+
]
471+
format: Annotated[
472+
Coding | None,
473+
Field(
474+
description="An identifier of the document encoding, structure, and template that the document conforms to beyond the base format indicated in the mimeType."
475+
),
476+
] = None
477+
extension: Annotated[
478+
list[Extension] | None,
479+
Field(
480+
description="Additional code system information for the document content."
463481
),
464482
] = None
465483

layer/nrlf/core/tests/test_validators.py

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,236 @@ def test_validate_category_coding_invalid_system():
599599
}
600600

601601

602+
def test_validate_content_extension_too_many_extensions():
603+
validator = DocumentReferenceValidator()
604+
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")
605+
606+
document_ref_data["content"][0]["extension"].append(
607+
{
608+
"url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-ContentStability",
609+
"valueCodeableConcept": {
610+
"coding": [
611+
{
612+
"system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLContentStability",
613+
"code": "static",
614+
"display": "static",
615+
}
616+
]
617+
},
618+
}
619+
)
620+
621+
result = validator.validate(document_ref_data)
622+
623+
assert result.is_valid is False
624+
assert result.resource.id == "Y05868-99999-99999-999999"
625+
assert len(result.issues) == 1
626+
assert result.issues[0].dict(exclude_none=True) == {
627+
"severity": "error",
628+
"code": "invalid",
629+
"details": {
630+
"coding": [
631+
{
632+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
633+
"code": "INVALID_RESOURCE",
634+
"display": "Invalid validation of resource",
635+
}
636+
]
637+
},
638+
"diagnostics": "Invalid content extension length: 2 Extension must only contain a single value",
639+
"expression": ["content[0].extension"],
640+
}
641+
642+
643+
def test_validate_content_extension_invalid_code():
644+
validator = DocumentReferenceValidator()
645+
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")
646+
647+
document_ref_data["content"][0]["extension"][0] = {
648+
"url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-ContentStability",
649+
"valueCodeableConcept": {
650+
"coding": [
651+
{
652+
"system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLContentStability",
653+
"code": "invalid",
654+
"display": "invalid",
655+
}
656+
]
657+
},
658+
}
659+
660+
result = validator.validate(document_ref_data)
661+
662+
assert result.is_valid is False
663+
assert result.resource.id == "Y05868-99999-99999-999999"
664+
assert len(result.issues) == 1
665+
assert result.issues[0].dict(exclude_none=True) == {
666+
"severity": "error",
667+
"code": "value",
668+
"details": {
669+
"coding": [
670+
{
671+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
672+
"code": "INVALID_RESOURCE",
673+
"display": "Invalid validation of resource",
674+
}
675+
]
676+
},
677+
"diagnostics": "Invalid content extension code: invalid Extension code must be 'static' or 'dynamic'",
678+
"expression": ["content[0].extension[0].valueCodeableConcept.coding[0].code"],
679+
}
680+
681+
682+
def test_validate_content_extension_invalid_display():
683+
validator = DocumentReferenceValidator()
684+
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")
685+
686+
document_ref_data["content"][0]["extension"][0] = {
687+
"url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-ContentStability",
688+
"valueCodeableConcept": {
689+
"coding": [
690+
{
691+
"system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLContentStability",
692+
"code": "static",
693+
"display": "invalid",
694+
}
695+
]
696+
},
697+
}
698+
699+
result = validator.validate(document_ref_data)
700+
701+
assert result.is_valid is False
702+
assert result.resource.id == "Y05868-99999-99999-999999"
703+
assert len(result.issues) == 1
704+
assert result.issues[0].dict(exclude_none=True) == {
705+
"severity": "error",
706+
"code": "value",
707+
"details": {
708+
"coding": [
709+
{
710+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
711+
"code": "INVALID_RESOURCE",
712+
"display": "Invalid validation of resource",
713+
}
714+
]
715+
},
716+
"diagnostics": "Invalid content extension display: invalid Extension display must be the same as code either 'static' or 'dynamic'",
717+
"expression": [
718+
"content[0].extension[0].valueCodeableConcept.coding[0].display"
719+
],
720+
}
721+
722+
723+
def test_validate_content_extension_invalid_system():
724+
validator = DocumentReferenceValidator()
725+
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")
726+
727+
document_ref_data["content"][0]["extension"][0] = {
728+
"url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-ContentStability",
729+
"valueCodeableConcept": {
730+
"coding": [
731+
{
732+
"system": "invalid",
733+
"code": "static",
734+
"display": "static",
735+
}
736+
]
737+
},
738+
}
739+
740+
result = validator.validate(document_ref_data)
741+
742+
assert result.is_valid is False
743+
assert result.resource.id == "Y05868-99999-99999-999999"
744+
assert len(result.issues) == 1
745+
assert result.issues[0].dict(exclude_none=True) == {
746+
"severity": "error",
747+
"code": "value",
748+
"details": {
749+
"coding": [
750+
{
751+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
752+
"code": "INVALID_RESOURCE",
753+
"display": "Invalid validation of resource",
754+
}
755+
]
756+
},
757+
"diagnostics": "Invalid content extension system: invalid Extension system must be 'https://fhir.nhs.uk/England/CodeSystem/England-NRLContentStability'",
758+
"expression": ["content[0].extension[0].valueCodeableConcept.coding[0].system"],
759+
}
760+
761+
762+
def test_validate_content_extension_invalid_url():
763+
validator = DocumentReferenceValidator()
764+
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")
765+
766+
document_ref_data["content"][0]["extension"][0] = {
767+
"url": "invalid",
768+
"valueCodeableConcept": {
769+
"coding": [
770+
{
771+
"system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLContentStability",
772+
"code": "static",
773+
"display": "static",
774+
}
775+
]
776+
},
777+
}
778+
779+
result = validator.validate(document_ref_data)
780+
781+
assert result.is_valid is False
782+
assert result.resource.id == "Y05868-99999-99999-999999"
783+
assert len(result.issues) == 1
784+
assert result.issues[0].dict(exclude_none=True) == {
785+
"severity": "error",
786+
"code": "value",
787+
"details": {
788+
"coding": [
789+
{
790+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
791+
"code": "INVALID_RESOURCE",
792+
"display": "Invalid validation of resource",
793+
}
794+
]
795+
},
796+
"diagnostics": "Invalid content extension url: invalid Extension url must be 'https://fhir.nhs.uk/England/StructureDefinition/Extension-England-ContentStability'",
797+
"expression": ["content[0].extension[0].url"],
798+
}
799+
800+
801+
def test_validate_content_extension_missing_coding():
802+
validator = DocumentReferenceValidator()
803+
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")
804+
805+
document_ref_data["content"][0]["extension"][0] = {
806+
"url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-ContentStability",
807+
"valueCodeableConcept": {"coding": []},
808+
}
809+
810+
result = validator.validate(document_ref_data)
811+
812+
assert result.is_valid is False
813+
assert result.resource.id == "Y05868-99999-99999-999999"
814+
assert len(result.issues) == 1
815+
assert result.issues[0].dict(exclude_none=True) == {
816+
"severity": "error",
817+
"code": "required",
818+
"details": {
819+
"coding": [
820+
{
821+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
822+
"code": "INVALID_RESOURCE",
823+
"display": "Invalid validation of resource",
824+
}
825+
]
826+
},
827+
"diagnostics": "Missing content[0].extension[0].valueCodeableConcept.coding, extension must have at least one coding.",
828+
"expression": ["content[0].extension.valueCodeableConcept.coding"],
829+
}
830+
831+
602832
def test_validate_identifiers_invalid_systems():
603833
validator = DocumentReferenceValidator()
604834
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")

0 commit comments

Comments
 (0)