pysdmx 1.2.2__tar.gz → 1.4.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.
- pysdmx-1.4.0/PKG-INFO +119 -0
- pysdmx-1.4.0/README.rst +78 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/pyproject.toml +5 -4
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/__extras_check.py +3 -2
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/__init__.py +1 -1
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/fmr/__init__.py +4 -4
- pysdmx-1.4.0/src/pysdmx/api/gds/__init__.py +328 -0
- pysdmx-1.4.0/src/pysdmx/api/qb/gds.py +153 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/qb/refmeta.py +33 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/qb/service.py +91 -3
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/qb/structure.py +50 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/qb/util.py +1 -0
- pysdmx-1.4.0/src/pysdmx/io/__init__.py +6 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/csv/sdmx10/reader/__init__.py +4 -2
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/csv/sdmx10/writer/__init__.py +15 -2
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/csv/sdmx20/reader/__init__.py +5 -2
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/csv/sdmx20/writer/__init__.py +13 -2
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/format.py +4 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/input_processor.py +12 -3
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/messages/core.py +2 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/messages/report.py +13 -7
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/messages/vtl.py +9 -1
- pysdmx-1.4.0/src/pysdmx/io/json/gds/messages/__init__.py +35 -0
- pysdmx-1.4.0/src/pysdmx/io/json/gds/messages/agencies.py +41 -0
- pysdmx-1.4.0/src/pysdmx/io/json/gds/messages/catalog.py +79 -0
- pysdmx-1.4.0/src/pysdmx/io/json/gds/messages/sdmx_api.py +23 -0
- pysdmx-1.4.0/src/pysdmx/io/json/gds/messages/services.py +49 -0
- pysdmx-1.4.0/src/pysdmx/io/json/gds/messages/urn_resolver.py +43 -0
- pysdmx-1.4.0/src/pysdmx/io/json/gds/reader/__init__.py +12 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/sdmxjson2/messages/__init__.py +12 -4
- pysdmx-1.4.0/src/pysdmx/io/json/sdmxjson2/messages/agency.py +72 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/sdmxjson2/messages/category.py +22 -29
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/sdmxjson2/messages/code.py +68 -64
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/sdmxjson2/messages/concept.py +9 -18
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/sdmxjson2/messages/constraint.py +2 -13
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/sdmxjson2/messages/core.py +113 -21
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/sdmxjson2/messages/dataflow.py +51 -21
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/sdmxjson2/messages/dsd.py +110 -36
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/sdmxjson2/messages/map.py +61 -49
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/sdmxjson2/messages/pa.py +9 -17
- pysdmx-1.4.0/src/pysdmx/io/json/sdmxjson2/messages/provider.py +88 -0
- pysdmx-1.4.0/src/pysdmx/io/json/sdmxjson2/messages/report.py +102 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/sdmxjson2/messages/schema.py +14 -5
- pysdmx-1.4.0/src/pysdmx/io/json/sdmxjson2/messages/structure.py +140 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/sdmxjson2/messages/vtl.py +55 -99
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/pd.py +2 -9
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/reader.py +76 -51
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/serde.py +11 -0
- pysdmx-1.4.0/src/pysdmx/io/writer.py +134 -0
- {pysdmx-1.2.2/src/pysdmx/io/xml/sdmx21/reader → pysdmx-1.4.0/src/pysdmx/io/xml}/__data_aux.py +9 -2
- {pysdmx-1.2.2/src/pysdmx/io/xml/sdmx21/reader → pysdmx-1.4.0/src/pysdmx/io/xml}/__parse_xml.py +30 -6
- pysdmx-1.2.2/src/pysdmx/io/xml/sdmx21/reader/structure_specific.py → pysdmx-1.4.0/src/pysdmx/io/xml/__ss_aux_reader.py +13 -40
- pysdmx-1.2.2/src/pysdmx/io/xml/sdmx21/reader/structure.py → pysdmx-1.4.0/src/pysdmx/io/xml/__structure_aux_reader.py +465 -123
- pysdmx-1.4.0/src/pysdmx/io/xml/__structure_aux_writer.py +1233 -0
- {pysdmx-1.2.2/src/pysdmx/io/xml/sdmx21 → pysdmx-1.4.0/src/pysdmx/io/xml}/__tokens.py +40 -1
- {pysdmx-1.2.2/src/pysdmx/io/xml/sdmx21/writer → pysdmx-1.4.0/src/pysdmx/io/xml}/__write_aux.py +137 -42
- {pysdmx-1.2.2/src/pysdmx/io/xml/sdmx21/writer → pysdmx-1.4.0/src/pysdmx/io/xml}/__write_data_aux.py +1 -1
- pysdmx-1.2.2/src/pysdmx/io/xml/sdmx21/writer/structure_specific.py → pysdmx-1.4.0/src/pysdmx/io/xml/__write_structure_specific_aux.py +23 -87
- {pysdmx-1.2.2/src/pysdmx/io/xml/sdmx21/reader → pysdmx-1.4.0/src/pysdmx/io/xml}/doc_validation.py +10 -2
- {pysdmx-1.2.2/src/pysdmx/io/xml/sdmx21/reader → pysdmx-1.4.0/src/pysdmx/io/xml}/header.py +42 -7
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/xml/sdmx21/reader/error.py +2 -2
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/xml/sdmx21/reader/generic.py +12 -8
- pysdmx-1.4.0/src/pysdmx/io/xml/sdmx21/reader/structure.py +39 -0
- pysdmx-1.4.0/src/pysdmx/io/xml/sdmx21/reader/structure_specific.py +39 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/xml/sdmx21/reader/submission.py +2 -2
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/xml/sdmx21/writer/error.py +1 -1
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/xml/sdmx21/writer/generic.py +13 -7
- pysdmx-1.4.0/src/pysdmx/io/xml/sdmx21/writer/structure.py +66 -0
- pysdmx-1.4.0/src/pysdmx/io/xml/sdmx21/writer/structure_specific.py +93 -0
- pysdmx-1.4.0/src/pysdmx/io/xml/sdmx30/__init__.py +1 -0
- pysdmx-1.4.0/src/pysdmx/io/xml/sdmx30/reader/__init__.py +1 -0
- pysdmx-1.4.0/src/pysdmx/io/xml/sdmx30/reader/structure.py +39 -0
- pysdmx-1.4.0/src/pysdmx/io/xml/sdmx30/reader/structure_specific.py +39 -0
- pysdmx-1.4.0/src/pysdmx/io/xml/sdmx30/writer/__init__.py +1 -0
- pysdmx-1.4.0/src/pysdmx/io/xml/sdmx30/writer/structure.py +67 -0
- pysdmx-1.4.0/src/pysdmx/io/xml/sdmx30/writer/structure_specific.py +108 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/model/__base.py +99 -34
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/model/__init__.py +4 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/model/category.py +20 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/model/code.py +29 -8
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/model/concept.py +52 -11
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/model/dataflow.py +117 -33
- pysdmx-1.4.0/src/pysdmx/model/dataset.py +133 -0
- pysdmx-1.4.0/src/pysdmx/model/gds.py +161 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/model/map.py +51 -8
- pysdmx-1.4.0/src/pysdmx/model/message.py +384 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/model/metadata.py +79 -16
- pysdmx-1.4.0/src/pysdmx/model/submission.py +25 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/model/vtl.py +36 -16
- pysdmx-1.4.0/src/pysdmx/toolkit/__init__.py +1 -0
- pysdmx-1.4.0/src/pysdmx/toolkit/pd/__init__.py +85 -0
- pysdmx-1.4.0/src/pysdmx/toolkit/vtl/__init__.py +6 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/toolkit/vtl/_validations.py +1 -1
- pysdmx-1.2.2/src/pysdmx/toolkit/vtl/generate_vtl_script.py → pysdmx-1.4.0/src/pysdmx/toolkit/vtl/script_generation.py +30 -4
- pysdmx-1.4.0/src/pysdmx/toolkit/vtl/validation.py +119 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/util/__init__.py +42 -5
- pysdmx-1.4.0/src/pysdmx/util/_model_utils.py +58 -0
- pysdmx-1.2.2/PKG-INFO +0 -76
- pysdmx-1.2.2/README.rst +0 -35
- pysdmx-1.2.2/src/pysdmx/io/__init__.py +0 -5
- pysdmx-1.2.2/src/pysdmx/io/json/sdmxjson2/messages/org.py +0 -140
- pysdmx-1.2.2/src/pysdmx/io/json/sdmxjson2/messages/report.py +0 -32
- pysdmx-1.2.2/src/pysdmx/io/json/sdmxjson2/messages/structure.py +0 -71
- pysdmx-1.2.2/src/pysdmx/io/xml/sdmx21/writer/structure.py +0 -840
- pysdmx-1.2.2/src/pysdmx/model/dataset.py +0 -81
- pysdmx-1.2.2/src/pysdmx/model/message.py +0 -204
- pysdmx-1.2.2/src/pysdmx/model/submission.py +0 -20
- pysdmx-1.2.2/src/pysdmx/toolkit/__init__.py +0 -1
- pysdmx-1.2.2/src/pysdmx/toolkit/vtl/__init__.py +0 -5
- pysdmx-1.2.2/src/pysdmx/toolkit/vtl/model_validations.py +0 -50
- {pysdmx-1.2.2 → pysdmx-1.4.0}/LICENSE +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/__init__.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/dc/__init__.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/dc/_api.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/dc/query/__init__.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/dc/query/_model.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/dc/query/_parsing_model.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/dc/query/_parsing_util.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/dc/query/_py_parser.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/dc/query/_sql_parser.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/dc/query/util.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/qb/__init__.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/qb/availability.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/qb/data.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/qb/registration.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/api/qb/schema.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/errors.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/csv/__init__.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/csv/sdmx10/__init__.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/csv/sdmx20/__init__.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/messages/__init__.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/messages/category.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/messages/code.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/messages/concept.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/messages/constraint.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/messages/dataflow.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/messages/dsd.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/messages/map.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/messages/org.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/messages/pa.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/messages/schema.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/fusion/reader/__init__.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/json/sdmxjson2/reader/__init__.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/xml/__allowed_lxml_errors.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/xml/__init__.py +0 -0
- {pysdmx-1.2.2/src/pysdmx/io/xml/sdmx21/writer → pysdmx-1.4.0/src/pysdmx/io/xml}/config.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/xml/sdmx21/__init__.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/xml/sdmx21/reader/__init__.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/xml/sdmx21/writer/__init__.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/io/xml/utils.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/model/organisation.py +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/py.typed +0 -0
- {pysdmx-1.2.2 → pysdmx-1.4.0}/src/pysdmx/util/_date_pattern_map.py +0 -0
pysdmx-1.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: pysdmx
|
|
3
|
+
Version: 1.4.0
|
|
4
|
+
Summary: Your opinionated Python SDMX library
|
|
5
|
+
License: Apache-2.0
|
|
6
|
+
Keywords: sdmx,data discovery,data retrieval,metadata,fmr
|
|
7
|
+
Author: Xavier Sosnovsky
|
|
8
|
+
Author-email: <xavier.sosnovsky@bis.org>
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
|
+
Classifier: Typing :: Typed
|
|
15
|
+
Provides-Extra: all
|
|
16
|
+
Provides-Extra: data
|
|
17
|
+
Provides-Extra: dc
|
|
18
|
+
Provides-Extra: vtl
|
|
19
|
+
Provides-Extra: xml
|
|
20
|
+
Requires-Dist: httpx (>=0)
|
|
21
|
+
Requires-Dist: lxml (>=5.2) ; extra == "all"
|
|
22
|
+
Requires-Dist: lxml (>=5.2) ; extra == "xml"
|
|
23
|
+
Requires-Dist: msgspec (>=0)
|
|
24
|
+
Requires-Dist: pandas (>=2.1.4) ; extra == "all"
|
|
25
|
+
Requires-Dist: pandas (>=2.1.4) ; extra == "data"
|
|
26
|
+
Requires-Dist: parsy (>=2.1)
|
|
27
|
+
Requires-Dist: python-dateutil (>=2.8.2) ; extra == "all"
|
|
28
|
+
Requires-Dist: python-dateutil (>=2.8.2) ; extra == "dc"
|
|
29
|
+
Requires-Dist: sdmxschemas (>=0.2.0) ; extra == "all"
|
|
30
|
+
Requires-Dist: sdmxschemas (>=0.2.0) ; extra == "xml"
|
|
31
|
+
Requires-Dist: vtlengine (>=1.1,<2.0) ; extra == "all"
|
|
32
|
+
Requires-Dist: vtlengine (>=1.1,<2.0) ; extra == "vtl"
|
|
33
|
+
Requires-Dist: xmltodict (>=0.13) ; extra == "all"
|
|
34
|
+
Requires-Dist: xmltodict (>=0.13) ; extra == "xml"
|
|
35
|
+
Project-URL: Bug Tracker, https://bis-med-it.github.io/pysdmx/issues
|
|
36
|
+
Project-URL: Documentation, https://bis-med-it.github.io/pysdmx
|
|
37
|
+
Project-URL: Homepage, https://sdmx.io/tools/pysdmx
|
|
38
|
+
Project-URL: Repository, https://github.com/bis-med-it/pysdmx
|
|
39
|
+
Description-Content-Type: text/x-rst
|
|
40
|
+
|
|
41
|
+
.. |pypi badge| image:: https://img.shields.io/pypi/v/pysdmx.svg
|
|
42
|
+
:target: https://pypi.org/project/pysdmx/
|
|
43
|
+
|
|
44
|
+
.. |awesome badge| image:: https://awesome.re/mentioned-badge.svg
|
|
45
|
+
:target: http://www.awesomeofficialstatistics.org
|
|
46
|
+
|
|
47
|
+
|pypi badge| |awesome badge|
|
|
48
|
+
|
|
49
|
+
``pysdmx`` in a nutshell
|
|
50
|
+
************************
|
|
51
|
+
|
|
52
|
+
What is pysdmx?
|
|
53
|
+
===============
|
|
54
|
+
|
|
55
|
+
``pysdmx`` is a **pragmatic** and **opinionated** SDMX library written in
|
|
56
|
+
**Python**. It focuses on **simplicity**, providing a subset of SDMX functionalities
|
|
57
|
+
without requiring advanced knowledge of SDMX. ``pysdmx`` is developed as part of
|
|
58
|
+
the `sdmx.io <http://sdmx.io/>`_ project under the **BIS Open Tech initiative**.
|
|
59
|
+
|
|
60
|
+
What does it do?
|
|
61
|
+
================
|
|
62
|
+
|
|
63
|
+
``pysdmx`` aspires to be a versatile SDMX toolbox for Python, covering various
|
|
64
|
+
use cases. Here are some highlights:
|
|
65
|
+
|
|
66
|
+
SDMX information model in Python
|
|
67
|
+
--------------------------------
|
|
68
|
+
|
|
69
|
+
``pysdmx`` offers Python classes representing a **simplified subset of the SDMX
|
|
70
|
+
information model**, enabling a domain-driven development of SDMX processes in
|
|
71
|
+
Python. The model classes support serialization in formats like JSON, YAML, or
|
|
72
|
+
MessagePack. This functionality relies on the
|
|
73
|
+
`msgspec library <https://jcristharif.com/msgspec/>`_.
|
|
74
|
+
|
|
75
|
+
Metadata in action
|
|
76
|
+
------------------
|
|
77
|
+
|
|
78
|
+
SDMX metadata are very useful for documenting statistical processes. For example,
|
|
79
|
+
they can define the structure we expect for a data collection process and share
|
|
80
|
+
it with the organizations providing data so that they know what to send.
|
|
81
|
+
|
|
82
|
+
However, metadata can do so much more than that, i.e., they can be “active” and
|
|
83
|
+
**drive various types of statistical processes**, such as generating the filesystem
|
|
84
|
+
layout, creating the physical data model, validating data, mapping data, and
|
|
85
|
+
configuring processes. To drive such processes, ``pysdmx`` supports retrieving
|
|
86
|
+
metadata from an SDMX Registry or any service compliant with the SDMX-REST 2.0.0 (or
|
|
87
|
+
above) API. Use these metadata to power your own statistical processes!
|
|
88
|
+
|
|
89
|
+
Reading and writing SDMX files
|
|
90
|
+
------------------------------
|
|
91
|
+
|
|
92
|
+
``pysdmx`` supports reading and writing SDMX data and structure messages, in various
|
|
93
|
+
formats, such as SDMX-CSV, SDMX-JSON, and SDMX-ML.
|
|
94
|
+
|
|
95
|
+
Data discovery and data retrieval
|
|
96
|
+
---------------------------------
|
|
97
|
+
|
|
98
|
+
This functionality is under development. Once ready, ``pysdmx`` will allow:
|
|
99
|
+
|
|
100
|
+
- **Listing public SDMX services**.
|
|
101
|
+
- **Discovering data** available in these services.
|
|
102
|
+
- **Retrieving data** from these services.
|
|
103
|
+
|
|
104
|
+
This functionality is based on the **SDMX Global Discovery Service initiative**.
|
|
105
|
+
|
|
106
|
+
Integration with the ecosystem
|
|
107
|
+
------------------------------
|
|
108
|
+
|
|
109
|
+
``pysdmx`` integrates nicely with other standards, like the `Validation and
|
|
110
|
+
Transformation Language (VTL) <https://sdmx.org/about-sdmx/about-vtl/>`_,
|
|
111
|
+
and major Python libraries like `Pandas <https://pandas.pydata.org/>`_.
|
|
112
|
+
Take a look at the ``pysdmx`` toolkit module to learn more.
|
|
113
|
+
|
|
114
|
+
``pysdmx`` is available on `PyPI <https://pypi.org/>`_ and can be
|
|
115
|
+
installed using options such as pip, pipx, poetry, etc.
|
|
116
|
+
|
|
117
|
+
For more details, check the `project documentation
|
|
118
|
+
<https://py.sdmx.io>`_.
|
|
119
|
+
|
pysdmx-1.4.0/README.rst
ADDED
|
@@ -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>`_.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pysdmx"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.4.0"
|
|
4
4
|
description = "Your opinionated Python SDMX library"
|
|
5
5
|
license = { text = "Apache-2.0" }
|
|
6
6
|
readme = "README.rst"
|
|
@@ -9,7 +9,8 @@ authors = [
|
|
|
9
9
|
{ name = "Xavier Sosnovsky", email = "<xavier.sosnovsky@bis.org>" },
|
|
10
10
|
{ name = "Stratos Nikoloutsos", email = "<stratos.nikoloutsos@bis.org>" },
|
|
11
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>" }
|
|
12
|
+
{ name = "Mateo de Lorenzo Argelés", email = "<mateo.delorenzo@meaningfuldata.eu>" },
|
|
13
|
+
{ name = "Jose Antonio Franco Martin", email = "<jose.franco@meaningfuldata.eu>" }
|
|
13
14
|
]
|
|
14
15
|
keywords = ["sdmx", "data discovery", "data retrieval", "metadata", "fmr"]
|
|
15
16
|
classifiers = [
|
|
@@ -34,9 +35,9 @@ documentation = "https://bis-med-it.github.io/pysdmx"
|
|
|
34
35
|
[project.optional-dependencies]
|
|
35
36
|
data = ["pandas>=2.1.4"]
|
|
36
37
|
dc = ["python-dateutil>=2.8.2"]
|
|
37
|
-
vtl = ["vtlengine>=1.
|
|
38
|
+
vtl = ["vtlengine>=1.1,<2.0"]
|
|
38
39
|
xml = ["lxml>=5.2", "xmltodict>=0.13", "sdmxschemas>=0.2.0"]
|
|
39
|
-
all = ["lxml>=5.2", "xmltodict>=0.13", "sdmxschemas>=0.2.0", "pandas>=2.1.4", "python-dateutil>=2.8.2", "vtlengine>=1.
|
|
40
|
+
all = ["lxml>=5.2", "xmltodict>=0.13", "sdmxschemas>=0.2.0", "pandas>=2.1.4", "python-dateutil>=2.8.2", "vtlengine>=1.1,<2.0"]
|
|
40
41
|
|
|
41
42
|
[tool.poetry]
|
|
42
43
|
requires-poetry = ">=2.0"
|
|
@@ -50,7 +50,8 @@ def __check_vtl_extra() -> None:
|
|
|
50
50
|
except ImportError:
|
|
51
51
|
raise ImportError(
|
|
52
52
|
ERROR_MESSAGE.format(
|
|
53
|
-
extra_name="
|
|
54
|
-
extra_desc="
|
|
53
|
+
extra_name="vtl",
|
|
54
|
+
extra_desc="VTL Scripts, SDMX-VTL model validations"
|
|
55
|
+
" and prettify",
|
|
55
56
|
)
|
|
56
57
|
) from None
|
|
@@ -642,7 +642,7 @@ class RegistryClient(__BaseRegistryClient):
|
|
|
642
642
|
"""
|
|
643
643
|
query = super()._report_q(provider, id, version)
|
|
644
644
|
out = self.__fetch(query)
|
|
645
|
-
return super()._out(out, self.deser.report)[0]
|
|
645
|
+
return super()._out(out, self.deser.report).reports[0]
|
|
646
646
|
|
|
647
647
|
def get_reports(
|
|
648
648
|
self,
|
|
@@ -667,7 +667,7 @@ class RegistryClient(__BaseRegistryClient):
|
|
|
667
667
|
"""
|
|
668
668
|
query = super()._reports_q(artefact_type, agency, id, version)
|
|
669
669
|
out = self.__fetch(query)
|
|
670
|
-
return super()._out(out, self.deser.report
|
|
670
|
+
return super()._out(out, self.deser.report).reports
|
|
671
671
|
|
|
672
672
|
def get_mapping(
|
|
673
673
|
self,
|
|
@@ -1104,7 +1104,7 @@ class AsyncRegistryClient(__BaseRegistryClient):
|
|
|
1104
1104
|
"""
|
|
1105
1105
|
query = super()._report_q(provider, id, version)
|
|
1106
1106
|
out = await self.__fetch(query)
|
|
1107
|
-
return super()._out(out, self.deser.report)[0]
|
|
1107
|
+
return super()._out(out, self.deser.report).reports[0]
|
|
1108
1108
|
|
|
1109
1109
|
async def get_reports(
|
|
1110
1110
|
self,
|
|
@@ -1129,7 +1129,7 @@ class AsyncRegistryClient(__BaseRegistryClient):
|
|
|
1129
1129
|
"""
|
|
1130
1130
|
query = super()._reports_q(artefact_type, agency, id, version)
|
|
1131
1131
|
out = await self.__fetch(query)
|
|
1132
|
-
return super()._out(out, self.deser.report
|
|
1132
|
+
return super()._out(out, self.deser.report).reports
|
|
1133
1133
|
|
|
1134
1134
|
async def get_mapping(
|
|
1135
1135
|
self,
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
"""API client for interacting with the GDS (Global Discovery Service) service.
|
|
2
|
+
|
|
3
|
+
This module provides classes and utilities to interact with the GDS service,
|
|
4
|
+
allowing retrieval of metadata such as agency information in SDMX-JSON format.
|
|
5
|
+
|
|
6
|
+
Exports: GdsClient: A synchronous client for retrieving metadata from
|
|
7
|
+
the GDS.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Any, Literal, Optional, Sequence
|
|
11
|
+
|
|
12
|
+
from msgspec.json import decode
|
|
13
|
+
|
|
14
|
+
from pysdmx.api.qb.gds import GdsQuery, GdsType
|
|
15
|
+
from pysdmx.api.qb.service import GdsAsyncRestService, GdsRestService
|
|
16
|
+
from pysdmx.api.qb.util import REST_ALL
|
|
17
|
+
from pysdmx.io.json.gds.reader import deserializers as gds_readers
|
|
18
|
+
from pysdmx.io.serde import Deserializer
|
|
19
|
+
from pysdmx.model import Agency
|
|
20
|
+
from pysdmx.model.gds import (
|
|
21
|
+
GdsCatalog,
|
|
22
|
+
GdsSdmxApi,
|
|
23
|
+
GdsService,
|
|
24
|
+
GdsUrnResolver,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
GDS_BASE_ENDPOINT = "https://gds.sdmx.io/"
|
|
28
|
+
|
|
29
|
+
READERS = gds_readers
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class __BaseGdsClient:
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
api_endpoint: str = GDS_BASE_ENDPOINT,
|
|
36
|
+
pem: Optional[str] = None,
|
|
37
|
+
):
|
|
38
|
+
"""Instantiate a new client against the target endpoint."""
|
|
39
|
+
if api_endpoint.endswith("/"):
|
|
40
|
+
api_endpoint = api_endpoint[0:-1]
|
|
41
|
+
self.api_endpoint = api_endpoint
|
|
42
|
+
self.reader = READERS
|
|
43
|
+
|
|
44
|
+
def _out(self, response: bytes, typ: Deserializer, *params: Any) -> Any:
|
|
45
|
+
return decode(response, type=typ).to_model(*params)
|
|
46
|
+
|
|
47
|
+
def _agencies_q(self, agency: str) -> GdsQuery:
|
|
48
|
+
return GdsQuery(artefact_type=GdsType.GDS_AGENCY, resource_id=agency)
|
|
49
|
+
|
|
50
|
+
def _catalogs_q(
|
|
51
|
+
self,
|
|
52
|
+
agency: str,
|
|
53
|
+
resource: str = REST_ALL,
|
|
54
|
+
version: str = REST_ALL,
|
|
55
|
+
resource_type: Optional[Literal["data", "metadata"]] = None,
|
|
56
|
+
message_format: Optional[Literal["json", "csv", "xml"]] = None,
|
|
57
|
+
api_version: Optional[str] = None,
|
|
58
|
+
detail: Optional[Literal["full", "raw"]] = None,
|
|
59
|
+
references: Optional[Literal["none", "children"]] = None,
|
|
60
|
+
) -> GdsQuery:
|
|
61
|
+
return GdsQuery(
|
|
62
|
+
artefact_type=GdsType.GDS_CATALOG,
|
|
63
|
+
agency=agency,
|
|
64
|
+
resource_id=resource,
|
|
65
|
+
version=version,
|
|
66
|
+
resource_type=resource_type,
|
|
67
|
+
message_format=message_format,
|
|
68
|
+
api_version=api_version,
|
|
69
|
+
detail=detail,
|
|
70
|
+
references=references,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def _sdmx_api_q(self, id: str = REST_ALL) -> GdsQuery:
|
|
74
|
+
return GdsQuery(artefact_type=GdsType.GDS_SDMX_API, resource_id=id)
|
|
75
|
+
|
|
76
|
+
def _services_q(
|
|
77
|
+
self, agency: str, resource: str = REST_ALL, version: str = REST_ALL
|
|
78
|
+
) -> GdsQuery:
|
|
79
|
+
return GdsQuery(
|
|
80
|
+
artefact_type=GdsType.GDS_SERVICE,
|
|
81
|
+
agency=agency,
|
|
82
|
+
resource_id=resource,
|
|
83
|
+
version=version,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def _urn_resolver_q(self, urn: str) -> GdsQuery:
|
|
87
|
+
return GdsQuery(
|
|
88
|
+
artefact_type=GdsType.GDS_URN_RESOLVER, resource_id=urn
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class GdsClient(__BaseGdsClient):
|
|
93
|
+
"""A client to be used to retrieve metadata from the GDS.
|
|
94
|
+
|
|
95
|
+
With this client, metadata will be retrieved in a synchronous fashion.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
def __init__(
|
|
99
|
+
self,
|
|
100
|
+
api_endpoint: str = GDS_BASE_ENDPOINT,
|
|
101
|
+
pem: Optional[str] = None,
|
|
102
|
+
) -> None:
|
|
103
|
+
"""Instantiate a new client against the target endpoint.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
api_endpoint: The endpoint of the targeted service.
|
|
107
|
+
pem: In case the service exposed a certificate created
|
|
108
|
+
by an unknown certificate authority, you can pass
|
|
109
|
+
a pem file for this authority using this parameter.
|
|
110
|
+
"""
|
|
111
|
+
super().__init__(api_endpoint, pem)
|
|
112
|
+
self.__service = GdsRestService(
|
|
113
|
+
self.api_endpoint,
|
|
114
|
+
pem=pem,
|
|
115
|
+
timeout=10.0,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
def __fetch(
|
|
119
|
+
self,
|
|
120
|
+
query: GdsQuery,
|
|
121
|
+
) -> bytes:
|
|
122
|
+
"""Fetch the requested metadata from the GDS service."""
|
|
123
|
+
return self.__service.gds(query)
|
|
124
|
+
|
|
125
|
+
def get_agencies(self, agency: str) -> Sequence[Agency]:
|
|
126
|
+
"""Get the list of agencies for the supplied name.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
agency: The agency maintaining the agency scheme from
|
|
130
|
+
which sub-agencies must be returned.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
The requested list of agencies.
|
|
134
|
+
"""
|
|
135
|
+
query = super()._agencies_q(agency)
|
|
136
|
+
out = self.__fetch(query)
|
|
137
|
+
agencies = super()._out(out, self.reader.agencies)
|
|
138
|
+
return agencies
|
|
139
|
+
|
|
140
|
+
def get_catalogs(
|
|
141
|
+
self,
|
|
142
|
+
catalog: str,
|
|
143
|
+
resource: str = REST_ALL,
|
|
144
|
+
version: str = REST_ALL,
|
|
145
|
+
resource_type: Optional[Literal["data", "metadata"]] = None,
|
|
146
|
+
message_format: Optional[Literal["json", "csv", "xml"]] = None,
|
|
147
|
+
api_version: Optional[str] = None,
|
|
148
|
+
detail: Optional[Literal["full", "raw"]] = None,
|
|
149
|
+
references: Optional[Literal["none", "children"]] = None,
|
|
150
|
+
) -> Sequence[GdsCatalog]:
|
|
151
|
+
"""Get the list of catalogs for the supplied parameters.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
catalog: The agency maintaining the catalog.
|
|
155
|
+
resource: The resource ID(s) to query. Defaults to '*'.
|
|
156
|
+
version: The version(s) of the resource. Defaults to '*'.
|
|
157
|
+
resource_type: Filters the endpoints that support
|
|
158
|
+
the requested resource type (eg, 'data', 'metadata')
|
|
159
|
+
message_format: Filters the endpoints that support any
|
|
160
|
+
of the requested message formats.
|
|
161
|
+
api_version: Filters the endpoints that is in a
|
|
162
|
+
specific SDMX API version.
|
|
163
|
+
Multiple values separated by commas are possible.
|
|
164
|
+
By default (if nothing is sent) it returns everything.
|
|
165
|
+
detail: The amount of information to be returned.
|
|
166
|
+
If detail=full: All available information for all artefacts
|
|
167
|
+
should be returned.
|
|
168
|
+
If detail=raw: Any nested service will be referenced.
|
|
169
|
+
references: Instructs the web service to return
|
|
170
|
+
(or not) the artefacts referenced by the
|
|
171
|
+
artefact to be returned.
|
|
172
|
+
If references=none: No referenced artefacts will be returned.
|
|
173
|
+
If references=children: Returns the artefacts
|
|
174
|
+
referenced by the artefact to be returned.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
A list of GdsCatalog objects.
|
|
178
|
+
"""
|
|
179
|
+
query = super()._catalogs_q(
|
|
180
|
+
catalog,
|
|
181
|
+
resource,
|
|
182
|
+
version,
|
|
183
|
+
resource_type,
|
|
184
|
+
message_format,
|
|
185
|
+
api_version,
|
|
186
|
+
detail,
|
|
187
|
+
references,
|
|
188
|
+
)
|
|
189
|
+
response = self.__fetch(query)
|
|
190
|
+
catalogs = super()._out(response, self.reader.catalogs)
|
|
191
|
+
return catalogs
|
|
192
|
+
|
|
193
|
+
def get_sdmx_apis(
|
|
194
|
+
self, api_version: str = REST_ALL
|
|
195
|
+
) -> Sequence[GdsSdmxApi]:
|
|
196
|
+
"""Get the list of SDMX API versions.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
api_version: The version of the SDMX API to be returned.
|
|
200
|
+
Defaults to '*'.
|
|
201
|
+
"""
|
|
202
|
+
query = super()._sdmx_api_q(api_version)
|
|
203
|
+
response = self.__fetch(query)
|
|
204
|
+
sdmx_api = super()._out(response, self.reader.sdmx_api)
|
|
205
|
+
return sdmx_api
|
|
206
|
+
|
|
207
|
+
def get_services(
|
|
208
|
+
self, service: str, resource: str = REST_ALL, version: str = REST_ALL
|
|
209
|
+
) -> Sequence[GdsService]:
|
|
210
|
+
"""Get the list of services for the supplied parameters.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
service: The agency maintaining the service.
|
|
214
|
+
resource: The resource ID(s) to query. Defaults to '*'.
|
|
215
|
+
version: The version(s) of the resource. Defaults to '*'.
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
A list of GdsService objects.
|
|
219
|
+
"""
|
|
220
|
+
query = super()._services_q(service, resource, version)
|
|
221
|
+
response = self.__fetch(query)
|
|
222
|
+
services = super()._out(response, self.reader.services)
|
|
223
|
+
return services
|
|
224
|
+
|
|
225
|
+
def get_urn_resolver(self, urn: str) -> GdsUrnResolver:
|
|
226
|
+
"""Resolve a URN to its corresponding resource.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
urn: The URN to resolve.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
A GdsUrnResolver object with the resolved information.
|
|
233
|
+
"""
|
|
234
|
+
query = super()._urn_resolver_q(urn)
|
|
235
|
+
response = self.__fetch(query)
|
|
236
|
+
urn_resolution = super()._out(response, self.reader.urn_resolver)
|
|
237
|
+
return urn_resolution
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class AsyncGdsClient(__BaseGdsClient):
|
|
241
|
+
"""A client to be used to retrieve metadata from the GDS asynchronously."""
|
|
242
|
+
|
|
243
|
+
def __init__(
|
|
244
|
+
self,
|
|
245
|
+
api_endpoint: str = GDS_BASE_ENDPOINT,
|
|
246
|
+
pem: Optional[str] = None,
|
|
247
|
+
) -> None:
|
|
248
|
+
"""Instantiate a new client against the target endpoint.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
api_endpoint: The endpoint of the targeted service.
|
|
252
|
+
pem: PEM file for unknown certificate authorities.
|
|
253
|
+
"""
|
|
254
|
+
super().__init__(api_endpoint, pem)
|
|
255
|
+
self.__service = GdsAsyncRestService(
|
|
256
|
+
self.api_endpoint,
|
|
257
|
+
pem=pem,
|
|
258
|
+
timeout=10.0,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
async def __fetch(self, query: GdsQuery) -> bytes:
|
|
262
|
+
"""Fetch the requested metadata from the GDS service asynchronously."""
|
|
263
|
+
return await self.__service.gds(query)
|
|
264
|
+
|
|
265
|
+
async def get_agencies(self, agency: str) -> Sequence[Agency]:
|
|
266
|
+
"""Get the list of agencies for the supplied name asynchronously.
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
agency: The agency maintaining the agency scheme.
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
The requested list of agencies.
|
|
273
|
+
"""
|
|
274
|
+
query = super(AsyncGdsClient, self)._agencies_q(agency)
|
|
275
|
+
out = await self.__fetch(query)
|
|
276
|
+
agencies = super(AsyncGdsClient, self)._out(out, self.reader.agencies)
|
|
277
|
+
return agencies
|
|
278
|
+
|
|
279
|
+
async def get_catalogs(
|
|
280
|
+
self,
|
|
281
|
+
catalog: str,
|
|
282
|
+
resource: str = REST_ALL,
|
|
283
|
+
version: str = REST_ALL,
|
|
284
|
+
resource_type: Optional[Literal["data", "metadata"]] = None,
|
|
285
|
+
message_format: Optional[Literal["json", "csv", "xml"]] = None,
|
|
286
|
+
api_version: Optional[str] = None,
|
|
287
|
+
detail: Optional[Literal["full", "raw"]] = None,
|
|
288
|
+
references: Optional[Literal["none", "children"]] = None,
|
|
289
|
+
) -> Sequence[GdsCatalog]:
|
|
290
|
+
"""Get the list of catalogs for the supplied params asynchronously."""
|
|
291
|
+
query = super()._catalogs_q(
|
|
292
|
+
catalog,
|
|
293
|
+
resource,
|
|
294
|
+
version,
|
|
295
|
+
resource_type,
|
|
296
|
+
message_format,
|
|
297
|
+
api_version,
|
|
298
|
+
detail,
|
|
299
|
+
references,
|
|
300
|
+
)
|
|
301
|
+
response = await self.__fetch(query)
|
|
302
|
+
catalogs = super()._out(response, self.reader.catalogs)
|
|
303
|
+
return catalogs
|
|
304
|
+
|
|
305
|
+
async def get_sdmx_apis(
|
|
306
|
+
self, api_version: str = REST_ALL
|
|
307
|
+
) -> Sequence[GdsSdmxApi]:
|
|
308
|
+
"""Get the list of SDMX API versions asynchronously."""
|
|
309
|
+
query = super()._sdmx_api_q(api_version)
|
|
310
|
+
response = await self.__fetch(query)
|
|
311
|
+
sdmx_api = super()._out(response, self.reader.sdmx_api)
|
|
312
|
+
return sdmx_api
|
|
313
|
+
|
|
314
|
+
async def get_services(
|
|
315
|
+
self, service: str, resource: str = REST_ALL, version: str = REST_ALL
|
|
316
|
+
) -> Sequence[GdsService]:
|
|
317
|
+
"""Get a list of services for the supplied params asynchronously."""
|
|
318
|
+
query = super()._services_q(service, resource, version)
|
|
319
|
+
response = await self.__fetch(query)
|
|
320
|
+
services = super()._out(response, self.reader.services)
|
|
321
|
+
return services
|
|
322
|
+
|
|
323
|
+
async def get_urn_resolver(self, urn: str) -> GdsUrnResolver:
|
|
324
|
+
"""Resolve a URN to its corresponding resource asynchronously."""
|
|
325
|
+
query = super()._urn_resolver_q(urn)
|
|
326
|
+
response = await self.__fetch(query)
|
|
327
|
+
urn_resolution = super()._out(response, self.reader.urn_resolver)
|
|
328
|
+
return urn_resolution
|