pysdmx 1.6.0__tar.gz → 1.7.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.6.0 → pysdmx-1.7.0}/PKG-INFO +2 -2
- {pysdmx-1.6.0 → pysdmx-1.7.0}/pyproject.toml +22 -8
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/__init__.py +1 -1
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/input_processor.py +4 -4
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/messages/concept.py +2 -8
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/code.py +35 -13
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/concept.py +5 -8
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/__ss_aux_reader.py +1 -2
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/__structure_aux_reader.py +15 -10
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/__structure_aux_writer.py +15 -13
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/__write_data_aux.py +5 -3
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/__write_structure_specific_aux.py +6 -2
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/doc_validation.py +1 -3
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx21/writer/generic.py +5 -3
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/model/__init__.py +1 -3
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/model/map.py +7 -9
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/model/message.py +1 -4
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/toolkit/pd/_data_utils.py +3 -4
- {pysdmx-1.6.0 → pysdmx-1.7.0}/LICENSE +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/README.rst +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/__extras_check.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/dc/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/dc/_api.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/dc/query/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/dc/query/_model.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/dc/query/_parsing_model.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/dc/query/_parsing_util.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/dc/query/_py_parser.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/dc/query/_sql_parser.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/dc/query/util.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/fmr/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/fmr/maintenance.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/gds/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/qb/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/qb/availability.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/qb/data.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/qb/gds.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/qb/refmeta.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/qb/registration.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/qb/schema.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/qb/service.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/qb/structure.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/api/qb/util.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/errors.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/csv/__csv_aux_reader.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/csv/__csv_aux_writer.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/csv/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/csv/sdmx10/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/csv/sdmx10/reader/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/csv/sdmx10/writer/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/csv/sdmx20/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/csv/sdmx20/reader/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/csv/sdmx20/writer/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/csv/sdmx21/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/csv/sdmx21/reader/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/csv/sdmx21/writer/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/format.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/messages/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/messages/category.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/messages/code.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/messages/constraint.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/messages/core.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/messages/dataflow.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/messages/dsd.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/messages/map.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/messages/org.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/messages/pa.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/messages/report.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/messages/schema.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/messages/vtl.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/fusion/reader/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/gds/messages/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/gds/messages/agencies.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/gds/messages/catalog.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/gds/messages/sdmx_api.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/gds/messages/services.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/gds/messages/urn_resolver.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/gds/reader/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/agency.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/category.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/constraint.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/core.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/dataflow.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/dsd.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/map.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/pa.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/provider.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/report.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/schema.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/structure.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/messages/vtl.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/reader/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/reader/metadata.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/reader/structure.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/writer/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/writer/metadata.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/json/sdmxjson2/writer/structure.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/pd.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/reader.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/serde.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/writer.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/__allowed_lxml_errors.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/__data_aux.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/__parse_xml.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/__tokens.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/__write_aux.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/config.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/header.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx21/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx21/reader/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx21/reader/error.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx21/reader/generic.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx21/reader/structure.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx21/reader/structure_specific.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx21/reader/submission.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx21/writer/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx21/writer/error.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx21/writer/structure.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx21/writer/structure_specific.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx30/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx30/reader/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx30/reader/structure.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx30/reader/structure_specific.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx30/writer/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx30/writer/structure.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx30/writer/structure_specific.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx31/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx31/reader/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx31/reader/structure.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx31/reader/structure_specific.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx31/writer/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx31/writer/structure.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/sdmx31/writer/structure_specific.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/io/xml/utils.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/model/__base.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/model/category.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/model/code.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/model/concept.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/model/dataflow.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/model/dataset.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/model/gds.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/model/metadata.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/model/organisation.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/model/submission.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/model/vtl.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/py.typed +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/toolkit/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/toolkit/pd/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/toolkit/vtl/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/toolkit/vtl/_validations.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/toolkit/vtl/script_generation.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/toolkit/vtl/validation.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/util/__init__.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/util/_date_pattern_map.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.0}/src/pysdmx/util/_model_utils.py +0 -0
- {pysdmx-1.6.0 → pysdmx-1.7.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.7.0
|
|
4
4
|
Summary: Your opinionated Python SDMX library
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -18,7 +18,7 @@ Provides-Extra: data
|
|
|
18
18
|
Provides-Extra: dc
|
|
19
19
|
Provides-Extra: vtl
|
|
20
20
|
Provides-Extra: xml
|
|
21
|
-
Requires-Dist: httpx (>=0)
|
|
21
|
+
Requires-Dist: httpx[http2] (>=0)
|
|
22
22
|
Requires-Dist: lxml (>=5.2) ; extra == "all"
|
|
23
23
|
Requires-Dist: lxml (>=5.2) ; extra == "xml"
|
|
24
24
|
Requires-Dist: msgspec (>=0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pysdmx"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.7.0"
|
|
4
4
|
description = "Your opinionated Python SDMX library"
|
|
5
5
|
license = { text = "Apache-2.0" }
|
|
6
6
|
readme = "README.rst"
|
|
@@ -21,7 +21,7 @@ classifiers = [
|
|
|
21
21
|
"Typing :: Typed"
|
|
22
22
|
]
|
|
23
23
|
dependencies = [
|
|
24
|
-
"httpx>=0.*",
|
|
24
|
+
"httpx[http2]>=0.*",
|
|
25
25
|
"msgspec>=0.*",
|
|
26
26
|
"parsy>=2.1",
|
|
27
27
|
]
|
|
@@ -46,7 +46,7 @@ requires-poetry = ">=2.0"
|
|
|
46
46
|
python = ">=3.9,<4.0"
|
|
47
47
|
|
|
48
48
|
[tool.poetry.group.dev.dependencies]
|
|
49
|
-
ruff = "
|
|
49
|
+
ruff = ">=0.13.2"
|
|
50
50
|
mypy = "^1.1.1"
|
|
51
51
|
pytest = "^8.3.2"
|
|
52
52
|
pytest-asyncio = "^0.21.1"
|
|
@@ -70,16 +70,30 @@ build-backend = "poetry.core.masonry.api"
|
|
|
70
70
|
[tool.ruff]
|
|
71
71
|
line-length = 79
|
|
72
72
|
lint.select = [
|
|
73
|
-
"ASYNC",
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
"
|
|
73
|
+
"ASYNC", # flake8-async: checks for async/await best practices
|
|
74
|
+
"B", # flake8-bugbear: detect bugs and design problems
|
|
75
|
+
"C4", # flake8-comprehensions: better list/dict/set comprehensions
|
|
76
|
+
"C90", # mccabe: code complexity checker
|
|
77
|
+
"D", # pydocstyle: enforce docstring conventions
|
|
78
|
+
"DTZ", # flake8-datetimez: datetime best practices and timezone issues
|
|
79
|
+
"E", # pycodestyle errors
|
|
80
|
+
"ERA", # eradicate: Find commented-out code that should be removed
|
|
81
|
+
"F", # pyflakes: detect various errors
|
|
82
|
+
"FURB", # refurb: functional Python improvements and refactoring
|
|
83
|
+
"I", # isort: import sorting
|
|
84
|
+
"LOG", # flake8-logging: logging best practices
|
|
85
|
+
"PERF", # perflint: performance optimizations
|
|
86
|
+
"PT", # flake8-pytest-style: pytest best practices
|
|
87
|
+
"S", # flake8-bandit: security issues
|
|
88
|
+
"SIM", # flake8-simplify: code simplification suggestions
|
|
89
|
+
"W" # pycodestyle warnings
|
|
77
90
|
]
|
|
91
|
+
lint.ignore = ["D411", "E203", "F901"]
|
|
78
92
|
lint.mccabe.max-complexity = 10
|
|
79
93
|
lint.pydocstyle.convention = "google"
|
|
80
94
|
|
|
81
95
|
[tool.ruff.lint.per-file-ignores]
|
|
82
|
-
"tests/*" = ["
|
|
96
|
+
"tests/*" = ["DTZ", "D100", "D103", "D104", "PERF", "S101", "S311"]
|
|
83
97
|
|
|
84
98
|
[tool.mypy]
|
|
85
99
|
files = "src"
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
import csv
|
|
4
4
|
import os.path
|
|
5
5
|
from io import BytesIO, StringIO, TextIOWrapper
|
|
6
|
-
from json import JSONDecodeError, loads
|
|
7
6
|
from os import PathLike
|
|
8
7
|
from pathlib import Path
|
|
9
8
|
from typing import Optional, Tuple, Union
|
|
10
9
|
|
|
10
|
+
import msgspec
|
|
11
11
|
from httpx import Client as httpx_Client
|
|
12
12
|
from httpx import HTTPStatusError, create_ssl_context
|
|
13
13
|
|
|
@@ -29,7 +29,7 @@ def __check_xml(input_str: str) -> bool:
|
|
|
29
29
|
|
|
30
30
|
def __check_csv(input_str: str) -> bool:
|
|
31
31
|
try:
|
|
32
|
-
max_length =
|
|
32
|
+
max_length = min(2048, len(input_str))
|
|
33
33
|
dialect = csv.Sniffer().sniff(input_str[:max_length])
|
|
34
34
|
control_csv_format = (
|
|
35
35
|
dialect.delimiter == "," and dialect.quotechar == '"'
|
|
@@ -47,9 +47,9 @@ def __check_csv(input_str: str) -> bool:
|
|
|
47
47
|
|
|
48
48
|
def __check_json(input_str: str) -> bool:
|
|
49
49
|
try:
|
|
50
|
-
|
|
50
|
+
msgspec.json.decode(input_str)
|
|
51
51
|
return True
|
|
52
|
-
except
|
|
52
|
+
except msgspec.DecodeError:
|
|
53
53
|
return False
|
|
54
54
|
|
|
55
55
|
|
|
@@ -17,6 +17,7 @@ class FusionConcept(msgspec.Struct, frozen=True):
|
|
|
17
17
|
"""Fusion-JSON payload for concepts."""
|
|
18
18
|
|
|
19
19
|
id: str
|
|
20
|
+
urn: str
|
|
20
21
|
names: Sequence[FusionString]
|
|
21
22
|
representation: Optional[FusionRepresentation] = None
|
|
22
23
|
descriptions: Optional[Sequence[FusionString]] = None
|
|
@@ -48,6 +49,7 @@ class FusionConcept(msgspec.Struct, frozen=True):
|
|
|
48
49
|
description=d,
|
|
49
50
|
codes=c,
|
|
50
51
|
enum_ref=cl_ref,
|
|
52
|
+
urn=self.urn,
|
|
51
53
|
)
|
|
52
54
|
|
|
53
55
|
|
|
@@ -63,18 +65,10 @@ class FusionConceptScheme(
|
|
|
63
65
|
version: str = "1.0"
|
|
64
66
|
items: Sequence[FusionConcept] = ()
|
|
65
67
|
|
|
66
|
-
def __set_urn(self, concept: Concept) -> Concept:
|
|
67
|
-
urn = (
|
|
68
|
-
"urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept="
|
|
69
|
-
f"{self.agency}:{self.id}({self.version}).{concept.id}"
|
|
70
|
-
)
|
|
71
|
-
return msgspec.structs.replace(concept, urn=urn)
|
|
72
|
-
|
|
73
68
|
def to_model(self, codelists: Sequence[FusionCodelist]) -> CS:
|
|
74
69
|
"""Converts a FusionConceptScheme to a standard concept scheme."""
|
|
75
70
|
d = self.descriptions[0].value if self.descriptions else None
|
|
76
71
|
concepts = [c.to_model(codelists) for c in self.items]
|
|
77
|
-
concepts = [self.__set_urn(c) for c in concepts]
|
|
78
72
|
return CS(
|
|
79
73
|
id=self.id,
|
|
80
74
|
name=self.names[0].value,
|
|
@@ -34,7 +34,7 @@ class JsonCode(NameableType, frozen=True, omit_defaults=True):
|
|
|
34
34
|
parent: Optional[str] = None
|
|
35
35
|
|
|
36
36
|
def __handle_date(self, datestr: str) -> datetime:
|
|
37
|
-
return datetime.strptime(datestr, _VAL_FMT)
|
|
37
|
+
return datetime.strptime(datestr, _VAL_FMT) # noqa
|
|
38
38
|
|
|
39
39
|
def __get_val(
|
|
40
40
|
self, a: JsonAnnotation
|
|
@@ -49,26 +49,38 @@ class JsonCode(NameableType, frozen=True, omit_defaults=True):
|
|
|
49
49
|
|
|
50
50
|
def to_model(self) -> Code:
|
|
51
51
|
"""Converts a JsonCode to a standard code."""
|
|
52
|
+
# Pre-filter annotations once outside the tuple creation
|
|
53
|
+
vf, vt = None, None
|
|
54
|
+
|
|
52
55
|
if self.annotations:
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
# Get validity period info
|
|
57
|
+
vp = next(
|
|
58
|
+
(
|
|
59
|
+
a
|
|
60
|
+
for a in self.annotations
|
|
61
|
+
if a.type == "FR_VALIDITY_PERIOD"
|
|
62
|
+
),
|
|
63
|
+
None,
|
|
64
|
+
)
|
|
65
|
+
if vp:
|
|
66
|
+
vf, vt = self.__get_val(vp)
|
|
67
|
+
|
|
68
|
+
# Pre-filter non-validity period annotations
|
|
69
|
+
filtered_annotations = [
|
|
70
|
+
a.to_model()
|
|
71
|
+
for a in self.annotations
|
|
72
|
+
if a.type != "FR_VALIDITY_PERIOD"
|
|
55
73
|
]
|
|
56
74
|
else:
|
|
57
|
-
|
|
58
|
-
|
|
75
|
+
filtered_annotations = []
|
|
76
|
+
|
|
59
77
|
return Code(
|
|
60
78
|
id=self.id,
|
|
61
79
|
name=self.name,
|
|
62
80
|
description=self.description,
|
|
63
81
|
valid_from=vf,
|
|
64
82
|
valid_to=vt,
|
|
65
|
-
annotations=tuple(
|
|
66
|
-
[
|
|
67
|
-
a.to_model()
|
|
68
|
-
for a in self.annotations
|
|
69
|
-
if a.type != "FR_VALIDITY_PERIOD"
|
|
70
|
-
]
|
|
71
|
-
),
|
|
83
|
+
annotations=tuple(filtered_annotations),
|
|
72
84
|
)
|
|
73
85
|
|
|
74
86
|
@classmethod
|
|
@@ -113,13 +125,23 @@ class JsonCodelist(ItemSchemeType, frozen=True, omit_defaults=True):
|
|
|
113
125
|
|
|
114
126
|
def to_model(self) -> Codelist:
|
|
115
127
|
"""Converts a JsonCodelist to a standard codelist."""
|
|
128
|
+
# Process codes in batches to reduce memory pressure
|
|
129
|
+
batch_size = 10000
|
|
130
|
+
all_codes = []
|
|
131
|
+
|
|
132
|
+
# Process in batches
|
|
133
|
+
for i in range(0, len(self.codes), batch_size):
|
|
134
|
+
batch = self.codes[i : i + batch_size]
|
|
135
|
+
batch_models = [code.to_model() for code in batch]
|
|
136
|
+
all_codes.extend(batch_models)
|
|
137
|
+
|
|
116
138
|
return Codelist(
|
|
117
139
|
id=self.id,
|
|
118
140
|
name=self.name,
|
|
119
141
|
agency=self.agency,
|
|
120
142
|
description=self.description,
|
|
121
143
|
version=self.version,
|
|
122
|
-
items=tuple(
|
|
144
|
+
items=tuple(all_codes),
|
|
123
145
|
annotations=tuple([a.to_model() for a in self.annotations]),
|
|
124
146
|
is_external_reference=self.isExternalReference,
|
|
125
147
|
is_partial=self.isPartial,
|
|
@@ -9,6 +9,7 @@ from pysdmx.io.json.sdmxjson2.messages.code import JsonCodelist
|
|
|
9
9
|
from pysdmx.io.json.sdmxjson2.messages.core import (
|
|
10
10
|
ItemSchemeType,
|
|
11
11
|
JsonAnnotation,
|
|
12
|
+
JsonLink,
|
|
12
13
|
JsonRepresentation,
|
|
13
14
|
NameableType,
|
|
14
15
|
)
|
|
@@ -29,6 +30,7 @@ class JsonConcept(NameableType, frozen=True, omit_defaults=True):
|
|
|
29
30
|
coreRepresentation: Optional[JsonRepresentation] = None
|
|
30
31
|
parent: Optional[str] = None
|
|
31
32
|
isoConceptReference: Optional[IsoConceptReference] = None
|
|
33
|
+
links: Sequence[JsonLink] = ()
|
|
32
34
|
|
|
33
35
|
def to_model(self, codelists: Sequence[Codelist]) -> Concept:
|
|
34
36
|
"""Converts a JsonConcept to a standard concept."""
|
|
@@ -48,6 +50,8 @@ class JsonConcept(NameableType, frozen=True, omit_defaults=True):
|
|
|
48
50
|
facets = None
|
|
49
51
|
codes = None
|
|
50
52
|
cl_ref = None
|
|
53
|
+
urn_lnk = [lnk for lnk in self.links if lnk.rel == "self"]
|
|
54
|
+
c_urn = urn_lnk[0].urn if len(urn_lnk) > 0 else None
|
|
51
55
|
return Concept(
|
|
52
56
|
id=self.id,
|
|
53
57
|
dtype=dt,
|
|
@@ -56,6 +60,7 @@ class JsonConcept(NameableType, frozen=True, omit_defaults=True):
|
|
|
56
60
|
description=self.description,
|
|
57
61
|
codes=codes,
|
|
58
62
|
enum_ref=cl_ref,
|
|
63
|
+
urn=c_urn,
|
|
59
64
|
)
|
|
60
65
|
|
|
61
66
|
@classmethod
|
|
@@ -95,18 +100,10 @@ class JsonConceptScheme(ItemSchemeType, frozen=True, omit_defaults=True):
|
|
|
95
100
|
|
|
96
101
|
concepts: Sequence[JsonConcept] = ()
|
|
97
102
|
|
|
98
|
-
def __set_urn(self, concept: Concept) -> Concept:
|
|
99
|
-
urn = (
|
|
100
|
-
"urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept="
|
|
101
|
-
f"{self.agency}:{self.id}({self.version}).{concept.id}"
|
|
102
|
-
)
|
|
103
|
-
return msgspec.structs.replace(concept, urn=urn)
|
|
104
|
-
|
|
105
103
|
def to_model(self, codelists: Sequence[JsonCodelist]) -> ConceptScheme:
|
|
106
104
|
"""Converts a JsonConceptScheme to a standard concept scheme."""
|
|
107
105
|
cls = [cl.to_model() for cl in codelists]
|
|
108
106
|
concepts = [c.to_model(cls) for c in self.concepts]
|
|
109
|
-
concepts = [self.__set_urn(c) for c in concepts]
|
|
110
107
|
return ConceptScheme(
|
|
111
108
|
id=self.id,
|
|
112
109
|
name=self.name,
|
|
@@ -30,8 +30,7 @@ def _reading_str_series(dataset: Dict[str, Any]) -> pd.DataFrame:
|
|
|
30
30
|
if OBS in data:
|
|
31
31
|
del keys[OBS]
|
|
32
32
|
data[OBS] = add_list(data[OBS])
|
|
33
|
-
for j in data[OBS]
|
|
34
|
-
test_list.append({**keys, **j})
|
|
33
|
+
test_list.extend([{**keys, **j} for j in data[OBS]])
|
|
35
34
|
else:
|
|
36
35
|
test_list.append(keys)
|
|
37
36
|
test_list, df = __process_df(test_list, df)
|
|
@@ -397,7 +397,7 @@ class StructureParser(Struct):
|
|
|
397
397
|
"""
|
|
398
398
|
if json_fac is None:
|
|
399
399
|
return
|
|
400
|
-
for key
|
|
400
|
+
for key in json_fac:
|
|
401
401
|
if key == TEXT_TYPE and json_fac[TEXT_TYPE] in list(DataType):
|
|
402
402
|
json_obj["dtype"] = DataType(json_fac[TEXT_TYPE])
|
|
403
403
|
|
|
@@ -907,9 +907,9 @@ class StructureParser(Struct):
|
|
|
907
907
|
item_json_info = self.__format_name_description(item_json_info)
|
|
908
908
|
if CONTACT in item_json_info and item_name_class == AGENCY:
|
|
909
909
|
item_json_info[CONTACT] = add_list(item_json_info[CONTACT])
|
|
910
|
-
contacts = [
|
|
911
|
-
|
|
912
|
-
|
|
910
|
+
contacts = [
|
|
911
|
+
self.__format_contact(e) for e in item_json_info[CONTACT]
|
|
912
|
+
]
|
|
913
913
|
item_json_info[CONTACT.lower() + "s"] = contacts
|
|
914
914
|
del item_json_info[CONTACT]
|
|
915
915
|
|
|
@@ -949,9 +949,11 @@ class StructureParser(Struct):
|
|
|
949
949
|
group_dimensions = [group_dimensions]
|
|
950
950
|
|
|
951
951
|
group["dimensions"] = [
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
952
|
+
(
|
|
953
|
+
d[DIM_REF]
|
|
954
|
+
if isinstance(d[DIM_REF], str)
|
|
955
|
+
else d[DIM_REF][REF][ID]
|
|
956
|
+
)
|
|
955
957
|
for d in group_dimensions
|
|
956
958
|
]
|
|
957
959
|
|
|
@@ -994,9 +996,12 @@ class StructureParser(Struct):
|
|
|
994
996
|
items = []
|
|
995
997
|
if item in element:
|
|
996
998
|
element[item] = add_list(element[item])
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
999
|
+
items.extend(
|
|
1000
|
+
[
|
|
1001
|
+
self.__format_item(item_elem, item)
|
|
1002
|
+
for item_elem in element[item]
|
|
1003
|
+
]
|
|
1004
|
+
)
|
|
1000
1005
|
del element[item]
|
|
1001
1006
|
element["items"] = items
|
|
1002
1007
|
element = self.__format_agency(element)
|
|
@@ -310,9 +310,9 @@ def __write_maintainable(
|
|
|
310
310
|
f"{str(maintainable.is_external_reference).lower()!r}"
|
|
311
311
|
)
|
|
312
312
|
if not references_30 and not (isinstance(maintainable, AgencyScheme)):
|
|
313
|
-
outfile[
|
|
314
|
-
|
|
315
|
-
)
|
|
313
|
+
outfile[
|
|
314
|
+
"Attributes"
|
|
315
|
+
] += f" isFinal={str(maintainable.is_final).lower()!r}"
|
|
316
316
|
|
|
317
317
|
if isinstance(maintainable.agency, str):
|
|
318
318
|
outfile["Attributes"] += f" agencyID={maintainable.agency!r}"
|
|
@@ -462,7 +462,7 @@ def __write_components( # noqa: C901
|
|
|
462
462
|
)
|
|
463
463
|
|
|
464
464
|
position = 1
|
|
465
|
-
for
|
|
465
|
+
for comps in components.values():
|
|
466
466
|
if comps:
|
|
467
467
|
role_name = ROLE_MAPPING[comps[0].role]
|
|
468
468
|
if role_name == MEASURE:
|
|
@@ -809,9 +809,9 @@ def __write_scheme( # noqa: C901
|
|
|
809
809
|
DSD,
|
|
810
810
|
DFW,
|
|
811
811
|
]:
|
|
812
|
-
data[
|
|
813
|
-
|
|
814
|
-
)
|
|
812
|
+
data[
|
|
813
|
+
"Attributes"
|
|
814
|
+
] += f" isPartial={str(item_scheme.is_partial).lower()!r}"
|
|
815
815
|
if scheme in [
|
|
816
816
|
RULE_SCHEME,
|
|
817
817
|
UDO_SCHEME,
|
|
@@ -820,9 +820,9 @@ def __write_scheme( # noqa: C901
|
|
|
820
820
|
CUSTOM_TYPE_SCHEME,
|
|
821
821
|
NAME_PER_SCHEME,
|
|
822
822
|
]:
|
|
823
|
-
data[
|
|
824
|
-
|
|
825
|
-
)
|
|
823
|
+
data[
|
|
824
|
+
"Attributes"
|
|
825
|
+
] += f" {_write_vtl(item_scheme, indent, references_30)}"
|
|
826
826
|
|
|
827
827
|
outfile = ""
|
|
828
828
|
|
|
@@ -1129,9 +1129,11 @@ def _write_vtl( # noqa: C901
|
|
|
1129
1129
|
ref_codelist = (
|
|
1130
1130
|
item_or_scheme.codelist
|
|
1131
1131
|
if isinstance(item_or_scheme.codelist, Reference)
|
|
1132
|
-
else
|
|
1133
|
-
|
|
1134
|
-
|
|
1132
|
+
else (
|
|
1133
|
+
parse_urn(item_or_scheme.codelist)
|
|
1134
|
+
if isinstance(item_or_scheme.codelist, str)
|
|
1135
|
+
else parse_short_urn(item_or_scheme.codelist.short_urn)
|
|
1136
|
+
)
|
|
1135
1137
|
)
|
|
1136
1138
|
if references_30:
|
|
1137
1139
|
data += (
|
|
@@ -54,13 +54,15 @@ def writing_validation(dataset: PandasDataset) -> None:
|
|
|
54
54
|
for comp in dataset.structure.components
|
|
55
55
|
if comp.role in (Role.DIMENSION, Role.MEASURE)
|
|
56
56
|
]
|
|
57
|
-
|
|
57
|
+
required_components.extend(
|
|
58
|
+
att.id
|
|
59
|
+
for att in dataset.structure.components.attributes
|
|
58
60
|
if (
|
|
59
61
|
att.required
|
|
60
62
|
and att.attachment_level is not None
|
|
61
63
|
and att.attachment_level != "D"
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
+
)
|
|
65
|
+
)
|
|
64
66
|
non_required = [
|
|
65
67
|
comp.id
|
|
66
68
|
for comp in dataset.structure.components
|
|
@@ -198,8 +198,12 @@ def __group_processing(
|
|
|
198
198
|
.to_dict(orient="records")
|
|
199
199
|
)
|
|
200
200
|
|
|
201
|
-
|
|
202
|
-
|
|
201
|
+
out_list.extend(
|
|
202
|
+
[
|
|
203
|
+
__format_group_str(record, group["group_id"])
|
|
204
|
+
for record in grouped_data
|
|
205
|
+
]
|
|
206
|
+
)
|
|
203
207
|
|
|
204
208
|
return "".join(out_list)
|
|
205
209
|
|
|
@@ -39,9 +39,7 @@ def validate_doc(input_str: str) -> None:
|
|
|
39
39
|
doc = etree.parse(bytes_infile, parser=parser)
|
|
40
40
|
if not xmlschema.validate(doc):
|
|
41
41
|
log_errors = list(xmlschema.error_log) # type: ignore[call-overload]
|
|
42
|
-
unhandled_errors = []
|
|
43
|
-
for e in log_errors:
|
|
44
|
-
unhandled_errors.append(e.message)
|
|
42
|
+
unhandled_errors = [e.message for e in log_errors]
|
|
45
43
|
severe_errors = unhandled_errors.copy()
|
|
46
44
|
for e in unhandled_errors:
|
|
47
45
|
for allowed_error in ALLOWED_ERRORS_CONTENT:
|
|
@@ -327,10 +327,12 @@ def __group_processing(
|
|
|
327
327
|
.to_dict(orient="records")
|
|
328
328
|
)
|
|
329
329
|
|
|
330
|
-
|
|
331
|
-
|
|
330
|
+
out_list.extend(
|
|
331
|
+
[
|
|
332
332
|
__format_group_str(record, group_id, dimensions, attribute)
|
|
333
|
-
|
|
333
|
+
for record in grouped_data
|
|
334
|
+
]
|
|
335
|
+
)
|
|
334
336
|
|
|
335
337
|
return "".join(out_list)
|
|
336
338
|
|
|
@@ -131,9 +131,7 @@ def decoders(type: Type, obj: Any) -> Any: # type: ignore[type-arg]
|
|
|
131
131
|
target types
|
|
132
132
|
"""
|
|
133
133
|
if type is Components:
|
|
134
|
-
comps = []
|
|
135
|
-
for item in obj:
|
|
136
|
-
comps.append(msgspec.convert(item, Component))
|
|
134
|
+
comps = [msgspec.convert(item, Component) for item in obj]
|
|
137
135
|
return Components(comps)
|
|
138
136
|
else:
|
|
139
137
|
raise NotImplementedError(f"Objects of type {type} are not supported")
|
|
@@ -486,9 +486,7 @@ class StructureMap(MaintainableArtefact, frozen=True, omit_defaults=True):
|
|
|
486
486
|
"""Return the number of mapping rules in the structure map."""
|
|
487
487
|
return len(self.maps)
|
|
488
488
|
|
|
489
|
-
def __getitem__(
|
|
490
|
-
self, id_: str
|
|
491
|
-
) -> Optional[
|
|
489
|
+
def __getitem__(self, id_: str) -> Optional[
|
|
492
490
|
Sequence[
|
|
493
491
|
Union[
|
|
494
492
|
ComponentMap,
|
|
@@ -500,12 +498,12 @@ class StructureMap(MaintainableArtefact, frozen=True, omit_defaults=True):
|
|
|
500
498
|
]
|
|
501
499
|
]:
|
|
502
500
|
"""Return the mapping rules for the supplied component."""
|
|
503
|
-
out = [
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
501
|
+
out = [
|
|
502
|
+
m
|
|
503
|
+
for m in self.maps
|
|
504
|
+
if (hasattr(m, "source") and (m.source == id_ or id_ in m.source))
|
|
505
|
+
or (isinstance(m, FixedValueMap) and m.target == id_)
|
|
506
|
+
]
|
|
509
507
|
if len(out) == 0:
|
|
510
508
|
return None
|
|
511
509
|
else:
|
|
@@ -168,10 +168,7 @@ class StructureMessage(Struct, repr_omit_defaults=True, frozen=True):
|
|
|
168
168
|
raise NotFound(
|
|
169
169
|
f"No {type_.__name__} found in message.",
|
|
170
170
|
)
|
|
171
|
-
structures = []
|
|
172
|
-
for element in self.structures:
|
|
173
|
-
if isinstance(element, type_):
|
|
174
|
-
structures.append(element)
|
|
171
|
+
structures = [e for e in self.structures if isinstance(e, type_)]
|
|
175
172
|
return structures
|
|
176
173
|
|
|
177
174
|
def __get_enumerations(
|
|
@@ -53,15 +53,14 @@ def get_codes(
|
|
|
53
53
|
dimension_code: str, structure: Schema, data: pd.DataFrame
|
|
54
54
|
) -> Tuple[List[str], List[str], List[Dict[str, Any]]]:
|
|
55
55
|
"""This function divides the components in Series and Obs."""
|
|
56
|
-
series_codes = []
|
|
57
56
|
groups = structure.groups
|
|
58
57
|
group_codes = []
|
|
59
58
|
obs_codes = [dimension_code, structure.components.measures[0].id]
|
|
60
59
|
|
|
61
60
|
# Getting the series and obs codes
|
|
62
|
-
|
|
63
|
-
if
|
|
64
|
-
|
|
61
|
+
series_codes = [
|
|
62
|
+
d.id for d in structure.components.dimensions if d.id != dimension_code
|
|
63
|
+
]
|
|
65
64
|
|
|
66
65
|
# Adding the attributes based on the attachment level
|
|
67
66
|
for att in structure.components.attributes:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|