pysdmx 1.5.1__py3-none-any.whl → 1.6.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 +16 -2
- pysdmx/io/json/fusion/messages/code.py +21 -4
- pysdmx/io/json/fusion/messages/concept.py +16 -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 +239 -18
- pysdmx/io/json/sdmxjson2/messages/concept.py +78 -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/__structure_aux_reader.py +2 -2
- pysdmx/io/xml/__structure_aux_writer.py +5 -5
- pysdmx/io/xml/__write_data_aux.py +1 -54
- pysdmx/io/xml/__write_structure_specific_aux.py +1 -1
- pysdmx/io/xml/sdmx21/writer/generic.py +1 -1
- pysdmx/model/code.py +11 -1
- pysdmx/model/dataflow.py +26 -3
- pysdmx/model/map.py +12 -4
- pysdmx/model/message.py +9 -1
- pysdmx/toolkit/pd/_data_utils.py +100 -0
- pysdmx/toolkit/vtl/_validations.py +2 -3
- {pysdmx-1.5.1.dist-info → pysdmx-1.6.0.dist-info}/METADATA +3 -2
- {pysdmx-1.5.1.dist-info → pysdmx-1.6.0.dist-info}/RECORD +60 -48
- {pysdmx-1.5.1.dist-info → pysdmx-1.6.0.dist-info}/WHEEL +1 -1
- {pysdmx-1.5.1.dist-info → pysdmx-1.6.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -4,12 +4,13 @@ from typing import Literal, Optional, Sequence
|
|
|
4
4
|
|
|
5
5
|
from msgspec import Struct
|
|
6
6
|
|
|
7
|
+
from pysdmx import errors
|
|
7
8
|
from pysdmx.io.json.sdmxjson2.messages.core import (
|
|
8
9
|
ItemSchemeType,
|
|
9
10
|
JsonAnnotation,
|
|
10
11
|
NameableType,
|
|
11
12
|
)
|
|
12
|
-
from pysdmx.model.__base import DataflowRef
|
|
13
|
+
from pysdmx.model.__base import Agency, DataflowRef, ItemReference
|
|
13
14
|
from pysdmx.model.vtl import (
|
|
14
15
|
CustomType,
|
|
15
16
|
CustomTypeScheme,
|
|
@@ -32,7 +33,7 @@ from pysdmx.model.vtl import (
|
|
|
32
33
|
from pysdmx.util import parse_urn
|
|
33
34
|
|
|
34
35
|
|
|
35
|
-
class JsonCustomType(NameableType, frozen=True):
|
|
36
|
+
class JsonCustomType(NameableType, frozen=True, omit_defaults=True):
|
|
36
37
|
"""SDMX-JSON payload for custom types."""
|
|
37
38
|
|
|
38
39
|
vtlScalarType: str = ""
|
|
@@ -55,8 +56,31 @@ class JsonCustomType(NameableType, frozen=True):
|
|
|
55
56
|
annotations=[a.to_model() for a in self.annotations],
|
|
56
57
|
)
|
|
57
58
|
|
|
59
|
+
@classmethod
|
|
60
|
+
def from_model(self, ct: CustomType) -> "JsonCustomType":
|
|
61
|
+
"""Converts a pysdmx custom type to an SDMX-JSON one."""
|
|
62
|
+
if not ct.name:
|
|
63
|
+
raise errors.Invalid(
|
|
64
|
+
"Invalid input",
|
|
65
|
+
"SDMX-JSON custom types must have a name",
|
|
66
|
+
{"custom_type": ct.id},
|
|
67
|
+
)
|
|
68
|
+
return JsonCustomType(
|
|
69
|
+
id=ct.id,
|
|
70
|
+
name=ct.name,
|
|
71
|
+
description=ct.description,
|
|
72
|
+
annotations=tuple(
|
|
73
|
+
[JsonAnnotation.from_model(a) for a in ct.annotations]
|
|
74
|
+
),
|
|
75
|
+
vtlScalarType=ct.vtl_scalar_type,
|
|
76
|
+
dataType=ct.data_type,
|
|
77
|
+
vtlLiteralFormat=ct.vtl_literal_format,
|
|
78
|
+
outputFormat=ct.output_format,
|
|
79
|
+
nullValue=ct.null_value,
|
|
80
|
+
)
|
|
81
|
+
|
|
58
82
|
|
|
59
|
-
class JsonCustomTypeScheme(ItemSchemeType, frozen=True):
|
|
83
|
+
class JsonCustomTypeScheme(ItemSchemeType, frozen=True, omit_defaults=True):
|
|
60
84
|
"""SDMX-JSON payload for custom type schemes."""
|
|
61
85
|
|
|
62
86
|
vtlVersion: str = ""
|
|
@@ -80,8 +104,38 @@ class JsonCustomTypeScheme(ItemSchemeType, frozen=True):
|
|
|
80
104
|
annotations=[a.to_model() for a in self.annotations],
|
|
81
105
|
)
|
|
82
106
|
|
|
107
|
+
@classmethod
|
|
108
|
+
def from_model(self, cts: CustomTypeScheme) -> "JsonCustomTypeScheme":
|
|
109
|
+
"""Converts a pysdmx custom type scheme to an SDMX-JSON one."""
|
|
110
|
+
if not cts.name:
|
|
111
|
+
raise errors.Invalid(
|
|
112
|
+
"Invalid input",
|
|
113
|
+
"SDMX-JSON custom type schemes must have a name",
|
|
114
|
+
{"custom_type_scheme": cts.id},
|
|
115
|
+
)
|
|
116
|
+
return JsonCustomTypeScheme(
|
|
117
|
+
agency=(
|
|
118
|
+
cts.agency.id if isinstance(cts.agency, Agency) else cts.agency
|
|
119
|
+
),
|
|
120
|
+
id=cts.id,
|
|
121
|
+
name=cts.name,
|
|
122
|
+
version=cts.version,
|
|
123
|
+
isExternalReference=cts.is_external_reference,
|
|
124
|
+
validFrom=cts.valid_from,
|
|
125
|
+
validTo=cts.valid_to,
|
|
126
|
+
description=cts.description,
|
|
127
|
+
annotations=tuple(
|
|
128
|
+
[JsonAnnotation.from_model(a) for a in cts.annotations]
|
|
129
|
+
),
|
|
130
|
+
isPartial=cts.is_partial,
|
|
131
|
+
vtlVersion=cts.vtl_version, # type: ignore[arg-type]
|
|
132
|
+
customTypes=tuple(
|
|
133
|
+
[JsonCustomType.from_model(i) for i in cts.items]
|
|
134
|
+
),
|
|
135
|
+
)
|
|
83
136
|
|
|
84
|
-
|
|
137
|
+
|
|
138
|
+
class JsonNamePersonalisation(NameableType, frozen=True, omit_defaults=True):
|
|
85
139
|
"""SDMX-JSON payload for name personalisations."""
|
|
86
140
|
|
|
87
141
|
vtlDefaultName: str = ""
|
|
@@ -100,8 +154,31 @@ class JsonNamePersonalisation(NameableType, frozen=True):
|
|
|
100
154
|
annotations=[a.to_model() for a in self.annotations],
|
|
101
155
|
)
|
|
102
156
|
|
|
157
|
+
@classmethod
|
|
158
|
+
def from_model(cls, np: NamePersonalisation) -> "JsonNamePersonalisation":
|
|
159
|
+
"""Converts a pysdmx name personalisation to an SDMX-JSON one."""
|
|
160
|
+
if not np.name:
|
|
161
|
+
raise errors.Invalid(
|
|
162
|
+
"Invalid input",
|
|
163
|
+
"SDMX-JSON name personalisations must have a name",
|
|
164
|
+
{"name_personalisation": np.id},
|
|
165
|
+
)
|
|
166
|
+
return JsonNamePersonalisation(
|
|
167
|
+
id=np.id,
|
|
168
|
+
name=np.name,
|
|
169
|
+
description=np.description,
|
|
170
|
+
annotations=tuple(
|
|
171
|
+
[JsonAnnotation.from_model(a) for a in np.annotations]
|
|
172
|
+
),
|
|
173
|
+
vtlDefaultName=np.vtl_default_name,
|
|
174
|
+
personalisedName=np.personalised_name,
|
|
175
|
+
vtlArtefact=np.vtl_artefact,
|
|
176
|
+
)
|
|
177
|
+
|
|
103
178
|
|
|
104
|
-
class JsonNamePersonalisationScheme(
|
|
179
|
+
class JsonNamePersonalisationScheme(
|
|
180
|
+
ItemSchemeType, frozen=True, omit_defaults=True
|
|
181
|
+
):
|
|
105
182
|
"""SDMX-JSON payload for name personalisation schemes."""
|
|
106
183
|
|
|
107
184
|
vtlVersion: str = ""
|
|
@@ -125,8 +202,40 @@ class JsonNamePersonalisationScheme(ItemSchemeType, frozen=True):
|
|
|
125
202
|
annotations=[a.to_model() for a in self.annotations],
|
|
126
203
|
)
|
|
127
204
|
|
|
205
|
+
@classmethod
|
|
206
|
+
def from_model(
|
|
207
|
+
cls, nps: NamePersonalisationScheme
|
|
208
|
+
) -> "JsonNamePersonalisationScheme":
|
|
209
|
+
"""Converts a pysdmx name personalisation scheme to SDMX-JSON."""
|
|
210
|
+
if not nps.name:
|
|
211
|
+
raise errors.Invalid(
|
|
212
|
+
"Invalid input",
|
|
213
|
+
"SDMX-JSON name personalisation schemes must have a name",
|
|
214
|
+
{"name_personalisation_scheme": nps.id},
|
|
215
|
+
)
|
|
216
|
+
return JsonNamePersonalisationScheme(
|
|
217
|
+
agency=(
|
|
218
|
+
nps.agency.id if isinstance(nps.agency, Agency) else nps.agency
|
|
219
|
+
),
|
|
220
|
+
id=nps.id,
|
|
221
|
+
name=nps.name,
|
|
222
|
+
version=nps.version,
|
|
223
|
+
isExternalReference=nps.is_external_reference,
|
|
224
|
+
validFrom=nps.valid_from,
|
|
225
|
+
validTo=nps.valid_to,
|
|
226
|
+
description=nps.description,
|
|
227
|
+
annotations=tuple(
|
|
228
|
+
[JsonAnnotation.from_model(a) for a in nps.annotations]
|
|
229
|
+
),
|
|
230
|
+
isPartial=nps.is_partial,
|
|
231
|
+
vtlVersion=nps.vtl_version, # type: ignore[arg-type]
|
|
232
|
+
namePersonalisations=tuple(
|
|
233
|
+
[JsonNamePersonalisation.from_model(i) for i in nps.items]
|
|
234
|
+
),
|
|
235
|
+
)
|
|
128
236
|
|
|
129
|
-
|
|
237
|
+
|
|
238
|
+
class JsonUserDefinedOperator(NameableType, frozen=True, omit_defaults=True):
|
|
130
239
|
"""SDMX-JSON payload for user defined operator."""
|
|
131
240
|
|
|
132
241
|
operatorDefinition: str = ""
|
|
@@ -141,8 +250,29 @@ class JsonUserDefinedOperator(NameableType, frozen=True):
|
|
|
141
250
|
annotations=[a.to_model() for a in self.annotations],
|
|
142
251
|
)
|
|
143
252
|
|
|
253
|
+
@classmethod
|
|
254
|
+
def from_model(cls, udo: UserDefinedOperator) -> "JsonUserDefinedOperator":
|
|
255
|
+
"""Converts a pysdmx user defined operator to an SDMX-JSON one."""
|
|
256
|
+
if not udo.name:
|
|
257
|
+
raise errors.Invalid(
|
|
258
|
+
"Invalid input",
|
|
259
|
+
"SDMX-JSON user defined operators must have a name",
|
|
260
|
+
{"user_defined_operator": udo.id},
|
|
261
|
+
)
|
|
262
|
+
return JsonUserDefinedOperator(
|
|
263
|
+
id=udo.id,
|
|
264
|
+
name=udo.name,
|
|
265
|
+
description=udo.description,
|
|
266
|
+
annotations=tuple(
|
|
267
|
+
[JsonAnnotation.from_model(a) for a in udo.annotations]
|
|
268
|
+
),
|
|
269
|
+
operatorDefinition=udo.operator_definition,
|
|
270
|
+
)
|
|
271
|
+
|
|
144
272
|
|
|
145
|
-
class JsonUserDefinedOperatorScheme(
|
|
273
|
+
class JsonUserDefinedOperatorScheme(
|
|
274
|
+
ItemSchemeType, frozen=True, omit_defaults=True
|
|
275
|
+
):
|
|
146
276
|
"""SDMX-JSON payload for user defined operator schemes."""
|
|
147
277
|
|
|
148
278
|
vtlVersion: str = ""
|
|
@@ -170,8 +300,78 @@ class JsonUserDefinedOperatorScheme(ItemSchemeType, frozen=True):
|
|
|
170
300
|
annotations=[a.to_model() for a in self.annotations],
|
|
171
301
|
)
|
|
172
302
|
|
|
303
|
+
@classmethod
|
|
304
|
+
def from_model(
|
|
305
|
+
cls, udos: UserDefinedOperatorScheme
|
|
306
|
+
) -> "JsonUserDefinedOperatorScheme":
|
|
307
|
+
"""Converts a pysdmx user defined operator scheme to SDMX-JSON."""
|
|
308
|
+
if not udos.name:
|
|
309
|
+
raise errors.Invalid(
|
|
310
|
+
"Invalid input",
|
|
311
|
+
"SDMX-JSON user defined operator schemes must have a name",
|
|
312
|
+
{"user_defined_operator_scheme": udos.id},
|
|
313
|
+
)
|
|
173
314
|
|
|
174
|
-
|
|
315
|
+
# Convert vtl_mapping_scheme to URN string
|
|
316
|
+
vtl_mapping_ref = None
|
|
317
|
+
if udos.vtl_mapping_scheme:
|
|
318
|
+
if isinstance(udos.vtl_mapping_scheme, str):
|
|
319
|
+
vtl_mapping_ref = udos.vtl_mapping_scheme
|
|
320
|
+
else:
|
|
321
|
+
# Handle both VtlMappingScheme objects and References
|
|
322
|
+
agency = (
|
|
323
|
+
udos.vtl_mapping_scheme.agency.id
|
|
324
|
+
if hasattr(udos.vtl_mapping_scheme.agency, "id")
|
|
325
|
+
else udos.vtl_mapping_scheme.agency
|
|
326
|
+
)
|
|
327
|
+
vtl_mapping_ref = (
|
|
328
|
+
f"urn:sdmx:org.sdmx.infomodel.transformation.VtlMappingScheme="
|
|
329
|
+
f"{agency}:{udos.vtl_mapping_scheme.id}"
|
|
330
|
+
f"({udos.vtl_mapping_scheme.version})"
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
# Convert ruleset_schemes to URN strings
|
|
334
|
+
ruleset_refs = []
|
|
335
|
+
for rs in udos.ruleset_schemes:
|
|
336
|
+
if isinstance(rs, str):
|
|
337
|
+
ruleset_refs.append(rs)
|
|
338
|
+
else:
|
|
339
|
+
# Handle both RulesetScheme objects and References
|
|
340
|
+
agency = (
|
|
341
|
+
rs.agency.id if hasattr(rs.agency, "id") else rs.agency
|
|
342
|
+
)
|
|
343
|
+
ruleset_refs.append(
|
|
344
|
+
f"urn:sdmx:org.sdmx.infomodel.transformation.RulesetScheme="
|
|
345
|
+
f"{agency}:{rs.id}({rs.version})"
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
return JsonUserDefinedOperatorScheme(
|
|
349
|
+
agency=(
|
|
350
|
+
udos.agency.id
|
|
351
|
+
if isinstance(udos.agency, Agency)
|
|
352
|
+
else udos.agency
|
|
353
|
+
),
|
|
354
|
+
id=udos.id,
|
|
355
|
+
name=udos.name,
|
|
356
|
+
version=udos.version,
|
|
357
|
+
isExternalReference=udos.is_external_reference,
|
|
358
|
+
validFrom=udos.valid_from,
|
|
359
|
+
validTo=udos.valid_to,
|
|
360
|
+
description=udos.description,
|
|
361
|
+
annotations=tuple(
|
|
362
|
+
[JsonAnnotation.from_model(a) for a in udos.annotations]
|
|
363
|
+
),
|
|
364
|
+
isPartial=udos.is_partial,
|
|
365
|
+
vtlVersion=udos.vtl_version, # type: ignore[arg-type]
|
|
366
|
+
vtlMappingScheme=vtl_mapping_ref,
|
|
367
|
+
rulesetSchemes=ruleset_refs,
|
|
368
|
+
userDefinedOperators=tuple(
|
|
369
|
+
[JsonUserDefinedOperator.from_model(i) for i in udos.items]
|
|
370
|
+
),
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
class JsonRuleset(Struct, frozen=True, omit_defaults=True):
|
|
175
375
|
"""SDMX-JSON payload for rulesets."""
|
|
176
376
|
|
|
177
377
|
id: str
|
|
@@ -194,8 +394,41 @@ class JsonRuleset(Struct, frozen=True):
|
|
|
194
394
|
annotations=[a.to_model() for a in self.annotations],
|
|
195
395
|
)
|
|
196
396
|
|
|
397
|
+
@classmethod
|
|
398
|
+
def from_model(cls, ruleset: Ruleset) -> "JsonRuleset":
|
|
399
|
+
"""Converts a pysdmx ruleset to an SDMX-JSON one."""
|
|
400
|
+
if not ruleset.name:
|
|
401
|
+
raise errors.Invalid(
|
|
402
|
+
"Invalid input",
|
|
403
|
+
"SDMX-JSON rulesets must have a name",
|
|
404
|
+
{"ruleset": ruleset.id},
|
|
405
|
+
)
|
|
406
|
+
if not ruleset.ruleset_type:
|
|
407
|
+
raise errors.Invalid(
|
|
408
|
+
"Invalid input",
|
|
409
|
+
"SDMX-JSON rulesets must have a ruleset type",
|
|
410
|
+
{"ruleset": ruleset.id},
|
|
411
|
+
)
|
|
412
|
+
if not ruleset.ruleset_scope:
|
|
413
|
+
raise errors.Invalid(
|
|
414
|
+
"Invalid input",
|
|
415
|
+
"SDMX-JSON rulesets must have a ruleset scope",
|
|
416
|
+
{"ruleset": ruleset.id},
|
|
417
|
+
)
|
|
418
|
+
return JsonRuleset(
|
|
419
|
+
id=ruleset.id,
|
|
420
|
+
name=ruleset.name,
|
|
421
|
+
description=ruleset.description,
|
|
422
|
+
annotations=tuple(
|
|
423
|
+
[JsonAnnotation.from_model(a) for a in ruleset.annotations]
|
|
424
|
+
),
|
|
425
|
+
rulesetDefinition=ruleset.ruleset_definition,
|
|
426
|
+
rulesetType=ruleset.ruleset_type,
|
|
427
|
+
rulesetScope=ruleset.ruleset_scope,
|
|
428
|
+
)
|
|
429
|
+
|
|
197
430
|
|
|
198
|
-
class JsonRulesetScheme(ItemSchemeType, frozen=True):
|
|
431
|
+
class JsonRulesetScheme(ItemSchemeType, frozen=True, omit_defaults=True):
|
|
199
432
|
"""SDMX-JSON payload for ruleset schemes."""
|
|
200
433
|
|
|
201
434
|
vtlVersion: str = ""
|
|
@@ -221,8 +454,56 @@ class JsonRulesetScheme(ItemSchemeType, frozen=True):
|
|
|
221
454
|
annotations=[a.to_model() for a in self.annotations],
|
|
222
455
|
)
|
|
223
456
|
|
|
457
|
+
@classmethod
|
|
458
|
+
def from_model(cls, rss: RulesetScheme) -> "JsonRulesetScheme":
|
|
459
|
+
"""Converts a pysdmx ruleset scheme to an SDMX-JSON one."""
|
|
460
|
+
if not rss.name:
|
|
461
|
+
raise errors.Invalid(
|
|
462
|
+
"Invalid input",
|
|
463
|
+
"SDMX-JSON ruleset schemes must have a name",
|
|
464
|
+
{"ruleset_scheme": rss.id},
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
# Convert vtl_mapping_scheme to URN string
|
|
468
|
+
vtl_mapping_ref = None
|
|
469
|
+
if rss.vtl_mapping_scheme:
|
|
470
|
+
if isinstance(rss.vtl_mapping_scheme, str):
|
|
471
|
+
vtl_mapping_ref = rss.vtl_mapping_scheme
|
|
472
|
+
else:
|
|
473
|
+
# Handle both VtlMappingScheme objects and References
|
|
474
|
+
agency = (
|
|
475
|
+
rss.vtl_mapping_scheme.agency.id
|
|
476
|
+
if hasattr(rss.vtl_mapping_scheme.agency, "id")
|
|
477
|
+
else rss.vtl_mapping_scheme.agency
|
|
478
|
+
)
|
|
479
|
+
vtl_mapping_ref = (
|
|
480
|
+
f"urn:sdmx:org.sdmx.infomodel.transformation.VtlMappingScheme="
|
|
481
|
+
f"{agency}:{rss.vtl_mapping_scheme.id}"
|
|
482
|
+
f"({rss.vtl_mapping_scheme.version})"
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
return JsonRulesetScheme(
|
|
486
|
+
agency=(
|
|
487
|
+
rss.agency.id if isinstance(rss.agency, Agency) else rss.agency
|
|
488
|
+
),
|
|
489
|
+
id=rss.id,
|
|
490
|
+
name=rss.name,
|
|
491
|
+
version=rss.version,
|
|
492
|
+
isExternalReference=rss.is_external_reference,
|
|
493
|
+
validFrom=rss.valid_from,
|
|
494
|
+
validTo=rss.valid_to,
|
|
495
|
+
description=rss.description,
|
|
496
|
+
annotations=tuple(
|
|
497
|
+
[JsonAnnotation.from_model(a) for a in rss.annotations]
|
|
498
|
+
),
|
|
499
|
+
isPartial=rss.is_partial,
|
|
500
|
+
vtlVersion=rss.vtl_version, # type: ignore[arg-type]
|
|
501
|
+
vtlMappingScheme=vtl_mapping_ref,
|
|
502
|
+
rulesets=tuple([JsonRuleset.from_model(i) for i in rss.items]),
|
|
503
|
+
)
|
|
504
|
+
|
|
224
505
|
|
|
225
|
-
class JsonToVtlMapping(Struct, frozen=True):
|
|
506
|
+
class JsonToVtlMapping(Struct, frozen=True, omit_defaults=True):
|
|
226
507
|
"""SDMX-JSON payload for To VTL mappings."""
|
|
227
508
|
|
|
228
509
|
toVtlSubSpace: Sequence[str]
|
|
@@ -232,8 +513,13 @@ class JsonToVtlMapping(Struct, frozen=True):
|
|
|
232
513
|
"""Converts deserialized class to pysdmx model class."""
|
|
233
514
|
return ToVtlMapping(self.toVtlSubSpace, self.type)
|
|
234
515
|
|
|
516
|
+
@classmethod
|
|
517
|
+
def from_model(cls, mapping: ToVtlMapping) -> "JsonToVtlMapping":
|
|
518
|
+
"""Converts a pysdmx "to VTL" mapping to an SDMX-JSON one."""
|
|
519
|
+
return JsonToVtlMapping(mapping.to_vtl_sub_space, mapping.method)
|
|
520
|
+
|
|
235
521
|
|
|
236
|
-
class JsonFromVtlMapping(Struct, frozen=True):
|
|
522
|
+
class JsonFromVtlMapping(Struct, frozen=True, omit_defaults=True):
|
|
237
523
|
"""SDMX-JSON payload for from VTL mappings."""
|
|
238
524
|
|
|
239
525
|
fromVtlSuperSpace: Sequence[str]
|
|
@@ -243,8 +529,13 @@ class JsonFromVtlMapping(Struct, frozen=True):
|
|
|
243
529
|
"""Converts deserialized class to pysdmx model class."""
|
|
244
530
|
return FromVtlMapping(self.fromVtlSuperSpace, self.type)
|
|
245
531
|
|
|
532
|
+
@classmethod
|
|
533
|
+
def from_model(cls, mapping: FromVtlMapping) -> "JsonFromVtlMapping":
|
|
534
|
+
"""Converts a pysdmx "from VTL" mapping to an SDMX-JSON one."""
|
|
535
|
+
return JsonFromVtlMapping(mapping.from_vtl_sub_space, mapping.method)
|
|
246
536
|
|
|
247
|
-
|
|
537
|
+
|
|
538
|
+
class JsonVtlMapping(NameableType, frozen=True, omit_defaults=True):
|
|
248
539
|
"""SDMX-JSON payload for VTL mappings."""
|
|
249
540
|
|
|
250
541
|
alias: str = ""
|
|
@@ -301,8 +592,107 @@ class JsonVtlMapping(NameableType, frozen=True):
|
|
|
301
592
|
annotations=[a.to_model() for a in self.annotations],
|
|
302
593
|
)
|
|
303
594
|
|
|
595
|
+
@classmethod
|
|
596
|
+
def from_model(cls, mapping: VtlMapping) -> "JsonVtlMapping":
|
|
597
|
+
"""Converts a pysdmx VTL mapping to an SDMX-JSON one."""
|
|
598
|
+
if not mapping.name:
|
|
599
|
+
raise errors.Invalid(
|
|
600
|
+
"Invalid input",
|
|
601
|
+
"SDMX-JSON VTL mappings must have a name",
|
|
602
|
+
{"vtl_mapping": mapping.id},
|
|
603
|
+
)
|
|
304
604
|
|
|
305
|
-
|
|
605
|
+
if isinstance(mapping, VtlCodelistMapping):
|
|
606
|
+
# Convert codelist to URN string
|
|
607
|
+
if not isinstance(mapping.codelist, str):
|
|
608
|
+
# Handle both Codelist objects and References
|
|
609
|
+
agency = (
|
|
610
|
+
mapping.codelist.agency.id
|
|
611
|
+
if hasattr(mapping.codelist.agency, "id")
|
|
612
|
+
else mapping.codelist.agency
|
|
613
|
+
)
|
|
614
|
+
codelist_ref = (
|
|
615
|
+
f"urn:sdmx:org.sdmx.infomodel.codelist.Codelist="
|
|
616
|
+
f"{agency}:{mapping.codelist.id}({mapping.codelist.version})"
|
|
617
|
+
)
|
|
618
|
+
else:
|
|
619
|
+
codelist_ref = mapping.codelist
|
|
620
|
+
|
|
621
|
+
return JsonVtlMapping(
|
|
622
|
+
id=mapping.id,
|
|
623
|
+
name=mapping.name,
|
|
624
|
+
description=mapping.description,
|
|
625
|
+
annotations=tuple(
|
|
626
|
+
[JsonAnnotation.from_model(a) for a in mapping.annotations]
|
|
627
|
+
),
|
|
628
|
+
alias=mapping.codelist_alias,
|
|
629
|
+
codelist=codelist_ref,
|
|
630
|
+
)
|
|
631
|
+
elif isinstance(mapping, VtlConceptMapping):
|
|
632
|
+
# Convert concept to URN string
|
|
633
|
+
if isinstance(mapping.concept, str):
|
|
634
|
+
concept_ref = mapping.concept
|
|
635
|
+
elif isinstance(mapping.concept, ItemReference):
|
|
636
|
+
concept_ref = (
|
|
637
|
+
"urn:sdmx:org.sdmx.infomodel.conceptscheme."
|
|
638
|
+
f"{mapping.concept.sdmx_type}={mapping.concept.agency}:"
|
|
639
|
+
f"{mapping.concept.id}({mapping.concept.version})."
|
|
640
|
+
f"{mapping.concept.item_id}"
|
|
641
|
+
)
|
|
642
|
+
elif mapping.concept.urn:
|
|
643
|
+
concept_ref = mapping.concept.urn
|
|
644
|
+
else:
|
|
645
|
+
raise errors.Invalid(
|
|
646
|
+
"Missing concept reference",
|
|
647
|
+
(
|
|
648
|
+
"The full reference to the concept is missing but "
|
|
649
|
+
"this is mandatory in a VtlConceptMapping"
|
|
650
|
+
),
|
|
651
|
+
{"referenced_concept": mapping.concept},
|
|
652
|
+
)
|
|
653
|
+
|
|
654
|
+
return JsonVtlMapping(
|
|
655
|
+
id=mapping.id,
|
|
656
|
+
name=mapping.name,
|
|
657
|
+
description=mapping.description,
|
|
658
|
+
annotations=tuple(
|
|
659
|
+
[JsonAnnotation.from_model(a) for a in mapping.annotations]
|
|
660
|
+
),
|
|
661
|
+
alias=mapping.concept_alias,
|
|
662
|
+
concept=concept_ref,
|
|
663
|
+
)
|
|
664
|
+
elif isinstance(mapping, VtlDataflowMapping):
|
|
665
|
+
return JsonVtlMapping(
|
|
666
|
+
id=mapping.id,
|
|
667
|
+
name=mapping.name,
|
|
668
|
+
description=mapping.description,
|
|
669
|
+
annotations=tuple(
|
|
670
|
+
[JsonAnnotation.from_model(a) for a in mapping.annotations]
|
|
671
|
+
),
|
|
672
|
+
alias=mapping.dataflow_alias,
|
|
673
|
+
dataflow=f"urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow={mapping.dataflow.agency}:{mapping.dataflow.id}({mapping.dataflow.version})",
|
|
674
|
+
toVtlMapping=(
|
|
675
|
+
JsonToVtlMapping.from_model(mapping.to_vtl_mapping_method)
|
|
676
|
+
if mapping.to_vtl_mapping_method
|
|
677
|
+
else None
|
|
678
|
+
),
|
|
679
|
+
fromVtlMapping=(
|
|
680
|
+
JsonFromVtlMapping.from_model(
|
|
681
|
+
mapping.from_vtl_mapping_method
|
|
682
|
+
)
|
|
683
|
+
if mapping.from_vtl_mapping_method
|
|
684
|
+
else None
|
|
685
|
+
),
|
|
686
|
+
)
|
|
687
|
+
else:
|
|
688
|
+
raise errors.Invalid(
|
|
689
|
+
"Invalid input",
|
|
690
|
+
f"Unsupported VTL mapping type: {type(mapping)}",
|
|
691
|
+
{"vtl_mapping": mapping.id},
|
|
692
|
+
)
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
class JsonVtlMappingScheme(ItemSchemeType, frozen=True, omit_defaults=True):
|
|
306
696
|
"""SDMX-JSON payload for VTL mapping schemes."""
|
|
307
697
|
|
|
308
698
|
vtlMappings: Sequence[JsonVtlMapping] = ()
|
|
@@ -325,8 +715,40 @@ class JsonVtlMappingScheme(ItemSchemeType, frozen=True):
|
|
|
325
715
|
annotations=[a.to_model() for a in self.annotations],
|
|
326
716
|
)
|
|
327
717
|
|
|
718
|
+
@classmethod
|
|
719
|
+
def from_model(cls, vms: VtlMappingScheme) -> "JsonVtlMappingScheme":
|
|
720
|
+
"""Converts a pysdmx VTL mapping scheme to an SDMX-JSON one."""
|
|
721
|
+
if not vms.name:
|
|
722
|
+
raise errors.Invalid(
|
|
723
|
+
"Invalid input",
|
|
724
|
+
"SDMX-JSON VTL mapping schemes must have a name",
|
|
725
|
+
{"vtl_mapping_scheme": vms.id},
|
|
726
|
+
)
|
|
727
|
+
return JsonVtlMappingScheme(
|
|
728
|
+
agency=(
|
|
729
|
+
vms.agency.id if isinstance(vms.agency, Agency) else vms.agency
|
|
730
|
+
),
|
|
731
|
+
id=vms.id,
|
|
732
|
+
name=vms.name,
|
|
733
|
+
version=vms.version,
|
|
734
|
+
isExternalReference=vms.is_external_reference,
|
|
735
|
+
validFrom=vms.valid_from,
|
|
736
|
+
validTo=vms.valid_to,
|
|
737
|
+
description=vms.description,
|
|
738
|
+
annotations=tuple(
|
|
739
|
+
[JsonAnnotation.from_model(a) for a in vms.annotations]
|
|
740
|
+
),
|
|
741
|
+
isPartial=vms.is_partial,
|
|
742
|
+
vtlMappings=tuple(
|
|
743
|
+
[
|
|
744
|
+
JsonVtlMapping.from_model(i) # type: ignore[arg-type]
|
|
745
|
+
for i in vms.items
|
|
746
|
+
]
|
|
747
|
+
),
|
|
748
|
+
)
|
|
328
749
|
|
|
329
|
-
|
|
750
|
+
|
|
751
|
+
class JsonTransformation(Struct, frozen=True, omit_defaults=True):
|
|
330
752
|
"""SDMX-JSON payload for VTL transformations."""
|
|
331
753
|
|
|
332
754
|
id: str
|
|
@@ -349,8 +771,36 @@ class JsonTransformation(Struct, frozen=True):
|
|
|
349
771
|
annotations=[a.to_model() for a in self.annotations],
|
|
350
772
|
)
|
|
351
773
|
|
|
774
|
+
@classmethod
|
|
775
|
+
def from_model(
|
|
776
|
+
cls, transformation: Transformation
|
|
777
|
+
) -> "JsonTransformation":
|
|
778
|
+
"""Converts a pysdmx transformation to an SDMX-JSON one."""
|
|
779
|
+
if not transformation.name:
|
|
780
|
+
raise errors.Invalid(
|
|
781
|
+
"Invalid input",
|
|
782
|
+
"SDMX-JSON transformations must have a name",
|
|
783
|
+
{"transformation": transformation.id},
|
|
784
|
+
)
|
|
785
|
+
return JsonTransformation(
|
|
786
|
+
id=transformation.id,
|
|
787
|
+
name=transformation.name,
|
|
788
|
+
expression=transformation.expression,
|
|
789
|
+
result=transformation.result,
|
|
790
|
+
isPersistent=transformation.is_persistent,
|
|
791
|
+
description=transformation.description,
|
|
792
|
+
annotations=tuple(
|
|
793
|
+
[
|
|
794
|
+
JsonAnnotation.from_model(a)
|
|
795
|
+
for a in transformation.annotations
|
|
796
|
+
]
|
|
797
|
+
),
|
|
798
|
+
)
|
|
799
|
+
|
|
352
800
|
|
|
353
|
-
class JsonTransformationScheme(
|
|
801
|
+
class JsonTransformationScheme(
|
|
802
|
+
ItemSchemeType, frozen=True, omit_defaults=True
|
|
803
|
+
):
|
|
354
804
|
"""SDMX-JSON payload for VTL transformation schemes."""
|
|
355
805
|
|
|
356
806
|
vtlVersion: str = ""
|
|
@@ -396,8 +846,88 @@ class JsonTransformationScheme(ItemSchemeType, frozen=True):
|
|
|
396
846
|
annotations=[a.to_model() for a in self.annotations],
|
|
397
847
|
)
|
|
398
848
|
|
|
849
|
+
@classmethod
|
|
850
|
+
def from_model(
|
|
851
|
+
cls, ts: TransformationScheme
|
|
852
|
+
) -> "JsonTransformationScheme":
|
|
853
|
+
"""Converts a pysdmx transformation scheme to an SDMX-JSON one."""
|
|
854
|
+
if not ts.name:
|
|
855
|
+
raise errors.Invalid(
|
|
856
|
+
"Invalid input",
|
|
857
|
+
"SDMX-JSON transformation schemes must have a name",
|
|
858
|
+
{"transformation_scheme": ts.id},
|
|
859
|
+
)
|
|
860
|
+
|
|
861
|
+
# Convert scheme references to strings
|
|
862
|
+
mapping_ref = None
|
|
863
|
+
if ts.vtl_mapping_scheme:
|
|
864
|
+
mapping_ref = (
|
|
865
|
+
f"urn:sdmx:org.sdmx.infomodel.transformation.VtlMappingScheme="
|
|
866
|
+
f"{ts.vtl_mapping_scheme.agency}:{ts.vtl_mapping_scheme.id}"
|
|
867
|
+
f"({ts.vtl_mapping_scheme.version})"
|
|
868
|
+
)
|
|
869
|
+
|
|
870
|
+
np_ref = None
|
|
871
|
+
if ts.name_personalisation_scheme:
|
|
872
|
+
np_ref = (
|
|
873
|
+
f"urn:sdmx:org.sdmx.infomodel.transformation.NamePersonalisationScheme="
|
|
874
|
+
f"{ts.name_personalisation_scheme.agency}:"
|
|
875
|
+
f"{ts.name_personalisation_scheme.id}"
|
|
876
|
+
f"({ts.name_personalisation_scheme.version})"
|
|
877
|
+
)
|
|
878
|
+
|
|
879
|
+
ct_ref = None
|
|
880
|
+
if ts.custom_type_scheme:
|
|
881
|
+
ct_ref = (
|
|
882
|
+
f"urn:sdmx:org.sdmx.infomodel.transformation.CustomTypeScheme="
|
|
883
|
+
f"{ts.custom_type_scheme.agency}:{ts.custom_type_scheme.id}"
|
|
884
|
+
f"({ts.custom_type_scheme.version})"
|
|
885
|
+
)
|
|
886
|
+
|
|
887
|
+
rs_refs = tuple(
|
|
888
|
+
[
|
|
889
|
+
f"urn:sdmx:org.sdmx.infomodel.transformation.RulesetScheme="
|
|
890
|
+
f"{rs.agency}:{rs.id}({rs.version})"
|
|
891
|
+
for rs in ts.ruleset_schemes
|
|
892
|
+
]
|
|
893
|
+
)
|
|
894
|
+
|
|
895
|
+
udo_refs = tuple(
|
|
896
|
+
[
|
|
897
|
+
f"urn:sdmx:org.sdmx.infomodel.transformation.UserDefinedOperatorScheme="
|
|
898
|
+
f"{udos.agency}:{udos.id}({udos.version})"
|
|
899
|
+
for udos in ts.user_defined_operator_schemes
|
|
900
|
+
]
|
|
901
|
+
)
|
|
902
|
+
|
|
903
|
+
return JsonTransformationScheme(
|
|
904
|
+
agency=(
|
|
905
|
+
ts.agency.id if isinstance(ts.agency, Agency) else ts.agency
|
|
906
|
+
),
|
|
907
|
+
id=ts.id,
|
|
908
|
+
name=ts.name,
|
|
909
|
+
version=ts.version,
|
|
910
|
+
isExternalReference=ts.is_external_reference,
|
|
911
|
+
validFrom=ts.valid_from,
|
|
912
|
+
validTo=ts.valid_to,
|
|
913
|
+
description=ts.description,
|
|
914
|
+
annotations=tuple(
|
|
915
|
+
[JsonAnnotation.from_model(a) for a in ts.annotations]
|
|
916
|
+
),
|
|
917
|
+
isPartial=ts.is_partial,
|
|
918
|
+
vtlVersion=ts.vtl_version, # type: ignore[arg-type]
|
|
919
|
+
vtlMappingScheme=mapping_ref,
|
|
920
|
+
namePersonalisationScheme=np_ref,
|
|
921
|
+
customTypeScheme=ct_ref,
|
|
922
|
+
rulesetSchemes=rs_refs,
|
|
923
|
+
userDefinedOperatorSchemes=udo_refs,
|
|
924
|
+
transformations=tuple(
|
|
925
|
+
[JsonTransformation.from_model(i) for i in ts.items]
|
|
926
|
+
),
|
|
927
|
+
)
|
|
928
|
+
|
|
399
929
|
|
|
400
|
-
class JsonVtlTransformations(Struct, frozen=True):
|
|
930
|
+
class JsonVtlTransformations(Struct, frozen=True, omit_defaults=True):
|
|
401
931
|
"""SDMX-JSON payload for VTL transformation schemes."""
|
|
402
932
|
|
|
403
933
|
transformationSchemes: Sequence[JsonTransformationScheme]
|
|
@@ -418,7 +948,7 @@ class JsonVtlTransformations(Struct, frozen=True):
|
|
|
418
948
|
)
|
|
419
949
|
|
|
420
950
|
|
|
421
|
-
class JsonVtlTransformationsMessage(Struct, frozen=True):
|
|
951
|
+
class JsonVtlTransformationsMessage(Struct, frozen=True, omit_defaults=True):
|
|
422
952
|
"""SDMX-JSON payload for /transformationscheme queries."""
|
|
423
953
|
|
|
424
954
|
data: JsonVtlTransformations
|