sdmxlib 0.28.2__tar.gz → 0.29.0__tar.gz
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.
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/PKG-INFO +1 -1
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/pyproject.toml +13 -2
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/__init__.py +37 -15
- sdmxlib-0.29.0/src/sdmxlib/_duckdb.py +18 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/api/client.py +6 -2
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/api/federated.py +10 -10
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/api/filters.py +3 -3
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/api/policy.py +1 -1
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/api/providers.py +2 -2
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/api/query.py +12 -12
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/api/registry.py +121 -137
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/catalog.py +30 -31
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/data_store.py +16 -22
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/formats/__init__.py +10 -2
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/formats/sdmx_csv/reader.py +5 -5
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/formats/sdmx_csv/writer.py +10 -8
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/formats/sdmx_json/reader.py +78 -62
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/formats/sdmx_json/writer.py +109 -122
- sdmxlib-0.29.0/src/sdmxlib/formats/sdmx_ml/__init__.py +8 -0
- sdmxlib-0.29.0/src/sdmxlib/formats/sdmx_ml/_common.py +1006 -0
- sdmxlib-0.29.0/src/sdmxlib/formats/sdmx_ml21/reader.py +820 -0
- sdmxlib-0.29.0/src/sdmxlib/formats/sdmx_ml21/writer.py +603 -0
- sdmxlib-0.29.0/src/sdmxlib/formats/sdmx_ml30/reader.py +1057 -0
- sdmxlib-0.29.0/src/sdmxlib/formats/sdmx_ml30/writer.py +880 -0
- sdmxlib-0.29.0/src/sdmxlib/formats/sdmx_ml31/__init__.py +1 -0
- sdmxlib-0.29.0/src/sdmxlib/formats/sdmx_ml31/namespaces.py +14 -0
- sdmxlib-0.29.0/src/sdmxlib/formats/sdmx_ml31/reader.py +1056 -0
- sdmxlib-0.29.0/src/sdmxlib/formats/sdmx_ml31/writer.py +893 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/local/__init__.py +1 -1
- sdmxlib-0.28.2/src/sdmxlib/local/_data_store.py → sdmxlib-0.29.0/src/sdmxlib/local/data_store.py +39 -21
- sdmxlib-0.28.2/src/sdmxlib/local/_registry.py → sdmxlib-0.29.0/src/sdmxlib/local/registry.py +17 -17
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/__init__.py +38 -16
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/annotations.py +1 -4
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/base.py +15 -3
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/binding.py +9 -9
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/category.py +7 -7
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/code_query.py +4 -4
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/codelist.py +95 -6
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/collections.py +15 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/concept.py +4 -6
- sdmxlib-0.29.0/src/sdmxlib/model/constraint.py +166 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/convert.py +3 -2
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/dataflow.py +19 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/dataset.py +18 -17
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/datastructure.py +73 -27
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/hierarchy.py +72 -6
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/hierarchy_query.py +8 -8
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/in_memory_registry.py +5 -7
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/istring.py +9 -0
- sdmxlib-0.29.0/src/sdmxlib/model/mapping.py +243 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/message.py +26 -7
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/metadataflow.py +7 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/metadataset.py +3 -15
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/metadatastructure.py +3 -15
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/organisation.py +4 -4
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/provision.py +3 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/ref.py +11 -8
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/registry.py +4 -5
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/representation.py +1 -1
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/validation.py +10 -10
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/polars.py +22 -23
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/rest.py +14 -14
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/sql.py +10 -10
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/storage/__init__.py +1 -2
- sdmxlib-0.29.0/src/sdmxlib/storage/_kinds.py +60 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/storage/lazy.py +24 -31
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/storage/readers.py +44 -50
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/storage/schema.py +22 -25
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/storage/writers.py +53 -64
- sdmxlib-0.28.2/src/sdmxlib/formats/sdmx_ml21/reader.py +0 -1147
- sdmxlib-0.28.2/src/sdmxlib/formats/sdmx_ml21/writer.py +0 -709
- sdmxlib-0.28.2/src/sdmxlib/formats/sdmx_ml30/reader.py +0 -1286
- sdmxlib-0.28.2/src/sdmxlib/formats/sdmx_ml30/writer.py +0 -803
- sdmxlib-0.28.2/src/sdmxlib/model/constraint.py +0 -92
- sdmxlib-0.28.2/src/sdmxlib/model/mapping.py +0 -134
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/README.md +0 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/api/__init__.py +0 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/api/session.py +0 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/formats/sdmx_csv/__init__.py +0 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/formats/sdmx_json/__init__.py +0 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/formats/sdmx_json/metadata.py +0 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/formats/sdmx_ml21/__init__.py +0 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/formats/sdmx_ml21/namespaces.py +0 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/formats/sdmx_ml30/__init__.py +0 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/formats/sdmx_ml30/metadata.py +0 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/formats/sdmx_ml30/namespaces.py +0 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/expr.py +0 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/model/urn.py +0 -0
- {sdmxlib-0.28.2 → sdmxlib-0.29.0}/src/sdmxlib/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sdmxlib"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.29.0"
|
|
4
4
|
description = "SDMX structural metadata library for Python"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "Apache-2.0" }
|
|
@@ -45,7 +45,6 @@ markers = [
|
|
|
45
45
|
|
|
46
46
|
[tool.coverage.run]
|
|
47
47
|
source = ["src/sdmxlib"]
|
|
48
|
-
omit = ["src/sdmxlib/contrib/*"]
|
|
49
48
|
|
|
50
49
|
[tool.coverage.report]
|
|
51
50
|
show_missing = true
|
|
@@ -63,7 +62,19 @@ pythonVersion = "3.13"
|
|
|
63
62
|
pythonPlatform = "Linux"
|
|
64
63
|
venvPath = "."
|
|
65
64
|
venv = ".venv"
|
|
65
|
+
# "standard" rather than "strict" because the strict-only rules
|
|
66
|
+
# (reportUnknownMemberType, reportUnknownArgumentType,
|
|
67
|
+
# reportUnknownVariableType) fire on every duckdb / lxml / pyarrow
|
|
68
|
+
# touch — third-party stubs we don't control. Standard mode still
|
|
69
|
+
# catches the bugs we care about (assignments, attribute access,
|
|
70
|
+
# return types, missing arguments). Strict-mode rules that *are*
|
|
71
|
+
# enforceable on this codebase are turned on manually via
|
|
72
|
+
# `# pyright: ignore[...]` opt-outs at the call sites that need them.
|
|
66
73
|
typeCheckingMode = "standard"
|
|
74
|
+
# `pytest.raises(...)` doesn't bind a name — without this every
|
|
75
|
+
# `with pytest.raises(...):` block would need `# pyright: ignore`.
|
|
76
|
+
# Off project-wide since the only places that consume return values
|
|
77
|
+
# we *don't* care about are tests.
|
|
67
78
|
reportUnusedCallResult = false
|
|
68
79
|
|
|
69
80
|
[dependency-groups]
|
|
@@ -11,7 +11,7 @@ from sdmxlib.data_store import DataStore
|
|
|
11
11
|
from sdmxlib.sql import CompileContext, Predicate, SqlRelation
|
|
12
12
|
from sdmxlib.formats import parse, read, serialize, to_json, to_xml
|
|
13
13
|
from sdmxlib.local import LazyCodelist, LazyHierarchy, Registry
|
|
14
|
-
from sdmxlib.local.
|
|
14
|
+
from sdmxlib.local.data_store import DuckDBDataStore
|
|
15
15
|
from sdmxlib.rest import ComponentFilter, parse_components
|
|
16
16
|
from sdmxlib.model.convert import from_dict, to_dict
|
|
17
17
|
from sdmxlib.model.validation import ReferenceIssue, ValidationIssue, validate, validate_references
|
|
@@ -20,27 +20,31 @@ from sdmxlib.model import (
|
|
|
20
20
|
AgencyScheme,
|
|
21
21
|
Annotation,
|
|
22
22
|
Annotations,
|
|
23
|
+
AnyRef,
|
|
23
24
|
ArtefactList,
|
|
24
25
|
AttachmentLevel,
|
|
25
26
|
Attribute,
|
|
27
|
+
AttributeUsage,
|
|
28
|
+
CascadeSelection,
|
|
26
29
|
Categorisation,
|
|
27
30
|
Category,
|
|
28
31
|
CategoryScheme,
|
|
29
32
|
Code,
|
|
30
33
|
CodeQuery,
|
|
34
|
+
CodeSelection,
|
|
31
35
|
Codelist,
|
|
36
|
+
CodelistExtension,
|
|
32
37
|
Concept,
|
|
33
38
|
ConceptScheme,
|
|
34
|
-
CategoryMap,
|
|
35
39
|
CategorySchemeMap,
|
|
36
|
-
CodeMap,
|
|
37
|
-
CodelistMap,
|
|
38
40
|
ComponentMap,
|
|
39
|
-
ConceptMap,
|
|
40
41
|
ConceptSchemeMap,
|
|
42
|
+
AttachmentConstraint,
|
|
41
43
|
ConstraintAttachment,
|
|
44
|
+
ConstraintType,
|
|
42
45
|
Contact,
|
|
43
46
|
DataConstraint,
|
|
47
|
+
DataKey,
|
|
44
48
|
CubeRegion,
|
|
45
49
|
ReferencePeriod,
|
|
46
50
|
ReleaseCalendar,
|
|
@@ -48,26 +52,30 @@ from sdmxlib.model import (
|
|
|
48
52
|
DataProviderScheme,
|
|
49
53
|
DataStructure,
|
|
50
54
|
Dataset,
|
|
51
|
-
DataStructureMap,
|
|
52
55
|
Dataflow,
|
|
53
56
|
DataflowBinding,
|
|
54
|
-
DataflowMap,
|
|
55
57
|
Dimension,
|
|
56
58
|
DriftIssue,
|
|
57
59
|
Hierarchy,
|
|
58
60
|
HierarchicalCode,
|
|
61
|
+
HierarchyAssociation,
|
|
59
62
|
Group,
|
|
63
|
+
InclusionMode,
|
|
64
|
+
IndexValueMap,
|
|
60
65
|
InMemoryRegistry,
|
|
61
66
|
InternationalString,
|
|
62
67
|
ItemExpr,
|
|
63
68
|
ItemList,
|
|
69
|
+
ItemMap,
|
|
64
70
|
ItemPredicate,
|
|
65
71
|
KeyValue,
|
|
66
72
|
Level,
|
|
73
|
+
LiteralValueMap,
|
|
67
74
|
item,
|
|
68
75
|
Maintainable,
|
|
69
76
|
MaintainableArtefact,
|
|
70
77
|
Measure,
|
|
78
|
+
MemberValue,
|
|
71
79
|
MeasureDimension,
|
|
72
80
|
MetadataAttribute,
|
|
73
81
|
MetadataMessage,
|
|
@@ -80,14 +88,17 @@ from sdmxlib.model import (
|
|
|
80
88
|
DataType,
|
|
81
89
|
Facet,
|
|
82
90
|
Ref,
|
|
91
|
+
RegexValueMap,
|
|
83
92
|
RegistryReader,
|
|
84
93
|
Representation,
|
|
94
|
+
RepresentationMap,
|
|
85
95
|
SdmxRef,
|
|
86
96
|
SdmxUrn,
|
|
97
|
+
StructureMap,
|
|
87
98
|
StructureMessage,
|
|
88
|
-
StructureSet,
|
|
89
99
|
TimeDimension,
|
|
90
100
|
UnresolvedRef,
|
|
101
|
+
ValueMap,
|
|
91
102
|
artefact_urn,
|
|
92
103
|
code,
|
|
93
104
|
node,
|
|
@@ -100,42 +111,44 @@ __all__ = [
|
|
|
100
111
|
"AgencyScheme",
|
|
101
112
|
"Annotation",
|
|
102
113
|
"Annotations",
|
|
114
|
+
"AnyRef",
|
|
103
115
|
"ArtefactList",
|
|
116
|
+
"AttachmentConstraint",
|
|
104
117
|
"AttachmentLevel",
|
|
105
118
|
"Attribute",
|
|
119
|
+
"AttributeUsage",
|
|
106
120
|
"BearerToken",
|
|
121
|
+
"CascadeSelection",
|
|
107
122
|
"Categorisation",
|
|
108
123
|
"Category",
|
|
109
|
-
"CategoryMap",
|
|
110
124
|
"CategoryScheme",
|
|
111
125
|
"CategorySchemeMap",
|
|
112
126
|
"Code",
|
|
113
|
-
"CodeMap",
|
|
114
127
|
"CodeQuery",
|
|
128
|
+
"CodeSelection",
|
|
115
129
|
"Codelist",
|
|
116
|
-
"
|
|
130
|
+
"CodelistExtension",
|
|
117
131
|
"CompileContext",
|
|
118
132
|
"ComponentFilter",
|
|
119
133
|
"ComponentMap",
|
|
120
134
|
"Concept",
|
|
121
|
-
"ConceptMap",
|
|
122
135
|
"ConceptScheme",
|
|
123
136
|
"ConceptSchemeMap",
|
|
124
137
|
"ConstraintAttachment",
|
|
138
|
+
"ConstraintType",
|
|
125
139
|
"Contact",
|
|
126
140
|
"CubeRegion",
|
|
127
141
|
"DataConstraint",
|
|
142
|
+
"DataKey",
|
|
128
143
|
"DataProvider",
|
|
129
144
|
"DataProviderScheme",
|
|
130
145
|
"DataQuery",
|
|
131
146
|
"DataStore",
|
|
132
147
|
"DataStructure",
|
|
133
|
-
"DataStructureMap",
|
|
134
148
|
"DataType",
|
|
135
149
|
"Dataflow",
|
|
136
150
|
"DataflowBinding",
|
|
137
151
|
"DataflowEntry",
|
|
138
|
-
"DataflowMap",
|
|
139
152
|
"Dataset",
|
|
140
153
|
"DimFilter",
|
|
141
154
|
"Dimension",
|
|
@@ -149,20 +162,26 @@ __all__ = [
|
|
|
149
162
|
"Group",
|
|
150
163
|
"HierarchicalCode",
|
|
151
164
|
"Hierarchy",
|
|
165
|
+
"HierarchyAssociation",
|
|
152
166
|
"HierarchyNodeQuery",
|
|
153
167
|
"InMemoryRegistry",
|
|
168
|
+
"InclusionMode",
|
|
169
|
+
"IndexValueMap",
|
|
154
170
|
"InternationalString",
|
|
155
171
|
"ItemExpr",
|
|
156
172
|
"ItemList",
|
|
173
|
+
"ItemMap",
|
|
157
174
|
"ItemPredicate",
|
|
158
175
|
"KeyValue",
|
|
159
176
|
"LazyCodelist",
|
|
160
177
|
"LazyHierarchy",
|
|
161
178
|
"Level",
|
|
179
|
+
"LiteralValueMap",
|
|
162
180
|
"Maintainable",
|
|
163
181
|
"MaintainableArtefact",
|
|
164
182
|
"Measure",
|
|
165
183
|
"MeasureDimension",
|
|
184
|
+
"MemberValue",
|
|
166
185
|
"MetadataAttribute",
|
|
167
186
|
"MetadataMessage",
|
|
168
187
|
"MetadataSet",
|
|
@@ -174,6 +193,7 @@ __all__ = [
|
|
|
174
193
|
"Ref",
|
|
175
194
|
"ReferenceIssue",
|
|
176
195
|
"ReferencePeriod",
|
|
196
|
+
"RegexValueMap",
|
|
177
197
|
"Registry",
|
|
178
198
|
"RegistryReader",
|
|
179
199
|
"RegistryUnavailable",
|
|
@@ -181,15 +201,17 @@ __all__ = [
|
|
|
181
201
|
"ReportedAttribute",
|
|
182
202
|
"ReportedAttributeValue",
|
|
183
203
|
"Representation",
|
|
204
|
+
"RepresentationMap",
|
|
184
205
|
"RestRegistry",
|
|
185
206
|
"SdmxRef",
|
|
186
207
|
"SdmxUrn",
|
|
187
208
|
"SqlRelation",
|
|
209
|
+
"StructureMap",
|
|
188
210
|
"StructureMessage",
|
|
189
|
-
"StructureSet",
|
|
190
211
|
"TimeDimension",
|
|
191
212
|
"UnresolvedRef",
|
|
192
213
|
"ValidationIssue",
|
|
214
|
+
"ValueMap",
|
|
193
215
|
"artefact_urn",
|
|
194
216
|
"code",
|
|
195
217
|
"dim",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Private DuckDB helpers shared by the storage layer and model query DSLs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import duckdb
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def scalar(cursor: duckdb.DuckDBPyConnection, default: Any = None) -> Any:
|
|
11
|
+
"""Return the first column of the cursor's first row, or *default* if empty.
|
|
12
|
+
|
|
13
|
+
Centralises the ``row = cur.fetchone(); row[0] if row else default``
|
|
14
|
+
idiom so callers don't need to repeat the indexing dance or paper over
|
|
15
|
+
pyright with ``# type: ignore[index]``.
|
|
16
|
+
"""
|
|
17
|
+
row = cursor.fetchone()
|
|
18
|
+
return row[0] if row is not None else default
|
|
@@ -134,7 +134,9 @@ class SdmxClient:
|
|
|
134
134
|
response = self._client.get(url, params=params)
|
|
135
135
|
response.raise_for_status()
|
|
136
136
|
msg = parse(response.content, version=self._parse_version)
|
|
137
|
-
|
|
137
|
+
if not isinstance(msg, StructureMessage):
|
|
138
|
+
err = f"Expected StructureMessage from structure endpoint, got {type(msg).__name__}"
|
|
139
|
+
raise TypeError(err)
|
|
138
140
|
return msg
|
|
139
141
|
|
|
140
142
|
def get_all(
|
|
@@ -153,7 +155,9 @@ class SdmxClient:
|
|
|
153
155
|
response = self._client.get(url, params=params)
|
|
154
156
|
response.raise_for_status()
|
|
155
157
|
msg = parse(response.content, version=self._parse_version)
|
|
156
|
-
|
|
158
|
+
if not isinstance(msg, StructureMessage):
|
|
159
|
+
err = f"Expected StructureMessage from structure endpoint, got {type(msg).__name__}"
|
|
160
|
+
raise TypeError(err)
|
|
157
161
|
return msg
|
|
158
162
|
|
|
159
163
|
def _data_url(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""FederatedRegistry — agency-routed dispatch across multiple sources.
|
|
2
2
|
|
|
3
|
-
The headline of #46. Composes any number of
|
|
3
|
+
The headline of #46. Composes any number of `Registry`
|
|
4
4
|
instances (in-memory, local DuckDB, REST) and dispatches each ``get(urn)``
|
|
5
5
|
call to the source responsible for the URN's maintenance agency. The user
|
|
6
6
|
sees a single registry that resolves URNs from many backends.
|
|
@@ -45,23 +45,23 @@ class FederatedRegistry:
|
|
|
45
45
|
"""Read-side dispatcher across multiple Registry sources.
|
|
46
46
|
|
|
47
47
|
Routes each URN-keyed lookup by maintenance agency. Configure with a
|
|
48
|
-
``routing`` map from agency id to a
|
|
48
|
+
``routing`` map from agency id to a `Registry` source, plus
|
|
49
49
|
an optional ``default`` source for agencies absent from the map.
|
|
50
50
|
|
|
51
|
-
Satisfies the
|
|
51
|
+
Satisfies the `Registry` Protocol —
|
|
52
52
|
a ``FederatedRegistry`` can itself be a source in another
|
|
53
53
|
``FederatedRegistry`` (composition).
|
|
54
54
|
|
|
55
55
|
Args:
|
|
56
56
|
routing: Mapping of agency id (e.g. ``"ESTAT"``, ``"SDMX"``) to a
|
|
57
|
-
|
|
57
|
+
`Registry` source. Lookup keys are matched against
|
|
58
58
|
``SdmxUrn.agency``.
|
|
59
59
|
default: Optional fallback source for URNs whose agency is not
|
|
60
60
|
in ``routing``. ``None`` (the default) means "no fallback":
|
|
61
|
-
unrouted URNs raise
|
|
61
|
+
unrouted URNs raise `KeyError`.
|
|
62
62
|
failure: How to treat exceptions raised by a routed source.
|
|
63
|
-
Defaults to
|
|
64
|
-
underlying error wrapped in
|
|
63
|
+
Defaults to `HARD_FAIL` — propagate the
|
|
64
|
+
underlying error wrapped in `RegistryUnavailable`.
|
|
65
65
|
|
|
66
66
|
Note:
|
|
67
67
|
FederatedRegistry is a *router*, not a *store*. It has no
|
|
@@ -117,9 +117,9 @@ class FederatedRegistry:
|
|
|
117
117
|
- URN agency absent and no default → raise ``KeyError``.
|
|
118
118
|
|
|
119
119
|
Errors from the routed source are wrapped in
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
``None``) when ``failure`` is
|
|
120
|
+
`RegistryUnavailable` when ``failure`` is
|
|
121
|
+
`HARD_FAIL` (default), or swallowed (returning
|
|
122
|
+
``None``) when ``failure`` is `RETURN_NONE`.
|
|
123
123
|
"""
|
|
124
124
|
source = self._route(urn)
|
|
125
125
|
if source is None:
|
|
@@ -9,7 +9,7 @@ from attrs import frozen
|
|
|
9
9
|
class DimFilter:
|
|
10
10
|
"""A resolved server-side filter on a single dimension.
|
|
11
11
|
|
|
12
|
-
Produced by
|
|
12
|
+
Produced by `dim` expressions — not constructed directly.
|
|
13
13
|
|
|
14
14
|
Attributes:
|
|
15
15
|
id: DSD dimension id.
|
|
@@ -21,7 +21,7 @@ class DimFilter:
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class _DimExpr:
|
|
24
|
-
"""Builder returned by
|
|
24
|
+
"""Builder returned by `dim`. Produces a `DimFilter` via ``==`` or ``.isin()``."""
|
|
25
25
|
|
|
26
26
|
def __init__(self, id: str) -> None: # noqa: A002
|
|
27
27
|
self._id = id
|
|
@@ -50,7 +50,7 @@ class _DimExpr:
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
def dim(id: str) -> _DimExpr: # noqa: A002
|
|
53
|
-
"""Create a server-side dimension filter expression for
|
|
53
|
+
"""Create a server-side dimension filter expression for `slice`.
|
|
54
54
|
|
|
55
55
|
Use ``==`` for a single code or ``.isin()`` for multiple codes (OR semantics).
|
|
56
56
|
Dimensions not mentioned in any filter become wildcards in the SDMX REST key.
|
|
@@ -4,7 +4,7 @@ Per #46's pitfall list ("Partial failure handling"), there are several
|
|
|
4
4
|
valid behaviours when a routed source is unreachable: hard-fail, return
|
|
5
5
|
``None`` (treat as not-found), or fall through to a stale local cache.
|
|
6
6
|
The policy is configurable per source or globally on
|
|
7
|
-
|
|
7
|
+
`FederatedRegistry`.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
from enum import Enum
|
|
@@ -19,7 +19,7 @@ class ProviderInfo:
|
|
|
19
19
|
url: Base REST endpoint URL.
|
|
20
20
|
api: SDMX REST API version (``"2.1"`` or ``"3.0"``).
|
|
21
21
|
id: Stable identifier used as the ``source_registry`` provenance
|
|
22
|
-
tag when a
|
|
22
|
+
tag when a `RestRegistry` materialises through to a
|
|
23
23
|
local store. Required for federation; ``None`` for ad-hoc
|
|
24
24
|
URLs without a known label.
|
|
25
25
|
"""
|
|
@@ -32,7 +32,7 @@ class ProviderInfo:
|
|
|
32
32
|
class Provider:
|
|
33
33
|
"""Built-in SDMX REST endpoint URLs.
|
|
34
34
|
|
|
35
|
-
Each entry is a
|
|
35
|
+
Each entry is a `ProviderInfo` carrying the endpoint URL and its
|
|
36
36
|
REST API version. Pass directly to ``RestRegistry``::
|
|
37
37
|
|
|
38
38
|
with sl.RestRegistry(sl.Provider.ECB) as reg:
|
|
@@ -252,15 +252,15 @@ class Query[T]:
|
|
|
252
252
|
|
|
253
253
|
|
|
254
254
|
class DataQuery:
|
|
255
|
-
"""Lazy data fetch — resolves to a
|
|
255
|
+
"""Lazy data fetch — resolves to a `Dataset`.
|
|
256
256
|
|
|
257
|
-
Returned by
|
|
258
|
-
|
|
259
|
-
directly to a file for large datasets. Use
|
|
260
|
-
|
|
257
|
+
Returned by `data`. Use
|
|
258
|
+
`fetch` for in-memory loading or `fetch_to` to stream
|
|
259
|
+
directly to a file for large datasets. Use `slice` and
|
|
260
|
+
`measures` to filter what comes over the wire.
|
|
261
261
|
|
|
262
262
|
Example:
|
|
263
|
-
# Raw positional key string
|
|
263
|
+
# Raw SDMX REST positional key string
|
|
264
264
|
ds = reg.data(flow, key="M.USD.EUR.SP00.A").fetch()
|
|
265
265
|
|
|
266
266
|
# Named dimension filter — no positional knowledge needed
|
|
@@ -301,13 +301,13 @@ class DataQuery:
|
|
|
301
301
|
def slice(self, *filters: DimFilter) -> Self:
|
|
302
302
|
"""Add server-side dimension filters to the SDMX key.
|
|
303
303
|
|
|
304
|
-
Each filter is a
|
|
305
|
-
|
|
304
|
+
Each filter is a `DimFilter` produced by
|
|
305
|
+
`dim`. Calling ``.slice()`` multiple times accumulates
|
|
306
306
|
filters — each call is additive.
|
|
307
307
|
|
|
308
308
|
Unspecified dimensions become wildcards. Raises ``ValueError`` if
|
|
309
309
|
``key=`` was also passed to
|
|
310
|
-
|
|
310
|
+
`data`.
|
|
311
311
|
|
|
312
312
|
Example:
|
|
313
313
|
import sdmxlib as sl
|
|
@@ -337,7 +337,7 @@ class DataQuery:
|
|
|
337
337
|
|
|
338
338
|
For SDMX 2.1 flows with a ``MeasureDimension`` (e.g. ``INDIC_EM``),
|
|
339
339
|
this filters the indicator key segment — controlling which columns
|
|
340
|
-
appear after
|
|
340
|
+
appear after `pivot`. For SDMX 3.0 multi-measure flows this
|
|
341
341
|
will become the ``measures=`` query parameter.
|
|
342
342
|
|
|
343
343
|
``codes`` is a single code string or a list of code strings.
|
|
@@ -412,8 +412,8 @@ class DataQuery:
|
|
|
412
412
|
|
|
413
413
|
Uses httpx chunked streaming — the response is never fully loaded into
|
|
414
414
|
memory. The returned ``Dataset.data`` is a genuine ``pl.LazyFrame``
|
|
415
|
-
backed by ``pl.scan_csv``, so
|
|
416
|
-
and
|
|
415
|
+
backed by ``pl.scan_csv``, so `sink_parquet`
|
|
416
|
+
and `sink_csv` are truly streaming.
|
|
417
417
|
|
|
418
418
|
The caller owns the file — it is not deleted when the Dataset is
|
|
419
419
|
garbage collected.
|