hdx-python-api 6.7.2__tar.gz → 6.7.4__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.
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/PKG-INFO +1 -1
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/documentation/index.md +159 -5
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/api/_version.py +2 -2
- hdx_python_api-6.7.4/src/hdx/api/utilities/hdx_stats.py +86 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/data/activity.py +3 -1
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/data/dataset.py +158 -7
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/data/hdxobject.py +28 -1
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/data/location.py +44 -7
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/data/organization.py +1 -7
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/data/resource.py +337 -18
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/data/user.py +21 -8
- hdx_python_api-6.7.4/tests/hdx/api/utilities/test_hdx_stats.py +89 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/test_activity.py +6 -1
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/test_dataset_noncore.py +142 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/test_location.py +65 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/test_resource.py +339 -1
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/test_user.py +28 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/.github/workflows/publish.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/.github/workflows/run-python-tests.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/.gitignore +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/.pre-commit-config.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/CLAUDE.md +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/LICENSE +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/README.md +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/documentation/.readthedocs.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/documentation/mkdocs.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/pyproject.toml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/api/__init__.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/api/configuration.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/api/hdx_base_configuration.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/api/locations.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/api/remotehdx.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/api/utilities/__init__.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/api/utilities/date_helper.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/api/utilities/filestore_helper.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/api/utilities/hdx_error_handler.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/api/utilities/hdx_state.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/api/utilities/url_utils.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/data/__init__.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/data/resource_matcher.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/data/resource_view.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/data/showcase.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/data/vocabulary.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/facades/__init__.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/facades/infer_arguments.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/facades/keyword_arguments.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/src/hdx/facades/simple.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/__init__.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/Accepted_Tags.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/CKAN/hdx_dataset_static.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/Tag_Mapping.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/Tag_Mapping_ChainRuleError.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/empty.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_base_config.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_base_config.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_config.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_config.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_dataset_static.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_dataset_static.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_datasource_topline.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_datasource_topline.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_email_configuration.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_email_configuration.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_missing_site_config.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_organization_static.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_organization_static.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_resource_static.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_resource_static.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_resource_view_static.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_resource_view_static.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_showcase_static.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_showcase_static.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_user_static.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_user_static.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_vocabulary_static.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_vocabulary_static.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/project_configuration.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/project_configuration.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/user_agent_config.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/user_agent_config2.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/user_agent_config3.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/config/user_agent_config_wrong.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/dataset_search_results.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/download_gen_resource/conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/download_gen_resource/min_qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/download_gen_resource/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/download_gen_resource/test_data_no_data.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/download_gen_resource/test_data_no_years.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/empty.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/gen_resource/conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/gen_resource/min_qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/gen_resource/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/gen_resource/test_data_no_data.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/gen_resource/test_data_no_years.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/location/location_list_all_fields.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/location/location_show_results.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/organization/organization_list_all_fields.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/organization/organization_show_results.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/qc_from_rows/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/qc_from_rows/qc_conflict_data_alg_one_col.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/resource_formats.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/showcase_all_search_results.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/size_hash/ACLED-All-Africa-File_20170101-to-20170708.xlsx +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/state/analysis_dates.txt +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/state/last_build_date.txt +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/test_data.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/test_data.zip +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/dem_data_zwe.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/dem_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/expected_resources_to_update.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/opri_data_zwe.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/opri_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/opri_metadata_zwe.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/qc_sdg_data_zwe.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/sdg_data_zwe.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/sdg_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/sdg_metadata_zwe.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/unesco_dataset.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/unesco_update_dataset.json +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/update_logic/update_logic_resources.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/fixtures/update_logic/update_logic_resources_new.yaml +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/__init__.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/api/__init__.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/api/test_ckan.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/api/test_configuration.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/api/test_locations.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/api/utilities/__init__.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/api/utilities/test_filestore_helper.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/api/utilities/test_hdx_error_handler.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/api/utilities/test_hdx_state.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/api/utilities/test_url_utils.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/conftest.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/__init__.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/test_dataset_add_hapi_error.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/test_dataset_core.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/test_dataset_resource_generation.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/test_organization.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/test_resource_view.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/test_showcase.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/test_update_dataset_resources.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/test_update_logic.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/data/test_vocabulary.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/facades/__init__.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/facades/test_infer_arguments.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/facades/test_keyword_arguments.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/tests/hdx/facades/test_simple.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/uv.lock +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/workingexample/my_code.py +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/workingexample/my_resource.csv +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/workingexample/my_resource.xlsx +0 -0
- {hdx_python_api-6.7.2 → hdx_python_api-6.7.4}/workingexample/run.py +0 -0
|
@@ -36,6 +36,7 @@ upload your datasets to HDX.
|
|
|
36
36
|
- [Location Management](#location-management)
|
|
37
37
|
- [Vocabulary Management](#vocabulary-management)
|
|
38
38
|
- [Activity Streams](#activity-streams)
|
|
39
|
+
- [HDX Statistics](#hdx-statistics)
|
|
39
40
|
- [Pipeline State](#pipeline-state)
|
|
40
41
|
- [Working Examples](#working-examples)
|
|
41
42
|
- [Project Framework](#project-framework)
|
|
@@ -636,6 +637,45 @@ function, for example:
|
|
|
636
637
|
|
|
637
638
|
dataset.remove_showcase(showcase)
|
|
638
639
|
|
|
640
|
+
HDX runs file structure checks on resources, recording schema changes (eg.
|
|
641
|
+
column names, order or types) and whether sheets have merged cells. You can get
|
|
642
|
+
these checks for all of a dataset's resources from HDX:
|
|
643
|
+
|
|
644
|
+
fs_check_info = dataset.get_fs_check_info()
|
|
645
|
+
|
|
646
|
+
This returns a list of dictionaries, each from a resource name to a list of
|
|
647
|
+
check events with keys such as `state`, `timestamp`, `sheet_changes` and
|
|
648
|
+
`hxl_proxy_response`.
|
|
649
|
+
|
|
650
|
+
Similarly, you can get the geopreview shape information of a dataset's
|
|
651
|
+
resources:
|
|
652
|
+
|
|
653
|
+
shape_info = dataset.get_shape_info()
|
|
654
|
+
|
|
655
|
+
HDX can recommend tags for a dataset based on its title and organization
|
|
656
|
+
(`owner_org`). Tags are ordered from most to least recommended:
|
|
657
|
+
|
|
658
|
+
tags = dataset.get_recommended_tags()
|
|
659
|
+
|
|
660
|
+
You can check if the dataset or its organization is in HDX's allowlist for
|
|
661
|
+
automatic loading of resources into the datastore:
|
|
662
|
+
|
|
663
|
+
allowed = dataset.is_allowed_for_datastore()
|
|
664
|
+
|
|
665
|
+
HDX sysadmins can submit all of a dataset's CSV resources to DataPusher+
|
|
666
|
+
(returning False if there are none):
|
|
667
|
+
|
|
668
|
+
submitted = dataset.push_to_datastore()
|
|
669
|
+
|
|
670
|
+
Users who are sysadmins or have permission to manage QA can mark QA of a
|
|
671
|
+
dataset as completed, set a QA field of all its resources or clear a file
|
|
672
|
+
structure check field (`fs_check_info` by default) of all its resources. The
|
|
673
|
+
dataset is updated from the result:
|
|
674
|
+
|
|
675
|
+
dataset.set_qa_completed(True)
|
|
676
|
+
dataset.qa_revise_resources("pii", "false")
|
|
677
|
+
dataset.reset_fs_check()
|
|
678
|
+
|
|
639
679
|
### Time Period
|
|
640
680
|
|
|
641
681
|
Time Period is a mandatory field in HDX. It is the earliest start date and
|
|
@@ -947,6 +987,38 @@ If the method **set_file_to_upload** is used to supply a file, the resource
|
|
|
947
987
|
`last_modified` field is set to now automatically regardless of the value of
|
|
948
988
|
`data_updated` or whether **mark_data_updated** has been called.
|
|
949
989
|
|
|
990
|
+
The file structure check events of a resource (see Dataset Specific
|
|
991
|
+
Operations) can be obtained from its `fs_check_info` field without a call to
|
|
992
|
+
HDX:
|
|
993
|
+
|
|
994
|
+
events = resource.get_fs_check_info()
|
|
995
|
+
|
|
996
|
+
Users who are sysadmins or have permission to manage QA can set or clear a
|
|
997
|
+
file structure check field of a resource. If the key is `fs_check_info` and the
|
|
998
|
+
value is a dictionary, it is appended to the existing check events (the last 20
|
|
999
|
+
are kept):
|
|
1000
|
+
|
|
1001
|
+
resource.revise_fs_check("fs_check_info", {"state": "success", ...})
|
|
1002
|
+
resource.reset_fs_check() # key defaults to fs_check_info
|
|
1003
|
+
|
|
1004
|
+
They can also quarantine a resource (which removes its `shape_info` and
|
|
1005
|
+
geopreview) or take it out of quarantine, and patch other QA fields:
|
|
1006
|
+
|
|
1007
|
+
in_quarantine = resource.is_in_quarantine()
|
|
1008
|
+
resource.set_in_quarantine(True)
|
|
1009
|
+
resource.qa_patch(pii="true", sdc_report_flag="false")
|
|
1010
|
+
|
|
1011
|
+
A resource can be flagged as containing p-codes or as being in HAPI. Setting
|
|
1012
|
+
these flags requires sysadmin or permission to manage p-codes or the in HAPI
|
|
1013
|
+
flag respectively:
|
|
1014
|
+
|
|
1015
|
+
p_coded = resource.is_p_coded() # None if not set
|
|
1016
|
+
resource.set_p_coded(True)
|
|
1017
|
+
in_hapi = resource.is_in_hapi()
|
|
1018
|
+
resource.set_in_hapi(True)
|
|
1019
|
+
|
|
1020
|
+
These methods update the resource from the result.
|
|
1021
|
+
|
|
950
1022
|
### Data Dictionary
|
|
951
1023
|
|
|
952
1024
|
A resource can have a data dictionary describing the columns in the data it
|
|
@@ -974,11 +1046,36 @@ using the getter:
|
|
|
974
1046
|
|
|
975
1047
|
data_dictionary = resource.get_hdx_data_dictionary()
|
|
976
1048
|
|
|
1049
|
+
To change the data dictionary of a resource already in HDX without sending
|
|
1050
|
+
dataset update notifications, use **update_hdx_data_dictionary**. It patches
|
|
1051
|
+
only the `hdx_data_dictionary` field (so `last_modified` is unchanged), then,
|
|
1052
|
+
if the resource has a datastore, updates the datastore field labels and
|
|
1053
|
+
descriptions without reloading the data. The given columns are merged by
|
|
1054
|
+
`field` into the existing data dictionary in the resource metadata, so read
|
|
1055
|
+
the resource from HDX first. Pass `replace=True` to replace the data
|
|
1056
|
+
dictionary instead and `update_datastore=False` to leave the datastore alone:
|
|
1057
|
+
|
|
1058
|
+
resource = Resource.read_from_hdx(RESOURCE_ID)
|
|
1059
|
+
resource.update_hdx_data_dictionary([
|
|
1060
|
+
{
|
|
1061
|
+
"field": "col_name",
|
|
1062
|
+
"label": "Column Label",
|
|
1063
|
+
"description": "New description.",
|
|
1064
|
+
},
|
|
1065
|
+
])
|
|
1066
|
+
|
|
1067
|
+
Columns are matched to datastore fields by `field`. A warning is logged for
|
|
1068
|
+
any column with no matching datastore field.
|
|
1069
|
+
|
|
977
1070
|
### Datastore
|
|
978
1071
|
|
|
979
|
-
A resource's data can be loaded into the HDX datastore and queried. HDX
|
|
980
|
-
|
|
981
|
-
|
|
1072
|
+
A resource's data can be loaded into the HDX datastore and queried. HDX calls this
|
|
1073
|
+
[Tabular Data Endpoints (TDE)](https://docs.humdata.org/build/hdx-apis/tabular-data-endpoints),
|
|
1074
|
+
and it is available only for resources with TDE enabled (their `datastore_active`
|
|
1075
|
+
field is true). Contact hdx@un.org to request TDE for your datasets. HDX requires an
|
|
1076
|
+
API key for all datastore actions and dumps, including reads of public resources,
|
|
1077
|
+
and limits each IP address to 60 requests per minute. To create, update or delete
|
|
1078
|
+
the datastore for a resource:
|
|
982
1079
|
|
|
983
1080
|
resource.create_datastore(
|
|
984
1081
|
[{"id": "code", "type": "text"}, {"id": "value", "type": "numeric"}],
|
|
@@ -988,6 +1085,22 @@ public resources. To create, update or delete the datastore for a resource:
|
|
|
988
1085
|
has_datastore = resource.has_datastore()
|
|
989
1086
|
resource.delete_datastore()
|
|
990
1087
|
|
|
1088
|
+
HDX loads uploaded files into the datastore using DataPusher+. To reload a
|
|
1089
|
+
resource's file into the datastore without uploading it again (so
|
|
1090
|
+
`last_modified` is unchanged), use **submit_to_datapusher**. It returns False
|
|
1091
|
+
if the job was not submitted, eg. because one is already pending. HDX's
|
|
1092
|
+
datastore allowlist and format checks, which apply to automatic submissions
|
|
1093
|
+
on upload, are not applied. **get_datapusher_status** returns the status of
|
|
1094
|
+
the latest job or None if there is none:
|
|
1095
|
+
|
|
1096
|
+
submitted = resource.submit_to_datapusher(ignore_hash=True)
|
|
1097
|
+
status = resource.get_datapusher_status() # eg. status["status"] == "complete"
|
|
1098
|
+
|
|
1099
|
+
HDX sysadmins can instead use **push_to_datastore**, which submits the
|
|
1100
|
+
resource through HDX's wrapper action:
|
|
1101
|
+
|
|
1102
|
+
submitted = resource.push_to_datastore()
|
|
1103
|
+
|
|
991
1104
|
To download the whole datastore (rather than the resource's file) use
|
|
992
1105
|
**download_datastore**, which returns the URL and path like **download**.
|
|
993
1106
|
`file_format` can be `csv` (default), `tsv`, `json` or `xml`, and `filename`
|
|
@@ -1008,7 +1121,8 @@ and `include_total`, and passes any other keyword arguments to CKAN:
|
|
|
1008
1121
|
records = result["records"]
|
|
1009
1122
|
|
|
1010
1123
|
**get_datastore_records** takes the same query parameters but pages through
|
|
1011
|
-
all matching rows, yielding each record (`page_size` defaults to 10000)
|
|
1124
|
+
all matching rows, yielding each record (`page_size` defaults to 10000).
|
|
1125
|
+
`records_format` csv and tsv are not supported; use `search_datastore` for those:
|
|
1012
1126
|
|
|
1013
1127
|
for record in resource.get_datastore_records(filters={"code": "A"}):
|
|
1014
1128
|
...
|
|
@@ -1020,7 +1134,9 @@ internal `_id` field:
|
|
|
1020
1134
|
|
|
1021
1135
|
**search_datastore_sql** wraps CKAN's `datastore_search_sql`, running a
|
|
1022
1136
|
SELECT statement where tables are named by double quoted resource id and
|
|
1023
|
-
returning the list of records
|
|
1137
|
+
returning the list of records. HDX returns at most 32,000 rows per query and
|
|
1138
|
+
cuts off larger results, in which case a warning is logged (see
|
|
1139
|
+
[paging in the TDE docs](https://docs.humdata.org/build/hdx-apis/tabular-data-endpoints/troubleshooting-and-error-handling#pagination)):
|
|
1024
1140
|
|
|
1025
1141
|
records = Resource.search_datastore_sql(
|
|
1026
1142
|
'SELECT code, SUM(value) AS total FROM "RESOURCE_ID" GROUP BY code'
|
|
@@ -1067,6 +1183,11 @@ configuration):
|
|
|
1067
1183
|
|
|
1068
1184
|
user = User.get_current_user()
|
|
1069
1185
|
|
|
1186
|
+
You can get the name of the API token in the configuration and the md5 hash
|
|
1187
|
+
of its owner's email:
|
|
1188
|
+
|
|
1189
|
+
token_info = User.get_current_token_info() # {"email_hash": ..., "token_name": ...}
|
|
1190
|
+
|
|
1070
1191
|
You can check that the current user has a particular permission to a specific
|
|
1071
1192
|
organization:
|
|
1072
1193
|
|
|
@@ -1152,6 +1273,17 @@ since Data Grid membership changes over time, rather than a fixed list):
|
|
|
1152
1273
|
|
|
1153
1274
|
This returns a sorted list of 3-letter location codes.
|
|
1154
1275
|
|
|
1276
|
+
HDX sysadmins can get the Data Grid of a country and clear HDX's cached copy of
|
|
1277
|
+
it:
|
|
1278
|
+
|
|
1279
|
+
data_grid = Location.get_data_grid("AFG")
|
|
1280
|
+
Location.invalidate_data_grid("AFG")
|
|
1281
|
+
|
|
1282
|
+
**get_data_grid** returns a dictionary with keys including `title`, `date`,
|
|
1283
|
+
`stats` and `categories` (or None if not found). Each category has
|
|
1284
|
+
`subcategories`, each with a list of `datasets`. Complementary datasets have
|
|
1285
|
+
`is_complementary` set to True.
|
|
1286
|
+
|
|
1155
1287
|
You can get the datasets belonging to a location as follows:
|
|
1156
1288
|
|
|
1157
1289
|
datasets = location.get_datasets(**kwargs)
|
|
@@ -1223,6 +1355,28 @@ permission to edit the object the activity relates to for these:
|
|
|
1223
1355
|
data = activity.get_data()
|
|
1224
1356
|
diff = activity.get_diff(diff_type="unified") # or "context" or "html"
|
|
1225
1357
|
|
|
1358
|
+
## HDX Statistics
|
|
1359
|
+
|
|
1360
|
+
General statistics about datasets, organizations and users on HDX can be
|
|
1361
|
+
obtained as follows:
|
|
1362
|
+
|
|
1363
|
+
from hdx.api.utilities.hdx_stats import get_general_statistics, push_general_stats
|
|
1364
|
+
|
|
1365
|
+
stats = get_general_statistics()
|
|
1366
|
+
|
|
1367
|
+
Users with permission to manage basic scheduled tasks can compute the statistics
|
|
1368
|
+
and push them to analytics:
|
|
1369
|
+
|
|
1370
|
+
pushed_stats = push_general_stats()
|
|
1371
|
+
|
|
1372
|
+
HDX sysadmins can get the number of activities of each active user (optionally
|
|
1373
|
+
between start and end dates) and lists of active and inactive organizations:
|
|
1374
|
+
|
|
1375
|
+
from hdx.api.utilities.hdx_stats import get_organization_statistics, get_user_statistics
|
|
1376
|
+
|
|
1377
|
+
user_stats = get_user_statistics(start_date="2026-01-01", end_date="2026-06-30")
|
|
1378
|
+
org_stats = get_organization_statistics()
|
|
1379
|
+
|
|
1226
1380
|
## Pipeline State
|
|
1227
1381
|
|
|
1228
1382
|
The HDXState class allows the reading and writing of state to a given dataset. Input
|
|
@@ -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.
|
|
22
|
-
__version_tuple__ = version_tuple = (6, 7,
|
|
21
|
+
__version__ = version = '6.7.4'
|
|
22
|
+
__version_tuple__ = version_tuple = (6, 7, 4)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""HDX site-wide statistics"""
|
|
2
|
+
|
|
3
|
+
from hdx.api.configuration import Configuration
|
|
4
|
+
from hdx.data.hdxobject import HDXError
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _call_stats_action(
|
|
8
|
+
action: str, configuration: Configuration | None, data: dict | None = None
|
|
9
|
+
) -> dict:
|
|
10
|
+
"""Call an HDX statistics action
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
action: CKAN action name
|
|
14
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
15
|
+
data: Parameters to pass to the action. Defaults to None.
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
Statistics dictionary
|
|
19
|
+
"""
|
|
20
|
+
if configuration is None:
|
|
21
|
+
configuration = Configuration.read()
|
|
22
|
+
try:
|
|
23
|
+
return configuration.call_remoteckan(action, data or {})
|
|
24
|
+
except Exception as e:
|
|
25
|
+
raise HDXError(f"Failed when trying to call {action}!") from e
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_general_statistics(configuration: Configuration | None = None) -> dict:
|
|
29
|
+
"""Get general statistics about datasets, organizations and users on HDX
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Dictionary with keys datasets, organizations and users
|
|
36
|
+
"""
|
|
37
|
+
return _call_stats_action("hdx_general_statistics", configuration)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def push_general_stats(configuration: Configuration | None = None) -> dict:
|
|
41
|
+
"""Compute general statistics on HDX and push them to analytics. Requires
|
|
42
|
+
permission to manage basic scheduled tasks.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
Statistics that were pushed
|
|
49
|
+
"""
|
|
50
|
+
return _call_stats_action("hdx_push_general_stats", configuration)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_user_statistics(
|
|
54
|
+
start_date: str | None = None,
|
|
55
|
+
end_date: str | None = None,
|
|
56
|
+
configuration: Configuration | None = None,
|
|
57
|
+
) -> dict:
|
|
58
|
+
"""Get the number of activities of each active user on HDX, optionally
|
|
59
|
+
between start and end dates. Requires sysadmin.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
start_date: Count activities on or after this date eg. 2026-01-01. Defaults to None.
|
|
63
|
+
end_date: Count activities on or before this date. Defaults to None.
|
|
64
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Dictionary from user id to dictionary with keys id, name and no_of_activities
|
|
68
|
+
"""
|
|
69
|
+
data = {}
|
|
70
|
+
if start_date:
|
|
71
|
+
data["start_date"] = start_date
|
|
72
|
+
if end_date:
|
|
73
|
+
data["end_date"] = end_date
|
|
74
|
+
return _call_stats_action("hdx_user_statistics", configuration, data)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def get_organization_statistics(configuration: Configuration | None = None) -> dict:
|
|
78
|
+
"""Get active and inactive organizations on HDX. Requires sysadmin.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
Dictionary with keys active_organizations and inactive_organizations
|
|
85
|
+
"""
|
|
86
|
+
return _call_stats_action("hdx_organization_statistics", configuration)
|
|
@@ -129,7 +129,9 @@ class Activity(HDXObject):
|
|
|
129
129
|
result = activity._write_to_hdx(action, data)
|
|
130
130
|
return [cls(x, configuration=configuration) for x in result]
|
|
131
131
|
data = dict(data)
|
|
132
|
-
limit
|
|
132
|
+
# HDX silently caps limit at ckan.activity_list_limit_max
|
|
133
|
+
limit = min(data.get("limit", 100), 100)
|
|
134
|
+
data["limit"] = limit
|
|
133
135
|
offset = data.get("offset", 0)
|
|
134
136
|
activities = []
|
|
135
137
|
while True:
|
|
@@ -147,6 +147,14 @@ class Dataset(HDXObject):
|
|
|
147
147
|
"list": "package_list",
|
|
148
148
|
"autocomplete": "package_autocomplete",
|
|
149
149
|
"create_default_views": "package_create_default_resource_views",
|
|
150
|
+
"fs_check_info": "fs_check_info_show",
|
|
151
|
+
"fs_check_reset": "hdx_fs_check_package_reset",
|
|
152
|
+
"shape_info": "shape_info_show",
|
|
153
|
+
"recommend_tags": "hdx_recommend_tags",
|
|
154
|
+
"allowed_for_datastore": "hdx_is_package_allowed_for_datastore",
|
|
155
|
+
"push_to_datastore": "hdx_push_resource_to_datastore",
|
|
156
|
+
"qa_completed": "hdx_mark_qa_completed",
|
|
157
|
+
"qa_revise_resources": "hdx_qa_package_revise_resource",
|
|
150
158
|
}
|
|
151
159
|
|
|
152
160
|
def __setitem__(self, key: Any, value: Any) -> None:
|
|
@@ -1447,13 +1455,7 @@ class Dataset(HDXObject):
|
|
|
1447
1455
|
Returns:
|
|
1448
1456
|
List of Activity objects
|
|
1449
1457
|
"""
|
|
1450
|
-
return
|
|
1451
|
-
"package",
|
|
1452
|
-
self.data.get("id") or self.data.get("name"),
|
|
1453
|
-
self.configuration,
|
|
1454
|
-
all_pages,
|
|
1455
|
-
**kwargs,
|
|
1456
|
-
)
|
|
1458
|
+
return self._get_activities("package", all_pages, **kwargs)
|
|
1457
1459
|
|
|
1458
1460
|
@classmethod
|
|
1459
1461
|
def autocomplete(
|
|
@@ -2333,6 +2335,155 @@ class Dataset(HDXObject):
|
|
|
2333
2335
|
return None
|
|
2334
2336
|
return f"{self.configuration.get_hdx_site_url()}/api/3/action/package_show?id={name_or_id}"
|
|
2335
2337
|
|
|
2338
|
+
def get_fs_check_info(self) -> list[dict]:
|
|
2339
|
+
"""Get file structure check information for the dataset's resources
|
|
2340
|
+
from HDX. Each list item is a dictionary from resource name to a list
|
|
2341
|
+
of check events, each of which can have keys such as state, timestamp,
|
|
2342
|
+
sheet_changes and hxl_proxy_response.
|
|
2343
|
+
|
|
2344
|
+
Returns:
|
|
2345
|
+
List of dictionaries from resource name to file structure checks
|
|
2346
|
+
"""
|
|
2347
|
+
success, result = self._read_from_hdx(
|
|
2348
|
+
"dataset",
|
|
2349
|
+
self.get_name_or_id(prefer_name=False),
|
|
2350
|
+
"id",
|
|
2351
|
+
self.actions()["fs_check_info"],
|
|
2352
|
+
)
|
|
2353
|
+
if success:
|
|
2354
|
+
return result
|
|
2355
|
+
return []
|
|
2356
|
+
|
|
2357
|
+
def _set_from_package(self, package: dict) -> None:
|
|
2358
|
+
"""Set the dataset's metadata and resources from a package metadata
|
|
2359
|
+
dictionary returned by HDX
|
|
2360
|
+
|
|
2361
|
+
Args:
|
|
2362
|
+
package: Package metadata dictionary
|
|
2363
|
+
|
|
2364
|
+
Returns:
|
|
2365
|
+
None
|
|
2366
|
+
"""
|
|
2367
|
+
self.data = package
|
|
2368
|
+
self.init_resources()
|
|
2369
|
+
self.separate_resources()
|
|
2370
|
+
|
|
2371
|
+
def reset_fs_check(self, key: str = "fs_check_info") -> None:
|
|
2372
|
+
"""Clear a file structure check field of all the dataset's resources
|
|
2373
|
+
in HDX. Requires sysadmin or permission to manage QA.
|
|
2374
|
+
|
|
2375
|
+
Args:
|
|
2376
|
+
key: Resource field to clear. Defaults to fs_check_info.
|
|
2377
|
+
|
|
2378
|
+
Returns:
|
|
2379
|
+
None
|
|
2380
|
+
"""
|
|
2381
|
+
result = self._write_to_hdx(
|
|
2382
|
+
"fs_check_reset", {"package_id": self.data["id"], "key": key}, "package_id"
|
|
2383
|
+
)
|
|
2384
|
+
self._set_from_package(result["package"])
|
|
2385
|
+
|
|
2386
|
+
def set_qa_completed(self, qa_completed: bool) -> None:
|
|
2387
|
+
"""Mark QA of the dataset in HDX as completed or not. Requires
|
|
2388
|
+
sysadmin or permission to manage QA.
|
|
2389
|
+
|
|
2390
|
+
Args:
|
|
2391
|
+
qa_completed: Whether QA is completed
|
|
2392
|
+
|
|
2393
|
+
Returns:
|
|
2394
|
+
None
|
|
2395
|
+
"""
|
|
2396
|
+
result = self._write_to_hdx(
|
|
2397
|
+
"qa_completed", {"id": self.data["id"], "qa_completed": qa_completed}, "id"
|
|
2398
|
+
)
|
|
2399
|
+
self._set_from_package(result["package"])
|
|
2400
|
+
|
|
2401
|
+
def qa_revise_resources(self, key: str, value: Any) -> None:
|
|
2402
|
+
"""Set a QA field of all the dataset's resources in HDX. Requires
|
|
2403
|
+
sysadmin or permission to manage QA.
|
|
2404
|
+
|
|
2405
|
+
Args:
|
|
2406
|
+
key: Resource field eg. pii
|
|
2407
|
+
value: Value to set
|
|
2408
|
+
|
|
2409
|
+
Returns:
|
|
2410
|
+
None
|
|
2411
|
+
"""
|
|
2412
|
+
result = self._write_to_hdx(
|
|
2413
|
+
"qa_revise_resources",
|
|
2414
|
+
{"id": self.data["id"], "key": key, "value": value},
|
|
2415
|
+
"id",
|
|
2416
|
+
)
|
|
2417
|
+
self._set_from_package(result["package"])
|
|
2418
|
+
|
|
2419
|
+
def get_shape_info(self) -> list[dict]:
|
|
2420
|
+
"""Get geopreview shape information for the dataset's resources from
|
|
2421
|
+
HDX
|
|
2422
|
+
|
|
2423
|
+
Returns:
|
|
2424
|
+
List of dictionaries from resource name to shape information
|
|
2425
|
+
"""
|
|
2426
|
+
success, result = self._read_from_hdx(
|
|
2427
|
+
"dataset",
|
|
2428
|
+
self.get_name_or_id(prefer_name=False),
|
|
2429
|
+
"id",
|
|
2430
|
+
self.actions()["shape_info"],
|
|
2431
|
+
)
|
|
2432
|
+
if success:
|
|
2433
|
+
return result
|
|
2434
|
+
return []
|
|
2435
|
+
|
|
2436
|
+
def get_recommended_tags(self) -> list[str]:
|
|
2437
|
+
"""Get tags recommended by HDX for the dataset based on its title and
|
|
2438
|
+
organization. Tags are ordered from most to least recommended.
|
|
2439
|
+
|
|
2440
|
+
Returns:
|
|
2441
|
+
List of recommended tags
|
|
2442
|
+
"""
|
|
2443
|
+
data = {"title": self.data.get("title")}
|
|
2444
|
+
organization = self.data.get("owner_org")
|
|
2445
|
+
if organization:
|
|
2446
|
+
data["organization"] = organization
|
|
2447
|
+
try:
|
|
2448
|
+
result = self.configuration.call_remoteckan(
|
|
2449
|
+
self.actions()["recommend_tags"], data
|
|
2450
|
+
)
|
|
2451
|
+
except Exception as e:
|
|
2452
|
+
raise HDXError("Failed when trying to get recommended tags!") from e
|
|
2453
|
+
return [tag["name"] for tag in result]
|
|
2454
|
+
|
|
2455
|
+
def is_allowed_for_datastore(self) -> bool:
|
|
2456
|
+
"""Return if the dataset or its organization is in HDX's allowlist for
|
|
2457
|
+
automatic loading of resources into the datastore
|
|
2458
|
+
|
|
2459
|
+
Returns:
|
|
2460
|
+
Whether dataset is allowed for datastore
|
|
2461
|
+
"""
|
|
2462
|
+
success, result = self._read_from_hdx(
|
|
2463
|
+
"dataset",
|
|
2464
|
+
self.data["id"],
|
|
2465
|
+
"package_id",
|
|
2466
|
+
self.actions()["allowed_for_datastore"],
|
|
2467
|
+
)
|
|
2468
|
+
if success:
|
|
2469
|
+
return result
|
|
2470
|
+
logger.debug(result)
|
|
2471
|
+
return False
|
|
2472
|
+
|
|
2473
|
+
def push_to_datastore(self) -> bool:
|
|
2474
|
+
"""Submit all the dataset's CSV resources to DataPusher+ using HDX's
|
|
2475
|
+
wrapper action. Requires sysadmin.
|
|
2476
|
+
|
|
2477
|
+
Returns:
|
|
2478
|
+
True if submitted, False if not (eg. no CSV resources)
|
|
2479
|
+
"""
|
|
2480
|
+
result = self._write_to_hdx(
|
|
2481
|
+
"push_to_datastore", {"dataset_id": self.data["id"]}, "dataset_id"
|
|
2482
|
+
)
|
|
2483
|
+
if not result["success"]:
|
|
2484
|
+
logger.debug(result["message"])
|
|
2485
|
+
return result["success"]
|
|
2486
|
+
|
|
2336
2487
|
def generate_resource(
|
|
2337
2488
|
self,
|
|
2338
2489
|
folder: Path | str,
|
|
@@ -9,7 +9,7 @@ from collections import UserDict
|
|
|
9
9
|
from collections.abc import Sequence
|
|
10
10
|
from os.path import isfile
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import Any, Optional, Union
|
|
12
|
+
from typing import TYPE_CHECKING, Any, Optional, Union
|
|
13
13
|
|
|
14
14
|
from ckanapi.errors import NotFound
|
|
15
15
|
from hdx.utilities.dictandlist import merge_two_dictionaries
|
|
@@ -20,6 +20,9 @@ from hdx.utilities.loader import (
|
|
|
20
20
|
|
|
21
21
|
from hdx.api.configuration import Configuration
|
|
22
22
|
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from hdx.data.activity import Activity
|
|
25
|
+
|
|
23
26
|
logger = logging.getLogger(__name__)
|
|
24
27
|
|
|
25
28
|
|
|
@@ -376,6 +379,30 @@ class HDXObject(UserDict, ABC):
|
|
|
376
379
|
**kwargs,
|
|
377
380
|
)
|
|
378
381
|
|
|
382
|
+
def _get_activities(
|
|
383
|
+
self, object_type: str, all_pages: bool = False, **kwargs: Any
|
|
384
|
+
) -> list["Activity"]:
|
|
385
|
+
"""Helper method to get the activity stream of this object
|
|
386
|
+
|
|
387
|
+
Args:
|
|
388
|
+
object_type: One of package, organization, group or user
|
|
389
|
+
all_pages: Whether to get all pages of results. Defaults to False.
|
|
390
|
+
**kwargs: Parameters to pass to Activity.get_activities
|
|
391
|
+
|
|
392
|
+
Returns:
|
|
393
|
+
List of Activity objects
|
|
394
|
+
"""
|
|
395
|
+
# Imported here as hdx.data.activity imports this module
|
|
396
|
+
from hdx.data.activity import Activity
|
|
397
|
+
|
|
398
|
+
return Activity.get_activities(
|
|
399
|
+
object_type,
|
|
400
|
+
self.data.get("id") or self.data.get("name"),
|
|
401
|
+
self.configuration,
|
|
402
|
+
all_pages,
|
|
403
|
+
**kwargs,
|
|
404
|
+
)
|
|
405
|
+
|
|
379
406
|
def _write_to_hdx(
|
|
380
407
|
self,
|
|
381
408
|
action: str,
|
|
@@ -43,6 +43,8 @@ class Location(HDXObject):
|
|
|
43
43
|
"delete": "group_delete",
|
|
44
44
|
"list": "group_list",
|
|
45
45
|
"autocomplete": "group_autocomplete",
|
|
46
|
+
"data_grid": "hdx_datagrid_show",
|
|
47
|
+
"invalidate_data_grid": "invalidate_data_completeness_for_location",
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
@classmethod
|
|
@@ -218,6 +220,47 @@ class Location(HDXObject):
|
|
|
218
220
|
if len(group["name"]) == 3 and group.get("data_completeness") == "active"
|
|
219
221
|
)
|
|
220
222
|
|
|
223
|
+
@staticmethod
|
|
224
|
+
def get_data_grid(
|
|
225
|
+
iso3: str, configuration: Configuration | None = None
|
|
226
|
+
) -> dict | None:
|
|
227
|
+
"""Get the Data Grid of a country. The dictionary has keys including
|
|
228
|
+
title, date, stats and categories. Each category has subcategories,
|
|
229
|
+
each with a list of datasets. Complementary datasets have
|
|
230
|
+
is_complementary set to True. Requires sysadmin.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
iso3: Country ISO 3-letter code
|
|
234
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
Data Grid dictionary or None if not found
|
|
238
|
+
"""
|
|
239
|
+
location = Location(configuration=configuration)
|
|
240
|
+
success, result = location._read_from_hdx(
|
|
241
|
+
"location", iso3.lower(), "id", location.actions()["data_grid"]
|
|
242
|
+
)
|
|
243
|
+
if success:
|
|
244
|
+
return result
|
|
245
|
+
logger.debug(result)
|
|
246
|
+
return None
|
|
247
|
+
|
|
248
|
+
@staticmethod
|
|
249
|
+
def invalidate_data_grid(
|
|
250
|
+
iso3: str, configuration: Configuration | None = None
|
|
251
|
+
) -> None:
|
|
252
|
+
"""Clear HDX's cached Data Grid of a country. Requires sysadmin.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
iso3: Country ISO 3-letter code
|
|
256
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
None
|
|
260
|
+
"""
|
|
261
|
+
location = Location(configuration=configuration)
|
|
262
|
+
location._write_to_hdx("invalidate_data_grid", {"name": iso3.lower()}, "name")
|
|
263
|
+
|
|
221
264
|
def get_activities(self, all_pages: bool = False, **kwargs: Any) -> list[Activity]:
|
|
222
265
|
"""Get the activity stream of this location. One page of results (whose size
|
|
223
266
|
is given by limit) is returned unless all_pages is True.
|
|
@@ -232,13 +275,7 @@ class Location(HDXObject):
|
|
|
232
275
|
Returns:
|
|
233
276
|
List of Activity objects
|
|
234
277
|
"""
|
|
235
|
-
return
|
|
236
|
-
"group",
|
|
237
|
-
self.data.get("id") or self.data.get("name"),
|
|
238
|
-
self.configuration,
|
|
239
|
-
all_pages,
|
|
240
|
-
**kwargs,
|
|
241
|
-
)
|
|
278
|
+
return self._get_activities("group", all_pages, **kwargs)
|
|
242
279
|
|
|
243
280
|
@classmethod
|
|
244
281
|
def autocomplete(
|
|
@@ -326,13 +326,7 @@ class Organization(HDXObject):
|
|
|
326
326
|
Returns:
|
|
327
327
|
List of Activity objects
|
|
328
328
|
"""
|
|
329
|
-
return
|
|
330
|
-
"organization",
|
|
331
|
-
self.data.get("id") or self.data.get("name"),
|
|
332
|
-
self.configuration,
|
|
333
|
-
all_pages,
|
|
334
|
-
**kwargs,
|
|
335
|
-
)
|
|
329
|
+
return self._get_activities("organization", all_pages, **kwargs)
|
|
336
330
|
|
|
337
331
|
@classmethod
|
|
338
332
|
def autocomplete(
|