hdx-python-api 6.7.1__tar.gz → 6.7.2__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.2}/PKG-INFO +1 -1
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/documentation/index.md +35 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/api/_version.py +2 -2
- hdx_python_api-6.7.2/src/hdx/data/activity.py +245 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/data/dataset.py +27 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/data/location.py +23 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/data/organization.py +23 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/data/user.py +25 -0
- hdx_python_api-6.7.2/tests/hdx/data/test_activity.py +196 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/.github/workflows/publish.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/.github/workflows/run-python-tests.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/.gitignore +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/.pre-commit-config.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/CLAUDE.md +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/LICENSE +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/README.md +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/documentation/.readthedocs.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/documentation/mkdocs.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/pyproject.toml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/api/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/api/configuration.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/api/hdx_base_configuration.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/api/locations.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/api/remotehdx.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/api/utilities/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/api/utilities/date_helper.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/api/utilities/filestore_helper.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/api/utilities/hdx_error_handler.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/api/utilities/hdx_state.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/api/utilities/url_utils.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/data/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/data/hdxobject.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/data/resource.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/data/resource_matcher.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/data/resource_view.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/data/showcase.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/data/vocabulary.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/facades/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/facades/infer_arguments.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/facades/keyword_arguments.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/src/hdx/facades/simple.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/Accepted_Tags.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/CKAN/hdx_dataset_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/Tag_Mapping.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/Tag_Mapping_ChainRuleError.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/empty.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_base_config.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_base_config.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_config.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_config.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_dataset_static.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_dataset_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_datasource_topline.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_datasource_topline.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_email_configuration.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_email_configuration.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_missing_site_config.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_organization_static.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_organization_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_resource_static.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_resource_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_resource_view_static.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_resource_view_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_showcase_static.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_showcase_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_user_static.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_user_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_vocabulary_static.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_vocabulary_static.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/project_configuration.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/project_configuration.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/user_agent_config.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/user_agent_config2.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/user_agent_config3.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/user_agent_config_wrong.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/dataset_search_results.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/download_gen_resource/conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/download_gen_resource/min_qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/download_gen_resource/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/download_gen_resource/test_data_no_data.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/download_gen_resource/test_data_no_years.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/empty.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/gen_resource/conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/gen_resource/min_qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/gen_resource/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/gen_resource/test_data_no_data.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/gen_resource/test_data_no_years.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/location/location_list_all_fields.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/location/location_show_results.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/organization/organization_list_all_fields.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/organization/organization_show_results.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/qc_from_rows/qc_conflict_data_alg.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/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.2}/tests/fixtures/resource_formats.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/showcase_all_search_results.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/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.2}/tests/fixtures/state/analysis_dates.txt +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/state/last_build_date.txt +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/test_data.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/test_data.zip +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/update_dataset_resources/dem_data_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/update_dataset_resources/dem_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/update_dataset_resources/expected_resources_to_update.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/update_dataset_resources/opri_data_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/update_dataset_resources/opri_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/update_dataset_resources/opri_metadata_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/update_dataset_resources/qc_sdg_data_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/update_dataset_resources/sdg_data_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/update_dataset_resources/sdg_indicatorlist_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/update_dataset_resources/sdg_metadata_zwe.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/update_dataset_resources/unesco_dataset.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/update_dataset_resources/unesco_update_dataset.json +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/update_logic/update_logic_resources.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/update_logic/update_logic_resources_new.yaml +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/api/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/api/test_ckan.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/api/test_configuration.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/api/test_locations.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/api/utilities/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/api/utilities/test_filestore_helper.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/api/utilities/test_hdx_error_handler.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/api/utilities/test_hdx_state.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/api/utilities/test_url_utils.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/conftest.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_dataset_add_hapi_error.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_dataset_core.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_dataset_noncore.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_dataset_resource_generation.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_location.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_organization.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_resource.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_resource_view.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_showcase.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_update_dataset_resources.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_update_logic.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_user.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_vocabulary.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/facades/__init__.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/facades/test_infer_arguments.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/facades/test_keyword_arguments.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/facades/test_simple.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/uv.lock +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/workingexample/my_code.py +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/workingexample/my_resource.csv +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/workingexample/my_resource.xlsx +0 -0
- {hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/workingexample/run.py +0 -0
|
@@ -35,6 +35,7 @@ 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)
|
|
38
39
|
- [Pipeline State](#pipeline-state)
|
|
39
40
|
- [Working Examples](#working-examples)
|
|
40
41
|
- [Project Framework](#project-framework)
|
|
@@ -1188,6 +1189,40 @@ If you want to add a list of tags, you do it as follows:
|
|
|
1188
1189
|
|
|
1189
1190
|
vocabulary.add_tags(["TAG","TAG","TAG"...])
|
|
1190
1191
|
|
|
1192
|
+
## Activity Streams
|
|
1193
|
+
|
|
1194
|
+
The **Activity** class wraps CKAN activities, which record who changed what and when.
|
|
1195
|
+
Activities are read only. You can get the activity stream of a dataset, organization,
|
|
1196
|
+
location or user:
|
|
1197
|
+
|
|
1198
|
+
activities = dataset.get_activities(**kwargs)
|
|
1199
|
+
activities = organization.get_activities(**kwargs)
|
|
1200
|
+
activities = location.get_activities(**kwargs)
|
|
1201
|
+
activities = user.get_activities(**kwargs)
|
|
1202
|
+
|
|
1203
|
+
These return a list of **Activity** objects, each with fields like `timestamp`,
|
|
1204
|
+
`user_id`, `object_id` and `activity_type` (eg. "changed package"). One page of results
|
|
1205
|
+
is returned. Its size is set by `limit` (default 31, HDX maximum 100) and where it starts
|
|
1206
|
+
by `offset`. Passing `all_pages=True` gets every page. Other arguments (`**kwargs`) like
|
|
1207
|
+
`after`, `before` and `activity_types` depend on the object type and are detailed in the
|
|
1208
|
+
API documentation. Getting a user's activity stream requires authorisation to view the
|
|
1209
|
+
user's profile.
|
|
1210
|
+
|
|
1211
|
+
You can get the activity stream of all recently added or changed datasets:
|
|
1212
|
+
|
|
1213
|
+
activities = Activity.get_recently_changed_packages(limit=10)
|
|
1214
|
+
|
|
1215
|
+
With `all_pages=True`, this stream covers the whole history of HDX so it is capped by
|
|
1216
|
+
`max_activities` (default 1000). Pass `max_activities=None` to remove the cap.
|
|
1217
|
+
|
|
1218
|
+
You can read a single activity, get its data (including a snapshot of the object at the
|
|
1219
|
+
time of the activity) or get a diff against the object's previous version. HDX requires
|
|
1220
|
+
permission to edit the object the activity relates to for these:
|
|
1221
|
+
|
|
1222
|
+
activity = Activity.read_from_hdx("ACTIVITY_ID")
|
|
1223
|
+
data = activity.get_data()
|
|
1224
|
+
diff = activity.get_diff(diff_type="unified") # or "context" or "html"
|
|
1225
|
+
|
|
1191
1226
|
## Pipeline State
|
|
1192
1227
|
|
|
1193
1228
|
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.2'
|
|
22
|
+
__version_tuple__ = version_tuple = (6, 7, 2)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -0,0 +1,245 @@
|
|
|
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
|
+
limit = data.setdefault("limit", 100)
|
|
133
|
+
offset = data.get("offset", 0)
|
|
134
|
+
activities = []
|
|
135
|
+
while True:
|
|
136
|
+
data["offset"] = offset
|
|
137
|
+
result = activity._write_to_hdx(action, data)
|
|
138
|
+
activities.extend(cls(x, configuration=configuration) for x in result)
|
|
139
|
+
if max_activities is not None and len(activities) >= max_activities:
|
|
140
|
+
return activities[:max_activities]
|
|
141
|
+
if len(result) < limit:
|
|
142
|
+
return activities
|
|
143
|
+
offset += limit
|
|
144
|
+
|
|
145
|
+
@classmethod
|
|
146
|
+
def get_activities(
|
|
147
|
+
cls,
|
|
148
|
+
object_type: str,
|
|
149
|
+
identifier: str,
|
|
150
|
+
configuration: Configuration | None = None,
|
|
151
|
+
all_pages: bool = False,
|
|
152
|
+
**kwargs: Any,
|
|
153
|
+
) -> list["Activity"]:
|
|
154
|
+
"""Get the activity stream of a CKAN object. One page of results (whose
|
|
155
|
+
size is given by limit) is returned unless all_pages is True.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
object_type: One of package, organization, group or user
|
|
159
|
+
identifier: Id or name of object
|
|
160
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
161
|
+
all_pages: Whether to get all pages of results. Defaults to False.
|
|
162
|
+
**kwargs: See below
|
|
163
|
+
offset (int): Where to start getting activity items from. Defaults to 0.
|
|
164
|
+
limit (int): Maximum number of activities per page. Defaults to 31 (HDX maximum 100) or 100 if all_pages is True.
|
|
165
|
+
after (int | str): Only activities after this timestamp (package and user only)
|
|
166
|
+
before (int | str): Only activities before this timestamp (package and user only)
|
|
167
|
+
include_hidden_activity (bool): Include hidden activity, sysadmins only (package, organization and group only)
|
|
168
|
+
activity_types (list): Activity types to include (package only)
|
|
169
|
+
exclude_activity_types (list): Activity types to exclude (package only)
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
List of Activity objects
|
|
173
|
+
"""
|
|
174
|
+
if not identifier:
|
|
175
|
+
raise HDXError(f"No id or name for {object_type} to get activities!")
|
|
176
|
+
data = {"id": identifier}
|
|
177
|
+
data.update(kwargs)
|
|
178
|
+
return cls._get_list(f"{object_type}_list", data, configuration, all_pages)
|
|
179
|
+
|
|
180
|
+
@classmethod
|
|
181
|
+
def get_recently_changed_packages(
|
|
182
|
+
cls,
|
|
183
|
+
configuration: Configuration | None = None,
|
|
184
|
+
all_pages: bool = False,
|
|
185
|
+
max_activities: int | None = 1000,
|
|
186
|
+
**kwargs: Any,
|
|
187
|
+
) -> list["Activity"]:
|
|
188
|
+
"""Get the activity stream of all recently added or changed datasets.
|
|
189
|
+
One page of results (whose size is given by limit) is returned unless
|
|
190
|
+
all_pages is True. all_pages is capped by max_activities because the
|
|
191
|
+
stream covers the whole history of HDX.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
195
|
+
all_pages: Whether to get all pages of results. Defaults to False.
|
|
196
|
+
max_activities: Maximum number of activities if all_pages is True. Defaults to 1000. None means no maximum (very slow).
|
|
197
|
+
**kwargs: See below
|
|
198
|
+
offset (int): Where to start getting activity items from. Defaults to 0.
|
|
199
|
+
limit (int): Maximum number of activities per page. Defaults to 31 (HDX maximum 100) or 100 if all_pages is True.
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
List of Activity objects
|
|
203
|
+
"""
|
|
204
|
+
return cls._get_list(
|
|
205
|
+
"recently_changed_packages",
|
|
206
|
+
kwargs,
|
|
207
|
+
configuration,
|
|
208
|
+
all_pages,
|
|
209
|
+
max_activities,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
def check_required_fields(self, ignore_fields: Sequence[str] = ()) -> None:
|
|
213
|
+
"""Activities are read only so this raises an exception
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
ignore_fields: Fields to ignore. Default is ().
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
None
|
|
220
|
+
"""
|
|
221
|
+
raise HDXError("Activities are read only!")
|
|
222
|
+
|
|
223
|
+
def update_in_hdx(self, **kwargs: Any) -> None:
|
|
224
|
+
"""Activities are read only so this raises an exception
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
None
|
|
228
|
+
"""
|
|
229
|
+
raise HDXError("Activities are read only!")
|
|
230
|
+
|
|
231
|
+
def create_in_hdx(self, **kwargs: Any) -> None:
|
|
232
|
+
"""Activities are read only so this raises an exception
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
None
|
|
236
|
+
"""
|
|
237
|
+
raise HDXError("Activities are read only!")
|
|
238
|
+
|
|
239
|
+
def delete_from_hdx(self) -> None:
|
|
240
|
+
"""Activities are read only so this raises an exception
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
None
|
|
244
|
+
"""
|
|
245
|
+
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
|
|
|
@@ -1428,6 +1429,32 @@ class Dataset(HDXObject):
|
|
|
1428
1429
|
resources.append(resource)
|
|
1429
1430
|
return resources
|
|
1430
1431
|
|
|
1432
|
+
def get_activities(self, all_pages: bool = False, **kwargs: Any) -> list[Activity]:
|
|
1433
|
+
"""Get the activity stream of this dataset. One page of results (whose size
|
|
1434
|
+
is given by limit) is returned unless all_pages is True.
|
|
1435
|
+
|
|
1436
|
+
Args:
|
|
1437
|
+
all_pages: Whether to get all pages of results. Defaults to False.
|
|
1438
|
+
**kwargs: See below
|
|
1439
|
+
offset (int): Where to start getting activity items from. Defaults to 0.
|
|
1440
|
+
limit (int): Maximum number of activities per page. Defaults to 31 (HDX maximum 100) or 100 if all_pages is True.
|
|
1441
|
+
after (int | str): Only activities after this timestamp
|
|
1442
|
+
before (int | str): Only activities before this timestamp
|
|
1443
|
+
include_hidden_activity (bool): Include hidden activity (sysadmins only)
|
|
1444
|
+
activity_types (list): Activity types to include
|
|
1445
|
+
exclude_activity_types (list): Activity types to exclude
|
|
1446
|
+
|
|
1447
|
+
Returns:
|
|
1448
|
+
List of Activity objects
|
|
1449
|
+
"""
|
|
1450
|
+
return Activity.get_activities(
|
|
1451
|
+
"package",
|
|
1452
|
+
self.data.get("id") or self.data.get("name"),
|
|
1453
|
+
self.configuration,
|
|
1454
|
+
all_pages,
|
|
1455
|
+
**kwargs,
|
|
1456
|
+
)
|
|
1457
|
+
|
|
1431
1458
|
@classmethod
|
|
1432
1459
|
def autocomplete(
|
|
1433
1460
|
cls,
|
|
@@ -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,28 @@ 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 Activity.get_activities(
|
|
236
|
+
"group",
|
|
237
|
+
self.data.get("id") or self.data.get("name"),
|
|
238
|
+
self.configuration,
|
|
239
|
+
all_pages,
|
|
240
|
+
**kwargs,
|
|
241
|
+
)
|
|
242
|
+
|
|
220
243
|
@classmethod
|
|
221
244
|
def autocomplete(
|
|
222
245
|
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,28 @@ 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 Activity.get_activities(
|
|
330
|
+
"organization",
|
|
331
|
+
self.data.get("id") or self.data.get("name"),
|
|
332
|
+
self.configuration,
|
|
333
|
+
all_pages,
|
|
334
|
+
**kwargs,
|
|
335
|
+
)
|
|
336
|
+
|
|
314
337
|
@classmethod
|
|
315
338
|
def autocomplete(
|
|
316
339
|
cls,
|
|
@@ -7,6 +7,7 @@ from typing import Any, Optional
|
|
|
7
7
|
|
|
8
8
|
import hdx.data.organization
|
|
9
9
|
from hdx.api.configuration import Configuration
|
|
10
|
+
from hdx.data.activity import Activity
|
|
10
11
|
from hdx.data.hdxobject import HDXError, HDXObject
|
|
11
12
|
|
|
12
13
|
logger = logging.getLogger(__name__)
|
|
@@ -453,6 +454,30 @@ class User(HDXObject):
|
|
|
453
454
|
return result
|
|
454
455
|
return []
|
|
455
456
|
|
|
457
|
+
def get_activities(self, all_pages: bool = False, **kwargs: Any) -> list[Activity]:
|
|
458
|
+
"""Get the activity stream of this user. One page of results (whose size
|
|
459
|
+
is given by limit) is returned unless all_pages is True. HDX requires
|
|
460
|
+
authorisation to view the user's profile.
|
|
461
|
+
|
|
462
|
+
Args:
|
|
463
|
+
all_pages: Whether to get all pages of results. Defaults to False.
|
|
464
|
+
**kwargs: See below
|
|
465
|
+
offset (int): Where to start getting activity items from. Defaults to 0.
|
|
466
|
+
limit (int): Maximum number of activities per page. Defaults to 31 (HDX maximum 100) or 100 if all_pages is True.
|
|
467
|
+
after (int | str): Only activities after this timestamp
|
|
468
|
+
before (int | str): Only activities before this timestamp
|
|
469
|
+
|
|
470
|
+
Returns:
|
|
471
|
+
List of Activity objects
|
|
472
|
+
"""
|
|
473
|
+
return Activity.get_activities(
|
|
474
|
+
"user",
|
|
475
|
+
self.data.get("id") or self.data.get("name"),
|
|
476
|
+
self.configuration,
|
|
477
|
+
all_pages,
|
|
478
|
+
**kwargs,
|
|
479
|
+
)
|
|
480
|
+
|
|
456
481
|
@classmethod
|
|
457
482
|
def autocomplete(
|
|
458
483
|
cls,
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"""Activity Tests"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from .. import MockResponse
|
|
8
|
+
from hdx.api.configuration import Configuration
|
|
9
|
+
from hdx.data.activity import Activity
|
|
10
|
+
from hdx.data.dataset import Dataset
|
|
11
|
+
from hdx.data.hdxobject import HDXError
|
|
12
|
+
from hdx.data.location import Location
|
|
13
|
+
from hdx.data.organization import Organization
|
|
14
|
+
from hdx.data.user import User
|
|
15
|
+
|
|
16
|
+
activity_id = "7d18e25e-c004-4e9f-8f6b-a4b4fe8a0159"
|
|
17
|
+
activity = {
|
|
18
|
+
"id": activity_id,
|
|
19
|
+
"timestamp": "2026-10-14T01:49:59.740998",
|
|
20
|
+
"user_id": "52c8d2f3-a0d6-4cd9-8765-cf5cb4b67427",
|
|
21
|
+
"object_id": "38772da7-c0b0-477e-a60e-a385a9dd4d64",
|
|
22
|
+
"activity_type": "changed package",
|
|
23
|
+
"permission_labels": ["public"],
|
|
24
|
+
}
|
|
25
|
+
activity_data = {"package": {"name": "test-dataset"}, "actor": "testuser"}
|
|
26
|
+
activity_diff = {"diff": "--- a\n+++ b\n", "activities": []}
|
|
27
|
+
|
|
28
|
+
total_activities = 250
|
|
29
|
+
activities = [
|
|
30
|
+
activity | {"id": f"activity{i}", "timestamp": str(i)}
|
|
31
|
+
for i in range(total_activities)
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def mockresponse(result, action):
|
|
36
|
+
return MockResponse(
|
|
37
|
+
200,
|
|
38
|
+
f'{{"success": true, "result": {json.dumps(result)}, "help": "http://test-data.humdata.org/api/3/action/help_show?name={action}"}}',
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def mocknotfound(action):
|
|
43
|
+
return MockResponse(
|
|
44
|
+
404,
|
|
45
|
+
f'{{"success": false, "error": {{"message": "Not found", "__type": "Not Found Error"}}, "help": "http://test-data.humdata.org/api/3/action/help_show?name={action}"}}',
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class TestActivity:
|
|
50
|
+
calls = []
|
|
51
|
+
|
|
52
|
+
@pytest.fixture(scope="function")
|
|
53
|
+
def post_activity(self):
|
|
54
|
+
TestActivity.calls = []
|
|
55
|
+
|
|
56
|
+
class MockSession:
|
|
57
|
+
@staticmethod
|
|
58
|
+
def post(url, data, **kwargs):
|
|
59
|
+
datadict = json.loads(data.decode("utf-8"))
|
|
60
|
+
action = url.split("/")[-1]
|
|
61
|
+
TestActivity.calls.append((action, datadict))
|
|
62
|
+
if action.endswith("_activity_list"):
|
|
63
|
+
if (
|
|
64
|
+
action != "recently_changed_packages_activity_list"
|
|
65
|
+
and datadict["id"] != "TEST1"
|
|
66
|
+
):
|
|
67
|
+
return mocknotfound(action)
|
|
68
|
+
offset = datadict.get("offset", 0)
|
|
69
|
+
limit = datadict.get("limit", 31)
|
|
70
|
+
return mockresponse(activities[offset : offset + limit], action)
|
|
71
|
+
if datadict["id"] != activity_id:
|
|
72
|
+
return mocknotfound(action)
|
|
73
|
+
if action == "activity_show":
|
|
74
|
+
return mockresponse(activity, action)
|
|
75
|
+
if action == "activity_data_show":
|
|
76
|
+
return mockresponse(activity_data, action)
|
|
77
|
+
if action == "activity_diff":
|
|
78
|
+
return mockresponse(activity_diff, action)
|
|
79
|
+
return mocknotfound(action)
|
|
80
|
+
|
|
81
|
+
Configuration.read().remoteckan().session = MockSession()
|
|
82
|
+
|
|
83
|
+
def test_read_from_hdx(self, configuration, post_activity):
|
|
84
|
+
result = Activity.read_from_hdx(activity_id)
|
|
85
|
+
assert result.data == activity
|
|
86
|
+
assert Activity.read_from_hdx("TEST2") is None
|
|
87
|
+
|
|
88
|
+
def test_get_object_type(self, configuration):
|
|
89
|
+
assert Activity(activity).get_object_type() == "package"
|
|
90
|
+
result = Activity({"activity_type": "new organization"}).get_object_type()
|
|
91
|
+
assert result == "organization"
|
|
92
|
+
result = Activity({"activity_type": "follow dataset"}).get_object_type()
|
|
93
|
+
assert result == "package"
|
|
94
|
+
|
|
95
|
+
def test_get_data_and_diff(self, configuration, post_activity):
|
|
96
|
+
result = Activity(activity)
|
|
97
|
+
assert result.get_data() == activity_data
|
|
98
|
+
assert result.get_diff() == activity_diff
|
|
99
|
+
assert TestActivity.calls[-1] == (
|
|
100
|
+
"activity_diff",
|
|
101
|
+
{"id": activity_id, "object_type": "package", "diff_type": "unified"},
|
|
102
|
+
)
|
|
103
|
+
result.get_diff("html")
|
|
104
|
+
assert TestActivity.calls[-1][1]["diff_type"] == "html"
|
|
105
|
+
result = Activity({"id": "TEST2", "activity_type": "changed package"})
|
|
106
|
+
with pytest.raises(HDXError):
|
|
107
|
+
result.get_data()
|
|
108
|
+
with pytest.raises(HDXError):
|
|
109
|
+
result.get_diff()
|
|
110
|
+
|
|
111
|
+
def test_get_activities(self, configuration, post_activity):
|
|
112
|
+
result = Activity.get_activities("package", "TEST1")
|
|
113
|
+
assert len(result) == 31
|
|
114
|
+
assert isinstance(result[0], Activity)
|
|
115
|
+
assert result[0]["id"] == "activity0"
|
|
116
|
+
result = Activity.get_activities("package", "TEST1", offset=10, limit=5)
|
|
117
|
+
assert [x["id"] for x in result] == [f"activity{i}" for i in range(10, 15)]
|
|
118
|
+
assert TestActivity.calls[-1] == (
|
|
119
|
+
"package_activity_list",
|
|
120
|
+
{"id": "TEST1", "offset": 10, "limit": 5},
|
|
121
|
+
)
|
|
122
|
+
with pytest.raises(HDXError):
|
|
123
|
+
Activity.get_activities("package", "TEST2")
|
|
124
|
+
with pytest.raises(HDXError):
|
|
125
|
+
Activity.get_activities("package", None)
|
|
126
|
+
|
|
127
|
+
def test_get_activities_all_pages(self, configuration, post_activity):
|
|
128
|
+
result = Activity.get_activities("package", "TEST1", all_pages=True)
|
|
129
|
+
assert [x["id"] for x in result] == [x["id"] for x in activities]
|
|
130
|
+
assert [x[1]["offset"] for x in TestActivity.calls] == [0, 100, 200]
|
|
131
|
+
TestActivity.calls = []
|
|
132
|
+
result = Activity.get_activities(
|
|
133
|
+
"package", "TEST1", all_pages=True, offset=150, limit=50
|
|
134
|
+
)
|
|
135
|
+
assert [x["id"] for x in result] == [x["id"] for x in activities[150:]]
|
|
136
|
+
assert [x[1]["offset"] for x in TestActivity.calls] == [150, 200, 250]
|
|
137
|
+
|
|
138
|
+
def test_get_recently_changed_packages(self, configuration, post_activity):
|
|
139
|
+
result = Activity.get_recently_changed_packages(limit=3)
|
|
140
|
+
assert [x["id"] for x in result] == ["activity0", "activity1", "activity2"]
|
|
141
|
+
assert TestActivity.calls[-1] == (
|
|
142
|
+
"recently_changed_packages_activity_list",
|
|
143
|
+
{"limit": 3},
|
|
144
|
+
)
|
|
145
|
+
TestActivity.calls = []
|
|
146
|
+
result = Activity.get_recently_changed_packages(all_pages=True)
|
|
147
|
+
assert len(result) == total_activities
|
|
148
|
+
assert [x[1]["offset"] for x in TestActivity.calls] == [0, 100, 200]
|
|
149
|
+
TestActivity.calls = []
|
|
150
|
+
result = Activity.get_recently_changed_packages(
|
|
151
|
+
all_pages=True, max_activities=120
|
|
152
|
+
)
|
|
153
|
+
assert [x["id"] for x in result] == [x["id"] for x in activities[:120]]
|
|
154
|
+
assert [x[1]["offset"] for x in TestActivity.calls] == [0, 100]
|
|
155
|
+
result = Activity.get_recently_changed_packages(
|
|
156
|
+
all_pages=True, max_activities=100
|
|
157
|
+
)
|
|
158
|
+
assert len(result) == 100
|
|
159
|
+
result = Activity.get_recently_changed_packages(
|
|
160
|
+
all_pages=True, max_activities=None, limit=50
|
|
161
|
+
)
|
|
162
|
+
assert len(result) == total_activities
|
|
163
|
+
|
|
164
|
+
@pytest.mark.parametrize(
|
|
165
|
+
"hdxobjectclass,action",
|
|
166
|
+
[
|
|
167
|
+
(Dataset, "package_activity_list"),
|
|
168
|
+
(Organization, "organization_activity_list"),
|
|
169
|
+
(Location, "group_activity_list"),
|
|
170
|
+
(User, "user_activity_list"),
|
|
171
|
+
],
|
|
172
|
+
)
|
|
173
|
+
def test_hdxobject_get_activities(
|
|
174
|
+
self, configuration, post_activity, hdxobjectclass, action
|
|
175
|
+
):
|
|
176
|
+
hdxobject = hdxobjectclass({"name": "TEST1"})
|
|
177
|
+
result = hdxobject.get_activities(limit=2)
|
|
178
|
+
assert [x["id"] for x in result] == ["activity0", "activity1"]
|
|
179
|
+
assert isinstance(result[0], Activity)
|
|
180
|
+
assert TestActivity.calls[-1] == (action, {"id": "TEST1", "limit": 2})
|
|
181
|
+
hdxobject = hdxobjectclass({"id": "TEST1", "name": "TEST2"})
|
|
182
|
+
hdxobject.get_activities()
|
|
183
|
+
assert TestActivity.calls[-1] == (action, {"id": "TEST1"})
|
|
184
|
+
with pytest.raises(HDXError):
|
|
185
|
+
hdxobjectclass().get_activities()
|
|
186
|
+
|
|
187
|
+
def test_read_only(self, configuration):
|
|
188
|
+
result = Activity(activity)
|
|
189
|
+
with pytest.raises(HDXError):
|
|
190
|
+
result.check_required_fields()
|
|
191
|
+
with pytest.raises(HDXError):
|
|
192
|
+
result.create_in_hdx()
|
|
193
|
+
with pytest.raises(HDXError):
|
|
194
|
+
result.update_in_hdx()
|
|
195
|
+
with pytest.raises(HDXError):
|
|
196
|
+
result.delete_from_hdx()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_datasource_topline.json
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_datasource_topline.yaml
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_email_configuration.json
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_email_configuration.yaml
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_missing_site_config.json
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_organization_static.json
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_organization_static.yaml
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_resource_static.json
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_resource_static.yaml
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_resource_view_static.json
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_resource_view_static.yaml
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_showcase_static.json
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_showcase_static.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_vocabulary_static.json
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/hdx_vocabulary_static.yaml
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/project_configuration.json
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/project_configuration.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/config/user_agent_config_wrong.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/gen_resource/conflict_data_alg.csv
RENAMED
|
File without changes
|
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/gen_resource/qc_conflict_data_alg.csv
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/gen_resource/test_data_no_data.csv
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/gen_resource/test_data_no_years.csv
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/location/location_list_all_fields.yaml
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/location/location_show_results.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/qc_from_rows/qc_conflict_data_alg.csv
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/fixtures/showcase_all_search_results.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/api/utilities/test_filestore_helper.py
RENAMED
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/api/utilities/test_hdx_error_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_dataset_resource_generation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hdx_python_api-6.7.1 → hdx_python_api-6.7.2}/tests/hdx/data/test_update_dataset_resources.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|