Skip to content

Commit 3084986

Browse files
committed
🐛 fixes business logic for xml serilizer, when summary mode is active. There was problem when summary mode is active, it worked in opposite way!
* tests coverages are added, fhir resources fixtures are updated.
1 parent 0284acd commit 3084986

File tree

13 files changed

+631
-458
lines changed

13 files changed

+631
-458
lines changed

HISTORY.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ History
44
1.1.3 (unreleased)
55
------------------
66

7-
- Nothing changed yet.
7+
- Fixes business logic for xml serializer, when summary move is active.
88

99

1010
1.1.2 (2025-07-09)

fhir_core/xml_utils.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,14 @@ def add_fhir_element(
642642
ext_field=None,
643643
summary_only=False,
644644
):
645-
""""""
645+
""" """
646+
if summary_only and not field.json_schema_extra.get( # type: ignore
647+
"summary_element_property", False
648+
):
649+
# we are not accepting the field, which is not the summary element, if summary mode is active.
650+
return
651+
if isinstance(value, dict):
652+
value = value.items()
646653
child = Node.create(field.alias)
647654
if is_primitive_type(field):
648655
if isinstance(value, list):
@@ -673,7 +680,7 @@ def add_fhir_element(
673680
)
674681
elif value is not None:
675682
child.value = xml_represent(field, value)
676-
if ext is not None:
683+
if ext is not None and not summary_only:
677684
Node.inject_comments(
678685
parent, ext.__dict__.get("fhir_comments", None)
679686
)
@@ -688,7 +695,7 @@ def add_fhir_element(
688695
parent.children.append(child)
689696
else:
690697
child.value = EMPTY_VALUE
691-
if ext is not None:
698+
if ext is not None and not summary_only:
692699
exts = not isinstance(ext, list) and [ext] or ext
693700
for ext_ in exts:
694701
if ext_ is None:
@@ -745,14 +752,16 @@ def add_fhir_element(
745752
summary_only=summary_only,
746753
)
747754
return
748-
# working comments
749-
comments = value.__dict__.get("fhir_comments", None)
750-
Node.inject_comments(parent, comments)
755+
756+
if not summary_only:
757+
# working comments on conditional
758+
comments = value.__dict__.get("fhir_comments", None)
759+
Node.inject_comments(parent, comments)
751760

752761
alias_maps = value.__class__.get_alias_mapping()
753762
summery_elements_sequence = value.__class__.summary_elements_sequence()
754763
for prop_name in value.__class__.elements_sequence():
755-
if prop_name in summery_elements_sequence and summary_only:
764+
if prop_name not in summery_elements_sequence and summary_only:
756765
# we filter non-summary field
757766
continue
758767
field_ = value.__class__.model_fields[alias_maps[prop_name]]
@@ -805,10 +814,10 @@ def from_fhir_obj(cls, model: "FHIRAbstractModel"):
805814
summery_elements_sequence = model.__class__.summary_elements_sequence()
806815
for prop_name in model.__class__.elements_sequence():
807816
if (
808-
prop_name in summery_elements_sequence
817+
prop_name not in summery_elements_sequence
809818
and model.__fhir_serialization_summary_only__
810819
):
811-
# we filter non-summary element
820+
# we filter a non-summary element
812821
continue
813822
field = model.__class__.model_fields[alias_maps[prop_name]]
814823
if typing.TYPE_CHECKING:

tests/fixtures/resources/address.py

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class Address(datatype.DataType):
3333
__resource_type__ = "Address"
3434

3535
city: fhirtypes.StringType | None = Field( # type: ignore
36-
None,
36+
default=None,
3737
alias="city",
3838
title="Name of city, town etc.",
3939
description=(
@@ -42,40 +42,43 @@ class Address(datatype.DataType):
4242
),
4343
json_schema_extra={
4444
"element_property": True,
45+
"summary_element_property": True,
4546
},
4647
)
4748
city__ext: fhirtypes.FHIRPrimitiveExtensionType | None = Field( # type: ignore
48-
None, alias="_city", title="Extension field for ``city``."
49+
default=None, alias="_city", title="Extension field for ``city``."
4950
)
5051

5152
country: fhirtypes.StringType | None = Field( # type: ignore
52-
None,
53+
default=None,
5354
alias="country",
5455
title="Country (e.g. may be ISO 3166 2 or 3 letter code)",
5556
description="Country - a nation as commonly understood or generally accepted.",
5657
json_schema_extra={
5758
"element_property": True,
59+
"summary_element_property": True,
5860
},
5961
)
6062
country__ext: fhirtypes.FHIRPrimitiveExtensionType | None = Field( # type: ignore
61-
None, alias="_country", title="Extension field for ``country``."
63+
default=None, alias="_country", title="Extension field for ``country``."
6264
)
6365

6466
district: fhirtypes.StringType | None = Field( # type: ignore
65-
None,
67+
default=None,
6668
alias="district",
6769
title="District name (aka county)",
6870
description="The name of the administrative area (county).",
6971
json_schema_extra={
7072
"element_property": True,
73+
"summary_element_property": True,
7174
},
7275
)
7376
district__ext: fhirtypes.FHIRPrimitiveExtensionType | None = Field( # type: ignore
74-
None, alias="_district", title="Extension field for ``district``."
77+
default=None, alias="_district", title="Extension field for ``district``."
7578
)
7679

7780
line: typing.List[fhirtypes.StringType | None] | None = Field( # type: ignore
78-
None,
81+
default=None,
7982
alias="line",
8083
title="Street name, number, direction & P.O. Box etc.",
8184
description=(
@@ -85,37 +88,40 @@ class Address(datatype.DataType):
8588
),
8689
json_schema_extra={
8790
"element_property": True,
91+
"summary_element_property": True,
8892
},
8993
)
9094
line__ext: typing.List[fhirtypes.FHIRPrimitiveExtensionType | None] | None = Field( # type: ignore
91-
None, alias="_line", title="Extension field for ``line``."
95+
default=None, alias="_line", title="Extension field for ``line``."
9296
)
9397

9498
period: fhirtypes.PeriodType | None = Field( # type: ignore
95-
None,
99+
default=None,
96100
alias="period",
97101
title="Time period when address was/is in use",
98102
description=None,
99103
json_schema_extra={
100104
"element_property": True,
105+
"summary_element_property": True,
101106
},
102107
)
103108

104109
postalCode: fhirtypes.StringType | None = Field( # type: ignore
105-
None,
110+
default=None,
106111
alias="postalCode",
107112
title="Postal code for area",
108113
description="A postal code designating a region defined by the postal service.",
109114
json_schema_extra={
110115
"element_property": True,
116+
"summary_element_property": True,
111117
},
112118
)
113119
postalCode__ext: fhirtypes.FHIRPrimitiveExtensionType | None = Field( # type: ignore
114-
None, alias="_postalCode", title="Extension field for ``postalCode``."
120+
default=None, alias="_postalCode", title="Extension field for ``postalCode``."
115121
)
116122

117123
state: fhirtypes.StringType | None = Field( # type: ignore
118-
None,
124+
default=None,
119125
alias="state",
120126
title="Sub-unit of country (abbreviations ok)",
121127
description=(
@@ -125,14 +131,15 @@ class Address(datatype.DataType):
125131
),
126132
json_schema_extra={
127133
"element_property": True,
134+
"summary_element_property": True,
128135
},
129136
)
130137
state__ext: fhirtypes.FHIRPrimitiveExtensionType | None = Field( # type: ignore
131-
None, alias="_state", title="Extension field for ``state``."
138+
default=None, alias="_state", title="Extension field for ``state``."
132139
)
133140

134141
text: fhirtypes.StringType | None = Field( # type: ignore
135-
None,
142+
default=None,
136143
alias="text",
137144
title="Text representation of the address",
138145
description=(
@@ -142,14 +149,15 @@ class Address(datatype.DataType):
142149
),
143150
json_schema_extra={
144151
"element_property": True,
152+
"summary_element_property": True,
145153
},
146154
)
147155
text__ext: fhirtypes.FHIRPrimitiveExtensionType | None = Field( # type: ignore
148-
None, alias="_text", title="Extension field for ``text``."
156+
default=None, alias="_text", title="Extension field for ``text``."
149157
)
150158

151159
type: fhirtypes.CodeType | None = Field( # type: ignore
152-
None,
160+
default=None,
153161
alias="type",
154162
title="postal | physical | both",
155163
description=(
@@ -159,36 +167,38 @@ class Address(datatype.DataType):
159167
),
160168
json_schema_extra={
161169
"element_property": True,
170+
"summary_element_property": True,
162171
# note: Enum values can be used in validation,
163172
# but use in your own responsibilities, read official FHIR documentation.
164173
"enum_values": ["postal", "physical", "both"],
165174
},
166175
)
167176
type__ext: fhirtypes.FHIRPrimitiveExtensionType | None = Field( # type: ignore
168-
None, alias="_type", title="Extension field for ``type``."
177+
default=None, alias="_type", title="Extension field for ``type``."
169178
)
170179

171180
use: fhirtypes.CodeType | None = Field( # type: ignore
172-
None,
181+
default=None,
173182
alias="use",
174183
title="home | work | temp | old | billing - purpose of this address",
175184
description="The purpose of this address.",
176185
json_schema_extra={
177186
"element_property": True,
187+
"summary_element_property": True,
178188
# note: Enum values can be used in validation,
179189
# but use in your own responsibilities, read official FHIR documentation.
180190
"enum_values": ["home", "work", "temp", "old", "billing"],
181191
},
182192
)
183193
use__ext: fhirtypes.FHIRPrimitiveExtensionType | None = Field( # type: ignore
184-
None, alias="_use", title="Extension field for ``use``."
194+
default=None, alias="_use", title="Extension field for ``use``."
185195
)
186196

187197
@classmethod
188198
def elements_sequence(cls):
189-
"""returning all elements names from
190-
``Address`` according specification,
191-
with preserving original sequence order.
199+
"""returning all element names from
200+
``Address`` according to specification,
201+
with preserving the original sequence order.
192202
"""
193203
return [
194204
"id",
@@ -204,3 +214,21 @@ def elements_sequence(cls):
204214
"country",
205215
"period",
206216
]
217+
218+
@classmethod
219+
def summary_elements_sequence(cls):
220+
"""returning all element names (those have summary mode are enabled) from ``Address`` according to specification,
221+
with preserving the original sequence order.
222+
"""
223+
return [
224+
"use",
225+
"type",
226+
"text",
227+
"line",
228+
"city",
229+
"district",
230+
"state",
231+
"postalCode",
232+
"country",
233+
"period",
234+
]

tests/fixtures/resources/age.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
# -*- coding: utf-8 -*-
1+
from __future__ import annotations as _annotations
2+
23
"""
34
Profile: http://hl7.org/fhir/StructureDefinition/Age
45
Release: R5
56
Version: 5.0.0
67
Build ID: 2aecd53
78
Last updated: 2023-03-26T15:21:02.749+11:00
89
"""
9-
from pydantic import Field
10-
1110
from . import quantity
1211

1312

@@ -23,8 +22,15 @@ class Age(quantity.Quantity):
2322

2423
@classmethod
2524
def elements_sequence(cls):
26-
"""returning all elements names from
27-
``Age`` according specification,
28-
with preserving original sequence order.
25+
"""returning all element names from
26+
``Age`` according to specification,
27+
with preserving the original sequence order.
2928
"""
3029
return ["id", "extension", "value", "comparator", "unit", "system", "code"]
30+
31+
@classmethod
32+
def summary_elements_sequence(cls):
33+
"""returning all element names (those have summary mode are enabled) from ``Age`` according to specification,
34+
with preserving the original sequence order.
35+
"""
36+
return ["value", "comparator", "unit", "system", "code"]

tests/fixtures/resources/codeableconcept.py

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# -*- coding: utf-8 -*-
1+
from __future__ import annotations as _annotations
2+
23
"""
34
Profile: http://hl7.org/fhir/StructureDefinition/CodeableConcept
45
Release: R5
@@ -25,43 +26,46 @@ class CodeableConcept(datatype.DataType):
2526

2627
__resource_type__ = "CodeableConcept"
2728

28-
coding: typing.List[fhirtypes.CodingType] = Field(
29-
None,
29+
coding: typing.List[fhirtypes.CodingType] | None = Field( # type: ignore
30+
default=None,
3031
alias="coding",
3132
title="Code defined by a terminology system",
3233
description="A reference to a code defined by a terminology system.",
33-
# if property is element of this resource.
34-
json_schema_extra={"element_property": True},
34+
json_schema_extra={
35+
"element_property": True,
36+
"summary_element_property": True,
37+
},
3538
)
3639

37-
text: fhirtypes.StringType = Field(
38-
None,
40+
text: fhirtypes.StringType | None = Field( # type: ignore
41+
default=None,
3942
alias="text",
4043
title="Plain text representation of the concept",
4144
description=(
4245
"A human language representation of the concept as "
4346
"seen/selected/uttered by the user who entered the data and/or which "
4447
"represents the intended meaning of the user."
4548
),
46-
# if property is element of this resource.
47-
json_schema_extra={"element_property": True},
49+
json_schema_extra={
50+
"element_property": True,
51+
"summary_element_property": True,
52+
},
4853
)
49-
text__ext: fhirtypes.FHIRPrimitiveExtensionType = Field(
50-
None, alias="_text", title="Extension field for ``text``."
54+
text__ext: fhirtypes.FHIRPrimitiveExtensionType | None = Field( # type: ignore
55+
default=None, alias="_text", title="Extension field for ``text``."
5156
)
5257

5358
@classmethod
5459
def elements_sequence(cls):
55-
"""returning all elements names from
56-
``CodeableConcept`` according specification,
57-
with preserving original sequence order.
60+
"""returning all element names from
61+
``CodeableConcept`` according to specification,
62+
with preserving the original sequence order.
5863
"""
5964
return ["id", "extension", "coding", "text"]
6065

6166
@classmethod
6267
def summary_elements_sequence(cls):
63-
"""returning all elements names from
64-
``CodeableConcept`` according specification,
65-
with preserving original sequence order.
68+
"""returning all element names (those have summary mode are enabled) from ``CodeableConcept`` according to specification,
69+
with preserving the original sequence order.
6670
"""
6771
return ["coding", "text"]

0 commit comments

Comments
 (0)