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.
Files changed (63) hide show
  1. pysdmx/__init__.py +1 -1
  2. pysdmx/api/fmr/__init__.py +8 -3
  3. pysdmx/api/fmr/maintenance.py +158 -0
  4. pysdmx/api/qb/structure.py +1 -0
  5. pysdmx/api/qb/util.py +1 -0
  6. pysdmx/io/csv/__csv_aux_reader.py +99 -0
  7. pysdmx/io/csv/__csv_aux_writer.py +118 -0
  8. pysdmx/io/csv/sdmx10/reader/__init__.py +9 -14
  9. pysdmx/io/csv/sdmx10/writer/__init__.py +28 -2
  10. pysdmx/io/csv/sdmx20/__init__.py +0 -9
  11. pysdmx/io/csv/sdmx20/reader/__init__.py +8 -61
  12. pysdmx/io/csv/sdmx20/writer/__init__.py +32 -25
  13. pysdmx/io/csv/sdmx21/__init__.py +1 -0
  14. pysdmx/io/csv/sdmx21/reader/__init__.py +86 -0
  15. pysdmx/io/csv/sdmx21/writer/__init__.py +70 -0
  16. pysdmx/io/format.py +8 -0
  17. pysdmx/io/input_processor.py +20 -6
  18. pysdmx/io/json/fusion/messages/code.py +21 -4
  19. pysdmx/io/json/fusion/messages/concept.py +10 -8
  20. pysdmx/io/json/fusion/messages/dataflow.py +8 -1
  21. pysdmx/io/json/fusion/messages/dsd.py +15 -0
  22. pysdmx/io/json/fusion/messages/schema.py +8 -1
  23. pysdmx/io/json/sdmxjson2/messages/agency.py +43 -7
  24. pysdmx/io/json/sdmxjson2/messages/category.py +92 -7
  25. pysdmx/io/json/sdmxjson2/messages/code.py +265 -22
  26. pysdmx/io/json/sdmxjson2/messages/concept.py +75 -13
  27. pysdmx/io/json/sdmxjson2/messages/constraint.py +5 -5
  28. pysdmx/io/json/sdmxjson2/messages/core.py +121 -14
  29. pysdmx/io/json/sdmxjson2/messages/dataflow.py +63 -8
  30. pysdmx/io/json/sdmxjson2/messages/dsd.py +215 -20
  31. pysdmx/io/json/sdmxjson2/messages/map.py +200 -24
  32. pysdmx/io/json/sdmxjson2/messages/pa.py +36 -5
  33. pysdmx/io/json/sdmxjson2/messages/provider.py +35 -7
  34. pysdmx/io/json/sdmxjson2/messages/report.py +85 -7
  35. pysdmx/io/json/sdmxjson2/messages/schema.py +11 -12
  36. pysdmx/io/json/sdmxjson2/messages/structure.py +150 -2
  37. pysdmx/io/json/sdmxjson2/messages/vtl.py +547 -17
  38. pysdmx/io/json/sdmxjson2/reader/metadata.py +32 -0
  39. pysdmx/io/json/sdmxjson2/reader/structure.py +32 -0
  40. pysdmx/io/json/sdmxjson2/writer/__init__.py +9 -0
  41. pysdmx/io/json/sdmxjson2/writer/metadata.py +60 -0
  42. pysdmx/io/json/sdmxjson2/writer/structure.py +61 -0
  43. pysdmx/io/reader.py +28 -9
  44. pysdmx/io/serde.py +17 -0
  45. pysdmx/io/writer.py +45 -9
  46. pysdmx/io/xml/__ss_aux_reader.py +1 -2
  47. pysdmx/io/xml/__structure_aux_reader.py +15 -10
  48. pysdmx/io/xml/__structure_aux_writer.py +15 -13
  49. pysdmx/io/xml/__write_data_aux.py +6 -57
  50. pysdmx/io/xml/__write_structure_specific_aux.py +7 -3
  51. pysdmx/io/xml/doc_validation.py +1 -3
  52. pysdmx/io/xml/sdmx21/writer/generic.py +6 -4
  53. pysdmx/model/__init__.py +1 -3
  54. pysdmx/model/code.py +11 -1
  55. pysdmx/model/dataflow.py +23 -0
  56. pysdmx/model/map.py +19 -13
  57. pysdmx/model/message.py +10 -5
  58. pysdmx/toolkit/pd/_data_utils.py +99 -0
  59. pysdmx/toolkit/vtl/_validations.py +2 -3
  60. {pysdmx-1.5.2.dist-info → pysdmx-1.7.0.dist-info}/METADATA +4 -3
  61. {pysdmx-1.5.2.dist-info → pysdmx-1.7.0.dist-info}/RECORD +63 -51
  62. {pysdmx-1.5.2.dist-info → pysdmx-1.7.0.dist-info}/WHEEL +1 -1
  63. {pysdmx-1.5.2.dist-info → pysdmx-1.7.0.dist-info/licenses}/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  """Collection of SDMX-JSON schemas for SDMX-REST schema queries."""
2
2
 
3
- from typing import Literal, Sequence
3
+ from typing import Literal, Optional, Sequence, Tuple
4
4
 
5
5
  import msgspec
6
6
 
@@ -10,13 +10,11 @@ from pysdmx.io.json.sdmxjson2.messages.constraint import JsonDataConstraint
10
10
  from pysdmx.io.json.sdmxjson2.messages.core import JsonHeader
11
11
  from pysdmx.io.json.sdmxjson2.messages.dsd import JsonDataStructure
12
12
  from pysdmx.model import Components, HierarchyAssociation, Schema
13
+ from pysdmx.model.dataflow import Group
13
14
  from pysdmx.util import parse_item_urn
14
15
 
15
16
 
16
- class JsonSchemas(
17
- msgspec.Struct,
18
- frozen=True,
19
- ):
17
+ class JsonSchemas(msgspec.Struct, frozen=True, omit_defaults=True):
20
18
  """SDMX-JSON payload schema structures."""
21
19
 
22
20
  conceptSchemes: Sequence[JsonConceptScheme]
@@ -25,21 +23,21 @@ class JsonSchemas(
25
23
  codelists: Sequence[JsonCodelist] = ()
26
24
  contentConstraints: Sequence[JsonDataConstraint] = ()
27
25
 
28
- def to_model(self) -> Components:
26
+ def to_model(
27
+ self,
28
+ ) -> Tuple[Components, Optional[Sequence[Group]]]:
29
29
  """Returns the requested schema."""
30
30
  comps = self.dataStructures[0].dataStructureComponents
31
- return comps.to_model( # type: ignore[union-attr]
31
+ comps, grps = comps.to_model( # type: ignore[union-attr,assignment]
32
32
  self.conceptSchemes,
33
33
  self.codelists,
34
34
  self.valuelists,
35
35
  self.contentConstraints,
36
36
  )
37
+ return comps, grps # type: ignore[return-value]
37
38
 
38
39
 
39
- class JsonSchemaMessage(
40
- msgspec.Struct,
41
- frozen=True,
42
- ):
40
+ class JsonSchemaMessage(msgspec.Struct, frozen=True, omit_defaults=True):
43
41
  """SDMX-JSON payload for /schema queries."""
44
42
 
45
43
  meta: JsonHeader
@@ -54,7 +52,7 @@ class JsonSchemaMessage(
54
52
  hierarchies: Sequence[HierarchyAssociation],
55
53
  ) -> Schema:
56
54
  """Returns the requested schema."""
57
- components = self.data.to_model()
55
+ components, groups = self.data.to_model()
58
56
  comp_dict = {c.id: c for c in components}
59
57
  urns = [a.urn for a in self.meta.links]
60
58
  for ha in hierarchies:
@@ -78,4 +76,5 @@ class JsonSchemaMessage(
78
76
  comps,
79
77
  version,
80
78
  urns, # type: ignore[arg-type]
79
+ groups=groups,
81
80
  )
@@ -4,6 +4,7 @@ from typing import Sequence
4
4
 
5
5
  from msgspec import Struct
6
6
 
7
+ from pysdmx import errors
7
8
  from pysdmx.io.json.sdmxjson2.messages.agency import JsonAgencyScheme
8
9
  from pysdmx.io.json.sdmxjson2.messages.category import (
9
10
  JsonCategorisation,
@@ -37,7 +38,7 @@ from pysdmx.model.__base import MaintainableArtefact
37
38
  from pysdmx.model.message import StructureMessage
38
39
 
39
40
 
40
- class JsonStructures(Struct, frozen=True):
41
+ class JsonStructures(Struct, frozen=True, omit_defaults=True):
41
42
  """The allowed strutures."""
42
43
 
43
44
  dataStructures: Sequence[JsonDataStructure] = ()
@@ -126,8 +127,144 @@ class JsonStructures(Struct, frozen=True):
126
127
  structures.append(rm.to_model(multi))
127
128
  return structures
128
129
 
130
+ @classmethod
131
+ def from_model(cls, msg: StructureMessage) -> "JsonStructures":
132
+ """Create an SDMX-JSON structures from a list of artefacts."""
133
+ if not msg.structures:
134
+ raise errors.Invalid(
135
+ "Invalid input",
136
+ "SDMX-JSON structure messages must have structures.",
137
+ )
138
+ codelists = tuple(
139
+ [JsonCodelist.from_model(c) for c in msg.get_codelists()]
140
+ )
141
+ valuelists = tuple(
142
+ [JsonValuelist.from_model(c) for c in msg.get_value_lists()]
143
+ )
144
+ agencies = tuple(
145
+ [JsonAgencyScheme.from_model(a) for a in msg.get_agency_schemes()]
146
+ )
147
+ dataflows = tuple(
148
+ [JsonDataflow.from_model(d) for d in msg.get_dataflows()]
149
+ )
150
+ agreements = tuple(
151
+ [
152
+ JsonProvisionAgreement.from_model(p)
153
+ for p in msg.get_provision_agreements()
154
+ ]
155
+ )
156
+ categorisations = tuple(
157
+ [
158
+ JsonCategorisation.from_model(c)
159
+ for c in msg.get_categorisations()
160
+ ]
161
+ )
162
+ hier_associations = tuple(
163
+ [
164
+ JsonHierarchyAssociation.from_model(ha)
165
+ for ha in msg.get_hierarchy_associations()
166
+ ]
167
+ )
168
+ category_schemes = tuple(
169
+ [
170
+ JsonCategoryScheme.from_model(cs)
171
+ for cs in msg.get_category_schemes()
172
+ ]
173
+ )
174
+ concept_schemes = tuple(
175
+ [
176
+ JsonConceptScheme.from_model(cs)
177
+ for cs in msg.get_concept_schemes()
178
+ ]
179
+ )
180
+ data_structures = tuple(
181
+ [
182
+ JsonDataStructure.from_model(ds)
183
+ for ds in msg.get_data_structure_definitions()
184
+ ]
185
+ )
186
+ data_providers = tuple(
187
+ [
188
+ JsonDataProviderScheme.from_model(dps)
189
+ for dps in msg.get_data_provider_schemes()
190
+ ]
191
+ )
192
+ representations_maps = tuple(
193
+ [
194
+ JsonRepresentationMap.from_model(rm)
195
+ for rm in msg.get_representation_maps()
196
+ ]
197
+ )
198
+ structure_maps = tuple(
199
+ [
200
+ JsonStructureMap.from_model(sm)
201
+ for sm in msg.get_structure_maps()
202
+ ]
203
+ )
204
+ custom_types = tuple(
205
+ [
206
+ JsonCustomTypeScheme.from_model(ct)
207
+ for ct in msg.get_custom_type_schemes()
208
+ ]
209
+ )
210
+ name_personalisations = tuple(
211
+ [
212
+ JsonNamePersonalisationScheme.from_model(np)
213
+ for np in msg.get_name_personalisation_schemes()
214
+ ]
215
+ )
216
+ user_operators = tuple(
217
+ [
218
+ JsonUserDefinedOperatorScheme.from_model(uo)
219
+ for uo in msg.get_user_defined_operator_schemes()
220
+ ]
221
+ )
222
+ rulesets = tuple(
223
+ [
224
+ JsonRulesetScheme.from_model(rs)
225
+ for rs in msg.get_ruleset_schemes()
226
+ ]
227
+ )
228
+ vtl_mappings = tuple(
229
+ [
230
+ JsonVtlMappingScheme.from_model(vm)
231
+ for vm in msg.get_vtl_mapping_schemes()
232
+ ]
233
+ )
234
+ transformations = tuple(
235
+ [
236
+ JsonTransformationScheme.from_model(ts)
237
+ for ts in msg.get_transformation_schemes()
238
+ ]
239
+ )
240
+ hierarchies = tuple(
241
+ [JsonHierarchy.from_model(h) for h in msg.get_hierarchies()]
242
+ )
243
+ return JsonStructures(
244
+ agencySchemes=agencies,
245
+ categorisations=categorisations,
246
+ categorySchemes=category_schemes,
247
+ codelists=codelists,
248
+ conceptSchemes=concept_schemes,
249
+ customTypeSchemes=custom_types,
250
+ dataflows=dataflows,
251
+ dataProviderSchemes=data_providers,
252
+ dataStructures=data_structures,
253
+ hierarchies=hierarchies,
254
+ hierarchyAssociations=hier_associations,
255
+ namePersonalisationSchemes=name_personalisations,
256
+ provisionAgreements=agreements,
257
+ representationMaps=representations_maps,
258
+ rulesetSchemes=rulesets,
259
+ structureMaps=structure_maps,
260
+ transformationSchemes=transformations,
261
+ userDefinedOperatorSchemes=user_operators,
262
+ valueLists=valuelists,
263
+ vtlMappingSchemes=vtl_mappings,
264
+ )
129
265
 
130
- class JsonStructureMessage(Struct, frozen=True):
266
+
267
+ class JsonStructureMessage(Struct, frozen=True, omit_defaults=True):
131
268
  """A generic SDMX-JSON 2.0 Structure message."""
132
269
 
133
270
  meta: JsonHeader
@@ -138,3 +275,14 @@ class JsonStructureMessage(Struct, frozen=True):
138
275
  header = self.meta.to_model()
139
276
  structures = self.data.to_model()
140
277
  return StructureMessage(header, structures)
278
+
279
+ @classmethod
280
+ def from_model(cls, message: StructureMessage) -> "JsonStructureMessage":
281
+ """Creates an SDMX-JSON payload from a pysdmx StructureMessage."""
282
+ if not message.header:
283
+ raise errors.Invalid(
284
+ "Invalid input", "SDMX-JSON messages must have a header."
285
+ )
286
+ header = JsonHeader.from_model(message.header)
287
+ structs = JsonStructures.from_model(message)
288
+ return JsonStructureMessage(header, structs)