hdx-python-api 6.7.3__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.3 → hdx_python_api-6.7.4}/PKG-INFO +1 -1
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/documentation/index.md +79 -0
- {hdx_python_api-6.7.3 → 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.3 → hdx_python_api-6.7.4}/src/hdx/data/dataset.py +137 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/data/location.py +43 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/data/resource.py +174 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/api/utilities/test_hdx_stats.py +32 -2
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/test_dataset_noncore.py +104 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/test_location.py +65 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/test_resource.py +129 -0
- hdx_python_api-6.7.3/src/hdx/api/utilities/hdx_stats.py +0 -47
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/.github/workflows/publish.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/.github/workflows/run-python-tests.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/.gitignore +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/.pre-commit-config.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/CLAUDE.md +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/LICENSE +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/README.md +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/documentation/.readthedocs.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/documentation/mkdocs.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/pyproject.toml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/api/__init__.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/api/configuration.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/api/hdx_base_configuration.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/api/locations.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/api/remotehdx.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/api/utilities/__init__.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/api/utilities/date_helper.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/api/utilities/filestore_helper.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/api/utilities/hdx_error_handler.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/api/utilities/hdx_state.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/api/utilities/url_utils.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/data/__init__.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/data/activity.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/data/hdxobject.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/data/organization.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/data/resource_matcher.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/data/resource_view.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/data/showcase.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/data/user.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/data/vocabulary.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/facades/__init__.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/facades/infer_arguments.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/facades/keyword_arguments.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/src/hdx/facades/simple.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/__init__.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/Accepted_Tags.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/CKAN/hdx_dataset_static.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/Tag_Mapping.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/Tag_Mapping_ChainRuleError.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/empty.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_base_config.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_base_config.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_config.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_config.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_dataset_static.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_dataset_static.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_datasource_topline.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_datasource_topline.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_email_configuration.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_email_configuration.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_missing_site_config.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_organization_static.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_organization_static.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_resource_static.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_resource_static.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_resource_view_static.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_resource_view_static.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_showcase_static.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_showcase_static.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_user_static.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_user_static.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_vocabulary_static.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/hdx_vocabulary_static.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/project_configuration.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/project_configuration.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/user_agent_config.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/user_agent_config2.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/user_agent_config3.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/config/user_agent_config_wrong.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/dataset_search_results.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/download_gen_resource/conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/download_gen_resource/min_qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/download_gen_resource/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/download_gen_resource/test_data_no_data.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/download_gen_resource/test_data_no_years.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/empty.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/gen_resource/conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/gen_resource/min_qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/gen_resource/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/gen_resource/test_data_no_data.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/gen_resource/test_data_no_years.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/location/location_list_all_fields.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/location/location_show_results.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/organization/organization_list_all_fields.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/organization/organization_show_results.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/qc_from_rows/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.3 → 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.3 → hdx_python_api-6.7.4}/tests/fixtures/resource_formats.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/showcase_all_search_results.yaml +0 -0
- {hdx_python_api-6.7.3 → 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.3 → hdx_python_api-6.7.4}/tests/fixtures/state/analysis_dates.txt +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/state/last_build_date.txt +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/test_data.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/test_data.zip +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/dem_data_zwe.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/dem_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/expected_resources_to_update.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/opri_data_zwe.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/opri_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/opri_metadata_zwe.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/qc_sdg_data_zwe.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/sdg_data_zwe.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/sdg_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/sdg_metadata_zwe.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/unesco_dataset.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/update_dataset_resources/unesco_update_dataset.json +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/update_logic/update_logic_resources.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/fixtures/update_logic/update_logic_resources_new.yaml +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/__init__.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/api/__init__.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/api/test_ckan.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/api/test_configuration.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/api/test_locations.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/api/utilities/__init__.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/api/utilities/test_filestore_helper.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/api/utilities/test_hdx_error_handler.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/api/utilities/test_hdx_state.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/api/utilities/test_url_utils.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/conftest.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/__init__.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/test_activity.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/test_dataset_add_hapi_error.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/test_dataset_core.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/test_dataset_resource_generation.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/test_organization.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/test_resource_view.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/test_showcase.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/test_update_dataset_resources.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/test_update_logic.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/test_user.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/data/test_vocabulary.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/facades/__init__.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/facades/test_infer_arguments.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/facades/test_keyword_arguments.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/tests/hdx/facades/test_simple.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/uv.lock +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/workingexample/my_code.py +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/workingexample/my_resource.csv +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/workingexample/my_resource.xlsx +0 -0
- {hdx_python_api-6.7.3 → hdx_python_api-6.7.4}/workingexample/run.py +0 -0
|
@@ -647,6 +647,35 @@ This returns a list of dictionaries, each from a resource name to a list of
|
|
|
647
647
|
check events with keys such as `state`, `timestamp`, `sheet_changes` and
|
|
648
648
|
`hxl_proxy_response`.
|
|
649
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
|
+
|
|
650
679
|
### Time Period
|
|
651
680
|
|
|
652
681
|
Time Period is a mandatory field in HDX. It is the earliest start date and
|
|
@@ -964,6 +993,32 @@ HDX:
|
|
|
964
993
|
|
|
965
994
|
events = resource.get_fs_check_info()
|
|
966
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
|
+
|
|
967
1022
|
### Data Dictionary
|
|
968
1023
|
|
|
969
1024
|
A resource can have a data dictionary describing the columns in the data it
|
|
@@ -1041,6 +1096,11 @@ the latest job or None if there is none:
|
|
|
1041
1096
|
submitted = resource.submit_to_datapusher(ignore_hash=True)
|
|
1042
1097
|
status = resource.get_datapusher_status() # eg. status["status"] == "complete"
|
|
1043
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
|
+
|
|
1044
1104
|
To download the whole datastore (rather than the resource's file) use
|
|
1045
1105
|
**download_datastore**, which returns the URL and path like **download**.
|
|
1046
1106
|
`file_format` can be `csv` (default), `tsv`, `json` or `xml`, and `filename`
|
|
@@ -1213,6 +1273,17 @@ since Data Grid membership changes over time, rather than a fixed list):
|
|
|
1213
1273
|
|
|
1214
1274
|
This returns a sorted list of 3-letter location codes.
|
|
1215
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
|
+
|
|
1216
1287
|
You can get the datasets belonging to a location as follows:
|
|
1217
1288
|
|
|
1218
1289
|
datasets = location.get_datasets(**kwargs)
|
|
@@ -1298,6 +1369,14 @@ and push them to analytics:
|
|
|
1298
1369
|
|
|
1299
1370
|
pushed_stats = push_general_stats()
|
|
1300
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
|
+
|
|
1301
1380
|
## Pipeline State
|
|
1302
1381
|
|
|
1303
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)
|
|
@@ -148,6 +148,13 @@ class Dataset(HDXObject):
|
|
|
148
148
|
"autocomplete": "package_autocomplete",
|
|
149
149
|
"create_default_views": "package_create_default_resource_views",
|
|
150
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",
|
|
151
158
|
}
|
|
152
159
|
|
|
153
160
|
def __setitem__(self, key: Any, value: Any) -> None:
|
|
@@ -2347,6 +2354,136 @@ class Dataset(HDXObject):
|
|
|
2347
2354
|
return result
|
|
2348
2355
|
return []
|
|
2349
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
|
+
|
|
2350
2487
|
def generate_resource(
|
|
2351
2488
|
self,
|
|
2352
2489
|
folder: Path | 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.
|
|
@@ -74,6 +74,13 @@ class Resource(HDXObject):
|
|
|
74
74
|
"datastore_search_sql": "datastore_search_sql",
|
|
75
75
|
"datapusher_submit": "datapusher_submit",
|
|
76
76
|
"datapusher_status": "datapusher_status",
|
|
77
|
+
"push_to_datastore": "hdx_push_resource_to_datastore",
|
|
78
|
+
"p_coded": "hdx_p_coded_resource_update",
|
|
79
|
+
"in_hapi": "hdx_mark_resource_in_hapi",
|
|
80
|
+
"in_quarantine": "hdx_mark_resource_in_quarantine",
|
|
81
|
+
"qa_patch": "hdx_qa_resource_patch",
|
|
82
|
+
"fs_check_revise": "hdx_fs_check_resource_revise",
|
|
83
|
+
"fs_check_reset": "hdx_fs_check_resource_reset",
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
def update_from_yaml(
|
|
@@ -1113,6 +1120,20 @@ class Resource(HDXObject):
|
|
|
1113
1120
|
"resource_id",
|
|
1114
1121
|
)
|
|
1115
1122
|
|
|
1123
|
+
def push_to_datastore(self) -> bool:
|
|
1124
|
+
"""Submit the resource to DataPusher+ using HDX's wrapper action.
|
|
1125
|
+
Unlike submit_to_datapusher, this requires sysadmin.
|
|
1126
|
+
|
|
1127
|
+
Returns:
|
|
1128
|
+
True if submitted, False if not
|
|
1129
|
+
"""
|
|
1130
|
+
result = self._write_to_hdx(
|
|
1131
|
+
"push_to_datastore", {"resource_id": self.data["id"]}, "resource_id"
|
|
1132
|
+
)
|
|
1133
|
+
if not result["success"]:
|
|
1134
|
+
logger.debug(result["message"])
|
|
1135
|
+
return result["success"]
|
|
1136
|
+
|
|
1116
1137
|
def get_datapusher_status(self) -> dict | None:
|
|
1117
1138
|
"""Get the status of the resource's latest DataPusher+ job
|
|
1118
1139
|
|
|
@@ -1304,6 +1325,159 @@ class Resource(HDXObject):
|
|
|
1304
1325
|
return json.loads(fs_check_info)
|
|
1305
1326
|
return fs_check_info
|
|
1306
1327
|
|
|
1328
|
+
def _set_from_package(self, package: dict) -> None:
|
|
1329
|
+
"""Set the resource's metadata from the matching resource in a package
|
|
1330
|
+
metadata dictionary returned by HDX
|
|
1331
|
+
|
|
1332
|
+
Args:
|
|
1333
|
+
package: Package metadata dictionary
|
|
1334
|
+
|
|
1335
|
+
Returns:
|
|
1336
|
+
None
|
|
1337
|
+
"""
|
|
1338
|
+
for resource in package.get("resources", []):
|
|
1339
|
+
if resource["id"] == self.data["id"]:
|
|
1340
|
+
self.data = resource
|
|
1341
|
+
return
|
|
1342
|
+
|
|
1343
|
+
def revise_fs_check(self, key: str, value: Any) -> None:
|
|
1344
|
+
"""Set a file structure check field of the resource in HDX. If key is
|
|
1345
|
+
fs_check_info and value is a dictionary, it is appended to the
|
|
1346
|
+
existing check events (the last 20 are kept) rather than replacing
|
|
1347
|
+
them. Requires sysadmin or permission to manage QA.
|
|
1348
|
+
|
|
1349
|
+
Args:
|
|
1350
|
+
key: Resource field eg. fs_check_info
|
|
1351
|
+
value: Value to set
|
|
1352
|
+
|
|
1353
|
+
Returns:
|
|
1354
|
+
None
|
|
1355
|
+
"""
|
|
1356
|
+
result = self._write_to_hdx(
|
|
1357
|
+
"fs_check_revise",
|
|
1358
|
+
{
|
|
1359
|
+
"package_id": self.data["package_id"],
|
|
1360
|
+
"id": self.data["id"],
|
|
1361
|
+
"key": key,
|
|
1362
|
+
"value": value,
|
|
1363
|
+
},
|
|
1364
|
+
"id",
|
|
1365
|
+
)
|
|
1366
|
+
self._set_from_package(result["package"])
|
|
1367
|
+
|
|
1368
|
+
def reset_fs_check(self, key: str = "fs_check_info") -> None:
|
|
1369
|
+
"""Clear a file structure check field of the resource in HDX. Requires
|
|
1370
|
+
sysadmin or permission to manage QA.
|
|
1371
|
+
|
|
1372
|
+
Args:
|
|
1373
|
+
key: Resource field to clear. Defaults to fs_check_info.
|
|
1374
|
+
|
|
1375
|
+
Returns:
|
|
1376
|
+
None
|
|
1377
|
+
"""
|
|
1378
|
+
result = self._write_to_hdx(
|
|
1379
|
+
"fs_check_reset",
|
|
1380
|
+
{"package_id": self.data["package_id"], "id": self.data["id"], "key": key},
|
|
1381
|
+
"id",
|
|
1382
|
+
)
|
|
1383
|
+
self._set_from_package(result["package"])
|
|
1384
|
+
|
|
1385
|
+
def is_p_coded(self) -> bool | None:
|
|
1386
|
+
"""Return if the resource is marked as containing p-codes
|
|
1387
|
+
|
|
1388
|
+
Returns:
|
|
1389
|
+
Whether resource is p-coded or None if not set
|
|
1390
|
+
"""
|
|
1391
|
+
p_coded = self.data.get("p_coded")
|
|
1392
|
+
if p_coded is None:
|
|
1393
|
+
return None
|
|
1394
|
+
if isinstance(p_coded, str):
|
|
1395
|
+
return p_coded.lower() == "true"
|
|
1396
|
+
return p_coded
|
|
1397
|
+
|
|
1398
|
+
def set_p_coded(self, p_coded: bool) -> None:
|
|
1399
|
+
"""Mark the resource in HDX as containing p-codes or not. Requires
|
|
1400
|
+
sysadmin or permission to manage p-codes.
|
|
1401
|
+
|
|
1402
|
+
Args:
|
|
1403
|
+
p_coded: Whether resource is p-coded
|
|
1404
|
+
|
|
1405
|
+
Returns:
|
|
1406
|
+
None
|
|
1407
|
+
"""
|
|
1408
|
+
self.data = self._write_to_hdx(
|
|
1409
|
+
"p_coded", {"id": self.data["id"], "p_coded": p_coded}, "id"
|
|
1410
|
+
)
|
|
1411
|
+
|
|
1412
|
+
def is_in_hapi(self) -> bool:
|
|
1413
|
+
"""Return if the resource is marked as being in HAPI
|
|
1414
|
+
|
|
1415
|
+
Returns:
|
|
1416
|
+
Whether resource is in HAPI
|
|
1417
|
+
"""
|
|
1418
|
+
return self.data.get("in_hapi") == "yes"
|
|
1419
|
+
|
|
1420
|
+
def set_in_hapi(self, in_hapi: bool) -> None:
|
|
1421
|
+
"""Mark the resource in HDX as being in HAPI or not. Requires sysadmin
|
|
1422
|
+
or permission to manage the in HAPI flag.
|
|
1423
|
+
|
|
1424
|
+
Args:
|
|
1425
|
+
in_hapi: Whether resource is in HAPI
|
|
1426
|
+
|
|
1427
|
+
Returns:
|
|
1428
|
+
None
|
|
1429
|
+
"""
|
|
1430
|
+
self.data = self._write_to_hdx(
|
|
1431
|
+
"in_hapi",
|
|
1432
|
+
{"id": self.data["id"], "in_hapi": "yes" if in_hapi else "no-data"},
|
|
1433
|
+
"id",
|
|
1434
|
+
)
|
|
1435
|
+
|
|
1436
|
+
def is_in_quarantine(self) -> bool:
|
|
1437
|
+
"""Return if the resource is in quarantine
|
|
1438
|
+
|
|
1439
|
+
Returns:
|
|
1440
|
+
Whether resource is in quarantine
|
|
1441
|
+
"""
|
|
1442
|
+
in_quarantine = self.data.get("in_quarantine", False)
|
|
1443
|
+
if isinstance(in_quarantine, str):
|
|
1444
|
+
return in_quarantine.lower() == "true"
|
|
1445
|
+
return in_quarantine
|
|
1446
|
+
|
|
1447
|
+
def set_in_quarantine(self, in_quarantine: bool) -> None:
|
|
1448
|
+
"""Put the resource in HDX in quarantine or take it out. Quarantining
|
|
1449
|
+
also removes the resource's shape_info and geopreview. Requires
|
|
1450
|
+
sysadmin or permission to manage QA.
|
|
1451
|
+
|
|
1452
|
+
Args:
|
|
1453
|
+
in_quarantine: Whether resource is in quarantine
|
|
1454
|
+
|
|
1455
|
+
Returns:
|
|
1456
|
+
None
|
|
1457
|
+
"""
|
|
1458
|
+
self.data = self._write_to_hdx(
|
|
1459
|
+
"in_quarantine",
|
|
1460
|
+
{
|
|
1461
|
+
"id": self.data["id"],
|
|
1462
|
+
"in_quarantine": "true" if in_quarantine else "false",
|
|
1463
|
+
},
|
|
1464
|
+
"id",
|
|
1465
|
+
)
|
|
1466
|
+
|
|
1467
|
+
def qa_patch(self, **kwargs: Any) -> None:
|
|
1468
|
+
"""Patch QA fields of the resource in HDX eg. pii, sdc_report_flag,
|
|
1469
|
+
broken_link. Requires sysadmin or permission to manage QA.
|
|
1470
|
+
|
|
1471
|
+
Args:
|
|
1472
|
+
**kwargs: Resource fields to patch
|
|
1473
|
+
|
|
1474
|
+
Returns:
|
|
1475
|
+
None
|
|
1476
|
+
"""
|
|
1477
|
+
self.data = self._write_to_hdx(
|
|
1478
|
+
"qa_patch", {"id": self.data["id"], **kwargs}, "id"
|
|
1479
|
+
)
|
|
1480
|
+
|
|
1307
1481
|
def is_marked_data_updated(self) -> bool:
|
|
1308
1482
|
"""Return if the resource's data is marked to be updated
|
|
1309
1483
|
|
|
@@ -6,7 +6,12 @@ import pytest
|
|
|
6
6
|
|
|
7
7
|
from ... import MockResponse
|
|
8
8
|
from hdx.api.configuration import Configuration
|
|
9
|
-
from hdx.api.utilities.hdx_stats import
|
|
9
|
+
from hdx.api.utilities.hdx_stats import (
|
|
10
|
+
get_general_statistics,
|
|
11
|
+
get_organization_statistics,
|
|
12
|
+
get_user_statistics,
|
|
13
|
+
push_general_stats,
|
|
14
|
+
)
|
|
10
15
|
from hdx.data.hdxobject import HDXError
|
|
11
16
|
|
|
12
17
|
general_statistics = {
|
|
@@ -17,17 +22,30 @@ general_statistics = {
|
|
|
17
22
|
|
|
18
23
|
pushed_stats = {"mixpanel_meta": {"datasets total": 100, "orgs total": 30}}
|
|
19
24
|
|
|
25
|
+
user_statistics = {"USER1": {"id": "USER1", "name": "user1", "no_of_activities": 5}}
|
|
26
|
+
|
|
27
|
+
organization_statistics = {
|
|
28
|
+
"active_organizations": [{"id": "ORG1", "name": "org1"}],
|
|
29
|
+
"inactive_organizations": [],
|
|
30
|
+
}
|
|
31
|
+
|
|
20
32
|
|
|
21
33
|
class TestHDXStats:
|
|
22
34
|
succeed = True
|
|
35
|
+
data = None
|
|
23
36
|
|
|
24
37
|
@pytest.fixture(scope="function")
|
|
25
38
|
def post_stats(self):
|
|
26
39
|
class MockSession:
|
|
27
40
|
@staticmethod
|
|
28
41
|
def post(url, data, **kwargs):
|
|
42
|
+
TestHDXStats.data = json.loads(data.decode("utf-8"))
|
|
29
43
|
if TestHDXStats.succeed:
|
|
30
|
-
if "
|
|
44
|
+
if "hdx_user_statistics" in url:
|
|
45
|
+
result = json.dumps(user_statistics)
|
|
46
|
+
elif "hdx_organization_statistics" in url:
|
|
47
|
+
result = json.dumps(organization_statistics)
|
|
48
|
+
elif "hdx_general_statistics" in url:
|
|
31
49
|
result = json.dumps(general_statistics)
|
|
32
50
|
elif "hdx_push_general_stats" in url:
|
|
33
51
|
result = json.dumps(pushed_stats)
|
|
@@ -49,6 +67,18 @@ class TestHDXStats:
|
|
|
49
67
|
assert get_general_statistics() == general_statistics
|
|
50
68
|
assert get_general_statistics(Configuration.read()) == general_statistics
|
|
51
69
|
|
|
70
|
+
def test_get_user_statistics(self, configuration, post_stats):
|
|
71
|
+
assert get_user_statistics() == user_statistics
|
|
72
|
+
assert TestHDXStats.data == {}
|
|
73
|
+
assert get_user_statistics("2026-01-01", "2026-06-30") == user_statistics
|
|
74
|
+
assert TestHDXStats.data == {
|
|
75
|
+
"start_date": "2026-01-01",
|
|
76
|
+
"end_date": "2026-06-30",
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
def test_get_organization_statistics(self, configuration, post_stats):
|
|
80
|
+
assert get_organization_statistics() == organization_statistics
|
|
81
|
+
|
|
52
82
|
def test_push_general_stats(self, configuration, post_stats):
|
|
53
83
|
assert push_general_stats() == pushed_stats
|
|
54
84
|
TestHDXStats.succeed = False
|