pysdmx 1.7.0__tar.gz → 1.8.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. {pysdmx-1.7.0 → pysdmx-1.8.1}/PKG-INFO +1 -1
  2. {pysdmx-1.7.0 → pysdmx-1.8.1}/pyproject.toml +2 -2
  3. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/__init__.py +1 -1
  4. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/fmr/__init__.py +266 -0
  5. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/qb/refmeta.py +1 -1
  6. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/qb/schema.py +4 -10
  7. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/qb/service.py +26 -4
  8. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/qb/structure.py +2 -2
  9. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/messages/__init__.py +14 -0
  10. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/messages/dsd.py +52 -1
  11. pysdmx-1.8.1/src/pysdmx/io/json/fusion/messages/metadataflow.py +44 -0
  12. pysdmx-1.8.1/src/pysdmx/io/json/fusion/messages/mpa.py +45 -0
  13. pysdmx-1.8.1/src/pysdmx/io/json/fusion/messages/msd.py +121 -0
  14. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/messages/org.py +90 -0
  15. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/reader/__init__.py +5 -0
  16. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/__init__.py +15 -1
  17. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/dsd.py +9 -6
  18. pysdmx-1.8.1/src/pysdmx/io/json/sdmxjson2/messages/metadataflow.py +88 -0
  19. pysdmx-1.8.1/src/pysdmx/io/json/sdmxjson2/messages/mpa.py +88 -0
  20. pysdmx-1.8.1/src/pysdmx/io/json/sdmxjson2/messages/msd.py +245 -0
  21. pysdmx-1.8.1/src/pysdmx/io/json/sdmxjson2/messages/provider.py +232 -0
  22. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/structure.py +25 -1
  23. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/reader/__init__.py +5 -0
  24. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/serde.py +5 -0
  25. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/writer.py +2 -4
  26. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/__structure_aux_writer.py +9 -9
  27. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/__write_data_aux.py +1 -2
  28. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/model/__init__.py +12 -1
  29. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/model/dataflow.py +1 -0
  30. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/model/map.py +3 -1
  31. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/model/message.py +29 -2
  32. pysdmx-1.8.1/src/pysdmx/model/metadata.py +453 -0
  33. pysdmx-1.7.0/src/pysdmx/io/json/sdmxjson2/messages/provider.py +0 -116
  34. pysdmx-1.7.0/src/pysdmx/model/metadata.py +0 -202
  35. {pysdmx-1.7.0 → pysdmx-1.8.1}/LICENSE +0 -0
  36. {pysdmx-1.7.0 → pysdmx-1.8.1}/README.rst +0 -0
  37. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/__extras_check.py +0 -0
  38. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/__init__.py +0 -0
  39. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/dc/__init__.py +0 -0
  40. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/dc/_api.py +0 -0
  41. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/dc/query/__init__.py +0 -0
  42. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/dc/query/_model.py +0 -0
  43. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/dc/query/_parsing_model.py +0 -0
  44. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/dc/query/_parsing_util.py +0 -0
  45. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/dc/query/_py_parser.py +0 -0
  46. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/dc/query/_sql_parser.py +0 -0
  47. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/dc/query/util.py +0 -0
  48. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/fmr/maintenance.py +0 -0
  49. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/gds/__init__.py +0 -0
  50. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/qb/__init__.py +0 -0
  51. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/qb/availability.py +0 -0
  52. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/qb/data.py +0 -0
  53. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/qb/gds.py +0 -0
  54. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/qb/registration.py +0 -0
  55. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/api/qb/util.py +0 -0
  56. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/errors.py +0 -0
  57. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/__init__.py +0 -0
  58. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/csv/__csv_aux_reader.py +0 -0
  59. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/csv/__csv_aux_writer.py +0 -0
  60. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/csv/__init__.py +0 -0
  61. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/csv/sdmx10/__init__.py +0 -0
  62. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/csv/sdmx10/reader/__init__.py +0 -0
  63. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/csv/sdmx10/writer/__init__.py +0 -0
  64. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/csv/sdmx20/__init__.py +0 -0
  65. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/csv/sdmx20/reader/__init__.py +0 -0
  66. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/csv/sdmx20/writer/__init__.py +0 -0
  67. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/csv/sdmx21/__init__.py +0 -0
  68. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/csv/sdmx21/reader/__init__.py +0 -0
  69. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/csv/sdmx21/writer/__init__.py +0 -0
  70. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/format.py +0 -0
  71. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/input_processor.py +0 -0
  72. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/messages/category.py +0 -0
  73. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/messages/code.py +0 -0
  74. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/messages/concept.py +0 -0
  75. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/messages/constraint.py +0 -0
  76. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/messages/core.py +0 -0
  77. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/messages/dataflow.py +0 -0
  78. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/messages/map.py +0 -0
  79. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/messages/pa.py +0 -0
  80. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/messages/report.py +0 -0
  81. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/messages/schema.py +0 -0
  82. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/fusion/messages/vtl.py +0 -0
  83. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/gds/messages/__init__.py +0 -0
  84. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/gds/messages/agencies.py +0 -0
  85. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/gds/messages/catalog.py +0 -0
  86. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/gds/messages/sdmx_api.py +0 -0
  87. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/gds/messages/services.py +0 -0
  88. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/gds/messages/urn_resolver.py +0 -0
  89. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/gds/reader/__init__.py +0 -0
  90. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/agency.py +0 -0
  91. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/category.py +0 -0
  92. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/code.py +0 -0
  93. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/concept.py +0 -0
  94. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/constraint.py +0 -0
  95. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/core.py +0 -0
  96. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/dataflow.py +0 -0
  97. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/map.py +0 -0
  98. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/pa.py +0 -0
  99. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/report.py +0 -0
  100. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/schema.py +0 -0
  101. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/messages/vtl.py +0 -0
  102. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/reader/metadata.py +0 -0
  103. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/reader/structure.py +0 -0
  104. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/writer/__init__.py +0 -0
  105. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/writer/metadata.py +0 -0
  106. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/json/sdmxjson2/writer/structure.py +0 -0
  107. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/pd.py +0 -0
  108. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/reader.py +0 -0
  109. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/__allowed_lxml_errors.py +0 -0
  110. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/__data_aux.py +0 -0
  111. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/__init__.py +0 -0
  112. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/__parse_xml.py +0 -0
  113. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/__ss_aux_reader.py +0 -0
  114. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/__structure_aux_reader.py +0 -0
  115. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/__tokens.py +0 -0
  116. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/__write_aux.py +0 -0
  117. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/__write_structure_specific_aux.py +0 -0
  118. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/config.py +0 -0
  119. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/doc_validation.py +0 -0
  120. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/header.py +0 -0
  121. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx21/__init__.py +0 -0
  122. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx21/reader/__init__.py +0 -0
  123. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx21/reader/error.py +0 -0
  124. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx21/reader/generic.py +0 -0
  125. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx21/reader/structure.py +0 -0
  126. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx21/reader/structure_specific.py +0 -0
  127. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx21/reader/submission.py +0 -0
  128. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx21/writer/__init__.py +0 -0
  129. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx21/writer/error.py +0 -0
  130. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx21/writer/generic.py +0 -0
  131. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx21/writer/structure.py +0 -0
  132. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx21/writer/structure_specific.py +0 -0
  133. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx30/__init__.py +0 -0
  134. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx30/reader/__init__.py +0 -0
  135. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx30/reader/structure.py +0 -0
  136. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx30/reader/structure_specific.py +0 -0
  137. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx30/writer/__init__.py +0 -0
  138. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx30/writer/structure.py +0 -0
  139. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx30/writer/structure_specific.py +0 -0
  140. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx31/__init__.py +0 -0
  141. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx31/reader/__init__.py +0 -0
  142. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx31/reader/structure.py +0 -0
  143. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx31/reader/structure_specific.py +0 -0
  144. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx31/writer/__init__.py +0 -0
  145. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx31/writer/structure.py +0 -0
  146. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/sdmx31/writer/structure_specific.py +0 -0
  147. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/io/xml/utils.py +0 -0
  148. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/model/__base.py +0 -0
  149. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/model/category.py +0 -0
  150. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/model/code.py +0 -0
  151. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/model/concept.py +0 -0
  152. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/model/dataset.py +0 -0
  153. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/model/gds.py +0 -0
  154. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/model/organisation.py +0 -0
  155. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/model/submission.py +0 -0
  156. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/model/vtl.py +0 -0
  157. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/py.typed +0 -0
  158. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/toolkit/__init__.py +0 -0
  159. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/toolkit/pd/__init__.py +0 -0
  160. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/toolkit/pd/_data_utils.py +0 -0
  161. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/toolkit/vtl/__init__.py +0 -0
  162. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/toolkit/vtl/_validations.py +0 -0
  163. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/toolkit/vtl/script_generation.py +0 -0
  164. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/toolkit/vtl/validation.py +0 -0
  165. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/util/__init__.py +0 -0
  166. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/util/_date_pattern_map.py +0 -0
  167. {pysdmx-1.7.0 → pysdmx-1.8.1}/src/pysdmx/util/_model_utils.py +0 -0
  168. {pysdmx-1.7.0 → pysdmx-1.8.1}/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.7.0
3
+ Version: 1.8.1
4
4
  Summary: Your opinionated Python SDMX library
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pysdmx"
3
- version = "1.7.0"
3
+ version = "1.8.1"
4
4
  description = "Your opinionated Python SDMX library"
5
5
  license = { text = "Apache-2.0" }
6
6
  readme = "README.rst"
@@ -93,7 +93,7 @@ lint.mccabe.max-complexity = 10
93
93
  lint.pydocstyle.convention = "google"
94
94
 
95
95
  [tool.ruff.lint.per-file-ignores]
96
- "tests/*" = ["DTZ", "D100", "D103", "D104", "PERF", "S101", "S311"]
96
+ "tests/*" = ["C901", "DTZ", "D100", "D103", "D104", "PERF", "S101", "S311"]
97
97
 
98
98
  [tool.mypy]
99
99
  files = "src"
@@ -1,3 +1,3 @@
1
1
  """Your opinionated Python SDMX library."""
2
2
 
3
- __version__ = "1.7.0"
3
+ __version__ = "1.8.1"
@@ -41,6 +41,8 @@ from pysdmx.model import (
41
41
  DataProvider,
42
42
  Hierarchy,
43
43
  HierarchyAssociation,
44
+ Metadataflow,
45
+ MetadataProvisionAgreement,
44
46
  MetadataReport,
45
47
  MultiRepresentationMap,
46
48
  ProvisionAgreement,
@@ -196,6 +198,18 @@ class __BaseRegistryClient:
196
198
  StructureType.DATA_PROVIDER_SCHEME, agency, references=r
197
199
  )
198
200
 
201
+ def _metadata_providers_q(
202
+ self, agency: str, with_flows: bool
203
+ ) -> StructureQuery:
204
+ r = (
205
+ StructureReference.METADATA_PROVISION_AGREEMENT
206
+ if with_flows
207
+ else StructureReference.NONE
208
+ )
209
+ return StructureQuery(
210
+ StructureType.METADATA_PROVIDER_SCHEME, agency, references=r
211
+ )
212
+
199
213
  def _categories_q(
200
214
  self, agency: str, id: str, version: str
201
215
  ) -> StructureQuery:
@@ -273,6 +287,38 @@ class __BaseRegistryClient:
273
287
  StructureType.PROVISION_AGREEMENT, agency, id, version
274
288
  )
275
289
 
290
+ def _metadataflows_q(
291
+ self, agency: str, id: str, version: str
292
+ ) -> StructureQuery:
293
+ return StructureQuery(StructureType.METADATAFLOW, agency, id, version)
294
+
295
+ def _mpa_q(self, agency: str, id: str, version: str) -> StructureQuery:
296
+ return StructureQuery(
297
+ StructureType.METADATA_PROVISION_AGREEMENT, agency, id, version
298
+ )
299
+
300
+ def _msds_q(self, agency: str, id: str, version: str) -> StructureQuery:
301
+ return StructureQuery(
302
+ StructureType.METADATA_STRUCTURE,
303
+ agency,
304
+ id,
305
+ version,
306
+ detail=StructureDetail.REFERENCE_PARTIAL,
307
+ references=StructureReference.DESCENDANTS,
308
+ )
309
+
310
+ def _data_structures_q(
311
+ self, agency: str, id: str, version: str
312
+ ) -> StructureQuery:
313
+ return StructureQuery(
314
+ StructureType.DATA_STRUCTURE,
315
+ agency,
316
+ id,
317
+ version,
318
+ detail=StructureDetail.REFERENCE_PARTIAL,
319
+ references=StructureReference.DESCENDANTS,
320
+ )
321
+
276
322
 
277
323
  class RegistryClient(__BaseRegistryClient):
278
324
  """A client to be used to retrieve metadata from the FMR.
@@ -385,6 +431,28 @@ class RegistryClient(__BaseRegistryClient):
385
431
  schemes = super()._out(out, self.deser.providers)
386
432
  return schemes[0].items
387
433
 
434
+ def get_metadata_providers(
435
+ self,
436
+ agency: str,
437
+ with_flows: bool = False,
438
+ ) -> Sequence[DataProvider]:
439
+ """Get the list of **metadata providers** for the supplied agency.
440
+
441
+ Args:
442
+ agency: The agency maintaining the metadata provider scheme from
443
+ which metadata providers must be returned.
444
+ with_flows: Whether the metadata providers should contain the list
445
+ of metadataflows for which the metadata provider provides
446
+ metadata reports.
447
+
448
+ Returns:
449
+ The requested list of metadata providers.
450
+ """
451
+ query = super()._metadata_providers_q(agency, with_flows)
452
+ out = self.__fetch(query)
453
+ schemes = super()._out(out, self.deser.metadata_providers)
454
+ return schemes[0].items
455
+
388
456
  def get_categories(
389
457
  self,
390
458
  agency: str,
@@ -605,6 +673,28 @@ class RegistryClient(__BaseRegistryClient):
605
673
  out = self.__fetch(query)
606
674
  return super()._out(out, self.deser.dataflows)
607
675
 
676
+ def get_data_structures(
677
+ self,
678
+ agency: str = "*",
679
+ id: str = "*",
680
+ version: str = "+",
681
+ ) -> Sequence[Dataflow]:
682
+ """Get the data structures(s) matching the supplied parameters.
683
+
684
+ Args:
685
+ agency: The agency maintaining the data structures(s).
686
+ id: The ID of the data structures(s) to be returned.
687
+ version: The version of the data structures(s) to be returned.
688
+ The most recent version will be returned, unless specified
689
+ otherwise.
690
+
691
+ Returns:
692
+ The requested data structures(s).
693
+ """
694
+ query = super()._data_structures_q(agency, id, version)
695
+ out = self.__fetch(query)
696
+ return super()._out(out, self.deser.data_structures)
697
+
608
698
  def get_hierarchy(
609
699
  self,
610
700
  agency: str,
@@ -672,6 +762,72 @@ class RegistryClient(__BaseRegistryClient):
672
762
  out = self.__fetch(query)
673
763
  return super()._out(out, self.deser.report).reports
674
764
 
765
+ def get_metadata_structures(
766
+ self,
767
+ agency: str = "*",
768
+ id: str = "*",
769
+ version: str = "+",
770
+ ) -> Sequence[Dataflow]:
771
+ """Get the metadata structures (MSD) matching the supplied parameters.
772
+
773
+ Args:
774
+ agency: The agency maintaining the MSD(s).
775
+ id: The ID of the metadata structure(s) to be returned.
776
+ version: The version of the metadata structure(s) to be returned.
777
+ The most recent version will be returned, unless specified
778
+ otherwise.
779
+
780
+ Returns:
781
+ The requested MSD(s).
782
+ """
783
+ query = super()._msds_q(agency, id, version)
784
+ out = self.__fetch(query)
785
+ return super()._out(out, self.deser.msds)
786
+
787
+ def get_metadataflows(
788
+ self,
789
+ agency: str = "*",
790
+ id: str = "*",
791
+ version: str = "+",
792
+ ) -> Sequence[Metadataflow]:
793
+ """Get the metadataflow(s) matching the supplied parameters.
794
+
795
+ Args:
796
+ agency: The agency maintaining the metadataflow(s).
797
+ id: The ID of the metadataflow(s) to be returned.
798
+ version: The version of the metadataflow(s) to be returned.
799
+ The most recent version will be returned, unless specified
800
+ otherwise.
801
+
802
+ Returns:
803
+ The requested metadataflow(s).
804
+ """
805
+ query = super()._metadataflows_q(agency, id, version)
806
+ out = self.__fetch(query)
807
+ return super()._out(out, self.deser.metadataflows)
808
+
809
+ def get_metadata_provision_agreement(
810
+ self,
811
+ agency: str,
812
+ id: str,
813
+ version: str = "+",
814
+ ) -> MetadataProvisionAgreement:
815
+ """Get the metadata provision agreement matching the parameters.
816
+
817
+ Args:
818
+ agency: The agency maintaining the metadata provision agreement.
819
+ id: The ID of the metadata provision agreement to be returned.
820
+ version: The version of the metadata provision agreement to be
821
+ returned. The most recent version will be returned, unless
822
+ specified otherwise.
823
+
824
+ Returns:
825
+ The requested metadata provision agreement.
826
+ """
827
+ query = super()._mpa_q(agency, id, version)
828
+ out = self.__fetch(query)
829
+ return super()._out(out, self.deser.metadata_provision_agreement)[0]
830
+
675
831
  def get_mapping(
676
832
  self,
677
833
  agency: str,
@@ -844,6 +1000,28 @@ class AsyncRegistryClient(__BaseRegistryClient):
844
1000
  schemes = super()._out(out, self.deser.providers)
845
1001
  return schemes[0].items
846
1002
 
1003
+ async def get_metadata_providers(
1004
+ self,
1005
+ agency: str,
1006
+ with_flows: bool = False,
1007
+ ) -> Sequence[DataProvider]:
1008
+ """Get the list of **metadata providers** for the supplied agency.
1009
+
1010
+ Args:
1011
+ agency: The agency maintaining the metadata provider scheme from
1012
+ which metadata providers must be returned.
1013
+ with_flows: Whether the metadata providers should contain the list
1014
+ of metadataflows for which the metadata provider provides
1015
+ metadata reports.
1016
+
1017
+ Returns:
1018
+ The requested list of metadata providers.
1019
+ """
1020
+ query = super()._metadata_providers_q(agency, with_flows)
1021
+ out = await self.__fetch(query)
1022
+ schemes = super()._out(out, self.deser.metadata_providers)
1023
+ return schemes[0].items
1024
+
847
1025
  async def get_categories(
848
1026
  self,
849
1027
  agency: str,
@@ -1069,6 +1247,28 @@ class AsyncRegistryClient(__BaseRegistryClient):
1069
1247
  out = await self.__fetch(query)
1070
1248
  return super()._out(out, self.deser.dataflows)
1071
1249
 
1250
+ async def get_data_structures(
1251
+ self,
1252
+ agency: str = "*",
1253
+ id: str = "*",
1254
+ version: str = "+",
1255
+ ) -> Sequence[Dataflow]:
1256
+ """Get the data structures(s) matching the supplied parameters.
1257
+
1258
+ Args:
1259
+ agency: The agency maintaining the data structures(s).
1260
+ id: The ID of the data structures(s) to be returned.
1261
+ version: The version of the data structures(s) to be returned.
1262
+ The most recent version will be returned, unless specified
1263
+ otherwise.
1264
+
1265
+ Returns:
1266
+ The requested data structures(s).
1267
+ """
1268
+ query = super()._data_structures_q(agency, id, version)
1269
+ out = await self.__fetch(query)
1270
+ return super()._out(out, self.deser.data_structures)
1271
+
1072
1272
  async def get_hierarchy(
1073
1273
  self,
1074
1274
  agency: str,
@@ -1136,6 +1336,72 @@ class AsyncRegistryClient(__BaseRegistryClient):
1136
1336
  out = await self.__fetch(query)
1137
1337
  return super()._out(out, self.deser.report).reports
1138
1338
 
1339
+ async def get_metadata_structures(
1340
+ self,
1341
+ agency: str = "*",
1342
+ id: str = "*",
1343
+ version: str = "+",
1344
+ ) -> Sequence[Dataflow]:
1345
+ """Get the metadata structures (MSD) matching the supplied parameters.
1346
+
1347
+ Args:
1348
+ agency: The agency maintaining the MSD(s).
1349
+ id: The ID of the metadata structure(s) to be returned.
1350
+ version: The version of the metadata structure(s) to be returned.
1351
+ The most recent version will be returned, unless specified
1352
+ otherwise.
1353
+
1354
+ Returns:
1355
+ The requested MSD(s).
1356
+ """
1357
+ query = super()._msds_q(agency, id, version)
1358
+ out = await self.__fetch(query)
1359
+ return super()._out(out, self.deser.msds)
1360
+
1361
+ async def get_metadataflows(
1362
+ self,
1363
+ agency: str = "*",
1364
+ id: str = "*",
1365
+ version: str = "+",
1366
+ ) -> Sequence[Metadataflow]:
1367
+ """Get the metadataflow(s) matching the supplied parameters.
1368
+
1369
+ Args:
1370
+ agency: The agency maintaining the metadataflow(s).
1371
+ id: The ID of the metadataflow(s) to be returned.
1372
+ version: The version of the metadataflow(s) to be returned.
1373
+ The most recent version will be returned, unless specified
1374
+ otherwise.
1375
+
1376
+ Returns:
1377
+ The requested metadataflow(s).
1378
+ """
1379
+ query = super()._metadataflows_q(agency, id, version)
1380
+ out = await self.__fetch(query)
1381
+ return super()._out(out, self.deser.metadataflows)
1382
+
1383
+ async def get_metadata_provision_agreement(
1384
+ self,
1385
+ agency: str,
1386
+ id: str,
1387
+ version: str = "+",
1388
+ ) -> MetadataProvisionAgreement:
1389
+ """Get the metadata provision agreement matching the parameters.
1390
+
1391
+ Args:
1392
+ agency: The agency maintaining the metadata provision agreement.
1393
+ id: The ID of the metadata provision agreement to be returned.
1394
+ version: The version of the metadata provision agreement to be
1395
+ returned. The most recent version will be returned, unless
1396
+ specified otherwise.
1397
+
1398
+ Returns:
1399
+ The requested metadata provision agreement.
1400
+ """
1401
+ query = super()._mpa_q(agency, id, version)
1402
+ out = await self.__fetch(query)
1403
+ return super()._out(out, self.deser.metadata_provision_agreement)[0]
1404
+
1139
1405
  async def get_mapping(
1140
1406
  self,
1141
1407
  agency: str,
@@ -43,7 +43,7 @@ class _RefMetaCoreQuery(CoreQuery, frozen=True, omit_defaults=True):
43
43
  )
44
44
 
45
45
  def _get_as_of_value(self, as_of: Optional[datetime]) -> str:
46
- return f'&asOf={as_of.isoformat("T", "seconds")}' if as_of else ""
46
+ return f"&asOf={as_of.isoformat('T', 'seconds')}" if as_of else ""
47
47
 
48
48
  def _get_short_qs(
49
49
  self, detail: RefMetaDetail, as_of: Optional[datetime]
@@ -101,10 +101,7 @@ class SchemaQuery(CoreQuery, frozen=True, omit_defaults=True):
101
101
  self.__check_deletion(version)
102
102
 
103
103
  def _create_full_query(self, ver: ApiVersion) -> str:
104
- u = (
105
- f"/schema/{self.context.value}/"
106
- f"{self.agency_id}/{self.resource_id}"
107
- )
104
+ u = f"/schema/{self.context.value}/{self.agency_id}/{self.resource_id}"
108
105
  u += f"/{self._to_kw(self.version, ver)}"
109
106
  if (
110
107
  self.obs_dimension
@@ -122,7 +119,7 @@ class SchemaQuery(CoreQuery, frozen=True, omit_defaults=True):
122
119
  if self.as_of:
123
120
  if self.obs_dimension:
124
121
  u += "&"
125
- u += f'asOf={self.as_of.isoformat("T", "seconds")}'
122
+ u += f"asOf={self.as_of.isoformat('T', 'seconds')}"
126
123
  if ver >= ApiVersion.V2_2_0:
127
124
  if self.obs_dimension or self.as_of:
128
125
  u += "&"
@@ -130,10 +127,7 @@ class SchemaQuery(CoreQuery, frozen=True, omit_defaults=True):
130
127
  return u
131
128
 
132
129
  def _create_short_query(self, ver: ApiVersion) -> str:
133
- u = (
134
- f"/schema/{self.context.value}/"
135
- f"{self.agency_id}/{self.resource_id}"
136
- )
130
+ u = f"/schema/{self.context.value}/{self.agency_id}/{self.resource_id}"
137
131
  if self.version != REST_LATEST:
138
132
  u += f"/{self._to_kw(self.version, ver)}"
139
133
  if self.obs_dimension or self.explicit or self.as_of or self.deletion:
@@ -147,7 +141,7 @@ class SchemaQuery(CoreQuery, frozen=True, omit_defaults=True):
147
141
  if self.as_of:
148
142
  if self.obs_dimension:
149
143
  u += "&"
150
- u += f'asOf={self.as_of.isoformat("T", "seconds")}'
144
+ u += f"asOf={self.as_of.isoformat('T', 'seconds')}"
151
145
  if self.deletion:
152
146
  if self.obs_dimension or self.as_of:
153
147
  u += "&"
@@ -166,8 +166,12 @@ class RestService(_CoreRestService):
166
166
  return self.__fetch(q, f)
167
167
 
168
168
  def __fetch(self, query: str, format: str) -> bytes:
169
- with httpx.Client(verify=self._ssl_context) as client:
169
+ with httpx.Client(
170
+ verify=self._ssl_context, follow_redirects=True
171
+ ) as client:
170
172
  try:
173
+ query = _add_query_slash(query)
174
+
171
175
  url = f"{self._api_endpoint}{query}"
172
176
  h = self._headers.copy()
173
177
  h["Accept"] = format
@@ -282,8 +286,12 @@ class AsyncRestService(_CoreRestService):
282
286
  return out
283
287
 
284
288
  async def __fetch(self, query: str, format: str) -> bytes:
285
- async with httpx.AsyncClient(verify=self._ssl_context) as client:
289
+ async with httpx.AsyncClient(
290
+ verify=self._ssl_context, follow_redirects=True
291
+ ) as client:
286
292
  try:
293
+ query = _add_query_slash(query)
294
+
287
295
  url = f"{self._api_endpoint}{query}"
288
296
  h = self._headers.copy()
289
297
  h["Accept"] = format
@@ -336,12 +344,22 @@ class _CoreGdsRestService:
336
344
  raise errors.Unavailable("Connection error", msg) from e
337
345
 
338
346
 
347
+ def _add_query_slash(query: str) -> str:
348
+ if "?" not in query and "#" not in query and not query.endswith("/"):
349
+ query += "/"
350
+ return query
351
+
352
+
339
353
  class GdsRestService(_CoreGdsRestService):
340
354
  """Synchronous GDS-REST service."""
341
355
 
342
356
  def _fetch(self, query: str, format_: str) -> bytes:
343
- with httpx.Client(verify=self._ssl_context) as client:
357
+ with httpx.Client(
358
+ verify=self._ssl_context, follow_redirects=True
359
+ ) as client:
344
360
  try:
361
+ query = _add_query_slash(query)
362
+
345
363
  url = f"{self._api_endpoint}{query}"
346
364
  headers = {**self._headers, "Accept": format_}
347
365
  response = client.get(
@@ -362,8 +380,12 @@ class GdsAsyncRestService(_CoreGdsRestService):
362
380
  """Asynchronous GDS-REST service."""
363
381
 
364
382
  async def _fetch(self, query: str, format_: str) -> bytes:
365
- async with httpx.AsyncClient(verify=self._ssl_context) as client:
383
+ async with httpx.AsyncClient(
384
+ verify=self._ssl_context, follow_redirects=True
385
+ ) as client:
366
386
  try:
387
+ query = _add_query_slash(query)
388
+
367
389
  url = f"{self._api_endpoint}{query}"
368
390
  headers = {**self._headers, "Accept": format_}
369
391
  response = await client.get(
@@ -433,7 +433,7 @@ class StructureQuery(CoreQuery, frozen=True, omit_defaults=True):
433
433
  u += f"/{i}" if all(ck) else ""
434
434
  u += f"?detail={self.detail.value}&references={self.references.value}"
435
435
  if self.as_of:
436
- u += f'&asOf={self.as_of.isoformat("T", "seconds")}'
436
+ u += f"&asOf={self.as_of.isoformat('T', 'seconds')}"
437
437
  return u
438
438
 
439
439
  def _create_short_query(self, ver: ApiVersion) -> str:
@@ -492,7 +492,7 @@ class StructureQuery(CoreQuery, frozen=True, omit_defaults=True):
492
492
  else ""
493
493
  )
494
494
  u += (
495
- f'asOf={self.as_of.isoformat("T", "seconds")}'
495
+ f"asOf={self.as_of.isoformat('T', 'seconds')}"
496
496
  if self.as_of
497
497
  else ""
498
498
  )
@@ -14,12 +14,21 @@ from pysdmx.io.json.fusion.messages.dataflow import (
14
14
  FusionDataflowMessage,
15
15
  FusionDataflowsMessage,
16
16
  )
17
+ from pysdmx.io.json.fusion.messages.dsd import FusionDataStructuresMessage
17
18
  from pysdmx.io.json.fusion.messages.map import (
18
19
  FusionMappingMessage,
19
20
  FusionRepresentationMapMessage,
20
21
  )
22
+ from pysdmx.io.json.fusion.messages.metadataflow import (
23
+ FusionMetadataflowsMessage,
24
+ )
25
+ from pysdmx.io.json.fusion.messages.mpa import (
26
+ FusionMetadataProvisionAgreementMessage,
27
+ )
28
+ from pysdmx.io.json.fusion.messages.msd import FusionMetadataStructuresMessage
21
29
  from pysdmx.io.json.fusion.messages.org import (
22
30
  FusionAgencyMessage,
31
+ FusionMetadataProviderMessage,
23
32
  FusionProviderMessage,
24
33
  )
25
34
  from pysdmx.io.json.fusion.messages.pa import (
@@ -41,6 +50,10 @@ __all__ = [
41
50
  "FusionDataflowMessage",
42
51
  "FusionDataflowsMessage",
43
52
  "FusionMappingMessage",
53
+ "FusionMetadataflowsMessage",
54
+ "FusionMetadataProviderMessage",
55
+ "FusionMetadataProvisionAgreementMessage",
56
+ "FusionMetadataStructuresMessage",
44
57
  "FusionRepresentationMapMessage",
45
58
  "FusionAgencyMessage",
46
59
  "FusionProviderMessage",
@@ -48,4 +61,5 @@ __all__ = [
48
61
  "FusionSchemaMessage",
49
62
  "FusionTransfoMsg",
50
63
  "FusionPAMessage",
64
+ "FusionDataStructuresMessage",
51
65
  ]
@@ -20,10 +20,12 @@ from pysdmx.model import (
20
20
  Codelist,
21
21
  Component,
22
22
  Components,
23
+ DataStructureDefinition,
23
24
  DataType,
24
25
  Facets,
25
26
  Role,
26
27
  )
28
+ from pysdmx.model.dataflow import Group
27
29
  from pysdmx.util import parse_item_urn
28
30
 
29
31
 
@@ -248,7 +250,7 @@ class FusionDataStructure(Struct, frozen=True, rename={"agency": "agencyId"}):
248
250
  measures: Sequence[FusionMeasure] = ()
249
251
  attributeList: Optional[FusionAttributes] = None
250
252
  groups: Sequence[FusionGroup] = ()
251
- description: Optional[Sequence[FusionString]] = None
253
+ descriptions: Optional[Sequence[FusionString]] = None
252
254
  version: str = "1.0"
253
255
 
254
256
  def get_components(
@@ -273,3 +275,52 @@ class FusionDataStructure(Struct, frozen=True, rename={"agency": "agencyId"}):
273
275
  )
274
276
  )
275
277
  return Components(comps)
278
+
279
+ def to_model(
280
+ self,
281
+ cs: Sequence[FusionConceptScheme],
282
+ cls: Sequence[FusionCodelist],
283
+ vls: Sequence[FusionCodelist],
284
+ constraints: Sequence[FusionContentConstraint],
285
+ ) -> DataStructureDefinition:
286
+ """Map to pysdmx model class."""
287
+ enums: list[FusionCodelist] = []
288
+ enums.extend(cls)
289
+ enums.extend(vls)
290
+ cmps = self.get_components(cs, enums, constraints)
291
+ grps = [
292
+ Group(g.id, dimensions=g.dimensionReferences) for g in self.groups
293
+ ]
294
+ return DataStructureDefinition(
295
+ id=self.id,
296
+ name=self.names[0].value,
297
+ agency=self.agency,
298
+ description=(
299
+ self.descriptions[0].value if self.descriptions else None
300
+ ),
301
+ version=self.version,
302
+ components=cmps,
303
+ groups=grps,
304
+ )
305
+
306
+
307
+ class FusionDataStructuresMessage(Struct, frozen=True, omit_defaults=True):
308
+ """Fusion-JSON payload for /datastructure queries."""
309
+
310
+ ConceptScheme: Sequence[FusionConceptScheme]
311
+ DataStructure: Sequence[FusionDataStructure]
312
+ ValueList: Sequence[FusionCodelist] = ()
313
+ Codelist: Sequence[FusionCodelist] = ()
314
+ DataConstraint: Sequence[FusionContentConstraint] = ()
315
+
316
+ def to_model(self) -> Sequence[DataStructureDefinition]:
317
+ """Returns the requested data structures."""
318
+ return [
319
+ dsd.to_model(
320
+ self.ConceptScheme,
321
+ self.Codelist,
322
+ self.ValueList,
323
+ self.DataConstraint,
324
+ )
325
+ for dsd in self.DataStructure
326
+ ]
@@ -0,0 +1,44 @@
1
+ """Collection of Fusion-JSON schemas for dataflow queries."""
2
+
3
+ from typing import Optional, Sequence
4
+
5
+ from msgspec import Struct
6
+
7
+ from pysdmx.io.json.fusion.messages.core import FusionString
8
+ from pysdmx.model import Metadataflow as MDF
9
+
10
+
11
+ class FusionMetadataflow(Struct, frozen=True, rename={"agency": "agencyId"}):
12
+ """Fusion-JSON payload for a metadataflow."""
13
+
14
+ id: str
15
+ agency: str
16
+ names: Sequence[FusionString]
17
+ metadataStructureRef: str
18
+ targets: Sequence[str]
19
+ descriptions: Optional[Sequence[FusionString]] = None
20
+ version: str = "1.0"
21
+
22
+ def to_model(self) -> MDF:
23
+ """Converts a FusionMetadataflow to a standard metadataflow."""
24
+ return MDF(
25
+ id=self.id,
26
+ agency=self.agency,
27
+ name=self.names[0].value if self.names else None,
28
+ description=(
29
+ self.descriptions[0].value if self.descriptions else None
30
+ ),
31
+ version=self.version,
32
+ structure=self.metadataStructureRef,
33
+ targets=self.targets,
34
+ )
35
+
36
+
37
+ class FusionMetadataflowsMessage(Struct, frozen=True):
38
+ """Fusion-JSON payload for /metadataflow queries."""
39
+
40
+ Metadataflow: Sequence[FusionMetadataflow]
41
+
42
+ def to_model(self) -> Sequence[MDF]:
43
+ """Returns the requested metadataflow details."""
44
+ return [df.to_model() for df in self.Metadataflow]