pysdmx 1.5.2__py3-none-any.whl → 1.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pysdmx/__init__.py +1 -1
- pysdmx/api/fmr/__init__.py +8 -3
- pysdmx/api/fmr/maintenance.py +158 -0
- pysdmx/api/qb/structure.py +1 -0
- pysdmx/api/qb/util.py +1 -0
- pysdmx/io/csv/__csv_aux_reader.py +99 -0
- pysdmx/io/csv/__csv_aux_writer.py +118 -0
- pysdmx/io/csv/sdmx10/reader/__init__.py +9 -14
- pysdmx/io/csv/sdmx10/writer/__init__.py +28 -2
- pysdmx/io/csv/sdmx20/__init__.py +0 -9
- pysdmx/io/csv/sdmx20/reader/__init__.py +8 -61
- pysdmx/io/csv/sdmx20/writer/__init__.py +32 -25
- pysdmx/io/csv/sdmx21/__init__.py +1 -0
- pysdmx/io/csv/sdmx21/reader/__init__.py +86 -0
- pysdmx/io/csv/sdmx21/writer/__init__.py +70 -0
- pysdmx/io/format.py +8 -0
- pysdmx/io/input_processor.py +20 -6
- pysdmx/io/json/fusion/messages/code.py +21 -4
- pysdmx/io/json/fusion/messages/concept.py +10 -8
- pysdmx/io/json/fusion/messages/dataflow.py +8 -1
- pysdmx/io/json/fusion/messages/dsd.py +15 -0
- pysdmx/io/json/fusion/messages/schema.py +8 -1
- pysdmx/io/json/sdmxjson2/messages/agency.py +43 -7
- pysdmx/io/json/sdmxjson2/messages/category.py +92 -7
- pysdmx/io/json/sdmxjson2/messages/code.py +265 -22
- pysdmx/io/json/sdmxjson2/messages/concept.py +75 -13
- pysdmx/io/json/sdmxjson2/messages/constraint.py +5 -5
- pysdmx/io/json/sdmxjson2/messages/core.py +121 -14
- pysdmx/io/json/sdmxjson2/messages/dataflow.py +63 -8
- pysdmx/io/json/sdmxjson2/messages/dsd.py +215 -20
- pysdmx/io/json/sdmxjson2/messages/map.py +200 -24
- pysdmx/io/json/sdmxjson2/messages/pa.py +36 -5
- pysdmx/io/json/sdmxjson2/messages/provider.py +35 -7
- pysdmx/io/json/sdmxjson2/messages/report.py +85 -7
- pysdmx/io/json/sdmxjson2/messages/schema.py +11 -12
- pysdmx/io/json/sdmxjson2/messages/structure.py +150 -2
- pysdmx/io/json/sdmxjson2/messages/vtl.py +547 -17
- pysdmx/io/json/sdmxjson2/reader/metadata.py +32 -0
- pysdmx/io/json/sdmxjson2/reader/structure.py +32 -0
- pysdmx/io/json/sdmxjson2/writer/__init__.py +9 -0
- pysdmx/io/json/sdmxjson2/writer/metadata.py +60 -0
- pysdmx/io/json/sdmxjson2/writer/structure.py +61 -0
- pysdmx/io/reader.py +28 -9
- pysdmx/io/serde.py +17 -0
- pysdmx/io/writer.py +45 -9
- pysdmx/io/xml/__ss_aux_reader.py +1 -2
- pysdmx/io/xml/__structure_aux_reader.py +15 -10
- pysdmx/io/xml/__structure_aux_writer.py +15 -13
- pysdmx/io/xml/__write_data_aux.py +6 -57
- pysdmx/io/xml/__write_structure_specific_aux.py +7 -3
- pysdmx/io/xml/doc_validation.py +1 -3
- pysdmx/io/xml/sdmx21/writer/generic.py +6 -4
- pysdmx/model/__init__.py +1 -3
- pysdmx/model/code.py +11 -1
- pysdmx/model/dataflow.py +23 -0
- pysdmx/model/map.py +19 -13
- pysdmx/model/message.py +10 -5
- pysdmx/toolkit/pd/_data_utils.py +99 -0
- pysdmx/toolkit/vtl/_validations.py +2 -3
- {pysdmx-1.5.2.dist-info → pysdmx-1.7.0.dist-info}/METADATA +4 -3
- {pysdmx-1.5.2.dist-info → pysdmx-1.7.0.dist-info}/RECORD +63 -51
- {pysdmx-1.5.2.dist-info → pysdmx-1.7.0.dist-info}/WHEEL +1 -1
- {pysdmx-1.5.2.dist-info → pysdmx-1.7.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"""Collection of SDMX-JSON schemas for SDMX-REST schema queries."""
|
|
2
2
|
|
|
3
|
-
from typing import Dict, List, Optional, Sequence, Tuple
|
|
3
|
+
from typing import Dict, List, Literal, Optional, Sequence, Tuple
|
|
4
4
|
|
|
5
5
|
from msgspec import Struct
|
|
6
6
|
|
|
7
|
+
from pysdmx import errors
|
|
7
8
|
from pysdmx.io.json.sdmxjson2.messages.code import JsonCodelist, JsonValuelist
|
|
8
9
|
from pysdmx.io.json.sdmxjson2.messages.concept import (
|
|
9
10
|
JsonConcept,
|
|
@@ -11,10 +12,12 @@ from pysdmx.io.json.sdmxjson2.messages.concept import (
|
|
|
11
12
|
)
|
|
12
13
|
from pysdmx.io.json.sdmxjson2.messages.constraint import JsonDataConstraint
|
|
13
14
|
from pysdmx.io.json.sdmxjson2.messages.core import (
|
|
15
|
+
JsonAnnotation,
|
|
14
16
|
JsonRepresentation,
|
|
15
17
|
MaintainableType,
|
|
16
18
|
)
|
|
17
19
|
from pysdmx.model import (
|
|
20
|
+
Agency,
|
|
18
21
|
ArrayBoundaries,
|
|
19
22
|
Codelist,
|
|
20
23
|
Component,
|
|
@@ -23,8 +26,10 @@ from pysdmx.model import (
|
|
|
23
26
|
DataStructureDefinition,
|
|
24
27
|
DataType,
|
|
25
28
|
Facets,
|
|
29
|
+
ItemReference,
|
|
26
30
|
Role,
|
|
27
31
|
)
|
|
32
|
+
from pysdmx.model.dataflow import Group
|
|
28
33
|
from pysdmx.util import parse_item_urn
|
|
29
34
|
|
|
30
35
|
|
|
@@ -38,12 +43,13 @@ def _find_concept(cs: Sequence[JsonConceptScheme], urn: str) -> JsonConcept:
|
|
|
38
43
|
return [c for c in f[0].concepts if c.id == r.item_id][0]
|
|
39
44
|
|
|
40
45
|
|
|
41
|
-
def __get_type(repr_: JsonRepresentation) -> str:
|
|
46
|
+
def __get_type(repr_: JsonRepresentation) -> Optional[str]:
|
|
47
|
+
t: Optional[str] = None
|
|
42
48
|
if repr_.enumerationFormat:
|
|
43
49
|
t = repr_.enumerationFormat.dataType
|
|
44
50
|
elif repr_.format:
|
|
45
51
|
t = repr_.format.dataType
|
|
46
|
-
|
|
52
|
+
if not t:
|
|
47
53
|
t = "String"
|
|
48
54
|
return t
|
|
49
55
|
|
|
@@ -67,14 +73,44 @@ def _get_representation(
|
|
|
67
73
|
return (dt, facets, codes, ab)
|
|
68
74
|
|
|
69
75
|
|
|
70
|
-
|
|
76
|
+
def _get_concept_reference(component: Component) -> str:
|
|
77
|
+
if isinstance(component.concept, ItemReference):
|
|
78
|
+
concept = (
|
|
79
|
+
"urn:sdmx:org.sdmx.infomodel.conceptscheme."
|
|
80
|
+
f"{str(component.concept)}"
|
|
81
|
+
)
|
|
82
|
+
elif component.concept.urn:
|
|
83
|
+
concept = component.concept.urn
|
|
84
|
+
else:
|
|
85
|
+
raise errors.Invalid(
|
|
86
|
+
"Missing concept reference",
|
|
87
|
+
(
|
|
88
|
+
"The full reference to the concept must be available "
|
|
89
|
+
"but could not be found. To have the full reference, "
|
|
90
|
+
"either the concept must be an ItemReference or a "
|
|
91
|
+
"concept object with a urn."
|
|
92
|
+
),
|
|
93
|
+
)
|
|
94
|
+
return concept
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _get_json_representation(
|
|
98
|
+
comp: Component,
|
|
99
|
+
) -> Optional[JsonRepresentation]:
|
|
100
|
+
enum = comp.local_enum_ref if comp.local_enum_ref else None
|
|
101
|
+
return JsonRepresentation.from_model(
|
|
102
|
+
comp.local_dtype, enum, comp.local_facets, comp.array_def
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class JsonGroup(Struct, frozen=True, omit_defaults=True):
|
|
71
107
|
"""SDMX-JSON payload for a group."""
|
|
72
108
|
|
|
73
109
|
id: str
|
|
74
110
|
groupDimensions: Sequence[str]
|
|
75
111
|
|
|
76
112
|
|
|
77
|
-
class JsonAttributeRelationship(Struct, frozen=True):
|
|
113
|
+
class JsonAttributeRelationship(Struct, frozen=True, omit_defaults=True):
|
|
78
114
|
"""SDMX-JSON payload for an attribute relationship."""
|
|
79
115
|
|
|
80
116
|
dataflow: Optional[Dict] = None # type: ignore[type-arg]
|
|
@@ -96,8 +132,19 @@ class JsonAttributeRelationship(Struct, frozen=True):
|
|
|
96
132
|
else:
|
|
97
133
|
return "D"
|
|
98
134
|
|
|
135
|
+
@classmethod
|
|
136
|
+
def from_model(self, rel: str) -> "JsonAttributeRelationship":
|
|
137
|
+
"""Converts a pysdmx attribute relationship to an SDMX-JSON one."""
|
|
138
|
+
if rel == "D":
|
|
139
|
+
return JsonAttributeRelationship(dataflow={})
|
|
140
|
+
elif rel == "O":
|
|
141
|
+
return JsonAttributeRelationship(observation={})
|
|
142
|
+
else:
|
|
143
|
+
dims = rel.split(",")
|
|
144
|
+
return JsonAttributeRelationship(dimensions=dims)
|
|
145
|
+
|
|
99
146
|
|
|
100
|
-
class JsonDimension(Struct, frozen=True):
|
|
147
|
+
class JsonDimension(Struct, frozen=True, omit_defaults=True):
|
|
101
148
|
"""SDMX-JSON payload for a component."""
|
|
102
149
|
|
|
103
150
|
id: str
|
|
@@ -123,6 +170,10 @@ class JsonDimension(Struct, frozen=True):
|
|
|
123
170
|
dt, facets, codes, ab = _get_representation(
|
|
124
171
|
self.id, self.localRepresentation, cls, cons
|
|
125
172
|
)
|
|
173
|
+
if self.localRepresentation and self.localRepresentation.enumeration:
|
|
174
|
+
local_enum_ref = self.localRepresentation.enumeration
|
|
175
|
+
else:
|
|
176
|
+
local_enum_ref = None
|
|
126
177
|
return Component(
|
|
127
178
|
id=self.id,
|
|
128
179
|
required=True,
|
|
@@ -134,10 +185,22 @@ class JsonDimension(Struct, frozen=True):
|
|
|
134
185
|
description=desc,
|
|
135
186
|
local_codes=codes,
|
|
136
187
|
array_def=ab,
|
|
188
|
+
local_enum_ref=local_enum_ref,
|
|
137
189
|
)
|
|
138
190
|
|
|
191
|
+
@classmethod
|
|
192
|
+
def from_model(self, dimension: Component) -> "JsonDimension":
|
|
193
|
+
"""Converts a pysdmx dimension to an SDMX-JSON one."""
|
|
194
|
+
concept = _get_concept_reference(dimension)
|
|
195
|
+
repr = _get_json_representation(dimension)
|
|
196
|
+
return JsonDimension(
|
|
197
|
+
id=dimension.id,
|
|
198
|
+
conceptIdentity=concept,
|
|
199
|
+
localRepresentation=repr,
|
|
200
|
+
)
|
|
139
201
|
|
|
140
|
-
|
|
202
|
+
|
|
203
|
+
class JsonAttribute(Struct, frozen=True, omit_defaults=True):
|
|
141
204
|
"""SDMX-JSON payload for an attribute."""
|
|
142
205
|
|
|
143
206
|
id: str
|
|
@@ -171,6 +234,10 @@ class JsonAttribute(Struct, frozen=True):
|
|
|
171
234
|
groups,
|
|
172
235
|
self.measureRelationship,
|
|
173
236
|
)
|
|
237
|
+
if self.localRepresentation and self.localRepresentation.enumeration:
|
|
238
|
+
local_enum_ref = self.localRepresentation.enumeration
|
|
239
|
+
else:
|
|
240
|
+
local_enum_ref = None
|
|
174
241
|
return Component(
|
|
175
242
|
id=self.id,
|
|
176
243
|
required=req,
|
|
@@ -183,10 +250,28 @@ class JsonAttribute(Struct, frozen=True):
|
|
|
183
250
|
local_codes=codes,
|
|
184
251
|
attachment_level=lvl,
|
|
185
252
|
array_def=ab,
|
|
253
|
+
local_enum_ref=local_enum_ref,
|
|
186
254
|
)
|
|
187
255
|
|
|
256
|
+
@classmethod
|
|
257
|
+
def from_model(self, attribute: Component) -> "JsonAttribute":
|
|
258
|
+
"""Converts a pysdmx attribute to an SDMX-JSON one."""
|
|
259
|
+
concept = _get_concept_reference(attribute)
|
|
260
|
+
usage = "mandatory" if attribute.required else "optional"
|
|
261
|
+
level = JsonAttributeRelationship.from_model(
|
|
262
|
+
attribute.attachment_level # type: ignore[arg-type]
|
|
263
|
+
)
|
|
264
|
+
repr = _get_json_representation(attribute)
|
|
265
|
+
return JsonAttribute(
|
|
266
|
+
id=attribute.id,
|
|
267
|
+
conceptIdentity=concept,
|
|
268
|
+
attributeRelationship=level,
|
|
269
|
+
usage=usage,
|
|
270
|
+
localRepresentation=repr,
|
|
271
|
+
)
|
|
188
272
|
|
|
189
|
-
|
|
273
|
+
|
|
274
|
+
class JsonMeasure(Struct, frozen=True, omit_defaults=True):
|
|
190
275
|
"""SDMX-JSON payload for a measure."""
|
|
191
276
|
|
|
192
277
|
id: str
|
|
@@ -213,6 +298,10 @@ class JsonMeasure(Struct, frozen=True):
|
|
|
213
298
|
self.id, self.localRepresentation, cls, cons
|
|
214
299
|
)
|
|
215
300
|
req = self.usage != "optional"
|
|
301
|
+
if self.localRepresentation and self.localRepresentation.enumeration:
|
|
302
|
+
local_enum_ref = self.localRepresentation.enumeration
|
|
303
|
+
else:
|
|
304
|
+
local_enum_ref = None
|
|
216
305
|
return Component(
|
|
217
306
|
id=self.id,
|
|
218
307
|
required=req,
|
|
@@ -224,12 +313,27 @@ class JsonMeasure(Struct, frozen=True):
|
|
|
224
313
|
description=desc,
|
|
225
314
|
local_codes=codes,
|
|
226
315
|
array_def=ab,
|
|
316
|
+
local_enum_ref=local_enum_ref,
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
@classmethod
|
|
320
|
+
def from_model(self, measure: Component) -> "JsonMeasure":
|
|
321
|
+
"""Converts a pysdmx measure to an SDMX-JSON one."""
|
|
322
|
+
concept = _get_concept_reference(measure)
|
|
323
|
+
usage = "mandatory" if measure.required else "optional"
|
|
324
|
+
repr = _get_json_representation(measure)
|
|
325
|
+
return JsonMeasure(
|
|
326
|
+
id=measure.id,
|
|
327
|
+
conceptIdentity=concept,
|
|
328
|
+
usage=usage,
|
|
329
|
+
localRepresentation=repr,
|
|
227
330
|
)
|
|
228
331
|
|
|
229
332
|
|
|
230
|
-
class JsonAttributes(Struct, frozen=True):
|
|
333
|
+
class JsonAttributes(Struct, frozen=True, omit_defaults=True):
|
|
231
334
|
"""SDMX-JSON payload for the list of attributes."""
|
|
232
335
|
|
|
336
|
+
id: Literal["AttributeDescriptor"] = "AttributeDescriptor"
|
|
233
337
|
attributes: Sequence[JsonAttribute] = ()
|
|
234
338
|
|
|
235
339
|
def to_model(
|
|
@@ -242,11 +346,24 @@ class JsonAttributes(Struct, frozen=True):
|
|
|
242
346
|
"""Returns the list of attributes."""
|
|
243
347
|
return [a.to_model(cs, cls, cons, groups) for a in self.attributes]
|
|
244
348
|
|
|
349
|
+
@classmethod
|
|
350
|
+
def from_model(
|
|
351
|
+
self, attributes: Sequence[Component]
|
|
352
|
+
) -> Optional["JsonAttributes"]:
|
|
353
|
+
"""Converts a pysdmx list of attributes to an SDMX-JSON one."""
|
|
354
|
+
if len(attributes) > 0:
|
|
355
|
+
return JsonAttributes(
|
|
356
|
+
attributes=[JsonAttribute.from_model(a) for a in attributes]
|
|
357
|
+
)
|
|
358
|
+
else:
|
|
359
|
+
return None
|
|
360
|
+
|
|
245
361
|
|
|
246
|
-
class JsonDimensions(Struct, frozen=True):
|
|
362
|
+
class JsonDimensions(Struct, frozen=True, omit_defaults=True):
|
|
247
363
|
"""SDMX-JSON payload for the list of dimensions."""
|
|
248
364
|
|
|
249
|
-
|
|
365
|
+
id: Literal["DimensionDescriptor"] = "DimensionDescriptor"
|
|
366
|
+
dimensions: Sequence[JsonDimension] = ()
|
|
250
367
|
timeDimension: Optional[JsonDimension] = None
|
|
251
368
|
|
|
252
369
|
def to_model(
|
|
@@ -262,11 +379,29 @@ class JsonDimensions(Struct, frozen=True):
|
|
|
262
379
|
dims.append(self.timeDimension.to_model(cs, cls, cons))
|
|
263
380
|
return dims
|
|
264
381
|
|
|
382
|
+
@classmethod
|
|
383
|
+
def from_model(
|
|
384
|
+
self,
|
|
385
|
+
dimensions: Sequence[Component],
|
|
386
|
+
) -> "JsonDimensions":
|
|
387
|
+
"""Converts a pysdmx list of dimensions to an SDMX-JSON one."""
|
|
388
|
+
td = [d for d in dimensions if d.id == "TIME_PERIOD"]
|
|
389
|
+
ftd = None if len(td) == 0 else JsonDimension.from_model(td[0])
|
|
390
|
+
return JsonDimensions(
|
|
391
|
+
dimensions=[
|
|
392
|
+
JsonDimension.from_model(d)
|
|
393
|
+
for d in dimensions
|
|
394
|
+
if d.id != "TIME_PERIOD"
|
|
395
|
+
],
|
|
396
|
+
timeDimension=ftd,
|
|
397
|
+
)
|
|
265
398
|
|
|
266
|
-
|
|
399
|
+
|
|
400
|
+
class JsonMeasures(Struct, frozen=True, omit_defaults=True):
|
|
267
401
|
"""SDMX-JSON payload for the list of measures."""
|
|
268
402
|
|
|
269
|
-
|
|
403
|
+
id: Literal["MeasureDescriptor"] = "MeasureDescriptor"
|
|
404
|
+
measures: Sequence[JsonMeasure] = ()
|
|
270
405
|
|
|
271
406
|
def to_model(
|
|
272
407
|
self,
|
|
@@ -277,8 +412,20 @@ class JsonMeasures(Struct, frozen=True):
|
|
|
277
412
|
"""Returns the list of measures."""
|
|
278
413
|
return [m.to_model(cs, cls, cons) for m in self.measures]
|
|
279
414
|
|
|
415
|
+
@classmethod
|
|
416
|
+
def from_model(
|
|
417
|
+
self, measures: Sequence[Component]
|
|
418
|
+
) -> Optional["JsonMeasures"]:
|
|
419
|
+
"""Converts a pysdmx list of measures to an SDMX-JSON one."""
|
|
420
|
+
if len(measures) > 0:
|
|
421
|
+
return JsonMeasures(
|
|
422
|
+
measures=[JsonMeasure.from_model(m) for m in measures]
|
|
423
|
+
)
|
|
424
|
+
else:
|
|
425
|
+
return None
|
|
426
|
+
|
|
280
427
|
|
|
281
|
-
class JsonComponents(Struct, frozen=True):
|
|
428
|
+
class JsonComponents(Struct, frozen=True, omit_defaults=True):
|
|
282
429
|
"""SDMX-JSON payload for the list of DSD components."""
|
|
283
430
|
|
|
284
431
|
dimensionList: JsonDimensions
|
|
@@ -292,7 +439,7 @@ class JsonComponents(Struct, frozen=True):
|
|
|
292
439
|
cls: Sequence[JsonCodelist],
|
|
293
440
|
vls: Sequence[JsonValuelist],
|
|
294
441
|
constraints: Sequence[JsonDataConstraint],
|
|
295
|
-
) -> Components:
|
|
442
|
+
) -> Tuple[Components, Sequence[Group]]:
|
|
296
443
|
"""Returns the components for this DSD."""
|
|
297
444
|
enums = [cl.to_model() for cl in cls]
|
|
298
445
|
enums.extend([vl.to_model() for vl in vls])
|
|
@@ -313,10 +460,27 @@ class JsonComponents(Struct, frozen=True):
|
|
|
313
460
|
self.groups,
|
|
314
461
|
)
|
|
315
462
|
)
|
|
316
|
-
|
|
463
|
+
mapped_grps = [
|
|
464
|
+
Group(g.id, dimensions=g.groupDimensions) for g in self.groups
|
|
465
|
+
]
|
|
466
|
+
return (Components(comps), mapped_grps)
|
|
467
|
+
|
|
468
|
+
@classmethod
|
|
469
|
+
def from_model(
|
|
470
|
+
self, components: Components, grps: Optional[Sequence[Group]]
|
|
471
|
+
) -> "JsonComponents":
|
|
472
|
+
"""Converts a pysdmx components list to an SDMX-JSON one."""
|
|
473
|
+
dimensions = JsonDimensions.from_model(components.dimensions)
|
|
474
|
+
attributes = JsonAttributes.from_model(components.attributes)
|
|
475
|
+
measures = JsonMeasures.from_model(components.measures)
|
|
476
|
+
if grps is None:
|
|
477
|
+
groups = []
|
|
478
|
+
else:
|
|
479
|
+
groups = [JsonGroup(g.id, g.dimensions) for g in grps]
|
|
480
|
+
return JsonComponents(dimensions, measures, attributes, groups)
|
|
317
481
|
|
|
318
482
|
|
|
319
|
-
class JsonDataStructure(MaintainableType, frozen=True):
|
|
483
|
+
class JsonDataStructure(MaintainableType, frozen=True, omit_defaults=True):
|
|
320
484
|
"""SDMX-JSON payload for a DSD."""
|
|
321
485
|
|
|
322
486
|
dataStructureComponents: Optional[JsonComponents] = None
|
|
@@ -330,7 +494,7 @@ class JsonDataStructure(MaintainableType, frozen=True):
|
|
|
330
494
|
constraints: Sequence[JsonDataConstraint],
|
|
331
495
|
) -> DataStructureDefinition:
|
|
332
496
|
"""Map to pysdmx model class."""
|
|
333
|
-
c = self.dataStructureComponents.to_model( # type: ignore[union-attr]
|
|
497
|
+
c, grps = self.dataStructureComponents.to_model( # type: ignore[union-attr]
|
|
334
498
|
cs,
|
|
335
499
|
cls,
|
|
336
500
|
vls,
|
|
@@ -348,10 +512,41 @@ class JsonDataStructure(MaintainableType, frozen=True):
|
|
|
348
512
|
valid_to=self.validTo,
|
|
349
513
|
components=c,
|
|
350
514
|
evolving_structure=self.evolvingStructure,
|
|
515
|
+
groups=grps,
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
@classmethod
|
|
519
|
+
def from_model(self, dsd: DataStructureDefinition) -> "JsonDataStructure":
|
|
520
|
+
"""Converts a pysdmx dsd to an SDMX-JSON one."""
|
|
521
|
+
if not dsd.name:
|
|
522
|
+
raise errors.Invalid(
|
|
523
|
+
"Invalid input",
|
|
524
|
+
"SDMX-JSON data structures must have a name",
|
|
525
|
+
{"data_structure": dsd.id},
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
return JsonDataStructure(
|
|
529
|
+
agency=(
|
|
530
|
+
dsd.agency.id if isinstance(dsd.agency, Agency) else dsd.agency
|
|
531
|
+
),
|
|
532
|
+
id=dsd.id,
|
|
533
|
+
name=dsd.name,
|
|
534
|
+
version=dsd.version,
|
|
535
|
+
isExternalReference=dsd.is_external_reference,
|
|
536
|
+
validFrom=dsd.valid_from,
|
|
537
|
+
validTo=dsd.valid_to,
|
|
538
|
+
description=dsd.description,
|
|
539
|
+
annotations=tuple(
|
|
540
|
+
[JsonAnnotation.from_model(a) for a in dsd.annotations]
|
|
541
|
+
),
|
|
542
|
+
dataStructureComponents=JsonComponents.from_model(
|
|
543
|
+
dsd.components, dsd.groups
|
|
544
|
+
),
|
|
545
|
+
evolvingStructure=dsd.evolving_structure,
|
|
351
546
|
)
|
|
352
547
|
|
|
353
548
|
|
|
354
|
-
class JsonDataStructures(Struct, frozen=True):
|
|
549
|
+
class JsonDataStructures(Struct, frozen=True, omit_defaults=True):
|
|
355
550
|
"""SDMX-JSON payload for data structures."""
|
|
356
551
|
|
|
357
552
|
dataStructures: Sequence[JsonDataStructure]
|
|
@@ -373,7 +568,7 @@ class JsonDataStructures(Struct, frozen=True):
|
|
|
373
568
|
]
|
|
374
569
|
|
|
375
570
|
|
|
376
|
-
class JsonDataStructuresMessage(Struct, frozen=True):
|
|
571
|
+
class JsonDataStructuresMessage(Struct, frozen=True, omit_defaults=True):
|
|
377
572
|
"""SDMX-JSON payload for /datastructure queries."""
|
|
378
573
|
|
|
379
574
|
data: JsonDataStructures
|