hdx-python-api 6.5.4__tar.gz → 6.5.6__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 (150) hide show
  1. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/.github/workflows/publish.yaml +2 -2
  2. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/.github/workflows/run-python-tests.yaml +2 -2
  3. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/PKG-INFO +2 -2
  4. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/documentation/index.md +7 -0
  5. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/pyproject.toml +1 -1
  6. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/requirements.txt +15 -15
  7. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/api/_version.py +2 -2
  8. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/data/dataset.py +11 -10
  9. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/data/resource.py +61 -4
  10. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/data/test_resource.py +62 -4
  11. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/.coveragerc +0 -0
  12. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/.gitignore +0 -0
  13. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/.pre-commit-config.yaml +0 -0
  14. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/CONTRIBUTING.md +0 -0
  15. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/LICENSE +0 -0
  16. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/README.md +0 -0
  17. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/documentation/.readthedocs.yaml +0 -0
  18. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/documentation/mkdocs.yaml +0 -0
  19. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/hatch.toml +0 -0
  20. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/pytest.ini +0 -0
  21. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/ruff.toml +0 -0
  22. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/api/__init__.py +0 -0
  23. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/api/configuration.py +0 -0
  24. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/api/hdx_base_configuration.yaml +0 -0
  25. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/api/locations.py +0 -0
  26. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/api/remotehdx.py +0 -0
  27. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/api/utilities/__init__.py +0 -0
  28. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/api/utilities/dataset_title_helper.py +0 -0
  29. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/api/utilities/date_helper.py +0 -0
  30. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/api/utilities/filestore_helper.py +0 -0
  31. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/api/utilities/hdx_error_handler.py +0 -0
  32. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/api/utilities/hdx_state.py +0 -0
  33. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/api/utilities/size_hash.py +0 -0
  34. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/data/__init__.py +0 -0
  35. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/data/hdx_datasource_topline.yaml +0 -0
  36. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/data/hdxobject.py +0 -0
  37. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/data/indicator_resource_view_template.yaml +0 -0
  38. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/data/organization.py +0 -0
  39. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/data/resource_matcher.py +0 -0
  40. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/data/resource_view.py +0 -0
  41. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/data/showcase.py +0 -0
  42. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/data/user.py +0 -0
  43. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/data/vocabulary.py +0 -0
  44. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/facades/__init__.py +0 -0
  45. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/facades/infer_arguments.py +0 -0
  46. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/facades/keyword_arguments.py +0 -0
  47. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/src/hdx/facades/simple.py +0 -0
  48. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/__init__.py +0 -0
  49. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/Accepted_Tags.csv +0 -0
  50. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/CKAN/hdx_dataset_static.yaml +0 -0
  51. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/Tag_Mapping.csv +0 -0
  52. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/Tag_Mapping_ChainRuleError.csv +0 -0
  53. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/empty.yaml +0 -0
  54. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_base_config.json +0 -0
  55. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_base_config.yaml +0 -0
  56. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_config.json +0 -0
  57. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_config.yaml +0 -0
  58. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_dataset_static.json +0 -0
  59. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_dataset_static.yaml +0 -0
  60. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_datasource_topline.json +0 -0
  61. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_datasource_topline.yaml +0 -0
  62. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_email_configuration.json +0 -0
  63. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_email_configuration.yaml +0 -0
  64. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_missing_site_config.json +0 -0
  65. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_organization_static.json +0 -0
  66. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_organization_static.yaml +0 -0
  67. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_resource_static.json +0 -0
  68. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_resource_static.yaml +0 -0
  69. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_resource_view_static.json +0 -0
  70. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_resource_view_static.yaml +0 -0
  71. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_showcase_static.json +0 -0
  72. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_showcase_static.yaml +0 -0
  73. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_user_static.json +0 -0
  74. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_user_static.yaml +0 -0
  75. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_vocabulary_static.json +0 -0
  76. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/hdx_vocabulary_static.yaml +0 -0
  77. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/project_configuration.json +0 -0
  78. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/project_configuration.yaml +0 -0
  79. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/user_agent_config.yaml +0 -0
  80. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/user_agent_config2.yaml +0 -0
  81. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/user_agent_config3.yaml +0 -0
  82. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/config/user_agent_config_wrong.yaml +0 -0
  83. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/dataset_search_results.yaml +0 -0
  84. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/download_gen_resource/conflict_data_alg.csv +0 -0
  85. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/download_gen_resource/min_qc_conflict_data_alg.csv +0 -0
  86. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/download_gen_resource/qc_conflict_data_alg.csv +0 -0
  87. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/download_gen_resource/test_data_no_data.csv +0 -0
  88. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/download_gen_resource/test_data_no_years.csv +0 -0
  89. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/empty.csv +0 -0
  90. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/gen_resource/conflict_data_alg.csv +0 -0
  91. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/gen_resource/min_qc_conflict_data_alg.csv +0 -0
  92. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/gen_resource/qc_conflict_data_alg.csv +0 -0
  93. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/gen_resource/test_data_no_data.csv +0 -0
  94. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/gen_resource/test_data_no_years.csv +0 -0
  95. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/organization_show_results.yaml +0 -0
  96. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/qc_from_rows/qc_conflict_data_alg.csv +0 -0
  97. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/qc_from_rows/qc_conflict_data_alg_one_col.csv +0 -0
  98. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/resource_formats.json +0 -0
  99. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/showcase_all_search_results.yaml +0 -0
  100. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/size_hash/ACLED-All-Africa-File_20170101-to-20170708.xlsx +0 -0
  101. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/state/analysis_dates.txt +0 -0
  102. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/state/last_build_date.txt +0 -0
  103. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/test_data.csv +0 -0
  104. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/test_data.zip +0 -0
  105. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/update_dataset_resources/dem_data_zwe.csv +0 -0
  106. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/update_dataset_resources/dem_indicatorlist_zwe.csv +0 -0
  107. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/update_dataset_resources/expected_resources_to_update.json +0 -0
  108. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/update_dataset_resources/opri_data_zwe.csv +0 -0
  109. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/update_dataset_resources/opri_indicatorlist_zwe.csv +0 -0
  110. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/update_dataset_resources/opri_metadata_zwe.csv +0 -0
  111. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/update_dataset_resources/qc_sdg_data_zwe.csv +0 -0
  112. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/update_dataset_resources/sdg_data_zwe.csv +0 -0
  113. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/update_dataset_resources/sdg_indicatorlist_zwe.csv +0 -0
  114. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/update_dataset_resources/sdg_metadata_zwe.csv +0 -0
  115. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/update_dataset_resources/unesco_dataset.json +0 -0
  116. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/update_dataset_resources/unesco_update_dataset.json +0 -0
  117. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/update_logic/update_logic_resources.yaml +0 -0
  118. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/fixtures/update_logic/update_logic_resources_new.yaml +0 -0
  119. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/__init__.py +0 -0
  120. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/api/__init__.py +0 -0
  121. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/api/test_ckan.py +0 -0
  122. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/api/test_configuration.py +0 -0
  123. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/api/test_locations.py +0 -0
  124. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/api/utilities/__init__.py +0 -0
  125. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/api/utilities/test_dataset_title_helper.py +0 -0
  126. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/api/utilities/test_filestore_helper.py +0 -0
  127. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/api/utilities/test_hdx_error_handler.py +0 -0
  128. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/api/utilities/test_hdx_state.py +0 -0
  129. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/api/utilities/test_size_hash.py +0 -0
  130. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/conftest.py +0 -0
  131. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/data/__init__.py +0 -0
  132. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/data/test_dataset_add_hapi_error.py +0 -0
  133. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/data/test_dataset_core.py +0 -0
  134. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/data/test_dataset_noncore.py +0 -0
  135. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/data/test_dataset_resource_generation.py +0 -0
  136. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/data/test_organization.py +0 -0
  137. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/data/test_resource_view.py +0 -0
  138. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/data/test_showcase.py +0 -0
  139. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/data/test_update_dataset_resources.py +0 -0
  140. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/data/test_update_logic.py +0 -0
  141. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/data/test_user.py +0 -0
  142. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/data/test_vocabulary.py +0 -0
  143. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/facades/__init__.py +0 -0
  144. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/facades/test_infer_arguments.py +0 -0
  145. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/facades/test_keyword_arguments.py +0 -0
  146. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/tests/hdx/facades/test_simple.py +0 -0
  147. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/workingexample/my_code.py +0 -0
  148. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/workingexample/my_resource.csv +0 -0
  149. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/workingexample/my_resource.xlsx +0 -0
  150. {hdx_python_api-6.5.4 → hdx_python_api-6.5.6}/workingexample/run.py +0 -0
@@ -16,13 +16,13 @@ jobs:
16
16
  id-token: write # IMPORTANT: mandatory for trusted publishing
17
17
 
18
18
  steps:
19
- - uses: actions/checkout@v4
19
+ - uses: actions/checkout@v6
20
20
  - name: Get history and tags for versioning to work
21
21
  run: |
22
22
  git fetch --prune --unshallow
23
23
  git fetch --depth=1 origin +refs/tags/*:refs/tags/*
24
24
  - name: Set up Python
25
- uses: actions/setup-python@v5
25
+ uses: actions/setup-python@v6
26
26
  with:
27
27
  python-version: '3.x'
28
28
  - name: Install dependencies
@@ -26,9 +26,9 @@ jobs:
26
26
  pull-requests: write
27
27
 
28
28
  steps:
29
- - uses: actions/checkout@v4
29
+ - uses: actions/checkout@v6
30
30
  - name: Set up Python
31
- uses: actions/setup-python@v5
31
+ uses: actions/setup-python@v6
32
32
  with:
33
33
  python-version: '3.x'
34
34
  - name: Install dependencies
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hdx-python-api
3
- Version: 6.5.4
3
+ Version: 6.5.6
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
@@ -29,7 +29,7 @@ Requires-Dist: ckanapi>=4.8
29
29
  Requires-Dist: defopt>=7.0.0
30
30
  Requires-Dist: email-validator
31
31
  Requires-Dist: hdx-python-country>=3.9.8
32
- Requires-Dist: hdx-python-utilities>=3.9.5
32
+ Requires-Dist: hdx-python-utilities>=3.9.6
33
33
  Requires-Dist: libhxl>=5.2.2
34
34
  Requires-Dist: makefun
35
35
  Requires-Dist: quantulum3
@@ -899,6 +899,13 @@ The built-in configuration assumes data will be of form similar to below:
899
899
 
900
900
  ## Resource Specific Operations
901
901
 
902
+ When creating or updating a resource that doesn't have an id, if you supply a parameter
903
+ dataset, then the resource will be assigned to that dataset and it will be compared to
904
+ resources in that dataset. If a match is found, then the resource will be given the
905
+ corresponding id and that resource on HDX will be overwritten.
906
+
907
+ resource.create_in_hdx(dataset=DATASET)
908
+
902
909
  You can download a resource using the **download** function eg.
903
910
 
904
911
  url, path = resource.download("FOLDER_TO_DOWNLOAD_TO")
@@ -38,7 +38,7 @@ dependencies = [
38
38
  "defopt>=7.0.0",
39
39
  "email_validator",
40
40
  "hdx-python-country>=3.9.8",
41
- "hdx-python-utilities>=3.9.5",
41
+ "hdx-python-utilities>=3.9.6",
42
42
  "libhxl>=5.2.2",
43
43
  "makefun",
44
44
  "quantulum3",
@@ -14,11 +14,11 @@ babel==2.17.0
14
14
  # via mkdocs-material
15
15
  backrefs==6.1
16
16
  # via mkdocs-material
17
- cachetools==6.2.2
17
+ cachetools==6.2.4
18
18
  # via google-auth
19
19
  certifi==2025.11.12
20
20
  # via requests
21
- cfgv==3.4.0
21
+ cfgv==3.5.0
22
22
  # via pre-commit
23
23
  chardet==5.2.0
24
24
  # via frictionless
@@ -32,7 +32,7 @@ click==8.3.1
32
32
  # typer
33
33
  colorama==0.4.6
34
34
  # via mkdocs-material
35
- coverage==7.12.0
35
+ coverage==7.13.0
36
36
  # via pytest-cov
37
37
  defopt==7.0.0
38
38
  # via hdx-python-api (pyproject.toml)
@@ -50,13 +50,13 @@ email-validator==2.3.0
50
50
  # via hdx-python-api (pyproject.toml)
51
51
  et-xmlfile==2.0.0
52
52
  # via openpyxl
53
- filelock==3.20.0
53
+ filelock==3.20.1
54
54
  # via virtualenv
55
55
  frictionless==5.18.1
56
56
  # via hdx-python-utilities
57
57
  ghp-import==2.1.0
58
58
  # via mkdocs
59
- google-auth==2.43.0
59
+ google-auth==2.45.0
60
60
  # via
61
61
  # google-auth-oauthlib
62
62
  # gspread
@@ -66,7 +66,7 @@ gspread==6.2.1
66
66
  # via hdx-python-api (pyproject.toml)
67
67
  hdx-python-country==3.9.8
68
68
  # via hdx-python-api (pyproject.toml)
69
- hdx-python-utilities==3.9.5
69
+ hdx-python-utilities==3.9.6
70
70
  # via
71
71
  # hdx-python-api (pyproject.toml)
72
72
  # hdx-python-country
@@ -161,7 +161,7 @@ pathspec==0.12.1
161
161
  # via mkdocs
162
162
  petl==1.7.17
163
163
  # via frictionless
164
- platformdirs==4.5.0
164
+ platformdirs==4.5.1
165
165
  # via
166
166
  # mkdocs-get-deps
167
167
  # virtualenv
@@ -175,7 +175,7 @@ ply==3.11
175
175
  # libhxl
176
176
  pockets==0.9.1
177
177
  # via sphinxcontrib-napoleon
178
- pre-commit==4.4.0
178
+ pre-commit==4.5.1
179
179
  # via hdx-python-api (pyproject.toml)
180
180
  pyasn1==0.6.1
181
181
  # via
@@ -183,7 +183,7 @@ pyasn1==0.6.1
183
183
  # rsa
184
184
  pyasn1-modules==0.4.2
185
185
  # via google-auth
186
- pydantic==2.12.4
186
+ pydantic==2.12.5
187
187
  # via frictionless
188
188
  pydantic-core==2.41.5
189
189
  # via pydantic
@@ -192,16 +192,16 @@ pygments==2.19.2
192
192
  # mkdocs-material
193
193
  # pytest
194
194
  # rich
195
- pymdown-extensions==10.17.1
195
+ pymdown-extensions==10.19.1
196
196
  # via mkdocs-material
197
197
  pyphonetics==0.5.3
198
198
  # via hdx-python-utilities
199
- pytest==9.0.1
199
+ pytest==9.0.2
200
200
  # via
201
201
  # hdx-python-api (pyproject.toml)
202
202
  # pytest-check
203
203
  # pytest-cov
204
- pytest-check==2.6.0
204
+ pytest-check==2.6.2
205
205
  # via hdx-python-api (pyproject.toml)
206
206
  pytest-cov==7.0.0
207
207
  # via hdx-python-api (pyproject.toml)
@@ -253,13 +253,13 @@ rfc3986==2.0.0
253
253
  # via frictionless
254
254
  rich==14.2.0
255
255
  # via typer
256
- rpds-py==0.29.0
256
+ rpds-py==0.30.0
257
257
  # via
258
258
  # jsonschema
259
259
  # referencing
260
260
  rsa==4.9.1
261
261
  # via google-auth
262
- ruamel-yaml==0.18.16
262
+ ruamel-yaml==0.18.17
263
263
  # via hdx-python-utilities
264
264
  ruamel-yaml-clib==0.2.15
265
265
  # via ruamel-yaml
@@ -307,7 +307,7 @@ unidecode==1.4.0
307
307
  # via
308
308
  # libhxl
309
309
  # pyphonetics
310
- urllib3==2.5.0
310
+ urllib3==2.6.2
311
311
  # via
312
312
  # libhxl
313
313
  # requests
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '6.5.4'
32
- __version_tuple__ = version_tuple = (6, 5, 4)
31
+ __version__ = version = '6.5.6'
32
+ __version_tuple__ = version_tuple = (6, 5, 6)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -278,7 +278,7 @@ class Dataset(HDXObject):
278
278
  self,
279
279
  resource: Union["Resource", Dict, str],
280
280
  ignore_datasetid: bool = False,
281
- ) -> None:
281
+ ) -> "Resource":
282
282
  """Add new or update existing resource in dataset with new metadata
283
283
 
284
284
  Args:
@@ -286,7 +286,7 @@ class Dataset(HDXObject):
286
286
  ignore_datasetid (bool): Whether to ignore dataset id in the resource
287
287
 
288
288
  Returns:
289
- None
289
+ Resource: The resource that was added after matching with any existing resource
290
290
  """
291
291
  resource = self._get_resource_from_obj(resource)
292
292
  if "package_id" in resource:
@@ -298,14 +298,15 @@ class Dataset(HDXObject):
298
298
  resource_index = ResourceMatcher.match_resource_list(self._resources, resource)
299
299
  if resource_index is None:
300
300
  self._resources.append(resource)
301
- else:
302
- updated_resource = merge_two_dictionaries(
303
- self._resources[resource_index], resource
304
- )
305
- if resource.get_file_to_upload():
306
- updated_resource.set_file_to_upload(resource.get_file_to_upload())
307
- if resource.is_marked_data_updated():
308
- updated_resource.mark_data_updated()
301
+ return resource
302
+ updated_resource = merge_two_dictionaries(
303
+ self._resources[resource_index], resource
304
+ )
305
+ if resource.get_file_to_upload():
306
+ updated_resource.set_file_to_upload(resource.get_file_to_upload())
307
+ if resource.is_marked_data_updated():
308
+ updated_resource.mark_data_updated()
309
+ return updated_resource
309
310
 
310
311
  def add_update_resources(
311
312
  self,
@@ -8,6 +8,7 @@ from pathlib import Path
8
8
  from typing import Any, Dict, List, Optional, Tuple, Union
9
9
 
10
10
  import hdx.data.dataset
11
+ import hdx.data.resource_matcher
11
12
  from hdx.api.configuration import Configuration
12
13
  from hdx.api.utilities.date_helper import DateHelper
13
14
  from hdx.api.utilities.size_hash import get_size_and_hash
@@ -460,6 +461,57 @@ class Resource(HDXObject):
460
461
  self._merge_hdx_update("resource", "id", files, True, **kwargs)
461
462
  return status
462
463
 
464
+ def _get_resource_id(self, **kwargs: Any) -> Optional[str]:
465
+ """Helper function to get resource id if available from given resource or by
466
+ comparing ot a given dataset's resources.
467
+
468
+ Args:
469
+ **kwargs: See below
470
+ dataset (Dataset): Existing dataset if available to obtain resource id
471
+
472
+ Returns:
473
+ Optional[str]: Resource id or None
474
+ """
475
+ loadedid = self.data.get("id")
476
+ if loadedid is None:
477
+ dataset = kwargs.get("dataset")
478
+ if dataset:
479
+ dataset_id = dataset.get("id")
480
+ if not dataset_id:
481
+ dataset_name = dataset.get("name")
482
+ if dataset_name:
483
+ dataset = hdx.data.dataset.Dataset.read_from_hdx(dataset_name)
484
+ if dataset:
485
+ dataset_id = dataset["id"]
486
+ else:
487
+ raise HDXError("No dataset id or name in dataset!")
488
+ if dataset_id:
489
+ package_id = self.data.get("package_id")
490
+ if package_id and package_id != dataset_id:
491
+ logger.warning(
492
+ f"Using dataset id {dataset_id} from dataset parameter which doesn't match {package_id} in resource!"
493
+ )
494
+ else:
495
+ dataset_id = self.data.get("package_id")
496
+ if dataset_id:
497
+ dataset = hdx.data.dataset.Dataset.read_from_hdx(dataset_id)
498
+ if not dataset:
499
+ dataset_id = None
500
+ if dataset_id:
501
+ self.data["package_id"] = dataset["id"]
502
+ dataset_resources = dataset.get_resources()
503
+ matching_index = (
504
+ hdx.data.resource_matcher.ResourceMatcher.match_resource_list(
505
+ dataset_resources, self
506
+ )
507
+ )
508
+ if matching_index:
509
+ matching_resource = dataset_resources[matching_index]
510
+ loadedid = matching_resource.get("id")
511
+ if loadedid:
512
+ self.data["id"] = loadedid
513
+ return loadedid
514
+
463
515
  def update_in_hdx(self, **kwargs: Any) -> int:
464
516
  """Check if resource exists in HDX and if so, update it. To indicate
465
517
  that the data in an external resource (given by a URL) has been
@@ -482,11 +534,13 @@ class Resource(HDXObject):
482
534
  data_updated (bool): If True, set last_modified to now. Defaults to False.
483
535
  date_data_updated (datetime): Date to use for last_modified. Default to None.
484
536
  force_update (bool): Force file to be updated even if it hasn't changed. Defaults to False.
537
+ dataset (Dataset): Existing dataset if available to obtain resource id
485
538
 
486
539
  Returns:
487
540
  int: Status code
488
541
  """
489
542
  self.check_both_url_filetoupload()
543
+ _ = self._get_resource_id(**kwargs)
490
544
  self._check_load_existing_object("resource", "id")
491
545
  return self._resource_merge_hdx_update(**kwargs)
492
546
 
@@ -513,15 +567,18 @@ class Resource(HDXObject):
513
567
  data_updated (bool): If True, set last_modified to now. Defaults to False.
514
568
  date_data_updated (datetime): Date to use for last_modified. Default to None.
515
569
  force_update (bool): Force file to be updated even if it hasn't changed. Defaults to False.
570
+ dataset (Dataset): Existing dataset if available to obtain resource id
516
571
 
517
572
  Returns:
518
573
  int: Status code
519
574
  """
520
575
  self.check_both_url_filetoupload()
521
- id = self.data.get("id")
522
- if id and self._load_from_hdx("resource", id):
523
- logger.warning(f"{'resource'} exists. Updating {id}")
524
- return self._resource_merge_hdx_update(**kwargs)
576
+ loadedid = self._get_resource_id(**kwargs)
577
+ if loadedid:
578
+ if self._load_from_hdx("resource", loadedid):
579
+ logger.warning(f"{'resource'} exists. Updating {loadedid}")
580
+ return self._resource_merge_hdx_update(**kwargs)
581
+ logger.warning(f"Failed to load resource with id {loadedid}")
525
582
 
526
583
  self.set_types()
527
584
  self.correct_format(self.data)
@@ -12,6 +12,7 @@ import pytest
12
12
  from .. import MockResponse, dataset_resultdict, resource_data
13
13
  from .test_resource_view import resource_view_list, resource_view_mocklist
14
14
  from hdx.api.configuration import Configuration
15
+ from hdx.data.dataset import Dataset
15
16
  from hdx.data.hdxobject import HDXError
16
17
  from hdx.data.resource import Resource
17
18
  from hdx.utilities.dateparse import parse_date
@@ -234,11 +235,20 @@ def mockdataset(url, datadict):
234
235
  404,
235
236
  '{"success": false, "error": {"message": "TEST ERROR: Not show", "__type": "TEST ERROR: Not Show Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=package_show"}',
236
237
  )
237
- result = json.dumps(dataset_resultdict)
238
+ if datadict["id"] in (
239
+ "1234",
240
+ "6f36a41c-f126-4b18-aaaf-6c2ddfbc5d4d",
241
+ "test_dataset",
242
+ ):
243
+ result = json.dumps(dataset_resultdict)
244
+ return MockResponse(
245
+ 200,
246
+ '{"success": true, "result": %s, "help": "http://test-data.humdata.org/api/3/action/help_show?name=package_show"}'
247
+ % result,
248
+ )
238
249
  return MockResponse(
239
- 200,
240
- '{"success": true, "result": %s, "help": "http://test-data.humdata.org/api/3/action/help_show?name=package_show"}'
241
- % result,
250
+ 404,
251
+ '{"success": false, "error": {"message": "Not found", "__type": "Not Found Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=package_show"}',
242
252
  )
243
253
 
244
254
 
@@ -1068,3 +1078,51 @@ class TestResource:
1068
1078
  )
1069
1079
  del resource["id"]
1070
1080
  assert resource.get_api_url() is None
1081
+
1082
+ def test_get_resource_id(self, configuration, post_dataset):
1083
+ resources = [
1084
+ {"id": "abcd", "name": "Resource1", "format": "CSV"},
1085
+ {"id": "efgh", "name": "Resource2", "format": "CSV"},
1086
+ {"id": "ijkl", "name": "Resource3", "format": "XLSX"},
1087
+ ]
1088
+ dataset = Dataset({"id": "1234", "name": "test_dataset", "format": "CSV"})
1089
+ dataset.add_update_resources(resources)
1090
+
1091
+ # Uses resource["name"] and resource["format"]
1092
+ resource = Resource({"name": "Resource2", "format": "CSV"})
1093
+ result = resource._get_resource_id(dataset=dataset)
1094
+ assert result == "efgh"
1095
+
1096
+ # Uses resource["id"]
1097
+ result = resource._get_resource_id(dataset=dataset)
1098
+ assert result == "efgh"
1099
+
1100
+ # Uses dataset["name"]
1101
+ del resource["id"]
1102
+ del resource["package_id"]
1103
+ del dataset["id"]
1104
+ result = resource._get_resource_id(dataset=dataset)
1105
+ assert result == "3d777226-96aa-4239-860a-703389d16d1f"
1106
+
1107
+ # Uses resource["package id"]
1108
+ del resource["id"]
1109
+ result = resource._get_resource_id()
1110
+ assert result == "3d777226-96aa-4239-860a-703389d16d1f"
1111
+
1112
+ # Uses resource["package id"]
1113
+ del resource["id"]
1114
+ resource["package_id"] = "NOTFOUND"
1115
+ result = resource._get_resource_id()
1116
+ assert result is None
1117
+
1118
+ # resource["package id"] != dataset["id"]
1119
+ resource["package_id"] = "NOTFOUND"
1120
+ result = resource._get_resource_id(dataset=dataset)
1121
+ assert result == "3d777226-96aa-4239-860a-703389d16d1f"
1122
+
1123
+ # Invalid dataset
1124
+ del resource["id"]
1125
+ del resource["package_id"]
1126
+ del dataset["name"]
1127
+ with pytest.raises(HDXError):
1128
+ resource._get_resource_id(dataset=dataset)
File without changes
File without changes
File without changes