hdx-python-api 6.7.1__tar.gz → 6.7.3__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.1 → hdx_python_api-6.7.3}/PKG-INFO +1 -1
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/documentation/index.md +115 -5
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/api/_version.py +2 -2
- hdx_python_api-6.7.3/src/hdx/api/utilities/hdx_stats.py +47 -0
- hdx_python_api-6.7.3/src/hdx/data/activity.py +247 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/data/dataset.py +41 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/data/hdxobject.py +28 -1
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/data/location.py +17 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/data/organization.py +17 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/data/resource.py +163 -18
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/data/user.py +39 -1
- hdx_python_api-6.7.3/tests/hdx/api/utilities/test_hdx_stats.py +59 -0
- hdx_python_api-6.7.3/tests/hdx/data/test_activity.py +201 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/data/test_dataset_noncore.py +38 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/data/test_resource.py +210 -1
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/data/test_user.py +28 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/.github/workflows/publish.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/.github/workflows/run-python-tests.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/.gitignore +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/.pre-commit-config.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/CLAUDE.md +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/LICENSE +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/README.md +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/documentation/.readthedocs.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/documentation/mkdocs.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/pyproject.toml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/api/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/api/configuration.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/api/hdx_base_configuration.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/api/locations.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/api/remotehdx.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/api/utilities/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/api/utilities/date_helper.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/api/utilities/filestore_helper.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/api/utilities/hdx_error_handler.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/api/utilities/hdx_state.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/api/utilities/url_utils.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/data/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/data/resource_matcher.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/data/resource_view.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/data/showcase.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/data/vocabulary.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/facades/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/facades/infer_arguments.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/facades/keyword_arguments.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/src/hdx/facades/simple.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/Accepted_Tags.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/CKAN/hdx_dataset_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/Tag_Mapping.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/Tag_Mapping_ChainRuleError.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/empty.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_base_config.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_base_config.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_config.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_config.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_dataset_static.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_dataset_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_datasource_topline.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_datasource_topline.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_email_configuration.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_email_configuration.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_missing_site_config.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_organization_static.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_organization_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_resource_static.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_resource_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_resource_view_static.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_resource_view_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_showcase_static.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_showcase_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_user_static.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_user_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_vocabulary_static.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/hdx_vocabulary_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/project_configuration.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/project_configuration.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/user_agent_config.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/user_agent_config2.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/user_agent_config3.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/config/user_agent_config_wrong.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/dataset_search_results.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/download_gen_resource/conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/download_gen_resource/min_qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/download_gen_resource/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/download_gen_resource/test_data_no_data.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/download_gen_resource/test_data_no_years.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/empty.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/gen_resource/conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/gen_resource/min_qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/gen_resource/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/gen_resource/test_data_no_data.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/gen_resource/test_data_no_years.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/location/location_list_all_fields.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/location/location_show_results.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/organization/organization_list_all_fields.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/organization/organization_show_results.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/qc_from_rows/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/qc_from_rows/qc_conflict_data_alg_one_col.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/resource_formats.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/showcase_all_search_results.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/size_hash/ACLED-All-Africa-File_20170101-to-20170708.xlsx +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/state/analysis_dates.txt +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/state/last_build_date.txt +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/test_data.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/test_data.zip +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/update_dataset_resources/dem_data_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/update_dataset_resources/dem_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/update_dataset_resources/expected_resources_to_update.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/update_dataset_resources/opri_data_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/update_dataset_resources/opri_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/update_dataset_resources/opri_metadata_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/update_dataset_resources/qc_sdg_data_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/update_dataset_resources/sdg_data_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/update_dataset_resources/sdg_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/update_dataset_resources/sdg_metadata_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/update_dataset_resources/unesco_dataset.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/update_dataset_resources/unesco_update_dataset.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/update_logic/update_logic_resources.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/fixtures/update_logic/update_logic_resources_new.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/api/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/api/test_ckan.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/api/test_configuration.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/api/test_locations.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/api/utilities/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/api/utilities/test_filestore_helper.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/api/utilities/test_hdx_error_handler.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/api/utilities/test_hdx_state.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/api/utilities/test_url_utils.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/conftest.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/data/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/data/test_dataset_add_hapi_error.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/data/test_dataset_core.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/data/test_dataset_resource_generation.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/data/test_location.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/data/test_organization.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/data/test_resource_view.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/data/test_showcase.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/data/test_update_dataset_resources.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/data/test_update_logic.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/data/test_vocabulary.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/facades/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/facades/test_infer_arguments.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/facades/test_keyword_arguments.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/tests/hdx/facades/test_simple.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/uv.lock +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/workingexample/my_code.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/workingexample/my_resource.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/workingexample/my_resource.xlsx +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.3}/workingexample/run.py +0 -0
|
@@ -35,6 +35,8 @@ upload your datasets to HDX.
|
|
|
35
35
|
- [Organization Management](#organization-management)
|
|
36
36
|
- [Location Management](#location-management)
|
|
37
37
|
- [Vocabulary Management](#vocabulary-management)
|
|
38
|
+
- [Activity Streams](#activity-streams)
|
|
39
|
+
- [HDX Statistics](#hdx-statistics)
|
|
38
40
|
- [Pipeline State](#pipeline-state)
|
|
39
41
|
- [Working Examples](#working-examples)
|
|
40
42
|
- [Project Framework](#project-framework)
|
|
@@ -635,6 +637,16 @@ function, for example:
|
|
|
635
637
|
|
|
636
638
|
dataset.remove_showcase(showcase)
|
|
637
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
|
+
|
|
638
650
|
### Time Period
|
|
639
651
|
|
|
640
652
|
Time Period is a mandatory field in HDX. It is the earliest start date and
|
|
@@ -946,6 +958,12 @@ If the method **set_file_to_upload** is used to supply a file, the resource
|
|
|
946
958
|
`last_modified` field is set to now automatically regardless of the value of
|
|
947
959
|
`data_updated` or whether **mark_data_updated** has been called.
|
|
948
960
|
|
|
961
|
+
The file structure check events of a resource (see Dataset Specific
|
|
962
|
+
Operations) can be obtained from its `fs_check_info` field without a call to
|
|
963
|
+
HDX:
|
|
964
|
+
|
|
965
|
+
events = resource.get_fs_check_info()
|
|
966
|
+
|
|
949
967
|
### Data Dictionary
|
|
950
968
|
|
|
951
969
|
A resource can have a data dictionary describing the columns in the data it
|
|
@@ -973,11 +991,36 @@ using the getter:
|
|
|
973
991
|
|
|
974
992
|
data_dictionary = resource.get_hdx_data_dictionary()
|
|
975
993
|
|
|
994
|
+
To change the data dictionary of a resource already in HDX without sending
|
|
995
|
+
dataset update notifications, use **update_hdx_data_dictionary**. It patches
|
|
996
|
+
only the `hdx_data_dictionary` field (so `last_modified` is unchanged), then,
|
|
997
|
+
if the resource has a datastore, updates the datastore field labels and
|
|
998
|
+
descriptions without reloading the data. The given columns are merged by
|
|
999
|
+
`field` into the existing data dictionary in the resource metadata, so read
|
|
1000
|
+
the resource from HDX first. Pass `replace=True` to replace the data
|
|
1001
|
+
dictionary instead and `update_datastore=False` to leave the datastore alone:
|
|
1002
|
+
|
|
1003
|
+
resource = Resource.read_from_hdx(RESOURCE_ID)
|
|
1004
|
+
resource.update_hdx_data_dictionary([
|
|
1005
|
+
{
|
|
1006
|
+
"field": "col_name",
|
|
1007
|
+
"label": "Column Label",
|
|
1008
|
+
"description": "New description.",
|
|
1009
|
+
},
|
|
1010
|
+
])
|
|
1011
|
+
|
|
1012
|
+
Columns are matched to datastore fields by `field`. A warning is logged for
|
|
1013
|
+
any column with no matching datastore field.
|
|
1014
|
+
|
|
976
1015
|
### Datastore
|
|
977
1016
|
|
|
978
|
-
A resource's data can be loaded into the HDX datastore and queried. HDX
|
|
979
|
-
|
|
980
|
-
|
|
1017
|
+
A resource's data can be loaded into the HDX datastore and queried. HDX calls this
|
|
1018
|
+
[Tabular Data Endpoints (TDE)](https://docs.humdata.org/build/hdx-apis/tabular-data-endpoints),
|
|
1019
|
+
and it is available only for resources with TDE enabled (their `datastore_active`
|
|
1020
|
+
field is true). Contact hdx@un.org to request TDE for your datasets. HDX requires an
|
|
1021
|
+
API key for all datastore actions and dumps, including reads of public resources,
|
|
1022
|
+
and limits each IP address to 60 requests per minute. To create, update or delete
|
|
1023
|
+
the datastore for a resource:
|
|
981
1024
|
|
|
982
1025
|
resource.create_datastore(
|
|
983
1026
|
[{"id": "code", "type": "text"}, {"id": "value", "type": "numeric"}],
|
|
@@ -987,6 +1030,17 @@ public resources. To create, update or delete the datastore for a resource:
|
|
|
987
1030
|
has_datastore = resource.has_datastore()
|
|
988
1031
|
resource.delete_datastore()
|
|
989
1032
|
|
|
1033
|
+
HDX loads uploaded files into the datastore using DataPusher+. To reload a
|
|
1034
|
+
resource's file into the datastore without uploading it again (so
|
|
1035
|
+
`last_modified` is unchanged), use **submit_to_datapusher**. It returns False
|
|
1036
|
+
if the job was not submitted, eg. because one is already pending. HDX's
|
|
1037
|
+
datastore allowlist and format checks, which apply to automatic submissions
|
|
1038
|
+
on upload, are not applied. **get_datapusher_status** returns the status of
|
|
1039
|
+
the latest job or None if there is none:
|
|
1040
|
+
|
|
1041
|
+
submitted = resource.submit_to_datapusher(ignore_hash=True)
|
|
1042
|
+
status = resource.get_datapusher_status() # eg. status["status"] == "complete"
|
|
1043
|
+
|
|
990
1044
|
To download the whole datastore (rather than the resource's file) use
|
|
991
1045
|
**download_datastore**, which returns the URL and path like **download**.
|
|
992
1046
|
`file_format` can be `csv` (default), `tsv`, `json` or `xml`, and `filename`
|
|
@@ -1007,7 +1061,8 @@ and `include_total`, and passes any other keyword arguments to CKAN:
|
|
|
1007
1061
|
records = result["records"]
|
|
1008
1062
|
|
|
1009
1063
|
**get_datastore_records** takes the same query parameters but pages through
|
|
1010
|
-
all matching rows, yielding each record (`page_size` defaults to 10000)
|
|
1064
|
+
all matching rows, yielding each record (`page_size` defaults to 10000).
|
|
1065
|
+
`records_format` csv and tsv are not supported; use `search_datastore` for those:
|
|
1011
1066
|
|
|
1012
1067
|
for record in resource.get_datastore_records(filters={"code": "A"}):
|
|
1013
1068
|
...
|
|
@@ -1019,7 +1074,9 @@ internal `_id` field:
|
|
|
1019
1074
|
|
|
1020
1075
|
**search_datastore_sql** wraps CKAN's `datastore_search_sql`, running a
|
|
1021
1076
|
SELECT statement where tables are named by double quoted resource id and
|
|
1022
|
-
returning the list of records
|
|
1077
|
+
returning the list of records. HDX returns at most 32,000 rows per query and
|
|
1078
|
+
cuts off larger results, in which case a warning is logged (see
|
|
1079
|
+
[paging in the TDE docs](https://docs.humdata.org/build/hdx-apis/tabular-data-endpoints/troubleshooting-and-error-handling#pagination)):
|
|
1023
1080
|
|
|
1024
1081
|
records = Resource.search_datastore_sql(
|
|
1025
1082
|
'SELECT code, SUM(value) AS total FROM "RESOURCE_ID" GROUP BY code'
|
|
@@ -1066,6 +1123,11 @@ configuration):
|
|
|
1066
1123
|
|
|
1067
1124
|
user = User.get_current_user()
|
|
1068
1125
|
|
|
1126
|
+
You can get the name of the API token in the configuration and the md5 hash
|
|
1127
|
+
of its owner's email:
|
|
1128
|
+
|
|
1129
|
+
token_info = User.get_current_token_info() # {"email_hash": ..., "token_name": ...}
|
|
1130
|
+
|
|
1069
1131
|
You can check that the current user has a particular permission to a specific
|
|
1070
1132
|
organization:
|
|
1071
1133
|
|
|
@@ -1188,6 +1250,54 @@ If you want to add a list of tags, you do it as follows:
|
|
|
1188
1250
|
|
|
1189
1251
|
vocabulary.add_tags(["TAG","TAG","TAG"...])
|
|
1190
1252
|
|
|
1253
|
+
## Activity Streams
|
|
1254
|
+
|
|
1255
|
+
The **Activity** class wraps CKAN activities, which record who changed what and when.
|
|
1256
|
+
Activities are read only. You can get the activity stream of a dataset, organization,
|
|
1257
|
+
location or user:
|
|
1258
|
+
|
|
1259
|
+
activities = dataset.get_activities(**kwargs)
|
|
1260
|
+
activities = organization.get_activities(**kwargs)
|
|
1261
|
+
activities = location.get_activities(**kwargs)
|
|
1262
|
+
activities = user.get_activities(**kwargs)
|
|
1263
|
+
|
|
1264
|
+
These return a list of **Activity** objects, each with fields like `timestamp`,
|
|
1265
|
+
`user_id`, `object_id` and `activity_type` (eg. "changed package"). One page of results
|
|
1266
|
+
is returned. Its size is set by `limit` (default 31, HDX maximum 100) and where it starts
|
|
1267
|
+
by `offset`. Passing `all_pages=True` gets every page. Other arguments (`**kwargs`) like
|
|
1268
|
+
`after`, `before` and `activity_types` depend on the object type and are detailed in the
|
|
1269
|
+
API documentation. Getting a user's activity stream requires authorisation to view the
|
|
1270
|
+
user's profile.
|
|
1271
|
+
|
|
1272
|
+
You can get the activity stream of all recently added or changed datasets:
|
|
1273
|
+
|
|
1274
|
+
activities = Activity.get_recently_changed_packages(limit=10)
|
|
1275
|
+
|
|
1276
|
+
With `all_pages=True`, this stream covers the whole history of HDX so it is capped by
|
|
1277
|
+
`max_activities` (default 1000). Pass `max_activities=None` to remove the cap.
|
|
1278
|
+
|
|
1279
|
+
You can read a single activity, get its data (including a snapshot of the object at the
|
|
1280
|
+
time of the activity) or get a diff against the object's previous version. HDX requires
|
|
1281
|
+
permission to edit the object the activity relates to for these:
|
|
1282
|
+
|
|
1283
|
+
activity = Activity.read_from_hdx("ACTIVITY_ID")
|
|
1284
|
+
data = activity.get_data()
|
|
1285
|
+
diff = activity.get_diff(diff_type="unified") # or "context" or "html"
|
|
1286
|
+
|
|
1287
|
+
## HDX Statistics
|
|
1288
|
+
|
|
1289
|
+
General statistics about datasets, organizations and users on HDX can be
|
|
1290
|
+
obtained as follows:
|
|
1291
|
+
|
|
1292
|
+
from hdx.api.utilities.hdx_stats import get_general_statistics, push_general_stats
|
|
1293
|
+
|
|
1294
|
+
stats = get_general_statistics()
|
|
1295
|
+
|
|
1296
|
+
Users with permission to manage basic scheduled tasks can compute the statistics
|
|
1297
|
+
and push them to analytics:
|
|
1298
|
+
|
|
1299
|
+
pushed_stats = push_general_stats()
|
|
1300
|
+
|
|
1191
1301
|
## Pipeline State
|
|
1192
1302
|
|
|
1193
1303
|
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.3'
|
|
22
|
+
__version_tuple__ = version_tuple = (6, 7, 3)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -0,0 +1,47 @@
|
|
|
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(action: str, configuration: Configuration | None) -> dict:
|
|
8
|
+
"""Call an HDX statistics action
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
action: CKAN action name
|
|
12
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
Statistics dictionary
|
|
16
|
+
"""
|
|
17
|
+
if configuration is None:
|
|
18
|
+
configuration = Configuration.read()
|
|
19
|
+
try:
|
|
20
|
+
return configuration.call_remoteckan(action, {})
|
|
21
|
+
except Exception as e:
|
|
22
|
+
raise HDXError(f"Failed when trying to call {action}!") from e
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_general_statistics(configuration: Configuration | None = None) -> dict:
|
|
26
|
+
"""Get general statistics about datasets, organizations and users on HDX
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Dictionary with keys datasets, organizations and users
|
|
33
|
+
"""
|
|
34
|
+
return _call_stats_action("hdx_general_statistics", configuration)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def push_general_stats(configuration: Configuration | None = None) -> dict:
|
|
38
|
+
"""Compute general statistics on HDX and push them to analytics. Requires
|
|
39
|
+
permission to manage basic scheduled tasks.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Statistics that were pushed
|
|
46
|
+
"""
|
|
47
|
+
return _call_stats_action("hdx_push_general_stats", configuration)
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""Activity class containing all logic for reading activity streams."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from collections.abc import Sequence
|
|
5
|
+
from typing import Any, Optional
|
|
6
|
+
|
|
7
|
+
from hdx.api.configuration import Configuration
|
|
8
|
+
from hdx.data.hdxobject import HDXError, HDXObject
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Activity(HDXObject):
|
|
14
|
+
"""Activity class containing all logic for reading activity streams. Activities
|
|
15
|
+
are read only.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
initial_data: Initial activity metadata dictionary. Defaults to None.
|
|
19
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
initial_data: dict | None = None,
|
|
25
|
+
configuration: Configuration | None = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
if not initial_data:
|
|
28
|
+
initial_data = {}
|
|
29
|
+
super().__init__(initial_data, configuration=configuration)
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def actions() -> dict[str, str]:
|
|
33
|
+
"""Dictionary of actions that can be performed on object
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Dictionary of actions that can be performed on object
|
|
37
|
+
"""
|
|
38
|
+
return {
|
|
39
|
+
"show": "activity_show",
|
|
40
|
+
"data_show": "activity_data_show",
|
|
41
|
+
"diff": "activity_diff",
|
|
42
|
+
"package_list": "package_activity_list",
|
|
43
|
+
"organization_list": "organization_activity_list",
|
|
44
|
+
"group_list": "group_activity_list",
|
|
45
|
+
"user_list": "user_activity_list",
|
|
46
|
+
"recently_changed_packages": "recently_changed_packages_activity_list",
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
def read_from_hdx(
|
|
51
|
+
cls, identifier: str, configuration: Configuration | None = None
|
|
52
|
+
) -> Optional["Activity"]:
|
|
53
|
+
"""Reads the activity given by identifier from HDX and returns Activity object.
|
|
54
|
+
HDX requires permission to edit the object the activity relates to.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
identifier: Identifier of activity
|
|
58
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Activity object if successful read, None if not
|
|
62
|
+
"""
|
|
63
|
+
return cls._read_from_hdx_class("activity", identifier, configuration)
|
|
64
|
+
|
|
65
|
+
def get_object_type(self) -> str:
|
|
66
|
+
"""Get the CKAN object type the activity relates to eg. package,
|
|
67
|
+
organization, group or user. This is the last word of the activity type
|
|
68
|
+
(eg. "changed package") with "dataset" (from "follow dataset") mapped to
|
|
69
|
+
"package".
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Object type
|
|
73
|
+
"""
|
|
74
|
+
object_type = self.data["activity_type"].split(" ")[-1]
|
|
75
|
+
if object_type == "dataset":
|
|
76
|
+
return "package"
|
|
77
|
+
return object_type
|
|
78
|
+
|
|
79
|
+
def get_data(self) -> dict:
|
|
80
|
+
"""Get the data of the activity which includes a snapshot of the object
|
|
81
|
+
at the time of the activity. HDX requires permission to edit the object
|
|
82
|
+
the activity relates to.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Activity data
|
|
86
|
+
"""
|
|
87
|
+
return self._write_to_hdx("data_show", {"id": self.data["id"]}, "id")
|
|
88
|
+
|
|
89
|
+
def get_diff(self, diff_type: str = "unified") -> dict:
|
|
90
|
+
"""Get a diff of the object compared to its previous version. HDX requires
|
|
91
|
+
permission to edit the object the activity relates to.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
diff_type: One of unified, context or html. Defaults to unified.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Activity diff
|
|
98
|
+
"""
|
|
99
|
+
data = {
|
|
100
|
+
"id": self.data["id"],
|
|
101
|
+
"object_type": self.get_object_type(),
|
|
102
|
+
"diff_type": diff_type,
|
|
103
|
+
}
|
|
104
|
+
return self._write_to_hdx("diff", data, "id")
|
|
105
|
+
|
|
106
|
+
@classmethod
|
|
107
|
+
def _get_list(
|
|
108
|
+
cls,
|
|
109
|
+
action: str,
|
|
110
|
+
data: dict,
|
|
111
|
+
configuration: Configuration | None = None,
|
|
112
|
+
all_pages: bool = False,
|
|
113
|
+
max_activities: int | None = None,
|
|
114
|
+
) -> list["Activity"]:
|
|
115
|
+
"""Helper method to get a list of activities from HDX
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
action: Action to perform
|
|
119
|
+
data: Data to pass to CKAN including any offset and limit
|
|
120
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
121
|
+
all_pages: Whether to get all pages of results. Defaults to False.
|
|
122
|
+
max_activities: Maximum number of activities if all_pages is True. Defaults to None (no maximum).
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
List of Activity objects
|
|
126
|
+
"""
|
|
127
|
+
activity = cls(configuration=configuration)
|
|
128
|
+
if not all_pages:
|
|
129
|
+
result = activity._write_to_hdx(action, data)
|
|
130
|
+
return [cls(x, configuration=configuration) for x in result]
|
|
131
|
+
data = dict(data)
|
|
132
|
+
# HDX silently caps limit at ckan.activity_list_limit_max
|
|
133
|
+
limit = min(data.get("limit", 100), 100)
|
|
134
|
+
data["limit"] = limit
|
|
135
|
+
offset = data.get("offset", 0)
|
|
136
|
+
activities = []
|
|
137
|
+
while True:
|
|
138
|
+
data["offset"] = offset
|
|
139
|
+
result = activity._write_to_hdx(action, data)
|
|
140
|
+
activities.extend(cls(x, configuration=configuration) for x in result)
|
|
141
|
+
if max_activities is not None and len(activities) >= max_activities:
|
|
142
|
+
return activities[:max_activities]
|
|
143
|
+
if len(result) < limit:
|
|
144
|
+
return activities
|
|
145
|
+
offset += limit
|
|
146
|
+
|
|
147
|
+
@classmethod
|
|
148
|
+
def get_activities(
|
|
149
|
+
cls,
|
|
150
|
+
object_type: str,
|
|
151
|
+
identifier: str,
|
|
152
|
+
configuration: Configuration | None = None,
|
|
153
|
+
all_pages: bool = False,
|
|
154
|
+
**kwargs: Any,
|
|
155
|
+
) -> list["Activity"]:
|
|
156
|
+
"""Get the activity stream of a CKAN object. One page of results (whose
|
|
157
|
+
size is given by limit) is returned unless all_pages is True.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
object_type: One of package, organization, group or user
|
|
161
|
+
identifier: Id or name of object
|
|
162
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
163
|
+
all_pages: Whether to get all pages of results. Defaults to False.
|
|
164
|
+
**kwargs: See below
|
|
165
|
+
offset (int): Where to start getting activity items from. Defaults to 0.
|
|
166
|
+
limit (int): Maximum number of activities per page. Defaults to 31 (HDX maximum 100) or 100 if all_pages is True.
|
|
167
|
+
after (int | str): Only activities after this timestamp (package and user only)
|
|
168
|
+
before (int | str): Only activities before this timestamp (package and user only)
|
|
169
|
+
include_hidden_activity (bool): Include hidden activity, sysadmins only (package, organization and group only)
|
|
170
|
+
activity_types (list): Activity types to include (package only)
|
|
171
|
+
exclude_activity_types (list): Activity types to exclude (package only)
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
List of Activity objects
|
|
175
|
+
"""
|
|
176
|
+
if not identifier:
|
|
177
|
+
raise HDXError(f"No id or name for {object_type} to get activities!")
|
|
178
|
+
data = {"id": identifier}
|
|
179
|
+
data.update(kwargs)
|
|
180
|
+
return cls._get_list(f"{object_type}_list", data, configuration, all_pages)
|
|
181
|
+
|
|
182
|
+
@classmethod
|
|
183
|
+
def get_recently_changed_packages(
|
|
184
|
+
cls,
|
|
185
|
+
configuration: Configuration | None = None,
|
|
186
|
+
all_pages: bool = False,
|
|
187
|
+
max_activities: int | None = 1000,
|
|
188
|
+
**kwargs: Any,
|
|
189
|
+
) -> list["Activity"]:
|
|
190
|
+
"""Get the activity stream of all recently added or changed datasets.
|
|
191
|
+
One page of results (whose size is given by limit) is returned unless
|
|
192
|
+
all_pages is True. all_pages is capped by max_activities because the
|
|
193
|
+
stream covers the whole history of HDX.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
197
|
+
all_pages: Whether to get all pages of results. Defaults to False.
|
|
198
|
+
max_activities: Maximum number of activities if all_pages is True. Defaults to 1000. None means no maximum (very slow).
|
|
199
|
+
**kwargs: See below
|
|
200
|
+
offset (int): Where to start getting activity items from. Defaults to 0.
|
|
201
|
+
limit (int): Maximum number of activities per page. Defaults to 31 (HDX maximum 100) or 100 if all_pages is True.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
List of Activity objects
|
|
205
|
+
"""
|
|
206
|
+
return cls._get_list(
|
|
207
|
+
"recently_changed_packages",
|
|
208
|
+
kwargs,
|
|
209
|
+
configuration,
|
|
210
|
+
all_pages,
|
|
211
|
+
max_activities,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
def check_required_fields(self, ignore_fields: Sequence[str] = ()) -> None:
|
|
215
|
+
"""Activities are read only so this raises an exception
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
ignore_fields: Fields to ignore. Default is ().
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
None
|
|
222
|
+
"""
|
|
223
|
+
raise HDXError("Activities are read only!")
|
|
224
|
+
|
|
225
|
+
def update_in_hdx(self, **kwargs: Any) -> None:
|
|
226
|
+
"""Activities are read only so this raises an exception
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
None
|
|
230
|
+
"""
|
|
231
|
+
raise HDXError("Activities are read only!")
|
|
232
|
+
|
|
233
|
+
def create_in_hdx(self, **kwargs: Any) -> None:
|
|
234
|
+
"""Activities are read only so this raises an exception
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
None
|
|
238
|
+
"""
|
|
239
|
+
raise HDXError("Activities are read only!")
|
|
240
|
+
|
|
241
|
+
def delete_from_hdx(self) -> None:
|
|
242
|
+
"""Activities are read only so this raises an exception
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
None
|
|
246
|
+
"""
|
|
247
|
+
raise HDXError("Activities are read only!")
|
|
@@ -40,6 +40,7 @@ from hdx.api.configuration import Configuration
|
|
|
40
40
|
from hdx.api.locations import Locations
|
|
41
41
|
from hdx.api.utilities.date_helper import DateHelper
|
|
42
42
|
from hdx.api.utilities.filestore_helper import FilestoreHelper
|
|
43
|
+
from hdx.data.activity import Activity
|
|
43
44
|
from hdx.data.hdxobject import HDXError, HDXObject
|
|
44
45
|
from hdx.data.resource_matcher import ResourceMatcher
|
|
45
46
|
|
|
@@ -146,6 +147,7 @@ class Dataset(HDXObject):
|
|
|
146
147
|
"list": "package_list",
|
|
147
148
|
"autocomplete": "package_autocomplete",
|
|
148
149
|
"create_default_views": "package_create_default_resource_views",
|
|
150
|
+
"fs_check_info": "fs_check_info_show",
|
|
149
151
|
}
|
|
150
152
|
|
|
151
153
|
def __setitem__(self, key: Any, value: Any) -> None:
|
|
@@ -1428,6 +1430,26 @@ class Dataset(HDXObject):
|
|
|
1428
1430
|
resources.append(resource)
|
|
1429
1431
|
return resources
|
|
1430
1432
|
|
|
1433
|
+
def get_activities(self, all_pages: bool = False, **kwargs: Any) -> list[Activity]:
|
|
1434
|
+
"""Get the activity stream of this dataset. One page of results (whose size
|
|
1435
|
+
is given by limit) is returned unless all_pages is True.
|
|
1436
|
+
|
|
1437
|
+
Args:
|
|
1438
|
+
all_pages: Whether to get all pages of results. Defaults to False.
|
|
1439
|
+
**kwargs: See below
|
|
1440
|
+
offset (int): Where to start getting activity items from. Defaults to 0.
|
|
1441
|
+
limit (int): Maximum number of activities per page. Defaults to 31 (HDX maximum 100) or 100 if all_pages is True.
|
|
1442
|
+
after (int | str): Only activities after this timestamp
|
|
1443
|
+
before (int | str): Only activities before this timestamp
|
|
1444
|
+
include_hidden_activity (bool): Include hidden activity (sysadmins only)
|
|
1445
|
+
activity_types (list): Activity types to include
|
|
1446
|
+
exclude_activity_types (list): Activity types to exclude
|
|
1447
|
+
|
|
1448
|
+
Returns:
|
|
1449
|
+
List of Activity objects
|
|
1450
|
+
"""
|
|
1451
|
+
return self._get_activities("package", all_pages, **kwargs)
|
|
1452
|
+
|
|
1431
1453
|
@classmethod
|
|
1432
1454
|
def autocomplete(
|
|
1433
1455
|
cls,
|
|
@@ -2306,6 +2328,25 @@ class Dataset(HDXObject):
|
|
|
2306
2328
|
return None
|
|
2307
2329
|
return f"{self.configuration.get_hdx_site_url()}/api/3/action/package_show?id={name_or_id}"
|
|
2308
2330
|
|
|
2331
|
+
def get_fs_check_info(self) -> list[dict]:
|
|
2332
|
+
"""Get file structure check information for the dataset's resources
|
|
2333
|
+
from HDX. Each list item is a dictionary from resource name to a list
|
|
2334
|
+
of check events, each of which can have keys such as state, timestamp,
|
|
2335
|
+
sheet_changes and hxl_proxy_response.
|
|
2336
|
+
|
|
2337
|
+
Returns:
|
|
2338
|
+
List of dictionaries from resource name to file structure checks
|
|
2339
|
+
"""
|
|
2340
|
+
success, result = self._read_from_hdx(
|
|
2341
|
+
"dataset",
|
|
2342
|
+
self.get_name_or_id(prefer_name=False),
|
|
2343
|
+
"id",
|
|
2344
|
+
self.actions()["fs_check_info"],
|
|
2345
|
+
)
|
|
2346
|
+
if success:
|
|
2347
|
+
return result
|
|
2348
|
+
return []
|
|
2349
|
+
|
|
2309
2350
|
def generate_resource(
|
|
2310
2351
|
self,
|
|
2311
2352
|
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,
|
|
@@ -5,6 +5,7 @@ from collections.abc import Sequence
|
|
|
5
5
|
from typing import Any, Optional
|
|
6
6
|
|
|
7
7
|
from hdx.api.configuration import Configuration
|
|
8
|
+
from hdx.data.activity import Activity
|
|
8
9
|
from hdx.data.hdxobject import HDXObject
|
|
9
10
|
|
|
10
11
|
logger = logging.getLogger(__name__)
|
|
@@ -217,6 +218,22 @@ class Location(HDXObject):
|
|
|
217
218
|
if len(group["name"]) == 3 and group.get("data_completeness") == "active"
|
|
218
219
|
)
|
|
219
220
|
|
|
221
|
+
def get_activities(self, all_pages: bool = False, **kwargs: Any) -> list[Activity]:
|
|
222
|
+
"""Get the activity stream of this location. One page of results (whose size
|
|
223
|
+
is given by limit) is returned unless all_pages is True.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
all_pages: Whether to get all pages of results. Defaults to False.
|
|
227
|
+
**kwargs: See below
|
|
228
|
+
offset (int): Where to start getting activity items from. Defaults to 0.
|
|
229
|
+
limit (int): Maximum number of activities per page. Defaults to 31 (HDX maximum 100) or 100 if all_pages is True.
|
|
230
|
+
include_hidden_activity (bool): Include hidden activity (sysadmins only)
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
List of Activity objects
|
|
234
|
+
"""
|
|
235
|
+
return self._get_activities("group", all_pages, **kwargs)
|
|
236
|
+
|
|
220
237
|
@classmethod
|
|
221
238
|
def autocomplete(
|
|
222
239
|
cls,
|
|
@@ -8,6 +8,7 @@ from typing import TYPE_CHECKING, Any, Optional, Union
|
|
|
8
8
|
import hdx.data.dataset
|
|
9
9
|
import hdx.data.user as user_module
|
|
10
10
|
from hdx.api.configuration import Configuration
|
|
11
|
+
from hdx.data.activity import Activity
|
|
11
12
|
from hdx.data.hdxobject import HDXError, HDXObject
|
|
12
13
|
|
|
13
14
|
if TYPE_CHECKING:
|
|
@@ -311,6 +312,22 @@ class Organization(HDXObject):
|
|
|
311
312
|
|
|
312
313
|
return final_orgs
|
|
313
314
|
|
|
315
|
+
def get_activities(self, all_pages: bool = False, **kwargs: Any) -> list[Activity]:
|
|
316
|
+
"""Get the activity stream of this organization. One page of results (whose size
|
|
317
|
+
is given by limit) is returned unless all_pages is True.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
all_pages: Whether to get all pages of results. Defaults to False.
|
|
321
|
+
**kwargs: See below
|
|
322
|
+
offset (int): Where to start getting activity items from. Defaults to 0.
|
|
323
|
+
limit (int): Maximum number of activities per page. Defaults to 31 (HDX maximum 100) or 100 if all_pages is True.
|
|
324
|
+
include_hidden_activity (bool): Include hidden activity (sysadmins only)
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
List of Activity objects
|
|
328
|
+
"""
|
|
329
|
+
return self._get_activities("organization", all_pages, **kwargs)
|
|
330
|
+
|
|
314
331
|
@classmethod
|
|
315
332
|
def autocomplete(
|
|
316
333
|
cls,
|