hdx-python-api 6.7.0__py3-none-any.whl → 6.7.1__py3-none-any.whl
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/api/_version.py +2 -2
- hdx/data/resource.py +180 -1
- {hdx_python_api-6.7.0.dist-info → hdx_python_api-6.7.1.dist-info}/METADATA +3 -3
- {hdx_python_api-6.7.0.dist-info → hdx_python_api-6.7.1.dist-info}/RECORD +6 -6
- {hdx_python_api-6.7.0.dist-info → hdx_python_api-6.7.1.dist-info}/WHEEL +1 -1
- {hdx_python_api-6.7.0.dist-info → hdx_python_api-6.7.1.dist-info}/licenses/LICENSE +0 -0
hdx/api/_version.py
CHANGED
|
@@ -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.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (6, 7, 1)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
hdx/data/resource.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
|
-
from collections.abc import Sequence
|
|
5
|
+
from collections.abc import Iterator, Sequence
|
|
6
6
|
from datetime import datetime
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import Any, Optional
|
|
@@ -34,6 +34,7 @@ class Resource(HDXObject):
|
|
|
34
34
|
"""
|
|
35
35
|
|
|
36
36
|
_formats_dict = None
|
|
37
|
+
_valid_datastore_dump_formats = frozenset({"csv", "tsv", "json", "xml"})
|
|
37
38
|
_valid_data_dictionary_types = frozenset(
|
|
38
39
|
{"text", "numeric", "date", "timestamp without time zone"}
|
|
39
40
|
)
|
|
@@ -70,6 +71,7 @@ class Resource(HDXObject):
|
|
|
70
71
|
"datastore_insert": "datastore_insert",
|
|
71
72
|
"datastore_upsert": "datastore_upsert",
|
|
72
73
|
"datastore_search": "datastore_search",
|
|
74
|
+
"datastore_search_sql": "datastore_search_sql",
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
def update_from_yaml(
|
|
@@ -711,6 +713,62 @@ class Resource(HDXObject):
|
|
|
711
713
|
path = downloader.download_file(url, folder=folder, filename=filename)
|
|
712
714
|
return url, path
|
|
713
715
|
|
|
716
|
+
def get_datastore_dump_url(self, file_format: str = "csv") -> str:
|
|
717
|
+
"""Get the URL from which the resource datastore can be downloaded in
|
|
718
|
+
full.
|
|
719
|
+
|
|
720
|
+
Args:
|
|
721
|
+
file_format: Dump format (csv, tsv, json or xml). Defaults to csv.
|
|
722
|
+
|
|
723
|
+
Returns:
|
|
724
|
+
Datastore dump URL
|
|
725
|
+
"""
|
|
726
|
+
file_format = file_format.lower()
|
|
727
|
+
if file_format not in self._valid_datastore_dump_formats:
|
|
728
|
+
valid_formats = ", ".join(sorted(self._valid_datastore_dump_formats))
|
|
729
|
+
raise HDXError(
|
|
730
|
+
f"Invalid datastore dump format '{file_format}'! Must be one of: {valid_formats}"
|
|
731
|
+
)
|
|
732
|
+
url = (
|
|
733
|
+
f"{self.configuration.get_hdx_site_url()}/datastore/dump/{self.data['id']}"
|
|
734
|
+
)
|
|
735
|
+
if file_format != "csv":
|
|
736
|
+
url = f"{url}?format={file_format}"
|
|
737
|
+
return url
|
|
738
|
+
|
|
739
|
+
def download_datastore(
|
|
740
|
+
self,
|
|
741
|
+
folder: Path | str | None = None,
|
|
742
|
+
filename: str | None = None,
|
|
743
|
+
file_format: str = "csv",
|
|
744
|
+
retriever: Retrieve | None = None,
|
|
745
|
+
) -> tuple[str, Path]:
|
|
746
|
+
"""Download the resource datastore in full to provided folder or
|
|
747
|
+
temporary folder if no folder supplied
|
|
748
|
+
|
|
749
|
+
Args:
|
|
750
|
+
folder: Folder to download datastore to. Defaults to None.
|
|
751
|
+
filename: Filename to use. Defaults to None (resource name with file_format extension).
|
|
752
|
+
file_format: Dump format (csv, tsv, json or xml). Defaults to csv.
|
|
753
|
+
retriever: Retrieve object to use. Defaults to None.
|
|
754
|
+
|
|
755
|
+
Returns:
|
|
756
|
+
(URL downloaded, Path to downloaded file)
|
|
757
|
+
"""
|
|
758
|
+
url = self.get_datastore_dump_url(file_format)
|
|
759
|
+
logger.debug(f"Downloading {url}")
|
|
760
|
+
if filename is None:
|
|
761
|
+
filename = self.data["name"]
|
|
762
|
+
extension = f".{file_format.lower()}"
|
|
763
|
+
if not filename.endswith(extension):
|
|
764
|
+
filename = f"{filename}{extension}"
|
|
765
|
+
session = hdx.api.utilities.url_utils.get_ckan_ready_session(self.configuration)
|
|
766
|
+
with Download(session=session) as downloader:
|
|
767
|
+
if retriever:
|
|
768
|
+
downloader = retriever.clone(downloader)
|
|
769
|
+
path = downloader.download_file(url, folder=folder, filename=filename)
|
|
770
|
+
return url, path
|
|
771
|
+
|
|
714
772
|
@staticmethod
|
|
715
773
|
def get_all_resource_ids_in_datastore(
|
|
716
774
|
configuration: Configuration | None = None,
|
|
@@ -805,6 +863,127 @@ class Resource(HDXObject):
|
|
|
805
863
|
}
|
|
806
864
|
self._write_to_hdx("datastore_upsert", data, "resource_id")
|
|
807
865
|
|
|
866
|
+
def search_datastore(
|
|
867
|
+
self,
|
|
868
|
+
filters: dict | None = None,
|
|
869
|
+
q: str | dict | None = None,
|
|
870
|
+
fields: Sequence[str] | None = None,
|
|
871
|
+
sort: str | None = None,
|
|
872
|
+
distinct: bool = False,
|
|
873
|
+
limit: int = 100,
|
|
874
|
+
offset: int = 0,
|
|
875
|
+
include_total: bool = True,
|
|
876
|
+
**kwargs: Any,
|
|
877
|
+
) -> dict:
|
|
878
|
+
"""Search the resource datastore using CKAN datastore_search.
|
|
879
|
+
|
|
880
|
+
Args:
|
|
881
|
+
filters: Dictionary of field name to value(s) to match. Defaults to None.
|
|
882
|
+
q: Full text query string or dictionary of field name to query. Defaults to None.
|
|
883
|
+
fields: Fields to return. Defaults to None (all fields).
|
|
884
|
+
sort: Comma separated field names with optional asc/desc eg. "code desc". Defaults to None.
|
|
885
|
+
distinct: Whether to return only distinct rows. Defaults to False.
|
|
886
|
+
limit: Maximum number of rows to return. Defaults to 100.
|
|
887
|
+
offset: Number of rows to skip. Defaults to 0.
|
|
888
|
+
include_total: Whether to include total number of matching rows. Defaults to True.
|
|
889
|
+
**kwargs: Other parameters to pass to datastore_search eg. plain, language.
|
|
890
|
+
|
|
891
|
+
Returns:
|
|
892
|
+
datastore_search result dictionary with keys including records, fields and total
|
|
893
|
+
"""
|
|
894
|
+
data: dict = {
|
|
895
|
+
"resource_id": self.data["id"],
|
|
896
|
+
"limit": limit,
|
|
897
|
+
"offset": offset,
|
|
898
|
+
"include_total": include_total,
|
|
899
|
+
}
|
|
900
|
+
if filters is not None:
|
|
901
|
+
data["filters"] = filters
|
|
902
|
+
if q is not None:
|
|
903
|
+
data["q"] = q
|
|
904
|
+
if fields is not None:
|
|
905
|
+
data["fields"] = ",".join(fields)
|
|
906
|
+
if sort is not None:
|
|
907
|
+
data["sort"] = sort
|
|
908
|
+
if distinct:
|
|
909
|
+
data["distinct"] = True
|
|
910
|
+
data.update(kwargs)
|
|
911
|
+
return self._write_to_hdx("datastore_search", data, "resource_id")
|
|
912
|
+
|
|
913
|
+
def get_datastore_records(
|
|
914
|
+
self,
|
|
915
|
+
filters: dict | None = None,
|
|
916
|
+
q: str | dict | None = None,
|
|
917
|
+
fields: Sequence[str] | None = None,
|
|
918
|
+
sort: str | None = None,
|
|
919
|
+
distinct: bool = False,
|
|
920
|
+
page_size: int = 10000,
|
|
921
|
+
**kwargs: Any,
|
|
922
|
+
) -> Iterator[dict]:
|
|
923
|
+
"""Iterate over all matching records in the resource datastore, paging
|
|
924
|
+
through datastore_search results.
|
|
925
|
+
|
|
926
|
+
Args:
|
|
927
|
+
filters: Dictionary of field name to value(s) to match. Defaults to None.
|
|
928
|
+
q: Full text query string or dictionary of field name to query. Defaults to None.
|
|
929
|
+
fields: Fields to return. Defaults to None (all fields).
|
|
930
|
+
sort: Comma separated field names with optional asc/desc eg. "code desc". Defaults to None.
|
|
931
|
+
distinct: Whether to return only distinct rows. Defaults to False.
|
|
932
|
+
page_size: Number of rows to request per call. Defaults to 10000.
|
|
933
|
+
**kwargs: Other parameters to pass to datastore_search eg. plain, language.
|
|
934
|
+
|
|
935
|
+
Returns:
|
|
936
|
+
Iterator of record dictionaries
|
|
937
|
+
"""
|
|
938
|
+
offset = 0
|
|
939
|
+
while True:
|
|
940
|
+
result = self.search_datastore(
|
|
941
|
+
filters=filters,
|
|
942
|
+
q=q,
|
|
943
|
+
fields=fields,
|
|
944
|
+
sort=sort,
|
|
945
|
+
distinct=distinct,
|
|
946
|
+
limit=page_size,
|
|
947
|
+
offset=offset,
|
|
948
|
+
include_total=False,
|
|
949
|
+
**kwargs,
|
|
950
|
+
)
|
|
951
|
+
records = result["records"]
|
|
952
|
+
yield from records
|
|
953
|
+
if len(records) < page_size:
|
|
954
|
+
return
|
|
955
|
+
offset += page_size
|
|
956
|
+
|
|
957
|
+
def get_datastore_fields(self) -> list[dict]:
|
|
958
|
+
"""Get the field definitions of the resource datastore excluding the
|
|
959
|
+
internal _id field.
|
|
960
|
+
|
|
961
|
+
Returns:
|
|
962
|
+
List of field dictionaries each with id and type keys
|
|
963
|
+
"""
|
|
964
|
+
result = self.search_datastore(limit=0, include_total=False)
|
|
965
|
+
return [field for field in result["fields"] if field["id"] != "_id"]
|
|
966
|
+
|
|
967
|
+
@staticmethod
|
|
968
|
+
def search_datastore_sql(
|
|
969
|
+
sql: str,
|
|
970
|
+
configuration: Configuration | None = None,
|
|
971
|
+
) -> list[dict]:
|
|
972
|
+
"""Run a read-only SQL query against the HDX datastore using CKAN
|
|
973
|
+
datastore_search_sql. Tables are named by resource id, which must be
|
|
974
|
+
double quoted eg. SELECT * FROM "RESOURCE_ID".
|
|
975
|
+
|
|
976
|
+
Args:
|
|
977
|
+
sql: SQL SELECT statement
|
|
978
|
+
configuration: HDX configuration. Defaults to global configuration.
|
|
979
|
+
|
|
980
|
+
Returns:
|
|
981
|
+
List of record dictionaries
|
|
982
|
+
"""
|
|
983
|
+
resource = Resource(configuration=configuration)
|
|
984
|
+
result = resource._write_to_hdx("datastore_search_sql", {"sql": sql})
|
|
985
|
+
return result["records"]
|
|
986
|
+
|
|
808
987
|
def delete_datastore(self) -> None:
|
|
809
988
|
"""Delete a resource from the HDX datastore
|
|
810
989
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: hdx-python-api
|
|
3
|
-
Version: 6.7.
|
|
3
|
+
Version: 6.7.1
|
|
4
4
|
Summary: HDX Python API for interacting with the Humanitarian Data Exchange
|
|
5
5
|
Project-URL: Homepage, https://github.com/OCHA-DAP/hdx-python-api
|
|
6
6
|
Author: Michael Rans
|
|
@@ -28,8 +28,8 @@ Requires-Python: >=3.10
|
|
|
28
28
|
Requires-Dist: ckanapi>=4.11
|
|
29
29
|
Requires-Dist: defopt>=7.0.0
|
|
30
30
|
Requires-Dist: email-validator
|
|
31
|
-
Requires-Dist: hdx-python-country>=4.
|
|
32
|
-
Requires-Dist: hdx-python-utilities>=4.1
|
|
31
|
+
Requires-Dist: hdx-python-country>=4.2.3
|
|
32
|
+
Requires-Dist: hdx-python-utilities>=4.2.1
|
|
33
33
|
Requires-Dist: makefun
|
|
34
34
|
Requires-Dist: requests
|
|
35
35
|
Provides-Extra: docs
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
hdx/api/__init__.py,sha256=11ozJKiUsqDCZ3_mcAHhGYUyGK_Unl54djVSBBExFB4,59
|
|
2
|
-
hdx/api/_version.py,sha256=
|
|
2
|
+
hdx/api/_version.py,sha256=7uXJAam46P0GVJ-CiBxd6tVnUUkt-epJdnvQ6m2fpb4,520
|
|
3
3
|
hdx/api/configuration.py,sha256=9WvuVI-3th2Dv70_t_4VoyrlJwB_9qUSN5_zUKbp4sQ,23805
|
|
4
4
|
hdx/api/hdx_base_configuration.yaml,sha256=jj2t5b7NnI499rHVwOjj3Q5BAjE8i7NDGVKnWZ5P5-4,2222
|
|
5
5
|
hdx/api/locations.py,sha256=bFl_cKz_AEQzkE_xWOkrRlUQ0GT2LMPSk-G_LsbV-Ns,4099
|
|
@@ -15,7 +15,7 @@ hdx/data/dataset.py,sha256=0gS7tQSswTgG0g8YeXg0FL8pFVkocBQSRPFpQAurN00,99455
|
|
|
15
15
|
hdx/data/hdxobject.py,sha256=_jlwYjb_CcjaXsTXObknMfq-OiNOcpJfLJ9b1vKV1Zo,27494
|
|
16
16
|
hdx/data/location.py,sha256=WIQRdY1boy6xPweIWRczWNiJLFrp4w0DVUwppHeNccU,8765
|
|
17
17
|
hdx/data/organization.py,sha256=HGopFsCYOWrR7sUtZzZSXq6wLFw4djus2gzg6yNXOqc,12296
|
|
18
|
-
hdx/data/resource.py,sha256=
|
|
18
|
+
hdx/data/resource.py,sha256=iVARfA3_8gGsGjXgNxomm7umAadvxzFsGGqxTpBB3WQ,45196
|
|
19
19
|
hdx/data/resource_matcher.py,sha256=Yzk9pWa4zk1p09m6zcZMj0XZf5Y16Pa3KToOdUt7rP8,4247
|
|
20
20
|
hdx/data/resource_view.py,sha256=GcYkh0iDAe6_m2ErY_A6i3Z7ZFX949eGt1TLnLZv_8s,7346
|
|
21
21
|
hdx/data/showcase.py,sha256=vnRZ45xd9Ct65eFQkWZtMIJPFifZfKOrH4obO5D5Pvc,14062
|
|
@@ -25,7 +25,7 @@ hdx/facades/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
25
25
|
hdx/facades/infer_arguments.py,sha256=DvyDuozfOPmoaV7HjhQySojGIrMWW9nos31auQBVVl8,4032
|
|
26
26
|
hdx/facades/keyword_arguments.py,sha256=aVapHCfqBO6H7xxBgTdK9ISdgrBFsNypPDWihfQ3edU,1125
|
|
27
27
|
hdx/facades/simple.py,sha256=QWsBkaHG_UM6X3Zu2u3LWVOQzeR24q-EUClrfsL_mkM,1064
|
|
28
|
-
hdx_python_api-6.7.
|
|
29
|
-
hdx_python_api-6.7.
|
|
30
|
-
hdx_python_api-6.7.
|
|
31
|
-
hdx_python_api-6.7.
|
|
28
|
+
hdx_python_api-6.7.1.dist-info/METADATA,sha256=7SaqX2zZKJ828e94hbPjvjJ_3q5obaL0NU9Ghut_86A,4946
|
|
29
|
+
hdx_python_api-6.7.1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
30
|
+
hdx_python_api-6.7.1.dist-info/licenses/LICENSE,sha256=wc-4GpMn-ODs-U_bTe1YCiPVgvcjzrpYOx2wPuyAeII,1079
|
|
31
|
+
hdx_python_api-6.7.1.dist-info/RECORD,,
|
|
File without changes
|