pysdmx 1.10.0rc2__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.
Files changed (177) hide show
  1. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/PKG-INFO +7 -1
  2. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/pyproject.toml +13 -6
  3. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/__init__.py +1 -1
  4. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/fmr/__init__.py +3 -2
  5. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/fmr/maintenance.py +10 -5
  6. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/qb/data.py +2 -0
  7. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/csv/__csv_aux_writer.py +0 -23
  8. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx10/reader/__init__.py +1 -1
  9. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx10/writer/__init__.py +9 -15
  10. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx20/reader/__init__.py +1 -1
  11. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx20/writer/__init__.py +1 -1
  12. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx21/reader/__init__.py +1 -1
  13. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx21/writer/__init__.py +1 -1
  14. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/input_processor.py +4 -0
  15. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/dsd.py +27 -16
  16. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/msd.py +6 -9
  17. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/core.py +12 -5
  18. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/dsd.py +46 -31
  19. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/msd.py +2 -5
  20. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/report.py +7 -3
  21. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/structure.py +7 -3
  22. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/reader/doc_validation.py +4 -0
  23. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/reader/metadata.py +3 -3
  24. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/reader/structure.py +3 -3
  25. pysdmx-1.11.0/src/pysdmx/io/json/sdmxjson2/writer/_helper.py +118 -0
  26. pysdmx-1.11.0/src/pysdmx/io/json/sdmxjson2/writer/v2_0/__init__.py +1 -0
  27. pysdmx-1.11.0/src/pysdmx/io/json/sdmxjson2/writer/v2_0/metadata.py +33 -0
  28. pysdmx-1.11.0/src/pysdmx/io/json/sdmxjson2/writer/v2_0/structure.py +33 -0
  29. pysdmx-1.11.0/src/pysdmx/io/json/sdmxjson2/writer/v2_1/__init__.py +1 -0
  30. pysdmx-1.11.0/src/pysdmx/io/json/sdmxjson2/writer/v2_1/metadata.py +31 -0
  31. pysdmx-1.11.0/src/pysdmx/io/json/sdmxjson2/writer/v2_1/structure.py +33 -0
  32. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/reader.py +12 -3
  33. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/writer.py +13 -3
  34. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/__ss_aux_reader.py +39 -17
  35. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/__structure_aux_reader.py +221 -33
  36. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/__structure_aux_writer.py +304 -5
  37. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/__tokens.py +12 -0
  38. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/__write_aux.py +9 -0
  39. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/__write_data_aux.py +9 -20
  40. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/__write_structure_specific_aux.py +54 -71
  41. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/writer/generic.py +20 -32
  42. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/concept.py +0 -16
  43. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/dataflow.py +11 -8
  44. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/toolkit/pd/_data_utils.py +1 -1
  45. pysdmx-1.10.0rc2/src/pysdmx/io/_pd_utils.py +0 -83
  46. pysdmx-1.10.0rc2/src/pysdmx/io/json/sdmxjson2/writer/metadata.py +0 -60
  47. pysdmx-1.10.0rc2/src/pysdmx/io/json/sdmxjson2/writer/structure.py +0 -61
  48. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/LICENSE +0 -0
  49. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/README.rst +0 -0
  50. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/__extras_check.py +0 -0
  51. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/__init__.py +0 -0
  52. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/dc/__init__.py +0 -0
  53. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/dc/_api.py +0 -0
  54. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/dc/query/__init__.py +0 -0
  55. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/dc/query/_model.py +0 -0
  56. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/dc/query/_parsing_model.py +0 -0
  57. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/dc/query/_parsing_util.py +0 -0
  58. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/dc/query/_py_parser.py +0 -0
  59. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/dc/query/_sql_parser.py +0 -0
  60. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/dc/query/util.py +0 -0
  61. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/gds/__init__.py +0 -0
  62. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/qb/__init__.py +0 -0
  63. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/qb/availability.py +0 -0
  64. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/qb/gds.py +0 -0
  65. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/qb/refmeta.py +0 -0
  66. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/qb/registration.py +0 -0
  67. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/qb/schema.py +0 -0
  68. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/qb/service.py +0 -0
  69. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/qb/structure.py +0 -0
  70. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/api/qb/util.py +0 -0
  71. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/errors.py +0 -0
  72. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/__init__.py +0 -0
  73. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/csv/__csv_aux_reader.py +0 -0
  74. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/csv/__init__.py +0 -0
  75. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx10/__init__.py +0 -0
  76. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx20/__init__.py +0 -0
  77. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/csv/sdmx21/__init__.py +0 -0
  78. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/format.py +0 -0
  79. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/__init__.py +0 -0
  80. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/category.py +0 -0
  81. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/code.py +0 -0
  82. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/concept.py +0 -0
  83. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/constraint.py +0 -0
  84. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/core.py +0 -0
  85. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/dataflow.py +0 -0
  86. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/map.py +0 -0
  87. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/metadataflow.py +0 -0
  88. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/mpa.py +0 -0
  89. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/org.py +0 -0
  90. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/pa.py +0 -0
  91. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/report.py +0 -0
  92. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/schema.py +0 -0
  93. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/messages/vtl.py +0 -0
  94. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/fusion/reader/__init__.py +0 -0
  95. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/gds/messages/__init__.py +0 -0
  96. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/gds/messages/agencies.py +0 -0
  97. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/gds/messages/catalog.py +0 -0
  98. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/gds/messages/sdmx_api.py +0 -0
  99. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/gds/messages/services.py +0 -0
  100. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/gds/messages/urn_resolver.py +0 -0
  101. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/gds/reader/__init__.py +0 -0
  102. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/__init__.py +0 -0
  103. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/agency.py +0 -0
  104. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/category.py +0 -0
  105. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/code.py +0 -0
  106. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/concept.py +0 -0
  107. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/constraint.py +0 -0
  108. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/dataflow.py +0 -0
  109. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/map.py +0 -0
  110. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/metadataflow.py +0 -0
  111. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/mpa.py +0 -0
  112. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/pa.py +0 -0
  113. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/provider.py +0 -0
  114. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/schema.py +0 -0
  115. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/messages/vtl.py +0 -0
  116. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/reader/__init__.py +0 -0
  117. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/json/sdmxjson2/writer/__init__.py +0 -0
  118. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/pd.py +0 -0
  119. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/serde.py +0 -0
  120. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/__allowed_lxml_errors.py +0 -0
  121. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/__data_aux.py +0 -0
  122. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/__init__.py +0 -0
  123. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/__parse_xml.py +0 -0
  124. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/config.py +0 -0
  125. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/doc_validation.py +0 -0
  126. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/header.py +0 -0
  127. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/__init__.py +0 -0
  128. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/reader/__init__.py +0 -0
  129. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/reader/error.py +0 -0
  130. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/reader/generic.py +0 -0
  131. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/reader/structure.py +0 -0
  132. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/reader/structure_specific.py +0 -0
  133. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/reader/submission.py +0 -0
  134. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/writer/__init__.py +0 -0
  135. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/writer/error.py +0 -0
  136. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/writer/structure.py +0 -0
  137. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx21/writer/structure_specific.py +0 -0
  138. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx30/__init__.py +0 -0
  139. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx30/reader/__init__.py +0 -0
  140. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx30/reader/structure.py +0 -0
  141. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx30/reader/structure_specific.py +0 -0
  142. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx30/writer/__init__.py +0 -0
  143. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx30/writer/structure.py +0 -0
  144. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx30/writer/structure_specific.py +0 -0
  145. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx31/__init__.py +0 -0
  146. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx31/reader/__init__.py +0 -0
  147. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx31/reader/structure.py +0 -0
  148. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx31/reader/structure_specific.py +0 -0
  149. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx31/writer/__init__.py +0 -0
  150. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx31/writer/structure.py +0 -0
  151. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/sdmx31/writer/structure_specific.py +0 -0
  152. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/io/xml/utils.py +0 -0
  153. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/__base.py +0 -0
  154. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/__init__.py +0 -0
  155. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/category.py +0 -0
  156. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/code.py +0 -0
  157. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/constraint.py +0 -0
  158. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/dataset.py +0 -0
  159. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/gds.py +0 -0
  160. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/map.py +0 -0
  161. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/message.py +0 -0
  162. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/metadata.py +0 -0
  163. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/organisation.py +0 -0
  164. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/submission.py +0 -0
  165. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/model/vtl.py +0 -0
  166. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/py.typed +0 -0
  167. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/toolkit/__init__.py +0 -0
  168. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/toolkit/pd/__init__.py +0 -0
  169. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/toolkit/vtl/__init__.py +0 -0
  170. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/toolkit/vtl/_validations.py +0 -0
  171. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/toolkit/vtl/convert.py +0 -0
  172. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/toolkit/vtl/script_generation.py +0 -0
  173. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/toolkit/vtl/validation.py +0 -0
  174. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/util/__init__.py +0 -0
  175. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/util/_date_pattern_map.py +0 -0
  176. {pysdmx-1.10.0rc2 → pysdmx-1.11.0}/src/pysdmx/util/_model_utils.py +0 -0
  177. {pysdmx-1.10.0rc2 → 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.10.0rc2
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.10.0rc2"
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"
@@ -10,7 +10,9 @@ authors = [
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
12
  { name = "Mateo de Lorenzo Argelés", email = "<mateo.delorenzo@meaningfuldata.eu>" },
13
- { name = "Jose Antonio Franco Martin", email = "<jose.franco@meaningfuldata.eu>" }
13
+ { name = "Jose Antonio Franco Martin", email = "<jose.franco@meaningfuldata.eu>" },
14
+ { name = "Mario Cortés Ruiz", email = "<mario.cortes@meaningfuldata.eu>" }
15
+
14
16
  ]
15
17
  keywords = ["sdmx", "data discovery", "data retrieval", "metadata", "fmr"]
16
18
  classifiers = [
@@ -33,12 +35,13 @@ documentation = "https://bis-med-it.github.io/pysdmx"
33
35
  "Bug Tracker" = "https://bis-med-it.github.io/pysdmx/issues"
34
36
 
35
37
  [project.optional-dependencies]
36
- 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'"]
37
39
  dc = ["python-dateutil>=2.8.2"]
38
- 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'"]
39
41
  json = ["sdmxschemas>=1.0.0", "jsonschema>=4.10"]
40
42
  xml = ["lxml>=5.2", "xmltodict>=0.13", "sdmxschemas>=1.0.0"]
41
- 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'"]
42
45
 
43
46
  [tool.poetry]
44
47
  requires-poetry = ">=2.0"
@@ -47,6 +50,7 @@ requires-poetry = ">=2.0"
47
50
  python = ">=3.9,<4.0"
48
51
 
49
52
  [tool.poetry.group.dev.dependencies]
53
+ coverage = ">=7.0,!=7.13.0,<8.0"
50
54
  ruff = ">=0.13.2"
51
55
  mypy = "^1.18.2"
52
56
  pytest = "^8.3.2"
@@ -57,7 +61,10 @@ pyroma = "^4.2"
57
61
  lxml-stubs = "^0.5.1"
58
62
  types-xmltodict = "^0.13.0.3"
59
63
  types-python-dateutil = "^2.9.0.20240316"
60
- pandas-stubs = "^2.1.4.231227"
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
+ ]
61
68
  types-jsonschema = "^4.25.1.20251009"
62
69
 
63
70
  [tool.poetry.group.docs.dependencies]
@@ -1,3 +1,3 @@
1
1
  """Your opinionated Python SDMX library."""
2
2
 
3
- __version__ = "1.10.0rc2"
3
+ __version__ = "1.11.0"
@@ -39,6 +39,7 @@ from pysdmx.model import (
39
39
  Dataflow,
40
40
  DataflowInfo,
41
41
  DataProvider,
42
+ DataStructureDefinition,
42
43
  Hierarchy,
43
44
  HierarchyAssociation,
44
45
  Metadataflow,
@@ -679,7 +680,7 @@ class RegistryClient(__BaseRegistryClient):
679
680
  agency: str = "*",
680
681
  id: str = "*",
681
682
  version: str = "+",
682
- ) -> Sequence[Dataflow]:
683
+ ) -> Sequence[DataStructureDefinition]:
683
684
  """Get the data structures(s) matching the supplied parameters.
684
685
 
685
686
  Args:
@@ -1253,7 +1254,7 @@ class AsyncRegistryClient(__BaseRegistryClient):
1253
1254
  agency: str = "*",
1254
1255
  id: str = "*",
1255
1256
  version: str = "+",
1256
- ) -> Sequence[Dataflow]:
1257
+ ) -> Sequence[DataStructureDefinition]:
1257
1258
  """Get the data structures(s) matching the supplied parameters.
1258
1259
 
1259
1260
  Args:
@@ -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
- if api_endpoint.endswith("/"):
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
- url,
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
@@ -329,6 +329,8 @@ class DataQuery(_CoreDataQuery, frozen=True, omit_defaults=True):
329
329
 
330
330
  def __get_short_v2_qs(self, api_version: ApiVersion) -> str:
331
331
  qs = ""
332
+ if self.components:
333
+ qs += self._create_component_filters(self.components)
332
334
  if self.updated_after:
333
335
  qs = super()._append_qs_param(
334
336
  qs,
@@ -3,8 +3,6 @@ from typing import List, Literal, Optional, Sequence
3
3
 
4
4
  import pandas as pd
5
5
 
6
- from pysdmx.errors import Invalid
7
- from pysdmx.io._pd_utils import _fill_na_values
8
6
  from pysdmx.io.pd import PandasDataset
9
7
  from pysdmx.model import Schema
10
8
  from pysdmx.model.dataset import ActionType
@@ -18,25 +16,6 @@ SDMX_CSV_ACTION_MAPPER = {
18
16
  }
19
17
 
20
18
 
21
- def _validate_schema_exists(dataset: PandasDataset) -> Schema:
22
- """Validates that the dataset has a Schema defined.
23
-
24
- Args:
25
- dataset: The dataset to validate.
26
-
27
- Returns:
28
- The `Schema` from the dataset.
29
-
30
- Raises:
31
- Invalid: If the structure is not a `Schema`.
32
- """
33
- if not isinstance(dataset.structure, Schema):
34
- raise Invalid(
35
- "Dataset Structure is not a Schema. Cannot perform operation."
36
- )
37
- return dataset.structure
38
-
39
-
40
19
  def __write_time_period(df: pd.DataFrame, time_format: str) -> None:
41
20
  # TODO: Correct handle of normalized time format
42
21
  raise NotImplementedError("Normalized time format is not implemented yet.")
@@ -91,10 +70,8 @@ def _write_csv_2_aux(
91
70
  ) -> List[pd.DataFrame]:
92
71
  dataframes = []
93
72
  for dataset in datasets:
94
- schema = _validate_schema_exists(dataset)
95
73
  # Create a copy of the dataset
96
74
  df: pd.DataFrame = copy(dataset.data)
97
- df = _fill_na_values(df, schema)
98
75
  structure_ref, unique_id = dataset.short_urn.split("=", maxsplit=1)
99
76
 
100
77
  # Add additional attributes to the dataset
@@ -24,7 +24,7 @@ def read(input_str: str) -> Sequence[PandasDataset]:
24
24
  """
25
25
  # Get Dataframe from CSV file
26
26
  df_csv = pd.read_csv(
27
- StringIO(input_str), keep_default_na=False, na_values=[]
27
+ StringIO(input_str), keep_default_na=False, na_values=[""]
28
28
  )
29
29
  # Drop empty columns
30
30
  df_csv = df_csv.dropna(axis=1, how="all")
@@ -6,12 +6,9 @@ from typing import Literal, Optional, Sequence, Union
6
6
 
7
7
  import pandas as pd
8
8
 
9
- from pysdmx.io._pd_utils import _fill_na_values
10
- from pysdmx.io.csv.__csv_aux_writer import (
11
- __write_time_period,
12
- _validate_schema_exists,
13
- )
9
+ from pysdmx.io.csv.__csv_aux_writer import __write_time_period
14
10
  from pysdmx.io.pd import PandasDataset
11
+ from pysdmx.model import Schema
15
12
  from pysdmx.toolkit.pd._data_utils import format_labels
16
13
 
17
14
 
@@ -47,26 +44,22 @@ def write(
47
44
  # Create a copy of the dataset
48
45
  dataframes = []
49
46
  for dataset in datasets:
50
- # Validate that dataset has a proper Schema
51
- schema = _validate_schema_exists(dataset)
52
-
53
47
  df: pd.DataFrame = copy(dataset.data)
54
48
 
55
- # Fill missing values
56
- df = _fill_na_values(df, schema)
57
-
58
49
  # Add additional attributes to the dataset
59
50
  for k, v in dataset.attributes.items():
60
51
  df[k] = v
61
52
  structure_id = dataset.short_urn.split("=")[1]
62
53
  if time_format is not None and time_format != "original":
63
54
  __write_time_period(df, time_format)
64
- if labels is not None:
65
- format_labels(df, labels, schema.components)
55
+ if labels is not None and isinstance(dataset.structure, Schema):
56
+ format_labels(df, labels, dataset.structure.components)
66
57
  if labels == "id":
67
58
  df.insert(0, "DATAFLOW", structure_id)
68
59
  else:
69
- df.insert(0, "DATAFLOW", f"{structure_id}:{schema.name}")
60
+ df.insert(
61
+ 0, "DATAFLOW", f"{structure_id}:{dataset.structure.name}"
62
+ )
70
63
  else:
71
64
  df.insert(0, "DATAFLOW", structure_id)
72
65
 
@@ -75,7 +68,8 @@ def write(
75
68
  # Concatenate the dataframes
76
69
  all_data = pd.concat(dataframes, ignore_index=True, axis=0)
77
70
 
78
- all_data = all_data.astype(str)
71
+ # Ensure null values are represented as empty strings
72
+ all_data = all_data.astype(str).replace({"nan": "", "<NA>": ""})
79
73
  # If the output path is an empty string we use None
80
74
  output_path = (
81
75
  None
@@ -24,7 +24,7 @@ def read(input_str: str) -> Sequence[PandasDataset]:
24
24
  """
25
25
  # Get Dataframe from CSV file
26
26
  df_csv = pd.read_csv(
27
- StringIO(input_str), keep_default_na=False, na_values=[]
27
+ StringIO(input_str), keep_default_na=False, na_values=[""]
28
28
  )
29
29
  # Drop empty columns
30
30
  df_csv = df_csv.dropna(axis=1, how="all")
@@ -60,7 +60,7 @@ def write(
60
60
 
61
61
  all_data = pd.concat(dataframes, ignore_index=True, axis=0)
62
62
 
63
- all_data = all_data.astype(str)
63
+ all_data = all_data.astype(str).replace({"nan": "", "<NA>": ""})
64
64
 
65
65
  # If the output path is an empty string we use None
66
66
  output_path = (
@@ -24,7 +24,7 @@ def read(input_str: str) -> Sequence[PandasDataset]:
24
24
  """
25
25
  # Get Dataframe from CSV file
26
26
  df_csv = pd.read_csv(
27
- StringIO(input_str), keep_default_na=False, na_values=[]
27
+ StringIO(input_str), keep_default_na=False, na_values=[""]
28
28
  )
29
29
  # Drop empty columns
30
30
  df_csv = df_csv.dropna(axis=1, how="all")
@@ -57,7 +57,7 @@ def write(
57
57
 
58
58
  all_data = pd.concat(dataframes, ignore_index=True, axis=0)
59
59
 
60
- all_data = all_data.astype(str)
60
+ all_data = all_data.astype(str).replace({"nan": "", "<NA>": ""})
61
61
 
62
62
  # If the output path is an empty string we use None
63
63
  output_path = (
@@ -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
- return [c for c in f[0].items if c.id == r.item_id][0]
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(
@@ -80,8 +82,14 @@ class FusionAttribute(Struct, frozen=True):
80
82
  measureReferences: Optional[Sequence[str]] = None
81
83
 
82
84
  def __derive_level(self, groups: Sequence[FusionGroup]) -> str:
83
- if self.attachmentLevel == "OBSERVATION":
84
- return "O"
85
+ if self.measureReferences:
86
+ if (
87
+ len(self.measureReferences) == 1
88
+ and self.measureReferences[0] == "OBS_VALUE"
89
+ ):
90
+ return "O"
91
+ else:
92
+ return ",".join(self.measureReferences)
85
93
  elif self.attachmentLevel == "DATA_SET":
86
94
  return "D"
87
95
  elif self.attachmentLevel == "GROUP":
@@ -106,12 +114,13 @@ class FusionAttribute(Struct, frozen=True):
106
114
  groups: Sequence[FusionGroup],
107
115
  ) -> Component:
108
116
  """Returns an attribute."""
109
- c = _find_concept(cs, self.concept)
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)
110
119
  dt, facets, codes, ab = _get_representation(
111
120
  self.id, self.representation, cls, cons
112
121
  )
113
122
  lvl = self.__derive_level(groups)
114
- desc = c.descriptions[0].value if c.descriptions else None
123
+ desc = c.description if isinstance(c, Concept) else None
115
124
  if self.representation and self.representation.representation:
116
125
  local_enum_ref = self.representation.representation
117
126
  else:
@@ -120,10 +129,10 @@ class FusionAttribute(Struct, frozen=True):
120
129
  id=self.id,
121
130
  required=self.mandatory,
122
131
  role=Role.ATTRIBUTE,
123
- concept=c.to_model(cls),
132
+ concept=c,
124
133
  local_dtype=dt,
125
134
  local_facets=facets,
126
- name=c.names[0].value,
135
+ name=c.name if isinstance(c, Concept) else None,
127
136
  description=desc,
128
137
  local_codes=codes,
129
138
  attachment_level=lvl,
@@ -162,11 +171,12 @@ class FusionDimension(Struct, frozen=True):
162
171
  cons: Dict[str, Sequence[str]],
163
172
  ) -> Component:
164
173
  """Returns a dimension."""
165
- c = _find_concept(cs, self.concept)
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)
166
176
  dt, facets, codes, ab = _get_representation(
167
177
  self.id, self.representation, cls, cons
168
178
  )
169
- desc = c.descriptions[0].value if c.descriptions else None
179
+ desc = c.description if isinstance(c, Concept) else None
170
180
  if self.representation and self.representation.representation:
171
181
  local_enum_ref = self.representation.representation
172
182
  else:
@@ -175,10 +185,10 @@ class FusionDimension(Struct, frozen=True):
175
185
  id=self.id,
176
186
  required=True,
177
187
  role=Role.DIMENSION,
178
- concept=c.to_model(cls),
188
+ concept=c,
179
189
  local_dtype=dt,
180
190
  local_facets=facets,
181
- name=c.names[0].value,
191
+ name=c.name if isinstance(c, Concept) else None,
182
192
  description=desc,
183
193
  local_codes=codes,
184
194
  array_def=ab,
@@ -216,11 +226,12 @@ class FusionMeasure(Struct, frozen=True):
216
226
  cons: Dict[str, Sequence[str]],
217
227
  ) -> Component:
218
228
  """Returns a measure."""
219
- c = _find_concept(cs, self.concept)
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)
220
231
  dt, facets, codes, ab = _get_representation(
221
232
  self.id, self.representation, cls, cons
222
233
  )
223
- desc = c.descriptions[0].value if c.descriptions else None
234
+ desc = c.description if isinstance(c, Concept) else None
224
235
  if self.representation and self.representation.representation:
225
236
  local_enum_ref = self.representation.representation
226
237
  else:
@@ -229,10 +240,10 @@ class FusionMeasure(Struct, frozen=True):
229
240
  id=self.id,
230
241
  required=self.mandatory,
231
242
  role=Role.MEASURE,
232
- concept=c.to_model(cls),
243
+ concept=c,
233
244
  local_dtype=dt,
234
245
  local_facets=facets,
235
- name=c.names[0].value,
246
+ name=c.name if isinstance(c, Concept) else None,
236
247
  description=desc,
237
248
  local_codes=codes,
238
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
- ArrayBoundaries,
19
- MetadataComponent,
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
- c = _find_concept(cs, self.concept)
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.to_model(cls),
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
  )