pysdmx 1.10.1__tar.gz → 1.11.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.10.1 → pysdmx-1.11.0}/PKG-INFO +7 -1
- {pysdmx-1.10.1 → pysdmx-1.11.0}/pyproject.toml +10 -5
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/__init__.py +1 -1
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/fmr/maintenance.py +10 -5
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/input_processor.py +4 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/dsd.py +19 -14
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/msd.py +6 -9
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/core.py +12 -5
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/dsd.py +11 -17
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/msd.py +2 -5
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/report.py +7 -3
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/structure.py +7 -3
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/reader/metadata.py +3 -3
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/reader/structure.py +3 -3
- pysdmx-1.11.0/src/pysdmx/io/json/sdmxjson2/writer/_helper.py +118 -0
- pysdmx-1.11.0/src/pysdmx/io/json/sdmxjson2/writer/v2_0/__init__.py +1 -0
- pysdmx-1.11.0/src/pysdmx/io/json/sdmxjson2/writer/v2_0/metadata.py +33 -0
- pysdmx-1.11.0/src/pysdmx/io/json/sdmxjson2/writer/v2_0/structure.py +33 -0
- pysdmx-1.11.0/src/pysdmx/io/json/sdmxjson2/writer/v2_1/__init__.py +1 -0
- pysdmx-1.11.0/src/pysdmx/io/json/sdmxjson2/writer/v2_1/metadata.py +31 -0
- pysdmx-1.11.0/src/pysdmx/io/json/sdmxjson2/writer/v2_1/structure.py +33 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/reader.py +12 -3
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/writer.py +13 -3
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/__ss_aux_reader.py +39 -17
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/__structure_aux_reader.py +221 -33
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/__structure_aux_writer.py +304 -5
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/__tokens.py +12 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/__write_aux.py +9 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/writer/generic.py +2 -2
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/dataflow.py +2 -2
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/toolkit/pd/_data_utils.py +1 -1
- pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/writer/metadata.py +0 -60
- pysdmx-1.10.1/src/pysdmx/io/json/sdmxjson2/writer/structure.py +0 -61
- {pysdmx-1.10.1 → pysdmx-1.11.0}/LICENSE +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/README.rst +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/__extras_check.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/dc/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/dc/_api.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/dc/query/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/dc/query/_model.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/dc/query/_parsing_model.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/dc/query/_parsing_util.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/dc/query/_py_parser.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/dc/query/_sql_parser.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/dc/query/util.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/fmr/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/gds/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/qb/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/qb/availability.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/qb/data.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/qb/gds.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/qb/refmeta.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/qb/registration.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/qb/schema.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/qb/service.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/qb/structure.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/api/qb/util.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/errors.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/csv/__csv_aux_reader.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/csv/__csv_aux_writer.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/csv/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx10/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx10/reader/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx10/writer/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx20/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx20/reader/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx20/writer/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx21/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx21/reader/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx21/writer/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/format.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/category.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/code.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/concept.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/constraint.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/core.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/dataflow.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/map.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/metadataflow.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/mpa.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/org.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/pa.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/report.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/schema.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/vtl.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/reader/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/gds/messages/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/gds/messages/agencies.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/gds/messages/catalog.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/gds/messages/sdmx_api.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/gds/messages/services.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/gds/messages/urn_resolver.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/gds/reader/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/agency.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/category.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/code.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/concept.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/constraint.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/dataflow.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/map.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/metadataflow.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/mpa.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/pa.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/provider.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/schema.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/vtl.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/reader/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/reader/doc_validation.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/writer/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/pd.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/serde.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/__allowed_lxml_errors.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/__data_aux.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/__parse_xml.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/__write_data_aux.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/__write_structure_specific_aux.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/config.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/doc_validation.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/header.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/reader/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/reader/error.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/reader/generic.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/reader/structure.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/reader/structure_specific.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/reader/submission.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/writer/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/writer/error.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/writer/structure.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/writer/structure_specific.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx30/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx30/reader/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx30/reader/structure.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx30/reader/structure_specific.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx30/writer/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx30/writer/structure.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx30/writer/structure_specific.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx31/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx31/reader/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx31/reader/structure.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx31/reader/structure_specific.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx31/writer/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx31/writer/structure.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx31/writer/structure_specific.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/io/xml/utils.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/__base.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/category.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/code.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/concept.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/constraint.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/dataset.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/gds.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/map.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/message.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/metadata.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/organisation.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/submission.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/model/vtl.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/py.typed +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/toolkit/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/toolkit/pd/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/toolkit/vtl/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/toolkit/vtl/_validations.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/toolkit/vtl/convert.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/toolkit/vtl/script_generation.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/toolkit/vtl/validation.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/util/__init__.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/util/_date_pattern_map.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/util/_model_utils.py +0 -0
- {pysdmx-1.10.1 → pysdmx-1.11.0}/src/pysdmx/util/_net_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pysdmx
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.11.0
|
|
4
4
|
Summary: Your opinionated Python SDMX library
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -24,6 +24,12 @@ Requires-Dist: jsonschema (>=4.10) ; extra == "json"
|
|
|
24
24
|
Requires-Dist: lxml (>=5.2) ; extra == "all"
|
|
25
25
|
Requires-Dist: lxml (>=5.2) ; extra == "xml"
|
|
26
26
|
Requires-Dist: msgspec (>=0)
|
|
27
|
+
Requires-Dist: numpy (>=2.0.2,<2.1) ; (python_version < "3.13") and (extra == "all")
|
|
28
|
+
Requires-Dist: numpy (>=2.0.2,<2.1) ; (python_version < "3.13") and (extra == "data")
|
|
29
|
+
Requires-Dist: numpy (>=2.0.2,<2.1) ; (python_version < "3.13") and (extra == "vtl")
|
|
30
|
+
Requires-Dist: numpy (>=2.1.0,<2.3) ; (python_version >= "3.13") and (extra == "all")
|
|
31
|
+
Requires-Dist: numpy (>=2.1.0,<2.3) ; (python_version >= "3.13") and (extra == "data")
|
|
32
|
+
Requires-Dist: numpy (>=2.1.0,<2.3) ; (python_version >= "3.13") and (extra == "vtl")
|
|
27
33
|
Requires-Dist: pandas (>=2.1.4) ; extra == "all"
|
|
28
34
|
Requires-Dist: pandas (>=2.1.4) ; extra == "data"
|
|
29
35
|
Requires-Dist: parsy (>=2.1)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pysdmx"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.11.0"
|
|
4
4
|
description = "Your opinionated Python SDMX library"
|
|
5
5
|
license = { text = "Apache-2.0" }
|
|
6
6
|
readme = "README.rst"
|
|
@@ -35,12 +35,13 @@ documentation = "https://bis-med-it.github.io/pysdmx"
|
|
|
35
35
|
"Bug Tracker" = "https://bis-med-it.github.io/pysdmx/issues"
|
|
36
36
|
|
|
37
37
|
[project.optional-dependencies]
|
|
38
|
-
data = ["pandas>=2.1.4"]
|
|
38
|
+
data = ["pandas>=2.1.4", "numpy>=2.0.2,<2.1; python_version < '3.13'", "numpy>=2.1.0,<2.3; python_version >= '3.13'"]
|
|
39
39
|
dc = ["python-dateutil>=2.8.2"]
|
|
40
|
-
vtl = ["vtlengine>=1.2,<2.0"]
|
|
40
|
+
vtl = ["vtlengine>=1.2,<2.0", "numpy>=2.0.2,<2.1; python_version < '3.13'", "numpy>=2.1.0,<2.3; python_version >= '3.13'"]
|
|
41
41
|
json = ["sdmxschemas>=1.0.0", "jsonschema>=4.10"]
|
|
42
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"
|
|
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
|
+
"numpy>=2.0.2,<2.1; python_version < '3.13'", "numpy>=2.1.0,<2.3; python_version >= '3.13'"]
|
|
44
45
|
|
|
45
46
|
[tool.poetry]
|
|
46
47
|
requires-poetry = ">=2.0"
|
|
@@ -49,6 +50,7 @@ requires-poetry = ">=2.0"
|
|
|
49
50
|
python = ">=3.9,<4.0"
|
|
50
51
|
|
|
51
52
|
[tool.poetry.group.dev.dependencies]
|
|
53
|
+
coverage = ">=7.0,!=7.13.0,<8.0"
|
|
52
54
|
ruff = ">=0.13.2"
|
|
53
55
|
mypy = "^1.18.2"
|
|
54
56
|
pytest = "^8.3.2"
|
|
@@ -59,7 +61,10 @@ pyroma = "^4.2"
|
|
|
59
61
|
lxml-stubs = "^0.5.1"
|
|
60
62
|
types-xmltodict = "^0.13.0.3"
|
|
61
63
|
types-python-dateutil = "^2.9.0.20240316"
|
|
62
|
-
pandas-stubs =
|
|
64
|
+
pandas-stubs = [
|
|
65
|
+
{ version = ">2.1.4.231227,<2.2.3.240901", python = "<3.13" },
|
|
66
|
+
{ version = ">=2.2.3.241009", python = ">=3.13" }
|
|
67
|
+
]
|
|
63
68
|
types-jsonschema = "^4.25.1.20251009"
|
|
64
69
|
|
|
65
70
|
[tool.poetry.group.docs.dependencies]
|
|
@@ -64,9 +64,7 @@ class RegistryMaintenanceClient:
|
|
|
64
64
|
timeout: The maximum number of seconds to wait before considering
|
|
65
65
|
that a request timed out. Defaults to 10 seconds.
|
|
66
66
|
"""
|
|
67
|
-
|
|
68
|
-
api_endpoint = api_endpoint[0:-1]
|
|
69
|
-
self._api_endpoint = f"{api_endpoint}"
|
|
67
|
+
self._api_endpoint = self.__sanitize_endpoint(api_endpoint)
|
|
70
68
|
self._user = user
|
|
71
69
|
self._password = password
|
|
72
70
|
self._timeout = timeout
|
|
@@ -87,7 +85,6 @@ class RegistryMaintenanceClient:
|
|
|
87
85
|
) -> None:
|
|
88
86
|
with httpx.Client(verify=self._ssl_context) as client:
|
|
89
87
|
try:
|
|
90
|
-
url = f"{endpoint}"
|
|
91
88
|
auth = httpx.BasicAuth(self._user, self._password)
|
|
92
89
|
headers = {
|
|
93
90
|
"Content-Type": "application/text",
|
|
@@ -99,7 +96,7 @@ class RegistryMaintenanceClient:
|
|
|
99
96
|
serializer = serializers.structure_message
|
|
100
97
|
bodyjs = self._encoder.encode(serializer.from_model(message))
|
|
101
98
|
r = client.post(
|
|
102
|
-
|
|
99
|
+
endpoint,
|
|
103
100
|
headers=headers,
|
|
104
101
|
content=bodyjs,
|
|
105
102
|
timeout=self._timeout,
|
|
@@ -156,3 +153,11 @@ class RegistryMaintenanceClient:
|
|
|
156
153
|
message = MetadataMessage(header=header, reports=reports)
|
|
157
154
|
endpoint = f"{self._api_endpoint}/ws/secure/sdmx/v2/metadata"
|
|
158
155
|
return self.__post(message, action, endpoint)
|
|
156
|
+
|
|
157
|
+
def __sanitize_endpoint(self, endpoint: str) -> str:
|
|
158
|
+
if endpoint.endswith("/"):
|
|
159
|
+
endpoint = endpoint[0:-1]
|
|
160
|
+
endpoint = endpoint.replace("/ws/secure/sdmx/v2/metadata", "")
|
|
161
|
+
endpoint = endpoint.replace("/sdmx/v2", "")
|
|
162
|
+
endpoint = endpoint.replace("/ws/secure/sdmxapi/rest", "")
|
|
163
|
+
return endpoint
|
|
@@ -97,6 +97,10 @@ def __get_sdmx_json_flavour(input_str: str) -> Tuple[str, Format]:
|
|
|
97
97
|
return input_str, Format.STRUCTURE_SDMX_JSON_2_0_0
|
|
98
98
|
elif "2.0.0/sdmx-json-metadata-schema.json" in flavour_check:
|
|
99
99
|
return input_str, Format.REFMETA_SDMX_JSON_2_0_0
|
|
100
|
+
elif "2.1/sdmx-json-structure-schema.json" in flavour_check:
|
|
101
|
+
return input_str, Format.STRUCTURE_SDMX_JSON_2_1_0
|
|
102
|
+
elif "2.1/sdmx-json-metadata-schema.json" in flavour_check:
|
|
103
|
+
return input_str, Format.REFMETA_SDMX_JSON_2_1_0
|
|
100
104
|
elif "sdmx-json" in flavour_check:
|
|
101
105
|
raise NotImplemented(
|
|
102
106
|
"Unsupported format", "This flavour of SDMX-JSON is not supported."
|
|
@@ -20,6 +20,7 @@ from pysdmx.model import (
|
|
|
20
20
|
Codelist,
|
|
21
21
|
Component,
|
|
22
22
|
Components,
|
|
23
|
+
Concept,
|
|
23
24
|
DataStructureDefinition,
|
|
24
25
|
DataType,
|
|
25
26
|
Facets,
|
|
@@ -32,14 +33,15 @@ from pysdmx.util import parse_item_urn
|
|
|
32
33
|
def _find_concept(
|
|
33
34
|
cs: Sequence[FusionConceptScheme],
|
|
34
35
|
urn: str,
|
|
35
|
-
) -> FusionConcept:
|
|
36
|
+
) -> Optional[FusionConcept]:
|
|
36
37
|
r = parse_item_urn(urn)
|
|
37
38
|
f = [
|
|
38
39
|
m
|
|
39
40
|
for m in cs
|
|
40
41
|
if (m.agency == r.agency and m.id == r.id and m.version == r.version)
|
|
41
42
|
]
|
|
42
|
-
|
|
43
|
+
m = [c for c in f[0].items if c.id == r.item_id]
|
|
44
|
+
return m[0] if m else None
|
|
43
45
|
|
|
44
46
|
|
|
45
47
|
def _get_representation(
|
|
@@ -112,12 +114,13 @@ class FusionAttribute(Struct, frozen=True):
|
|
|
112
114
|
groups: Sequence[FusionGroup],
|
|
113
115
|
) -> Component:
|
|
114
116
|
"""Returns an attribute."""
|
|
115
|
-
|
|
117
|
+
m = _find_concept(cs, self.concept) if cs else None
|
|
118
|
+
c = m.to_model(cls) if m else parse_item_urn(self.concept)
|
|
116
119
|
dt, facets, codes, ab = _get_representation(
|
|
117
120
|
self.id, self.representation, cls, cons
|
|
118
121
|
)
|
|
119
122
|
lvl = self.__derive_level(groups)
|
|
120
|
-
desc = c.
|
|
123
|
+
desc = c.description if isinstance(c, Concept) else None
|
|
121
124
|
if self.representation and self.representation.representation:
|
|
122
125
|
local_enum_ref = self.representation.representation
|
|
123
126
|
else:
|
|
@@ -126,10 +129,10 @@ class FusionAttribute(Struct, frozen=True):
|
|
|
126
129
|
id=self.id,
|
|
127
130
|
required=self.mandatory,
|
|
128
131
|
role=Role.ATTRIBUTE,
|
|
129
|
-
concept=c
|
|
132
|
+
concept=c,
|
|
130
133
|
local_dtype=dt,
|
|
131
134
|
local_facets=facets,
|
|
132
|
-
name=c.
|
|
135
|
+
name=c.name if isinstance(c, Concept) else None,
|
|
133
136
|
description=desc,
|
|
134
137
|
local_codes=codes,
|
|
135
138
|
attachment_level=lvl,
|
|
@@ -168,11 +171,12 @@ class FusionDimension(Struct, frozen=True):
|
|
|
168
171
|
cons: Dict[str, Sequence[str]],
|
|
169
172
|
) -> Component:
|
|
170
173
|
"""Returns a dimension."""
|
|
171
|
-
|
|
174
|
+
m = _find_concept(cs, self.concept) if cs else None
|
|
175
|
+
c = m.to_model(cls) if m else parse_item_urn(self.concept)
|
|
172
176
|
dt, facets, codes, ab = _get_representation(
|
|
173
177
|
self.id, self.representation, cls, cons
|
|
174
178
|
)
|
|
175
|
-
desc = c.
|
|
179
|
+
desc = c.description if isinstance(c, Concept) else None
|
|
176
180
|
if self.representation and self.representation.representation:
|
|
177
181
|
local_enum_ref = self.representation.representation
|
|
178
182
|
else:
|
|
@@ -181,10 +185,10 @@ class FusionDimension(Struct, frozen=True):
|
|
|
181
185
|
id=self.id,
|
|
182
186
|
required=True,
|
|
183
187
|
role=Role.DIMENSION,
|
|
184
|
-
concept=c
|
|
188
|
+
concept=c,
|
|
185
189
|
local_dtype=dt,
|
|
186
190
|
local_facets=facets,
|
|
187
|
-
name=c.
|
|
191
|
+
name=c.name if isinstance(c, Concept) else None,
|
|
188
192
|
description=desc,
|
|
189
193
|
local_codes=codes,
|
|
190
194
|
array_def=ab,
|
|
@@ -222,11 +226,12 @@ class FusionMeasure(Struct, frozen=True):
|
|
|
222
226
|
cons: Dict[str, Sequence[str]],
|
|
223
227
|
) -> Component:
|
|
224
228
|
"""Returns a measure."""
|
|
225
|
-
|
|
229
|
+
m = _find_concept(cs, self.concept) if cs else None
|
|
230
|
+
c = m.to_model(cls) if m else parse_item_urn(self.concept)
|
|
226
231
|
dt, facets, codes, ab = _get_representation(
|
|
227
232
|
self.id, self.representation, cls, cons
|
|
228
233
|
)
|
|
229
|
-
desc = c.
|
|
234
|
+
desc = c.description if isinstance(c, Concept) else None
|
|
230
235
|
if self.representation and self.representation.representation:
|
|
231
236
|
local_enum_ref = self.representation.representation
|
|
232
237
|
else:
|
|
@@ -235,10 +240,10 @@ class FusionMeasure(Struct, frozen=True):
|
|
|
235
240
|
id=self.id,
|
|
236
241
|
required=self.mandatory,
|
|
237
242
|
role=Role.MEASURE,
|
|
238
|
-
concept=c
|
|
243
|
+
concept=c,
|
|
239
244
|
local_dtype=dt,
|
|
240
245
|
local_facets=facets,
|
|
241
|
-
name=c.
|
|
246
|
+
name=c.name if isinstance(c, Concept) else None,
|
|
242
247
|
description=desc,
|
|
243
248
|
local_codes=codes,
|
|
244
249
|
array_def=ab,
|
|
@@ -14,13 +14,9 @@ from pysdmx.io.json.fusion.messages.dsd import (
|
|
|
14
14
|
_find_concept,
|
|
15
15
|
_get_representation,
|
|
16
16
|
)
|
|
17
|
-
from pysdmx.model import
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
)
|
|
21
|
-
from pysdmx.model import (
|
|
22
|
-
MetadataStructure as MSD,
|
|
23
|
-
)
|
|
17
|
+
from pysdmx.model import ArrayBoundaries, MetadataComponent
|
|
18
|
+
from pysdmx.model import MetadataStructure as MSD
|
|
19
|
+
from pysdmx.util import parse_item_urn
|
|
24
20
|
|
|
25
21
|
|
|
26
22
|
class FusionMetadataAttribute(Struct, frozen=True):
|
|
@@ -40,7 +36,8 @@ class FusionMetadataAttribute(Struct, frozen=True):
|
|
|
40
36
|
cls: Sequence[FusionCodelist],
|
|
41
37
|
) -> MetadataComponent:
|
|
42
38
|
"""Returns an attribute."""
|
|
43
|
-
|
|
39
|
+
m = _find_concept(cs, self.concept) if cs else None
|
|
40
|
+
c = m.to_model(cls) if m else parse_item_urn(self.concept)
|
|
44
41
|
dt, facets, codes, _ = _get_representation(
|
|
45
42
|
self.id, self.representation, cls, {}
|
|
46
43
|
)
|
|
@@ -60,7 +57,7 @@ class FusionMetadataAttribute(Struct, frozen=True):
|
|
|
60
57
|
return MetadataComponent(
|
|
61
58
|
self.id,
|
|
62
59
|
is_presentational=self.presentational, # type: ignore[arg-type]
|
|
63
|
-
concept=c
|
|
60
|
+
concept=c,
|
|
64
61
|
local_dtype=dt,
|
|
65
62
|
local_facets=facets,
|
|
66
63
|
local_codes=codes,
|
|
@@ -307,17 +307,24 @@ class JsonHeader(msgspec.Struct, frozen=True, omit_defaults=True):
|
|
|
307
307
|
self,
|
|
308
308
|
header: Header,
|
|
309
309
|
msg_type: Literal["structure", "metadata"] = "structure",
|
|
310
|
+
msg_version: Literal["2.0.0", "2.1"] = "2.0.0",
|
|
310
311
|
) -> "JsonHeader":
|
|
311
312
|
"""Create an SDMX-JSON header from a pysdmx Header."""
|
|
313
|
+
if msg_version == "2.0.0":
|
|
314
|
+
schema = (
|
|
315
|
+
"https://raw.githubusercontent.com/sdmx-twg/sdmx-json/"
|
|
316
|
+
f"develop/structure-message/tools/schemas/{msg_version}/"
|
|
317
|
+
f"sdmx-json-{msg_type}-schema.json"
|
|
318
|
+
)
|
|
319
|
+
else:
|
|
320
|
+
schema = (
|
|
321
|
+
f"https://json.sdmx.org/2.1/sdmx-json-{msg_type}-schema.json"
|
|
322
|
+
)
|
|
312
323
|
return JsonHeader(
|
|
313
324
|
header.id,
|
|
314
325
|
header.prepared,
|
|
315
326
|
header.sender,
|
|
316
327
|
header.test,
|
|
317
328
|
receivers=header.receiver if header.receiver else None,
|
|
318
|
-
schema=
|
|
319
|
-
"https://raw.githubusercontent.com/sdmx-twg/sdmx-json/"
|
|
320
|
-
"develop/structure-message/tools/schemas/2.0.0/"
|
|
321
|
-
f"sdmx-json-{msg_type}-schema.json"
|
|
322
|
-
),
|
|
329
|
+
schema=schema,
|
|
323
330
|
)
|
|
@@ -34,14 +34,17 @@ from pysdmx.model.dataflow import Group
|
|
|
34
34
|
from pysdmx.util import parse_item_urn
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def _find_concept(
|
|
37
|
+
def _find_concept(
|
|
38
|
+
cs: Sequence[JsonConceptScheme], urn: str
|
|
39
|
+
) -> Optional[JsonConcept]:
|
|
38
40
|
r = parse_item_urn(urn)
|
|
39
41
|
f = [
|
|
40
42
|
m
|
|
41
43
|
for m in cs
|
|
42
44
|
if (m.agency == r.agency and m.id == r.id and m.version == r.version)
|
|
43
45
|
]
|
|
44
|
-
|
|
46
|
+
m = [c for c in f[0].concepts if c.id == r.item_id]
|
|
47
|
+
return m[0] if m else None
|
|
45
48
|
|
|
46
49
|
|
|
47
50
|
def _get_type(repr_: JsonRepresentation) -> Optional[str]:
|
|
@@ -168,11 +171,8 @@ class JsonDimension(Struct, frozen=True, omit_defaults=True):
|
|
|
168
171
|
cons: Dict[str, Sequence[str]],
|
|
169
172
|
) -> Component:
|
|
170
173
|
"""Returns a component."""
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if cs
|
|
174
|
-
else parse_item_urn(self.conceptIdentity)
|
|
175
|
-
)
|
|
174
|
+
m = _find_concept(cs, self.conceptIdentity) if cs else None
|
|
175
|
+
c = m.to_model(cls) if m else parse_item_urn(self.conceptIdentity)
|
|
176
176
|
name = c.name if isinstance(c, Concept) else None
|
|
177
177
|
desc = c.description if isinstance(c, Concept) else None
|
|
178
178
|
dt, facets, codes, ab = _get_representation(
|
|
@@ -227,11 +227,8 @@ class JsonAttribute(Struct, frozen=True, omit_defaults=True):
|
|
|
227
227
|
groups: Sequence[JsonGroup],
|
|
228
228
|
) -> Component:
|
|
229
229
|
"""Returns a component."""
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if cs
|
|
233
|
-
else parse_item_urn(self.conceptIdentity)
|
|
234
|
-
)
|
|
230
|
+
m = _find_concept(cs, self.conceptIdentity) if cs else None
|
|
231
|
+
c = m.to_model(cls) if m else parse_item_urn(self.conceptIdentity)
|
|
235
232
|
name = c.name if isinstance(c, Concept) else None
|
|
236
233
|
desc = c.description if isinstance(c, Concept) else None
|
|
237
234
|
dt, facets, codes, ab = _get_representation(
|
|
@@ -312,11 +309,8 @@ class JsonMeasure(Struct, frozen=True, omit_defaults=True):
|
|
|
312
309
|
cons: Dict[str, Sequence[str]],
|
|
313
310
|
) -> Component:
|
|
314
311
|
"""Returns a component."""
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
if cs
|
|
318
|
-
else parse_item_urn(self.conceptIdentity)
|
|
319
|
-
)
|
|
312
|
+
m = _find_concept(cs, self.conceptIdentity) if cs else None
|
|
313
|
+
c = m.to_model(cls) if m else parse_item_urn(self.conceptIdentity)
|
|
320
314
|
name = c.name if isinstance(c, Concept) else None
|
|
321
315
|
desc = c.description if isinstance(c, Concept) else None
|
|
322
316
|
dt, facets, codes, ab = _get_representation(
|
|
@@ -49,11 +49,8 @@ class JsonMetadataAttribute(Struct, frozen=True, omit_defaults=True):
|
|
|
49
49
|
self, cs: Sequence[JsonConceptScheme], cls: Sequence[Codelist]
|
|
50
50
|
) -> MetadataComponent:
|
|
51
51
|
"""Returns a metadata component."""
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if cs
|
|
55
|
-
else parse_item_urn(self.conceptIdentity)
|
|
56
|
-
)
|
|
52
|
+
m = _find_concept(cs, self.conceptIdentity) if cs else None
|
|
53
|
+
c = m.to_model(cls) if m else parse_item_urn(self.conceptIdentity)
|
|
57
54
|
dt, facets, codes, _ = _get_representation(
|
|
58
55
|
self.id, self.localRepresentation, cls, {}
|
|
59
56
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Collection of SDMX-JSON schemas for reference metadata queries."""
|
|
2
2
|
|
|
3
|
-
from typing import Any, Optional, Sequence
|
|
3
|
+
from typing import Any, Literal, Optional, Sequence
|
|
4
4
|
|
|
5
5
|
from msgspec import Struct
|
|
6
6
|
|
|
@@ -162,7 +162,11 @@ class JsonMetadataMessage(Struct, frozen=True, omit_defaults=True):
|
|
|
162
162
|
return MetadataMessage(header, reports)
|
|
163
163
|
|
|
164
164
|
@classmethod
|
|
165
|
-
def from_model(
|
|
165
|
+
def from_model(
|
|
166
|
+
self,
|
|
167
|
+
msg: MetadataMessage,
|
|
168
|
+
msg_version: Literal["2.0.0", "2.1"] = "2.0.0",
|
|
169
|
+
) -> "JsonMetadataMessage":
|
|
166
170
|
"""Converts a pysdmx metadata message to an SDMX-JSON one."""
|
|
167
171
|
if not msg.header:
|
|
168
172
|
raise errors.Invalid(
|
|
@@ -175,6 +179,6 @@ class JsonMetadataMessage(Struct, frozen=True, omit_defaults=True):
|
|
|
175
179
|
"SDMX-JSON metadata messages must have metadata reports.",
|
|
176
180
|
)
|
|
177
181
|
|
|
178
|
-
header = JsonHeader.from_model(msg.header, "metadata")
|
|
182
|
+
header = JsonHeader.from_model(msg.header, "metadata", msg_version)
|
|
179
183
|
reports = [JsonMetadataReport.from_model(r) for r in msg.reports]
|
|
180
184
|
return JsonMetadataMessage(header, JsonMetadataSets(reports))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Collection of SDMX-JSON schemas for generic structure messages."""
|
|
2
2
|
|
|
3
|
-
from typing import Sequence
|
|
3
|
+
from typing import Literal, Sequence
|
|
4
4
|
|
|
5
5
|
from msgspec import Struct
|
|
6
6
|
|
|
@@ -338,12 +338,16 @@ class JsonStructureMessage(Struct, frozen=True, omit_defaults=True):
|
|
|
338
338
|
return StructureMessage(header, structures)
|
|
339
339
|
|
|
340
340
|
@classmethod
|
|
341
|
-
def from_model(
|
|
341
|
+
def from_model(
|
|
342
|
+
cls,
|
|
343
|
+
message: StructureMessage,
|
|
344
|
+
msg_version: Literal["2.0.0", "2.1"] = "2.0.0",
|
|
345
|
+
) -> "JsonStructureMessage":
|
|
342
346
|
"""Creates an SDMX-JSON payload from a pysdmx StructureMessage."""
|
|
343
347
|
if not message.header:
|
|
344
348
|
raise errors.Invalid(
|
|
345
349
|
"Invalid input", "SDMX-JSON messages must have a header."
|
|
346
350
|
)
|
|
347
|
-
header = JsonHeader.from_model(message.header)
|
|
351
|
+
header = JsonHeader.from_model(message.header, msg_version=msg_version)
|
|
348
352
|
structs = JsonStructures.from_model(message)
|
|
349
353
|
return JsonStructureMessage(header, structs)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Reader interface for SDMX-JSON 2.0.0 and 2.1.0 Reference Metadata."""
|
|
2
2
|
|
|
3
3
|
import msgspec
|
|
4
4
|
|
|
@@ -11,7 +11,7 @@ from pysdmx.model.message import MetadataMessage
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def read(input_str: str, validate: bool = True) -> MetadataMessage:
|
|
14
|
-
"""Read
|
|
14
|
+
"""Read SDMX-JSON 2.0.0 and 2.1.0 Metadata messages.
|
|
15
15
|
|
|
16
16
|
Args:
|
|
17
17
|
input_str: SDMX-JSON reference metadata message to read.
|
|
@@ -34,6 +34,6 @@ def read(input_str: str, validate: bool = True) -> MetadataMessage:
|
|
|
34
34
|
"Invalid message",
|
|
35
35
|
(
|
|
36
36
|
"The supplied file could not be read as SDMX-JSON 2.0.0 "
|
|
37
|
-
"reference metadata message."
|
|
37
|
+
"or 2.1.0 reference metadata message."
|
|
38
38
|
),
|
|
39
39
|
) from de
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Reader interface for SDMX-JSON 2.0.0 Structure messages."""
|
|
1
|
+
"""Reader interface for SDMX-JSON 2.0.0 and 2.1.0 Structure messages."""
|
|
2
2
|
|
|
3
3
|
import msgspec
|
|
4
4
|
|
|
@@ -11,7 +11,7 @@ from pysdmx.model.message import StructureMessage
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def read(input_str: str, validate: bool = True) -> StructureMessage:
|
|
14
|
-
"""Read
|
|
14
|
+
"""Read SDMX-JSON 2.0.0 and 2.1.0 Structure messages.
|
|
15
15
|
|
|
16
16
|
Args:
|
|
17
17
|
input_str: SDMX-JSON structure message to read.
|
|
@@ -34,6 +34,6 @@ def read(input_str: str, validate: bool = True) -> StructureMessage:
|
|
|
34
34
|
"Invalid message",
|
|
35
35
|
(
|
|
36
36
|
"The supplied file could not be read as SDMX-JSON 2.0.0 "
|
|
37
|
-
"structure message."
|
|
37
|
+
"or 2.1.0 structure message."
|
|
38
38
|
),
|
|
39
39
|
) from de
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Writer interface for SDMX-JSON 2.0.0 Reference Metadata messages."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Literal, Optional, Sequence, Union
|
|
5
|
+
|
|
6
|
+
import msgspec
|
|
7
|
+
|
|
8
|
+
from pysdmx.io.json.sdmxjson2.messages import (
|
|
9
|
+
JsonMetadataMessage,
|
|
10
|
+
JsonStructureMessage,
|
|
11
|
+
)
|
|
12
|
+
from pysdmx.model import MetadataReport, encoders
|
|
13
|
+
from pysdmx.model.__base import MaintainableArtefact
|
|
14
|
+
from pysdmx.model.message import Header, MetadataMessage, StructureMessage
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def write_metadata_msg(
|
|
18
|
+
reports: Sequence[MetadataReport],
|
|
19
|
+
output_path: Optional[Union[str, Path]] = None,
|
|
20
|
+
prettyprint: bool = True,
|
|
21
|
+
header: Optional[Header] = None,
|
|
22
|
+
msg_version: Literal["2.0.0", "2.1"] = "2.0.0",
|
|
23
|
+
) -> Optional[str]:
|
|
24
|
+
"""Write metadata reports in requested SDMX-JSON version.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
reports: The reference metadata reports to be serialized.
|
|
28
|
+
output_path: The path to save the JSON file. If None or empty, the
|
|
29
|
+
serialized content is returned as a string instead.
|
|
30
|
+
prettyprint: Whether to format the JSON output with indentation (True)
|
|
31
|
+
or output compact JSON without extra whitespace (False).
|
|
32
|
+
header: The header to be used in the SDMX-JSON message
|
|
33
|
+
(will be generated if no header is supplied).
|
|
34
|
+
msg_version: The desired version of SDMX-JSON. Defaults to 2.0.0.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
The JSON string if output_path is None or empty, None otherwise.
|
|
38
|
+
"""
|
|
39
|
+
if not header:
|
|
40
|
+
header = Header()
|
|
41
|
+
sm = MetadataMessage(header, reports)
|
|
42
|
+
jsm = JsonMetadataMessage.from_model(sm, msg_version)
|
|
43
|
+
|
|
44
|
+
encoder = msgspec.json.Encoder(enc_hook=encoders)
|
|
45
|
+
serialized_data = encoder.encode(jsm)
|
|
46
|
+
|
|
47
|
+
# Apply pretty-printing if requested
|
|
48
|
+
if prettyprint:
|
|
49
|
+
serialized_data = msgspec.json.format(serialized_data, indent=4)
|
|
50
|
+
|
|
51
|
+
# If output_path is provided, write to file
|
|
52
|
+
if output_path:
|
|
53
|
+
# Convert to Path object if string
|
|
54
|
+
if isinstance(output_path, str):
|
|
55
|
+
output_path = Path(output_path)
|
|
56
|
+
|
|
57
|
+
# Create parent directories if they don't exist
|
|
58
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
59
|
+
|
|
60
|
+
# Write to file
|
|
61
|
+
with open(output_path, "wb") as f:
|
|
62
|
+
f.write(serialized_data)
|
|
63
|
+
return None
|
|
64
|
+
else:
|
|
65
|
+
# Return as string
|
|
66
|
+
return serialized_data.decode("utf-8")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def write_structure_msg(
|
|
70
|
+
structures: Sequence[MaintainableArtefact],
|
|
71
|
+
output_path: Optional[Union[str, Path]] = None,
|
|
72
|
+
prettyprint: bool = True,
|
|
73
|
+
header: Optional[Header] = None,
|
|
74
|
+
msg_version: Literal["2.0.0", "2.1"] = "2.0.0",
|
|
75
|
+
) -> Optional[str]:
|
|
76
|
+
"""Write maintainable SDMX artefacts in SDMX-JSON 2.0.0.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
structures: The maintainable SDMX artefacts to be serialized.
|
|
80
|
+
output_path: The path to save the JSON file. If None or empty, the
|
|
81
|
+
serialized content is returned as a string instead.
|
|
82
|
+
prettyprint: Whether to format the JSON output with indentation (True)
|
|
83
|
+
or output compact JSON without extra whitespace (False).
|
|
84
|
+
header: The header to be used in the SDMX-JSON message
|
|
85
|
+
(will be generated if no header is supplied).
|
|
86
|
+
msg_version: The desired version of SDMX-JSON. Defaults to 2.0.0.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
The JSON string if output_path is None or empty, None otherwise.
|
|
90
|
+
"""
|
|
91
|
+
if not header:
|
|
92
|
+
header = Header()
|
|
93
|
+
sm = StructureMessage(header, structures)
|
|
94
|
+
jsm = JsonStructureMessage.from_model(sm, msg_version)
|
|
95
|
+
|
|
96
|
+
encoder = msgspec.json.Encoder(enc_hook=encoders)
|
|
97
|
+
serialized_data = encoder.encode(jsm)
|
|
98
|
+
|
|
99
|
+
# Apply pretty-printing if requested
|
|
100
|
+
if prettyprint:
|
|
101
|
+
serialized_data = msgspec.json.format(serialized_data, indent=4)
|
|
102
|
+
|
|
103
|
+
# If output_path is provided, write to file
|
|
104
|
+
if output_path:
|
|
105
|
+
# Convert to Path object if string
|
|
106
|
+
if isinstance(output_path, str):
|
|
107
|
+
output_path = Path(output_path)
|
|
108
|
+
|
|
109
|
+
# Create parent directories if they don't exist
|
|
110
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
111
|
+
|
|
112
|
+
# Write to file
|
|
113
|
+
with open(output_path, "wb") as f:
|
|
114
|
+
f.write(serialized_data)
|
|
115
|
+
return None
|
|
116
|
+
else:
|
|
117
|
+
# Return as string
|
|
118
|
+
return serialized_data.decode("utf-8")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Collection of writers for SDMX-JSON 2.0.0 messages."""
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Writer interface for SDMX-JSON 2.0.0 Reference Metadata messages."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional, Sequence, Union
|
|
5
|
+
|
|
6
|
+
from pysdmx.io.json.sdmxjson2.writer._helper import write_metadata_msg
|
|
7
|
+
from pysdmx.model import MetadataReport
|
|
8
|
+
from pysdmx.model.message import Header
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def write(
|
|
12
|
+
reports: Sequence[MetadataReport],
|
|
13
|
+
output_path: Optional[Union[str, Path]] = None,
|
|
14
|
+
prettyprint: bool = True,
|
|
15
|
+
header: Optional[Header] = None,
|
|
16
|
+
) -> Optional[str]:
|
|
17
|
+
"""Write metadata reports in SDMX-JSON 2.0.0.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
reports: The reference metadata reports to be serialized.
|
|
21
|
+
output_path: The path to save the JSON file. If None or empty, the
|
|
22
|
+
serialized content is returned as a string instead.
|
|
23
|
+
prettyprint: Whether to format the JSON output with indentation (True)
|
|
24
|
+
or output compact JSON without extra whitespace (False).
|
|
25
|
+
header: The header to be used in the SDMX-JSON message
|
|
26
|
+
(will be generated if no header is supplied).
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
The JSON string if output_path is None or empty, None otherwise.
|
|
30
|
+
"""
|
|
31
|
+
return write_metadata_msg(
|
|
32
|
+
reports, output_path, prettyprint, header, "2.0.0"
|
|
33
|
+
)
|