pysdmx 1.6.0__py3-none-any.whl → 1.8.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 +266 -0
- pysdmx/api/qb/refmeta.py +1 -1
- pysdmx/api/qb/schema.py +4 -10
- pysdmx/api/qb/service.py +26 -4
- pysdmx/api/qb/structure.py +2 -2
- pysdmx/io/input_processor.py +4 -4
- pysdmx/io/json/fusion/messages/__init__.py +14 -0
- pysdmx/io/json/fusion/messages/concept.py +2 -8
- pysdmx/io/json/fusion/messages/dsd.py +52 -1
- pysdmx/io/json/fusion/messages/metadataflow.py +44 -0
- pysdmx/io/json/fusion/messages/mpa.py +45 -0
- pysdmx/io/json/fusion/messages/msd.py +121 -0
- pysdmx/io/json/fusion/messages/org.py +90 -0
- pysdmx/io/json/fusion/reader/__init__.py +5 -0
- pysdmx/io/json/sdmxjson2/messages/__init__.py +15 -1
- pysdmx/io/json/sdmxjson2/messages/code.py +35 -13
- pysdmx/io/json/sdmxjson2/messages/concept.py +5 -8
- pysdmx/io/json/sdmxjson2/messages/dsd.py +9 -6
- pysdmx/io/json/sdmxjson2/messages/metadataflow.py +88 -0
- pysdmx/io/json/sdmxjson2/messages/mpa.py +88 -0
- pysdmx/io/json/sdmxjson2/messages/msd.py +241 -0
- pysdmx/io/json/sdmxjson2/messages/provider.py +117 -1
- pysdmx/io/json/sdmxjson2/messages/structure.py +25 -1
- pysdmx/io/json/sdmxjson2/reader/__init__.py +5 -0
- pysdmx/io/serde.py +5 -0
- pysdmx/io/writer.py +2 -4
- 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 +6 -4
- pysdmx/io/xml/__write_data_aux.py +6 -5
- pysdmx/io/xml/__write_structure_specific_aux.py +6 -2
- pysdmx/io/xml/doc_validation.py +1 -3
- pysdmx/io/xml/sdmx21/writer/generic.py +5 -3
- pysdmx/model/__init__.py +13 -4
- pysdmx/model/dataflow.py +1 -0
- pysdmx/model/map.py +6 -6
- pysdmx/model/message.py +30 -6
- pysdmx/model/metadata.py +255 -4
- pysdmx/toolkit/pd/_data_utils.py +3 -4
- {pysdmx-1.6.0.dist-info → pysdmx-1.8.0.dist-info}/METADATA +2 -2
- {pysdmx-1.6.0.dist-info → pysdmx-1.8.0.dist-info}/RECORD +44 -38
- {pysdmx-1.6.0.dist-info → pysdmx-1.8.0.dist-info}/WHEEL +0 -0
- {pysdmx-1.6.0.dist-info → pysdmx-1.8.0.dist-info}/licenses/LICENSE +0 -0
pysdmx/io/xml/doc_validation.py
CHANGED
|
@@ -39,9 +39,7 @@ def validate_doc(input_str: str) -> None:
|
|
|
39
39
|
doc = etree.parse(bytes_infile, parser=parser)
|
|
40
40
|
if not xmlschema.validate(doc):
|
|
41
41
|
log_errors = list(xmlschema.error_log) # type: ignore[call-overload]
|
|
42
|
-
unhandled_errors = []
|
|
43
|
-
for e in log_errors:
|
|
44
|
-
unhandled_errors.append(e.message)
|
|
42
|
+
unhandled_errors = [e.message for e in log_errors]
|
|
45
43
|
severe_errors = unhandled_errors.copy()
|
|
46
44
|
for e in unhandled_errors:
|
|
47
45
|
for allowed_error in ALLOWED_ERRORS_CONTENT:
|
|
@@ -327,10 +327,12 @@ def __group_processing(
|
|
|
327
327
|
.to_dict(orient="records")
|
|
328
328
|
)
|
|
329
329
|
|
|
330
|
-
|
|
331
|
-
|
|
330
|
+
out_list.extend(
|
|
331
|
+
[
|
|
332
332
|
__format_group_str(record, group_id, dimensions, attribute)
|
|
333
|
-
|
|
333
|
+
for record in grouped_data
|
|
334
|
+
]
|
|
335
|
+
)
|
|
334
336
|
|
|
335
337
|
return "".join(out_list)
|
|
336
338
|
|
pysdmx/model/__init__.py
CHANGED
|
@@ -53,7 +53,14 @@ from pysdmx.model.map import (
|
|
|
53
53
|
StructureMap,
|
|
54
54
|
ValueMap,
|
|
55
55
|
)
|
|
56
|
-
from pysdmx.model.metadata import
|
|
56
|
+
from pysdmx.model.metadata import (
|
|
57
|
+
MetadataAttribute,
|
|
58
|
+
MetadataComponent,
|
|
59
|
+
Metadataflow,
|
|
60
|
+
MetadataProvisionAgreement,
|
|
61
|
+
MetadataReport,
|
|
62
|
+
MetadataStructure,
|
|
63
|
+
)
|
|
57
64
|
from pysdmx.model.organisation import (
|
|
58
65
|
AgencyScheme,
|
|
59
66
|
DataConsumerScheme,
|
|
@@ -131,9 +138,7 @@ def decoders(type: Type, obj: Any) -> Any: # type: ignore[type-arg]
|
|
|
131
138
|
target types
|
|
132
139
|
"""
|
|
133
140
|
if type is Components:
|
|
134
|
-
comps = []
|
|
135
|
-
for item in obj:
|
|
136
|
-
comps.append(msgspec.convert(item, Component))
|
|
141
|
+
comps = [msgspec.convert(item, Component) for item in obj]
|
|
137
142
|
return Components(comps)
|
|
138
143
|
else:
|
|
139
144
|
raise NotImplementedError(f"Objects of type {type} are not supported")
|
|
@@ -176,9 +181,13 @@ __all__ = [
|
|
|
176
181
|
"ImplicitComponentMap",
|
|
177
182
|
"ItemReference",
|
|
178
183
|
"MetadataAttribute",
|
|
184
|
+
"MetadataComponent",
|
|
185
|
+
"Metadataflow",
|
|
179
186
|
"MetadataProvider",
|
|
180
187
|
"MetadataProviderScheme",
|
|
188
|
+
"MetadataProvisionAgreement",
|
|
181
189
|
"MetadataReport",
|
|
190
|
+
"MetadataStructure",
|
|
182
191
|
"MultiComponentMap",
|
|
183
192
|
"MultiRepresentationMap",
|
|
184
193
|
"MultiValueMap",
|
pysdmx/model/dataflow.py
CHANGED
|
@@ -116,6 +116,7 @@ class Component(
|
|
|
116
116
|
id: A unique identifier for the component (e.g. FREQ).
|
|
117
117
|
required: Whether the component must have a value.
|
|
118
118
|
role: The role played by the component.
|
|
119
|
+
concept: The concept giving its identity to the component.
|
|
119
120
|
local_dtype: The component's local data type (string, number, etc.).
|
|
120
121
|
local_facets: Additional local details such as the component's minimum
|
|
121
122
|
length.
|
pysdmx/model/map.py
CHANGED
|
@@ -500,12 +500,12 @@ class StructureMap(MaintainableArtefact, frozen=True, omit_defaults=True):
|
|
|
500
500
|
]
|
|
501
501
|
]:
|
|
502
502
|
"""Return the mapping rules for the supplied component."""
|
|
503
|
-
out = [
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
503
|
+
out = [
|
|
504
|
+
m
|
|
505
|
+
for m in self.maps
|
|
506
|
+
if (hasattr(m, "source") and (m.source == id_ or id_ in m.source))
|
|
507
|
+
or (isinstance(m, FixedValueMap) and m.target == id_)
|
|
508
|
+
]
|
|
509
509
|
if len(out) == 0:
|
|
510
510
|
return None
|
|
511
511
|
else:
|
pysdmx/model/message.py
CHANGED
|
@@ -34,8 +34,17 @@ from pysdmx.model.map import (
|
|
|
34
34
|
RepresentationMap,
|
|
35
35
|
StructureMap,
|
|
36
36
|
)
|
|
37
|
-
from pysdmx.model.metadata import
|
|
38
|
-
|
|
37
|
+
from pysdmx.model.metadata import (
|
|
38
|
+
Metadataflow,
|
|
39
|
+
MetadataProvisionAgreement,
|
|
40
|
+
MetadataReport,
|
|
41
|
+
MetadataStructure,
|
|
42
|
+
)
|
|
43
|
+
from pysdmx.model.organisation import (
|
|
44
|
+
AgencyScheme,
|
|
45
|
+
DataProviderScheme,
|
|
46
|
+
MetadataProviderScheme,
|
|
47
|
+
)
|
|
39
48
|
from pysdmx.model.submission import SubmissionResult
|
|
40
49
|
from pysdmx.model.vtl import (
|
|
41
50
|
CustomTypeScheme,
|
|
@@ -168,10 +177,7 @@ class StructureMessage(Struct, repr_omit_defaults=True, frozen=True):
|
|
|
168
177
|
raise NotFound(
|
|
169
178
|
f"No {type_.__name__} found in message.",
|
|
170
179
|
)
|
|
171
|
-
structures = []
|
|
172
|
-
for element in self.structures:
|
|
173
|
-
if isinstance(element, type_):
|
|
174
|
-
structures.append(element)
|
|
180
|
+
structures = [e for e in self.structures if isinstance(e, type_)]
|
|
175
181
|
return structures
|
|
176
182
|
|
|
177
183
|
def __get_enumerations(
|
|
@@ -224,6 +230,10 @@ class StructureMessage(Struct, repr_omit_defaults=True, frozen=True):
|
|
|
224
230
|
"""Returns the Dataflows."""
|
|
225
231
|
return self.__get_elements(Dataflow)
|
|
226
232
|
|
|
233
|
+
def get_metadataflows(self) -> List[Metadataflow]:
|
|
234
|
+
"""Returns the MetadataProvisionAgreements."""
|
|
235
|
+
return self.__get_elements(Metadataflow)
|
|
236
|
+
|
|
227
237
|
def get_organisation_scheme(self, short_urn: str) -> AgencyScheme:
|
|
228
238
|
"""Returns a specific OrganisationScheme."""
|
|
229
239
|
return self.__get_single_structure(AgencyScheme, short_urn)
|
|
@@ -284,6 +294,20 @@ class StructureMessage(Struct, repr_omit_defaults=True, frozen=True):
|
|
|
284
294
|
"""Returns the ProvisionAgreements."""
|
|
285
295
|
return self.__get_elements(ProvisionAgreement)
|
|
286
296
|
|
|
297
|
+
def get_metadata_provider_schemes(self) -> List[MetadataProviderScheme]:
|
|
298
|
+
"""Returns the MetadataProviderSchemes."""
|
|
299
|
+
return self.__get_elements(MetadataProviderScheme)
|
|
300
|
+
|
|
301
|
+
def get_metadata_provision_agreements(
|
|
302
|
+
self,
|
|
303
|
+
) -> List[MetadataProvisionAgreement]:
|
|
304
|
+
"""Returns the MetadataProvisionAgreements."""
|
|
305
|
+
return self.__get_elements(MetadataProvisionAgreement)
|
|
306
|
+
|
|
307
|
+
def get_metadata_structures(self) -> List[MetadataStructure]:
|
|
308
|
+
"""Returns the MetadataStructures."""
|
|
309
|
+
return self.__get_elements(MetadataStructure)
|
|
310
|
+
|
|
287
311
|
def get_structure_maps(self) -> List[StructureMap]:
|
|
288
312
|
"""Returns the StructureMaps."""
|
|
289
313
|
return self.__get_elements(StructureMap)
|
pysdmx/model/metadata.py
CHANGED
|
@@ -9,21 +9,272 @@ example by providing configuration details in a metadata report.
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
from collections import defaultdict
|
|
12
|
-
from typing import Any, Dict, Iterator, List, Optional, Sequence
|
|
12
|
+
from typing import Any, Dict, Iterator, List, Optional, Sequence, Union
|
|
13
13
|
|
|
14
14
|
from msgspec import Struct
|
|
15
15
|
|
|
16
|
-
from pysdmx.model.__base import
|
|
17
|
-
|
|
16
|
+
from pysdmx.model.__base import (
|
|
17
|
+
Annotation,
|
|
18
|
+
IdentifiableArtefact,
|
|
19
|
+
ItemReference,
|
|
20
|
+
MaintainableArtefact,
|
|
21
|
+
Reference,
|
|
22
|
+
)
|
|
23
|
+
from pysdmx.model.code import Codelist, Hierarchy
|
|
24
|
+
from pysdmx.model.concept import Concept, DataType, Facets
|
|
25
|
+
from pysdmx.model.dataflow import ArrayBoundaries
|
|
18
26
|
from pysdmx.model.dataset import ActionType
|
|
19
27
|
|
|
20
28
|
|
|
29
|
+
class MetadataComponent(
|
|
30
|
+
IdentifiableArtefact, frozen=True, omit_defaults=True, kw_only=True
|
|
31
|
+
):
|
|
32
|
+
"""A component defines the expected structure of a metadata attribute.
|
|
33
|
+
|
|
34
|
+
The metadata component takes its semantic, and in some cases it
|
|
35
|
+
representation, from its concept identity. A metadata component
|
|
36
|
+
may be coded (via the local representation), uncoded (via the text
|
|
37
|
+
format), or take no value. In addition to this value, the metadata
|
|
38
|
+
component may also specify subordinate metadata components.
|
|
39
|
+
|
|
40
|
+
If a metadata component only serves the purpose of containing
|
|
41
|
+
subordinate metadata components, then the is_presentational attribute
|
|
42
|
+
should be set to True. Otherwise, it is assumed to also take a value.
|
|
43
|
+
|
|
44
|
+
If the metadata component does take a value, and a representation is
|
|
45
|
+
not defined, it will be inherited from the concept it takes its
|
|
46
|
+
semantic from. The optional id on the metadata component uniquely
|
|
47
|
+
identifies it within the metadata structured definition.
|
|
48
|
+
|
|
49
|
+
If this id is not supplied, its value is assumed to be that of the
|
|
50
|
+
concept referenced from the concept identity. Note that a metadata
|
|
51
|
+
component (as identified by the id attribute) definition must be
|
|
52
|
+
unique across the entire metadata structure definition.
|
|
53
|
+
|
|
54
|
+
Attributes:
|
|
55
|
+
id: The identifier of the component.
|
|
56
|
+
is_presentational: Whether the component is for presentation
|
|
57
|
+
purposes only (e.g. a section header), or may contain a
|
|
58
|
+
value.
|
|
59
|
+
concept: The concept giving its identity to the component.
|
|
60
|
+
local_dtype: The component's local data type (string, number, etc.).
|
|
61
|
+
local_facets: Additional local details such as the component's minimum
|
|
62
|
+
length.
|
|
63
|
+
local_codes: The expected local values for the component (e.g. currency
|
|
64
|
+
codes).
|
|
65
|
+
array_def: Any additional constraints for array types.
|
|
66
|
+
local_enum_ref: The URN of the enumeration (codelist or valuelist) from
|
|
67
|
+
which the local codes are taken.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
is_presentational: bool = False
|
|
71
|
+
concept: Union[Concept, ItemReference]
|
|
72
|
+
local_dtype: Optional[DataType] = None
|
|
73
|
+
local_facets: Optional[Facets] = None
|
|
74
|
+
local_codes: Union[Codelist, Hierarchy, None] = None
|
|
75
|
+
array_def: Optional[ArrayBoundaries] = None
|
|
76
|
+
local_enum_ref: Optional[str] = None
|
|
77
|
+
components: Sequence["MetadataComponent"] = ()
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def dtype(self) -> DataType:
|
|
81
|
+
"""Returns the component data type.
|
|
82
|
+
|
|
83
|
+
This will return the local data type (if any) or
|
|
84
|
+
the data type of the referenced concept (if any).
|
|
85
|
+
In case neither are set, the data type will default
|
|
86
|
+
to string.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
The component data type (local, core or default).
|
|
90
|
+
"""
|
|
91
|
+
if self.local_dtype:
|
|
92
|
+
return self.local_dtype
|
|
93
|
+
elif isinstance(self.concept, Concept) and self.concept.dtype:
|
|
94
|
+
return self.concept.dtype
|
|
95
|
+
else:
|
|
96
|
+
return DataType.STRING
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def facets(self) -> Optional[Facets]:
|
|
100
|
+
"""Returns the component facets.
|
|
101
|
+
|
|
102
|
+
This will return the local facets (if any) or
|
|
103
|
+
the facets of the referenced concept (if any), or
|
|
104
|
+
None in case neither are set.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
The component facets (local or core).
|
|
108
|
+
"""
|
|
109
|
+
if self.local_facets:
|
|
110
|
+
return self.local_facets
|
|
111
|
+
elif isinstance(self.concept, Concept) and self.concept.facets:
|
|
112
|
+
return self.concept.facets
|
|
113
|
+
else:
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def enumeration(self) -> Union[Codelist, Hierarchy, None]:
|
|
118
|
+
"""Returns the list of valid codes for the component.
|
|
119
|
+
|
|
120
|
+
This will return the local codes (if any) or
|
|
121
|
+
the codes of the referenced concept (if any), or
|
|
122
|
+
None in case neither are set.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
The component codes (local or core).
|
|
126
|
+
"""
|
|
127
|
+
if self.local_codes:
|
|
128
|
+
return self.local_codes
|
|
129
|
+
elif isinstance(self.concept, Concept) and self.concept.codes:
|
|
130
|
+
return self.concept.codes
|
|
131
|
+
else:
|
|
132
|
+
return None
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def enum_ref(self) -> Optional[str]:
|
|
136
|
+
"""Returns the URN of the enumeration from which the codes are taken.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
The URN of the enumeration from which the codes are taken.
|
|
140
|
+
"""
|
|
141
|
+
if self.local_enum_ref:
|
|
142
|
+
return self.local_enum_ref
|
|
143
|
+
elif isinstance(self.concept, Concept) and self.concept.enum_ref:
|
|
144
|
+
return self.concept.enum_ref
|
|
145
|
+
else:
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
def __str__(self) -> str:
|
|
149
|
+
"""Custom string representation without the class name."""
|
|
150
|
+
processed_output = []
|
|
151
|
+
for attr, value, *_ in self.__rich_repr__(): # type: ignore[misc]
|
|
152
|
+
processed_output.append(f"{attr}: {value}")
|
|
153
|
+
return f"{', '.join(processed_output)}"
|
|
154
|
+
|
|
155
|
+
def __repr__(self) -> str:
|
|
156
|
+
"""Custom __repr__ that omits empty sequences."""
|
|
157
|
+
attrs = []
|
|
158
|
+
for attr, value, *_ in self.__rich_repr__(): # type: ignore[misc]
|
|
159
|
+
attrs.append(f"{attr}={repr(value)}")
|
|
160
|
+
return f"{self.__class__.__name__}({', '.join(attrs)})"
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class MetadataStructure(
|
|
164
|
+
MaintainableArtefact, frozen=True, omit_defaults=True, kw_only=True
|
|
165
|
+
):
|
|
166
|
+
"""A metadata structure definition, i.e. a collection of metadata concepts.
|
|
167
|
+
|
|
168
|
+
Attributes:
|
|
169
|
+
id: The identifier for the MSD.
|
|
170
|
+
name: The MSD name (e.g. "Frequency codelist").
|
|
171
|
+
agency: The maintainer of the MSD (e.g. SDMX).
|
|
172
|
+
description: Additional descriptive information about the MSD.
|
|
173
|
+
version: The MSD version (e.g. 1.0.1)
|
|
174
|
+
components: The MSD components, i.e. the collection of metadata
|
|
175
|
+
concepts.
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
components: Sequence[MetadataComponent] = ()
|
|
179
|
+
|
|
180
|
+
def __iter__(self) -> Iterator[MetadataComponent]:
|
|
181
|
+
"""Return an iterator over the list of components."""
|
|
182
|
+
yield from self.components
|
|
183
|
+
|
|
184
|
+
def __len__(self) -> int:
|
|
185
|
+
"""Return the number of components in the MSD."""
|
|
186
|
+
return self.__get_count(self.components)
|
|
187
|
+
|
|
188
|
+
def __getitem__(self, id_: str) -> Optional[MetadataComponent]:
|
|
189
|
+
"""Return the component identified by the given ID."""
|
|
190
|
+
return self.__extract_cat(self.components, id_)
|
|
191
|
+
|
|
192
|
+
def __contains__(self, id_: str) -> bool:
|
|
193
|
+
"""Whether there is a component with the supplied ID in the MSD."""
|
|
194
|
+
return bool(self.__getitem__(id_))
|
|
195
|
+
|
|
196
|
+
def __get_count(self, comps: Sequence[MetadataComponent]) -> int:
|
|
197
|
+
"""Return the number of components at any levels."""
|
|
198
|
+
count = len(comps)
|
|
199
|
+
for comp in comps:
|
|
200
|
+
if comp.components:
|
|
201
|
+
count += self.__get_count(comp.components)
|
|
202
|
+
return count
|
|
203
|
+
|
|
204
|
+
def __extract_cat(
|
|
205
|
+
self, comps: Sequence[MetadataComponent], id_: str
|
|
206
|
+
) -> Optional[MetadataComponent]:
|
|
207
|
+
if "." in id_:
|
|
208
|
+
ids = id_.split(".")
|
|
209
|
+
out = list(filter(lambda cat: cat.id == ids[0], comps))
|
|
210
|
+
if out:
|
|
211
|
+
pkey = ".".join(ids[1:])
|
|
212
|
+
return self.__extract_cat(out[0].components, pkey)
|
|
213
|
+
else:
|
|
214
|
+
out = list(filter(lambda cat: cat.id == id_, comps))
|
|
215
|
+
if out:
|
|
216
|
+
return out[0]
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
def __str__(self) -> str:
|
|
220
|
+
"""Custom string representation without the class name."""
|
|
221
|
+
processed_output = []
|
|
222
|
+
for attr, value, *_ in self.__rich_repr__(): # type: ignore[misc]
|
|
223
|
+
# str is taken as a Sequence, so we need to check it's not a str
|
|
224
|
+
if isinstance(value, Sequence) and not isinstance(value, str):
|
|
225
|
+
# Handle empty lists
|
|
226
|
+
if not value:
|
|
227
|
+
continue
|
|
228
|
+
class_name = value[0].__class__.__name__
|
|
229
|
+
class_name = (
|
|
230
|
+
class_name.lower() + "s"
|
|
231
|
+
if attr != "components"
|
|
232
|
+
else "components"
|
|
233
|
+
)
|
|
234
|
+
value = f"{len(value)} {class_name}"
|
|
235
|
+
|
|
236
|
+
processed_output.append(f"{attr}: {value}")
|
|
237
|
+
return f"{', '.join(processed_output)}"
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class Metadataflow(
|
|
241
|
+
MaintainableArtefact,
|
|
242
|
+
frozen=True,
|
|
243
|
+
omit_defaults=True,
|
|
244
|
+
tag=True,
|
|
245
|
+
kw_only=True,
|
|
246
|
+
):
|
|
247
|
+
"""A flow of reference metadata that metadata providers will provide.
|
|
248
|
+
|
|
249
|
+
Attributes:
|
|
250
|
+
structure: The MSD describing the structure of all reference
|
|
251
|
+
metadata reports for this metadataflow.
|
|
252
|
+
targets: Identifiable structures to which the reference metadata
|
|
253
|
+
reports described by the referenced MSD should be restricted to.
|
|
254
|
+
For example, to indicate that the reports can be related to
|
|
255
|
+
dataflows only, the following can be used:
|
|
256
|
+
urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=*:*(*)
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
structure: Optional[Union[MetadataStructure, str]]
|
|
260
|
+
targets: Union[Sequence[str], Sequence[Reference]]
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
class MetadataProvisionAgreement(
|
|
264
|
+
MaintainableArtefact, frozen=True, omit_defaults=True, kw_only=True
|
|
265
|
+
):
|
|
266
|
+
"""Link between a metadata provider and metadataflow."""
|
|
267
|
+
|
|
268
|
+
metadataflow: str
|
|
269
|
+
metadata_provider: str
|
|
270
|
+
|
|
271
|
+
|
|
21
272
|
class MetadataAttribute(
|
|
22
273
|
Struct, frozen=True, omit_defaults=True, repr_omit_defaults=True
|
|
23
274
|
):
|
|
24
275
|
"""An entry in a metadata report.
|
|
25
276
|
|
|
26
|
-
An
|
|
277
|
+
An component is iterable, as it may contain other attributes.
|
|
27
278
|
|
|
28
279
|
Attributes:
|
|
29
280
|
id: The identifier of the attribute (e.g. "License").
|
pysdmx/toolkit/pd/_data_utils.py
CHANGED
|
@@ -53,15 +53,14 @@ def get_codes(
|
|
|
53
53
|
dimension_code: str, structure: Schema, data: pd.DataFrame
|
|
54
54
|
) -> Tuple[List[str], List[str], List[Dict[str, Any]]]:
|
|
55
55
|
"""This function divides the components in Series and Obs."""
|
|
56
|
-
series_codes = []
|
|
57
56
|
groups = structure.groups
|
|
58
57
|
group_codes = []
|
|
59
58
|
obs_codes = [dimension_code, structure.components.measures[0].id]
|
|
60
59
|
|
|
61
60
|
# Getting the series and obs codes
|
|
62
|
-
|
|
63
|
-
if
|
|
64
|
-
|
|
61
|
+
series_codes = [
|
|
62
|
+
d.id for d in structure.components.dimensions if d.id != dimension_code
|
|
63
|
+
]
|
|
65
64
|
|
|
66
65
|
# Adding the attributes based on the attachment level
|
|
67
66
|
for att in structure.components.attributes:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pysdmx
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.0
|
|
4
4
|
Summary: Your opinionated Python SDMX library
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -18,7 +18,7 @@ Provides-Extra: data
|
|
|
18
18
|
Provides-Extra: dc
|
|
19
19
|
Provides-Extra: vtl
|
|
20
20
|
Provides-Extra: xml
|
|
21
|
-
Requires-Dist: httpx (>=0)
|
|
21
|
+
Requires-Dist: httpx[http2] (>=0)
|
|
22
22
|
Requires-Dist: lxml (>=5.2) ; extra == "all"
|
|
23
23
|
Requires-Dist: lxml (>=5.2) ; extra == "xml"
|
|
24
24
|
Requires-Dist: msgspec (>=0)
|