hdx-python-api 6.7.8__tar.gz → 6.7.9__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 (186) hide show
  1. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/.github/workflows/run-python-tests.yaml +4 -2
  2. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/PKG-INFO +3 -3
  3. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/pyproject.toml +2 -2
  4. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/api/_version.py +2 -2
  5. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/data/dataset.py +82 -50
  6. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/api/test_ckan.py +4 -2
  7. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/api/test_configuration.py +18 -9
  8. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/api/utilities/test_hdx_state.py +12 -6
  9. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/test_dataset_core.py +4 -2
  10. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/test_dataset_noncore.py +2 -1
  11. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/test_dataset_resource_generation.py +4 -4
  12. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/test_organization.py +4 -2
  13. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/test_resource.py +8 -4
  14. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/test_resource_view.py +4 -2
  15. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/test_showcase.py +4 -2
  16. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/test_update_dataset_resources.py +10 -5
  17. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/test_update_logic.py +54 -8
  18. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/test_user.py +4 -2
  19. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/test_vocabulary.py +4 -2
  20. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/uv.lock +390 -341
  21. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/.github/workflows/publish.yaml +0 -0
  22. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/.gitignore +0 -0
  23. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/.pre-commit-config.yaml +0 -0
  24. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/CLAUDE.md +0 -0
  25. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/LICENSE +0 -0
  26. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/README.md +0 -0
  27. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/.readthedocs.yaml +0 -0
  28. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/explanation/facades.md +0 -0
  29. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/explanation/history.md +0 -0
  30. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/explanation/information.md +0 -0
  31. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/activity-streams.md +0 -0
  32. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/api-key.md +0 -0
  33. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/customisation.md +0 -0
  34. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/docker.md +0 -0
  35. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/facades.md +0 -0
  36. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/framework.md +0 -0
  37. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/idmc-example.md +0 -0
  38. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/install.md +0 -0
  39. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/locations.md +0 -0
  40. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/logging.md +0 -0
  41. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/objects.md +0 -0
  42. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/operate-datasets/dataset-resources.md +0 -0
  43. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/operate-datasets/location.md +0 -0
  44. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/operate-datasets/maintainer.md +0 -0
  45. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/operate-datasets/organization.md +0 -0
  46. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/operate-datasets/resource-generation.md +0 -0
  47. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/operate-datasets/tags.md +0 -0
  48. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/operate-datasets/time-period.md +0 -0
  49. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/operate-datasets/update-frequency.md +0 -0
  50. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/operate-datasets/visualization.md +0 -0
  51. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/operate-resources/data-dictionary.md +0 -0
  52. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/operate-resources/datastore.md +0 -0
  53. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/operate-resources/resource-operations.md +0 -0
  54. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/organizations.md +0 -0
  55. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/pipeline-state.md +0 -0
  56. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/showcases.md +0 -0
  57. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/statistics.md +0 -0
  58. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/users.md +0 -0
  59. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/vocabularies.md +0 -0
  60. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/how-to/working-examples.md +0 -0
  61. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/index.md +0 -0
  62. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/mkdocs.yaml +0 -0
  63. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/reference/changelog.md +0 -0
  64. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/documentation/tutorials/getting-started.md +0 -0
  65. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/api/__init__.py +0 -0
  66. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/api/configuration.py +0 -0
  67. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/api/hdx_base_configuration.yaml +0 -0
  68. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/api/locations.py +0 -0
  69. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/api/remotehdx.py +0 -0
  70. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/api/utilities/__init__.py +0 -0
  71. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/api/utilities/date_helper.py +0 -0
  72. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/api/utilities/filestore_helper.py +0 -0
  73. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/api/utilities/hdx_error_handler.py +0 -0
  74. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/api/utilities/hdx_state.py +0 -0
  75. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/api/utilities/hdx_stats.py +0 -0
  76. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/api/utilities/url_utils.py +0 -0
  77. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/data/__init__.py +0 -0
  78. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/data/activity.py +0 -0
  79. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/data/hdxobject.py +0 -0
  80. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/data/location.py +0 -0
  81. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/data/organization.py +0 -0
  82. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/data/resource.py +0 -0
  83. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/data/resource_matcher.py +0 -0
  84. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/data/resource_view.py +0 -0
  85. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/data/showcase.py +0 -0
  86. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/data/user.py +0 -0
  87. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/data/vocabulary.py +0 -0
  88. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/facades/__init__.py +0 -0
  89. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/facades/infer_arguments.py +0 -0
  90. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/facades/keyword_arguments.py +0 -0
  91. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/src/hdx/facades/simple.py +0 -0
  92. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/__init__.py +0 -0
  93. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/Accepted_Tags.csv +0 -0
  94. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/CKAN/hdx_dataset_static.yaml +0 -0
  95. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/Tag_Mapping.csv +0 -0
  96. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/Tag_Mapping_ChainRuleError.csv +0 -0
  97. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/empty.yaml +0 -0
  98. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_base_config.json +0 -0
  99. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_base_config.yaml +0 -0
  100. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_config.json +0 -0
  101. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_config.yaml +0 -0
  102. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_dataset_static.json +0 -0
  103. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_dataset_static.yaml +0 -0
  104. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_datasource_topline.json +0 -0
  105. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_datasource_topline.yaml +0 -0
  106. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_email_configuration.json +0 -0
  107. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_email_configuration.yaml +0 -0
  108. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_missing_site_config.json +0 -0
  109. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_organization_static.json +0 -0
  110. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_organization_static.yaml +0 -0
  111. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_resource_static.json +0 -0
  112. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_resource_static.yaml +0 -0
  113. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_resource_view_static.json +0 -0
  114. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_resource_view_static.yaml +0 -0
  115. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_showcase_static.json +0 -0
  116. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_showcase_static.yaml +0 -0
  117. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_user_static.json +0 -0
  118. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_user_static.yaml +0 -0
  119. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_vocabulary_static.json +0 -0
  120. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/hdx_vocabulary_static.yaml +0 -0
  121. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/project_configuration.json +0 -0
  122. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/project_configuration.yaml +0 -0
  123. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/user_agent_config.yaml +0 -0
  124. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/user_agent_config2.yaml +0 -0
  125. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/user_agent_config3.yaml +0 -0
  126. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/config/user_agent_config_wrong.yaml +0 -0
  127. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/dataset_search_results.yaml +0 -0
  128. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/download_gen_resource/conflict_data_alg.csv +0 -0
  129. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/download_gen_resource/min_qc_conflict_data_alg.csv +0 -0
  130. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/download_gen_resource/qc_conflict_data_alg.csv +0 -0
  131. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/download_gen_resource/test_data_no_data.csv +0 -0
  132. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/download_gen_resource/test_data_no_years.csv +0 -0
  133. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/empty.csv +0 -0
  134. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/gen_resource/conflict_data_alg.csv +0 -0
  135. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/gen_resource/min_qc_conflict_data_alg.csv +0 -0
  136. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/gen_resource/qc_conflict_data_alg.csv +0 -0
  137. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/gen_resource/test_data_no_data.csv +0 -0
  138. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/gen_resource/test_data_no_years.csv +0 -0
  139. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/location/location_list_all_fields.yaml +0 -0
  140. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/location/location_show_results.yaml +0 -0
  141. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/organization/organization_list_all_fields.yaml +0 -0
  142. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/organization/organization_show_results.yaml +0 -0
  143. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/qc_from_rows/qc_conflict_data_alg.csv +0 -0
  144. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/qc_from_rows/qc_conflict_data_alg_one_col.csv +0 -0
  145. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/resource_formats.json +0 -0
  146. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/showcase_all_search_results.yaml +0 -0
  147. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/size_hash/ACLED-All-Africa-File_20170101-to-20170708.xlsx +0 -0
  148. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/state/analysis_dates.txt +0 -0
  149. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/state/last_build_date.txt +0 -0
  150. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/test_data.csv +0 -0
  151. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/test_data.zip +0 -0
  152. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/update_dataset_resources/dem_data_zwe.csv +0 -0
  153. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/update_dataset_resources/dem_indicatorlist_zwe.csv +0 -0
  154. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/update_dataset_resources/expected_resources_to_update.json +0 -0
  155. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/update_dataset_resources/opri_data_zwe.csv +0 -0
  156. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/update_dataset_resources/opri_indicatorlist_zwe.csv +0 -0
  157. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/update_dataset_resources/opri_metadata_zwe.csv +0 -0
  158. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/update_dataset_resources/qc_sdg_data_zwe.csv +0 -0
  159. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/update_dataset_resources/sdg_data_zwe.csv +0 -0
  160. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/update_dataset_resources/sdg_indicatorlist_zwe.csv +0 -0
  161. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/update_dataset_resources/sdg_metadata_zwe.csv +0 -0
  162. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/update_dataset_resources/unesco_dataset.json +0 -0
  163. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/update_dataset_resources/unesco_update_dataset.json +0 -0
  164. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/update_logic/update_logic_resources.yaml +0 -0
  165. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/fixtures/update_logic/update_logic_resources_new.yaml +0 -0
  166. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/__init__.py +0 -0
  167. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/api/__init__.py +0 -0
  168. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/api/test_locations.py +0 -0
  169. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/api/utilities/__init__.py +0 -0
  170. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/api/utilities/test_filestore_helper.py +0 -0
  171. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/api/utilities/test_hdx_error_handler.py +0 -0
  172. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/api/utilities/test_hdx_stats.py +0 -0
  173. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/api/utilities/test_url_utils.py +0 -0
  174. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/conftest.py +0 -0
  175. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/__init__.py +0 -0
  176. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/test_activity.py +0 -0
  177. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/test_dataset_add_hapi_error.py +0 -0
  178. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/data/test_location.py +0 -0
  179. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/facades/__init__.py +0 -0
  180. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/facades/test_infer_arguments.py +0 -0
  181. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/facades/test_keyword_arguments.py +0 -0
  182. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/tests/hdx/facades/test_simple.py +0 -0
  183. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/workingexample/my_code.py +0 -0
  184. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/workingexample/my_resource.csv +0 -0
  185. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/workingexample/my_resource.xlsx +0 -0
  186. {hdx_python_api-6.7.8 → hdx_python_api-6.7.9}/workingexample/run.py +0 -0
@@ -7,6 +7,9 @@ on:
7
7
  pull_request:
8
8
  branches-ignore: [gh-pages]
9
9
 
10
+ concurrency:
11
+ group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }}
12
+
10
13
  jobs:
11
14
  build:
12
15
  runs-on: ubuntu-latest
@@ -40,13 +43,12 @@ jobs:
40
43
 
41
44
  - name: Publish Unit Test Results
42
45
  uses: EnricoMi/publish-unit-test-result-action@7622c5bf3d112a72ab4fa3951c2aa5723d8ab92d # v2.25.0
43
- if: always()
46
+ if: (!cancelled())
44
47
  with:
45
48
  files: test-results.xml
46
49
 
47
50
  - name: Publish in Coveralls
48
51
  uses: coverallsapp/github-action@8d6379e14d29928660c4ba802d8e85393440b329 # v2.3.8
49
- if: always()
50
52
  with:
51
53
  flag-name: tests
52
54
  format: lcov
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: hdx-python-api
3
- Version: 6.7.8
3
+ Version: 6.7.9
4
4
  Summary: HDX Python API for interacting with the Humanitarian Data Exchange
5
5
  Project-URL: Homepage, https://github.com/OCHA-DAP/hdx-python-api
6
6
  Author: Michael Rans
@@ -27,8 +27,8 @@ Requires-Python: >=3.11
27
27
  Requires-Dist: ckanapi>=4.11
28
28
  Requires-Dist: defopt>=7.0.0
29
29
  Requires-Dist: email-validator
30
- Requires-Dist: hdx-python-country>=4.2.6
31
- Requires-Dist: hdx-python-utilities>=4.2.6
30
+ Requires-Dist: hdx-python-country>=4.3.1
31
+ Requires-Dist: hdx-python-utilities>=4.2.7
32
32
  Requires-Dist: makefun
33
33
  Requires-Dist: requests
34
34
  Provides-Extra: docs
@@ -38,8 +38,8 @@ dependencies = [
38
38
  "ckanapi>=4.11",
39
39
  "defopt>=7.0.0",
40
40
  "email_validator",
41
- "hdx-python-country>=4.2.6",
42
- "hdx-python-utilities>=4.2.6",
41
+ "hdx-python-country>=4.3.1",
42
+ "hdx-python-utilities>=4.2.7",
43
43
  "makefun",
44
44
  "requests",
45
45
  ]
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '6.7.8'
22
- __version_tuple__ = version_tuple = (6, 7, 8)
21
+ __version__ = version = '6.7.9'
22
+ __version_tuple__ = version_tuple = (6, 7, 9)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -667,21 +667,90 @@ class Dataset(HDXObject):
667
667
  if "batch_mode" not in kwargs:
668
668
  kwargs["batch_mode"] = "DONT_GROUP"
669
669
 
670
+ def _merge_list_fields(self, dataset_data_to_update: dict) -> list[str]:
671
+ """Merges each non-resource list in dataset_data_to_update with the
672
+ existing list of the same key (see _merge_list) in place.
673
+
674
+ Args:
675
+ dataset_data_to_update: Dataset data to be updated
676
+
677
+ Returns:
678
+ Keys whose merged list differs from the existing one
679
+ """
680
+ changed_keys = []
681
+ for key, value in dataset_data_to_update.items():
682
+ if (
683
+ key == "resources"
684
+ or not isinstance(value, list)
685
+ or key not in self._old_data
686
+ ):
687
+ continue
688
+ orig_list = self._old_data[key]
689
+ if not isinstance(orig_list, list):
690
+ orig_list = []
691
+ merged_list = self._merge_list(orig_list, value)
692
+ dataset_data_to_update[key] = merged_list
693
+ if merged_list != orig_list:
694
+ changed_keys.append(key)
695
+ return changed_keys
696
+
697
+ @staticmethod
698
+ def _merge_list(orig_list: list, new_list: list) -> list:
699
+ """Merges each dict in new_list that has an id or name with the dict in
700
+ orig_list with the same id (or failing that, name) so that fields not
701
+ given in new_list are kept. Other elements of new_list are kept as is.
702
+ Elements of orig_list that are not matched are dropped.
703
+
704
+ Args:
705
+ orig_list: Existing list
706
+ new_list: Updated list
707
+
708
+ Returns:
709
+ Merged list
710
+ """
711
+ merged_list = []
712
+ for new_value in new_list:
713
+ if not isinstance(new_value, dict):
714
+ merged_list.append(new_value)
715
+ continue
716
+ match = {}
717
+ for field in ("id", "name"):
718
+ field_value = new_value.get(field)
719
+ if not field_value:
720
+ continue
721
+ match = next(
722
+ (
723
+ orig_value
724
+ for orig_value in orig_list
725
+ if isinstance(orig_value, dict)
726
+ and orig_value.get(field) == field_value
727
+ ),
728
+ {},
729
+ )
730
+ if match:
731
+ break
732
+ merged_list.append(match | new_value)
733
+ return merged_list
734
+
670
735
  def _revise_filter(
671
736
  self,
672
- dataset_data_to_update: dict,
673
737
  keys_to_delete: Sequence[str],
674
738
  resources_to_delete: Sequence[int],
675
- ):
739
+ changed_list_keys: Sequence[str],
740
+ ) -> list[str]:
676
741
  """Returns the revise filter parameter adding to it any keys in the
677
- dataset metadata and resources that are specified to be deleted. Also compare
678
- lists in original and updated metadata to see if any have had elements
679
- removed in which case these should be added to the filter
742
+ dataset metadata and resources that are specified to be deleted. Keys
743
+ of changed lists are also added so that package_revise replaces those
744
+ lists rather than merging them by position (which keeps the existing
745
+ elements' ids eg. for groups).
680
746
 
681
747
  Args:
682
- dataset_data_to_update: Dataset data to be updated
683
748
  keys_to_delete: List of top level metadata keys to delete
684
749
  resources_to_delete: List of indexes of resources to delete
750
+ changed_list_keys: Keys of lists that differ from the existing ones
751
+
752
+ Returns:
753
+ Revise filter
685
754
  """
686
755
  revise_filter = []
687
756
  for key in keys_to_delete:
@@ -689,46 +758,9 @@ class Dataset(HDXObject):
689
758
  if not self.is_requestable():
690
759
  for resource_index in resources_to_delete:
691
760
  revise_filter.append(f"-resources__{resource_index}")
692
- for key, value in dataset_data_to_update.items():
693
- if not isinstance(value, list):
694
- continue
695
- if key not in self._old_data:
696
- continue
697
- orig_list = self._old_data[key]
698
- elements_to_remove = []
699
- for i, orig_value in enumerate(orig_list):
700
- if isinstance(orig_value, dict) and any(
701
- x in orig_value for x in ("id", "name")
702
- ):
703
- # Where lists have an id or name, we use one of those to
704
- # match elements and work out what needs to be deleted
705
- # ie. any elements in the original list that don't exist
706
- # in the updated list
707
- el_id = orig_value.get("id")
708
- el_name = orig_value.get("name")
709
- present = False
710
- for value_dict in value:
711
- if el_id and "id" in value_dict and value_dict["id"] == el_id:
712
- present = True
713
- break
714
- if (
715
- el_name
716
- and "name" in value_dict
717
- and value_dict["name"] == el_name
718
- ):
719
- present = True
720
- break
721
- if not present:
722
- elements_to_remove.append(i)
723
- elif orig_value not in value:
724
- # Otherwise we do a simple exact match of list elements
725
- # and delete any elements that are in the original list but
726
- # not in the updated list
727
- elements_to_remove.append(i)
728
- for element_index in reversed(elements_to_remove):
729
- del orig_list[element_index]
730
- if element_index == len(orig_list):
731
- revise_filter.append(f"-{key}__{element_index}")
761
+ for key in changed_list_keys:
762
+ if key not in keys_to_delete:
763
+ revise_filter.append(f"-{key}")
732
764
  return revise_filter
733
765
 
734
766
  def _revise_files_to_upload_resource_deletions(
@@ -806,8 +838,9 @@ class Dataset(HDXObject):
806
838
  ): # Whether or not CKAN should perform validation steps (checking fields present)
807
839
  dataset_data_to_update["skip_validation"] = kwargs["skip_validation"]
808
840
  dataset_data_to_update["state"] = "active"
841
+ changed_list_keys = self._merge_list_fields(dataset_data_to_update)
809
842
  revise_filter = self._revise_filter(
810
- dataset_data_to_update, keys_to_delete, resources_to_delete
843
+ keys_to_delete, resources_to_delete, changed_list_keys
811
844
  )
812
845
  files_to_upload = self._revise_files_to_upload_resource_deletions(
813
846
  resources_to_update,
@@ -1048,8 +1081,8 @@ class Dataset(HDXObject):
1048
1081
  **kwargs,
1049
1082
  )
1050
1083
  keep_crisis_tags = kwargs.get("keep_crisis_tags", True)
1051
- if keep_crisis_tags:
1052
- old_tags = self._old_data.get("tags", [])
1084
+ if keep_crisis_tags and "tags" in self._old_data:
1085
+ old_tags = self._old_data["tags"]
1053
1086
  for tag in self.data.get("tags", []):
1054
1087
  tag_name = tag["name"]
1055
1088
  if tag_name[:7] != "crisis-":
@@ -1061,7 +1094,6 @@ class Dataset(HDXObject):
1061
1094
  break
1062
1095
  if not found:
1063
1096
  old_tags.append(tag)
1064
- self._old_data["tags"] = old_tags
1065
1097
  self._prepare_hdx_call(self._old_data, kwargs)
1066
1098
  revise_call = self._revise_dataset(
1067
1099
  allow_no_resources,
@@ -29,7 +29,8 @@ logger = logging.getLogger(__name__)
29
29
 
30
30
  class TestCKAN:
31
31
  @pytest.fixture(scope="class")
32
- def configuration(self):
32
+ @classmethod
33
+ def configuration(cls):
33
34
  hdx_key = getenv("HDX_KEY_TEST")
34
35
  Configuration._create(
35
36
  hdx_site="demo",
@@ -47,7 +48,8 @@ class TestCKAN:
47
48
  return fixturesfolder / "CKAN" / "hdx_dataset_static.yaml"
48
49
 
49
50
  @pytest.fixture(scope="class")
50
- def params(self):
51
+ @classmethod
52
+ def params(cls):
51
53
  return {
52
54
  "corpora": "teamDrive",
53
55
  "teamDriveId": "0AKCBfHI3H-hcUk9PVA",
@@ -11,39 +11,48 @@ from hdx.api.remotehdx import RemoteHDX
11
11
 
12
12
  class TestConfiguration:
13
13
  @pytest.fixture(scope="class")
14
- def hdx_base_config_yaml(self, configfolder):
14
+ @classmethod
15
+ def hdx_base_config_yaml(cls, configfolder):
15
16
  return configfolder / "hdx_base_config.yaml"
16
17
 
17
18
  @pytest.fixture(scope="class")
18
- def hdx_base_config_json(self, configfolder):
19
+ @classmethod
20
+ def hdx_base_config_json(cls, configfolder):
19
21
  return configfolder / "hdx_base_config.json"
20
22
 
21
23
  @pytest.fixture(scope="class")
22
- def hdx_missing_site_config_json(self, configfolder):
24
+ @classmethod
25
+ def hdx_missing_site_config_json(cls, configfolder):
23
26
  return configfolder / "hdx_missing_site_config.json"
24
27
 
25
28
  @pytest.fixture(scope="class")
26
- def project_config_json(self, configfolder):
29
+ @classmethod
30
+ def project_config_json(cls, configfolder):
27
31
  return configfolder / "project_configuration.json"
28
32
 
29
33
  @pytest.fixture(scope="class")
30
- def user_agent_config_yaml(self, configfolder):
34
+ @classmethod
35
+ def user_agent_config_yaml(cls, configfolder):
31
36
  return configfolder / "user_agent_config.yaml"
32
37
 
33
38
  @pytest.fixture(scope="class")
34
- def user_agent_config2_yaml(self, configfolder):
39
+ @classmethod
40
+ def user_agent_config2_yaml(cls, configfolder):
35
41
  return configfolder / "user_agent_config2.yaml"
36
42
 
37
43
  @pytest.fixture(scope="class")
38
- def user_agent_config3_yaml(self, configfolder):
44
+ @classmethod
45
+ def user_agent_config3_yaml(cls, configfolder):
39
46
  return configfolder / "user_agent_config3.yaml"
40
47
 
41
48
  @pytest.fixture(scope="class")
42
- def empty_yaml(self, configfolder):
49
+ @classmethod
50
+ def empty_yaml(cls, configfolder):
43
51
  return configfolder / "empty.yaml"
44
52
 
45
53
  @pytest.fixture(scope="class")
46
- def user_agent_config_wrong_yaml(self, configfolder):
54
+ @classmethod
55
+ def user_agent_config_wrong_yaml(cls, configfolder):
47
56
  return configfolder / "user_agent_config_wrong.yaml"
48
57
 
49
58
  def test_init(
@@ -20,27 +20,33 @@ from hdx.api.utilities.hdx_state import HDXState
20
20
 
21
21
  class TestState:
22
22
  @pytest.fixture(scope="class")
23
- def tempfolder(self):
23
+ @classmethod
24
+ def tempfolder(cls):
24
25
  return Path(gettempdir(), "test_state")
25
26
 
26
27
  @pytest.fixture(scope="class")
27
- def statefolder(self, fixturesfolder):
28
+ @classmethod
29
+ def statefolder(cls, fixturesfolder):
28
30
  return fixturesfolder / "state"
29
31
 
30
32
  @pytest.fixture(scope="class")
31
- def statefile(self):
33
+ @classmethod
34
+ def statefile(cls):
32
35
  return "last_build_date.txt"
33
36
 
34
37
  @pytest.fixture(scope="class")
35
- def multidatestatefile(self):
38
+ @classmethod
39
+ def multidatestatefile(cls):
36
40
  return "analysis_dates.txt"
37
41
 
38
42
  @pytest.fixture(scope="class")
39
- def date1(self):
43
+ @classmethod
44
+ def date1(cls):
40
45
  return datetime(2020, 9, 23, 0, 0, tzinfo=UTC)
41
46
 
42
47
  @pytest.fixture(scope="class")
43
- def date2(self):
48
+ @classmethod
49
+ def date2(cls):
44
50
  return datetime(2022, 5, 12, 10, 15, tzinfo=UTC)
45
51
 
46
52
  @pytest.fixture(scope="function")
@@ -171,11 +171,13 @@ def mockall(url, datadict):
171
171
 
172
172
  class TestDatasetCore:
173
173
  @pytest.fixture(scope="class")
174
- def static_yaml(self, configfolder):
174
+ @classmethod
175
+ def static_yaml(cls, configfolder):
175
176
  return configfolder / "hdx_dataset_static.yaml"
176
177
 
177
178
  @pytest.fixture(scope="class")
178
- def static_json(self, configfolder):
179
+ @classmethod
180
+ def static_json(cls, configfolder):
179
181
  return configfolder / "hdx_dataset_static.json"
180
182
 
181
183
  @pytest.fixture(scope="function")
@@ -55,7 +55,8 @@ class TestDatasetNoncore:
55
55
  association = None
56
56
 
57
57
  @pytest.fixture(scope="class")
58
- def static_resource_view_yaml(self, configfolder):
58
+ @classmethod
59
+ def static_resource_view_yaml(cls, configfolder):
59
60
  return configfolder / "hdx_resource_view_static.yaml"
60
61
 
61
62
  @pytest.fixture(scope="function")
@@ -13,7 +13,7 @@ from hdx.data.hdxobject import HDXError
13
13
 
14
14
 
15
15
  class TestDatasetResourceGeneration:
16
- url = "https://raw.githubusercontent.com/OCHA-DAP/hdx-python-api/main/tests/fixtures/test_data.csv"
16
+ url = "tests/fixtures/test_data.csv"
17
17
 
18
18
  def test_download_generate_resource(self, configuration, fixturesfolder):
19
19
  with temp_dir("test") as folder:
@@ -462,7 +462,7 @@ class TestDatasetResourceGeneration:
462
462
  row_function=process_row,
463
463
  )
464
464
  assert success is True
465
- url = "https://raw.githubusercontent.com/OCHA-DAP/hdx-python-api/main/tests/fixtures/empty.csv"
465
+ url = "tests/fixtures/empty.csv"
466
466
  success, results = dataset.download_generate_resource(
467
467
  downloader,
468
468
  url,
@@ -474,7 +474,7 @@ class TestDatasetResourceGeneration:
474
474
  yearcol="YEAR",
475
475
  )
476
476
  assert success is False
477
- url = "https://raw.githubusercontent.com/OCHA-DAP/hdx-python-api/main/tests/fixtures/gen_resource/test_data_no_data.csv"
477
+ url = "tests/fixtures/gen_resource/test_data_no_data.csv"
478
478
  success, results = dataset.download_generate_resource(
479
479
  downloader,
480
480
  url,
@@ -502,7 +502,7 @@ class TestDatasetResourceGeneration:
502
502
  row_function=process_row,
503
503
  )
504
504
  assert success is False
505
- url = "https://raw.githubusercontent.com/OCHA-DAP/hdx-python-api/main/tests/fixtures/gen_resource/test_data_no_years.csv"
505
+ url = "tests/fixtures/gen_resource/test_data_no_years.csv"
506
506
  success, results = dataset.download_generate_resource(
507
507
  downloader,
508
508
  url,
@@ -104,11 +104,13 @@ def mockgetdatasets(url, datadict):
104
104
 
105
105
  class TestOrganization:
106
106
  @pytest.fixture(scope="class")
107
- def static_yaml(self, configfolder):
107
+ @classmethod
108
+ def static_yaml(cls, configfolder):
108
109
  return configfolder / "hdx_organization_static.yaml"
109
110
 
110
111
  @pytest.fixture(scope="class")
111
- def static_json(self, configfolder):
112
+ @classmethod
113
+ def static_json(cls, configfolder):
112
114
  return configfolder / "hdx_organization_static.json"
113
115
 
114
116
  @pytest.fixture(scope="function")
@@ -344,19 +344,23 @@ class TestResource:
344
344
  datastore_rows_max = None
345
345
 
346
346
  @pytest.fixture(scope="class")
347
- def static_yaml(self, configfolder):
347
+ @classmethod
348
+ def static_yaml(cls, configfolder):
348
349
  return configfolder / "hdx_resource_static.yaml"
349
350
 
350
351
  @pytest.fixture(scope="class")
351
- def static_json(self, configfolder):
352
+ @classmethod
353
+ def static_json(cls, configfolder):
352
354
  return configfolder / "hdx_resource_static.json"
353
355
 
354
356
  @pytest.fixture(scope="class")
355
- def topline_yaml(self, configfolder):
357
+ @classmethod
358
+ def topline_yaml(cls, configfolder):
356
359
  return configfolder / "hdx_datasource_topline.yaml"
357
360
 
358
361
  @pytest.fixture(scope="class")
359
- def topline_json(self, configfolder):
362
+ @classmethod
363
+ def topline_json(cls, configfolder):
360
364
  return configfolder / "hdx_datasource_topline.json"
361
365
 
362
366
  @pytest.fixture(scope="function")
@@ -126,11 +126,13 @@ class TestResourceView:
126
126
  }
127
127
 
128
128
  @pytest.fixture(scope="class")
129
- def static_yaml(self, configfolder):
129
+ @classmethod
130
+ def static_yaml(cls, configfolder):
130
131
  return configfolder / "hdx_resource_view_static.yaml"
131
132
 
132
133
  @pytest.fixture(scope="class")
133
- def static_json(self, configfolder):
134
+ @classmethod
135
+ def static_json(cls, configfolder):
134
136
  return configfolder / "hdx_resource_view_static.json"
135
137
 
136
138
  @pytest.fixture(scope="function")
@@ -175,11 +175,13 @@ class TestShowcase:
175
175
  association = None
176
176
 
177
177
  @pytest.fixture(scope="class")
178
- def static_yaml(self, configfolder):
178
+ @classmethod
179
+ def static_yaml(cls, configfolder):
179
180
  return configfolder / "hdx_showcase_static.yaml"
180
181
 
181
182
  @pytest.fixture(scope="class")
182
- def static_json(self, configfolder):
183
+ @classmethod
184
+ def static_json(cls, configfolder):
183
185
  return configfolder / "hdx_showcase_static.json"
184
186
 
185
187
  @pytest.fixture(scope="function")
@@ -51,19 +51,23 @@ class TestUpdateDatasetResourcesLogic:
51
51
  }
52
52
 
53
53
  @pytest.fixture(scope="class")
54
- def fixture_path(self, fixturesfolder):
54
+ @classmethod
55
+ def fixture_path(cls, fixturesfolder):
55
56
  return fixturesfolder / "update_dataset_resources"
56
57
 
57
58
  @pytest.fixture(scope="class")
58
- def new_dataset_json(self, fixture_path):
59
+ @classmethod
60
+ def new_dataset_json(cls, fixture_path):
59
61
  return fixture_path / "unesco_update_dataset.json"
60
62
 
61
63
  @pytest.fixture(scope="class")
62
- def dataset_json(self, fixture_path):
64
+ @classmethod
65
+ def dataset_json(cls, fixture_path):
63
66
  return fixture_path / "unesco_dataset.json"
64
67
 
65
68
  @pytest.fixture(scope="class")
66
- def expected_resources_to_update_json(self, fixture_path):
69
+ @classmethod
70
+ def expected_resources_to_update_json(cls, fixture_path):
67
71
  return fixture_path / "expected_resources_to_update.json"
68
72
 
69
73
  @pytest.fixture(scope="function")
@@ -84,7 +88,8 @@ class TestUpdateDatasetResourcesLogic:
84
88
  return dataset
85
89
 
86
90
  @pytest.fixture(scope="class")
87
- def expected_resources_to_update(self, expected_resources_to_update_json):
91
+ @classmethod
92
+ def expected_resources_to_update(cls, expected_resources_to_update_json):
88
93
  return load_json(expected_resources_to_update_json)
89
94
 
90
95
  def test_dataset_update_resources(
@@ -42,23 +42,28 @@ class TestUpdateLogic:
42
42
  }
43
43
 
44
44
  @pytest.fixture(scope="class")
45
- def fixture_path(self, fixturesfolder):
45
+ @classmethod
46
+ def fixture_path(cls, fixturesfolder):
46
47
  return fixturesfolder / "update_logic"
47
48
 
48
49
  @pytest.fixture(scope="class")
49
- def temp_dir(self):
50
+ @classmethod
51
+ def temp_dir(cls):
50
52
  return get_temp_dir("WHO", delete_if_exists=True)
51
53
 
52
54
  @pytest.fixture(scope="class")
53
- def new_resources_yaml(self, fixture_path):
55
+ @classmethod
56
+ def new_resources_yaml(cls, fixture_path):
54
57
  return fixture_path / "update_logic_resources_new.yaml"
55
58
 
56
59
  @pytest.fixture(scope="class")
57
- def resources_yaml(self, fixture_path):
60
+ @classmethod
61
+ def resources_yaml(cls, fixture_path):
58
62
  return fixture_path / "update_logic_resources.yaml"
59
63
 
60
64
  @pytest.fixture(scope="class")
61
- def dataset_data(self):
65
+ @classmethod
66
+ def dataset_data(cls):
62
67
  return {
63
68
  "name": "who-data-for-zambia",
64
69
  "title": "Zambia - Health Indicators",
@@ -158,6 +163,50 @@ class TestUpdateLogic:
158
163
  f'Mismatch at index {index}: "{rn}", file to upload is "{fu}"'
159
164
  )
160
165
 
166
+ def test_revise_filter_lists(self, configuration, dataset):
167
+ # HDX returns list elements with ids. package_revise merges an update
168
+ # list into the existing one by position and CKAN looks up groups by
169
+ # id before name, so changed lists must be filtered out and replaced
170
+ dataset._old_data = {
171
+ "groups": [
172
+ {"id": "afg-id", "name": "afg", "title": "Afghanistan"},
173
+ {"id": "zmb-id", "name": "zmb", "title": "Zambia"},
174
+ ],
175
+ "tags": [{"id": "tag-id", "name": "health"}],
176
+ "customviz": [{"url": "a", "extra": 1}],
177
+ "solr_additions": None,
178
+ "notes": "old notes",
179
+ }
180
+ dataset_data_to_update = {
181
+ "groups": [{"name": "nru"}, {"name": "zmb"}, {"name": "vut"}],
182
+ "tags": [{"name": "health"}],
183
+ "customviz": [{"url": "b"}],
184
+ "solr_additions": [{"name": "x"}],
185
+ "notes": "new notes",
186
+ }
187
+ changed_list_keys = dataset._merge_list_fields(dataset_data_to_update)
188
+ assert changed_list_keys == ["groups", "customviz", "solr_additions"]
189
+ revise_filter = dataset._revise_filter(["notes"], [], changed_list_keys)
190
+ assert revise_filter == ["-notes", "-groups", "-customviz", "-solr_additions"]
191
+ revise_filter = dataset._revise_filter(["groups"], [], changed_list_keys)
192
+ assert revise_filter == ["-groups", "-customviz", "-solr_additions"]
193
+ assert dataset_data_to_update["groups"] == [
194
+ {"name": "nru"},
195
+ {"id": "zmb-id", "name": "zmb", "title": "Zambia"},
196
+ {"name": "vut"},
197
+ ]
198
+ assert dataset_data_to_update["tags"] == [{"id": "tag-id", "name": "health"}]
199
+ assert dataset_data_to_update["customviz"] == [{"url": "b"}]
200
+ assert dataset_data_to_update["solr_additions"] == [{"name": "x"}]
201
+
202
+ def test_merge_list_id_before_name(self):
203
+ orig_list = [
204
+ {"id": "1", "name": "x", "f": "A"},
205
+ {"id": "2", "name": "y", "f": "B"},
206
+ ]
207
+ merged_list = Dataset._merge_list(orig_list, [{"id": "2", "name": "x"}])
208
+ assert merged_list == [{"id": "2", "name": "x", "f": "B"}]
209
+
161
210
  def test_update_logic_1(
162
211
  self,
163
212
  configuration,
@@ -863,7 +912,6 @@ class TestUpdateLogic:
863
912
  ],
864
913
  "state": "active",
865
914
  "subnational": "0",
866
- "tags": [],
867
915
  "title": "Zambia - Health Indicators",
868
916
  }
869
917
  self.check_resources(update, results)
@@ -1573,7 +1621,6 @@ class TestUpdateLogic:
1573
1621
  ],
1574
1622
  "state": "active",
1575
1623
  "subnational": "0",
1576
- "tags": [],
1577
1624
  "title": "Zambia - Health Indicators",
1578
1625
  }
1579
1626
  self.check_resources(update, results)
@@ -1649,7 +1696,6 @@ class TestUpdateLogic:
1649
1696
  ],
1650
1697
  "state": "active",
1651
1698
  "subnational": "0",
1652
- "tags": [],
1653
1699
  "title": "Zambia - Health Indicators",
1654
1700
  }
1655
1701
  self.check_resources(update, results)