pysdmx 1.8.1__py3-none-any.whl → 1.10.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/__extras_check.py +15 -1
- pysdmx/__init__.py +1 -1
- pysdmx/api/fmr/__init__.py +3 -2
- pysdmx/io/input_processor.py +9 -6
- pysdmx/io/json/fusion/messages/category.py +69 -41
- pysdmx/io/json/sdmxjson2/messages/__init__.py +4 -0
- pysdmx/io/json/sdmxjson2/messages/category.py +76 -43
- pysdmx/io/json/sdmxjson2/messages/code.py +16 -6
- pysdmx/io/json/sdmxjson2/messages/constraint.py +235 -16
- pysdmx/io/json/sdmxjson2/messages/core.py +2 -1
- pysdmx/io/json/sdmxjson2/messages/dsd.py +35 -7
- pysdmx/io/json/sdmxjson2/messages/map.py +5 -4
- pysdmx/io/json/sdmxjson2/messages/metadataflow.py +1 -0
- pysdmx/io/json/sdmxjson2/messages/msd.py +18 -10
- pysdmx/io/json/sdmxjson2/messages/schema.py +2 -2
- pysdmx/io/json/sdmxjson2/messages/structure.py +81 -44
- pysdmx/io/json/sdmxjson2/messages/vtl.py +13 -9
- pysdmx/io/json/sdmxjson2/reader/doc_validation.py +112 -0
- pysdmx/io/json/sdmxjson2/reader/metadata.py +8 -1
- pysdmx/io/json/sdmxjson2/reader/structure.py +9 -2
- pysdmx/io/reader.py +18 -4
- pysdmx/io/xml/__data_aux.py +9 -4
- pysdmx/io/xml/__parse_xml.py +2 -0
- pysdmx/io/xml/__structure_aux_reader.py +70 -0
- pysdmx/io/xml/__structure_aux_writer.py +63 -9
- pysdmx/io/xml/__tokens.py +3 -0
- pysdmx/io/xml/__write_aux.py +35 -30
- pysdmx/io/xml/header.py +48 -35
- pysdmx/model/__base.py +47 -2
- pysdmx/model/__init__.py +18 -0
- pysdmx/model/category.py +23 -1
- pysdmx/model/constraint.py +69 -0
- pysdmx/model/message.py +97 -72
- pysdmx/toolkit/vtl/__init__.py +10 -1
- pysdmx/toolkit/vtl/_validations.py +8 -12
- pysdmx/toolkit/vtl/convert.py +333 -0
- pysdmx/toolkit/vtl/script_generation.py +1 -1
- pysdmx/util/_model_utils.py +40 -3
- {pysdmx-1.8.1.dist-info → pysdmx-1.10.0.dist-info}/METADATA +6 -3
- {pysdmx-1.8.1.dist-info → pysdmx-1.10.0.dist-info}/RECORD +42 -39
- {pysdmx-1.8.1.dist-info → pysdmx-1.10.0.dist-info}/WHEEL +0 -0
- {pysdmx-1.8.1.dist-info → pysdmx-1.10.0.dist-info}/licenses/LICENSE +0 -0
pysdmx/__extras_check.py
CHANGED
|
@@ -46,7 +46,7 @@ def __check_xml_extra() -> None:
|
|
|
46
46
|
|
|
47
47
|
def __check_vtl_extra() -> None:
|
|
48
48
|
try:
|
|
49
|
-
import vtlengine #
|
|
49
|
+
import vtlengine # noqa: F401
|
|
50
50
|
except ImportError:
|
|
51
51
|
raise ImportError(
|
|
52
52
|
ERROR_MESSAGE.format(
|
|
@@ -55,3 +55,17 @@ def __check_vtl_extra() -> None:
|
|
|
55
55
|
" and prettify",
|
|
56
56
|
)
|
|
57
57
|
) from None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def __check_json_extra() -> None:
|
|
61
|
+
try:
|
|
62
|
+
import jsonschema # noqa: F401
|
|
63
|
+
import sdmxschemas # noqa: F401
|
|
64
|
+
except ImportError:
|
|
65
|
+
raise ImportError(
|
|
66
|
+
ERROR_MESSAGE.format(
|
|
67
|
+
extra_name="json",
|
|
68
|
+
extra_desc="the validation of SDMX-JSON Structure Messages "
|
|
69
|
+
"(hint, use validate=False if you don't need validation)",
|
|
70
|
+
)
|
|
71
|
+
) from None
|
pysdmx/__init__.py
CHANGED
pysdmx/api/fmr/__init__.py
CHANGED
|
@@ -44,6 +44,7 @@ from pysdmx.model import (
|
|
|
44
44
|
Metadataflow,
|
|
45
45
|
MetadataProvisionAgreement,
|
|
46
46
|
MetadataReport,
|
|
47
|
+
MetadataStructure,
|
|
47
48
|
MultiRepresentationMap,
|
|
48
49
|
ProvisionAgreement,
|
|
49
50
|
RepresentationMap,
|
|
@@ -767,7 +768,7 @@ class RegistryClient(__BaseRegistryClient):
|
|
|
767
768
|
agency: str = "*",
|
|
768
769
|
id: str = "*",
|
|
769
770
|
version: str = "+",
|
|
770
|
-
) -> Sequence[
|
|
771
|
+
) -> Sequence[MetadataStructure]:
|
|
771
772
|
"""Get the metadata structures (MSD) matching the supplied parameters.
|
|
772
773
|
|
|
773
774
|
Args:
|
|
@@ -1341,7 +1342,7 @@ class AsyncRegistryClient(__BaseRegistryClient):
|
|
|
1341
1342
|
agency: str = "*",
|
|
1342
1343
|
id: str = "*",
|
|
1343
1344
|
version: str = "+",
|
|
1344
|
-
) -> Sequence[
|
|
1345
|
+
) -> Sequence[MetadataStructure]:
|
|
1345
1346
|
"""Get the metadata structures (MSD) matching the supplied parameters.
|
|
1346
1347
|
|
|
1347
1348
|
Args:
|
pysdmx/io/input_processor.py
CHANGED
|
@@ -29,16 +29,19 @@ def __check_xml(input_str: str) -> bool:
|
|
|
29
29
|
|
|
30
30
|
def __check_csv(input_str: str) -> bool:
|
|
31
31
|
try:
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
lines = input_str.splitlines()
|
|
33
|
+
|
|
34
|
+
# Use the first N complete lines
|
|
35
|
+
# (1 should be enough)
|
|
36
|
+
max_lines = 1
|
|
37
|
+
sample = "\n".join(lines[:max_lines])
|
|
38
|
+
|
|
39
|
+
dialect = csv.Sniffer().sniff(sample)
|
|
34
40
|
control_csv_format = (
|
|
35
41
|
dialect.delimiter == "," and dialect.quotechar == '"'
|
|
36
42
|
)
|
|
37
43
|
# Check we can access the data and it is not empty
|
|
38
|
-
if (
|
|
39
|
-
len(input_str.splitlines()) > 1
|
|
40
|
-
or input_str.splitlines()[0].count(",") > 1
|
|
41
|
-
) and control_csv_format:
|
|
44
|
+
if (len(lines) > 1 or lines[0].count(",") > 1) and control_csv_format:
|
|
42
45
|
return True
|
|
43
46
|
except Exception:
|
|
44
47
|
return False
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Collection of Fusion-JSON schemas for categories and category schemes."""
|
|
2
2
|
|
|
3
3
|
from collections import defaultdict
|
|
4
|
-
from typing import Dict, Optional, Sequence
|
|
4
|
+
from typing import Dict, Optional, Sequence, Tuple, Union
|
|
5
5
|
|
|
6
6
|
from msgspec import Struct
|
|
7
7
|
|
|
@@ -11,6 +11,8 @@ from pysdmx.model import (
|
|
|
11
11
|
Agency,
|
|
12
12
|
Category,
|
|
13
13
|
DataflowRef,
|
|
14
|
+
ItemReference,
|
|
15
|
+
Reference,
|
|
14
16
|
)
|
|
15
17
|
from pysdmx.model import (
|
|
16
18
|
Categorisation as CT,
|
|
@@ -21,7 +23,7 @@ from pysdmx.model import (
|
|
|
21
23
|
from pysdmx.model import (
|
|
22
24
|
Dataflow as DF,
|
|
23
25
|
)
|
|
24
|
-
from pysdmx.util import find_by_urn
|
|
26
|
+
from pysdmx.util import find_by_urn, parse_urn
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
class FusionCategorisation(Struct, frozen=True, rename={"agency": "agencyId"}):
|
|
@@ -57,14 +59,46 @@ class FusionCategory(Struct, frozen=True):
|
|
|
57
59
|
descriptions: Optional[Sequence[FusionString]] = None
|
|
58
60
|
items: Sequence["FusionCategory"] = ()
|
|
59
61
|
|
|
60
|
-
def
|
|
62
|
+
def __add_flows(
|
|
63
|
+
self, cni: str, cf: Dict[str, list[DF]]
|
|
64
|
+
) -> Sequence[DataflowRef]:
|
|
65
|
+
if cni in cf:
|
|
66
|
+
return [
|
|
67
|
+
DataflowRef(
|
|
68
|
+
(
|
|
69
|
+
df.agency.id
|
|
70
|
+
if isinstance(df.agency, Agency)
|
|
71
|
+
else df.agency
|
|
72
|
+
),
|
|
73
|
+
df.id,
|
|
74
|
+
df.version,
|
|
75
|
+
df.name,
|
|
76
|
+
)
|
|
77
|
+
for df in cf[cni]
|
|
78
|
+
]
|
|
79
|
+
else:
|
|
80
|
+
return ()
|
|
81
|
+
|
|
82
|
+
def to_model(
|
|
83
|
+
self,
|
|
84
|
+
cat_flows: dict[str, list[DF]],
|
|
85
|
+
cat_other: dict[str, list[Union[ItemReference, Reference]]],
|
|
86
|
+
parent_id: Optional[str] = None,
|
|
87
|
+
) -> Category:
|
|
61
88
|
"""Converts a FusionCode to a standard code."""
|
|
62
89
|
description = self.descriptions[0].value if self.descriptions else None
|
|
90
|
+
cni = f"{parent_id}.{self.id}" if parent_id else self.id
|
|
91
|
+
dataflows = self.__add_flows(cni, cat_flows)
|
|
92
|
+
others = cat_other.get(cni, ())
|
|
63
93
|
return Category(
|
|
64
94
|
id=self.id,
|
|
65
95
|
name=self.names[0].value,
|
|
66
96
|
description=description,
|
|
67
|
-
categories=[
|
|
97
|
+
categories=[
|
|
98
|
+
c.to_model(cat_flows, cat_other, cni) for c in self.items
|
|
99
|
+
],
|
|
100
|
+
dataflows=dataflows,
|
|
101
|
+
other_references=others,
|
|
68
102
|
)
|
|
69
103
|
|
|
70
104
|
|
|
@@ -78,16 +112,42 @@ class FusionCategoryScheme(Struct, frozen=True, rename={"agency": "agencyId"}):
|
|
|
78
112
|
version: str = "1.0"
|
|
79
113
|
items: Sequence[FusionCategory] = ()
|
|
80
114
|
|
|
81
|
-
def
|
|
115
|
+
def __group_refs(
|
|
116
|
+
self,
|
|
117
|
+
categorisations: Sequence[FusionCategorisation],
|
|
118
|
+
dataflows: Sequence[FusionDataflow],
|
|
119
|
+
) -> Tuple[
|
|
120
|
+
dict[str, list[DF]], dict[str, list[Union[ItemReference, Reference]]]
|
|
121
|
+
]:
|
|
122
|
+
flows: defaultdict[str, list[DF]] = defaultdict(list)
|
|
123
|
+
other: defaultdict[str, list[Union[ItemReference, Reference]]] = (
|
|
124
|
+
defaultdict(list)
|
|
125
|
+
)
|
|
126
|
+
for c in categorisations:
|
|
127
|
+
ref = parse_urn(c.structureReference)
|
|
128
|
+
src = c.categoryReference[c.categoryReference.find(")") + 2 :]
|
|
129
|
+
if ref.sdmx_type == "Dataflow":
|
|
130
|
+
d = find_by_urn(dataflows, c.structureReference)
|
|
131
|
+
flows[src].append(d.to_model())
|
|
132
|
+
else:
|
|
133
|
+
other[src].append(ref)
|
|
134
|
+
return (flows, other)
|
|
135
|
+
|
|
136
|
+
def to_model(
|
|
137
|
+
self,
|
|
138
|
+
categorisations: Sequence[FusionCategorisation] = (),
|
|
139
|
+
dataflows: Sequence[FusionDataflow] = (),
|
|
140
|
+
) -> CS:
|
|
82
141
|
"""Converts a JsonCodelist to a standard codelist."""
|
|
83
142
|
description = self.descriptions[0].value if self.descriptions else None
|
|
143
|
+
cat_flows, cat_others = self.__group_refs(categorisations, dataflows)
|
|
84
144
|
return CS(
|
|
85
145
|
id=self.id,
|
|
86
146
|
name=self.names[0].value,
|
|
87
147
|
agency=self.agency,
|
|
88
148
|
description=description,
|
|
89
149
|
version=self.version,
|
|
90
|
-
items=[c.to_model() for c in self.items],
|
|
150
|
+
items=[c.to_model(cat_flows, cat_others) for c in self.items],
|
|
91
151
|
)
|
|
92
152
|
|
|
93
153
|
|
|
@@ -98,43 +158,11 @@ class FusionCategorySchemeMessage(Struct, frozen=True):
|
|
|
98
158
|
Categorisation: Sequence[FusionCategorisation] = ()
|
|
99
159
|
Dataflow: Sequence[FusionDataflow] = ()
|
|
100
160
|
|
|
101
|
-
def __group_flows(self) -> defaultdict[str, list[DF]]:
|
|
102
|
-
out: defaultdict[str, list[DF]] = defaultdict(list)
|
|
103
|
-
for c in self.Categorisation:
|
|
104
|
-
d = find_by_urn(self.Dataflow, c.structureReference)
|
|
105
|
-
src = c.categoryReference[c.categoryReference.find(")") + 2 :]
|
|
106
|
-
out[src].append(d.to_model())
|
|
107
|
-
return out
|
|
108
|
-
|
|
109
|
-
def __add_flows(
|
|
110
|
-
self, cat: Category, cni: str, cf: Dict[str, list[DF]]
|
|
111
|
-
) -> None:
|
|
112
|
-
if cat.categories:
|
|
113
|
-
for c in cat.categories:
|
|
114
|
-
self.__add_flows(c, f"{cni}.{c.id}", cf)
|
|
115
|
-
if cni in cf:
|
|
116
|
-
dfrefs = [
|
|
117
|
-
DataflowRef(
|
|
118
|
-
(
|
|
119
|
-
df.agency.id
|
|
120
|
-
if isinstance(df.agency, Agency)
|
|
121
|
-
else df.agency
|
|
122
|
-
),
|
|
123
|
-
df.id,
|
|
124
|
-
df.version,
|
|
125
|
-
df.name,
|
|
126
|
-
)
|
|
127
|
-
for df in cf[cni]
|
|
128
|
-
]
|
|
129
|
-
cat.dataflows = dfrefs
|
|
130
|
-
|
|
131
161
|
def to_model(self) -> CS:
|
|
132
162
|
"""Returns the requested category scheme."""
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
self.__add_flows(c, c.id, cf)
|
|
137
|
-
return cs
|
|
163
|
+
return self.CategoryScheme[0].to_model(
|
|
164
|
+
self.Categorisation, self.Dataflow
|
|
165
|
+
)
|
|
138
166
|
|
|
139
167
|
|
|
140
168
|
class FusionCategorisationMessage(Struct, frozen=True):
|
|
@@ -12,6 +12,9 @@ from pysdmx.io.json.sdmxjson2.messages.code import (
|
|
|
12
12
|
JsonHierarchyMessage,
|
|
13
13
|
)
|
|
14
14
|
from pysdmx.io.json.sdmxjson2.messages.concept import JsonConceptSchemeMessage
|
|
15
|
+
from pysdmx.io.json.sdmxjson2.messages.constraint import (
|
|
16
|
+
JsonDataConstraintMessage,
|
|
17
|
+
)
|
|
15
18
|
from pysdmx.io.json.sdmxjson2.messages.dataflow import (
|
|
16
19
|
JsonDataflowMessage,
|
|
17
20
|
JsonDataflowsMessage,
|
|
@@ -50,6 +53,7 @@ __all__ = [
|
|
|
50
53
|
"JsonCategorySchemeMessage",
|
|
51
54
|
"JsonCodelistMessage",
|
|
52
55
|
"JsonConceptSchemeMessage",
|
|
56
|
+
"JsonDataConstraintMessage",
|
|
53
57
|
"JsonDataflowMessage",
|
|
54
58
|
"JsonDataflowsMessage",
|
|
55
59
|
"JsonDataStructuresMessage",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Collection of SDMX-JSON schemas for categories and category schemes."""
|
|
2
2
|
|
|
3
3
|
from collections import defaultdict
|
|
4
|
-
from typing import Dict, Sequence
|
|
4
|
+
from typing import Dict, Optional, Sequence, Tuple, Union
|
|
5
5
|
|
|
6
6
|
from msgspec import Struct
|
|
7
7
|
|
|
@@ -20,8 +20,10 @@ from pysdmx.model import (
|
|
|
20
20
|
CategoryScheme,
|
|
21
21
|
Dataflow,
|
|
22
22
|
DataflowRef,
|
|
23
|
+
ItemReference,
|
|
24
|
+
Reference,
|
|
23
25
|
)
|
|
24
|
-
from pysdmx.util import find_by_urn
|
|
26
|
+
from pysdmx.util import find_by_urn, parse_urn
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
class JsonCategorisation(
|
|
@@ -84,14 +86,46 @@ class JsonCategory(NameableType, frozen=True, omit_defaults=True):
|
|
|
84
86
|
|
|
85
87
|
categories: Sequence["JsonCategory"] = ()
|
|
86
88
|
|
|
87
|
-
def
|
|
89
|
+
def __add_flows(
|
|
90
|
+
self, cni: str, cf: Dict[str, list[Dataflow]]
|
|
91
|
+
) -> Sequence[DataflowRef]:
|
|
92
|
+
if cni in cf:
|
|
93
|
+
return [
|
|
94
|
+
DataflowRef(
|
|
95
|
+
(
|
|
96
|
+
df.agency.id
|
|
97
|
+
if isinstance(df.agency, Agency)
|
|
98
|
+
else df.agency
|
|
99
|
+
),
|
|
100
|
+
df.id,
|
|
101
|
+
df.version,
|
|
102
|
+
df.name,
|
|
103
|
+
)
|
|
104
|
+
for df in cf[cni]
|
|
105
|
+
]
|
|
106
|
+
else:
|
|
107
|
+
return ()
|
|
108
|
+
|
|
109
|
+
def to_model(
|
|
110
|
+
self,
|
|
111
|
+
cat_flows: dict[str, list[Dataflow]],
|
|
112
|
+
cat_other: dict[str, list[Union[ItemReference, Reference]]],
|
|
113
|
+
parent_id: Optional[str] = None,
|
|
114
|
+
) -> Category:
|
|
88
115
|
"""Converts a FusionCode to a standard code."""
|
|
116
|
+
cni = f"{parent_id}.{self.id}" if parent_id else self.id
|
|
117
|
+
dataflows = self.__add_flows(cni, cat_flows)
|
|
118
|
+
others = cat_other.get(cni, ())
|
|
89
119
|
return Category(
|
|
90
120
|
id=self.id,
|
|
91
121
|
name=self.name,
|
|
92
122
|
description=self.description,
|
|
93
|
-
categories=[
|
|
123
|
+
categories=[
|
|
124
|
+
c.to_model(cat_flows, cat_other, cni) for c in self.categories
|
|
125
|
+
],
|
|
94
126
|
annotations=[a.to_model() for a in self.annotations],
|
|
127
|
+
dataflows=dataflows,
|
|
128
|
+
other_references=others,
|
|
95
129
|
)
|
|
96
130
|
|
|
97
131
|
@classmethod
|
|
@@ -126,15 +160,42 @@ class JsonCategoryScheme(
|
|
|
126
160
|
|
|
127
161
|
categories: Sequence[JsonCategory] = ()
|
|
128
162
|
|
|
129
|
-
def
|
|
130
|
-
|
|
163
|
+
def __group_refs(
|
|
164
|
+
self,
|
|
165
|
+
categorisations: Sequence[JsonCategorisation] = (),
|
|
166
|
+
dataflows: Sequence[JsonDataflow] = (),
|
|
167
|
+
) -> Tuple[
|
|
168
|
+
dict[str, list[Dataflow]],
|
|
169
|
+
dict[str, list[Union[ItemReference, Reference]]],
|
|
170
|
+
]:
|
|
171
|
+
flows: defaultdict[str, list[Dataflow]] = defaultdict(list)
|
|
172
|
+
other: defaultdict[str, list[Union[ItemReference, Reference]]] = (
|
|
173
|
+
defaultdict(list)
|
|
174
|
+
)
|
|
175
|
+
for c in categorisations:
|
|
176
|
+
ref = parse_urn(c.source)
|
|
177
|
+
src = c.target[c.target.find(")") + 2 :]
|
|
178
|
+
if ref.sdmx_type == "Dataflow":
|
|
179
|
+
d = find_by_urn(dataflows, c.source)
|
|
180
|
+
flows[src].append(d.to_model())
|
|
181
|
+
else:
|
|
182
|
+
other[src].append(ref)
|
|
183
|
+
return (flows, other)
|
|
184
|
+
|
|
185
|
+
def to_model(
|
|
186
|
+
self,
|
|
187
|
+
categorisations: Sequence[JsonCategorisation] = (),
|
|
188
|
+
dataflows: Sequence[JsonDataflow] = (),
|
|
189
|
+
) -> CategoryScheme:
|
|
190
|
+
"""Converts a JsonCategoryScheme to a standard one."""
|
|
191
|
+
cat_flows, cat_other = self.__group_refs(categorisations, dataflows)
|
|
131
192
|
return CategoryScheme(
|
|
132
193
|
id=self.id,
|
|
133
194
|
name=self.name,
|
|
134
195
|
agency=self.agency,
|
|
135
196
|
description=self.description,
|
|
136
197
|
version=self.version,
|
|
137
|
-
items=[c.to_model() for c in self.categories],
|
|
198
|
+
items=[c.to_model(cat_flows, cat_other) for c in self.categories],
|
|
138
199
|
is_external_reference=self.isExternalReference,
|
|
139
200
|
is_partial=self.isPartial,
|
|
140
201
|
valid_from=self.validFrom,
|
|
@@ -179,49 +240,21 @@ class JsonCategorySchemes(Struct, frozen=True, omit_defaults=True):
|
|
|
179
240
|
categorisations: Sequence[JsonCategorisation] = ()
|
|
180
241
|
dataflows: Sequence[JsonDataflow] = ()
|
|
181
242
|
|
|
243
|
+
def to_model(self) -> CategoryScheme:
|
|
244
|
+
"""Returns the requested codelist."""
|
|
245
|
+
return self.categorySchemes[0].to_model(
|
|
246
|
+
self.categorisations, self.dataflows
|
|
247
|
+
)
|
|
248
|
+
|
|
182
249
|
|
|
183
250
|
class JsonCategorySchemeMessage(Struct, frozen=True, omit_defaults=True):
|
|
184
251
|
"""SDMX-JSON payload for /categoryscheme queries."""
|
|
185
252
|
|
|
186
253
|
data: JsonCategorySchemes
|
|
187
254
|
|
|
188
|
-
def __group_flows(self) -> defaultdict[str, list[Dataflow]]:
|
|
189
|
-
out: defaultdict[str, list[Dataflow]] = defaultdict(list)
|
|
190
|
-
for c in self.data.categorisations:
|
|
191
|
-
d = find_by_urn(self.data.dataflows, c.source)
|
|
192
|
-
src = c.target[c.target.find(")") + 2 :]
|
|
193
|
-
out[src].append(d.to_model())
|
|
194
|
-
return out
|
|
195
|
-
|
|
196
|
-
def __add_flows(
|
|
197
|
-
self, cat: Category, cni: str, cf: Dict[str, list[Dataflow]]
|
|
198
|
-
) -> None:
|
|
199
|
-
if cat.categories:
|
|
200
|
-
for c in cat.categories:
|
|
201
|
-
self.__add_flows(c, f"{cni}.{c.id}", cf)
|
|
202
|
-
if cni in cf:
|
|
203
|
-
dfrefs = [
|
|
204
|
-
DataflowRef(
|
|
205
|
-
(
|
|
206
|
-
df.agency.id
|
|
207
|
-
if isinstance(df.agency, Agency)
|
|
208
|
-
else df.agency
|
|
209
|
-
),
|
|
210
|
-
df.id,
|
|
211
|
-
df.version,
|
|
212
|
-
df.name,
|
|
213
|
-
)
|
|
214
|
-
for df in cf[cni]
|
|
215
|
-
]
|
|
216
|
-
cat.dataflows = dfrefs
|
|
217
|
-
|
|
218
255
|
def to_model(self) -> CategoryScheme:
|
|
219
|
-
"""Returns the requested
|
|
220
|
-
|
|
221
|
-
cs = self.data.categorySchemes[0].to_model()
|
|
222
|
-
for c in cs:
|
|
223
|
-
self.__add_flows(c, c.id, cf)
|
|
224
|
-
return cs
|
|
256
|
+
"""Returns the requested category scheme."""
|
|
257
|
+
return self.data.to_model()
|
|
225
258
|
|
|
226
259
|
|
|
227
260
|
class JsonCategorisations(Struct, frozen=True, omit_defaults=True):
|
|
@@ -231,7 +231,7 @@ class JsonCodelists(Struct, frozen=True, omit_defaults=True):
|
|
|
231
231
|
"""SDMX-JSON payload for lists of codes."""
|
|
232
232
|
|
|
233
233
|
codelists: Sequence[JsonCodelist] = ()
|
|
234
|
-
|
|
234
|
+
valueLists: Sequence[JsonValuelist] = ()
|
|
235
235
|
|
|
236
236
|
|
|
237
237
|
class JsonCodelistMessage(Struct, frozen=True, omit_defaults=True):
|
|
@@ -244,7 +244,7 @@ class JsonCodelistMessage(Struct, frozen=True, omit_defaults=True):
|
|
|
244
244
|
if self.data.codelists:
|
|
245
245
|
return self.data.codelists[0].to_model()
|
|
246
246
|
else:
|
|
247
|
-
return self.data.
|
|
247
|
+
return self.data.valueLists[0].to_model()
|
|
248
248
|
|
|
249
249
|
|
|
250
250
|
class JsonHierarchicalCode(Struct, frozen=True, omit_defaults=True):
|
|
@@ -329,10 +329,10 @@ class JsonHierarchicalCode(Struct, frozen=True, omit_defaults=True):
|
|
|
329
329
|
code=code.urn,
|
|
330
330
|
validFrom=code.rel_valid_from,
|
|
331
331
|
validTo=code.rel_valid_to,
|
|
332
|
-
annotations=tuple(annotations),
|
|
333
|
-
hierarchicalCodes=
|
|
334
|
-
JsonHierarchicalCode.from_model(c) for c in code.codes
|
|
335
|
-
|
|
332
|
+
annotations=tuple(annotations) if annotations else None,
|
|
333
|
+
hierarchicalCodes=tuple(
|
|
334
|
+
[JsonHierarchicalCode.from_model(c) for c in code.codes]
|
|
335
|
+
),
|
|
336
336
|
)
|
|
337
337
|
|
|
338
338
|
|
|
@@ -475,6 +475,15 @@ class JsonHierarchyAssociation(
|
|
|
475
475
|
"SDMX-JSON hierarchy associations must reference a context",
|
|
476
476
|
{"hierarchy_association": ha.id},
|
|
477
477
|
)
|
|
478
|
+
lnk = (
|
|
479
|
+
JsonLink(
|
|
480
|
+
rel="UserDefinedOperator",
|
|
481
|
+
type="sdmx_artefact",
|
|
482
|
+
urn=ha.operator,
|
|
483
|
+
)
|
|
484
|
+
if ha.operator
|
|
485
|
+
else None
|
|
486
|
+
)
|
|
478
487
|
return JsonHierarchyAssociation(
|
|
479
488
|
agency=(
|
|
480
489
|
ha.agency.id if isinstance(ha.agency, Agency) else ha.agency
|
|
@@ -492,6 +501,7 @@ class JsonHierarchyAssociation(
|
|
|
492
501
|
linkedHierarchy=href,
|
|
493
502
|
linkedObject=ha.component_ref,
|
|
494
503
|
contextObject=ha.context_ref,
|
|
504
|
+
links=[lnk] if lnk else (),
|
|
495
505
|
)
|
|
496
506
|
|
|
497
507
|
|