pysdmx 1.3.0__py3-none-any.whl → 1.4.0rc1__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/__extras_check.py +3 -2
- pysdmx/__init__.py +1 -1
- pysdmx/api/fmr/__init__.py +4 -4
- pysdmx/api/gds/__init__.py +328 -0
- pysdmx/api/qb/gds.py +153 -0
- pysdmx/api/qb/service.py +91 -3
- pysdmx/api/qb/structure.py +1 -0
- pysdmx/api/qb/util.py +1 -0
- pysdmx/io/__init__.py +2 -1
- pysdmx/io/csv/sdmx10/reader/__init__.py +4 -2
- pysdmx/io/csv/sdmx10/writer/__init__.py +15 -2
- pysdmx/io/csv/sdmx20/reader/__init__.py +5 -2
- pysdmx/io/csv/sdmx20/writer/__init__.py +13 -2
- pysdmx/io/format.py +4 -0
- pysdmx/io/input_processor.py +12 -3
- pysdmx/io/json/fusion/messages/core.py +2 -0
- pysdmx/io/json/fusion/messages/report.py +13 -7
- pysdmx/io/json/gds/messages/__init__.py +35 -0
- pysdmx/io/json/gds/messages/agencies.py +41 -0
- pysdmx/io/json/gds/messages/catalog.py +79 -0
- pysdmx/io/json/gds/messages/sdmx_api.py +23 -0
- pysdmx/io/json/gds/messages/services.py +49 -0
- pysdmx/io/json/gds/messages/urn_resolver.py +43 -0
- pysdmx/io/json/gds/reader/__init__.py +12 -0
- pysdmx/io/json/sdmxjson2/messages/__init__.py +12 -4
- pysdmx/io/json/sdmxjson2/messages/agency.py +72 -0
- pysdmx/io/json/sdmxjson2/messages/category.py +22 -29
- pysdmx/io/json/sdmxjson2/messages/code.py +68 -64
- pysdmx/io/json/sdmxjson2/messages/concept.py +9 -18
- pysdmx/io/json/sdmxjson2/messages/constraint.py +2 -13
- pysdmx/io/json/sdmxjson2/messages/core.py +113 -21
- pysdmx/io/json/sdmxjson2/messages/dataflow.py +51 -21
- pysdmx/io/json/sdmxjson2/messages/dsd.py +110 -36
- pysdmx/io/json/sdmxjson2/messages/map.py +61 -49
- pysdmx/io/json/sdmxjson2/messages/pa.py +9 -17
- pysdmx/io/json/sdmxjson2/messages/provider.py +88 -0
- pysdmx/io/json/sdmxjson2/messages/report.py +84 -14
- pysdmx/io/json/sdmxjson2/messages/schema.py +14 -5
- pysdmx/io/json/sdmxjson2/messages/structure.py +105 -36
- pysdmx/io/json/sdmxjson2/messages/vtl.py +42 -96
- pysdmx/io/pd.py +2 -9
- pysdmx/io/reader.py +72 -27
- pysdmx/io/serde.py +11 -0
- pysdmx/io/writer.py +134 -0
- pysdmx/io/xml/{sdmx21/reader/__data_aux.py → __data_aux.py} +9 -2
- pysdmx/io/xml/{sdmx21/reader/__parse_xml.py → __parse_xml.py} +30 -6
- pysdmx/io/xml/__ss_aux_reader.py +96 -0
- pysdmx/io/xml/__structure_aux_reader.py +1174 -0
- pysdmx/io/xml/__structure_aux_writer.py +1233 -0
- pysdmx/io/xml/{sdmx21/__tokens.py → __tokens.py} +33 -1
- pysdmx/io/xml/{sdmx21/writer/__write_aux.py → __write_aux.py} +129 -37
- pysdmx/io/xml/{sdmx21/writer/__write_data_aux.py → __write_data_aux.py} +1 -1
- pysdmx/io/xml/__write_structure_specific_aux.py +254 -0
- pysdmx/io/xml/{sdmx21/reader/doc_validation.py → doc_validation.py} +10 -2
- pysdmx/io/xml/{sdmx21/reader/header.py → header.py} +11 -3
- pysdmx/io/xml/sdmx21/reader/error.py +2 -2
- pysdmx/io/xml/sdmx21/reader/generic.py +12 -8
- pysdmx/io/xml/sdmx21/reader/structure.py +5 -840
- pysdmx/io/xml/sdmx21/reader/structure_specific.py +13 -97
- pysdmx/io/xml/sdmx21/reader/submission.py +2 -2
- pysdmx/io/xml/sdmx21/writer/error.py +1 -1
- pysdmx/io/xml/sdmx21/writer/generic.py +13 -7
- pysdmx/io/xml/sdmx21/writer/structure.py +16 -828
- pysdmx/io/xml/sdmx21/writer/structure_specific.py +13 -238
- pysdmx/io/xml/sdmx30/__init__.py +1 -0
- pysdmx/io/xml/sdmx30/reader/__init__.py +1 -0
- pysdmx/io/xml/sdmx30/reader/structure.py +39 -0
- pysdmx/io/xml/sdmx30/reader/structure_specific.py +39 -0
- pysdmx/io/xml/sdmx30/writer/__init__.py +1 -0
- pysdmx/io/xml/sdmx30/writer/structure.py +67 -0
- pysdmx/io/xml/sdmx30/writer/structure_specific.py +108 -0
- pysdmx/model/__base.py +99 -34
- pysdmx/model/__init__.py +4 -0
- pysdmx/model/category.py +20 -0
- pysdmx/model/code.py +29 -8
- pysdmx/model/concept.py +52 -11
- pysdmx/model/dataflow.py +117 -33
- pysdmx/model/dataset.py +66 -14
- pysdmx/model/gds.py +161 -0
- pysdmx/model/map.py +51 -8
- pysdmx/model/message.py +235 -55
- pysdmx/model/metadata.py +79 -16
- pysdmx/model/submission.py +12 -7
- pysdmx/model/vtl.py +30 -13
- pysdmx/toolkit/__init__.py +1 -1
- pysdmx/toolkit/pd/__init__.py +85 -0
- pysdmx/toolkit/vtl/__init__.py +2 -1
- pysdmx/toolkit/vtl/_validations.py +1 -1
- pysdmx/toolkit/vtl/{generate_vtl_script.py → script_generation.py} +30 -4
- pysdmx/toolkit/vtl/validation.py +119 -0
- pysdmx/util/_model_utils.py +1 -1
- pysdmx-1.4.0rc1.dist-info/METADATA +119 -0
- pysdmx-1.4.0rc1.dist-info/RECORD +140 -0
- pysdmx/io/json/sdmxjson2/messages/org.py +0 -140
- pysdmx/toolkit/vtl/model_validations.py +0 -50
- pysdmx-1.3.0.dist-info/METADATA +0 -76
- pysdmx-1.3.0.dist-info/RECORD +0 -116
- /pysdmx/io/xml/{sdmx21/writer/config.py → config.py} +0 -0
- {pysdmx-1.3.0.dist-info → pysdmx-1.4.0rc1.dist-info}/LICENSE +0 -0
- {pysdmx-1.3.0.dist-info → pysdmx-1.4.0rc1.dist-info}/WHEEL +0 -0
|
@@ -1,108 +1,24 @@
|
|
|
1
|
-
"""SDMX 2.1
|
|
1
|
+
"""SDMX XML 2.1 StructureSpecificData reader module."""
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
from typing import Any, Dict, Sequence
|
|
5
|
-
|
|
6
|
-
import numpy as np
|
|
7
|
-
import pandas as pd
|
|
3
|
+
from typing import Sequence
|
|
8
4
|
|
|
9
5
|
from pysdmx.errors import Invalid
|
|
10
6
|
from pysdmx.io.pd import PandasDataset
|
|
11
|
-
from pysdmx.io.xml.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
from pysdmx.io.xml.__data_aux import (
|
|
8
|
+
get_data_objects,
|
|
9
|
+
)
|
|
10
|
+
from pysdmx.io.xml.__parse_xml import parse_xml
|
|
11
|
+
from pysdmx.io.xml.__ss_aux_reader import (
|
|
12
|
+
_parse_structure_specific_data,
|
|
13
|
+
)
|
|
14
|
+
from pysdmx.io.xml.__tokens import (
|
|
16
15
|
STR_REF,
|
|
17
16
|
STR_SPE,
|
|
18
17
|
)
|
|
19
|
-
from pysdmx.io.xml.sdmx21.reader.__data_aux import (
|
|
20
|
-
__process_df,
|
|
21
|
-
get_data_objects,
|
|
22
|
-
)
|
|
23
|
-
from pysdmx.io.xml.sdmx21.reader.__parse_xml import parse_xml
|
|
24
|
-
from pysdmx.io.xml.utils import add_list
|
|
25
|
-
from pysdmx.model.dataset import ActionType
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def __reading_str_series(dataset: Dict[str, Any]) -> pd.DataFrame:
|
|
29
|
-
# Structure Specific Series
|
|
30
|
-
test_list = []
|
|
31
|
-
df = None
|
|
32
|
-
dataset[SERIES] = add_list(dataset[SERIES])
|
|
33
|
-
for data in dataset[SERIES]:
|
|
34
|
-
keys = dict(itertools.islice(data.items(), len(data)))
|
|
35
|
-
if OBS in data:
|
|
36
|
-
del keys[OBS]
|
|
37
|
-
data[OBS] = add_list(data[OBS])
|
|
38
|
-
for j in data[OBS]:
|
|
39
|
-
test_list.append({**keys, **j})
|
|
40
|
-
else:
|
|
41
|
-
test_list.append(keys)
|
|
42
|
-
test_list, df = __process_df(test_list, df)
|
|
43
|
-
|
|
44
|
-
test_list, df = __process_df(test_list, df, is_end=True)
|
|
45
|
-
|
|
46
|
-
return df
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def __reading_group_data(dataset: Dict[str, Any]) -> pd.DataFrame:
|
|
50
|
-
# Structure Specific Group Data
|
|
51
|
-
test_list = []
|
|
52
|
-
df = None
|
|
53
|
-
dataset[GROUP] = add_list(dataset[GROUP])
|
|
54
|
-
for data in dataset[GROUP]:
|
|
55
|
-
test_list.append(dict(data.items()))
|
|
56
|
-
test_list, df = __process_df(test_list, df)
|
|
57
|
-
test_list, df = __process_df(test_list, df, is_end=True)
|
|
58
|
-
|
|
59
|
-
cols_to_delete = [x for x in df.columns if ":type" in x]
|
|
60
|
-
for x in cols_to_delete:
|
|
61
|
-
del df[x]
|
|
62
|
-
|
|
63
|
-
df = df.drop_duplicates(keep="first").reset_index(drop=True)
|
|
64
|
-
|
|
65
|
-
return df
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def __get_at_att_str(dataset: Dict[str, Any]) -> Dict[str, Any]:
|
|
69
|
-
"""Gets the elements of the dataset if it is Structure Specific Data."""
|
|
70
|
-
return {k: dataset[k] for k in dataset if k not in EXCLUDED_ATTRIBUTES}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def __parse_structure_specific_data(
|
|
74
|
-
dataset: Dict[str, Any], structure_info: Dict[str, Any]
|
|
75
|
-
) -> PandasDataset:
|
|
76
|
-
attached_attributes = __get_at_att_str(dataset)
|
|
77
|
-
|
|
78
|
-
df = pd.DataFrame()
|
|
79
|
-
|
|
80
|
-
# Parsing data
|
|
81
|
-
if SERIES in dataset:
|
|
82
|
-
# Structure Specific Series
|
|
83
|
-
df = __reading_str_series(dataset)
|
|
84
|
-
if GROUP in dataset:
|
|
85
|
-
df_group = __reading_group_data(dataset)
|
|
86
|
-
common_columns = list(
|
|
87
|
-
set(df.columns).intersection(set(df_group.columns))
|
|
88
|
-
)
|
|
89
|
-
df = pd.merge(df, df_group, on=common_columns, how="left")
|
|
90
|
-
elif OBS in dataset:
|
|
91
|
-
dataset[OBS] = add_list(dataset[OBS])
|
|
92
|
-
# Structure Specific All dimensions
|
|
93
|
-
df = pd.DataFrame(dataset[OBS]).replace(np.nan, "")
|
|
94
|
-
|
|
95
|
-
urn = f"{structure_info['structure_type']}={structure_info['unique_id']}"
|
|
96
|
-
action = dataset.get("action", "Information")
|
|
97
|
-
action = ActionType(action)
|
|
98
|
-
|
|
99
|
-
return PandasDataset(
|
|
100
|
-
structure=urn, attributes=attached_attributes, data=df, action=action
|
|
101
|
-
)
|
|
102
18
|
|
|
103
19
|
|
|
104
20
|
def read(input_str: str, validate: bool = True) -> Sequence[PandasDataset]:
|
|
105
|
-
"""Reads an SDMX-ML 2.1
|
|
21
|
+
"""Reads an SDMX-ML 2.1 and returns a Sequence of Datasets.
|
|
106
22
|
|
|
107
23
|
Args:
|
|
108
24
|
input_str: SDMX-ML data to read.
|
|
@@ -111,12 +27,12 @@ def read(input_str: str, validate: bool = True) -> Sequence[PandasDataset]:
|
|
|
111
27
|
dict_info = parse_xml(input_str, validate=validate)
|
|
112
28
|
if STR_SPE not in dict_info:
|
|
113
29
|
raise Invalid(
|
|
114
|
-
"This SDMX document is not an SDMX-ML
|
|
30
|
+
"This SDMX document is not an SDMX-ML StructureSpecificData."
|
|
115
31
|
)
|
|
116
32
|
dataset_info, str_info = get_data_objects(dict_info[STR_SPE])
|
|
117
33
|
datasets = []
|
|
118
34
|
for dataset in dataset_info:
|
|
119
|
-
ds =
|
|
35
|
+
ds = _parse_structure_specific_data(
|
|
120
36
|
dataset, str_info[dataset[STR_REF]]
|
|
121
37
|
)
|
|
122
38
|
datasets.append(ds)
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
from typing import Any, Dict, Sequence
|
|
4
4
|
|
|
5
5
|
from pysdmx.errors import Invalid
|
|
6
|
-
from pysdmx.io.xml.
|
|
6
|
+
from pysdmx.io.xml.__parse_xml import parse_xml
|
|
7
|
+
from pysdmx.io.xml.__tokens import (
|
|
7
8
|
ACTION,
|
|
8
9
|
MAINTAINABLE_OBJECT,
|
|
9
10
|
REG_INTERFACE,
|
|
@@ -14,7 +15,6 @@ from pysdmx.io.xml.sdmx21.__tokens import (
|
|
|
14
15
|
SUBMITTED_STRUCTURE,
|
|
15
16
|
URN,
|
|
16
17
|
)
|
|
17
|
-
from pysdmx.io.xml.sdmx21.reader.__parse_xml import parse_xml
|
|
18
18
|
from pysdmx.model.submission import SubmissionResult
|
|
19
19
|
from pysdmx.util import parse_urn
|
|
20
20
|
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# mypy: disable-error-code="union-attr"
|
|
2
2
|
"""Module for writing SDMX-ML 2.1 Generic data messages."""
|
|
3
3
|
|
|
4
|
-
from
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
|
|
5
6
|
|
|
6
7
|
import pandas as pd
|
|
7
8
|
|
|
8
9
|
from pysdmx.io.format import Format
|
|
9
10
|
from pysdmx.io.pd import PandasDataset
|
|
10
|
-
from pysdmx.io.xml.
|
|
11
|
+
from pysdmx.io.xml.__write_aux import (
|
|
11
12
|
ABBR_GEN,
|
|
12
13
|
ABBR_MSG,
|
|
13
14
|
ALL_DIM,
|
|
@@ -17,13 +18,13 @@ from pysdmx.io.xml.sdmx21.writer.__write_aux import (
|
|
|
17
18
|
get_end_message,
|
|
18
19
|
get_structure,
|
|
19
20
|
)
|
|
20
|
-
from pysdmx.io.xml.
|
|
21
|
+
from pysdmx.io.xml.__write_data_aux import (
|
|
21
22
|
check_content_dataset,
|
|
22
23
|
check_dimension_at_observation,
|
|
23
24
|
get_codes,
|
|
24
25
|
writing_validation,
|
|
25
26
|
)
|
|
26
|
-
from pysdmx.io.xml.
|
|
27
|
+
from pysdmx.io.xml.config import CHUNKSIZE
|
|
27
28
|
from pysdmx.model.message import Header
|
|
28
29
|
from pysdmx.util import parse_short_urn
|
|
29
30
|
|
|
@@ -159,6 +160,7 @@ def __write_data_single_dataset(
|
|
|
159
160
|
outfile = ""
|
|
160
161
|
structure_urn = get_structure(dataset)
|
|
161
162
|
id_structure = parse_short_urn(structure_urn).id
|
|
163
|
+
dataset.data = dataset.data.fillna("").astype(str).replace("nan", "")
|
|
162
164
|
|
|
163
165
|
nl = "\n" if prettyprint else ""
|
|
164
166
|
child1 = "\t" if prettyprint else ""
|
|
@@ -277,7 +279,7 @@ def __series_processing(
|
|
|
277
279
|
) -> str:
|
|
278
280
|
def __generate_series_str() -> str:
|
|
279
281
|
out_list: List[str] = []
|
|
280
|
-
data.groupby(by=series_codes + series_att_codes).apply(
|
|
282
|
+
data.groupby(by=series_codes + series_att_codes)[data.columns].apply(
|
|
281
283
|
lambda x: __format_dict_ser(out_list, x)
|
|
282
284
|
)
|
|
283
285
|
|
|
@@ -383,7 +385,7 @@ def __format_ser_str(
|
|
|
383
385
|
|
|
384
386
|
def write(
|
|
385
387
|
datasets: Sequence[PandasDataset],
|
|
386
|
-
output_path: str =
|
|
388
|
+
output_path: Optional[Union[str, Path]] = None,
|
|
387
389
|
prettyprint: bool = True,
|
|
388
390
|
header: Optional[Header] = None,
|
|
389
391
|
dimension_at_observation: Optional[Dict[str, str]] = None,
|
|
@@ -425,7 +427,11 @@ def write(
|
|
|
425
427
|
|
|
426
428
|
outfile += get_end_message(type_, prettyprint)
|
|
427
429
|
|
|
428
|
-
|
|
430
|
+
output_path = (
|
|
431
|
+
str(output_path) if isinstance(output_path, Path) else output_path
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
if output_path is None or output_path == "":
|
|
429
435
|
return outfile
|
|
430
436
|
|
|
431
437
|
with open(output_path, "w", encoding="UTF-8", errors="replace") as f:
|