pysdmx 1.11.0__py3-none-any.whl → 1.12.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 CHANGED
@@ -1,3 +1,3 @@
1
1
  """Your opinionated Python SDMX library."""
2
2
 
3
- __version__ = "1.11.0"
3
+ __version__ = "1.12.0"
@@ -1,6 +1,6 @@
1
1
  """Collection of Fusion-JSON schemas for content constraints."""
2
2
 
3
- from typing import Dict, Sequence
3
+ from typing import Dict, List, Optional, Sequence
4
4
 
5
5
  from msgspec import Struct
6
6
 
@@ -11,11 +11,32 @@ class FusionKeyValue(Struct, frozen=True):
11
11
  values: Sequence[str]
12
12
 
13
13
 
14
+ class FusionKeySet(Struct, frozen=True):
15
+ """Fusion-JSON payload for the list of allowed values per component."""
16
+
17
+ dims: Sequence[str]
18
+ rows: Sequence[Sequence[str]]
19
+
20
+
14
21
  class FusionContentConstraint(Struct, frozen=True):
15
22
  """Fusion-JSON payload for a content constraint."""
16
23
 
17
24
  includeCube: Dict[str, FusionKeyValue] = {}
25
+ includeSeries: Optional[FusionKeySet] = None
18
26
 
19
27
  def to_map(self) -> Dict[str, Sequence[str]]:
20
28
  """Gets the list of allowed values for a component."""
21
29
  return {k: v.values for k, v in self.includeCube.items()}
30
+
31
+ def get_series(self, dimensions: List[str]) -> Sequence[str]:
32
+ """Get the list of series defined in the keyset."""
33
+ if self.includeSeries:
34
+ series = []
35
+ for r in self.includeSeries.rows:
36
+ s = dict.fromkeys(dimensions, "*")
37
+ for idx, cd in enumerate(self.includeSeries.dims):
38
+ s[cd] = r[idx]
39
+ series.append(".".join(s.values()))
40
+ return series
41
+ else:
42
+ return []
@@ -163,6 +163,7 @@ class FusionDimension(Struct, frozen=True):
163
163
  id: str
164
164
  concept: str
165
165
  representation: Optional[FusionRepresentation] = None
166
+ isTimeDimension: bool = False
166
167
 
167
168
  def to_model(
168
169
  self,
@@ -65,6 +65,25 @@ class FusionSchemaMessage(msgspec.Struct, frozen=True):
65
65
  mapped_grps = [
66
66
  Group(g.id, dimensions=g.dimensionReferences) for g in grps
67
67
  ]
68
+ keys: List[str] = []
69
+ for dc in self.DataConstraint:
70
+ keys.extend(
71
+ dc.get_series(
72
+ [
73
+ d.id
74
+ for d in self.DataStructure[0].dimensionList.dimensions
75
+ if not d.isTimeDimension
76
+ ]
77
+ )
78
+ )
79
+ keys = list(set(keys)) if keys else None # type: ignore[assignment]
68
80
  return Schema(
69
- context, agency, id_, comps, version, urns, groups=mapped_grps
81
+ context,
82
+ agency,
83
+ id_,
84
+ comps,
85
+ version,
86
+ urns,
87
+ groups=mapped_grps,
88
+ keys=keys,
70
89
  )
@@ -1,12 +1,15 @@
1
1
  """Collection of SDMX-JSON schemas for SDMX-REST schema queries."""
2
2
 
3
- from typing import Literal, Optional, Sequence, Tuple
3
+ from typing import Dict, Literal, Optional, Sequence, Tuple
4
4
 
5
5
  import msgspec
6
6
 
7
7
  from pysdmx.io.json.sdmxjson2.messages.code import JsonCodelist, JsonValuelist
8
8
  from pysdmx.io.json.sdmxjson2.messages.concept import JsonConceptScheme
9
- from pysdmx.io.json.sdmxjson2.messages.constraint import JsonDataConstraint
9
+ from pysdmx.io.json.sdmxjson2.messages.constraint import (
10
+ JsonDataConstraint,
11
+ JsonKeySet,
12
+ )
10
13
  from pysdmx.io.json.sdmxjson2.messages.core import JsonHeader
11
14
  from pysdmx.io.json.sdmxjson2.messages.dsd import JsonDataStructure
12
15
  from pysdmx.model import Components, HierarchyAssociation, Schema
@@ -25,7 +28,7 @@ class JsonSchemas(msgspec.Struct, frozen=True, omit_defaults=True):
25
28
 
26
29
  def to_model(
27
30
  self,
28
- ) -> Tuple[Components, Optional[Sequence[Group]]]:
31
+ ) -> Tuple[Components, Optional[Sequence[Group]], Optional[Sequence[str]]]:
29
32
  """Returns the requested schema."""
30
33
  comps = self.dataStructures[0].dataStructureComponents
31
34
  comps, grps = comps.to_model( # type: ignore[union-attr,assignment]
@@ -34,7 +37,36 @@ class JsonSchemas(msgspec.Struct, frozen=True, omit_defaults=True):
34
37
  self.valuelists,
35
38
  self.dataConstraints,
36
39
  )
37
- return comps, grps # type: ignore[return-value]
40
+ keys = self.__process_keys()
41
+ return comps, grps, keys # type: ignore[return-value]
42
+
43
+ def __extract_keys_dict(
44
+ self, keysets: Sequence[JsonKeySet]
45
+ ) -> Sequence[Dict[str, str]]:
46
+ keys = []
47
+ for ks in keysets:
48
+ keys.extend(
49
+ [{kv.id: kv.value for kv in k.keyValues} for k in ks.keys]
50
+ )
51
+ return keys
52
+
53
+ def __infer_keys(self, keys_dict: Dict[str, str]) -> str:
54
+ dimensions = [
55
+ d.id
56
+ for d in self.dataStructures[ # type: ignore[union-attr]
57
+ 0
58
+ ].dataStructureComponents.dimensionList.dimensions
59
+ ]
60
+ dim_values = [keys_dict.get(d, "*") for d in dimensions]
61
+ return ".".join(dim_values)
62
+
63
+ def __process_keys(self) -> Optional[Sequence[str]]:
64
+ keys = []
65
+ for c in self.dataConstraints:
66
+ if c.dataKeySets:
67
+ keys_dicts = self.__extract_keys_dict(c.dataKeySets)
68
+ keys.extend([self.__infer_keys(d) for d in keys_dicts])
69
+ return list(set(keys))
38
70
 
39
71
 
40
72
  class JsonSchemaMessage(msgspec.Struct, frozen=True, omit_defaults=True):
@@ -52,7 +84,7 @@ class JsonSchemaMessage(msgspec.Struct, frozen=True, omit_defaults=True):
52
84
  hierarchies: Sequence[HierarchyAssociation],
53
85
  ) -> Schema:
54
86
  """Returns the requested schema."""
55
- components, groups = self.data.to_model()
87
+ components, groups, keys = self.data.to_model()
56
88
  comp_dict = {c.id: c for c in components}
57
89
  urns = [a.urn for a in self.meta.links]
58
90
  for ha in hierarchies:
@@ -77,4 +109,5 @@ class JsonSchemaMessage(msgspec.Struct, frozen=True, omit_defaults=True):
77
109
  version,
78
110
  urns, # type: ignore[arg-type]
79
111
  groups=groups,
112
+ keys=keys,
80
113
  )
pysdmx/model/dataflow.py CHANGED
@@ -487,6 +487,14 @@ class Schema(Struct, frozen=True, omit_defaults=True, repr_omit_defaults=True):
487
487
  if any of the artefacts listed under the artefacts
488
488
  property has been updated after the schema was
489
489
  generated, you might want to regenerate the schema.
490
+ name: The schema name.
491
+ groups: The list of groups defined in the data structure.
492
+ keys: The list of allowed series. This is the equivalent
493
+ of an SDMX KeySet. KeySets allow finer
494
+ restrictions than when components only (i.e. SDMX
495
+ CubeRegions). The values in the sequence follow
496
+ the SDMX-REST conventions for series wildcarding
497
+ (e.g. *.USD.CHF.*).
490
498
  """
491
499
 
492
500
  context: Literal["datastructure", "dataflow", "provisionagreement"]
@@ -498,6 +506,7 @@ class Schema(Struct, frozen=True, omit_defaults=True, repr_omit_defaults=True):
498
506
  generated: datetime = datetime.now(timezone.utc)
499
507
  name: Optional[str] = None
500
508
  groups: Optional[Sequence[Group]] = None
509
+ keys: Optional[Sequence[str]] = None
501
510
 
502
511
  def __str__(self) -> str:
503
512
  """Custom string representation without the class name."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pysdmx
3
- Version: 1.11.0
3
+ Version: 1.12.0
4
4
  Summary: Your opinionated Python SDMX library
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -1,5 +1,5 @@
1
1
  pysdmx/__extras_check.py,sha256=Tmluui2OuJVyJB6a1Jl0PlrRjpsswhtCjAqtRLOSero,2059
2
- pysdmx/__init__.py,sha256=8EDbBiciJ8gxk5fE9tPCuRnhh-xaYrjzgW5j86WRuwk,68
2
+ pysdmx/__init__.py,sha256=LCdSlP0rLXyq15h8hnc9obDN-ntA9c4EgVNKcYeP7IM,68
3
3
  pysdmx/api/__init__.py,sha256=8lRaF6kEO51ehl0fmW_pHLvkN_34TtEhqhr3oKo6E6g,26
4
4
  pysdmx/api/dc/__init__.py,sha256=oPU32X8CRZy4T1to9mO5KMqMwxQsVI424dPqai-I8zI,121
5
5
  pysdmx/api/dc/_api.py,sha256=poy1FYFXnF6maBGy5lpOodf32-7QQjH8PCBNDkuOXxQ,7747
@@ -43,10 +43,10 @@ pysdmx/io/json/fusion/messages/__init__.py,sha256=ac2jWfjGGBcfoSutiKy68LzqwNp_cl
43
43
  pysdmx/io/json/fusion/messages/category.py,sha256=2NnYTptQ6nAdeYBIkAysyriTFF6dW8fjb9AvRWtTOao,5606
44
44
  pysdmx/io/json/fusion/messages/code.py,sha256=YayxSKiHa124WTr_lK8HTfXHomh_e0oDZvuydd29XKg,8300
45
45
  pysdmx/io/json/fusion/messages/concept.py,sha256=m4lTyncSIriFXWWupE-zLxUVPx3Xrg56qahzKr4HEag,2824
46
- pysdmx/io/json/fusion/messages/constraint.py,sha256=dPkzhCWN49Y9ReSZPRFTdM6GWc0rU2BZTyFfWsqlX34,615
46
+ pysdmx/io/json/fusion/messages/constraint.py,sha256=pQlirYnZLCD-qqwcqHtAuYaBqU3R-o449nMubyDyC-g,1353
47
47
  pysdmx/io/json/fusion/messages/core.py,sha256=GdzF3TNUGrB0gxuaaSpk9LaYqcdy_M6L2azExZQfM0Q,4843
48
48
  pysdmx/io/json/fusion/messages/dataflow.py,sha256=lsaMPjmA-KiM51I78wrONfNHyvfBSeAll5Sp0jmTezc,2972
49
- pysdmx/io/json/fusion/messages/dsd.py,sha256=0YA87KkDAoFlOCi4MboU4MhHEqc_5Wqx2A90pZG5q6o,10668
49
+ pysdmx/io/json/fusion/messages/dsd.py,sha256=67Wym_OLnUERBQGJehu08MdFvH1p3UcUbiz0WZ69zV8,10702
50
50
  pysdmx/io/json/fusion/messages/map.py,sha256=TPsCFuUfk5Jhhe7CNvEoHuFNZFpHhvNiYFWeIEUx-sc,7695
51
51
  pysdmx/io/json/fusion/messages/metadataflow.py,sha256=Js4j8lUF9ZwqL7lJUrfrjk9tmBmRQPt8qxdrfnZ6R5E,1374
52
52
  pysdmx/io/json/fusion/messages/mpa.py,sha256=WvcHn7Pa_UBHxkZbfSzIxc8qeeMfTWThxgCRHuioXFY,1494
@@ -54,7 +54,7 @@ pysdmx/io/json/fusion/messages/msd.py,sha256=XzQ5JiX0rAswj71a3mCYulhGLtu7GDp_RzL
54
54
  pysdmx/io/json/fusion/messages/org.py,sha256=gWIvmvVrj5wXCrwbsJL0B13YM3WjlfIQxrRUc_WAoYs,9538
55
55
  pysdmx/io/json/fusion/messages/pa.py,sha256=6zN8Qxj5bdf5zo2N9TwYlSLyGxokvsELtk1--1cMbxw,1393
56
56
  pysdmx/io/json/fusion/messages/report.py,sha256=ZE62ZmHlCXk3TxRTRWCDCKVMhnN0J5UjMEzrsnD5I3E,1551
57
- pysdmx/io/json/fusion/messages/schema.py,sha256=xBbpLyJNapJpzZA4vAvROmWTSNYymcpggqMZ_NjL444,2603
57
+ pysdmx/io/json/fusion/messages/schema.py,sha256=cdC2OTcuJFqR9GeyCr0OxL-jYjSdN0HKFMp1OkfORCA,3134
58
58
  pysdmx/io/json/fusion/messages/vtl.py,sha256=7VGjDRWzKMO6WT4CnGvGBKinhX06DzrJmDRudnvN4XM,16092
59
59
  pysdmx/io/json/fusion/reader/__init__.py,sha256=4lFrsX0Flhvlopv5FAYZBeQMPtmnMm5HgC-q7Pey0dw,1710
60
60
  pysdmx/io/json/gds/messages/__init__.py,sha256=5LqGtO3GDi2B6HM2eDGCSJCncLS8C4MQ7vd5YBvCRok,885
@@ -80,7 +80,7 @@ pysdmx/io/json/sdmxjson2/messages/msd.py,sha256=cYQqWOex5LVYE-8ASsyIwI_Y0jCuT9IP
80
80
  pysdmx/io/json/sdmxjson2/messages/pa.py,sha256=VoaPBgcWGwWU7h5IaVa5wNWncOoktWihSXjcP4vEb00,2780
81
81
  pysdmx/io/json/sdmxjson2/messages/provider.py,sha256=htAwdDzVR3qeyExhmjpvg8W0X4lWqRh2Bvd5H8wsOTY,8197
82
82
  pysdmx/io/json/sdmxjson2/messages/report.py,sha256=jr4HZunfnQicG2AFi15AGX_v031jNb3d6PiQgc8TPgY,6672
83
- pysdmx/io/json/sdmxjson2/messages/schema.py,sha256=JwFYjgvhK_1NN5KQIUYNb0ul4ywQhDQ28ZQBGnsX5X4,2862
83
+ pysdmx/io/json/sdmxjson2/messages/schema.py,sha256=TfsYPKyaQRz-nd6wiSwtL2_VrLJFJQ4rzZmFeU-bH3E,3960
84
84
  pysdmx/io/json/sdmxjson2/messages/structure.py,sha256=GCpQboHEpDyfCmXVJGbCyKpIaLCbOXYDxj6WXnvv9pw,12851
85
85
  pysdmx/io/json/sdmxjson2/messages/vtl.py,sha256=C-JQY1_W8SrJd2lLdUGCmQO9Br1pdqdT8WmB1K4e_yY,35284
86
86
  pysdmx/io/json/sdmxjson2/reader/__init__.py,sha256=RbNnZSrGQa4OE0HBWJau9tPFSQbDklcKZaBWOzxEw4I,1629
@@ -146,7 +146,7 @@ pysdmx/model/category.py,sha256=ksYIOGPHgZI619RhmRXZUXHP_juY9im40tWzR2yuMEc,6796
146
146
  pysdmx/model/code.py,sha256=Wu6rEXeZf_XA0aBrDXgN-3yvySAHH7SAjrWliFlmC24,12799
147
147
  pysdmx/model/concept.py,sha256=mQfqJdtWc10WdTKX_Mw7Znw65cN3QO-kCar9MWYeWO4,9645
148
148
  pysdmx/model/constraint.py,sha256=MwI_GLKzwkuo0BzAsgcnDeB-b7bq8qqwHNte5JjCEFA,1960
149
- pysdmx/model/dataflow.py,sha256=hNeQjNXebjaDbakx05bfzcQ9DoplZMQi1BUW4NH6lnI,24201
149
+ pysdmx/model/dataflow.py,sha256=FjXuMfAme1JyO1WCFV_yw0WcYqwXMB7kG0mOUwh04q8,24670
150
150
  pysdmx/model/dataset.py,sha256=Lbr7tYonGHD3NZUD-M9hK2puaEAluOVPG2DbkOohzMM,4861
151
151
  pysdmx/model/gds.py,sha256=QrnmI8Hn--C95gGXCeUeWwhn-Ur7DuT08Cg7oPJIEVI,4976
152
152
  pysdmx/model/map.py,sha256=9a3hl6efq_5kAYuJWkepoQOkao8Eqk17N69JGyRfxsk,17506
@@ -168,7 +168,7 @@ pysdmx/util/__init__.py,sha256=m_XWRAmVJ7F6ai4Ckrj_YuPbhg3cJZAXeZrEThrL88k,3997
168
168
  pysdmx/util/_date_pattern_map.py,sha256=IS1qONwVHbTBNIFCT0Rqbijj2a9mYvs7onXSK6GeQAQ,1620
169
169
  pysdmx/util/_model_utils.py,sha256=nQ1yWBt-tZYDios9xvRvJ7tHq6A8_RoGdY1wi7WGz2w,3793
170
170
  pysdmx/util/_net_utils.py,sha256=nOTz_x3FgFrwKh42_J70IqYXz9duQkMFJWtejZXcLHs,1326
171
- pysdmx-1.11.0.dist-info/METADATA,sha256=eO9SWX3mB1x9glSSm9wEJxu7JQoiHz9Rj9Ac1oPnQZI,5364
172
- pysdmx-1.11.0.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
173
- pysdmx-1.11.0.dist-info/licenses/LICENSE,sha256=3XTNDPtv2RxDUNkQzn9MIWit2u7_Ob5daMLEq-4pBJs,649
174
- pysdmx-1.11.0.dist-info/RECORD,,
171
+ pysdmx-1.12.0.dist-info/METADATA,sha256=Lh2s5ZlVZY0MY1taf1MeFSTlqF1mJIiWEYX1qqRCLps,5364
172
+ pysdmx-1.12.0.dist-info/WHEEL,sha256=kJCRJT_g0adfAJzTx2GUMmS80rTJIVHRCfG0DQgLq3o,88
173
+ pysdmx-1.12.0.dist-info/licenses/LICENSE,sha256=3XTNDPtv2RxDUNkQzn9MIWit2u7_Ob5daMLEq-4pBJs,649
174
+ pysdmx-1.12.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.3.0
2
+ Generator: poetry-core 2.3.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any