pysdmx 1.0.0b3__tar.gz → 1.10.1__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.
Files changed (200) hide show
  1. pysdmx-1.10.1/PKG-INFO +123 -0
  2. pysdmx-1.10.1/README.rst +78 -0
  3. pysdmx-1.10.1/pyproject.toml +123 -0
  4. pysdmx-1.10.1/src/pysdmx/__extras_check.py +71 -0
  5. {pysdmx-1.0.0b3 → pysdmx-1.10.1}/src/pysdmx/__init__.py +1 -1
  6. pysdmx-1.10.1/src/pysdmx/api/__init__.py +1 -0
  7. pysdmx-1.10.1/src/pysdmx/api/dc/__init__.py +5 -0
  8. pysdmx-1.10.1/src/pysdmx/api/dc/_api.py +213 -0
  9. pysdmx-1.10.1/src/pysdmx/api/dc/query/__init__.py +27 -0
  10. pysdmx-1.10.1/src/pysdmx/api/dc/query/_model.py +135 -0
  11. pysdmx-1.10.1/src/pysdmx/api/dc/query/_parsing_model.py +70 -0
  12. pysdmx-1.10.1/src/pysdmx/api/dc/query/_parsing_util.py +80 -0
  13. pysdmx-1.10.1/src/pysdmx/api/dc/query/_py_parser.py +67 -0
  14. pysdmx-1.10.1/src/pysdmx/api/dc/query/_sql_parser.py +67 -0
  15. pysdmx-1.10.1/src/pysdmx/api/dc/query/util.py +30 -0
  16. pysdmx-1.10.1/src/pysdmx/api/fmr/__init__.py +1464 -0
  17. pysdmx-1.10.1/src/pysdmx/api/fmr/maintenance.py +158 -0
  18. pysdmx-1.10.1/src/pysdmx/api/gds/__init__.py +328 -0
  19. pysdmx-1.10.1/src/pysdmx/api/qb/__init__.py +60 -0
  20. pysdmx-1.10.1/src/pysdmx/api/qb/availability.py +280 -0
  21. pysdmx-1.10.1/src/pysdmx/api/qb/data.py +629 -0
  22. pysdmx-1.10.1/src/pysdmx/api/qb/gds.py +153 -0
  23. pysdmx-1.10.1/src/pysdmx/api/qb/refmeta.py +295 -0
  24. pysdmx-1.10.1/src/pysdmx/api/qb/registration.py +227 -0
  25. pysdmx-1.10.1/src/pysdmx/api/qb/schema.py +157 -0
  26. pysdmx-1.10.1/src/pysdmx/api/qb/service.py +402 -0
  27. pysdmx-1.10.1/src/pysdmx/api/qb/structure.py +515 -0
  28. pysdmx-1.10.1/src/pysdmx/api/qb/util.py +120 -0
  29. pysdmx-1.10.1/src/pysdmx/errors.py +104 -0
  30. pysdmx-1.10.1/src/pysdmx/io/__init__.py +6 -0
  31. pysdmx-1.10.1/src/pysdmx/io/csv/__csv_aux_reader.py +99 -0
  32. pysdmx-1.10.1/src/pysdmx/io/csv/__csv_aux_writer.py +118 -0
  33. pysdmx-1.10.1/src/pysdmx/io/csv/__init__.py +5 -0
  34. pysdmx-1.10.1/src/pysdmx/io/csv/sdmx10/__init__.py +1 -0
  35. pysdmx-1.10.1/src/pysdmx/io/csv/sdmx10/reader/__init__.py +84 -0
  36. pysdmx-1.10.1/src/pysdmx/io/csv/sdmx10/writer/__init__.py +81 -0
  37. pysdmx-1.10.1/src/pysdmx/io/csv/sdmx20/__init__.py +1 -0
  38. pysdmx-1.10.1/src/pysdmx/io/csv/sdmx20/reader/__init__.py +86 -0
  39. pysdmx-1.10.1/src/pysdmx/io/csv/sdmx20/writer/__init__.py +73 -0
  40. pysdmx-1.10.1/src/pysdmx/io/csv/sdmx21/__init__.py +1 -0
  41. pysdmx-1.10.1/src/pysdmx/io/csv/sdmx21/reader/__init__.py +86 -0
  42. pysdmx-1.10.1/src/pysdmx/io/csv/sdmx21/writer/__init__.py +70 -0
  43. pysdmx-1.10.1/src/pysdmx/io/format.py +124 -0
  44. pysdmx-1.10.1/src/pysdmx/io/input_processor.py +200 -0
  45. pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages/__init__.py +65 -0
  46. pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages/category.py +175 -0
  47. {pysdmx-1.0.0b3/src/pysdmx/fmr/fusion → pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages}/code.py +117 -26
  48. {pysdmx-1.0.0b3/src/pysdmx/fmr/fusion → pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages}/concept.py +25 -19
  49. pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages/core.py +149 -0
  50. pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages/dataflow.py +103 -0
  51. {pysdmx-1.0.0b3/src/pysdmx/fmr/fusion → pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages}/dsd.py +131 -83
  52. {pysdmx-1.0.0b3/src/pysdmx/fmr/fusion → pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages}/map.py +72 -28
  53. pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages/metadataflow.py +44 -0
  54. pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages/mpa.py +45 -0
  55. pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages/msd.py +121 -0
  56. pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages/org.py +280 -0
  57. pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages/pa.py +45 -0
  58. pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages/report.py +54 -0
  59. pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages/schema.py +70 -0
  60. pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages/vtl.py +485 -0
  61. pysdmx-1.10.1/src/pysdmx/io/json/fusion/reader/__init__.py +28 -0
  62. pysdmx-1.10.1/src/pysdmx/io/json/gds/messages/__init__.py +35 -0
  63. pysdmx-1.10.1/src/pysdmx/io/json/gds/messages/agencies.py +41 -0
  64. pysdmx-1.10.1/src/pysdmx/io/json/gds/messages/catalog.py +79 -0
  65. pysdmx-1.10.1/src/pysdmx/io/json/gds/messages/sdmx_api.py +23 -0
  66. pysdmx-1.10.1/src/pysdmx/io/json/gds/messages/services.py +49 -0
  67. pysdmx-1.10.1/src/pysdmx/io/json/gds/messages/urn_resolver.py +43 -0
  68. pysdmx-1.10.1/src/pysdmx/io/json/gds/reader/__init__.py +12 -0
  69. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/__init__.py +77 -0
  70. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/agency.py +108 -0
  71. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/category.py +273 -0
  72. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/code.py +550 -0
  73. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/concept.py +165 -0
  74. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/constraint.py +272 -0
  75. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/core.py +323 -0
  76. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/dataflow.py +194 -0
  77. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/dsd.py +630 -0
  78. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/map.py +486 -0
  79. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/metadataflow.py +89 -0
  80. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/mpa.py +88 -0
  81. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/msd.py +253 -0
  82. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/pa.py +84 -0
  83. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/provider.py +232 -0
  84. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/report.py +180 -0
  85. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/schema.py +80 -0
  86. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/structure.py +349 -0
  87. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/messages/vtl.py +962 -0
  88. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/reader/__init__.py +28 -0
  89. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/reader/doc_validation.py +112 -0
  90. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/reader/metadata.py +39 -0
  91. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/reader/structure.py +39 -0
  92. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/writer/__init__.py +9 -0
  93. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/writer/metadata.py +60 -0
  94. pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/writer/structure.py +61 -0
  95. pysdmx-1.10.1/src/pysdmx/io/pd.py +19 -0
  96. pysdmx-1.10.1/src/pysdmx/io/reader.py +281 -0
  97. pysdmx-1.10.1/src/pysdmx/io/serde.py +67 -0
  98. pysdmx-1.10.1/src/pysdmx/io/writer.py +172 -0
  99. pysdmx-1.10.1/src/pysdmx/io/xml/__allowed_lxml_errors.py +6 -0
  100. pysdmx-1.10.1/src/pysdmx/io/xml/__data_aux.py +151 -0
  101. pysdmx-1.10.1/src/pysdmx/io/xml/__init__.py +5 -0
  102. pysdmx-1.10.1/src/pysdmx/io/xml/__parse_xml.py +102 -0
  103. pysdmx-1.10.1/src/pysdmx/io/xml/__ss_aux_reader.py +95 -0
  104. pysdmx-1.10.1/src/pysdmx/io/xml/__structure_aux_reader.py +1318 -0
  105. pysdmx-1.10.1/src/pysdmx/io/xml/__structure_aux_writer.py +1380 -0
  106. pysdmx-1.10.1/src/pysdmx/io/xml/__tokens.py +299 -0
  107. pysdmx-1.10.1/src/pysdmx/io/xml/__write_aux.py +517 -0
  108. pysdmx-1.10.1/src/pysdmx/io/xml/__write_data_aux.py +90 -0
  109. pysdmx-1.10.1/src/pysdmx/io/xml/__write_structure_specific_aux.py +298 -0
  110. pysdmx-1.10.1/src/pysdmx/io/xml/config.py +4 -0
  111. pysdmx-1.10.1/src/pysdmx/io/xml/doc_validation.py +50 -0
  112. pysdmx-1.10.1/src/pysdmx/io/xml/header.py +211 -0
  113. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx21/__init__.py +1 -0
  114. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx21/reader/__init__.py +1 -0
  115. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx21/reader/error.py +30 -0
  116. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx21/reader/generic.py +191 -0
  117. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx21/reader/structure.py +39 -0
  118. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx21/reader/structure_specific.py +39 -0
  119. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx21/reader/submission.py +57 -0
  120. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx21/writer/__init__.py +1 -0
  121. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx21/writer/error.py +13 -0
  122. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx21/writer/generic.py +508 -0
  123. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx21/writer/structure.py +66 -0
  124. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx21/writer/structure_specific.py +93 -0
  125. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx30/__init__.py +1 -0
  126. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx30/reader/__init__.py +1 -0
  127. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx30/reader/structure.py +39 -0
  128. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx30/reader/structure_specific.py +39 -0
  129. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx30/writer/__init__.py +1 -0
  130. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx30/writer/structure.py +67 -0
  131. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx30/writer/structure_specific.py +108 -0
  132. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx31/__init__.py +1 -0
  133. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx31/reader/__init__.py +1 -0
  134. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx31/reader/structure.py +39 -0
  135. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx31/reader/structure_specific.py +39 -0
  136. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx31/writer/__init__.py +1 -0
  137. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx31/writer/structure.py +67 -0
  138. pysdmx-1.10.1/src/pysdmx/io/xml/sdmx31/writer/structure_specific.py +108 -0
  139. pysdmx-1.10.1/src/pysdmx/io/xml/utils.py +21 -0
  140. pysdmx-1.10.1/src/pysdmx/model/__base.py +463 -0
  141. pysdmx-1.10.1/src/pysdmx/model/__init__.py +236 -0
  142. {pysdmx-1.0.0b3 → pysdmx-1.10.1}/src/pysdmx/model/category.py +78 -28
  143. {pysdmx-1.0.0b3 → pysdmx-1.10.1}/src/pysdmx/model/code.py +165 -34
  144. {pysdmx-1.0.0b3 → pysdmx-1.10.1}/src/pysdmx/model/concept.py +72 -39
  145. pysdmx-1.10.1/src/pysdmx/model/constraint.py +69 -0
  146. pysdmx-1.10.1/src/pysdmx/model/dataflow.py +627 -0
  147. pysdmx-1.10.1/src/pysdmx/model/dataset.py +133 -0
  148. pysdmx-1.10.1/src/pysdmx/model/gds.py +161 -0
  149. {pysdmx-1.0.0b3 → pysdmx-1.10.1}/src/pysdmx/model/map.py +184 -41
  150. pysdmx-1.10.1/src/pysdmx/model/message.py +441 -0
  151. pysdmx-1.10.1/src/pysdmx/model/metadata.py +453 -0
  152. pysdmx-1.10.1/src/pysdmx/model/organisation.py +147 -0
  153. pysdmx-1.10.1/src/pysdmx/model/submission.py +25 -0
  154. pysdmx-1.10.1/src/pysdmx/model/vtl.py +222 -0
  155. pysdmx-1.10.1/src/pysdmx/toolkit/__init__.py +1 -0
  156. pysdmx-1.10.1/src/pysdmx/toolkit/pd/__init__.py +85 -0
  157. pysdmx-1.10.1/src/pysdmx/toolkit/pd/_data_utils.py +99 -0
  158. pysdmx-1.10.1/src/pysdmx/toolkit/vtl/__init__.py +15 -0
  159. pysdmx-1.10.1/src/pysdmx/toolkit/vtl/_validations.py +145 -0
  160. pysdmx-1.10.1/src/pysdmx/toolkit/vtl/convert.py +333 -0
  161. pysdmx-1.10.1/src/pysdmx/toolkit/vtl/script_generation.py +104 -0
  162. pysdmx-1.10.1/src/pysdmx/toolkit/vtl/validation.py +119 -0
  163. pysdmx-1.10.1/src/pysdmx/util/__init__.py +139 -0
  164. pysdmx-1.10.1/src/pysdmx/util/_date_pattern_map.py +59 -0
  165. pysdmx-1.10.1/src/pysdmx/util/_model_utils.py +96 -0
  166. pysdmx-1.10.1/src/pysdmx/util/_net_utils.py +39 -0
  167. pysdmx-1.0.0b3/PKG-INFO +0 -56
  168. pysdmx-1.0.0b3/README.rst +0 -28
  169. pysdmx-1.0.0b3/pyproject.toml +0 -79
  170. pysdmx-1.0.0b3/src/pysdmx/errors.py +0 -73
  171. pysdmx-1.0.0b3/src/pysdmx/fmr/__init__.py +0 -775
  172. pysdmx-1.0.0b3/src/pysdmx/fmr/fusion/__init__.py +0 -31
  173. pysdmx-1.0.0b3/src/pysdmx/fmr/fusion/category.py +0 -91
  174. pysdmx-1.0.0b3/src/pysdmx/fmr/fusion/core.py +0 -100
  175. pysdmx-1.0.0b3/src/pysdmx/fmr/fusion/dataflow.py +0 -85
  176. pysdmx-1.0.0b3/src/pysdmx/fmr/fusion/org.py +0 -128
  177. pysdmx-1.0.0b3/src/pysdmx/fmr/fusion/report.py +0 -39
  178. pysdmx-1.0.0b3/src/pysdmx/fmr/fusion/schema.py +0 -53
  179. pysdmx-1.0.0b3/src/pysdmx/fmr/reader.py +0 -71
  180. pysdmx-1.0.0b3/src/pysdmx/fmr/sdmx/__init__.py +0 -28
  181. pysdmx-1.0.0b3/src/pysdmx/fmr/sdmx/category.py +0 -78
  182. pysdmx-1.0.0b3/src/pysdmx/fmr/sdmx/code.py +0 -186
  183. pysdmx-1.0.0b3/src/pysdmx/fmr/sdmx/concept.py +0 -95
  184. pysdmx-1.0.0b3/src/pysdmx/fmr/sdmx/constraint.py +0 -38
  185. pysdmx-1.0.0b3/src/pysdmx/fmr/sdmx/core.py +0 -111
  186. pysdmx-1.0.0b3/src/pysdmx/fmr/sdmx/dataflow.py +0 -92
  187. pysdmx-1.0.0b3/src/pysdmx/fmr/sdmx/dsd.py +0 -306
  188. pysdmx-1.0.0b3/src/pysdmx/fmr/sdmx/map.py +0 -238
  189. pysdmx-1.0.0b3/src/pysdmx/fmr/sdmx/org.py +0 -90
  190. pysdmx-1.0.0b3/src/pysdmx/fmr/sdmx/pa.py +0 -10
  191. pysdmx-1.0.0b3/src/pysdmx/fmr/sdmx/report.py +0 -26
  192. pysdmx-1.0.0b3/src/pysdmx/fmr/sdmx/schema.py +0 -54
  193. pysdmx-1.0.0b3/src/pysdmx/model/__init__.py +0 -101
  194. pysdmx-1.0.0b3/src/pysdmx/model/dataflow.py +0 -333
  195. pysdmx-1.0.0b3/src/pysdmx/model/metadata.py +0 -97
  196. pysdmx-1.0.0b3/src/pysdmx/model/organisation.py +0 -117
  197. pysdmx-1.0.0b3/src/pysdmx/util/__init__.py +0 -103
  198. {pysdmx-1.0.0b3 → pysdmx-1.10.1}/LICENSE +0 -0
  199. {pysdmx-1.0.0b3/src/pysdmx/fmr/fusion → pysdmx-1.10.1/src/pysdmx/io/json/fusion/messages}/constraint.py +0 -0
  200. {pysdmx-1.0.0b3 → pysdmx-1.10.1}/src/pysdmx/py.typed +0 -0
pysdmx-1.10.1/PKG-INFO ADDED
@@ -0,0 +1,123 @@
1
+ Metadata-Version: 2.4
2
+ Name: pysdmx
3
+ Version: 1.10.1
4
+ Summary: Your opinionated Python SDMX library
5
+ License: Apache-2.0
6
+ License-File: LICENSE
7
+ Keywords: sdmx,data discovery,data retrieval,metadata,fmr
8
+ Author: Xavier Sosnovsky
9
+ Author-email: <xavier.sosnovsky@bis.org>
10
+ Requires-Python: >=3.9
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Typing :: Typed
16
+ Provides-Extra: all
17
+ Provides-Extra: data
18
+ Provides-Extra: dc
19
+ Provides-Extra: json
20
+ Provides-Extra: vtl
21
+ Provides-Extra: xml
22
+ Requires-Dist: httpx[http2] (>=0)
23
+ Requires-Dist: jsonschema (>=4.10) ; extra == "json"
24
+ Requires-Dist: lxml (>=5.2) ; extra == "all"
25
+ Requires-Dist: lxml (>=5.2) ; extra == "xml"
26
+ Requires-Dist: msgspec (>=0)
27
+ Requires-Dist: pandas (>=2.1.4) ; extra == "all"
28
+ Requires-Dist: pandas (>=2.1.4) ; extra == "data"
29
+ Requires-Dist: parsy (>=2.1)
30
+ Requires-Dist: python-dateutil (>=2.8.2) ; extra == "all"
31
+ Requires-Dist: python-dateutil (>=2.8.2) ; extra == "dc"
32
+ Requires-Dist: sdmxschemas (>=1.0.0) ; extra == "all"
33
+ Requires-Dist: sdmxschemas (>=1.0.0) ; extra == "json"
34
+ Requires-Dist: sdmxschemas (>=1.0.0) ; extra == "xml"
35
+ Requires-Dist: vtlengine (>=1.2,<2.0) ; extra == "all"
36
+ Requires-Dist: vtlengine (>=1.2,<2.0) ; extra == "vtl"
37
+ Requires-Dist: xmltodict (>=0.13) ; extra == "all"
38
+ Requires-Dist: xmltodict (>=0.13) ; extra == "xml"
39
+ Project-URL: Bug Tracker, https://bis-med-it.github.io/pysdmx/issues
40
+ Project-URL: Documentation, https://bis-med-it.github.io/pysdmx
41
+ Project-URL: Homepage, https://sdmx.io/tools/pysdmx
42
+ Project-URL: Repository, https://github.com/bis-med-it/pysdmx
43
+ Description-Content-Type: text/x-rst
44
+
45
+ .. |pypi badge| image:: https://img.shields.io/pypi/v/pysdmx.svg
46
+ :target: https://pypi.org/project/pysdmx/
47
+
48
+ .. |awesome badge| image:: https://awesome.re/mentioned-badge.svg
49
+ :target: http://www.awesomeofficialstatistics.org
50
+
51
+ |pypi badge| |awesome badge|
52
+
53
+ ``pysdmx`` in a nutshell
54
+ ************************
55
+
56
+ What is pysdmx?
57
+ ===============
58
+
59
+ ``pysdmx`` is a **pragmatic** and **opinionated** SDMX library written in
60
+ **Python**. It focuses on **simplicity**, providing a subset of SDMX functionalities
61
+ without requiring advanced knowledge of SDMX. ``pysdmx`` is developed as part of
62
+ the `sdmx.io <http://sdmx.io/>`_ project under the **BIS Open Tech initiative**.
63
+
64
+ What does it do?
65
+ ================
66
+
67
+ ``pysdmx`` aspires to be a versatile SDMX toolbox for Python, covering various
68
+ use cases. Here are some highlights:
69
+
70
+ SDMX information model in Python
71
+ --------------------------------
72
+
73
+ ``pysdmx`` offers Python classes representing a **simplified subset of the SDMX
74
+ information model**, enabling a domain-driven development of SDMX processes in
75
+ Python. The model classes support serialization in formats like JSON, YAML, or
76
+ MessagePack. This functionality relies on the
77
+ `msgspec library <https://jcristharif.com/msgspec/>`_.
78
+
79
+ Metadata in action
80
+ ------------------
81
+
82
+ SDMX metadata are very useful for documenting statistical processes. For example,
83
+ they can define the structure we expect for a data collection process and share
84
+ it with the organizations providing data so that they know what to send.
85
+
86
+ However, metadata can do so much more than that, i.e., they can be “active” and
87
+ **drive various types of statistical processes**, such as generating the filesystem
88
+ layout, creating the physical data model, validating data, mapping data, and
89
+ configuring processes. To drive such processes, ``pysdmx`` supports retrieving
90
+ metadata from an SDMX Registry or any service compliant with the SDMX-REST 2.0.0 (or
91
+ above) API. Use these metadata to power your own statistical processes!
92
+
93
+ Reading and writing SDMX files
94
+ ------------------------------
95
+
96
+ ``pysdmx`` supports reading and writing SDMX data and structure messages, in various
97
+ formats, such as SDMX-CSV, SDMX-JSON, and SDMX-ML.
98
+
99
+ Data discovery and data retrieval
100
+ ---------------------------------
101
+
102
+ This functionality is under development. Once ready, ``pysdmx`` will allow:
103
+
104
+ - **Listing public SDMX services**.
105
+ - **Discovering data** available in these services.
106
+ - **Retrieving data** from these services.
107
+
108
+ This functionality is based on the **SDMX Global Discovery Service initiative**.
109
+
110
+ Integration with the ecosystem
111
+ ------------------------------
112
+
113
+ ``pysdmx`` integrates nicely with other standards, like the `Validation and
114
+ Transformation Language (VTL) <https://sdmx.org/about-sdmx/about-vtl/>`_,
115
+ and major Python libraries like `Pandas <https://pandas.pydata.org/>`_.
116
+ Take a look at the ``pysdmx`` toolkit module to learn more.
117
+
118
+ ``pysdmx`` is available on `PyPI <https://pypi.org/>`_ and can be
119
+ installed using options such as pip, pipx, poetry, etc.
120
+
121
+ For more details, check the `project documentation
122
+ <https://py.sdmx.io>`_.
123
+
@@ -0,0 +1,78 @@
1
+ .. |pypi badge| image:: https://img.shields.io/pypi/v/pysdmx.svg
2
+ :target: https://pypi.org/project/pysdmx/
3
+
4
+ .. |awesome badge| image:: https://awesome.re/mentioned-badge.svg
5
+ :target: http://www.awesomeofficialstatistics.org
6
+
7
+ |pypi badge| |awesome badge|
8
+
9
+ ``pysdmx`` in a nutshell
10
+ ************************
11
+
12
+ What is pysdmx?
13
+ ===============
14
+
15
+ ``pysdmx`` is a **pragmatic** and **opinionated** SDMX library written in
16
+ **Python**. It focuses on **simplicity**, providing a subset of SDMX functionalities
17
+ without requiring advanced knowledge of SDMX. ``pysdmx`` is developed as part of
18
+ the `sdmx.io <http://sdmx.io/>`_ project under the **BIS Open Tech initiative**.
19
+
20
+ What does it do?
21
+ ================
22
+
23
+ ``pysdmx`` aspires to be a versatile SDMX toolbox for Python, covering various
24
+ use cases. Here are some highlights:
25
+
26
+ SDMX information model in Python
27
+ --------------------------------
28
+
29
+ ``pysdmx`` offers Python classes representing a **simplified subset of the SDMX
30
+ information model**, enabling a domain-driven development of SDMX processes in
31
+ Python. The model classes support serialization in formats like JSON, YAML, or
32
+ MessagePack. This functionality relies on the
33
+ `msgspec library <https://jcristharif.com/msgspec/>`_.
34
+
35
+ Metadata in action
36
+ ------------------
37
+
38
+ SDMX metadata are very useful for documenting statistical processes. For example,
39
+ they can define the structure we expect for a data collection process and share
40
+ it with the organizations providing data so that they know what to send.
41
+
42
+ However, metadata can do so much more than that, i.e., they can be “active” and
43
+ **drive various types of statistical processes**, such as generating the filesystem
44
+ layout, creating the physical data model, validating data, mapping data, and
45
+ configuring processes. To drive such processes, ``pysdmx`` supports retrieving
46
+ metadata from an SDMX Registry or any service compliant with the SDMX-REST 2.0.0 (or
47
+ above) API. Use these metadata to power your own statistical processes!
48
+
49
+ Reading and writing SDMX files
50
+ ------------------------------
51
+
52
+ ``pysdmx`` supports reading and writing SDMX data and structure messages, in various
53
+ formats, such as SDMX-CSV, SDMX-JSON, and SDMX-ML.
54
+
55
+ Data discovery and data retrieval
56
+ ---------------------------------
57
+
58
+ This functionality is under development. Once ready, ``pysdmx`` will allow:
59
+
60
+ - **Listing public SDMX services**.
61
+ - **Discovering data** available in these services.
62
+ - **Retrieving data** from these services.
63
+
64
+ This functionality is based on the **SDMX Global Discovery Service initiative**.
65
+
66
+ Integration with the ecosystem
67
+ ------------------------------
68
+
69
+ ``pysdmx`` integrates nicely with other standards, like the `Validation and
70
+ Transformation Language (VTL) <https://sdmx.org/about-sdmx/about-vtl/>`_,
71
+ and major Python libraries like `Pandas <https://pandas.pydata.org/>`_.
72
+ Take a look at the ``pysdmx`` toolkit module to learn more.
73
+
74
+ ``pysdmx`` is available on `PyPI <https://pypi.org/>`_ and can be
75
+ installed using options such as pip, pipx, poetry, etc.
76
+
77
+ For more details, check the `project documentation
78
+ <https://py.sdmx.io>`_.
@@ -0,0 +1,123 @@
1
+ [project]
2
+ name = "pysdmx"
3
+ version = "1.10.1"
4
+ description = "Your opinionated Python SDMX library"
5
+ license = { text = "Apache-2.0" }
6
+ readme = "README.rst"
7
+ requires-python = ">=3.9"
8
+ authors = [
9
+ { name = "Xavier Sosnovsky", email = "<xavier.sosnovsky@bis.org>" },
10
+ { name = "Stratos Nikoloutsos", email = "<stratos.nikoloutsos@bis.org>" },
11
+ { name = "Francisco Javier Hernandez del Caño", email = "<javier.hernandez@meaningfuldata.eu>" },
12
+ { name = "Mateo de Lorenzo Argelés", email = "<mateo.delorenzo@meaningfuldata.eu>" },
13
+ { name = "Jose Antonio Franco Martin", email = "<jose.franco@meaningfuldata.eu>" },
14
+ { name = "Mario Cortés Ruiz", email = "<mario.cortes@meaningfuldata.eu>" }
15
+
16
+ ]
17
+ keywords = ["sdmx", "data discovery", "data retrieval", "metadata", "fmr"]
18
+ classifiers = [
19
+ "Development Status :: 5 - Production/Stable",
20
+ "Intended Audience :: Developers",
21
+ "Intended Audience :: Science/Research",
22
+ "License :: OSI Approved :: Apache Software License",
23
+ "Typing :: Typed"
24
+ ]
25
+ dependencies = [
26
+ "httpx[http2]>=0.*",
27
+ "msgspec>=0.*",
28
+ "parsy>=2.1"
29
+ ]
30
+
31
+ [project.urls]
32
+ homepage = "https://sdmx.io/tools/pysdmx"
33
+ repository = "https://github.com/bis-med-it/pysdmx"
34
+ documentation = "https://bis-med-it.github.io/pysdmx"
35
+ "Bug Tracker" = "https://bis-med-it.github.io/pysdmx/issues"
36
+
37
+ [project.optional-dependencies]
38
+ data = ["pandas>=2.1.4"]
39
+ dc = ["python-dateutil>=2.8.2"]
40
+ vtl = ["vtlengine>=1.2,<2.0"]
41
+ json = ["sdmxschemas>=1.0.0", "jsonschema>=4.10"]
42
+ xml = ["lxml>=5.2", "xmltodict>=0.13", "sdmxschemas>=1.0.0"]
43
+ all = ["lxml>=5.2", "xmltodict>=0.13", "sdmxschemas>=1.0.0", "pandas>=2.1.4", "python-dateutil>=2.8.2", "vtlengine>=1.2,<2.0"]
44
+
45
+ [tool.poetry]
46
+ requires-poetry = ">=2.0"
47
+
48
+ [tool.poetry.dependencies]
49
+ python = ">=3.9,<4.0"
50
+
51
+ [tool.poetry.group.dev.dependencies]
52
+ ruff = ">=0.13.2"
53
+ mypy = "^1.18.2"
54
+ pytest = "^8.3.2"
55
+ pytest-asyncio = "^0.21.1"
56
+ pytest-cov = "^4.0.0"
57
+ respx = "^0.22.0"
58
+ pyroma = "^4.2"
59
+ lxml-stubs = "^0.5.1"
60
+ types-xmltodict = "^0.13.0.3"
61
+ types-python-dateutil = "^2.9.0.20240316"
62
+ pandas-stubs = "^2.1.4.231227"
63
+ types-jsonschema = "^4.25.1.20251009"
64
+
65
+ [tool.poetry.group.docs.dependencies]
66
+ sphinx = "^7.2.6"
67
+ sphinx-rtd-theme = "^1.3.0"
68
+ sphinx-autodoc-typehints = "^1.24.0"
69
+
70
+ [build-system]
71
+ requires = ["poetry-core>=1.0.0"]
72
+ build-backend = "poetry.core.masonry.api"
73
+
74
+ [tool.ruff]
75
+ line-length = 79
76
+ lint.select = [
77
+ "ASYNC", # flake8-async: checks for async/await best practices
78
+ "B", # flake8-bugbear: detect bugs and design problems
79
+ "C4", # flake8-comprehensions: better list/dict/set comprehensions
80
+ "C90", # mccabe: code complexity checker
81
+ "D", # pydocstyle: enforce docstring conventions
82
+ "DTZ", # flake8-datetimez: datetime best practices and timezone issues
83
+ "E", # pycodestyle errors
84
+ "ERA", # eradicate: Find commented-out code that should be removed
85
+ "F", # pyflakes: detect various errors
86
+ "FURB", # refurb: functional Python improvements and refactoring
87
+ "I", # isort: import sorting
88
+ "LOG", # flake8-logging: logging best practices
89
+ "PERF", # perflint: performance optimizations
90
+ "PT", # flake8-pytest-style: pytest best practices
91
+ "S", # flake8-bandit: security issues
92
+ "SIM", # flake8-simplify: code simplification suggestions
93
+ "W" # pycodestyle warnings
94
+ ]
95
+ lint.ignore = ["D411", "E203", "F901"]
96
+ lint.mccabe.max-complexity = 10
97
+ lint.pydocstyle.convention = "google"
98
+
99
+ [tool.ruff.lint.per-file-ignores]
100
+ "tests/*" = ["C901", "DTZ", "D100", "D103", "D104", "PERF", "S101", "S311"]
101
+
102
+ [tool.mypy]
103
+ files = "src"
104
+ disallow_untyped_defs = true
105
+ disallow_untyped_calls = true
106
+ ignore_errors = false
107
+ no_implicit_optional = true
108
+ show_column_numbers = true
109
+ strict_equality = true
110
+ strict_optional = true
111
+ strict = true
112
+ enable_error_code = [
113
+ "redundant-expr",
114
+ "truthy-bool",
115
+ ]
116
+ warn_return_any = false
117
+
118
+ [tool.coverage.run]
119
+ branch = true
120
+ omit = [
121
+ # We cannot test this properly with pytest as we always install all extras
122
+ "__extras_check.py"
123
+ ]
@@ -0,0 +1,71 @@
1
+ EXTRAS_DOCS = "https://py.sdmx.io/start.html#how-can-i-get-it"
2
+ ERROR_MESSAGE = (
3
+ "The '{extra_name}' extra is required to run {extra_desc}. "
4
+ "Please install it using 'pip install pysdmx[{extra_name}]' or "
5
+ "install all extras with 'pip install pysdmx[all]'. "
6
+ f"Check the documentation at: {EXTRAS_DOCS}"
7
+ )
8
+
9
+
10
+ def __check_dc_extra() -> None:
11
+ try:
12
+ import dateutil # noqa: F401
13
+ except ImportError:
14
+ raise ImportError(
15
+ ERROR_MESSAGE.format(
16
+ extra_name="dc", extra_desc="the python parser for dates"
17
+ )
18
+ ) from None
19
+
20
+
21
+ def __check_data_extra() -> None:
22
+ try:
23
+ import pandas # noqa: F401
24
+ except ImportError:
25
+ raise ImportError(
26
+ ERROR_MESSAGE.format(
27
+ extra_name="data",
28
+ extra_desc="the reading and writing of Data Messages",
29
+ )
30
+ ) from None
31
+
32
+
33
+ def __check_xml_extra() -> None:
34
+ try:
35
+ import lxml # noqa: F401
36
+ import sdmxschemas # noqa: F401
37
+ import xmltodict # noqa: F401
38
+ except ImportError:
39
+ raise ImportError(
40
+ ERROR_MESSAGE.format(
41
+ extra_name="xml",
42
+ extra_desc="the reading and writing of SDMX-ML Messages",
43
+ )
44
+ ) from None
45
+
46
+
47
+ def __check_vtl_extra() -> None:
48
+ try:
49
+ import vtlengine # noqa: F401
50
+ except ImportError:
51
+ raise ImportError(
52
+ ERROR_MESSAGE.format(
53
+ extra_name="vtl",
54
+ extra_desc="VTL Scripts, SDMX-VTL model validations"
55
+ " and prettify",
56
+ )
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
@@ -1,3 +1,3 @@
1
1
  """Your opinionated Python SDMX library."""
2
2
 
3
- __version__ = "1.0.0-beta-3"
3
+ __version__ = "1.10.1"
@@ -0,0 +1 @@
1
+ """pysdmx api package."""
@@ -0,0 +1,5 @@
1
+ """pysdmx simple data discovery and retrieval API."""
2
+
3
+ from pysdmx.api.dc._api import Connector
4
+
5
+ __all__ = ["Connector"]
@@ -0,0 +1,213 @@
1
+ """API to be implemented by connectors."""
2
+
3
+ from datetime import datetime
4
+ from typing import (
5
+ Any,
6
+ Generator,
7
+ Iterable,
8
+ List,
9
+ Literal,
10
+ Optional,
11
+ Protocol,
12
+ Union,
13
+ runtime_checkable,
14
+ )
15
+
16
+ from pysdmx.api.dc.query import (
17
+ BooleanFilter,
18
+ DateTimeFilter,
19
+ MultiFilter,
20
+ NotFilter,
21
+ NumberFilter,
22
+ SortBy,
23
+ TextFilter,
24
+ )
25
+ from pysdmx.model import (
26
+ Dataflow,
27
+ DataflowInfo,
28
+ DataflowRef,
29
+ Organisation,
30
+ SeriesInfo,
31
+ )
32
+
33
+
34
+ @runtime_checkable
35
+ class Connector(Protocol):
36
+ """A Connector provides access to a data source.
37
+
38
+ Connectors support both data discovery and data retrieval.
39
+
40
+ Attributes:
41
+ owner: The organisation providing the Connector.
42
+ It is recommended to provide contact details, in case users
43
+ of the Connector have questions about it.
44
+ """
45
+
46
+ owner: Organisation
47
+
48
+ def dataflows(
49
+ self,
50
+ filter_query: Optional[str] = None,
51
+ provider: Optional[str] = None,
52
+ ) -> Union[Iterable[Dataflow], Iterable[DataflowRef]]:
53
+ """Get the dataflows provided by the Connector.
54
+
55
+ Args:
56
+ filter_query: A search term. If set, any dataflow containing the
57
+ term in its id, name or description will be returned.
58
+ provider: A data provider. If set, any dataflow for which data are
59
+ being provided by the supplied provider will be returned.
60
+
61
+ Returns: Iterable[DataflowRef]: A collection of dataflow references.
62
+
63
+ The references contain core information about the
64
+ dataflows provided by the Connector. Most importantly,
65
+ they contain the identifying information required to
66
+ retrieve more information about a specific dataflow
67
+ (see dataflow).
68
+
69
+ It is expected that this method, if implemented,
70
+ will return at least one DataflowRef object.
71
+ """
72
+
73
+ def providers(
74
+ self,
75
+ filter_query: Optional[str] = None,
76
+ ) -> Iterable[Organisation]:
77
+ """Get the providers of which data are available in the Connector.
78
+
79
+ Args:
80
+ filter_query: A search term. If set, any provider containing the
81
+ term in its id, name or description will be returned.
82
+
83
+ Returns: Iterable[Organisation]: A collection of data providers.
84
+ """
85
+
86
+ def dataflow(
87
+ self,
88
+ dataflow: Union[str, DataflowRef, Dataflow],
89
+ metrics: bool = False,
90
+ ) -> DataflowInfo:
91
+ """Get information about a dataflow.
92
+
93
+ Args:
94
+ dataflow: Either a string representing the dataflow ID or
95
+ a DataflowRef, as returned by calling the dataflows
96
+ function.
97
+ metrics: Metrics contain useful information such as
98
+ the number of observations, series, when the
99
+ dataflow was last updated, etc. However, it may be
100
+ expensive to fetch this information. In case metrics
101
+ are not required, you may set metrics to False, to
102
+ prevent them from being computed.
103
+
104
+ Returns: DataflowInfo: Information about the requested dataflow.
105
+
106
+ The information includes:
107
+
108
+ - Some basic metadata about the dataflow (such as its ID and name).
109
+ - Some useful metrics such as the number of observations.
110
+ - The expected structure of data (i.e. the data schema), including
111
+ the expected columns, their types, etc.
112
+ """
113
+
114
+ def series(
115
+ self,
116
+ dataflow: Union[str, DataflowRef, Dataflow, DataflowInfo],
117
+ provider: Optional[Union[str, Organisation]] = None,
118
+ filters: Optional[
119
+ Union[
120
+ BooleanFilter,
121
+ DateTimeFilter,
122
+ MultiFilter,
123
+ NotFilter,
124
+ NumberFilter,
125
+ str,
126
+ TextFilter,
127
+ ]
128
+ ] = None,
129
+ discontinued: bool = False,
130
+ updated_after: Optional[datetime] = None,
131
+ ) -> Generator[SeriesInfo, None, None]:
132
+ """Get the series available in the dataflow.
133
+
134
+ Args:
135
+ dataflow: Either a string representing the dataflow ID or
136
+ a DataflowRef, as returned by calling the dataflows
137
+ function, or a DataflowInfo, as returned by calling the
138
+ dataflow function.
139
+ provider: The organisation providing the data to be returned.
140
+ filters: A dictionary, where the keys are the IDs of the
141
+ components used for filtering and the values
142
+ represent the filters to be applied.
143
+ discontinued: Whether discontinued (i.e. old)
144
+ series should be returned. Defaults to `False`.
145
+ updated_after: Retrieve the series updated after
146
+ the supplied timestamp.
147
+
148
+ Returns: A generator, to iterate over the collection matching series
149
+ The information includes:
150
+
151
+ - Some basic metadata about the series (such as an ID or name).
152
+ - Some useful metrics such as the number of observations, the last
153
+ time it was updated, etc.
154
+ """
155
+
156
+ def data(
157
+ self,
158
+ dataflow: Union[str, DataflowRef, Dataflow, DataflowInfo],
159
+ provider: Optional[Union[str, Organisation]] = None,
160
+ series: Optional[Iterable[str]] = None,
161
+ filters: Optional[
162
+ Union[
163
+ BooleanFilter,
164
+ DateTimeFilter,
165
+ MultiFilter,
166
+ NotFilter,
167
+ NumberFilter,
168
+ str,
169
+ TextFilter,
170
+ ]
171
+ ] = None,
172
+ columns: Optional[Iterable[str]] = None,
173
+ sort: Optional[List[SortBy]] = None,
174
+ offset: int = 0,
175
+ limit: Optional[int] = None,
176
+ history: bool = False,
177
+ updated_after: Optional[datetime] = None,
178
+ format: Literal["dict", "pandas"] = "dict",
179
+ ) -> Any:
180
+ """Get data for the selected dataflow.
181
+
182
+ Args:
183
+ dataflow: Either a string representing the dataflow ID or
184
+ a DataflowRef, as returned by calling the dataflows
185
+ function, or a DataflowInfo, as returned by calling the
186
+ dataflow function.
187
+ provider: The organisation providing the data to be returned.
188
+ series: One or more strings identifying the series
189
+ for which data should be returned (e.g. D.USD.EUR.SP00).
190
+ wildcards can be used too (e.g. D.*.EUR.SP00).
191
+ filters: A dictionary, where the keys are the IDs of the
192
+ components used for filtering and the values
193
+ represent the filters to be applied.
194
+ columns: The fields to be returned.
195
+ sort: The desired sorting order of the results.
196
+ offset: From which row to start fetching. This is useful to
197
+ paginate results. Default to 0.
198
+ limit: The number of rows to be returned.
199
+ history: Whether to retrieve previous "versions" of the data or
200
+ only the latest one. This is useful to see how the data may
201
+ have evolved or have been corrected over time.
202
+ updated_after: Retrieve the series updated after
203
+ the supplied timestamp.
204
+ format: The desired format for the data. By default, a generator
205
+ of dict objects will be returned, but there are other options
206
+ such as pandas data frames.
207
+
208
+ Returns: A generator, to iterate over the matching data, if format is
209
+ set to dict (the default), or a pandas data frame.
210
+ """
211
+
212
+
213
+ __all__ = ["Connector"]
@@ -0,0 +1,27 @@
1
+ """Classes and parsers for data queries."""
2
+
3
+ from pysdmx.api.dc.query._model import (
4
+ BooleanFilter,
5
+ DateTimeFilter,
6
+ LogicalOperator,
7
+ MultiFilter,
8
+ NotFilter,
9
+ NullFilter,
10
+ NumberFilter,
11
+ Operator,
12
+ SortBy,
13
+ TextFilter,
14
+ )
15
+
16
+ __all__ = [
17
+ "BooleanFilter",
18
+ "DateTimeFilter",
19
+ "LogicalOperator",
20
+ "MultiFilter",
21
+ "NotFilter",
22
+ "NullFilter",
23
+ "NumberFilter",
24
+ "Operator",
25
+ "SortBy",
26
+ "TextFilter",
27
+ ]